Thread: Research: Items
View Single Post
Old January 5th, 2010 (7:22 PM).
JPAN JPAN is offline
pokemon rom researcher
    Join Date: Dec 2008
    Posts: 104
    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