• Our software update is now concluded. You will need to reset your password to log in. In order to do this, you will have to click "Log in" in the top right corner and then "Forgot your password?".
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

ASM: How the objects in FR work

Kyoko1

Banned
63
Posts
10
Years
  • Seen Feb 27, 2014
The object-system in FireRed

A few ASM hackers out there probably have wondered about it at least once: The objects in FireRed.
Some of you may also have tried to directly manipulate the OAM at 0x7000000 in the RAM, what didn't
work out.. The OAM updates every game-cycle and the bytes are refreshed by GameFreaks routines.
Because I needed to find out how this works (to make features like this..) I researched closely and with
the help of knizz' documentation about the OAM I finally found GFs routines and used it for myself.

I think I shouldn't write so much, I better tell you everything about my research now =)


Creating a new object

There are multiple routines of GF which all do something similar, but the most efficient function
I found is located at 0x08006F8C. It has 4 arguments in total, containing r0-r3.

Code:
.align 2
.thumb
.equ FUNCTION, 0x08006F8D

push {r0-r4, lr}
ldr r0, DATA
mov r1, #0xX    @ The X-position of the obj
mov r2, #0xY    @ The Y-position of the obj
mov r3,  #0x0    @ r3 must be set to 0 because the function needs it for calculation
ldr r4, =FUNCTION
bl execute
pop {r0-r4}
pop {pc}

execute:
bx r4
But what do we actually need at "ldr r0, DATA"?
Well, the data we need there is nothing else than the stuff at the oam-buffer at 0x0202063C.
It contains the oam-attributes 0, 1 and 2, which you can look up here and some callbacks.

Code:
.align 2

DATA: .word DATA2 + 0x08[The position of this ASM code]
DATA2:
.hword 0x2
.hword 0x1
.word OAM + 0x08[The position of this ASM code]
.word ANIM + 0x08[The position of this ASM code]
.word 0x0
.word 0x08231CFC
.word 0x080EE765
.byte 0xFF

.align 2

OAM:
.byte 0x0     @ This is meant to be the X-position but its overwritten ;)
.byte 0x0     @ This is the OBJ-shape (look GBAtek) 0 = square, 1 = horiz., 2 = vert., 3 = prohibited
.byte 0x0     @ This is meant to be the Y-position but its overwritten ;)
.byte 0xB0   @ This is the size of the obj (look GBAtek) C0 = 64x64, B0 = 32x32, 80 = 16x16, ..
.hword 0x1
.hword 0x0
     
.align 2

ANIM2:
.hword 0x21   @ TILENUMBER IN THE VRAM!! (from 0x06010000 are objects)
.hword 0xA
.byte 0xFE
.byte 0xFF
.hword 0x0
     
.align 2

ANIM:
.word ANIM2 + 0x08[The position of this ASM code]
You should focus on the things, which I wrote commands to. The other things are the same for every obj.
However, all of these created obj use the obj-pal #0x15 (0x050003E0).
In the next chapter you will learn how to change this obj-pal to #0x14 for example.


Changing the used pal & other useful stuff

You should change the pal, if you want, directly after you called the function.
And then you run yet into another problem: the OAM-buffer contains dozens of indexes, but which one
is actually our newly created object? Well, every "index" is 0x44 bytes long. And our useful function
which is at 0x08006F8C returns the index of our new object in r0!!
So you simply multiply r0 with 0x44 and add it to our OAM buffer, 0x0202063C!

Your code should look like this now:

Spoiler:

Let's grab some information at gbatek.

OBJ Attribute 2 (R/W)
Bit Expl.
0-9 Character Name (0-1023=Tile Number)
10-11 Priority relative to BG (0-3; 0=Highest)
12-15 Palette Number (0-15) (Not used in 256 color/1 palette mode)
Bit 10-11 you can just let them be 0, so just concentrate on Palette number.
You don't even need to bitcalculate there, write for example 0xE for palette 14.
But of course we need to add 0x5 to our current offset, cause we are still at attribute 0 =)

Spoiler:

And that's basically how you create an obj and edit it afterwards!
Hmm, and how to delete an object? =(


Deleting an object

As you might've expected, gamefreak provides another function for us.
Its located at 0x08007280.
It only needs one arguement, the offset of our index in the OAM-buffer.
We can just use the calculation above to get this offset.
If you were clever enough to save the index, which stood in r0 after the function, to a free-space
in the RAM, you can load this byte from the offset and delete objects whenever you want.

Here's a little snippet:

Code:
.align 2
.thumb

.equ BUFFER, 0x0202063C
.equ FUNCTION, 0x08007281

push {r0-r4, lr}
mov r0, #0x0  @this is a placeholder for your own index-loading-from-freespace
mov r1, #0x44
ldr r2, =BUFFER
mul r0, r0, r1
add r0, r2, r0  @In r0 is now our offset
ldr r4, =FUNCTION
bl execute
pop {r0-r4}
pop {pc}

execute:
bx r4
Well, that was all my knowledge to the OAM, I still can't figure out how to interrupt gamefreaks function
to move and manipulate objects WHENEVER I WANT. Maybe i have to just put a different function in the
OAM-buffer, I don't know...

If you use any of this knowledge, it would be nice to mention knizz and me.

Have fun experimenting with this! =)
 

Bonnox

Time (wasting) Lord
47
Posts
8
Years
wow, this is... just great! I was looking for something like this for months! I always tried to directly manipulate the 07 area just to see them being "obliterated" by the game engine! thank you. ^_^

I'm sorry to clutter your good tutorial, but I have some questions.
First I don't understand why you put the 0x08; and then, could I just calculate manually my OAM and slap it onto the LDR, thus skipping the data section?

Finally, I haven't tried to do this yet, because I need something similar for AXVE. Maybe the procedures are the same, but the offsets change (almost certainly). So is there a tutorial somewhere about ruby? Or, maybe, what are your advices to help me investigate and "port" this amazing feature to the poor ruby ROM?

really thankyou, and excuse me moderators if I revived a very old topic, but it is for the good of science this is really a worth one, so keep it alive!

have a nice day

EDIT:
oh, no! you're banned! such a pity.
is there anyone else who knows how to "prompt" me to do it for ruby?
 
Last edited:
Back
Top