Binary ROM HackingNeed a helping hand or just want to talk about binary ROM hacks? Get comments and answers to any ROM Hacking-related problems, questions or thoughts you have here.
Hello guys, I'm trying to build a routine that lets the Var 8000 edit thePokémon data substructures(Bulbapedia term)
.... I had read the entire site but I can't find the RAM Address of that Pokemon Data substructure
__________________
This signature has been disabled.
Scrollbar appears
Please review and fix the issues by reading the signature rules.
You must edit it to meet the limits set by the rules before you may remove the [sig-reason] code from your signature. Removing this tag will re-enable it.
Do not remove the tag until you fix the issues in your signature. You may be infracted for removing this tag if you do not fix the specified issues. Do not use this tag for decoration purposes.
Hello guys, I'm trying to build a routine that lets the Var 8000 edit thePokémon data substructures(Bulbapedia term)
.... I had read the entire site but I can't find the RAM Address of that Pokemon Data substructure
Use the FBI's routine in the ASM resource thread. For the substructure it's wrote in bulbapedia, something like 0x020244EC for emerald if I remember well
Use the FBI's routine in the ASM resource thread. For the substructure it's wrote in bulbapedia, something like 0x020244EC for emerald if I remember well
Thanks, gonna check this
__________________
This signature has been disabled.
Scrollbar appears
Please review and fix the issues by reading the signature rules.
You must edit it to meet the limits set by the rules before you may remove the [sig-reason] code from your signature. Removing this tag will re-enable it.
Do not remove the tag until you fix the issues in your signature. You may be infracted for removing this tag if you do not fix the specified issues. Do not use this tag for decoration purposes.
Hello guys, I'm trying to build a routine that lets the Var 8000 edit thePokémon data substructures(Bulbapedia term)
.... I had read the entire site but I can't find the RAM Address of that Pokemon Data substructure
Are you just asking how to edit things in it like IVs? Because if that's the case, there's no reason to "build a routine," as a vanilla rom already has it built in. You can just move/load to a few registers then call it. I'm on a phone now so I can't give it to you right now, but I could give it to you the next time I'm on my computer/ you could probably find it with a quick google.
Also, what do you mean by "that" RAM address? There are six party slots and 30 pokemon in each box.
Hello guys, I'm trying to build a routine that lets the Var 8000 edit thePokémon data substructures(Bulbapedia term)
.... I had read the entire site but I can't find the RAM Address of that Pokemon Data substructure
Pokémon data tables are not copied to RAM, they're read from the ROM. You can't change them in real time because you can't edit them from the game. (Obviously)
You may want to have a special case of reading a different piece of data or something. But I'm here to tell you that what you're doing is impossible by normal means.
The reason why I'm looking for that is for the pokemon current experience, anyway please forgive me if this routine I created is too dumb, I'm trying to create a routine that var 8004 is the slot number, 8005 is the Stat 0 is Current HP, 1 is Total HP, 2 is Attack and so on, then in 8006 is XXYY where XX can be only be 00(Add YY) or 01(Subtract YY) and YY is the value to add or subtract
But yeah, when I call it in a script, the game freezes
Spoiler:
.text
.align 2
.thumb
.thumb_func
main:
push {r0-r4, lr}
ldr r0, var @loads the var 8004 in r0
ldrb r0, [r0] @loads the byte of var 8004
cmp r0, #0x05 @compares var 8004 into 5
bgt end @if greater than 5 jump to Label end
ldr r1, Stat @loads the Pokemon data into r1
mov r2, #0x64 @moves 64 in r2
mul r2, r0 @multiplies value of Var 8004 into by 64 so that it jumps to the data of the selected pokemon slot
add r1, r2, r1 @adds the product of r2 and r0 in r1 then places it to r1
first_loop:
mov r2, #0x0 @cleans r2
ldr r3, var @loads var 8004 in r3
ldrb r3, [r3, #0x02] loads the byte in var 8005
cmp r3, #0x06 compares var 8005 in 6, r3 is the Stat choices, Current Hp, Total Hp, Atk and etc
bgt end @if greater than, jumps to end
add r1, r3, r1 @adds the stat choice in the r1 so that the address is fixed, then places the sum in r1
second_loop:
ldr r2, var @loads var 8004 in
ldrb r2, [r2, #0x05] @loads the second byte of var 8006 in r2
cmp r2, #0x0 @compares r2 to 0
beq add2 @if equal, jump to add2
cmp r2, #0x1 @compares r2 to 1
bgt end @if greater than, jump to end
ldr r1, var @loads var 8004
ldrb r1, [r1, #0x4] loads the byte of var 8006
sub r1, r3, r1 @subtracts the stat offset and var 8006 then places the difference in r1
strb r1, [r1] @stores the byte or r1 in r1
b end @jumps to end
add2:
ldr, var @loads var 8004
ldrb, [r1, #0x4] @loads the byte in var 8006
add r1, r3, r1 @adds the stat offset to var 8006 then places the sum in rq
b end @jumps to end
end:
pop {r1-r4, pc} @pops all registers I used, AAAARRRRRGH! It should be pop {r0-r4, pc}
.align 2
var .word 0x020370c0
Stat .word 0x02024284
__________________
This signature has been disabled.
Scrollbar appears
Please review and fix the issues by reading the signature rules.
You must edit it to meet the limits set by the rules before you may remove the [sig-reason] code from your signature. Removing this tag will re-enable it.
Do not remove the tag until you fix the issues in your signature. You may be infracted for removing this tag if you do not fix the specified issues. Do not use this tag for decoration purposes.
The reason why I'm looking for that is for the pokemon current experience, anyway please forgive me if this routine I created is too dumb, I'm trying to create a routine that var 8004 is the slot number, 8005 is the Stat 0 is Current HP, 1 is Total HP, 2 is Attack and so on, then in 8006 is XXYY where XX can be only be 00(Add YY) or 01(Subtract YY) and YY is the value to add or subtract
But yeah, when I call it in a script, the game freezes
Spoiler:
.text
.align 2
.thumb
.thumb_func
main:
push {r0-r4, lr}
ldr r0, var
ldrb r0, [r0]
cmp r0, #0x05
bgt end
ldr r1, Stat
mov r2, #0x64
mul r2, r0
add r1, r2, r1
first_loop:
mov r2, #0x0
ldr r3, var
ldrb r3, [r3, #0x02]
cmp r3, #0x06
bgt end
add r1, r3, r1
second_loop:
ldr r2, var
ldrb r2, [r2, #0x03]
cmp r2, #0x0
beq add2
cmp r2, #0x1
bgt end
ldr r1, var
ldrb r1, [r1, #0x4]
sub r1, r3, r1
strb r1, [r1]
b end
add2:
ldr, var
ldrb, [r1, #0x4]
add r1, r3, r1
b end
end:
pop {r1-r4, pc}
.align 2
var .word 0x020370c0
Stat .word 0x02024284
So much is wrong with this - the cause for the freeze being the least worrying. You label stuff as loops, yet they don't loop? Anyway, your main problem is you push more than you pop, thus causing stack corruption.
Please comment what you think you are doing so I can correct it - I can't guess what this is supposed to do without comments.
__________________
A Pokemon that is discriminated!
Support squirtle and make it everyone's favourite.
So much is wrong with this - the cause for the freeze being the least worrying. You label stuff as loops, yet they don't loop? Anyway, your main problem is you push more than you pop, thus causing stack corruption.
Please comment what you think you are doing so I can correct it - I can't guess what this is supposed to do without comments.
am already put the comment
__________________
This signature has been disabled.
Scrollbar appears
Please review and fix the issues by reading the signature rules.
You must edit it to meet the limits set by the rules before you may remove the [sig-reason] code from your signature. Removing this tag will re-enable it.
Do not remove the tag until you fix the issues in your signature. You may be infracted for removing this tag if you do not fix the specified issues. Do not use this tag for decoration purposes.
The reason why I'm looking for that is for the pokemon current experience, anyway please forgive me if this routine I created is too dumb, I'm trying to create a routine that var 8004 is the slot number, 8005 is the Stat 0 is Current HP, 1 is Total HP, 2 is Attack and so on, then in 8006 is XXYY where XX can be only be 00(Add YY) or 01(Subtract YY) and YY is the value to add or subtract
But yeah, when I call it in a script, the game freezes
Spoiler:
.text
.align 2
.thumb
.thumb_func
main:
push {r0-r4, lr} @(#1)
ldr r0, var @loads the var 8004 in r0
ldrb r0, [r0] @loads the byte of var 8004
cmp r0, #0x05 @compares var 8004 into 5
bgt end @if greater than 5 jump to Label end
ldr r1, Stat @loads the Pokemon data into r1
mov r2, #0x64 @moves 64 in r2
mul r2, r0 @multiplies value of Var 8004 into by 64 so that it jumps to the data of the selected pokemon slot
add r1, r2, r1 @adds the product of r2 and r0 in r1 then places it to r1
first_loop:
mov r2, #0x0 @cleans r2 (#2)
ldr r3, var @loads var 8004 in r3
ldrb r3, [r3, #0x02] loads the byte in var 8005
cmp r3, #0x06 compares var 8005 in 6, r3 is the Stat choices, Current Hp, Total Hp, Atk and etc
bgt end @if greater than, jumps to end
add r1, r3, r1 @adds the stat choice in the r1 so that the address is fixed, then places the sum in r1 (#3)
second_loop:
ldr r2, var @loads var 8004 in
ldrb r2, [r2, #0x05] @loads the second byte of var 8006 in r2
cmp r2, #0x0 @compares r2 to 0
beq add2 @if equal, jump to add2
cmp r2, #0x1 @compares r2 to 1
bgt end @if greater than, jump to end
ldr r1, var @loads var 8004 (#4)
ldrb r1, [r1, #0x4] loads the byte of var 8006 (#4)
sub r1, r3, r1 @subtracts the stat offset and var 8006 then places the difference in r1 (#5)
strb r1, [r1] @stores the byte or r1 in r1 (#6)
b end @jumps to end
add2:
ldr, var @loads var 8004 (#4)
ldrb, [r1, #0x4] @loads the byte in var 8006 (#4)
add r1, r3, r1 @adds the stat offset to var 8006 then places the sum in rq (#5, #6)
b end @jumps to end
end:
pop {r1-r4, pc} @pops all registers I used, AAAARRRRRGH! It should be pop {r0-r4, pc} (#1)
.align 2
var .word 0x020370c0
Stat .word 0x02024284
Spoiler:
#1: Since r4 won't be used, IMO {r0-r3,lr/pc} is safer. You should check available bytes in SP first
#2: This step is redundant.
#3: IIRC, it's 2 byte per stat, so you should multiply r3 by 2 first.
#4: r1 isn't usable due to #3. Use r0 instead.
#5: The value in r1 should be loaded first into r3 (ldrh). Then, use sub/add r3, r3, r0 instead, assuming you're using r0 and r3 as I've mentioned.
#6: At this rate, you should store the value of r3 into r1 (strh instead of strb). Also, put r3 between limit (0 - 999) before storing them.
#1: Since r4 won't be used, IMO {r0-r3,lr/pc} is safer. You should check available bytes in SP first
#2: This step is redundant.
#3: IIRC, it's 2 byte per stat, so you should multiply r3 by 2 first.
#4: r1 isn't usable due to #3. Use r0 instead.
#5: The value in r1 should be loaded first into r3 (ldrh). Then, use sub/add r3, r3, r0 instead, assuming you're using r0 and r3 as I've mentioned.
#6: At this rate, you should store the value of r3 into r1 (strh instead of strb). Also, put r3 between limit (0 - 999) before storing them.
#1: If he doesn't use R4 he doesn't need to push/pop any registers...
__________________
A Pokemon that is discriminated!
Support squirtle and make it everyone's favourite.
It's not assuming, it's a standard. And may I ask how on earth you would check available space on the stack?
Since the only pokemon game I've ever hacked is R/S, I don't have any good example. In other GBA games, there are times where I need to push some registers (r0-r3) to insert a routine. I'm putting those just for insurance.
To check the availability of the stack, I'm checking all routines before and after this function. A function with SP modifying instruction can limit the space on the stack. If he calls the function inside a SP modifying function, there is a chance that pushing will overwrite important data.
Since the only pokemon game I've ever hacked is R/S, I don't have any good example. In other GBA games, there are times where I need to push some registers (r0-r3) to insert a routine. I'm putting those just for insurance.
To check the availability of the stack, I'm checking all routines before and after this function. A function with SP modifying instruction can limit the space on the stack. If he calls the function inside a SP modifying function, there is a chance that pushing will overwrite important data.
Since the game was compiled, it follows a rather strict calling convention. This means that routines that are designed to be called as functions (i.e. they are called and then return) do not need push/pop r0-r3 because these are reserved for arguments and return values - a caller assumes the callee will alter these values. This is always the case for functions. However, you may need to push these registers if you are modify existing functions by hooking into a routine. However, since the question was about a routine that was called from a script, we know it is a function; the script handler and function code for callasm expect r0-r3 to be messed up, thus we need not push them. Another point I should make is that LR is not used therefore pushing it is not necessary.
I assume stack overflow (for the user stack at least) is incredibly unlikely unless you are implementing a recursive function that uses stack space or you are allocating an absurd amount of space on the stack; I highly doubt you could overflow the stack just by pushing once. Have you ever seen the stack overflow?
__________________
A Pokemon that is discriminated!
Support squirtle and make it everyone's favourite.
Hi, so I am still a bit new to asm (very new actually..) and I am trying to copy an 8 byte long piece of code from FireRed's RAM, and place it somewhere else. Is there any way I can do that? For example, it takes whatever is at (said offset) and places it somewhere else. It doesn't have to be cut and pasted either (it can) but it could also just be copied and pasted. Thank you
Very soon I can fix the errors,
Loading the party slot is fine, it works perfectly
while Loading the Correct Stat isn't yet working, and
it only stores the value from 8006 in the stat, it doesn't add the current stat and the value in 8006
Scrollbar appears
Please review and fix the issues by reading the signature rules.
You must edit it to meet the limits set by the rules before you may remove the [sig-reason] code from your signature. Removing this tag will re-enable it.
Do not remove the tag until you fix the issues in your signature. You may be infracted for removing this tag if you do not fix the specified issues. Do not use this tag for decoration purposes.
Hey guys! I'm actually writing my very first (free-handed or should I say free-minded) routine and I'm stuck.
Is there something like a compare command in ASM?
Here's what I'm trying to do: Compare the values of 2 vars (0x8000 and 0x800D) and make it return to 0x800D 0x0 if 0x8000 is lower, 0x1 if it is equal and 0x2 if 0x8000 is greater than 0x800D. I just need instructions, not the code itself.
Oh and on a side note, when a var's value is 0 and when something is subtracted to it, it becomes 65535 minus the value you subtracted. Is there a way to counter this using ASM?
Hi, so I am still a bit new to asm (very new actually..) and I am trying to copy an 8 byte long piece of code from FireRed's RAM, and place it somewhere else. Is there any way I can do that? For example, it takes whatever is at (said offset) and places it somewhere else. It doesn't have to be cut and pasted either (it can) but it could also just be copied and pasted. Thank you
There are a variety of ways you can do this, and most depend on the alignment of the destination and source addresses. If both addresses are word aligned, one can simply:
Code:
ldr r0, source
ldmia r0!, {r1-r2} @ loads two words (8 bytes) into r1 and r2 starting from r0
ldr r0, dest
stmia r0!, {r1-r2} @ opposite of ldmia - stores to r0
@ This is the same as swi 0xC and the word variant of swi 0xB
@ Use those for bigger copies
However if the addresses aren't word aligned, or you can't guarantee that they will be, you must resort to memcpy. There is already an implementation of this function - see the FireRed IDB for addresses and parameters. Its basically a loop with ldrb and strb.
Quote:
Originally Posted by Lance32497
Very soon I can fix the errors,
Loading the party slot is fine, it works perfectly
while Loading the Correct Stat isn't yet working, and
it only stores the value from 8006 in the stat, it doesn't add the current stat and the value in 8006
@ Avoid MUL if possible. Use LSL for multiplying by a power of two
mov r3, #0x02
mul r0, r3
add r2, r0, r2
add r1, r1, r2
ldr r0, Var_8004
ldrb r0, [r0, #0x4]
lsr r0, #0x8
cmp r0, #0x1
bgt sub1
ldr r0, Var_8004
ldrb r0, [r0, #0x4]
add r1, r0, r1
strh r0, [r1]
cmp r1, #0xFF
bgt add_end
b end
sub1:
ldr r0, Var_8004
ldr r0, [r0, #0x4]
sub r1, r0, r1
strh r0, [r1]
cmp r1, #0x00
bgt sub_end
b end
add_end:
mov r1, #0xFF
@ You don't need to b end before the end label - it "falls through" automatically
b end
sub_end:
mov r1, #0x0
b end
end:
@ You don't need to push/pop any registers. r0-r3 don't
@ needed to be push for functions and you're not calling anything.
@ A simple bx lr to return will do
pop {r0-r3, pc}
To add to the stat, load the current value of the stat, add to it, then store it. Keep in mind that this stat increase will be lost when the stats are recalculated, which is quite often.
I have commented where you can improve. You should also comment your routines (and don't just explain the opcodes, explain your intention) and break them up into logical sections so its easier on the eye to read.
Quote:
Originally Posted by BlackWhiteRobin
Hey guys! I'm actually writing my very first (free-handed or should I say free-minded) routine and I'm stuck.
Is there something like a compare command in ASM?
Here's what I'm trying to do: Compare the values of 2 vars (0x8000 and 0x800D) and make it return to 0x800D 0x0 if 0x8000 is lower, 0x1 if it is equal and 0x2 if 0x8000 is greater than 0x800D. I just need instructions, not the code itself.
Oh and on a side note, when a var's value is 0 and when something is subtracted to it, it becomes 65535 minus the value you subtracted. Is there a way to counter this using ASM?
You will need to use a series of CMPs and conditional branches to set a register to the desired value. Then store the value in the target variable.
As for your second question on subtracting a value from 0: variables are treated as unsigned values by the scripting engine, so you couldn't use saved signed values reliably in a script. However, if you were to use the value only in ASM, you could use the load sign-extended halfword opcode (LDSH) to use that value as a signed half-word. This could represent -0x8000 to 0x7FFF. You would have to be careful to only load values you KNEW were signed with this, otherwise it could corrupt large unsigned values. It depends on what you want to use it for.
__________________
A Pokemon that is discriminated!
Support squirtle and make it everyone's favourite.
There are a variety of ways you can do this, and most depend on the alignment of the destination and source addresses. If both addresses are word aligned, one can simply:
Code:
ldr r0, source
ldmia r0!, {r1-r2} @ loads two words (8 bytes) into r1 and r2 starting from r0
ldr r0, dest
stmia r0!, {r1-r2} @ opposite of ldmia - stores to r0
@ This is the same as swi 0xC and the word variant of swi 0xB
@ Use those for bigger copies
However if the addresses aren't word aligned, or you can't guarantee that they will be, you must resort to memcpy. There is already an implementation of this function - see the FireRed IDB for addresses and parameters. Its basically a loop with ldrb and strb.
Thanks a ton! Hmm.. Well the address I'm trying to copy is a pointer to the code (the code is in different locations depending on the length the player chooses in game.. Its the player's name) so I can't exactly put the exact address of the code. I can put the offset of the pointer to it though right? (300500C)? Also, does the destination have to be in the ram or can it be in the game's offsets? Either should be fine. Thanks again.
You will need to use a series of CMPs and conditional branches to set a register to the desired value. Then store the value in the target variable.
As for your second question on subtracting a value from 0: variables are treated as unsigned values by the scripting engine, so you couldn't use saved signed values reliably in a script. However, if you were to use the value only in ASM, you could use the load sign-extended halfword opcode (LDSH) to use that value as a signed half-word. This could represent -0x8000 to 0x7FFF. You would have to be careful to only load values you KNEW were signed with this, otherwise it could corrupt large unsigned values. It depends on what you want to use it for.
Not to sound super noobish but how would I use THUMB.16 in a code? Like a sample or something?
Thanks a ton! Hmm.. Well the address I'm trying to copy is a pointer to the code (the code is in different locations depending on the length the player chooses in game.. Its the player's name) so I can't exactly put the exact address of the code. I can put the offset of the pointer to it though right? (300500C)? Also, does the destination have to be in the ram or can it be in the game's offsets? Either should be fine. Thanks again.
You can't use a pointer to the pointer. You have to dereference it before copying, otherwise you'll copy the wrong thing. E.g.
Code:
ldr r0, =0x300500C
@ r0 is pointing to another pointer so copying from here will result in
@ the pointer being copied, not the data
ldr r0, [r0] @ dereference
@ Now you can copy from/to r0 as it is now pointing to data
Of course, since the data is being moved constantly (probably with DMA), it's almost certainly word or halfword aligned (aligned copies will be faster). Check the alignment of the pointers in a debugger if you are unsure.
The destination of course has to be in the RAM, as you can't write to the ROM. The source can be in the ROM.
Quote:
Originally Posted by BlackWhiteRobin
Not to sound super noobish but how would I use THUMB.16 in a code? Like a sample or something?
I'd guess. THUMB.16 C I got that wrong didn't I?
Uhh, that's the section number. I was referring to the opcodes BEQ, BNE, BCS etc. Those are called conditional branches because they jump to a different location if a certain condition is true. If you look at a tree diagram of the code, it forks the path of execution at the branches, hence the name. They're a way of performing certain actions only if a condition is true. You can do:
You can't use a pointer to the pointer. You have to dereference it before copying, otherwise you'll copy the wrong thing. E.g.
Code:
ldr r0, =0x300500C
@ r0 is pointing to another pointer so copying from here will result in
@ the pointer being copied, not the data
ldr r0, [r0] @ dereference
@ Now you can copy from/to r0 as it is now pointing to data
Of course, since the data is being moved constantly (probably with DMA), it's almost certainly word or halfword aligned (aligned copies will be faster).[URL="http://www.pokecommunity.com/#82366744"] Check the alignment of the pointers in a debugger if you are unsure.
The destination of course has to be in the RAM, as you can't write to the ROM. The source can be in the ROM.
That was a pretty foolish question, the ram or rom question.. Wasn't thinking straight :/ But anyway I tried dereferencing 300500C (at least I think) and it still will not copy it to the offset stated. Well, this is what I have:
As you can see I did what you said by loading r0 again with ldr r0, [r0]. I guess it should copy it to 0x84EE00 (just a test offset I used), do you spot anything thats wrong or anything I'm missing? Sorry for so many questions.. I hope I'm not sounding rude :/ )