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: 26
    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
    	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 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
    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:080700C8 dword_80700C8   DCD 0x83A7660           ; DATA XREF: FlowerAnimation+6r
    ROM:080700CC dword_80700CC   DCD 0x6003F80           ; DATA XREF: FlowerAnimation+16r
    ROM:080700D0 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
    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:080700F0 dword_80700F0   DCD 0x83AA654           ; DATA XREF: WaterAnimation2+4r
    ROM:080700F4 dword_80700F4   DCD 0x6003400           ; DATA XREF: WaterAnimation2+12r
    ROM:080700F8 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
    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: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
    	pop {r4-r6}
    	pop {r0}
    	bx r0
    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
    	cmp r0, #1
    	bne NoneAnimation
    	bl Animation2
    	pop {r4-r6}
    	pop {r0}
    	bx r0
    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