jueves, 29 de enero de 2026

Flappy Adventure 3 - Nuevo juego para PS1

 Descarga ISO Aquí

Era un secreto a voces: Flappy Adventure 3, la entrega que pondría fin a la saga "Flappy Adventure" estaba en desarrollo, no para version web como planeaba originalmente, sino para PS1 igual que su predecesor Flappy Adventure X, al ser una plataforma para la cual apenas hay homebrew en la actualidad. De hecho fue a finales de Octubre de 2024 cuando me puse a experimentar en la creación de un motor 3D decente para PS1, puesto que no existía ninguno de software libre y esto frenaba mucho la creación de homebrew para PS1 (El de Flappy Adventure X era muy simple) y fue poco después en Noviembre, cuando viendo que el motor funcionaba e iba bien, decidí empezar la idea de crear una pequeña demo de como podría verse mi proyecto abandonado de "Flappy Adventure 3" en la PS1 con ese motor. Sería en 3ª persona, tal y como siempre había planeado, no sería "cel shading" pero si tendría una apariencia con colores vivos y poquitas texturas dándole un aspecto caricaturesco.

¡Y así empezó todo! Aunque el proyecto fue abandonado en varias ocasiones por pura dejadez, estando parado casi un año entero, finalmente "Flappy Adventure 3" vio la luz, con muchos recortes frente a la idea original, eso sí, puesto que el desarrollo se estaba alargando mucho para las no más de 10 personas que planeo podrían llegar a probar el juego.

⚫ La pantalla original de selección de niveles iba a ser el nivel 0 del juego basado en Minecraft, con portales que tele-transportarían al resto de niveles como en Flappy Adventure X, aunque descarté la idea por ser muy repetitiva (ya se hizo en FADVX) y demasiado lento para acceder al nivel concreto que quisiéramos. Al final terminó siendo un nivel más (nivel bonus)

⚫ Se descartó totalmente la funcionalidad de la Memory-Card puesto que uno de los mayores problemas que tuvo FADVX fue que debido a su alta dificultad, la mayoría de jugadores no alcanzaban a ver más que el primer nivel. Todos los niveles están desbloqueados desde el primer momento.

⚫ El nivel de la feria de Albacete iba a tener una noria gigante girando (es una idea que tenía en mente desde hace muchos años). No obstante, no supe ver como hacerla encajar con el nivel, y lo más que podía hacer es que nos ayudase a subir a cierta altura, aunque eso forzaría a añadir plataformas en el aire que no encajaban con el resto de nivel basado en el recinto ferial real en tierra.

⚫ La batalla final con Duolingo fue descartada totalmente por todo el tiempo que llevaría implementarla. En ella Duolingo se enfrentaría a Flappy con la escusa de: -"Flappy, ¿Cuanto tiempo llevas sin repasar tu nivel de esloveno?" A lo que Flappy contestaría que quien c**o es él y que para que iba a querer él aprender esloveno, enfadando a Duolingo e iniciándose así la batalla. Algunos de los samples de Duolingo al ser atacado por Flappy serían cosas inesperadas como: -"¡Auch!... que en japones se dice: (sonido de orgasmo)"
⚫ También contaría con una animación inicial al iniciar el juego mostrando a Flappy y su chica hablando en una cueva sobre su futuro con lluvia de fondo usando el motor del juego. En su lugar hice un video de repaso de todos los Flappy Adventures, que fue una idea de última hora y que me pareció una idea muy acertada para toda la gente que me preguntaba por: "¿Y donde están el Flappy Adventure 1 y 2?". Hacer la animación con el motor me habría llevado mucho tiempo para la poca gente que realmente le prestaría atención.
⚫ El juego planeaba tener más objetos dinámicos, pero con solo 5 niveles y un objetivo tan simple para completar los niveles (recoger las 30 monedas y llevarlas con la chica) me pareció innecesario.


Aun así, con todos los recortes, estoy bastante contento con el resultado del juego, que espero que con suerte lleguen a probar unas 10-20 personas, y es que no debemos olvidar que "Flappy Adventure X" fue un autentico fracaso en su recepción. Aunque fuese una obra maestra, al final si no tienes alcance, de nada sirve! Y como ya sabéis, no tengo ni los medios, ni la popularidad en redes sociales ni para que incluso los más fans de PS1 sepan siquiera de la existencia del proyecto. En este punto en 2026 solo hay 3 grandes proyectos para PS1 terminados o en desarrollo. El primero, Flappy Adventure 3 (obvio), el segundo, un port de Super Mario 64 para PS1, y por último un juego aun sin titulo desarrollado por Elias Daler (quien también hizo un minijuego para PS1 bastante bueno llamado Yume Nikki).
A día de hoy actualmente, hay miles y miles de personas siguiendo de cerca estos dos últimos. Una lastima que Flappy Adventure 3 jamas tendrá ni la milésima parte de ese seguimiento ni de cerca, quedando olvidado para siempre en la deep-web

miércoles, 20 de agosto de 2025

Lenguaje LOGO, el "Scratch" de los 80s y 90s

Hoy día para enseñar programación por primera vez a niños (y no tan niños) es habitual usar Scratch, haciendo de la programación algo más visual 
Pero... ¿Que alternativas había antiguamente en los 80s y 90s antes de Scratch? Pues había un lenguaje muy popular, creado en 1967 llamado LOGO, en cual aun siendo de texto, tenía comandos muy simples y la salida era bastante visual al igual que Scratch. En este caso se trataba de hacer dibujos moviendo un puntero representado por una tortuga, de ahí que también se le conociera como "El lenguaje de la tortuga".
Pues queriendo recordar este lenguaje, no solo hice una adaptación al lenguaje C de la tortuga hace unos años, sino que también recientemente encontré una versión online de LOGO bastante buena y que os recomiendo: Turtle Academy.
Pues bien, aunque el lenguaje LOGO es bastante limitado al ser ser de finalidad didáctica, con el único objetivo de hacer dibujos sencillos, usando esta web decidí poner la tortuga al límite, y hacer los programas más bizarros, aquí os los muestro, tenéis los links a los programas haciendo clic en los títulos:

3D game engine voxel space

Os resultará bastante familiar. Sí, se trata de la misma demo que hice anteriormente para la GameBoy Advance, aunque en esta ocasión bastante limitada por la velocidad del interprete LOGO. Aun así el simple hecho de generar pseudo-3D con la tortuga de LOGO es una verdadera locura

Bad Apple!!

Si generar pseudo-3D en LOGO no fue ya suficiente, en esa ocasión genero el FMV completo de "Bad Apple!!" en tiempo real. Los frames están almacenados como un array de números con un número para cada scanline en el que cada número representa los bits de cada pixel (blanco/negro). En esta ocasión y para contrarrestar la lentitud de la tortuga de LOGO para pintar los frames, pongo la tortuga en modo "window" (cuando alcanza un limite, por ejemplo abajo sale por el opuesto, en este caso arriba) le seteo un angulo muy pequeño y lo hago avanzar únicamente en linea recta durante toda la ejecución del programa. De esta forma, la tortuga dibuja las scanlines automáticamente con entrelazado, y lo único que tengo que hacer es cambiar el color conforme avanza recto. ¡Ingenioso y efectivo!

QR text input generator

Aunque los QRs parezcan sencillos, la generación de los datos y la corrección de errores llevan algoritmos complejos. Realmente fue bastante difícil crear este programa con todas las limitaciones de LOGO, pero finalmente lo hice.

3D Raytracing Sphere

¿Raytracing de primitivas 3D en LOGO? jajaj ¿es un chiste? ...Ah ...pues no, no lo es. No hay ningún truco, es raytracing de verdad. Va bastante lento como podeis imaginar, pero claro, hay que recordar lo absurdo que es ejecutar algo así en LOGO.


Interactive maze game

Decompilando el motor LOGO de Turtle Academy descubrí que habían funciones indocumentadas (y rotas, todo hay que decirlo) que permitían obtener la posición del ratón, y los botones del ratón. Que mejor manera de aprovecharlo que haciendo un juego de laberinto interactivo usando un algoritmo de detección de colisiones 2D. Muy probablemente el primer juego interactivo hecho en toda la historia de LOGO.


¿Vulnerar el sandbox de ejecución de LOGO y ejecutar código JavaScript a través de instrucciones LOGO en Turtle Academy? ¡No, eso ya no hay quien se lo crea! Espera... ¿Eso es un canvas? ¿De donde viene esa música? Podría robar cookies, hacer peticiones XHR para darme autolikes a mis programas,... Pero como mi epoca jaker ya terminó, en lugar de eso os dejo con esta demo re-shula
Y por aquí lo dejamos... Tenéis más programas en mi perfil de Turtle Academy.

martes, 10 de septiembre de 2024

Creamos el mejor "Crack No CD" para un juego retro (Tarzán)

 Descarga Tarzan PC Portable aquí.

Aunque el tema del crackeo es un tema delicado, si que es verdad que hay veces donde puede estar medio justificado en abandonware y PCs que ya no disponen de lector de CD. El problema es que estos cracks no siempre son del todo fiables (algunos incluso pueden llevar algún regalito), y los creadores de estos cracks nunca revelan detalles de como lo hicieron, permaneciendo ademas en el anonimato mediante un pseudonimo.

Pues por primera vez, y con motivos didácticos, vamos a crear nuestro propio crack de código abierto para un juego abandonware: Tarzán de Disney Interactive.

Pues bien, este juego aunque copia todos los archivos del juego al disco duro al instalarlo, requiere tener el CD insertado para poder jugar. Si abres el juego sin el CD aparece la siguiente pantalla y no permite jugar

Pues tras un breve análisis, detectamos que existe un flag en memoria en 0x837A24 que indica cuando el juego original esta insertado, y buscando la rutina que setea este flag encontramos lo siguiente
En el primer call el juego comprueba que hay un CD insertado y que contiene determinados archivos, haciendo luego comprobaciones adicionales en el segundo call. Pues bien, nosotros queremos setear siempre ese flag sin hacer todas estas comprobaciones, así que reemplazaremos todas las instrucciones hasta el mov del final por nop.
"TARZAN.EXE"+A39C9: //CD Check db 90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90
Y tampoco nos olvidemos de dejar nuestra firma ;) reemplazaremos el mensaje de CPU con MMX ya que en 2024 no es que nos aporte mucha información
"TARZAN.EXE"+1050E0: //Crack NOCD signature db 'CRACK NOCD JUANMV94',0 "TARZAN.EXE"+8FF33: db 90,90,90,90,90,90,90,90,90
Y... voilà. ¡Crackeo completo! Ya podemos jugar sin CD

FIN


Pero... Esperad un minuto... ¡El juego no tiene música! Resulta que el juego es un CD mixto y la música se encuentra en los distintos tracks del CD.
Y aquí es donde sacamos el armamento pesado, y procedemos a hacer una locura que a ningún cracker se le ocurriría hacer...
Vamos a reescribir las rutinas del juego que leen las pistas del CD, para que lean ficheros MP3 en su lugar ¡y todo ello en puro ensamblador!
Esto lo hacemos usando la librería WinMM que ya usaba el juego, concrétamente usando comandos MCI.
Pues bien, tenemos que localizar las funciones del juego de "reproducir el track XX", "parar CD",... y reescribirlas, aparte de almacenar un handle al archivo MP3 que se este reproduciendo en algún sitio. Nos quedamos con lo siguiente:
define(MUSHANDLE,1051C8) "TARZAN.EXE"+89020: //Stop track push 00 push 00 push 0804 //MCI_CLOSE push ["TARZAN.EXE"+MUSHANDLE] call dword ptr ["TARZAN.EXE"+AF234] //WINMM.mciSendCommandA mov ["TARZAN.EXE"+MUSHANDLE],00000000 ret "TARZAN.EXE"+88FB0: //Disable music call "TARZAN.EXE"+89020 //Stop track ret "TARZAN.EXE"+89070: //Request track mov eax,[esp+04] push 00 push eax call "TARZAN.EXE"+89170 //Play track add esp,08 ret "TARZAN.EXE"+89170: //Play track mov eax,["TARZAN.EXE"+12A5C4] test eax,eax //Music enabled? je RETPLAY sub esp,0C //Alloc 12 bytes for file name push [esp+10] //Track no push FILENAME //File name template with %02d lea eax,[esp+08] push eax call "TARZAN.EXE"+A4190 //sprintf call "TARZAN.EXE"+89020 //Stop track //push MCI_OPEN_PARMS to stack push 00 //LPCTSTR lpstrAlias; lea eax,[esp+10] push eax push MPEGVIDEO //LPCTSTR lpstrDeviceType; push 00 //MCIDEVICEID wDeviceID; push 00 //DWORD_PTR dwCallback; push esp //MCI_OPEN_PARMS push 2200 //MCI_OPEN_ELEMENT | MCI_OPEN_TYPE push 0803 //MCI_OPEN push 00 call dword ptr ["TARZAN.EXE"+AF234] //WINMM.mciSendCommandA mov eax,[esp+4] //store handle mov ["TARZAN.EXE"+MUSHANDLE],eax push MCI_PLAY_PARMS push 00010000 //MCI_DGV_PLAY_REPEAT push 0806 //MCI_PLAY push [esp+10] call dword ptr ["TARZAN.EXE"+AF234] //WINMM.mciSendCommandA add esp,2C RETPLAY: ret MCI_PLAY_PARMS: dd 0 //DWORD_PTR dwCallback; dd 0 //DWORD dwFrom; dd 0 //DWORD dwTo; MPEGVIDEO: db 'mpegvideo',0 FILENAME: db 'MUS/%02d.MP3',0
* Os habréis fijado que hay una función que solicita reproducir un track, y otra que procede a reproducirlo. Esta primera función realizaba varios checks del CD que no nos interesan, así que la re-implementamos de forma que únicamente re-ordenará los parámetros y llamará a la segunda función sin realizar ningún check.
* La función que silencia el audio del CD al des-habilitar la música en el menú de opciones la simplificaremos a simplemente parar la reproducción. No es el mismo comportamiento exacto, pero nos vale.
* La función que reproduce el track comprobará que la música este habilitada en el menú de opciones, y convertirá ese numero de track en un path a un archivo MP3 con sprintf, de forma que el track 2 sea por ejemplo "MUS/02.MP3", lo cargará y lo empezará a reproducir de inmediato en modo repetición, habiendo parado previamente la reproducción previa en caso de existir.

¡Y ahora sí! Extraemos los tracks del CD a MP3 y ya podemos jugar a nuestro juego con la música del CD original en un PC sin unidad de disco.

Hacedme saber si queréis más contenido como este en los comentarios

jueves, 8 de febrero de 2024

¿Se pueden predecir los números aleatorios de un videojuego?

Aunque la mayoria de veces esto es muy complicado, o prácticamente imposible, existen ciertas implementaciones de los PRNG en las que puede resultar bastante sencillo predecir estos números.
En esta ocasión me centro en un par de juegos J2ME elegidos al azar, uno de parchís y otro de ruleta, y me dispongo a predecir los números que generará el juego

domingo, 19 de noviembre de 2023

Generador de códigos de amigo para Torre Miau (Meow Tower)

 
 
Recientemente me descargué un juego de nonogramas para el móvil llamado Meow Tower
En este juego en concreto concreto vas subiendo de nivel, desbloqueando "gatos", aspectos, y temas. Pero existen varios de esos desbloqueables que la única manera de conseguirlos es mediante códigos de amigo. 5 en total.

Pero... ¿Y si no tienes amigos? :( Nah, fuera coñas, tú no vas a molestar a nadie pidiendo que se instale el jueguecito para que te de su p*** código. Ademas para evitar que la gente comparta los códigos de amigo en grupos de Facebook o Reddit estos códigos una vez se generan caducan a los 15 minutos.
Pues bien, hay un dicho popular que se remonta a hace miles de años que dice que quien es hacker, ya lo es para toda la vida, así que ahí tenéis hermosos, un generador de códigos de amigo para que no tengáis que molestar a nadie más :')

viernes, 1 de septiembre de 2023

Frikada del mes: Crackeando un juego J2ME de mi infancia

Hace muchismos años, estamos hablando de cuando los teléfonos móviles aun no tenían pantalla táctil, las marcas de moda eran Nokia y Sony Ericsson, y los juegos que se descargaban en formato .JAR no te pedían microtransacciones, hubo uno en especial que me llamó bastante la atención. Se trataba de un juego de golf que era capaz de generar 3D incluso en los teléfonos más sencillos llamado Par 3 Golf.

No os imagináis la de veces que completé el primer nivel, y digo esto porque el juego te pedía que comprases una clave si querías jugar al resto de niveles. Esta clave es vinculada a un PIN que cambiaba si re-instalabas el juego y no era precisamente baratica la p** clave.
Pues bien, eso fue mucho antes de que me convirtiese en un friki, así que ahora llegó el momento de crackear finalmente el juego después de tantos años. Para ello tan solo necesitamos un decompilador de Java. Empecemos por ver de donde viene el valor del PIN:
Antes de que os asustéis debo deciros que el código decompilado aparte de no incluir nombres de variables/funciones, las pocas que sí tienen están ofuscadas usando términos del lenguaje Java aleatorias como append, insert, equals, parseInt... que sus nombres no tienen ninguna relación con lo que hacen realmente. Esto esta hecho con la única intención de confundir a los hackers de ingeniería inversa como yo. Buena jugada, ResetGame. 
Os hago un resumen, la función D checkea mediante la función AI.I si hay datos guardados del juego (lo cual incluye el PIN) y si no existen porque es la primera vez que se abre el juego, setea el PIN (que está en la dirección de almacenamiento 6) a los últimos 16 bits bits del timestamp en ese momento. Lo cual viene siendo... aleatoriedad total.
Pero... un momento... 16 bits significa que tenemos numeros del 0-65535 pero el PIN tiene 6 digitos. WTF??
Miremos el codigo que imprime el PIN:
El PIN se obtiene con la funcion de "Obtener valor de memoria" this.C para la dirección 6. Pues al resultado que se obtuvo de (timestamp & 0xFFFF) se le va a hacer padding con 0s hasta tener 5 cifras, por ejemplo, si el valor es 999 quedará 00999. Y finalmente el primer dígito será la suma de estos 5 digitos modulo 10. En este caso 0+0+9+9+9=27 por lo que nos quedamos con el 7 y el PIN mostrado sería 700999.
Lo mismo aplica con mi PIN del primer screenshot: 1+7+4+6+6=24, por lo que el primer digito del PIN será... sorpresa.
Pero vayamos a lo importante... ¿Como podemos generar una clave a partir del PIN? Vayamos a la funcion que procesa el valor introducido...
Lo primero que hace es borrar el primer dígito que introducimos... Interesante, el primer dígito de la clave no se tiene en cuenta. Después guarda en la posición 8 del almacenamiento el valor del PIN introducido, sea correcto o no.
Pues bien, resulta que hay una función que se llama en varias partes del juego que comprueba si la última clave introducida coincide con el PIN denominada "length" que a su vez aplica una función matemática que han llamado "parseInt" al PIN y este resultado debe coincidir con la clave introducida.
¡Ya esta! Si no os han sangrados los ojos viendo los nombres ofuscados de las funciones, os daréis cuenta de que la clave a introducir debe ser el resultado de (PIN<<5 & 0xFFFF) | (PIN >> 11 & 0x1F) con un digito cualquiera 0-9 delante de ese resultado. Os dejo Un calculador de claves que podeis usar desde el navegador:
Introduzca PIN:
Más tarde apareció... Par 72 Golf, que si me preguntáis la diferencia con el 3 la verdad no lo se ya que el juego es prácticamente idéntico aunque con más niveles. En este caso se puede decir que directamente no existía PIN, ya que siempre mostraba el mismo (RESETgame). Veamos lo que hace en esta ocasión:


Pues vemos que en esta ocasión el valor que se almacena del timestamp no son los 16 bits menos significativos, sino que es el número de día (1000*60*60*24). Ademas es muy curioso, ya que parece que la clave a introducir sería ese número de día de la instalación con un margen de 15 días a partir de los cuales la clave que te entregan dejaría de ser valida. Aparte de eso, también existe una clave "55205" que siempre funcionaría e imagino que únicamente se entregaría en caso de "emergencia" cuando alguien se quejase de que la clave basada en días que le entregaron no funcionaba. Pero... tenemos un problema. Por alguna razón le dieron fecha de caducidad a las keys basadas en el día actual. Con la operación & 0x3FFF impiden que se puedan introducir fechas posteriores a Noviembre de 2014, así que a día de hoy la unica forma de desbloquear el juego es con la clave "55205".

En fin, si de verdad has llegado hasta aquí, que sepas que eres 1 entre un millón. ¡Enhorabuena!