ah, cutscenes

ya había hecho el trabajo de reescribir el código relacionado con las cutscenes, pero todavía no lo implementaba. lo acabo de hacer, y funciona muy bien. arreglé unos bugs que se producían principalmente por la centralización de los cutscenes en el obj_control y de los cuales no me había dado cuenta hasta que implementé el código; ahora todo funciona. lo único que me falta por escribir es unir el motor de diálogos con las cutscenes. voy a tener que escribir algunas cosas extras para eso, como por ejemplo, un controlador que le indique al diálogo que el usuario no tiene que presionar nada para que el diálogo avance, junto con un contador para que se defina un tiempo personalizado cuando el diálogo termine.

he estado posponiendo mucho el tema de los caracteres controladores en el diálogo. no debiese ser dificil; lo tenía implementado en el sistema anterior, así que es cosa de revisar si puedo reutilizar ése código y listo.

lo más bacán del código actual para manejar las cutscenes es que se puede definir un cutscene en la creación de una room, y se pueden orquestar a todos los actores presentes con identificador, por lo que hacer cutscenes para el juego debiese ser fácil. añadir casos al sistema de cutscenes es tan sencillo como añadir casos al de diálogos. con los cutscenes hechos y una vez que le añada los caracteres especiales al asunto comienzo a trabajar en el código que se refiera a enemigos: variables extras, comportamientos básicos, y cosas así. voy a tener que reimplementar el código de los sparks (por fin se cómo ponerles a esas cosas) para las explosiones y esas cuestiones. también voy a tener que trabajar en el sistema que se encargue de las muertes, de los enemigos, los aliados y esas cosas.

cuando termine el sistema de enemigos, tengo muchos puntos por seguir desarrollando, y procedo a dejarlos anotados antes de que se me olviden:

  • tipos de diálogos: diálogos que ocupen imágenes/ilustraciones, diálogos sin marco, etc.
  • portales: ésto lo tengo solucionado desde una de las iteraciones anteriores de catbox. No debiese ser problema.
  • transición desde una escena a otra: ésto siempre me dio problemas. Éstaba pensando que la forma más sencilla de hacerlo es haciendo que los personajes sean persistentes y ubicarlos en cierto lugar al principio de cada escena. Tengo que cachar, además, el código para que los personajes entren y salgan de las escenas. No me gusta el código viejo mio, así que hay que cambiarlo.
  • clima y Hora: ésto es algo que se me ocurrió hace un tiempo. Las escenas de las iteraciones anteriores se podían definir con hora y clima, pero ahora me gustaría tener un sistema que maneje todo eso de forma automática. La forma de proceder en éste caso es asumir el acercamiento de Legend of Zelda: Ocarina of Time con respecto al tema, y hacer ciertos lugares en que el tiempo trascurra, y que el resto sean puntos fijos; En la carretera/los caminos, el día pasa y según los horarios del día aparecen o se esconden ciertos enemigos, y en el resto de los lugares el tiempo o bien es estático o se comporta de forma arbitraria, por ejemplo, si debes salir de noche a un lugar, que la forma de "hacer de noche" sea entrando a una casa a la que debes pasar a buscar un item o a un personaje. Lo que quiero es no perder la linealidad de la narrativa del juego, pero que existan cambios de terreno que afecten al gameplay. El motor debe estar preparado para ambos casos.
  • menus: sí, tengo resuelto el tema de los menu en los diálogos, pero todavía no hago uno para el resto de las instancias de menu en el juego. Ésto implica implementar offsets para menús en que hayan más opciones de las que se muestran en pantalla.
  • inventario: lo tengo medianamente resuelto en otras iteraciones, pero se me ocurrió, inspirado en Earthbound, que cada aliado debiese tener su propio inventario, y que los items, al usarlos, debiese ser posible elegir quién los va a usar. También debería existir una opción para desocupar celdas en el inventario o traspasar los items entre aliados. Lo que es aún más importante, tengo que programar un sistema de almacenamiento de items. No es difícil, pero es un sistema completamente nuevo y debe funcionar de forma similar a las tiendas.
  • aliados: lo tengo medianamente resuelto, pero hay un asunto con las views que nunca me gustó. Tengo que arreglar eso. Probablemente pausando el juego cuando un aliado está muy lejos de otro.
  • música y sonidos: meh.

una vez que pueda resolver todos los temas pendientes, puedo decir con libertad (¡y de una buenas vez!) que la versión 1.0 del motor está lista, y por lo tanto voy a liberarlo junto a una demo cortita que muestre todo lo que se puede hacer con el motor. antes, eso sí, tengo que pensar en una licencia buena onda para liberarlo. me gustaría liberarlo bajo una licencia similar a las GPL v2, pero tengo que ver exactamente qué quiero hacer. hm.

cutscenes

el código básico de las cutscenes está listo. relativamente.

el sistema funciona de forma similar al de diálogos, con una fila de comandos que el sistema interpreta como acciones (1 caminar, 2 correr, 3 saltar, etc) y, tal como el sistema de diálogos, es muy sencillo programar una secuencia de comandos para un actor.

sin embargo, por algún motivo, código que en el sistema de diálogos funciona impecable no funciona en lo absoluto en el sistema de cutscenes. probablemente es un condoro mio, pero honestamente miré el código muchas veces y no logré identificar la pifia. cuando llego a ése punto la solución es sencilla: me olvido del tema y hago otra cosa, hasta eventualmente retomarlo. distancia crítica le llaman.

(sin embargo introduje manualmente algunos valores y funcionan, aunque es un poco extraño ver a un personaje que no tiene gráficos para saltar saltando. el sistema se buggea entero y reemplaza el gráfico por lo primero que encuentra, lo que aparentemente en mi índice de sprites equivale a una caja negra. oh, bueno.)

también me di cuenta que cuando no quiero programar, lo único que tengo que hacer es agarrar lápiz y papel y tratar de resolver el problema lógicamente. a veces el lenguaje se vuelve un estorbo para ver exactamente cuál es el problema. espero tener eso en cuenta durante el resto de mi vida.

ah, y arreglé un bug en que el juego crasheaba si le hablabas a un actor sin diálogo definido. por extraño que pueda parecer, el código no lo contemplaba. un hack rápido al código rompió, además, el sistema de almacenamiento de ids de objetos que tienen asignados diálogos o comandos de cutscenes en la escena, y, por ende, el juego sencillamente no sabía quién tenía diálogo y asumía que nadie tenía dialogos, por lo que no se podía hablar con nadie. eso también lo arreglé.

edit: el asunto de los cutscenes está resuelto. lamentablemente estaba pensando en que necesito una forma centralizada de trabajar con cutscenes, por lo que voy a tener que adaptar el código para que pueda ser activado remotamente, y no sencillamente recurrir al índice de la cutscene.

la mejor tienda del mundo

con ésto, y en resúmen, toda la funcionalidad básica de la tienda (relacionada con comprar objetos) está lista. falta trabajar bien el asunto de vender objetos. ¿es realmente necesario? yo no creo, pero bueh.

también hay algo que me complica, y es el hecho de comprar más objetos de los que puedes llevar. no lanza ningún error, pero así como el juego detecta cuando estás comprando más del dinero que tienes, debería hacer algo que detecte cuando estás comprando más objetos de los que puedes llevar. ésto puede ser un cacho porque cuando un objeto tiene más de 99 instancias en inventario, se crea una nueva instancia para agruparlos. ésta restricción es principalmente para que uno no pueda comprar 99999999999999999999 objetos del mismo tipo, sin embargo, supongamos que tenemos 52 instancias de un objeto, y compramos 99, pero no quedan más espacios. el juego te debiese dejar comprar hasta 47 veces el mismo objeto, sin embargo el límite es 99. ¿cómo checamos eso? se me ocurren dos soluciones:

podría hacerse con una función (que llamaremos inventory_cancarryitem() o algo así) que recibe un índice de objeto, y que s- no, espera, el trabajo lógico de ésto ya está hecho en el script para dar items. podría hacer que sencillamente ése mismo script devuelva un true o false si puede o no puede conservar la cantidad de items en inventario. me imagino que se podría usar la función sólo para devolver el true o false dentro de una expresión, sin que, efectivamente, añada el item, pero no se. tengo que cachar si funca o no funca.

la otra opción es cagarse en el jugador. mala cuea si compra más items de los que puede llevar.

(sin embargo ésta última opción no es tan recomendable, tomando en cuenta que cuando haga la parte de vender voy a tener que tener una comprobación similar para evitar transacciones de más items que los poseídos. mejor me ahorro pega y lo hago bien al tiro.)

lo siguiente que voy a abordar va a ser el sistema de cutscenes con texto e imagen, mientras pienso en el otro sistema de cutscenes, con actores. de hecho, voy a aprovechar de antor acá las ideas para eso.

lo más lógico es que el sistema de cutscenes en que se utilicen actores, cada actor tenga preprogramada un trigger y una secuencia de comandos, más o menos así:

if_trigger("trigger de la cutscene",true); // si el trigger está activado,
move("+64",false); //camina 64 pixeles a la izquierda, la siguiente acción no empieza hasta que avance esos 64 píxeles o se tope con un obstáculo.
jump("+32"); //Salta mientras avanza 32 píxeles. La siguiente acción no empieza hasta que el personaje caiga al piso.
dialog_hold("Dios mio, me estoy moviendo solo. Creo que estoy poseído por un script de cutscene.",false); //Muestra el diálogo en pantalla. El diálogo debe ser acabado por el usuario y la acción se pausa hasta que el diálogo acabe.
dialog_free("¡A correr!",true); //Muestra el díalogo en pantalla. El diálogo acaba solo y la acción en pantalla no se pausa.
move("-256",true); //Corre 128 píxeles a la derecha.
trigger("trigger de la cutscene",false); // desactiva el trigger
block_end(); //Termina el bloque

éstos comandos se ejecutarían de forma similar al actual sistema de diálogos, sólo que completamente diferente. no se cómo explicarlo, honestamente, pero tengo el código para hacerlo posible. debería darme las gracias por programar los actores en forma modular. lo normal es que los personajes en un juego estén programados con sus movimientos en "código duro", pero en catbox los actores tienen variables que les indican qué están haciendo, qué pueden hacer y el código determina qué sucede si éstas variables son verdaderas o falsas, entonces el código para mover al personaje no es "si la tecla está apreatada, mueve al personaje n pixeles en el eje x" si no "si la tecla está apretada, activa la variable caminar" y luego otro script dice "si la variable caminar está activada, mueve al personaje n pixeles en el eje x", entonces si quiero hacer un script para mover al personaje escribiendo comandos en pantalla, no hace falta que reescriba todo, si no que basta con reemplazar el primer script por algo que diga "si el comando dice caminar, activa la variable caminar", entonces el sistema para cutscenes no sería más que un agregado del script de todos los actores, para que, si el trigger de cutscenes está activo o la variable de cutscenes tiene otro valor que no sea 0 (todavía no decido eso), active el script que maneja a los personajes durante las cutscenes y desactive el que los maneja normalmente.

pero todo ésto es más fácil dicho que hecho.

rescate (de cosas)

estaba revisando mis archivos antiguos y encontré esto:


siendo bien honesto, no recuerdo haberlo hecho. aunque me gustan, a goph le sienta bien una cabeza separada del cuerpo. el gráfico de título, eso sí, es horrible. y no me gusta tar. los pájaros se ven bien de un solo color. chi no me gusta, tiene las orejas muy chicas. la idea del diseño original es que fuese mitad orejas mitad cuerpo.

y de nuevo, honestamente, no se si ésta entrada era para eso. la tenía en borrador sólo con el encabezado, y me acuerdo que una vez quise subir ésto pero no lo encontré, así que supuse que era hora de hacerlo de una buena vez. los borradores de éste blog son una cosa oscura.

tiendas (de nuevo)

en una implementación imperialmente flaite, las tiendas ya "funcionan". cuando digo que funcionan, me refiero a que ya escribí el código que recrea las tiendas de las iteraciones anteriores de catbox visualmente hablando, los scripts para hacer el llamado a una tienda durante un diálogo ya existen, los scripts para añadir items con sus precios (definidos por el usuario o por defecto) a una tienda en específico aún no existen pero hacerlos no es tan dificil, y todos los cuadros (excepto el que muestra los objetos actuales del inventario, pero eso ya lo implementé en el inventario como tal) muestran la información correctamente. falta hacer algunas cosas todavía (el menú para decidir los objetos que vas a comprar y cuántos objetos vas a comprar, o bien cancelar la compra, por ejemplo) pero, si bien no lo he programado, lógicamente no debiese ser taaaaaaaan dificil de hacer.

lo que más me gusta del asunto es que la tienda funciona a través de una variable global definida en el sistema nuevo de variables. ¿qué es el sistema nuevo de variables? veran: el sistema de variables de antaño funcionaba con, bueno, variables, entonces había ciertas cosas, como definir dentro de un diálogo el valor de una variable, que no se podían hacer de forma limpia. actualmente, en lugar de variables como tales, todas las operaciones que se hacen dentro del sistema de diálogos quedan almacenadas dentro de una estructura de datos, un mapa para ser más precisos, que guarda el nombre de la variable como llave y su valor, entonces la variable "shop" se puede manejar como cualquier otra variable, sin necesidad de crear código específico para llamarla en cierto momento, como lo hacía antes. para comodidad, igual tengo un script para llamar a la variable shop, pero lo estaba pensando e incluso ése script podría servir para insertar el recuadro de opción para comprar o no comprar, y hasta incluso los items que la tienda va a vender.

sin embargo, como todavía no implemento algunas cosas, todos los items que salen en la tienda de la screenshot son los primeros items de la lista de items del juego. uhhh, spoilers.

edit: me cago en dios, funciona. las tiendas (en su funcionalidad más básica) ya están funcionando. actualmente sólo me falta hacer el diálogo de compra (más que nada para poder decidir cuántos items comprar, o cancelar la compra) e implementar cómo lo voy a hacer para vender items. no debiese ser muy dificil, en realidad sólo hay que definir cómo lo voy a mostrar, si en un diálogo idéntico a la tienda, pero con tus items en la lista en lugar de los de la tienda, o si va a ser en un menú igual al del inventario. yo me inclino por la primera, pero uno nunca sabe.

una consecuencia lateral (pero esperada) de usar un mapa para guardar los valores de la tienda es que el motor ordena los items de menor a mayor automáticamente, entonces si ingreso el item 8, 2, 4, 5, 6 y 1, la tienda los va a mostrar como 1, 2, 4, 5, 6 y 8. no es malo, pero es lateral.

díalogos (de nuevo)

lo malo de catbox siempre han sido los diálogos. o sea, entre otras cosas, siempre han sido los diálogos. para hacer un juego como el que quiero, necesito que el motor tenga un sistema de diálogos completo. y cuando digo completo, me refiero a todo lo que uno pueda querer poner en un diálogo.

la primera iteración del motor de diálogos dejaba bastante qué desear. las líneas de texto (y sus "características", un concepto bastante absurdo) estaban almacenadas en arrays dentro de cada actor, y el objeto principal "leía" éstas líneas en orden. ¿problemas? muchos: cada nueva característica que quisiese añadir al sistema de diálogos iba acompañada de una nueva característica para las líneas, ergo había que actualizar todo el motor para hacer algo tan sencillo como, no se, ser capaz de cambiar el gráfico de la cara en una ventana de diálogo. ésto restringía el motor a héroes mudos. dudo que 2079 tenga un héroe que hable, pero honestamente no pretendo usar el motor únicamente para 2079, y eventualmente, si yo (o alguien) quisiese hacer un juego en que el protagonista hablase, tendría que modificar el código brutalmente.

la segunda iteración del motor de diálogos era un poco más aceptable: diálogos, cambio de valor en triggers y variables, sonidos, items, ejecución de código, caracteres de control, etc. ¿problemas? el sistema seguía siendo esencialmente el mismo, sólo que un tanto más flexible. ésta iteración del motor de texto se vino abajo cuando intenté implementar diálogos alternativos. así, tal cual estaba, cada actor sólo podía contar con un diálogo alternativo.

la tercera iteración del motor de diálogos ya era más aceptable. en realidad, y pese a ser una reescritura total, mantenía toda la funcionalidad de su forma anterior (exceptuando la llamada a una tienda, más que nada porque todavía no había un sistema de tiendas reescrito para llamar) sólo que ridículamente más flexible. la principal diferencia era la posibilidad de infinitos "bancos" de diálogo alternativo, gracias a que cada diálogo estaba almacenado por índices. éste sistema se vino abajo cuando intenté implementar algo tan esencial como respuestas múltiples.

ahora, en teoría un sistema de respuestas múltiples es algo sencillo. en teoría. llevarlo a la práctica es un poco más complejo de lo que parece.

la actual iteración del motor de texto, la cual acabo de dejar funcionando, aún no la implementa, pero es una reescritura mayor del motor. para comenzar, ya no es una lista de texto con propiedades, si no una suerte de "secuencia de comandos" que un script, haciendo de intérprete, ejecuta. en todas las iteraciones anteriores, cada línea tenía en sus propiedades cosas como el nombre a mostrar en la ventana de diálogo, el gráfico de la cara, cómo funcionaba la línea de texto, etc. esencialmente, todas las líneas eran líneas de texto, sólo que algunas funcionaban de formas levemente distintas. eso ya no es así. ahora cada línea de una secuencia de diálogos es una instrucción a ejecutar, completamente independiente de la anterior. ésta foram de ordenamiento me permitió hacer cosas bacanes, como deshacerme de los índices. o sea, no es que me haya deshecho de los índices, igual, cuando haga el juego, cada actor va a llamar a un script que va a estar almacenado bajo un índice numérico en un script, pero ahora, por ejemplo, dentro de la misma secuencia puedo hacer bloques condicionales y, por ejemplo, mostrar cierta parte del código sólo si cierto trigger lleva cierto valor.

Otra cosa que hice fue reimplementar los triggers. Me pareció mucho más sensato implementarlos como una estructura de datos que como un array. Antes el límite de los triggers era la cantidad de escenarios del juego X un número fijo. ahora el límite es la memoria ram disponible. otra cosa buena es que, en lugar de asignarles índices numéricos, ahora se les asignan llaves como strings de texto. por lo que en vez de 4,2 ser el abierto o cerrado de la primera puerta, ahora "primerapuerta" es el trigger correspondiente a ésa puerta.

en fin, diálogos. la otra cosa que me permite el motor nuevo es crear nuevas instancias de posibles comandos a ejecutar en un diálogo sin necesidad de crear nuevos scripts para implementarlo. en una de las iteraciones tenía ejecución de código, derechamente. no puedo negar que ésto es más práctico, pero también es mucho más engorroso y destinado a la perdición, pues las funciones que ocupaba ya estan obsoletas. ahora, con un solo script puedo hacer funcionar los 11 comandos actuales del sistema de diálogos. pretendo seguir ampliandolo. lo mejor de todo es que éste dinamismo me permite crear scripts de uso rápido de forma mucho más sencilla. un ejemplo: en una de las iteraciones anteriores usaba un script sin entrada de texto para la entrega de items, cosa que todas las entregas de items tenían el mismo texto "¡Has recibido !". actualmente el script de entrega de items tampoco tiene entrada de texto, pero si quiero, puedo hacer un script que contenga una secuencia con un mensaje estandar y la entrega de cierto item, e incluso, si no quiero ocupar ése script, puedo entregar directamente el item y decir otra cosa.

los planes a futuro para el sistema de diálogos es implementar el sistema de respuestas múltiples. se me ocurrió más o menos cómo se hace (una lista temporal donde se almacenan las opciones ingresadas desde un string, separadas por un caracter, y donde el índice de cada item de la lista representa un valor en una variable general, denominada "respuesta" o algo así, y dentro de la sencuencia de diálogo referir que si la variable tiene tal o cual valor, hacer tal o cual cosa), reimplementar caracteres y frases de control para ciertas cosas (nombres de héroes y actores en general, valor de variables y triggers, cuestiones de tiempo, cosas así) y, por qué no, un sistema de pseudoscripting para escribir los diálogos en código, sin tener que estar llamando a otros scripts, entonces un diálogo quedaría escrito algo así:

>Esto es una línea de diálogo
>Y esta es otra línea de diálogo
>¿Que les parecen éstas líneas de diálogo?
?Son muy buenas|Meh|Son horribles
/El hombre de las nieves
!0
>Me gusta que le gusten. Me alegro.
_
!1
>Meh.
_
!2
>Eres un vil y asqueroso ser. Ojalá mueras.
_
@"trigger"|true
%"trigger"|true
>Ésto sólo debería salir si el trigger "trigger" está activado.
>Dado que lo activamos sólo dos líneas atrás, es buena idea asumir que está activado.
>Además estás leyendo ésto
_
>Eso, chao.

éste tema del pseudoscripting es muy a largo plazo, y sólo lo implementaría después de terminado todo el motor. por lo demás, el resto de los planes a futuro para los diálogos son bastante aterrizados. probablemente tenga algo terminado para la próxima semana.

slacker

una idea para un sandbox en 2d: eres un joven cesante que vive en la casa de sus padres. a ellos no les gusta tu estilo de vida y deciden obligarte a conseguir un trabajo para hoy o si no estás fuera de la casa. desde ahí en adelante, tienes la completa libertad dentro de la ciudad para trabajar en lo que quieras, o sencillamente no trabajar y vivir en la calle. puedes trabajar en algo pequeño, puedes crear un imperio multinacional si eres lo suficientemente astuto y estas en el lugar y el momento correcto, puedes dedicarte a hacer trabajos sucios y acabar muerto o preso, etc.

lo dejo anotado acá para que no se me olvide.

algunas ideas:

  • lo único que tu personaje tiene designado por el programa son habilidades físicas, que se definen luego de que creas al personaje según el peso, tamaño, y una breve encuesta sobre ti mismo y tus hábitos. las habilidades de inteligencia se dan según cómo aproveches tu las oportunidades que te ofrece el juego. por ejemplo, al principio del juego hay un tablon de anuncios donde puedes encontrar datos rápidos de trabajos pequeños, pero también puedes ir y pasearte por la ciudad, toparte casualmente con un amigo que te invita a beber a un bar, en el bar encontrar a un gerente borracho con ganas de hablar, fanfarronear y comenzar un negocio grande pero riesgoso, o bien puedes ir y mendigar monedas en la calle. cualquiera de éstas habilidades estan disponibles desde el principio, pero depende de ti cómo las usas.
  • según el tipo de vida que lleves en el juego (cuánto caminas y cuánto usas transporte, cómo te alimentas, etc) tus estados cambias. en tu cumpleaños el juego te regala puntos para las habilidades físicas.
  • puedes hacer buenas o malas migas con cualquier persona en el juego. hacerse amigo de alguien significa expandir tu red de contactos, lo que de un modo u otro significa más alternativas de trabajo. enemistarse con alguien significa mala reputación, perder amigos en común (si es que los hay) y en general perder oportunidades de trabajo en la zona donde hiciste un escándalo durante un tiempo.
  • el único game over que hay en el juego sería morir, ya sea de hambre, suicidio o en un accidente. estos dos últimos casos son especiales: el suicidio sólo es una opción si llevas mucho tiempo como vago, sin una casa o si muchas cosas malas seguidas te han sucedido (llegar tarde a una entrevista, que tu novia/un amigo corte relaciones contigo) y realmente todo parece perdido. los accidentes serían casos en que algo inesperado sucede, como la caída de algo pesado desde un edificio o un atropello. si sobrevives a un accidente, puedes ir y exigir una compensación monetaria.
  • tus padres nunca saben en qué trabajas a menos que les digas, por lo que puedes ser un hampón o un traficante de drogas y vivir en la casa de tus padres, siempre y cuando traigas dinero.
  • debiese haber otro game over, cuando cierta cantidad de tiempo muy larga pase, o cuando logres ahorrar cierta cantidad de dinero, o logres comprar algo grande como una casa. más que nada para evitar llegar al año 5000 y que los autos voladores todavía no existan.

si algún día hago éste juego, me gustaría que fuese el sandbox más bizarro posible. nada de simulación de vida, más bien en una línea caricaturezca. me gustaría usar el estilo de arte de los monos de alvin y joe. eso. chao.

items

quizás una de las partes más restrictivas de la iteración anterior de catbox es que existían tipos de items. entonces ciertos ítems en lugar de funcionar diciendole al motor exactamente qué es lo que hacen, le pasan al motor un montón de variables y el tipo de ítem, lo que luego el motor interpreta. entonces SUMAR_VARIABLE hp hpmax 1 era interpretado como "a la variable hp se le suma 1 a menos que sobrepase hpmax". ahora, imagínense el problema para hacer items que afectasen a todo el grupo, o cualquier otra forma de ítem que no calzase con los tipos predeterminados.

para ésos tipos existía un tipo especial, que lo que hacía era llamar un script y ejecutarlo. no es nada tan terrible superficialmente, pero a nivel interno ocupaba algunas de las funciones más lentas de game maker.

con orgullo puedo decir que se acabó. tengo el sistema de ítems hecho por completo. o casi por completo. me faltan un par de detalles, como programar la posibilidad de que existan ítems que no pueden ser utilizados desde el inventario, y cosas así.

¡pero programé un jetpack y funciona!


por fin logré lo que en la iteración anterior de catbox nunca pude lograr: diálogos alternativos infinitos. lo que anteriormente sólo había hecho de forma parcial (un diálogo principal y un diálogo alternativo) ahora lo puedo hacer en múltiples niveles. ahora me falta implementar los tipos de líneas (para poder ejecutar código, lo cual haré a través de un script que liste el código que se puede ejecutar en los diálogos o algo así, activar interruptores y cosas así) y, sobre todo, implementar los interruptores. por ahora voy a trabajar en otras cosas mejor.

reescribiendo catbox


decidí que lo que le hacía falta a catbox era una reescritura, así que en eso estoy.

cosas buenas suceden y me da lata explicarlas. chao.

¿mencioné en alguna ocasión cómo se hacía llamar el tipo a quien no di créditos en z hell por enviarme música de seiken densetsu haciéndola pasar por propia?

Dual Z se hacía llamar el desgraciado.

z hell - what the hell was i thinking pt. II - IA

acá la parte anterior

sí se que dije que iba a hablar de las armas, pero primero el tema de la IA. de las armas hablo después, porque no es una comparativa si no más bien un descargo.

para hablar de lo mal programada que está la primera iteración de zoldier, en ése entonces llamada z hell, debo hablar de la IA.

la IA, o inteligencia artificial, se refiere al modo en que un objeto interactua por sí mismo con su entorno. programar una IA realmente inteligente no es fácil, y generalmente los juegos -o por lo menos los de antaño y los amateur- se quedan en un comportamiento que puede ser mejor referido como patron de acción, pues no hay mucha inteligencia en la forma que ésta funciona.

de más está decir que ésto último no es más que una visión personal del tema. yo no tengo idea dónde empieza y dónde termina la inteligencia artificial. pero puedo decir que lo que yo usaba como inteligencia artificial en z hell era horrible. he visto juegos peores con algo mejor hecho. en serio.

la inteligencia artificial de z hell consistía en avanzar hasta estar a cierta distancia del personaje principal y empezar a atacarlo. ¿paredes? ¿distancia a la que está el personaje para activarse? ¿forma de perder a un enemigo para que te deje de seguir? olvidenlo. los hijos de puta venían desde el otro extremo de la habitación a dispararte si no hubiese un muro que se los impidiese.


ésta imágen muestra mejor de lo que yo puedo explicar con palabras el comportamiento de un enemigo en z hell. los enemigos estáticos eran básicamente lo mismo, sólo que en vez de moverse esperaban a que tu estuvieses a cierta distancia. de más está decir que siempre te estaban apuntando.

ahora, zoldier. de antemano aclaro que ésta es una IA que sólo es para los enemigos básicos que patrullan. la IA por defecto. eventualmente quiero hacer IAs para enemigos más complejos. no tanto, porque no es un juego en 3D, la idea es tirarse a matar, no quiero perder el espíritu doom del juego original tampoco.


cuando el enemigo no te ha visto se dedica a pasear por el mapa. los giros que hace nunca son muy bruscos. si llega a un punto en el que no puede seguir avanzando, comienza a ponderar hacia dónde tiene libre para caminar y sigue caminando.


una vez que el enemigo te ha visto (para lo cual tienes que estar frente a él o muy cerca de él) te apunta y camina hasta estar a una distancia prudente para comenzar a atacar. si te mueves y sigues en su campo de visión, te sigue a ti.


si saliste de su campo de visión (te alejaste mucho o un muro se interpuso entre ambos) camina hasta la última posición en la que te vió. si en el nuevo punto estás en su campo de visión, vuelve a la rutina anterior, de otro modo vuelve a la rutina inicial

es una IA bastante básica, pero hace que el juego no sea sencillamente ir esquivando bestias que vienen a atacarte, si no que te da también la oportunidad de pasar desapercibido. aún hay cosas que debo implementar (alertar a otros enemigos cercanos, que identifiquen el lugar del que se disparó una bala que no estaba en su campo de visión) pero la IA es más que competente. me enorgullece acotar que lo implementé en tres scripts, por lo que trabajar con éste código es muy sencillo.

lo siguiente será hablar de los gráficos. eso, chao.

z hell - what the hell was i thinking

uno siempre es jóven e inexperto. probablemente en 9 años más me ría de cosas que haya hecho hace 9 años y diga "dios santo, en qué estaba pensando". hoy es el turno de mi yo presente de burlarse de mi yo pasado.

en ésta caso, mi yo pasado quizo rendir una suerte de homenaje a doom haciendo un fps. dada su inexperticia con game maker, la herramienta que estaba aprendiendo a ocupar en ése entonces con sus jóvenes e inexpertos 13 años de edad, se las arregló para terminar un juego de 16 niveles de disparos en tercera persona, o léase de otro modo, wolfenstein 3d pero sin ser cool. y ya pasado el año 2000. el juego en cuestión se llamaba z hell e incluso lo envié a un concurso de uan comunidad de game maker donde alcanzó a quedar semifinalista si mal no recuerdo.

el juego en cuestión tenía muchos avances con respecto a otros juegos del mismo género que había visto en game maker: un sistema para cambiar las armas (créanlo o no, parece que nadie había hecho uno en game maker antes), y, eh, bueno, cosas. nada muy espectacular pero era mi primer juego en serio y yo estaba orgulloso de haber hecho un juego donde se podía cambiar las armas como en doom.

el tiempo pasó y entre cambios de equipo de trabajo creí haber perdido para siempre el juego en cuestión, quedado sólo en mi poder versiones preeliminares con 4 niveles, alphas, betas, y el aborto de un tipo al cual inocentemente le mandé la fuente de una alpha y el muy conchesumadre lo utilizó como base y me dio créditos mínimos. una lástima, creé un amor idílico hacia el juego y un día decidí empezar a hacerle un remake como la gente. en eso estaba hasta que apareció el juego original. "¡muy bien!" pensé "así podré utilizar versiones de los mapas y no tendré que inventar nada. maravilloso".

cuál sería mi sorpresa al comenzar a revisar las fuentes del juego. quizás he ahí mi homenaje al horror de doom: mi juego era caótico. no me extraña que me haya costado tanto completarlo, con lo desordenado que estaba.

para muestra, un botón: para asuntos de ésta review (que iré haciendo por partes) tuve que meterle mano al juego original, pues quería sacar screenshots recortadas con una sola tecla. cuando abrí la fuente del juego para hacerlo, me encontré con esto:


¿no lo entienden? miren una screenshot de cómo se ve la carpeta de sprites del remake:


es el equivalente a guardar las cosas en carpetas frente a dejar todo en el escritorio. todo el puto juego está ordenado así. eso, entre otras cosas, hacen del juego un desastre. otro ejemplo: para hacer mensajes de interludio entre nivel y nivel ocupé rooms y objetos distintos. pudiendo hacer una room donde un solo objeto recibia los datos, yo copié 16 veces la misma room y el mismo objeto y les cambié los datos.

en fin, vayamos a la primera y única comparativa de ésta vez, porque tengo sueño y quiero dormir.

pero antes, acotar algo: mi otra inspiración es half-life/counterstrike. ¿saben dónde se nota? en la pantalla de título:



¿notan el parecido?

nota aparte. el z2 no es tan gratuito como parece, yo realmente ofrecía un código fuente para hacer juegos en base a lo hecho en z hell. solo una persona lo ocupó y fue sin mi autorización. bleh.

en fin, ahora sí. comaprativa entre el original y el remake, para que vean qué está mal y qué está no tan mal.

esto es lo primero que ves cuando empiezas a jugar z hell:


voy a intentar hacer un sumario de todos los problemas que veo en la screenshot: hay una barra de dios sabe qué tapando lo que parece ser un personaje, pero que en realidad es el personaje que controlas pero que por falta de intuitividad pues el encuadre de la pantalla no lo dice ni lo anuncia de ningún modo no te enteras hasta que te das cuenta que hay un tipo disparandote en la puta cara apenas empieza el juego y que cada disparo te quita un poco de vida y te hace sangrar irremediablemente antes de que alguien te haya dicho algo sobre los controles, los cuales, muy poco intuitivamente nuevamente, no te hacen moverte si no girar, avanzar y retroceder, similar a manejar un auto o al personaje de los GTA antiguos. ah y encima de eso la pantalla está repleta de información inútil.

ahora, vamos a ver el remake:


no hay problemas con el HUD tapando el área de juego, la información justa y necesaria, tiempo para acostumbrarse a los controles y, sobre todo, ningún enemigo disparando de entrada. ¿no se ve, además, mucho más agradable a la vista?

eso por ahora. la próxima vez voy a tocar un poco el tema de las armas, eventualmente hablaré de la inteligencia artificial y quizás si no me da mucha verguenza les muestro algunas cosas terribles del juego viejo, como los jefes y esas cosas.

revisitar z hell

hoy en la madrugada estuve revisitando z hell. si me da el cuero más tarde hago un pseudoreview con comparativas y esquemas y cosas raras para mostrar los cambios de diseño que le he hecho al motor nuevo y burlarme de mi yo con 13 años y sus decisiones extrañas al hacer un juego.

todavía me parece chistoso que yo haya pretendido ganar un concurso con ése juego.

el motor satánico (o el bug más raro que me ha tocado debuggear)

sí, hace un tiempo que no estoy trabajando en catbox. así soy yo, de repente avanzo mucho y luego dejo de avanzar hasta la siguiente vez en que avanzo mucho.

pero eso no significa que no esté haciendo nada. hace un tiempo terminé el motor del remake de rescate. arreglé TODOS los problemas del motor anterior, y también implementé cosas nuevas. quizás la que más me gusta es un script que dibuja esos números delgados y altos para marcar puntajes. no tengo idea cómo se llaman, pero antes usaba sprites estáticos y ahora puedo hacer cualquier puntaje :D. no implementé el arma nueva al final, y preferí quedarme con una modificada de la original, bastante más controlable, por cierto. es como un punto medio entre ambas. los tilesets nuevos se ven espectaculares y en general todo funciona mucho mejor.

sin embargo, algo extraño sucedió hace unos días: estaba debuggeando las plataformas móviles y de la nada el juego saltó del nivel 1 al nivel 7 y el puntaje quedó en 666. es la cosa más rara que me ha pasado, pues yo no he programado nada para hacer algo así. si cada enemigo de 250 puntos y si cada segundo da un punto y el primer nivel da 180 puntos, tendría que haber golpeado a dos enemigos y haberme demorado 14 segundos en pasar el primer nivel, pero eso sigue sin explicar el salto del nivel 1 al 7.

no he podido recrear el bug nunca más.