diff --git a/Makefile b/Makefile index 113aee26..929082e8 100644 --- a/Makefile +++ b/Makefile @@ -140,7 +140,7 @@ CODE_OVERLAYS := field_init intro field \ tripletriad battle_render battle world ALL_EFFECT_OVERLAYS := $(filter effect_%,$(SPLAT_BINARIES)) -EFFECTS ?= effect_001 effect_025 effect_028 +EFFECTS ?= effect_001 effect_025 effect_028 effect_052 EFFECT_OVERLAYS := $(if $(filter all,$(EFFECTS)),$(ALL_EFFECT_OVERLAYS),$(EFFECTS)) OVERLAYS := $(MENU_OVERLAYS) $(CODE_OVERLAYS) $(EFFECT_OVERLAYS) ALL_OVERLAYS := $(MENU_OVERLAYS) $(CODE_OVERLAYS) $(ALL_EFFECT_OVERLAYS) diff --git a/config/ff8.yaml b/config/ff8.yaml index ae67bb81..53db92e2 100644 --- a/config/ff8.yaml +++ b/config/ff8.yaml @@ -1496,15 +1496,41 @@ binaries: options: target_path: original/effect/effect_052.bin src_path: src/effect + section_order: [.text, .rodata, .data, .bss] segments: - name: effect_052 type: code start: 0x0 vram: 0x801A0000 subsegments: - - [0x0, c, effect_052] - - [0x9BDC, .rodata, effect_052] - - [0x9BF0, bin, effect_052] + - [0x0, c, effect_052_entry] + - [0x1EC, c, lib/common] + - [0x95C, c, lib/rotz] + - [0xAE8, c, lib/heading] + - [0xB18, c, lib/entity] + - [0x1688, c, lib/tint] + - [0x1964, c, lib/vector] + - [0x20D0, c, lib/emit] + - [0x3F04, c, lib/packet] + - [0x410C, c, lib/particlestep] + - [0x5400, c, lib/particlealloc] + - [0x551C, c, lib/draw] + - [0x6178, c, lib/emitteralloc] + - [0x6298, c, lib/spawn] + - [0x804C, c, lib/list] + - [0x8668, c, lib/trail] + - [0x87DC, c, lib/strands] + - [0x8CC8, c, lib/tables] + - [0x8FDC, c, lib/bankclear] + - [0x9034, c, lib/drawscript] + - [0x9498, c, effect_052] + # particlestep's jump table, then the pad its section end carried, then + # list's two, then the script dispatch tables. + - [0x9BDC, .rodata, lib/particlestep] + - [0x9BF0, pad] + - [0x9BF4, .rodata, lib/list] + - [0x9C20, .rodata, effect_052] + - [0x9C68, bin, effect_052] - [0x3C6D8] - name: effect_053 sha1: 738b1bb7de8b266db68995f925e9602f88fca51f diff --git a/config/symbols.effect_052.txt b/config/symbols.effect_052.txt new file mode 100644 index 00000000..4601a392 --- /dev/null +++ b/config/symbols.effect_052.txt @@ -0,0 +1,116 @@ +effectTextInit = 0x801A01EC; // type:func +effectTextHex = 0x801A033C; // type:func +effectTextNewline = 0x801A03E8; // type:func +effectNop = 0x801A0408; // type:func +effectDrawQuad128 = 0x801A0410; // type:func +effectDrawQuad256 = 0x801A050C; // type:func +effectMatrixIdentity = 0x801A0608; // type:func +effectMatrixRotX = 0x801A0640; // type:func +effectMatrixRotY = 0x801A07D0; // type:func +effectMatrixRotZ = 0x801A095C; // type:func +effectMatrixHeading = 0x801A0AE8; // type:func +effectReleaseWait = 0x801A0B18; // type:func +effectSpawnTask = 0x801A0B40; // type:func +effectCacheSlotAnchors = 0x801A0CCC; // type:func +effectSlotAnchor0 = 0x801A0E00; // type:func +effectSlotAnchor1 = 0x801A0E30; // type:func +effectSlotAnchorMid = 0x801A0E60; // type:func +effectCacheAnimSlotAnchors = 0x801A0E90; // type:func +effectAnimSlotAnchor0 = 0x801A0FCC; // type:func +effectAnimSlotAnchor1 = 0x801A0FFC; // type:func +effectAnimSlotAnchorMid = 0x801A102C; // type:func +effectUpdateModelBounds = 0x801A105C; // type:func +effectGetModelBounds = 0x801A12A8; // type:func +effectModelRadius = 0x801A12F8; // type:func +effectModelHalfHeight = 0x801A139C; // type:func +effectModelHalfWidth = 0x801A13CC; // type:func +effectModelHeight = 0x801A1424; // type:func +effectModelTop = 0x801A1448; // type:func +effectModelBottom = 0x801A1490; // type:func +effectModelRandomY = 0x801A14D8; // type:func +effectModelCentreY = 0x801A1590; // type:func +effectModelCentre = 0x801A15E4; // type:func +effectZeroWords = 0x801A1650; // type:func +effectTintPlay = 0x801A1688; // type:func +effectRandBetween = 0x801A1964; // type:func +effectRandProduct = 0x801A19E8; // type:func +effectRandVector = 0x801A1A8C; // type:func +effectMatrixFromAngles = 0x801A1B04; // type:func +effectJitterAngle = 0x801A1BD0; // type:func +effectJitterVector = 0x801A1C64; // type:func +effectJitterAngleS = 0x801A1CDC; // type:func +effectJitterSVector = 0x801A1D6C; // type:func +effectCopyVector = 0x801A1DE4; // type:func +effectFadeValue = 0x801A1E14; // type:func +effectFadeVector = 0x801A1E70; // type:func +effectBlendPointSets = 0x801A1F3C; // type:func +effectEmitTris = 0x801A20D0; // type:func +effectEmitQuads = 0x801A239C; // type:func +effectEmitTexTris = 0x801A26C0; // type:func +effectEmitTexQuads = 0x801A2A48; // type:func +effectEmitGouraudTris = 0x801A2E2C; // type:func +effectEmitGouraudQuads = 0x801A3134; // type:func +effectEmitGouraudTexTris = 0x801A34BC; // type:func +effectEmitGouraudTexQuads = 0x801A3878; // type:func +effectEmitStream = 0x801A3CC0; // type:func +effectBuildMeshPacket = 0x801A3F04; // type:func +effectParticleLateStep = 0x801A410C; // type:func +effectParticleAdvance = 0x801A41C4; // type:func +effectParticleAgeHold = 0x801A49CC; // type:func +effectParticlePose = 0x801A4AC0; // type:func +effectParticleAlloc = 0x801A5400; // type:func +effectStepRunKind = 0x801A551C; // type:func +effectStepFire = 0x801A5554; // type:func +effectParticleStep = 0x801A5600; // type:func +effectEmitterCountStep = 0x801A56EC; // type:func +effectSpriteEmit = 0x801A5704; // type:func +effectSpritePacket = 0x801A5D30; // type:func +effectParticleDrawPacket = 0x801A5F98; // type:func +effectDrawParticles = 0x801A6058; // type:func +effectEmitterAlloc = 0x801A6178; // type:func +effectEmitterAge = 0x801A6298; // type:func +effectEmitterSpawn = 0x801A6300; // type:func +effectEmitterSpawnShare = 0x801A6D9C; // type:func +effectEmitterStep = 0x801A6E9C; // type:func +effectEmitterOnStrand = 0x801A6F3C; // type:func +effectEmitterOnTrail = 0x801A71C4; // type:func +effectEmitterOnOwner = 0x801A73CC; // type:func +effectEmitterSlide = 0x801A75DC; // type:func +effectListAppend = 0x801A804C; // type:func +effectListRemove = 0x801A8088; // type:func +effectListClear = 0x801A80C8; // type:func +effectListRun = 0x801A80E0; // type:func +effectEmitterSetup = 0x801A8168; // type:func +effectStepFireSlots = 0x801A839C; // type:func +effectEmittersOnCue = 0x801A8450; // type:func +effectTrailPush = 0x801A858C; // type:func +effectTrailAim = 0x801A8668; // type:func +effectStrandsSeed = 0x801A87DC; // type:func +effectStrandsPush = 0x801A88E8; // type:func +effectStrandsAim = 0x801A8A00; // type:func +effectPoseTablesRelocate = 0x801A8CC8; // type:func +effectStartChildScript = 0x801A8F6C; // type:func +effectBanksClear = 0x801A8FDC; // type:func +effectDrawScriptStart = 0x801A9034; // type:func +effectDrawScriptRun = 0x801A92DC; // type:func +effectDrawListSpan = 0x801A9404; // type:func +func_801A953C = 0x801A953C; // type:func +func_801A96F8 = 0x801A96F8; // type:func +func_801A99E4 = 0x801A99E4; // type:func +g_effectStackBase = 0x801D399C; +g_effectStackTop = 0x801D39A0; +g_effectEmitterBank = 0x801D39A8; +g_effectParticleBank = 0x801D39AC; +g_effectDrawList = 0x801D39B0; +g_effectEmitterCursor = 0x801D39B4; +g_effectParticleCursor = 0x801D39B6; +g_effectParticleTotal = 0x801D39B8; +g_effectLiveTotal = 0x801D39BA; +g_effectBankUnk90 = 0x801D39BC; +g_effectBankUnk92 = 0x801D39BE; +g_effectChildPool = 0x801D41B4; +g_effectPrimCursor = 0x801D41C4; +g_effectHexGlyphs = 0x801D4504; +g_effectTextX = 0x801D4518; +g_effectTextY = 0x801D451C; +g_effectTextColour = 0x801D4520; diff --git a/include/effect/effect_052.h b/include/effect/effect_052.h new file mode 100644 index 00000000..7992fead --- /dev/null +++ b/include/effect/effect_052.h @@ -0,0 +1,60 @@ +#ifndef EFFECT_EFFECT_052_H +#define EFFECT_EFFECT_052_H + +#include "effect.h" +#include "effect/lib/particle.h" +#include "effect/lib/tint.h" + +/** + * @file effect_052.h + * @brief X-Potion: the overlay's own storage. + */ + +/** @brief Argument the frame-20 child is started with. */ +extern EffectTintStep D_801A9C68[]; + +/** @brief Sound cue the take-model script fires on its first frame. */ +extern u8 D_801A9C74[]; + +/** @brief Pool the trailing sparks are allocated from. */ +extern s32 D_801D4424; + +/** @brief Pool the frame-20 child is allocated from. */ +extern s32 D_801D44F4; + +/** @brief Pose script the model-taking handler runs. */ +extern EffectPoseTables D_801D4524; + +/** @brief Cleared when the effect starts. */ +extern s32 D_801D3994; +extern s32 D_801D3998; + +/** @brief Task pools the script's children run in. */ +extern s32 D_801D42B4; +extern s32 D_801D41E4; +extern s32 D_801D42C4; +extern s32 D_801D4434; +extern s32 D_801D39C4; + +/** @brief Table of two offsets battle.bin resolves when the effect starts. */ +extern u8 D_801A9DD4; + +/** @brief TIM uploaded to VRAM when the effect starts; also the first bank. */ +extern u8 D_801AA974; + +/** @brief Cursor the record banks are carved off, moving up as they are taken. */ +extern u8 *D_801D39A4; + +/** @brief Cursor the effect's second prim buffer is written through. */ +extern void *D_801D41C8; + +/** @brief The four bank pointers the emitters and the renderer read. */ +extern void *D_801D41CC; +extern void *D_801D41D0; +extern void *D_801D41D4; +extern void *D_801D41D8; + +/** @brief Run one frame of the effect: its opcode, then every task pool it owns. */ +s32 func_801A99EC(EffectEntity *entity); + +#endif /* EFFECT_EFFECT_052_H */ diff --git a/include/effect/effect_052_entry.h b/include/effect/effect_052_entry.h new file mode 100644 index 00000000..1f582804 --- /dev/null +++ b/include/effect/effect_052_entry.h @@ -0,0 +1,19 @@ +#ifndef EFFECT_EFFECT_052_ENTRY_H +#define EFFECT_EFFECT_052_ENTRY_H + +#include "effect.h" + +/** + * @file effect_052_entry.h + * @brief X-Potion: the overlay entry point. + */ + +/** + * @brief Start the effect's script and hand back its task pool. + * + * @param animSet Animation set the effect plays. + * @return The pool the root entity lives in. + */ +void *func_801A0000(EffectAnimSet *animSet); + +#endif /* EFFECT_EFFECT_052_ENTRY_H */ diff --git a/include/effect/params/effect_052/effect_params.h b/include/effect/params/effect_052/effect_params.h new file mode 100644 index 00000000..3ce28748 --- /dev/null +++ b/include/effect/params/effect_052/effect_params.h @@ -0,0 +1,13 @@ +#ifndef EFFECT_PARAMS_H +#define EFFECT_PARAMS_H + +/** + * @file effect_params.h + * @brief X-Potion: the ring sizes its particle engine is built with. + */ + +/** @brief Highest index each ring reaches before it wraps. */ +#define EFFECT_EMITTER_COUNT 0x59 +#define EFFECT_PARTICLE_COUNT 0x8B + +#endif /* EFFECT_PARAMS_H */ diff --git a/src/effect/effect_052.c b/src/effect/effect_052.c index ce370ca6..ba8bc84c 100644 --- a/src/effect/effect_052.c +++ b/src/effect/effect_052.c @@ -3,243 +3,259 @@ * @brief X-Potion */ #include "common.h" - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A0000); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A01EC); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A033C); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A03E8); - -void func_801A0408(void) { +#include "game.h" +#include "effect.h" +#include "effect/effect_052.h" +#include "effect/lib/particle.h" +#include "effect/lib/entity.h" +#include "effect/lib/tint.h" +#include "psxsdk/libgte.h" +#include "effect/lib/bankclear.h" +#include "effect/lib/tables.h" +#include "effect/lib/drawscript.h" +#include "effect/lib/common.h" +#include "btl_entity.h" + +/** @brief Where in the scratchpad the effect keeps its view matrix. */ +#define EFFECT_SCRATCHPAD ((MATRIX *)0x1F8002E0) + +/** @brief @ref EffectEntity::unk05C -- the frame counter's low bit picks a bank. */ +#define EFFECT_FRAME_ODD 0x1 + +static void func_801A9498(EffectEntity *entity); +static void func_801A94F4(EffectEntity *entity); +static void func_801A953C(EffectEntity *entity); +static s32 func_801A9544(EffectEntity *entity); +static void func_801A95E4(EffectEntity *entity); +static void func_801A963C(EffectEntity *entity); +static void func_801A9670(EffectEntity *entity); +static void func_801A96F8(EffectEntity *entity); +static s32 func_801A9700(EffectEntity *entity); +static void func_801A9810(EffectEntity *entity); +static void func_801A9824(EffectEntity *entity); +static void func_801A9838(EffectEntity *entity); +static void func_801A98AC(EffectEntity *entity); +static void func_801A9904(EffectEntity *entity); +static void func_801A9964(EffectEntity *entity); +static void func_801A9978(EffectEntity *entity); +static void func_801A99A0(EffectEntity *entity); +static void func_801A99B4(EffectEntity *entity); +static void func_801A99C8(EffectEntity *entity); +static void func_801A99E4(EffectEntity *entity); + +/** @brief Opcode handler: draw and retire once the frame count is reached. */ +static void func_801A9498(EffectEntity *entity) { + EffectDrawScript *script = (EffectDrawScript *)entity; + + if (entity->unk024 >= script->stopFrame) { + /* Called with no argument: the entity is already in $a0 and stays there. */ + ((void (*)())effectDrawScriptStart)(); + effectDrawScriptRun(script); + entity->pc++; + } } -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A0410); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A050C); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A0608); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A0640); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A07D0); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A095C); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A0AE8); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A0B18); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A0B40); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A0CCC); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A0E00); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A0E30); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A0E60); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A0E90); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A0FCC); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A0FFC); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A102C); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A105C); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A12A8); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A12F8); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A139C); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A13CC); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A1424); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A1448); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A1490); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A14D8); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A1590); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A15E4); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A1650); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A1688); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A1964); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A19E8); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A1A8C); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A1B04); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A1BD0); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A1C64); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A1CDC); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A1D6C); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A1DE4); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A1E14); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A1E70); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A1F3C); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A20D0); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A239C); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A26C0); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A2A48); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A2E2C); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A3134); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A34BC); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A3878); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A3CC0); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A3F04); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A410C); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A41C4); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A49CC); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A4AC0); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A5400); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A551C); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A5554); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A5600); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A56EC); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A5704); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A5D30); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A5F98); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A6058); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A6178); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A6298); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A6300); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A6D9C); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A6E9C); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A6F3C); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A71C4); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A73CC); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A75DC); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A804C); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A8088); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A80C8); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A80E0); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A8168); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A839C); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A8450); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A858C); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A8668); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A87DC); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A88E8); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A8A00); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A8CC8); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A8F6C); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A8FDC); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A9034); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A92DC); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A9404); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A9498); - -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A94F4); +/** @brief Opcode handler: hold still until the count runs out. */ +static void func_801A94F4(EffectEntity *entity) { + if (effectDrawScriptRun((EffectDrawScript *)entity) != 0) { + entity->flags |= EFFECT_FLAG_STOP; + entity->pc++; + } +} -void func_801A953C(void) { +/** @brief Opcode handler: no-op. */ +static void func_801A953C(EffectEntity *entity) { } -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A9544); +/** + * @brief Script dispatcher: run this frame's step, draw, and retire the entity. + * + * @return 2 once the script has stopped and its children have drained, 0 while + * it is still running. + */ +static s32 func_801A9544(EffectEntity *entity) { + EffectHandler handlers[3] = { func_801A9498, func_801A94F4, func_801A953C }; + + handlers[entity->pc](entity); + entity->unk024++; + if (entity->flags & EFFECT_FLAG_STOP) { + if (entity->wait != 0) { + return 0; + } + effectReleaseWait(entity); + return 2; + } + return 0; +} -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A95E4); +/** @brief Opcode handler: start the pose script on the taken model. */ +static void func_801A95E4(EffectEntity *entity) { + effectStartChildScript(entity, func_801A9544, &D_801D4524, 0, 0x2D, 0); + entity->pc++; +} -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A963C); +/** @brief Opcode handler: release the model once the count reaches 30. */ +static void func_801A963C(EffectEntity *entity) { + if (entity->unk024 == 30) { + entity->unk010->unk063 = 0; + entity->pc++; + } +} -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A9670); +/** @brief Opcode handler: hand the current part to battle, then stop. */ +static void func_801A9670(EffectEntity *entity) { + if (entity->unk024 >= 30) { + func_800BFE1C(&entity->animSet->anims[entity->unk02A].parts[entity->unk02B]); + entity->flags |= EFFECT_FLAG_STOP; + entity->pc++; + } +} -void func_801A96F8(void) { +/** @brief Opcode handler: no-op. */ +static void func_801A96F8(EffectEntity *entity) { } -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A9700); +/** @brief Script dispatcher: the take-model script, with its two timed cues. */ +static s32 func_801A9700(EffectEntity *entity) { + EffectHandler handlers[4] = { func_801A95E4, func_801A963C, func_801A9670, func_801A96F8 }; + + effectCacheSlotAnchors(entity); + effectUpdateModelBounds(entity); + handlers[entity->pc](entity); + if (entity->unk024 == 0) { + func_800C4764(D_801A9C74, 0, 0x80); + } + if (entity->unk024 == 20) { + EffectTintScript *child = + effectSpawnTask(&D_801D44F4, effectTintPlay, sizeof(EffectTintScript), entity); + + child->steps = D_801A9C68; + } + entity->unk024++; + if (entity->flags & EFFECT_FLAG_STOP) { + if (entity->wait != 0) { + return 0; + } + effectReleaseWait(entity); + return 2; + } + return 0; +} -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A9810); +/** @brief Opcode handler: consume the opcode and do nothing else. */ +static void func_801A9810(EffectEntity *entity) { + entity->pc++; +} -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A9824); +/** @brief Opcode handler: consume the opcode and do nothing else. */ +static void func_801A9824(EffectEntity *entity) { + entity->pc++; +} -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A9838); +/** @brief Opcode handler: carve both record banks and start the draw script. */ +static void func_801A9838(EffectEntity *entity) { + if (entity->wait == 0) { + /* Both banks are carved out of the same byte arena behind the TIM. */ + g_effectEmitterBank = (EffectEmitter *)D_801D39A4; + D_801D39A4 += EFFECT_EMITTER_BANK_BYTES; + g_effectParticleBank = (EffectParticle *)D_801D39A4; + D_801D39A4 += EFFECT_PARTICLE_BANK_BYTES; + effectBanksClear(); + entity->pc++; + } +} -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A98AC); +/** @brief Opcode handler: start a task running @ref func_801A9700. */ +static void func_801A98AC(EffectEntity *entity) { + entity->unk063 = 1; + effectSpawnTask(&D_801D4424, func_801A9700, 0x58, entity); + entity->pc++; +} -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A9904); +/** @brief Opcode handler: repeat the preceding opcode until the count runs out. */ +static void func_801A9904(EffectEntity *entity) { + if (entity->unk063 != 0) { + return; + } + if (entity->unk02A < entity->unk058) { + entity->unk02A++; + entity->unk02E++; + entity->pc--; + } else { + entity->pc++; + } +} -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A9964); +/** @brief Opcode handler: consume the opcode and do nothing else. */ +static void func_801A9964(EffectEntity *entity) { + entity->pc++; +} -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A9978); +/** @brief Opcode handler: stall here until @c unk05E reaches zero. */ +static void func_801A9978(EffectEntity *entity) { + if (entity->unk05E == 0) { + entity->pc++; + } +} -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A99A0); +/** @brief Opcode handler: consume the opcode and do nothing else. */ +static void func_801A99A0(EffectEntity *entity) { + entity->pc++; +} -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A99B4); +/** @brief Opcode handler: consume the opcode and do nothing else. */ +static void func_801A99B4(EffectEntity *entity) { + entity->pc++; +} -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A99C8); +/** @brief Opcode handler: raise @ref EFFECT_FLAG_STOP and consume the opcode. */ +static void func_801A99C8(EffectEntity *entity) { + entity->flags |= EFFECT_FLAG_STOP; + entity->pc++; +} -void func_801A99E4(void) { +/** @brief Opcode handler: no-op. */ +static void func_801A99E4(EffectEntity *entity) { } -INCLUDE_ASM("asm/ovl/effect_052/nonmatchings/effect_052", func_801A99EC); +/** + * @brief Run one frame of the effect: its opcode, then every task pool it owns. + * + * @return 2 once the script has stopped and its children have drained. + */ +s32 func_801A99EC(EffectEntity *entity) { + EffectHandler handlers[11] = { + func_801A9810, func_801A9824, func_801A9838, func_801A98AC, func_801A9904, + func_801A9964, func_801A9978, func_801A99A0, func_801A99B4, func_801A99C8, + func_801A99E4 + }; + MATRIX *view = EFFECT_SCRATCHPAD; + + *view = D_800F02C8; + g_effectStackTop = (u8 *)view; + g_effectStackBase = view; + if (entity->unk05C & EFFECT_FRAME_ODD) { + g_effectPrimCursor = D_801D41CC; + D_801D41C8 = D_801D41D4; + } else { + g_effectPrimCursor = D_801D41D0; + D_801D41C8 = D_801D41D8; + } + effectCacheAnimSlotAnchors(entity); + handlers[entity->pc](entity); + g_effectParticleTotal = 0; + entity->unk05E = 0; + g_effectLiveTotal = 0; + entity->unk05E += func_800B2B68(&D_801D4424); + entity->unk05E += func_800B2B68(&D_801D44F4); + entity->unk05E += func_800B2B68(&g_effectChildPool); + entity->unk05C++; + entity->unk024++; + if (entity->flags & EFFECT_FLAG_STOP) { + if (entity->wait == 0) { + effectReleaseWait(entity); + return 2; + } + } + return 0; +} diff --git a/src/effect/effect_052_entry.c b/src/effect/effect_052_entry.c new file mode 100644 index 00000000..e2294ce6 --- /dev/null +++ b/src/effect/effect_052_entry.c @@ -0,0 +1,61 @@ +/** + * @file effect_052_entry.c + * @brief X-Potion: the overlay entry point. + */ +#include "common.h" +#include "effect.h" +#include "effect/lib/entity.h" +#include "effect/lib/tables.h" +#include "effect/effect_052.h" +#include "effect/effect_052_entry.h" + +/** @brief Stride between the prim and frame banks carved out of the TIM. */ +#define EFFECT_BANK_SIZE 0x6000 + +/** + * @brief Start the effect's script and hand back its task pool. + * + * @param animSet Animation set the effect plays. + * @return The pool the root entity lives in. + */ +void *func_801A0000(EffectAnimSet *animSet) { + u8 *bank0; + EffectEntity *entity; + u8 *bank1; + u8 *frames; + + D_801D3994 = 0; + D_801D3998 = 0; + func_800B2A00(&D_801D42B4, &D_801D41E4, 0x64, 2); + entity = effectSpawnTask(&D_801D42B4, func_801A99EC, 0x64, NULL); + entity->animSet = animSet; + entity->unk02C = animSet->anims[entity->unk02A].unk000; + entity->unk02D = + entity->animSet->anims[entity->unk02A].parts[entity->unk02B].unk000; + entity->pc = 0; + entity->unk05A = animSet->anims->unk010; + entity->unk058 = animSet->anims->unk011; + entity->unk02F = entity->unk05A - 1; + if (entity->unk02F < entity->unk058) { + entity->unk02F = entity->unk058; + } + if (!(animSet->flags & EFFECT_ANIMSET_FLAG_LOADED)) { + func_800C3BE0(&D_801A9DD4); + func_800BB084(&D_801AA974); + } + D_801D39A4 = &D_801AA974; + bank0 = &D_801AA974; + D_801D41CC = bank0; + bank1 = bank0 + EFFECT_BANK_SIZE; + D_801D41D4 = bank0 + EFFECT_BANK_SIZE; + D_801D39A4 = bank0 + EFFECT_BANK_SIZE; + frames = bank1; + D_801D41D0 = frames; + frames += EFFECT_BANK_SIZE; + D_801D39A4 = frames; + D_801D41D8 = frames; + func_800B2A00(&D_801D4424, &D_801D42C4, 0x58, 4); + func_800B2A00(&D_801D44F4, &D_801D4434, 0x3C, 3); + func_800B2A00(&g_effectChildPool, &D_801D39C4, 0x2A4, 3); + return &D_801D42B4; +}