PDA

View Full Version : Items


JPAN
January 5th, 2010, 07:22 PM
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 usesThis 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:
THE REPEL CALLED ROUTINE
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
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
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

THE CHARGE REPEL ROUTINE
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
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
.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 0x08108E71And 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):
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.

ZodiacDaGreat
January 7th, 2010, 12:39 PM
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

.BranchLink:
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.

JPAN
January 8th, 2010, 06:55 PM
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
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
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: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
ROM:080A0FE0 loc_80A0FE0 ; CODE XREF: sub_80A0FBC+Cj
ROM:080A0FE0 LDRH R0, [R1]
ROM:080A0FE2 BL get_item_type
ROM:080A0FE6
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
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
ROM:080A102C loc_80A102C ; CODE XREF: sub_80A0FBC+6Aj
ROM:080A102C ADD R0, R5, #0
ROM:080A102E BL sub_8108B50
ROM:080A1032
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:080A1036 ; ---------------------------------------------------------------------------
ROM:080A1038 off_80A1038 DCD off_83E2954 ; DATA XREF: sub_80A0FBC:loc_80A1018r

ZodiacDaGreat
January 8th, 2010, 07:24 PM
I think we should call both exitbag followed by a exitmenu function.

interdpth
January 8th, 2010, 07:35 PM
Jpan, please reply to my PM, yo. :D

liuyanghejerry
January 9th, 2010, 09:48 PM
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...

JPAN
January 11th, 2010, 07:10 PM
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
.thumb
/*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
.thumb
/*
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
.thumb
/*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.

liuyanghejerry
February 5th, 2010, 12:44 AM
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...

Edit:
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

kittopian
March 19th, 2010, 10:13 PM
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?

JPAN
May 4th, 2010, 04:55 PM
After studying battle scripts (here (http://www.pokecommunity.com/showthread.php?t=215644)), 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:
ItemScript_Activator
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
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
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
.thumb
/*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
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
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
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
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
.thumb
/*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".

JPAN
July 13th, 2011, 11:29 PM
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.

knizz
July 14th, 2011, 05:40 AM
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 (irc.irchighway.net #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
080A1998
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
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
080A19D8 loc_080A19D8: @ CODE XREF: repel+26j
080A19D8 POP {R4}
080A19DA POP {R0}
080A19DC BX R0
080A19DC @ End of function repel
080A19DC
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
080A19E8 @ =============== S U B R O U T I N E =======================================
080A19E8
080A19E8
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
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
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
080A1A44

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
08109C50
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
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
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
08109CB8 @ ---------------------------------------------------------------------------
08109CBA .byte 0
08109CBB .byte 0
08109CBC off_08109CBC: .long var_800E @ DATA XREF: brm_use:loc_08109CA4r
08109CC0



EDIT 2:
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.

LocksmithArmy
September 6th, 2014, 07:49 PM
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


I just wanted to point out that these are bit fields...

Its not if byte 0 has a value of 80, its if bit 0 of byte 0 is 1 (or on, or true or however you wanna say it)...

I'm sure this is understood by most, but some may have missed it...

ALSO, if byte 6 is not needed, it is not present, byte 7 becomes byte 6, and so on. Same with bytes 7 8 and 9. they are all not required and only the needed ones are placed at the end of the first 0-5 bytes (in the described order).
SOOO if you are programaticly checking which items increase happiness, keep in mind that many times byte 6 will be the 0-99 happiness byte.