diff --git a/Makefile b/Makefile index 2206756c..961fc794 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 effect_052 effect_039 effect_056 effect_050 effect_051 effect_036 +EFFECTS ?= effect_001 effect_025 effect_028 effect_052 effect_039 effect_056 effect_050 effect_051 effect_036 effect_027 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 d87ccc74..020cae12 100644 --- a/config/ff8.yaml +++ b/config/ff8.yaml @@ -1097,16 +1097,40 @@ binaries: options: target_path: original/effect/effect_027.bin src_path: src/effect + section_order: [.text, .rodata, .data, .bss] segments: - name: effect_027 type: code start: 0x0 vram: 0x801A0000 subsegments: - - [0x0, c, effect_027] - - [0x9BB8, .rodata, effect_027] - - [0x9BCC, bin, effect_027] + - [0x0, c, effect_027_entry] + - [0x1EC, c, lib/common] + - [0x95C, c, lib/rotz] + - [0xAE8, c, lib/heading] + - [0xB18, c, lib/entity] + - [0x1688, c, lib/vector] + - [0x1DF4, c, lib/emit] + - [0x3C28, c, lib/packet] + - [0x3E30, c, lib/particlestep] + - [0x5124, c, lib/particlealloc] + - [0x5240, c, lib/draw] + - [0x5E9C, c, lib/emitteralloc] + - [0x5FBC, c, lib/spawn] + - [0x7D70, c, lib/list] + - [0x838C, c, lib/trail] + - [0x8500, c, lib/strands] + - [0x89EC, c, lib/tables] + - [0x8D00, c, lib/bankclear] + - [0x8D58, c, lib/drawscript] + - [0x91BC, c, effect_027] + - [0x9BB8, .rodata, lib/particlestep] + - [0x9BCC, pad] + - [0x9BD0, .rodata, lib/list] + - [0x9BFC, .rodata, effect_027] + - [0x9C5C, bin, effect_027] - [0x3AAF8] + - name: effect_028 sha1: eb8243db98aedc14e57e62c7b42d639c8171f9c5 options: diff --git a/config/symbols.effect_027.txt b/config/symbols.effect_027.txt new file mode 100644 index 00000000..840d55c9 --- /dev/null +++ b/config/symbols.effect_027.txt @@ -0,0 +1,112 @@ +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 +effectRandBetween = 0x801A1688; // type:func +effectRandProduct = 0x801A170C; // type:func +effectRandVector = 0x801A17B0; // type:func +effectMatrixFromAngles = 0x801A1828; // type:func +effectJitterAngle = 0x801A18F4; // type:func +effectJitterVector = 0x801A1988; // type:func +effectJitterAngleS = 0x801A1A00; // type:func +effectJitterSVector = 0x801A1A90; // type:func +effectCopyVector = 0x801A1B08; // type:func +effectFadeValue = 0x801A1B38; // type:func +effectFadeVector = 0x801A1B94; // type:func +effectBlendPointSets = 0x801A1C60; // type:func +effectEmitTris = 0x801A1DF4; // type:func +effectEmitQuads = 0x801A20C0; // type:func +effectEmitTexTris = 0x801A23E4; // type:func +effectEmitTexQuads = 0x801A276C; // type:func +effectEmitGouraudTris = 0x801A2B50; // type:func +effectEmitGouraudQuads = 0x801A2E58; // type:func +effectEmitGouraudTexTris = 0x801A31E0; // type:func +effectEmitGouraudTexQuads = 0x801A359C; // type:func +effectEmitStream = 0x801A39E4; // type:func +effectBuildMeshPacket = 0x801A3C28; // type:func +effectParticleLateStep = 0x801A3E30; // type:func +effectParticleAdvance = 0x801A3EE8; // type:func +effectParticleAgeHold = 0x801A46F0; // type:func +effectParticlePose = 0x801A47E4; // type:func +effectParticleAlloc = 0x801A5124; // type:func +effectStepRunKind = 0x801A5240; // type:func +effectStepFire = 0x801A5278; // type:func +effectParticleStep = 0x801A5324; // type:func +effectEmitterCountStep = 0x801A5410; // type:func +effectSpriteEmit = 0x801A5428; // type:func +effectSpritePacket = 0x801A5A54; // type:func +effectParticleDrawPacket = 0x801A5CBC; // type:func +effectDrawParticles = 0x801A5D7C; // type:func +effectEmitterAlloc = 0x801A5E9C; // type:func +effectEmitterAge = 0x801A5FBC; // type:func +effectEmitterSpawn = 0x801A6024; // type:func +effectEmitterSpawnShare = 0x801A6AC0; // type:func +effectEmitterStep = 0x801A6BC0; // type:func +effectEmitterOnStrand = 0x801A6C60; // type:func +effectEmitterOnTrail = 0x801A6EE8; // type:func +effectEmitterOnOwner = 0x801A70F0; // type:func +effectEmitterSlide = 0x801A7300; // type:func +effectListAppend = 0x801A7D70; // type:func +effectListRemove = 0x801A7DAC; // type:func +effectListClear = 0x801A7DEC; // type:func +effectListRun = 0x801A7E04; // type:func +effectEmitterSetup = 0x801A7E8C; // type:func +effectStepFireSlots = 0x801A80C0; // type:func +effectEmittersOnCue = 0x801A8174; // type:func +effectTrailPush = 0x801A82B0; // type:func +effectTrailAim = 0x801A838C; // type:func +effectStrandsSeed = 0x801A8500; // type:func +effectStrandsPush = 0x801A860C; // type:func +effectStrandsAim = 0x801A8724; // type:func +effectPoseTablesRelocate = 0x801A89EC; // type:func +effectStartChildScript = 0x801A8C90; // type:func +effectBanksClear = 0x801A8D00; // type:func +effectDrawScriptStart = 0x801A8D58; // type:func +effectDrawScriptRun = 0x801A9000; // type:func +effectDrawListSpan = 0x801A9128; // type:func +g_effectStackBase = 0x801D35BC; +g_effectStackTop = 0x801D35C0; +g_effectEmitterBank = 0x801D3864; +g_effectParticleBank = 0x801D3868; +g_effectDrawList = 0x801D386C; +g_effectEmitterCursor = 0x801D3870; +g_effectParticleCursor = 0x801D3872; +g_effectParticleTotal = 0x801D3874; +g_effectLiveTotal = 0x801D3876; +g_effectBankUnk90 = 0x801D3878; +g_effectBankUnk92 = 0x801D387A; +g_effectChildPool = 0x801D4074; +g_effectPrimCursor = 0x801D4084; +g_effectHexGlyphs = 0x801D42F4; +g_effectTextX = 0x801D4308; +g_effectTextY = 0x801D430C; +g_effectTextColour = 0x801D4310; diff --git a/include/effect/effect_027.h b/include/effect/effect_027.h new file mode 100644 index 00000000..6f851c78 --- /dev/null +++ b/include/effect/effect_027.h @@ -0,0 +1,68 @@ +#ifndef EFFECT_EFFECT_027_H +#define EFFECT_EFFECT_027_H + +#include "effect.h" +#include "effect/lib/particle.h" + +/** + * @file + * @brief Full-Life: the overlay's own storage. + */ + +/** @brief Cursor the record banks are carved off, moving up as they are taken. */ +extern u8 *D_801D35C4; + +/** @brief Sound cue the script fires on its first frame. */ +extern u8 D_801A9C5C[]; + +/** @brief Pose script the model-taking handler runs. */ +extern EffectPoseTables D_801D4314; + +/** @brief Task pools the script's children run in, and their storage. */ +extern s32 D_801D4174; +extern s32 D_801D42E4; +extern s32 D_801D3854; +extern s32 D_801D40A4; +extern s32 D_801D4184; +extern s32 D_801D3884; +extern s32 D_801D35D4; + +/** @brief Cleared when the effect starts. */ +extern s32 D_801D35B4; +extern s32 D_801D35B8; + +/** + * @name Prim buffers + * + * Two of each, so the frame being built and the frame being drawn never share. + * @{ + */ +extern void *D_801D408C; +extern void *D_801D4090; +extern void *D_801D4094; +extern void *D_801D4098; +/** @} */ + +/** @brief Cursor the effect's second prim buffer is written through. */ +extern void *D_801D4088; + +/** + * @name Overlay blob + * + * The data carried in the overlay image behind the code. + * @{ + */ + +/** @brief Table of two offsets battle.bin resolves when the effect starts. */ +extern u8 D_801A9D3C; + +/** @brief TIM uploaded to VRAM when the effect starts. */ +extern u8 D_801AA794; +/** @} */ + +/** + * @brief Run one frame of the effect: its opcode, then every task pool it owns. + */ +s32 func_801A99C8(EffectEntity *entity); + +#endif /* EFFECT_EFFECT_027_H */ diff --git a/include/effect/effect_027_entry.h b/include/effect/effect_027_entry.h new file mode 100644 index 00000000..0b48a4d4 --- /dev/null +++ b/include/effect/effect_027_entry.h @@ -0,0 +1,19 @@ +#ifndef EFFECT_EFFECT_027_ENTRY_H +#define EFFECT_EFFECT_027_ENTRY_H + +#include "effect.h" + +/** + * @file effect_027_entry.h + * @brief Full-Life: 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_027_ENTRY_H */ diff --git a/include/effect/params/effect_027/effect_params.h b/include/effect/params/effect_027/effect_params.h new file mode 100644 index 00000000..42463bb7 --- /dev/null +++ b/include/effect/params/effect_027/effect_params.h @@ -0,0 +1,13 @@ +#ifndef EFFECT_PARAMS_H +#define EFFECT_PARAMS_H + +/** + * @file effect_params.h + * @brief Full-Life: the ring sizes its particle engine is built with. + */ + +/** @brief Highest index each ring reaches before it wraps. */ +#define EFFECT_EMITTER_COUNT 0x31 +#define EFFECT_PARTICLE_COUNT 0x8B + +#endif /* EFFECT_PARAMS_H */ diff --git a/src/effect/effect_025.c b/src/effect/effect_025.c index f707faa9..8ff0a161 100644 --- a/src/effect/effect_025.c +++ b/src/effect/effect_025.c @@ -279,7 +279,7 @@ static void func_801A71B8(EffectEntity *entity) { entity->pos.vx = 0x600; entity->pc++; } - for (i = 3; i >= 0; i--) { + for (i = 0; i < 4; i++) { tint->level = entity->pos.vx; tint++; } @@ -304,7 +304,7 @@ static void func_801A7240(EffectEntity *entity) { entity->flags |= EFFECT_FLAG_STOP; entity->pc++; } - for (i = 3; i >= 0; i--) { + for (i = 0; i < 4; i++) { tint->level = entity->pos.vx; tint++; } diff --git a/src/effect/effect_027.c b/src/effect/effect_027.c index 4b60d2b6..d4ecf6c1 100644 --- a/src/effect/effect_027.c +++ b/src/effect/effect_027.c @@ -3,259 +3,383 @@ * @brief Full-Life */ #include "common.h" - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A0000); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A01EC); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A033C); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A03E8); - -void func_801A0408(void) { +#include "game.h" +#include "effect.h" +#include "psxsdk/libgte.h" +#include "effect/effect_027.h" +#include "effect/lib/particle.h" +#include "effect/lib/entity.h" +#include "effect/lib/tables.h" +#include "effect/lib/drawscript.h" +#include "effect/lib/bankclear.h" +#include "effect/lib/common.h" +#include "battle.h" +#include "btl_entity.h" +#include "effect_params.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 + +/** @brief Ceiling the tint ramp clamps to, four @ref EFFECT_TINT_STEP steps up. */ +#define EFFECT_TINT_MAX 0x400 + +/** @brief How far the tint ramp moves per frame. */ +#define EFFECT_TINT_STEP 0x100 + +static void func_801A91BC(EffectEntity *entity); +static void func_801A9208(EffectEntity *entity); +static void func_801A9270(EffectEntity *entity); +static s32 func_801A9278(EffectEntity *entity); +static void func_801A9318(EffectEntity *entity); +static void func_801A9330(EffectEntity *entity); +static void func_801A938C(EffectEntity *entity); +static s32 func_801A9394(EffectEntity *entity); +static void func_801A9434(EffectEntity *entity); +static void func_801A9490(EffectEntity *entity); +static void func_801A94D8(EffectEntity *entity); +static s32 func_801A94E0(EffectEntity *entity); +static void func_801A9580(EffectEntity *entity); +static void func_801A95D8(EffectEntity *entity); +static void func_801A960C(EffectEntity *entity); +static void func_801A9694(EffectEntity *entity); +static s32 func_801A969C(EffectEntity *entity); +static void func_801A9778(EffectEntity *entity); +static void func_801A978C(EffectEntity *entity); +static void func_801A97A0(EffectEntity *entity); +static void func_801A9830(EffectEntity *entity); +static void func_801A9888(EffectEntity *entity); +static void func_801A98EC(EffectEntity *entity); +static void func_801A9954(EffectEntity *entity); +static void func_801A997C(EffectEntity *entity); +static void func_801A9990(EffectEntity *entity); +static void func_801A99A4(EffectEntity *entity); +static void func_801A99C0(EffectEntity *entity); + +/** @brief Opcode handler: clear the screen tint. */ +static void func_801A91BC(EffectEntity *entity) { + BattleTint *tint = D_800EF738; + s32 i; + + entity->pos.vx = 0; + for (i = 0; i < 4; i++) { + tint->level = entity->pos.vx; + tint->b = 0; + tint->g = 0; + tint->r = 0; + tint++; + } + entity->pc++; } -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A0410); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A050C); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A0608); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A0640); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A07D0); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A095C); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A0AE8); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A0B18); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A0B40); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A0CCC); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A0E00); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A0E30); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A0E60); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A0E90); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A0FCC); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A0FFC); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A102C); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A105C); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A12A8); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A12F8); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A139C); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A13CC); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A1424); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A1448); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A1490); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A14D8); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A1590); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A15E4); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A1650); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A1688); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A170C); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A17B0); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A1828); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A18F4); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A1988); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A1A00); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A1A90); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A1B08); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A1B38); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A1B94); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A1C60); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A1DF4); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A20C0); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A23E4); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A276C); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A2B50); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A2E58); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A31E0); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A359C); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A39E4); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A3C28); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A3E30); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A3EE8); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A46F0); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A47E4); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A5124); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A5240); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A5278); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A5324); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A5410); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A5428); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A5A54); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A5CBC); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A5D7C); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A5E9C); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A5FBC); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A6024); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A6AC0); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A6BC0); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A6C60); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A6EE8); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A70F0); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A7300); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A7D70); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A7DAC); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A7DEC); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A7E04); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A7E8C); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A80C0); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A8174); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A82B0); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A838C); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A8500); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A860C); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A8724); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A89EC); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A8C90); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A8D00); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A8D58); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A9000); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A9128); - -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A91BC); +/** @brief Opcode handler: ramp the screen tint up to the maximum, then stop. */ +static void func_801A9208(EffectEntity *entity) { + BattleTint *tint = D_800EF738; + s32 i; + + entity->pos.vx += EFFECT_TINT_STEP; + if (entity->pos.vx >= EFFECT_TINT_MAX) { + entity->pos.vx = EFFECT_TINT_MAX; + entity->flags |= EFFECT_FLAG_STOP; + entity->pc++; + } + for (i = 0; i < 4; i++) { + tint->level = entity->pos.vx; + tint++; + } +} -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A9208); +/** @brief Opcode handler: no-op. */ +static void func_801A9270(EffectEntity *entity) { +} -void func_801A9270(void) { +/** + * @brief Script dispatcher for the tint fade-in. + * + * @return 2 once the script has stopped and its children have drained, 0 while + * it is still running. + */ +static s32 func_801A9278(EffectEntity *entity) { + EffectHandler handlers[3] = { func_801A91BC, func_801A9208, func_801A9270 }; + + 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_027/nonmatchings/effect_027", func_801A9278); +/** @brief Opcode handler: hold the screen tint at the maximum. */ +static void func_801A9318(EffectEntity *entity) { + entity->pos.vx = EFFECT_TINT_MAX; + entity->pc++; +} -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A9318); +/** @brief Opcode handler: ramp the screen tint back to zero, then stop. */ +static void func_801A9330(EffectEntity *entity) { + BattleTint *tint = D_800EF738; + s32 i; + + entity->pos.vx -= EFFECT_TINT_STEP; + if (entity->pos.vx <= 0) { + entity->pos.vx = 0; + entity->flags |= EFFECT_FLAG_STOP; + entity->pc++; + } + for (i = 0; i < 4; i++) { + tint->level = entity->pos.vx; + tint++; + } +} -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A9330); +/** @brief Opcode handler: no-op. */ +static void func_801A938C(EffectEntity *entity) { +} -void func_801A938C(void) { +/** + * @brief Script dispatcher for the tint fade-out. + * + * @return 2 once the script has stopped and its children have drained, 0 while + * it is still running. + */ +static s32 func_801A9394(EffectEntity *entity) { + EffectHandler handlers[3] = { func_801A9318, func_801A9330, func_801A938C }; + + 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_027/nonmatchings/effect_027", func_801A9394); +/** @brief Opcode handler: draw and retire once the frame count is reached. */ +static void func_801A9434(EffectEntity *entity) { + EffectDrawScript *script = (EffectDrawScript *)entity; -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A9434); + 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_027/nonmatchings/effect_027", func_801A9490); +/** @brief Opcode handler: hold still until the draw script finishes. */ +static void func_801A9490(EffectEntity *entity) { + if (effectDrawScriptRun((EffectDrawScript *)entity) != 0) { + entity->flags |= EFFECT_FLAG_STOP; + entity->pc++; + } +} -void func_801A94D8(void) { +/** @brief Opcode handler: no-op. */ +static void func_801A94D8(EffectEntity *entity) { } -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A94E0); +/** + * @brief Script dispatcher for the draw script. + * + * @return 2 once the script has stopped and its children have drained, 0 while + * it is still running. + */ +static s32 func_801A94E0(EffectEntity *entity) { + EffectHandler handlers[3] = { func_801A9434, func_801A9490, func_801A94D8 }; + + 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_027/nonmatchings/effect_027", func_801A9580); +/** @brief Opcode handler: start the pose script on the taken model. */ +static void func_801A9580(EffectEntity *entity) { + effectStartChildScript(entity, func_801A94E0, &D_801D4314, 0, 0x2D, 0); + entity->pc++; +} -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A95D8); +/** @brief Opcode handler: release the model once the count reaches 30. */ +static void func_801A95D8(EffectEntity *entity) { + if (entity->unk024 == 30) { + entity->unk010->unk063 = 0; + entity->pc++; + } +} -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A960C); +/** @brief Opcode handler: hand the current part to battle, then stop. */ +static void func_801A960C(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_801A9694(void) { +/** @brief Opcode handler: no-op. */ +static void func_801A9694(EffectEntity *entity) { } -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A969C); +/** @brief Run one frame of this effect's script and report whether it ended. */ +static s32 func_801A969C(EffectEntity *entity) { + EffectHandler handlers[4] = { func_801A9580, func_801A95D8, func_801A960C, + func_801A9694 }; + + effectCacheSlotAnchors(entity); + effectUpdateModelBounds(entity); + handlers[entity->pc](entity); + if (entity->unk024 == 0) { + func_800C4764(D_801A9C5C, 0, 0x80); + } + 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_027/nonmatchings/effect_027", func_801A9778); +/** @brief Opcode handler: consume the opcode and do nothing else. */ +static void func_801A9778(EffectEntity *entity) { + entity->pc++; +} -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A978C); +/** @brief Opcode handler: consume the opcode and do nothing else. */ +static void func_801A978C(EffectEntity *entity) { + entity->pc++; +} -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A97A0); +/** @brief Opcode handler: carve both record banks and start the draw script. */ +static void func_801A97A0(EffectEntity *entity) { + if (entity->wait == 0) { + /* Both banks are carved out of the same byte arena behind the TIM. */ + g_effectEmitterBank = (EffectEmitter *)D_801D35C4; + D_801D35C4 += EFFECT_EMITTER_BANK_BYTES; + g_effectParticleBank = (EffectParticle *)D_801D35C4; + D_801D35C4 += EFFECT_PARTICLE_BANK_BYTES; + effectBanksClear(); + effectSpawnTask(&D_801D3854, func_801A9278, 0x40, entity); + entity->pc++; + } +} -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A9830); +/** @brief Opcode handler: start a task running @ref func_801A969C. */ +static void func_801A9830(EffectEntity *entity) { + entity->unk063 = 1; + effectSpawnTask(&D_801D42E4, func_801A969C, 0x58, entity); + entity->pc++; +} -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A9888); +/** @brief Opcode handler: repeat the step until the loop counter runs out. */ +static void func_801A9888(EffectEntity *entity) { + if (entity->unk063 == 0) { + if (entity->unk02A < entity->unk058) { + entity->unk02A++; + entity->unk02E++; + entity->pc--; + } else { + /* The byte trio at unk060 is this script's countdown, one halfword wide. */ + *(s16 *)entity->unk060 = 10; + entity->pc++; + } + } +} -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A98EC); +/** @brief Opcode handler: spawn the tint fade-out once the wait runs out. */ +static void func_801A98EC(EffectEntity *entity) { + /* The byte trio at unk060 is this script's countdown, one halfword wide. */ + if (--*(s16 *)entity->unk060 <= 0) { + effectSpawnTask(&D_801D3854, func_801A9394, 0x40, entity); + entity->pc++; + } +} -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A9954); +/** @brief Opcode handler: stall here until @c unk05E reaches zero. */ +static void func_801A9954(EffectEntity *entity) { + if (entity->unk05E == 0) { + entity->pc++; + } +} -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A997C); +/** @brief Opcode handler: consume the opcode and do nothing else. */ +static void func_801A997C(EffectEntity *entity) { + entity->pc++; +} -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A9990); +/** @brief Opcode handler: consume the opcode and do nothing else. */ +static void func_801A9990(EffectEntity *entity) { + entity->pc++; +} -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A99A4); +/** @brief Opcode handler: raise @ref EFFECT_FLAG_STOP and consume the opcode. */ +static void func_801A99A4(EffectEntity *entity) { + entity->flags |= EFFECT_FLAG_STOP; + entity->pc++; +} -void func_801A99C0(void) { +/** @brief Opcode handler: no-op. */ +static void func_801A99C0(EffectEntity *entity) { } -INCLUDE_ASM("asm/ovl/effect_027/nonmatchings/effect_027", func_801A99C8); +/** + * @brief Run one frame of the effect: its opcode, then every task pool it owns. + * + * @param entity The script's root entity. + * @return 2 once the script has stopped and its children have drained, 0 while + * it is still running. + */ +s32 func_801A99C8(EffectEntity *entity) { + EffectHandler handlers[11] = { + func_801A9778, func_801A978C, func_801A97A0, func_801A9830, func_801A9888, + func_801A98EC, func_801A9954, func_801A997C, func_801A9990, func_801A99A4, + func_801A99C0 + }; + MATRIX *view = EFFECT_SCRATCHPAD; + + *view = D_800F02C8; + g_effectStackTop = (u8 *)view; + g_effectStackBase = view; + if (entity->unk05C & EFFECT_FRAME_ODD) { + g_effectPrimCursor = D_801D408C; + D_801D4088 = D_801D4094; + } else { + g_effectPrimCursor = D_801D4090; + D_801D4088 = D_801D4098; + } + effectCacheAnimSlotAnchors(entity); + handlers[entity->pc](entity); + g_effectParticleTotal = 0; + entity->unk05E = 0; + g_effectLiveTotal = 0; + entity->unk05E += func_800B2B68(&D_801D42E4); + entity->unk05E += func_800B2B68(&g_effectChildPool); + entity->unk05E += func_800B2B68(&D_801D3854); + 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_027_entry.c b/src/effect/effect_027_entry.c new file mode 100644 index 00000000..727e07ff --- /dev/null +++ b/src/effect/effect_027_entry.c @@ -0,0 +1,61 @@ +/** + * @file effect_027_entry.c + * @brief Full-Life: the overlay entry point. + */ +#include "common.h" +#include "effect.h" +#include "effect/lib/entity.h" +#include "effect/lib/tables.h" +#include "effect/effect_027.h" +#include "effect/effect_027_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_801D35B4 = 0; + D_801D35B8 = 0; + func_800B2A00(&D_801D4174, &D_801D40A4, 0x64, 2); + entity = effectSpawnTask(&D_801D4174, func_801A99C8, 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_801A9D3C); + func_800BB084(&D_801AA794); + } + D_801D35C4 = &D_801AA794; + bank0 = &D_801AA794; + D_801D408C = bank0; + bank1 = bank0 + EFFECT_BANK_SIZE; + D_801D4094 = bank0 + EFFECT_BANK_SIZE; + D_801D35C4 = bank0 + EFFECT_BANK_SIZE; + frames = bank1; + D_801D4090 = frames; + frames += EFFECT_BANK_SIZE; + D_801D35C4 = frames; + D_801D4098 = frames; + func_800B2A00(&D_801D42E4, &D_801D4184, 0x58, 4); + func_800B2A00(&g_effectChildPool, &D_801D3884, 0x2A4, 3); + func_800B2A00(&D_801D3854, &D_801D35D4, 0x40, 0xA); + return &D_801D4174; +} diff --git a/src/effect/effect_028.c b/src/effect/effect_028.c index 929f8133..5dcc75ce 100644 --- a/src/effect/effect_028.c +++ b/src/effect/effect_028.c @@ -86,7 +86,7 @@ static void func_801A9500(EffectEntity *entity) { entity->flags |= EFFECT_FLAG_STOP; entity->pc++; } - for (i = 3; i >= 0; i--) { + for (i = 0; i < 4; i++) { tint->level = entity->pos.vx; tint++; } @@ -134,7 +134,7 @@ static void func_801A9628(EffectEntity *entity) { entity->flags |= EFFECT_FLAG_STOP; entity->pc++; } - for (i = 3; i >= 0; i--) { + for (i = 0; i < 4; i++) { tint->level = entity->pos.vx; tint++; } diff --git a/src/effect/effect_039.c b/src/effect/effect_039.c index c7af5bf2..264e07a0 100644 --- a/src/effect/effect_039.c +++ b/src/effect/effect_039.c @@ -80,7 +80,7 @@ static void func_801A9500(EffectEntity *entity) { entity->flags |= EFFECT_FLAG_STOP; entity->pc++; } - for (i = 3; i >= 0; i--) { + for (i = 0; i < 4; i++) { tint->level = entity->pos.vx; tint++; } @@ -128,7 +128,7 @@ static void func_801A9628(EffectEntity *entity) { entity->flags |= EFFECT_FLAG_STOP; entity->pc++; } - for (i = 3; i >= 0; i--) { + for (i = 0; i < 4; i++) { tint->level = entity->pos.vx; tint++; } diff --git a/src/effect/lib/fill.c b/src/effect/lib/fill.c index 284c5e71..38557ed8 100644 --- a/src/effect/lib/fill.c +++ b/src/effect/lib/fill.c @@ -6,7 +6,13 @@ #include "effect.h" #include "effect/lib/fill.h" -/** @brief Fill @p count words at @p dst with @p value. */ +/** + * @brief Fill @p count words at @p dst with @p value. + * + * The index is never read, which makes it look like a loop that should count + * up. It is not: the ascending form generates different code, so counting down + * to @c -1 is load-bearing. + */ void effectFillWords(s32 *dst, s32 value, s32 count) { s32 i; diff --git a/src/effect/lib/rot.c b/src/effect/lib/rot.c index 2efe4010..2d475252 100644 --- a/src/effect/lib/rot.c +++ b/src/effect/lib/rot.c @@ -1,6 +1,10 @@ /** * @file rot.c * @brief Rotation matrices built from an angle. + * + * The three builders clear the matrix through a countdown whose index is never + * read, which makes it look like a loop that should count up. It is not: the + * ascending form generates different code, so the countdown is load-bearing. */ #include "common.h" #include "effect.h"