- 58
- Posts
- 9
- Years
- Seen Jan 7, 2017
How to use custom ASM routines in move animation scripts (Part 1)
As more and more people are interested in the move animation scripts, I'm determined to write a simple tutorial on command "03" in animation scripts. As for now, almost all hackers uses built-in functions. However, using custom routines is quite easy so I'm going to explain it as it seems that no one wants to do this kind of boring work.This tutorial require basic ASM knowledge.
You'd better read these threads before going on.
https://www.pokecommunity.com/threads/281520
https://www.pokecommunity.com/threads/354621
https://www.pokecommunity.com/threads/238937
Before we start, let's get some basic information of the script:
1. Firstly let's take a look at the script for the move "Slash":
RAW version:
Code:
00 C7 27 02 A4 35 3E 08 82 03 01 00 F8 FF F8 FF 19 81 00 3F 04 04 02 A4 35 3E 08 82 03 01 00 08 00 F8 FF 03 1D 8B 09 08 02 05 01 00 04 00 00 00 12 00 01 00 19 81 00 3F 05 08
Code:
#org @slash
loadgraphic 0x27c7 //slash
loadobjtemplate 0x83e35a4 0x82 0x3 0x1 0xfff8 0x0
sound 0x81 0x3f
pause 0x4
loadobjtemplate 0x83e35a4 0x82 0x3 0x1 0x8 0x0
launchtask 0x8098b1d 0x2 0x5 0x1 0x4 0x0 0x12 0x1
sound 0x81 0x3f
waitanimation
end
2. A quick note on some information:
Code:
cmd2_args: used by callback_80A5940 in objtemplate_83e35a4
arg1_0x1: indicating defender //see knizz's db for more information
arg2_0xfff8: x_coordinate_offset
arg3_0x0: y_coordinate_offset
If you define a new template, you can change the callback function to your custom one.
The function is as such, which is easy for understanding:
Code:
callback_80A5940:
ROM:080A5940 sub_80A5940: @ DATA XREF: ROM:stru_83E35A4o
ROM:080A5940 PUSH {R4-R6,LR}
ROM:080A5942 MOVS R5, R0
ROM:080A5944 LDR R6, =ma02_t0_02037F02 @ 0-attacker
ROM:080A5944 @ 1-defender
ROM:080A5944 @ 2-other attacker
ROM:080A5944 @ 3-other defender
ROM:080A5946 MOVS R1, #0
ROM:080A5948 LDRSH R0, [R6,R1]
ROM:080A594A CMP R0, #0
ROM:080A594C BNE loc_80A595C
ROM:080A594E LDR R4, =b_anim_attacker
ROM:080A5950 B loc_80A595E
ROM:080A5950 @ ---------------------------------------------------------------------------
ROM:080A5952 .align 4
ROM:080A5954 off_80A5954: .long ma02_t0_02037F02 @ DATA XREF: sub_80A5940+4r
ROM:080A5954 @ 0-attacker
ROM:080A5954 @ 1-defender
ROM:080A5954 @ 2-other attacker
ROM:080A5954 @ 3-other defender
ROM:080A5958 off_80A5958: .long b_anim_attacker @ DATA XREF: sub_80A5940+Er
ROM:080A595C @ ---------------------------------------------------------------------------
ROM:080A595C
ROM:080A595C loc_80A595C: @ CODE XREF: sub_80A5940+Cj
ROM:080A595C LDR R4, =b_anim_defender
ROM:080A595E
ROM:080A595E loc_80A595E: @ CODE XREF: sub_80A5940+10j
ROM:080A595E LDRB R0, [R4]
ROM:080A5960 MOVS R1, #2
ROM:080A5962 BL sub_8074480
ROM:080A5966 LSLS R0, R0, #0x18
ROM:080A5968 LSRS R0, R0, #0x18
ROM:080A596A LDRH R1, [R6,#2]
ROM:080A596C ADDS R0, R0, R1
ROM:080A596E STRH R0, [R5,#obj.pos_1]
ROM:080A5970 LDRB R0, [R4]
ROM:080A5972 MOVS R1, #3
ROM:080A5974 BL sub_8074480
ROM:080A5978 LSLS R0, R0, #0x18
ROM:080A597A LSRS R0, R0, #0x18
ROM:080A597C LDRH R6, [R6,#4]
ROM:080A597E ADDS R0, R0, R6
ROM:080A5980 STRH R0, [R5,#obj.pos_1.y]
ROM:080A5982 MOVS R0, #0
ROM:080A5984 STRH R0, [R5,#obj.private0]
ROM:080A5986 STRH R0, [R5,#obj.private1]
ROM:080A5988 LDR R1, =(sub_80A5A8C+1)
ROM:080A598A MOVS R0, R5
ROM:080A598C BL oamt_set_x3A_32
ROM:080A5990 LDR R0, =(sub_8074F6C+1)
ROM:080A5992 STR R0, [R5,#obj.callback]
ROM:080A5994 POP {R4-R6}
ROM:080A5996 POP {R0}
ROM:080A5998 BX R0
ROM:080A5998 @ End of function sub_80A5940
ROM:080A5998
ROM:080A5998 @ ---------------------------------------------------------------------------
ROM:080A599A .align 4
ROM:080A599C off_80A599C: .long b_anim_defender @ DATA XREF: sub_80A5940:loc_80A595Cr
ROM:080A59A0 off_80A59A0: .long sub_80A5A8C+1 @ DATA XREF: sub_80A5940+48r
ROM:080A59A4 off_80A59A4: .long sub_8074F6C+1 @ DATA XREF: sub_80A5940+50r
Therefore, it's quite straight forward for how to change the x&y offset of the object. As you can see, the EWRAM address 0x2037F02 contains the arguments. As you can imagine, it adds the arguments (I'm speaking of 0xfff8 & 0) to the initial location of the object, which is defined by the first arg (0x1). Here it's 0x1, which means that it's on the defender of the move.
3. obj_anim_scr_data defined for the object of "slash" (ripped from template):
Code:
00 00 04 00 10 00 04 00 20 00 04 00 30 00 04 00 FF FF 00 00
Code:
firstframe 0x4
secondframe 0x4
thirdframe 0x4
fourthframe 0x4
end 0x0
4. Now we're getting to the main part. The function located at 0x8098b1c is moving the defender. However, we want to customize the movement, so we need to build a new function. As we write the function on our own, arguments are really not necessary. Here's just an example using one argument:
change this
Code:
launchtask 0x8098b1d 0x2 0x5 0x1 0x4 0x0 0x12 0x1
Code:
launchtask 0x8[offset of the following asm + 1] 0x2 0x1 0x1
Absolutely, you should adjust the data or the game will freeze:
New animation:
Code:
00 C7 27 02 A4 35 3E 08 82 03 01 00 F8 FF F8 FF 19 81 00 3F 04 04 02 A4 35 3E 08 82 03 01 00 08 00 F8 FF 03 [asm ptr + 1] 02 01 01 00 19 81 00 3F 05 08
The main part of the original function:
Code:
ROM:08098B1C PUSH {R4-R6,LR}
ROM:08098B1E LSLS R0, R0, #0x18
ROM:08098B20 LSRS R5, R0, #0x18
ROM:08098B22 MOVS R6, #0
ROM:08098B24 LDR R2, =ma02_t0_02037F02 @ 0-attacker
ROM:08098B24 @ 1-defender
ROM:08098B24 @ 2-other attacker
ROM:08098B24 @ 3-other defender
ROM:08098B26 LDRH R0, [R2] @ 0-attacker
ROM:08098B26 @ 1-defender
ROM:08098B26 @ 2-other attacker
ROM:08098B26 @ 3-other defender
ROM:08098B28 MOVS R3, #0
ROM:08098B2A LDRSH R1, [R2,R3]
ROM:08098B2C CMP R1, #3
ROM:08098B2E BGT loc_8098B48
ROM:08098B30 LSLS R0, R0, #0x18
ROM:08098B32 LSRS R0, R0, #0x18
ROM:08098B34 BL obj_id_for_side_relative_to_move
ROM:08098B38 LSLS R0, R0, #0x18
ROM:08098B3A LSRS R3, R0, #0x18
ROM:08098B3C CMP R3, #0xFF
ROM:08098B3E BNE loc_8098B9E @jump
ROM:08098B40 B loc_8098BA2
ROM:08098B9E loc_8098B9E: @ CODE XREF: sub_8098B1C+22j
ROM:08098B9E CMP R6, #0
ROM:08098BA0 BEQ loc_8098BB4
ROM:08098BB4 loc_8098BB4: @ CODE XREF: sub_8098B1C+84j
ROM:08098BB4 LDR R1, =objects
ROM:08098BB6 LSLS R0, R3, #4
ROM:08098BB8 ADDS R0, R0, R3
ROM:08098BBA LSLS R0, R0, #2
ROM:08098BBC ADDS R0, R0, R1
ROM:08098BBE LDR R2, =ma02_t0_02037F02 @ 0-attacker
ROM:08098BBE @ 1-defender
ROM:08098BBE @ 2-other attacker
ROM:08098BBE @ 3-other defender
ROM:08098BC0 LDRH R1, [R2,#(dp09_pos2x__ma02_t2 - ma02_t0_02037F02)]
ROM:08098BC2 STRH R1, [R0,#obj.pos_2]
ROM:08098BC4 LDRH R1, [R2,#(dp09_pos2y__ma02_t3 - ma02_t0_02037F02)]
ROM:08098BC6 STRH R1, [R0,#obj.pos_2.y]
ROM:08098BC8 LDR R1, =tasks
ROM:08098BCA LSLS R0, R5, #2
ROM:08098BCC ADDS R0, R0, R5
ROM:08098BCE LSLS R0, R0, #3
ROM:08098BD0 ADDS R0, R0, R1
ROM:08098BD2 STRH R3, [R0,#8]
ROM:08098BD4 LDRH R1, [R2,#(ma02_t4_02037F08 - ma02_t0_02037F02)]
ROM:08098BD6 STRH R1, [R0,#0xA]
ROM:08098BD8 LDRH R1, [R2,#(ma02_t5_02037F0A - ma02_t0_02037F02)]
ROM:08098BDA STRH R1, [R0,#0xC]
ROM:08098BDC LDRH R1, [R2,#(ma02_t5_02037F0A - ma02_t0_02037F02)]
ROM:08098BDE STRH R1, [R0,#0xE]
ROM:08098BE0 LDRH R1, [R2,#(dp09_pos2x__ma02_t2 - ma02_t0_02037F02)]
ROM:08098BE2 STRH R1, [R0,#0x10]
ROM:08098BE4 LDRH R1, [R2,#(dp09_pos2y__ma02_t3 - ma02_t0_02037F02)]
ROM:08098BE6 STRH R1, [R0,#0x12]
ROM:08098BE8 LDR R1, =(sub_8098C08+1)
ROM:08098BEA STR R1, [R0]
ROM:08098BEC MOVS R0, R5
ROM:08098BEE BL _call_via_r1
ROM:08098BF2
ROM:08098BF2 loc_8098BF2: @ CODE XREF: sub_8098B1C+8Cj
ROM:08098BF2 POP {R4-R6}
ROM:08098BF4 POP {R0}
ROM:08098BF6 BX R0
Code:
.thumb
push {r4, lr}
add r4, r0, #0 @task_id
ldr r2, =0x2037f02 @args
ldrh r0, [r2] @here r0 = 1, for defender
ldr r3, =0x80749D5
bl caller_r3
cmp r0, #0xff
beq back
ldr r1, =0x202063C @objects
mov r2, #0x44
mul r2, r0
add r0, r1, r2
ldr r1, =0x8[offset of this code + 1] + move_function
mov r3, #0x28
mul r3, r4
ldr r2, =0x3005090 @tasks
add r3, r3, r2
str r1, [r3]
str r0, [r3, #8] @task_arg
mov r2, #0
strh r2, [r3, #0xc]
add r0, r4, #0
bl caller_r1
b back_2
back:
add r0, r4, #0 @task_id
ldr r3, =0x8072761 @move_task_del
bl caller_r3
back_2:
pop {r4, pc}
.ltorg
move_function:
push {r4, lr}
add r4, r0, #0
mov r1, #0x28
mul r1, r0
ldr r2, =0x3005090
add r2, r1, r2
ldrh r0, [r2, #0xc]
cmp r0, #0
bne other
ldr r2, [r2, #8] @task_arg
ldrh r0, [r2, #0x26] @Y_2
sub r0, #1
lsl r0, r0, #0x10
lsr r0, r0, #0x10
strh r0, [r2, #0x26]
ldrh r0, [r2, #0x24] @X_2
add r0, #1
strh r0, [r2, #0x24]
cmp r0, #0x20
beq change
b move_back_2
other:
ldr r2, [r2, #8] @task_arg
ldrh r0, [r2, #0x26] @Y_2
add r0, #1
lsl r0, r0, #0x10
lsr r0, r0, #0x10
strh r0, [r2, #0x26]
ldrh r0, [r2, #0x24] @X_2
sub r0, #1
strh r0, [r2, #0x24]
cmp r0, #0
beq move_back
b move_back_2
change:
mov r1, #0x28
mul r1, r4
ldr r2, =0x3005090
add r2, r1, r2
mov r1, #1
strh r1, [r2, #0xc]
b move_back_2
move_back:
add r0, r4, #0
ldr r3, =0x8072761 @move_task_del
bl caller_r3
move_back_2:
pop {r4, pc}
caller_r1: bx r1
caller_r3: bx r3
Change [offset of this code + 1] in the code above to the offset of the code + 1.
The routine will make the defender move upright, and then downleft.
As you can see, this is only a small part and I admit that it looks ugly but it's just an example. The main idea of the tutorial is just to provide some information for hackers interested in such things. I may add more information in the future, but I'm busy currently.
Absolutely, you can read more built-in functions like this to get more information. I know that most people wanna control the custom particles, so why not find a proper move animation script and try it yourself? Gook luck. xD
Credits: knizz, Touched, Chaos Rush
Edit: To get more information, please continue reading.
Last edited: