The PokéCommunity Forums  

Go Back   The PokéCommunity Forums > ROM Hacking > Research & Development
Sign Up Rules/FAQ Live Battle Blogs Mark Forums Read


Research & Development Got a well-founded knack with ROM hacking? Love reverse-engineering the Pokémon games? Or perhaps you love your assembly language. 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!
Research & Development programs in this forum are subject to moderator approval before they are displayed.

Advertise here

Thread Tools
Old January 5th, 2010, 07:22 PM
pokemon rom researcher
Join Date: Dec 2008

Advertise here
Warning: this post's examples and code snippets were taken and\or written for US Fire Red version. Because the engine is virtually the same between all Gen III games, the inner workings should be similar. But you need to find their equivalents in all other versions if you wish to use them.

Also I wish for this topic to gather knowledge for all advance generation games. As such, feel free to post findings on other versions. Moving on...

I find it incredible that we know so little about such a large part of the games we hack. I'm talking about, as the title implies, Items. How do they work, and more importantly, how to make them do what we want? So, for a while now, every now and then, I tackle the subject by examining the code for some simple items: the MasterBall, the Potion and the FireStone. Up until now, I have got little to almost none information out of it, as there are several routines required for them to work. So, I decided to change items a little and tried to decompile Repel: After some tries, I have found that it can actually be changed and allows for the creation of a new items. But first, I start with what items are:
The item data is composed of:
14 bytes for the name, a string in the same encoding as all in-game strings, finished by 0xff
2 bytes for the item number, that is used for some integrity checks
2 bytes for the item market price
1 byte that I know not it's use
1 byte used for item usage values, such as potion HP recovery or Repel steps
4 bytes for a pointer to a small description of the item, as seen in the market and in the bag screen
2 bytes for something else
1 byte for the number of the pocket the item is stored in (tm case and berry bag included)
1 byte that usually allow to distinguish between between types of item
4 bytes pointer for item's THUMB routine start.
1 byte for item usage location
3 bytes for something else
4 bytes for the battle routine start.
4 bytes for other uses
This data, as one can see, still has many holes and unfound data, even being so small. In here, I hope we can find the total of their workings.
But, most importantly, finding out how they work, and if they can be manipulated, really falls down to examine the two ASM work pointers. I will start with the success case, the REPEL routine. Repel sets its item value to variable 0x4020, that will be decreased every step you take. Here’s the routines:
ROM:080A1998                 PUSH    {R4,LR}
ROM:080A199A                 LSL     R0, R0, #0x18
ROM:080A199C                 LSR     R4, R0, #0x18
ROM:080A199E                 LDR     R0, =0x4020
ROM:080A19A0                 BL      sub_806E568  ;loads variable and retrives the value 
ROM:080A19A4                 LSL     R0, R0, #0x10
ROM:080A19A6                 CMP     R0, #0  ;if there is at least a step remaining, goes to exit function
ROM:080A19A8                 BNE     loc_80A19CC
ROM:080A19AA                 MOV     R0, #0x29
ROM:080A19AC                 BL      sub_80722CC
ROM:080A19B0                 LDR     R0, =0x3005090 ;this is the routine pointer for later execution (note 1)
ROM:080A19B2                 LSL     R1, R4, #2
ROM:080A19B4                 ADD     R1, R1, R4
ROM:080A19B6                 LSL     R1, R1, #3
ROM:080A19B8                 ADD     R1, R1, R0
ROM:080A19BA                 LDR     R0, =(loc_80A19E8+1)
ROM:080A19BC                 STR     R0, [R1]  ;stores the second routine for later execution
ROM:080A19BE                 B       loc_80A19D8
ROM:080A19BE ; ---------------------------------------------------------------------------
ROM:080A19C0 dword_80A19C0   DCD 0x4020              ; DATA XREF: ROM:080A199Er
ROM:080A19C4 dword_80A19C4   DCD 0x3005090           ; DATA XREF: ROM:080A19B0r
ROM:080A19C8 off_80A19C8     DCD loc_80A19E8+1       ; DATA XREF: ROM:080A19BAr
ROM:080A19CC ; ---------------------------------------------------------------------------
ROM:080A19CC loc_80A19CC                             ; CODE XREF: ROM:080A19A8j
ROM:080A19CC                 LDR     R2, =unk_841659E ; this is the "already in use sentence"
ROM:080A19CE                 LDR     R3, =(loc_810A1F8+1) ;this loads the message to be executed in the bag.
ROM:080A19D0                 ADD     R0, R4, #0
ROM:080A19D2                 MOV     R1, #2
ROM:080A19D4                 BL      sub_8108E70
ROM:080A19D8 loc_80A19D8                             ; CODE XREF: ROM:080A19BEj
ROM:080A19D8                 POP     {R4}
ROM:080A19DA                 POP     {R0}
ROM:080A19DC                 BX      R0
ROM:080A19DC ; ---------------------------------------------------------------------------
ROM:080A19DE                 DCB    0
ROM:080A19DF                 DCB    0
ROM:080A19E0 off_80A19E0     DCD unk_841659E         ; DATA XREF: ROM:loc_80A19CCr
ROM:080A19E4 off_80A19E4     DCD loc_810A1F8+1       ; DATA XREF: ROM:080A19CEr
ROM:080A19E8 loc_80A19E8                             ; DATA XREF: ROM:off_80A19C8o
ROM:080A19E8                 PUSH    {R4-R6,LR}
ROM:080A19EA                 LSL     R0, R0, #0x18
ROM:080A19EC                 LSR     R6, R0, #0x18
ROM:080A19EE                 BL      sub_80723E0
ROM:080A19F2                 LSL     R0, R0, #0x18
ROM:080A19F4                 CMP     R0, #0
ROM:080A19F6                 BNE     loc_80A1A2A
ROM:080A19F8                 LDR     R4, =0x203AD30 ;used item number location
ROM:080A19FA                 LDRH    R2, [R4]
ROM:080A19FC                 LDR     R3, =0xFFFF
ROM:080A19FE                 MOV     R0, #4
ROM:080A1A00                 MOV     R1, #0
ROM:080A1A02                 BL      sub_80A2294
ROM:080A1A06                 LDR     R5, =0x4020
ROM:080A1A08                 LDRH    R0, [R4]
ROM:080A1A0A                 BL      sub_809A948     ;this is the routine that gets the actual repel value
ROM:080A1A0E                 ADD     R1, R0, #0      
ROM:080A1A10                 LSL     R1, R1, #0x18
ROM:080A1A12                 LSR     R1, R1, #0x18
ROM:080A1A14                 ADD     R0, R5, #0
ROM:080A1A16                 BL      sub_806E584     ;this is the function that stores values in a variable
ROM:080A1A1A                 BL      sub_80A1A44     ;this one buffers the string to print "[player] used [Item]"
ROM:080A1A1E                 LDR     R2, =0x2021D18
ROM:080A1A20                 LDR     R3, =(loc_810A1F8+1) ; the same function as in the exit. ends with a return to the bag screen. 
ROM:080A1A22                 ADD     R0, R6, #0
ROM:080A1A24                 MOV     R1, #2
ROM:080A1A26                 BL      sub_8108E70
ROM:080A1A2A loc_80A1A2A                             ; CODE XREF: ROM:080A19F6j
ROM:080A1A2A                 POP     {R4-R6}
ROM:080A1A2C                 POP     {R0}
ROM:080A1A2E                 BX      R0
ROM:080A1A2E ; ---------------------------------------------------------------------------
ROM:080A1A30 dword_80A1A30   DCD 0x203AD30           ; DATA XREF: ROM:080A19F8r
ROM:080A1A34 dword_80A1A34   DCD 0xFFFF              ; DATA XREF: ROM:080A19FCr
ROM:080A1A38 dword_80A1A38   DCD 0x4020              ; DATA XREF: ROM:080A1A06r
ROM:080A1A3C dword_80A1A3C   DCD 0x2021D18           ; DATA XREF: ROM:080A1A1Er
ROM:080A1A40 off_80A1A40     DCD loc_810A1F8+1       ; DATA XREF: ROM:080A1A20r
ROM:0809A948 sub_809A948                             ; CODE XREF: sub_803ECEC+C2p
ROM:0809A948                                         ; sub_803ECEC+10Cp ...
ROM:0809A948                 PUSH    {R4,LR}
ROM:0809A94A                 LSL     R0, R0, #0x10
ROM:0809A94C                 LSR     R0, R0, #0x10
ROM:0809A94E                 LDR     R4, =unk_83DB028     ;item table pointer
ROM:0809A950                 BL      sub_809A8A4        ;checks for item_validity (note 2)
ROM:0809A954                 LSL     R0, R0, #0x10
ROM:0809A956                 LSR     R0, R0, #0x10
ROM:0809A958                 MOV     R1, #0x2C
ROM:0809A95A                 MUL     R0, R1
ROM:0809A95C                 ADD     R0, R0, R4
ROM:0809A95E                 LDRB    R0, [R0,#0x13]
ROM:0809A960                 POP     {R4}
ROM:0809A962                 POP     {R1}
ROM:0809A964                 BX      R1
(note 1): this is the location in the RAM the game keeps the pointers for the functions it must execute next. It’s like a small queue that allows the game to run several things “at once”. This is very important because this allows for things like separate screens to exist, such as the normal map, town map, trainer card or bag. The routine for the bag screen to come forward is at 0x08108F0C.
(note 2): this function is called on every piece of code that concerns items. This code checks if they are the e-berries, or even if they are legal. To increase the number of items, one needed to expand the number in here (currently 0x176) first. But in theory, that would allow us to have 65535 items allowed.
In order for an item to disappear after use, you need to use a disappearing code such as the one in 0x0809A1D8. This routine is, in fact, called for every item removal. It receives r0 as the item number and R1 as the number of items to remove.
The Items in the bag, in the RAM, are stored in a very annoying way, made to throw cheaters away from editing them. Just like the pokémon box data, they are stored dynamically, and are accessed by going to the pointers indicated in 0x0203988c + (pocket_number * 8) , adding to that pointer the item slot, and finally going to 0x300500c, add to the pointer there f20, and performing an exclusive OR between the two values.
Here, I shall present an example of a new functional item, a portable pokecenter. It will always be spent when used, even if the pokémon were fully healed. But if you can follow that routine, you most likely can come up with a solution to that problem if you wish to use it. Also, the message loaded is the normal "repel is already on" message, so feel free to change it.
.align 2
     push {r4, lr}
     ldr r0, item_location
     ldrh r0, [r0]
     mov r1, #0x1
     bl call_erase_me
     bl call_special0
     mov r0, #0x0
     mov r1, #0x2
     ldr r2, phrase
     ldr r3, message_manage
     bl call_loader
     pop {r4, pc}
    .hword 0x0000
item_location: .word 0x0203ad30
phrase: .word 0x841659e
message_manage: .word 0x0810a1f9
call_erase_me: ldr r4, erase_me 
                            bx r4
erase_me: .word 0x0809A1D9
call_special0: ldr r0, special_0
                          bx r0
special_0: .word 0x080a0059
call_loader: ldr r4, loader_addr 
                       bx r4
loader_addr: .word 0x08108E71
And this is it for now. With this thread I have started an overlook on the Item world, that remains dark for too long. I hope that you who understand this can help understand the Items in all their workings.

So, I ask you to share any information you have on the subject, namely, these three main topics (for starters):
  1. How can we create new pokeball behaviours, such as new catch rates and specific pokemon targeting (any of the custom balls);
  2. How are the Pokemon submenu items (potions, berries, stones, TM's) organized, so we can create more of the above items;
  3. (ultimate goal) It is possible, but how can we create items that execute scripts.
Here are the links for my work

Currently working on:
Battle Script Documentation
Another large project
Reply With Quote
Old January 7th, 2010, 12:39 PM
ZodiacDaGreat's Avatar
Working on a Mobile System
Join Date: Feb 2007
Location: South Pacific
Age: 21
Gender: Male
Nature: Relaxed
Send a message via ICQ to ZodiacDaGreat
I've tried to make one item that executes scripts. I called a script from ASM in a item, if the type is set to others - the script doesn't work but when it was set to 'Use-Of-Select' type. The bag exited and the script worked but it kept running. So, I guess the bag's environment isn't compatible with the scripts - this is what I first thought too until I saw Juan's explanation of script execution. I've never initialised the script structure. So, I'll try again and post some discoveries.

Ah, I found a way to show a message box from examining the coin case.
	push {r4-r5, lr}

	mov r0, #0x0 @ Textbox left position*
	mov r1, #0x0 @ Textbox top position*
	ldr r2, =0x0890000B @ Text data**
	ldr r5, .DisplayTextFunc
	bl .BranchLink

	pop {r4-r5}
	pop {r0}
	bx r0

	bx r5
* I'm not sure about this as I haven't really messed with it. It could be the other way round.
** The text data must end with '\c\h09'. The wait for keypress code or else it'll display the text and close down.

Last edited by ZodiacDaGreat; January 7th, 2010 at 05:36 PM.
Reply With Quote
Old January 8th, 2010, 06:55 PM
pokemon rom researcher
Join Date: Dec 2008
I have sucessfully managed to execute a script through an item. But it is still quite buggy. First, I bring you what matters most, the code:
/*this routine loads a fixed script and runs it*/
New_item_start:  push {r4,lr}
                        ldr r0, script
                        bl script_executer
                        ldr R1, Script_flag_set
                        mov R0, #0x1
                        strb R0, [R1]
                        bl bag_exiter
                        pop {r4,pc}

script: .word 0x08801000 /*the script to execute after leaving the bag*/
Script_flag_set: .word 0x03000f9c
script_executer:  ldr r1, exe_addr
                        bx r1
exe_addr: .word 0x08069AE5
bag_exiter:  ldr r1, exit_code
                 bx r1
exit_code: .word 0x080a103d
(ps: this code does not delete the item used.)
This will sucessfully run a piece of code through the map, just like a normal script. This code has been tested for all pockets, and only works if it's type byte is not 2. In fact, the type byte 2 seems to be used by the game to determine if a code is stored for posterior execution. Items with 2 on it that try to leave the bag will trigger a condition that calls for another type of exit.
As for the bugs, I must say, it all comes down to one: the Start menu.
The game exits the bag and re-opens the menu, a convenient feature most of the time. But, when the game exits the bag and asks to run a script, the game will run both at once. That, besides being graphically ugly (see attatchment), is also very bad for us, as the control scheme for the menu overwrite the normal world controls, and pressing A will automatically open the bag menu once more. Depending on how you start the script, or how you encode your Item, this bug may not be a problem. Using any scripting function that overwrites the Overworld screen, or that refreshes the map entirely (and there are many, refreshing with warps, loading the PC screens, the pokemon selection menu, the town map special...) the bug is no longer important. Also, being a fully functional script, it also allows trainer battles and set wild battles, but message boxes, multichoice boxes (like the Yes\no one) and the like will not work until the map is refreshed somehow.
And here is where I ask for your help. I can't seem to find the location the Menu opens after the return for the OW map (as all of the OW functions located at the function execution table at 0x3005090 seem to be the same when it's on or not, only one byte changes from 0xff to something else, and changing it will crash the game). So, I will place here some of the bag_exit routine, and hope someone will be able to find where to change it to prevent the menu when one of our items runs.
ROM:080A103C Bag_exit                                ; CODE XREF: Bicycle_func+AAp
ROM:080A103C                                         ; ROM:080A1352p ...
ROM:080A103C                 PUSH    {LR}
ROM:080A103E                 LSL     R0, R0, #0x18
ROM:080A1040                 LSR     R2, R0, #0x18
ROM:080A1042                 LDR     R1, =0x3005090
ROM:080A1044                 LSL     R0, R2, #2
ROM:080A1046                 ADD     R0, R0, R2
ROM:080A1048                 LSL     R0, R0, #3
ROM:080A104A                 ADD     R0, R0, R1
ROM:080A104C                 MOV     R1, #0xE
ROM:080A104E                 LDRSH   R0, [R0,R1]
ROM:080A1050                 CMP     R0, #1
ROM:080A1052                 BEQ     loc_80A1070
ROM:080A1054                 LDR     R1, =0x3005020
ROM:080A1056                 LDR     R0, =(loc_80A1084+1)
ROM:080A1058                 STR     R0, [R1]
ROM:080A105A                 ADD     R0, R2, #0
ROM:080A105C                 BL      sub_80A0FBC
ROM:080A1060                 B       loc_80A107A
ROM:080A1060 ; ---------------------------------------------------------------------------
ROM:080A1062                 DCB    0
ROM:080A1063                 DCB    0
ROM:080A1064 dword_80A1064   DCD 0x3005090           ; DATA XREF: Bag_exit+6r
ROM:080A1068 dword_80A1068   DCD 0x3005020           ; DATA XREF: Bag_exit+18r
ROM:080A106C off_80A106C     DCD loc_80A1084+1       ; DATA XREF: Bag_exit+1Ar
ROM:080A1070 ; ---------------------------------------------------------------------------
ROM:080A1070 loc_80A1070                             ; CODE XREF: Bag_exit+16j
ROM:080A1070                 LDR     R0, =0x2039998
ROM:080A1072                 LDR     R1, [R0]
ROM:080A1074                 ADD     R0, R2, #0
ROM:080A1076                 BL      sub_81E3BAC
ROM:080A107A loc_80A107A                             ; CODE XREF: Bag_exit+24j
ROM:080A107A                 POP     {R0}
ROM:080A107C                 BX      R0
ROM:080A107C ; End of function Bag_exit
ROM:080A107C ; ---------------------------------------------------------------------------
ROM:080A107E                 DCB    0
ROM:080A107F                 DCB    0
ROM:080A1080 dword_80A1080   DCD 0x2039998           ; DATA XREF: Bag_exit:loc_80A1070r
ROM:080A1084 ; ---------------------------------------------------------------------------
ROM:080A0FBC sub_80A0FBC                             ; CODE XREF: Bag_exit+20p
ROM:080A0FBC                                         ; sub_80A16D0+6p
ROM:080A0FBC                 PUSH    {R4,R5,LR}
ROM:080A0FBE                 LSL     R0, R0, #0x18
ROM:080A0FC0                 LSR     R5, R0, #0x18
ROM:080A0FC2                 LDR     R1, =0x203AD30
ROM:080A0FC4                 LDRH    R0, [R1]
ROM:080A0FC6                 CMP     R0, #0xAF
ROM:080A0FC8                 BNE     loc_80A0FE0
ROM:080A0FCA                 LDR     R0, =0x3005090
ROM:080A0FCC                 LSL     R1, R5, #2
ROM:080A0FCE                 ADD     R1, R1, R5
ROM:080A0FD0                 LSL     R1, R1, #3
ROM:080A0FD2                 ADD     R1, R1, R0
ROM:080A0FD4                 LDRB    R0, [R1,#0x10]
ROM:080A0FD6                 B       loc_80A0FE6
ROM:080A0FD6 ; ---------------------------------------------------------------------------
ROM:080A0FD8 dword_80A0FD8   DCD 0x203AD30           ; DATA XREF: sub_80A0FBC+6r
ROM:080A0FDC dword_80A0FDC   DCD 0x3005090           ; DATA XREF: sub_80A0FBC+Er
ROM:080A0FE0 ; ---------------------------------------------------------------------------
ROM:080A0FE0 loc_80A0FE0                             ; CODE XREF: sub_80A0FBC+Cj
ROM:080A0FE0                 LDRH    R0, [R1]
ROM:080A0FE2                 BL      get_item_type
ROM:080A0FE6 loc_80A0FE6                             ; CODE XREF: sub_80A0FBC+1Aj
ROM:080A0FE6                 SUB     R0, #1
ROM:080A0FE8                 LSL     R0, R0, #0x18
ROM:080A0FEA                 LSR     R4, R0, #0x18
ROM:080A0FEC                 LDR     R0, =0x203AD30
ROM:080A0FEE                 LDRH    R0, [R0]
ROM:080A0FF0                 BL      sub_809A260
ROM:080A0FF4                 LSL     R0, R0, #0x18
ROM:080A0FF6                 LSR     R0, R0, #0x18
ROM:080A0FF8                 CMP     R0, #5
ROM:080A0FFA                 BNE     loc_80A1018
ROM:080A0FFC                 LDR     R0, =off_83E2954
ROM:080A0FFE                 LSL     R1, R4, #2
ROM:080A1000                 ADD     R1, R1, R0
ROM:080A1002                 LDR     R0, [R1]
ROM:080A1004                 BL      sub_813D934
ROM:080A1008                 ADD     R0, R5, #0
ROM:080A100A                 BL      sub_813D808
ROM:080A100E                 B       loc_80A1032
ROM:080A100E ; ---------------------------------------------------------------------------
ROM:080A1010 dword_80A1010   DCD 0x203AD30           ; DATA XREF: sub_80A0FBC+30r
ROM:080A1014 off_80A1014     DCD off_83E2954         ; DATA XREF: sub_80A0FBC+40r
ROM:080A1018 ; ---------------------------------------------------------------------------
ROM:080A1018 loc_80A1018                             ; CODE XREF: sub_80A0FBC+3Ej
ROM:080A1018                 LDR     R0, =off_83E2954
ROM:080A101A                 LSL     R1, R4, #2
ROM:080A101C                 ADD     R1, R1, R0
ROM:080A101E                 LDR     R0, [R1]
ROM:080A1020                 BL      sub_8108EE0
ROM:080A1024                 CMP     R4, #1
ROM:080A1026                 BNE     loc_80A102C
ROM:080A1028                 BL      sub_8108CB4
ROM:080A102C loc_80A102C                             ; CODE XREF: sub_80A0FBC+6Aj
ROM:080A102C                 ADD     R0, R5, #0
ROM:080A102E                 BL      sub_8108B50
ROM:080A1032 loc_80A1032                             ; CODE XREF: sub_80A0FBC+52j
ROM:080A1032                 POP     {R4,R5}
ROM:080A1034                 POP     {R0}
ROM:080A1036                 BX      R0
ROM:080A1036 ; End of function sub_80A0FBC
ROM:080A1036 ; ---------------------------------------------------------------------------
ROM:080A1038 off_80A1038     DCD off_83E2954         ; DATA XREF: sub_80A0FBC:loc_80A1018r
Attached Images
File Type: png Dirty_image.png‎ (7.8 KB, 251 views) (Save to Dropbox)
Here are the links for my work

Currently working on:
Battle Script Documentation
Another large project
Reply With Quote
Old January 8th, 2010, 07:24 PM
ZodiacDaGreat's Avatar
Working on a Mobile System
Join Date: Feb 2007
Location: South Pacific
Age: 21
Gender: Male
Nature: Relaxed
Send a message via ICQ to ZodiacDaGreat
I think we should call both exitbag followed by a exitmenu function.
Reply With Quote
Old January 8th, 2010, 07:35 PM
I've seen things, man.
Join Date: Jul 2004
Jpan, please reply to my PM, yo. :D
yes, this is doge.

potato is not here.

Reply With Quote
Old January 9th, 2010, 09:48 PM
liuyanghejerry's Avatar
Join Date: Jan 2008
Location: China,Xi'an
Nature: Calm
Send a message via ICQ to liuyanghejerry Send a message via Windows Live Messenger to liuyanghejerry Send a message via Yahoo to liuyanghejerry
Originally Posted by JPAN View Post
I have sucessfully managed to execute a script through an item. But it is still quite buggy. First, I bring you what matters most, the code:
/*this routine loads a fixed script and runs it*/
New_item_start:  push {r4,lr}
                        ldr r0, script
                        bl script_executer
                        ldr R1, Script_flag_set
                        mov R0, #0x1
                        strb R0, [R1]
                        bl bag_exiter
                        pop {r4,pc}
script: .word 0x08801000 /*the script to execute after leaving the bag*/
Script_flag_set: .word 0x03000f9c
script_executer:  ldr r1, exe_addr
                        bx r1
exe_addr: .word 0x08069AE5
bag_exiter:  ldr r1, exit_code
                 bx r1
exit_code: .word 0x080a103d
(ps: this code does not delete the item used.)
Well,I'm not sure,but what I saw of the mach bike,is running the 0x080a103d before it works in the map.
I don't have my own computer for now,so I can't research deeper,sorry...
Hope this helps...
Zel,thethethethe,LU-HO,Darthatron,HackMew,ZodiacDaGreat,Juan,score_under,JPAN,Tamah-chan,I really appreciate your kindness and your help!:D

I did something that really bad.But made all Chinese can hack Pokemon, too.If you guys hate me, I totally understand,but cannot do anything but force to keep everything.
If there must be someone to undertake all spit and curse, it must be me.
Reply With Quote
Old January 11th, 2010, 07:10 PM
pokemon rom researcher
Join Date: Dec 2008
I created an alternative way to run the script through an item, using a really cheap method.
The return is executed as normally would, and the script starts executing as soon as it leaves the bag.
But the script it runs is not the one the hacker placed therem but one at a fixed ROM position.
A "header" that forces the BAG window to close before starting to execute the main code.
This is the final result asm source file, the version I shall make available in my next hack release:
.align 2
/*this is the final result of the first stage of item usage. This code will allow you to run scripts through an item.
Usage Requirements:
Compiled key_change_hack;
compiled special 0xc9 (force key), even if not as a special
to use:
1 - place the pointer to this routine in the OW execution word of the item of your choice
2 - Place the Script pointer in the last word (right next to the name of the next item)
2.5 - this code does not remove the item, to make it easier to code Key items. Just place in your script somewhere a "removeitem item_num 0x1" to destroy it.
This has been made to run trainer battles, map display, pokemon selection screen and some specials. seems to work well with all scripting commands.
New_item_start:  push {r4,lr}
                        ldr r0, RAM_item
                        ldrh r0, [r0]
                        mov r1, #0x2c
                        mul r0, r1
                        ldr r1, item_addr
                        add r0, r0, r1
                        ldr r4, [r0]            /*loads item script*/
                        ldr r2, script_area
                        str r4, [r2]
                        mov r4, #0x5
                        sub r2, #0x1
                        strb r4, [r2]       /*creates a bypass for our real script*/
                        ldr r0, script_pos /*the starter script with the menu shut*/
                        bl script_executer
                        ldr     R1, Script_flag_set
                        mov  R0, #0x1
                        strb R0, [R1]
                        bl bag_exiter
                        pop {r4,pc}
RAM_item: .word 0x0203ad30
item_addr: .word 0x083db050
Script_flag_set: .word 0x03000f9c
script_executer: ldr r1, exe_addr
                       bx r1
exe_addr: .word 0x08069AE5
bag_exiter:  ldr r1, exit_code
                 bx r1
exit_code: .word 0x080a103d
script_area: .word 0x0203f3ec
script_pos: .word 0x00000000
This script must be compiled and put somewhere in the rom, and the pointer to this placed in script_pos. 
Compiled version already comes with it compiled, but you need to put the pointer in the 4 zero bytes area in the middle of the code.
copyvar 0x8012 0x8004
copyvar 0x8013 0x8005
setvar 0x8004 0x2
setvar 0x8005 0x7
pause 0x16
special 0xC9 'or callasm @location_you_put_key_presser
pause 0x1
copyvar 0x8004 0x8012
copyvar 0x8005 0x8013
goto 0x203F3EB
And the dependencies
.align 2
This code will be replacing the two lines at 0x80005e8, the Key loader
This will, at an end, allow for us to input keys of our own, to create several key-manipulation techniques. Examples:
 key inibition; key replacement.
to apply, place a bx r0 (00 47) at 0x080005ec and replace the pointer at 0x08000624 to this routine's one.
Stuff this will do:
type of change will depend on 0203f4ec contents.
bit set -> effect
0 -> change value to and with, so it makes the game believe a certain key is pressed.
       This key value is placed at 0x0203f4de.
1 -> makes sure a key is not detected. However, that key is allways detected by the key specials.
      Allows you to delete the access to the help menu, or start, etc.
      That keymap must be placed at 0203f4fc.
2 -> if the player is in the OW, forces the script at 0203f4f4 to run when a key in 
       the position 0x0203f4ee
Key_wrecker_start: push {r4-r7} 
                           ldr r0, key_addr
                           ldrh r0, [r0]
                           ldr r4, switches
                           ldrb r1, [r4]
                           cmp r1, #0x0
                           beq nothing_to_do
                           bl check_for_script
                           bl check_for_forced
                           bl check_for_cancel
nothing_to_do:       pop {r4-r7}
                           add r1, r0, #0x0
                           ldr r0, return_place
                           bx r0
.hword 0x0000
key_addr: .word 0x04000130
switches: .word 0x0203f4ec
return_place: .word 0x080005ef
check_for_script: push {r0-r1,lr}
                        mov r2, #0x4       /*check for flag*/
                        and r2, r1
                        cmp r2, #0x0
                        beq end_all
                        ldr r5, script_on    /*check if a script is executing*/
                        ldrb r3, [r5]
                        cmp r3, #0x1
                        beq end_all
                        ldrh r2, [r4, #0x2]  /*check if the keys are pressed*/
                        and r2, r0
                        cmp r2, #0x0
                        bne end_all
                        ldr r3, first_function    /*checks if we are in the OW*/
                        ldr r2, [r3]
                        ldr r3, OW_function
                        cmp r2, r3
                        bne end_all
                        mov r2, #0x1 /*if all is ok, run script*/
                        strb r2, [r5]
                        ldr  r0, [r4, #0x8]
                        bl script_executer
end_all:              pop {r0-r1,pc}
script_on: .word 0x03000f9c
first_function: .word 0x03005090
OW_function: .word 0x08079e0d
check_for_forced: push {lr}
                         mov r2, #0x1 /*check for flag*/
                         and r2, r1
                         cmp r2, #0x0
                         beq end_all_2
                         ldrb r2, [r4, #0x1] /*check if it should apply it*/
                         cmp r2, #0x0
                         beq end_all_2
                         sub r2, #0x1
                         strb r2, [r4, #0x1] /*updates counter*/
                         sub r4, #0xE
                         ldrh r2, [r4]     /*gets keymap to force*/
                         add r4, #0xe
                         mvn r2, r2
                         and r0, r2         /*keys changed*/
end_all_2:           pop {pc}
check_for_cancel: push {lr}
                         mov r2, #0x2 /*check for flag*/
                         and r2, r1
                         cmp r2, #0x0
                         beq end_all_3
                         ldr r2, [r4, #0x10] /*loads key to ignore*/
                         orr r0, r2 /*ignored*/
end_all_3:           pop {pc}
script_executer: ldr r1, exe_addr
                       bx r1
exe_addr: .word 0x08069AE5
The special is only a setter for the Force B flag. If you understood the above code, you could probably do the same with writebytes
.align 2
/*this code forces one keyMap stored on your ROM to run for the asked number of times
Special c9 receives:
0x8004 is the keys to set
0x8005 is the times to set it to
returns nothing
Special_c9:  push {r0-r2, lr}
                 ldr r0, key_store_addr
                 ldr r2, var_8004
                 ldrh r1, [r2]
                 strh r1, [r0]
                 ldrh r1, [r2, #0x2]
                 add r0, #0xe
                 strb r1, [r0, #0x1]
                 ldrb r1, [r0]
                 mov r2, #0x1
                 orr r1, r2
                 strb r1, [r0]
                 pop {r0-r2, pc}
.hword 0x0000
key_store_addr: .word 0x0203f4de
var_8004: .word 0x020370c0
This method will only not work if the player holds down the B button at the same time it exits the bag.
It could be made certain that B button was not pressed at least for one check, but probably wouldn't be worth it.

And that's it for Script Items. Just as mentioned in the code above, this is a generic item for any OW activity, and as such, is only guaranteed to work at the Overworld. Next step, finding the battle items code and usages.
Here are the links for my work

Currently working on:
Battle Script Documentation
Another large project
Reply With Quote
Old February 5th, 2010, 12:44 AM
liuyanghejerry's Avatar
Join Date: Jan 2008
Location: China,Xi'an
Nature: Calm
Send a message via ICQ to liuyanghejerry Send a message via Windows Live Messenger to liuyanghejerry Send a message via Yahoo to liuyanghejerry
Originally Posted by JPAN View Post
How are the Pokemon submenu items (potions, berries, stones, TM's) organized, so we can create more of the above items;
I trace two potions for days and got some useful information.

There is a group of pointers stored at 0x2528BC in the ROM,about items,which includes potions.
These pointers are just base pointers.
Trace with you debugger at 0x08126C9C.
There is a algorithm about pointers.
And finally,the HP points the potion can restore is store in 0x03007D68 which will be a pointer in SP when run at 0x08041C58.
BTW,as a little hack profit,change the value at 0x2526F2 in ROM can change the value that normal potion restored.

This is for now.
Sorry the routine is so complex that I can't figure it out...

The key point around different potions is at 0x08126C68.
When run to here,this is what happened:
08126C68 b530 push {r4,r5,lr}
08126C6A 0400 lsl r0, r0, #0x10
08126C6C 0c01 lsr r1, r0, #0x10
08126C6E 1c0a add r2, r1, #0x0
08126C70 3a0d sub r2, #0xd
08126C72 0410 lsl r0, r2, #0x10
08126C74 0c00 lsr r0, r0, #0x10
08126C76 28a5 cmp r0, #0xa5
08126C78 d900 bls $08126c7c
08126C7C 29af cmp r1, #0xaf
08126C7E d109 bne $08126c94
08126C94 490b ldr r1, [$08126cc4] (=$082528bc)
08126C96 0090 lsl r0, r2, #0x02
08126C98 1840 add r0, r0, r1
Zel,thethethethe,LU-HO,Darthatron,HackMew,ZodiacDaGreat,Juan,score_under,JPAN,Tamah-chan,I really appreciate your kindness and your help!:D

I did something that really bad.But made all Chinese can hack Pokemon, too.If you guys hate me, I totally understand,but cannot do anything but force to keep everything.
If there must be someone to undertake all spit and curse, it must be me.

Last edited by liuyanghejerry; February 5th, 2010 at 01:12 AM. Reason: Add info
Reply With Quote
Old March 19th, 2010, 10:13 PM
kittopian's Avatar
The Kittopian CREATOR
Join Date: Mar 2010
Location: KITTOPIA
I am sorry if I am off topic but for the "ITEMS RUNNING SCRIPTS" ASM code, could someone explain how to convert it to PKMN RUBY (AXVE)? Any help will be greatly appreciated (PS, I do not know much about ASM). Also how do I insert them?

Last edited by kittopian; March 23rd, 2010 at 02:09 PM.
Reply With Quote
Old May 4th, 2010, 04:55 PM
pokemon rom researcher
Join Date: Dec 2008
After studying battle scripts (here), I've come across the code that kept coming around to bug me, the capture rate function. Turns out, the reason we couldn't find it on the item function was because the ball function is, in fact, a simple generic "load item" function with a "search if there's room for more pokemon" function attached. The battle script function was the one that did all the work.
But this function alone was not enough. The game has two checks preventing an item to be used in battle if not real. The first one was the one who loaded the script. An extensive search for the script assumed address linked to a table, and that table linked to a function that kept all allowed items to run scripts for. The function is too big (and largely irrelevant), so only part of it will be posted:
ROM:08016418                 PUSH    {R4-R7,LR}
ROM:0801641A                 MOV     R7, R10
ROM:0801641C                 MOV     R6, R9
ROM:0801641E                 MOV     R5, R8
ROM:08016420                 PUSH    {R5-R7}
ROM:08016422                 LDR     R4, =0x2023D6B
ROM:08016424                 LDR     R2, =0x2023D6C
ROM:08016426                 LDR     R1, =0x2023BDE
ROM:08016428                 LDR     R0, =0x2023BE2
ROM:0801642A                 LDRB    R0, [R0]
ROM:0801642C                 ADD     R0, R0, R1
ROM:0801642E                 LDRB    R0, [R0]
ROM:08016430                 STRB    R0, [R2]
ROM:08016432                 STRB    R0, [R4]
ROM:08016434                 LDR     R0, =0x2022974
ROM:08016436                 MOV     R1, #0
ROM:08016438                 STRH    R1, [R0]
ROM:0801643A                 LDR     R0, =0x2022976
ROM:0801643C                 STRH    R1, [R0]
ROM:0801643E                 LDRB    R0, [R4]
ROM:08016440                 BL      sub_801CFE4
ROM:08016444                 LDR     R5, =0x2023D68
ROM:08016446                 LDR     R2, =0x20233C4
ROM:08016448                 LDRB    R1, [R4]
ROM:0801644A                 LSL     R1, R1, #9
ROM:0801644C                 ADD     R0, R2, #1
ROM:0801644E                 ADD     R0, R1, R0
ROM:08016450                 LDRB    R3, [R0]
ROM:08016452                 ADD     R2, #2
ROM:08016454                 ADD     R1, R1, R2
ROM:08016456                 LDRB    R0, [R1]
ROM:08016458                 LSL     R0, R0, #8
ROM:0801645A                 ORR     R3, R0
ROM:0801645C                 STRH    R3, [R5]
ROM:0801645E                 ADD     R1, R3, #0
ROM:08016460                 CMP     R1, #0xC     ;number of pokeball types
ROM:08016462                 BHI     loc_801649C     ;larger means other item
ROM:08016464                 LDR     R2, =0x2023D74
ROM:08016466                 LDR     R1, =PokeBall_Toss
ROM:08016468                 LDRH    R0, [R5]
ROM:0801646A                 LSL     R0, R0, #2
ROM:0801646C                 ADD     R0, R0, R1
ROM:0801646E                 LDR     R0, [R0]
ROM:08016470                 STR     R0, [R2]
ROM:08016472                 B       loc_80164FC
ROM:08016472 ; ---------------------------------------------------------------------------
ROM:08016474 dword_8016474   DCD 0x2023D6B           ; DATA XREF: ROM:08016422r
ROM:08016478 dword_8016478   DCD 0x2023D6C           ; DATA XREF: ROM:08016424r
ROM:0801647C dword_801647C   DCD 0x2023BDE           ; DATA XREF: ROM:08016426r
ROM:08016480 dword_8016480   DCD 0x2023BE2           ; DATA XREF: ROM:08016428r
ROM:08016484 dword_8016484   DCD 0x2022974           ; DATA XREF: ROM:08016434r
ROM:08016488 dword_8016488   DCD 0x2022976           ; DATA XREF: ROM:0801643Ar
ROM:0801648C dword_801648C   DCD 0x2023D68           ; DATA XREF: ROM:08016444r
ROM:08016490 dword_8016490   DCD 0x20233C4           ; DATA XREF: ROM:08016446r
ROM:08016494 dword_8016494   DCD 0x2023D74           ; DATA XREF: ROM:08016464r
ROM:08016498 off_8016498     DCD PokeBall_Toss       ; DATA XREF: ROM:08016466r
ROM:0801649C ; ---------------------------------------------------------------------------
ROM:0801649C loc_801649C                             ; CODE XREF: ROM:08016462j
ROM:0801649C                 ADD     R0, R3, #0
ROM:0801649E                 SUB     R0, #0x50
ROM:080164A0                 LSL     R0, R0, #0x10
ROM:080164A2                 LSR     R0, R0, #0x10
ROM:080164A4                 CMP     R0, #1 ;0x50 and 0x51 are the pokedoll and fluffy tail items
ROM:080164A6                 BHI     loc_80164C4
ROM:080164A8                 LDR     R0, =0x2023D74
ROM:080164AA                 LDR     R1, =off_81D99FC
ROM:080164AC                 LDR     R1, [R1]
ROM:080164AE                 STR     R1, [R0]
ROM:080164B0                 LDR     R1, =0x2023BE3
ROM:080164B2                 MOV     R10, R1
ROM:080164B4                 B       loc_801671E
ROM:080164B4 ; ---------------------------------------------------------------------------
ROM:080164B6                 DCB    0
ROM:080164B7                 DCB    0
ROM:080164B8 dword_80164B8   DCD 0x2023D74           ; DATA XREF: ROM:080164A8r
ROM:080164BC off_80164BC     DCD off_81D99FC         ; DATA XREF: ROM:080164AAr
ROM:080164C0 dword_80164C0   DCD 0x2023BE3           ; DATA XREF: ROM:080164B0r
ROM:080164C4 ; ---------------------------------------------------------------------------
ROM:080164C4 loc_80164C4                             ; CODE XREF: ROM:080164A6j
ROM:080164C4                 MOVL    R0, 0x15E  ;check for the pokeflute
ROM:080164C8                 CMP     R1, R0
ROM:080164CA                 BNE     loc_80164E8
ROM:080164CC                 LDR     R0, =0x2023D74
ROM:080164CE                 LDR     R1, =off_81D99FC
ROM:080164D0                 LDR     R1, [R1,#4]
ROM:080164D2                 STR     R1, [R0]
ROM:080164D4                 LDR     R2, =0x2023BE3
ROM:080164D6                 MOV     R10, R2
ROM:080164D8                 B       loc_801671E
ROM:080164D8 ; ---------------------------------------------------------------------------
ROM:080164DA                 DCB    0
ROM:080164DB                 DCB    0
ROM:080164DC dword_80164DC   DCD 0x2023D74           ; DATA XREF: ROM:080164CCr
ROM:080164E0 off_80164E0     DCD off_81D99FC         ; DATA XREF: ROM:080164CEr
ROM:080164E4 dword_80164E4   DCD 0x2023BE3           ; DATA XREF: ROM:080164D4r
This code is still quite big, so focus on the item-indicating lines. Directly below them there are some lines of code that load a script onto the BattleScript Pointer (0x2023D74). But those scripts are limited for the balls, pointing to a table of 12 positions. What is their content? This is it:
ROM:081D99B0 PokeBall_Toss   DCD unk_81D9A14         
ROM:081D99B4                 DCD unk_81D9A14
ROM:081D99B8                 DCD unk_81D9A14
ROM:081D99BC                 DCD unk_81D9A14
ROM:081D99C0                 DCD unk_81D9A14
ROM:081D99C4                 DCD unk_81D9A3C
ROM:081D99C8                 DCD unk_81D9A14
ROM:081D99CC                 DCD unk_81D9A14
ROM:081D99D0                 DCD unk_81D9A14
ROM:081D99D4                 DCD unk_81D9A14
ROM:081D99D8                 DCD unk_81D9A14
ROM:081D99DC                 DCD unk_81D9A14
ROM:081D99E0                 DCD unk_81D9A14
As you can see, apart from one, they are the same script. The different one is the Safari Ball.
Now, imagine you want a new type of ball. Repointing the table would work if it wasn't for a simple detail: Potions (0xd) are handy items, but adding one entry would replace their behaviour for this one. Unless you're interested in a potion that captures pokemon and does not heal them, this wouldn't be the best solution. Instead, let's repoint the whole relevant part of this function and work from it. Here's my take:
.align 2
/*This function is meant to replace the one at 08016460, where the choice
of which item is delegated to. 
08016460 to 08016463 will be replaced by a null op (0s), 08016464 stays as-is and 08016466 will be replaced by a bx r2 (10 47). At 0x08016494, place pointer to this*/
/*r1,r3 are the item, r5 is the item temp storage addr*/
/*this code will simulate the interesting part of the code, not using redundant functions.*/
Item_get:  cmp r1, #0x5
               beq Is_safari_ball
               cmp r1, #0xc
               bls Is_ball
               /*add new balls here, example given with item 0x3d*/
               cmp r1, #0x3d
               beq Is_ball
               cmp r1, #0x50
               beq dolly
               cmp r1, #0x51
               beq dolly
               mov r0, #0xaf
               lsl r0, r0, #0x1
               cmp r1, r0
               beq flute
               ldr r0, return_addr
               bx r0
.hword 0x0000
Is_safari_ball:   ldr r1, safari_script
                     b script_ender
Is_ball:           ldr r1, ball_script
                     b script_ender
dolly:              ldr r1, doll_script
                     b script_ender
flute:  ldr r1, flute_script
script_ender: ldr r0, script_ptr
                  str r1, [r0]
                  ldr r1, be3_addr
                  mov r10, r1
                  ldr r0, end_addr
                  bx r0
safari_script: .word 0x081D9A3c
ball_script:  .word 0x081D9A14
doll_script: .word 0x081D9B7C
flute_script: .word 0x081D9B86
script_ptr: .word 0x02023d74
be3_addr: .word 0x02023be3
return_addr:  .word 0x080164e9
end_addr: .word 0x0801671f
This code example shows a previously added 0x3d item as a ball. To add it yourselves, simply copy-paste the pokeball item on this new ball, changing the index to 0x3d.
Now, if you try to use it as-is, you'll have a funny scene where the player throws <insert ball name here> and it always fails to capture the target. At least it's a working ball, right? Also, note the graphics shown are those of the normal pokeball. The game defaults to that when the graphics to the corresponding ball do not exist. I will not address this problem yet.
So, it would be nice if our ball could capture something, right? Well, that's the area of another function, the one mentioned at the beggining of this post, the EF battle command, Pokemon catching function. Located at 0x0802D434, it's even bigger than the one before. It starts out by calculating lots of stuff, but let's focus only on the part that matters:
loc_802D4DC                             ; CODE XREF: ROM:0802D4BCj
ROM:0802D4DC                 LDR     R0, =0x2023D68 ;item address
ROM:0802D4DE                 LDRH    R0, [R0]
ROM:0802D4E0                 CMP     R0, #5 ;is safari ball
ROM:0802D4E2                 BNE     loc_802D508
ROM:0802D4E4                 LDR     R0, =0x2023FE8 ;special safari ball case
ROM:0802D4E6                 LDR     R0, [R0]
ROM:0802D4E8                 ADD     R0, #0x7C
ROM:0802D4EA                 LDRB    R0, [R0]
ROM:0802D4EC                 LSL     R1, R0, #2
ROM:0802D4EE                 ADD     R1, R1, R0
ROM:0802D4F0                 LSL     R0, R1, #8
ROM:0802D4F2                 SUB     R0, R0, R1
ROM:0802D4F4                 MOV     R1, #0x64
ROM:0802D4F6                 BL      sub_81E4018
ROM:0802D4FA                 LSL     R0, R0, #0x18
ROM:0802D4FC                 LSR     R5, R0, #0x18
ROM:0802D4FE                 B       loc_802D520
ROM:0802D4FE ; ---------------------------------------------------------------------------
ROM:0802D500 dword_802D500   DCD 0x2023D68           ; DATA XREF: ROM:loc_802D4DCr
ROM:0802D504 dword_802D504   DCD 0x2023FE8           ; DATA XREF: ROM:0802D4E4r
ROM:0802D508 ; ---------------------------------------------------------------------------
ROM:0802D508 loc_802D508                             ; CODE XREF: ROM:0802D4E2j
ROM:0802D508                 LDR     R3, =Base_Stats
ROM:0802D50A                 LDR     R2, =0x2023BE4
ROM:0802D50C                 LDRB    R1, [R6]
ROM:0802D50E                 MOV     R0, #0x58
ROM:0802D510                 MUL     R0, R1
ROM:0802D512                 ADD     R0, R0, R2
ROM:0802D514                 LDRH    R1, [R0]
ROM:0802D516                 LSL     R0, R1, #3
ROM:0802D518                 SUB     R0, R0, R1
ROM:0802D51A                 LSL     R0, R0, #2
ROM:0802D51C                 ADD     R0, R0, R3
ROM:0802D51E                 LDRB    R5, [R0,#8]
ROM:0802D520 loc_802D520                             ; CODE XREF: ROM:0802D4FEj
ROM:0802D520                 LDR     R2, =0x2023D68
ROM:0802D522                 LDRH    R0, [R2]
ROM:0802D524                 CMP     R0, #5
ROM:0802D526                 BHI     loc_802D52A
ROM:0802D528                 B       loc_802D620 ;is regular ball
ROM:0802D52A ; ---------------------------------------------------------------------------
ROM:0802D52A loc_802D52A                             ; CODE XREF: ROM:0802D526j
ROM:0802D52A                 SUB     R0, #6 ;is special ball
ROM:0802D52C                 CMP     R0, #6
ROM:0802D52E                 BLS     loc_802D532
ROM:0802D530                 B       loc_802D62A
ROM:0802D532 ; ---------------------------------------------------------------------------
ROM:0802D532 loc_802D532                             ; CODE XREF: ROM:0802D52Ej
ROM:0802D532                 LSL     R0, R0, #2
ROM:0802D534                 LDR     R1, =off_802D54C
ROM:0802D536                 ADD     R0, R0, R1
ROM:0802D538                 LDR     R0, [R0]
ROM:0802D53A                 MOV     PC, R0
ROM:0802D53A ; ---------------------------------------------------------------------------
ROM:0802D53C off_802D53C     DCD Base_Stats          ; DATA XREF: ROM:loc_802D508r
ROM:0802D540 dword_802D540   DCD 0x2023BE4           ; DATA XREF: ROM:0802D50Ar
ROM:0802D544 dword_802D544   DCD 0x2023D68           ; DATA XREF: ROM:loc_802D520r
ROM:0802D548 off_802D548     DCD off_802D54C         ; DATA XREF: ROM:0802D534r
ROM:0802D54C off_802D54C     DCD loc_802D568         ; DATA XREF: ROM:off_802D548o
ROM:0802D550                 DCD loc_802D598
ROM:0802D554                 DCD loc_802D5AA
ROM:0802D558                 DCD loc_802D5D8
ROM:0802D55C                 DCD loc_802D608
ROM:0802D560                 DCD loc_802D5CA
ROM:0802D564                 DCD loc_802D5CA
The way the capture is calculated for individual balls is not relevant here, so check them out if you want to know how they did it. First let's take a look at this code. Once again, balls are chosen for being below 0xc. the last piece of code perform a jump based on the ball chosen. If we replace that function with one of our own, we can jump to our own functions with our own balls of choice. But that is irrelevant if we know nothing of how to calculate the catch rate. Well, to learn that the easy way, let's check the simple pokeball codes (master ball not included):
loc_802D620                             ; CODE XREF: ROM:0802D528j
ROM:0802D620                 LDR     R1, =unk_8250892
ROM:0802D622                 LDRH    R0, [R2]
ROM:0802D624                 SUB     R0, #2
ROM:0802D626                 ADD     R0, R0, R1
ROM:0802D628                 LDRB    R4, [R0]
ROM:08250892 unk_8250892     DCB 0x14                ; DATA XREF: ROM:off_802D694o
ROM:08250893                 DCB  0xF
ROM:08250894                 DCB  0xA
This piece of code is the answer to our problems. It basically subtracts two from the item number (so ultra ball is 0x0), and goes to a small table to get the catch rate value, that is stored in R4. Basically, in Fire Red, pokeballs have a catch multiplier of 10, great balls a mutiplier of 15 and ultra balls have a catch rate of 20, meaning that 5 is the true base value, even though no balls use it. Now, we know how to change the catch rate of a pokeball: simply place a different value in r4 before going to the actual catch chance calculation.
With all of the above in mind, I created a small example for a replacement function that uses the old functions for all old pokeballs, but uses our own for the ones we add.
.align 2
/*this code is to be inserted at 0802d52c, implementing a simple bx r1(08 47), and deleting 0802d52a (00 00)
This piece of code will replace the old check for balls larger than 5 (6 to c) and determine
a new catch rate for other balls, for any new balls we wish to add.*/
new_code:    cmp r0, #0xc
                   bgt not_normal_ball /*Our balls go here*/
                   sub r0, #0x6
                   lsl r0, r0, #0x2
                   ldr r1, old_ball_checks
                   add r0, r0, r1
                   ldr r0, [r0]
                   mov pc, r0
old_ball_checks: .word 0x0802d54c
not_normal_ball:  cmp r0, #0x3d
                        beq check_this_ball
                        mov r4, #0x0
                        ldr r0, return_me
                        bx r0
/*our simple ball function, ball rate depends on a value we set in the RAM address 0x0203fe00*/
check_this_ball: ldr r0, a_RAM_addr
                       ldrb r4, [r0]
                       ldr r0, return_me
                       bx r0
.hword 0x0000
a_RAM_addr: .word 0x0203fe00 
return_me: .word 0x0802d62b
With this, we are now able to build any type of ball we want, as long as we know how to check for the condition.
I know this might be a bit confusing, but I encourage those who know to compile it and see that it works. With this, ball hacking is possible. Last entry here will be the "how to change the throw ball graphics and the in-game status screen ball graphics".
Here are the links for my work

Currently working on:
Battle Script Documentation
Another large project
Reply With Quote
Old July 13th, 2011, 11:29 PM
pokemon rom researcher
Join Date: Dec 2008
It's been a long time since I last posted, but I'm back with some new information on Items. Today, I'll be updating you on how Party-screen Items work.

Party screen Items are a variety of items that are used directly on your pokemon on the party screen, or that are used in battle and affect your party pokemon. These include Healing items, Rare candy, Stones, Vitamins and stat-boosting items (like X-attack). TM's use a different system.

Party-items use the same routines to be executed, but differ in the routine called. Namely, they are:
Healing Item Function
Used by: Potion, Antidote, revive,, Vitamins, Berries
Does: Allows pokemon selection, prints the "restored X HP" or "cured from X" after displaying the health bar restoring.
Normal routine: 080a16e1
Battle routine:  080a1fbd
PP Restoring Function
Used by: Elixir, Ether, Leppa berry
Does: Allows pokemon selection,then attack selection on a small mini-screen, prints the "restored X PP"
Normal routine: 080a16fd
Battle routine:  080a1ff5
Healing item on all Pokemon
Used by: Sacred Ash
Does: Allows pokemon selection,then uses desired effect on all pokemon that are capable of using it
Normal routine: 080a176d
Battle routine:  none
Level up screen
Used by: Rare candy
Does: Allows pokemon selection, prints the stats screen after use
Normal routine: 080a1735
Battle routine:  none
Increase PP screen
Used by: PP Up
Does: Allows pokemon selection,attack selection, prints effect
Differs only from the restore screen because of the "PP to increase" line that appears next to the Attack selection box.
Normal routine: 080a1719
Battle routine:  none
Battle stats
Used by: X Attack, Dire Hit
Does: No pokemon selection, prints effect after used.
Normal routine: none
Battle routine:  080a1e7d
CanUse-ShowHP screen
Used by: Fire Stone, Leaf stone
Does: Allows pokemon selection, Shows "can't use" on top of pokemon where the item has no effect and HP bars over the ones where it works.
Normal routine: 080a1751
Battle routine:  none
There is still one used by Yellow flute at 080a2239

Putting this UI differences aside, the code beneath is pretty much the same. It runs two functions, one at 080413E4, that actually executes the code, and one at 08042414, that is called before, when the item is to be used on the pokemon, to determine if it will work at all. If either of them fails a "It Won't work" message is displayed.
Each of this functions border the 4KB in size, so I won't be posting them here. But they work by reading from a table of Item Flags, and working on each.
ItemFlags are stored in a table starting at 082528BC, starting with the value for the potion, and going all the way to Sitrus Berry, placing 0 on the items that have no party use. Those flags are a group of 6 to 10 bytes(depends on the flags present). Their layout is as follows:
byte 0
80 heals infatuation
40 forces to apply to first pokemon (no selection)
20 is dire-hit (up to 30)
1-f is increase attack battle stat by the given value
byte 1
1-f is increase speed battle stat by given value
10-f0 is increase defence, in the same manner
byte 2
1-f is increase special attack (note: x special raises only special attack)
10-f0 is increase accuracy
byte 3
80 is guard-spec 
40 for level up
20 for clear sleep
10 for clear poison
8 for clear burn
4 for clear ice
2 for clear paralyze
1 for clear confusion
byte 4
1 is up HP EV
2 is up Attack EV
4 means heal HP
8 means heal PP
10 means only to selected attack (select made by GUI choice)
20 means increase max PP
40 means revive and heal
80 means it's an evolution stone
when 40 and 4 are set, item only heals fainted pokemon
4 and 8 are mutually exclusive, you cannot heal PP and HP at the same time. 4 takes precedence over 8. 
byte 5
0x80 is the change happiness when 200+
0x40 is the change happiness when 100-->199
0x20 is the change happiness when -99
0x10 is the increase PP to max on selected attack
0x08 special defense ev up
0x04 special attack ev up
0x02 speed ev up
0x01 defense ev up
byte 6 
recovery value for Potion-like items,
increase in EV for EV-increasing items.
PP restoring items have a maximum of 7f
For health restoration, ff means max health, fe means half max health, fd is used by rare candy (only increase with level up)
byte 7
happiness increase/decrease for happiness on the range of 0-99
byte 8
happiness increase/decrease for happiness on the range of 100-199
byte 9
happiness increase/decrease for happiness on the range of 200-255
bytes 7 to 9 are signed bytes, meaning that FF = decrease of 1 happiness

So, what can we do with this information? Well, we can start designing new items with uses, such as new types of potions, new evolution stones, or new battle items. However, please note that you are limited to using items in the range between Potion(0d) and Sitrus berry (8e). To change that, we can erase the limiters at 0x08042508 (for the check routine) and the one at 0x0804152C (for the actual item usage). Replace each of those locations with 00 00 00 00. That will replace the jump with nop operations, erasing the check. Remember to repoint the entire table to a safe location if you do.

But the best part about this find is that we now know all items of this type call two functions to determine what to do. If we change these functions, we can make items do whatever we want to the pokemon in our party.
The system in place right now gives you some freedom to combine effects. But it will not allow you to do much. Even something as simple as an item that heals both PP and HP is impossible (without changing the routine).

To end, an example of a new item, a candy that boosts happiness and heals 10 hp to your pokemon:
The script would be
00 00 00 00 04 e0 0a 0a 06 04
Which means happiness boosted by 10 if less than 99, 6 if between 100 and 199 and 4 if over 200.
Placing this item immediately before HP-up, you would:
- place this in the rom in some location
- place the address to this location at 08252980
- overwrite the item above HP-up (Starting at 083dbad0), with all the usual data (index, name, price...)
- place as the Normal usage pointer the healing item function.
Here are the links for my work

Currently working on:
Battle Script Documentation
Another large project
Reply With Quote
Old July 14th, 2011, 05:40 AM
knizz's Avatar
Join Date: Aug 2007
I'm sorry I can't post anything on-topic now. But I'll look into this thread again when I have my own computer back. (~4 days) I'm happy you're back and posting, JPAN. I have a IDA-Database for firered. It's worth taking a look at. I have at least some basic notes about items in there too. Also all asm-hackers are invited to join Darthatrons and my IRC-Channel ( #pokehack) which is like this thread just with faster responses.

EDIT: I hope this helps a bit.
080A1998 @ =============== S U B R O U T I N E =======================================
080A1998 repel:                                  @ DATA XREF: ROM:item_super_repelo
080A1998                                         @ ROM:083DBE98o ...
080A1998                 PUSH    {R4,LR}
080A199A                 LSLS    R0, R0, #0x18
080A199C                 LSRS    R4, R0, #0x18
080A199E                 LDR     R0, =0x4020
080A19A0                 BL      var_load
080A19A4                 LSLS    R0, R0, #0x10
080A19A6                 CMP     R0, #0
080A19A8                 BNE     loc_080A19CC
080A19AA                 MOVS    R0, #0x29
080A19AC                 BL      music_play
080A19B0                 LDR     R0, =callback3table
080A19B2                 LSLS    R1, R4, #2
080A19B4                 ADDS    R1, R1, R4
080A19B6                 LSLS    R1, R1, #3
080A19B8                 ADDS    R1, R1, R0
080A19BA                 LDR     R0, =(c3_repel+1)
080A19BC                 STR     R0, [R1]
080A19BE                 B       loc_080A19D8
080A19BE @ ---------------------------------------------------------------------------
080A19C0 dword_080A19C0: .long 0x4020            @ DATA XREF: repel+6r
080A19C4 off_080A19C4:   .long callback3table    @ DATA XREF: repel+18r
080A19C8 off_080A19C8:   .long c3_repel+1        @ DATA XREF: repel+22r
080A19CC @ ---------------------------------------------------------------------------
080A19CC loc_080A19CC:                           @ CODE XREF: repel+10j
080A19CC                 LDR     R2, =aButTheEffectsOfARepelLingeredF @ "But the effects of a REPEL lingered fro"...
080A19CE                 LDR     R3, =(bag_print+1)
080A19D0                 MOVS    R0, R4
080A19D2                 MOVS    R1, #2
080A19D4                 BL      sub_08108E70
080A19D8 loc_080A19D8:                           @ CODE XREF: repel+26j
080A19D8                 POP     {R4}
080A19DA                 POP     {R0}
080A19DC                 BX      R0
080A19DC @ End of function repel
080A19DC @ ---------------------------------------------------------------------------
080A19DE                 .byte    0
080A19DF                 .byte    0
080A19E0 off_080A19E0:   .long aButTheEffectsOfARepelLingeredF
080A19E0                                         @ DATA XREF: repel:loc_080A19CCr
080A19E0                                         @ "But the effects of a REPEL lingered fro"...
080A19E4 off_080A19E4:   .long bag_print+1       @ DATA XREF: repel+36r
080A19E8 @ =============== S U B R O U T I N E =======================================
080A19E8 c3_repel:                               @ DATA XREF: repel+22o
080A19E8                                         @ repel:off_080A19C8o
080A19E8                 PUSH    {R4-R6,LR}
080A19EA                 LSLS    R0, R0, #0x18
080A19EC                 LSRS    R6, R0, #0x18
080A19EE                 BL      sub_080723E0
080A19F2                 LSLS    R0, R0, #0x18
080A19F4                 CMP     R0, #0
080A19F6                 BNE     loc_080A1A2A
080A19F8                 LDR     R4, =var_800E   @ Used item number location
080A19FA                 LDRH    R2, [R4]
080A19FC                 LDR     R3, =0xFFFF
080A19FE                 MOVS    R0, #4
080A1A00                 MOVS    R1, #0
080A1A02                 BL      sub_080A2294
080A1A06                 LDR     R5, =0x4020
080A1A08                 LDRH    R0, [R4]
080A1A0A                 BL      item_get_quality
080A1A0E                 MOVS    R1, R0
080A1A10                 LSLS    R1, R1, #0x18
080A1A12                 LSRS    R1, R1, #0x18
080A1A14                 MOVS    R0, R5
080A1A16                 BL      var_set
080A1A1A                 BL      sub_080A1A44
080A1A1E                 LDR     R2, =displayed_string
080A1A20                 LDR     R3, =(bag_print+1)
080A1A22                 MOVS    R0, R6
080A1A24                 MOVS    R1, #2
080A1A26                 BL      sub_08108E70
080A1A2A loc_080A1A2A:                           @ CODE XREF: c3_repel+Ej
080A1A2A                 POP     {R4-R6}
080A1A2C                 POP     {R0}
080A1A2E                 BX      R0
080A1A2E @ End of function c3_repel
080A1A2E @ ---------------------------------------------------------------------------
080A1A30 off_080A1A30:   .long var_800E          @ DATA XREF: c3_repel+10r
080A1A34 dword_080A1A34: .long 0xFFFF            @ DATA XREF: c3_repel+14r
080A1A38 dword_080A1A38: .long 0x4020            @ DATA XREF: c3_repel+1Er
080A1A3C off_080A1A3C:   .long displayed_string  @ DATA XREF: c3_repel+36r
080A1A40 off_080A1A40:   .long bag_print+1       @ DATA XREF: c3_repel+38r

08452EB8 brm_bottom_right_menu:seisof <aUse, brm_use+1>@ 0 @ DATA XREF: mega_func_3+28Ao
08452EB8                                         @ ROM:off_08109BA4o ...
08452EB8                 seisof <aToss, sub_08109CC0+1>@ 1 @ "USE"
08452EB8                 seisof <aRegister_0, sub_0810A000+1>@ 2
08452EB8                 seisof <aGive, sub_0810A0A8+1>@ 3
08452EB8                 seisof <aCancel_0, brm_cancel+1>@ 4
08452EB8                 seisof <aUse, sub_0810A324+1>@ 5
08452EB8                 seisof <aCheck, brm_use+1>@ 6
08452EB8                 seisof <aOpen, brm_use+1>@ 7
08452EB8                 seisof <aOpen, sub_0810A324+1>@ 8
08452EB8                 seisof <aWalk, brm_use+1>@ 9
08452EB8                 seisof <aDeselect, sub_0810A000+1>@ 10
08452EB8                 seisof <unk_084161CD, 0>@ 11

08109C50 @ =============== S U B R O U T I N E =======================================
08109C50 brm_use:                                @ DATA XREF: ROM:brm_bottom_right_menuo
08109C50                 PUSH    {R4,R5,LR}
08109C52                 LSLS    R0, R0, #0x18
08109C54                 LSRS    R4, R0, #0x18
08109C56                 LDR     R5, =var_800E
08109C58                 LDRH    R0, [R5]
08109C5A                 BL      sub_0809AA20
08109C5E                 CMP     R0, #0
08109C60                 BEQ     loc_08109CB4
08109C62                 MOVS    R0, #0xA
08109C64                 BL      sub_0810BA3C
08109C68                 MOVS    R0, #6
08109C6A                 BL      sub_0810BA3C
08109C6E                 MOVS    R0, #0
08109C70                 BL      sub_08003FA0
08109C74                 MOVS    R0, #1
08109C76                 BL      sub_08003FA0
08109C7A                 MOVS    R0, #0
08109C7C                 BL      sub_080F67A4
08109C80                 BL      count_pokemon
08109C84                 LSLS    R0, R0, #0x18
08109C86                 CMP     R0, #0
08109C88                 BNE     loc_08109CA4
08109C8A                 LDRH    R0, [R5]
08109C8C                 BL      sub_0809A9FC
08109C90                 LSLS    R0, R0, #0x18
08109C92                 LSRS    R0, R0, #0x18
08109C94                 CMP     R0, #1
08109C96                 BNE     loc_08109CA4
08109C98                 MOVS    R0, R4
08109C9A                 BL      sub_0810A170
08109C9E                 B       loc_08109CB4
08109C9E @ ---------------------------------------------------------------------------
08109CA0 off_08109CA0:   .long var_800E          @ DATA XREF: brm_use+6r
08109CA4 @ ---------------------------------------------------------------------------
08109CA4 loc_08109CA4:                           @ CODE XREF: brm_use+38j
08109CA4                                         @ brm_use+46j
08109CA4                 LDR     R0, =var_800E
08109CA6                 LDRH    R0, [R0]
08109CA8                 BL      sub_0809AA20
08109CAC                 MOVS    R1, R0
08109CAE                 MOVS    R0, R4
08109CB0                 BL      bx_r1           @ Call item function
08109CB4 loc_08109CB4:                           @ CODE XREF: brm_use+10j
08109CB4                                         @ brm_use+4Ej
08109CB4                 POP     {R4,R5}
08109CB6                 POP     {R0}
08109CB8                 BX      R0
08109CB8 @ End of function brm_use
08109CB8 @ ---------------------------------------------------------------------------
08109CBA                 .byte    0
08109CBB                 .byte    0
08109CBC off_08109CBC:   .long var_800E          @ DATA XREF: brm_use:loc_08109CA4r
JPAN, I have two of your wanted offsets.
03005074 is the number of the NPC that is executing a script.
03005090 is a table of structures with a function pointer that is called every frame. Think of it as pokemons multithreading system. It's called callback3 in my DB.
Firered IDA 6.1 DB:
VBA-M with lua scripting support (no longer in development)

Last edited by knizz; July 16th, 2011 at 12:58 PM.
Reply With Quote
Quick Reply

Sponsored Links

Advertise here
Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Minimum Characters Per Post: 25

All times are UTC -8. The time now is 04:18 PM.

Style by Nymphadora, artwork by Sa-Dui.
Like our Facebook Page Follow us on Twitter © 2002 - 2014 The PokéCommunity™,
Pokémon characters and images belong to The Pokémon Company International and Nintendo. This website is in no way affiliated with or endorsed by Nintendo, Creatures, GAMEFREAK, The Pokémon Company or The Pokémon Company International. We just love Pokémon.
All forum styles, their images (unless noted otherwise) and site designs are © 2002 - 2014 The PokéCommunity / Poké
PokéCommunity™ is a trademark of The PokéCommunity. All rights reserved. Sponsor advertisements do not imply our endorsement of that product or service. User generated content remains the property of its creator.