Registrarse

[RH - ASM] Clase 2

Estado
Cerrado para nuevas respuestas.

MetalKaktus

A la luz del quinto día, mira al este
Miembro insignia
Clase 2​

En la clase de hoy empezaremos a hacer nuestras propias rutinas, y como no podía ser de otro modo empezaremos con el concurso para ver quien es el mejor alumno. Sobre el contenido de la clase daremos las siguientes cosas.

  • Sintaxis principal de la rutina
  • Cargar y almacenar datos mediante registros
  • Operaciones matemáticas básicas con registros

Antes de nada, como procederemos a hacer una rutina necesitaréis un compilador. En el siguiente enlace os dejaré un archivo que entre otras cosas contiene un compilador, por ahora, centraos en el compilador solo.

Sintaxis principal de la rutina

No sabía muy bien como llamar a este apartado, creo que os abréis dado cuenta al ver el título tan cutre que he puesto, pero simplemente quiero explicar las cosas que se ponen en todas las rutinas. Cabe destacar que para hacer las propias rutinas usaré un editor de textos, como el Notepad que viene de serie con Windows.

Por lo tanto, primero abrimos el editor de texto, tal que así:


Y ahora empieza la rutina. Lo primero que pondremos siempre (siempre) será lo siguente:

Código:
.text
.align 2
.thumb

main:
Como he puesto main podéis poner lo que os salga de ahí, siempre y cuando sea una palabra. No voy a pararme a explicar en profundidad que significa cada cosa, pues no es algo relevante a la hora de hacer las rutinas.

Con esto ya podemos empezar con la rutina!

Cargar y almacenar datos mediante registros

En el ASM el objetivo principal es mediante unos datos iniciales editar cierta parte de la RAM, a grandes rasgos vamos. Por lo tanto, primero necesitaremos cargar nuestros datos de inicio. ¿Dónde los cargamos? Sencillo, en los registros. Si no te acuerdas de lo que es un registro vuelve a la clase anterior.

Los comandos para cumplir esto son ldr, ldrb y ldrh

Cada uno de estos comandos se puede usar de dos formas posibles. La primera para cargar un offset en un registro. La segunda, para cargar los valores que haya en los offsets antes mencionados.

Pero antes de nada, la diferencia entre todos ellos radica en la capacidad de cargar valores en los registros. Es decir, el ldr es capaz de cargar una word (cuatro bytes) en un registro desde un offset. El ldrb puede cargar un byte desde un offset y el ldrh hace lo mismo pero con dos bytes (half word).

Para aclarar esto, un ejemplo. Imaginad que queremos cargar en r0 el valor de la variable 0x800D, más conocida como LASTRESULT.

Lo primero es hacer una equivalencia entre el offset y una palabra que vosotros queráis. Es decir, como normalmente los offsets se usan más de una vez, es más cómodos darle un nombre y usarlo, habiendo definido que offset corresponde a esa palabra:

Código:
.text
.align 2
.thumb

main:




.align 2
	lastresult:	.word 0x20370D0
Como veis, simplemente después de un .align 2 (pura sintaxis, solo ponedlo y despreocupaos por ello) hay que poner el nombre que eligamos y después con ese patrón el offset. Y aquí quiero hacer un pequeño paréntesis.

Algunos os preguntaréis que diablos querrá decir el offset que yo he puesto. Porque al principio he dicho que usaré la variable 0x800D. Pues bien, los valores de las variables se almacenan en distintos offsets de la memoria RAM (de ahí el prefijo 2, si fuera un offset de la ROM sería 8, esto os lo recordaré más adelante).

Y el offset en el que se almacena el valor de la variables 0x800D es precisamente 20370D0. Por ejemplo, estos son los offsets de otras variables.

0x20370B8 0x8000
0x20370BA 0x8001
0x20370BC 0x8002
0x20370BE 0x8003
(al final del post os podré una lista de offsets de la RAM)

Ahora vamos a cargar el offset correspondiente a lastresult en r0:

Código:
.text
.align 2
.thumb

main:

	push {r0, lr}
	ldr r0, lastresult


.align 2
	lastresult:	.word 0x20370D0

Este es un comando que lo podremos en el 99 por cada 100 casos. Se trata de hacer un backup de los valores que tenían los registros seleccionados para que podamos usarlos sin perder los anteriores datos. Esto se guarda en un stack (mirar clase anterior si no sabéis que es) y el funcionamiento del comando es el siguiente.

Push {r0-rX, lr}
Es decir, empujaremos a la pila los valores de los registros r0, r1, r2... hasta rX incluido. Además del registro link register (simplemente hay que ponerlo, no tiene más misterio). Por ejemplo, si en mi rutina voy a usar dos registros al principio tendré que poner lo siguiente:

Código:
.text
.align 2
.thumb

main:

	push {r0-r1, lr}
Si voy a usar tres registros:

Código:
.text
.align 2
.thumb

main:

	push {r0-r2, lr}
Otra forma de usar el push es seleccionar uno a uno cada uno de los registros a usar (es absurdo pero lo explicaré igual. Imaginad que quiero usar r0, r2 y r6. Pues el push será así:

Código:
.text
.align 2
.thumb

main:

	push {r0, r2, r6, lr}
Pero vamos, el primer método es el útil, esto no tiene mucho sentido, al darnos igual que registro usar.

Lo siguiente será cargar el valor de la variable 0x800D en un registro, para ello continuaremos así:

Código:
.text
.align 2
.thumb

main:

	push {r0, lr}
	ldr r0, lastresult
	ldrh r0, [r0]


.align 2
	lastresult:	.word 0x20370D0
Lo primero, como el valor de una variable son dos bytes (un half word) usaré el comando ldrh. En caso que queramos cargar un byte de un offset pues usaremos ldrb.

Bien, usado de esta forma el ldr (o ldrh o ldrb) lo que hará será cargar en el registro primero indicado una word, half word o byte (depende del comando usado) del offset contenido por el registro entre corchetes. Así de simple. En este caso, para ahorrarme registros sobrescribiré el offset del r0 por el valor de la variables, al ser inútil la anterior información (por ahora...)

Si en vez de querer cargar datos de un offset de un registro quiero hacerlo, por ejemplo, de cuatro bytes más adelante, simplemente haré esto:

Código:
.text
.align 2
.thumb

main:

	push {r0, lr}
	ldr r0, lastresult
	ldrh r0, [r0, #0x4]


.align 2
	lastresult:	.word 0x20370D0
Y así se usan estos comandos.

Para guardar datos en determinados offset de la RAM se usarán los comandos str, strb y strh. Tiene un único uso y es el siguiente:

Guarda el word almacenado en el registro r0 en el offset almacenado en el registro r1. Si se usa strb se cogerá el byte de r0, con strh el half word. Como en el caso del ldr aquí también podemos seleccionar un offset de más adelante:

str r0, [r1, #0xC]
Para entender esto vamos con un ejemplo. Lo que haré será simular el comando copyvar del XSE, que copia el valor de una variable en otra. En este caso copiaré el valor de 0x800D en 0x8000.


Lo primero, la sintaxis y declarar los offsets:

Código:
.text
.align 2
.thumb

main:




.align 2
	lastresult:	.word 0x20370D0
	varnumber_8000:	.word 0x20370B8
Ahora viene el push:

Código:
.text
.align 2
.thumb

main:
	push {r0, lr}


.align 2
	lastresult:	.word 0x20370D0
	varnumber_8000:	.word 0x20370B8
A continuación cargaremos el valor de lastresult en r0:

Código:
.text
.align 2
.thumb

main:
	push {r0, lr}
	ldr r0, lastresult
	ldrh r0, [r0]

.align 2
	lastresult:	.word 0x20370D0
	varnumber_8000:	.word 0x20370B8
Ahora necesitamos cargar el offset de la varialbe 0x8000. Pero como en r0 tenemos el valor de la otra varialbe habrá que usar otro registro, pues editamos el comando push y añadimos otro ldr:

Código:
.text
.align 2
.thumb

main:
	push {r0-r1, lr}
	ldr r0, lastresult
	ldrh r0, [r0]
	ldr r1, varnumber_8000

.align 2
	lastresult:	.word 0x20370D0
	varnumber_8000:	.word 0x20370B8
Ahora cargaremos el valor de r0 en el offset dado por r1. Para ello usaremos el fantastico comando str:

Código:
.text
.align 2
.thumb

main:
	push {r0-r1, lr}
	ldr r0, lastresult
	ldrh r0, [r0]
	ldr r1, varnumber_8000
	strh r0, [r1]

.align 2
	lastresult:	.word 0x20370D0
	varnumber_8000:	.word 0x20370B8
Y ya está, el valor de 0x800D ha sido copiado en 0x8000. Pero espera, falta un comando, el pop.

Al usar un push y empujar los valores de los registros, después de la rutina necesitamos devolver sus valores originales a los registros. Para eso existe el comando pop. Sabed que necesitamos usar pop con todos los registro a los que hayamos usado push. Su sintaxís es exactamente igual al push.

Por lo tanto, la rutina queda así:

Código:
.text
.align 2
.thumb

main:
	push {r0-r1, lr}
	ldr r0, lastresult
	ldrh r0, [r0]
	ldr r1, varnumber_8000
	strh r0, [r1]
	pop {r0-r1, pc}

.align 2
	lastresult:	.word 0x20370D0
	varnumber_8000:	.word 0x20370B8
Bueno, en vez de lr se pone pc, simplemente ponedlo.

Se que esta parte de la clase ha sido un infierno, pero necesito que los comandos push, pop, ldr y str (y sus derivados) sean entendidos al cien por cien. Y si han quedado dudas, preguntad porque esto es muy muy muy importante. De verdad, preguntad sin miedo (en serio).

Operaciones matemáticas básicas con registros

Esta parte de la clase no es especialmente pesada ni difícil, simplemente os enseñaré a hacer operaciones entre registro. A si que... pues empezamos con el primero.

mov

No es una operación por si misma, pero es un comando importante y hay que aprenderlo. Lo que hace es mover un byte a un registro, es decir, un valor ente 0x00 y 0xFF ambos incluidos. Con el siguiente ejemplo veréis como se usa.

Es decir, definís el registro de destino y el byte que queráis.

add

Suma el valor de dos registros o el valor de un registro con un byte (de ahora en adelante conocidos como valores inmediatos). Un ejemplo,

Guarda en el primero registro el valor de la suma de los valores que contienen los otros dos registro. En este caso, r0 + r1 => r0

add r0, r0, #0x3
Guarda en el primer registro la suma del valor del siguiente registro y el valor inmediato que hayáis definido. En este caso, r0 + #0x3 => r0

sub

Resta el valor de un registro al valor de otro registro o resta al valor de un registro un valor inmediato. For example,

Guarda en el primero registro el valor de la resta de los valores que contienen los otros dos registro. En este caso, r0 - r1 => r0

sub r0, r0, #0x3
Guarda en el primer registro la resta del valor del siguiente registro y el valor inmediato que hayáis definido. En este caso, r0 - #0x3 => r0

mul

Multiplica el valor de dos registros y los guarda en un registro (notese que se puede elevar un valor en dos si los dos registros a multiplicar son el mismo).

Guarda en r0 en resultado de la multiplicación de los valores de r0 y r1.

Para hacer el valor de un registro al cuadrado:

Bueno, por hay suficiente, me he pasado lo sé, pero eh, aquí venimos aprender. La cosa es que hoy ya toca tarea. No os voy a poner ninguna, que cada uno haga una rutina y que lo postee en este post, que me lo mande por perfil o por MP (como queráis).

Cabe decir que cada rutina tendrá que estar explicada. Y cada offset que uséis decid cual es, que no soy adivino (por ahora).

Os pongo una lista de offset de la RAM a ver si se os ocurre algo. Aunque con estos conocimientos no os aconsejo ir más lejos de las variables.

Map of FireRed's RAM
0x02002D40 ? Start of data that apparently controls
the colors of the pixels inside of the
current box (menu, msgbox, etc.).

0x020204B4 12b Dialog box 1
0x020204C0 12b Dialog box 2
0x020204CC 12b Dialog box 3
0x020204D8 12b Dialog box 4
0x020204E4 12b Dialog box 5
0x020204F0 12b Dialog box 6
0x020204FC 12b Dialog box 7
0x02020508 12b Dialog box 8
0x02020514 12b Dialog box 9
0x02020520 12b Dialog box 10
0x0202052C 12b Dialog box 11
0x02020538 12b Dialog box 12
0x02020544 12b Dialog box 13
0x02020550 12b Dialog box 14
0x0202055C 12b Dialog box 15
0x02020568 12b Dialog box 16
0x02020574 12b Dialog box 17
0x02020580 12b Dialog box 18
0x0202058C 12b Dialog box 19
0x02020598 12b Dialog box 20
0x020205A4 12b Dialog box 21
0x020205B0 12b Dialog box 22
0x020205BC 12b Dialog box 23
0x020205C8 12b Dialog box 24
0x020205D4 12b Dialog box 25
0x020205E0 12b Dialog box 26
0x020205EC 12b Dialog box 27
0x020205F8 12b Dialog box 28
0x02020604 12b Dialog box 29
0x02020610 12b Dialog box 30
0x0202061C 12b Dialog box 31
0x02020628 12b Dialog box 32

0x02021CD0 32b String buffer 0
0x02021CF0 20b String buffer 1
0x02021D04 20b String buffer 2
0x02021D18 ? String to be displayed in a message box

0x02022B4B 1b Flags for current battle?
0x02022B4C 4b Flags for current battle? Set to 0x8 by repeattrainerbattle.

0x02023E8A 1b Repeattrainerbattle: Unknown. Loaded if battle type is 9.

0x02024029 1b Repeattrainerbattle: Unknown. Loaded if battle type is 9.

0x0202402C 100b Enemy Pokemon 1
0x02024090 100b Enemy Pokemon 2
0x020240F4 100b Enemy Pokemon 3
0x02024158 100b Enemy Pokemon 4
0x020241BC 100b Enemy Pokemon 5
0x02024220 100b Enemy Pokemon 6
0x02024284 100b Party Pokemon 1
0x020242E8 100b Party Pokemon 2
0x0202434C 100b Party Pokemon 3
0x020243B0 100b Party Pokemon 4
0x02024414 100b Party Pokemon 5
0x02024478 100b Party Pokemon 6

0x02031DB4 1b Previous map bank number
0x02031DB5 1b Previous map number
0x02031DB6 1b Warp through which the player entered the current map?
0x02031DB7 1b Padding?
0x02031DB8 2b X where player entered previous map, or 0xFFFF if unused.
(Only seems to be used when the warp was a door.)
0x02031DBA 2b Y where player entered previous map, or 0xFFFF if unused.
(Only seems to be used when the warp was a door.)
0x02031DBC 1b Current map bank number
0x02031DBD 1b Current map number
0x02031DBE 1b Warp through which the player entered the current map?
0x02031DBF 1b Padding?
0x02031DC0 2b X where player entered current map, or 0xFFFF if unused.
(Only seems to be used when the warp was a door.)
0x02031DC2 2b Y where player entered current map, or 0xFFFF if unused.
(Only seems to be used when the warp was a door.)
0x02031DC3 1b Padding?
0x02031DC4 1b Current2 map bank number
0x02031DC5 1b Current2 map number
0x02031DC6 1b Warp through which the player entered the current2 map?
0x02031DC7 1b Padding?
0x02031DC8 2b X where player entered current2 map, or 0xFFFF if unused.
(Only seems to be used when the warp was a door.)
0x02031DCA 2b Y where player entered current2 map, or 0xFFFF if unused.
(Only seems to be used when the warp was a door.)
0x02031DCC 1b Current3 map bank number
0x02031DCD 1b Current3 map number
0x02031DCE 1b Warp through which the player entered the current3 map?
0x02031DCF 1b Padding?
0x02031DD0 2b X where player entered current3 map, or 0xFFFF if unused.
(Only seems to be used when the warp was a door.)
0x02031DD2 2b Y where player entered current3 map, or 0xFFFF if unused.
(Only seems to be used when the warp was a door.)
0x02031DD4 3b? Warping: Unknown. Always set to 01 01 00 when "warp" and
"warpmuted" finish, but not when "warp3" finishes. While
walking into a door warp, the second byte is 02.
0x02031DD7 1b Warping: Unknown. Seems to always be 0x03.
0x02031DD8 1b Warping: Unknown. If non-zero, "warp" fails to play a
sound.

0x02031DDA 2b? Unknown. Changes every time you warp.

0x02036E38 36b OW 00 (player)
0x02036E5C 36b OW 01
0x02036E80 36b OW 02
0x02036EA4 36b OW 03
0x02036EC8 36b OW 04
0x02036EEC 36b OW 05
0x02036F10 36b OW 06
0x02036F34 36b OW 07
0x02036F58 36b OW 08
0x02036F7C 36b OW 09
0x02036FA0 36b OW 10
0x02036FC4 36b OW 11
0x02036FE8 36b OW 12
0x0203700C 36b OW 13
0x02037030 36b OW 14
0x02037054 36b OW 15

0x02037078 1b Three least-significant bits control player speed.
0x02037079 1b Something to do with switching into biking OW?
0x0203707A 1b Is a D-pad button pressed (player attempting to move)?
0x0203707B 1b Is the player actually moving?
0x0203707C 1b Unknown.
0x0203707D 1b Person number to be controlled by the D-pad.
0x0203707E 1b If set to 0x01, all OW movement is locked. (lockall flag?)

0x020370B8 2b Script variable 0x8000
0x020370BA 2b Script variable 0x8001
0x020370BC 2b Script variable 0x8002
0x020370BE 2b Script variable 0x8003
0x020370C0 2b Script variable 0x8004
0x020370C2 2b Script variable 0x8005
0x020370C4 2b Script variable 0x8006
0x020370C6 2b Script variable 0x8007
0x020370C8 2b Script variable 0x8008
0x020370CA 2b Script variable 0x8009
0x020370CC 2b Script variable 0x800A
0x020370CE 2b Script variable 0x800B
0x020370D0 2b Script variable 0x800D // there is no var 0x800C?
0x020370D2 2b Script variable 0x800E // overwritten by "trainerbattle"?
0x020370D4 2b Script variable 0x800F

0x020386AC 2b Trainerbattle: Battle type.
0x020386AE 2b Trainerbattle: Trainer flag.
0x020386B0 2b Trainerbattle: Argument 3.
Some battle types save it into var 0x800E.
0x020386B2 2b Unknown.
0x020386B4 4b Trainerbattle: Arg4 (types 1, 2, 4, 6, 7, 8) or null (others).
0x020386B8 4b Trainerbattle: A4 (0, 3, 5), A5 (1, 2, 4, 6, 7, 8, 9), or null.
0x020386BC 4b Trainerbattle: Argument 5 (type 9) or null (others).
0x020386C0 4b Trainerbattle: Argument 6 (types 6, 8) or null (others).
0x020386C4 4b Trainerbattle: Offset of next script command byte.
0x020386C8 4b Trainerbattle: A6 (types 1, 2), A7 (types 6, 8), or null.
0x020386CC 2b Trainerbattle: Unknown.

0x0203AAA8 4b Unknown. Written to by the "setbyte" command.

0x0203ADFA 1b Unknown.
If equal to 0x2, "warp" fails to play a sound.
If lower than 0x04, "setworldmapflag" fails to set
the specified flag.
If equal to 1, trainerbattle types 5 and 7 will
clear this byte and then some sections of RAM.

0x0203ADFC 4b Unknown. A pointer used by trainerbattle types 5 and 7.

0x0203AE04 4b? Unknown. Cleared by "trainerbattle" (types 5, 7) if the byte
at 0x0203ADFA is 0x01.
0x0203AE08 4b? Unknown. Used and cleared by "trainerbattle" (types 5, 7)
if the byte at 0x0203ADFA is 0x01.

0x0203AE8C 4b? Unknown. Cleared by "trainerbattle" (types 5, 7) if the byte
at 0x0203ADFA is 0x01.

0x0203AE98 ? Unknown.

0x0203AF98 ? Unknown. A pointer used by trainerbattle types 5 and 7.

0x0203B01E 2b Unknown. Read by a reused ASM routine in script commands'
code.

0x0203B0EE 1b Help: Player's opened it before? Y / N, 0x00 / 0x01.

0x0203B1A0 14291b Help: unknown. // to 0x0203E973
0x0203E973 2050b Help: unknown. Cleared only when opening help for the 1st
time. // to 0x0203F175
0x0203F176 1b Help: start of GUI state data.

0x0203F194 1b Help: number of menu options.
0x0203F195 1b Help: Unknown.
0x0203F196 1b Help: number of menu options visible on-screen.

0x0203F199 1b Help: Unknown. Apparently 0x04 for top-level menu or 0x15
for submenus.

0x0203F19C 1b Help: scroll position in a menu.
0x0203F19D 1b Help: cursor position in a menu (relative to scroll).
0x0203F19E 1b Help: unknown. Apparently 0x00 for top-level menu, 0x03
for submenus, and 0x06 for static pages.

0x0203F1AC ?b Help: start of menu data. String pointer (not aligned),
followed by menu item number. List is terminated with
0xFEFFFFFF

0x0203E000 4096b Unused RAM found by JPAN (is used by D/N patch)

0x0203F3C0 1856b RAM used in JPAN's Hacked Engine.

0x03000EA8 1b Unknown. Set by (defunct?) "choosecontestpkmn" command, and
also set to 0x1 by "repeattrainerbattle".

0x03000EB0 74b Script engine RAM

0x03000F9C 1b 0x01 if the screen is fading, 0x00 otherwise.

0x03000FC0 4b Music for the current map (truncated to 2b when read)
0x03000FC4 1b Warping: Unknown.

0x03005000 4b Current PRNG seed

0x03005008 4b Pointer to a DMA-protected save block (map data)
0x0300500C 4b Pointer to a DMA-protected save block (personal data)
0x03005010 4b Pointer to a DMA-protected save block (box data)

0x03005074 1b Trainerbattle: number of the OW we are battling, or 0x10 if
invalid. This offset is used by special 13A, which in turn
is called by some of the scripts (yes, scripts) that
trainerbattle calls.

0x03005E88 1b? Unknown. Cleared by "trainerbattle" (types 5, 7) if the byte
at 0x0203ADFA is 0x01.

0x03007324 2b Warping: Unknown. Related to the fade timer.
0x03007326 2b Warping: Unknown. Related to the fade timer.
0x03007328 2b Warping: Timer used for fades. Duration varies with type
of map being entered.
-----------------------------------------------
[0x03005008] + 0x0000 2b Camera X-position
[0x03005008] + 0x0002 2b Camera Y-position
[0x03005008] + 0x0004 1b Current map.
[0x03005008] + 0x0005 1b Current map bank.

-------------------------------------------------------------------------
Map of DMA-protected RAM:

[0x0300500C] + 0x0000 8b Character name including terminator, padded to end with 0xFFs
[0x0300500C] + 0x0008 1b Gender (00/01 m/f)
[0x0300500C] + 0x0009 1b Unknown
[0x0300500C] + 0x000A 2b Trainer ID
[0x0300500C] + 0x000C 2b Secret ID (halfword)
[0x0300500C] + 0x000E 2b Playtime (hours)
[0x0300500C] + 0x0010 1b Playtime (minutes)
[0x0300500C] + 0x0011 1b Playtime (seconds)
[0x0300500C] + 0x0012 1b Playtime (frames)
[0x0300500C] + 0x0013 1b Unknown
[0x0300500C] + 0x0014 2b Options // this and above thanks to hackmew's asm tut pt. 1
...
[0x0300500C] + 0x001A 1b If 0xDA, then National Dex is enabled.
...
[0x0300500C] + 0x0F20 4b Unknown (encryption key for hidden vars)
[0x0300500C] + 0x0F24 End (byte after)

Créditos a Missingyep Pokecommunity por la lista de los offsets

Si queréis testear vuestras rutinas compiladlas (explicado en la primera clase) con el compilador que os he dejado y valeos del scripting para ver sus resultados. Las rutinas deberán ser entregadas como muy tarde (se agradece antes) el próximo miércoles día 12 de Septiembre.

 

Asmodeo Leviatan

¿La Iglesia inventó el Infierno? O es lo contrario
la eh leído hasta la parte de push, y esta shido todo, profe, hay alguna manera de que se pueda desactivar algo del juego y activarlo mediante un scrip?

Me explico, algo como desactivar la trainer card o el boton de salvar, algo como la mochila o el menu?

me gusta la tarea, ya no tendre que pedir que me ayuden a hacer la rutina XD :( saludos!
 

White

--------------------------------------------------
Me ha costado entender la clase y aun no se si lo he entendido todo bien porque estoy hecho un lió.
He visto que necesito A-Map y XSE para hacer los scripts que llamen a las rutinas.
He seguido los pasos de varios tutoriales de Wah para insertar un script pero no se si no lo hago bien y por eso no funciona, o es que la rutina esta mal escrita.

Código:
.text
.align 2
.thumb

main:
	push {r0, lr}
	ldr r0, menu
	ldrb r0, [r0]
	sub r0, r0, r0
	pop {r0, pc}


.align 2
	menu:	.word 0x0203F194
Mi intención era hacer que el valor de las opciones del menu fuese 0 por lo que no se podría interactuar con el.



Lo he asignado a un NPC con este script:

Código:
'---------------
#org 0x800007
callasm 0x4656F1
release
end
Pero no ocurre nada.


Supongo que no he entendido bien la clase y el "sub r0, r0, r0" no va ahí o he compilado algo mal.

Voy a releer ambas clases para entenderlo mejor y por si me he saltado algo. Porque no he entendido casi nada '^^
 

MetalKaktus

A la luz del quinto día, mira al este
Miembro insignia
Re: Respuesta: Clase 2

Me ha costado entender la clase y aun no se si lo he entendido todo bien porque estoy hecho un lió.
He visto que necesito A-Map y XSE para hacer los scripts que llamen a las rutinas.
He seguido los pasos de varios tutoriales de Wah para insertar un script pero no se si no lo hago bien y por eso no funciona, o es que la rutina esta mal escrita.

Código:
.text
.align 2
.thumb

main:
	push {r0, lr}
	ldr r0, menu
	ldrb r0, [r0]
	sub r0, r0, r0
	pop {r0, pc}


.align 2
	menu:	.word 0x0203F194
Mi intención era hacer que el valor de las opciones del menu fuese 0 por lo que no se podría interactuar con el.



Lo he asignado a un NPC con este script:

Código:
'---------------
#org 0x800007
callasm 0x4656F1
release
end
Pero no ocurre nada.


Supongo que no he entendido bien la clase y el "sub r0, r0, r0" no va ahí o he compilado algo mal.

Voy a releer ambas clases para entenderlo mejor y por si me he saltado algo. Porque no he entendido casi nada '^^
A ver, simplemente en la rutina has cargado en r0 el valor de un offset en concreto. Pero a ver, así solo lo cargas. Lo que tienes que hacer es guardar el byte en dicho offset. Es decir,

Código:
.text
.align 2
.thumb

main:
     push {r0-rX, lr}
     ldr r0, menu
     mov r1, #0x0
     strb r1, [r0]
     pop {r0-r1, pc}

.align 2
     menu:    .word 0x0203F194
De este modo coges el valor 0 y lo guardas en dicha dirección, sin importar lo que ahí había antes.

Tu método, aunque absurdo, no era malo. Sólo te faltaba el strb, en r0 tendrás un 0, como bien has hecho, y en r1 la dirección.

Y el script está bien (offset + 1) recuerda. E insertarlo en un espacio vacío.

Dime si te funciona.
 

MetalKaktus

A la luz del quinto día, mira al este
Miembro insignia
Re: Respuesta: Clase 2

la eh leído hasta la parte de push, y esta shido todo, profe, hay alguna manera de que se pueda desactivar algo del juego y activarlo mediante un scrip?

Me explico, algo como desactivar la trainer card o el boton de salvar, algo como la mochila o el menu?

me gusta la tarea, ya no tendre que pedir que me ayuden a hacer la rutina XD :( saludos!
A ver, lo que entiendo es que quieres activar o desactivar algo usando ASM. Pues prácticamente es el mismo procedimiento que he explicado a @White, simplemente tienes que mover a un registro el valor deseado y en otro registro cargas el offset, luego lo guardas.

Si no lo entiendes dime un ejemplo y te pongo la rutina.
 

CompuMax

Discord: CompuMax#0425
Miembro insignia
La verdad es que anhelaba una escuela de ASM prácticamente desde que me registré en el foro y me pareció genial la idea, por eso me apunté. Pero veo que muchas cosas se están tirando en el post así como así y no se le da la importancia que debería, no sé si es porque no les parece importante, que desconocen sus funciones o es que lo van a desarrollar luego y voy a pasar a desglosar algunas de ellas haciendo citas de las mismas:

Y ahora empieza la rutina. Lo primero que pondremos siempre (siempre) será lo siguente:

Código:
.text
.align 2
.thumb

main:
Como he puesto main podéis poner lo que os salga de ahí, siempre y cuando sea una palabra. No voy a pararme a explicar en profundidad que significa cada cosa, pues no es algo relevante a la hora de hacer las rutinas.


Y ahora explico desde mi punto de vista por qué sí es relevante saber que es cada cosa a la hora de hacer una rutina (y si estoy equivocado acepto perfectamente las correcciones)

.text La verdad no sé para que sirve y de hecho no lo usó en mis rutinas hoy en día y se compilan sin problemas
.align 2 Le indica al compilador la alineación de bytes del código. En este caso le dice que todos los datos deben estar en bytes pares de 2 en 2. Si por casualidad los datos terminan en un byte impar, éste completa el código con un par de ceros para mantener la alineación
.thumb Indica el modo en que está escrita la rutina por lo que también podría ser .asm otra forma de verlo es la manera de decirle al compilador que opcodes va a usar, en el caso del modo THUMB están codificados a 2 bytes y en el caso de ASM a 4 bytes y sí, podemos compilar rutinas ASM también, no solamente rutinas en modo THUMB
main: No sólo es el inicio de la rutina, sino que es una label o etiqueta a la cual se puede acceder en cualquier momento con un simple branch a dicha etiqueta. También cabe destacar que si no se va a hacer uso de la etiqueta, no es estrictamente necesaria, aunque podría usarse para identificar las distintas etapas del código de manera organizacional

Lo primero es hacer una equivalencia entre el offset y una palabra que vosotros queráis. Es decir, como normalmente los offsets se usan más de una vez, es más cómodos darle un nombre y usarlo, habiendo definido que offset corresponde a esa palabra:

Código:
.text
.align 2
.thumb

main:




.align 2
	lastresult:	.word 0x20370D0
Como veis, simplemente después de un .align 2 (pura sintaxis, solo ponedlo y despreocupaos por ello) hay que poner el nombre que eligamos y después con ese patrón el offset.
. . .
Ahora vamos a cargar el offset correspondiente a lastresult en r0:


Código:
.text
.align 2
.thumb

main:

	push {r0, lr}
	ldr r0, lastresult


.align 2
	lastresult:	.word 0x20370D0


En este caso se ha argumentado que como normalmente los offsets se usan más de una vez, es más cómodos darle un nombre y usarlo esto es totalmente falso. La razón por la que se usa nuevamente una etiqueta para identificar un offset en lugar de hacer directamente un LDR R0, 0x20370D0 es porque como ya mencioné los opcodes del ASM en modo THUMB tiene una longitud de 2 bytes, independientemente de la instrucción a usar, por tal motivo no se puede escribir un código donde se ejecute un comando seguido de un offset ya que solo el offset consta de 4 bytes. La solución a esto es cargar en el registro el valor encontrado en una etiqueta, esta etiqueta se encuentra a ciertos bytes respecto al PC y puede estar a una diferecia de offsets de hasta 10 bits, es decir, 1023 bytes respecto al PC

Finalmente unas aclaratorias con respecto al uso del PUSH y el POP de los registros:

- Los registros R0, R1, R2 y R3 son de propósitos generales, por lo que no es estrictamente necesario pushearlos y popearlos a menos que se vayan a seguir usando una vez salido de la sub-rutina
- La instrucción POP {LR} almacena en la stack o pila el registro de enlace LR. Un registro de enlace es un registro de propósito especial que contiene la dirección a la que regresar cuando se completa una llamada de función
- La instrucción PUSH {PC} devuelve al contador de programa la siguiente instrucción a ser ejecutada después de haber llamado la sub-rutina que se acaba de ejecutar

Si a alguien le parece que la información que les he dado le parece innecesaria, simplemente óbvienla. Yo por mi parte prefiero que se me de la información lo más completa y clara posible. No entregaré tareas porque ando bastante ocupado con otras cosas, pero si seguiré de cerca la escuela y todos los temas que faltan por desarrollar. Así que cualquier cosa en la que pueda ayudar ya saben donde encontrarme

Saludos y mucha suerte a todos los que se han propuesto aprender este maravilloso y potente lenguaje de programación
 

Ancer

Usuario de oro
Yo me medio me emocione y probé con varios
pero la verdad no soy muy creativo y esto fue lo que logre

Código:
.text
.align 2
.thumb

main:
	push {r0-r1, lr}
	ldr r0, hora\\se carga el offset datos del entrenador
	ldr r0,[r0]\\se carga los datos
	mov r1,#0x2\\el valor por el que quieres la hora ,si quieres hora diferentes pos mas rx
	strh r1, [r0,#0xE]\\editar hora
	strb r1, [r0,#0x10]\\editar minuto
	pop {r0-r1, pc}
	
.align 2
	hora:	.word 0x0300500C

Código:
.text
.align 2
.thumb

main:
	push {r0-r1, lr}
	ldr r0, datos\\ se cargar el offset de los datos
	ldr r0, [r0]\\ se cargan los datos 
	ldr r1, var_8000\\ se carga la variable 8000
	ldrb r1, [r1]\\se cargamos el valor de la variable 8000
	strb r1, [r0,#0x8]\\se pone el valor de la variable 8000 en el lugar de el sexo es decir 0 hombre ,1 mujer
	pop {r0-r1, pc}
	
.align 2
	datos:	.word 0x0300500C
	var_8000:	.word 0x20370B8

Código:
.texto
.align 2
.thumb

main:
posh {r0-r2,lr}
ldr r0,datos
mov r1,#0x58
add r0,r1,r0
ldrb r0,[r0]
ldr r1,datos
mov r2,#0x56
add r1,r2,r1
strb r0,[r1]
pop {r0-r2,pc}

.align 2
   datos:  .word 0x02024284

esta se guarda en las var 8000,8001,8002,8003,8004 en el orde de atk,def,spe,satk,sdef
Código:
.text
.align 2
.thumb

main:
	push {r0-r1, lr}
	ldr r0, datos//ataque
	mov r1, #0x5A
	add r0,r1,r0
	ldrh r0,[r0]
	ldr r1,var_8000
	strh r0,[r1]
	ldr r0, datos//defensa
	mov r1, #0x5C
	add r0,r1,r0
	ldrh r0,[r0]
	ldr r1,var_8001
	strh r0,[r1]
	ldr r0, datos//velocidad
	mov r1, #0x5F
	add r0,r1,r0
	ldrh r0,[r0]
	ldr r1,var_8002
	strh r0,[r1]
	ldr r0, datos//satk
	mov r1, #0x63
	add r0,r1,r0
	ldrh r0,[r0]
	ldr r1,var_8003
	strh r0,[r1]
	ldr r0, datos//sdef
	mov r1, #0x65
	add r0,r1,r0
	ldrh r0,[r0]
	ldr r1,var_8004
	strh r0,[r1]
	pop {r0-r1, pc}
	
.align 2
	datos:       .word 0x0202402c
	var_8000: .word 0x020370b8
	var_8001: .word 0x020370BA
	var_8002: .word 0x020370BC 
	var_8003: .word 0x020370BE 
	var_8004: .word 0x020370C0
 
Última edición:

Asmodeo Leviatan

¿La Iglesia inventó el Infierno? O es lo contrario
A ver, lo que entiendo es que quieres activar o desactivar algo usando ASM. Pues prácticamente es el mismo procedimiento que he explicado a @White, simplemente tienes que mover a un registro el valor deseado y en otro registro cargas el offset, luego lo guardas.

Si no lo entiendes dime un ejemplo y te pongo la rutina.


desactivar el menu pokemon, seria eso, y luego mediante otra cosa como un scrip o evento se active, algo como las zapatillas...

otra pregunta seria si se puede desactivar la box de los diálogos como se hace con el showpokepic o eso ya es con hxd?
 
Última edición:

Ancer

Usuario de oro
desactivar el menu pokemon, seria eso, y luego mediante otra cosa como un scrip o evento se active, algo como las zapatillas...

otra pregunta seria si se puede desactivar la box de los diálogos como se hace con el showpokepic o eso ya es con hxd?
lo de las zapatillas es por una flash y los del menú es una opción es que busques (o lo saques de Internet) los offset y los modifiques a gusto
para esto te recomiendo usar este post
https://whackahack.com/foro/t-31139/gba-asm-menu-funciones-personalizadas

lo que haces es ver el offset del menu pokemon y hacer una rutina ejemplo
si tiene la variable o preferentemente flash activada se puede usar el menu pero si esta desactivada te mande un mensaje

https://whackahack.com/foro/t-45950/asm-2-menus
o algo como eso que te deja poner 2 menus

lo de la box de dialogo es un si y hay varias formas y incluso puedes hacer una transparente para que se vean solo las letra o personalizarlas esto si buscas en unLZ.GBA
 

CompuMax

Discord: CompuMax#0425
Miembro insignia
Yo me medio me emocione y probé con varios
pero la verdad no soy muy creativo y esto fue lo que logre

Código:
.text
.align 2
.thumb

main:
	push {r0-r1, lr}
	ldr r0, 0x0300500C\\se carga el offset datos del entrenador
	ldr r0,[r0]\\se carga los datos
	mov r1,#0x2\\el valor por el que quieres la hora ,si quieres hora diferentes pos mas rx
	strb r1, [r0,#0xE]\\editar hora
	strb r1, [r0,#0x10]\\editar minuto
	pop {r0-r1, pc}

Código:
.text
.align 2
.thumb

main:
	push {r0-r1, lr}
	ldr r0, 0x0300500C\\ se cargar el offset de los datos
	ldr r0, [r0]\\ se cargan los datos 
	ldr r1, 0x20370B8\\ se carga la variable 8000
	ldrb r1, [r1]\\se cargamos el valor de la variable 8000
	strb r1, [r0,#0x8]\\se pone el valor de la variable 8000 en el lugar de el sexo es decir 0 hombre ,1 mujer
	pop {r0-r1, pc}
Deberías no solo revisar que tu código está mal hecho, ya que para empezar no puedes hacer un LDR R0, 0x0300500C y los datos que deseas cargar no están en esa dirección de memoria sino que deberías de intentar compilar y probar tus sub-rutinas antes de publicarlas para ver si funcionan como deberían.
 

Ancer

Usuario de oro
Deberías no solo revisar que tu código está mal hecho, ya que para empezar no puedes hacer un LDR R0, 0x0300500C y los datos que deseas cargar no están en esa dirección de memoria sino que deberías de intentar compilar y probar tus sub-rutinas antes de publicarlas para ver si funcionan como deberían.
si lo hice pero después le hice la modificación sin el .align 2
ya acomode el post con las que si funcionan gracias por avisar :p

y si esta ya las probé
 

Chema

Very Friendly
Wow, aquí me volví un lío, necesito un empujón para ensamblar mi rutina. Supongamos que quisiera desactivar la opción de la trainer card en FR, ¿que offset de la RAM puedo implementar para dicha rutina?
 

Ancer

Usuario de oro
Wow, aquí me volví un lío, necesito un empujón para ensamblar mi rutina. Supongamos que quisiera desactivar la opción de la trainer card en FR, ¿que offset de la RAM puedo implementar para dicha rutina?
En ese caso quieres desactivar una opción del menú te recomiendo lo mismo que an la anterior
Que podrías ver el offset del menú y si esta activado una variable que tu pongas que puedas usarlo y si esta desactivado te de un mensaje
 

Asmodeo Leviatan

¿La Iglesia inventó el Infierno? O es lo contrario
lo de las zapatillas es por una flash y los del menú es una opción es que busques (o lo saques de Internet) los offset y los modifiques a gusto
para esto te recomiendo usar este post
https://whackahack.com/foro/t-31139/gba-asm-menu-funciones-personalizadas

lo que haces es ver el offset del menu pokemon y hacer una rutina ejemplo
si tiene la variable o preferentemente flash activada se puede usar el menu pero si esta desactivada te mande un mensaje

https://whackahack.com/foro/t-45950/asm-2-menus
o algo como eso que te deja poner 2 menus

lo de la box de dialogo es un si y hay varias formas y incluso puedes hacer una transparente para que se vean solo las letra o personalizarlas esto si buscas en unLZ.GBA
suena bien tener dos menu pokemon, lo intentare, y a lo de la box como seria?
 

Ancer

Usuario de oro
suena bien tener dos menu pokemon, lo intentare, y a lo de la box como seria?
Lo de la box son imágenes en cuadros que se ordenan para que vea como la caja
Es decir si vas y pones envés de un cuadro una imagen de las mismas dimensiones que sea toda transparente se seria el efecto de que las letras se verían sin una box
 

Asmodeo Leviatan

¿La Iglesia inventó el Infierno? O es lo contrario
Lo de la box son imágenes en cuadros que se ordenan para que vea como la caja
Es decir si vas y pones envés de un cuadro una imagen de las mismas dimensiones que sea toda transparente se seria el efecto de que las letras se verían sin una box

no hay un tutorial explicandolo? y a todo esto, las rutinas asm deben terminar en 0, 4 y eso pero como ago para que terminen en dicho numero...?
 

Ancer

Usuario de oro
no hay un tutorial explicandolo? y a todo esto, las rutinas asm deben terminar en 0, 4 y eso pero como ago para que terminen en dicho numero...?
Lo de la box no se si hay tutoriales
Lo de 0,4,8,c es donde las insertas no es la rutina cómo tal es decir la rutina la insertas en un offset que termine en 0,4,8 o C
 

Ancer

Usuario de oro
Alguien me dice que tiene de mal esta rutina
Código:
.text
.align 2
.thumb

main:
 push {r0-r1,lr}
 ldr r0, datos
 ldr r0,[r0]
 mov r1, #0xDA
 strb r1,[r0,#0x1A]
 pop {r0-r1,pc}

.align 2
    datos:     .word 0x0300500C
Esto es para activar la dex nacional en los offset que dieron sale en la ultima parte que es hací pero falta algo
Alguien sabe?

suena bien tener dos menu pokemon, lo intentare, y a lo de la box como seria?
https://whackahack.com/foro/t-53970/fr-como-cambiar-forma-diseno-textbox

Lo encontre
 
Última edición:

~Lukhi

El tipo que a veces comenta en tu post.
Como no quería quedarme sin mostrar mi tarea voy a entregar la rutina, intente hacer una rutina en la que al utilizarse se reiniciara el el tiempo jugando. Les presento mi rutina:

Código:
.text
.align 2
.thumb

main:
        push {r0-r1, lr}
		ldr r0, lastresult
		ldr r0, [r0]
		sub r0, r0, r1
		ldr r1, var_8000
		strh r0, [r1]
		pop {r0-r1, pc}

.align 2
	lastresult:	.word 0x0300500C
	varnumber_8000: .word 0x20370B8
Aun no la he probado en mi rom,aunque dudo que funcione así que probablemente halla un error, si es así por favor corrijan me porque esto del ASM se me hace bastante complicado así que quiero aprender bien. :p Por cierto disculpa por la demora ya que he estado bastante ocupado estos días y me cuesta a veces entender algunas cosas.
 
Estado
Cerrado para nuevas respuestas.
Arriba