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!
Welp, it didn't work.
I compiled the routine and dropped it in the offset 71A250, wrote this script and once I checked it In-Game, this was the result. Note: Just for the record, the savefile is right after defeating my Rival for the very first time, so there's no way for my Pokémon to have 76 points.
Dunno if you'll be able to fix it, but in any case thank you very much.
Welp, it didn't work.
I compiled the routine and dropped it in the offset 71A250, wrote this script and once I checked it In-Game, this was the result. Note: Just for the record, the savefile is right after defeating my Rival for the very first time, so there's no way for my Pokémon to have 76 points.
Dunno if you'll be able to fix it, but in any case thank you very much.
You could test it by using the following set happiness (slot in 0x8004, value to set in 0x8005) routine with a pokemon that evolves via happiness. I think the threshold for evolving is 220? (Routine is also untested)
Oh shoot, you're right! I absolutely forgot the base happiness and the bonus for leveling up!
I thought that the +1 could be because I defeated his Squirtle and that summed one point to my Charmander's happiness, but nope, I tested it by killing a wild Pokémon and it didn't add a point, so I guess the amount of steps must be the answer.
I also fixed my issue with the name by adding the special 0x7C to my script, so yeah, it's over.
Thank you so much for making this routine Ghoul <3
SPEEDING UP FIRERED
All this does is make the turbo button on VBA work faster.
Emerald solution is found here. That's also the source of my implementation of this.
Is it possible to make turbo unusable by editing this routine?
Basically to prevent the player from abusing it for grinding and so on.
You mean the turbo function on VBA? If yes, it's impossible.
Quote:
Originally Posted by MWisBest
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
Does anybody know how I can edit this in order to make it highlight the stat names instead of values? (ex. 'Attack' instead of '255')
Is it possible to add or subtract a value from a var? For example, if I have var x4000 set to 0x3, could I call ASM that dynamically subtracts 1 from it (making it 0x2)?
Is it possible to add or subtract a value from a var? For example, if I have var x4000 set to 0x3, could I call ASM that dynamically subtracts 1 from it (making it 0x2)?
Is it possible to add or subtract a value from a var? For example, if I have var x4000 set to 0x3, could I call ASM that dynamically subtracts 1 from it (making it 0x2)?
Use the addvar scripting command. Look up in the xse commands how it works.
.text
.align 2
.thumb
.thumb_func
main:
push {r0-r1, lr}
ldr r0, =(0x[address of var])
ldrh r0, [r0]
sub r0, #0x1
ldr r1, =(0x[address of var])
strh r0, [r1]
pop {r0-r1, pc}
.align 2
This would break for every var not in the 0x8000s. Most scripting variables shuffle around with the saveblocks and you need to call the var_access function to get their locations. There is also var_set, var_load and over/underflow to think about. Overall, doing this in scripting is recommended as the callasm setup + execution ends up being slower.
Btw, you don't need to push scratch registers unless you were hooking (do so on a case by case basis). Nor the link register here because you're not calling a function.
This would break for every var not in the 0x8000s. Most scripting variables shuffle around with the saveblocks and you need to call the var_access function to get their locations. There is also var_set, var_load and over/underflow to think about. Overall, doing this in scripting is recommended as the callasm setup + execution ends up being slower.
Btw, you don't need to push scratch registers unless you were hooking (do so on a case by case basis). Nor the link register here because you're not calling a function.
Something like this. But as mentioned before it's unadvisable to do it this way.
On this note, I want to use something similar to this in the future, but I need the value to stay within a certain range (0x0 - 0x5, for example). Is there a command that checks var values so that the script knows not to add or subtract once the value reaches either end of that range? Or would this require ASM?
Is there a document with all the XSE commands? I can't seem to find one.
On this note, I want to use something similar to this in the future, but I need the value to stay within a certain range (0x0 - 0x5, for example). Is there a command that checks var values so that the script knows not to add or subtract once the value reaches either end of that range? Or would this require ASM?
Is there a document with all the XSE commands? I can't seem to find one.
Go into XSE and click on the "Help" tab at the top, then "Command Help."
You could do something like:
compare 0x5000 0x5
if >= jump :end
addvar 0x5000 0x1
:end
end
Hi. Does anyone over here have an ASM Routine that allows you to hide and show the Trainer Card's access from the Start Menu at will?
Thanks in advance for reading.
You can adjust this routine to do this. The "noMon" header determines the start menu options after pokedex and pokemon, where
Code:
mov r0, #0xX
ldr r1, =(0x806ED94 +1)
bl linker
shows the start menu option 'X'. So in that particular routine, 0x4 is not being added, which is the 'Save' function. So, to remove the trainer card, you would just leave out the 0x3 index of the start menu
I would like someone to make an ASM Routine to have separate palletes for the OWs which appear on the World Map. (Fire Red)
Here are the offsets for the images
Male
Spoiler:
Female
Spoiler:
You actually probably don't need an assembly routine for this. I would use
Navenatox's dynamic overworld palettes patch. You can just re-upload the female sprites and it will inherit a different palette number. And combined with JPAN's engine allows you to swap player overworld sprites, all with individual palettes.
You actually probably don't need an assembly routine for this. I would use
Navenatox's dynamic overworld palettes patch. You can just re-upload the female sprites and it will inherit a different palette number. And combined with JPAN's engine allows you to swap player overworld sprites, all with individual palettes.
1. Other Forms
I am looking for a routine that allows 2 or more species to share similar dex number. By that, we can have a feature for Flabébé forms and other Pokémon
Hello,
After taking a tutorial from FBI we where able to come up with this.
Here is how it works:
Var 0x8004 value
0x0 = Players 1st Pokemon
0x1 = Players 2nd Pokemon
0x2 = Players 3rd Pokemon
0x3 = Players 4th Pokemon
0x4 = Players 5th Pokemon
0x5 = Players 6th Pokemon
So you could use Special 0x9F.
Which will let you choose the Pokemon you want deleted.
Then callasm 0x?????? +1(where "??????" is where you placed this routine).
C source:
Code:
#include
void delete_pokemon()
{
u8 slot = var_8004; // get slot id from variable
if (slot != 5) {
memcpy(&party_player[slot], &party_player[slot + 1], 100 * (5 - slot));
}
memset(&party_player[5], 0x0, 100);
return;
}
#dynamic 0x810000
#org @start
lockall
faceplayer
msgbox @question 0x5
compare 0x800D 0x1
if 0x1 goto @yes
msgbox @no 0x6
releaseall
end
#org @yes
msgbox @delete 0x6
special 0x9F
waitstate
callasm 0x??????+1 //make sure to change this to pointer where you put routine
msgbox @done 0x6
release
end
#org @question
= Would you like me to delete a Pokemon?
#org @delete
=Alright then here we go!
#org @done
= There the deed has been done!
#org @no
= Maybe next time then.
Hope this helps and credit to FBI once again.
This post motivated me to create an actual regional dex instead of just giving a national dex at the start, so thanks :D I've added some extra routines to do things like display the correct regional dex number in summary screens, displaying dex info on capture, and having the proper regional dex count. New hooks:
I have modified and enhanced azurile13's (credits and kudos to him) routine to make this supported on the Compiler's THUMB.bat. These are the things I modified:
Added routines creating the hooks that are to be copy-pasted on their respective locations. There are 11 hooks.
Added the master location of the routine in which the hooks will create locations for those routines. Insert your free space on .equ MyLoc. Format: 0x###### (Hexadecimal Number)
Created and added a new index list of Pokémon up to Generation VI including the formes in style of KDS/Chacha Dinosaur from the filenames of MrDollSteak's sprites in his Sugimori and Gen VI threads. I think there is no master index list for Generation VII. If there is, please PM me and I will add those.
With the list created as stated above, you will just have to create your own Regional Pokédex by copy-pasting from your Excel and Notepad file to below "regional_dex_order" and .hword 0x0000 should be first in the list. Make sure the names are all CAPS-LOCKED. In case of Nidorans, Farfetch'd, Mr. Mime, Ho-Oh, Mime Jr., Porygon-Z, and Flabébé, their characters are changed so you'll have to look for them in the master list. NOTE: Cohagrigus have been filtered out and changed into asterisks (*). Remember to correct its name before generating the binary file otherwise the .asm file won't work.
Just going to publish this combination of two routines and a script excerpt that you can use to let the player select one Pokémon from their team, and then deposit the rest of their team.
Spoiler: Script
Code:
...
countpokemon
callasm ROUTINE_ONE+1
compare LASTRESULT 0x1
if B_<> goto @snippet1
msgbox @string1 MSG_NORMAL
call @snippet2
callasm ROUTINE_TWO+1
textcolor 0x2 // black
bufferpartypokemon 0x0 0x0
bufferboxname 0x1 0x4035
checkflag 0x834
if 0x1 goto @snippet3
msgbox @string2 MSG_NORMAL
goto @snippet4
//---------------
#org @snippet1
msgbox @string3 MSG_NORMAL
release
end
//---------------
#org @snippet2
special 0x9F
waitstate
special2 LASTRESULT 0x147
compare LASTRESULT 0x19C
if 0x1 goto @egg
compare 0x8004 0x5
if 0x2 goto @exited_out
return
//---------------
#org @snippet3
msgbox @string4 MSG_NORMAL
goto @snippet4
//---------------
#org @snippet4
...
//---------
// Strings
//---------
#org @string1
= You are only allowed to bring one\nPOKéMON.\pPlease select which one you would\nlike to bring.
#org @string2
= [buffer1] will join you.\pThe rest of your team was\ntransferred to SOMEONE's PC.\pThey were placed starting\nin BOX ["][buffer2]."
#org @string3
= You are only allowed to bring one\nPOKéMON.\pNormally, we would offer to deposit\nthe rest of your team into a BOX.\pHowever, it seems like all of your\nBOXES are full.\pPlease make room and return later.
#org @string4
= [buffer1] will join you.\pThe rest of your team was\ntransferred to BILL's PC.\pThey were placed starting\nin BOX ["][buffer2]."
Spoiler: ROUTINE_ONE
Code:
.thumb
@ This routine loops through the player's boxes to make sure there is room in a given box to deposit the entire team
main:
push {r4-r7, lr}
ldr r0, =(0x020370D0) @ var_800D
ldrh r0, [r0]
sub r0, #2 @ party size - 1
mov r4, r0
mov r5, #0
box_loop:
mov r6, #0 @ box_id
mov r7, #0 @ pos_in_box
pokemon_in_box_loop:
mov r0, r6
mov r1, r7
ldr r3, =(0x0808BD30+1) @ pokemon_by_box_and_position
bl call_via_r3
mov r1, #0xB @ req_species
ldr r3, =(0x0803FD44+1) @ pokemon_getattr_encrypted
bl call_via_r3
cmp r0, #0
beq empty_space_found
next_loop:
add r7, #1
cmp r7, #30
bls pokemon_in_box_loop
completed_current_box:
add r6, #1
cmp r6, #14
bge not_enough_space
mov r7, #0
b pokemon_in_box_loop
empty_space_found:
add r5, #1
cmp r5, r4
bls next_loop
enough_space:
mov r0, #1
b end
not_enough_space:
mov r0, #0
end:
ldr r1, =(0x020370D0) @ var_800D
str r0, [r1]
pop {r4-r7}
pop {r3}
call_via_r3:
bx r3
.pool
Spoiler: ROUTINE_TWO
Code:
.thumb
@ This routine loops through the player's party, depositing every slot (slot 0 to 5) except for the slot number in var 8004
@ It then copies the Pokémon in the remaining slot to slot 0, and then erases each Pokémon from slots 1 to 5
main:
push {r4-r6,lr}
ldr r4, =(0x020370C0) @ var_8004
ldrh r4, [r4]
ldr r5, =(0x02024284) @ party_player
mov r6, #0
loop:
cmp r6, #6
beq continue
cmp r6, r4
beq skip
mov r1, #0x64
mul r1, r6
add r0, r1, r5
ldr r3, =(0x08040B90|1) @ pokemon_add_to_pc
bl call_via_r3
skip:
add r6, #1
b loop
continue:
mov r1, #0x64
mul r1, r4
add r1, r5
mov r0, r5
mov r2, #0x64
ldr r3, =(0x081E5E78|1) @ memcpy
bl call_via_r3
ldr r0, =(0x02024284+0x64) @ second Pokémon party address
ldr r1, =(0x081F42A0) @ just a random 500 (dec) 00 bytes in the ROM
ldrh r2, =(0x1F4)
ldr r3, =(0x081E5E78|1) @ memcpy
bl call_via_r3
pop {r4-r6}
pop {r3}
call_via_r3:
bx r3
.pool
Exp. All / Gen. 6 Exp. Share [Emerald]
This routine was created by Samu from Wahack and it was posted right here. All the credits belong to him.
I'm afraid that I'll have to leave the comments in Spanish because I don't know how to properly translate them to English due to my lack of knowledge on the ASM programming language. Sorry :(
ASM Routine:
Code:
.thumb
.align 2
/****** NEW GEN EXP SHARE + EGG EXP FIX *******
************************************************
************************************************
************************************************
Créditos a BluRose & Lunos *********************
************************************************
************************************************/
no_crash:
ldr r0, [r5]
mov r1, r0
add r1, #0x53
ldrb r0, [r1]
flag_check: @Se encarga de comprobar si hemos activado el flag
push {r0-r2}
ldr r0, flag_number
ldr r2, flag_routine
push {r1-r3}
bl linker
pop {r1-r3}
cmp r0, #0x1 @Compara el flag con 0x1 (activado)
bne routine_off
pop {r0-r2}
main:
@Comprobar el slot y guardarlo en una variable.
push {r3-r6}
ldr r6, slot_var @Carga en r3 el slot del pokemon
ldrb r3, [r6]
ldr r4, is_egg_party
mov r5, #0x64
mul r5, r5, r3 @Calcula las posiciones a avanzar
ldrb r4, [r4, r5] @Carga en r4 el byte egg/not
cmp r4, #0x6
beq pokemonIsEgg
mov r2, #0x1
b update_slot
pokemonIsEgg:
mov r2, #0x0 @Establece r2 en 0 (no ganará exp)
update_slot: @Actualiza y resetea el valor del slot
add r3, #0x1
cmp r3, #0x6
bne end
mov r3, #0x0
end:
strh r3, [r6]
pop {r3-r6}
return:
push {r2}
ldr r2, return_dir
bx r2
routine_off: @Ejecuta las instrucciones "originales"
pop {r0-r2}
mov r2, #0x1
and r2, r0
b return
linker:
bx r2
.align 2
flag_number:
.word 0x00000XXX @Elige el numero del flag
flag_routine:
.word 0x0809D790 +1 @Rutina que checkea el flag
slot_var: @Escoge una variable temporal (no uses la 0x8000,
.word 0x020275D6 + (0x800Y * 2) @el juego la utiliza al inicializar combates dobles
is_egg_party:
.word 0x020244EC + 0x13 @Byte que comprueba si es un huevo
return_dir:
.word 0x0804A592 + 1 @Dirección de retorno a la rutina
Note: In order to use this routine, you must set a flag and a temp var in the Lines 72 and 76 respectively.
After inserting the routine in your ROM, open your Pokémon Emerald ROM in a hex editor and make the following changes:
-04A4BE: 02 21
-04A634: 01 20
-04A58A: C0 46 00 4A 10 47 XX XX XX 08 04 BC Note: XX XX XX = Pointer to the ASM Routine, +1. Example: If I were to put it in E3CF80, I'd have to replace XX XX XX with 81 CF E3.
Relevant information:
The flag handles the effect itself. If the flag you gave to the routine is OFF (0x0) the Exp. Share will work just like in Gen. 3. If it's ON (0x1), it'll work like in Gen. 1/6/7.
Result:
I'm sure there's ways to make this better, so if anyone could give that a try, that'd be awesome :)
Custom Victory Music [FR]:
Everyone knows of the code that allows you have custom trainer battle music, but as far as I'm aware, no one has ever written code that allows you have custom victory music (that jingle that plays when you win a battle).
This code is very similar to the custom trainer battle music in which it loads the data from a table structured [Byte - Trainer Class] 00 [HWord - Song ID]. The table is ended with a 0xFFFF.
But before you do anything though, you need to decide how many jingles you want. If you don't need more than 7, just compile the code as it is. If you don't modify the code, the table is at 0x15740 (there's enough space there for 7 jingles, just make sure you put the end 0xFFFF). Otherwise change the last line in the code to your table's pointer.
In order to get this working all you need to do is compile the ASM and copy whatever's at the offset 0x156F4 in the bin into your Rom. Due to the way the original code was written, the new code can be completely pasted over.
Enjoy!