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!
I'm having a problem with shiny odds, compiled all three parts but when I clear the textbox after receiving my starter the game resets, any idea what I did wrong?
This small hack loads map music by a variable rather than the map header (if the variable is set to a non-zero value). just set MUSIC_VAR to some variable value and compile, insert into free space, and overwrite the corresponding bytes at 0x55D70 (found at top of routine).
In a script, set the variable to a specific song ID, and the game will play that song ID after trainerbattles and warps (perhaps others that I have not thought of or tested).
Spoiler:
Code:
.text
.align 2
.thumb
.thumb_func
.global LoadMapMusic
/*
load song regardless of map default
hook at 55D70 via r0
aka 00 48 00 47 xx+1 xx xx 08
*/
.equ MUSIC_VAR, 0x4XXX @some free variable in save block
Main:
push {r1-r3}
ldr r0, .var
bl GetVarVal
pop {r1-r3}
cmp r0, #0x0
beq LoadFromMapHeader
pop {pc}
LoadFromMapHeader:
ldrb r0, [r1]
ldr r2, =(0x08055D78 +1)
bx r2
GetVarVal:
ldr r2, =(0x0806e568 +1)
bx r2
.align 2
.var: .word MUSIC_VAR
so basically i was talking with petuh 2 days ago about how rusty i probably am at strict assembly
so here i am! i made a thing
Spoiler:
Code:
@ the whole headbutt tree system
@ it implements jpan's behavior byte hack as well as the headbutt system in the space that the old routine took up. when he said it was overly inefficient, he meant it!
@ compile this and then go to the offset 0x806D1F0 in the resulting .bin output. copy everything there until the next block of zeros. paste it to offset 0x6D1F0 in your rom.
@ there are various parameters you can play around with. most of these are primarily the tables halfway through this.
@ i tried to comment it throughout!
@ now, in amap, there's the one field that is primarily used in wild encounter spots. it's 2 when wild grass and 4 when surfing on water encounters.
@ because we won't be walking on the headbutt tree, we can use this field to our advantage.
@ cur_mapdata_block_get_field_at(s16 x, s16 y, u8 field) references a bunch of other routines, but eventually, it boils down to a bunch of preset fields or'd with the header info.
@ the first is 0x1FF, or the 9 least significant bits. this is the behavior byte itself.
@ the second is 0x3E00, or the next 5 bits in terms of significance. this allows for 2^5 (32) bits for use for our table.
@ note that the entry entered in this table should be multiplied by 2 because of the way that amap (incorrectly) displays the data. this allows the code below to reference it properly.
@ screens are given in the post.
.text
.align 2
.thumb
.thumb_func
.org 0x08044EC8
@ returns r0 = pseudorandom number
random:
.hword 0x4A04
.org 0x08058F48
@ returns r0 = (metatile behavior long or blockinfo_bit_masks[field]) >> blockinfo_bit_right_shift_num[field]
cur_mapdata_block_get_field_at: @ (s16 x, s16 y, u8 field)
push {r4, lr}
.org 0x0806CE38
@ writes the next pos and height to the pointer given in r0
player_get_next_pos_and_height: @ (*[s16 x, s16 y, u8 height])
push {r4, r5, lr}
.org 0x0806D1F0
@ this assembly routine is a modded version of jpan's behavior byte hack that decreases space required for the table while slightly increasing what's needed for the code
onpress_a_get_script_tile:
lsl r1, r1, #0x18
lsr r0, r1, #0x18
cmp r0, #0x80
blt _not_governed @ we don't care about entries less than h80
sub r0, r0, #0x80
lsl r0, r0, #0x2
ldr r1, behavior_table_ref @ load the table pointer here
add r0, r0, r1
ldr r0, [r0] @ load the script pointer here
b _return_loc
_not_governed:
mov r0, #0
_return_loc:
mov pc, lr
.align 2
behavior_table_ref:
.word behavior_table
behavior_table: @ for the playerfacing behaviors
.word 0
.word 0x081A7606 @ bookshelf
.word 0x081A760F @ market shelf
.word 0x081A6955 @ pc
.word 0
.word 0x081A6C32 @ town map
.word 0x081A764E @ tv
.word 0x081A76E7 @ pokemon center
.word 0x081A76DE @ pokemon mart
.word 0x081A7657 @ cabinet
.word 0x081A7660 @ cooking smells great!
.word 0x081A7669 @ dresser
.word 0x081A7672 @ snacks
.word 0x081BBFD8 @ wireless
.word 0x081BB8A7 @ not available
.word 0x081A7702 @ questionnaire
@ 0x90
.word 0x081A7618 @ fridge
.word 0x081A76F0 @ indigo plateau
.word 0x081A76F9 @ indigo plateau 2
.word 0x081A763C @ blueprint
.word 0x081A767B @ pokemon pics
.word 0x081A7684 @ complex machine. better not touch it!
.word 0x081A768D @ telephone
.word 0x081A762A @ complex numbers
.word 0x081A7696 @ ads
.word 0x081A769F @ tasty food
.word 0x081A76A8 @ trash can
.word 0x081A76B1 @ cup
.word 0
.word 0
.word 0x081A76CC @ lights
.word 0x081A76D5 @ tools
@ 0xA0
.word 0x081A7633 @ random machine
.word 0x081A7621 @ consoles
.word 0x081A7645 @ robbery
.word 0x081C549C @ timer
@ now, i personally added headbutt_script here, but it can go in any one of the zeros above. just make sure that you note the entry correctly!
.word headbutt_script @ headbutt tree behavior byte (0xA4)
.equ table_amount, 3
.equ terminate, 0xFE @ only rule here is that it isn't a pokemon you want to appear in a tree. if you wanted to use pokemon index 254, go for it i guess, but change this
.equ var_begin, 0x020270B8
headbutt_tree:
push {r4-r6, lr}
ldr r0, var_8000 @ position_ptr
@ the below branch will store the position in front of the player's x in var_8000, y in var_8001, and the height in the most significant byte of var_8002
@ this is because it writes to the pointer in r0
bl player_get_next_pos_and_height
ldr r4, var_8000
ldrh r0, [r4] @ x
ldrh r1, [r4, #2] @ y
mov r2, #1 @ field id
@ the field entry 1 is 5 bits of the second behavior byte thing in advancemap. this means we can have up to 32 headbutt tables denoted by even numbers from 0-64 in amap.
@ this is explained further above
bl cur_mapdata_block_get_field_at
lsl r0, r0, #0x18
lsr r4, r0, #0x18 @ r4 = table number
@ part below catches invalid tables and prevents them from working
cmp r4, #table_amount
bge _nothingfell
ldr r0, tableoftables_ref
lsl r1, r4, #2 @ r1 = table number * 4
ldr r4, [r0, r1] @ r4 = table pointer to the relevant one
@ below, generate a random number less than 100 to emulate chance
bl random @ r0 = random()
mov r1, #100
bl __umodsi3 @ r0 = r0 % 100
mov r5, #0 @ set up the loop counter
ldr r6, terminate_byte
@ at this point, r0 = random() % 100, r4 = table pointer, r5 = loop counter, r6 = terminator
_loop:
mov r1, #7 @ 7 being the size of each entry
mul r1, r5, r1
add r3, r4, r1 @ store the current entry's pointer in r3
ldrh r2, [r3] @ seems to be very finicky at times, loading random values from the surroundings?
lsl r2, r2, #0x10
lsr r2, r2, #0x10
cmp r2, r6
beq _nothingfell
ldrb r2, [r3, #6] @ load the chance of this entry into r2
cmp r0, r2
ble _somethingfell
add r5, r5, #1 @ increment the loop counter
b _loop
_somethingfell:
mov r4, r3
@ at this point, r4 is the table entry we care about. don't touch it
bl random @ generate a new random number
@ r0 = random()
ldrb r2, [r4, #2] @ load the lower level
ldrb r1, [r4, #3] @ load the higher level
sub r1, r1, r2 @ subtract the lower level from the higher level, store it as the parameter for modulo
bl __umodsi3
@ r0 = random() % (highlevel - lowlevel)
ldrb r2, [r4, #2] @ load the lower level again bc umodsi ****in w the value
add r1, r0, r2 @ level parameter
ldrh r0, [r4] @ species parameter
ldrh r2, [r4, #4] @ item parameter
bl create_scripted_mon
ldr r0, var_8000
mov r1, #0
strh r1, [r0, #0x18] @ store 0 into var_800D
b _end
_nothingfell:
ldr r0, var_8000
mov r1, #0xFF
strh r1, [r0, #0x18] @ store 0xFF into var_800D
_end:
pop {r4-r6}
pop {r1} @ this is the return method used by many of the script stuff so
bx r1
.align 2
@ used to store the position struct
var_8000:
.word (var_begin + (0x8000 * 2))
terminate_byte:
.word terminate
tableoftables_ref:
.word tableoftables
@ note that, in order to expand the tables, you need to add another entry here for each of the tables.
tableoftables:
.word lowencounter
.word medencounter
.word highencounter
@ bunch of defines to make the below better readable
.equ caterpie, 10
.equ metapod, 11
.equ butterfree, 12
.equ weedle, 13
.equ kakuna, 14
.equ beedrill, 15
.equ exeggcute, 102
.equ exeggutor, 103
.equ tangela, 114
.equ pinsir, 127
.equ snorlax, 143
.equ pineco, 204
.equ heracross, 214
@ a sample item
.equ brightpowder, 179
@.org 0x08XXXXXX @ optional repoint of the tables below in case you want a higher amount of pokemon.
@ here's the table format:
@ [2 bytes - species] [1 byte - lower level] [1 byte - higher level] [2 bytes] - item it can hold] [1 byte - chance it will appear]
@ the chance byte at the very end is subtracted from the previous entry in the tables in order to get that specific entry's chance of showing up.
@ sample entries are below:
lowencounter:
.hword weedle @ species
.byte 5 @ lower level
.byte 7 @ higher level
.hword brightpowder @ item
.byte 20 @ chance
.hword kakuna @ species
.byte 12 @ lower level
.byte 15 @ higher level
.hword 0 @ no item
.byte 40 @ chance: 40 - 20 (weedle's entry above) = 20
.hword beedrill
.byte 60
.byte 70
.hword brightpowder
.byte 100 @ chance: 100 - 40 (kakuna's entry above) = 60
.hword terminate
@ this table represents an instance where we don't have to get a pokemon 100% of the time. the code handles it!
medencounter:
.hword caterpie
.byte 5
.byte 7
.hword brightpowder
.byte 35
.hword metapod
.byte 12
.byte 15
.hword 0
.byte 45
.hword butterfree
.byte 60
.byte 70
.hword brightpowder
.byte 50
.hword terminate
@ 50% of the time, a pokemon won't fall.
highencounter:
.hword exeggcute
.byte 10
.byte 12
.hword 0
.byte 40
.hword tangela
.byte 20
.byte 25
.hword 0
.byte 60
.hword heracross
.byte 17
.byte 22
.hword brightpowder
.byte 90
.hword snorlax
.byte 50
.byte 60
.hword brightpowder
.byte 100
.hword terminate
@ optional insert of the script. there's still about hB0 bytes left over after the script is inserted, allowing for about 19 EXTRA mon entries (on top of the 10 there already)
@ repoint if so desired. the assembly will take care of it!
@.org 0x08XXXXXX
.equ headbutt, 0x1D
.equ lastresult, 0x800D
headbutt_script: @ this is included here for the dynamic compiling so that you don't have to care. feel free to edit it though
.byte 0x6A
.byte 0x7C
.hword headbutt
.byte 0x21
.hword lastresult
.hword 0x06
.byte 0x06
.byte 0x01
.word no_headbutt_in_party
.byte 0x9D
.byte 0x00
.hword lastresult
.byte 0x7F
.byte 0x00
.hword lastresult
.byte 0x82
.byte 0x01
.hword headbutt
.byte 0x0F
.byte 0x00
.word text_headbutt_in_party
.byte 0x09
.byte 0x05
.byte 0x21
.hword lastresult
.hword 0x00
.byte 0x06
.byte 0x01
.word said_no
.byte 0x0F
.byte 0x00
.word text_poke_used_atk
.byte 0x09
.byte 0x04
.byte 0x68
.byte 0x9C
.hword 0x2
.byte 0x27
@ the callasm is here
.byte 0x23
.word headbutt_tree + 1
@ this comparison here prevents the dowildbattle from happening if lastresult is 0xFF (the chance was higher than the highest chance defined in the table)
@ lastresult's modification is in the assembly above
.byte 0x21
.hword lastresult
.hword 0xFF
.byte 0x06
.byte 0x01
.word tree_was_undisturbed
.byte 0x0F
.byte 0x00
.word text_exclamation
.byte 0x09
.byte 0x06
.byte 0xB7
.byte 0x6C
.byte 0x02
.byte 0xFF
no_headbutt_in_party:
.byte 0x0F
.byte 0x00
.word text_cant_headbutt
.byte 0x09
.byte 0x06
.byte 0x6C
.byte 0x02
.byte 0xFF
said_no: @ closes the textbox
.byte 0x68
.byte 0x6C
.byte 0x02
.byte 0xFF
tree_was_undisturbed:
.byte 0x0F
.byte 0x00
.word text_tree_undisturbed
.byte 0x09
.byte 0x06
.byte 0x6C
.byte 0x02
.byte 0xFF
text_headbutt_in_party: @ This tree can be headbutted! Would you like to use headbutt?
.byte 0xCE
.byte 0xDC
.byte 0xDD
.byte 0xE7
.byte 0x00
.byte 0xE8
.byte 0xE6
.byte 0xD9
.byte 0xD9
.byte 0x00
.byte 0xD7
.byte 0xD5
.byte 0xE2
.byte 0x00
.byte 0xD6
.byte 0xD9
.byte 0x00
.byte 0xDC
.byte 0xD9
.byte 0xD5
.byte 0xD8
.byte 0xD6
.byte 0xE9
.byte 0xE8
.byte 0xE8
.byte 0xD9
.byte 0xD8
.byte 0xAB
.byte 0xFE
.byte 0xD1
.byte 0xE3
.byte 0xE9
.byte 0xE0
.byte 0xD8
.byte 0x00
.byte 0xED
.byte 0xE3
.byte 0xE9
.byte 0x00
.byte 0xE0
.byte 0xDD
.byte 0xDF
.byte 0xD9
.byte 0x00
.byte 0xE8
.byte 0xE3
.byte 0x00
.byte 0xE9
.byte 0xE7
.byte 0xD9
.byte 0x00
.byte 0xC2
.byte 0xD9
.byte 0xD5
.byte 0xD8
.byte 0xD6
.byte 0xE9
.byte 0xE8
.byte 0xE8
.byte 0xAC
.byte 0xFF
.byte 0x00
.byte 0xFF
text_poke_used_atk: @ [string1] used [string2]!
.byte 0xFD
.byte 0x02
.byte 0x00
.byte 0xE9
.byte 0xE7
.byte 0xD9
.byte 0xD8
.byte 0x00
.byte 0xFD
.byte 0x03
.byte 0xAB
.byte 0xFF
.byte 0x00
.byte 0xFF
text_exclamation: @ Whoa!
.byte 0xD1
.byte 0xDC
.byte 0xE3
.byte 0xD5
.byte 0xAB
.byte 0xFF
.byte 0x00
.byte 0xFF
text_cant_headbutt: @ This tree looks like Pokémon can live in it.
.byte 0xCE
.byte 0xDC
.byte 0xDD
.byte 0xE7
.byte 0x00
.byte 0xE8
.byte 0xE6
.byte 0xD9
.byte 0xD9
.byte 0x00
.byte 0xE0
.byte 0xE3
.byte 0xE3
.byte 0xDF
.byte 0xE7
.byte 0x00
.byte 0xE0
.byte 0xDD
.byte 0xDF
.byte 0xD9
.byte 0x00
.byte 0xCA
.byte 0xE3
.byte 0xDF
.byte 0x1B
.byte 0xE1
.byte 0xE3
.byte 0xE2
.byte 0x00
.byte 0xD7
.byte 0xD5
.byte 0xE2
.byte 0xFE
.byte 0xE0
.byte 0xDD
.byte 0xEA
.byte 0xD9
.byte 0x00
.byte 0xDD
.byte 0xE2
.byte 0x00
.byte 0xDD
.byte 0xE8
.byte 0xAD
.byte 0xFF
.byte 0x00
.byte 0xFF
text_tree_undisturbed: @ But the tree remained undisturbed...
.byte 0xBC
.byte 0xE9
.byte 0xE8
.byte 0x00
.byte 0xE8
.byte 0xDC
.byte 0xD9
.byte 0x00
.byte 0xE8
.byte 0xE6
.byte 0xD9
.byte 0xD9
.byte 0x00
.byte 0xE6
.byte 0xD9
.byte 0xE1
.byte 0xD5
.byte 0xDD
.byte 0xE2
.byte 0xD9
.byte 0xD8
.byte 0xFE
.byte 0xE9
.byte 0xE2
.byte 0xD8
.byte 0xDD
.byte 0xE7
.byte 0xE8
.byte 0xE9
.byte 0xE6
.byte 0xD6
.byte 0xD9
.byte 0xD8
.byte 0xAD
.byte 0xAD
.byte 0xAD
.byte 0xFF
.byte 0x00
.org 0x080A029C
create_scripted_mon: @ (u16 species, u8 level, u16 item)
push {r4-r7, lr}
.org 0x081E4684
@ returns r0 = dividend % divisor
__umodsi3: @ (u16 dividend, u16 divisor)
cmp r1, #0
this implements a modified jpan's behavior byte hack so that it takes up far less space (only affects the behavior byte entries it governs). it then adds a new entry, a pointer to the script that's also dynamically compiled. by default, this new one is behavior byte 0xA4!
in its purest form, you need to configure the tables and then compile it using your favorite asm compiling software. go to 0x806D1F0 and copy it until the zeros are reached. note that you will need to edit the tables in there as you so desire.
each new table needs to be referenced in tableoftables so that the code will read it.
copy that over to 0x6D1F0 in your fire red v1.0 rom. that's it! all you have to do.
tables are split into entries for each pokemon, each 7 bytes:
[2 bytes] - species
[1 byte] - lower level
[1 byte] - higher level
[2 bytes] - item
[1 byte] - chance of appearing (when subtracted from the previous entry's chance entry, it gives the specific entry's chance of appearing
this will generate a pokemon of the defined species with a random level between lower level and higher level with the item in the table.
in editing the tables, there's an .equ for table_amount. edit that to accomodate the new tables; it's currently at 3.
now, i tried to label it as well as i could. ask me any questions you have on the code ahaha
this system works by loading separate tables based on the second byte in advancemap labeled "behavior byte" when given a certain behavior byte. you know, this one:
in classic amap fashion, this is rather wrong
what happens in the code is that all 4 of those are considered one 4-byte word and the game retrieves the values it wants in various fields
everything that wants to retrieve a value from this area eventually references 0x8058F1C, or blockinfo_get_field in knizz's idb.
it takes the blockinfo and a field value and returns the value of that field.
blockinfo_get_field uses the words at 352EF0, or's it w the blockinfo (the 4 bytes from the block editor in amap), and returns the result shifted right by the corresponding entry in the byte array at 352F10. this results in a neat return value.
field 0 is the behavior byte field, like the main one, but is also 1 bit from the second byte (it's 9 bits long)
the one that is kind of labeled in amap
field 1 is then part of the second byte labeled as a behavior byte. this is the field i used in this to try not to rewrite anything too extensively
within the second byte, we split it down into bits:
[7] [6] [5] [4] [3] [2] [1] [0]
field 1 is bits 1-5 (NOT zero!). they are bold in the above example. this is why the grass is 2, and the water is 4; the values for field 1 for these respective values are actually 1 and 2!
what this practically means? the second byte is the table number * 2. so if i wanted to use table 3 (the 4th table because of 0-indexing), then i would put 6 in that second field.
for ease of editing, a bunch of equ's for various bug pokemon are included in the file. brightpowder is also the only defined item, but that can be changed if you so desire.
so that tree in the amap screen up there? it's a headbutt tree (behavior byte 0xA4) that accesses table 2.
ONE NOTE ON THIS
you have 0x358 bytes to work with here. if you go to 0x806D1F0 in the compiled binary and select all those bytes and the size is over 0x358, then you will be overwriting surfing code.
you have up to 0x6D548.
this supports easy repointing, be it the tree tables or the script. either way, just uncomment one of the org's and change it to the place where free space is.
with all that done, you should have a new headbutt tree system in your game! see you next time~
EDIT: also i have half a mind to take thread ownership. i'll start compiling a list of everything here and links to them w descriptions when i have free time tomorrow and then ask if i can take over after everything is compiled
After compiling the routine in a free offset, go to 0x09FFBC and overwrite the bytes with 00480047xxxxxx08.
Instead of the XX, will be entered the offset of previous routine + 1 and in Little Endian format (example: 08123456 -> 57 34 12 08).
This hack converts the PC item storage menu into a side quest menu, or task list, etc.
Here is the repository, the compilation instructions are included in the readme. You will need to define your own parameters/ram in src/headers/defs.asm and create your own tables of string pointers for all of the quest names, descriptions, item images, and quest details. I kept the item image part to allow hackers to include items that might be symbolic of their quest, eg. a scroll or key or pokeball.
I want to change the amount of experience given by pokemon in Fire Red. I could go through and manually update the values of each pokemon, but I'm just wondering if anybody knows where to find the offset where the experience formula is.
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
It seems that the memory location for the storage system (0x203C000) has been used already by another ASM routine my ROM base (Leon/UltimaSoul's) has implemented. I cannot find which exact memory locations are free, but I figured the best shot would be 0x203CC00.
I have tried to amend the routine by simply changing the memory location in the routine under .STORAGE. However, unfortunately the game freezes when the ASM routine is called. What is the best way to relocate the storage system to free memory space? Am I missing something obvious? Thanks in advance for any help!
It allows you to have In-Game Trades that come with/at/in:
Static levels, like in newer games
Pokérus
Custom movesets
PP bonuses
Poké Balls other than the default
You can also use it as a sort of trade editor, because it extracts the in-game trade data from your ROM in a compilable form you can modify.
Let me know if you run into issues.
Spoiler:
I originally posted several of these as standalone ASM hacks. I decided to bring them together by reimplementing them in C instead of having so many
bpre-trade-whatever
repositories on my Github. I have privated the repos containing the standalone ASM versions, and deleted the posts about them. Sorry for any confusion.
After compiling the routine in a free offset, go to 0x09FFBC and overwrite the bytes with 00480047xxxxxx08.
Instead of the XX, will be entered the offset of previous routine + 1 and in Little Endian format (example: 08123456 -> 57 34 12 08).
Thanks. Though I would like to point out, to use them all you really need to know is how to insert them and what they do. I've documented a guide on how to insert for beginners (it's a link in the FAQ first post). If you don't understand something or don't see how some routine works, feel free to ask!
:3
I'm still not understanding the incentive to randomizing the starting Pokemon. I suppose it would be a small bit of "game change" if someone were to play your hack more than once, but the feature seems a little useless to me :/
Yeah it definitely could, and should read off of a table. I'll have to redo that little bit :x
Battle Modes addon: Delete fainted Pokemon
For those hackers who like minigames, this routine will delete Pokemon who have fainted in battle. There's a few things that need to happen for this effect to occur.
1) Pokemon who die in battle must be deleted
2) Eggs are spared
3) Pokemon who die outside of battle must be deleted (Poison or another similar effect)
However, if you put this in turn basis, you will NEED to make another routine to delete the Player's party if he/she loses the match. This is because the turn counter isn't reached on the last turn the player loses :x
If you're lazy like me you can just put this routine in as a battle by move addon and cover the whiteout case. Which is actually fine. It's rather fast, because it deletes the Pokemon as they die, so the worse case scenario is unforeseeable. And if a Pokemon dies it will only need to loop 5 times only doing operations on one of the 5 loops. If you're curious looping a maximum of 21 times is the worst case scenario (all 6 of your Pokemon die in 1 turn i.e never, and even if that did happen it'd be done in less .25 seconds). So it's fine to put in the battle by move section without expecting the game to lag.
How to insert:
Insert as addon to battle modes battle by move.
You will notice that near the start of the routine there is some commented out code (denoted by a prefix "@" symbol). That's for a flag check. Change [flag/4] = your flag/4 in hex if you want to toggle by flag. Of course the normal battle mode toggle flag should be used as well.
Usage:
If you opted to use a flag, set it to allow further battles to delete Pokemon as they faint. If you didn't just sit back and let the unicorns inside the game do the rest.
It was brought to my attention by some requesters that for their battle/tournament events they wouldn't want their Pokemon leveling up. This routine disables the exp gains in battle. Note that the player can still use stuff like Rare Candy to level. The fix to that is exactly the same as this, but with slight modifications. I hope you don't give the player a chance to rare candy in battle though or I will go to your hack's thread and severly criticize your lack of common sense :c
How to insert:
Compile and insert the following routine into free space:
Now navigate to 0x21CFA and insert the following byte changes:
Code:
00 00 00 49 08 47 XX XX XX 08
Where XX XX XX is the reverse hex pointer to where you inserted this routine +1.
Usage:
If flag 0x202 is set, the EXP gains will be disabled. Obviously, to re-enable just clear the flag.
Currently the way I'm doing this is by making the game act like the player's party is already max level, so therefore they don't gain exp :)
Is there a way to do this in Emerald? Also, is there a way to have a flag reduce experience gain by half in Emerald? I've implemented the gen VI exp share asm but that gives 100% to every pokemon, I would really like to have the amount be configurable!
If you use these two routines, then if you set Var 0x8003 to 0x1, before using the showpokepic command in an NPC script, then the Pokemon in the resulting picture will appear Shiny!
Spoiler:
/* Put 00 49 08 47 XX XX XX 08 at 0x8398C */
.text
.align 2
.thumb
.thumb_func
.global ShinyPalette
(First picture is with 0x8003 = 0x1, second is without).
__________________
"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
Preview: (Click to see the GIF animation) Attachment 77173
The routines are only for FR. I haven't found any bugs in it. However, the CPU will run much more instructions so that it will be a bit (really?) slower when you open the 'pokemon', 'bag'..... menus.
1) Insert the RTC routine via the tool 'DNS'.
2) Insert these routines and do the byte changes:
Routine I:
Spoiler:
byte changes:
Code:
0x6F09C - 00 48 00 47 XX+1 XX XX 08
change all the 0x8750000 in the routine to the insert offset of the routine.
change all the 0x8750001 in the routine to the insert offset + 1 of the routine.
I encountered a bug on custom give pokemon.
If the specie number is 5, the level of the pokemon will also be 5 no matter what the value you put in var 0x8001.
Okay, the real problem here is if your specie number is greater than 411 then the level of the pokemon you get is not correct.
EDIT: I have extended Pokemon. I'm using pokefreak890's base
EDITEDIT: I found the fix
Code:
.language: .word 0x081E9F11
.stat: .word 0x08254784 Change this to the location where your Pokemon Data is.
.exp: .word 0x08253AE4
I don't know if there are other stuffs that needs to be change. You only need to do this if you have extended the number of Pokemon in you rom.
EDITEDITEDIT: For some reason there are still problems to some Pokemon.
Sometimes you get Level 0, sometimes 100, sometimes 58.
I hope someone can fix this.
Did anyone ever make a fix for this? I'm trying to use it now and I can't control the level of the Pokemon.
EDIT: It works if you change the Pokemon data location.
Question:
Has anybody got the Rival Naming Routine by Jambo51?
I believe the post [link] has died. Any help would be appreciated, and I under stand if Jambo has prohibited from spreading it.
This isn't a request, but a favour.
Hey all, I have a question that I was hoping someone here could help me out with. Spherical Ice was kind enough to send me some scripts and routines for me to edit to implement the "Madam Celadon" NPC feature from the Let's Go games into my Fakemon FireRed hack - you know, an NPC you talk to which predicts the nature for future encounters, at least for a set amount of time - or, steps. The first two scripts and the first asm routine I don't have any trouble editing and inserting, but the second asm routine gives me some error messages that I don't really know how to tackle. I hope it's cool if I post everything here.
The "Mrs. Nature" script is inserted at 3B1B44
The "Nature manipulation" routine is inserted at 34F050
The "Wore off" script is inserted at 3ADDD4
And the "Pedometer" routine is supposed to be inserted at 3ADE14, but I can't convert it to a .bin file without getting these error messages:
Code:
pedometer.asm:30: Warning: Failed to find real start of function: call_via_r2
pedometer.asm:39: Warning: Failed to find real start of function: call_via_r2
pedometer.asm:51: Warning: Failed to find real start of function: call_via_r2
pedometer.asm:58: Warning: Failed to find real start of function: call_via_r2
pedometer.asm:61: Warning: Failed to find real start of function: call_via_r2
pedometer.asm:28: Error: invalid offset, value too big (0xFFFFFFFC)
I'm wondering if there's a different way I'm supposed to convert these, though, the only way I know is to put the .asm file in the same folder as thumb.bat, then navigate there with command prompt and type in "thumb routine.asm routine.bin" or something like that. I've noticed that this gives me some ridiculously long files with these routines - I can tell that it's because the new routine is generated at the specified offset, and the new pointer is included and everything, I'm just wondering if I'm supposed to be doing something different.
Anyway, here's what I got from Spherical Ice, all credit goes to him. I hope it's okay to post this here, he was a little too busy himself. Everything is pretty much the way I've inserted it - I'll edit the dialogue later, but other than that, the offsets and everything should match the way I've been inserting these.
Hey everybody. First I would like to thank Andrea for successfully porting the physical/special split to Pokémon Ruby. Can someone take his ASM routine and update it to work with an expanded move table?
Hey everybody. First I would like to thank Andrea for successfully porting the physical/special split to Pokémon Ruby. Can someone take his ASM routine and update it to work with an expanded move table?
Thanks for your reply Super Dark. I think my last post wasn't clear enough I am not talking about updating an editor's tool like PGE to support the expanded move table I've already done that. What I'm asking about is how to update Andrea's ASM routine to support the expanded move table in my ROM. Although I think were on the right track I wonder if change I posted below will work or do any other numbers need to be changed?
Question:
Has anybody got the Rival Naming Routine by Jambo51?
I believe the post [link] has died. Any help would be appreciated, and I under stand if Jambo has prohibited from spreading it.
This isn't a request, but a favour.
Where to insert: Anywhere! This routine is called from a script in the game, and as such, doesn't need to be carefully linked into existing routines. All you need to do is remember the rule of THUMB, add 1 to the offset when calling it!
Explanation: It's what it says on the tin, it lets you name your rival from the in game overworld, allowing for Silver like naming, or indeed, any other possibility you can come up with. The rivalname: .word 0x08FFFFFF is for if the player leaves the name box blank. It will fill it with a standard name instead. This standard name is up to you to create. Simply compile a name with XSE, and point that pointer to it.
You also need to put this routine in the game, or else it won't be able to load past the intro without naming the rival. All it does is temporarily write a holding name to the rival buffer so that the game doesn't crash.
Where to insert: Navigate to 0x54A6A, and change the following bytes to this:
01 49 08 47 00 00 XX XX XX 08.
Where the XX's stand for the pointer to the new routine plus 1.
Explanation: It simply writes a placeholder name into the [rival] buffer so the game doesn't crash. Obviously, you shouldn't be using the [rival] buffer until the player has named the rival, so it shouldn't be a problem.
To make this work, navigate to 0x103690, and change the pointer there to 0x1307D1.
Where to insert: Anywhere! This routine is called from a script in the game, and as such, doesn't need to be carefully linked into existing routines. All you need to do is remember the rule of THUMB, add 1 to the offset when calling it!
Explanation: It's what it says on the tin, it lets you name your rival from the in game overworld, allowing for Silver like naming, or indeed, any other possibility you can come up with. The rivalname: .word 0x08FFFFFF is for if the player leaves the name box blank. It will fill it with a standard name instead. This standard name is up to you to create. Simply compile a name with XSE, and point that pointer to it.
You also need to put this routine in the game, or else it won't be able to load past the intro without naming the rival. All it does is temporarily write a holding name to the rival buffer so that the game doesn't crash.
Where to insert: Navigate to 0x54A6A, and change the following bytes to this:
01 49 08 47 00 00 XX XX XX 08.
Where the XX's stand for the pointer to the new routine plus 1.
Explanation: It simply writes a placeholder name into the [rival] buffer so the game doesn't crash. Obviously, you shouldn't be using the [rival] buffer until the player has named the rival, so it shouldn't be a problem.
To make this work, navigate to 0x103690, and change the pointer there to 0x1307D1.
OG post by tajaros
I am so sorry! I had found this routine and forgot to mention it here. Terribly sorry.