Author Topic: Reverse Engineering the handling of attack animations  (Read 2645 times)

quantumpencil

  • *
  • Posts: 72
    • View Profile
UPDATE: The stated goals here have been achieved. I have a burn effect, displaying the "fire" animation on every tick, working for both enemies and player characters =). Thanks ergo_joe for the help,  looking forward to announcing/sharing some things with all of you soon =D

Starting a new thread for this specific issue. I've successfully gotten a fire-elemental burn effect working, which ticks alongside poison (but is inflicted/removed differently) by hooking into the poison callback and poison data setter that's run in the games main action routine(0x435D81) during the big switch statement on the command that loads data and calculates damage.

I would like to have these ticks display a fire attack. the main current action struct of size 0x260h has fields 0x24 (which is set from ability data to the effect ID toplay) and 0x14 (which the wiki says is the base index for calculating absolute animation indexes from relative ones). Unfortunately setting thes to 0x01B and 0x00 by replacing the poison-preparation function(0x5C9FC0)  respectively does not cause poison (issued via command (0x023) to play the fire animation.

So there are two current goals:

1: This whole mess about relative animation indexes is inconvenient for modding, as it would be great to be able to reuse all animations in any context; So I am going to work on replacing this behavior with a simpler absolute animation index system, so that any command type can use any animation.

2: I want to get the new burn effect to display the Fire 1 animation on tick (Which is probably more difficult than 1, as I recall certain player ability "scripts" call additional affect animations -- and poisons 0x23 command likely has no animation scripts associated -- so it's possible a very simple script which does nothing but display the animation effect itself at the target location will need to be created, if there is no "idle/no actor animation and then display an effect at target location" ability-effect using script currently in the game.)

EDIT 2 - GOOD PROGRESS: Did a bunch of reversing tonight. The scripts in question are actually loaded from the model files, and accessed by a routine which switches on the opcodes in the scripts which lives at 0x41FBA4. This function seems to be holding the a pointer to the script in ebp-14h, which it's setting based on some kind of other switch statement, but I don't quite understand what this is doing currently.

Now I have a much clearer idea of what I'm looking for, if anyone wants to help reverse/knows this. Basically this function gets a pointer to an animation script and runs it. These scripts are loaded up from model files. When the an action is popped of the battle queue and its main action routine is called, there must be a way in which the information about that attack reaches this function for the execution of the animation.

We don't need to fully disassembly 0x41FBA4 right now (it would take a while) to get a ton of power here; If we can just trace how we get from "setting a bunch of fields in the BattleDataContext Ptr" to "Ptr to correct action script is parsed by 0x41FBA4, we can interject code into the process and instead pass a ptr to a custom animation script under-the right conditions (which we can just hold in RAM somwhere).

This would be sufficient for injecting and creating more or less arbitrary in battle animation effects -- we'll just need to figure out a model script which corresponds to magic, and play around with the op-codes until we get it to "only" display an added effect (replace the 1B with 00 and try to shorten the length it's played). Then when-ever the command index is 0x23, run that script =)
« Last Edit: 2018-12-24 00:07:10 by quantumpencil »

ergonomy_joe

  • *
  • Posts: 20
    • View Profile
Re: Reverse Engineering the handling of attack animations
« Reply #1 on: 2018-12-19 23:45:14 »
Hi, it's me again.

I'm not sure I understand all you say, but here is my C version of the function at 0x0041FBA4:
Code: [Select]
//execute combat script?
void C_0041FBA4(short bp08, unsigned char **ppScriptData/*bp0c*/, int bp10, int bp14) {
struct {
struct tTextureObj *bp_38;
int bp_34;
tRGBA bp_30;
struct t_f0 *bp_2c;
short bp_28; char ___26[2];
tRGBA *bp_24;
void *bp_20;
int bp_1c;
int bp_18;
struct t_battle_ScriptContext *pScriptContext;//bp_14
int i;//bp_10
struct t_menu_temp_440 *bp_0c;
struct t_battle_B_Header *bp_08;
struct t_battle_B_Header *bp_04;
}lolo;

if(D_00DC0E6C)
return;
lolo.pScriptContext = (struct t_battle_ScriptContext *)D_008FE2AC;
D_009ADEF8 = 0;
lolo.pScriptContext->bScriptActive = 1;
//-- set script data --
lolo.pScriptContext->pScriptData = ppScriptData[D_00BE1178[bp08].wCurScriptId];
switch(D_00BE1178[bp08].wCurScriptId) {
case 0x2e: lolo.pScriptContext->pScriptData = D_007C10E0; break;
case 0x2f: lolo.pScriptContext->pScriptData = D_007C10F0; break;
case 0x30: lolo.pScriptContext->pScriptData = D_007C10F8; break;
case 0x31: lolo.pScriptContext->pScriptData = D_007C1120; break;
case 0x32: lolo.pScriptContext->pScriptData = D_007C1130; break;
case 0x34: lolo.pScriptContext->pScriptData = D_007C1118; break;
case 0x35: lolo.pScriptContext->pScriptData = D_007C1170; break;
case 0x36: lolo.pScriptContext->pScriptData = D_007C1160; break;
case 0x37: lolo.pScriptContext->pScriptData = D_007C1150; break;
case 0x38: lolo.pScriptContext->pScriptData = D_007C1140; break;
case 0x39:
D_00BE1178[bp08].f_0025 = D_00BE1178[bp08].f_0025 | 0x80;
lolo.pScriptContext->pScriptData = D_007C1110;
break;
case 0x3a: lolo.pScriptContext->pScriptData = D_007C1108; break;
case 0x3b: lolo.pScriptContext->pScriptData = D_007C110C; break;
}//end switch
//-- --
if(D_00BE1178[bp08].f_003e & 1) {
C_004254B0(bp08);
D_00BE1178[bp08].f_003e = D_00BE1178[bp08].f_003e & ~1;
}
if(D_00BE1178[bp08].f_003b) {//else 00424745
D_00BE1178[bp08].f_0b9c = 0;
while(lolo.pScriptContext->bScriptActive) {//else 00424745
lolo.pScriptContext->bOpcode = CURSCRIPT_GETBYTE;
switch(lolo.pScriptContext->bOpcode) {
case 0xfe:
if(D_00BE1178[bp08].f_003d == 0) {
lolo.pScriptContext->bOpcode = lolo.pScriptContext->pScriptData[D_00BE1178[bp08].f_003c];
if(lolo.pScriptContext->bOpcode == 0xc0) {
D_00BE1178[bp08].f_003c = 0;
D_00BE0E28[bp08].f_00 = 0;
D_00BF23C0[bp08].f_36 = 0;
D_00BE1178[bp08].f_0074 = 0;
D_00BE1178[bp08].f_003d = 0;
D_00BE1178[bp08].f_000e = lolo.pScriptContext->pScriptData[0];
D_00BE1178[bp08].wCurScriptId = D_00BF2DF8[bp08];
lolo.pScriptContext->pScriptData = ppScriptData[D_00BE1178[bp08].wCurScriptId];
C_004254B0(bp08);
}
}
break;
case 0x91:
*D_00C05FE8 = CURSCRIPT_GETBYTE;
lolo.pScriptContext->f_14 = C_005BED92(C_004255B7);
D_00BFC3A0[lolo.pScriptContext->f_14].f_04 = *D_00C05FE8;
break;
case 0x9c:
C_00430C9F();
break;
case 0xf8:
*D_00C05FE8 = CURSCRIPT_GETBYTE;
lolo.pScriptContext->f_0a = C_005BED92(C_00425AAD);
if(bp08 < 4) {
*D_00C05FF0 = bp08;
lolo.bp_04 = D_00BFB2B8[*D_00C05FF0]->f_00;
} else {
*D_00C05FF0 = D_00BF2054[bp08 - 4].f_00;
lolo.bp_04 = D_00BFB2B8[*D_00C05FF0]->f_00;
}
D_00BFC3A0[lolo.pScriptContext->f_0a].f_10 = lolo.bp_04->f_24[*D_00C05FE8];
D_00BFC3A0[lolo.pScriptContext->f_0a].f_06 = bp08;
D_00BFC3A0[lolo.pScriptContext->f_0a].f_18 = 0;
D_00BFC3A0[lolo.pScriptContext->f_0a].f_04 = 0;
D_00BF23C0[bp08].f_34 ++;
D_00BFC3A0[lolo.pScriptContext->f_0a].f_02 = D_00BF23C0[bp08].f_34;
break;
case 0xa9:
D_00BE1178[bp08].f_003c ++;
D_00BE1178[bp08].f_000e = CURSCRIPT_GETBYTE;
D_00BE1178[bp08].f_0074 = 0;
D_00BF23C0[bp08].f_36 = 0;
D_00BE0E28[bp08].f_00 = 0;
D_00C05F80 += 3;
*D_00C05FE8 = D_00C05F80 & 0xf;
for(lolo.i = 0; lolo.i < *D_00C05FE8; lolo.i ++) {
D_00BF23C0[bp08].f_36 ++;
C_00424B4B(bp08, bp10, bp14);
}//end for
lolo.pScriptContext->bScriptActive = 0;
break;
case 0x8f:
D_00BF2150 = 0;
break;
case 0x8e:
if(D_00BFB710 == 0) {
D_00BF2150 = 1;
D_00BFB710 = 1;
}
break;
case 0x92:
D_00BFB2EC = 1;
break;
case 0x93://some fade to white?
C_005BED92(C_005BCD42);
break;
case 0xb9:
D_00BF211C = CURSCRIPT_GETBYTE;
D_009AAD70[D_00BF2A38].f_08 = -2;
C_00430AA7();
break;
case 0xbc:
D_00BFCB28 = CURSCRIPT_GETBYTE;
break;
case 0xfd:
D_00BE1178[bp08].f_0140.f_26.f_00 = CURSCRIPT_GETWORD;
D_00BE1178[bp08].f_0140.f_26.f_02 = CURSCRIPT_GETWORD;
D_00BE1178[bp08].f_0140.f_26.f_04 = CURSCRIPT_GETWORD;
break;
case 0x94:
*D_00C05FE8 = CURSCRIPT_GETWORD;
*D_00C05FEC = CURSCRIPT_GETWORD;
*D_00C05FF0 = CURSCRIPT_GETBYTE;
lolo.pScriptContext->f_14 = C_005BECF1(C_00426899);
D_00BF2E70[lolo.pScriptContext->f_14].f_08 = bp08;
D_00BF2E70[lolo.pScriptContext->f_14].f_0a = *D_00C05FE8;
D_00BF2E70[lolo.pScriptContext->f_14].f_0c = *D_00C05FEC;
D_00BF2E70[lolo.pScriptContext->f_14].f_0e = (*D_00C05FEC - *D_00C05FE8) / *D_00C05FF0;
D_00BF2E70[lolo.pScriptContext->f_14].f_04 = *D_00C05FF0;
break;
case 0xba:
D_00BE1178[bp08].f_0140.f_1e.f_02 = D_00BE1178[bp08].f_0018;
D_00BE1178[bp08].f_0140.f_1e.f_02 += CURSCRIPT_GETWORD;
//break;
case 0xb4:
switch(D_00BFD0E0) {
case 2: D_00BE1178[bp08].f_0018 = 0x800; break;
case 4: D_00BE1178[bp08].f_0018 = 0; break;
}//end switch
D_00BE1178[bp08].f_0140.f_1e.f_02 = D_00BE1178[bp08].f_0018;
break;
case 0x95:
switch(D_00BFD0E0) {
case 1: break;
case 2: if(bp08 < 4) D_00BE1178[bp08].f_0018 = 0x800; break;
}//end switch
D_00BE1178[bp08].f_0140.f_1e.f_02 = D_00BE1178[bp08].f_0018;
break;
case 0xe5:
switch(D_00BFD0E0) {
case 4:
if(bp08 < 4 && (bp08 != D_00BFCDE0 || bp08 != D_00BE1170) && D_00BF2E1C == 0) {
if(bp08 == D_00BE1170) {//else 0042063A
if(D_00BE1178[D_00BFCDE0].f_0018 == 0)
D_00BE1178[bp08].f_0018 = 0x800;
else
D_00BE1178[bp08].f_0018 = 0;
} else {
if(D_00BE1178[D_00BE1170].f_0018 == 0)
D_00BE1178[bp08].f_0018 = 0x800;
else
D_00BE1178[bp08].f_0018 = 0;
}
}
break;
case 3: case 5: case 6:
if(bp08 >= 4) {
if(bp08 == D_00BE1170) {
if(D_00BE1178[D_00BFCDE0].f_0018 == 0)
D_00BE1178[bp08].f_0018 = 0x800;
else
D_00BE1178[bp08].f_0018 = 0;
} else {
if(D_00BE1178[D_00BE1170].f_0018 == 0)
D_00BE1178[bp08].f_0018 = 0x800;
else
D_00BE1178[bp08].f_0018 = 0;
}
}
break;
case 1:
if(bp08 >= 4)
D_00BE1178[bp08].f_0018 = 0x800;
break;
case 2:
if(bp08 < 4)
D_00BE1178[bp08].f_0018 = 0x800;
break;
}//end switch
D_00BE1178[bp08].f_0140.f_1e.f_02 = D_00BE1178[bp08].f_0018;
break;
case 0xc7:
lolo.pScriptContext->f_0e = bp08 + CURSCRIPT_GETWORD;
lolo.pScriptContext->f_10 = CURSCRIPT_GETBYTE;
if(lolo.pScriptContext->f_0e < 0xa && lolo.pScriptContext->f_0e >= 4) {//else 00420AA3
if((D_00BF23C0[bp08].f_0c & 4) == 0) {//else 0042091B
if(D_00BE1178[lolo.pScriptContext->f_0e].f_0025 & 0x80) {//else 00420916
D_00BE1178[lolo.pScriptContext->f_0e].f_0018 = D_00BE1178[bp08].f_0018;
D_00BE1178[lolo.pScriptContext->f_0e].f_0140.f_1e.f_02 = D_00BE1178[lolo.pScriptContext->f_0e].f_0018;
D_00BE1178[lolo.pScriptContext->f_0e].wCurScriptId = lolo.pScriptContext->f_10;
D_00BE1178[lolo.pScriptContext->f_0e].f_003e = D_00BE1178[lolo.pScriptContext->f_0e].f_003e | 1;
D_00BE1178[lolo.pScriptContext->f_0e].f_0026 = 0;
D_00BF23C0[lolo.pScriptContext->f_0e].f_0c = D_00BF23C0[lolo.pScriptContext->f_0e].f_0c | 4;
}
//goto 00420AA3
} else if(D_00BF23C0[bp08].f_0c & 8) {//else 00420AA3
if(D_00BF2E1C) {//else 00420A00
if(D_00BFD0DC == bp08 && (D_00BE1178[lolo.pScriptContext->f_0e].f_0025 & 0x80)) {//else 004209FB
D_00BE1178[lolo.pScriptContext->f_0e].wCurScriptId = lolo.pScriptContext->f_10;
D_00BE1178[lolo.pScriptContext->f_0e].f_003e = D_00BE1178[lolo.pScriptContext->f_0e].f_003e | 1;
D_00BE1178[lolo.pScriptContext->f_0e].f_0026 = 0;
D_00BF23C0[lolo.pScriptContext->f_0e].f_0c = D_00BF23C0[lolo.pScriptContext->f_0e].f_0c | 4;
}
//goto 00420AA3
} else if(D_00BE1178[lolo.pScriptContext->f_0e].f_0025 & 0x80) {//else 00420AA3
D_00BE1178[lolo.pScriptContext->f_0e].wCurScriptId = lolo.pScriptContext->f_10;
D_00BE1178[lolo.pScriptContext->f_0e].f_003e = D_00BE1178[lolo.pScriptContext->f_0e].f_003e | 1;
D_00BE1178[lolo.pScriptContext->f_0e].f_0026 = 0;
D_00BF23C0[lolo.pScriptContext->f_0e].f_0c = D_00BF23C0[lolo.pScriptContext->f_0e].f_0c | 4;
}
}
}
break;
case 0xf9:
D_00BE1178[bp08].f_0140.f_1e.f_02 = D_00BE1178[bp08].f_0018;
break;
case 0xe3:
D_00BFD0A0[D_00BE1170].wX = D_00BE1178[D_00BE1170].f_0140.f_26.f_00;
D_00BFD0A0[D_00BE1170].wZ = D_00BE1178[D_00BE1170].f_0140.f_26.f_04;
break;
case 0xd4:
lolo.pScriptContext->f_12 = CURSCRIPT_GETWORD;
lolo.pScriptContext->f_10 = CURSCRIPT_GETBYTE;
*D_00C05FE8 = lolo.pScriptContext->f_12 / lolo.pScriptContext->f_10;
lolo.pScriptContext->f_14 = C_005BECF1(C_004267F1);
D_00BF2E70[lolo.pScriptContext->f_14].f_08 = bp08;
D_00BF2E70[lolo.pScriptContext->f_14].f_0a = *D_00C05FE8;
D_00BF2E70[lolo.pScriptContext->f_14].f_04 = lolo.pScriptContext->f_10;
break;
case 0xdf:
C_005BFEC9(D_00BFD0F8, &(lolo.pScriptContext->f_16));
D_00BE1178[bp08].f_0140.f_1e.f_02 = C_00662573(lolo.pScriptContext->f_16.f_00 - D_00BE1178[bp08].f_0140.f_26.f_00, lolo.pScriptContext->f_16.f_04 - D_00BE1178[bp08].f_0140.f_26.f_04) + 0x800;
break;
case 0xfc:
if(D_00BF2E1C) {//else 00420D4B
switch(D_00BFD0E0) {
case 3: case 5: case 6: case 7:
for(lolo.i = 4; lolo.i < 0xa; lolo.i ++) {
if(D_00BE1178[bp08].f_0018 == 0)
D_00BE1178[lolo.i].f_0018 = 0x800;
else
D_00BE1178[lolo.i].f_0018 = 0;
}//end for
break;
case 4:
if(D_009A8748.f_162[0] & D_00BFD0F8)
D_00BE1178[bp08].f_0140.f_1e.f_02 = 0;
if(D_009A8748.f_162[2] & D_00BFD0F8)
D_00BE1178[bp08].f_0140.f_1e.f_02 = 0x800;
break;
}//end switch
//goto 00420E6A
} else if((D_00BE1178[bp08].cLimitBreakId != 0x15 || D_00BE1178[bp08].f_0023 != 0xd) && D_00BE1170 != D_00BFB198) {//else 00420E6A
D_00BE1178[bp08].f_0140.f_1e.f_02 = C_00662573(D_00BE1178[D_00BFB198].f_0140.f_26.f_00 - D_00BE1178[bp08].f_0140.f_26.f_00, D_00BE1178[D_00BFB198].f_0140.f_26.f_04 - D_00BE1178[bp08].f_0140.f_26.f_04) + 0x800;
D_00BF23C0[D_00BFB198].f_2c = C_00662573(D_00BE1178[D_00BFB198].f_0140.f_26.f_00 - D_00BE1178[bp08].f_0140.f_26.f_00, D_00BE1178[D_00BFB198].f_0140.f_26.f_04 - D_00BE1178[bp08].f_0140.f_26.f_04);
}
break;
case 0x9a: case 0xfb:
lolo.pScriptContext->f_12 = CURSCRIPT_GETWORD;
lolo.pScriptContext->f_0c = CURSCRIPT_GETWORD;
lolo.pScriptContext->f_08 = 0x1000 - (D_00BF23C0[D_00BFB198].f_2c + 0x800);
lolo.pScriptContext->f_0a =
FIX_MUL(lolo.pScriptContext->f_12, D_00BE1178[bp08].f_0006) +
FIX_MUL(D_00BE1178[D_00BFB198].f_0012, D_00BE1178[D_00BFB198].f_0006)
;
D_00BE1178[bp08].f_0140.f_26.f_00 = D_00BE1178[D_00BFB198].f_0140.f_26.f_00 - FIX_MUL(C_00662538(lolo.pScriptContext->f_08), lolo.pScriptContext->f_0a);
D_00BE1178[bp08].f_0140.f_26.f_04 = D_00BE1178[D_00BFB198].f_0140.f_26.f_04 + FIX_MUL(C_006624FD(lolo.pScriptContext->f_08), lolo.pScriptContext->f_0a);
D_00BE1178[bp08].f_0140.f_26.f_02 = lolo.pScriptContext->f_0c;
break;
case 0xa8:
*D_00C05FE8 = CURSCRIPT_GETBYTE;
*D_00C05FEC = CURSCRIPT_GETBYTE;
C_00426C9B(bp08, *D_00C05FEC, *D_00C05FE8);
break;
case 0xe9:
lolo.pScriptContext->f_12 = CURSCRIPT_GETWORD;
lolo.pScriptContext->f_10 = CURSCRIPT_GETBYTE;
*D_00C05FE8 = D_00BF23C0[bp08].f_28;
C_0042519A(bp08, lolo.pScriptContext->pScriptData, lolo.pScriptContext->f_12, C_00426A26, lolo.pScriptContext->f_10, &(D_00BE1178[D_00BFB198].f_0140.f_26));
break;
case 0x99:
D_00BE10B4 = CURSCRIPT_GETBYTE;
lolo.pScriptContext->f_12 = CURSCRIPT_GETWORD;
*D_00C05FE8 = CURSCRIPT_GETWORD;
lolo.pScriptContext->f_10 = CURSCRIPT_GETBYTE;
if(D_00BF2E1C == 0) {
C_0042519A(bp08, lolo.pScriptContext->pScriptData, lolo.pScriptContext->f_12, C_00426A26, lolo.pScriptContext->f_10, &(D_00BE1178[D_00BFB198].f_0140.f_26));
} else {
C_005BFEC9(D_00BFD0F8, &(lolo.pScriptContext->f_16));
C_0042519A(bp08, lolo.pScriptContext->pScriptData, lolo.pScriptContext->f_12, C_00426A26, lolo.pScriptContext->f_10, &(lolo.pScriptContext->f_16));
}
break;
case 0xd1:
lolo.pScriptContext->f_12 = CURSCRIPT_GETWORD;
*D_00C05FE8 = CURSCRIPT_GETWORD;
lolo.pScriptContext->f_10 = CURSCRIPT_GETBYTE;
if(D_00BF2E1C == 0) {
C_0042519A(bp08, lolo.pScriptContext->pScriptData, lolo.pScriptContext->f_12, C_00426A26, lolo.pScriptContext->f_10, &(D_00BE1178[D_00BFB198].f_0140.f_26));
} else {
C_005BFEC9(D_00BFD0F8, &(lolo.pScriptContext->f_16));
C_0042519A(bp08, lolo.pScriptContext->pScriptData, lolo.pScriptContext->f_12, C_00426A26, lolo.pScriptContext->f_10, &(lolo.pScriptContext->f_16));
}
break;
case 0xc8:
*D_00C05FE8 = CURSCRIPT_GETWORD;
*D_00C05FEC = CURSCRIPT_GETWORD;
*D_00C05FF0 = CURSCRIPT_GETBYTE;
*D_00C05FF4 = C_005BECF1(C_00426941);
D_00BF2E70[*D_00C05FF4].f_08 = bp08;
D_00BF2E70[*D_00C05FF4].f_0a = *D_00C05FE8;
D_00BF2E70[*D_00C05FF4].f_0c = *D_00C05FEC;
D_00BF2E70[*D_00C05FF4].f_04 = *D_00C05FF0;
break;
case 0xc3:
D_00BE1178[bp08].f_0026 = 1;
C_00425628(bp08);
lolo.pScriptContext->f_14 = C_005BECF1(C_005BBF31);
D_00BF2E70[lolo.pScriptContext->f_14].f_08 = bp08;
D_00BF2E70[lolo.pScriptContext->f_14].f_0a = 0;
D_00BF2E70[lolo.pScriptContext->f_14].f_06 = 1;
break;
case 0xb8:
D_00BE1178[bp08].f_0025 = D_00BE1178[bp08].f_0025 & ~0x80;
D_00BE1178[bp08].f_0025 = D_00BE1178[bp08].f_0025 | 4;
break;
case 0xb7:
C_00425890(bp08, 1);
break;
case 0xc4:
if(D_009ADF08 == 0) {
C_00430D32(0x185, -1, 0x40);
D_009ADF08 = 1;
}
*D_00C05FEC = CURSCRIPT_GETWORD;
*D_00C05FF0 = CURSCRIPT_GETBYTE;
*D_00C05FF4 = C_005BECF1(C_00426941);
D_00BF2E70[*D_00C05FF4].f_08 = bp08;
D_00BF2E70[*D_00C05FF4].f_0a = 0;
D_00BF2E70[*D_00C05FF4].f_04 = *D_00C05FF0;
switch(D_00BFD0E0) {
case 0: case 1: case 8:
*D_00C05FF8 = *D_00C05FEC;
break;
case 2:
*D_00C05FF8 = -*D_00C05FEC;
break;
case 3: case 5: case 6: case 7:
if(D_00BE1178[bp08].f_0018 == 0)
*D_00C05FF8 = *D_00C05FEC;
else
*D_00C05FF8 = -*D_00C05FEC;
break;
case 4:
if(D_009A8748.f_174) {
D_00BE1178[bp08].f_0140.f_1e.f_02 = 0;
*D_00C05FF8 = *D_00C05FEC;
} else {
D_00BE1178[bp08].f_0140.f_1e.f_02 = 0x800;
*D_00C05FF8 = -*D_00C05FEC;
}
break;
}//end switch
D_00BF2E70[*D_00C05FF4].f_0c = *D_00C05FF8;
break;
case 0xbd:
D_00BF2370 = 1;
lolo.pScriptContext->f_12 = CURSCRIPT_GETWORD;
lolo.pScriptContext->f_0c = CURSCRIPT_GETWORD;
C_00424FF1(bp08, D_00BFB198, lolo.pScriptContext->f_12, lolo.pScriptContext->f_0c);
break;
case 0xa6:
D_00BE1178[D_00BFCB68].f_0140.f_26.f_00 = D_00BFD0A0[D_00BFCB68].wX;
D_00BE1178[D_00BFCB68].f_0140.f_26.f_02 = D_00BFD0A0[D_00BFCB68].wY;
D_00BE1178[D_00BFCB68].f_0140.f_26.f_04 = D_00BFD0A0[D_00BFCB68].wZ;
break;
case 0xab:
*D_00C05FE8 = CURSCRIPT_GETWORD;
lolo.pScriptContext->f_12 = 0;
lolo.pScriptContext->f_0c = CURSCRIPT_GETWORD;
D_00BE1178[bp08].f_0140.f_26.f_00 = D_00BFD0A0[D_00BFCB68].wX;
D_00BE1178[bp08].f_0140.f_26.f_02 = D_00BFD0A0[D_00BFCB68].wY;
D_00BE1178[bp08].f_0140.f_26.f_04 = D_00BFD0A0[D_00BFCB68].wZ;
D_00BE1178[bp08].f_0140.f_1e.f_02 = D_00BE1178[D_00BFCB68].f_0018;
lolo.pScriptContext->f_12 = *D_00C05FE8;
lolo.pScriptContext->f_0c = 0;
lolo.pScriptContext->f_08 = 0x1000 - (D_00BE1178[D_00BE1170].f_0140.f_1e.f_02 + 0x800);
lolo.pScriptContext->f_0a = FIX_MUL(lolo.pScriptContext->f_12, D_00BE1178[D_00BFCB68].f_0006) + FIX_MUL(D_00BE1178[bp08].f_0012, D_00BE1178[bp08].f_0006);
D_00BE1178[D_00BFCB68].f_0140.f_26.f_00 = D_00BE1178[bp08].f_0140.f_26.f_00 - FIX_MUL(C_00662538(lolo.pScriptContext->f_08), lolo.pScriptContext->f_0a);
D_00BE1178[D_00BFCB68].f_0140.f_26.f_04 = D_00BE1178[bp08].f_0140.f_26.f_04 + FIX_MUL(C_006624FD(lolo.pScriptContext->f_08), lolo.pScriptContext->f_0a);
D_00BE1178[D_00BFCB68].f_0140.f_26.f_02 = lolo.pScriptContext->f_0c;
break;
case 0xcc:
lolo.pScriptContext->f_12 = 0;
*D_00C05FE8 = 0;
lolo.pScriptContext->f_10 = CURSCRIPT_GETBYTE;
C_005BFEC9(D_00BFD0F8, &(lolo.pScriptContext->f_16));
lolo.pScriptContext->f_16.f_00 = lolo.pScriptContext->f_16.f_00 << 1;
lolo.pScriptContext->f_16.f_04 = lolo.pScriptContext->f_16.f_04 << 1;
C_0042519A(bp08, lolo.pScriptContext->pScriptData, lolo.pScriptContext->f_12, C_00426A26, lolo.pScriptContext->f_10, &(lolo.pScriptContext->f_16));
break;

case 0xa3:
C_00740D80(0xa4, CURSCRIPT_GETBYTE, 0, 0, 0, 0, 0, 0, 0);
break;
case 0xcb:
*D_00C05FE8 = CURSCRIPT_GETBYTE;
*D_00C05FEC = CURSCRIPT_GETWORD;
*D_00C05FF0 = CURSCRIPT_GETBYTE;
*D_00C06000 = CURSCRIPT_GETBYTE;
*D_00C06004 = CURSCRIPT_GETBYTE;
*D_00C05FF4 = CURSCRIPT_GETBYTE;
*D_00C05FF8 = CURSCRIPT_GETBYTE;
*D_00C05FFC = ((*D_00C05FF0 & 0xff) << 10) | ((*D_00C06000 & 0xff) << 5) | (*D_00C06004 & 0xff);
if(*D_00C05FE8 == 0xff)
C_005BF388(bp08, 0, *D_00C05FEC, *D_00C05FFC, *D_00C05FF4, *D_00C05FF8);
else
C_005BF388(bp08, *D_00C05FE8, *D_00C05FEC, *D_00C05FFC, *D_00C05FF4, *D_00C05FF8);
break;
case 0xd5:
lolo.pScriptContext->f_12 = CURSCRIPT_GETWORD;
*D_00C05FEC = CURSCRIPT_GETWORD;
*D_00C05FE8 = CURSCRIPT_GETWORD;
*D_00C05FF0 = CURSCRIPT_GETBYTE;
*D_00C05FF4 = CURSCRIPT_GETBYTE;
lolo.pScriptContext->f_10 = *D_00C05FF4;
C_0042519A(bp08, lolo.pScriptContext->pScriptData, lolo.pScriptContext->f_12, C_004270DE, lolo.pScriptContext->f_10, &(D_00BE1178[D_00BFB198].f_0140.f_26));
break;
case 0xcf:
lolo.pScriptContext->f_12 = CURSCRIPT_GETWORD;
*D_00C05FEC = CURSCRIPT_GETWORD;
*D_00C05FE8 = CURSCRIPT_GETWORD;
*D_00C05FF0 = CURSCRIPT_GETBYTE;
*D_00C05FF4 = CURSCRIPT_GETBYTE;
lolo.pScriptContext->f_10 = *D_00C05FF4;
C_0042519A(bp08, lolo.pScriptContext->pScriptData, lolo.pScriptContext->f_12, C_0042739D, lolo.pScriptContext->f_10, &(D_00BE1178[D_00BFB198].f_0140.f_26));
break;
case 0xe7:
*D_00C05FF0 = CURSCRIPT_GETBYTE;
if(*D_00C05FF0 == 0)
D_00BE1178[bp08].f_0025 = D_00BE1178[bp08].f_0025 | 4;
else
D_00BE1178[bp08].f_0025 = D_00BE1178[bp08].f_0025 & ~4;
break;
case 0xf5:
*D_00C05FF4 = CURSCRIPT_GETBYTE;
D_00BF2054[bp08 - 4].f_00 = *D_00C05FF4 + 3;
C_0042BC15(bp08);
D_00BE1178[bp08].f_003e = D_00BE1178[bp08].f_003e | 1;
break;
case 0xd0:
lolo.pScriptContext->f_12 = CURSCRIPT_GETWORD;
*D_00C05FE8 = CURSCRIPT_GETBYTE;
switch(*D_00C05FE8) {
case 0: case 1: case 2: case 3: lolo.pScriptContext->f_10 = 5; break;
case 4: case 5: case 6: case 7: lolo.pScriptContext->f_10 = 8; break;
}//end switch
if(D_00BF2E1C == 0) {
C_0042519A(bp08, lolo.pScriptContext->pScriptData, lolo.pScriptContext->f_12, C_00426F58, lolo.pScriptContext->f_10, &(D_00BE1178[D_00BFB198].f_0140.f_26));
} else {
C_005BFEC9(D_00BFD0F8, &(lolo.pScriptContext->f_16));
C_0042519A(bp08, lolo.pScriptContext->pScriptData, lolo.pScriptContext->f_12, C_00426F58, lolo.pScriptContext->f_10, &(lolo.pScriptContext->f_16));
}
break;
case 0xf3:
if(D_00BE1178[bp08].f_003d) {
D_00BE1178[bp08].f_003d --;
D_00BE1178[bp08].f_003c --;
lolo.pScriptContext->bScriptActive = 0;
return;
}
break;
case 0xf4:
D_00BE1178[bp08].f_003d = CURSCRIPT_GETBYTE;
break;
case 0xc5:
D_00BE1178[bp08].f_003d = D_00BFD0F0;
break;
case 0xfa:
C_00425119(bp08);
break;
case 0xc2:
*D_00C05FE8 = CURSCRIPT_GETBYTE;
*D_00C05FEC = C_005BEC50(C_00425D29);
D_00BFB718[*D_00C05FEC].f_08 = D_00BFCDE0;
lolo.i = C_0042DE25(D_00BFCDE0);
D_00BFB718[*D_00C05FEC].f_0a = D_00BF2A40[lolo.i].f_00;
D_00BFB718[*D_00C05FEC].f_0e = D_00BF2A40[lolo.i].f_02;
D_00BFB718[*D_00C05FEC].f_06 = D_00BF2A40[lolo.i].f_08;
D_00BFB718[*D_00C05FEC].f_19 = D_00BF2A40[lolo.i].f_0a;
D_00BFB718[*D_00C05FEC].f_04 = *D_00C05FE8;
break;
case 0xf7:
D_00BF23BC = 0;
*D_00C05FE8 = CURSCRIPT_GETBYTE;
C_005BE9F0(D_00BFD0F8, *D_00C05FE8, 1);
break;
case 0xa1:
D_00BF23BC = 0;
*D_00C05FE8 = CURSCRIPT_GETBYTE;
*D_00C05FEC = CURSCRIPT_GETBYTE;
C_005BEB27(*D_00C05FE8, *D_00C05FEC);
break;
case 0xbe:
D_00BF23BC = 1;
*D_00C05FE8 = CURSCRIPT_GETBYTE;
if(
D_009A8748.f_0ac[D_00BE1170].f_00 != 2 ||
*D_00C05FE8 != 8 ||
!(D_009A8748.f_0ac[D_00BFCDE0].f_08 & 0x00000800)
) {
C_005BE9F0(D_00BFD0F8, *D_00C05FE8, 1);
}
break;
case 0xf6:
if(D_00BFC398 == 0) {
if(D_00BFCB20 & BIT(bp08))
C_00425890(bp08, 1);
} else {
if(D_00BF23C0[bp08].f_0c & 0x10)
C_00425890(bp08, 1);
}
break;
case 0xce:
if(bp08 >= 4) {
while(CURSCRIPT_GETBYTE != 0xcd)
;
}
break;
case 0xb3:
if(D_00BF23C0[bp08].f_00 & 0x1000) {
while(CURSCRIPT_GETBYTE != 0xb2)
;
}
break;
case 0xbf:
*D_00C05FE8 = CURSCRIPT_GETBYTE;
*D_00C05FEC = CURSCRIPT_GETBYTE;
D_00BFCDF0[*D_00C05FE8] = *D_00C05FEC;
C_004254E8();
break;
case 0xc1:
D_00BE1178[bp08].f_003c = 0;
while(CURSCRIPT_GETBYTE != 0xc9)
;
break;
case 0xca:
if(D_00BF2A30) {
D_00BE1178[bp08].f_003c = 0;
while(CURSCRIPT_GETBYTE != 0xc9)
;
}
break;
case 0xed:
*D_00C05FE8 = D_00BE1178[bp08].f_0140.f_1e.f_02;
D_00BE1178[bp08].f_0140.f_26.f_00 -= FIX_MUL(C_00662538(*D_00C05FE8), 0x204);
D_00BE1178[bp08].f_0140.f_26.f_04 -= FIX_MUL(C_006624FD(*D_00C05FE8), 0x204);
break;
case 0xe4:
*D_00C05FE8 = D_00BE1178[bp08].f_0140.f_1e.f_02 + 0x800;
D_00BE1178[bp08].f_0140.f_26.f_00 -= FIX_MUL(C_00662538(*D_00C05FE8), 0x204);
D_00BE1178[bp08].f_0140.f_26.f_04 -= FIX_MUL(C_006624FD(*D_00C05FE8), 0x204);
break;
case 0xb1:
*D_00C05FE8 = D_00BE1178[bp08].f_0140.f_1e.f_02;
D_00BE1178[bp08].f_0140.f_26.f_00 -= FIX_MUL(C_00662538(*D_00C05FE8), 0x102);
D_00BE1178[bp08].f_0140.f_26.f_04 -= FIX_MUL(C_006624FD(*D_00C05FE8), 0x102);
break;
case 0xb0:
*D_00C05FE8 = D_00BE1178[bp08].f_0140.f_1e.f_02 + 0x800;
D_00BE1178[bp08].f_0140.f_26.f_00 -= FIX_MUL(C_00662538(*D_00C05FE8), 0x102);
D_00BE1178[bp08].f_0140.f_26.f_04 -= FIX_MUL(C_006624FD(*D_00C05FE8), 0x102);
break;
case 0xd7:
*D_00C05FE8 = CURSCRIPT_GETBYTE;
*D_00C05FEC = CURSCRIPT_GETBYTE;
lolo.pScriptContext->f_0a = C_005BED92(C_004276B6);
D_00BFC3A0[lolo.pScriptContext->f_0a].f_04 = *D_00C05FE8;
D_00BFC3A0[lolo.pScriptContext->f_0a].f_06 = *D_00C05FEC;
D_00BFC3A0[lolo.pScriptContext->f_0a].f_08 = bp08;
break;
case 0xd8:
*D_00C05FE8 = CURSCRIPT_GETBYTE;
*D_00C05FEC = CURSCRIPT_GETWORD;
lolo.pScriptContext->f_0a = C_005BED92(C_00427737);
D_00BFC3A0[lolo.pScriptContext->f_0a].f_04 = *D_00C05FE8;
D_00BFC3A0[lolo.pScriptContext->f_0a].f_06 = *D_00C05FEC;
break;
case 0xf2:
break;
case 0x9e:
if(bp08 == D_00BFCDE0) {//else 00422DA4
if(D_00C05EBC == 0) {
D_00BE1178[bp08].f_0026 = 1;
return;
}
D_00BE1178[bp08].f_003c --;
return;
}
if(D_00BE1178[D_00BFCDE0].f_0026 == 1 && D_00C05EBC == 0) {
D_00BE1178[bp08].f_0026 = 1;
return;
}
D_00BE1178[bp08].f_003c --;
return;
//break;
case 0xee:
case 0xff:
D_00BF23C0[bp08].f_0c = D_00BF23C0[bp08].f_0c & ~4;
D_00BE1178[bp08].f_0026 = 1;
D_00BF23C0[bp08].f_0c = D_00BF23C0[bp08].f_0c & ~8;
D_00BF2DF8[bp08] = D_009A8748.f_0ac[bp08].f_01;
D_00BE1178[bp08].wCurScriptId = D_00BF2DF8[bp08];
lolo.pScriptContext->pScriptData = ppScriptData[D_00BE1178[bp08].wCurScriptId];
C_004254B0(bp08);
break;
case 0xf1:
D_00BF23C0[bp08].f_0c = D_00BF23C0[bp08].f_0c & ~4;
D_00BE1178[bp08].f_0026 = 1;
D_00BF23C0[bp08].f_0c = D_00BF23C0[bp08].f_0c & ~8;
D_00BE1178[bp08].f_003c --;
return;
//break;
case 0xa0:
D_00BF23C0[D_00BFB198].f_0c = D_00BF23C0[D_00BFB198].f_0c | 1;
*D_00C05FE8 = CURSCRIPT_GETBYTE;
C_00430A99(&(D_00BE1178[bp08].f_0174[*D_00C05FE8]), &(D_00BE1178[D_00BFB198].f_0140));
D_00BE1178[D_00BFB198].f_0140.f_1e.f_02 = 0;
D_00BE1178[D_00BFB198].f_0140.f_1e.f_00 = 0;
D_00BE1178[D_00BFB198].f_0140.f_26.f_00 = D_00BE1178[D_00BFB198].f_0140.f_26.f_02 = D_00BE1178[D_00BFB198].f_0140.f_26.f_04 = 0;
D_00BE1178[D_00BFB198].f_0140.f_1e.f_04 = 0x800;
D_00BE1178[D_00BFB198].f_0025 = D_00BE1178[D_00BFB198].f_0025 | 0x10;
D_00BE1178[D_00BFB198].f_1ae4 = bp08;
D_00BE1178[D_00BFB198].f_1ae8 = *D_00C05FE8;
break;
case 0xaf:
D_00BF23C0[D_00BFB198].f_0c = D_00BF23C0[D_00BFB198].f_0c | 1;
*D_00C05FE8 = CURSCRIPT_GETBYTE;
C_00430A99(&(D_00BE1178[bp08].f_0174[*D_00C05FE8]), &(D_00BE1178[D_00BFB198].f_0140));
D_00BE1178[D_00BFB198].f_0140.f_1e.f_00 = D_00BE1178[D_00BFB198].f_0140.f_1e.f_02 = D_00BE1178[D_00BFB198].f_0140.f_1e.f_04 = 0;
D_00BE1178[D_00BFB198].f_0140.f_26.f_00 = D_00BE1178[D_00BFB198].f_0140.f_26.f_02 = D_00BE1178[D_00BFB198].f_0140.f_26.f_04 = 0;
D_00BE1178[D_00BFB198].f_0025 = D_00BE1178[D_00BFB198].f_0025 | 0x10;
D_00BE1178[D_00BFB198].f_1ae4 = bp08;
D_00BE1178[D_00BFB198].f_1ae8 = *D_00C05FE8;
break;
case 0xae:
D_00BF23C0[D_00BFB198].f_0c = D_00BF23C0[D_00BFB198].f_0c & ~1;
C_00430A99(D_00BF2168, &(D_00BE1178[D_00BFB198].f_0140));
D_00BE1178[D_00BFB198].f_0140.f_26.f_00 = D_00BFD0A0[D_00BFB198].wX;
D_00BE1178[D_00BFB198].f_0140.f_26.f_02 = D_00BFD0A0[D_00BFB198].wY;
D_00BE1178[D_00BFB198].f_0140.f_26.f_04 = D_00BFD0A0[D_00BFB198].wZ;
D_00BE1178[D_00BFB198].f_0140.f_1e.f_00 = D_00BE1178[D_00BFB198].f_0140.f_1e.f_02 = D_00BE1178[D_00BFB198].f_0140.f_1e.f_04 = 0;
D_00BE1178[D_00BFB198].f_0025 = D_00BE1178[D_00BFB198].f_0025 & ~0x10;
break;
case 0x9d://limit2/tifa1 related?
*D_00C05FE8 = CURSCRIPT_GETBYTE;
switch(*D_00C05FE8) {
case 0: C_004E1627(D_00BFD0F8, D_00BE1170); break;
case 1: C_004E163E(D_00BFD0F8, D_00BE1170); break;
case 2: C_004E1655(D_00BFD0F8, D_00BE1170); break;
case 3: C_004E166C(D_00BFD0F8, D_00BE1170); break;
case 4: C_004E1683(D_00BFD0F8, D_00BE1170); break;
case 5: C_004E169A(D_00BFD0F8, D_00BE1170); break;
case 6: C_004E16B1(D_00BFD0F8, D_00BE1170); break;
}//end switch
break;
case 0xda:
D_00BE1178[bp08].cLimitBreakId = CURSCRIPT_GETBYTE;
D_00BE1178[bp08].f_0023 = 2;
break;
case 0x96:
lolo.pScriptContext->f_0a = CURSCRIPT_GETBYTE;
lolo.pScriptContext->f_0c = CURSCRIPT_GETBYTE;
lolo.bp_0c = C_006CB98E(bp08);//get character's info object?
if(lolo.bp_0c) {
lolo.pScriptContext->f_0e = D_007C10B8[lolo.bp_0c->f_408.f_09 & 0xf];
C_0043930D(D_00BFCDE0, bp08, -1, lolo.pScriptContext->f_0e, lolo.pScriptContext->f_0a, lolo.pScriptContext->f_0c);//MAGIC/MGUN
}
break;
case 0xdc:
lolo.pScriptContext->f_0a = CURSCRIPT_GETBYTE;
D_00BE1178[bp08].f_001a[lolo.pScriptContext->f_0a] = FIX_MUL(CURSCRIPT_GETWORD, D_00BE1178[bp08].f_0006);
break;
case 0xde:
lolo.pScriptContext->f_0a = CURSCRIPT_GETBYTE;
lolo.pScriptContext->f_0c = CURSCRIPT_GETBYTE;
C_00439907(D_00BFCDE0, bp08, lolo.pScriptContext->f_0a, lolo.pScriptContext->f_0c);//MAGIC/MGUN
break;
case 0xdd:
lolo.pScriptContext->f_0a = CURSCRIPT_GETBYTE;
lolo.pScriptContext->f_0c = CURSCRIPT_GETBYTE;
C_00439946(D_00BFCDE0, bp08, lolo.pScriptContext->f_0a, lolo.pScriptContext->f_0c);//MAGIC/MGUN
break;
case 0xad:
lolo.pScriptContext->f_10 = CURSCRIPT_GETBYTE;
lolo.pScriptContext->f_0e = CURSCRIPT_GETWORD;
lolo.pScriptContext->f_0a = CURSCRIPT_GETBYTE;
lolo.pScriptContext->f_0c = CURSCRIPT_GETBYTE;
C_0043930D(D_00BFCDE0, bp08, D_00BE1178[bp08].f_002b[lolo.pScriptContext->f_10], lolo.pScriptContext->f_0e, lolo.pScriptContext->f_0a, lolo.pScriptContext->f_0c);//MAGIC/MGUN
break;
case 0xdb:
lolo.pScriptContext->f_0e = CURSCRIPT_GETWORD;
lolo.pScriptContext->f_0a = CURSCRIPT_GETBYTE;
lolo.pScriptContext->f_0c = CURSCRIPT_GETBYTE;
C_0043930D(D_00BFCDE0, bp08, -1, lolo.pScriptContext->f_0e, lolo.pScriptContext->f_0a, lolo.pScriptContext->f_0c);//MAGIC/MGUN
break;
case 0xf0:
C_005BE490(bp08);//make smoke trail?
break;
case 0xb5:
lolo.pScriptContext->f_16.f_00 = CURSCRIPT_GETWORD;
lolo.pScriptContext->f_16.f_02 = CURSCRIPT_GETWORD;
lolo.pScriptContext->f_16.f_04 = CURSCRIPT_GETWORD;
lolo.pScriptContext->f_0a = CURSCRIPT_GETBYTE;
lolo.pScriptContext->f_0c = CURSCRIPT_GETWORD;
lolo.pScriptContext->f_0e = CURSCRIPT_GETWORD;
C_005BE844(bp08, &(lolo.pScriptContext->f_16), lolo.pScriptContext->f_0a, lolo.pScriptContext->f_0c, lolo.pScriptContext->f_0e);
break;
case 0xa4:
lolo.i = C_005BED92(C_00425520);
D_00BFC3A0[lolo.i].f_02 = 2;
D_00BFC3A0[lolo.i].f_04 = 0x1f0;
break;
case 0xa5:
lolo.i = C_005BED92(C_00425520);
D_00BFC3A0[lolo.i].f_02 = 3;
D_00BFC3A0[lolo.i].f_04 = 0x1e9;
break;
case 0xe6:
lolo.i = C_005BED92(C_00425520);
D_00BFC3A0[lolo.i].f_02 = 0;
D_00BFC3A0[lolo.i].f_04 = 0xd;
break;
case 0xe0:
lolo.i = C_005BED92(C_00425520);
D_00BFC3A0[lolo.i].f_02 = 1;
D_00BFC3A0[lolo.i].f_04 = 0x24;
break;
case 0x90:
lolo.pScriptContext->f_15 = CURSCRIPT_GETBYTE;
switch(bp08) {
case 6:
*D_00C05FE8 = 0;
*D_00C05FEC = lolo.pScriptContext->f_15;
break;
case 7:
*D_00C05FE8 = 0;
*D_00C05FEC = lolo.pScriptContext->f_15 + 8;
break;
case 8:
*D_00C05FE8 = 1;
*D_00C05FEC = lolo.pScriptContext->f_15;
break;
case 9:
*D_00C05FE8 = 1;
*D_00C05FEC = lolo.pScriptContext->f_15 + 8;
break;
}//end switch
lolo.bp_2c = C_00666BBE(C_00676578());//get field_934[gfx_driver]?
lolo.bp_34 = 4;
lolo.bp_28 = CURSCRIPT_GETWORD;
lolo.bp_24 = &lolo.bp_30;
lolo.bp_24->c.b = (lolo.bp_28 & 0x001f) << 3;
lolo.bp_24->c.g = (lolo.bp_28 & 0x03e0) >> 2;
lolo.bp_24->c.r = (lolo.bp_28 & 0x7c00) >> 7;
lolo.bp_24->c.a = 0xff;
lolo.bp_18 = *D_00C05FEC;
lolo.bp_20 = 0;

D_009ADEE8 = 0;
D_009ADEE0[0] = 0;
D_009ADEE0[1] = 0;
D_009ADEF0[0] = 0;
D_009ADEF0[1] = 0;
C_00685028(lolo.bp_20, C_0041FB1C, D_00BE1178[lolo.bp_34].f_0ba8->f_04);//anm:apply function to skeleton?
if(bp08 < 8)
lolo.bp_38 = D_009ADEE0[0];
else
lolo.bp_38 = D_009ADEE0[1];
if(lolo.bp_38) {
C_0068924B(0, 1, lolo.bp_24, lolo.bp_18, lolo.bp_38);//dx_graph:SetPaletteData
lolo.bp_2c->f_54(lolo.bp_18, 1, lolo.bp_18, lolo.bp_38->f_8c, lolo.bp_38);
}
break;
case 0x9b:
D_00BF2370 = 1;
break;
case 0x9f:
D_00BF2370 = 0;
break;
case 0xc6:
D_00BFD0F0 = CURSCRIPT_GETBYTE;
break;
case 0xe2:
D_00BE1178[bp08].f_003e = D_00BE1178[bp08].f_003e | 2;
break;
case 0xe1:
D_00BE1178[bp08].f_003e = D_00BE1178[bp08].f_003e | 4;
break;
case 0xe8:
C_004281B1(bp08);//launch magic attack?
break;
case 0xac:
D_00BE1178[bp08].f_003e = D_00BE1178[bp08].f_003e | 0x20;
D_00BF23C0[bp08].f_00 = D_009A8748.f_0ac[bp08].f_08;
D_00BE1178[bp08].f_0140.f_1e.f_02 = D_00BE1178[bp08].f_0018;
lolo.pScriptContext->f_0a = CURSCRIPT_GETBYTE;
if(lolo.pScriptContext->f_0a == 0xa) {//else 00424012
lolo.bp_0c = C_006CB98E(bp08);//get character's info object?
if(lolo.bp_0c) {//else 00423FFD
lolo.pScriptContext->f_0c = lolo.bp_0c->f_408.f_09 & 0xf0;
switch(lolo.pScriptContext->f_0c) {
case 0x00: lolo.pScriptContext->f_0e = 4; break;
case 0x10: lolo.pScriptContext->f_0e = 5; break;
case 0x20: lolo.pScriptContext->f_0e = 6; break;
default:
lolo.pScriptContext->f_0e = 4;
}//end switch
} else {
lolo.pScriptContext->f_0e = 4;
}
lolo.bp_1c = lolo.pScriptContext->f_0e;
} else {
lolo.bp_1c = lolo.pScriptContext->f_0a;
}
D_009ADED8 = lolo.bp_1c;
break;
case 0xa2:
lolo.pScriptContext->f_0e = CURSCRIPT_GETBYTE;
if(D_009ADED8 >= 4)
C_0042A330(0, 0, bp08, D_007C1098[D_009ADED8]);
else
C_0042A330(0, 1, bp08, D_007C1098[D_009ADED8]);
if(D_00BFB2B8[bp08])
D_00BE1178[bp08].f_0ba8 = D_00BFB2B8[bp08];
D_00BE1178[bp08].f_000e = 0;
D_00BE1178[bp08].f_0b9c = 0;
D_00BE1178[bp08].f_0ba0 = 0;
D_00BE1178[bp08].f_0ba4 = 0;
D_00BE1178[bp08].f_1ac4 = 0;
C_0042C21B(bp08);
C_0042C1B4(bp08);
//-- update scripts pointers --
lolo.bp_08 = D_00BFB2B8[bp08]->f_00;
for(lolo.i = 0; lolo.i < 0x4a; lolo.i ++)
lolo.bp_08->f_68[lolo.i] += (int)(D_00BFB2B8[bp08]->f_00);
//-- --
C_0042B66A(bp08);
D_00BE1178[bp08].wCurScriptId = lolo.pScriptContext->f_0e;
D_009A8748.f_0ac[bp08].f_01 = D_00BE1178[bp08].wCurScriptId;
D_00BF2DF8[bp08] = D_009A8748.f_0ac[bp08].f_01;
D_00BE1178[bp08].f_003e = D_00BE1178[bp08].f_003e | 1;
D_00BE1178[bp08].f_003e = D_00BE1178[bp08].f_003e | 4;
D_00BE1178[bp08].f_0025 = D_00BE1178[bp08].f_0025 & ~2;
C_00430D32(0x2d9, bp08, 0);
return;
//break;
case 0xd6:
lolo.pScriptContext->f_0a = CURSCRIPT_GETBYTE;
lolo.pScriptContext->f_0c = C_005BED92(C_004277B1);
D_00BFC3A0[lolo.pScriptContext->f_0c].f_06 = bp08;
D_00BFC3A0[lolo.pScriptContext->f_0c].f_04 = lolo.pScriptContext->f_0a;
break;
case 0xec:
if(D_00BF2A30 == 0) {
C_00427C22(bp08);
D_009ADF04 = 0;
} else {
D_00BE1178[bp08].f_003c --;
lolo.pScriptContext->bScriptActive = 0;
D_009ADF04 = 1;
}
break;
case 0x97:
*D_00C05FE8 = CURSCRIPT_GETBYTE;
*D_00C05FEC = CURSCRIPT_GETBYTE;
C_0042567E(bp08, *D_00C05FE8, *D_00C05FEC);
break;
case 0x98:
*D_00C05FE8 = CURSCRIPT_GETBYTE;
lolo.pScriptContext->f_14 = C_005BEC50(C_0042782A);
D_00BFB718[lolo.pScriptContext->f_14].f_04 = C_005BE475();//battle message speed?
D_00BFB718[lolo.pScriptContext->f_14].f_06 = *D_00C05FE8;
break;
case 0xea:
lolo.pScriptContext->f_14 = C_005BEC50(C_0042782A);
D_00BFB718[lolo.pScriptContext->f_14].f_04 = C_005BE475();//battle message speed?
D_00BFB718[lolo.pScriptContext->f_14].f_06 = 0;
break;
case 0xeb:
if(D_00BF2A30 == 0) {
C_00427B4B(bp08);
} else {
D_00BE1178[bp08].f_003c --;
lolo.pScriptContext->bScriptActive = 0;
}
break;
case 0xb2:
case 0xc9:
break;
case 0xaa:
D_00BF2A2C = 0;
break;
case 0xa7:
D_00BE1178[bp08].f_000e = CURSCRIPT_GETBYTE;
D_00BE1178[bp08].f_0074 = 0;
D_00BE0E28[bp08].f_00 = 0;
if(D_00BF23C0[bp08].f_36) {
for(lolo.i = 0; lolo.i < D_00BF23C0[bp08].f_36; lolo.i ++)
C_00424B4B(bp08, bp10, bp14);
}
lolo.pScriptContext->bScriptActive = 0;
break;
case 0xb6:
C_005BED92(C_0042517B);
D_00BE1178[bp08].f_000e = CURSCRIPT_GETBYTE;
D_00BE1178[bp08].f_0074 = 0;
D_00BE0E28[bp08].f_00 = 0;
if(D_00BF23C0[bp08].f_36) {
for(lolo.i = 0; lolo.i < D_00BF23C0[bp08].f_36; lolo.i ++)
C_00424B4B(bp08, bp10, bp14);
}
lolo.pScriptContext->bScriptActive = 0;
break;
default:
D_00BE1178[bp08].f_000e = lolo.pScriptContext->bOpcode;
D_00BE1178[bp08].f_0074 = 0;
D_00BF23C0[bp08].f_36 = 0;
D_00BE0E28[bp08].f_00 = 0;
lolo.pScriptContext->bScriptActive = 0;
}//end switch(lolo.pScriptContext->f_01)
}//end while(lolo.pScriptContext->bScriptActive)
}
//00424745
if(D_00BF23C0[bp08].f_0c & 2)
return;
D_00BF23C0[bp08].f_36 ++;
if(D_00BE1178[bp08].wCurScriptId != D_00BF2DF8[bp08]) {
C_00424B4B(bp08, bp10, bp14);
return;
}
switch(D_00BF23C0[bp08].f_33) {
default:
C_00424B4B(bp08, bp10, bp14);
break;
case 1:
C_00424B4B(bp08, bp10, bp14);
C_00424B4B(bp08, bp10, bp14);
break;
case 2:
if(D_00BFD0E4 & 1)
C_00424B4B(bp08, bp10, bp14);
break;
case 3:
D_00BE1178[bp08].f_0074 = 0;
D_00BE0E28[bp08].f_00 = 0;
D_009ADEF8 = 1;
C_00424B4B(bp08, bp10, bp14);
break;
}//end switch
}

I know, it's pretty ugly. Concerning CURSCRIPT_GETBYTE, it's a macro I made to make the code more "readable". For info:
Code: [Select]
#define CURSCRIPT_GETBYTE lolo.pScriptContext->pScriptData[D_00BE1178[bp08].f_003c ++]
#define CURSCRIPT_GETWORD C_00424F5F(bp08, lolo.pScriptContext->pScriptData)

Also, here is what I call the script context structure:
Code: [Select]
struct t_battle_ScriptContext {//size 0x1e?
/*00*/char bScriptActive;
/*01*/unsigned char bOpcode;
/*02*/char __02[2];//pad
/*04*/unsigned char *pScriptData;
/*08*/short f_08;
/*0a*/short f_0a;
//-- --
/*0c*/short f_0c;
/*0e*/short f_0e;
/*10*/short f_10;
/*12*/short f_12;
/*14*/char f_14;
/*15*/char f_15;
/*16*/struct SVECTOR f_16;
//-- --
/*1e*/
};

Enjoy :D

quantumpencil

  • *
  • Posts: 72
    • View Profile
Re: Reverse Engineering the handling of attack animations
« Reply #2 on: 2018-12-20 05:34:06 »
Thanks ergonomy_joe! Definitely helpful, I think I mis-reversed the struct initially, +1 is the current opcode, not a ptr to the script -- that had me going down some wild goose-chases. This should help reversing the individual opcodes =)

Ok, some more progress tonight. This is as much of the path as I have figured out between "Command" and "Animation Run"

1:MainActionRoutine calls command specific loading functions which set the MainBattleStructures animation related fields.

2:The function which inflicts damage for most commands calls another function at 0x5DBD40, where it calls a "copy" anim data function at 0x5CAB7C.

3: The function at 0x5CAB7C just copies the animation related data and calls another function at 0x5C7DEA with with the AnimData as args.

4: The function at 0x5C7DEA copies this data into two different arrays of maximum size 0x40(EDIT: 0x40 and 0x80, actually), both of which have element sizes of 0xC: These two arrays are located 0x9AAD70 and 0x9ACB98, and the indexes (maintained separately) at which these structs are enqueued are held at 0x9AEA9C and 0x9AEAA0, and incremented after each copy.

5: The data in these structs is consumed 0x42CBF9, which seems to copy data from a specific "enqueued" animation block into ANOTHER array of structs of size 0x20, which starts at 0xBFB710(CommandID ends up here) and a giant array with elements of size 0x1AEC (haven't found the start of this one yet, but the "Animation Effect ID" form kernel.bin or scene.bin ends up here) The values in these structs are directly referenced by The function ergo_joe linked which runs all the scripts

Some copyceptron right there

Surprisingly, Even though I've traced the animation index and command indexes this far (which is pretty close to the end) I still haven't come across the relative offset math used to fetch actual additional effects. Nor have a found where the game actually says "If the command index is 0x02, run the 'magic cast' animation script -- which is the paydirt.
« Last Edit: 2018-12-21 00:14:08 by quantumpencil »

ergonomy_joe

  • *
  • Posts: 20
    • View Profile
Re: Reverse Engineering the handling of attack animations
« Reply #3 on: 2018-12-20 23:46:58 »
You seem to be doing a great job quantumpencil.
Honestly this battle code is either a clever engineering job or a total mess, I cannot tell yet.
Either way, it is really hard to understand.
Just a thing, the array at 0x009ACB98 has a maximum size of 0x80.

quantumpencil

  • *
  • Posts: 72
    • View Profile
Re: Reverse Engineering the handling of attack animations
« Reply #4 on: 2018-12-21 00:24:03 »
EDITED to reflect solved problems.

Ok, I have found out how the relevant offsetting/handling of magic actually works. It is handled by the routine at 0x4281B1, corresponding to animation script opcode 0xE8. This explains why only matching command indexes AND model scripts can summon effects. There is a switch 31 in here, and based on the command ID, it fetches the final copy of the (relative animation ID)  and looks up an index in a table; This is an index to another big table of subroutines associated with various "animation" effects. (Mostly, Magic also has a few subs at random places handled by a secondary switch). These subs get passed to 0x4284A7 which actually executes the animations (and hits opengl libraries)

This is possibly the least modular way I can imagine this being implemented. It would still be possible to execute an Enemy Skill or something with a magic animation, but it requires some ugliness. Only way I can think of is to wrap this function and then prior to calling the original, change the Command ID and the Animation Indexes to whatever you want based on their copied values; i.e, if the it's command 0x0D (ES) with Effect ID (0x04), Instead go to the magic case with ID 0x1B and you got Fire. I'll work on a wrapper like this, but this is the actual code (I stepped through the animation frame by frame) so it's gonna work =). Not as elegant as I'd hoped though.

This also means getting burn to display will be a little tricky, as this function doesn't have a "case" for command index 23 at all, meaning I do not think that index can ever display additional effects Even if the particular model animation allows it (I know this, from testing, but now I know the reason). If this function is still called for out of range indexes then that's not too bad, but if it's not it might be annoying.

Moreover, I have found out how the game actually gets "which" script to run. This was hard to reverse as runAnimationScript is constantly running asynchronously for various actors, but basically the block that sets the ptr is at 41FBBB and it's said by taking the commandID (1D) for magic and offsetting from a ptr which is set per actor when a game,the ptr is at 0x8FE2AC, and is different every battle. For command indexes less than 2E, this is the final say on the script being run. This script is iterated over at 0x41FD66, opcode by opcode  and the calls underneath it touch openGL.


UPDATE:Burn effect is now fully functional for both player and enemy characters, and animated =).
« Last Edit: 2018-12-24 00:24:46 by quantumpencil »