• Just a reminder that providing specifics on, sharing links to, or naming websites where ROMs can be accessed is against the rules. If your post has any of this information it will be removed.
  • Ever thought it'd be cool to have your art, writing, or challenge runs featured on PokéCommunity? Click here for info - we'd love to spotlight your work!
  • Our weekly protagonist poll is now up! Vote for your favorite Trading Card Game 2 protagonist in the poll by clicking here.
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

Help Thread: ASM & Disassembly

Status
Not open for further replies.
OK so I'm trying to make a routine that takes a pokemon thats stored in FBI's storage routine(which is determined by the value in var 0x8000) then store it into a trainers party setup in RAM(which trainer slot determined by var 0x8001)
the EV for the transferred Pokemon is set by var 0x8002. Now I have 2 versions of the routine, the first works, but is very messy/has poor execution, in which it will only store the first Pokemon.

The second routine has been rewritten a few times, each time with different results, none good. Currently it crashes the ROM, previously it just froze.

Working old routine:
Spoiler:

Broken new routine:
Spoiler:

Any help is appreciated!
 
OK so I'm trying to make a routine that takes a pokemon thats stored in FBI's storage routine(which is determined by the value in var 0x8000) then store it into a trainers party setup in RAM(which trainer slot determined by var 0x8001)
the EV for the transferred Pokemon is set by var 0x8002. Now I have 2 versions of the routine, the first works, but is very messy/has poor execution, in which it will only store the first Pokemon.

The second routine has been rewritten a few times, each time with different results, none good. Currently it crashes the ROM, previously it just froze.

Working old routine:
Spoiler:

Broken new routine:
Spoiler:

Any help is appreciated!
I'm not too familiar with the storage routine, so I'm not entirely sure what you're trying to do. Anyways, a few things popped out when I scanned what you wrote.

I'm surprised the first routine even worked because you have
Code:
Decrypt:
ldr r2, =(0x803FBE8)
bx r2
That should be executing 0x0803FBE8 as ARM, which I doubt you want. And also, after each of the decrypts, you have strh r0, [r2, imm]. But r2 should have been messed up by the get_attr. The offset you're storing the decrypted data to should be held in a register above r3, or at the very least re-derived after the bl. As a side note, the .align 2 should come before the literal pool. The entire reason it exists is because the .VAR and .Var_8004 needs to be word aligned.

You make a similar assumption in the second routine. You appear to assume that r3 remains unchanged during get_attr. So the second time you "bl Linker," you are almost definitely bx'ing to an address that you should not. That seems to be your main issue in both routines. You should assume that r1-r3 (and r0 if there is no return) are rubbish after bl'ing to anything. This also means you shouldn't have to push r0-r3 at the beginning unless there's something specific you're saving.

I just noticed something else. You have
Code:
ldr r7, =(0x2037102)
strb r0, [r7]
.....
ldr r7, =(0x2037104)
strh r0, [r7]
.....
ldr r7, =(0x2037106)
strh r0, [r7]
.....
ldr r7, =(0x2037108)
strh r0, [r7]
.....
ldr r7, =(0x203710A)
strh r0, [r7]
.....
ldr r7, =(0x203710C)
strh r0, [r7]
.....
ldr r7, =(0x203710E)
strh r0, [r7]
When you could instead be using
Code:
strb r0, [r7, #0x0]
.....
strh r0, [r7, #0x2]
.....
strh r0, [r7, #0x4]
.....
strh r0, [r7, #0x6]
.....
strh r0, [r7, #0x8]
etc
 
Last edited:
OK so I'm trying to make a routine that takes a pokemon thats stored in FBI's storage routine(which is determined by the value in var 0x8000) then store it into a trainers party setup in RAM(which trainer slot determined by var 0x8001)
the EV for the transferred Pokemon is set by var 0x8002. Now I have 2 versions of the routine, the first works, but is very messy/has poor execution, in which it will only store the first Pokemon.

The second routine has been rewritten a few times, each time with different results, none good. Currently it crashes the ROM, previously it just froze.

Are you sure you haven't mixed up which is working and which is not? The one you've labelled working branches to a THUMB routine in ARM mode which should crash. I don't see anything wrong with the second routine besides some needless code repetition. But I'm not familiar with the addresses being used, so I'm not too sure.

EDIT: Ninja
 
Last edited:
OK so I'm trying to make a routine that takes a pokemon thats stored in FBI's storage routine(which is determined by the value in var 0x8000) then store it into a trainers party setup in RAM(which trainer slot determined by var 0x8001)
the EV for the transferred Pokemon is set by var 0x8002. Now I have 2 versions of the routine, the first works, but is very messy/has poor execution, in which it will only store the first Pokemon.

The second routine has been rewritten a few times, each time with different results, none good. Currently it crashes the ROM, previously it just froze.

Working old routine:
Spoiler:

Broken new routine:
Spoiler:

Any help is appreciated!


Well, you don't even have to use set_attr or get_attr if you use this, it's much more convenient to edit pokemon data.
 
OK so I'm trying to make a routine that takes a pokemon thats stored in FBI's storage routine(which is determined by the value in var 0x8000) then store it into a trainers party setup in RAM(which trainer slot determined by var 0x8001)
the EV for the transferred Pokemon is set by var 0x8002. Now I have 2 versions of the routine, the first works, but is very messy/has poor execution, in which it will only store the first Pokemon.

The second routine has been rewritten a few times, each time with different results, none good. Currently it crashes the ROM, previously it just froze.

Any help is appreciated!

If I'm understanding correctly, you're trying to take a stored Pokemon and add it to the party? In which case, "compressed" Pokemon don't need to have their EVs reset or stored. Pokemon compression takes the first 0x50 bytes of the 0x64 Pokemon data structure (the rest is calculated upon uncompression, hence why you'll notice putting a Pokemon into the PC and withdrawing it resets its HP/status).

Anyways, there's a few problems you need to consider before doing something.
1) If pokemon you take from storage is not the last one, storage Pokemon after it need to be moved up to utilise empty slots later on.
2) If party already has 6 pkmn, how will you handle it?

there's a lot of edge cases when it comes to Pokemon storage, anyways, I suggest you use memcpy. Also the need to pass a slot ID for the party isn't needed because if it's not-full we can just place it in the next available slot.

You should just use a memcpy/swi like this:


Code:
ldr r0, =(0x2024029)
ldr r1, =(0x2024284)
ldrb r0, [r0]
mov r2, #0x64
mul r0, r0, r2
add r0, r0, r1 @dest
ldr r1, =(0x203C000)
ldr r2, =(0x20370B8)
ldrh r2, [r2]
mov r3, #0x50
mul r2, r2, r3
add r1, r1, r2 @src
mov r2, #0x50 @size

swi 0xC @alternatively you can use memcpy

Well, you don't even have to use set_attr or get_attr if you use this, it's much more convenient to edit pokemon data.

You lose portability to ROMs without this implemented. Also, the code isn't more simplified length-wise since now you need to do bit-wise operations for certain accesses (though it's simplified execution wise).
 
I'm not too familiar with the storage routine, so I'm not entirely sure what you're trying to do. Anyways, a few things popped out when I scanned what you wrote.

I'm surprised the first routine even worked because you have
Code:
Decrypt:
ldr r2, =(0x803FBE8)
bx r2
That should be executing 0x0803FBE8 as ARM, which I doubt you want. And also, after each of the decrypts, you have strh r0, [r2, imm]. But r2 should have been messed up by the get_attr. The offset you're storing the decrypted data to should be held in a register above r3, or at the very least re-derived after the bl. As a side note, the .align 2 should come before the literal pool. The entire reason it exists is because the .VAR and .Var_8004 needs to be word aligned.

You make a similar assumption in the second routine. You appear to assume that r3 remains unchanged during get_attr. So the second time you "bl Linker," you are almost definitely bx'ing to an address that you should not. That seems to be your main issue in both routines. You should assume that r1-r3 (and r0 if there is no return) are rubbish after bl'ing to anything. This also means you shouldn't have to push r0-r3 at the beginning unless there's something specific you're saving.

I just noticed something else. You have
Code:
ldr r7, =(0x2037102)
strb r0, [r7]
.....
ldr r7, =(0x2037104)
strh r0, [r7]
.....
ldr r7, =(0x2037106)
strh r0, [r7]
.....
ldr r7, =(0x2037108)
strh r0, [r7]
.....
ldr r7, =(0x203710A)
strh r0, [r7]
.....
ldr r7, =(0x203710C)
strh r0, [r7]
.....
ldr r7, =(0x203710E)
strh r0, [r7]
When you could instead be using
Code:
strb r0, [r7, #0x0]
.....
strh r0, [r7, #0x2]
.....
strh r0, [r7, #0x4]
.....
strh r0, [r7, #0x6]
.....
strh r0, [r7, #0x8]
etc
Ok Ill see if I cant fix it with those suggestions. In regards to the strh r0, [r7, #0x2], I originally had it like that, but was just messing around seeing if that was what was causing any of my issues.
Are you sure you haven't mixed up which is working and which is not? The one you've labelled working branches to a THUMB routine in ARM mode which should crash. I don't see anything wrong with the second routine besides some needless code repetition. But I'm not familiar with the addresses being used, so I'm not too sure.

EDIT: Ninja
I hope not

Well, you don't even have to use set_attr or get_attr if you use this, it's much more convenient to edit pokemon data.
I sorta kinda forgot about that, but I'll leave it as is just cause that's what I know.(ish)

If I'm understanding correctly, you're trying to take a stored Pokemon and add it to the party? In which case, "compressed" Pokemon don't need to have their EVs reset or stored. Pokemon compression takes the first 0x50 bytes of the 0x64 Pokemon data structure (the rest is calculated upon uncompression, hence why you'll notice putting a Pokemon into the PC and withdrawing it resets its HP/status).

Anyways, there's a few problems you need to consider before doing something.
1) If pokemon you take from storage is not the last one, storage Pokemon after it need to be moved up to utilise empty slots later on.
2) If party already has 6 pkmn, how will you handle it?

there's a lot of edge cases when it comes to Pokemon storage, anyways, I suggest you use memcpy. Also the need to pass a slot ID for the party isn't needed because if it's not-full we can just place it in the next available slot.

You should just use a memcpy/swi like this:


Code:
ldr r0, =(0x2024029)
ldr r1, =(0x2024284)
ldrb r0, [r0]
mov r2, #0x64
mul r0, r0, r2
add r0, r0, r1 @dest
ldr r1, =(0x203C000)
ldr r2, =(0x20370B8)
ldrh r2, [r2]
mov r3, #0x50
mul r2, r2, r3
add r1, r1, r2 @src
mov r2, #0x50 @size

swi 0xC @alternatively you can use memcpy
No what I'm tryiong to do is take the stored pokemon and turn it into an enemy trainers party Pokemon, not removing anything from the storage or the players party.
 
Last edited:
Ok Ill see if I cant fix it with those suggestions. In regards to the strh r0, [r7, #0x2], I originally had it like that, but was just messing around seeing if that was what was causing any of my issues.

I hope not


I sorta kinda forgot about that, but I'll leave it as is just cause that's what I know.(ish)


No what I'm tryiong to do is take the stored pokemon and turn it into an enemy trainers party Pokemon, not removing anything from the storage or the players party.

Err, that's going to take a hook, just as an aside. Also, use the snippet I posted but change 0x2024284 into the opponent's party, it should still work. The hook will have to remove "Opponent party purge" or whatever it's called.
 
Err, that's going to take a hook, just as an aside. Also, use the snippet I posted but change 0x2024284 into the opponent's party, it should still work. The hook will have to remove "Opponent party purge" or whatever it's called.

Why would it need a hook?
 
Why would it need a hook?

I assume you're copying this data over to opponent party because you want to battle an opponent with that party later on? Well, generally, before a battle happens, during the setup the opponent's Party is purged. You'd need to remove this purge based on condition, hence the hook.
 
I assume you're copying this data over to opponent party because you want to battle an opponent with that party later on? Well, generally, before a battle happens, during the setup the opponent's Party is purged. You'd need to remove this purge based on condition, hence the hook.

The party is strictly in RAM, that way its not purged.
 
The party is strictly in RAM, that way its not purged.

The opponent's party is purged before each battle via 0803DA34. It's because it's in the RAM which allows it to be purged, ofc, the copy you'd have in 0203C000 will not be purged. Anyways, if it was your plan to have the player battle a stored Pokemon, then a hook would be necessary.
 
The opponent's party is purged before each battle via 0803DA34. It's because it's in the RAM which allows it to be purged, ofc, the copy you'd have in 0203C000 will not be purged. Anyways, if it was your plan to have the player battle a stored Pokemon, then a hook would be necessary.

Opps sorry i miss worded that. What i meant was the data that the game reads to determine the party is stored in ram instead of the Rom. Butafter some tweaking the issue persists and the game is reset upon calling the routine.
 
Opps sorry i miss worded that. What i meant was the data that the game reads to determine the party is stored in ram instead of the Rom. Butafter some tweaking the issue persists and the game is reset upon calling the routine.

Perhaps it was I who was being unclear. First, can I confirm that you are trying to make the player battle 1 or more pokemon from the storage?

If that's not the case, then the routine I posted in an earlier post is the solution. Also,
What i meant was the data that the game reads to determine the party is stored in ram instead of the Rom.
I was talking about the opponent party, since that (unlike the player party) is not stored in the sav datastructure, and thus will not be derived on reset. The opponent's party is purged every time you do battle as well.
 
Perhaps it was I who was being unclear. First, can I confirm that you are trying to make the player battle 1 or more pokemon from the storage?

If that's not the case, then the routine I posted in an earlier post is the solution. Also,
Yes I'm trying to make the player battle pokemon from the storage. The routine is simply meant to take the species, level, and moves from the stored pokemon and store them in RAM to be used as a trainer's party.(plus evs set by a var)

I was talking about the opponent party, since that (unlike the player party) is not stored in the sav datastructure, and thus will not be derived on reset. The opponent's party is purged every time you do battle as well.

Yea I understand that.
 
Yes I'm trying to make the player battle pokemon from the storage. The routine is simply meant to take the species, level, and moves from the stored pokemon and store them in RAM to be used as a trainer's party.(plus evs set by a var)
I don't think I quite understand why you need to use an intermediate step of storing those things in a specific ram location, but maybe I'm just terrible at understanding. Regardless, going from an offset of an encrypted pokemon and storing the unencrypted data in a specific location is simple enough, so perhaps you can post your modified routines for us to see?

MY question: could someone describe simplest way to go from numerator and denominator to a percentage? I found "Div," but I'm not sure how to utilize what "Supervisor Mode " 6 does. I specifically would like a rounded percentage as an integer, not the number of times the numerator goes into the denominator/ignoring remainder.
 
Yes I'm trying to make the player battle pokemon from the storage. The routine is simply meant to take the species, level, and moves from the stored pokemon and store them in RAM to be used as a trainer's party.(plus evs set by a var)

Yea I understand that.


Yeah, you don't need to do all of that. Just uncompress the Pokemon, and copy it into the opponent's party space. What I've been trying to say is that the opponent's party is purged before battling, so inorder for your storage pokemon which you've copied over to not be purged, you'd need to hook to turn off the purging mechanic. :)

MY question: could someone describe simplest way to go from numerator and denominator to a percentage? I found "Div," but I'm not sure how to utilize what "Supervisor Mode " 6 does. I specifically would like a rounded percentage as an integer, not the number of times the numerator goes into the denominator/ignoring remainder.

So you want to get a percentage which takes the remainder into account when rounding? Hmm, I don't believe such a built-in function exists. What you can do is:

Code:
main:
	push {r4, lr}
	mov r0, numerator
	mov r1, denomenator
	mov r4, r1
	swi #0x6
	lsr r1, r1, #0x2
	lsr r4, r4, #0x2
	cmp r4, r1
	bhi end

round:
	@calculating how much percent to add is a pain in itself...
	push {r0}
	mov r0, r1
	mov r1, #0x64
	swi #0x6
	mov r1, r0
	pop {r0}
	add r0, r0, r1
	
end:
	pop {r4, pc}

swi 0x6 does modulo division and normal division. The modulo return is in r1 and normal version is in r0 with abs in r3. From there you need to check if the modulo / 2 > denominator/2 and manually increment the percentage if this is the case. Above is untested.
 
Last edited:
So you want to get a percentage which takes the remainder into account when rounding? Hmm, I don't believe such a built-in function exists. What you can do is:

swi 0x6 does modulo division and normal division. The modulo return is in r1 and normal version is in r0 with abs in r3. From there you need to check if the modulo / 2 > denominator/2 and manually increment the percentage if this is the case. Above is untested.
Hmm. Well what I meant was that say you have the numerator = 40 and denominator = 200. Anyone could tell you that it is equivalent to 20%, but I wasn't sure on how to efficiently write it as a routine that takes #40 and #200 and returns #20.

I'm not sure I understand the code that you wrote out. Especially the part where you mentioned modulo / 2 and denominator / 2. Are those division signs? Because in the code, you logical shifted right by two, which would be more closely estimated as division by four? And when I plugged a few numbers in, it didn't seem to return what I wanted. Does it only work for numerator > denominator and the return is greater than 100%?

I'm not sure whether my lack of understanding on the code is due to not being well versed in bit logic or being bad at math :P Either way, the information on swi 0x6 is useful by itself. I didn't expect anyone to write out an actual code, so I appreciate that!
 
Hmm. Well what I meant was that say you have the numerator = 40 and denominator = 200. Anyone could tell you that it is equivalent to 20%, but I wasn't sure on how to efficiently write it as a routine that takes #40 and #200 and returns #20.

I'm not sure I understand the code that you wrote out. Especially the part where you mentioned modulo / 2 and denominator / 2. Are those division signs? Because in the code, you logical shifted right by two, which would be more closely estimated as division by four? And when I plugged a few numbers in, it didn't seem to return what I wanted. Does it only work for numerator > denominator and the return is greater than 100%?

I'm not sure whether my lack of understanding on the code is due to not being well versed in bit logic or being bad at math :P Either way, the information on swi 0x6 is useful by itself. I didn't expect anyone to write out an actual code, so I appreciate that!

Yeah, you're right, it should've been lsr #0x1, and those "/" are division signs (I'm not sure how I'd go about making the division symbol on a keyboard) whoops.

Yes, it should work for all cases, try it with the lsr #0x1.
 
MY question: could someone describe simplest way to go from numerator and denominator to a percentage? I found "Div," but I'm not sure how to utilize what "Supervisor Mode " 6 does. I specifically would like a rounded percentage as an integer, not the number of times the numerator goes into the denominator/ignoring remainder.
I think the simplest way would be like this:
Code:
mov r0, numerator
mov r1, denominator
mov r2, #100
mul r0, r2
lsr r2, r1, #1
add r0, r2
swi #6
What it does is it multiplies the numerator by 100 so the result is a percentage, then adds half of the denominator to make sure the result is correctly rounded (no need to process the remainder), and then divides. I haven't tested this code, but I'm pretty sure it works.
 
FireRed actually has two routines for integer division:

DivMod1 (Takes in R0 as Numerator and R1 as Denominator; Returns INTEGER DIVISION (9/2 = 4 r 1) result to R0): 0x1E4018
DivMod2 (Takes in R0 as Numerator and R1 as Denominator; Returns REMAINDER OF INTEGER DIVISION (23/4 = 5 r 3 to R0): 0x1E4684
 
Status
Not open for further replies.
Back
Top