Skip to content
Baltasar García Perez-Schofield edited this page Oct 29, 2023 · 12 revisions

Objetos, objetos contenedores y objetos para ponerse

Los objetos que el jugador puede manipular en el juego son instancias de Obj. Para crearlos, se utiliza la función ctrl.creaObj(). Sus parámetros son: nombre, sinónimos, descripción, localidad en la que se encuentra y Ent.Scenery o Ent.Portable según sea escenario o sea un objeto que se pueda transportar.

const objMesa = ctrl.creaObj( "mesa",
     [],
     "Una mesa antigua.",
     locSalon,
     Ent.Scenery
);

const objBotella = ctrl.creaObj( "botella",
     [ "agua", "recipiente" ],
     "Una botella llena de agua.",
     ctrl.lugares.limbo,
     Ent.Portable
);

Cuando por localidad se indica ctrl.lugares.limbo, la botella no será visible en ninguna localidad del juego, hasta que se mueva a alguna de ellas.

Nótese que los sinónimos se pasan utilizando un vector de JavaScript. Como cualquier otro objeto, se le pueden añadir atributos y métodos que sirvan a nuestros propósitos.

objBotella.llena = false;
objBotella.describe = function() {
    let toret = "Una botella de vidrio. ";

    if ( this.llena ) {
        toret += "Está llena de agua.";
    } else {
        toret += "Está vacía.";
    }

    return toret;
};

objBotella.preExamine = function() {
    return this.describe();
};

Ahora se puede llamar al método describe() para obtener una descripción detallada de la botella. Por ejemplo, podría ser llamado desde preExamine(), si se va a hacer algo más (al contrario que en el ejemplo). O, quizás, pueda ser llamada directamente, como se ve a continuación.

objBotella.llena = false;
objBotella.preExamine = function() {
    let toret = "Una botella de vidrio. ";

    if ( this.llena ) {
        toret += "Está llena de agua.";
    } else {
        toret += "Está vacía.";
    }

    return toret;
};

Como se menciona más arriba, la botella tiene que moverse a la localidad del salón (locSalon), para que se vea allí.

    objBotella.mueveA( locSalon );

Contenedores

Otra posibilidad es que la mesa sea un objeto contenedor. Para marcar Los objetos como contenedores se utiliza setContainer()/ponContenedor(), que por defecto, si no se les pasa un parámetro, se asume que este es true. Los métodos esContenedor()/isContainer() devuelven true o false según el objeto sea o no contenedor.

Estos objetos pueden contener otros objetos, y son visibles para el jugador si están abiertos (por defecto lo están). Para saber si un contenedor está abierto, se usa el método isOpen()/estaAbierto(). Se cambia el estado de abierto a cerrado con setOpen()/ponAbierto(). Por defecto, si no se pasa un parámetro, se entiende que es true.

Nótese que nada impide llamar a estaAbierto() o esContenedor() incluso aunque el objeto no sea un contenedor. Por defecto, los objetos no son contenedores y están abiertos. También es posible meter objetos dentro de otros, pero no serán manipulables si el contenedor no está marcado como tal y está abierto.

En el caso del salón, la mesa es un contenedor que siempre está abierto (para el usuario será un soporte, pero es indifirente). Solo lo siguiente obtiene ya el comportamiento deseado.

objMesa.ponContenedor();
objBotella.mueveA( objMesa );

Así, al jugar:

> m
Salón
Estás en el salón, hay una mesa.

> ex mesa
Una mesa antigua.
Tiene: botella.

> coge la botella
Cogida.

En lugar de una mesa, podría tratarse de un armario que puede abrirse y cerrarse.

const objArmario = ctrl.creaObj( "armario",
     [],
     "Un armario antiguo.",
     locSalon,
     Ent.Scenery
);

objArmario.ponContenedor();
objArmario.ponAbierto( false );
objArmario.preOpen = function() {
        let toret = "Pero si ya está abierto...";

        if ( !this.isOpen() ) {
            this.setOpen();
            toret = "El armario está ahora abierto.";
        }

        return toret;
};

objArmario.preExamine = function() {
    let toret = this.desc;

    if ( this.isOpen() ) {
        toret += " Está abierto.";
    } else {
        toret += " Está cerrado.";
    }

    return toret;
}

objBotella.mueveA( objArmario );

Ahora, al jugar...

> m
Salón
Estás en el salón, hay una mesa flanqueada por un armario.

> ex mesa
Una mesa antigua.

> ex armario
Un armario antiguo. Está cerrado.

> abre el armario
El armario está ahora abierto.

> abre el armario
Pero si ya está abierto...

> ex armario
Un armario antiguo. Está abierto.
Tiene: botella.

> coge la botella
Cogida.

Objetos (in)alcanzables

Además, hay objetos que son manipulables del todo por el jugador, como la botella: puede cogerla, dejarla... o parcialmente manipulables, como la mesa: se puede examinar, y coger cosas de ella, pero no llevársela. Hay objetos que tienen una restricción más: ¿son o no son alcanzables? Por supuesto, por defecto sí lo son. ¿Qué es un objeto no alcanzable? Por ejemplo, podría ser una flor en lo alto de un acantilado, el sol o la luna...

Para manejar esta restricción extra, se utilizan isReachable()/esAlcanzable() para saber si el objeto está o no al alcance, y setReachable()/ponAlcanzable() para saber si está o no alcanzable. Por defecto, si no se le pasa ningún parámetro, se asume true, es decir, que el objeto es alcanzable. Es importante tener en cuenta, de nuevo, que los objetos son alcanzables por defecto.

Supongamos que en el salón hay una lámpara.

const objLampara = ctrl.creaObj( "lámpara",
     [ "lampara", "arana" ],
     "Una vieja araña.",
     locSalon,
     Ent.Scenery
);
objLampara.ponAlcanzable( false );

Ahora, al jugar...

> m
Salón
Estás en el salón, hay una mesa flanqueada por un armario. En el techo, puedes ver una antigua lámpara.

> ex lampara
Una vieja araña.

> ex mesa
Una mesa antigua.

> lame mesa
Al final, decides no hacerlo.

> lame lampara
Demasiado lejos.

> huele mesa
No huele a nada especial.

> huele lampara.
Demasiado lejos.

Este comportamiento puede por supuesto cambiarse con los métodos preExamine(), preTaste() o preSmell(), pero el objetivo es que las respuestas por defecto tengan sentido incluso cuando se estén utilizando aquellas por defecto.

Ropa

Hay objetos que se los puede poner el jugador, como un jersey o unos pantalones. Para ello, solo es necesario marcarlo como ropa. Los métodos setClothing()/ponPrenda() marca un objeto como que se lo puede poner el jugador (si no se pasa un valor booleano, se asume true). Los métodos isClothing()/esPrenda() devuelven si un objeto es o no es ropa. De la misma manera, isWorn()/estaPuesto() devuelve si el jugador lleva dicho objeto puesto. Los métodos setWorn()/ponPuesto() cambian la prenda a estar o no sobre el jugador.

Es importante tener en cuenta que el proceso de ponerse o quitarse algo, igual que el proceso de coger o dejar algo, es automático. También de la misma forma, si quieremos intervenir en el proceso de vestir algo, debemos crear un método preWear() en nuestro objeto, mientras que para desvestirse, se llama a preDisrobe() en nuestro objeto, si existe. Estas acciones se describe en profundidad en la lista de acciones.

El siguiente código está tomado de Vampiro, el juego obligatorio de demostración para cualquier lenguaje, que es accesible desde la web de fi-js.

const objRistraDeAjos = ctrl.creaObj(
    "ristra de ajos",
    [ "ristra", "ajos", "ajo" ],
    "Es una ristra entera de ajos que expelen \
     un olor un tanto asqueroso. \
     Es uno de los cuatro elementos que me servirán \
     para derrotar al vampiro.",
    ctrl.lugares.limbo,
    Ent.Portable
);

objRistraDeAjos.ponPrenda();
// ...más cosas...

objAtaud.preOpen = function() {
        var toret = "";

        // La estaca
        if ( !ctrl.estaPresente( objTrozoDeMadera ) )
        {
                toret += "Necesitas un estaca que clavar en el \
                          corazón del vampiro.\n";
        } else {
                if ( !objTrozoDeMadera.afilado ) {
                        toret += "Podrías utilizar el madero, como \
                                  estaca, pero no está afilado.\n";
                }
        }

        // El martillo
        if ( !ctrl.estaPresente( objMartillo ) ) {
                toret += "Falta algo con lo que golpear la estaca.\n";
        }

        // El crucifijo
        if ( !ctrl.estaPresente( objCrucifijoPlateado ) ) {
                toret += "Es básica una protección religiosa.\n";
        } else {
                if ( !objCrucifijoPlateado.estaPuesto() ) {
                        toret += "El crucifijo debería colgar de tu \
                                  cuello.\n";
                }
        }

        // La ristra de ajos
        if ( !ctrl.estaPresente( objRistraDeAjos ) ) {
                toret += "Es básica una protección pagana.\n";
        } else {
                if ( !objRistraDeAjos.estaPuesto() ) {
                        toret += "La protección del ajo solamente se \
                                  logra si cuelga de tu cuello.\n";
                }
        }

        // Es el final?
        if ( toret.length === 0 ) {
            const dvFrame = ctrl.getHtmlPart( "dvFrame", "missing frame div" );

            dvFrame.style.display = "none";
            ctrl.logros.logrado( "matavampiros" );
            msg = "\
                    Abres el ataúd, y, protegido por \
                    los ajos y el crucifijo, comienzas \
                    tu tarea. La cara de horror del \
                    vampiro cuando le clavas la estaca \
                    solo es comparable al rostro \
                    lleno de paz que puedes observar \
                    unos cuantos martillazos después. \
                    La reducción del cuerpo a cenizas \
                    te confirma que tu misión está ya \
                    cumplida. \
                    <p class='clsAchieved'>Logros: "
                + ctrl.logros.completadosComoTexto()
                + "</p>";

            ctrl.terminaJuego( msg, "res/portada_vampiro.jpg" );
        } else {
                toret = "Revisas que tengas todo lo necesario...<br>"
                        + toret;
        }

        return toret;
};

Ini

Puede redefinirse una función ini() que será ejecutada antes del comienzo del juego. Por defecto, esta función no hace nada.

const objRistraDeAjos = ctrl.creaObj(
    "ristra de ajos",
    [ "ristra", "ajos", "ajo" ],
    "Es una ristra entera de ajos que expelen \
     un olor un tanto asqueroso. \
     Es uno de los cuatro elementos que me servir&aacute;n \
     para derrotar al vampiro.",
    ctrl.lugares.limbo,
    Ent.Portable
);

objRistraDeAjos.ini = function() {
    this.ponPrenda();
};

La función ini() también puede darse como último parámetro durante la creación.

const objRistraDeAjos = ctrl.creaObj(
    "ristra de ajos",
    [ "ristra", "ajos", "ajo" ],
    "Es una ristra entera de ajos que expelen \
     un olor un tanto asqueroso. \
     Es uno de los cuatro elementos que me servir&aacute;n \
     para derrotar al vampiro.",
    ctrl.lugares.limbo,
    Ent.Portable,
    function() {
        this.ponPrenda();
    }
);