Binary Hack Research & DevelopmentGot a well-founded knack with your binary Pokémon hacks? Love reverse-engineering them? For the traditional Pokémon ROM hacker, this is the spot for polling and gathering your ideas, and then implementing them! Share your hypothesis, get ideas from others, and collaborate to create!
Change the A9 at 0x9FD54 to C5 and then try to callasm 0x809FD31. (It's from my old note in firered db, so i'm not sure whether it's correct or not...)
Yep, that worked, thanks! :)
EDIT: actually it turns out that edits the players name instead of the rival's name
EDIT 2: looks like setting 0xA9 at 0x9FCB4 0xC5 fixed both naming the player and Jambo's routine (or I had made a mistake using it initially). Setting 0xA9 at 0x9FD54 to 0xC5 doesn't appear to change this either, but callasm 0x809FD31 will overwrite the player's name instead of the rival's
The user Andrea make this awesome ASM for icon in menu like DPPt,
Quote:
Originally Posted by ~Andrea
Hello everyone, today I would share with you this little patch:
As you can see from the screen, the patch will add the icons of the DPP next to each menu item.
- ONLY FOR RUBY -
Note:
- If the menu item "Pokenav" should be active, the icons will be loaded out of phase respect to the corresponding menu item.
This is caused by the lack of an icon for Pokenav in DPP.
Technical information:
Offsets routine: 0x720000
Offset Images Icons (uncompressed): 0x7200D0
Offset Palette icons (uncompressed): 0x720610
To change icons you can open the ROM with NSE 2.X, click browse and input offsets earlier in the appropriate fields.
i no have knlowledge for ASM and i really love with some ASM expert convert it for FIRE RED and EMERALD, because it is very beautifull, and make a awesome hack improve.
BUGS:
-No have icon for dex nav- when this flag is active bug it (R, EM)
-when the player enter in map with some wheater the icons bug, probably are using same location memory pal used for it
The first is completely configurable (when you compile it), and the changes you need to make to do so are very simple and explained well in the code:
Spoiler:
Code:
.text
.align 2
.thumb
@ 0x6FE9E: 0A 31 00 48 00 47 XX+1 XX XX XX (original: 64 20 44 43 64 34 05 48 21 1C)
main:
@ at this point, r4 contains the "levels gained"
@ when we're finished, r4 will contain the money amnt
@ r0-r4 are all safe to use here, *however*: r1 contains
@ the address this routine was jumped to from, and using
@ that we can jump back there easier.
@
@ the original code we're replacing, for reference:
@ mov r0, #100
@ mul r4, r0
@ add r4, #100
@ need to copy r1 to r3 because r1 is clobbered later
mov r3, r1
@ adjust the following code like so:
@ mov r0, #BASE_PER_LEVEL_COST
@ mov r1, #PER_LEVEL_COST_MULTIPLIER
@ ...
mov r0, #100
mov r1, #2
mul r0, r1
@ ...
@ and adjust this like so:
@ mov r2, #BASE_MINIMUM_COST
@ mov r1, #MINIMUM_COST_MULTIPLIER
mov r2, #100
mov r1, #2
mul r2, r1
mul r4, r0 @ cost = levels gained * per level cost
add r4, r2 @ cost += minimum cost
@ the following instructions were chopped off to insert jump to this routine
ldr r0, .dword_806FEBC
mov r1, r4
@ resume execution of the original code
bx r3
.align 2
.dword_806FEBC:
.word 0x02021DC4
The second is a little different. Rather than a configurable multiplier, it uses the "XP per step" value as the multiplier, so if you're using this modification to adjust the XP per step amount it will scale the daycare cost accordingly, e.x. 2 XP per step will multiply the normal daycare cost by 2:
Spoiler:
Code:
.text
.align 2
.thumb
@ 0x6FE9E: 0A 31 00 48 00 47 XX+1 XX XX XX (original: 64 20 44 43 64 34 05 48 21 1C)
main:
@ at this point, r4 contains the "levels gained"
@ when we're finished, r4 will contain the money amnt
@ r0-r4 are all safe to use here, *however*: r1 contains
@ the address this routine was jumped to from, and using
@ that we can jump back there easier.
@
@ the original code we're replacing, for reference:
@ mov r0, #100
@ mul r4, r0
@ add r4, #100
@ need to copy r1 to r3 because r1 is clobbered later
mov r3, r1
mov r0, #100
ldr r1, .xp_per_step
ldrb r1, [r1]
mul r0, r1
mul r4, r0 @ cost = levels gained * per level cost
add r4, r0 @ cost += minimum cost
@ the following instructions were chopped off to insert jump to this routine
ldr r0, .dword_806FEBC
mov r1, r4
@ resume execution of the original code
bx r3
.align 2
.xp_per_step:
.word 0x08070AE8
.dword_806FEBC:
.word 0x02021DC4
Quote:
Originally Posted by mbcn10ww
sorry but can you port it to Fire Red?
I am planning on porting the stuff I've done for Emerald to Fire Red soon. I just got back into playing the Gen III games a little while ago and decided to start with Emerald for some reason.
EDIT: Made some changes to the original code I posted to make it more compact/efficient. For those that were already using the old version, note that the first 2 bytes of the byte edit required have also been changed.
1) Load 240x160 static images into BG1 or BG2 using (image, palette, RAW) table and allow (if possible) use BG0 to load texts (as in the presentation of Oak, Pokédex, etc.) and objects like pokepic, Mugshots, etc. And their respective routine to remove the image. If it is very difficult or impossible with ASM, it can be a routine that loads the image in BG0 and its respective routine to remove it. What I want to do is cinematic with frame sequences. I can not use the diploma hack because I need to make decisions by pressing the A, B and the arrow keys.
I tried this routine: FR - Vs. Bar Personalizable but it has no routine to remove the image so in the end I have to do a warp to refresh the screen and erase the image . Finally after 5 continuous frames the game freezes.
2) Load different dialogs in the presentation of Oak depending on the selected genre. What I want to do is a multi-language effect depending on gender. Example: Boy = Spanish, Girl = English.
1) Load 240x160 static images into BG1 or BG2 using (image, palette, RAW) table and allow (if possible) use BG0 to load texts (as in the presentation of Oak, Pokédex, etc.) and objects like pokepic, Mugshots, etc. And their respective routine to remove the image. If it is very difficult or impossible with ASM, it can be a routine that loads the image in BG0 and its respective routine to remove it. What I want to do is cinematic with frame sequences. I can not use the diploma hack because I need to make decisions by pressing the A, B and the arrow keys.
I tried this routine: FR - Vs. Bar Personalizable but it has no routine to remove the image so in the end I have to do a warp to refresh the screen and erase the image . Finally after 5 continuous frames the game freezes.
2) Load different dialogs in the presentation of Oak depending on the selected genre. What I want to do is a multi-language effect depending on gender. Example: Boy = Spanish, Girl = English.
for the first one, try this
for your second request, just use the checkgender command and branch accordingly. i believe it returns 0 for male and 1 for female
para tu primer, prueba esta rutina
para tu segundo, usa "checkgender" y haz lo que necesitas. creo que vuelve 0 si eres hombre y 1 si eres mujer
pd: doesn't use bg0. can switch it to any other bg easily tho, edit for text and lay an rbox above or something
The first is completely configurable (when you compile it), and the changes you need to make to do so are very simple and explained well in the code:
Spoiler:
Code:
.text
.align 2
.thumb
@ 0x6FE9E: C0 46 00 48 00 47 XX+1 XX XX XX (original: 64 20 44 43 64 34 05 48 21 1C)
main:
@ at this point, r4 contains the "levels gained"
@ when we're finished, r4 will contain the money amnt
@ r0-r4 are all safe to use here.
@
@ the original code:
@ mov r0, #100
@ mul r4, r0
@ add r4, #100
@ adjust the following code like so:
@ mov r0, #BASE_PER_LEVEL_COST
@ mov r1, #PER_LEVEL_COST_MULTIPLIER
@ mov r2, #BASE_MINIMUM_COST
@ mov r3, #MINIMUM_COST_MULTIPLIER
mov r0, #100
mov r1, #2
mov r2, #100
mov r3, #2
mul r0, r1
mul r2, r3
mul r4, r0 @ cost = levels gained * per level cost
add r4, r2 @ cost += minimum cost
@ the following instructions were chopped off to insert jump to this routine
ldr r0, .dword_806FEBC
mov r1, r4
@ resume execution of the original code
ldr r2, .continue_function
bx r2
.align 2
.dword_806FEBC:
.word 0x02021DC4
.continue_function:
.word 0x0806FEA8|1
The second is a little different. Rather than a configurable multiplier, it uses the "XP per step" value as the multiplier, so if you're using this modification to adjust the XP per step amount it will scale the daycare cost accordingly, e.x. 2 XP per step will multiply the normal daycare cost by 2:
Spoiler:
Code:
.text
.align 2
.thumb
@ 0x6FE9E: C0 46 00 48 00 47 XX+1 XX XX XX (original: 64 20 44 43 64 34 05 48 21 1C)
main:
@ at this point, r4 contains the "levels gained"
@ when we're finished, r4 will contain the money amnt
@ r0-r4 are all safe to use here.
@
@ the original code:
@ mov r0, #100
@ mul r4, r0
@ add r4, #100
mov r0, #100
ldr r1, .xp_per_step
ldrb r1, [r1]
mul r0, r1
mul r4, r0 @ cost = levels gained * per level cost
add r4, r0 @ cost += minimum cost
@ the following instructions were chopped off to insert jump to this routine
ldr r0, .dword_806FEBC
mov r1, r4
@ resume execution of the original code
ldr r2, .continue_function
bx r2
.align 2
.xp_per_step:
.word 0x08070AE8
.dword_806FEBC:
.word 0x02021DC4
.continue_function:
.word 0x0806FEA8|1
I am planning on porting the stuff I've done for Emerald to Fire Red soon. I just got back into playing the Gen III games a little while ago and decided to start with Emerald for some reason.
Thank you for the reply. You're doing a great work with your routines, I like the way you explain them, it becomes very easy to understand for people who haven't learned ASM (or are learning like me), nice work.
Thank you for the reply. You're doing a great work with your routines, I like the way you explain them, it becomes very easy to understand for people who haven't learned ASM (or are learning like me), nice work.
Thanks, I appreciate hearing that. My code comments can be a little excessive, but with reverse-engineering stuff I like to make notes of anything relevant in case I revisit it later. Glad it's helpful for you too.
for the first one, try this
for your second request, just use the checkgender command and branch accordingly. i believe it returns 0 for male and 1 for female
pd: doesn't use bg0. can switch it to any other bg easily tho, edit for text and lay an rbox above or something
Thanks for the prompt response!
1) I only need to load images (preferably compressed in LZ77) from a table through the control of a variable, in BG1 or BG2 to be able to use the BG0 text box. I think I can do it from the example you left me, although I assume that it does not work with compressed images. Really thank you very much. I am starting in ASM and would like to learn more. And of course how to erase that image, the rest would do with scripting controlling the variable. Finally what doo to do is a system of choice of the initial pokémon this way:
So I just need 2 routines. One that loads the image in with the following features preferably:
- That depends on the value of a variable (I can do it)
- Use a table (image) (pal) (raw) (I can do it)
- 16 colors (I can do it)
- Image compressed in LZ77 (since I need to insert many images)
- Use BG1 or BG2 to use the BG0 to load text boxes and OBJ
And another one that safely removes the image from said background
2) What I wanted was for the genre to be selected in Oak's presentation, immediately after selecting boy to show a text; And if you select girl it would show another different text. For example:
And here I need to know how to point to the next text depending on the gender selected.
Thank you in advance for the help you can give me.
PD: Gifs are not made since the rom, they were made with sequences of images obviously.
Hi everyone, does anyone knows how to remove the Field Moves options (like Flash, Dig, Fly...) from the Pokémon menu? Because I want to move them to some place but don't know how to make them never show up when I teach the respective move to a Pokémon. Thanks in advance.
This is kind of a continuation of this post. To put it simply, if you put a Bulbasaur and an Ivysaur in the daycare, they produce fewer eggs than if you paired two Bulbasaurs or two Ivysaurs. This changes it so the Bulbasaur+Ivysaur pair produce the same amount of eggs as a Bulbasaur pair (meaning more than they used to).
Code:
.text
.align 2
.thumb
.thumb_func
@ 0x70D88: 00 48 00 47 XX+1 XX XX XX (original: 20 1C 0B 21 F9 F7 72 FC)
main:
mov r0, r4 @ move pointer to pokemon to r0
mov r1, #0xB @ req_species
ldr r2, .pokemon_getattr_encrypted
bl x_r2
@ r0 now contains the species index, which the game *used* to use.
@ instead, replace it with the offspring index, so different Pokemon
@ from the same evolution chain are properly recognized as the same species
@ (e.x. breeding a Charmander and Charizard works as well as 2 Charmanders does)
ldr r2, .determine_offspring_from_species_index
bl x_r2
@ go back to where we came from. (this falls through to the bx r2 below)
ldr r2, .resume_execution
x_r2:
bx r2
.align 2
.pokemon_getattr_encrypted:
.word 0x0806A674|1
.determine_offspring_from_species_index:
.word 0x08070004|1
.resume_execution:
.word 0x08070D90|1
I've been trying to study how to decrypt/encrypt a pokemon in party all day and I think the routine would be fairly short and simple but I just don't get how to set up the routine. This page shows a brief explanation and the offsets for decrypting/encrypting: http://www.romhack.me/database/23/fire-red-commonly-used-asm-rom-offsets/ . All I know is that there should be a 'mov r1, 0x#C' (held item) somewhere in the routine. Also are we supposed to decrypt a pokemon before encrypting?
Decrypt and encrypt is a misnomer, it actually should be something like get_attribute and set_attribute or something. To encrypt, or set an attribute, you need to have the pointer to the pokemon structure in r0. r1 is the attribute to set, and r2 must be the pointer to the thing you're setting. Here's an example.
Code:
.thumb
main:
@get the address in r0
mov r1, #0x24 @catch level
mov r2, #0x10
push {r2}
mov r2, sp
bl encrypt
pop {r2}
This sets the catch level to 16. Now, I don't know why you'd want to set the catch level to something else, but you can do it. You can also just store the thing for r2 in some RAM address but I don't know an open word. And yes, the data must be stored as a word, so using var 0x8009 or whatever probably won't work.
JPAN had as part of his engine a way to make wild Pokemon and Trainers have dynamic levels (you can set a variable to certain values to change the levels to your liking, for example: setting the variable to 0x100 makes Wild/Trainer Pokemon levels match your highest Pokemon.)
However I've noticed that this doesn't seem to work with scripted battles (aka setwildbattle). It just uses the level that you buffered regardless of the routine.
Is there a way to make scripted battles have levels that match your highest level Pokemon?
__________________
"The human sacrificed himself, to save the Pokemon. I pitted them against each other, but not until they set aside their differences did I see the true power they all share deep inside. I see now that the circumstances of one's birth are irrelevant; it is what you do with the gift of life that determines who you are." -Mewtwo
FR has different stat summary screen display from Emerald, so you can't really change offsets. You're in luck though, as I wrote a routine that does that in EM.
LeftStats color change:
I combined this into 1 routine and cut the total size down a lot. All credit to DizzyEgg of course, this is nothing compared to creating the mod in the first place.
Code:
.text
.thumb
.thumb_func
.align 2
@ 0x1C379E: 02 30 00 4A 10 47 XX+1 XX XX 08
@ 0x1C3864: 00 4A 10 47 XX+1 XX XX 08
main:
@ at this point... r0 contains our return address (- 8). Convenient!
push {r5-r7}
@ save return address for later.
mov r6, r0
add r6, #0x8
@ to determine what function we were called from:
@ if it was right stats, r9 is 0. if it was left stats, r9 has something in it.
mov r7, r9 @ can't really use hi registers in thumb, mov it down.
@ so, to check the function type: cmp r7, #0. eq means right stats.
sub sp, sp, #0x20
ldr r0, [r4] @pokemon summary pointer. we're free to use r4 after this.
add r0, #0xA3 @poke nature
ldrb r1, [r0]
ldr r0, nature_stat_table
mov r2, #5
mul r2, r1
mov r1, sp
mov r5, #0
add r2, r2, r0 @r2 contains nature info
cmp r7, #0
beq right_stats_begin
@@ LEFT STAT COLORING BEGIN @@@
left_stats_begin:
ldr r3, left_stats_string
handle_hp:
ldrb r0, [r3, r5]
strb r0, [r1, r5]
add r5, #1
cmp r5, #6
bne handle_hp
add r3, #6
add r1, #6
mov r5, #0
handle_atk:
ldrb r0, [r2]
cmp r0, #1
beq red_font_atk
cmp r0, #0xFF
bne copy_atk
bl blue_font
b copy_atk
red_font_atk:
bl red_font
copy_atk:
ldrb r0, [r3, r5]
strb r0, [r1, r5]
add r5, #1
cmp r5, #3
bne copy_atk
add r3, #3
add r1, #3
mov r5, #0
handle_def:
add r2, #1
ldrb r0, [r2]
cmp r0, #1
beq red_font_def
cmp r0, #0xFF
beq blue_font_def
bl default_font
b copy_def
red_font_def:
bl red_font
b copy_def
blue_font_def:
bl blue_font
copy_def:
ldrb r0, [r3, r5]
strb r0, [r1, r5]
add r5, #1
cmp r5, #3
bne copy_def
b return
@@@ LEFT STAT COLORING END @@
@@@ RIGHT STAT COLORING BEGIN @@@
right_stats_begin:
add r2, #3 @r2 contains beg of spatk stat
ldr r3, right_stats_string
handle_spatk:
ldrb r0, [r2]
cmp r0, #1
beq red_font_spatk
cmp r0, #0xFF
bne copy_spatk
bl blue_font
b copy_spatk
red_font_spatk:
bl red_font
copy_spatk:
ldrb r0, [r3, r5]
strb r0, [r1, r5]
add r5, #1
cmp r5, #3
bne copy_spatk
add r3, #3
add r1, #3
mov r5, #0
handle_spdef:
add r2, #1
ldrb r0, [r2]
cmp r0, #1
beq red_font_spdef
cmp r0, #0xFF
beq blue_font_spdef
bl default_font
b copy_spdef
red_font_spdef:
bl red_font
b copy_spdef
blue_font_spdef:
bl blue_font
copy_spdef:
ldrb r0, [r3, r5]
strb r0, [r1, r5]
add r5, #1
cmp r5, #3
bne copy_spdef
add r3, #3
add r1, #3
mov r5, #0
handle_spd:
sub r2, #2
ldrb r0, [r2]
cmp r0, #1
beq red_font_spd
cmp r0, #0xFF
beq blue_font_spd
bl default_font
b copy_spd
red_font_spd:
bl red_font
b copy_spd
blue_font_spd:
bl blue_font
copy_spd:
ldrb r0, [r3, r5]
strb r0, [r1, r5]
add r5, #1
cmp r5, #3
bne copy_spd
b return
@@@ RIGHT STAT COLORING END @@@
@@@ FONT FUNCTIONS BEGIN @@@
blue_font: @FC 01 07
mov r4, #7 @color of the lowered stat
b font_common
red_font: @FC 01 05
mov r4, #5 @color of the raised stat
b font_common
default_font: @FC 01 01
mov r4, #1 @color of the regular stats
@ just fall through to font_common (no need to branch)
font_common:
mov r0, #0xFC
strb r0, [r1]
add r1, #1
mov r0, #1
strb r0, [r1]
add r1, #1
strb r4, [r1]
add r1, #1
bx lr
@@@ FONT FUNCTIONS END @@@
return:
ldr r0, displayed_string
mov r1, sp
ldr r2, special_f7_string_fct
bl x_r2
cmp r7, #0
beq skip_mov_r0_r9
mov r0, r9
skip_mov_r0_r9:
add sp, sp, #0x20
mov r2, r6
pop {r5-r7}
x_r2:
bx r2
.align 2
nature_stat_table: .word 0x0831E818
left_stats_string: .word 0x0861CE82
right_stats_string: .word 0x0861CE8E
displayed_string: .word 0x02021FC4
special_f7_string_fct: .word 0x081AFC29
I combined this into 1 routine and cut the total size down a lot. All credit to DizzyEgg of course, this is nothing compared to creating the mod in the first place.
Code:
.text
.thumb
.thumb_func
.align 2
@ 0x1C379E: 02 30 00 4A 10 47 XX+1 XX XX 08
@ 0x1C3864: 00 4A 10 47 XX+1 XX XX 08
main:
@ at this point... r0 contains our return address (- 8). Convenient!
push {r5-r7}
@ save return address for later.
mov r6, r0
add r6, #0x8
@ to determine what function we were called from:
@ if it was right stats, r9 is 0. if it was left stats, r9 has something in it.
mov r7, r9 @ can't really use hi registers in thumb, mov it down.
@ so, to check the function type: cmp r7, #0. eq means right stats.
sub sp, sp, #0x20
ldr r0, [r4] @pokemon summary pointer. we're free to use r4 after this.
add r0, #0xA3 @poke nature
ldrb r1, [r0]
ldr r0, nature_stat_table
mov r2, #5
mul r2, r1
mov r1, sp
mov r5, #0
add r2, r2, r0 @r2 contains nature info
cmp r7, #0
beq right_stats_begin
@@ LEFT STAT COLORING BEGIN @@@
left_stats_begin:
ldr r3, left_stats_string
handle_hp:
ldrb r0, [r3, r5]
strb r0, [r1, r5]
add r5, #1
cmp r5, #6
bne handle_hp
add r3, #6
add r1, #6
mov r5, #0
handle_atk:
ldrb r0, [r2]
cmp r0, #1
beq red_font_atk
cmp r0, #0xFF
bne copy_atk
bl blue_font
b copy_atk
red_font_atk:
bl red_font
copy_atk:
ldrb r0, [r3, r5]
strb r0, [r1, r5]
add r5, #1
cmp r5, #3
bne copy_atk
add r3, #3
add r1, #3
mov r5, #0
handle_def:
add r2, #1
ldrb r0, [r2]
cmp r0, #1
beq red_font_def
cmp r0, #0xFF
beq blue_font_def
bl default_font
b copy_def
red_font_def:
bl red_font
b copy_def
blue_font_def:
bl blue_font
copy_def:
ldrb r0, [r3, r5]
strb r0, [r1, r5]
add r5, #1
cmp r5, #3
bne copy_def
b return
@@@ LEFT STAT COLORING END @@
@@@ RIGHT STAT COLORING BEGIN @@@
right_stats_begin:
add r2, #3 @r2 contains beg of spatk stat
ldr r3, right_stats_string
handle_spatk:
ldrb r0, [r2]
cmp r0, #1
beq red_font_spatk
cmp r0, #0xFF
bne copy_spatk
bl blue_font
b copy_spatk
red_font_spatk:
bl red_font
copy_spatk:
ldrb r0, [r3, r5]
strb r0, [r1, r5]
add r5, #1
cmp r5, #3
bne copy_spatk
add r3, #3
add r1, #3
mov r5, #0
handle_spdef:
add r2, #1
ldrb r0, [r2]
cmp r0, #1
beq red_font_spdef
cmp r0, #0xFF
beq blue_font_spdef
bl default_font
b copy_spdef
red_font_spdef:
bl red_font
b copy_spdef
blue_font_spdef:
bl blue_font
copy_spdef:
ldrb r0, [r3, r5]
strb r0, [r1, r5]
add r5, #1
cmp r5, #3
bne copy_spdef
add r3, #3
add r1, #3
mov r5, #0
handle_spd:
sub r2, #2
ldrb r0, [r2]
cmp r0, #1
beq red_font_spd
cmp r0, #0xFF
beq blue_font_spd
bl default_font
b copy_spd
red_font_spd:
bl red_font
b copy_spd
blue_font_spd:
bl blue_font
copy_spd:
ldrb r0, [r3, r5]
strb r0, [r1, r5]
add r5, #1
cmp r5, #3
bne copy_spd
b return
@@@ RIGHT STAT COLORING END @@@
@@@ FONT FUNCTIONS BEGIN @@@
blue_font: @FC 01 07
mov r4, #7 @color of the lowered stat
b font_common
red_font: @FC 01 05
mov r4, #5 @color of the raised stat
b font_common
default_font: @FC 01 01
mov r4, #1 @color of the regular stats
@ just fall through to font_common (no need to branch)
font_common:
mov r0, #0xFC
strb r0, [r1]
add r1, #1
mov r0, #1
strb r0, [r1]
add r1, #1
strb r4, [r1]
add r1, #1
bx lr
@@@ FONT FUNCTIONS END @@@
return:
ldr r0, displayed_string
mov r1, sp
ldr r2, special_f7_string_fct
bl x_r2
cmp r7, #0
beq skip_mov_r0_r9
mov r0, r9
skip_mov_r0_r9:
add sp, sp, #0x20
mov r2, r6
pop {r5-r7}
x_r2:
bx r2
.align 2
nature_stat_table: .word 0x0831E818
left_stats_string: .word 0x0861CE82
right_stats_string: .word 0x0861CE8E
displayed_string: .word 0x02021FC4
special_f7_string_fct: .word 0x081AFC29
Good job :). I was pretty lazy back then and just duplicated the font functions :D.
Seems you're quite proficient in ASM. Wonder if you use IDE?
Good job :). I was pretty lazy back then and just duplicated the font functions :D.
Seems you're quite proficient in ASM. Wonder if you use IDE?
Thanks! Did you mean to ask if I use IDA? If so, yes. Been using it for years now, mainly with Android OS development (patching old closed-source libs to work on newer Android versions for example). This is my first time writing any substantial assembly though, just so happens that reading assembly the past few years translated well into writing it.
In a way, ARM assembly is really not that different from programming in high-level languages like C. I just look at all the opcodes like functions, registers are variables, etc. Just takes more steps to do a particular task.
I've also made use of the no$gba debugger, that's how I find tricks to save instructions, like r0 containing a return address and the usage of r9 to determine which code to run for the stat coloring merger.
Thanks! Did you mean to ask if I use IDA? If so, yes. Been using it for years now, mainly with Android OS development (patching old closed-source libs to work on newer Android versions for example). This is my first time writing any substantial assembly though, just so happens that reading assembly the past few years translated well into writing it.
In a way, ARM assembly is really not that different from programming in high-level languages like C. I just look at all the opcodes like functions, registers are variables, etc. Just takes more steps to do a particular task.
I've also made use of the no$gba debugger, that's how I find tricks to save instructions, like r0 containing a return address and the usage of r9 to determine which code to run for the stat coloring merger.
I think he wants to set a default name while skipping the intro. If you skip the intro via ASM, the default name is left as 0s aka blank.
Setting a static name to the player
Well, this is beyond simple, lol. I'll keep my post the same format though, because first post :3
How to insert:
Before you begin to insert the routine, there are a few steps. Firstly player names are limited to 8 characters with the eighth character = 0xFF.
Convert the static name you want from ascii to hex. For OP, he wanted Jesse and James which convert into:
C4 D9 E7 E7 D9 FF FF FF - Jesse
C4 D5 E1 D9 E7 FF FF FF -James
Note that if all eight bytes don't get used, you should pad them with "FF" in your hex editor.
Now insert the 8 byte names into some free space in your ROM via hex editor and write down the pointers.
Now copy the following routine into a text editor:
Change the [email protected] text to 0x[offset you inserted]. No need to add one.
After you've done that compile and insert into free space.
Usage:
You must callasm to the routine, and depending on the Player's gender it will set their name. To have their name inserted before the player starts playing the game, create a level script which calls this routine. If you don't know how, ask in a relevant thread (not here).
Hi, well I did exactly what you said but now my gba file just shows a blank screen when loaded into the emulator. What should I do?
Location: Johto. Or, to be serious, Massachusetts.
Gender:
Male
Nature: Quirky
Posts: 100
Hey, IDK if it is possible, but could it be made so the battle text auto-advances when in battle (like Gen 4)?
So, instead of being required to press A during certain parts (example: challenge, faint, disable, level up, etc), after 1 second, the next line will load. But you can interrupt it with A as well
I can make it automatically skip by editing the hex, but it does it immediately.
Basically, in it's current state, this is effectively a storage system. It stores Pokemon and can be interacted with by the player to withdraw or deposit Pokemon. It's standalone from the PC storage system and is also much smaller (I've limited it to 6, but it can go upto 47). Some things that you will be able to do with this routine (and conjunction with some smaller ones) include:
- Extra Pokemon storage, you can possibly get a little over 1 box worth
- Flash back battles (complete swap between stored Pokemon and party Pokemon with capabilities to swap back)
- Carry a party of greater than 6 Pokemon (you can use the 2nd party for HM slaves, or whatever)
- Trade evolver guy! He will take your Pokemon and then when you come back it can be evolved! (silent evolution ftw!)
- Separate Daycare holding larger amount of Pokemon at once
I've tested it thoroughly and there doesn't seem to be any problems. I will be adding more and more features into this because I believe that it has the potential to become a very useful feature.
Currently planning to add:
- Party swap completely all in one go (this will actually be in the very near future..maybe today even :P)
- Partial swapping (believe it or not, this is hard because there's no graphical support)
- Suggest me more :D
The routine itself manages party storage and storage extraction. What you need to do is determine which one it performs.
If you want to remove a Pokemon from the party and into storage, setvar 0x8000 anything but zero
if you want to remove a Pokemon from storage, setvar 0x8000 0x0
Which variable you used can be changed, as always, by editing the pointer at the bottom of the routine.
The next thing is variable 0x8004. I use this variable to determine the slot of extraction for both the Party and the Storage system.
If I wanted to take the 3rd Pokemon in the party and put it in storage:
setvar 0x8004 0x2
setvar 0x8000 0x1
callasm 0x[routine] +1
The reason for this is to support easy use of special 0x9F. Though you can use copyvar, I suppose.
Finally, the routine writes to RAM a counter, which keeps track of how many Pokemon are in the storage.
This is written at 0x203C000, and can be retrieved by using the "copybyte" scripting command. For example:
copybyte 0x20370D0 0x203C000 'puts the storage counter into variable 0x800D (lastresult).
I tried to keep it simple, and do the work inside the routine, hopefully that paid off.
Here's a very poor sample script. Poor because it handles all the cases, but it doesn't display the system's full potential :P
Spoiler:
PKSV script.
Code:
#dyn 0x740000
#org @start
lock
faceplayer
copybyte 0x20370D0 0x203C000 ' storage count into last result
compare LASTRESULT 0x0
if == jump @putOnly
msgbox @add
callstd MSG_YESNO 'want to take?
compare LASTRESULT 0x1
if == jump @addParty
jump @putOnly
#org @putOnly
countpokemon
copyvar 0x8000 0x800D
compare 0x8000 0x1
if <= jump @greetings
msgbox @put
callstd MSG_YESNO 'want to put?
compare LASTRESULT 0x1
if == jump @addStorage
msgbox @exit
callstd MSG_NORMAL
release
end
#org @addStorage
setvar 0x8000 0x1
special 0x9F
waitspecial
countpokemon
compare LASTRESULT 0x8004
if < jump @noSelection
callasm 0x[routine +1]
msgbox @gave
callstd MSG_NORMAL
release
end
#org @addParty
setvar 0x8000 0x0
countpokemon
compare LASTRESULT 0x6
if == jump @fullP
msgbox @store
callstd MSG_NORMAL
setvar 0x8004 0x0 'gotta rework this to work a better way
callasm 0x[routine +1]
fanfare 0x101
msgbox @complete
callstd MSG_NORMAL
release
end
#org @greetings
msgbox @hello
callstd MSG_NORMAL
release
end
#org @fullP
msgbox @full
callstd MSG_NORMAL
release
end
#org @noSelection
msgbox @exit
callstd MSG_NORMAL
release
end
#org @full
= You're party is full!
#org @hello
= Hi, I can't do anything\nyour slots are full or empty\lor mine are full while yours are\lfull[.]
#org @complete
= I gave it back.
#org @store
= Alright, I'll give it to you.
#org @gave
= Thanks for giving me this.
#org @exit
= Alright, next time then.
#org @add
= Want your Pokemon back?
#org @put
= Want to give me a pokemon?
That's it for now. Keep an eye out for "addons" for this routine in the future :)
Sorry for the double post. I like seperate posts for my routines to keep the first post's links neat :x
So for anyone who has used this they know that only the Pre-Compiled version works, and the routine given does not compile to match either and don't work at all for that matter.
Also the Pre-Compiled version does work but has a bug from using Special 0x9F(Choose Pokemon from party).
If the player says yes to storing a Pokemon then decides to either press "B" or "Cancel" then the game will jump to the overworld view, glitch out and freeze with a Black screen.
Now I worked on this all day and was able to rebuild the Pre-Compiled routine so we could actually have the working source.
FBI's - Pre-Compiled Storage System - Disassembled/Rebuilt Routine
Code:
Code:
.text
.align 2
.thumb
.thumb_func
main:
push {r0, r4, lr}
ldr r0, .FROM
ldr r1,[r0]
cmp r1, #0x0 @party
beq addParty
addStorage:
ldr r0, .STORAGE
sub r0, #0x1
ldrb r1, [r0]
cmp r1, #0x6 @limit of storage. Change depending on your space situation
beq end
add r0, #0x1
mov r2, #0x50
mul r1, r2
add r0, r0, r1 @destination
ldr r1, =(0x20370C0) @ 2b Var_8004
ldrb r1, [r1]
ldr r2, .PARTY
mov r3, #0x64
mul r1, r3
add r1, r1, r2 @source
mov r2, #0x50 @size
ldr r3, =(0x8040B09) @memcpy_pkm 'void __fastcall memcpy_pkm(void *dst, void *src, unsigned int size)'
bl linker
ldr r1, =(0x20370C0) @need to fix up Player's party slots @ 2b Var_8004
ldrb r1, [r1]
cmp r1, #0x5
beq writeLastZero
mov r2, #0x5
sub r2, r2, r1
mov r3, #0x64
mul r2, r3 @size
ldr r0, .PARTY
mul r1, r3
add r0, r0, r1 @dest
add r3, r3, r0
mov r1, r3 @src
ldr r3, =(0x8040B09) @memcpy_pkm 'void __fastcall memcpy_pkm(void *dst, void *src, unsigned int size)'
bl linker
writeLastZero:
ldr r0, =(0x2024478) @ 100b Party Pokemon 6
mov r1, #0x0
mov r2, #0x64
ldr r3, =(0x81E5ED9) @memset 'void __fastcall memset(char *dst, char pattern, int size)'
bl linker
correctCounters:
ldr r0, .STORAGE
sub r0, #0x1
ldrb r2, [r0] @pks in storage counter
ldr r1, =(0x2024029) @ 1b Repeattrainerbattle: Unknown. Loaded if battle type is 9.
ldrb r3, [r1] @pks in party
add r2, #0x1
strb r2,[r0]
sub r3, #0x1
strb r3, [r1]
b end
addParty:
ldr r0, =(0x2024029) @ 1b Repeattrainerbattle: Unknown. Loaded if battle type is 9.
ldrb r0, [r0]
cmp r0, #0x6
beq end
ldr r1, .PARTY
mov r2, #0x64
mul r0, r2
add r0, r0, r1 @destination
mov r4, r0
ldr r3, .STORAGE
ldr r1, =(0x20370C0) @'var 0x8004 determines which slot of storage to take from'
ldrb r1, [r1]
mov r2, #0x50 @size
mul r1, r2
add r1, r1, r3 @source
ldr r3, =(0x8040B09) @memcpy_pkm 'void __fastcall memcpy_pkm(void *dst, void *src, unsigned int size)'
bl linker
mov r0, r4 @update stats
ldr r3, =(0x803E47D) @pokemon_calc_effective_stats
bl linker
ldr r0, =(0x20370C0) @adjust the storage @ 2b Var_8004
ldrb r0, [r0]
cmp r0, #0x5 @storage limit minus 1
beq writeZero
mov r2, #0x5
sub r2, r2, r0
mov r3, #0x50
mul r2, r3 @size
ldr r1, .STORAGE
mul r0, r3
add r0, r0, r1 @dest
add r3, r3, r0
mov r1, r3 @src
ldr r3, =(0x8040B09) @memcpy_pkm 'void __fastcall memcpy_pkm(void *dst, void *src, unsigned int size)'
bl linker
writeZero:
ldr r0, .STORAGE
mov r1, #0xC8
lsl r1, r1, #0x1
add r0, r0, r1
mov r1, #0x0
mov r2, #0x50
ldr r3, =(0x81E5ED9) @memset 'void __fastcall memset(char *dst, char pattern, int size)'
bl linker
updateCounters:
ldr r0, .STORAGE
sub r0, #0x1
ldrb r2, [r0]
ldr r1, =(0x2024029) @ 1b Repeattrainerbattle: Unknown. Loaded if battle type is 9.
ldrb r3, [r1]
sub r2, #0x1
strb r2,[r0]
add r3, #0x1
strb r3, [r1]
end:
pop {r0-r4, pc}
linker:
bx r3
.align 2
.FROM:
.word 0x20370B8 @var_8000
.STORAGE:
.word 0x203C001 @storage location
.PARTY:
.word 0x2024284 @player's party
And to go along with that is the XSE script.
Code:
Code:
#dynamic 0xFreeSpaceToStartFrom
//---------------
#org @start
lock
faceplayer
copybyte 0x20370D0 0x203C000
compare 0x800D 0x0
if 0x1 goto @snippet1
msgbox @string1 0x5 //"Want your Pokemon back?"
compare 0x800D 0x1
if 0x1 goto @snippet2
goto @snippet1
//---------------
#org @snippet1
countpokemon
copyvar 0x8000 0x800D
compare 0x8000 0x1
if 0x3 goto @snippet3
msgbox @string2 0x5 //"Want to give me a pokemon?"
compare 0x800D 0x1
if 0x1 goto @snippet4
msgbox @string3 0x6 //"Alright, next time then."
release
end
//---------------
#org @snippet2
setvar 0x8000 0x0
countpokemon
compare 0x800D 0x6
if 0x1 goto @snippet5
msgbox @string4 0x6 //"Alright, I'll give it to you."
setvar 0x8004 0x0
callasm 0xWhereYouPutYourTheRoutine+1
fanfare 0x101
msgbox @string5 0x6 //"I gave it back."
release
end
//---------------
#org @snippet3
msgbox @string6 0x6 //"Hi, I can't do anything\nyour slot..."
release
end
//---------------
#org @snippet4
setvar 0x8000 0x1
special 0x9F
waitstate
lockall
compare 0x8004 0x7
if 0x1 goto @snippet6
countpokemon
compare 0x800D 0x1
if 0x3 goto @snippet6
callasm 0xWhereYouPutYourTheRoutine+1
msgbox @string7 0x6 //"Thanks for giving me this."
release
end
//---------------
#org @snippet5
msgbox @string8 0x6 //"You're party is full!"
release
end
//---------------
#org @snippet6
msgbox @string3 0x6 //"Alright, next time then."
release
end
//---------
// Strings
//---------
#org @string1
= Want your Pokemon back?
#org @string2
= Want to give me a pokemon?
#org @string3
= Alright, next time then.
#org @string4
= Alright, I'll give it to you.
#org @string5
= I gave it back.
#org @string6
= Hi, I can't do anything\nyour slots are full or empty\lor mine are full while yours are\lfull[.]
#org @string7
= Thanks for giving me this.
#org @string8
= You're party is full!
Edit the orange text before compiling.
Hope this helps anyone.
When I get the time I will see what I can do about fixing the bug as well.
Edit_Two:
Found the bug!
Special 0x9F lets you choose any Pokemon as well as Eggs.
And,
Special 0xBC lets you choose any Pokemon beside Eggs(used for daycare)
When pressing B var 0x8004 is set to 0x07 so I simply added a compare to fix the script.
I think he wants to set a default name while skipping the intro. If you skip the intro via ASM, the default name is left as 0s aka blank.
Setting a static name to the player
Well, this is beyond simple, lol. I'll keep my post the same format though, because first post :3
How to insert:
Before you begin to insert the routine, there are a few steps. Firstly player names are limited to 8 characters with the eighth character = 0xFF.
Convert the static name you want from ascii to hex. For OP, he wanted Jesse and James which convert into:
C4 D9 E7 E7 D9 FF FF FF - Jesse
C4 D5 E1 D9 E7 FF FF FF -James
Note that if all eight bytes don't get used, you should pad them with "FF" in your hex editor.
Now insert the 8 byte names into some free space in your ROM via hex editor and write down the pointers.
Now copy the following routine into a text editor:
Change the [email protected] text to 0x[offset you inserted]. No need to add one.
After you've done that compile and insert into free space.
Usage:
You must callasm to the routine, and depending on the Player's gender it will set their name. To have their name inserted before the player starts playing the game, create a level script which calls this routine. If you don't know how, ask in a relevant thread (not here).
It works, but the female player name becomes the same as the male.
I've noticed significant demand for working Dawn Stone evolutions, specifically ones that require the mon to be a specific gender. My bad if this is already posted somewhere but here y'all go:
Code:
.org 0x4318e
lsl r0, r0, #0x0
ldr r2, .MethodAddr
bx r2
.MethodAddr: .word 0x085B2521 #UPDATE THIS TO MAIN FUNCTION OFFSET+1
.org 0x5B2520 #UPDATE THIS TO MOST CONVENIENT FREE SPACE IN YOUR HACK
cmp r0, #0x7
beq StandardStone
cmp r0, #0x14 #UPDATE THIS
beq MaleStone
cmp r0, #0x15 #UPDATE THIS
beq FemaleStone
b NoEvo
MaleStone:
push {r1-r3}
mov r0, r7
mov r1, r8
ldr r1, [r1, #0x0]
bl DetermineGender
pop {r1-r3}
cmp r0, #0x0
beq StandardStone
b NoEvo
FemaleStone:
push {r1-r3}
mov r0, r7
mov r1, r8
ldr r1, [r1, #0x0]
bl DetermineGender
pop {r1-r3}
cmp r0, #0xFE
beq StandardStone
b NoEvo
StandardStone:
ldrh r0, [r1, #0x2]
cmp r0, r9
beq Finish
NoEvo:
ldr r2, .NoEvoReturn
bx r2
DetermineGender:
ldr r2, .DetermineGenderFunc
bx r2
Finish:
ldr r2, .EvoReturn
bx r2
.NoEvoReturn: .word 0x08043199
.EvoReturn: .word 0x0804317d
.DetermineGenderFunc: .word 0x0803f78d
Change the values in the lines marked UPDATE THIS to the indexes of male stone evos and female stone evos. Leave their entries blank in the general evolution table; stone evolutions function differently from level-up evolutions.
the value of "indexes of male stone" is the item value ?
will have two dawn stone, one work in male and one work in female, it is correct ?