Thread: [Tutorial] Add animations in Fire Red
View Single Post
Old November 17th, 2009 (8:34 AM). Edited November 26th, 2009 by Juan.
Juan Juan is offline
Brazilian with a bad English
Join Date: Jun 2007
Location: Pindamonhangaba - SP
Age: 25
Nature: Adamant
Posts: 92

Documentation(Emerald): here

struct FireRedTileset {
  u8  compressed		//00 = not compressed|| 01 = compressed
  u8  tileset			//00 = main tileset || 01 = secundary tileset
  u16 filler		        //00 00
  u32 *image			//image pointer
  u32 *palette			//pallete pointer
  u32 *block			//block pointer
  u32 *animation		//Animations routine pointer
  u32 *behavior  		//Behavior pointer
PS: LeafGreen uses the same structure then FireRed.
Explained by LU-HO.

Tileset 0:


ROM:082D4A94 DCB 1 //Compressed ROM:082D4A95 DCB 0 //main Tileset ROM:082D4A96 DCW 0 //0x0 ROM:082D4A98 DCD off_8EA1D68 //Image pointer ROM:082D4A9C DCD off_8EA1B68 //Pallete pointer ROM:082D4AA0 DCD off_829F6C8 //Block pointer ROM:082D4AA4 DCD off_8070155 //Animations routine pointer ROM:082D4AA8 DCD off_82A1EC8 //Behavior pointer

In this tutorial we will use only the "Animations routine pointer".
Decompile 0x8070154 (THUMB mode you should call the routines with "offset +1) we have:

ROM:08070154 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
ROM:08070154 Tileset0AnimationHeader                 ; DATA XREF: ROM:082D4AA4o
ROM:08070154                 LDR     R1, =0x3000FAE
ROM:08070156                 MOV     R0, #0
ROM:08070158                 STRH    R0, [R1]
ROM:0807015A                 LDR     R1, =0x3000FB0
ROM:0807015C                 MOV     R2, 0xA0
ROM:0807015E                 LSL     R2, R2, #2
ROM:08070160                 ADD     R0, R2, #0
ROM:08070162                 STRH    R0, [R1]
ROM:08070164                 LDR     R1, =0x3000FB8
ROM:08070166                 LDR     R0, =0x8070121
ROM:08070168                 STR     R0, [R1]
ROM:0807016A                 BX      LR
ROM:0807016A ; End of function Tileset0AnimationHeader
ROM:0807016A ; ---------------------------------------------------------------------------
ROM:0807016C dword_807016C   DCD 0x3000FAE           ; DATA XREF: Tileset0AnimationHeaderr
ROM:08070170 dword_8070170   DCD 0x3000FB0           ; DATA XREF: Tileset0AnimationHeader+6r
ROM:08070174 dword_8070174   DCD 0x3000FB8           ; DATA XREF: Tileset0AnimationHeader+10r
ROM:08070178 dword_8070178   DCD 0x8070121           ; DATA XREF: Tileset0AnimationHeader+12r

What is important in this routine:
0x3000FB8 : Local in RAM where it is stored the pointer to the routine of animation.
0x8070121 : Offset of routine animation + 1 (THUMB)

ROM:08070164                 LDR     R1, =0x3000FB8
ROM:08070166                 LDR     R0, =0x8070121
ROM:08070168                 STR     R0, [R1]
Stores the offset of the routine in RAM

Now we see a secondary tileset that has animations.

Tileset 28(Vermilion GYM):


ROM:082D4D34 DCB 1 //Compressed ROM:082D4D35 DCB 1 //Secundary Tileset ROM:082D4D36 DCW 0 //0x0 ROM:082D4D38 DCD off_82841F8 //Image pointer ROM:082D4D3C DCD off_82849B8 //Pallete pointer ROM:082D4D40 DCD off_82AB888 //Block pointer ROM:082D4D44 DCD off_807031D //Animations routine pointer ROM:082D4D48 DCD off_82ABD38 //Behavior pointer

Decompile 0x807031C(807031D - 1) we have:

ROM:0807031C ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
ROM:0807031C Tileset28AnimationHeader                ; DATA XREF: ROM:082D4D44o
ROM:0807031C                 LDR     R1, =0x3000FB2
ROM:0807031E                 MOV     R0, #0
ROM:08070320                 STRH    R0, [R1]
ROM:08070322                 LDR     R1, =0x3000FB4
ROM:08070324                 MOV     R0, #0xF0
ROM:08070326                 STRH    R0, [R1]
ROM:08070328                 LDR     R1, =0x3000FBC
ROM:0807032A                 LDR     R0, =0x8070305
ROM:0807032C                 STR     R0, [R1]
ROM:0807032E                 BX      LR
ROM:0807032E ; End of function Tileset28AnimationHeader
ROM:0807032E ; ---------------------------------------------------------------------------
ROM:08070330 dword_8070330   DCD 0x3000FB2           ; DATA XREF: Tileset28AnimationHeaderr
ROM:08070334 dword_8070334   DCD 0x3000FB4           ; DATA XREF: Tileset28AnimationHeader+6r
ROM:08070338 dword_8070338   DCD 0x3000FBC           ; DATA XREF: Tileset28AnimationHeader+Cr
ROM:0807033C dword_807033C   DCD 0x8070305           ; DATA XREF: Tileset28AnimationHeader+Er
What is important in this routine:
0x3000FBC : Local in RAM where it is stored the pointer to the routine of secundary tileset animation.
0x8070305 : Offset of routine animation + 1 (THUMB)

0x3000FB8: Location for the pointer to the routine of the main tileset
0x3000FBC: Location for the pointer to the routine of the secundary tileset

Then, to add animations tilesets that do not have any, please enter the following routine:
Main Tileset:

@define AnimationRoutine = Animation Routine Offset + 1

main: ldr r1,= #0x3000FAE mov r0, #0 strh r0, [r1] ldr r1,= #0x3000FB0 mov r2, #0xA0 lsl r2, r2, #2 add r0, r2, #0 strh r0, [r1] ldr r1,= #0x3000FB8 ldr r0,= AnimationRoutine str r0, [r1] bx lr

Compile and enter the routine in an empty space in ROM.
Add a pointer to this routine + 1 in the header of the tileset you want.

But what comes to be 'AnimationRoutine'?

'AnimationRoutine' is the routine that will 'create' the animation.

Tileset 0 example:
Remember this:

0x8070121 : Offset of routine animation + 1 (THUMB)

Decompile 0x8070120:

ROM:08070120 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
ROM:08070120 Tileset0Main
ROM:08070120                 PUSH    {R4-R6,LR}
ROM:08070122                 LSL     R5, R0, #0x10
ROM:08070124                 LSR     R6, R5, #0x10
ROM:08070126                 MOV     R0, #7
ROM:08070128                 AND     R0, R6
ROM:0807012A                 CMP     R0, #0
ROM:0807012C                 BNE     loc_8070134
ROM:0807012E                 LSR     R0, R5, #0x13
ROM:08070130                 BL      WaterAnimation
ROM:08070134 loc_8070134                             ; CODE XREF: Tileset0Main+Cj
ROM:08070134                 MOV     R4, #0xF
ROM:08070136                 AND     R4, R6
ROM:08070138                 CMP     R4, #1
ROM:0807013A                 BNE     loc_8070142
ROM:0807013C                 LSR     R0, R5, #0x14
ROM:0807013E                 BL      WaterAnimation2
ROM:08070142 loc_8070142                             ; CODE XREF: Tileset0Main+1Aj
ROM:08070142                 CMP     R4, #2
ROM:08070144                 BNE     loc_807014C
ROM:08070146                 LSR     R0, R5, #0x14
ROM:08070148                 BL      FlowerAnimation
ROM:0807014C loc_807014C                             ; CODE XREF: Tileset0Main+24j
ROM:0807014C                 POP     {R4-R6}
ROM:0807014E                 POP     {R0}
ROM:08070150                 BX      R0
ROM:08070150 ; End of function Tileset0Main
ROM:08070150 ; ---------------------------------------------------------------------------

@ ROM:080700A4 ROM:080700A4 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ ROM:080700A4 ROM:080700A4 ROM:080700A4 FlowerAnimation ; CODE XREF: Tileset0Main+28p ROM:080700A4 PUSH {R4,LR} ROM:080700A6 LSL R0, R0, #0x10 ROM:080700A8 LSR R0, R0, #0x10 ROM:080700AA LDR R4, =0x83A7660 ; Image Table pointer ROM:080700AC MOV R1, #5 ROM:080700AE BL sub_81E4684 ROM:080700B2 LSL R0, R0, #0x10 ROM:080700B4 LSR R0, R0, #0xE ROM:080700B6 ADD R0, R0, R4 ROM:080700B8 LDR R0, [R0] ROM:080700BA LDR R1, =0x6003F80 ; RAM Offset ROM:080700BC MOV R2, #0x80 ; Animation Size ROM:080700BE BL sub_806FF04 ; Subroutine then save the data in the DMA3. ROM:080700BE ; Don't change it. ROM:080700C2 POP {R4} ROM:080700C4 POP {R0} ROM:080700C6 BX R0 ROM:080700C6 ; End of function FlowerAnimation ROM:080700C6 ROM:080700C6 ; --------------------------------------------------------------------------- ROM:080700C8 dword_80700C8 DCD 0x83A7660 ; DATA XREF: FlowerAnimation+6r ROM:080700CC dword_80700CC DCD 0x6003F80 ; DATA XREF: FlowerAnimation+16r ROM:080700D0 ROM:080700D0 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ ROM:080700D0 ROM:080700D0 ROM:080700D0 WaterAnimation2 ; CODE XREF: Tileset0Main+1Ep ROM:080700D0 PUSH {LR} ROM:080700D2 LSL R0, R0, #0x10 ROM:080700D4 LDR R2, =0x83AA654 ; Image Table pointer ROM:080700D6 MOVL R1, 0x70000 ROM:080700DA AND R1, R0 ROM:080700DC LSR R1, R1, #0xE ROM:080700DE ADD R1, R1, R2 ROM:080700E0 LDR R0, [R1] ROM:080700E2 LDR R1, =0x6003400 ; RAM Offset ROM:080700E4 MOVL R2, 0x600 ; Animation Size ROM:080700E8 BL sub_806FF04 ; Subroutine then save the data in the DMA3. ROM:080700E8 ; Don't change it. ROM:080700EC POP {R0} ROM:080700EE BX R0 ROM:080700EE ; End of function WaterAnimation2 ROM:080700EE ROM:080700EE ; --------------------------------------------------------------------------- ROM:080700F0 dword_80700F0 DCD 0x83AA654 ; DATA XREF: WaterAnimation2+4r ROM:080700F4 dword_80700F4 DCD 0x6003400 ; DATA XREF: WaterAnimation2+12r ROM:080700F8 ROM:080700F8 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ ROM:080700F8 ROM:080700F8 ROM:080700F8 WaterAnimation ; CODE XREF: Tileset0Main+10p ROM:080700F8 PUSH {LR} ROM:080700FA LSL R0, R0, #0x10 ROM:080700FC LDR R2, =0x83AB874 ; Image Table pointer ROM:080700FE MOVL R1, 0x70000 ROM:08070102 AND R1, R0 ROM:08070104 LSR R1, R1, #0xE ROM:08070106 ADD R1, R1, R2 ROM:08070108 LDR R0, [R1] ROM:0807010A LDR R1, =0x6003A00 ; RAM Offset ROM:0807010C MOVL R2, 0x240 ; Animation Size ROM:08070110 BL sub_806FF04 ; Subroutine then save the data in the DMA3. ROM:08070110 ; Don't change it. ROM:08070114 POP {R0} ROM:08070116 BX R0 ROM:08070116 ; End of function WaterAnimation ROM:08070116 ROM:08070116 ; --------------------------------------------------------------------------- ROM:08070118 dword_8070118 DCD 0x83AB874 ; DATA XREF: WaterAnimation+4r ROM:0807011C dword_807011C DCD 0x6003A00 ; DATA XREF: WaterAnimation+12r

To create our own animation routine, we have:

  • Animation offset (can be drawn on TileMolester)
  • RAM offset *

How to calculate the offset in RAM:
Flower Animation Example:
ROM:080700BA                 LDR     R1, =0x6003F80  ; RAM Offset
The RAM offset is 0x6003F80. But why?
It's simple.
See the image:

Offset in RAM is the exact place where the flower tile is stored.

Routine to add more animations (1 animation):

	push {r4-r6, lr}
	lsl r5, r0, #0x10
	lsr r6, r5, #0x10
	mov r0, #7
	and r0, r6
	cmp r0, #0
	bne NoAnimation
	lsr r0, r5, #0x13
	bl Animation

NoAnimation: pop {r4-r6} pop {r0} bx r0

Animation: ...

More then 1 animation:

	push {r4-r6, lr}
	lsl r5, r0, #0x10
	lsr r6, r5, #0x10
	mov r0, #7
	and r0, r6
	cmp r0, #0
	bne NoAnimation1
	lsr r0, r5, #0x13
	bl Animation

NoAnimation1: cmp r0, #1 bne NoneAnimation bl Animation2

NoneAnimation: pop {r4-r6} pop {r0} bx r0

Animation1: ...

Animation2: ...

I will not write the whole routine because there is a tutorial on ASM.

Each animation must contain:
r0 = Image Table pointer
r1 = RAM offset
r2 = size
And must call the subroutine 0x806FF04.

Image Table pointer:
Table of pointers to each frame.

- LU-HO (TilesetStructure)
- GBATEK (GBA especifications)
- Me ([Document]Tile Animations in Pokémon Emerald)
- Me² (this tutorial ^^)

OBS: Sorry for my bad english.

Attached Images
File Type: png flower1.PNG‎ (37.5 KB, 1377 views) (Save to Dropbox)
Reply With Quote