ASM & Hex Trouble with an ASM routine

Started by JapaBijou November 27th, 2020 3:43 AM
  • 485 views
  • 4 replies
Seen 4 Weeks Ago
Posted December 14th, 2020
8 posts
64 Days
Hi guys

I've started to study asm, so I decided to try to create some routines as training, but I bumped into a problem:

The purpose of this routine is to heal every pokémon that is not fainted (so their hp must be different from 0, useful for things such as nuzlocke challenge ROM).
The routine iterates every pokémon in the party, until it finds a pokemon with level equal to 0 (because that's impossible so the party is over) and then quit

The Flow-Chart is the following:
Spoiler:
I don't know how to upload image online, so I attached it as thumbnails


The code is the following:
Spoiler:

.arm
.align 2

main:
/*
r0 -> address
r1 -> offset to add to r0
r2 -> data taken from r0 address
*/

push {r0-r2,lr}

ldr r0,pokemon_memory_start


loop:
ldrb r1,level_offset
add r0,r1
ldr r2,[r0]

cmp r2,#0
blNE finish

sub r0,r1

ldrb r1,current_HP_offset
add r0,r1
ldr r2,[r0]
sub r0,r1

cmp r2,#0
blNE restore_pokemon
add r0,#0x64
bl loop

restore_pokemon:
ldrb r1,total_HP_offset
add r0,r1
ldrh r2,[r0]
sub r0,r1
ldrb r1,current_HP_offset
add r0,r1
strh r2,[r0]
sub r0,r1
add r0,#0x64

bl loop


finish:
pop {r0-r2,pc}


.align 2

pokemon_memory_start:
.word 0x020244EC

level_offset:
.byte 0x54

current_HP_offset:
.byte 0x56

total_HP_offset:
.byte 0x58



Code explanation:
Spoiler:

In the register r0 I load the position of the current pokemon, starting from pokemon_memory_start, wich is the position of the first pokemon in the party
Everytime I have to read current pokemon's characteristic, such as level, the code adds the corrispective offset to the r0 register and then load the data into r2
To pass to the next pokemon in the party, the code adds 0x64 to r0, wich is the size of pokemon data structure (100 bytes)


I execute the routine in Littleroot town sign placed at position (000F;000D):
Spoiler:

'---------------
#org 0x1E7BDE
msgbox 0x81E87F2 MSG_SIGN '"ALBANOVA\n["]Città di una bellezza..."
callasm 0x8E4CF70
end


'---------
' Strings
'---------
#org 0x1E87F2
= ALBANOVA\n["]Città di una bellezza ineguagliabile".


I know that that routine is not the best way to handle only-one-dead-rule in a nuzlocke rom (because I should remove all healing items, change all pkmn center script and then it wouldn't work anyway because of healing-box), but this is only an exercise.

I'm not 100% sure,but the offset should be right.

So I have some questions:

1) Why does the game restart when I talk to the sign?
2) Can I use thumb set instead of arm set? The compiler told me that "Thumb does not support conditional execution", but I saw that on this forum someone using conditional branches with thumb.


Thanks for all

-JapaBijou
Seen 20 Hours Ago
Posted 20 Hours Ago
40 posts
3.2 Years
If you just want to just hack the gen3 games, you might find using the decompilations easier than assembly.
For example, in pokeemerald you could do this simply with:
int i;
for(i = 0; i < gPlayerPartyCount; i++){
	if(gPlayerParty[i].hp != 0) gPlayerParty[i].hp = gPlayerParty[i].maxHP;
}

But to actually answer your questions:
1) The game crashes because the processor is still in ARM-mode when you return to the game's thumb code by popping pc.
You should either just use thumb code or to return with the bx instruction, which can change the processor mode.

2) You're trying to use branch-with-link (BL) with conditions, which is not allowed in thumb mode, instead you should be using the branch instruction (B).
also you're using ldrb for loading single-byte constants like total_HP_offset, which is also not allowed, use mov instead.
Seen 4 Weeks Ago
Posted December 14th, 2020
8 posts
64 Days
If you just want to just hack the gen3 games, you might find using the decompilations easier than assembly.
For example, in pokeemerald you could do this simply with:
int i;
for(i = 0; i < gPlayerPartyCount; i++){
if(gPlayerParty[i].hp != 0) gPlayerParty[i].hp = gPlayerParty[i].maxHP;
}
How can I do that?

But to actually answer your questions:
1) The game crashes because the processor is still in ARM-mode when you return to the game's thumb code by popping pc.
You should either just use thumb code or to return with the bx instruction, which can change the processor mode.

2) You're trying to use branch-with-link (BL) with conditions, which is not allowed in thumb mode, instead you should be using the branch instruction (B).
also you're using ldrb for loading single-byte constants like total_HP_offset, which is also not allowed, use mov instead.
I managed to switch to thumb using b instead of bl. What is the difference between those two?
Anyway, I changed the code:

Spoiler:

.thumb
.align 2

main:
/*
r0 -> address
r1 -> offset to add to r0
r2 -> data taken from r0 address
*/

push {r0-r2,lr}

ldr r0,pokemon_memory_start

loop:
mov r1,#level_offset
add r0,r1
ldr r2,[r0]

cmp r2,#0
bNE finish

sub r0,r1

mov r1,#current_HP_offset
add r0,r1
ldr r2,[r0]
sub r0,r1

cmp r2,#0
bNE restore_pokemon
add r0,#0x64
b loop

restore_pokemon:
mov r1,#total_HP_offset
add r0,r1
ldrh r2,[r0]
sub r0,r1
mov r1,#current_HP_offset
add r0,r1
strh r2,[r0]
sub r0,r1
add r0,#0x64

b loop

finish:
pop {r0-r2,pc}


.align 2

pokemon_memory_start:
.word 0x020244EC

level_offset:
.byte 0x54

current_HP_offset:
.byte 0x56

total_HP_offset:
.byte 0x58



But compiler give me this error:

D:\..\temp.asm: 16: Error: cannot represent THUMB_IMM relocation in this object file format
D:\..\temp.asm: 25: Error: cannot represent THUMB_IMM relocation in this object file format
D:\..\temp.asm: 36: Error: cannot represent THUMB_IMM relocation in this object file format
D:\..\temp.asm: 40: Error: cannot represent THUMB_IMM relocation in this object file format

What that mean?

Thanks again

EDIT:

I removed r1 and add offsets in this way:
Spoiler:

.thumb
.align 2

main:
/*
r0 -> address
r1 -> offset to add to r0
r2 -> data taken from r0 address
*/

push {r0,r2,lr}

ldr r0,pokemon_memory_start

loop:
add r0,#0x54
ldr r2,[r0]

cmp r2,#0
bNE finish

sub r0,#0x54

add r0,#0x54
ldr r2,[r0]
sub r0,#0x54

cmp r2,#0
bNE restore_pokemon
add r0,#0x64
b loop

restore_pokemon:
add r0,#0x58
ldrh r2,[r0]
sub r0,#0x58
add r0,r1
strh r2,[r0]
sub r0,#0x56
add r0,#0x64

b loop

finish:
pop {r0,r2,pc}

.align 2

pokemon_memory_start:
.word 0x020244EC



Now it compiles and game doesn't reset but doesn't heal my team.
Why?
Seen 20 Hours Ago
Posted 20 Hours Ago
40 posts
3.2 Years
You can find a tutorial for setting up pokeemerald here: https://www.pokecommunity.com/showthread.php?t=426921

Your team doesn't get healed because your code is buggy:
- it jumps to finish when level is not 0
- it's reading the level a second time instead of hp
- It's accessing level as 4 bytes instead of 1
- it's using r1 even though you haven't set its value
...and maybe more.