Modificar PS de los Pokemon del equipo
El objetivo de este tutorial es explicar como podemos editar los Puntos de Salud de los Pokémon de nuestro equipo. Como bien sabréis Jpan hizo una rutina para cumplir este propósito. Pero su rutina no era nada practica.
Esa rutina resta un valor absoluto de PS al Pokémon seleccionado del equipo. Pero al ser un valor absoluto y al ignorar por completo los Puntos de Salud máximos del Pokemon en cuestión la rutina pierde eficacia.
La rutina que os explicaré en este tema hace lo mismo que la rutina de Jpan pero en vez de restar un valor absoluto resta un porcentaje del total de Puntos de Salud del Pokemon.
Antes de nada, si a alguien le interesa como he hecho la rutina y los pasos que he seguido dejaré en un spoiler el diario de investigación. Aclaro que no es necesario para seguir el tutorial, leedlo solo si tenéis interés (os lo recomiendo solo si tenéis un nivel aceptable de ASM).
Primero quiero aclarar los parámetros que tiene la rutina. La variable 0x8004 será la posición del Pokémon del equipo con el que trabajaremos. Por otro lado, la variable 0x8005 almacenará en porcentaje que vayamos a restarle a los PS actuales al Pokemon en cuestión.
Ahora paso a explicar como calcularemos el valor absoluto de PS a restar respecto al PS máximos. Nuestra herramienta será la clásica regla de tres.
Antes de nada quiero decir que todos los datos deberán estar en hexadecimal . Es decir, el 100 será 64 y todas esas cosas. Bien, pues para calcular x (PS a restar, valor absoluto) solo debemos multiplicar el valor de la variable 0x8005 y los PS máximos. A continuación habrá que dividir ese resultado entre 100 (64 en hex). La multiplicación es fácil, usaremos el comando mul. Pero la división la haremos usando una función de la BIOS, en este caso swi 0x6.
swi 0x6
Parámetros de entrada: r0 (numerador, el de arriba de la división) y r1 (divisor, el de abajo).
Parámetros de salida: r0 (valor sin comas del resultado) y r1 (resto, pero que nosotros ignoraremos)
Aclarado la obtención de los PS a restar paso a explicar el algoritmo a usar.
1. Cargar en un registro los PS absolutos a restar
2. Cargar los PS actuales y restarle lo obtenido en el primer paso
3. Cargar en la RAM el resultado
Ahora explicaré como se almacenan los datos de los offset que vayamos a usar.
Var_8004 y Var:8005
Simplemente son half words, no tiene más mismterio
PS y Psmax
Primero os mostraré estos offsets en la RAM, para ello usaré el comando mb del debugger (VBA-SDL-H)
En mi caso tengo un Miltank con un total de vidas de 313, que en hex es 01 39. Si permutamos estos dos bytes conseguiremos lo que hay en esa dirección de la memoria. Esto ocurre con los PS máximos y con los actuales. Por lo tanto, en la rutina habrá que cargar estos datos de una forma concreta, haciendo uso de los comandos lsl, lsr y orr.
Aclarada la forma de calcular los PS a restar y la estructura de los datos no hay más que hacer la rutina. Notese que hay una comparación la rutina. Esto debe a que en determinados casos los PS a restar e¡son más que los actuales, por lo tanto, al hacer la resta ya no nos funcionará la rutina. Por eso, comparamos si los PS a restar son más que los acutales, y en caso afirmativo saltaremos a la etiqueta not, donde simplemente en los PS actuales pondrémon 00 00. Aquí dejo la rutina explicada:
Mirad la rutina las veces que haga falta y entenderéis como lo he hecho.
Ahora paso a explicar como calcularemos el valor absoluto de PS a restar respecto al PS máximos. Nuestra herramienta será la clásica regla de tres.
Antes de nada quiero decir que todos los datos deberán estar en hexadecimal . Es decir, el 100 será 64 y todas esas cosas. Bien, pues para calcular x (PS a restar, valor absoluto) solo debemos multiplicar el valor de la variable 0x8005 y los PS máximos. A continuación habrá que dividir ese resultado entre 100 (64 en hex). La multiplicación es fácil, usaremos el comando mul. Pero la división la haremos usando una función de la BIOS, en este caso swi 0x6.
swi 0x6
Parámetros de entrada: r0 (numerador, el de arriba de la división) y r1 (divisor, el de abajo).
Parámetros de salida: r0 (valor sin comas del resultado) y r1 (resto, pero que nosotros ignoraremos)
Aclarado la obtención de los PS a restar paso a explicar el algoritmo a usar.
1. Cargar en un registro los PS absolutos a restar
2. Cargar los PS actuales y restarle lo obtenido en el primer paso
3. Cargar en la RAM el resultado
Ahora explicaré como se almacenan los datos de los offset que vayamos a usar.
Var_8004 y Var:8005
Simplemente son half words, no tiene más mismterio
PS y Psmax
Primero os mostraré estos offsets en la RAM, para ello usaré el comando mb del debugger (VBA-SDL-H)
En mi caso tengo un Miltank con un total de vidas de 313, que en hex es 01 39. Si permutamos estos dos bytes conseguiremos lo que hay en esa dirección de la memoria. Esto ocurre con los PS máximos y con los actuales. Por lo tanto, en la rutina habrá que cargar estos datos de una forma concreta, haciendo uso de los comandos lsl, lsr y orr.
Aclarada la forma de calcular los PS a restar y la estructura de los datos no hay más que hacer la rutina. Notese que hay una comparación la rutina. Esto debe a que en determinados casos los PS a restar e¡son más que los actuales, por lo tanto, al hacer la resta ya no nos funcionará la rutina. Por eso, comparamos si los PS a restar son más que los acutales, y en caso afirmativo saltaremos a la etiqueta not, donde simplemente en los PS actuales pondrémon 00 00. Aquí dejo la rutina explicada:
Código:
.text
.align 2
.thumb
main:
push {r0-r3, lr}
ldr r0, var_8004
ldrh r0, [r0]
mov r1, #0x64
mul r0, r0, r1
ldr r1, PSmax
add r0, r0, r1 @cargamos el offset de los PS maximos del Pokemon en r0
mov r1, r0 @hacemos un backup del offset, para ahorrar lines mas tarde
add r0, r0, #0x1
ldrb r0, [r0]
lsl r0, r0, #0x8
ldrb r1, [r1]
orr r0, r0, r1 @r0 = PS máximos
ldr r1, var_8005
ldrh r1, [r1]
mul r0, r0, r1
mov r1, #0x64
swi 0x6 @una vez ejecutado nos devolverá en r0 el valor de los PS a restar
ldr r1, var_8004
ldrh r1, [r1]
mov r2, #0x64
mul r1, r1, r2
ldr r2, PS
add r1, r1, r2 @cargamos el offset de los PS actuales
mov r2, r1
mov r3, r1
add r1, r1, #0x1
ldrb r1, [r1]
lsl r1, r1, #0x8
ldrb r2, [r2]
orr r1, r1, r2 @r1 =PS actuales
cmp r0, r1 @lo dicho antes, nos aseguramos que la resta será positiva, de lo contrario saltamos not
bhi not
sub r1, r1, r0
mov r0, r1
lsl r0, r0, #0x18
lsr r0, r0, #0x18
mov r2, r3
strb r0, [r2] @guardar un byte del PS nuevos
mov r0, r1
lsl r0, r0, #0x10
lsr r0, r0, #0x18
add r2, r2, #0x1
strb r0, [r2] @guardar el otro byte, aquí ya está completa la acción
b end
not:
mov r0, #0x0
strh r0, [r3] @guardar un cero el los PS nuevos
end:
pop {r0-r3, pc}
.align 2
var_8004: .word 0x020370C0
var_8005: .word 0x020370C2
PS: .word 0x020242DA
PSmax: .word 0x020242DC
La rutina para Fire Red es esta:
Código:
.text
.align 2
.thumb
main:
push {r0-r3, lr}
ldr r0, var_8004
ldrh r0, [r0]
mov r1, #0x64
mul r0, r0, r1
ldr r1, PSmax
add r0, r0, r1
mov r1, r0
add r0, r0, #0x1
ldrb r0, [r0]
lsl r0, r0, #0x8
ldrb r1, [r1]
orr r0, r0, r1
ldr r1, var_8005
ldrh r1, [r1]
mul r0, r0, r1
mov r1, #0x64
swi 0x6
ldr r1, var_8004
ldrh r1, [r1]
mov r2, #0x64
mul r1, r1, r2
ldr r2, PS
add r1, r1, r2
mov r2, r1
mov r3, r1
add r1, r1, #0x1
ldrb r1, [r1]
lsl r1, r1, #0x8
ldrb r2, [r2]
orr r1, r1, r2
cmp r0, r1
bhi not
sub r1, r1, r0
mov r0, r1
lsl r0, r0, #0x18
lsr r0, r0, #0x18
mov r2, r3
strb r0, [r2]
mov r0, r1
lsl r0, r0, #0x10
lsr r0, r0, #0x18
add r2, r2, #0x1
strb r0, [r2]
b end
not:
mov r0, #0x0
strh r0, [r3]
end:
pop {r0-r3, pc}
.align 2
var_8004: .word 0x020370C0
var_8005: .word 0x020370C2
PS: .word 0x020242DA
PSmax: .word 0x020242DC
Y aquí está la rutina compilada:
Código:
0F B5 17 48 00 88 64 21 48 43 18 49 40 18 01 1C 01 30 00 78 00 02 09 78 08 43 12 49 09 88 48 43 64 21 06 DF 0E 49 09 88 64 22 51 43 0E 4A 89 18 0A 1C 0B 1C 01 31 09 78 09 02 12 78 11 43 88 42 0B D8 09 1A 08 1C 00 06 00 0E 1A 1C 10 70 08 1C 00 04 00 0E 01 32 10 70 01 E0 00 20 18 80 0F BD C0 70 03 02 C2 70 03 02 DA 42 02 02 DC 42 02 02
Os pondré un script de ejemplo:Parámetros de la rutina:
Variable 0x8004: Posición del Pokémon a editar sus PS (recordar que el primero Pokemon tendrá la posición 0, y así sucesivamente)
Variable 0x8005: Porcentaje (en hexadecimal) a restar respecto a los PS máximos
Código:
#dynamic 0x800000
#org @start
lock
faceplayer
setvar 0x8004 0x2
setvar 0x8005 0x32
callasm 0x800001
release
end
Si quieres hacer esto para todo el equipo usad un loop dentro del script o repetid el callasm para cada uno de los integrantes del equipo.
Créditos @Heavy Metal Kaktus por la rutina.
Quiero agradecer a @Cheve_X su tutorial de ASM desde donde saque los offsets y a @Kate, AliKate por responder mis innumerables dudas.
Espero que os haya gustado el tutorial, y si tenéis cualquier duda o cualquier cosa que decir no dudeis en comentar