[FR]¡ASIGNAR SCRIPTS A TECLAS!
En este tutorial os traigo un sistema para poder asignar un script a una tecla. Antes de dar la rutina para insertarla y dar las instrucciones para usarla quiero explicar como he conseguido implementar este sistema, por si alguien está interesado en ello. Aclaro que la parte de la explicación no es necesario y si solo quieres implementar el sistema o no tienes conocimientos de ASM saltatela.
Antes de nada quiero aclarar la forma que usa el juego de leer las teclas. Antes de haber mirado podría ser de dos maneras, por interrupción o por polling. Una interrupción es que cuando pulsamos una tecla se ejecuta una función especifica de la ROM. El polling o sondeo mira el estado de las teclas cada x tiempo, si no me equivoco en este caso a cada frame, y actuá en función de ello. Pues visto lo visto el sistema que se usa es el polling. Una vez que se lee el estado de las teclas se almacena ese dato en la memoria, concretamente en la I/O Registers. La estructura es la siguiente:
Es decir que en una half word se almacena el estado de las teclas, cabe destacar que una vez que se leen las teclas permanecerá así durante todo el frame. Si no hay nada pulsado el valor de la half word es 0x03FF. Si presionamos cualquier tecla su bit se pondrá a 0 mientras lo estemos pulsando.
Nuestro objetivo es detectar ese cambio de 1 a 0, entonces, a la hora de hacer la rutina tendremos que tener eso en cuenta.
Ahora queda encontrar la rutina que lea de las teclas. No me ha costado mucho encotrarla. En el debugger he puesto un break point cuando se lea de esa dirección y encontré la rutina que está en el offset 0x080005E8.
Yo he hecho un hook en 0x080005EC. Si os fijáis al hacer el hook r0 = offset del estado de las teclas. De modo que lo usaremos a nuestro favor. La rutina que he hecho es la siguiente:
Quiero aclarar primero el valor que hay que guardar en r1 antes de la and lógica. Antes he explicado que cada tecla tiene un bit asociado. A mi solo me interesa una de las teclas, independientemente de como estén las demás, por tanto tendré que aislarla. Como el bit de la tecla B es el de la posición uno (empezando de cero) debemos cargar en r1 el valor de la posición decodificado, es decir, para 2 => 10, para 5 => 10000. Es decir, dejar todos los bits a cero excepto el bit que corresponde a la posición de la tecla, que lo dejaremos a uno.
Y con esto estaría todo. Todo lo que debéis configurar para vuestro uso es el valor decodificado, las variables y el offset del script.
No os olvidéis del hook.
Código:
Bit Expl.
0 Button A (0=Pressed, 1=Released)
1 Button B (etc.)
2 Select (etc.)
3 Start (etc.)
4 Right (etc.)
5 Left (etc.)
6 Up (etc.)
7 Down (etc.)
8 Button R (etc.)
9 Button L (etc.)
10-15 Not used
Nuestro objetivo es detectar ese cambio de 1 a 0, entonces, a la hora de hacer la rutina tendremos que tener eso en cuenta.
Ahora queda encontrar la rutina que lea de las teclas. No me ha costado mucho encotrarla. En el debugger he puesto un break point cuando se lea de esa dirección y encontré la rutina que está en el offset 0x080005E8.
Yo he hecho un hook en 0x080005EC. Si os fijáis al hacer el hook r0 = offset del estado de las teclas. De modo que lo usaremos a nuestro favor. La rutina que he hecho es la siguiente:
Código:
//hook en 0x5ec
//r0 = offset de la memoria que almacena el estado de las teclas durante el frame actual
.text
.align 2
.thumb
main:
push {r0-r2}
mov r2, r0 ;salvar el contenido de r0 en r2, r0 lo necesitamos para otra cosa
ldr r0, check_var_ID ;variable que se encarga de activar el sistema
ldr r1, =(0x0806E454 +1) ;var finder
push {r2}
bl linker
pop {r2}
ldrh r0, [r0]
cmp r0, #1
bne noCrash ;salta si la variable no está en 1
ldrh r0, [r2] ;cargar en r0 el estado de las teclas
ldr r1, =(valor decodificado del bit de la tecla, se explica más adelante)
and r0, r1 ;poner el resto de bits a 0 y dejar el del boton deseado como esta
ldrb r2, position
lsr r0, r2
mov r2, r0
ldr r0, state_var_ID ;variable que guarda el estado de la tecla en el frame anterior
ldr r1, =(0x0806E454 +1)
push {r2}
bl linker
pop {r2}
ldrh r0, [r0]
cmp r2, r0
blo execute_script ;detectar flanco de bajada en la tecla (es decir, que se pulsa)
b store_state
execute_script:
push {r2}
ldr r0, =(0x08[offset del script])
bl script_routine
pop {r2}
b store_state
script_routine:
ldr r1, =(0x08069AE4 +1) ;rutina interna de la ROM que se encarga de ejecutar scripts
bx r1
store_state:
ldr r0, state_var_ID
ldr r1, =(0x0806E454 +1)
push {r2}
bl linker
pop {r2}
strh r2, [r0] ;guardar el estado actual para el próximo ciclo
b noCrash
linker:
bx r1
noCrash:
pop {r0-r2}
ldrh r1, [r0]
ldr r2, =(0x3FF)
mov r0, r2
mov r3, r0
ldr r2, =(0x080005F4 +1)
bx r2 ;volver a la rutina original
.align 2
state_var_ID: .word 0x(variable para ir guardando el estado de las teclas en el frame anterior)
check_var_ID: .word 0x(numero de la variable a usar como flag para activar el sistema)
position: .byte 0x(posicion de la tecla, se especifica en una tabla que dejaré abajo)
Y con esto estaría todo. Todo lo que debéis configurar para vuestro uso es el valor decodificado, las variables y el offset del script.
No os olvidéis del hook.
La rutina que hay que insertar es la siguiente:
Código:
07 B4 02 1C 19 48 1B 49 04 B4 00 F0 24 F8 04 BC 00 88 01 28 20 D1 10 88 17 49 08 40 14 4A D0 40 02 1C 11 48 13 49 04 B4 00 F0 15 F8 04 BC 00 88 82 42 00 D3 07 E0 04 B4 10 48 00 F0 02 F8 04 BC 01 E0 0F 49 08 47 08 48 0A 49 04 B4 00 F0 03 F8 04 BC 02 80 00 E0 08 47 07 BC 01 88 09 4A 10 1C 03 1C 09 4A 10 47 C0 46 ZZ ZZ 00 00 VV VV 00 00 QQ 00 00 00 55 E4 06 08 XX XX 00 00 YY YY YY 08 E5 9A 06 08 FF 03 00 00 F5 05 00 08
XX XX: Es la tecla que queremos detectar, hay que seguir la tabla que dejo mas abajo. Permutado
YY YY YY: offset de vuestro script permutado. NO sumar 1, repito, no suméis 1.
ZZ ZZ: Usad una variable segura y mientras el sistema esté activado NO tocar esta variable, hay que permutar la variable
VV VV: Variable para activar el sistema. Para activarla setear la var a 1, para desactivarla sirve cualquier otro valor, por buenos habitos, recomiendo setearlo a 0. Hay que permutar la variable.
Para acabar debo explicar como hacer el script que queramos ejecutar cuando pulsamos una tecla. La estructura de TODOS los scripts de este sistema es el siguiente:
Código:
#dynamic 0x800000
#org @start
setvar 0x(variable que habéis puesto en VV VV, sin permutar claro está) 0x0
…
Aquí iría todo vuestro script
…
setvar 0x(variable que habéis puesto en VV VV, sin permutar claro está) 0x1
end
Código:
#dynamic 0x800000
#org @start
…
setvar 0x( variable que habéis puesto en VV VV, sin permutar claro está) 0x1
setvar 0x( variable que habeis puesto en ZZ ZZ, sin permutar claro está) 0x1
...
Código:
#dynamic 0x800000
#org @start
…
setvar 0x( variable que habéis puesto en VV VV, sin permutar claro está) 0x1
...
Tabla para las teclas:
Código:
Botón A 0x1
Botón B 0x2
Select 0x4
Start 0x8
Derecha 0x10
Izquierda 0x20
Arriba 0x40
Abajo 0x80
Botón R 0x100
Botón L 0x200
Código:
0 Button A
1 Button B
2 Select
3 Start
4 Right
5 Left
6 Up
7 Down
8 Button R
9 Button L
La variable que hayáis usado para activar y desactivar el sistema no podéis usarla para nada más. La otra variable podéis usarla sin problema siempre que el sistema no esté activado. Recomiendo usar variables seguras, de las de 0x40FF abajo.
Créditos a @Annatar (yo vamos) por la rutina.
Y esto es todo por ahora, espero que le deis un buen uso. Ante cualquier duda preguntad sin miedo
Última edición: