Lo primero, un saludo a todo el foro. Éste es mi primer mensaje y mi primera aportación al RH, espero que os sirva de ayuda.
El caso, que llevo tiempo buscando la forma de añadir Pokémon errantes al Esmeralda (en español, es la ROM que utilizo). He buscado en este foro y en foro de PokemonCommunity, y no he conseguido encontrar nada. Así que empecé a investigar la forma en que aparecían Latios y Latias en el juego. A continuación dejo los pasos que he seguido durante mi investigación, por si a alguien le interesa o le pueda servir de ayuda. Si sólo quieres saber cómo se meten pokémon errantes, sáltate este paso.
Hacer que aparezca un pokémon errante es tan simple como ejecutar un script. En Esmeralda el special 0x12B hace que aparezca un pokémon errante u otro dependiendo del valor que hay en la variable 0x8004: si es 0, aparece Latias, y si es 1 aparece Latios. En FR se usa el special 0x129 y la variable de entrada que utiliza es la 0x4031, que es donde se guarda el pokémon inicial que escogiste, y hace que aparezca Raikou, Entei o Suicune. Lo que vamos a hacer es llamar al special, hacer que aparezca uno de éstos pokemon como errante y sustituirlo por el pokemon que queramos.
Los datos del pokémon errante se guardan en variables, así que conociendo estas variables podemos editar al pokémon errante como queramos. Concretamente, las variables son éstas:
- Variable del pokémon: Esmeralda 0x4F24; RF 0x506C
- Variable de la vitalidad: Esmeralda 0x4F25; RF 0x506D
- Variable del nivel y estado: Esmeralda 0x4F26; RF 0x506E
- Variable de la disponibilidad (0x100 = disponible, 0x0 = no disponible) = Esmeralda 0x5F29; FR 0x5071
Ahora explicaré qué significa cada variable y los pasos a seguir en Esmeralda, para Fire Red los pasos a seguir son idénticos. El script del pokémon es el siguiente:
Voy a explicar para qué sirve cada variable:
La primera indica el pokémon que nos aparecerá por la región. Por poner un ejemplo, yo quiero que me aparezca Raikou, cuyo número es F3, pues en mi caso pondré setvar 0x4F24 0xF3.
La segunda determina la vida con la que nos encontramos al pokémon. Esto es muy importante, porque un valor muy alto provocaría que, al herir al pokémon, durante un tiempo su vida no decrezca (dependiendo de lo mucho que te hayas pasado de su vida máxima), y con un valor bajo te encontraías al pokémon con escasa vida. Para elegir un valor adecuado, podéis usar la siguiente calculadora Pokéxperto; Calculadora DS/Advance de IV's & Stats
Eliges el pokémon, su nivel, y a la derecha donde dice Resultados, en PS escribes 31, y pulsa "calcular stats"
A mí me ha salido a la izquierda, en PS, 165. Pues paso este valor a hexadecimal (165 = A5 en HEX) y ya está. Lo que tengo que poner es setvar 0x4F25 0xA5.
La tercera variable es complicada. En una misma variable se guarda el nivel y el estado (envenenamiento, parálisis...). El nivel es simple: escoge un nivel de 1 a 100 y lo pasas a hexadecimal. En mi caso quiero que salga al 50, que en HEX es 32, luego YY = 32. El estado es algo difícil; si no te interesa modificar el estado, ignora el siguiente spoiler y haz XX = 00.
La variable 0x4F29 indica si el pokémon está disponible (0x100 salvaje y vivo) o no (0x0 debilitado o capturado). Cuando llamas al "special" este valor es automáticamente 0x100, así que en principio no hace falta tocarlo. Lo que sí puede servir es para saber si ya hemos capturado o debilitado al pokémon (para interactuar con la historia de nuestro hack o cosas así).
A modo de ejemplo, mi script queda de la siguiente forma:
Ejecutamos el script y...
...
Vaya, parece que no ha pasado nada. Sin embargo, yo me he adelantado y antes programé un wildbattle contra Raikou para que me apareciera en la Pokédex. El resultado es el siguiente...
¡¡Funciona!!
Bueno, si y no. Todavía queda investigar las zonas donde aparece, y poder hacer que aparezca más de un pokémon errante a la vez. Pero... yo diría que es un buen comienzo, ¿no te parece?
Aquí dejo algunos ejemplos más, donde se ve que tampoco hace falta poner siempre la vida máxima al pokémon:
Para esta parte recomiendo que tengáis experiencia manejando editores hexadecimales. Cuando ejecutes el script de antes, el pokémon errante aparecerá por unos mapas específicos que están predefinidos en la ROM. Concretamente hay una tabla que indica las rutas por donde se mueve el poke:
Cada fila de la tabla tiene la siguiente información:
Además, nos encontramos con tres limitaciones:
Ya estamos en condiciones de editar la localización. Para editar esta tabla hará falta un editor hexadecimal, yo utilizo HxD. Primero debes tener una idea de las zonas donde se moverá el poke. Yo haré que el poke se mueva por este mapa (cortesía de Dani_SR_17):
-Pueblo Paleta - Ruta 1 - Ciudad Verde - Ruta 2
____ __ _ _ __- Ruta 3 -
Abre Advance Map y apunta el nº de cada mapa, y conviértelos a hexadecimal con la calculadora de windows:
Pueblo Paleta: 0 --> 0
Ciudad verde: 1 --> 1
Ruta 1: 19 --> 13
Ruta 2: 20 --> 14
Ruta 3: 21 --> 15
Ahora tenemos que hacer la tabla. Tenemos 5 localizaciones, así que la tabla tendrá 5 filas. No os preocupéis por el número de filas, podéis poner hasta 256 (LOL). Cada fila empieza con una localización, y los números siguientes son las localizaciones a las que se puede mover el poke. Mi tabla queda así:
00 13
01 13 14
13 00 01 15
14 01
15 13
Pero esta tabla puede hacer que el juego se trabe, porque hay filas con sólo 2 bytes y el mínimo es 3. En efecto, pueblo paleta y las rutas 2 y 3 sólo tienen una conexión, y el mínimo son 2 conexiones. Así que conectaré la ruta 2 con pueblo paleta y la ruta 3 con ciudad verde:
00 13 14
01 13 14
13 00 01 15
14 01 00
15 13 01
Rellena de FF hasta que cada fila tenga 7 bytes en FR, o hasta 6 bytes en esmeralda:
00 13 14 FF FF FF FF
01 13 14 FF FF FF FF
13 00 01 15 FF FF FF
14 01 00 FF FF FF FF
15 13 01 FF FF FF FF
Ya tenemos nuestra tabla lista. Ahora abre la ROM con tu editor hexadecimal y ve al offset donde se encuentra la tabla. Si tu tabla es más corta que la tabla original (como es mi caso), simplemente pégala sobreescribiendo la tabla original, y rellena de FF hasta borrar por completo la tabla anterior.
Si es más grande tendrás que buscar un espacio libre en la ROM terminado en 0, 4, 8, o C. El offset A00003 está vacío, pero no es válido porque termina en 3, pero el offset A00000 sí que nos sirve. Imaginemos que vas a pegar tu tabla en A00000. Ahora tendrás que hacer un repoint. Si usas HxD, ve a Buscar -> Reemplazar... Busca los pointers 58 6C 46 08 en FR, o 04 1A 5D 08 en esmeralda, y en reemplazar escribe el offset donde hayas puesto tu tabla, pero invertido: A00000 -> 00 00 A0 08. Tipo de datos: valores hexadecimales, Dirección Todo, y cuando esté todo listo Reemplazar todo.
El último paso es decirle a la rutina la nueva longitud de la tabla. ¿Habéis visto que la tabla de FR mide 25 filas? 25 en hex es 19. Hay 3 bytes que indican el nº de filas de la tabla, aquí se indica la dirección donde se encuentran:
La nueva longitud de la tabla es 5 filas, que en hex es 5 Así que cambiamos esos tres bytes por sus nuevos valores:
En 141d6e: 05
En 141df6: 05
En 141eae: 04
Y listo, ya hemos definido los mapas por donde se mueve el pokemon errante.
Hay que tener en cuenta que todos los números de mapa están referidos al banco 0 en esmeralda y al banco 3 en FR. Es decir, que nuestro poke sólo se podrá mover por los mapas del banco 0 en esmeralda y el banco 3 en FR. Si por algún motivo quieres que aparezca en un mapa fuera de ese banco (una cueva, una casa, la zona safari...) puedes ejecutar el siguiente script a la entrada del mapa:
Pero al cambiar de mapa el pokémon volverá a rondar por las rutas de la tabla.
Con lo que se ha explicado hasta ahora sería bastante para hacer que aparezca el pokémon errante que quieras en el estado que quieras y donde quieras. Pero parece que hay una pequeña limitación... y es que el juego no está pensado para que aparezca más de un pokémon errante a la vez. Así que en principio hacer que aparezca más de un pokémon errante a la vez no es posible. Pero bueno, tampoco hace falta llevarse las manos a la cabeza. Lo que sí podemos hacer es elegir el pokémon que aparece en cualquier momento, con sólo ejecutar un script.
Pondré un ejemplo: imagina que quieres que aparezcan un Lugia y un Ho-ho errantes por tu región, y que puedas elegir en cualquier momento cuál de los dos aparece. Primero tendrás que asignarle una flag a cada pokémon para establecer si ya se ha capturado o debilitado, en mi ejemplo la de Ho-ho es la 0x1100 y la de Lugia la 0x1101. Ahora puedes hacer que hayan dos personajes (o carteles, o lo que sea), de tal forma que el primero haga aparecer a Lugia y el segundo a Ho-ho. El script para el primero sería algo así:
El script para el segundo sería parecido. Este script es simple y te permite tener dos pokémon errantes, de tal forma que el jugador elige cuál de los dos quiere capturar en cualquier momento. Desafortunadamente no guarda los datos de vitalidad y estado, así que cuando se cambie a Lugia por Ho-ho o viceversa volverán a tener la vida máxima y ningún problema de estado (es decir, se "curarán"). Esto tampoco es un gran problema, si quieres guardar la salud del pokémon tendrías que guardar su vitalidad y estado en dos variables con el comando "copyvar". Pero por ejemplo en mi hack ya hay 6 pokémon errantes diferentes, si quisiera que se guardaran el estado y vit. de cada pokémon me harían falta 12 variables, y los script serían eternos. Así que no guardar el estado el errante es mucho más fácil de hacer y además tampoco supone un gran problema.
Si quieres que tus pokemon errantes aparezcan por rutas distintas, te recomiendo que uses el script que se explica al final de esta página. Así, puedes hacer que cada pokémon aparezca por rutas distintas.
¿Te ha parecido complicado? ¿No lo has entendido? ¿Se te ha ocurrido una idea pero no sabes cómo llevarla a cabo? Pues no te lo pienses y déjame un comentario, que estaré encantado de ayudarte
Para terminar, me gustaría aclarar que para los que uséis FR (que sereis la mayoría) hay un pequeño cabo suelto en mi investigación. Resulta que si buscáis en la pokédex el área del pokémon errante no aparecerá. Sin embargo sí que os saldrá el área de uno de los tres perros legendarios. De momento no he podido cambiar ese pequeño gran detalle, y me temo que no puedo asegurar que consiga arreglarlo... Si sois capaces de aceptar este defecto entonces no tendréis ningún problema. Aquí unas imágenes, donde se ve que aunque el área que aparece en la pokédex es la de Raikou, si lo buscamos nos encontramos al pokémon que hemos definido con la rutina:
Y creo que nada mas... Espero haberte ayudado a hacer lo que querías en tu hack. Pero si no has conseguido lo que querías ya sabes, ¡¡coméntamelo!! Lo único que te pido a cambio es que si has seguido este tutorial me menciones en los créditos de tu hack (que aunque antes ya era chulo, ahora que has metido esto seguro que te ha quedado mejor )
Gracias a todos los que os habéis tragado este tocho Y sobre todo a esta comunidad, que aunque éste sea mi primer mensaje he aprendido todo lo que sé de RH gracias a todos los tutoriales, las preguntas y las respuestas que hacéis continuamente.
Si os queda alguna duda, o veis algún fallo, mandadme un MP o comentadlo!!
Un saludo!!!
El caso, que llevo tiempo buscando la forma de añadir Pokémon errantes al Esmeralda (en español, es la ROM que utilizo). He buscado en este foro y en foro de PokemonCommunity, y no he conseguido encontrar nada. Así que empecé a investigar la forma en que aparecían Latios y Latias en el juego. A continuación dejo los pasos que he seguido durante mi investigación, por si a alguien le interesa o le pueda servir de ayuda. Si sólo quieres saber cómo se meten pokémon errantes, sáltate este paso.
En mi búsqueda, encontré la dirección del script de cuando te pasas la liga y tu madre te pregunta de qué color era el pokémon de la tele, si rojo o azul. Concretamente, el script es éste:
A nosotros nos interesa esta parte:
El special 0x12B tiene como variable de entrada la 0x8004. Lo que hace el special es lo siguiente: si 0x8004 es igual a 0, el pokémon errante que aparece es Latias; si es igual a 1, aparece Latios (por lo que he probado, cualquier valor distinto de 0 hace que aparezca Latios). La variable 0x40D5 no nos interesa, lo que hace es guardar el valor que hemos escogido para más tarde, en la isla del sur, que aparezca el pokémon que no hayamos elegido.
El special 0x12B nos lleva a la dirección 0x8161961 y ejecuta el código en ASM que se encuentra allí. Pensé que la información del pokémon que nos aparece se guardaba en alguna parte de ese código, pero he estado buscando y no he encontrado nada (aunque tampoco sé como funciona el código). El código en cuestión es éste:
Como no encontré nada buscando en el interior de la ROM, pasé a buscar en la memoria RAM. Para eso, hay que usar el buscador de cheats del emulador VBA (Ctrl + C). El valor de Latias en hexadecimal es 0x197, así que mi idea fue ejecutar el siguiente script:
Que hace que aparezca Latias. Después de activar el special, busqué en el buscador de cheats el valor 0197, y me apareció la siguiente dirección:
Si abrimos el Tools > Memory Viewer, y nos vamos a esa dirección…
Parece ser que esos números tienen que ver con el pokémon errante que nos aparece. Algunos se pueden deducir a primera vista, otros he tenido que investigarlos un poco:
Azul: número del pokémon errante invertido (Latias: 197, que invertido es 97 01)
Verde: vitalidad actual. Cuando hieres a un pokémon errante y se escapa, la próxima vez que te lo encuentras sigue con la misma vida. Pues parece ser que es aquí donde se guarda ese valor (en HEX, por supuesto).
Amarillo: nivel del pokémon, 28 en hex es 40 en decimal.
Marrón: el estado del pokémon, que también se guarda de un combate a otro.
Naranja: disponibilidad del pokémon (1 = vivo y salvaje, 0 = capturado o debilitado)
Rojo: información encriptada que definen los valores iniciales, la naturaleza y posiblemente el género.
Visto esto, mi primera idea fue bien simple, sustituir el número 0197 por el valor del nuevo pokémon. Después de investigar un poco acerca de las flags y las variables noté que la memoria donde se aloja la información del pokémon errante coincide con la memoria usada para las variables, es decir, que los pokémon errantes se guardan en variables. Las variables son:
- Variable del pokémon: Esmeralda 0x4F24; RF 0x506C
- Variable de la vitalidad: Esmeralda 0x4F25; RF 0x506D
- Variable del nivel y estado: Esmeralda 0x4F26; RF 0x506E
- Variable de la disponibilidad (0x100 = disponible, 0x0 = no disponible) = Esmeralda 0x5F29; FR 0x5071
Así que en teoría podríamos elegir al pokémon errante sólo editando las variables de antes con "setvar". En mi caso empecé probando con un Raikou, cuyo valor es 00F3. Ejecutando el script:
Debería de aparecernos un Raikou errante.
Efectivamente, nuestro script ha sustituido el 0197 por nuestro 00F3 que le habíamos dicho. Entonces… ¿Debería de aparecernos un Raikou errante? Vamos a consultar en la pokédex…
(Nota: para facilitar el proceso, antes programé un "wildbattle" contra un Raikou para que me saliera en la pokédex, y que después me diera una masterball):
Efectivamente aparece el área de Raikou en la pokédex, y además va cambiando cada vez que nos movemos. Pero y si lo buscamos, ¿que nos encontramos?
¡Toma, a la primera! ¡Nos ha salido un Raikou perfecto!
Ahora se pueden sustituir los valores del pokémon que nos encontramos por los que nosotros queramos usando sólo "setvar". Ésa es la sección que viene a continuación.
Bueno, el Raikou no es del todo perfecto... ¿Habéis notado ese trocito de vida que le falta? Eso es porque sólo he cambiado el pokémon que aparece, pero no la vida (¿os acordáis del 0076 que estaba marcado en verde? no es casualidad que 76 en HEX sea 118 en decimal). Por tanto, el pokémon tiene la misma vida que cuando era un Latias, y como Raikou tiene más vida máxima que Latias... ¿Entendéis?
De momento no he encontrado una solución permanente para esto. He provado a ponerle una vida mayor que la máxima, pero lo que pasa es que si hieres al pokémon, durante un tiempo parecerá que no le restas vida... Lo único que se me ocurre es que si quieres poner X pokemon al nivel Y, busques en una calculadora de estadísticas la vida que debería de tener a ese nivel con valores iniciales al máximo, para asegurarte de que no te quedas corto, y así tampoco te pasas mucho de la vida máxima.
Código:
#org 0x29793E
lockall
checkgender
compare LASTRESULT 0x0
if 0x1 call 0x8297AC2
compare LASTRESULT 0x1
if 0x1 call 0x8297AD2
compare 0x8008 0x0
if 0x1 call 0x8297B54
compare 0x8008 0x1
if 0x1 call 0x8297B5F
applymovement 0x8009 0x82763A2
waitmovement 0x0
sound 0x15
applymovement 0x8009 0x827639C
waitmovement 0x0
applymovement 0x8009 0x827639E
waitmovement 0x0
pause 0x14
compare 0x8008 0x0
if 0x1 call 0x8297AE2
compare 0x8008 0x1
if 0x1 call 0x8297AED
msgbox 0x81F87BF MSG_KEEPOPEN '"PAPÁ: ¿Eh?\p¡Pero si es mi [player..."
giveitem 0x109 0x1 MSG_OBTAIN
msgbox 0x81F8896 MSG_KEEPOPEN '"PAPÁ: ¿Un TICKET para el ferry?\pS..."
closeonkeypress
pause 0x14
compare 0x8008 0x0
if 0x1 call 0x8297AF8
compare 0x8008 0x1
if 0x1 call 0x8297B0D
msgbox 0x81F88FF MSG_KEEPOPEN '"Mejor vuelvo al GIMNASIO de PETALI..."
closeonkeypress
compare 0x8008 0x0
if 0x1 call 0x8297B22
compare 0x8008 0x1
if 0x1 call 0x8297B3B
sound 0x8
hidesprite 0x8009
setflag 0x123
pause 0x1E
compare 0x8008 0x0
if 0x1 call 0x8297B94
compare 0x8008 0x1
if 0x1 call 0x8297BA9
pause 0x14
msgbox 0x81F8965 MSG_KEEPOPEN '"MAMÁ: Este padre tuyo[.]\pCuando p..."
closeonkeypress
setflag 0x8BD
special 0x1F6
pause 0x3C
compare 0x8008 0x0
if 0x1 call 0x8297BBE
compare 0x8008 0x1
if 0x1 call 0x8297BC9
msgbox 0x81F8A08 MSG_KEEPOPEN '"MAMÁ: ¿Un especial informativo?"
closeonkeypress
compare 0x8008 0x0
if 0x1 call 0x8297B6A
compare 0x8008 0x1
if 0x1 call 0x8297B7F
msgbox 0x81F8A28 MSG_KEEPOPEN '"¡Interrumpimos la programación par..."
closeonkeypress
clearflag 0x8BD
setflag 0xFF
special 0x41
compare 0x8008 0x0
if 0x1 call 0x8297BD4
compare 0x8008 0x1
if 0x1 call 0x8297BE9
msgbox 0x81F8B40 MSG_KEEPOPEN '"MAMÁ: [player], ¿has oído eso?\p¿D..."
multichoice 0x16 0x8 0x6C 0x1
copyvar 0x8004 LASTRESULT
special 0x12B
copyvar 0x40D5 LASTRESULT
msgbox 0x81F8B93 MSG_KEEPOPEN '"MAMÁ: ¡Ver para creer!\n¡Aún hay P..."
closeonkeypress
setvar 0x4082 0x4
setvar 0x408C 0x4
releaseall
end
'---------------
#org 0x297AC2
setvar 0x8008 0x0
setvar 0x8009 0x5
setvar 0x800A 0x1
return
'---------------
#org 0x297AD2
setvar 0x8008 0x1
setvar 0x8009 0x5
setvar 0x800A 0x1
return
'---------------
#org 0x297B54
applymovement MOVE_PLAYER 0x8297C12
waitmovement 0x0
return
'---------------
#org 0x297B5F
applymovement MOVE_PLAYER 0x8297C1D
waitmovement 0x0
return
'---------------
#org 0x297AE2
applymovement 0x8009 0x8297BFE
waitmovement 0x0
return
'---------------
#org 0x297AED
applymovement 0x8009 0x8297C01
waitmovement 0x0
return
'---------------
#org 0x297AF8
applymovement 0x800A 0x82977D5
waitmovement 0x0
applymovement 0x8009 0x8297C04
waitmovement 0x0
return
'---------------
#org 0x297B0D
applymovement 0x800A 0x82977DD
waitmovement 0x0
applymovement 0x8009 0x8297C06
waitmovement 0x0
return
'---------------
#org 0x297B22
applymovement MOVE_PLAYER 0x8297C18
applymovement 0x800A 0x8297C18
applymovement 0x8009 0x8297C08
waitmovement 0x0
return
'---------------
#org 0x297B3B
applymovement MOVE_PLAYER 0x8297C18
applymovement 0x800A 0x8297C18
applymovement 0x8009 0x8297C0D
waitmovement 0x0
return
'---------------
#org 0x297B94
applymovement 0x800A 0x82977E5
waitmovement 0x0
applymovement MOVE_PLAYER 0x82763A8
waitmovement 0x0
return
'---------------
#org 0x297BA9
applymovement 0x800A 0x82977E7
waitmovement 0x0
applymovement MOVE_PLAYER 0x82763AC
waitmovement 0x0
return
'---------------
#org 0x297BBE
applymovement 0x800A 0x82977E9
waitmovement 0x0
return
'---------------
#org 0x297BC9
applymovement 0x800A 0x82977F2
waitmovement 0x0
return
'---------------
#org 0x297B6A
applymovement MOVE_PLAYER 0x8297C23
waitmovement 0x0
applymovement 0x800A 0x82763A8
waitmovement 0x0
return
'---------------
#org 0x297B7F
applymovement MOVE_PLAYER 0x8297C2A
waitmovement 0x0
applymovement 0x800A 0x82763AC
waitmovement 0x0
return
'---------------
#org 0x297BD4
applymovement 0x800A 0x82977FB
waitmovement 0x0
applymovement MOVE_PLAYER 0x82763AC
waitmovement 0x0
return
'---------------
#org 0x297BE9
applymovement 0x800A 0x82977FF
waitmovement 0x0
applymovement MOVE_PLAYER 0x82763A8
waitmovement 0x0
return
'---------
' Strings
'---------
#org 0x1F87BF
= PAPÁ: ¿Eh?\p¡Pero si es mi [player]!\pHace un siglo que no te veo[.]\n¡Si pareces mucho más fuerte!\pÉsa es la impresión que das, ¡pero\ntu padre aún puede dar guerra!\pAh, sí, tengo algo para ti.\nTe lo envía un tal SR. ARENQUE.
#org 0x1F8896
= PAPÁ: ¿Un TICKET para el ferry?\pSi recuerdo bien, los puertos donde\natraca son CIUDAD PORTUAL y CALAGUA.
#org 0x1F88FF
= Mejor vuelvo al GIMNASIO de PETALIA.\pCariño, gracias por ocuparte\nde la casa mientras yo estoy fuera.
#org 0x1F8965
= MAMÁ: Este padre tuyo[.]\pCuando por fin viene un poco a casa,\nsólo se le ocurre hablar de POKéMON.\pDebería relajarse un poco y quedarse\nmás tiempo aquí tranquilito[.]
#org 0x1F8A08
= MAMÁ: ¿Un especial informativo?
#org 0x1F8A28
= ¡Interrumpimos la programación para\ntraerles las últimas noticias!\pHay noticias confusas sobre supuestos\navistamientos de un POKéMON azzzrt[.]\lvolando en distintos puntos de HOENN.\pActualmente se desconoce la identidad\ndel POKéMON.\pY ahora les dejamos con la programación\nhabitual.
#org 0x1F8B40
= MAMÁ: [player], ¿has oído eso?\p¿De qué color ha dicho el de\nla tele que era ese POKéMON?
#org 0x1F8B93
= MAMÁ: ¡Ver para creer!\n¡Aún hay POKéMON desconocidos!
'-----------
' Movements
'-----------
#org 0x2763A2
#raw 0x3E 'Face Player
#raw 0xFE 'End of Movements
#org 0x27639C
#raw 0x56 'Exclamation Mark (!)
#raw 0xFE 'End of Movements
#org 0x27639E
#raw 0x14 'Delay5
#raw 0x14 'Delay5
#raw 0x14 'Delay5
#raw 0xFE 'End of Movements
#org 0x297C12
#raw 0x14 'Delay5
#raw 0x8 'Step Down (Normal)
#raw 0x8 'Step Down (Normal)
#raw 0x8 'Step Down (Normal)
#raw 0x27 'Step on the Spot Left (Fastest)
#raw 0xFE 'End of Movements
#org 0x297C1D
#raw 0x14 'Delay5
#raw 0x8 'Step Down (Normal)
#raw 0x8 'Step Down (Normal)
#raw 0x8 'Step Down (Normal)
#raw 0x28 'Step on the Spot Right (Fastest)
#raw 0xFE 'End of Movements
#org 0x297BFE
#raw 0xB 'Step Right (Normal)
#raw 0xB 'Step Right (Normal)
#raw 0xFE 'End of Movements
#org 0x297C01
#raw 0xA 'Step Left (Normal)
#raw 0xA 'Step Left (Normal)
#raw 0xFE 'End of Movements
#org 0x2977D5
#raw 0x9 'Step Up (Normal)
#raw 0xB 'Step Right (Normal)
#raw 0xB 'Step Right (Normal)
#raw 0xB 'Step Right (Normal)
#raw 0xB 'Step Right (Normal)
#raw 0x8 'Step Down (Normal)
#raw 0x28 'Step on the Spot Right (Fastest)
#raw 0xFE 'End of Movements
#org 0x297C04
#raw 0x2 'Face Left
#raw 0xFE 'End of Movements
#org 0x2977DD
#raw 0x9 'Step Up (Normal)
#raw 0xA 'Step Left (Normal)
#raw 0xA 'Step Left (Normal)
#raw 0xA 'Step Left (Normal)
#raw 0xA 'Step Left (Normal)
#raw 0x8 'Step Down (Normal)
#raw 0x27 'Step on the Spot Left (Fastest)
#raw 0xFE 'End of Movements
#org 0x297C06
#raw 0x3 'Face Right
#raw 0xFE 'End of Movements
#org 0x297C18
#raw 0x13 'Delay4
#raw 0x14 'Delay5
#raw 0x14 'Delay5
#raw 0x25 'Step on the Spot Down (Fastest)
#raw 0xFE 'End of Movements
#org 0x297C08
#raw 0x8 'Step Down (Normal)
#raw 0xB 'Step Right (Normal)
#raw 0x8 'Step Down (Normal)
#raw 0x13 'Delay4
#raw 0xFE 'End of Movements
#org 0x297C0D
#raw 0x8 'Step Down (Normal)
#raw 0xA 'Step Left (Normal)
#raw 0x8 'Step Down (Normal)
#raw 0x13 'Delay4
#raw 0xFE 'End of Movements
#org 0x2977E5
#raw 0xB 'Step Right (Normal)
#raw 0xFE 'End of Movements
#org 0x2763A8
#raw 0x27 'Step on the Spot Left (Fastest)
#raw 0xFE 'End of Movements
#org 0x2977E7
#raw 0xA 'Step Left (Normal)
#raw 0xFE 'End of Movements
#org 0x2763AC
#raw 0x28 'Step on the Spot Right (Fastest)
#raw 0xFE 'End of Movements
#org 0x2977E9
#raw 0x27 'Step on the Spot Left (Fastest)
#raw 0x14 'Delay5
#raw 0x14 'Delay5
#raw 0x14 'Delay5
#raw 0x14 'Delay5
#raw 0x28 'Step on the Spot Right (Fastest)
#raw 0x14 'Delay5
#raw 0x14 'Delay5
#raw 0xFE 'End of Movements
#org 0x2977F2
#raw 0x28 'Step on the Spot Right (Fastest)
#raw 0x14 'Delay5
#raw 0x14 'Delay5
#raw 0x14 'Delay5
#raw 0x14 'Delay5
#raw 0x27 'Step on the Spot Left (Fastest)
#raw 0x14 'Delay5
#raw 0x14 'Delay5
#raw 0xFE 'End of Movements
#org 0x297C23
#raw 0x9 'Step Up (Normal)
#raw 0xA 'Step Left (Normal)
#raw 0xA 'Step Left (Normal)
#raw 0xA 'Step Left (Normal)
#raw 0xA 'Step Left (Normal)
#raw 0x26 'Step on the Spot Up (Fastest)
#raw 0xFE 'End of Movements
#org 0x297C2A
#raw 0x9 'Step Up (Normal)
#raw 0xB 'Step Right (Normal)
#raw 0xB 'Step Right (Normal)
#raw 0xB 'Step Right (Normal)
#raw 0xB 'Step Right (Normal)
#raw 0x26 'Step on the Spot Up (Fastest)
#raw 0xFE 'End of Movements
#org 0x2977FB
#raw 0x9 'Step Up (Normal)
#raw 0xA 'Step Left (Normal)
#raw 0xA 'Step Left (Normal)
#raw 0xFE 'End of Movements
#org 0x2977FF
#raw 0x9 'Step Up (Normal)
#raw 0xB 'Step Right (Normal)
#raw 0xB 'Step Right (Normal)
#raw 0xFE 'End of Movements
A nosotros nos interesa esta parte:
Código:
multichoice 0x16 0x8 0x6C 0x1
copyvar 0x8004 LASTRESULT
special 0x12B
copyvar 0x40D5 LASTRESULT
El special 0x12B nos lleva a la dirección 0x8161961 y ejecuta el código en ASM que se encuentra allí. Pensé que la información del pokémon que nos aparece se guardaba en alguna parte de ese código, pero he estado buscando y no he encontrado nada (aunque tampoco sé como funciona el código). El código en cuestión es éste:
Como no encontré nada buscando en el interior de la ROM, pasé a buscar en la memoria RAM. Para eso, hay que usar el buscador de cheats del emulador VBA (Ctrl + C). El valor de Latias en hexadecimal es 0x197, así que mi idea fue ejecutar el siguiente script:
Código:
#org @inicio
setvar 0x8004 0x0
special 0x12B
end
Si abrimos el Tools > Memory Viewer, y nos vamos a esa dirección…
Parece ser que esos números tienen que ver con el pokémon errante que nos aparece. Algunos se pueden deducir a primera vista, otros he tenido que investigarlos un poco:
Azul: número del pokémon errante invertido (Latias: 197, que invertido es 97 01)
Verde: vitalidad actual. Cuando hieres a un pokémon errante y se escapa, la próxima vez que te lo encuentras sigue con la misma vida. Pues parece ser que es aquí donde se guarda ese valor (en HEX, por supuesto).
Amarillo: nivel del pokémon, 28 en hex es 40 en decimal.
Marrón: el estado del pokémon, que también se guarda de un combate a otro.
Naranja: disponibilidad del pokémon (1 = vivo y salvaje, 0 = capturado o debilitado)
Rojo: información encriptada que definen los valores iniciales, la naturaleza y posiblemente el género.
Visto esto, mi primera idea fue bien simple, sustituir el número 0197 por el valor del nuevo pokémon. Después de investigar un poco acerca de las flags y las variables noté que la memoria donde se aloja la información del pokémon errante coincide con la memoria usada para las variables, es decir, que los pokémon errantes se guardan en variables. Las variables son:
- Variable del pokémon: Esmeralda 0x4F24; RF 0x506C
- Variable de la vitalidad: Esmeralda 0x4F25; RF 0x506D
- Variable del nivel y estado: Esmeralda 0x4F26; RF 0x506E
- Variable de la disponibilidad (0x100 = disponible, 0x0 = no disponible) = Esmeralda 0x5F29; FR 0x5071
Así que en teoría podríamos elegir al pokémon errante sólo editando las variables de antes con "setvar". En mi caso empecé probando con un Raikou, cuyo valor es 00F3. Ejecutando el script:
Código:
#org @inicio
special 0x12B
setvar 0x4F24 0xF3
end
Debería de aparecernos un Raikou errante.
Efectivamente, nuestro script ha sustituido el 0197 por nuestro 00F3 que le habíamos dicho. Entonces… ¿Debería de aparecernos un Raikou errante? Vamos a consultar en la pokédex…
(Nota: para facilitar el proceso, antes programé un "wildbattle" contra un Raikou para que me saliera en la pokédex, y que después me diera una masterball):
Efectivamente aparece el área de Raikou en la pokédex, y además va cambiando cada vez que nos movemos. Pero y si lo buscamos, ¿que nos encontramos?
¡Toma, a la primera! ¡Nos ha salido un Raikou perfecto!
Ahora se pueden sustituir los valores del pokémon que nos encontramos por los que nosotros queramos usando sólo "setvar". Ésa es la sección que viene a continuación.
Bueno, el Raikou no es del todo perfecto... ¿Habéis notado ese trocito de vida que le falta? Eso es porque sólo he cambiado el pokémon que aparece, pero no la vida (¿os acordáis del 0076 que estaba marcado en verde? no es casualidad que 76 en HEX sea 118 en decimal). Por tanto, el pokémon tiene la misma vida que cuando era un Latias, y como Raikou tiene más vida máxima que Latias... ¿Entendéis?
De momento no he encontrado una solución permanente para esto. He provado a ponerle una vida mayor que la máxima, pero lo que pasa es que si hieres al pokémon, durante un tiempo parecerá que no le restas vida... Lo único que se me ocurre es que si quieres poner X pokemon al nivel Y, busques en una calculadora de estadísticas la vida que debería de tener a ese nivel con valores iniciales al máximo, para asegurarte de que no te quedas corto, y así tampoco te pasas mucho de la vida máxima.
Script del Pokémon Errante
Hacer que aparezca un pokémon errante es tan simple como ejecutar un script. En Esmeralda el special 0x12B hace que aparezca un pokémon errante u otro dependiendo del valor que hay en la variable 0x8004: si es 0, aparece Latias, y si es 1 aparece Latios. En FR se usa el special 0x129 y la variable de entrada que utiliza es la 0x4031, que es donde se guarda el pokémon inicial que escogiste, y hace que aparezca Raikou, Entei o Suicune. Lo que vamos a hacer es llamar al special, hacer que aparezca uno de éstos pokemon como errante y sustituirlo por el pokemon que queramos.
Los datos del pokémon errante se guardan en variables, así que conociendo estas variables podemos editar al pokémon errante como queramos. Concretamente, las variables son éstas:
- Variable del pokémon: Esmeralda 0x4F24; RF 0x506C
- Variable de la vitalidad: Esmeralda 0x4F25; RF 0x506D
- Variable del nivel y estado: Esmeralda 0x4F26; RF 0x506E
- Variable de la disponibilidad (0x100 = disponible, 0x0 = no disponible) = Esmeralda 0x5F29; FR 0x5071
Ahora explicaré qué significa cada variable y los pasos a seguir en Esmeralda, para Fire Red los pasos a seguir son idénticos. El script del pokémon es el siguiente:
Código:
#org inicio
special 0x12B
setvar 0x4F24 0x'(nº del pokémon que quieras que sea errante)
setvar 0x4F25 0x'(vitalidad del pokémon)
setvar 0x4F26 0xXXYY'(YY es el nivel y XX es el estado)
end
Código:
#org inicio
special 0x129
setvar 0x506C 0x'(nº del pokémon que quieras que sea errante)
setvar 0x506D 0x'(vitalidad del pokémon)
setvar 0x506E 0xXXYY'(YY es el nivel y XX es el estado)
end
Voy a explicar para qué sirve cada variable:
La primera indica el pokémon que nos aparecerá por la región. Por poner un ejemplo, yo quiero que me aparezca Raikou, cuyo número es F3, pues en mi caso pondré setvar 0x4F24 0xF3.
La segunda determina la vida con la que nos encontramos al pokémon. Esto es muy importante, porque un valor muy alto provocaría que, al herir al pokémon, durante un tiempo su vida no decrezca (dependiendo de lo mucho que te hayas pasado de su vida máxima), y con un valor bajo te encontraías al pokémon con escasa vida. Para elegir un valor adecuado, podéis usar la siguiente calculadora Pokéxperto; Calculadora DS/Advance de IV's & Stats
Eliges el pokémon, su nivel, y a la derecha donde dice Resultados, en PS escribes 31, y pulsa "calcular stats"
A mí me ha salido a la izquierda, en PS, 165. Pues paso este valor a hexadecimal (165 = A5 en HEX) y ya está. Lo que tengo que poner es setvar 0x4F25 0xA5.
La tercera variable es complicada. En una misma variable se guarda el nivel y el estado (envenenamiento, parálisis...). El nivel es simple: escoge un nivel de 1 a 100 y lo pasas a hexadecimal. En mi caso quiero que salga al 50, que en HEX es 32, luego YY = 32. El estado es algo difícil; si no te interesa modificar el estado, ignora el siguiente spoiler y haz XX = 00.
El XX es lo más difícil, establece el estado del pokémon. El estado se determina con la siguiente tabla, sacada de Pokémon data structure in Generation III - Bulbapedia, the community-driven Pokémon encyclopedia
Para poner un estado, escribe ocho ceros:
00000000
Esto es un número binario de ocho bits, donde cada uno puede tomar un valor entre 0 y 1. La tabla indica, para un número de 8 bits, qué estado aplica cada bit, leído de derecha a izquierda. Por ejemplo, este número
00001000
Tiene el cuarto bit igual a 1, y el resto 0. Según la tabla, el cuarto bit es envenenamiento, así que nuestro pokémon con este código estará envenenado (Notad que la tabla dice 3 para Poison, no 4, pero hay que tener en cuenta que empieza a contar desde 0, no desde 1).
Si por ejemplo, aplicamos este código
00010000
El quinto bit indica quemado, es decir, nos encontraremos al pokémon quemado. También podemos mezclar algunos estados, por ejemplo:
01100000
Hará que el pokémon esté congelado, y cuando se descongele estará paralizado.
El sueño ocupa 3 bits. Esto es porque además determina los turnos que quedan para que el pokémon se despierte. Por ejemplo, 001 en binario es 1, así que el próximo turno se despertará; 101 en binario es 5, así que dormirá durante 5 turnos, etc...
Vale, muy bonito esto de los bits, pero… ¿cómo se aplica?
Simple. Una vez que tengas tu código de 8 cifras en binario, lo pasas de binario a hexadecimal en la calculadora. Yo quiero que mi Raikou esté congelado. El código para congelamiento es 00100000, que en hexadecimal es 20. Por tanto, XX = 20.
Entiendo que este procedimiento es bastante confuso. Si no te ha quedado claro y tienes alguna duda, deja tu pregunta en los comentarios
Nota: Si lo que tienes pensado es dormir o congelar al pokémon para que no se escape... Olvídate, porque se va a escapar igualmente. Y si no, que le pregunten a este pobre hombre ... (min 8:00) Pokémon FireRed - Episode 37 - Suicune - YouTube
Para poner un estado, escribe ocho ceros:
00000000
Esto es un número binario de ocho bits, donde cada uno puede tomar un valor entre 0 y 1. La tabla indica, para un número de 8 bits, qué estado aplica cada bit, leído de derecha a izquierda. Por ejemplo, este número
00001000
Tiene el cuarto bit igual a 1, y el resto 0. Según la tabla, el cuarto bit es envenenamiento, así que nuestro pokémon con este código estará envenenado (Notad que la tabla dice 3 para Poison, no 4, pero hay que tener en cuenta que empieza a contar desde 0, no desde 1).
Si por ejemplo, aplicamos este código
00010000
El quinto bit indica quemado, es decir, nos encontraremos al pokémon quemado. También podemos mezclar algunos estados, por ejemplo:
01100000
Hará que el pokémon esté congelado, y cuando se descongele estará paralizado.
El sueño ocupa 3 bits. Esto es porque además determina los turnos que quedan para que el pokémon se despierte. Por ejemplo, 001 en binario es 1, así que el próximo turno se despertará; 101 en binario es 5, así que dormirá durante 5 turnos, etc...
Vale, muy bonito esto de los bits, pero… ¿cómo se aplica?
Simple. Una vez que tengas tu código de 8 cifras en binario, lo pasas de binario a hexadecimal en la calculadora. Yo quiero que mi Raikou esté congelado. El código para congelamiento es 00100000, que en hexadecimal es 20. Por tanto, XX = 20.
Entiendo que este procedimiento es bastante confuso. Si no te ha quedado claro y tienes alguna duda, deja tu pregunta en los comentarios
Nota: Si lo que tienes pensado es dormir o congelar al pokémon para que no se escape... Olvídate, porque se va a escapar igualmente. Y si no, que le pregunten a este pobre hombre ... (min 8:00) Pokémon FireRed - Episode 37 - Suicune - YouTube
La variable 0x4F29 indica si el pokémon está disponible (0x100 salvaje y vivo) o no (0x0 debilitado o capturado). Cuando llamas al "special" este valor es automáticamente 0x100, así que en principio no hace falta tocarlo. Lo que sí puede servir es para saber si ya hemos capturado o debilitado al pokémon (para interactuar con la historia de nuestro hack o cosas así).
A modo de ejemplo, mi script queda de la siguiente forma:
Código:
#org inicio
special 0x12B
setvar 0x4F24 0xF3
setvar 0x4F25 0xA5
setvar 0x4F26 0x2032 'o si no quieres poner ningún estado, simplemente 0x32
end
...
Vaya, parece que no ha pasado nada. Sin embargo, yo me he adelantado y antes programé un wildbattle contra Raikou para que me apareciera en la Pokédex. El resultado es el siguiente...
¡¡Funciona!!
Bueno, si y no. Todavía queda investigar las zonas donde aparece, y poder hacer que aparezca más de un pokémon errante a la vez. Pero... yo diría que es un buen comienzo, ¿no te parece?
Aquí dejo algunos ejemplos más, donde se ve que tampoco hace falta poner siempre la vida máxima al pokémon:
Editando la localización
Para esta parte recomiendo que tengáis experiencia manejando editores hexadecimales. Cuando ejecutes el script de antes, el pokémon errante aparecerá por unos mapas específicos que están predefinidos en la ROM. Concretamente hay una tabla que indica las rutas por donde se mueve el poke:
Código:
Offset 5D1A04:
19 1A 20 21 31 FF
1A 19 20 21 FF FF
20 1A 19 21 FF FF
21 20 19 1A 22 26
22 21 23 FF FF FF
23 22 24 FF FF FF
24 23 25 26 FF FF
25 24 26 FF FF FF
26 25 21 FF FF FF
27 24 28 29 FF FF
28 27 2A FF FF FF
29 27 2A FF FF FF
2A 28 29 2B FF FF
2B 2A 2C FF FF FF
2C 2B 2D FF FF FF
2D 2C 2E FF FF FF
2E 2D 2F FF FF FF
2F 2E 30 FF FF FF
30 2F 31 FF FF FF
31 30 19 FF FF FF
Código:
Offset 466C58:
13 14 27 29 FF FF FF
14 13 15 29 FF FF FF
15 14 16 FF FF FF FF
16 15 17 1B 2B FF FF
17 16 18 19 1A 1B 2B
18 17 19 1A 1D FF FF
19 17 18 1A 22 FF FF
1A 17 18 19 1C 1E FF
1B 16 17 1C 2B FF FF
1C 1A 1B 1E FF FF FF
1D 18 1E FF FF FF FF
1E 1C 1D 1F FF FF FF
1F 1E 20 FF FF FF FF
20 1F 21 FF FF FF FF
21 20 24 25 FF FF FF
22 19 23 FF FF FF FF
23 22 24 FF FF FF FF
24 21 23 25 FF FF FF
25 21 24 26 FF FF FF
26 25 27 FF FF FF FF
27 13 26 FF FF FF FF
29 13 14 2A FF FF FF
2A 29 14 FF FF FF FF
2B 16 17 1B FF FF FF
2C 2B 1B FF FF FF FF
Cada fila de la tabla tiene la siguiente información:
- [*]Primer byte: nº de mapa en hex donde se encuentra el pokémon.[*]Resto de bytes: nº de mapa en hex donde estará el pokémon cuando cambiemos de mapa.[*]FF: todos los bytes que sean FF son ignorados.
Además, nos encontramos con tres limitaciones:
- El nº de filas de la tabla indica el nº máximo de posibles localizaciones del pokémon. Por ejemplo, en esmeralda la tabla tiene 20 filas, así que el poke no podrá aparecer en más de 20 rutas. Ésta limitación se puede saltar.
- El ancho de la tabla - 1 indica el nº máximo de rutas a las que puede estar conectada una ruta. En esmeralda cada fila tiene 6 bytes, pues como máximo una ruta podrá estar conectada a 6 - 1 = 5 posibles rutas. Ésta limitación no se puede saltar.
- Cada fila tiene como mínimo 3 bytes distintos de FF. Es decir, cada ruta está conectada como mínimo con otras 2. Esto tiene una explicación curiosa, resulta que la rutina que calcula el área del pokemon errante está programada para que el poke no pueda aparecer donde tú estuviste hace 2 localizaciones. De esta forma se evita eso de alternar constantemente entre dos rutas hasta que aparezca el poke. Si un pokémon solo puede ir de una ruta a otra, y tu estuviste en esa ruta hace 2 mapas, el juego se queda pillado. Ésta limitación se puede saltar, pero requiere conocimientos de ASM y no lo recomiendo.
Ya estamos en condiciones de editar la localización. Para editar esta tabla hará falta un editor hexadecimal, yo utilizo HxD. Primero debes tener una idea de las zonas donde se moverá el poke. Yo haré que el poke se mueva por este mapa (cortesía de Dani_SR_17):
-Pueblo Paleta - Ruta 1 - Ciudad Verde - Ruta 2
____ __ _ _ __- Ruta 3 -
Abre Advance Map y apunta el nº de cada mapa, y conviértelos a hexadecimal con la calculadora de windows:
Pueblo Paleta: 0 --> 0
Ciudad verde: 1 --> 1
Ruta 1: 19 --> 13
Ruta 2: 20 --> 14
Ruta 3: 21 --> 15
Ahora tenemos que hacer la tabla. Tenemos 5 localizaciones, así que la tabla tendrá 5 filas. No os preocupéis por el número de filas, podéis poner hasta 256 (LOL). Cada fila empieza con una localización, y los números siguientes son las localizaciones a las que se puede mover el poke. Mi tabla queda así:
00 13
01 13 14
13 00 01 15
14 01
15 13
Pero esta tabla puede hacer que el juego se trabe, porque hay filas con sólo 2 bytes y el mínimo es 3. En efecto, pueblo paleta y las rutas 2 y 3 sólo tienen una conexión, y el mínimo son 2 conexiones. Así que conectaré la ruta 2 con pueblo paleta y la ruta 3 con ciudad verde:
00 13 14
01 13 14
13 00 01 15
14 01 00
15 13 01
Rellena de FF hasta que cada fila tenga 7 bytes en FR, o hasta 6 bytes en esmeralda:
00 13 14 FF FF FF FF
01 13 14 FF FF FF FF
13 00 01 15 FF FF FF
14 01 00 FF FF FF FF
15 13 01 FF FF FF FF
Ya tenemos nuestra tabla lista. Ahora abre la ROM con tu editor hexadecimal y ve al offset donde se encuentra la tabla. Si tu tabla es más corta que la tabla original (como es mi caso), simplemente pégala sobreescribiendo la tabla original, y rellena de FF hasta borrar por completo la tabla anterior.
Si es más grande tendrás que buscar un espacio libre en la ROM terminado en 0, 4, 8, o C. El offset A00003 está vacío, pero no es válido porque termina en 3, pero el offset A00000 sí que nos sirve. Imaginemos que vas a pegar tu tabla en A00000. Ahora tendrás que hacer un repoint. Si usas HxD, ve a Buscar -> Reemplazar... Busca los pointers 58 6C 46 08 en FR, o 04 1A 5D 08 en esmeralda, y en reemplazar escribe el offset donde hayas puesto tu tabla, pero invertido: A00000 -> 00 00 A0 08. Tipo de datos: valores hexadecimales, Dirección Todo, y cuando esté todo listo Reemplazar todo.
El último paso es decirle a la rutina la nueva longitud de la tabla. ¿Habéis visto que la tabla de FR mide 25 filas? 25 en hex es 19. Hay 3 bytes que indican el nº de filas de la tabla, aquí se indica la dirección donde se encuentran:
En 161928: 14
En 1619c6: 14
En 161a82: 13
En 1619c6: 14
En 161a82: 13
En 141d6e: 19
En 141df6: 19
En 141eae: 18
En 141df6: 19
En 141eae: 18
La nueva longitud de la tabla es 5 filas, que en hex es 5 Así que cambiamos esos tres bytes por sus nuevos valores:
En 141d6e: 05
En 141df6: 05
En 141eae: 04
Y listo, ya hemos definido los mapas por donde se mueve el pokemon errante.
Hay que tener en cuenta que todos los números de mapa están referidos al banco 0 en esmeralda y al banco 3 en FR. Es decir, que nuestro poke sólo se podrá mover por los mapas del banco 0 en esmeralda y el banco 3 en FR. Si por algún motivo quieres que aparezca en un mapa fuera de ese banco (una cueva, una casa, la zona safari...) puedes ejecutar el siguiente script a la entrada del mapa:
Código:
#org @inicio
writebytetooffset 0x(banco del mapa) 0x203BC86
writebytetooffset 0x(nº de mapa) 0x203BC87
end
Código:
#org @inicio
writebytetooffset 0x(banco del mapa) 0x203F3AE
writebytetooffset 0x(nº de mapa) 0x203F3AF
end
Pero al cambiar de mapa el pokémon volverá a rondar por las rutas de la tabla.
Varios Pokémon Errantes
Con lo que se ha explicado hasta ahora sería bastante para hacer que aparezca el pokémon errante que quieras en el estado que quieras y donde quieras. Pero parece que hay una pequeña limitación... y es que el juego no está pensado para que aparezca más de un pokémon errante a la vez. Así que en principio hacer que aparezca más de un pokémon errante a la vez no es posible. Pero bueno, tampoco hace falta llevarse las manos a la cabeza. Lo que sí podemos hacer es elegir el pokémon que aparece en cualquier momento, con sólo ejecutar un script.
Pondré un ejemplo: imagina que quieres que aparezcan un Lugia y un Ho-ho errantes por tu región, y que puedas elegir en cualquier momento cuál de los dos aparece. Primero tendrás que asignarle una flag a cada pokémon para establecer si ya se ha capturado o debilitado, en mi ejemplo la de Ho-ho es la 0x1100 y la de Lugia la 0x1101. Ahora puedes hacer que hayan dos personajes (o carteles, o lo que sea), de tal forma que el primero haga aparecer a Lugia y el segundo a Ho-ho. El script para el primero sería algo así:
Código:
#org @inicio
lock
faceplayer
compare 0x4F24 0xFA 'Comprueba si el errante actual es Ho-ho
if 0x1 goto Cambiarhohoporlugia 'Si lo es salta a esa línea
compare 0x4F29 0x0 'Si el errante no es Ho-ho, entonces es Lugia. Esto comprueba si Lugia está disponible
if 0x1 goto @capturado 'Si no está disponible, el hombre dice que está capturado
msgbox @a 0x6 'Si está disponible, el hombre dice que está suelto
release
end
#org Cambiarhohoporlugia
checkflag 0x1101 'En esta flag está guardada la disponibilidad de Lugia
if 0x1 goto @capturado 'Si es 1 ya lo hemos capturado (o debilitado :P)
special 0x12B
setvar 0x4F24 0xF9 'Lugia
setvar 0x4F25 0xD7 'con 215 de vitalidad
setvar 0x4F26 0x3C 'al nivel 60
msgbox @a 0x6 'El jipi nos dice que está disponible
release
end
#org @capturado
setflag 0x1101
msgbox @b 0x6
release
end
#org @a
= Ahora mismo hay un LUGIA salvaje\nrondando por HOENN.
#org @b
= Parece que alguien ha capturado al\nLUGIA que merodeaba por HOENN.
El script para el segundo sería parecido. Este script es simple y te permite tener dos pokémon errantes, de tal forma que el jugador elige cuál de los dos quiere capturar en cualquier momento. Desafortunadamente no guarda los datos de vitalidad y estado, así que cuando se cambie a Lugia por Ho-ho o viceversa volverán a tener la vida máxima y ningún problema de estado (es decir, se "curarán"). Esto tampoco es un gran problema, si quieres guardar la salud del pokémon tendrías que guardar su vitalidad y estado en dos variables con el comando "copyvar". Pero por ejemplo en mi hack ya hay 6 pokémon errantes diferentes, si quisiera que se guardaran el estado y vit. de cada pokémon me harían falta 12 variables, y los script serían eternos. Así que no guardar el estado el errante es mucho más fácil de hacer y además tampoco supone un gran problema.
Si quieres que tus pokemon errantes aparezcan por rutas distintas, te recomiendo que uses el script que se explica al final de esta página. Así, puedes hacer que cada pokémon aparezca por rutas distintas.
¿Te ha parecido complicado? ¿No lo has entendido? ¿Se te ha ocurrido una idea pero no sabes cómo llevarla a cabo? Pues no te lo pienses y déjame un comentario, que estaré encantado de ayudarte
FIN
El humano (?)
Para terminar, me gustaría aclarar que para los que uséis FR (que sereis la mayoría) hay un pequeño cabo suelto en mi investigación. Resulta que si buscáis en la pokédex el área del pokémon errante no aparecerá. Sin embargo sí que os saldrá el área de uno de los tres perros legendarios. De momento no he podido cambiar ese pequeño gran detalle, y me temo que no puedo asegurar que consiga arreglarlo... Si sois capaces de aceptar este defecto entonces no tendréis ningún problema. Aquí unas imágenes, donde se ve que aunque el área que aparece en la pokédex es la de Raikou, si lo buscamos nos encontramos al pokémon que hemos definido con la rutina:
Y creo que nada mas... Espero haberte ayudado a hacer lo que querías en tu hack. Pero si no has conseguido lo que querías ya sabes, ¡¡coméntamelo!! Lo único que te pido a cambio es que si has seguido este tutorial me menciones en los créditos de tu hack (que aunque antes ya era chulo, ahora que has metido esto seguro que te ha quedado mejor )
Gracias a todos los que os habéis tragado este tocho Y sobre todo a esta comunidad, que aunque éste sea mi primer mensaje he aprendido todo lo que sé de RH gracias a todos los tutoriales, las preguntas y las respuestas que hacéis continuamente.
Si os queda alguna duda, o veis algún fallo, mandadme un MP o comentadlo!!
Un saludo!!!