From 9f2a6b0fa22d633514dbf0611053851362881193 Mon Sep 17 00:00:00 2001 From: j3lee Date: Mon, 12 Oct 2026 12:06:45 +0930 Subject: [PATCH 01/10] kaen: import and decompile the overlay --- CMakeLists.txt | 1 + config/symbols.magic-kaen.us.txt | 13 ++ config/us.yaml | 15 ++ src/magic/kaen.c | 307 +++++++++++++++++++++++++++++++ src/magic/kaen.h | 6 + tools/builder/builder/objdiff.go | 1 + 6 files changed, 343 insertions(+) create mode 100644 config/symbols.magic-kaen.us.txt create mode 100644 src/magic/kaen.c create mode 100644 src/magic/kaen.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 14280eff..9ff5f05e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,6 +89,7 @@ set(FF7_MINI set(FF7_MAGIC src/magic/barrier.c src/magic/brizad.c + src/magic/kaen.c src/magic/lv5deth.c src/magic/mabaria.c src/magic/sennkoku.c diff --git a/config/symbols.magic-kaen.us.txt b/config/symbols.magic-kaen.us.txt new file mode 100644 index 00000000..edd880a4 --- /dev/null +++ b/config/symbols.magic-kaen.us.txt @@ -0,0 +1,13 @@ +func_801B0010 = 0x801B0010; +func_801B0030 = 0x801B0030; +func_801B01DC = 0x801B01DC; +func_801B030C = 0x801B030C; +KaenDoubleBufferFlip = 0x801B046C; +func_801B04D8 = 0x801B04D8; +func_801B05DC = 0x801B05DC; +func_801B080C = 0x801B080C; +func_801B0AEC = 0x801B0AEC; +func_801B0EAC = 0x801B0EAC; +func_801B0F6C = 0x801B0F6C; +g_KaenPrimBuffer = 0x801D3F30; +g_KaenBufferPtr = 0x801EBF30; diff --git a/config/us.yaml b/config/us.yaml index 69eaa150..c4ccb90c 100644 --- a/config/us.yaml +++ b/config/us.yaml @@ -807,3 +807,18 @@ overlays: - [0, c, sennkoku] - [0x930, data, sennkoku_model] - [0x559C, data, sennkoku_buffers] + # KAEN.BIN -- effect overlay + - name: kaen + disk_path: disks/us/MAGIC/KAEN.BIN + sha1: 2dc7702de646e5288feeae5f349b58ce88135b5e + base_path: magic + imports: [main, battle] + vram_start: 0x801B0000 + symbol_addrs_path: + - config/symbols.magic-kaen.us.txt + segments: + # REVIEW (split): the 0x10 bytes before the code are the effect's sprite descriptor; the linker script puts rodata first, so it is a rodata segment; cost: none, data only + - [0, rodata, kaen] + - [0x10, c, kaen] + - [0xFE8, data, kaen_model] + - [0x23F30, data, kaen_buffers] diff --git a/src/magic/kaen.c b/src/magic/kaen.c new file mode 100644 index 00000000..4460a8c4 --- /dev/null +++ b/src/magic/kaen.c @@ -0,0 +1,307 @@ +//! PSYQ=3.3 CC1=2.6.3 + +#include "common.h" +#include "magic.h" +#include "kaen.h" +#include "../battle/battle.h" + +// Effect KAEN. + +void func_801B0F6C(s32 targetMask, s32 callbackArg); + +// Primitive buffer pages, one 0xC000 page per double-buffered frame. +extern u8 g_KaenPrimBuffer[2][0xC000]; +extern void* g_KaenBufferPtr; + +// 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; +} KaenData; // size:0x20 + +extern ModelRenderDesc D_801D3EF4; +extern SVECTOR D_801D3EEC; +extern SpriteAnim* D_801D3ED4[]; +extern SpriteRenderDesc D_801D3EC8; +extern SpriteRenderDesc D_801D3EE0; +extern SpriteRenderDesc D_801D3F04; +extern VECTOR D_801B0000; +extern KaenData g_BattleEffectSlots[]; +extern KaenData g_BattleDetachedSlots[]; +extern s16 g_BattleDetachedCursor; +extern s32* D_801D3F10[]; +extern u_long D_801B0FE8[]; +extern void* D_80163C74; +s32 BattleDetachedRegister(void (*func)(void)); +void func_800BBA84(u16 arg0, s32 arg1, s32 arg2); +void func_801B0AEC(void); + +// Same as MAGIC_Biora. +void func_801B0010(s32 targetMask, s32 callbackArg) { func_801B0F6C(targetMask, callbackArg); } + +void func_801B0030(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 func_801B01DC(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 func_801B030C(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 BioraDoubleBufferFlip. +static void KaenDoubleBufferFlip(void) { + KaenData* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + g_KaenBufferPtr = g_KaenPrimBuffer[effect->AnimationFrame]; + effect->AnimationFrame ^= 1; + if (g_BattleEffectCount < 2) { + effect->StartFrame = -1; + } +} + +void func_801B04D8(void) { + KaenData* effect; + + effect = &g_BattleDetachedSlots[g_BattleDetachedCursor]; + BattleSetBillboardMatrix(&effect->Pos, effect->unk16 == 2 ? 0x2000 : 0x3000, 0); + D_801D3EC8.frames = D_801D3ED4[effect->unk16]; + D_801D3EC8.frameIndex = effect->AnimationFrame; + D_80163C74 = func_800D4D90(&D_801D3EC8, (u_long**)&g_cDb->unk70, 12, D_80163C74); + if (D_80062D98 == 0) { + effect->AnimationFrame++; + if (effect->AnimationFrame == D_801D3ED4[effect->unk16]->frameCount) { + effect->StartFrame = -1; + } + } +} + +void func_801B05DC(void) { + MATRIX rotated; + MATRIX matrix; + SVECTOR rot; + s32 flag; + KaenData* effect; + s16 fade; + s16 scale; + 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); + scale = 0x2000; + if (effect->unk16 < 4) { + scale = 0x1400; + } + matrix.m[0][0] = matrix.m[1][1] = matrix.m[2][2] = scale; + RotMatrixYXZ(&rot, &rotated); + MulMatrix(&matrix, &rotated); + SetRotMatrix(&matrix); + SetTransMatrix(&matrix); + D_801D3EE0.frameIndex = effect->unk16; + D_801D3EE0.color.cd = fade == 8 ? 0x2C : 0x2E; + D_801D3EE0.color.r = D_801D3EE0.color.g = D_801D3EE0.color.b = fade << 4; + D_80163C74 = func_800D4D90(&D_801D3EE0, (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 func_801B080C(void) { + MATRIX dirMatrix; + MATRIX matrix; + MATRIX composed; + s32 pad[2]; // match: unused, gives the original stack frame + VECTOR scale; + KaenData* effect; + KaenData* child; + + scale = D_801B0000; + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + BattleMatrixFromDirection(&effect->PartPos, &dirMatrix); + RotMatrixYXZ(&D_801D3EEC, &matrix); + MulMatrix0(&dirMatrix, &matrix, &matrix); + 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); + D_801D3EF4.model = D_801D3F10[effect->AnimationFrame % 8]; + g_KaenBufferPtr = func_800D29D4(&D_801D3EF4, g_cDb->unk70, 12, g_KaenBufferPtr); + BattleSetBillboardMatrix(&effect->Pos, 0x1000, 0); + D_80163C74 = func_800D4D90(&D_801D3F04, (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 == 8) { + child = &g_BattleDetachedSlots[BattleDetachedRegister(func_801B04D8)]; + child->Pos.vx = effect->Pos.vx + rand() % 800 - 400; + child->Pos.vy = effect->Pos.vy + rand() % 800 - 400; + child->Pos.vz = effect->Pos.vz + rand() % 800 - 400; + child->unk16 = 0; + effect->StartFrame = -1; + } + } +} + +void func_801B0AEC(void) { + s32 pad[12]; // match: unused, gives the original stack frame + KaenData* effect; + KaenData* child; + s16 i; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + if (D_80062D98 == 0) { + if (effect->AnimationFrame == 0) { + child = &g_BattleDetachedSlots[BattleDetachedRegister(func_801B04D8)]; + child->Pos.vx = effect->Pos.vx; + child->Pos.vy = effect->Pos.vy; + child->Pos.vz = effect->Pos.vz; + child->unk16 = 2; + child = &g_BattleEffectSlots[BattleEffectRegister(func_801B080C)]; + child->Pos.vx = effect->Pos.vx; + child->Pos.vy = effect->Pos.vy; + child->Pos.vz = effect->Pos.vz; + child->PartPos.vx = (effect->PartPos.vx - effect->Pos.vx) / 8; + child->PartPos.vy = (effect->PartPos.vy - effect->Pos.vy) / 8; + child->PartPos.vz = (effect->PartPos.vz - effect->Pos.vz) / 8; + } + if (effect->AnimationFrame == 8) { + i = 0; + do { + child = &g_BattleEffectSlots[BattleEffectRegister(func_801B05DC)]; + child->Pos.vx = effect->PartPos.vx + rand() % 400 - 200; + child->Pos.vz = effect->PartPos.vz + rand() % 400 - 200; + child->Pos.vy = 0; + func_801B01DC(-250, 100, &child->PartPos); + child->unk16 = rand() % 20; + i++; + } while (i < 8); + func_800BBA84(0xFA, effect->unk1C, 0); + } + if (effect->AnimationFrame >= 12 && effect->AnimationFrame < 19) { + child = &g_BattleDetachedSlots[BattleDetachedRegister(func_801B04D8)]; + child->Pos.vx = effect->PartPos.vx + rand() % 1200 - 600; + child->Pos.vy = effect->PartPos.vy + rand() % 1200 - 600; + child->Pos.vz = effect->PartPos.vz + rand() % 1200 - 600; + child->unk16 = 1; + } + if (effect->AnimationFrame == 15) { + func_800D5774(effect->unk1C); + } + effect->AnimationFrame++; + if (effect->AnimationFrame == 30) { + effect->StartFrame = -1; + } + } +} + +void func_801B0EAC(s32 target, s32 callbackArg) { + KaenData* effect; + + effect = &g_BattleEffectSlots[BattleEffectRegister(func_801B0AEC)]; + BattleGetPartPosition(callbackArg, g_BattleModels[callbackArg].boneIndices[8], &effect->Pos); + BattleGetPartPosition(target, g_BattleModels[target].boneIndices[0], &effect->PartPos); + effect->unk1C = target; +} + +void func_801B0F6C(s32 targetMask, s32 callbackArg) { + BattleEffectRegister(KaenDoubleBufferFlip); + BattleSetLoadTimToVram(D_801B0FE8, 0, 0, 0); + MagicAnimationRegister(targetMask, callbackArg, 4, func_801B0EAC); + func_800BBA84(0x163, callbackArg, 0); +} diff --git a/src/magic/kaen.h b/src/magic/kaen.h new file mode 100644 index 00000000..1ce076fd --- /dev/null +++ b/src/magic/kaen.h @@ -0,0 +1,6 @@ +#ifndef KAEN_H +#define KAEN_H + +#include "magic.h" + +#endif diff --git a/tools/builder/builder/objdiff.go b/tools/builder/builder/objdiff.go index 23967455..89fde310 100644 --- a/tools/builder/builder/objdiff.go +++ b/tools/builder/builder/objdiff.go @@ -113,6 +113,7 @@ var metaOverlays = map[string]metaOverlay{ "lv5deth": {"lv5deth", "magic", "LV.5 Death"}, "choco0": {"choco0", "magic", "choco0"}, "sennkoku": {"sennkoku", "magic", "Death Sentence / Roulette"}, + "kaen": {"kaen", "magic", "KAEN"}, } func makeObjdiffConfig(b BuildConfig) objdiffConfig { From 18f4a0da4076e926cffd228bf03db6db598d4525 Mon Sep 17 00:00:00 2001 From: j3lee Date: Mon, 12 Oct 2026 12:06:50 +0930 Subject: [PATCH 02/10] kaen2: import and decompile the overlay --- CMakeLists.txt | 1 + config/symbols.magic-kaen2.us.txt | 13 ++ config/us.yaml | 13 ++ src/magic/kaen2.c | 331 ++++++++++++++++++++++++++++++ src/magic/kaen2.h | 6 + tools/builder/builder/objdiff.go | 1 + 6 files changed, 365 insertions(+) create mode 100644 config/symbols.magic-kaen2.us.txt create mode 100644 src/magic/kaen2.c create mode 100644 src/magic/kaen2.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ff5f05e..ff2b7b32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,6 +90,7 @@ set(FF7_MAGIC src/magic/barrier.c src/magic/brizad.c src/magic/kaen.c + src/magic/kaen2.c src/magic/lv5deth.c src/magic/mabaria.c src/magic/sennkoku.c diff --git a/config/symbols.magic-kaen2.us.txt b/config/symbols.magic-kaen2.us.txt new file mode 100644 index 00000000..4c0d1a7d --- /dev/null +++ b/config/symbols.magic-kaen2.us.txt @@ -0,0 +1,13 @@ +func_801B0000 = 0x801B0000; +func_801B0020 = 0x801B0020; +func_801B01CC = 0x801B01CC; +func_801B02FC = 0x801B02FC; +Kaen2DoubleBufferFlip = 0x801B045C; +func_801B04C8 = 0x801B04C8; +func_801B0658 = 0x801B0658; +func_801B0888 = 0x801B0888; +func_801B0B40 = 0x801B0B40; +func_801B0FF0 = 0x801B0FF0; +func_801B10BC = 0x801B10BC; +g_Kaen2PrimBuffer = 0x801D4140; +g_Kaen2BufferPtr = 0x801EC140; diff --git a/config/us.yaml b/config/us.yaml index c4ccb90c..148592ff 100644 --- a/config/us.yaml +++ b/config/us.yaml @@ -822,3 +822,16 @@ overlays: - [0x10, c, kaen] - [0xFE8, data, kaen_model] - [0x23F30, data, kaen_buffers] + # KAEN2.BIN -- effect overlay + - name: kaen2 + disk_path: disks/us/MAGIC/KAEN2.BIN + sha1: 0bb5bf470e3b04dd658b7c28ff374464a1401ca6 + base_path: magic + imports: [main, battle] + vram_start: 0x801B0000 + symbol_addrs_path: + - config/symbols.magic-kaen2.us.txt + segments: + - [0, c, kaen2] + - [0x1128, data, kaen2_model] + - [0x24140, data, kaen2_buffers] diff --git a/src/magic/kaen2.c b/src/magic/kaen2.c new file mode 100644 index 00000000..ffcc231c --- /dev/null +++ b/src/magic/kaen2.c @@ -0,0 +1,331 @@ +//! PSYQ=3.3 CC1=2.6.3 + +#include "common.h" +#include "magic.h" +#include "kaen2.h" +#include "../battle/battle.h" + +// Effect KAEN2. + +void func_801B10BC(s32 targetMask, s32 callbackArg); + +// Primitive buffer pages, one 0xC000 page per double-buffered frame. +extern u8 g_Kaen2PrimBuffer[2][0xC000]; +extern void* g_Kaen2BufferPtr; + +// 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; +} Kaen2Data; // size:0x20 + +extern ModelRenderDesc D_801D4104; +extern SVECTOR D_801D40EC; +extern SpriteAnim* D_801D40D4[]; +extern SpriteRenderDesc D_801D40C8; +extern SpriteRenderDesc D_801D40E0; +extern SpriteRenderDesc D_801D4114; +extern VECTOR D_801D40F4; +extern Kaen2Data g_BattleEffectSlots[]; +extern Kaen2Data g_BattleDetachedSlots[]; +extern s16 g_BattleDetachedCursor; +extern s32* D_801D4120[]; +extern u_long D_801B1128[]; +extern void* D_80163C74; +s32 BattleDetachedRegister(void (*func)(void)); +void func_801B0FF0(s32 target, s32 callbackArg); +void func_801B04C8(void); +void func_801B0B40(void); + +// Same as MAGIC_Biora. +void func_801B0000(s32 targetMask, s32 callbackArg) { func_801B10BC(targetMask, callbackArg); } + +void func_801B0020(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 func_801B01CC(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 func_801B02FC(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 BioraDoubleBufferFlip. +static void Kaen2DoubleBufferFlip(void) { + Kaen2Data* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + g_Kaen2BufferPtr = g_Kaen2PrimBuffer[effect->AnimationFrame]; + effect->AnimationFrame ^= 1; + if (g_BattleEffectCount < 2) { + effect->StartFrame = -1; + } +} + +void func_801B04C8(void) { + Kaen2Data* effect; + + effect = &g_BattleDetachedSlots[g_BattleDetachedCursor]; + BattleSetBillboardMatrix(&effect->Pos, effect->unk16 == 2 ? 0x2000 : 0x3000, 0); + D_801D40C8.frames = D_801D40D4[effect->unk16]; + D_801D40C8.frameIndex = effect->AnimationFrame; + D_80163C74 = func_800D4D90(&D_801D40C8, (u_long**)&g_cDb->unk70, 12, D_80163C74); + if (D_80062D98 == 0) { + if (effect->unk16 == 1) { + effect->Pos.vx += effect->PartPos.vx; + effect->Pos.vy += effect->PartPos.vy; + effect->Pos.vz += effect->PartPos.vz; + effect->PartPos.vx -= effect->PartPos.vx / 8; + effect->PartPos.vy -= effect->PartPos.vy / 8; + effect->PartPos.vz -= effect->PartPos.vz / 8; + } + effect->AnimationFrame++; + if (effect->AnimationFrame == D_801D40D4[effect->unk16]->frameCount) { + effect->StartFrame = -1; + } + } +} + +void func_801B0658(void) { + MATRIX rotated; + MATRIX matrix; + SVECTOR rot; + s32 flag; + Kaen2Data* effect; + s16 fade; + s16 scale; + 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); + scale = 0x2000; + if (effect->unk16 < 4) { + scale = 0x1400; + } + matrix.m[0][0] = matrix.m[1][1] = matrix.m[2][2] = scale; + RotMatrixYXZ(&rot, &rotated); + MulMatrix(&matrix, &rotated); + SetRotMatrix(&matrix); + SetTransMatrix(&matrix); + D_801D40E0.frameIndex = effect->unk16; + D_801D40E0.color.cd = fade == 8 ? 0x2C : 0x2E; + D_801D40E0.color.r = D_801D40E0.color.g = D_801D40E0.color.b = fade << 4; + D_80163C74 = func_800D4D90(&D_801D40E0, (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 func_801B0888(void) { + MATRIX dirMatrix; + MATRIX matrix; + MATRIX composed; + s32 pad[2]; // match: unused, gives the original stack frame + Kaen2Data* effect; + Kaen2Data* child; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + BattleMatrixFromDirection(&effect->PartPos, &dirMatrix); + RotMatrixYXZ(&D_801D40EC, &matrix); + MulMatrix0(&dirMatrix, &matrix, &matrix); + ScaleMatrix(&matrix, &D_801D40F4); + 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_801D4104.model = D_801D4120[effect->AnimationFrame % 8]; + g_Kaen2BufferPtr = func_800D29D4(&D_801D4104, g_cDb->unk70, 12, g_Kaen2BufferPtr); + BattleSetBillboardMatrix(&effect->Pos, 0x1000, 0); + D_80163C74 = func_800D4D90(&D_801D4114, (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 == 8) { + child = &g_BattleDetachedSlots[BattleDetachedRegister(func_801B04C8)]; + child->Pos.vx = effect->Pos.vx + rand() % 800 - 400; + child->Pos.vy = effect->Pos.vy + rand() % 800 - 400; + child->Pos.vz = effect->Pos.vz + rand() % 800 - 400; + child->unk16 = 0; + effect->StartFrame = -1; + } + } +} + +void func_801B0B40(void) { + SVECTOR in; + SVECTOR rot; + MATRIX matrix; + Kaen2Data* effect; + Kaen2Data* child; + s16 i; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + if (D_80062D98 == 0) { + if (effect->AnimationFrame < 12) { + if ((effect->AnimationFrame % 4) == 0) { + child = &g_BattleDetachedSlots[BattleDetachedRegister(func_801B04C8)]; + child->Pos.vx = effect->Pos.vx; + child->Pos.vy = effect->Pos.vy; + child->Pos.vz = effect->Pos.vz; + child->unk16 = 2; + child = &g_BattleEffectSlots[BattleEffectRegister(func_801B0888)]; + child->Pos.vx = effect->Pos.vx; + child->Pos.vy = effect->Pos.vy; + child->Pos.vz = effect->Pos.vz; + child->PartPos.vx = (effect->PartPos.vx - effect->Pos.vx) / 8; + child->PartPos.vy = (effect->PartPos.vy - effect->Pos.vy) / 8; + child->PartPos.vz = (effect->PartPos.vz - effect->Pos.vz) / 8; + func_800BBA84(0x163, effect->unk1E, 0); + } + } + if (effect->AnimationFrame == 14) { + i = 0; + do { + child = &g_BattleEffectSlots[BattleEffectRegister(func_801B0658)]; + child->Pos.vx = effect->PartPos.vx + rand() % 400 - 200; + child->Pos.vz = effect->PartPos.vz + rand() % 400 - 200; + child->Pos.vy = 0; + func_801B01CC(-250, 100, &child->PartPos); + child->unk16 = rand() % 20; + i++; + } while (i < 8); + func_800BBA84(0x7C, effect->unk1C, 0); + } + if (effect->AnimationFrame >= 12 && effect->AnimationFrame < 19) { + i = 0; + do { + child = &g_BattleDetachedSlots[BattleDetachedRegister(func_801B04C8)]; + child->Pos.vx = effect->PartPos.vx + rand() % 1200 - 600; + child->Pos.vy = effect->PartPos.vy + rand() % 1200 - 600; + child->Pos.vz = effect->PartPos.vz + rand() % 1200 - 600; + rot.vx = rand() % 1200 - 600; + rot.vy = 0; + rot.vz = rand() % 1200 - 600; + in.vx = 0; + in.vy = -160; + in.vz = 0; + RotMatrixYXZ(&rot, &matrix); + ApplyMatrixSV(&matrix, &in, &child->PartPos); + i++; + child->unk16 = 1; + } while (i < 2); + } + if (effect->AnimationFrame == 15) { + func_800D5774(effect->unk1C); + } + effect->AnimationFrame++; + if (effect->AnimationFrame == 40) { + effect->StartFrame = -1; + } + } +} + +void func_801B0FF0(s32 target, s32 callbackArg) { + Kaen2Data* effect; + + effect = &g_BattleEffectSlots[BattleEffectRegister(func_801B0B40)]; + BattleGetPartPosition(callbackArg, g_BattleModels[callbackArg].boneIndices[8], &effect->Pos); + BattleGetPartPosition(target, g_BattleModels[target].boneIndices[0], &effect->PartPos); + effect->unk1C = target; + effect->unk1E = callbackArg; +} + +void func_801B10BC(s32 targetMask, s32 callbackArg) { + BattleEffectRegister(Kaen2DoubleBufferFlip); + BattleSetLoadTimToVram(D_801B1128, 0, 0, 0); + MagicAnimationRegister(targetMask, callbackArg, 4, func_801B0FF0); +} diff --git a/src/magic/kaen2.h b/src/magic/kaen2.h new file mode 100644 index 00000000..17e761d8 --- /dev/null +++ b/src/magic/kaen2.h @@ -0,0 +1,6 @@ +#ifndef KAEN2_H +#define KAEN2_H + +#include "magic.h" + +#endif diff --git a/tools/builder/builder/objdiff.go b/tools/builder/builder/objdiff.go index 89fde310..343e2994 100644 --- a/tools/builder/builder/objdiff.go +++ b/tools/builder/builder/objdiff.go @@ -114,6 +114,7 @@ var metaOverlays = map[string]metaOverlay{ "choco0": {"choco0", "magic", "choco0"}, "sennkoku": {"sennkoku", "magic", "Death Sentence / Roulette"}, "kaen": {"kaen", "magic", "KAEN"}, + "kaen2": {"kaen2", "magic", "KAEN2"}, } func makeObjdiffConfig(b BuildConfig) objdiffConfig { From f2aba7946fa6f14c23da0d41300961ce4f7bb19e Mon Sep 17 00:00:00 2001 From: j3lee Date: Mon, 12 Oct 2026 12:06:54 +0930 Subject: [PATCH 03/10] gas: import and decompile the overlay --- CMakeLists.txt | 1 + config/symbols.magic-gas.us.txt | 13 ++ config/us.yaml | 15 ++ src/magic/gas.c | 307 +++++++++++++++++++++++++++++++ src/magic/gas.h | 6 + tools/builder/builder/objdiff.go | 1 + 6 files changed, 343 insertions(+) create mode 100644 config/symbols.magic-gas.us.txt create mode 100644 src/magic/gas.c create mode 100644 src/magic/gas.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ff2b7b32..8726c020 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,6 +89,7 @@ set(FF7_MINI set(FF7_MAGIC src/magic/barrier.c src/magic/brizad.c + src/magic/gas.c src/magic/kaen.c src/magic/kaen2.c src/magic/lv5deth.c diff --git a/config/symbols.magic-gas.us.txt b/config/symbols.magic-gas.us.txt new file mode 100644 index 00000000..31bd6c75 --- /dev/null +++ b/config/symbols.magic-gas.us.txt @@ -0,0 +1,13 @@ +func_801B0010 = 0x801B0010; +func_801B0030 = 0x801B0030; +func_801B01DC = 0x801B01DC; +func_801B030C = 0x801B030C; +GasDoubleBufferFlip = 0x801B046C; +func_801B04D8 = 0x801B04D8; +func_801B05DC = 0x801B05DC; +func_801B080C = 0x801B080C; +func_801B0AEC = 0x801B0AEC; +func_801B0EAC = 0x801B0EAC; +func_801B0F84 = 0x801B0F84; +g_GasPrimBuffer = 0x801D3FF8; +g_GasBufferPtr = 0x801EBFF8; diff --git a/config/us.yaml b/config/us.yaml index 148592ff..b6bcacdc 100644 --- a/config/us.yaml +++ b/config/us.yaml @@ -835,3 +835,18 @@ overlays: - [0, c, kaen2] - [0x1128, data, kaen2_model] - [0x24140, data, kaen2_buffers] + # GAS.BIN -- effect overlay + - name: gas + disk_path: disks/us/MAGIC/GAS.BIN + sha1: 5fe66342aeed0b053440d8c66bc144a49445a016 + base_path: magic + imports: [main, battle] + vram_start: 0x801B0000 + symbol_addrs_path: + - config/symbols.magic-gas.us.txt + segments: + # REVIEW (split): the 0x10 bytes before the code are the effect's sprite descriptor; the linker script puts rodata first, so it is a rodata segment; cost: none, data only + - [0, rodata, gas] + - [0x10, c, gas] + - [0xFF0, data, gas_model] + - [0x23FF8, data, gas_buffers] diff --git a/src/magic/gas.c b/src/magic/gas.c new file mode 100644 index 00000000..ef3ebf21 --- /dev/null +++ b/src/magic/gas.c @@ -0,0 +1,307 @@ +//! PSYQ=3.3 CC1=2.6.3 + +#include "common.h" +#include "magic.h" +#include "gas.h" +#include "../battle/battle.h" + +// Effect GAS. + +void func_801B0F84(s32 targetMask, s32 callbackArg); + +// Primitive buffer pages, one 0xC000 page per double-buffered frame. +extern u8 g_GasPrimBuffer[2][0xC000]; +extern void* g_GasBufferPtr; + +// 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; +} GasData; // size:0x20 + +extern ModelRenderDesc D_801D3FBC; +extern SVECTOR D_801D3FB4; +extern SpriteAnim* D_801D3F9C[]; +extern SpriteRenderDesc D_801D3F90; +extern SpriteRenderDesc D_801D3FA8; +extern SpriteRenderDesc D_801D3FCC; +extern VECTOR D_801B0000; +extern GasData g_BattleEffectSlots[]; +extern GasData g_BattleDetachedSlots[]; +extern s16 g_BattleDetachedCursor; +extern s32* D_801D3FD8[]; +extern u_long D_801B0FF0[]; +extern void* D_80163C74; +s32 BattleDetachedRegister(void (*func)(void)); +void func_800BBA84(u16 arg0, s32 arg1, s32 arg2); +void func_801B0AEC(void); + +// Same as MAGIC_Biora. +void func_801B0010(s32 targetMask, s32 callbackArg) { func_801B0F84(targetMask, callbackArg); } + +void func_801B0030(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 func_801B01DC(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 func_801B030C(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 BioraDoubleBufferFlip. +static void GasDoubleBufferFlip(void) { + GasData* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + g_GasBufferPtr = g_GasPrimBuffer[effect->AnimationFrame]; + effect->AnimationFrame ^= 1; + if (g_BattleEffectCount < 2) { + effect->StartFrame = -1; + } +} + +void func_801B04D8(void) { + GasData* effect; + + effect = &g_BattleDetachedSlots[g_BattleDetachedCursor]; + BattleSetBillboardMatrix(&effect->Pos, effect->unk16 == 2 ? 0x2000 : 0x3000, 0); + D_801D3F90.frames = D_801D3F9C[effect->unk16]; + D_801D3F90.frameIndex = effect->AnimationFrame; + D_80163C74 = func_800D4D90(&D_801D3F90, (u_long**)&g_cDb->unk70, 12, D_80163C74); + if (D_80062D98 == 0) { + effect->AnimationFrame++; + if (effect->AnimationFrame == D_801D3F9C[effect->unk16]->frameCount) { + effect->StartFrame = -1; + } + } +} + +void func_801B05DC(void) { + MATRIX rotated; + MATRIX matrix; + SVECTOR rot; + s32 flag; + GasData* effect; + s16 fade; + s16 scale; + 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); + scale = 0x2000; + if (effect->unk16 < 4) { + scale = 0x1400; + } + matrix.m[0][0] = matrix.m[1][1] = matrix.m[2][2] = scale; + RotMatrixYXZ(&rot, &rotated); + MulMatrix(&matrix, &rotated); + SetRotMatrix(&matrix); + SetTransMatrix(&matrix); + D_801D3FA8.frameIndex = effect->unk16; + D_801D3FA8.color.cd = fade == 8 ? 0x2C : 0x2E; + D_801D3FA8.color.r = D_801D3FA8.color.g = D_801D3FA8.color.b = fade << 4; + D_80163C74 = func_800D4D90(&D_801D3FA8, (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 func_801B080C(void) { + MATRIX dirMatrix; + MATRIX matrix; + MATRIX composed; + s32 pad[2]; // match: unused, gives the original stack frame + VECTOR scale; + GasData* effect; + GasData* child; + + scale = D_801B0000; + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + BattleMatrixFromDirection(&effect->PartPos, &dirMatrix); + RotMatrixYXZ(&D_801D3FB4, &matrix); + MulMatrix0(&dirMatrix, &matrix, &matrix); + 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); + D_801D3FBC.model = D_801D3FD8[effect->AnimationFrame % 8]; + g_GasBufferPtr = func_800D29D4(&D_801D3FBC, g_cDb->unk70, 12, g_GasBufferPtr); + BattleSetBillboardMatrix(&effect->Pos, 0x1000, 0); + D_80163C74 = func_800D4D90(&D_801D3FCC, (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 == 8) { + child = &g_BattleDetachedSlots[BattleDetachedRegister(func_801B04D8)]; + child->Pos.vx = effect->Pos.vx + rand() % 800 - 400; + child->Pos.vy = effect->Pos.vy + rand() % 800 - 400; + child->Pos.vz = effect->Pos.vz + rand() % 800 - 400; + child->unk16 = 0; + effect->StartFrame = -1; + } + } +} + +void func_801B0AEC(void) { + s32 pad[12]; // match: unused, gives the original stack frame + GasData* effect; + GasData* child; + s16 i; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + if (D_80062D98 == 0) { + if (effect->AnimationFrame == 0) { + child = &g_BattleDetachedSlots[BattleDetachedRegister(func_801B04D8)]; + child->Pos.vx = effect->Pos.vx; + child->Pos.vy = effect->Pos.vy; + child->Pos.vz = effect->Pos.vz; + child->unk16 = 2; + child = &g_BattleEffectSlots[BattleEffectRegister(func_801B080C)]; + child->Pos.vx = effect->Pos.vx; + child->Pos.vy = effect->Pos.vy; + child->Pos.vz = effect->Pos.vz; + child->PartPos.vx = (effect->PartPos.vx - effect->Pos.vx) / 8; + child->PartPos.vy = (effect->PartPos.vy - effect->Pos.vy) / 8; + child->PartPos.vz = (effect->PartPos.vz - effect->Pos.vz) / 8; + } + if (effect->AnimationFrame == 8) { + i = 0; + do { + child = &g_BattleEffectSlots[BattleEffectRegister(func_801B05DC)]; + child->Pos.vx = effect->PartPos.vx + rand() % 400 - 200; + child->Pos.vz = effect->PartPos.vz + rand() % 400 - 200; + child->Pos.vy = 0; + func_801B01DC(-250, 100, &child->PartPos); + child->unk16 = rand() % 20; + i++; + } while (i < 12); + func_800BBA84(0xFA, effect->unk1C, 0); + } + if (effect->AnimationFrame >= 12 && effect->AnimationFrame < 19) { + child = &g_BattleDetachedSlots[BattleDetachedRegister(func_801B04D8)]; + child->Pos.vx = effect->PartPos.vx + rand() % 1200 - 600; + child->Pos.vy = effect->PartPos.vy + rand() % 1200 - 600; + child->Pos.vz = effect->PartPos.vz + rand() % 1200 - 600; + child->unk16 = 1; + } + if (effect->AnimationFrame == 15) { + func_800D5774(effect->unk1C); + } + effect->AnimationFrame++; + if (effect->AnimationFrame == 45) { + effect->StartFrame = -1; + } + } +} + +void func_801B0EAC(s32 target, s32 callbackArg) { + GasData* effect; + + effect = &g_BattleEffectSlots[BattleEffectRegister(func_801B0AEC)]; + BattleGetPartPosition(callbackArg, g_BattleModels[callbackArg].boneIndices[8], &effect->Pos); + BattleGetPartPosition(target, g_BattleModels[target].boneIndices[0], &effect->PartPos); + effect->unk1C = target; + func_800BBA84(0x163, callbackArg, 0); +} + +void func_801B0F84(s32 targetMask, s32 callbackArg) { + BattleEffectRegister(GasDoubleBufferFlip); + BattleSetLoadTimToVram(D_801B0FF0, 0, 0, 0); + MagicAnimationRegister(targetMask, callbackArg, 4, func_801B0EAC); +} diff --git a/src/magic/gas.h b/src/magic/gas.h new file mode 100644 index 00000000..cc6b0b87 --- /dev/null +++ b/src/magic/gas.h @@ -0,0 +1,6 @@ +#ifndef GAS_H +#define GAS_H + +#include "magic.h" + +#endif diff --git a/tools/builder/builder/objdiff.go b/tools/builder/builder/objdiff.go index 343e2994..92d176ed 100644 --- a/tools/builder/builder/objdiff.go +++ b/tools/builder/builder/objdiff.go @@ -115,6 +115,7 @@ var metaOverlays = map[string]metaOverlay{ "sennkoku": {"sennkoku", "magic", "Death Sentence / Roulette"}, "kaen": {"kaen", "magic", "KAEN"}, "kaen2": {"kaen2", "magic", "KAEN2"}, + "gas": {"gas", "magic", "GAS"}, } func makeObjdiffConfig(b BuildConfig) objdiffConfig { From a0ead3ac9f5b6926cf3f9b55b76b8cfdf9877b46 Mon Sep 17 00:00:00 2001 From: j3lee Date: Mon, 12 Oct 2026 12:06:59 +0930 Subject: [PATCH 04/10] hakugek1: import and decompile the overlay --- CMakeLists.txt | 1 + config/symbols.magic-hakugek1.us.txt | 14 + config/us.yaml | 13 + src/magic/hakugek1.c | 392 +++++++++++++++++++++++++++ src/magic/hakugek1.h | 6 + tools/builder/builder/objdiff.go | 1 + 6 files changed, 427 insertions(+) create mode 100644 config/symbols.magic-hakugek1.us.txt create mode 100644 src/magic/hakugek1.c create mode 100644 src/magic/hakugek1.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8726c020..e50d4292 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,6 +90,7 @@ set(FF7_MAGIC src/magic/barrier.c src/magic/brizad.c src/magic/gas.c + src/magic/hakugek1.c src/magic/kaen.c src/magic/kaen2.c src/magic/lv5deth.c diff --git a/config/symbols.magic-hakugek1.us.txt b/config/symbols.magic-hakugek1.us.txt new file mode 100644 index 00000000..50fdca53 --- /dev/null +++ b/config/symbols.magic-hakugek1.us.txt @@ -0,0 +1,14 @@ +func_801B0000 = 0x801B0000; +func_801B0020 = 0x801B0020; +func_801B01CC = 0x801B01CC; +func_801B02FC = 0x801B02FC; +Hakugek1DoubleBufferFlip = 0x801B045C; +func_801B04C8 = 0x801B04C8; +func_801B062C = 0x801B062C; +func_801B0878 = 0x801B0878; +func_801B09F0 = 0x801B09F0; +func_801B0D84 = 0x801B0D84; +func_801B11B4 = 0x801B11B4; +func_801B1290 = 0x801B1290; +g_Hakugek1PrimBuffer = 0x801D2A80; +g_Hakugek1BufferPtr = 0x801EAA80; diff --git a/config/us.yaml b/config/us.yaml index b6bcacdc..0aa23e38 100644 --- a/config/us.yaml +++ b/config/us.yaml @@ -850,3 +850,16 @@ overlays: - [0x10, c, gas] - [0xFF0, data, gas_model] - [0x23FF8, data, gas_buffers] + # HAKUGEK1.BIN -- effect overlay + - name: hakugek1 + disk_path: disks/us/MAGIC/HAKUGEK1.BIN + sha1: 5cf866b06953286fa308f84b04fc327c50c56669 + base_path: magic + imports: [main, battle] + vram_start: 0x801B0000 + symbol_addrs_path: + - config/symbols.magic-hakugek1.us.txt + segments: + - [0, c, hakugek1] + - [0x12FC, data, hakugek1_model] + - [0x22A80, data, hakugek1_buffers] diff --git a/src/magic/hakugek1.c b/src/magic/hakugek1.c new file mode 100644 index 00000000..5dec97da --- /dev/null +++ b/src/magic/hakugek1.c @@ -0,0 +1,392 @@ +//! PSYQ=3.3 CC1=2.6.3 + +#include "common.h" +#include "magic.h" +#include "hakugek1.h" +#include "../battle/battle.h" + +// Effect HAKUGEK1. + +void func_801B1290(s32 targetMask, s32 callbackArg); + +// Primitive buffer pages, one 0xC000 page per double-buffered frame. +extern u8 g_Hakugek1PrimBuffer[2][0xC000]; +extern void* g_Hakugek1BufferPtr; + +// 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; +} Hakugek1Data; // size:0x20 + +extern ModelRenderDesc D_801D2A54; +extern ModelRenderDesc D_801D2A64; +extern SpriteAnim* D_801D2A48[]; +extern SpriteRenderDesc D_801D2A30; +extern SpriteRenderDesc D_801D2A3C; +extern Hakugek1Data g_BattleEffectSlots[]; +extern Hakugek1Data g_BattleDetachedSlots[]; +extern s16 g_BattleDetachedCursor; +extern s32 D_801D296C; +extern s32 D_801D139C[]; +extern s32 D_801D1708[]; +extern s32 D_801D1B14[]; +extern s32 D_801D20E4[]; +extern u16 D_801D2A74[]; +extern u_long D_801B12FC[]; +extern void* D_80163C74; +void func_801B11B4(s32 target, s32 callbackArg); +void func_800BBA84(u16 arg0, s32 arg1, s32 arg2); +void func_801B0D84(void); + +// Same as MAGIC_Biora. +void func_801B0000(s32 targetMask, s32 callbackArg) { func_801B1290(targetMask, callbackArg); } + +void func_801B0020(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 func_801B01CC(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 func_801B02FC(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 BioraDoubleBufferFlip. +static void Hakugek1DoubleBufferFlip(void) { + Hakugek1Data* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + g_Hakugek1BufferPtr = g_Hakugek1PrimBuffer[effect->AnimationFrame]; + effect->AnimationFrame ^= 1; + if (g_BattleEffectCount < 2) { + effect->StartFrame = -1; + } +} + +void func_801B04C8(void) { + MATRIX matrix; + MATRIX rotated; + s32 flag; + Hakugek1Data* effect; + s16 i; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + for (i = 0; i < 3; i++) { + matrix.m[i][2] = 0; + matrix.m[i][1] = 0; + matrix.m[i][0] = 0; + } + 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] = 0x3000; + MulMatrix(&matrix, &g_BattleWorldView.m); + RotMatrixYXZ(&effect->PartPos, &rotated); + MulMatrix(&matrix, &rotated); + SetRotMatrix(&matrix); + SetTransMatrix(&matrix); + D_801D2A30.frameIndex = effect->AnimationFrame; + g_Hakugek1BufferPtr = func_800D4D90(&D_801D2A30, (u_long**)&g_cDb->unk70, 12, g_Hakugek1BufferPtr); + if (D_80062D98 == 0) { + effect->AnimationFrame++; + if (effect->AnimationFrame == D_801D296C) { + effect->StartFrame = -1; + } + } +} + +void func_801B062C(void) { + MATRIX rotated; + MATRIX matrix; + SVECTOR rot; + s32 flag; + Hakugek1Data* 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_801D2A3C.frameIndex = effect->unk16 % 3; + D_801D2A3C.frames = D_801D2A48[effect->unk16 / 3]; + D_801D2A3C.color.r = D_801D2A3C.color.g = D_801D2A3C.color.b = fade << 4; + D_80163C74 = func_800D4D90(&D_801D2A3C, (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->PartPos.vy += 0x14; + effect->unk14 += 0x200; + effect->AnimationFrame++; + if (effect->AnimationFrame == 0x14) { + effect->StartFrame = -1; + } + } +} +void func_801B0878(void) { + SVECTOR rot; + MATRIX matrix; + MATRIX composed; + VECTOR scale; + Hakugek1Data* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + rot.vz = 0; + rot.vx = 0; + rot.vy = effect->unk14; + RotMatrixYXZ(&rot, &matrix); + scale.vy = 0x1000; + scale.vx = scale.vz = effect->unk18; + 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_801D2A54.color = effect->AnimationFrame * 200; + g_Hakugek1BufferPtr = func_800D29D4(&D_801D2A54, g_cDb->unk70, 12, g_Hakugek1BufferPtr); + if (D_80062D98 == 0) { + effect->unk18 += 0x200; + effect->unk14 += 0x80; + effect->Pos.vy += effect->PartPos.vy; + effect->AnimationFrame++; + if (effect->AnimationFrame == 0x14) { + effect->StartFrame = -1; + } + } +} + +void func_801B09F0(void) { + SVECTOR rot; + MATRIX matrix; + MATRIX composed; + VECTOR scale; + Hakugek1Data* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + rot.vz = 0; + rot.vx = 0; + rot.vy = effect->AnimationFrame * 64; + RotMatrixYXZ(&rot, &matrix); + scale.vx = scale.vy = scale.vz = effect->AnimationFrame * 240 + 0x600; + ScaleMatrix(&matrix, &scale); + matrix.t[0] = effect->Pos.vx; + matrix.t[1] = 0; + matrix.t[2] = effect->Pos.vz; + CompMatrix(&g_BattleWorldView.m, &matrix, &composed); + SetRotMatrix(&composed); + SetTransMatrix(&composed); + SetFarColor(0, 0, 0); + D_801D2A64.flags = MODEL_NO_CULL | MODEL_SEMI_TRANS; + D_801D2A64.model = D_801D139C; + D_801D2A64.color = 0x80 - effect->AnimationFrame * 6; + g_Hakugek1BufferPtr = func_800D29D4(&D_801D2A64, g_cDb->unk70, 12, g_Hakugek1BufferPtr); + RotMatrixYXZ(&rot, &matrix); + scale.vx = scale.vy = scale.vz = effect->AnimationFrame * 320 + 0x800; + ScaleMatrix(&matrix, &scale); + matrix.t[0] = effect->Pos.vx; + matrix.t[1] = 0; + matrix.t[2] = effect->Pos.vz; + CompMatrix(&g_BattleWorldView.m, &matrix, &composed); + SetRotMatrix(&composed); + SetTransMatrix(&composed); + D_801D2A64.flags = MODEL_NO_CULL | MODEL_SEMI_TRANS; + D_801D2A64.model = D_801D1B14; + D_801D2A64.color = 0x80 - effect->AnimationFrame * 6; + g_Hakugek1BufferPtr = func_800D29D4(&D_801D2A64, g_cDb->unk70, 12, g_Hakugek1BufferPtr); + RotMatrixYXZ(&rot, &matrix); + scale.vx = scale.vy = scale.vz = effect->AnimationFrame * 240 + 0x600; + ScaleMatrix(&matrix, &scale); + matrix.t[0] = effect->Pos.vx; + matrix.t[1] = 0; + matrix.t[2] = effect->Pos.vz; + CompMatrix(&g_BattleWorldView.m, &matrix, &composed); + SetRotMatrix(&composed); + SetTransMatrix(&composed); + D_801D2A64.flags = MODEL_DEPTH_CUE | MODEL_NO_CULL | MODEL_SEMI_TRANS; + D_801D2A64.model = D_801D1708; + D_801D2A64.color = effect->AnimationFrame * 48 + 0xC00; + g_Hakugek1BufferPtr = func_800D29D4(&D_801D2A64, g_cDb->unk70, 12, g_Hakugek1BufferPtr); + D_801D2A64.flags = MODEL_DEPTH_CUE | MODEL_NO_CULL | MODEL_SEMI_TRANS; + D_801D2A64.model = D_801D20E4; + D_801D2A64.color = effect->AnimationFrame * 96; + g_Hakugek1BufferPtr = func_800D29D4(&D_801D2A64, g_cDb->unk70, 12, g_Hakugek1BufferPtr); + if (D_80062D98 == 0) { + effect->AnimationFrame++; + if (effect->AnimationFrame == 20) { + effect->StartFrame = -1; + } + } +} + +void func_801B0D84(void) { + SVECTOR pos; + s32 pad[10]; // unused; gives the function its 0x60 byte stack frame (match) + Hakugek1Data* effect; + Hakugek1Data* child; + s32 ang; + s16 i; + s16 j; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + if (D_80062D98 == 0) { + if (effect->AnimationFrame == 0) { + ang = ratan2(effect->PartPos.vx - effect->Pos.vx, effect->PartPos.vz - effect->Pos.vz); + child = &g_BattleEffectSlots[BattleEffectRegister(func_801B04C8)]; + BattleGetPartPosition(effect->unk1E, g_BattleModels[effect->unk1E].boneIndices[11], &child->Pos); + child->PartPos.vx = 0; + child->PartPos.vy = ang + 0x400; + child->PartPos.vz = -0x200; + child = &g_BattleEffectSlots[BattleEffectRegister(func_801B04C8)]; + BattleGetPartPosition(effect->unk1E, g_BattleModels[effect->unk1E].boneIndices[12], &child->Pos); + child->PartPos.vx = 0; + child->PartPos.vy = ang + 0x400; + child->PartPos.vz = -0x200; + } + if (effect->AnimationFrame == 20) { + i = 0; + do { + pos.vx = effect->PartPos.vx + (rcos((i << 16 >> 5) + 0x200) * 800 >> 12); + pos.vy = effect->PartPos.vy; + pos.vz = effect->PartPos.vz + (rsin((i << 16 >> 5) + 0x200) * 800 >> 12); + j = 0; + do { + child = &g_BattleEffectSlots[BattleEffectRegister(func_801B062C)]; + child->Pos.vx = pos.vx + rand() % 400 - 200; + child->Pos.vz = pos.vz + rand() % 400 - 200; + child->Pos.vy = 0; + func_801B01CC(-300, 50, &child->PartPos); + child->unk16 = rand() % 9; + j++; + } while (j < 24); + child = &g_BattleEffectSlots[BattleEffectRegister(func_801B09F0)]; + child->Pos.vx = pos.vx; + child->Pos.vy = 0; + child->Pos.vz = pos.vz; + j = 0; + do { + child = &g_BattleEffectSlots[BattleEffectRegister(func_801B0878)]; + child->Pos.vx = pos.vx; + child->Pos.vy = pos.vy; + child->Pos.vz = pos.vz; + child->Pos.vy = (j - 4) * 80; + child->unk18 = D_801D2A74[j]; + child->PartPos.vy = (j - 4) * 10; + child->unk14 = rand() % 4096; + j++; + } while (j < 5); + i++; + } while (i < 2); + func_800BBA84(0xFA, effect->unk1C, 0); + } + if (effect->AnimationFrame == 35) { + func_800D5774(effect->unk1C); + } + effect->AnimationFrame++; + if (effect->AnimationFrame == 45) { + effect->StartFrame = -1; + } + } +} + +void func_801B11B4(s32 target, s32 callbackArg) { + Hakugek1Data* effect; + + effect = &g_BattleEffectSlots[BattleEffectRegister(func_801B0D84)]; + BattleGetPartPosition(callbackArg, g_BattleModels[callbackArg].boneIndices[0], &effect->Pos); + BattleGetPartPosition(target, g_BattleModels[target].boneIndices[0], &effect->PartPos); + effect->unk1C = target; + effect->unk1E = callbackArg; + func_800BBA84(0x14, callbackArg, 0); +} + +void func_801B1290(s32 targetMask, s32 callbackArg) { + BattleEffectRegister(Hakugek1DoubleBufferFlip); + BattleSetLoadTimToVram(D_801B12FC, 0, 0, 0); + MagicAnimationRegister(targetMask, callbackArg, 4, func_801B11B4); +} diff --git a/src/magic/hakugek1.h b/src/magic/hakugek1.h new file mode 100644 index 00000000..5c489bd5 --- /dev/null +++ b/src/magic/hakugek1.h @@ -0,0 +1,6 @@ +#ifndef HAKUGEK1_H +#define HAKUGEK1_H + +#include "magic.h" + +#endif diff --git a/tools/builder/builder/objdiff.go b/tools/builder/builder/objdiff.go index 92d176ed..0d159d64 100644 --- a/tools/builder/builder/objdiff.go +++ b/tools/builder/builder/objdiff.go @@ -116,6 +116,7 @@ var metaOverlays = map[string]metaOverlay{ "kaen": {"kaen", "magic", "KAEN"}, "kaen2": {"kaen2", "magic", "KAEN2"}, "gas": {"gas", "magic", "GAS"}, + "hakugek1": {"hakugek1", "magic", "HAKUGEK1"}, } func makeObjdiffConfig(b BuildConfig) objdiffConfig { From 42c9d8dbdb6c1bad77502141fe0117c2fad201f6 Mon Sep 17 00:00:00 2001 From: j3lee Date: Mon, 12 Oct 2026 12:07:03 +0930 Subject: [PATCH 05/10] hakugek2: import and decompile the overlay --- CMakeLists.txt | 1 + config/symbols.magic-hakugek2.us.txt | 14 + config/us.yaml | 13 + src/magic/hakugek2.c | 377 +++++++++++++++++++++++++++ src/magic/hakugek2.h | 6 + tools/builder/builder/objdiff.go | 1 + 6 files changed, 412 insertions(+) create mode 100644 config/symbols.magic-hakugek2.us.txt create mode 100644 src/magic/hakugek2.c create mode 100644 src/magic/hakugek2.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e50d4292..72c6e18f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,6 +91,7 @@ set(FF7_MAGIC src/magic/brizad.c src/magic/gas.c src/magic/hakugek1.c + src/magic/hakugek2.c src/magic/kaen.c src/magic/kaen2.c src/magic/lv5deth.c diff --git a/config/symbols.magic-hakugek2.us.txt b/config/symbols.magic-hakugek2.us.txt new file mode 100644 index 00000000..99ac4519 --- /dev/null +++ b/config/symbols.magic-hakugek2.us.txt @@ -0,0 +1,14 @@ +func_801B0000 = 0x801B0000; +func_801B0020 = 0x801B0020; +func_801B01CC = 0x801B01CC; +func_801B02FC = 0x801B02FC; +Hakugek2DoubleBufferFlip = 0x801B045C; +func_801B04C8 = 0x801B04C8; +func_801B062C = 0x801B062C; +func_801B0878 = 0x801B0878; +func_801B09E0 = 0x801B09E0; +func_801B0D64 = 0x801B0D64; +func_801B10A0 = 0x801B10A0; +func_801B117C = 0x801B117C; +g_Hakugek2PrimBuffer = 0x801D296C; +g_Hakugek2BufferPtr = 0x801EA96C; diff --git a/config/us.yaml b/config/us.yaml index 0aa23e38..418b81c6 100644 --- a/config/us.yaml +++ b/config/us.yaml @@ -863,3 +863,16 @@ overlays: - [0, c, hakugek1] - [0x12FC, data, hakugek1_model] - [0x22A80, data, hakugek1_buffers] + # HAKUGEK2.BIN -- effect overlay + - name: hakugek2 + disk_path: disks/us/MAGIC/HAKUGEK2.BIN + sha1: a7385d17eb1439af1cb9b1282abd9e163e563b5f + base_path: magic + imports: [main, battle] + vram_start: 0x801B0000 + symbol_addrs_path: + - config/symbols.magic-hakugek2.us.txt + segments: + - [0, c, hakugek2] + - [0x11E8, data, hakugek2_model] + - [0x2296C, data, hakugek2_buffers] diff --git a/src/magic/hakugek2.c b/src/magic/hakugek2.c new file mode 100644 index 00000000..d416ed6f --- /dev/null +++ b/src/magic/hakugek2.c @@ -0,0 +1,377 @@ +//! PSYQ=3.3 CC1=2.6.3 + +#include "common.h" +#include "magic.h" +#include "hakugek2.h" +#include "../battle/battle.h" + +// Effect HAKUGEK2. + +void func_801B117C(s32 targetMask, s32 callbackArg); + +// Primitive buffer pages, one 0xC000 page per double-buffered frame. +extern u8 g_Hakugek2PrimBuffer[2][0xC000]; +extern void* g_Hakugek2BufferPtr; + +// 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; +} Hakugek2Data; // size:0x20 + +extern ModelRenderDesc D_801D2940; +extern ModelRenderDesc D_801D2950; +extern SpriteAnim* D_801D2934[]; +extern SpriteRenderDesc D_801D291C; +extern SpriteRenderDesc D_801D2928; +extern Hakugek2Data g_BattleEffectSlots[]; +extern Hakugek2Data g_BattleDetachedSlots[]; +extern s16 g_BattleDetachedCursor; +extern s32 D_801D2858; +extern s32 D_801D1288[]; +extern s32 D_801D15F4[]; +extern s32 D_801D1A00[]; +extern s32 D_801D1FD0[]; +extern u16 D_801D2960[]; +extern u_long D_801B11E8[]; +extern void* D_80163C74; +void func_801B10A0(s32 target, s32 callbackArg); +void func_801B0D64(void); + +// Same as MAGIC_Biora. +void func_801B0000(s32 targetMask, s32 callbackArg) { func_801B117C(targetMask, callbackArg); } + +void func_801B0020(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 func_801B01CC(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 func_801B02FC(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 BioraDoubleBufferFlip. +static void Hakugek2DoubleBufferFlip(void) { + Hakugek2Data* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + g_Hakugek2BufferPtr = g_Hakugek2PrimBuffer[effect->AnimationFrame]; + effect->AnimationFrame ^= 1; + if (g_BattleEffectCount < 2) { + effect->StartFrame = -1; + } +} + +void func_801B04C8(void) { + MATRIX matrix; + MATRIX rotated; + s32 flag; + Hakugek2Data* effect; + s16 i; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + for (i = 0; i < 3; i++) { + matrix.m[i][2] = 0; + matrix.m[i][1] = 0; + matrix.m[i][0] = 0; + } + 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] = 0x3000; + MulMatrix(&matrix, &g_BattleWorldView.m); + RotMatrixYXZ(&effect->PartPos, &rotated); + MulMatrix(&matrix, &rotated); + SetRotMatrix(&matrix); + SetTransMatrix(&matrix); + D_801D291C.frameIndex = effect->AnimationFrame; + g_Hakugek2BufferPtr = func_800D4D90(&D_801D291C, (u_long**)&g_cDb->unk70, 12, g_Hakugek2BufferPtr); + if (D_80062D98 == 0) { + effect->AnimationFrame++; + if (effect->AnimationFrame == D_801D2858) { + effect->StartFrame = -1; + } + } +} + +void func_801B062C(void) { + MATRIX rotated; + MATRIX matrix; + SVECTOR rot; + s32 flag; + Hakugek2Data* 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_801D2928.frameIndex = effect->unk16 % 3; + D_801D2928.frames = D_801D2934[effect->unk16 / 3]; + D_801D2928.color.r = D_801D2928.color.g = D_801D2928.color.b = fade << 4; + D_80163C74 = func_800D4D90(&D_801D2928, (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->PartPos.vy += 0x14; + effect->unk14 += 0x200; + effect->AnimationFrame++; + if (effect->AnimationFrame == 0x14) { + effect->StartFrame = -1; + } + } +} + +void func_801B0878(void) { + SVECTOR rot; + MATRIX matrix; + MATRIX composed; + VECTOR scale; + Hakugek2Data* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + rot.vz = 0; + rot.vx = 0; + rot.vy = effect->unk14; + RotMatrixYXZ(&rot, &matrix); + scale.vy = 0x1000; + scale.vx = scale.vz = effect->unk18; + 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); + D_801D2940.color = effect->AnimationFrame * 200; + g_Hakugek2BufferPtr = func_800D29D4(&D_801D2940, g_cDb->unk70, 12, g_Hakugek2BufferPtr); + if (D_80062D98 == 0) { + effect->unk18 += 0x200; + effect->unk14 += 0x80; + effect->Pos.vy += effect->PartPos.vy; + effect->AnimationFrame++; + if (effect->AnimationFrame == 0x14) { + effect->StartFrame = -1; + } + } +} + +void func_801B09E0(void) { + SVECTOR rot; + MATRIX matrix; + MATRIX composed; + VECTOR scale; + Hakugek2Data* effect; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + rot.vz = 0; + rot.vx = 0; + rot.vy = effect->AnimationFrame * 64; + RotMatrixYXZ(&rot, &matrix); + scale.vx = scale.vy = scale.vz = effect->AnimationFrame * 240 + 0x600; + ScaleMatrix(&matrix, &scale); + matrix.t[0] = effect->Pos.vx; + matrix.t[1] = 0; + matrix.t[2] = effect->Pos.vz; + CompMatrix(&g_BattleWorldView.m, &matrix, &composed); + SetRotMatrix(&composed); + SetTransMatrix(&composed); + D_801D2950.flags = MODEL_NO_CULL | MODEL_SEMI_TRANS; + D_801D2950.model = D_801D1288; + D_801D2950.color = 0x80 - effect->AnimationFrame * 6; + g_Hakugek2BufferPtr = func_800D29D4(&D_801D2950, g_cDb->unk70, 12, g_Hakugek2BufferPtr); + RotMatrixYXZ(&rot, &matrix); + scale.vx = scale.vy = scale.vz = effect->AnimationFrame * 320 + 0x800; + ScaleMatrix(&matrix, &scale); + matrix.t[0] = effect->Pos.vx; + matrix.t[1] = 0; + matrix.t[2] = effect->Pos.vz; + CompMatrix(&g_BattleWorldView.m, &matrix, &composed); + SetRotMatrix(&composed); + SetTransMatrix(&composed); + RotMatrixYXZ(&rot, &matrix); + D_801D2950.flags = MODEL_NO_CULL | MODEL_SEMI_TRANS; + D_801D2950.model = D_801D1A00; + D_801D2950.color = 0x80 - effect->AnimationFrame * 6; + g_Hakugek2BufferPtr = func_800D29D4(&D_801D2950, g_cDb->unk70, 12, g_Hakugek2BufferPtr); + scale.vx = scale.vy = scale.vz = effect->AnimationFrame * 240 + 0x600; + ScaleMatrix(&matrix, &scale); + matrix.t[0] = effect->Pos.vx; + matrix.t[1] = 0; + matrix.t[2] = effect->Pos.vz; + CompMatrix(&g_BattleWorldView.m, &matrix, &composed); + SetRotMatrix(&composed); + SetTransMatrix(&composed); + D_801D2950.flags = MODEL_DEPTH_CUE | MODEL_NO_CULL | MODEL_SEMI_TRANS; + D_801D2950.model = D_801D15F4; + D_801D2950.color = effect->AnimationFrame * 48 + 0xC00; + g_Hakugek2BufferPtr = func_800D29D4(&D_801D2950, g_cDb->unk70, 12, g_Hakugek2BufferPtr); + D_801D2950.flags = MODEL_DEPTH_CUE | MODEL_NO_CULL | MODEL_SEMI_TRANS; + D_801D2950.model = D_801D1FD0; + D_801D2950.color = effect->AnimationFrame * 96; + g_Hakugek2BufferPtr = func_800D29D4(&D_801D2950, g_cDb->unk70, 12, g_Hakugek2BufferPtr); + if (D_80062D98 == 0) { + effect->AnimationFrame++; + if (effect->AnimationFrame == 20) { + effect->StartFrame = -1; + } + } +} +void func_801B0D64(void) { + s32 pad[12]; // unused; gives the function its 0x58 byte stack frame (match) + Hakugek2Data* effect; + Hakugek2Data* child; + s32 ang; + s16 j; + + effect = &g_BattleEffectSlots[g_BattleEffectCursor]; + if (D_80062D98 == 0) { + if (effect->AnimationFrame == 0) { + ang = ratan2(effect->PartPos.vx - effect->Pos.vx, effect->PartPos.vz - effect->Pos.vz); + child = &g_BattleEffectSlots[BattleEffectRegister(func_801B04C8)]; + BattleGetPartPosition(effect->unk1E, g_BattleModels[effect->unk1E].boneIndices[8], &child->Pos); + child->PartPos.vx = 0; + child->PartPos.vy = ang + 0x400; + child->PartPos.vz = -0x200; + } + if (effect->AnimationFrame == 20) { + { + j = 0; + do { + child = &g_BattleEffectSlots[BattleEffectRegister(func_801B062C)]; + child->Pos.vx = effect->PartPos.vx + rand() % 400 - 200; + child->Pos.vz = effect->PartPos.vz + rand() % 400 - 200; + child->Pos.vy = 0; + func_801B01CC(-300, 50, &child->PartPos); + child->unk16 = rand() % 9; + j++; + } while (j < 24); + child = &g_BattleEffectSlots[BattleEffectRegister(func_801B09E0)]; + child->Pos.vx = effect->PartPos.vx; + child->Pos.vy = 0; + child->Pos.vz = effect->PartPos.vz; + j = 0; + do { + child = &g_BattleEffectSlots[BattleEffectRegister(func_801B0878)]; + child->Pos.vx = effect->PartPos.vx; + child->Pos.vy = effect->PartPos.vy; + child->Pos.vz = effect->PartPos.vz; + child->Pos.vy = (j - 4) * 80; + child->unk18 = D_801D2960[j]; + child->PartPos.vy = (j - 4) * 10; + child->unk14 = rand() % 4096; + j++; + } while (j < 5); + } + func_800BBA84(0xFA, effect->unk1C, 0); + } + if (effect->AnimationFrame == 35) { + func_800D5774(effect->unk1C); + } + effect->AnimationFrame++; + if (effect->AnimationFrame == 45) { + effect->StartFrame = -1; + } + } +} + +void func_801B10A0(s32 target, s32 callbackArg) { + Hakugek2Data* effect; + + effect = &g_BattleEffectSlots[BattleEffectRegister(func_801B0D64)]; + BattleGetPartPosition(callbackArg, g_BattleModels[callbackArg].boneIndices[0], &effect->Pos); + BattleGetPartPosition(target, g_BattleModels[target].boneIndices[0], &effect->PartPos); + effect->unk1C = target; + effect->unk1E = callbackArg; + func_800BBA84(0x14, callbackArg, 0); +} + +void func_801B117C(s32 targetMask, s32 callbackArg) { + BattleEffectRegister(Hakugek2DoubleBufferFlip); + BattleSetLoadTimToVram(D_801B11E8, 0, 0, 0); + MagicAnimationRegister(targetMask, callbackArg, 4, func_801B10A0); +} diff --git a/src/magic/hakugek2.h b/src/magic/hakugek2.h new file mode 100644 index 00000000..cfc31810 --- /dev/null +++ b/src/magic/hakugek2.h @@ -0,0 +1,6 @@ +#ifndef HAKUGEK2_H +#define HAKUGEK2_H + +#include "magic.h" + +#endif diff --git a/tools/builder/builder/objdiff.go b/tools/builder/builder/objdiff.go index 0d159d64..2c334913 100644 --- a/tools/builder/builder/objdiff.go +++ b/tools/builder/builder/objdiff.go @@ -117,6 +117,7 @@ var metaOverlays = map[string]metaOverlay{ "kaen2": {"kaen2", "magic", "KAEN2"}, "gas": {"gas", "magic", "GAS"}, "hakugek1": {"hakugek1", "magic", "HAKUGEK1"}, + "hakugek2": {"hakugek2", "magic", "HAKUGEK2"}, } func makeObjdiffConfig(b BuildConfig) objdiffConfig { From 084282b7e593d261e7ea7179f9528a20598839cf Mon Sep 17 00:00:00 2001 From: j3lee Date: Mon, 12 Oct 2026 12:29:27 +0930 Subject: [PATCH 06/10] magic: name the effects in the file headers --- src/magic/gas.c | 2 +- src/magic/hakugek1.c | 2 +- src/magic/hakugek2.c | 2 +- src/magic/kaen.c | 3 ++- src/magic/kaen2.c | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/magic/gas.c b/src/magic/gas.c index ef3ebf21..9b555226 100644 --- a/src/magic/gas.c +++ b/src/magic/gas.c @@ -5,7 +5,7 @@ #include "gas.h" #include "../battle/battle.h" -// Effect GAS. +// Effect shared by St. Elmos Fire (セントエルモスファイアー), Cold (冷気) and Diamond Fire (ダイヤファイア). void func_801B0F84(s32 targetMask, s32 callbackArg); diff --git a/src/magic/hakugek1.c b/src/magic/hakugek1.c index 5dec97da..523032ba 100644 --- a/src/magic/hakugek1.c +++ b/src/magic/hakugek1.c @@ -5,7 +5,7 @@ #include "hakugek1.h" #include "../battle/battle.h" -// Effect HAKUGEK1. +// Big Bomber (ビッグボンバー / Biggu Bonba). void func_801B1290(s32 targetMask, s32 callbackArg); diff --git a/src/magic/hakugek2.c b/src/magic/hakugek2.c index d416ed6f..f37dec79 100644 --- a/src/magic/hakugek2.c +++ b/src/magic/hakugek2.c @@ -5,7 +5,7 @@ #include "hakugek2.h" #include "../battle/battle.h" -// Effect HAKUGEK2. +// Effect shared by Seed Bullet (シード弾) and Throw (投げる). void func_801B117C(s32 targetMask, s32 callbackArg); diff --git a/src/magic/kaen.c b/src/magic/kaen.c index 4460a8c4..14d04d6d 100644 --- a/src/magic/kaen.c +++ b/src/magic/kaen.c @@ -5,7 +5,8 @@ #include "kaen.h" #include "../battle/battle.h" -// Effect KAEN. +// Effect shared by Fire Veil (火とん), Fireball (ファイアボール), Flame (火炎), Ghenghana (ゲヘナガナー) +// and Turk Light (タークス光線). void func_801B0F6C(s32 targetMask, s32 callbackArg); diff --git a/src/magic/kaen2.c b/src/magic/kaen2.c index ffcc231c..ba9a6a29 100644 --- a/src/magic/kaen2.c +++ b/src/magic/kaen2.c @@ -5,7 +5,7 @@ #include "kaen2.h" #include "../battle/battle.h" -// Effect KAEN2. +// Effect shared by Fire Shell (火炎弾), Gush (噴火) and S-Mine (Sマイン). void func_801B10BC(s32 targetMask, s32 callbackArg); From b9f01b5209df2b28fbc925389cd2e09946f802d6 Mon Sep 17 00:00:00 2001 From: j3lee Date: Mon, 12 Oct 2026 12:33:18 +0930 Subject: [PATCH 07/10] magic: name the effect functions Names from the label walker's table (labels-quest/NAMES-bundles.tsv, sure rows only); renames only. --- config/symbols.magic-gas.us.txt | 20 ++++++------- config/symbols.magic-hakugek1.us.txt | 20 ++++++------- config/symbols.magic-hakugek2.us.txt | 20 ++++++------- config/symbols.magic-kaen.us.txt | 18 ++++++------ config/symbols.magic-kaen2.us.txt | 20 ++++++------- src/magic/gas.c | 40 ++++++++++++------------- src/magic/hakugek1.c | 38 ++++++++++++------------ src/magic/hakugek2.c | 38 ++++++++++++------------ src/magic/kaen.c | 36 +++++++++++------------ src/magic/kaen2.c | 44 ++++++++++++++-------------- 10 files changed, 147 insertions(+), 147 deletions(-) diff --git a/config/symbols.magic-gas.us.txt b/config/symbols.magic-gas.us.txt index 31bd6c75..a4323cd4 100644 --- a/config/symbols.magic-gas.us.txt +++ b/config/symbols.magic-gas.us.txt @@ -1,13 +1,13 @@ -func_801B0010 = 0x801B0010; -func_801B0030 = 0x801B0030; -func_801B01DC = 0x801B01DC; -func_801B030C = 0x801B030C; +MAGIC_Gas = 0x801B0010; +GasTargetCenterCalc = 0x801B0030; +GasSprayVectorCalc = 0x801B01DC; +GasSpriteMatrixSetup = 0x801B030C; GasDoubleBufferFlip = 0x801B046C; -func_801B04D8 = 0x801B04D8; -func_801B05DC = 0x801B05DC; -func_801B080C = 0x801B080C; -func_801B0AEC = 0x801B0AEC; -func_801B0EAC = 0x801B0EAC; -func_801B0F84 = 0x801B0F84; +GasFlameSpriteTick = 0x801B04D8; +GasEmberTick = 0x801B05DC; +GasFireballTick = 0x801B080C; +GasTargetTick = 0x801B0AEC; +GasTargetSetup = 0x801B0EAC; +GasStart = 0x801B0F84; g_GasPrimBuffer = 0x801D3FF8; g_GasBufferPtr = 0x801EBFF8; diff --git a/config/symbols.magic-hakugek1.us.txt b/config/symbols.magic-hakugek1.us.txt index 50fdca53..3153d686 100644 --- a/config/symbols.magic-hakugek1.us.txt +++ b/config/symbols.magic-hakugek1.us.txt @@ -1,14 +1,14 @@ -func_801B0000 = 0x801B0000; -func_801B0020 = 0x801B0020; -func_801B01CC = 0x801B01CC; -func_801B02FC = 0x801B02FC; +MAGIC_Hakugek1 = 0x801B0000; +Hakugek1TargetCenterCalc = 0x801B0020; +Hakugek1SprayVectorCalc = 0x801B01CC; +Hakugek1SpriteMatrixSetup = 0x801B02FC; Hakugek1DoubleBufferFlip = 0x801B045C; func_801B04C8 = 0x801B04C8; -func_801B062C = 0x801B062C; -func_801B0878 = 0x801B0878; -func_801B09F0 = 0x801B09F0; -func_801B0D84 = 0x801B0D84; -func_801B11B4 = 0x801B11B4; -func_801B1290 = 0x801B1290; +Hakugek1DebrisTick = 0x801B062C; +Hakugek1PillarRiseTick = 0x801B0878; +Hakugek1ShockwaveTick = 0x801B09F0; +Hakugek1TargetTick = 0x801B0D84; +Hakugek1TargetSetup = 0x801B11B4; +Hakugek1Start = 0x801B1290; g_Hakugek1PrimBuffer = 0x801D2A80; g_Hakugek1BufferPtr = 0x801EAA80; diff --git a/config/symbols.magic-hakugek2.us.txt b/config/symbols.magic-hakugek2.us.txt index 99ac4519..905ba2dc 100644 --- a/config/symbols.magic-hakugek2.us.txt +++ b/config/symbols.magic-hakugek2.us.txt @@ -1,14 +1,14 @@ -func_801B0000 = 0x801B0000; -func_801B0020 = 0x801B0020; -func_801B01CC = 0x801B01CC; -func_801B02FC = 0x801B02FC; +MAGIC_Hakugek2 = 0x801B0000; +Hakugek2TargetCenterCalc = 0x801B0020; +Hakugek2SprayVectorCalc = 0x801B01CC; +Hakugek2SpriteMatrixSetup = 0x801B02FC; Hakugek2DoubleBufferFlip = 0x801B045C; func_801B04C8 = 0x801B04C8; -func_801B062C = 0x801B062C; -func_801B0878 = 0x801B0878; -func_801B09E0 = 0x801B09E0; -func_801B0D64 = 0x801B0D64; -func_801B10A0 = 0x801B10A0; -func_801B117C = 0x801B117C; +Hakugek2DebrisTick = 0x801B062C; +Hakugek2PillarRiseTick = 0x801B0878; +Hakugek2ShockwaveTick = 0x801B09E0; +Hakugek2TargetTick = 0x801B0D64; +Hakugek2TargetSetup = 0x801B10A0; +Hakugek2Start = 0x801B117C; g_Hakugek2PrimBuffer = 0x801D296C; g_Hakugek2BufferPtr = 0x801EA96C; diff --git a/config/symbols.magic-kaen.us.txt b/config/symbols.magic-kaen.us.txt index edd880a4..57ceccf4 100644 --- a/config/symbols.magic-kaen.us.txt +++ b/config/symbols.magic-kaen.us.txt @@ -1,13 +1,13 @@ -func_801B0010 = 0x801B0010; -func_801B0030 = 0x801B0030; -func_801B01DC = 0x801B01DC; -func_801B030C = 0x801B030C; +MAGIC_Kaen = 0x801B0010; +KaenTargetCenterCalc = 0x801B0030; +KaenSprayVectorCalc = 0x801B01DC; +KaenSpriteMatrixSetup = 0x801B030C; KaenDoubleBufferFlip = 0x801B046C; -func_801B04D8 = 0x801B04D8; -func_801B05DC = 0x801B05DC; -func_801B080C = 0x801B080C; -func_801B0AEC = 0x801B0AEC; -func_801B0EAC = 0x801B0EAC; +KaenFlameSpriteTick = 0x801B04D8; +KaenEmberTick = 0x801B05DC; +KaenFireballTick = 0x801B080C; +KaenTargetTick = 0x801B0AEC; +KaenTargetSetup = 0x801B0EAC; func_801B0F6C = 0x801B0F6C; g_KaenPrimBuffer = 0x801D3F30; g_KaenBufferPtr = 0x801EBF30; diff --git a/config/symbols.magic-kaen2.us.txt b/config/symbols.magic-kaen2.us.txt index 4c0d1a7d..aa1207be 100644 --- a/config/symbols.magic-kaen2.us.txt +++ b/config/symbols.magic-kaen2.us.txt @@ -1,13 +1,13 @@ -func_801B0000 = 0x801B0000; -func_801B0020 = 0x801B0020; -func_801B01CC = 0x801B01CC; -func_801B02FC = 0x801B02FC; +MAGIC_Kaen2 = 0x801B0000; +Kaen2TargetCenterCalc = 0x801B0020; +Kaen2SprayVectorCalc = 0x801B01CC; +Kaen2SpriteMatrixSetup = 0x801B02FC; Kaen2DoubleBufferFlip = 0x801B045C; -func_801B04C8 = 0x801B04C8; -func_801B0658 = 0x801B0658; -func_801B0888 = 0x801B0888; -func_801B0B40 = 0x801B0B40; -func_801B0FF0 = 0x801B0FF0; -func_801B10BC = 0x801B10BC; +Kaen2FlameSpriteTick = 0x801B04C8; +Kaen2EmberTick = 0x801B0658; +Kaen2FireballTick = 0x801B0888; +Kaen2TargetTick = 0x801B0B40; +Kaen2TargetSetup = 0x801B0FF0; +Kaen2Start = 0x801B10BC; g_Kaen2PrimBuffer = 0x801D4140; g_Kaen2BufferPtr = 0x801EC140; diff --git a/src/magic/gas.c b/src/magic/gas.c index 9b555226..5bdbe113 100644 --- a/src/magic/gas.c +++ b/src/magic/gas.c @@ -7,7 +7,7 @@ // Effect shared by St. Elmos Fire (セントエルモスファイアー), Cold (冷気) and Diamond Fire (ダイヤファイア). -void func_801B0F84(s32 targetMask, s32 callbackArg); +void GasStart(s32 targetMask, s32 callbackArg); // Primitive buffer pages, one 0xC000 page per double-buffered frame. extern u8 g_GasPrimBuffer[2][0xC000]; @@ -43,12 +43,12 @@ extern u_long D_801B0FF0[]; extern void* D_80163C74; s32 BattleDetachedRegister(void (*func)(void)); void func_800BBA84(u16 arg0, s32 arg1, s32 arg2); -void func_801B0AEC(void); +void GasTargetTick(void); // Same as MAGIC_Biora. -void func_801B0010(s32 targetMask, s32 callbackArg) { func_801B0F84(targetMask, callbackArg); } +void MAGIC_Gas(s32 targetMask, s32 callbackArg) { GasStart(targetMask, callbackArg); } -void func_801B0030(s16 targetMask, SVECTOR* out) { +void GasTargetCenterCalc(s16 targetMask, SVECTOR* out) { VECTOR sum; SVECTOR pos; s16 i; @@ -70,7 +70,7 @@ void func_801B0030(s16 targetMask, SVECTOR* out) { out->vz = sum.vz / count; } -void func_801B01DC(s32 offset, s16 spread, SVECTOR* out) { +void GasSprayVectorCalc(s32 offset, s16 spread, SVECTOR* out) { SVECTOR in; SVECTOR rot; MATRIX matrix; @@ -85,7 +85,7 @@ void func_801B01DC(s32 offset, s16 spread, SVECTOR* out) { ApplyMatrixSV(&matrix, &in, out); } -void func_801B030C(SVECTOR* pos, SVECTOR* rot, s16 scale, s32 offset) { +void GasSpriteMatrixSetup(SVECTOR* pos, SVECTOR* rot, s16 scale, s32 offset) { MATRIX matrix; MATRIX rotated; VECTOR dir; @@ -125,7 +125,7 @@ static void GasDoubleBufferFlip(void) { } } -void func_801B04D8(void) { +void GasFlameSpriteTick(void) { GasData* effect; effect = &g_BattleDetachedSlots[g_BattleDetachedCursor]; @@ -141,7 +141,7 @@ void func_801B04D8(void) { } } -void func_801B05DC(void) { +void GasEmberTick(void) { MATRIX rotated; MATRIX matrix; SVECTOR rot; @@ -197,7 +197,7 @@ void func_801B05DC(void) { } } -void func_801B080C(void) { +void GasFireballTick(void) { MATRIX dirMatrix; MATRIX matrix; MATRIX composed; @@ -228,7 +228,7 @@ void func_801B080C(void) { effect->Pos.vz += effect->PartPos.vz; effect->AnimationFrame++; if (effect->AnimationFrame == 8) { - child = &g_BattleDetachedSlots[BattleDetachedRegister(func_801B04D8)]; + child = &g_BattleDetachedSlots[BattleDetachedRegister(GasFlameSpriteTick)]; child->Pos.vx = effect->Pos.vx + rand() % 800 - 400; child->Pos.vy = effect->Pos.vy + rand() % 800 - 400; child->Pos.vz = effect->Pos.vz + rand() % 800 - 400; @@ -238,7 +238,7 @@ void func_801B080C(void) { } } -void func_801B0AEC(void) { +void GasTargetTick(void) { s32 pad[12]; // match: unused, gives the original stack frame GasData* effect; GasData* child; @@ -247,12 +247,12 @@ void func_801B0AEC(void) { effect = &g_BattleEffectSlots[g_BattleEffectCursor]; if (D_80062D98 == 0) { if (effect->AnimationFrame == 0) { - child = &g_BattleDetachedSlots[BattleDetachedRegister(func_801B04D8)]; + child = &g_BattleDetachedSlots[BattleDetachedRegister(GasFlameSpriteTick)]; child->Pos.vx = effect->Pos.vx; child->Pos.vy = effect->Pos.vy; child->Pos.vz = effect->Pos.vz; child->unk16 = 2; - child = &g_BattleEffectSlots[BattleEffectRegister(func_801B080C)]; + child = &g_BattleEffectSlots[BattleEffectRegister(GasFireballTick)]; child->Pos.vx = effect->Pos.vx; child->Pos.vy = effect->Pos.vy; child->Pos.vz = effect->Pos.vz; @@ -263,18 +263,18 @@ void func_801B0AEC(void) { if (effect->AnimationFrame == 8) { i = 0; do { - child = &g_BattleEffectSlots[BattleEffectRegister(func_801B05DC)]; + child = &g_BattleEffectSlots[BattleEffectRegister(GasEmberTick)]; child->Pos.vx = effect->PartPos.vx + rand() % 400 - 200; child->Pos.vz = effect->PartPos.vz + rand() % 400 - 200; child->Pos.vy = 0; - func_801B01DC(-250, 100, &child->PartPos); + GasSprayVectorCalc(-250, 100, &child->PartPos); child->unk16 = rand() % 20; i++; } while (i < 12); func_800BBA84(0xFA, effect->unk1C, 0); } if (effect->AnimationFrame >= 12 && effect->AnimationFrame < 19) { - child = &g_BattleDetachedSlots[BattleDetachedRegister(func_801B04D8)]; + child = &g_BattleDetachedSlots[BattleDetachedRegister(GasFlameSpriteTick)]; child->Pos.vx = effect->PartPos.vx + rand() % 1200 - 600; child->Pos.vy = effect->PartPos.vy + rand() % 1200 - 600; child->Pos.vz = effect->PartPos.vz + rand() % 1200 - 600; @@ -290,18 +290,18 @@ void func_801B0AEC(void) { } } -void func_801B0EAC(s32 target, s32 callbackArg) { +void GasTargetSetup(s32 target, s32 callbackArg) { GasData* effect; - effect = &g_BattleEffectSlots[BattleEffectRegister(func_801B0AEC)]; + effect = &g_BattleEffectSlots[BattleEffectRegister(GasTargetTick)]; BattleGetPartPosition(callbackArg, g_BattleModels[callbackArg].boneIndices[8], &effect->Pos); BattleGetPartPosition(target, g_BattleModels[target].boneIndices[0], &effect->PartPos); effect->unk1C = target; func_800BBA84(0x163, callbackArg, 0); } -void func_801B0F84(s32 targetMask, s32 callbackArg) { +void GasStart(s32 targetMask, s32 callbackArg) { BattleEffectRegister(GasDoubleBufferFlip); BattleSetLoadTimToVram(D_801B0FF0, 0, 0, 0); - MagicAnimationRegister(targetMask, callbackArg, 4, func_801B0EAC); + MagicAnimationRegister(targetMask, callbackArg, 4, GasTargetSetup); } diff --git a/src/magic/hakugek1.c b/src/magic/hakugek1.c index 523032ba..e1173d85 100644 --- a/src/magic/hakugek1.c +++ b/src/magic/hakugek1.c @@ -7,7 +7,7 @@ // Big Bomber (ビッグボンバー / Biggu Bonba). -void func_801B1290(s32 targetMask, s32 callbackArg); +void Hakugek1Start(s32 targetMask, s32 callbackArg); // Primitive buffer pages, one 0xC000 page per double-buffered frame. extern u8 g_Hakugek1PrimBuffer[2][0xC000]; @@ -44,14 +44,14 @@ extern s32 D_801D20E4[]; extern u16 D_801D2A74[]; extern u_long D_801B12FC[]; extern void* D_80163C74; -void func_801B11B4(s32 target, s32 callbackArg); +void Hakugek1TargetSetup(s32 target, s32 callbackArg); void func_800BBA84(u16 arg0, s32 arg1, s32 arg2); -void func_801B0D84(void); +void Hakugek1TargetTick(void); // Same as MAGIC_Biora. -void func_801B0000(s32 targetMask, s32 callbackArg) { func_801B1290(targetMask, callbackArg); } +void MAGIC_Hakugek1(s32 targetMask, s32 callbackArg) { Hakugek1Start(targetMask, callbackArg); } -void func_801B0020(s16 targetMask, SVECTOR* out) { +void Hakugek1TargetCenterCalc(s16 targetMask, SVECTOR* out) { VECTOR sum; SVECTOR pos; s16 i; @@ -73,7 +73,7 @@ void func_801B0020(s16 targetMask, SVECTOR* out) { out->vz = sum.vz / count; } -void func_801B01CC(s32 offset, s16 spread, SVECTOR* out) { +void Hakugek1SprayVectorCalc(s32 offset, s16 spread, SVECTOR* out) { SVECTOR in; SVECTOR rot; MATRIX matrix; @@ -88,7 +88,7 @@ void func_801B01CC(s32 offset, s16 spread, SVECTOR* out) { ApplyMatrixSV(&matrix, &in, out); } -void func_801B02FC(SVECTOR* pos, SVECTOR* rot, s16 scale, s32 offset) { +void Hakugek1SpriteMatrixSetup(SVECTOR* pos, SVECTOR* rot, s16 scale, s32 offset) { MATRIX matrix; MATRIX rotated; VECTOR dir; @@ -160,7 +160,7 @@ void func_801B04C8(void) { } } -void func_801B062C(void) { +void Hakugek1DebrisTick(void) { MATRIX rotated; MATRIX matrix; SVECTOR rot; @@ -206,7 +206,7 @@ void func_801B062C(void) { } } } -void func_801B0878(void) { +void Hakugek1PillarRiseTick(void) { SVECTOR rot; MATRIX matrix; MATRIX composed; @@ -241,7 +241,7 @@ void func_801B0878(void) { } } -void func_801B09F0(void) { +void Hakugek1ShockwaveTick(void) { SVECTOR rot; MATRIX matrix; MATRIX composed; @@ -304,7 +304,7 @@ void func_801B09F0(void) { } } -void func_801B0D84(void) { +void Hakugek1TargetTick(void) { SVECTOR pos; s32 pad[10]; // unused; gives the function its 0x60 byte stack frame (match) Hakugek1Data* effect; @@ -336,21 +336,21 @@ void func_801B0D84(void) { pos.vz = effect->PartPos.vz + (rsin((i << 16 >> 5) + 0x200) * 800 >> 12); j = 0; do { - child = &g_BattleEffectSlots[BattleEffectRegister(func_801B062C)]; + child = &g_BattleEffectSlots[BattleEffectRegister(Hakugek1DebrisTick)]; child->Pos.vx = pos.vx + rand() % 400 - 200; child->Pos.vz = pos.vz + rand() % 400 - 200; child->Pos.vy = 0; - func_801B01CC(-300, 50, &child->PartPos); + Hakugek1SprayVectorCalc(-300, 50, &child->PartPos); child->unk16 = rand() % 9; j++; } while (j < 24); - child = &g_BattleEffectSlots[BattleEffectRegister(func_801B09F0)]; + child = &g_BattleEffectSlots[BattleEffectRegister(Hakugek1ShockwaveTick)]; child->Pos.vx = pos.vx; child->Pos.vy = 0; child->Pos.vz = pos.vz; j = 0; do { - child = &g_BattleEffectSlots[BattleEffectRegister(func_801B0878)]; + child = &g_BattleEffectSlots[BattleEffectRegister(Hakugek1PillarRiseTick)]; child->Pos.vx = pos.vx; child->Pos.vy = pos.vy; child->Pos.vz = pos.vz; @@ -374,10 +374,10 @@ void func_801B0D84(void) { } } -void func_801B11B4(s32 target, s32 callbackArg) { +void Hakugek1TargetSetup(s32 target, s32 callbackArg) { Hakugek1Data* effect; - effect = &g_BattleEffectSlots[BattleEffectRegister(func_801B0D84)]; + effect = &g_BattleEffectSlots[BattleEffectRegister(Hakugek1TargetTick)]; BattleGetPartPosition(callbackArg, g_BattleModels[callbackArg].boneIndices[0], &effect->Pos); BattleGetPartPosition(target, g_BattleModels[target].boneIndices[0], &effect->PartPos); effect->unk1C = target; @@ -385,8 +385,8 @@ void func_801B11B4(s32 target, s32 callbackArg) { func_800BBA84(0x14, callbackArg, 0); } -void func_801B1290(s32 targetMask, s32 callbackArg) { +void Hakugek1Start(s32 targetMask, s32 callbackArg) { BattleEffectRegister(Hakugek1DoubleBufferFlip); BattleSetLoadTimToVram(D_801B12FC, 0, 0, 0); - MagicAnimationRegister(targetMask, callbackArg, 4, func_801B11B4); + MagicAnimationRegister(targetMask, callbackArg, 4, Hakugek1TargetSetup); } diff --git a/src/magic/hakugek2.c b/src/magic/hakugek2.c index f37dec79..f0a64da0 100644 --- a/src/magic/hakugek2.c +++ b/src/magic/hakugek2.c @@ -7,7 +7,7 @@ // Effect shared by Seed Bullet (シード弾) and Throw (投げる). -void func_801B117C(s32 targetMask, s32 callbackArg); +void Hakugek2Start(s32 targetMask, s32 callbackArg); // Primitive buffer pages, one 0xC000 page per double-buffered frame. extern u8 g_Hakugek2PrimBuffer[2][0xC000]; @@ -44,13 +44,13 @@ extern s32 D_801D1FD0[]; extern u16 D_801D2960[]; extern u_long D_801B11E8[]; extern void* D_80163C74; -void func_801B10A0(s32 target, s32 callbackArg); -void func_801B0D64(void); +void Hakugek2TargetSetup(s32 target, s32 callbackArg); +void Hakugek2TargetTick(void); // Same as MAGIC_Biora. -void func_801B0000(s32 targetMask, s32 callbackArg) { func_801B117C(targetMask, callbackArg); } +void MAGIC_Hakugek2(s32 targetMask, s32 callbackArg) { Hakugek2Start(targetMask, callbackArg); } -void func_801B0020(s16 targetMask, SVECTOR* out) { +void Hakugek2TargetCenterCalc(s16 targetMask, SVECTOR* out) { VECTOR sum; SVECTOR pos; s16 i; @@ -72,7 +72,7 @@ void func_801B0020(s16 targetMask, SVECTOR* out) { out->vz = sum.vz / count; } -void func_801B01CC(s32 offset, s16 spread, SVECTOR* out) { +void Hakugek2SprayVectorCalc(s32 offset, s16 spread, SVECTOR* out) { SVECTOR in; SVECTOR rot; MATRIX matrix; @@ -87,7 +87,7 @@ void func_801B01CC(s32 offset, s16 spread, SVECTOR* out) { ApplyMatrixSV(&matrix, &in, out); } -void func_801B02FC(SVECTOR* pos, SVECTOR* rot, s16 scale, s32 offset) { +void Hakugek2SpriteMatrixSetup(SVECTOR* pos, SVECTOR* rot, s16 scale, s32 offset) { MATRIX matrix; MATRIX rotated; VECTOR dir; @@ -159,7 +159,7 @@ void func_801B04C8(void) { } } -void func_801B062C(void) { +void Hakugek2DebrisTick(void) { MATRIX rotated; MATRIX matrix; SVECTOR rot; @@ -206,7 +206,7 @@ void func_801B062C(void) { } } -void func_801B0878(void) { +void Hakugek2PillarRiseTick(void) { SVECTOR rot; MATRIX matrix; MATRIX composed; @@ -240,7 +240,7 @@ void func_801B0878(void) { } } -void func_801B09E0(void) { +void Hakugek2ShockwaveTick(void) { SVECTOR rot; MATRIX matrix; MATRIX composed; @@ -301,7 +301,7 @@ void func_801B09E0(void) { } } } -void func_801B0D64(void) { +void Hakugek2TargetTick(void) { s32 pad[12]; // unused; gives the function its 0x58 byte stack frame (match) Hakugek2Data* effect; Hakugek2Data* child; @@ -322,21 +322,21 @@ void func_801B0D64(void) { { j = 0; do { - child = &g_BattleEffectSlots[BattleEffectRegister(func_801B062C)]; + child = &g_BattleEffectSlots[BattleEffectRegister(Hakugek2DebrisTick)]; child->Pos.vx = effect->PartPos.vx + rand() % 400 - 200; child->Pos.vz = effect->PartPos.vz + rand() % 400 - 200; child->Pos.vy = 0; - func_801B01CC(-300, 50, &child->PartPos); + Hakugek2SprayVectorCalc(-300, 50, &child->PartPos); child->unk16 = rand() % 9; j++; } while (j < 24); - child = &g_BattleEffectSlots[BattleEffectRegister(func_801B09E0)]; + child = &g_BattleEffectSlots[BattleEffectRegister(Hakugek2ShockwaveTick)]; child->Pos.vx = effect->PartPos.vx; child->Pos.vy = 0; child->Pos.vz = effect->PartPos.vz; j = 0; do { - child = &g_BattleEffectSlots[BattleEffectRegister(func_801B0878)]; + child = &g_BattleEffectSlots[BattleEffectRegister(Hakugek2PillarRiseTick)]; child->Pos.vx = effect->PartPos.vx; child->Pos.vy = effect->PartPos.vy; child->Pos.vz = effect->PartPos.vz; @@ -359,10 +359,10 @@ void func_801B0D64(void) { } } -void func_801B10A0(s32 target, s32 callbackArg) { +void Hakugek2TargetSetup(s32 target, s32 callbackArg) { Hakugek2Data* effect; - effect = &g_BattleEffectSlots[BattleEffectRegister(func_801B0D64)]; + effect = &g_BattleEffectSlots[BattleEffectRegister(Hakugek2TargetTick)]; BattleGetPartPosition(callbackArg, g_BattleModels[callbackArg].boneIndices[0], &effect->Pos); BattleGetPartPosition(target, g_BattleModels[target].boneIndices[0], &effect->PartPos); effect->unk1C = target; @@ -370,8 +370,8 @@ void func_801B10A0(s32 target, s32 callbackArg) { func_800BBA84(0x14, callbackArg, 0); } -void func_801B117C(s32 targetMask, s32 callbackArg) { +void Hakugek2Start(s32 targetMask, s32 callbackArg) { BattleEffectRegister(Hakugek2DoubleBufferFlip); BattleSetLoadTimToVram(D_801B11E8, 0, 0, 0); - MagicAnimationRegister(targetMask, callbackArg, 4, func_801B10A0); + MagicAnimationRegister(targetMask, callbackArg, 4, Hakugek2TargetSetup); } diff --git a/src/magic/kaen.c b/src/magic/kaen.c index 14d04d6d..51f2d3ad 100644 --- a/src/magic/kaen.c +++ b/src/magic/kaen.c @@ -44,12 +44,12 @@ extern u_long D_801B0FE8[]; extern void* D_80163C74; s32 BattleDetachedRegister(void (*func)(void)); void func_800BBA84(u16 arg0, s32 arg1, s32 arg2); -void func_801B0AEC(void); +void KaenTargetTick(void); // Same as MAGIC_Biora. -void func_801B0010(s32 targetMask, s32 callbackArg) { func_801B0F6C(targetMask, callbackArg); } +void MAGIC_Kaen(s32 targetMask, s32 callbackArg) { func_801B0F6C(targetMask, callbackArg); } -void func_801B0030(s16 targetMask, SVECTOR* out) { +void KaenTargetCenterCalc(s16 targetMask, SVECTOR* out) { VECTOR sum; SVECTOR pos; s16 i; @@ -71,7 +71,7 @@ void func_801B0030(s16 targetMask, SVECTOR* out) { out->vz = sum.vz / count; } -void func_801B01DC(s32 offset, s16 spread, SVECTOR* out) { +void KaenSprayVectorCalc(s32 offset, s16 spread, SVECTOR* out) { SVECTOR in; SVECTOR rot; MATRIX matrix; @@ -86,7 +86,7 @@ void func_801B01DC(s32 offset, s16 spread, SVECTOR* out) { ApplyMatrixSV(&matrix, &in, out); } -void func_801B030C(SVECTOR* pos, SVECTOR* rot, s16 scale, s32 offset) { +void KaenSpriteMatrixSetup(SVECTOR* pos, SVECTOR* rot, s16 scale, s32 offset) { MATRIX matrix; MATRIX rotated; VECTOR dir; @@ -126,7 +126,7 @@ static void KaenDoubleBufferFlip(void) { } } -void func_801B04D8(void) { +void KaenFlameSpriteTick(void) { KaenData* effect; effect = &g_BattleDetachedSlots[g_BattleDetachedCursor]; @@ -142,7 +142,7 @@ void func_801B04D8(void) { } } -void func_801B05DC(void) { +void KaenEmberTick(void) { MATRIX rotated; MATRIX matrix; SVECTOR rot; @@ -198,7 +198,7 @@ void func_801B05DC(void) { } } -void func_801B080C(void) { +void KaenFireballTick(void) { MATRIX dirMatrix; MATRIX matrix; MATRIX composed; @@ -229,7 +229,7 @@ void func_801B080C(void) { effect->Pos.vz += effect->PartPos.vz; effect->AnimationFrame++; if (effect->AnimationFrame == 8) { - child = &g_BattleDetachedSlots[BattleDetachedRegister(func_801B04D8)]; + child = &g_BattleDetachedSlots[BattleDetachedRegister(KaenFlameSpriteTick)]; child->Pos.vx = effect->Pos.vx + rand() % 800 - 400; child->Pos.vy = effect->Pos.vy + rand() % 800 - 400; child->Pos.vz = effect->Pos.vz + rand() % 800 - 400; @@ -239,7 +239,7 @@ void func_801B080C(void) { } } -void func_801B0AEC(void) { +void KaenTargetTick(void) { s32 pad[12]; // match: unused, gives the original stack frame KaenData* effect; KaenData* child; @@ -248,12 +248,12 @@ void func_801B0AEC(void) { effect = &g_BattleEffectSlots[g_BattleEffectCursor]; if (D_80062D98 == 0) { if (effect->AnimationFrame == 0) { - child = &g_BattleDetachedSlots[BattleDetachedRegister(func_801B04D8)]; + child = &g_BattleDetachedSlots[BattleDetachedRegister(KaenFlameSpriteTick)]; child->Pos.vx = effect->Pos.vx; child->Pos.vy = effect->Pos.vy; child->Pos.vz = effect->Pos.vz; child->unk16 = 2; - child = &g_BattleEffectSlots[BattleEffectRegister(func_801B080C)]; + child = &g_BattleEffectSlots[BattleEffectRegister(KaenFireballTick)]; child->Pos.vx = effect->Pos.vx; child->Pos.vy = effect->Pos.vy; child->Pos.vz = effect->Pos.vz; @@ -264,18 +264,18 @@ void func_801B0AEC(void) { if (effect->AnimationFrame == 8) { i = 0; do { - child = &g_BattleEffectSlots[BattleEffectRegister(func_801B05DC)]; + child = &g_BattleEffectSlots[BattleEffectRegister(KaenEmberTick)]; child->Pos.vx = effect->PartPos.vx + rand() % 400 - 200; child->Pos.vz = effect->PartPos.vz + rand() % 400 - 200; child->Pos.vy = 0; - func_801B01DC(-250, 100, &child->PartPos); + KaenSprayVectorCalc(-250, 100, &child->PartPos); child->unk16 = rand() % 20; i++; } while (i < 8); func_800BBA84(0xFA, effect->unk1C, 0); } if (effect->AnimationFrame >= 12 && effect->AnimationFrame < 19) { - child = &g_BattleDetachedSlots[BattleDetachedRegister(func_801B04D8)]; + child = &g_BattleDetachedSlots[BattleDetachedRegister(KaenFlameSpriteTick)]; child->Pos.vx = effect->PartPos.vx + rand() % 1200 - 600; child->Pos.vy = effect->PartPos.vy + rand() % 1200 - 600; child->Pos.vz = effect->PartPos.vz + rand() % 1200 - 600; @@ -291,10 +291,10 @@ void func_801B0AEC(void) { } } -void func_801B0EAC(s32 target, s32 callbackArg) { +void KaenTargetSetup(s32 target, s32 callbackArg) { KaenData* effect; - effect = &g_BattleEffectSlots[BattleEffectRegister(func_801B0AEC)]; + effect = &g_BattleEffectSlots[BattleEffectRegister(KaenTargetTick)]; BattleGetPartPosition(callbackArg, g_BattleModels[callbackArg].boneIndices[8], &effect->Pos); BattleGetPartPosition(target, g_BattleModels[target].boneIndices[0], &effect->PartPos); effect->unk1C = target; @@ -303,6 +303,6 @@ void func_801B0EAC(s32 target, s32 callbackArg) { void func_801B0F6C(s32 targetMask, s32 callbackArg) { BattleEffectRegister(KaenDoubleBufferFlip); BattleSetLoadTimToVram(D_801B0FE8, 0, 0, 0); - MagicAnimationRegister(targetMask, callbackArg, 4, func_801B0EAC); + MagicAnimationRegister(targetMask, callbackArg, 4, KaenTargetSetup); func_800BBA84(0x163, callbackArg, 0); } diff --git a/src/magic/kaen2.c b/src/magic/kaen2.c index ba9a6a29..5c123177 100644 --- a/src/magic/kaen2.c +++ b/src/magic/kaen2.c @@ -7,7 +7,7 @@ // Effect shared by Fire Shell (火炎弾), Gush (噴火) and S-Mine (Sマイン). -void func_801B10BC(s32 targetMask, s32 callbackArg); +void Kaen2Start(s32 targetMask, s32 callbackArg); // Primitive buffer pages, one 0xC000 page per double-buffered frame. extern u8 g_Kaen2PrimBuffer[2][0xC000]; @@ -42,14 +42,14 @@ extern s32* D_801D4120[]; extern u_long D_801B1128[]; extern void* D_80163C74; s32 BattleDetachedRegister(void (*func)(void)); -void func_801B0FF0(s32 target, s32 callbackArg); -void func_801B04C8(void); -void func_801B0B40(void); +void Kaen2TargetSetup(s32 target, s32 callbackArg); +void Kaen2FlameSpriteTick(void); +void Kaen2TargetTick(void); // Same as MAGIC_Biora. -void func_801B0000(s32 targetMask, s32 callbackArg) { func_801B10BC(targetMask, callbackArg); } +void MAGIC_Kaen2(s32 targetMask, s32 callbackArg) { Kaen2Start(targetMask, callbackArg); } -void func_801B0020(s16 targetMask, SVECTOR* out) { +void Kaen2TargetCenterCalc(s16 targetMask, SVECTOR* out) { VECTOR sum; SVECTOR pos; s16 i; @@ -71,7 +71,7 @@ void func_801B0020(s16 targetMask, SVECTOR* out) { out->vz = sum.vz / count; } -void func_801B01CC(s32 offset, s16 spread, SVECTOR* out) { +void Kaen2SprayVectorCalc(s32 offset, s16 spread, SVECTOR* out) { SVECTOR in; SVECTOR rot; MATRIX matrix; @@ -86,7 +86,7 @@ void func_801B01CC(s32 offset, s16 spread, SVECTOR* out) { ApplyMatrixSV(&matrix, &in, out); } -void func_801B02FC(SVECTOR* pos, SVECTOR* rot, s16 scale, s32 offset) { +void Kaen2SpriteMatrixSetup(SVECTOR* pos, SVECTOR* rot, s16 scale, s32 offset) { MATRIX matrix; MATRIX rotated; VECTOR dir; @@ -126,7 +126,7 @@ static void Kaen2DoubleBufferFlip(void) { } } -void func_801B04C8(void) { +void Kaen2FlameSpriteTick(void) { Kaen2Data* effect; effect = &g_BattleDetachedSlots[g_BattleDetachedCursor]; @@ -150,7 +150,7 @@ void func_801B04C8(void) { } } -void func_801B0658(void) { +void Kaen2EmberTick(void) { MATRIX rotated; MATRIX matrix; SVECTOR rot; @@ -206,7 +206,7 @@ void func_801B0658(void) { } } -void func_801B0888(void) { +void Kaen2FireballTick(void) { MATRIX dirMatrix; MATRIX matrix; MATRIX composed; @@ -235,7 +235,7 @@ void func_801B0888(void) { effect->Pos.vz += effect->PartPos.vz; effect->AnimationFrame++; if (effect->AnimationFrame == 8) { - child = &g_BattleDetachedSlots[BattleDetachedRegister(func_801B04C8)]; + child = &g_BattleDetachedSlots[BattleDetachedRegister(Kaen2FlameSpriteTick)]; child->Pos.vx = effect->Pos.vx + rand() % 800 - 400; child->Pos.vy = effect->Pos.vy + rand() % 800 - 400; child->Pos.vz = effect->Pos.vz + rand() % 800 - 400; @@ -245,7 +245,7 @@ void func_801B0888(void) { } } -void func_801B0B40(void) { +void Kaen2TargetTick(void) { SVECTOR in; SVECTOR rot; MATRIX matrix; @@ -257,12 +257,12 @@ void func_801B0B40(void) { if (D_80062D98 == 0) { if (effect->AnimationFrame < 12) { if ((effect->AnimationFrame % 4) == 0) { - child = &g_BattleDetachedSlots[BattleDetachedRegister(func_801B04C8)]; + child = &g_BattleDetachedSlots[BattleDetachedRegister(Kaen2FlameSpriteTick)]; child->Pos.vx = effect->Pos.vx; child->Pos.vy = effect->Pos.vy; child->Pos.vz = effect->Pos.vz; child->unk16 = 2; - child = &g_BattleEffectSlots[BattleEffectRegister(func_801B0888)]; + child = &g_BattleEffectSlots[BattleEffectRegister(Kaen2FireballTick)]; child->Pos.vx = effect->Pos.vx; child->Pos.vy = effect->Pos.vy; child->Pos.vz = effect->Pos.vz; @@ -275,11 +275,11 @@ void func_801B0B40(void) { if (effect->AnimationFrame == 14) { i = 0; do { - child = &g_BattleEffectSlots[BattleEffectRegister(func_801B0658)]; + child = &g_BattleEffectSlots[BattleEffectRegister(Kaen2EmberTick)]; child->Pos.vx = effect->PartPos.vx + rand() % 400 - 200; child->Pos.vz = effect->PartPos.vz + rand() % 400 - 200; child->Pos.vy = 0; - func_801B01CC(-250, 100, &child->PartPos); + Kaen2SprayVectorCalc(-250, 100, &child->PartPos); child->unk16 = rand() % 20; i++; } while (i < 8); @@ -288,7 +288,7 @@ void func_801B0B40(void) { if (effect->AnimationFrame >= 12 && effect->AnimationFrame < 19) { i = 0; do { - child = &g_BattleDetachedSlots[BattleDetachedRegister(func_801B04C8)]; + child = &g_BattleDetachedSlots[BattleDetachedRegister(Kaen2FlameSpriteTick)]; child->Pos.vx = effect->PartPos.vx + rand() % 1200 - 600; child->Pos.vy = effect->PartPos.vy + rand() % 1200 - 600; child->Pos.vz = effect->PartPos.vz + rand() % 1200 - 600; @@ -314,18 +314,18 @@ void func_801B0B40(void) { } } -void func_801B0FF0(s32 target, s32 callbackArg) { +void Kaen2TargetSetup(s32 target, s32 callbackArg) { Kaen2Data* effect; - effect = &g_BattleEffectSlots[BattleEffectRegister(func_801B0B40)]; + effect = &g_BattleEffectSlots[BattleEffectRegister(Kaen2TargetTick)]; BattleGetPartPosition(callbackArg, g_BattleModels[callbackArg].boneIndices[8], &effect->Pos); BattleGetPartPosition(target, g_BattleModels[target].boneIndices[0], &effect->PartPos); effect->unk1C = target; effect->unk1E = callbackArg; } -void func_801B10BC(s32 targetMask, s32 callbackArg) { +void Kaen2Start(s32 targetMask, s32 callbackArg) { BattleEffectRegister(Kaen2DoubleBufferFlip); BattleSetLoadTimToVram(D_801B1128, 0, 0, 0); - MagicAnimationRegister(targetMask, callbackArg, 4, func_801B0FF0); + MagicAnimationRegister(targetMask, callbackArg, 4, Kaen2TargetSetup); } From c06bf0ff8364c1b39a750fb11588cc8f29c40d03 Mon Sep 17 00:00:00 2001 From: j3lee Date: Mon, 12 Oct 2026 12:38:26 +0930 Subject: [PATCH 08/10] magic: name more effect functions Names from the label walker's table (labels-quest/NAMES-bundles.tsv, sure rows only); renames only. --- config/symbols.magic-kaen.us.txt | 2 +- src/magic/kaen.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/symbols.magic-kaen.us.txt b/config/symbols.magic-kaen.us.txt index 57ceccf4..86fe3b7e 100644 --- a/config/symbols.magic-kaen.us.txt +++ b/config/symbols.magic-kaen.us.txt @@ -8,6 +8,6 @@ KaenEmberTick = 0x801B05DC; KaenFireballTick = 0x801B080C; KaenTargetTick = 0x801B0AEC; KaenTargetSetup = 0x801B0EAC; -func_801B0F6C = 0x801B0F6C; +KaenStart = 0x801B0F6C; g_KaenPrimBuffer = 0x801D3F30; g_KaenBufferPtr = 0x801EBF30; diff --git a/src/magic/kaen.c b/src/magic/kaen.c index 51f2d3ad..9736a8f9 100644 --- a/src/magic/kaen.c +++ b/src/magic/kaen.c @@ -8,7 +8,7 @@ // Effect shared by Fire Veil (火とん), Fireball (ファイアボール), Flame (火炎), Ghenghana (ゲヘナガナー) // and Turk Light (タークス光線). -void func_801B0F6C(s32 targetMask, s32 callbackArg); +void KaenStart(s32 targetMask, s32 callbackArg); // Primitive buffer pages, one 0xC000 page per double-buffered frame. extern u8 g_KaenPrimBuffer[2][0xC000]; @@ -47,7 +47,7 @@ void func_800BBA84(u16 arg0, s32 arg1, s32 arg2); void KaenTargetTick(void); // Same as MAGIC_Biora. -void MAGIC_Kaen(s32 targetMask, s32 callbackArg) { func_801B0F6C(targetMask, callbackArg); } +void MAGIC_Kaen(s32 targetMask, s32 callbackArg) { KaenStart(targetMask, callbackArg); } void KaenTargetCenterCalc(s16 targetMask, SVECTOR* out) { VECTOR sum; @@ -300,7 +300,7 @@ void KaenTargetSetup(s32 target, s32 callbackArg) { effect->unk1C = target; } -void func_801B0F6C(s32 targetMask, s32 callbackArg) { +void KaenStart(s32 targetMask, s32 callbackArg) { BattleEffectRegister(KaenDoubleBufferFlip); BattleSetLoadTimToVram(D_801B0FE8, 0, 0, 0); MagicAnimationRegister(targetMask, callbackArg, 4, KaenTargetSetup); From 916f37a1c12ac7b91d635150256dc8361d82dfb3 Mon Sep 17 00:00:00 2001 From: j3lee Date: Mon, 12 Oct 2026 12:45:02 +0930 Subject: [PATCH 09/10] magic: name the remaining effect functions Names from the label walker's table (labels-quest/NAMES-bundles.tsv, sure rows only); renames only. --- config/symbols.magic-hakugek1.us.txt | 2 +- config/symbols.magic-hakugek2.us.txt | 2 +- src/magic/hakugek1.c | 6 +++--- src/magic/hakugek2.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/config/symbols.magic-hakugek1.us.txt b/config/symbols.magic-hakugek1.us.txt index 3153d686..f5347e0b 100644 --- a/config/symbols.magic-hakugek1.us.txt +++ b/config/symbols.magic-hakugek1.us.txt @@ -3,7 +3,7 @@ Hakugek1TargetCenterCalc = 0x801B0020; Hakugek1SprayVectorCalc = 0x801B01CC; Hakugek1SpriteMatrixSetup = 0x801B02FC; Hakugek1DoubleBufferFlip = 0x801B045C; -func_801B04C8 = 0x801B04C8; +Hakugek1FirePuffTick = 0x801B04C8; Hakugek1DebrisTick = 0x801B062C; Hakugek1PillarRiseTick = 0x801B0878; Hakugek1ShockwaveTick = 0x801B09F0; diff --git a/config/symbols.magic-hakugek2.us.txt b/config/symbols.magic-hakugek2.us.txt index 905ba2dc..d003865b 100644 --- a/config/symbols.magic-hakugek2.us.txt +++ b/config/symbols.magic-hakugek2.us.txt @@ -3,7 +3,7 @@ Hakugek2TargetCenterCalc = 0x801B0020; Hakugek2SprayVectorCalc = 0x801B01CC; Hakugek2SpriteMatrixSetup = 0x801B02FC; Hakugek2DoubleBufferFlip = 0x801B045C; -func_801B04C8 = 0x801B04C8; +Hakugek2FirePuffTick = 0x801B04C8; Hakugek2DebrisTick = 0x801B062C; Hakugek2PillarRiseTick = 0x801B0878; Hakugek2ShockwaveTick = 0x801B09E0; diff --git a/src/magic/hakugek1.c b/src/magic/hakugek1.c index e1173d85..e6694548 100644 --- a/src/magic/hakugek1.c +++ b/src/magic/hakugek1.c @@ -128,7 +128,7 @@ static void Hakugek1DoubleBufferFlip(void) { } } -void func_801B04C8(void) { +void Hakugek1FirePuffTick(void) { MATRIX matrix; MATRIX rotated; s32 flag; @@ -317,12 +317,12 @@ void Hakugek1TargetTick(void) { if (D_80062D98 == 0) { if (effect->AnimationFrame == 0) { ang = ratan2(effect->PartPos.vx - effect->Pos.vx, effect->PartPos.vz - effect->Pos.vz); - child = &g_BattleEffectSlots[BattleEffectRegister(func_801B04C8)]; + child = &g_BattleEffectSlots[BattleEffectRegister(Hakugek1FirePuffTick)]; BattleGetPartPosition(effect->unk1E, g_BattleModels[effect->unk1E].boneIndices[11], &child->Pos); child->PartPos.vx = 0; child->PartPos.vy = ang + 0x400; child->PartPos.vz = -0x200; - child = &g_BattleEffectSlots[BattleEffectRegister(func_801B04C8)]; + child = &g_BattleEffectSlots[BattleEffectRegister(Hakugek1FirePuffTick)]; BattleGetPartPosition(effect->unk1E, g_BattleModels[effect->unk1E].boneIndices[12], &child->Pos); child->PartPos.vx = 0; child->PartPos.vy = ang + 0x400; diff --git a/src/magic/hakugek2.c b/src/magic/hakugek2.c index f0a64da0..821923d9 100644 --- a/src/magic/hakugek2.c +++ b/src/magic/hakugek2.c @@ -127,7 +127,7 @@ static void Hakugek2DoubleBufferFlip(void) { } } -void func_801B04C8(void) { +void Hakugek2FirePuffTick(void) { MATRIX matrix; MATRIX rotated; s32 flag; @@ -312,7 +312,7 @@ void Hakugek2TargetTick(void) { if (D_80062D98 == 0) { if (effect->AnimationFrame == 0) { ang = ratan2(effect->PartPos.vx - effect->Pos.vx, effect->PartPos.vz - effect->Pos.vz); - child = &g_BattleEffectSlots[BattleEffectRegister(func_801B04C8)]; + child = &g_BattleEffectSlots[BattleEffectRegister(Hakugek2FirePuffTick)]; BattleGetPartPosition(effect->unk1E, g_BattleModels[effect->unk1E].boneIndices[8], &child->Pos); child->PartPos.vx = 0; child->PartPos.vy = ang + 0x400; From 4a04e27bb9f11fa7267100aaa0aa4fbd6dc60ffd Mon Sep 17 00:00:00 2001 From: j3lee Date: Mon, 12 Oct 2026 13:13:05 +0930 Subject: [PATCH 10/10] magic: point the "same as" comments at upstream functions Cites functions that exist on origin/main (or in this PR); comments that named draft-only functions are repointed or dropped. --- src/magic/gas.c | 3 +-- src/magic/hakugek1.c | 3 +-- src/magic/hakugek2.c | 3 +-- src/magic/kaen.c | 3 +-- src/magic/kaen2.c | 3 +-- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/magic/gas.c b/src/magic/gas.c index 5bdbe113..80dbc267 100644 --- a/src/magic/gas.c +++ b/src/magic/gas.c @@ -45,7 +45,6 @@ s32 BattleDetachedRegister(void (*func)(void)); void func_800BBA84(u16 arg0, s32 arg1, s32 arg2); void GasTargetTick(void); -// Same as MAGIC_Biora. void MAGIC_Gas(s32 targetMask, s32 callbackArg) { GasStart(targetMask, callbackArg); } void GasTargetCenterCalc(s16 targetMask, SVECTOR* out) { @@ -113,7 +112,7 @@ void GasSpriteMatrixSetup(SVECTOR* pos, SVECTOR* rot, s16 scale, s32 offset) { SetTransMatrix(&matrix); } -// Same as BioraDoubleBufferFlip. +// Same as BarrierDoubleBufferFlip. static void GasDoubleBufferFlip(void) { GasData* effect; diff --git a/src/magic/hakugek1.c b/src/magic/hakugek1.c index e6694548..4559c7f3 100644 --- a/src/magic/hakugek1.c +++ b/src/magic/hakugek1.c @@ -48,7 +48,6 @@ void Hakugek1TargetSetup(s32 target, s32 callbackArg); void func_800BBA84(u16 arg0, s32 arg1, s32 arg2); void Hakugek1TargetTick(void); -// Same as MAGIC_Biora. void MAGIC_Hakugek1(s32 targetMask, s32 callbackArg) { Hakugek1Start(targetMask, callbackArg); } void Hakugek1TargetCenterCalc(s16 targetMask, SVECTOR* out) { @@ -116,7 +115,7 @@ void Hakugek1SpriteMatrixSetup(SVECTOR* pos, SVECTOR* rot, s16 scale, s32 offset SetTransMatrix(&matrix); } -// Same as BioraDoubleBufferFlip. +// Same as BarrierDoubleBufferFlip. static void Hakugek1DoubleBufferFlip(void) { Hakugek1Data* effect; diff --git a/src/magic/hakugek2.c b/src/magic/hakugek2.c index 821923d9..f492b3be 100644 --- a/src/magic/hakugek2.c +++ b/src/magic/hakugek2.c @@ -47,7 +47,6 @@ extern void* D_80163C74; void Hakugek2TargetSetup(s32 target, s32 callbackArg); void Hakugek2TargetTick(void); -// Same as MAGIC_Biora. void MAGIC_Hakugek2(s32 targetMask, s32 callbackArg) { Hakugek2Start(targetMask, callbackArg); } void Hakugek2TargetCenterCalc(s16 targetMask, SVECTOR* out) { @@ -115,7 +114,7 @@ void Hakugek2SpriteMatrixSetup(SVECTOR* pos, SVECTOR* rot, s16 scale, s32 offset SetTransMatrix(&matrix); } -// Same as BioraDoubleBufferFlip. +// Same as BarrierDoubleBufferFlip. static void Hakugek2DoubleBufferFlip(void) { Hakugek2Data* effect; diff --git a/src/magic/kaen.c b/src/magic/kaen.c index 9736a8f9..34a4a2be 100644 --- a/src/magic/kaen.c +++ b/src/magic/kaen.c @@ -46,7 +46,6 @@ s32 BattleDetachedRegister(void (*func)(void)); void func_800BBA84(u16 arg0, s32 arg1, s32 arg2); void KaenTargetTick(void); -// Same as MAGIC_Biora. void MAGIC_Kaen(s32 targetMask, s32 callbackArg) { KaenStart(targetMask, callbackArg); } void KaenTargetCenterCalc(s16 targetMask, SVECTOR* out) { @@ -114,7 +113,7 @@ void KaenSpriteMatrixSetup(SVECTOR* pos, SVECTOR* rot, s16 scale, s32 offset) { SetTransMatrix(&matrix); } -// Same as BioraDoubleBufferFlip. +// Same as BarrierDoubleBufferFlip. static void KaenDoubleBufferFlip(void) { KaenData* effect; diff --git a/src/magic/kaen2.c b/src/magic/kaen2.c index 5c123177..50f0268d 100644 --- a/src/magic/kaen2.c +++ b/src/magic/kaen2.c @@ -46,7 +46,6 @@ void Kaen2TargetSetup(s32 target, s32 callbackArg); void Kaen2FlameSpriteTick(void); void Kaen2TargetTick(void); -// Same as MAGIC_Biora. void MAGIC_Kaen2(s32 targetMask, s32 callbackArg) { Kaen2Start(targetMask, callbackArg); } void Kaen2TargetCenterCalc(s16 targetMask, SVECTOR* out) { @@ -114,7 +113,7 @@ void Kaen2SpriteMatrixSetup(SVECTOR* pos, SVECTOR* rot, s16 scale, s32 offset) { SetTransMatrix(&matrix); } -// Same as BioraDoubleBufferFlip. +// Same as BarrierDoubleBufferFlip. static void Kaen2DoubleBufferFlip(void) { Kaen2Data* effect;