diff --git a/CMakeLists.txt b/CMakeLists.txt index 14280eff..9f401eb4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,9 +89,12 @@ set(FF7_MINI set(FF7_MAGIC src/magic/barrier.c src/magic/brizad.c + src/magic/hadoho.c src/magic/lv5deth.c src/magic/mabaria.c + src/magic/re_do.c src/magic/sennkoku.c + src/magic/shaku.c src/magic/thunder.c ) diff --git a/config/symbols.magic-hadoho.us.txt b/config/symbols.magic-hadoho.us.txt new file mode 100644 index 00000000..28920089 --- /dev/null +++ b/config/symbols.magic-hadoho.us.txt @@ -0,0 +1,19 @@ +MAGIC_Hadoho = 0x801B0000; +HadohoTargetCenterCalc = 0x801B0020; +HadohoSprayVectorCalc = 0x801B01CC; +HadohoSpriteMatrixSetup = 0x801B02FC; +HadohoDoubleBufferFlip = 0x801B045C; +HadohoViewportFlashTick = 0x801B04C8; +HadohoSparkSpriteTick = 0x801B05B0; +HadohoEmberTick = 0x801B066C; +HadohoRisingModelTick = 0x801B0888; +HadohoGrowingModelTick = 0x801B09E8; +HadohoShrinkingModelTick = 0x801B0B44; +HadohoDriftSpriteTick = 0x801B0CC8; +HadohoPulseSpriteTick = 0x801B0DB4; +HadohoBeamColumnTick = 0x801B0EB4; +HadohoBeamHeadTick = 0x801B10A8; +HadohoMainTick = 0x801B1598; +HadohoStart = 0x801B1978; +g_HadohoPrimBuffer = 0x801D5648; +g_HadohoBufferPtr = 0x801ED648; diff --git a/config/symbols.magic-re_do.us.txt b/config/symbols.magic-re_do.us.txt new file mode 100644 index 00000000..d67aa2f6 --- /dev/null +++ b/config/symbols.magic-re_do.us.txt @@ -0,0 +1,19 @@ +MAGIC_ReDo = 0x801B0000; +ReDoTargetCenterCalc = 0x801B0020; +ReDoSprayVectorCalc = 0x801B01CC; +ReDoSpriteMatrixSetup = 0x801B02FC; +ReDoDoubleBufferFlip = 0x801B045C; +ReDoViewportFlashTick = 0x801B04C8; +ReDoSparkSpriteTick = 0x801B05A8; +ReDoEmberTick = 0x801B0664; +ReDoRisingModelTick = 0x801B0880; +ReDoGrowingModelTick = 0x801B09E0; +ReDoShrinkingModelTick = 0x801B0B3C; +ReDoDriftSpriteTick = 0x801B0CC0; +ReDoPulseSpriteTick = 0x801B0DAC; +ReDoBeamColumnTick = 0x801B0EAC; +ReDoBeamHeadTick = 0x801B10A0; +ReDoMainTick = 0x801B1590; +ReDoStart = 0x801B1A54; +g_ReDoPrimBuffer = 0x801D5738; +g_ReDoBufferPtr = 0x801ED738; diff --git a/config/symbols.magic-shaku.us.txt b/config/symbols.magic-shaku.us.txt new file mode 100644 index 00000000..0d7b564e --- /dev/null +++ b/config/symbols.magic-shaku.us.txt @@ -0,0 +1,19 @@ +MAGIC_Shaku = 0x801B0000; +ShakuTargetCenterCalc = 0x801B0020; +ShakuSprayVectorCalc = 0x801B01CC; +ShakuSpriteMatrixSetup = 0x801B02FC; +ShakuDoubleBufferFlip = 0x801B045C; +ShakuViewportFlashTick = 0x801B04C8; +ShakuSparkSpriteTick = 0x801B05A8; +ShakuEmberTick = 0x801B0664; +ShakuRisingModelTick = 0x801B0880; +ShakuGrowingModelTick = 0x801B09E0; +ShakuShrinkingModelTick = 0x801B0B3C; +ShakuDriftSpriteTick = 0x801B0CC0; +ShakuPulseSpriteTick = 0x801B0DAC; +ShakuBeamColumnTick = 0x801B0EAC; +ShakuBeamHeadTick = 0x801B10A0; +ShakuMainTick = 0x801B1590; +ShakuStart = 0x801B1970; +g_ShakuPrimBuffer = 0x801D5768; +g_ShakuBufferPtr = 0x801ED768; diff --git a/config/us.yaml b/config/us.yaml index 69eaa150..11180dfb 100644 --- a/config/us.yaml +++ b/config/us.yaml @@ -807,3 +807,42 @@ overlays: - [0, c, sennkoku] - [0x930, data, sennkoku_model] - [0x559C, data, sennkoku_buffers] + # HADOHO.BIN -- effect overlay + - name: hadoho + disk_path: disks/us/MAGIC/HADOHO.BIN + sha1: 850cc7b46911dd9c300f4c0a7928a55cd097d84c + base_path: magic + imports: [main, battle] + vram_start: 0x801B0000 + symbol_addrs_path: + - config/symbols.magic-hadoho.us.txt + segments: + - [0, c, hadoho] + - [0x1B40, data, hadoho_model] + - [0x25648, data, hadoho_buffers] + # SHAKU.BIN -- effect overlay + - name: shaku + disk_path: disks/us/MAGIC/SHAKU.BIN + sha1: fe2958f8b1b2ac815ba968c1e9979e88daa943c2 + base_path: magic + imports: [main, battle] + vram_start: 0x801B0000 + symbol_addrs_path: + - config/symbols.magic-shaku.us.txt + segments: + - [0, c, shaku] + - [0x1B38, data, shaku_model] + - [0x25768, data, shaku_buffers] + # RE_DO.BIN -- effect overlay + - name: re_do + disk_path: disks/us/MAGIC/RE_DO.BIN + sha1: f27b56b6b0666873bb632a35d345ecbf6b15b52f + base_path: magic + imports: [main, battle] + vram_start: 0x801B0000 + symbol_addrs_path: + - config/symbols.magic-re_do.us.txt + segments: + - [0, c, re_do] + - [0x1B08, data, re_do_model] + - [0x25738, data, re_do_buffers] diff --git a/src/magic/hadoho.c b/src/magic/hadoho.c new file mode 100644 index 00000000..46a6c37f --- /dev/null +++ b/src/magic/hadoho.c @@ -0,0 +1,575 @@ +//! PSYQ=3.3 CC1=2.6.3 + +#include "common.h" +#include "magic.h" +#include "hadoho.h" +#include "../battle/battle.h" + +u_long* func_800C4FC8(); + +// Dragon Cannon (怒龍砲 / Doryuho). +// The file name (波動砲, Wave Artillery) is the attack that uses SHAKU. + +void HadohoStart(s32 targetMask, s32 callbackArg); + +// Primitive buffer pages, one 0xC000 page per double-buffered frame. +extern u8 g_HadohoPrimBuffer[2][0xC000]; +extern void* g_HadohoBufferPtr; + +// Only StartFrame/AnimationFrame are common to every magic overlay; the +// rest is payload this effect lays out for itself. +typedef struct { + /* 0x00 */ s16 StartFrame; + /* 0x02 */ s16 AnimationFrame; + /* 0x04 */ SVECTOR Pos; + /* 0x0C */ SVECTOR PartPos; + /* 0x14 */ s16 unk14; + /* 0x16 */ s16 unk16; + /* 0x18 */ s16 unk18; + /* 0x1A */ s16 unk1A; + /* 0x1C */ s16 unk1C; + /* 0x1E */ s16 unk1E; +} HadohoData; // size:0x20 + +extern MATRIX D_801D561C; +extern ModelRenderDesc D_801D555C; +extern ModelRenderDesc D_801D5584; +extern ModelRenderDesc D_801D559C; +extern ModelRenderDesc D_801D55C8; +extern ModelRenderDesc D_801D55F4; +extern SVECTOR D_801D557C; +extern SVECTOR D_801D5594; +extern SVECTOR D_801D55D8; +extern SVECTOR D_801D5610; +extern SVECTOR D_801D5640; +extern SpriteRenderDesc D_801D5534; +extern SpriteRenderDesc D_801D5540; +extern SpriteRenderDesc D_801D55AC; +extern SpriteRenderDesc D_801D55B8; +extern SpriteRenderDesc D_801D5604; +extern VECTOR D_801D554C; +extern VECTOR D_801D55E4; +extern HadohoData g_BattleEffectSlots[]; +extern HadohoData g_BattleDetachedSlots[]; +extern s16 g_BattleDetachedCursor; +extern s16 D_801D5530; +extern s16 D_801D55C4; +extern s16 D_801D55E0; +extern s16 D_801D5618; +extern s16 D_801D563C; +extern s32 D_801D5174; +extern s32 D_801D53AC; +extern s32 D_801D1C40[]; +extern s32 D_801D2244[]; +extern s32 D_801D2848[]; +extern s32 D_801D37EC[]; +extern s32 D_801D4790[]; +extern s32* D_801D556C[]; +extern u16 D_801031EA; +extern u8 D_800F5B70; +extern u8 D_800F5B71; +extern u8 D_800F5B72; +extern u_long D_801B1B40[]; +extern void* D_80163C74; +s32 BattleDetachedRegister(void (*func)(void)); +void func_800BBA84(u16 arg0, s32 arg1, s32 arg2); +void HadohoViewportFlashTick(void); +void HadohoEmberTick(void); +void HadohoRisingModelTick(void); +void HadohoShrinkingModelTick(void); +void HadohoBeamHeadTick(void); +void HadohoMainTick(void); + +void MAGIC_Hadoho(s32 targetMask, s32 callbackArg) { HadohoStart(targetMask, callbackArg); } + +void HadohoTargetCenterCalc(s16 targetMask, SVECTOR* out) { + VECTOR sum; + SVECTOR pos; + s16 i; + s16 count; + + count = 0; + sum.vx = sum.vy = sum.vz = 0; + for (i = 0; i < 10; i++) { + if ((targetMask >> i) & 1) { + BattleGetPartPosition(i, g_BattleModels[i].boneIndices[0], &pos); + count++; + sum.vx += pos.vx; + sum.vy += pos.vy; + sum.vz += pos.vz; + } + } + out->vx = sum.vx / count; + out->vy = sum.vy / count; + out->vz = sum.vz / count; +} + +void HadohoSprayVectorCalc(s32 offset, s16 spread, SVECTOR* out) { + SVECTOR in; + SVECTOR rot; + MATRIX matrix; + + in.vz = 0; + in.vx = 0; + in.vy = offset + (rand() % spread * 2 - spread); + rot.vy = 0; + rot.vx = rand() % 800 - 400; + rot.vz = rand() % 800 - 400; + RotMatrix(&rot, &matrix); + ApplyMatrixSV(&matrix, &in, out); +} + +void HadohoSpriteMatrixSetup(SVECTOR* pos, SVECTOR* rot, s16 scale, s32 offset) { + MATRIX matrix; + MATRIX rotated; + VECTOR dir; + s32 flag; + s16 i; + + for (i = 0; i < 3; i++) { + matrix.m[2][i] = 0; + matrix.m[1][i] = 0; + matrix.m[0][i] = 0; + } + SetRotMatrix(&g_BattleWorldView.m); + SetTransMatrix(&g_BattleWorldView.m); + RotTrans(pos, (VECTOR*)matrix.t, &flag); + if (offset != 0) { + VectorNormal((VECTOR*)matrix.t, &dir); + matrix.t[0] += offset * dir.vx >> 12; + matrix.t[1] += offset * dir.vy >> 12; + matrix.t[2] += offset * dir.vz >> 12; + } + matrix.m[0][0] = matrix.m[1][1] = matrix.m[2][2] = scale; + RotMatrixYXZ(rot, &rotated); + MulMatrix(&matrix, &rotated); + SetRotMatrix(&matrix); + SetTransMatrix(&matrix); +} + +// Same as BarrierDoubleBufferFlip. +static void HadohoDoubleBufferFlip(void) { + HadohoData* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + g_HadohoBufferPtr = g_HadohoPrimBuffer[effect->AnimationFrame]; + effect->AnimationFrame ^= 1; + if (g_BattleEffectCount < 2) { + effect->StartFrame = -1; + } +} + +void HadohoViewportFlashTick(void) { + HadohoData* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + D_80163C74 = func_800C4FC8(D_801D5530, D_801D5530 >> 1, 0); + if (D_80062D98 == 0) { + if (effect->AnimationFrame < 16) { + D_801D5530 += 15; + } + if (effect->AnimationFrame >= 35) { + D_801D5530 -= 15; + } + effect->AnimationFrame++; + if (effect->AnimationFrame == 50) { + effect->StartFrame = -1; + } + } +} + +void HadohoSparkSpriteTick(void) { + HadohoData* effect; + + effect = &g_BattleDetachedSlots[g_BattleDetachedCursor]; + BattleSetBillboardMatrix(&effect->Pos, 0x2800, 0); + D_801D5534.frameIndex = effect->AnimationFrame; + D_80163C74 = func_800D4D90(&D_801D5534, (u_long**)&g_cDb->unk70, 12, D_80163C74); + if (D_80062D98 == 0) { + effect->AnimationFrame++; + if (effect->AnimationFrame >= D_801D5174) { + effect->StartFrame = -1; + } + } +} + +void HadohoEmberTick(void) { + MATRIX rotated; + MATRIX matrix; + SVECTOR rot; + s32 flag; + HadohoData* effect; + s16 fade; + s16 i; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + for (i = 0; i < 3; i++) { + matrix.m[2][i] = 0; + matrix.m[1][i] = 0; + matrix.m[0][i] = 0; + } + fade = 8; + if (effect->AnimationFrame >= 12) { + fade = 20 - effect->AnimationFrame; + } + rot.vy = 0; + rot.vx = 0; + rot.vz = effect->unk14; + SetRotMatrix(&g_BattleWorldView.m); + SetTransMatrix(&g_BattleWorldView.m); + RotTrans(&effect->Pos, (VECTOR*)matrix.t, &flag); + matrix.m[0][0] = matrix.m[1][1] = matrix.m[2][2] = 0x2000; + RotMatrixYXZ(&rot, &rotated); + MulMatrix(&matrix, &rotated); + SetRotMatrix(&matrix); + SetTransMatrix(&matrix); + D_801D5540.frameIndex = effect->unk16; + D_801D5540.color.cd = fade == 8 ? 0x2C : 0x2E; + D_801D5540.color.r = D_801D5540.color.g = D_801D5540.color.b = fade << 4; + D_80163C74 = func_800D4D90(&D_801D5540, (u_long**)&g_cDb->unk70, 12, D_80163C74); + if (D_80062D98 == 0) { + effect->Pos.vx += effect->PartPos.vx; + effect->Pos.vy += effect->PartPos.vy; + effect->Pos.vz += effect->PartPos.vz; + if (effect->Pos.vy > 0) { + effect->Pos.vy = 0; + effect->PartPos.vy *= -1; + } + effect->PartPos.vy += 0x14; + effect->unk14 += 0x200; + effect->AnimationFrame++; + if (effect->AnimationFrame == 0x14) { + effect->StartFrame = -1; + } + } +} + +void HadohoRisingModelTick(void) { + MATRIX matrix; + MATRIX composed; + SVECTOR rot; + HadohoData* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + rot.vy = 0; + rot.vx = 0; + rot.vz = effect->unk14; + RotMatrix(&rot, &matrix); + ScaleMatrix(&matrix, &D_801D554C); + matrix.t[0] = effect->Pos.vx; + matrix.t[1] = effect->Pos.vy; + matrix.t[2] = effect->Pos.vz; + CompMatrix(&g_BattleWorldView.m, &matrix, &composed); + SetRotMatrix(&composed); + SetTransMatrix(&composed); + D_801D555C.color = 0x80 - effect->AnimationFrame * 6; + D_801D555C.model = D_801D556C[effect->unk16]; + g_HadohoBufferPtr = func_800D29D4(&D_801D555C, g_cDb->unk70, 12, g_HadohoBufferPtr); + if (D_80062D98 == 0) { + effect->Pos.vy -= 200; + effect->unk14 += 0x100; + effect->AnimationFrame++; + if (effect->AnimationFrame == 20) { + effect->StartFrame = -1; + } + } +} + +void HadohoGrowingModelTick(void) { + MATRIX matrix; + MATRIX composed; + VECTOR scale; + HadohoData* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + RotMatrixYXZ(&D_801D557C, &matrix); + MulMatrix0(&D_801D561C, &matrix, &matrix); + scale.vx = scale.vy = scale.vz = effect->AnimationFrame * 1500; + ScaleMatrix(&matrix, &scale); + matrix.t[0] = effect->Pos.vx; + matrix.t[1] = effect->Pos.vy; + matrix.t[2] = effect->Pos.vz; + CompMatrix(&g_BattleWorldView.m, &matrix, &composed); + SetRotMatrix(&composed); + SetTransMatrix(&composed); + SetFarColor(0, 0, 0); + D_801D5584.color = effect->AnimationFrame * 256; + g_HadohoBufferPtr = func_800D29D4(&D_801D5584, g_cDb->unk70, 12, g_HadohoBufferPtr); + if (D_80062D98 == 0) { + effect->AnimationFrame++; + if (effect->AnimationFrame == 20) { + effect->StartFrame = -1; + } + } +} + +void HadohoShrinkingModelTick(void) { + MATRIX matrix; + MATRIX composed; + VECTOR scale; + HadohoData* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + if (effect->AnimationFrame >= 3) { + RotMatrixYXZ(&D_801D5594, &matrix); + MulMatrix0(&D_801D561C, &matrix, &matrix); + scale.vx = scale.vy = scale.vz = 0x4000 - effect->AnimationFrame * 400; + ScaleMatrix(&matrix, &scale); + matrix.t[0] = effect->Pos.vx; + matrix.t[1] = effect->Pos.vy; + matrix.t[2] = effect->Pos.vz; + CompMatrix(&g_BattleWorldView.m, &matrix, &composed); + SetRotMatrix(&composed); + SetTransMatrix(&composed); + SetFarColor(0, 0, 0); + D_801D559C.color = effect->AnimationFrame * 200; + g_HadohoBufferPtr = func_800D29D4(&D_801D559C, g_cDb->unk70, 12, g_HadohoBufferPtr); + } + if (D_80062D98 == 0) { + effect->AnimationFrame++; + if (effect->AnimationFrame == 20) { + effect->StartFrame = -1; + } + } +} + +void HadohoDriftSpriteTick(void) { + HadohoData* effect; + + effect = &g_BattleDetachedSlots[g_BattleDetachedCursor]; + BattleSetBillboardMatrix(&effect->Pos, 0x4000, 0); + D_801D55AC.frameIndex = effect->AnimationFrame; + D_80163C74 = func_800D4D90(&D_801D55AC, (u_long**)&g_cDb->unk70, 12, D_80163C74); + if (D_80062D98 == 0) { + effect->Pos.vx += effect->PartPos.vx; + effect->Pos.vy += effect->PartPos.vy; + effect->Pos.vz += effect->PartPos.vz; + effect->AnimationFrame++; + if (effect->AnimationFrame >= D_801D53AC) { + effect->StartFrame = -1; + } + } +} + +void HadohoPulseSpriteTick(void) { + HadohoData* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + BattleSetBillboardMatrix(&effect->Pos, (s16)(0x1000 + ((rsin(effect->AnimationFrame * 51) << 11) >> 16 << 7)), 0); + D_801D55B8.frameIndex = effect->AnimationFrame % 2; + g_HadohoBufferPtr = func_800D4D90(&D_801D55B8, (u_long**)&g_cDb->unk70, 12, g_HadohoBufferPtr); + if (D_80062D98 == 0) { + effect->AnimationFrame++; + if (effect->AnimationFrame == 40) { + effect->StartFrame = -1; + } + } +} + +void HadohoBeamColumnTick(void) { + MATRIX matrix; + MATRIX composed; + VECTOR scale; + HadohoData* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + RotMatrixYXZ(&D_801D55D8, &matrix); + MulMatrix0(&D_801D561C, &matrix, &matrix); + scale.vx = scale.vz = 0x4000 - effect->AnimationFrame * 300; + scale.vy = effect->AnimationFrame * 900; + ScaleMatrix(&matrix, &scale); + matrix.t[0] = effect->Pos.vx; + matrix.t[1] = effect->Pos.vy; + matrix.t[2] = effect->Pos.vz; + CompMatrix(&g_BattleWorldView.m, &matrix, &composed); + SetRotMatrix(&composed); + SetTransMatrix(&composed); + SetFarColor(0, 0, 0); + D_801D55C8.color = 0x1000 - D_801D55C4 * 256; + D_801D55C8.model = D_801D1C40; + g_HadohoBufferPtr = func_800D29D4(&D_801D55C8, g_cDb->unk70, 12, g_HadohoBufferPtr); + D_801D55C8.model = D_801D2244; + g_HadohoBufferPtr = func_800D29D4(&D_801D55C8, g_cDb->unk70, 12, g_HadohoBufferPtr); + if (D_80062D98 == 0) { + if (effect->AnimationFrame >= 13) { + D_801D55C4 -= 1; + } + effect->AnimationFrame++; + if (effect->AnimationFrame == 20) { + effect->StartFrame = -1; + } + } +} + +void HadohoBeamHeadTick(void) { + MATRIX matrix; + MATRIX composed; + HadohoData* effect; + HadohoData* child; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + RotMatrixYXZ(&D_801D5610, &matrix); + MulMatrix0(&D_801D561C, &matrix, &matrix); + ScaleMatrix(&matrix, &D_801D55E4); + matrix.t[0] = effect->Pos.vx; + matrix.t[1] = effect->Pos.vy; + matrix.t[2] = effect->Pos.vz; + CompMatrix(&g_BattleWorldView.m, &matrix, &composed); + SetRotMatrix(&composed); + SetTransMatrix(&composed); + D_801D55F4.color = (u16)D_801D55E0 * 16; + D_801D55F4.model = D_801D2848; + g_HadohoBufferPtr = func_800D29D4(&D_801D55F4, g_cDb->unk70, 12, g_HadohoBufferPtr); + D_801D55F4.model = D_801D37EC; + g_HadohoBufferPtr = func_800D29D4(&D_801D55F4, g_cDb->unk70, 12, g_HadohoBufferPtr); + D_801D55F4.model = D_801D4790; + g_HadohoBufferPtr = func_800D29D4(&D_801D55F4, g_cDb->unk70, 12, g_HadohoBufferPtr); + BattleSetBillboardMatrix(&effect->Pos, 0x4000, 0); + D_801D5604.color.r = D_801D5604.color.g = D_801D5604.color.b = D_801D55E0 * 20; + D_801D5604.frameIndex = effect->AnimationFrame % 2; + g_HadohoBufferPtr = func_800D4D90(&D_801D5604, (u_long**)&g_cDb->unk70, 12, g_HadohoBufferPtr); + if (D_80062D98 == 0) { + effect->Pos.vx += effect->PartPos.vx; + effect->Pos.vy += effect->PartPos.vy; + effect->Pos.vz += effect->PartPos.vz; + if ((effect->AnimationFrame & 1) == 0) { + child = &g_BattleEffectSlots[BattleEffectRegister(HadohoShrinkingModelTick)]; + child->Pos.vx = effect->Pos.vx; + child->Pos.vy = effect->Pos.vy; + child->Pos.vz = effect->Pos.vz; + } + if (effect->Pos.vy < 0) { + child = &g_BattleEffectSlots[BattleEffectRegister(HadohoEmberTick)]; + child->Pos.vx = effect->Pos.vx; + child->Pos.vz = effect->Pos.vz; + child->Pos.vy = 0; + D_801D5618 = rand() % 4096; + child->PartPos.vx = (u32)(rcos(D_801D5618) * 15) >> 9; + child->PartPos.vz = (u32)(rsin(D_801D5618) * 15) >> 9; + child->PartPos.vy = -rand() % 300 - 50; + child->unk16 = rand() % 7; + if (effect->AnimationFrame % 3 == 0) { + child = &g_BattleEffectSlots[BattleEffectRegister(HadohoRisingModelTick)]; + child->Pos.vx = effect->Pos.vx + rand() % 4000 - 2000; + child->Pos.vz = effect->Pos.vz + rand() % 4000 - 2000; + child->Pos.vy = 0; + child->unk16 = rand() % 4; + } + } + if (effect->AnimationFrame >= 13) { + D_801D55E0 -= 1; + } + effect->AnimationFrame++; + if (effect->AnimationFrame == 20) { + effect->StartFrame = -1; + } + } +} +void HadohoMainTick(void) { + SVECTOR in; + SVECTOR rot; + MATRIX matrix; + s32 flag; + HadohoData* effect; + HadohoData* child; + s16 i; + u16* u16p; + u16 t; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + if (D_80062D98 == 0) { + if (effect->AnimationFrame == 0) { + child = &g_BattleEffectSlots[BattleEffectRegister(HadohoGrowingModelTick)]; + child->Pos.vx = effect->Pos.vx; + child->Pos.vy = effect->Pos.vy; + child->Pos.vz = effect->Pos.vz; + child = &g_BattleEffectSlots[BattleEffectRegister(HadohoPulseSpriteTick)]; + child->Pos.vx = effect->Pos.vx; + child->Pos.vy = effect->Pos.vy; + child->Pos.vz = effect->Pos.vz; + func_800BBA84(0x174, effect->unk1E, 0x40); + } + if (effect->AnimationFrame == 20) { + child = &g_BattleEffectSlots[BattleEffectRegister(HadohoBeamColumnTick)]; + child->Pos.vx = effect->Pos.vx; + child->Pos.vy = effect->Pos.vy; + child->Pos.vz = effect->Pos.vz; + child = &g_BattleEffectSlots[BattleEffectRegister(HadohoBeamHeadTick)]; + child->Pos.vx = effect->Pos.vx; + child->Pos.vy = effect->Pos.vy; + child->Pos.vz = effect->Pos.vz; + child->PartPos.vx = effect->PartPos.vx; + child->PartPos.vy = effect->PartPos.vy; + child->PartPos.vz = effect->PartPos.vz; + func_800BBA84(0x176, effect->unk1E, 0x40); + } + if (effect->AnimationFrame == 20) { + BattleEffectRegister(HadohoViewportFlashTick); + } + if (effect->AnimationFrame == 54) { + BattleFixedPointRampUpdateInit(0, 16); + } + if (effect->AnimationFrame >= 37 && effect->AnimationFrame < 44) { + for (i = 0; i < 10; i++) { + if ((D_801D563C >> i) & 1) { + child = &g_BattleDetachedSlots[BattleDetachedRegister(HadohoDriftSpriteTick)]; + BattleGetPartPosition(i, g_BattleModels[i].boneIndices[0], &child->Pos); + in.vy = 0x50; + in.vz = 0; + in.vx = 0; + rot.vx = rand() % 4096; + rot.vz = rand() % 4096; + rot.vy = 0; + RotMatrixYXZ(&rot, &matrix); + matrix.t[2] = 0; + matrix.t[1] = 0; + matrix.t[0] = 0; + SetRotMatrix(&matrix); + SetTransMatrix(&matrix); + RotTransSV(&in, &child->PartPos, &flag); + } + } + } + if (effect->AnimationFrame == 40) { + for (i = 0; i < 10; i++) { + if ((D_801D563C >> i) & 1) { + func_800D5774(i); + } + } + func_800BBA84(0xFA, -1, 0x40); + } + if (effect->AnimationFrame >= 21) { + u16p = &D_801031EA; + t = *u16p + 0x10; + *u16p = t - (effect->AnimationFrame % 2) * 32; + } + effect->AnimationFrame++; + if (effect->AnimationFrame == 75) { + effect->StartFrame = -1; + } + } +} + +void HadohoStart(s32 targetMask, s32 callbackArg) { + VECTOR vec; + SVECTOR dir; + HadohoData* effect; + + BattleEffectRegister(HadohoDoubleBufferFlip); + D_801D563C = targetMask; + effect = &g_BattleEffectSlots[BattleEffectRegister(HadohoMainTick)]; + BattleGetPartPosition(callbackArg, g_BattleModels[callbackArg].boneIndices[8], &effect->Pos); + HadohoTargetCenterCalc(targetMask, &D_801D5640); + vec.vx = dir.vx = D_801D5640.vx - effect->Pos.vx; + vec.vy = dir.vy = D_801D5640.vy - effect->Pos.vy; + vec.vz = dir.vz = D_801D5640.vz - effect->Pos.vz; + BattleMatrixFromDirection(&dir, &D_801D561C); + VectorNormal(&vec, &vec); + effect->PartPos.vx = (u32)(vec.vx * 75) >> 9; + effect->PartPos.vy = (u32)(vec.vy * 75) >> 9; + effect->PartPos.vz = (u32)(vec.vz * 75) >> 9; + effect->unk1E = callbackArg; + BattleSetLoadTimToVram(D_801B1B40, 0, 0, 0); + D_800F5B70 = D_800F5B71 = D_800F5B72 = 0; + BattleFixedPointRampUpdateInit(0x1000, 0x10); +} diff --git a/src/magic/hadoho.h b/src/magic/hadoho.h new file mode 100644 index 00000000..bb012511 --- /dev/null +++ b/src/magic/hadoho.h @@ -0,0 +1,6 @@ +#ifndef HADOHO_H +#define HADOHO_H + +#include "magic.h" + +#endif diff --git a/src/magic/re_do.c b/src/magic/re_do.c new file mode 100644 index 00000000..366f69c3 --- /dev/null +++ b/src/magic/re_do.c @@ -0,0 +1,575 @@ +//! PSYQ=3.3 CC1=2.6.3 + +#include "common.h" +#include "magic.h" +#include "re_do.h" +#include "../battle/battle.h" + +u_long* func_800C4FC8(); + +// Big Breath (大口ブレス / Oguchi Buresu). + +void ReDoStart(s32 targetMask, s32 callbackArg); + +// Primitive buffer pages, one 0xC000 page per double-buffered frame. +extern u8 g_ReDoPrimBuffer[2][0xC000]; +extern void* g_ReDoBufferPtr; + +// Only StartFrame/AnimationFrame are common to every magic overlay; the +// rest is payload this effect lays out for itself. +typedef struct { + /* 0x00 */ s16 StartFrame; + /* 0x02 */ s16 AnimationFrame; + /* 0x04 */ SVECTOR Pos; + /* 0x0C */ SVECTOR PartPos; + /* 0x14 */ s16 unk14; + /* 0x16 */ s16 unk16; + /* 0x18 */ s16 unk18; + /* 0x1A */ s16 unk1A; + /* 0x1C */ s16 unk1C; + /* 0x1E */ s16 unk1E; +} ReDoData; // size:0x20 + +extern MATRIX D_801D570C; +extern ModelRenderDesc D_801D564C; +extern ModelRenderDesc D_801D5674; +extern ModelRenderDesc D_801D568C; +extern ModelRenderDesc D_801D56B8; +extern ModelRenderDesc D_801D56E4; +extern ReDoData g_BattleEffectSlots[]; +extern ReDoData g_BattleDetachedSlots[]; +extern SVECTOR D_801D566C; +extern SVECTOR D_801D5684; +extern SVECTOR D_801D56C8; +extern SVECTOR D_801D5700; +extern SVECTOR D_801D5730; +extern SpriteRenderDesc D_801D5624; +extern SpriteRenderDesc D_801D5630; +extern SpriteRenderDesc D_801D569C; +extern SpriteRenderDesc D_801D56A8; +extern SpriteRenderDesc D_801D56F4; +extern VECTOR D_801D563C; +extern VECTOR D_801D56D4; +extern s16 g_BattleDetachedCursor; +extern s16 D_801D5620; +extern s16 D_801D56B4; +extern s16 D_801D56D0; +extern s16 D_801D5708; +extern s16 D_801D572C; +extern s32 D_801D5264; +extern s32 D_801D549C; +extern s32 D_801D1C08[]; +extern s32 D_801D220C[]; +extern s32 D_801D2810[]; +extern s32 D_801D37B4[]; +extern s32 D_801D4758[]; +extern s32* D_801D565C[]; +extern u16 D_801031EA; +extern u8 D_800F5B70; +extern u8 D_800F5B71; +extern u8 D_800F5B72; +extern u_long D_801B1B08[]; +extern u_long D_801B1B38[]; +extern void* D_80163C74; +s32 BattleDetachedRegister(void (*func)(void)); +void func_800BBA84(u16 arg0, s32 arg1, s32 arg2); +void ReDoViewportFlashTick(void); +void ReDoEmberTick(void); +void ReDoRisingModelTick(void); +void ReDoShrinkingModelTick(void); +void ReDoBeamHeadTick(void); +void ReDoMainTick(void); + +void MAGIC_ReDo(s32 targetMask, s32 callbackArg) { ReDoStart(targetMask, callbackArg); } + +void ReDoTargetCenterCalc(s16 targetMask, SVECTOR* out) { + VECTOR sum; + SVECTOR pos; + s16 i; + s16 count; + + count = 0; + sum.vx = sum.vy = sum.vz = 0; + for (i = 0; i < 10; i++) { + if ((targetMask >> i) & 1) { + BattleGetPartPosition(i, g_BattleModels[i].boneIndices[0], &pos); + count++; + sum.vx += pos.vx; + sum.vy += pos.vy; + sum.vz += pos.vz; + } + } + out->vx = sum.vx / count; + out->vy = sum.vy / count; + out->vz = sum.vz / count; +} + +void ReDoSprayVectorCalc(s32 offset, s16 spread, SVECTOR* out) { + SVECTOR in; + SVECTOR rot; + MATRIX matrix; + + in.vz = 0; + in.vx = 0; + in.vy = offset + (rand() % spread * 2 - spread); + rot.vy = 0; + rot.vx = rand() % 800 - 400; + rot.vz = rand() % 800 - 400; + RotMatrix(&rot, &matrix); + ApplyMatrixSV(&matrix, &in, out); +} + +void ReDoSpriteMatrixSetup(SVECTOR* pos, SVECTOR* rot, s16 scale, s32 offset) { + MATRIX matrix; + MATRIX rotated; + VECTOR dir; + s32 flag; + s16 i; + + for (i = 0; i < 3; i++) { + matrix.m[2][i] = 0; + matrix.m[1][i] = 0; + matrix.m[0][i] = 0; + } + SetRotMatrix(&g_BattleWorldView.m); + SetTransMatrix(&g_BattleWorldView.m); + RotTrans(pos, (VECTOR*)matrix.t, &flag); + if (offset != 0) { + VectorNormal((VECTOR*)matrix.t, &dir); + matrix.t[0] += offset * dir.vx >> 12; + matrix.t[1] += offset * dir.vy >> 12; + matrix.t[2] += offset * dir.vz >> 12; + } + matrix.m[0][0] = matrix.m[1][1] = matrix.m[2][2] = scale; + RotMatrixYXZ(rot, &rotated); + MulMatrix(&matrix, &rotated); + SetRotMatrix(&matrix); + SetTransMatrix(&matrix); +} + +// Same as BarrierDoubleBufferFlip. +static void ReDoDoubleBufferFlip(void) { + ReDoData* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + g_ReDoBufferPtr = g_ReDoPrimBuffer[effect->AnimationFrame]; + effect->AnimationFrame ^= 1; + if (g_BattleEffectCount < 2) { + effect->StartFrame = -1; + } +} + +void ReDoViewportFlashTick(void) { + ReDoData* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + D_80163C74 = func_800C4FC8(0, 0, D_801D5620); + if (D_80062D98 == 0) { + if (effect->AnimationFrame < 16) { + D_801D5620 += 15; + } + if (effect->AnimationFrame >= 35) { + D_801D5620 -= 15; + } + effect->AnimationFrame++; + if (effect->AnimationFrame == 50) { + effect->StartFrame = -1; + } + } +} + +void ReDoSparkSpriteTick(void) { + ReDoData* effect; + + effect = &g_BattleDetachedSlots[g_BattleDetachedCursor]; + BattleSetBillboardMatrix(&effect->Pos, 0x2800, 0); + D_801D5624.frameIndex = effect->AnimationFrame; + D_80163C74 = func_800D4D90(&D_801D5624, (u_long**)&g_cDb->unk70, 12, D_80163C74); + if (D_80062D98 == 0) { + effect->AnimationFrame++; + if (effect->AnimationFrame >= D_801D5264) { + effect->StartFrame = -1; + } + } +} + +void ReDoEmberTick(void) { + MATRIX rotated; + MATRIX matrix; + SVECTOR rot; + s32 flag; + ReDoData* effect; + s16 fade; + s16 i; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + for (i = 0; i < 3; i++) { + matrix.m[2][i] = 0; + matrix.m[1][i] = 0; + matrix.m[0][i] = 0; + } + fade = 8; + if (effect->AnimationFrame >= 12) { + fade = 20 - effect->AnimationFrame; + } + rot.vy = 0; + rot.vx = 0; + rot.vz = effect->unk14; + SetRotMatrix(&g_BattleWorldView.m); + SetTransMatrix(&g_BattleWorldView.m); + RotTrans(&effect->Pos, (VECTOR*)matrix.t, &flag); + matrix.m[0][0] = matrix.m[1][1] = matrix.m[2][2] = 0x2000; + RotMatrixYXZ(&rot, &rotated); + MulMatrix(&matrix, &rotated); + SetRotMatrix(&matrix); + SetTransMatrix(&matrix); + D_801D5630.frameIndex = effect->unk16; + D_801D5630.color.cd = fade == 8 ? 0x2C : 0x2E; + D_801D5630.color.r = D_801D5630.color.g = D_801D5630.color.b = fade << 4; + D_80163C74 = func_800D4D90(&D_801D5630, (u_long**)&g_cDb->unk70, 12, D_80163C74); + if (D_80062D98 == 0) { + effect->Pos.vx += effect->PartPos.vx; + effect->Pos.vy += effect->PartPos.vy; + effect->Pos.vz += effect->PartPos.vz; + if (effect->Pos.vy > 0) { + effect->Pos.vy = 0; + effect->PartPos.vy *= -1; + } + effect->PartPos.vy += 0x14; + effect->unk14 += 0x200; + effect->AnimationFrame++; + if (effect->AnimationFrame == 0x14) { + effect->StartFrame = -1; + } + } +} + +void ReDoRisingModelTick(void) { + MATRIX matrix; + MATRIX composed; + SVECTOR rot; + ReDoData* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + rot.vy = 0; + rot.vx = 0; + rot.vz = effect->unk14; + RotMatrix(&rot, &matrix); + ScaleMatrix(&matrix, &D_801D563C); + matrix.t[0] = effect->Pos.vx; + matrix.t[1] = effect->Pos.vy; + matrix.t[2] = effect->Pos.vz; + CompMatrix(&g_BattleWorldView.m, &matrix, &composed); + SetRotMatrix(&composed); + SetTransMatrix(&composed); + D_801D564C.color = 0x80 - effect->AnimationFrame * 6; + D_801D564C.model = D_801D565C[effect->unk16]; + g_ReDoBufferPtr = func_800D29D4(&D_801D564C, g_cDb->unk70, 12, g_ReDoBufferPtr); + if (D_80062D98 == 0) { + effect->Pos.vy -= 200; + effect->unk14 += 0x100; + effect->AnimationFrame++; + if (effect->AnimationFrame == 20) { + effect->StartFrame = -1; + } + } +} + +void ReDoGrowingModelTick(void) { + MATRIX matrix; + MATRIX composed; + VECTOR scale; + ReDoData* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + RotMatrixYXZ(&D_801D566C, &matrix); + MulMatrix0(&D_801D570C, &matrix, &matrix); + scale.vx = scale.vy = scale.vz = effect->AnimationFrame * 1500; + ScaleMatrix(&matrix, &scale); + matrix.t[0] = effect->Pos.vx; + matrix.t[1] = effect->Pos.vy; + matrix.t[2] = effect->Pos.vz; + CompMatrix(&g_BattleWorldView.m, &matrix, &composed); + SetRotMatrix(&composed); + SetTransMatrix(&composed); + SetFarColor(0, 0, 0); + D_801D5674.color = effect->AnimationFrame * 256; + g_ReDoBufferPtr = func_800D29D4(&D_801D5674, g_cDb->unk70, 12, g_ReDoBufferPtr); + if (D_80062D98 == 0) { + effect->AnimationFrame++; + if (effect->AnimationFrame == 20) { + effect->StartFrame = -1; + } + } +} + +void ReDoShrinkingModelTick(void) { + MATRIX matrix; + MATRIX composed; + VECTOR scale; + ReDoData* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + if (effect->AnimationFrame >= 3) { + RotMatrixYXZ(&D_801D5684, &matrix); + MulMatrix0(&D_801D570C, &matrix, &matrix); + scale.vx = scale.vy = scale.vz = 0x4000 - effect->AnimationFrame * 400; + ScaleMatrix(&matrix, &scale); + matrix.t[0] = effect->Pos.vx; + matrix.t[1] = effect->Pos.vy; + matrix.t[2] = effect->Pos.vz; + CompMatrix(&g_BattleWorldView.m, &matrix, &composed); + SetRotMatrix(&composed); + SetTransMatrix(&composed); + SetFarColor(0, 0, 0); + D_801D568C.color = effect->AnimationFrame * 200; + g_ReDoBufferPtr = func_800D29D4(&D_801D568C, g_cDb->unk70, 12, g_ReDoBufferPtr); + } + if (D_80062D98 == 0) { + effect->AnimationFrame++; + if (effect->AnimationFrame == 20) { + effect->StartFrame = -1; + } + } +} + +void ReDoDriftSpriteTick(void) { + ReDoData* effect; + + effect = &g_BattleDetachedSlots[g_BattleDetachedCursor]; + BattleSetBillboardMatrix(&effect->Pos, 0x4000, 0); + D_801D569C.frameIndex = effect->AnimationFrame; + D_80163C74 = func_800D4D90(&D_801D569C, (u_long**)&g_cDb->unk70, 12, D_80163C74); + if (D_80062D98 == 0) { + effect->Pos.vx += effect->PartPos.vx; + effect->Pos.vy += effect->PartPos.vy; + effect->Pos.vz += effect->PartPos.vz; + effect->AnimationFrame++; + if (effect->AnimationFrame >= D_801D549C) { + effect->StartFrame = -1; + } + } +} + +void ReDoPulseSpriteTick(void) { + ReDoData* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + BattleSetBillboardMatrix( + &effect->Pos, (s16)(0x1000 + ((rsin(effect->AnimationFrame * 51) << 11) >> 16 << 7)), -500); + D_801D56A8.frameIndex = effect->AnimationFrame % 2; + g_ReDoBufferPtr = func_800D4D90(&D_801D56A8, (u_long**)&g_cDb->unk70, 12, g_ReDoBufferPtr); + if (D_80062D98 == 0) { + effect->AnimationFrame++; + if (effect->AnimationFrame == 40) { + effect->StartFrame = -1; + } + } +} + +void ReDoBeamColumnTick(void) { + MATRIX matrix; + MATRIX composed; + VECTOR scale; + ReDoData* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + RotMatrixYXZ(&D_801D56C8, &matrix); + MulMatrix0(&D_801D570C, &matrix, &matrix); + scale.vx = scale.vz = 0x4000 - effect->AnimationFrame * 300; + scale.vy = effect->AnimationFrame * 900; + ScaleMatrix(&matrix, &scale); + matrix.t[0] = effect->Pos.vx; + matrix.t[1] = effect->Pos.vy; + matrix.t[2] = effect->Pos.vz; + CompMatrix(&g_BattleWorldView.m, &matrix, &composed); + SetRotMatrix(&composed); + SetTransMatrix(&composed); + SetFarColor(0, 0, 0); + D_801D56B8.color = 0x1000 - D_801D56B4 * 256; + D_801D56B8.model = D_801D1C08; + g_ReDoBufferPtr = func_800D29D4(&D_801D56B8, g_cDb->unk70, 12, g_ReDoBufferPtr); + D_801D56B8.model = D_801D220C; + g_ReDoBufferPtr = func_800D29D4(&D_801D56B8, g_cDb->unk70, 12, g_ReDoBufferPtr); + if (D_80062D98 == 0) { + if (effect->AnimationFrame >= 13) { + D_801D56B4 -= 1; + } + effect->AnimationFrame++; + if (effect->AnimationFrame == 20) { + effect->StartFrame = -1; + } + } +} + +void ReDoBeamHeadTick(void) { + MATRIX matrix; + MATRIX composed; + ReDoData* effect; + ReDoData* child; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + RotMatrixYXZ(&D_801D5700, &matrix); + MulMatrix0(&D_801D570C, &matrix, &matrix); + ScaleMatrix(&matrix, &D_801D56D4); + matrix.t[0] = effect->Pos.vx; + matrix.t[1] = effect->Pos.vy; + matrix.t[2] = effect->Pos.vz; + CompMatrix(&g_BattleWorldView.m, &matrix, &composed); + SetRotMatrix(&composed); + SetTransMatrix(&composed); + D_801D56E4.color = (u16)D_801D56D0 * 16; + D_801D56E4.model = D_801D2810; + g_ReDoBufferPtr = func_800D29D4(&D_801D56E4, g_cDb->unk70, 12, g_ReDoBufferPtr); + D_801D56E4.model = D_801D37B4; + g_ReDoBufferPtr = func_800D29D4(&D_801D56E4, g_cDb->unk70, 12, g_ReDoBufferPtr); + D_801D56E4.model = D_801D4758; + g_ReDoBufferPtr = func_800D29D4(&D_801D56E4, g_cDb->unk70, 12, g_ReDoBufferPtr); + BattleSetBillboardMatrix(&effect->Pos, 0x4000, 0); + D_801D56F4.color.r = D_801D56F4.color.g = D_801D56F4.color.b = D_801D56D0 * 20; + D_801D56F4.frameIndex = effect->AnimationFrame % 2; + g_ReDoBufferPtr = func_800D4D90(&D_801D56F4, (u_long**)&g_cDb->unk70, 12, g_ReDoBufferPtr); + if (D_80062D98 == 0) { + effect->Pos.vx += effect->PartPos.vx; + effect->Pos.vy += effect->PartPos.vy; + effect->Pos.vz += effect->PartPos.vz; + if ((effect->AnimationFrame & 1) == 0) { + child = &g_BattleEffectSlots[BattleEffectRegister(ReDoShrinkingModelTick)]; + child->Pos.vx = effect->Pos.vx; + child->Pos.vy = effect->Pos.vy; + child->Pos.vz = effect->Pos.vz; + } + if (effect->Pos.vy < 0) { + child = &g_BattleEffectSlots[BattleEffectRegister(ReDoEmberTick)]; + child->Pos.vx = effect->Pos.vx; + child->Pos.vz = effect->Pos.vz; + child->Pos.vy = 0; + D_801D5708 = rand() % 4096; + child->PartPos.vx = (u32)(rcos(D_801D5708) * 15) >> 9; + child->PartPos.vz = (u32)(rsin(D_801D5708) * 15) >> 9; + child->PartPos.vy = -rand() % 300 - 50; + child->unk16 = rand() % 7; + if (effect->AnimationFrame % 3 == 0) { + child = &g_BattleEffectSlots[BattleEffectRegister(ReDoRisingModelTick)]; + child->Pos.vx = effect->Pos.vx + rand() % 4000 - 2000; + child->Pos.vz = effect->Pos.vz + rand() % 4000 - 2000; + child->Pos.vy = 0; + child->unk16 = rand() % 4; + } + } + if (effect->AnimationFrame >= 13) { + D_801D56D0 -= 1; + } + effect->AnimationFrame++; + if (effect->AnimationFrame == 20) { + effect->StartFrame = -1; + } + } +} + +void ReDoMainTick(void) { + SVECTOR in; + SVECTOR rot; + MATRIX matrix; + s32 flag; + ReDoData* effect; + ReDoData* child; + s16 i; + u16* u16p; + u16 t; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + if (D_80062D98 == 0) { + if (effect->AnimationFrame == 4) { + BattleGetPartPosition(effect->unk1E, g_BattleModels[effect->unk1E].boneIndices[8], &effect->Pos); + in.vx = D_801D5730.vx - effect->Pos.vx; + in.vy = D_801D5730.vy - effect->Pos.vy; + in.vz = D_801D5730.vz - effect->Pos.vz; + BattleMatrixFromDirection(&in, &D_801D570C); + VectorNormalSS(&in, &in); + effect->PartPos.vx = in.vx * 75 >> 9; + effect->PartPos.vy = in.vy * 75 >> 9; + effect->PartPos.vz = in.vz * 75 >> 9; + child = &g_BattleEffectSlots[BattleEffectRegister(ReDoGrowingModelTick)]; + child->Pos.vx = effect->Pos.vx; + child->Pos.vy = effect->Pos.vy; + child->Pos.vz = effect->Pos.vz; + child = &g_BattleEffectSlots[BattleEffectRegister(ReDoPulseSpriteTick)]; + child->Pos.vx = effect->Pos.vx; + child->Pos.vy = effect->Pos.vy; + child->Pos.vz = effect->Pos.vz; + func_800BBA84(0x174, effect->unk1E, 0x40); + } + if (effect->AnimationFrame == 20) { + child = &g_BattleEffectSlots[BattleEffectRegister(ReDoBeamColumnTick)]; + child->Pos.vx = effect->Pos.vx; + child->Pos.vy = effect->Pos.vy; + child->Pos.vz = effect->Pos.vz; + child = &g_BattleEffectSlots[BattleEffectRegister(ReDoBeamHeadTick)]; + child->Pos.vx = effect->Pos.vx; + child->Pos.vy = effect->Pos.vy; + child->Pos.vz = effect->Pos.vz; + child->PartPos.vx = effect->PartPos.vx; + child->PartPos.vy = effect->PartPos.vy; + child->PartPos.vz = effect->PartPos.vz; + func_800BBA84(0x164, effect->unk1E, 0x40); + } + if (effect->AnimationFrame == 20) { + BattleEffectRegister(ReDoViewportFlashTick); + } + if (effect->AnimationFrame == 54) { + BattleFixedPointRampUpdateInit(0, 16); + } + if (effect->AnimationFrame >= 37 && effect->AnimationFrame < 44) { + for (i = 0; i < 10; i++) { + if ((D_801D572C >> i) & 1) { + child = &g_BattleDetachedSlots[BattleDetachedRegister(ReDoDriftSpriteTick)]; + BattleGetPartPosition(i, g_BattleModels[i].boneIndices[0], &child->Pos); + in.vy = 0x50; + in.vz = 0; + in.vx = 0; + rot.vx = rand() % 4096; + rot.vz = rand() % 4096; + rot.vy = 0; + RotMatrixYXZ(&rot, &matrix); + matrix.t[2] = 0; + matrix.t[1] = 0; + matrix.t[0] = 0; + SetRotMatrix(&matrix); + SetTransMatrix(&matrix); + RotTransSV(&in, &child->PartPos, &flag); + } + } + } + if (effect->AnimationFrame == 40) { + for (i = 0; i < 10; i++) { + if ((D_801D572C >> i) & 1) { + func_800D5774(i); + } + } + } + if (effect->AnimationFrame >= 21) { + u16p = &D_801031EA; + t = *u16p + 0x10; + *u16p = t - (effect->AnimationFrame % 2) * 32; + } + effect->AnimationFrame++; + if (effect->AnimationFrame == 70) { + effect->StartFrame = -1; + } + } +} + +void ReDoStart(s32 targetMask, s32 callbackArg) { + // pad0 and pad1 are unused; they only reproduce the original 0x38 stack frame. + VECTOR pad0; + SVECTOR pad1; + + BattleEffectRegister(ReDoDoubleBufferFlip); + D_801D572C = targetMask; + g_BattleEffectSlots[BattleEffectRegister(ReDoMainTick)].unk1E = callbackArg; + ReDoTargetCenterCalc(targetMask, &D_801D5730); + BattleSetLoadTimToVram(D_801B1B08, 0, 0, 0); + D_800F5B70 = D_800F5B71 = D_800F5B72 = 0; + BattleFixedPointRampUpdateInit(0x1000, 0x10); +} diff --git a/src/magic/re_do.h b/src/magic/re_do.h new file mode 100644 index 00000000..7a8f41f8 --- /dev/null +++ b/src/magic/re_do.h @@ -0,0 +1,6 @@ +#ifndef RE_DO_H +#define RE_DO_H + +#include "magic.h" + +#endif diff --git a/src/magic/shaku.c b/src/magic/shaku.c new file mode 100644 index 00000000..beacaaa2 --- /dev/null +++ b/src/magic/shaku.c @@ -0,0 +1,575 @@ +//! PSYQ=3.3 CC1=2.6.3 + +#include "common.h" +#include "magic.h" +#include "shaku.h" +#include "../battle/battle.h" + +u_long* func_800C4FC8(); + +// Effect shared by Wave Artillery (波動砲) and Golem Laser (ゴーレムレーザー). + +void ShakuStart(s32 targetMask, s32 callbackArg); + +// Primitive buffer pages, one 0xC000 page per double-buffered frame. +extern u8 g_ShakuPrimBuffer[2][0xC000]; +extern void* g_ShakuBufferPtr; + +// Only StartFrame/AnimationFrame are common to every magic overlay; the +// rest is payload this effect lays out for itself. +typedef struct { + /* 0x00 */ s16 StartFrame; + /* 0x02 */ s16 AnimationFrame; + /* 0x04 */ SVECTOR Pos; + /* 0x0C */ SVECTOR PartPos; + /* 0x14 */ s16 unk14; + /* 0x16 */ s16 unk16; + /* 0x18 */ s16 unk18; + /* 0x1A */ s16 unk1A; + /* 0x1C */ s16 unk1C; + /* 0x1E */ s16 unk1E; +} ShakuData; // size:0x20 + +extern MATRIX D_801D573C; +extern ModelRenderDesc D_801D567C; +extern ModelRenderDesc D_801D56A4; +extern ModelRenderDesc D_801D56BC; +extern ModelRenderDesc D_801D56E8; +extern ModelRenderDesc D_801D5714; +extern SVECTOR D_801D569C; +extern SVECTOR D_801D56B4; +extern SVECTOR D_801D56F8; +extern SVECTOR D_801D5730; +extern SVECTOR D_801D5760; +extern SpriteRenderDesc D_801D5654; +extern SpriteRenderDesc D_801D5660; +extern SpriteRenderDesc D_801D56CC; +extern SpriteRenderDesc D_801D56D8; +extern SpriteRenderDesc D_801D5724; +extern VECTOR D_801D566C; +extern VECTOR D_801D5704; +extern ShakuData g_BattleEffectSlots[]; +extern ShakuData g_BattleDetachedSlots[]; +extern s16 g_BattleDetachedCursor; +extern s16 D_801D5650; +extern s16 D_801D56E4; +extern s16 D_801D5700; +extern s16 D_801D5738; +extern s16 D_801D575C; +extern s32 D_801D5294; +extern s32 D_801D54CC; +extern s32 D_801D1C38[]; +extern s32 D_801D223C[]; +extern s32 D_801D2840[]; +extern s32 D_801D37E4[]; +extern s32 D_801D4788[]; +extern s32* D_801D568C[]; +extern u16 D_801031EA; +extern u8 D_800F5B70; +extern u8 D_800F5B71; +extern u8 D_800F5B72; +extern u_long D_801B1B38[]; +extern void* D_80163C74; +s32 BattleDetachedRegister(void (*func)(void)); +void func_800BBA84(u16 arg0, s32 arg1, s32 arg2); +void ShakuViewportFlashTick(void); +void ShakuEmberTick(void); +void ShakuRisingModelTick(void); +void ShakuShrinkingModelTick(void); +void ShakuBeamHeadTick(void); +void ShakuMainTick(void); + +void MAGIC_Shaku(s32 targetMask, s32 callbackArg) { ShakuStart(targetMask, callbackArg); } + +void ShakuTargetCenterCalc(s16 targetMask, SVECTOR* out) { + VECTOR sum; + SVECTOR pos; + s16 i; + s16 count; + + count = 0; + sum.vx = sum.vy = sum.vz = 0; + for (i = 0; i < 10; i++) { + if ((targetMask >> i) & 1) { + BattleGetPartPosition(i, g_BattleModels[i].boneIndices[0], &pos); + count++; + sum.vx += pos.vx; + sum.vy += pos.vy; + sum.vz += pos.vz; + } + } + out->vx = sum.vx / count; + out->vy = sum.vy / count; + out->vz = sum.vz / count; +} + +void ShakuSprayVectorCalc(s32 offset, s16 spread, SVECTOR* out) { + SVECTOR in; + SVECTOR rot; + MATRIX matrix; + + in.vz = 0; + in.vx = 0; + in.vy = offset + (rand() % spread * 2 - spread); + rot.vy = 0; + rot.vx = rand() % 800 - 400; + rot.vz = rand() % 800 - 400; + RotMatrix(&rot, &matrix); + ApplyMatrixSV(&matrix, &in, out); +} + +void ShakuSpriteMatrixSetup(SVECTOR* pos, SVECTOR* rot, s16 scale, s32 offset) { + MATRIX matrix; + MATRIX rotated; + VECTOR dir; + s32 flag; + s16 i; + + for (i = 0; i < 3; i++) { + matrix.m[2][i] = 0; + matrix.m[1][i] = 0; + matrix.m[0][i] = 0; + } + SetRotMatrix(&g_BattleWorldView.m); + SetTransMatrix(&g_BattleWorldView.m); + RotTrans(pos, (VECTOR*)matrix.t, &flag); + if (offset != 0) { + VectorNormal((VECTOR*)matrix.t, &dir); + matrix.t[0] += offset * dir.vx >> 12; + matrix.t[1] += offset * dir.vy >> 12; + matrix.t[2] += offset * dir.vz >> 12; + } + matrix.m[0][0] = matrix.m[1][1] = matrix.m[2][2] = scale; + RotMatrixYXZ(rot, &rotated); + MulMatrix(&matrix, &rotated); + SetRotMatrix(&matrix); + SetTransMatrix(&matrix); +} + +// Same as BarrierDoubleBufferFlip. +static void ShakuDoubleBufferFlip(void) { + ShakuData* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + g_ShakuBufferPtr = g_ShakuPrimBuffer[effect->AnimationFrame]; + effect->AnimationFrame ^= 1; + if (g_BattleEffectCount < 2) { + effect->StartFrame = -1; + } +} + +void ShakuViewportFlashTick(void) { + ShakuData* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + D_80163C74 = func_800C4FC8(D_801D5650, 0, 0); + if (D_80062D98 == 0) { + if (effect->AnimationFrame < 16) { + D_801D5650 += 15; + } + if (effect->AnimationFrame >= 35) { + D_801D5650 -= 15; + } + effect->AnimationFrame++; + if (effect->AnimationFrame == 50) { + effect->StartFrame = -1; + } + } +} + +void ShakuSparkSpriteTick(void) { + ShakuData* effect; + + effect = &g_BattleDetachedSlots[g_BattleDetachedCursor]; + BattleSetBillboardMatrix(&effect->Pos, 0x2800, 0); + D_801D5654.frameIndex = effect->AnimationFrame; + D_80163C74 = func_800D4D90(&D_801D5654, (u_long**)&g_cDb->unk70, 12, D_80163C74); + if (D_80062D98 == 0) { + effect->AnimationFrame++; + if (effect->AnimationFrame >= D_801D5294) { + effect->StartFrame = -1; + } + } +} + +void ShakuEmberTick(void) { + MATRIX rotated; + MATRIX matrix; + SVECTOR rot; + s32 flag; + ShakuData* effect; + s16 fade; + s16 i; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + for (i = 0; i < 3; i++) { + matrix.m[2][i] = 0; + matrix.m[1][i] = 0; + matrix.m[0][i] = 0; + } + fade = 8; + if (effect->AnimationFrame >= 12) { + fade = 20 - effect->AnimationFrame; + } + rot.vy = 0; + rot.vx = 0; + rot.vz = effect->unk14; + SetRotMatrix(&g_BattleWorldView.m); + SetTransMatrix(&g_BattleWorldView.m); + RotTrans(&effect->Pos, (VECTOR*)matrix.t, &flag); + matrix.m[0][0] = matrix.m[1][1] = matrix.m[2][2] = 0x2000; + RotMatrixYXZ(&rot, &rotated); + MulMatrix(&matrix, &rotated); + SetRotMatrix(&matrix); + SetTransMatrix(&matrix); + D_801D5660.frameIndex = effect->unk16; + D_801D5660.color.cd = fade == 8 ? 0x2C : 0x2E; + D_801D5660.color.r = D_801D5660.color.g = D_801D5660.color.b = fade << 4; + D_80163C74 = func_800D4D90(&D_801D5660, (u_long**)&g_cDb->unk70, 12, D_80163C74); + if (D_80062D98 == 0) { + effect->Pos.vx += effect->PartPos.vx; + effect->Pos.vy += effect->PartPos.vy; + effect->Pos.vz += effect->PartPos.vz; + if (effect->Pos.vy > 0) { + effect->Pos.vy = 0; + effect->PartPos.vy *= -1; + } + effect->PartPos.vy += 0x14; + effect->unk14 += 0x200; + effect->AnimationFrame++; + if (effect->AnimationFrame == 0x14) { + effect->StartFrame = -1; + } + } +} + +void ShakuRisingModelTick(void) { + MATRIX matrix; + MATRIX composed; + SVECTOR rot; + ShakuData* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + rot.vy = 0; + rot.vx = 0; + rot.vz = effect->unk14; + RotMatrix(&rot, &matrix); + ScaleMatrix(&matrix, &D_801D566C); + matrix.t[0] = effect->Pos.vx; + matrix.t[1] = effect->Pos.vy; + matrix.t[2] = effect->Pos.vz; + CompMatrix(&g_BattleWorldView.m, &matrix, &composed); + SetRotMatrix(&composed); + SetTransMatrix(&composed); + D_801D567C.color = 0x80 - effect->AnimationFrame * 6; + D_801D567C.model = D_801D568C[effect->unk16]; + g_ShakuBufferPtr = func_800D29D4(&D_801D567C, g_cDb->unk70, 12, g_ShakuBufferPtr); + if (D_80062D98 == 0) { + effect->Pos.vy -= 200; + effect->unk14 += 0x100; + effect->AnimationFrame++; + if (effect->AnimationFrame == 20) { + effect->StartFrame = -1; + } + } +} + +void ShakuGrowingModelTick(void) { + MATRIX matrix; + MATRIX composed; + VECTOR scale; + ShakuData* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + RotMatrixYXZ(&D_801D569C, &matrix); + MulMatrix0(&D_801D573C, &matrix, &matrix); + scale.vx = scale.vy = scale.vz = effect->AnimationFrame * 1500; + ScaleMatrix(&matrix, &scale); + matrix.t[0] = effect->Pos.vx; + matrix.t[1] = effect->Pos.vy; + matrix.t[2] = effect->Pos.vz; + CompMatrix(&g_BattleWorldView.m, &matrix, &composed); + SetRotMatrix(&composed); + SetTransMatrix(&composed); + SetFarColor(0, 0, 0); + D_801D56A4.color = effect->AnimationFrame * 256; + g_ShakuBufferPtr = func_800D29D4(&D_801D56A4, g_cDb->unk70, 12, g_ShakuBufferPtr); + if (D_80062D98 == 0) { + effect->AnimationFrame++; + if (effect->AnimationFrame == 20) { + effect->StartFrame = -1; + } + } +} + +void ShakuShrinkingModelTick(void) { + MATRIX matrix; + MATRIX composed; + VECTOR scale; + ShakuData* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + if (effect->AnimationFrame >= 3) { + RotMatrixYXZ(&D_801D56B4, &matrix); + MulMatrix0(&D_801D573C, &matrix, &matrix); + scale.vx = scale.vy = scale.vz = 0x4000 - effect->AnimationFrame * 400; + ScaleMatrix(&matrix, &scale); + matrix.t[0] = effect->Pos.vx; + matrix.t[1] = effect->Pos.vy; + matrix.t[2] = effect->Pos.vz; + CompMatrix(&g_BattleWorldView.m, &matrix, &composed); + SetRotMatrix(&composed); + SetTransMatrix(&composed); + SetFarColor(0, 0, 0); + D_801D56BC.color = effect->AnimationFrame * 200; + g_ShakuBufferPtr = func_800D29D4(&D_801D56BC, g_cDb->unk70, 12, g_ShakuBufferPtr); + } + if (D_80062D98 == 0) { + effect->AnimationFrame++; + if (effect->AnimationFrame == 20) { + effect->StartFrame = -1; + } + } +} + +void ShakuDriftSpriteTick(void) { + ShakuData* effect; + + effect = &g_BattleDetachedSlots[g_BattleDetachedCursor]; + BattleSetBillboardMatrix(&effect->Pos, 0x4000, 0); + D_801D56CC.frameIndex = effect->AnimationFrame; + D_80163C74 = func_800D4D90(&D_801D56CC, (u_long**)&g_cDb->unk70, 12, D_80163C74); + if (D_80062D98 == 0) { + effect->Pos.vx += effect->PartPos.vx; + effect->Pos.vy += effect->PartPos.vy; + effect->Pos.vz += effect->PartPos.vz; + effect->AnimationFrame++; + if (effect->AnimationFrame >= D_801D54CC) { + effect->StartFrame = -1; + } + } +} + +void ShakuPulseSpriteTick(void) { + ShakuData* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + BattleSetBillboardMatrix(&effect->Pos, (s16)(0x1000 + ((rsin(effect->AnimationFrame * 51) << 11) >> 16 << 7)), 0); + D_801D56D8.frameIndex = effect->AnimationFrame % 2; + g_ShakuBufferPtr = func_800D4D90(&D_801D56D8, (u_long**)&g_cDb->unk70, 12, g_ShakuBufferPtr); + if (D_80062D98 == 0) { + effect->AnimationFrame++; + if (effect->AnimationFrame == 40) { + effect->StartFrame = -1; + } + } +} + +void ShakuBeamColumnTick(void) { + MATRIX matrix; + MATRIX composed; + VECTOR scale; + ShakuData* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + RotMatrixYXZ(&D_801D56F8, &matrix); + MulMatrix0(&D_801D573C, &matrix, &matrix); + scale.vx = scale.vz = 0x4000 - effect->AnimationFrame * 300; + scale.vy = effect->AnimationFrame * 900; + ScaleMatrix(&matrix, &scale); + matrix.t[0] = effect->Pos.vx; + matrix.t[1] = effect->Pos.vy; + matrix.t[2] = effect->Pos.vz; + CompMatrix(&g_BattleWorldView.m, &matrix, &composed); + SetRotMatrix(&composed); + SetTransMatrix(&composed); + SetFarColor(0, 0, 0); + D_801D56E8.color = 0x1000 - D_801D56E4 * 256; + D_801D56E8.model = D_801D1C38; + g_ShakuBufferPtr = func_800D29D4(&D_801D56E8, g_cDb->unk70, 12, g_ShakuBufferPtr); + D_801D56E8.model = D_801D223C; + g_ShakuBufferPtr = func_800D29D4(&D_801D56E8, g_cDb->unk70, 12, g_ShakuBufferPtr); + if (D_80062D98 == 0) { + if (effect->AnimationFrame >= 13) { + D_801D56E4 -= 1; + } + effect->AnimationFrame++; + if (effect->AnimationFrame == 20) { + effect->StartFrame = -1; + } + } +} + +void ShakuBeamHeadTick(void) { + MATRIX matrix; + MATRIX composed; + ShakuData* effect; + ShakuData* child; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + RotMatrixYXZ(&D_801D5730, &matrix); + MulMatrix0(&D_801D573C, &matrix, &matrix); + ScaleMatrix(&matrix, &D_801D5704); + matrix.t[0] = effect->Pos.vx; + matrix.t[1] = effect->Pos.vy; + matrix.t[2] = effect->Pos.vz; + CompMatrix(&g_BattleWorldView.m, &matrix, &composed); + SetRotMatrix(&composed); + SetTransMatrix(&composed); + D_801D5714.color = (u16)D_801D5700 * 16; + D_801D5714.model = D_801D2840; + g_ShakuBufferPtr = func_800D29D4(&D_801D5714, g_cDb->unk70, 12, g_ShakuBufferPtr); + D_801D5714.model = D_801D37E4; + g_ShakuBufferPtr = func_800D29D4(&D_801D5714, g_cDb->unk70, 12, g_ShakuBufferPtr); + D_801D5714.model = D_801D4788; + g_ShakuBufferPtr = func_800D29D4(&D_801D5714, g_cDb->unk70, 12, g_ShakuBufferPtr); + BattleSetBillboardMatrix(&effect->Pos, 0x4000, 0); + D_801D5724.color.r = D_801D5724.color.g = D_801D5724.color.b = D_801D5700 * 20; + D_801D5724.frameIndex = effect->AnimationFrame % 2; + g_ShakuBufferPtr = func_800D4D90(&D_801D5724, (u_long**)&g_cDb->unk70, 12, g_ShakuBufferPtr); + if (D_80062D98 == 0) { + effect->Pos.vx += effect->PartPos.vx; + effect->Pos.vy += effect->PartPos.vy; + effect->Pos.vz += effect->PartPos.vz; + if ((effect->AnimationFrame & 1) == 0) { + child = &g_BattleEffectSlots[BattleEffectRegister(ShakuShrinkingModelTick)]; + child->Pos.vx = effect->Pos.vx; + child->Pos.vy = effect->Pos.vy; + child->Pos.vz = effect->Pos.vz; + } + if (effect->Pos.vy < 0) { + child = &g_BattleEffectSlots[BattleEffectRegister(ShakuEmberTick)]; + child->Pos.vx = effect->Pos.vx; + child->Pos.vz = effect->Pos.vz; + child->Pos.vy = 0; + D_801D5738 = rand() % 4096; + child->PartPos.vx = (u32)(rcos(D_801D5738) * 15) >> 9; + child->PartPos.vz = (u32)(rsin(D_801D5738) * 15) >> 9; + child->PartPos.vy = -rand() % 300 - 50; + child->unk16 = rand() % 7; + if (effect->AnimationFrame % 3 == 0) { + child = &g_BattleEffectSlots[BattleEffectRegister(ShakuRisingModelTick)]; + child->Pos.vx = effect->Pos.vx + rand() % 4000 - 2000; + child->Pos.vz = effect->Pos.vz + rand() % 4000 - 2000; + child->Pos.vy = 0; + child->unk16 = rand() % 4; + } + } + if (effect->AnimationFrame >= 13) { + D_801D5700 -= 1; + } + effect->AnimationFrame++; + if (effect->AnimationFrame == 20) { + effect->StartFrame = -1; + } + } +} + +void ShakuMainTick(void) { + SVECTOR in; + SVECTOR rot; + MATRIX matrix; + s32 flag; + ShakuData* effect; + ShakuData* child; + s16 i; + u16* u16p; + u16 t; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + if (D_80062D98 == 0) { + if (effect->AnimationFrame == 0) { + child = &g_BattleEffectSlots[BattleEffectRegister(ShakuGrowingModelTick)]; + child->Pos.vx = effect->Pos.vx; + child->Pos.vy = effect->Pos.vy; + child->Pos.vz = effect->Pos.vz; + child = &g_BattleEffectSlots[BattleEffectRegister(ShakuPulseSpriteTick)]; + child->Pos.vx = effect->Pos.vx; + child->Pos.vy = effect->Pos.vy; + child->Pos.vz = effect->Pos.vz; + func_800BBA84(0x174, effect->unk1E, 0x40); + } + if (effect->AnimationFrame == 20) { + child = &g_BattleEffectSlots[BattleEffectRegister(ShakuBeamColumnTick)]; + child->Pos.vx = effect->Pos.vx; + child->Pos.vy = effect->Pos.vy; + child->Pos.vz = effect->Pos.vz; + child = &g_BattleEffectSlots[BattleEffectRegister(ShakuBeamHeadTick)]; + child->Pos.vx = effect->Pos.vx; + child->Pos.vy = effect->Pos.vy; + child->Pos.vz = effect->Pos.vz; + child->PartPos.vx = effect->PartPos.vx; + child->PartPos.vy = effect->PartPos.vy; + child->PartPos.vz = effect->PartPos.vz; + func_800BBA84(0x176, effect->unk1E, 0x40); + } + if (effect->AnimationFrame == 20) { + BattleEffectRegister(ShakuViewportFlashTick); + } + if (effect->AnimationFrame == 54) { + BattleFixedPointRampUpdateInit(0, 16); + } + if (effect->AnimationFrame >= 37 && effect->AnimationFrame < 44) { + for (i = 0; i < 10; i++) { + if ((D_801D575C >> i) & 1) { + child = &g_BattleDetachedSlots[BattleDetachedRegister(ShakuDriftSpriteTick)]; + BattleGetPartPosition(i, g_BattleModels[i].boneIndices[0], &child->Pos); + in.vy = 0x50; + in.vz = 0; + in.vx = 0; + rot.vx = rand() % 4096; + rot.vz = rand() % 4096; + rot.vy = 0; + RotMatrixYXZ(&rot, &matrix); + matrix.t[2] = 0; + matrix.t[1] = 0; + matrix.t[0] = 0; + SetRotMatrix(&matrix); + SetTransMatrix(&matrix); + RotTransSV(&in, &child->PartPos, &flag); + } + } + } + if (effect->AnimationFrame == 40) { + for (i = 0; i < 10; i++) { + if ((D_801D575C >> i) & 1) { + func_800D5774(i); + } + } + func_800BBA84(0xFA, -1, 0x40); + } + if (effect->AnimationFrame >= 21) { + u16p = &D_801031EA; + t = *u16p + 0x10; + *u16p = t - (effect->AnimationFrame % 2) * 32; + } + effect->AnimationFrame++; + if (effect->AnimationFrame == 70) { + effect->StartFrame = -1; + } + } +} + +void ShakuStart(s32 targetMask, s32 callbackArg) { + VECTOR vec; + SVECTOR dir; + ShakuData* effect; + + BattleEffectRegister(ShakuDoubleBufferFlip); + D_801D575C = targetMask; + effect = &g_BattleEffectSlots[BattleEffectRegister(ShakuMainTick)]; + BattleGetPartPosition(callbackArg, g_BattleModels[callbackArg].boneIndices[8], &effect->Pos); + ShakuTargetCenterCalc(targetMask, &D_801D5760); + vec.vx = dir.vx = D_801D5760.vx - effect->Pos.vx; + vec.vy = dir.vy = D_801D5760.vy - effect->Pos.vy; + vec.vz = dir.vz = D_801D5760.vz - effect->Pos.vz; + BattleMatrixFromDirection(&dir, &D_801D573C); + VectorNormal(&vec, &vec); + effect->PartPos.vx = (u32)(vec.vx * 75) >> 9; + effect->PartPos.vy = (u32)(vec.vy * 75) >> 9; + effect->PartPos.vz = (u32)(vec.vz * 75) >> 9; + effect->unk1E = callbackArg; + BattleSetLoadTimToVram(D_801B1B38, 0, 0, 0); + D_800F5B70 = D_800F5B71 = D_800F5B72 = 0; + BattleFixedPointRampUpdateInit(0x1000, 0x10); +} diff --git a/src/magic/shaku.h b/src/magic/shaku.h new file mode 100644 index 00000000..9992fee7 --- /dev/null +++ b/src/magic/shaku.h @@ -0,0 +1,6 @@ +#ifndef SHAKU_H +#define SHAKU_H + +#include "magic.h" + +#endif diff --git a/tools/builder/builder/objdiff.go b/tools/builder/builder/objdiff.go index 23967455..4fe76b03 100644 --- a/tools/builder/builder/objdiff.go +++ b/tools/builder/builder/objdiff.go @@ -113,6 +113,9 @@ var metaOverlays = map[string]metaOverlay{ "lv5deth": {"lv5deth", "magic", "LV.5 Death"}, "choco0": {"choco0", "magic", "choco0"}, "sennkoku": {"sennkoku", "magic", "Death Sentence / Roulette"}, + "hadoho": {"hadoho", "magic", "HADOHO"}, + "shaku": {"shaku", "magic", "SHAKU"}, + "re_do": {"re_do", "magic", "RE_DO"}, } func makeObjdiffConfig(b BuildConfig) objdiffConfig {