JPAN
pokemon rom researcher
- 104
- Posts
- 16
- Years
- Seen Jul 2, 2016
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:
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:
(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.
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):
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:
Code:
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
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:
Code:
THE REPEL CALLED ROUTINE
Code:
[FONT=Calibri]ROM:080A1998 PUSH {R4,LR}[/FONT]
[FONT=Calibri]ROM:080A199A LSL R0, R0, #0x18[/FONT]
[FONT=Calibri]ROM:080A199C LSR R4, R0, #0x18[/FONT]
[FONT=Calibri]ROM:080A199E LDR R0, =0x4020[/FONT]
[FONT=Calibri]ROM:080A19A0 BL sub_806E568 ;loads variable and retrives the value [/FONT]
[FONT=Calibri]ROM:080A19A4 LSL R0, R0, #0x10[/FONT]
[FONT=Calibri]ROM:080A19A6 CMP R0, #0 ;if there is at least a step remaining, goes to exit function[/FONT]
[FONT=Calibri]ROM:080A19A8 BNE loc_80A19CC[/FONT]
[FONT=Calibri]ROM:080A19AA MOV R0, #0x29[/FONT]
[FONT=Calibri]ROM:080A19AC BL sub_80722CC[/FONT]
[FONT=Calibri]ROM:080A19B0 LDR R0, =0x3005090 ;this is the routine pointer for later execution (note 1)[/FONT]
[FONT=Calibri]ROM:080A19B2 LSL R1, R4, #2[/FONT]
[FONT=Calibri]ROM:080A19B4 ADD R1, R1, R4[/FONT]
[FONT=Calibri]ROM:080A19B6 LSL R1, R1, #3[/FONT]
[FONT=Calibri]ROM:080A19B8 ADD R1, R1, R0[/FONT]
[FONT=Calibri]ROM:080A19BA LDR R0, =(loc_80A19E8+1)[/FONT]
[FONT=Calibri]ROM:080A19BC STR R0, [R1] ;stores the second routine for later execution[/FONT]
[FONT=Calibri]ROM:080A19BE B loc_80A19D8[/FONT]
[FONT=Calibri]ROM:080A19BE ; ---------------------------------------------------------------------------[/FONT]
[FONT=Calibri]ROM:080A19C0 dword_80A19C0 DCD 0x4020 ; DATA XREF: ROM:080A199Er[/FONT]
[FONT=Calibri]ROM:080A19C4 dword_80A19C4 DCD 0x3005090 ; DATA XREF: ROM:080A19B0r[/FONT]
[FONT=Calibri]ROM:080A19C8 off_80A19C8 DCD loc_80A19E8+1 ; DATA XREF: ROM:080A19BAr[/FONT]
[FONT=Calibri]ROM:080A19CC ; ---------------------------------------------------------------------------[/FONT]
[FONT=Calibri]ROM:080A19CC[/FONT]
[FONT=Calibri]ROM:080A19CC loc_80A19CC ; CODE XREF: ROM:080A19A8j[/FONT]
[FONT=Calibri]ROM:080A19CC LDR R2, =unk_841659E ; this is the "already in use sentence"[/FONT]
[FONT=Calibri]ROM:080A19CE LDR R3, =(loc_810A1F8+1) ;this loads the message to be executed in the bag.[/FONT]
[FONT=Calibri]ROM:080A19D0 ADD R0, R4, #0[/FONT]
[FONT=Calibri]ROM:080A19D2 MOV R1, #2[/FONT]
[FONT=Calibri]ROM:080A19D4 BL sub_8108E70[/FONT]
[FONT=Calibri]ROM:080A19D8[/FONT]
[FONT=Calibri]ROM:080A19D8 loc_80A19D8 ; CODE XREF: ROM:080A19BEj[/FONT]
[FONT=Calibri]ROM:080A19D8 POP {R4}[/FONT]
[FONT=Calibri]ROM:080A19DA POP {R0}[/FONT]
[FONT=Calibri]ROM:080A19DC BX R0[/FONT]
[FONT=Calibri]ROM:080A19DC ; ---------------------------------------------------------------------------[/FONT]
[FONT=Calibri]ROM:080A19DE DCB 0[/FONT]
[FONT=Calibri]ROM:080A19DF DCB 0[/FONT]
[FONT=Calibri]ROM:080A19E0 off_80A19E0 DCD unk_841659E ; DATA XREF: ROM:loc_80A19CCr[/FONT]
[FONT=Calibri]ROM:080A19E4 off_80A19E4 DCD loc_810A1F8+1 ; DATA XREF: ROM:080A19CEr[/FONT]
[FONT=Calibri]THE CHARGE REPEL ROUTINE[/FONT]
[FONT=Calibri]ROM:080A19E8 loc_80A19E8 ; DATA XREF: ROM:off_80A19C8o[/FONT]
[FONT=Calibri]ROM:080A19E8 PUSH {R4-R6,LR}[/FONT]
[FONT=Calibri]ROM:080A19EA LSL R0, R0, #0x18[/FONT]
[FONT=Calibri]ROM:080A19EC LSR R6, R0, #0x18[/FONT]
[FONT=Calibri]ROM:080A19EE BL sub_80723E0[/FONT]
[FONT=Calibri]ROM:080A19F2 LSL R0, R0, #0x18[/FONT]
[FONT=Calibri]ROM:080A19F4 CMP R0, #0[/FONT]
[FONT=Calibri]ROM:080A19F6 BNE loc_80A1A2A[/FONT]
[FONT=Calibri]ROM:080A19F8 LDR R4, =0x203AD30 ;used item number location[/FONT]
[FONT=Calibri]ROM:080A19FA LDRH R2, [R4][/FONT]
[FONT=Calibri]ROM:080A19FC LDR R3, =0xFFFF[/FONT]
[FONT=Calibri]ROM:080A19FE MOV R0, #4[/FONT]
[FONT=Calibri]ROM:080A1A00 MOV R1, #0[/FONT]
[FONT=Calibri]ROM:080A1A02 BL sub_80A2294[/FONT]
[FONT=Calibri]ROM:080A1A06 LDR R5, =0x4020[/FONT]
[FONT=Calibri]ROM:080A1A08 LDRH R0, [R4][/FONT]
[FONT=Calibri]ROM:080A1A0A BL sub_809A948 ;this is the routine that gets the actual repel value[/FONT]
[FONT=Calibri]ROM:080A1A0E ADD R1, R0, #0 [/FONT]
[FONT=Calibri]ROM:080A1A10 LSL R1, R1, #0x18[/FONT]
[FONT=Calibri]ROM:080A1A12 LSR R1, R1, #0x18[/FONT]
[FONT=Calibri]ROM:080A1A14 ADD R0, R5, #0[/FONT]
[FONT=Calibri]ROM:080A1A16 BL sub_806E584 ;this is the function that stores values in a variable[/FONT]
[FONT=Calibri]ROM:080A1A1A BL sub_80A1A44 ;this one buffers the string to print "[player] used [Item]"[/FONT]
[FONT=Calibri]ROM:080A1A1E LDR R2, =0x2021D18[/FONT]
[FONT=Calibri]ROM:080A1A20 LDR R3, =(loc_810A1F8+1) ; the same function as in the exit. ends with a return to the bag screen. [/FONT]
[FONT=Calibri]ROM:080A1A22 ADD R0, R6, #0[/FONT]
[FONT=Calibri]ROM:080A1A24 MOV R1, #2[/FONT]
[FONT=Calibri]ROM:080A1A26 BL sub_8108E70[/FONT]
[FONT=Calibri]ROM:080A1A2A[/FONT]
[FONT=Calibri]ROM:080A1A2A loc_80A1A2A ; CODE XREF: ROM:080A19F6j[/FONT]
[FONT=Calibri]ROM:080A1A2A POP {R4-R6}[/FONT]
[FONT=Calibri]ROM:080A1A2C POP {R0}[/FONT]
[FONT=Calibri]ROM:080A1A2E BX R0[/FONT]
[FONT=Calibri]ROM:080A1A2E ; ---------------------------------------------------------------------------[/FONT]
[FONT=Calibri]ROM:080A1A30 dword_80A1A30 DCD 0x203AD30 ; DATA XREF: ROM:080A19F8r[/FONT]
[FONT=Calibri]ROM:080A1A34 dword_80A1A34 DCD 0xFFFF ; DATA XREF: ROM:080A19FCr[/FONT]
[FONT=Calibri]ROM:080A1A38 dword_80A1A38 DCD 0x4020 ; DATA XREF: ROM:080A1A06r[/FONT]
[FONT=Calibri]ROM:080A1A3C dword_80A1A3C DCD 0x2021D18 ; DATA XREF: ROM:080A1A1Er[/FONT]
[FONT=Calibri]ROM:080A1A40 off_80A1A40 DCD loc_810A1F8+1 ; DATA XREF: ROM:080A1A20r[/FONT]
[FONT=Calibri]ROM:0809A948 sub_809A948 ; CODE XREF: sub_803ECEC+C2p[/FONT]
[FONT=Calibri]ROM:0809A948 ; sub_803ECEC+10Cp ...[/FONT]
[FONT=Calibri]ROM:0809A948 PUSH {R4,LR}[/FONT]
[FONT=Calibri]ROM:0809A94A LSL R0, R0, #0x10[/FONT]
[FONT=Calibri]ROM:0809A94C LSR R0, R0, #0x10[/FONT]
[FONT=Calibri]ROM:0809A94E LDR R4, =unk_83DB028 ;item table pointer[/FONT]
[FONT=Calibri]ROM:0809A950 BL sub_809A8A4 ;checks for item_validity (note 2)[/FONT]
[FONT=Calibri]ROM:0809A954 LSL R0, R0, #0x10[/FONT]
[FONT=Calibri]ROM:0809A956 LSR R0, R0, #0x10[/FONT]
[FONT=Calibri]ROM:0809A958 MOV R1, #0x2C[/FONT]
[FONT=Calibri]ROM:0809A95A MUL R0, R1[/FONT]
[FONT=Calibri]ROM:0809A95C ADD R0, R0, R4[/FONT]
[FONT=Calibri]ROM:0809A95E LDRB R0, [R0,#0x13][/FONT]
[FONT=Calibri]ROM:0809A960 POP {R4}[/FONT]
[FONT=Calibri]ROM:0809A962 POP {R1}[/FONT]
[FONT=Calibri]ROM:0809A964 BX R1[/FONT]
(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.
Code:
.align 2
.thumb
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
So, I ask you to share any information you have on the subject, namely, these three main topics (for starters):
- How can we create new pokeball behaviours, such as new catch rates and specific pokemon targeting (any of the custom balls);
- How are the Pokemon submenu items (potions, berries, stones, TM's) organized, so we can create more of the above items;
- (ultimate goal) It is possible, but how can we create items that execute scripts.