diff --git a/assets/xml/objects/object_dy_obj.xml b/assets/xml/objects/object_dy_obj.xml index 91b9a55fbd..37fef4ab19 100644 --- a/assets/xml/objects/object_dy_obj.xml +++ b/assets/xml/objects/object_dy_obj.xml @@ -1,51 +1,62 @@  + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -55,42 +66,46 @@ + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/objects/object_efc_tw.xml b/assets/xml/objects/object_efc_tw.xml index a7ca81b55a..c28ae3c81f 100644 --- a/assets/xml/objects/object_efc_tw.xml +++ b/assets/xml/objects/object_efc_tw.xml @@ -1,13 +1,16 @@  - - + + + - - - - - + + + + + + + diff --git a/include/z64save.h b/include/z64save.h index 1db5a566df..7d1bc781d6 100644 --- a/include/z64save.h +++ b/include/z64save.h @@ -650,11 +650,14 @@ typedef enum { #define WEEKEVENTREG_CLOCK_TOWER_OPENED PACK_WEEKEVENTREG_FLAG(8, 0x40) #define WEEKEVENTREG_08_80 PACK_WEEKEVENTREG_FLAG(8, 0x80) + +// This 5 flags are managed in a special way by EnElfgrp #define WEEKEVENTREG_09_01 PACK_WEEKEVENTREG_FLAG(9, 0x01) #define WEEKEVENTREG_09_02 PACK_WEEKEVENTREG_FLAG(9, 0x02) #define WEEKEVENTREG_09_04 PACK_WEEKEVENTREG_FLAG(9, 0x04) #define WEEKEVENTREG_09_08 PACK_WEEKEVENTREG_FLAG(9, 0x08) #define WEEKEVENTREG_09_10 PACK_WEEKEVENTREG_FLAG(9, 0x10) + #define WEEKEVENTREG_09_20 PACK_WEEKEVENTREG_FLAG(9, 0x20) #define WEEKEVENTREG_09_40 PACK_WEEKEVENTREG_FLAG(9, 0x40) #define WEEKEVENTREG_09_80 PACK_WEEKEVENTREG_FLAG(9, 0x80) @@ -795,7 +798,7 @@ typedef enum { #define WEEKEVENTREG_22_40 PACK_WEEKEVENTREG_FLAG(22, 0x40) #define WEEKEVENTREG_22_80 PACK_WEEKEVENTREG_FLAG(22, 0x80) #define WEEKEVENTREG_23_01 PACK_WEEKEVENTREG_FLAG(23, 0x01) -#define WEEKEVENTREG_23_02 PACK_WEEKEVENTREG_FLAG(23, 0x02) +#define WEEKEVENTREG_OBTAINED_GREAT_SPIN_ATTACK PACK_WEEKEVENTREG_FLAG(23, 0x02) #define WEEKEVENTREG_23_04 PACK_WEEKEVENTREG_FLAG(23, 0x04) #define WEEKEVENTREG_23_08 PACK_WEEKEVENTREG_FLAG(23, 0x08) #define WEEKEVENTREG_23_10 PACK_WEEKEVENTREG_FLAG(23, 0x10) @@ -1631,6 +1634,9 @@ typedef enum { /* 3 */ DUNGEON_INDEX_STONE_TOWER_TEMPLE // Also applies to Inverted Stone Tower Temple } DungeonIndex; +#define STRAY_FAIRY_TOTAL 25 // total number of stray fairies, including those already in the Great Fairy Fountain +#define STRAY_FAIRY_SCATTERED_TOTAL 15 // original number of stray fairies in one dungeon area + void Sram_ActivateOwl(u8 owlId); void Sram_ClearFlagsAtDawnOfTheFirstDay(void); void Sram_SaveEndOfCycle(struct PlayState* play); diff --git a/spec b/spec index eb09f058f6..d7d51ec20a 100644 --- a/spec +++ b/spec @@ -2365,8 +2365,7 @@ beginseg name "ovl_Bg_Dy_Yoseizo" compress include "build/src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.o" - include "build/data/ovl_Bg_Dy_Yoseizo/ovl_Bg_Dy_Yoseizo.data.o" - include "build/data/ovl_Bg_Dy_Yoseizo/ovl_Bg_Dy_Yoseizo.reloc.o" + include "build/src/overlays/actors/ovl_Bg_Dy_Yoseizo/ovl_Bg_Dy_Yoseizo_reloc.o" endseg beginseg diff --git a/src/code/z_actor.c b/src/code/z_actor.c index a69dada412..10f782e25d 100644 --- a/src/code/z_actor.c +++ b/src/code/z_actor.c @@ -725,7 +725,7 @@ void Target_Update(TargetContext* targetCtx, Player* player, Actor* lockOnActor, /* Start of Flags section */ /** - * Tests if current scene switch flag is set. + * Tests if a current scene switch flag is set. */ s32 Flags_GetSwitch(PlayState* play, s32 flag) { if ((flag >= 0) && (flag < 0x80)) { @@ -735,7 +735,7 @@ s32 Flags_GetSwitch(PlayState* play, s32 flag) { } /** - * Sets current scene switch flag. + * Sets a current scene switch flag. */ void Flags_SetSwitch(PlayState* play, s32 flag) { if ((flag >= 0) && (flag < 0x80)) { @@ -744,7 +744,7 @@ void Flags_SetSwitch(PlayState* play, s32 flag) { } /** - * Unsets current scene switch flag. + * Unsets a current scene switch flag. */ void Flags_UnsetSwitch(PlayState* play, s32 flag) { if ((flag >= 0) && (flag < 0x80)) { @@ -753,77 +753,77 @@ void Flags_UnsetSwitch(PlayState* play, s32 flag) { } /** - * Tests if current scene chest flag is set. + * Tests if a current scene chest flag is set. */ s32 Flags_GetTreasure(PlayState* play, s32 flag) { return play->actorCtx.sceneFlags.chest & (1 << flag); } /** - * Sets current scene chest flag. + * Sets a current scene chest flag. */ void Flags_SetTreasure(PlayState* play, s32 flag) { play->actorCtx.sceneFlags.chest |= (1 << flag); } /** - * Overrides the all the chest flags. + * Overrides all the current scene chest flags. */ void Flags_SetAllTreasure(PlayState* play, s32 flag) { play->actorCtx.sceneFlags.chest = flag; } /** - * Returns all the chest flags. + * Returns all the current scene chest flags. */ s32 Flags_GetAllTreasure(PlayState* play) { return play->actorCtx.sceneFlags.chest; } /** - * Tests if current scene clear flag is set. + * Tests if a current scene clear flag is set. */ s32 Flags_GetClear(PlayState* play, s32 roomNumber) { return play->actorCtx.sceneFlags.clearedRoom & (1 << roomNumber); } /** - * Sets current scene clear flag. + * Sets a current scene clear flag. */ void Flags_SetClear(PlayState* play, s32 roomNumber) { play->actorCtx.sceneFlags.clearedRoom |= (1 << roomNumber); } /** - * Unsets current scene clear flag. + * Unsets a current scene clear flag. */ void Flags_UnsetClear(PlayState* play, s32 roomNumber) { play->actorCtx.sceneFlags.clearedRoom &= ~(1 << roomNumber); } /** - * Tests if current scene temp clear flag is set. + * Tests if a current scene temp clear flag is set. */ s32 Flags_GetClearTemp(PlayState* play, s32 roomNumber) { return play->actorCtx.sceneFlags.clearedRoomTemp & (1 << roomNumber); } /** - * Sets current scene temp clear flag. + * Sets a current scene temp clear flag. */ void Flags_SetClearTemp(PlayState* play, s32 roomNumber) { play->actorCtx.sceneFlags.clearedRoomTemp |= (1 << roomNumber); } /** - * Unsets current scene temp clear flag. + * Unsets a current scene temp clear flag. */ void Flags_UnsetClearTemp(PlayState* play, s32 roomNumber) { play->actorCtx.sceneFlags.clearedRoomTemp &= ~(1 << roomNumber); } /** - * Tests if current scene collectible flag is set. + * Tests if a current scene collectible flag is set. */ s32 Flags_GetCollectible(PlayState* play, s32 flag) { if ((flag > 0) && (flag < 0x80)) { @@ -833,7 +833,7 @@ s32 Flags_GetCollectible(PlayState* play, s32 flag) { } /** - * Sets current scene collectible flag. + * Sets a current scene collectible flag. */ void Flags_SetCollectible(PlayState* play, s32 flag) { if ((flag > 0) && (flag < 0x80)) { diff --git a/src/code/z_en_item00.c b/src/code/z_en_item00.c index 55ab1a7082..f9f5df5a83 100644 --- a/src/code/z_en_item00.c +++ b/src/code/z_en_item00.c @@ -1,4 +1,5 @@ #include "global.h" +#include "overlays/actors/ovl_En_Elforg/z_en_elforg.h" #include "objects/gameplay_keep/gameplay_keep.h" #include "objects/object_gi_hearts/object_gi_hearts.h" #include "overlays/actors/ovl_En_Elf/z_en_elf.h" @@ -935,9 +936,9 @@ Actor* Item_DropCollectible(PlayState* play, Vec3f* spawnPos, u32 params) { SoundSource_PlaySfxAtFixedWorldPos(play, spawnPos, 40, NA_SE_EV_BUTTERFRY_TO_FAIRY); } } else { - spawnedActor = - Actor_Spawn(&play->actorCtx, play, ACTOR_EN_ELFORG, spawnPos->x, spawnPos->y + 40.0f, spawnPos->z, 0, 0, - 0, STRAY_FAIRY_PARAMS(((param7F00 >> 8) & 0x7F), 0, STRAY_FAIRY_TYPE_COLLECTIBLE)); + spawnedActor = Actor_Spawn( + &play->actorCtx, play, ACTOR_EN_ELFORG, spawnPos->x, spawnPos->y + 40.0f, spawnPos->z, 0, 0, 0, + STRAY_FAIRY_PARAMS((param7F00 >> 8) & 0x7F, STRAY_FAIRY_AREA_CLOCK_TOWN, STRAY_FAIRY_TYPE_COLLECTIBLE)); if (param20000 == 0) { if (!Flags_GetCollectible(play, (param7F00 >> 8) & 0x7F)) { SoundSource_PlaySfxAtFixedWorldPos(play, spawnPos, 40, NA_SE_EV_BUTTERFRY_TO_FAIRY); @@ -993,9 +994,9 @@ Actor* Item_DropCollectible2(PlayState* play, Vec3f* spawnPos, s32 params) { spawnedActor = Actor_Spawn(&play->actorCtx, play, ACTOR_EN_ELF, spawnPos->x, spawnPos->y + 40.0f, spawnPos->z, 0, 0, 0, FAIRY_PARAMS(FAIRY_TYPE_2, true, param7F00 >> 8)); } else { - spawnedActor = - Actor_Spawn(&play->actorCtx, play, ACTOR_EN_ELFORG, spawnPos->x, spawnPos->y + 40.0f, spawnPos->z, 0, 0, - 0, STRAY_FAIRY_PARAMS(((param7F00 >> 8) & 0x7F), 0, STRAY_FAIRY_TYPE_COLLECTIBLE)); + spawnedActor = Actor_Spawn( + &play->actorCtx, play, ACTOR_EN_ELFORG, spawnPos->x, spawnPos->y + 40.0f, spawnPos->z, 0, 0, 0, + STRAY_FAIRY_PARAMS((param7F00 >> 8) & 0x7F, STRAY_FAIRY_AREA_CLOCK_TOWN, STRAY_FAIRY_TYPE_COLLECTIBLE)); } if (Flags_GetCollectible(play, (param7F00 >> 8) & 0x7F) == 0) { SoundSource_PlaySfxAtFixedWorldPos(play, spawnPos, 40, NA_SE_EV_BUTTERFRY_TO_FAIRY); diff --git a/src/code/z_sram_NES.c b/src/code/z_sram_NES.c index 8d382e5db3..c5fe03475e 100644 --- a/src/code/z_sram_NES.c +++ b/src/code/z_sram_NES.c @@ -97,7 +97,8 @@ u16 sPersistentCycleWeekEventRegs[ARRAY_COUNT(gSaveContext.save.saveInfo.weekEve /* 20 */ 0, /* 21 */ 0, /* 22 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_22_02) | PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_22_80), - /* 23 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_23_02) | PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_23_80), + /* 23 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_OBTAINED_GREAT_SPIN_ATTACK) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_23_80), /* 24 */ PERSISTENT_WEEKEVENTREG_ALT(WEEKEVENTREG_24_02) | PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_24_80), /* 25 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_25_01), /* 26 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_26_40), diff --git a/src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.c b/src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.c index 332e4e5430..4045303426 100644 --- a/src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.c +++ b/src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.c @@ -5,6 +5,7 @@ */ #include "z_bg_dy_yoseizo.h" +#include "overlays/actors/ovl_Demo_Effect/z_demo_effect.h" #define FLAGS (ACTOR_FLAG_10 | ACTOR_FLAG_20 | ACTOR_FLAG_2000000) @@ -13,19 +14,17 @@ void BgDyYoseizo_Init(Actor* thisx, PlayState* play); void BgDyYoseizo_Destroy(Actor* thisx, PlayState* play); void BgDyYoseizo_Update(Actor* thisx, PlayState* play); +void BgDyYoseizo_Draw(Actor* thisx, PlayState* play); -void func_80A0AE1C(BgDyYoseizo* this, PlayState* play); -void func_80A0B078(BgDyYoseizo* this, PlayState* play); void func_80A0B184(BgDyYoseizo* this, PlayState* play); -void func_80A0B290(BgDyYoseizo* this, PlayState* play); -void func_80A0B35C(BgDyYoseizo* this, PlayState* play); -void func_80A0B500(BgDyYoseizo* this, PlayState* play); -void func_80A0B5F0(BgDyYoseizo* this, PlayState* play); -void func_80A0B75C(BgDyYoseizo* this, PlayState* play); -void func_80A0B8CC(BgDyYoseizo* this, PlayState* play); void func_80A0BB08(BgDyYoseizo* this, PlayState* play); -#if 0 +/* Effects functions */ +void BgDyYoseizo_SpawnEffect(BgDyYoseizo* this, Vec3f* initPos, Vec3f* initVelocity, Vec3f* accel, + Color_RGB8* primColor, Color_RGB8* envColor, f32 scale, s16 life, s16 type); +void BgDyYoseizo_UpdateEffects(BgDyYoseizo* this, PlayState* play); +void BgDyYoseizo_DrawEffects(BgDyYoseizo* this, PlayState* play); + ActorInit Bg_Dy_Yoseizo_InitVars = { ACTOR_BG_DY_YOSEIZO, ACTORCAT_PROP, @@ -38,56 +37,730 @@ ActorInit Bg_Dy_Yoseizo_InitVars = { (ActorFunc)NULL, }; -#endif +typedef enum GreatFairyAnimation { + /* 0 */ GREATFAIRY_ANIM_START_GIVING_UPGRADE, + /* 1 */ GREATFAIRY_ANIM_GIVING_UPGRADE, + /* 2 */ GREATFAIRY_ANIM_SPIN_LAY_DOWN, + /* 3 */ GREATFAIRY_ANIM_LAY_DOWN_TRANSITION, + /* 4 */ GREATFAIRY_ANIM_LAYING_DOWN, + /* 5 */ GREATFAIRY_ANIM_SHOWING_ITEM, + /* 6 */ GREATFAIRY_ANIM_ARMS_FOLDED, + /* 7 */ GREATFAIRY_ANIM_CLAPPING, + /* 8 */ GREATFAIRY_ANIM_TEACH_SPIN_ATTACK, + /* 9 */ GREATFAIRY_ANIM_MAX +} GreatFairyAnimation; -extern UNK_TYPE D_06008090; -extern UNK_TYPE D_0600D228; -extern UNK_TYPE D_0601C6F4; +static AnimationHeader* sAnimations[GREATFAIRY_ANIM_MAX] = { + &gGreatFairyStartGivingUpgradeAnim, // GREATFAIRY_ANIM_START_GIVING_UPGRADE + &gGreatFairyGivingUpgradeAnim, // GREATFAIRY_ANIM_GIVING_UPGRADE + &gGreatFairySpinLayDownAnim, // GREATFAIRY_ANIM_SPIN_LAY_DOWN + &gGreatFairyLayDownTransitionAnim, // GREATFAIRY_ANIM_LAY_DOWN_TRANSITION + &gGreatFairyLayingDownAnim, // GREATFAIRY_ANIM_LAYING_DOWN + &gGreatFairyShowingItemAnim, // GREATFAIRY_ANIM_SHOWING_ITEM + &gGreatFairyArmsFoldedAnim, // GREATFAIRY_ANIM_ARMS_FOLDED + &gGreatFairyClappingAnim, // GREATFAIRY_ANIM_CLAPPING + &gGreatFairyTeachSpinAttackAnim, // GREATFAIRY_ANIM_TEACH_SPIN_ATTACK +}; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Dy_Yoseizo/BgDyYoseizo_Init.s") +void BgDyYoseizo_Init(Actor* thisx, PlayState* play) { + BgDyYoseizo* this = THIS; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Dy_Yoseizo/BgDyYoseizo_Destroy.s") + this->unk2EC = this->actor.world.pos.y + 40.0f; + this->actor.focus.pos = this->actor.world.pos; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Dy_Yoseizo/func_80A0A96C.s") + SkelAnime_InitFlex(play, &this->skelAnime, &gGreatFairySkel, &gGreatFairyShowingItemAnim, this->jointTable, + this->morphTable, GREAT_FAIRY_LIMB_MAX); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Dy_Yoseizo/func_80A0A9E4.s") + this->actionFunc = func_80A0BB08; + Actor_SetScale(&this->actor, 0.0f); + this->eyeIndex = 0; + this->mouthIndex = 0; + this->blinkTimer = 0; + this->unk2F8 = 0; + GREAT_FAIRY_ROTZ(&this->actor) = 1; + this->unk302 = 0; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Dy_Yoseizo/func_80A0AA40.s") +void BgDyYoseizo_Destroy(Actor* thisx, PlayState* play) { +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Dy_Yoseizo/func_80A0AD50.s") +// Has no visible effect since no segment is set for manually-controllable eye textures +void BgDyYoseizo_UpdateEyes(BgDyYoseizo* this) { + if (this->blinkTimer != 0) { + this->blinkTimer--; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Dy_Yoseizo/func_80A0AE1C.s") + if (this->blinkTimer == 0) { + this->eyeIndex++; + if (this->eyeIndex >= 3) { + this->eyeIndex = 0; + this->blinkTimer = (s32)Rand_ZeroFloat(60.0f) + 20; + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Dy_Yoseizo/func_80A0AFDC.s") +void BgDyYoseizo_Bob(BgDyYoseizo* this, PlayState* play) { + this->actor.shape.yOffset = Math_SinS(play->gameplayFrames * 1000) * 15.0f; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Dy_Yoseizo/func_80A0B078.s") +typedef enum GreatFairyEffectTrajectory { + /* 0 */ GREAT_FAIRY_EFFECT_TRAJECTORY_RADIANT, // Dispersing particles, in the Great Fairy's signature colour. + /* 2 */ GREAT_FAIRY_EFFECT_TRAJECTORY_FAST_RADIANT = 2, // As above, but initially move 10 times faster. + /* 5 */ GREAT_FAIRY_EFFECT_TRAJECTORY_CONVERGE_ON_PLAYER = 5 // Similar to OoT's healing effect, fixed colour. +} GreatFairyEffectTrajectory; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Dy_Yoseizo/func_80A0B184.s") +/** + * Spawn particle effects; see `GreatFairyEffectTrajectory` enum for details + * + * @param trajectoryType use the `GreatFairyEffectTrajectory` enum. + * @param count number to spawn. + */ +void BgDyYoseizo_SpawnEffects(BgDyYoseizo* this, s16 trajectoryType, s32 count) { + static Color_RGB8 sEffectPrimColors[] = { + { 255, 235, 220 }, // Magic + { 255, 220, 220 }, // Power + { 220, 255, 220 }, // Wisdom + { 220, 220, 255 }, // Courage + { 255, 255, 200 }, // Kindness + { 255, 255, 170 }, // GREAT_FAIRY_EFFECT_TRAJECTORY_CONVERGE_ON_PLAYER + }; + static Color_RGB8 sEffectEnvColors[] = { + { 255, 150, 0 }, // Magic + { 255, 0, 0 }, // Power + { 0, 255, 0 }, // Wisdom + { 0, 0, 255 }, // Courage + { 255, 255, 0 }, // Kindness + { 255, 100, 255 }, // GREAT_FAIRY_EFFECT_TRAJECTORY_CONVERGE_ON_PLAYER + }; + Vec3f velocity; + Vec3f accel; + Vec3f pos; + Color_RGB8 primColor; + Color_RGB8 envColor; + f32 spawnHeightVariation; + f32 scale; + s32 effectType; + s32 life; + s32 i; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Dy_Yoseizo/func_80A0B290.s") + if (this->actor.scale.y < 0.01f) { + return; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Dy_Yoseizo/func_80A0B35C.s") + spawnHeightVariation = this->actor.scale.y * 3500.0f; + accel.x = Rand_ZeroOne() - 0.5f; + accel.y = Rand_ZeroOne() - 0.5f; + accel.z = Rand_ZeroOne() - 0.5f; + velocity.x = accel.x * 10.0f; + velocity.y = accel.y * 10.0f; + velocity.z = accel.z * 10.0f; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Dy_Yoseizo/func_80A0B500.s") + for (i = 0; i < count; i++) { + switch (trajectoryType) { + case GREAT_FAIRY_EFFECT_TRAJECTORY_FAST_RADIANT: + scale = 1.0f; + life = 90; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Dy_Yoseizo/func_80A0B5F0.s") + velocity.x = accel.x * 100.0f; + velocity.y = accel.y * 100.0f; + velocity.z = accel.z * 100.0f; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Dy_Yoseizo/func_80A0B75C.s") + effectType = GREAT_FAIRY_GET_TYPE(&this->actor); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Dy_Yoseizo/func_80A0B834.s") + pos.x = this->actor.world.pos.x; + pos.y = this->actor.world.pos.y + spawnHeightVariation + + (Rand_ZeroOne() - 0.5f) * (spawnHeightVariation * 0.5f); + pos.z = this->actor.world.pos.z + 30.0f; + break; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Dy_Yoseizo/func_80A0B8CC.s") + case GREAT_FAIRY_EFFECT_TRAJECTORY_RADIANT: + scale = 1.0f; + life = 90; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Dy_Yoseizo/func_80A0BB08.s") + effectType = GREAT_FAIRY_GET_TYPE(&this->actor); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Dy_Yoseizo/BgDyYoseizo_Update.s") + pos.x = this->actor.world.pos.x; + pos.y = this->actor.world.pos.y + spawnHeightVariation + + (Rand_ZeroOne() - 0.5f) * (spawnHeightVariation * 0.5f); + pos.z = this->actor.world.pos.z + 30.0f; + break; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Dy_Yoseizo/func_80A0BCD8.s") + default: // all become convergent type + scale = 0.2f; + life = 50; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Dy_Yoseizo/func_80A0BD40.s") + effectType = GREAT_FAIRY_EFFECT_TRAJECTORY_CONVERGE_ON_PLAYER; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Dy_Yoseizo/func_80A0BE60.s") + pos.x = Rand_CenteredFloat(10.0f) + this->actor.world.pos.x; + pos.y = this->actor.world.pos.y + spawnHeightVariation + 50.0f + + (Rand_ZeroOne() - 0.5f) * (spawnHeightVariation * 0.1f); + pos.z = this->actor.world.pos.z + 30.0f; + break; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Dy_Yoseizo/func_80A0BF70.s") + primColor.r = sEffectPrimColors[effectType].r; + primColor.g = sEffectPrimColors[effectType].g; + primColor.b = sEffectPrimColors[effectType].b; + envColor.r = sEffectEnvColors[effectType].r; + envColor.g = sEffectEnvColors[effectType].g; + envColor.b = sEffectEnvColors[effectType].b; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Dy_Yoseizo/func_80A0C270.s") + BgDyYoseizo_SpawnEffect(this, &pos, &velocity, &accel, &primColor, &envColor, scale, life, effectType); + } +} + +void func_80A0AD50(BgDyYoseizo* this) { + f32 scale = this->actor.scale.x; + f32 heightTarget = this->actor.home.pos.y + 40.0f; + + Math_ApproachF(&this->actor.world.pos.y, heightTarget, this->unk2F0, 100.0f); + Math_ApproachF(&scale, 0.035f, this->unk2F4, 0.005f); + Math_ApproachF(&this->unk2F0, 0.8f, 0.1f, 0.02f); + Math_ApproachF(&this->unk2F4, 0.2f, 0.03f, 0.05f); + BgDyYoseizo_SpawnEffects(this, GREAT_FAIRY_EFFECT_TRAJECTORY_RADIANT, 2); + Actor_SetScale(&this->actor, scale); +} + +void func_80A0AE1C(BgDyYoseizo* this, PlayState* play) { + f32 scale = this->actor.scale.x; + f32 heightTarget = this->actor.home.pos.y; + + if (scale < 0.003f) { + this->actionFunc = func_80A0BB08; + Actor_SetScale(&this->actor, 0.0f); + this->unk2F0 = 0.0f; + this->unk2F4 = 0.0f; + this->unk2F8 = 0; + + if (GREAT_FAIRY_GET_TYPE(&this->actor) <= GREAT_FAIRY_TYPE_COURAGE) { + Actor_Spawn(&play->actorCtx, play, ACTOR_DEMO_EFFECT, this->actor.world.pos.x, + this->actor.world.pos.y + 20.0f, this->actor.world.pos.z, 0, 0, 0, + GREAT_FAIRY_GET_TYPE(&this->actor) + DEMO_EFFECT_TYPE_LIGHT_BASE); + } else { + Actor_Spawn(&play->actorCtx, play, ACTOR_DEMO_EFFECT, this->actor.world.pos.x, + this->actor.world.pos.y + 20.0f, this->actor.world.pos.z, 0, 0, 0, + DEMO_EFFECT_TYPE_LIGHT_DARK_YELLOW); + } + Audio_PlaySfx(NA_SE_SY_WHITE_OUT_T); + } else { + Math_ApproachF(&this->actor.world.pos.y, heightTarget, this->unk2F0, 100.0f); + Math_ApproachZeroF(&scale, this->unk2F4, 0.005f); + Math_ApproachF(&this->unk2F0, 0.8f, 0.1f, 0.02f); + Math_ApproachF(&this->unk2F4, 0.2f, 0.03f, 0.05f); + + this->actor.shape.rot.y += this->unk2F8; + if (this->unk2F8 < 0x1770) { + this->unk2F8 += 0x12C; + } + + BgDyYoseizo_SpawnEffects(this, GREAT_FAIRY_EFFECT_TRAJECTORY_RADIANT, 2); + Actor_SetScale(&this->actor, scale); + } +} + +void func_80A0AFDC(BgDyYoseizo* this) { + Animation_Change(&this->skelAnime, sAnimations[GREATFAIRY_ANIM_SPIN_LAY_DOWN], 0.0f, 46.0f, + Animation_GetLastFrame(sAnimations[GREATFAIRY_ANIM_SPIN_LAY_DOWN]), ANIMMODE_ONCE, 0.0f); + this->actionFunc = func_80A0AE1C; + Actor_PlaySfx(&this->actor, NA_SE_VO_FR_LAUGH_0); + Actor_PlaySfx(&this->actor, NA_SE_EV_GREAT_FAIRY_VANISH); + this->unk2F8 = 0; + this->actor.velocity.y = 0.0f; + this->unk2F0 = 0.0f; + this->unk2F4 = 0.0f; + this->actor.shape.yOffset = 0.0f; +} + +void func_80A0B078(BgDyYoseizo* this, PlayState* play) { + BgDyYoseizo_Bob(this, play); + SkelAnime_Update(&this->skelAnime); + + if (Cutscene_IsCueInChannel(play, CS_CMD_ACTOR_CUE_103) && + (play->csCtx.actorCues[Cutscene_GetCueChannel(play, CS_CMD_ACTOR_CUE_103)]->id == 7)) { + Animation_Change(&this->skelAnime, sAnimations[GREATFAIRY_ANIM_LAYING_DOWN], 1.0f, 0.0f, + Animation_GetLastFrame(sAnimations[GREATFAIRY_ANIM_LAYING_DOWN]), ANIMMODE_LOOP, 0.0f); + this->actionFunc = func_80A0B184; + } else if (Cutscene_IsCueInChannel(play, CS_CMD_ACTOR_CUE_103) && + (play->csCtx.actorCues[Cutscene_GetCueChannel(play, CS_CMD_ACTOR_CUE_103)]->id == 6)) { + func_80A0AFDC(this); + } +} + +void func_80A0B184(BgDyYoseizo* this, PlayState* play) { + BgDyYoseizo_Bob(this, play); + SkelAnime_Update(&this->skelAnime); + + if (Cutscene_IsCueInChannel(play, CS_CMD_ACTOR_CUE_103) && + (play->csCtx.actorCues[Cutscene_GetCueChannel(play, CS_CMD_ACTOR_CUE_103)]->id == 8)) { + Animation_Change(&this->skelAnime, sAnimations[GREATFAIRY_ANIM_SHOWING_ITEM], 1.0f, 0.0f, + Animation_GetLastFrame(sAnimations[GREATFAIRY_ANIM_SHOWING_ITEM]), ANIMMODE_LOOP, 0.0f); + this->actionFunc = func_80A0B078; + } else if (Cutscene_IsCueInChannel(play, CS_CMD_ACTOR_CUE_103) && + (play->csCtx.actorCues[Cutscene_GetCueChannel(play, CS_CMD_ACTOR_CUE_103)]->id == 6)) { + func_80A0AFDC(this); + } +} + +void func_80A0B290(BgDyYoseizo* this, PlayState* play) { + BgDyYoseizo_Bob(this, play); + SkelAnime_Update(&this->skelAnime); + + if (Cutscene_IsCueInChannel(play, CS_CMD_ACTOR_CUE_103) && + (play->csCtx.actorCues[Cutscene_GetCueChannel(play, CS_CMD_ACTOR_CUE_103)]->id == 7)) { + Animation_Change(&this->skelAnime, sAnimations[GREATFAIRY_ANIM_LAYING_DOWN], 1.0f, 0.0f, + Animation_GetLastFrame(sAnimations[GREATFAIRY_ANIM_LAYING_DOWN]), ANIMMODE_LOOP, -10.0f); + this->actionFunc = func_80A0B184; + this->mouthIndex = 0; + } +} + +void func_80A0B35C(BgDyYoseizo* this, PlayState* play) { + BgDyYoseizo_Bob(this, play); + SkelAnime_Update(&this->skelAnime); + + if (this->timer == 60) { + if (!Flags_GetSwitch(play, GREAT_FAIRY_GET_SWITCHFLAG(&this->actor))) { + switch (GREAT_FAIRY_GET_TYPE(&this->actor)) { + case GREAT_FAIRY_TYPE_MAGIC: + if (gSaveContext.save.saveInfo.playerData.isMagicAcquired != true) { + gSaveContext.save.saveInfo.playerData.isMagicAcquired = true; + gSaveContext.magicFillTarget = MAGIC_NORMAL_METER; + } + break; + + case GREAT_FAIRY_TYPE_WISDOM: + if (gSaveContext.save.saveInfo.playerData.isDoubleMagicAcquired != true) { + gSaveContext.save.saveInfo.playerData.isDoubleMagicAcquired = true; + gSaveContext.magicFillTarget = MAGIC_DOUBLE_METER; + gSaveContext.save.saveInfo.playerData.magicLevel = 0; + } + break; + + case GREAT_FAIRY_TYPE_COURAGE: + if (gSaveContext.save.saveInfo.playerData.doubleDefense != true) { + gSaveContext.save.saveInfo.playerData.doubleDefense = true; + } + break; + + default: + break; + } + } + Interface_SetHudVisibility(9); + } + + if ((this->timer < 50) && (GREAT_FAIRY_GET_TYPE(&this->actor) == GREAT_FAIRY_TYPE_COURAGE)) { + if (gSaveContext.save.saveInfo.inventory.defenseHearts < 20) { + gSaveContext.save.saveInfo.inventory.defenseHearts++; + } + } + + if (this->timer == 50) { + gSaveContext.healthAccumulator = 0x140; + Magic_Add(play, MAGIC_FILL_TO_CAPACITY); + } + + if (this->timer == 0) { + this->beam->trigger = true; + this->actionFunc = func_80A0B290; + } +} + +void func_80A0B500(BgDyYoseizo* this, PlayState* play) { + Player* player = GET_PLAYER(play); + + BgDyYoseizo_Bob(this, play); + + if (SkelAnime_Update(&this->skelAnime)) { + Vec3f pos; + + Animation_Change(&this->skelAnime, sAnimations[GREATFAIRY_ANIM_GIVING_UPGRADE], 1.0f, 0.0f, + Animation_GetLastFrame(sAnimations[GREATFAIRY_ANIM_GIVING_UPGRADE]), ANIMMODE_LOOP, 0.0f); + this->actionFunc = func_80A0B35C; + pos.x = player->actor.world.pos.x; + pos.y = player->actor.world.pos.y + 200.0f; + pos.z = player->actor.world.pos.z; + this->beam = (EnDyExtra*)Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_EN_DY_EXTRA, pos.x, + pos.y, pos.z, 0, 0, 0, GREAT_FAIRY_GET_TYPE(&this->actor)); + this->timer = 120; + } +} + +void func_80A0B5F0(BgDyYoseizo* this, PlayState* play) { + BgDyYoseizo_Bob(this, play); + + if (SkelAnime_Update(&this->skelAnime)) { + Animation_Change(&this->skelAnime, sAnimations[GREATFAIRY_ANIM_LAYING_DOWN], 1.0f, 0.0f, + Animation_GetLastFrame(sAnimations[GREATFAIRY_ANIM_LAYING_DOWN]), ANIMMODE_LOOP, 0.0f); + } + + if (Cutscene_IsCueInChannel(play, CS_CMD_ACTOR_CUE_103) && + (play->csCtx.actorCues[Cutscene_GetCueChannel(play, CS_CMD_ACTOR_CUE_103)]->id == 5)) { + Animation_Change(&this->skelAnime, sAnimations[GREATFAIRY_ANIM_START_GIVING_UPGRADE], 1.0f, 0.0f, + Animation_GetLastFrame(sAnimations[GREATFAIRY_ANIM_START_GIVING_UPGRADE]), ANIMMODE_ONCE, + -5.0f); + Actor_PlaySfx(&this->actor, NA_SE_VO_FR_SMILE_0); + this->mouthIndex = 1; + this->eyeIndex = 0; + this->actionFunc = func_80A0B500; + } + + if (Cutscene_IsCueInChannel(play, CS_CMD_ACTOR_CUE_103) && + (play->csCtx.actorCues[Cutscene_GetCueChannel(play, CS_CMD_ACTOR_CUE_103)]->id == 6)) { + func_80A0AFDC(this); + } + + BgDyYoseizo_UpdateEyes(this); +} + +void func_80A0B75C(BgDyYoseizo* this, PlayState* play) { + func_80A0AD50(this); + SkelAnime_Update(&this->skelAnime); + + if (Cutscene_IsCueInChannel(play, CS_CMD_ACTOR_CUE_103) && + (play->csCtx.actorCues[Cutscene_GetCueChannel(play, CS_CMD_ACTOR_CUE_103)]->id == 4)) { + this->actor.shape.rot.y = 0; + this->actionFunc = func_80A0B5F0; + Animation_Change(&this->skelAnime, sAnimations[GREATFAIRY_ANIM_LAY_DOWN_TRANSITION], 1.0f, 2.0f, + Animation_GetLastFrame(sAnimations[GREATFAIRY_ANIM_LAY_DOWN_TRANSITION]), ANIMMODE_ONCE, 0.0f); + Actor_PlaySfx(&this->actor, NA_SE_VO_FR_SMILE_0); + this->unk2F8 = 0; + } +} + +void func_80A0B834(BgDyYoseizo* this) { + this->actor.draw = BgDyYoseizo_Draw; + Animation_Change(&this->skelAnime, sAnimations[GREATFAIRY_ANIM_SPIN_LAY_DOWN], 1.0f, 0.0f, + Animation_GetLastFrame(sAnimations[GREATFAIRY_ANIM_SPIN_LAY_DOWN]), ANIMMODE_ONCE, 0.0f); + Actor_PlaySfx(&this->actor, NA_SE_VO_FR_LAUGH_0); + Actor_PlaySfx(&this->actor, NA_SE_EV_GREAT_FAIRY_APPEAR); + BgDyYoseizo_SpawnEffects(this, GREAT_FAIRY_EFFECT_TRAJECTORY_FAST_RADIANT, 30); +} + +void BgDyYoseizo_TrainPlayer(BgDyYoseizo* this, PlayState* play) { + s16 csId; + s32 pad; + Player* player = GET_PLAYER(play); + + SkelAnime_Update(&this->skelAnime); + + csId = 0; + if (Cutscene_IsCueInChannel(play, CS_CMD_ACTOR_CUE_103)) { + csId = play->csCtx.actorCues[Cutscene_GetCueChannel(play, CS_CMD_ACTOR_CUE_103)]->id; + Cutscene_ActorTranslateAndYaw(&this->actor, play, Cutscene_GetCueChannel(play, CS_CMD_ACTOR_CUE_103)); + } else { + if (GREAT_FAIRY_ROTZ(&this->actor) != 0) { + this->actor.home.pos.x = player->actor.world.pos.x; + this->actor.home.pos.z = player->actor.world.pos.z; + GREAT_FAIRY_ROTZ(&this->actor) = 0; + } else { + player->actor.world.pos.x = this->actor.home.pos.x; + player->actor.world.pos.z = this->actor.home.pos.z; + } + + if (this->unk302 & 1) { + if (this->timer == 0) { + if (CutsceneManager_IsNext(this->actor.csId)) { + CutsceneManager_StartWithPlayerCs(this->actor.csId, &this->actor); + this->unk302 &= ~1; + } else { + CutsceneManager_Queue(this->actor.csId); + } + } + } else if (!(this->unk302 & 2) && (player->meleeWeaponState != 0)) { + if (player->meleeWeaponAnimation >= PLAYER_MWA_SPIN_ATTACK_1H) { + if (player->unk_B08 >= 0.85f) { + this->unk302 |= 1; + this->unk302 |= 2; + if (play->msgCtx.currentTextId == 0x59A) { + Message_CloseTextbox(play); + } + this->timer = 20; + return; + } + } + + if (play->msgCtx.currentTextId != 0x59A) { + // "Hold B and then release" + Message_StartTextbox(play, 0x59A, &this->actor); + } + } + } + + if (csId != this->csId) { + switch (csId) { + case 9: + Animation_PlayLoop(&this->skelAnime, sAnimations[GREATFAIRY_ANIM_ARMS_FOLDED]); + break; + + case 10: + Animation_PlayLoop(&this->skelAnime, sAnimations[GREATFAIRY_ANIM_CLAPPING]); + break; + + case 11: + Animation_PlayOnce(&this->skelAnime, sAnimations[GREATFAIRY_ANIM_TEACH_SPIN_ATTACK]); + break; + + default: + break; + } + + this->csId = csId; + } +} + +// Choose behaviour? +void func_80A0BB08(BgDyYoseizo* this, PlayState* play) { + if (Cutscene_IsCueInChannel(play, CS_CMD_ACTOR_CUE_103) && + (play->csCtx.actorCues[Cutscene_GetCueChannel(play, CS_CMD_ACTOR_CUE_103)]->id == 2)) { + func_80A0B834(this); + this->actionFunc = func_80A0B75C; + } + + if (Cutscene_IsCueInChannel(play, CS_CMD_ACTOR_CUE_103) && + (play->csCtx.actorCues[Cutscene_GetCueChannel(play, CS_CMD_ACTOR_CUE_103)]->id == 7)) { + this->actor.draw = BgDyYoseizo_Draw; + Animation_PlayLoop(&this->skelAnime, sAnimations[GREATFAIRY_ANIM_LAYING_DOWN]); + this->actionFunc = func_80A0B184; + this->mouthIndex = 0; + this->actor.world.pos.y = this->actor.home.pos.y + 40.0f; + Actor_SetScale(&this->actor, 0.035f); + this->unk2F8 = 0; + } + + if (Cutscene_IsCueInChannel(play, CS_CMD_ACTOR_CUE_103) && + (play->csCtx.actorCues[Cutscene_GetCueChannel(play, CS_CMD_ACTOR_CUE_103)]->id == 9)) { + Actor_SetScale(&this->actor, 0.01f); + Animation_PlayLoop(&this->skelAnime, sAnimations[GREATFAIRY_ANIM_ARMS_FOLDED]); + this->csId = 9; + this->actionFunc = BgDyYoseizo_TrainPlayer; + this->actor.draw = BgDyYoseizo_Draw; + } +} + +void BgDyYoseizo_Update(Actor* thisx, PlayState* play) { + BgDyYoseizo* this = THIS; + + this->actionFunc(this, play); + Actor_MoveWithGravity(&this->actor); + + DECR(this->timer); + + BgDyYoseizo_UpdateEffects(this, play); +} + +s32 BgDyYoseizo_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, Actor* thisx) { + BgDyYoseizo* this = THIS; + + if (limbIndex == GREAT_FAIRY_LIMB_TORSO) { + rot->x += this->torsoRot.y; + } + + if (limbIndex == GREAT_FAIRY_LIMB_HEAD) { + rot->x += this->headRot.y; + rot->z += this->headRot.z; + } + + return false; +} + +/* Colour and shape of eyebrows, hair colour. */ +typedef enum GreatFairyAppearance { + /* 0 */ GREAT_FAIRY_APPEARANCE_MAGIC, // Orange + /* 1 */ GREAT_FAIRY_APPEARANCE_WISDOM, // Green + /* 2 */ GREAT_FAIRY_APPEARANCE_POWER, // Pink + /* 3 */ GREAT_FAIRY_APPEARANCE_COURAGE, // Purple + /* 4 */ GREAT_FAIRY_APPEARANCE_KINDNESS // Yellow +} GreatFairyAppearance; + +void BgDyYoseizo_Draw(Actor* thisx, PlayState* play) { + static TexturePtr sMouthTextures[] = { + gGreatFairyMouthClosedTex, + gGreatFairyMouthOpenTex, + }; + BgDyYoseizo* this = THIS; + GreatFairyAppearance appearance = GREAT_FAIRY_APPEARANCE_MAGIC; + + // The differing eyes and hair colours + switch (GREAT_FAIRY_GET_TYPE(&this->actor)) { + case GREAT_FAIRY_TYPE_POWER: + appearance = GREAT_FAIRY_APPEARANCE_POWER; + break; + + case GREAT_FAIRY_TYPE_WISDOM: + appearance = GREAT_FAIRY_APPEARANCE_WISDOM; + break; + + case GREAT_FAIRY_TYPE_COURAGE: + case GREAT_FAIRY_TYPE_KINDNESS: + appearance = GREAT_FAIRY_GET_TYPE(&this->actor); + break; + + default: // GREAT_FAIRY_APPEARANCE_MAGIC + break; + } + + OPEN_DISPS(play->state.gfxCtx); + + Gfx_SetupDL25_Opa(play->state.gfxCtx); + + // Set eyes and hair colour, not actually animated. + AnimatedMat_DrawStepOpa(play, Lib_SegmentedToVirtual(gGreatFairyAppearenceTexAnim), appearance); + + // Draw mouth + { + Gfx* gfx = POLY_OPA_DISP; + s16 index = this->mouthIndex; + TexturePtr mouthTex = Lib_SegmentedToVirtual(sMouthTextures[index]); + + gSPSegment(&gfx[0], 0x09, mouthTex); + POLY_OPA_DISP = &gfx[1]; + } + + SkelAnime_DrawFlexOpa(play, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount, + BgDyYoseizo_OverrideLimbDraw, NULL, &this->actor); + + CLOSE_DISPS(play->state.gfxCtx); + + BgDyYoseizo_DrawEffects(this, play); +} + +/* Effects functions */ + +void BgDyYoseizo_SpawnEffect(BgDyYoseizo* this, Vec3f* initPos, Vec3f* initVelocity, Vec3f* accel, + Color_RGB8* primColor, Color_RGB8* envColor, f32 scale, s16 life, s16 type) { + BgDyYoseizoEffect* effect = this->effects; + s16 i; + + for (i = 0; i < BG_DY_YOSEIZO_EFFECT_COUNT; i++, effect++) { + if (!effect->alive) { + effect->alive = true; + effect->pos = *initPos; + effect->velocity = *initVelocity; + effect->accel = *accel; + effect->primColor = *primColor; + effect->alpha = 0; + effect->envColor = *envColor; + effect->scale = scale; + effect->timer = life; + effect->type = type; + effect->pitch = 0; + effect->yaw = TRUNCF_BINANG(Rand_CenteredFloat(30000.0f)); + effect->roll = 0; + return; + } + } +} + +void BgDyYoseizo_UpdateEffects(BgDyYoseizo* this, PlayState* play) { + BgDyYoseizoEffect* effect = this->effects; + Player* player = GET_PLAYER(play); + Vec3f sp94; + Vec3f sp88; + s32 pad[2]; + f32 targetPitch; + f32 targetYaw; + f32 floatAngle; + s16 i = 0; + + for (i = 0; i < BG_DY_YOSEIZO_EFFECT_COUNT; i++, effect++) { + if (effect->alive) { + effect->roll += 3000; + + if (effect->type < GREAT_FAIRY_EFFECT_TRAJECTORY_CONVERGE_ON_PLAYER) { + effect->pos.x += effect->velocity.x; + effect->pos.y += effect->velocity.y; + effect->pos.z += effect->velocity.z; + effect->velocity.x += effect->accel.x; + effect->velocity.y += effect->accel.y; + effect->velocity.z += effect->accel.z; + } else { + Actor_PlaySfx(&this->actor, NA_SE_EV_HEALING - SFX_FLAG); + + sp94 = player->actor.world.pos; + sp94.y = player->actor.world.pos.y - 150.0f; + sp94.z = player->actor.world.pos.z - 50.0f; + + targetPitch = Math_Vec3f_Pitch(&effect->pos, &sp94); + targetYaw = Math_Vec3f_Yaw(&effect->pos, &sp94); + + floatAngle = effect->pitch; + Math_ApproachF(&floatAngle, targetPitch, 0.9f, 5000.0f); + effect->pitch = floatAngle; + + floatAngle = effect->yaw; + Math_ApproachF(&floatAngle, targetYaw, 0.9f, 5000.0f); + effect->yaw = floatAngle; + + Matrix_Push(); + Matrix_RotateYS(effect->yaw, MTXMODE_NEW); + Matrix_RotateXS(effect->pitch, MTXMODE_APPLY); + + sp94.x = sp94.y = sp94.z = 3.0f; + + Matrix_MultVec3f(&sp94, &sp88); + Matrix_Pop(); + effect->pos.x += sp88.x; + effect->pos.y += sp88.y; + effect->pos.z += sp88.z; + } + } + + // fade up, fade down, vanish and reset + if (effect->timer != 0) { + effect->timer--; + effect->alpha += 30; + + if (effect->alpha > 255) { + effect->alpha = 255; + } + } else { + effect->alpha -= 30; + + if (effect->alpha <= 0) { + effect->alpha = 0; + effect->alive = false; + } + } + } +} + +void BgDyYoseizo_DrawEffects(BgDyYoseizo* this, PlayState* play) { + static f32 sStretchFactors[] = { + 1.0f, 1.1f, 1.15f, 1.1f, 1.0f, 0.9f, 0.85f, 0.9f, + }; + GraphicsContext* gfxCtx = play->state.gfxCtx; + u8 setup = 0; + BgDyYoseizoEffect* effect = this->effects; + f32 stretchFactor = sStretchFactors[play->gameplayFrames % ARRAY_COUNT(sStretchFactors)]; + s16 i; + + OPEN_DISPS(gfxCtx); + + Gfx_SetupDL25_Xlu(play->state.gfxCtx); + + for (i = 0; i < BG_DY_YOSEIZO_EFFECT_COUNT; i++, effect++) { + if (effect->alive == true) { + if (setup == 0) { + gSPDisplayList(POLY_XLU_DISP++, gGreatFairyParticleSetupDL); + gDPPipeSync(POLY_XLU_DISP++); + setup++; + } + + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, effect->primColor.r, effect->primColor.g, effect->primColor.b, + effect->alpha); + gDPSetEnvColor(POLY_XLU_DISP++, effect->envColor.r, effect->envColor.g, effect->envColor.b, 0); + + Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW); + Matrix_ReplaceRotation(&play->billboardMtxF); + + Matrix_Scale(effect->scale, effect->scale * stretchFactor, 1.0f, MTXMODE_APPLY); + Matrix_RotateZS(effect->roll, MTXMODE_APPLY); + + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_XLU_DISP++, gGreatFairyParticleDL); + } + } + + CLOSE_DISPS(gfxCtx); +} diff --git a/src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.h b/src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.h index bd06cdb384..4aaf67e778 100644 --- a/src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.h +++ b/src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.h @@ -2,15 +2,65 @@ #define Z_BG_DY_YOSEIZO_H #include "global.h" +#include "overlays/actors/ovl_En_Dy_Extra/z_en_dy_extra.h" +#include "objects/object_dy_obj/object_dy_obj.h" struct BgDyYoseizo; typedef void (*BgDyYoseizoActionFunc)(struct BgDyYoseizo*, PlayState*); +#define GREAT_FAIRY_GET_SWITCHFLAG(thisx) (((thisx)->params & 0xFE00) >> 9) +#define GREAT_FAIRY_GET_TYPE(thisx) ((thisx)->params & 0xF) +#define GREAT_FAIRY_ROTZ(thisx) ((thisx)->home.rot.z) + +typedef enum GreatFairyType { + /* 0 */ GREAT_FAIRY_TYPE_MAGIC, + /* 1 */ GREAT_FAIRY_TYPE_POWER, + /* 2 */ GREAT_FAIRY_TYPE_WISDOM, + /* 3 */ GREAT_FAIRY_TYPE_COURAGE, + /* 4 */ GREAT_FAIRY_TYPE_KINDNESS +} GreatFairyType; + +#define BG_DY_YOSEIZO_EFFECT_COUNT 200 + +typedef struct BgDyYoseizoEffect { + /* 0x00 */ u8 alive; // drawn if 1, respawn if 0 + /* 0x04 */ Vec3f pos; + /* 0x10 */ Vec3f velocity; + /* 0x1C */ Vec3f accel; + /* 0x28 */ Color_RGB8 primColor; + /* 0x2B */ Color_RGB8 envColor; + /* 0x2E */ s16 alpha; + /* 0x30 */ f32 scale; + /* 0x34 */ s16 timer; // lifetime + /* 0x36 */ s16 type; // 0 is general radiance, else is directed towards Player + /* 0x38 */ s16 pitch; + /* 0x3A */ s16 yaw; + /* 0x3C */ s16 roll; // all three are f32 in OoT +} BgDyYoseizoEffect; // size = 0x40 + typedef struct BgDyYoseizo { /* 0x0000 */ Actor actor; /* 0x0144 */ BgDyYoseizoActionFunc actionFunc; - /* 0x0148 */ char unk_148[0x33BC]; + /* 0x0148 */ SkelAnime skelAnime; + /* 0x018C */ Vec3s jointTable[GREAT_FAIRY_LIMB_MAX]; + /* 0x0234 */ Vec3s morphTable[GREAT_FAIRY_LIMB_MAX]; + /* 0x02DC */ Vec3s headRot; + /* 0x02DC */ Vec3s torsoRot; + /* 0x02E8 */ EnDyExtra* beam; + /* 0x02EC */ f32 unk2EC; // unused + /* 0x02F0 */ f32 unk2F0; + /* 0x02F4 */ f32 unk2F4; + /* 0x02F8 */ union { + s16 unk2F8; + s16 csId; // used on BgDyYoseizo_TrainPlayer + }; + /* 0x02FA */ s16 eyeIndex; + /* 0x02FC */ s16 mouthIndex; + /* 0x02FE */ s16 blinkTimer; + /* 0x0300 */ s16 timer; + /* 0x0302 */ u16 unk302; + /* 0x0304 */ BgDyYoseizoEffect effects[BG_DY_YOSEIZO_EFFECT_COUNT]; } BgDyYoseizo; // size = 0x3504 #endif // Z_BG_DY_YOSEIZO_H diff --git a/src/overlays/actors/ovl_Demo_Effect/z_demo_effect.c b/src/overlays/actors/ovl_Demo_Effect/z_demo_effect.c index ca472ccc30..ff88a61db0 100644 --- a/src/overlays/actors/ovl_Demo_Effect/z_demo_effect.c +++ b/src/overlays/actors/ovl_Demo_Effect/z_demo_effect.c @@ -16,14 +16,13 @@ void DemoEffect_Init(Actor* thisx, PlayState* play); void DemoEffect_Destroy(Actor* thisx, PlayState* play); void DemoEffect_Update(Actor* thisx, PlayState* play); -void func_808CD940(DemoEffect* this, PlayState* play); -void func_808CD998(DemoEffect* this, PlayState* play); -void func_808CDBDC(DemoEffect* this, PlayState* play); -void func_808CDCEC(DemoEffect* this, PlayState* play); -void func_808CDD70(DemoEffect* this, PlayState* play); -void func_808CDDE0(DemoEffect* this, PlayState* play); -void func_808CDFF8(Actor* thisx, PlayState* play); -void func_808CE078(Actor* thisx, PlayState* play2); +void DemoEffect_WaitForObject(DemoEffect* this, PlayState* play); +void DemoEffect_SetupTimewarp(DemoEffect* this, PlayState* play); +void DemoEffect_StartTimewarp(DemoEffect* this, PlayState* play); +void DemoEffect_ShrinkLight(DemoEffect* this, PlayState* play); +void DemoEffect_ExpandLight(DemoEffect* this, PlayState* play); +void DemoEffect_DrawTimewarp(Actor* thisx, PlayState* play); +void DemoEffect_DrawLight(Actor* thisx, PlayState* play2); ActorInit Demo_Effect_InitVars = { ACTOR_DEMO_EFFECT, @@ -47,8 +46,12 @@ void DemoEffect_Init(Actor* thisx, PlayState* play) { s32 type = DEMO_EFFECT_GET_TYPE(&this->actor); s32 objectIndex; s32 pad2; - Color_RGB8 colors[] = { - { 200, 200, 0 }, { 255, 40, 100 }, { 50, 255, 0 }, { 0, 0, 255 }, { 255, 255, 80 }, + Color_RGB8 lightColors[] = { + { 200, 200, 0 }, // Yellow + { 255, 40, 100 }, // Pink + { 50, 255, 0 }, // Light green + { 0, 0, 255 }, // Blue + { 255, 255, 80 }, // Light Yellow }; if (sEffectTypeObjects[type] == GAMEPLAY_KEEP) { @@ -66,14 +69,14 @@ void DemoEffect_Init(Actor* thisx, PlayState* play) { Actor_SetScale(&this->actor, 0.2f); switch (type) { - case DEMO_EFFECT_TYPE_0: - case DEMO_EFFECT_TYPE_1: + case DEMO_EFFECT_TIMEWARP_TIMEBLOCK_LARGE: + case DEMO_EFFECT_TIMEWARP_TIMEBLOCK_SMALL: this->actor.flags |= ACTOR_FLAG_2000000; - - case DEMO_EFFECT_TYPE_2: - case DEMO_EFFECT_TYPE_3: - this->initDrawFunc = func_808CDFF8; - this->initActionFunc = func_808CD998; + // FALLTHROUGH + case DEMO_EFFECT_TIMEWARP_LIGHTBLOCK_LARGE: + case DEMO_EFFECT_TIMEWARP_LIGHTBLOCK_VERY_LARGE: + this->initDrawFunc = DemoEffect_DrawTimewarp; + this->initActionFunc = DemoEffect_SetupTimewarp; this->envXluColor[0] = 0; this->envXluColor[1] = 100; this->envXluColor[2] = 255; @@ -81,17 +84,17 @@ void DemoEffect_Init(Actor* thisx, PlayState* play) { this->timer = 0; break; - case DEMO_EFFECT_TYPE_4: - case DEMO_EFFECT_TYPE_5: - case DEMO_EFFECT_TYPE_6: - case DEMO_EFFECT_TYPE_7: - case DEMO_EFFECT_TYPE_8: - this->envXluColor[0] = colors[type - 4].r; - this->envXluColor[1] = colors[type - 4].g; - this->envXluColor[2] = colors[type - 4].b; + case DEMO_EFFECT_TYPE_LIGHT_DARK_YELLOW: + case DEMO_EFFECT_TYPE_LIGHT_PINK: + case DEMO_EFFECT_TYPE_LIGHT_GREEN: + case DEMO_EFFECT_TYPE_LIGHT_BLUE: + case DEMO_EFFECT_TYPE_LIGHT_YELLOW: + this->envXluColor[0] = lightColors[type - DEMO_EFFECT_TYPE_LIGHT_BASE].r; + this->envXluColor[1] = lightColors[type - DEMO_EFFECT_TYPE_LIGHT_BASE].g; + this->envXluColor[2] = lightColors[type - DEMO_EFFECT_TYPE_LIGHT_BASE].b; Actor_SetScale(&this->actor, 0.0f); - this->initDrawFunc = func_808CE078; - this->initActionFunc = func_808CDDE0; + this->initDrawFunc = DemoEffect_DrawLight; + this->initActionFunc = DemoEffect_ExpandLight; this->timer = 0; break; @@ -100,17 +103,17 @@ void DemoEffect_Init(Actor* thisx, PlayState* play) { } ActorShape_Init(&this->actor.shape, 0.0f, NULL, 0.0f); - this->actionFunc = func_808CD940; + this->actionFunc = DemoEffect_WaitForObject; } void DemoEffect_Destroy(Actor* thisx, PlayState* play) { DemoEffect* this = THIS; switch (DEMO_EFFECT_GET_TYPE(&this->actor)) { - case DEMO_EFFECT_TYPE_0: - case DEMO_EFFECT_TYPE_1: - case DEMO_EFFECT_TYPE_2: - case DEMO_EFFECT_TYPE_3: + case DEMO_EFFECT_TIMEWARP_TIMEBLOCK_LARGE: + case DEMO_EFFECT_TIMEWARP_TIMEBLOCK_SMALL: + case DEMO_EFFECT_TIMEWARP_LIGHTBLOCK_LARGE: + case DEMO_EFFECT_TIMEWARP_LIGHTBLOCK_VERY_LARGE: SkelCurve_Destroy(play, &this->skelCurve); break; @@ -119,7 +122,7 @@ void DemoEffect_Destroy(Actor* thisx, PlayState* play) { } } -void func_808CD940(DemoEffect* this, PlayState* play) { +void DemoEffect_WaitForObject(DemoEffect* this, PlayState* play) { if (Object_IsLoaded(&play->objectCtx, this->initObjectIndex)) { this->actor.objBankIndex = this->initObjectIndex; this->actor.draw = this->initDrawFunc; @@ -127,41 +130,41 @@ void func_808CD940(DemoEffect* this, PlayState* play) { } } -void func_808CD998(DemoEffect* this, PlayState* play) { +void DemoEffect_SetupTimewarp(DemoEffect* this, PlayState* play) { s32 type = DEMO_EFFECT_GET_TYPE(&this->actor); - if (SkelCurve_Init(play, &this->skelCurve, &object_efc_tw_Skel_0012E8, &object_efc_tw_CurveAnim_000050)) {} + if (SkelCurve_Init(play, &this->skelCurve, &gTimewarpSkel, &gTimewarpAnim)) {} - SkelCurve_SetAnim(&this->skelCurve, &object_efc_tw_CurveAnim_000050, 1.0f, 59.0f, 1.0f, 1.7f); + SkelCurve_SetAnim(&this->skelCurve, &gTimewarpAnim, 1.0f, 59.0f, 1.0f, 1.7f); SkelCurve_Update(play, &this->skelCurve); - this->actionFunc = func_808CDCEC; + this->actionFunc = DemoEffect_StartTimewarp; switch (type) { - case DEMO_EFFECT_TYPE_0: - Actor_SetScale(&this->actor, 0.16800001f); + case DEMO_EFFECT_TIMEWARP_TIMEBLOCK_LARGE: + Actor_SetScale(&this->actor, 168.0f * 0.001f); break; - case DEMO_EFFECT_TYPE_1: - Actor_SetScale(&this->actor, 0.08400001f); + case DEMO_EFFECT_TIMEWARP_TIMEBLOCK_SMALL: + Actor_SetScale(&this->actor, 84.0f * 0.001f); break; - case DEMO_EFFECT_TYPE_2: - Actor_SetScale(&this->actor, 0.16800001f); + case DEMO_EFFECT_TIMEWARP_LIGHTBLOCK_LARGE: + Actor_SetScale(&this->actor, 168.0f * 0.001f); break; - case DEMO_EFFECT_TYPE_3: - Actor_SetScale(&this->actor, 0.28f); + case DEMO_EFFECT_TIMEWARP_LIGHTBLOCK_VERY_LARGE: + Actor_SetScale(&this->actor, 280.0f * 0.001f); break; default: - Actor_SetScale(&this->actor, 0.014f); + Actor_SetScale(&this->actor, 14.0f * 0.001f); break; } } -void func_808CDAD0(f32 alphaScale) { +void DemoEffect_SetPerVertexAlpha(f32 alphaScale) { static u8 sAlphaTypes[] = { 1, 1, 2, 0, 1, 1, 2, 0, 1, 2, 0, 2, 1, 0, 1, 0, 2, 0, 2, 2, 0 }; - Vtx* vtx = Lib_SegmentedToVirtual(object_efc_tw_Vtx_000060); + Vtx* vtx = Lib_SegmentedToVirtual(gTimewarpVtx); s32 i; u8 alphas[3]; @@ -176,7 +179,10 @@ void func_808CDAD0(f32 alphaScale) { } } -void func_808CDBDC(DemoEffect* this, PlayState* play) { +/** + * Shrink and fade linearly for 100 frames then remove. + */ +void DemoEffect_FinishTimewarp(DemoEffect* this, PlayState* play) { s32 type = DEMO_EFFECT_GET_TYPE(&this->actor); f32 scale; f32 alphaScale; @@ -187,19 +193,19 @@ void func_808CDBDC(DemoEffect* this, PlayState* play) { scale = alphaScale * 0.14f; switch (type) { - case DEMO_EFFECT_TYPE_0: + case DEMO_EFFECT_TIMEWARP_TIMEBLOCK_LARGE: scale *= 1.2f; break; - case DEMO_EFFECT_TYPE_1: + case DEMO_EFFECT_TIMEWARP_TIMEBLOCK_SMALL: scale *= 0.6f; break; - case DEMO_EFFECT_TYPE_2: + case DEMO_EFFECT_TIMEWARP_LIGHTBLOCK_LARGE: scale *= 1.2f; break; - case DEMO_EFFECT_TYPE_3: + case DEMO_EFFECT_TIMEWARP_LIGHTBLOCK_VERY_LARGE: scale *= 2.0f; break; @@ -209,25 +215,31 @@ void func_808CDBDC(DemoEffect* this, PlayState* play) { this->actor.scale.x = scale; this->actor.scale.z = scale; - func_808CDAD0(alphaScale); + DemoEffect_SetPerVertexAlpha(alphaScale); Actor_PlaySfx_FlaggedCentered3(&this->actor, NA_SE_EV_TIMETRIP_LIGHT - SFX_FLAG); } else { - func_808CDAD0(1.0f); + DemoEffect_SetPerVertexAlpha(1.0f); Actor_Kill(&this->actor); } } -void func_808CDCEC(DemoEffect* this, PlayState* play) { +/** + * Runs until animation plays to frame 59 and pauses it on frame 59. + */ +void DemoEffect_StartTimewarp(DemoEffect* this, PlayState* play) { Actor_PlaySfx_FlaggedCentered3(&this->actor, NA_SE_EV_TIMETRIP_LIGHT - SFX_FLAG); if (SkelCurve_Update(play, &this->skelCurve)) { - SkelCurve_SetAnim(&this->skelCurve, &object_efc_tw_CurveAnim_000050, 1.0f, 60.0f, 59.0f, 0.0f); - this->actionFunc = func_808CDBDC; + SkelCurve_SetAnim(&this->skelCurve, &gTimewarpAnim, 1.0f, 60.0f, 59.0f, 0.0f); + this->actionFunc = DemoEffect_FinishTimewarp; this->timer = 0; } } -void func_808CDD70(DemoEffect* this, PlayState* play) { +/** + * Take scale to 0 linearly, when scale is small enough, remove. + */ +void DemoEffect_ShrinkLight(DemoEffect* this, PlayState* play) { Actor_SetScale(&this->actor, this->actor.scale.x - 0.02f); this->timer++; @@ -236,12 +248,16 @@ void func_808CDD70(DemoEffect* this, PlayState* play) { } } -void func_808CDDE0(DemoEffect* this, PlayState* play) { +/** + * Changes scale for 3 frames, scale is successively 0.0f, 0.2f, 0.3f, 0.35f (would converge to 0.4 exponentially if run + * for a long time). + */ +void DemoEffect_ExpandLight(DemoEffect* this, PlayState* play) { Actor_SetScale(&this->actor, (this->actor.scale.x * 0.5f) + 0.2f); this->timer++; if (this->timer >= 3) { - this->actionFunc = func_808CDD70; + this->actionFunc = DemoEffect_ShrinkLight; } } @@ -251,7 +267,7 @@ void DemoEffect_Update(Actor* thisx, PlayState* play) { this->actionFunc(this, play); } -s32 func_808CDE78(PlayState* play, SkelCurve* skelCurve, s32 limbIndex, Actor* thisx) { +s32 DemoEffect_OverrideLimbDrawTimewarp(PlayState* play, SkelCurve* skelCurve, s32 limbIndex, Actor* thisx) { s32 pad; DemoEffect* this = THIS; u32 frames = play->gameplayFrames; @@ -278,7 +294,7 @@ s32 func_808CDE78(PlayState* play, SkelCurve* skelCurve, s32 limbIndex, Actor* t return true; } -void func_808CDFF8(Actor* thisx, PlayState* play) { +void DemoEffect_DrawTimewarp(Actor* thisx, PlayState* play) { GraphicsContext* gfxCtx = play->state.gfxCtx; DemoEffect* this = THIS; @@ -287,12 +303,12 @@ void func_808CDFF8(Actor* thisx, PlayState* play) { POLY_XLU_DISP = Gfx_SetupDL(POLY_XLU_DISP, SETUPDL_25); Matrix_Scale(2.0f, 2.0f, 2.0f, MTXMODE_APPLY); - SkelCurve_Draw(&this->actor, play, &this->skelCurve, func_808CDE78, NULL, 1, &this->actor); + SkelCurve_Draw(&this->actor, play, &this->skelCurve, DemoEffect_OverrideLimbDrawTimewarp, NULL, 1, &this->actor); CLOSE_DISPS(gfxCtx); } -void func_808CE078(Actor* thisx, PlayState* play2) { +void DemoEffect_DrawLight(Actor* thisx, PlayState* play2) { PlayState* play = play2; DemoEffect* this = THIS; s16 zRot = (this->timer * 0x400) & 0xFFFF; diff --git a/src/overlays/actors/ovl_Demo_Effect/z_demo_effect.h b/src/overlays/actors/ovl_Demo_Effect/z_demo_effect.h index 9901a31898..a693163082 100644 --- a/src/overlays/actors/ovl_Demo_Effect/z_demo_effect.h +++ b/src/overlays/actors/ovl_Demo_Effect/z_demo_effect.h @@ -11,15 +11,16 @@ typedef void (*DemoEffectActionFunc)(struct DemoEffect*, PlayState*); #define DEMO_EFFECT_GET_TYPE(thisx) ((thisx)->params & 0xFF) typedef enum { - /* 0 */ DEMO_EFFECT_TYPE_0, - /* 1 */ DEMO_EFFECT_TYPE_1, - /* 2 */ DEMO_EFFECT_TYPE_2, - /* 3 */ DEMO_EFFECT_TYPE_3, - /* 4 */ DEMO_EFFECT_TYPE_4, - /* 5 */ DEMO_EFFECT_TYPE_5, - /* 6 */ DEMO_EFFECT_TYPE_6, - /* 7 */ DEMO_EFFECT_TYPE_7, - /* 8 */ DEMO_EFFECT_TYPE_8 + /* 0 */ DEMO_EFFECT_TIMEWARP_TIMEBLOCK_LARGE, + /* 1 */ DEMO_EFFECT_TIMEWARP_TIMEBLOCK_SMALL, + /* 2 */ DEMO_EFFECT_TIMEWARP_LIGHTBLOCK_LARGE, + /* 3 */ DEMO_EFFECT_TIMEWARP_LIGHTBLOCK_VERY_LARGE, + /* 4 */ DEMO_EFFECT_TYPE_LIGHT_BASE, + /* 4 */ DEMO_EFFECT_TYPE_LIGHT_DARK_YELLOW = DEMO_EFFECT_TYPE_LIGHT_BASE, + /* 5 */ DEMO_EFFECT_TYPE_LIGHT_PINK, + /* 6 */ DEMO_EFFECT_TYPE_LIGHT_GREEN, + /* 7 */ DEMO_EFFECT_TYPE_LIGHT_BLUE, + /* 8 */ DEMO_EFFECT_TYPE_LIGHT_YELLOW // Unused } DemoEffectType; typedef struct DemoEffect { diff --git a/src/overlays/actors/ovl_Demo_Getitem/z_demo_getitem.c b/src/overlays/actors/ovl_Demo_Getitem/z_demo_getitem.c index 6882c189a2..63228436f6 100644 --- a/src/overlays/actors/ovl_Demo_Getitem/z_demo_getitem.c +++ b/src/overlays/actors/ovl_Demo_Getitem/z_demo_getitem.c @@ -1,7 +1,7 @@ /* * File: z_demo_getitem.c * Overlay: ovl_Demo_Getitem - * Description: Cutscene objectIndex for Great Fairy's Mask and Great Fairy's Sword + * Description: Cutscene objects for Great Fairy's Mask and Great Fairy's Sword */ #include "z_demo_getitem.h" @@ -14,8 +14,8 @@ void DemoGetitem_Init(Actor* thisx, PlayState* play); void DemoGetitem_Destroy(Actor* thisx, PlayState* play); void DemoGetitem_Update(Actor* thisx, PlayState* play); -void func_80A4FB10(DemoGetitem* this, PlayState* play); -void func_80A4FB68(DemoGetitem* this, PlayState* play2); +void DemoGetitem_Wait(DemoGetitem* this, PlayState* play); +void DemoGetitem_PerformCutsceneActions(DemoGetitem* this, PlayState* play); void DemoGetitem_Draw(Actor* thisx, PlayState* play); ActorInit Demo_Getitem_InitVars = { @@ -36,20 +36,27 @@ static s16 sGetItemDraws[] = { GID_MASK_GREAT_FAIRY, GID_SWORD_GREAT_FAIRY }; static u16 sCueTypes[] = { CS_CMD_ACTOR_CUE_110, CS_CMD_ACTOR_CUE_566 }; +typedef enum GreatFairyRewardItem { + /* 0 */ DEMOGETITEM_ITEM_MASK_GREAT_FAIRY, + /* 1 */ DEMOGETITEM_ITEM_SWORD_GREAT_FAIRY +} GreatFairyRewardItem; + void DemoGetitem_Init(Actor* thisx, PlayState* play) { s32 pad; s32 objectIndex; s32 itemIndex; DemoGetitem* this = THIS; - itemIndex = 0; - if (DEMOGETITEM_GET_F(thisx) == 1) { - itemIndex = 1; + itemIndex = DEMOGETITEM_ITEM_MASK_GREAT_FAIRY; + if (DEMOGETITEM_GET_F(&this->actor) == 1) { + itemIndex = DEMOGETITEM_ITEM_SWORD_GREAT_FAIRY; } + Actor_SetScale(&this->actor, 0.25f); - this->actionFunc = func_80A4FB10; - this->item = sGetItemDraws[itemIndex]; + this->actionFunc = DemoGetitem_Wait; + this->getItemDrawId = sGetItemDraws[itemIndex]; this->cueType = sCueTypes[itemIndex]; + objectIndex = Object_GetIndex(&play->objectCtx, sObjectBankIndices[itemIndex]); if (objectIndex < 0) { Actor_Kill(&this->actor); @@ -62,22 +69,23 @@ void DemoGetitem_Init(Actor* thisx, PlayState* play) { void DemoGetitem_Destroy(Actor* thisx, PlayState* play) { } -void func_80A4FB10(DemoGetitem* this, PlayState* play) { +void DemoGetitem_Wait(DemoGetitem* this, PlayState* play) { if (Object_IsLoaded(&play->objectCtx, this->objectIndex)) { this->actor.draw = NULL; this->actor.objBankIndex = this->objectIndex; - this->actionFunc = func_80A4FB68; + this->actionFunc = DemoGetitem_PerformCutsceneActions; } } -void func_80A4FB68(DemoGetitem* this, PlayState* play2) { - PlayState* play = play2; - u16 sp22 = (play->gameplayFrames * 1000) & 0xFFFF; +void DemoGetitem_PerformCutsceneActions(DemoGetitem* this, PlayState* play) { + s32 pad; + u16 bobPhase = (play->gameplayFrames * 1000) % 0x10000; if (Cutscene_IsCueInChannel(play, this->cueType)) { if (play->csCtx.actorCues[Cutscene_GetCueChannel(play, this->cueType)]->id != 4) { this->actor.shape.yOffset = 0.0f; } + switch (play->csCtx.actorCues[Cutscene_GetCueChannel(play, this->cueType)]->id) { case 2: this->actor.draw = DemoGetitem_Draw; @@ -92,7 +100,7 @@ void func_80A4FB68(DemoGetitem* this, PlayState* play2) { case 4: this->actor.draw = DemoGetitem_Draw; Cutscene_ActorTranslateAndYaw(&this->actor, play, Cutscene_GetCueChannel(play, this->cueType)); - this->actor.shape.yOffset = Math_SinS(sp22) * 15.0f; + this->actor.shape.yOffset = Math_SinS(bobPhase) * 15.0f; break; default: @@ -115,5 +123,5 @@ void DemoGetitem_Draw(Actor* thisx, PlayState* play) { func_800B8050(&this->actor, play, 0); func_800B8118(&this->actor, play, 0); - GetItem_Draw(play, this->item); + GetItem_Draw(play, this->getItemDrawId); } diff --git a/src/overlays/actors/ovl_Demo_Getitem/z_demo_getitem.h b/src/overlays/actors/ovl_Demo_Getitem/z_demo_getitem.h index ca00f60484..130b2cfa64 100644 --- a/src/overlays/actors/ovl_Demo_Getitem/z_demo_getitem.h +++ b/src/overlays/actors/ovl_Demo_Getitem/z_demo_getitem.h @@ -11,7 +11,7 @@ typedef void (*DemoGetitemActionFunc)(struct DemoGetitem*, PlayState*); typedef struct DemoGetitem { /* 0x000 */ Actor actor; - /* 0x144 */ s16 item; + /* 0x144 */ s16 getItemDrawId; /* 0x146 */ u16 cueType; /* 0x148 */ s8 objectIndex; /* 0x14C */ DemoGetitemActionFunc actionFunc; diff --git a/src/overlays/actors/ovl_En_Box/z_en_box.c b/src/overlays/actors/ovl_En_Box/z_en_box.c index 959a986a41..8157d09c6b 100644 --- a/src/overlays/actors/ovl_En_Box/z_en_box.c +++ b/src/overlays/actors/ovl_En_Box/z_en_box.c @@ -539,7 +539,8 @@ void EnBox_Open(EnBox* this, PlayState* play) { Actor_SpawnAsChild(&play->actorCtx, &this->dyna.actor, play, ACTOR_EN_ELFORG, this->dyna.actor.world.pos.x, this->dyna.actor.world.pos.y, this->dyna.actor.world.pos.z, this->dyna.actor.world.rot.x, this->dyna.actor.world.rot.y, this->dyna.actor.world.rot.z, - STRAY_FAIRY_PARAMS(ENBOX_GET_CHEST_FLAG(&this->dyna.actor), 0, STRAY_FAIRY_TYPE_CHEST)); + STRAY_FAIRY_PARAMS(ENBOX_GET_CHEST_FLAG(&this->dyna.actor), STRAY_FAIRY_AREA_CLOCK_TOWN, + STRAY_FAIRY_TYPE_CHEST)); } else if (this->movementFlags & ENBOX_MOVE_0x40) { this->movementFlags &= ~ENBOX_MOVE_0x40; } diff --git a/src/overlays/actors/ovl_En_Dy_Extra/z_en_dy_extra.c b/src/overlays/actors/ovl_En_Dy_Extra/z_en_dy_extra.c index 14f08c5319..b8dea95a07 100644 --- a/src/overlays/actors/ovl_En_Dy_Extra/z_en_dy_extra.c +++ b/src/overlays/actors/ovl_En_Dy_Extra/z_en_dy_extra.c @@ -16,8 +16,8 @@ void EnDyExtra_Destroy(Actor* thisx, PlayState* play); void EnDyExtra_Update(Actor* thisx, PlayState* play); void EnDyExtra_Draw(Actor* thisx, PlayState* play); -void func_80A61334(EnDyExtra* this, PlayState* play); -void func_80A613C8(EnDyExtra* this, PlayState* play); +void EnDyExtra_WaitForTrigger(EnDyExtra* this, PlayState* play); +void EnDyExtra_Fall(EnDyExtra* this, PlayState* play); ActorInit En_Dy_Extra_InitVars = { ACTOR_EN_DY_EXTRA, @@ -41,35 +41,35 @@ void EnDyExtra_Init(Actor* thisx, PlayState* play) { this->actor.scale.x = 0.025f; this->actor.scale.y = 0.039f; this->actor.scale.z = 0.025f; - this->unk160 = this->actor.world.pos; + this->initPos = this->actor.world.pos; this->actor.gravity = -0.2f; - this->unk150 = 1.0f; - this->unk14C = 0x3C; - this->actionFunc = func_80A61334; + this->alphaScale = 1.0f; + this->timer = 60; + this->actionFunc = EnDyExtra_WaitForTrigger; } -void func_80A61334(EnDyExtra* this, PlayState* play) { +void EnDyExtra_WaitForTrigger(EnDyExtra* this, PlayState* play) { Math_ApproachF(&this->actor.gravity, 0.0f, 0.1f, 0.005f); if (this->actor.world.pos.y < -85.0f) { this->actor.velocity.y = 0.0f; } - if ((this->unk14C == 0) && (this->unk14A != 0)) { - this->unk14C = 0x32; - this->actionFunc = func_80A613C8; + if ((this->timer == 0) && this->trigger) { + this->timer = 50; + this->actionFunc = EnDyExtra_Fall; } } -void func_80A613C8(EnDyExtra* this, PlayState* play) { +void EnDyExtra_Fall(EnDyExtra* this, PlayState* play) { Math_ApproachF(&this->actor.gravity, 0.0f, 0.1f, 0.005f); - if ((this->unk14C == 0) || (this->unk150 < 0.02f)) { + if ((this->timer == 0) || (this->alphaScale < 0.02f)) { Actor_Kill(&this->actor); return; } - this->unk150 -= 0.02f; + this->alphaScale -= 0.02f; if (this->actor.world.pos.y < -85.0f) { this->actor.velocity.y = 0.0f; @@ -79,40 +79,40 @@ void func_80A613C8(EnDyExtra* this, PlayState* play) { void EnDyExtra_Update(Actor* thisx, PlayState* play) { EnDyExtra* this = THIS; - DECR(this->unk14C); + DECR(this->timer); Actor_PlaySfx(&this->actor, NA_SE_PL_SPIRAL_HEAL_BEAM - SFX_FLAG); this->actionFunc(this, play); Actor_MoveWithGravity(&this->actor); } -static Color_RGBA8 D_80A61740[] = { +static Color_RGBA8 sPrimColors[] = { { 255, 255, 170, 255 }, { 255, 170, 255, 255 }, { 255, 255, 170, 255 }, { 170, 255, 255, 255 }, { 255, 255, 170, 255 }, }; -static Color_RGBA8 D_80A61754[] = { +static Color_RGBA8 sEnvColors[] = { { 255, 100, 0, 255 }, { 255, 0, 100, 255 }, { 100, 255, 0, 255 }, { 0, 100, 255, 255 }, { 255, 230, 0, 255 } }; -static u8 D_80A61768[] = { - 2, 1, 1, 2, 0, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 1, 2, 0, 0, +static u8 sAlphaTypeIndices[] = { + 2, 1, 1, 2, 0, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 1, 2, 0, }; void EnDyExtra_Draw(Actor* thisx, PlayState* play) { - EnDyExtra* this = THIS; s32 pad; + EnDyExtra* this = THIS; GraphicsContext* gfxCtx = play->state.gfxCtx; - Vtx* vertices = Lib_SegmentedToVirtual(object_dy_obj_Vtx_00DD40); + Vtx* vertices = Lib_SegmentedToVirtual(gGreatFairySpiralBeamVtx); s32 i; - u8 unk[3]; + u8 alphas[3]; - unk[0] = 0.0f; - unk[1] = (s8)(this->unk150 * 240.0f); - unk[2] = (s8)(this->unk150 * 255.0f); + alphas[0] = 0.0f; + alphas[1] = (s32)(this->alphaScale * 240.0f); + alphas[2] = (s32)(this->alphaScale * 255.0f); - for (i = 0; i < 27; i++) { - if (D_80A61768[i]) { - vertices[i].v.cn[3] = unk[D_80A61768[i]]; + for (i = 0; i < ARRAY_COUNT(sAlphaTypeIndices); i++) { + if (sAlphaTypeIndices[i]) { + vertices[i].v.cn[3] = alphas[sAlphaTypeIndices[i]]; } } @@ -124,10 +124,10 @@ void EnDyExtra_Draw(Actor* thisx, PlayState* play) { play->state.frames * -8, 0x10, 0x10)); gDPPipeSync(POLY_XLU_DISP++); gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, D_80A61740[this->type].r, D_80A61740[this->type].g, - D_80A61740[this->type].b, 255); - gDPSetEnvColor(POLY_XLU_DISP++, D_80A61754[this->type].r, D_80A61754[this->type].g, D_80A61754[this->type].b, 128); - gSPDisplayList(POLY_XLU_DISP++, object_dy_obj_DL_00DEF0); + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, sPrimColors[this->type].r, sPrimColors[this->type].g, + sPrimColors[this->type].b, 255); + gDPSetEnvColor(POLY_XLU_DISP++, sEnvColors[this->type].r, sEnvColors[this->type].g, sEnvColors[this->type].b, 128); + gSPDisplayList(POLY_XLU_DISP++, gGreatFairySpiralBeamDL); CLOSE_DISPS(gfxCtx); } diff --git a/src/overlays/actors/ovl_En_Dy_Extra/z_en_dy_extra.h b/src/overlays/actors/ovl_En_Dy_Extra/z_en_dy_extra.h index 0e5d8614b7..f36b12051e 100644 --- a/src/overlays/actors/ovl_En_Dy_Extra/z_en_dy_extra.h +++ b/src/overlays/actors/ovl_En_Dy_Extra/z_en_dy_extra.h @@ -11,12 +11,11 @@ typedef struct EnDyExtra { /* 0x000 */ Actor actor; /* 0x144 */ EnDyExtraActionFunc actionFunc; /* 0x148 */ s16 type; - /* 0x14A */ s16 unk14A; - /* 0x14C */ s16 unk14C; - /* 0x14E */ s16 unk14E; - /* 0x150 */ f32 unk150; - /* 0x154 */ UNK_TYPE1 unk154[0xC]; - /* 0x160 */ Vec3f unk160; + /* 0x14A */ s16 trigger; + /* 0x14C */ s16 timer; + /* 0x150 */ f32 alphaScale; + /* 0x154 */ Vec3f scale; // not used, leftover from OoT + /* 0x160 */ Vec3f initPos; // set and not used } EnDyExtra; // size = 0x16C #endif // Z_EN_DY_EXTRA_H diff --git a/src/overlays/actors/ovl_En_Elf/z_en_elf.c b/src/overlays/actors/ovl_En_Elf/z_en_elf.c index 61cf693d7d..f1526d66b8 100644 --- a/src/overlays/actors/ovl_En_Elf/z_en_elf.c +++ b/src/overlays/actors/ovl_En_Elf/z_en_elf.c @@ -744,7 +744,7 @@ void func_8088E0F0(EnElf* this, PlayState* play) { if (this->unk_250 < 2.0f) { this->unk_250 += 0.1f; } else { - gSaveContext.healthAccumulator = 160; + gSaveContext.healthAccumulator = 0xA0; this->unk_246++; } break; diff --git a/src/overlays/actors/ovl_En_Elfbub/z_en_elfbub.c b/src/overlays/actors/ovl_En_Elfbub/z_en_elfbub.c index ef53999de0..9b34bf410e 100644 --- a/src/overlays/actors/ovl_En_Elfbub/z_en_elfbub.c +++ b/src/overlays/actors/ovl_En_Elfbub/z_en_elfbub.c @@ -73,10 +73,11 @@ void EnElfbub_Init(Actor* thisx, PlayState* play) { Collider_InitAndSetCylinder(play, &this->collider, &this->actor, &sCylinderInit); this->actor.colChkInfo.mass = MASS_IMMOVABLE; - childActor = Actor_SpawnAsChild( - &play->actorCtx, &this->actor, play, ACTOR_EN_ELFORG, this->actor.world.pos.x, this->actor.world.pos.y + 12.0f, - this->actor.world.pos.z, this->actor.world.rot.x, this->actor.world.rot.y, this->actor.world.rot.z, - STRAY_FAIRY_PARAMS(ENELFBUB_GET_SWITCHFLAG(&this->actor), 0, STRAY_FAIRY_TYPE_BUBBLE)); + childActor = Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_EN_ELFORG, this->actor.world.pos.x, + this->actor.world.pos.y + 12.0f, this->actor.world.pos.z, this->actor.world.rot.x, + this->actor.world.rot.y, this->actor.world.rot.z, + STRAY_FAIRY_PARAMS(ENELFBUB_GET_SWITCHFLAG(&this->actor), + STRAY_FAIRY_AREA_CLOCK_TOWN, STRAY_FAIRY_TYPE_BUBBLE)); if (childActor != NULL) { childActor->parent = &this->actor; } @@ -140,6 +141,7 @@ void EnElfbub_Idle(EnElfbub* this, PlayState* play) { void EnElfbub_Update(Actor* thisx, PlayState* play) { EnElfbub* this = THIS; + Collider_UpdateCylinder(&this->actor, &this->collider); this->actionFunc(this, play); Actor_SetFocus(&this->actor, this->actor.shape.yOffset); diff --git a/src/overlays/actors/ovl_En_Elfgrp/z_en_elfgrp.c b/src/overlays/actors/ovl_En_Elfgrp/z_en_elfgrp.c index 42ac47f699..937c6bc8ca 100644 --- a/src/overlays/actors/ovl_En_Elfgrp/z_en_elfgrp.c +++ b/src/overlays/actors/ovl_En_Elfgrp/z_en_elfgrp.c @@ -1,11 +1,38 @@ -/* - * File: z_en_elfgrp.c +/** + * @file z_en_elfgrp.c * Overlay: ovl_En_Elfgrp - * Description: Group of Stray Fairies in Fairy Fountain + * Description: Manager for group of Stray Fairies and Great Fairy in Fairy's Fountains + * + * There are many different quantities associated to the Stray Fairies in each of the 3 places (missing, in the + * Fountain, held by Player) + * - Total number of fairies (always 25 in the original game) + * - Original number in the Fountain (24 for Clock Town Fairy Fountain, 10 for the other 4) + * - Current number in the Fountain (bitpacked in Fountain scene flags, see below) + * - Total number found (stored in save context) + * - Current number held (i.e. found but not returned) + * + * The permanentSceneFlags for Fairy Fountains used in this actor are of the form + * ```c + * struct { + * u32 clockTown : 1; + * u32 fountains[4] : 5; + * } FairyFountains; + * ``` + * where arg1 is: + * - 0: Clock Town + * - 1: Woodfall, + * - 2: Snowhead, + * - 3: Great Bay, + * - 4: Ikana + * + * Clock Town is handled separately, and then the fountains are looked up with manual array indexing + * + * @note Clock Town is handled separately in a number of places */ #include "z_en_elfgrp.h" #include "overlays/actors/ovl_En_Elforg/z_en_elforg.h" +#include "overlays/actors/ovl_Demo_Effect/z_demo_effect.h" #define FLAGS (ACTOR_FLAG_10) @@ -17,24 +44,28 @@ void EnElfgrp_Init(Actor* thisx, PlayState* play); void EnElfgrp_Destroy(Actor* thisx, PlayState* play); void EnElfgrp_Update(Actor* thisx, PlayState* play); -s32 func_80A39BD0(PlayState* play, s32 arg2); -s32 func_80A39C1C(PlayState* play, s32 arg1); -void func_80A39DC8(EnElfgrp* this, PlayState* play, s32 arg2, s32 arg3); -void func_80A3A0AC(EnElfgrp* this, PlayState* play); -void func_80A3A0F4(EnElfgrp* this, PlayState* play); -void func_80A3A210(EnElfgrp* this, PlayState* play); -void func_80A3A274(EnElfgrp* this, PlayState* play); +s32 EnElfgrp_GetHeldFairiesCount(PlayState* play, s32 type); +s32 EnElfgrp_GetFountainFairiesCount(PlayState* play, s32 type); +void EnElfgrp_SpawnStrayFairies(EnElfgrp* this, PlayState* play, s32 count, s32 fairyType); void func_80A3A398(EnElfgrp* this, PlayState* play); -void func_80A3A484(EnElfgrp* this, PlayState* play); -void func_80A3A4AC(EnElfgrp* this, PlayState* play); void func_80A3A520(EnElfgrp* this, PlayState* play); -void func_80A3A600(EnElfgrp* this, PlayState* play); -void func_80A3A610(EnElfgrp* this, PlayState* play); -void func_80A3A6F4(EnElfgrp* this, PlayState* play); -void func_80A3A77C(EnElfgrp* this, PlayState* play); +void EnElfgrp_DoNothing(EnElfgrp* this, PlayState* play); void func_80A3A7FC(EnElfgrp* this, PlayState* play); void func_80A3A8F8(EnElfgrp* this, PlayState* play); +// State flags +#define ELFGRP_STATE_0 (1 << 0) +#define ELFGRP_STATE_1 (1 << 1) +#define ELFGRP_STATE_2 (1 << 2) +#define ELFGRP_STATE_3 (1 << 3) +#define ELFGRP_STATE_4 (1 << 4) + +// Used for the type in EnElfgrp_SpawnStrayFairies +typedef enum ElfgrpSpawnedFairyTypes { + /* 0 */ SPAWNED_STRAY_FAIRY_TYPE_PRESENT, // STRAY_FAIRY_TYPE_FAIRY_FOUNTAIN + /* 1 */ SPAWNED_STRAY_FAIRY_TYPE_RETURNING // STRAY_FAIRY_TYPE_RETURNING_TO_FOUNTAIN +} ElfgrpSpawnedFairyTypes; + ActorInit En_Elfgrp_InitVars = { ACTOR_EN_ELFGRP, ACTORCAT_PROP, @@ -47,7 +78,15 @@ ActorInit En_Elfgrp_InitVars = { (ActorFunc)NULL, }; -void func_80A396B0(EnElfgrp* this, s32 numCutscenes) { +/** + * Set the actor's cutscene id to a later one, or -1 if run out. + * + * @note This is only expected to be called in Init when this actor has the first cutscene set, but can also work for + * later cutscenes if \p numCutscenes is set correcly. + * + * @param numCutscenes Number of cutscenes in the list to skip forward to set this one. + */ +void EnElfgrp_SetCutscene(EnElfgrp* this, s32 numCutscenes) { while (numCutscenes > 0) { if (this->actor.csId == CS_ID_NONE) { break; @@ -61,113 +100,118 @@ void func_80A396B0(EnElfgrp* this, s32 numCutscenes) { void EnElfgrp_Init(Actor* thisx, PlayState* play) { s32 pad; EnElfgrp* this = THIS; - s32 sp24; + s32 numberInFountain; - this->unk_147 = ENELFGRP_GET(&this->actor); + this->type = ENELFGRP_GET_TYPE(&this->actor); this->unk_148 = 0; - this->unk_14A = 0; + this->stateFlags = 0; this->actor.focus.pos.y += 40.0f; this->actor.flags &= ~ACTOR_FLAG_TARGETABLE; - switch (this->unk_147) { - case ENELFGRP_1: - case ENELFGRP_2: - case ENELFGRP_3: - case ENELFGRP_4: - this->unk_148 = this->unk_147 - 1; - sp24 = func_80A39C1C(play, this->unk_147); - this->unk_146 = 1 << this->unk_147; + switch (this->type) { + case ENELFGRP_TYPE_POWER: + case ENELFGRP_TYPE_WISDOM: + case ENELFGRP_TYPE_COURAGE: + case ENELFGRP_TYPE_KINDNESS: + this->unk_148 = this->type - 1; + numberInFountain = EnElfgrp_GetFountainFairiesCount(play, this->type); + this->talkedOnceFlag = 1 << this->type; - if (sp24 < 25) { - func_80A39DC8(this, play, sp24, 0); + if (numberInFountain < STRAY_FAIRY_TOTAL) { + EnElfgrp_SpawnStrayFairies(this, play, numberInFountain, SPAWNED_STRAY_FAIRY_TYPE_PRESENT); } - if (sp24 >= 25) { + if (numberInFountain >= STRAY_FAIRY_TOTAL) { this->actionFunc = func_80A3A520; - func_80A396B0(this, 2); - return; + EnElfgrp_SetCutscene(this, 2); + break; } - if ((func_80A39BD0(play, this->unk_147) + sp24) >= 25) { + if ((EnElfgrp_GetHeldFairiesCount(play, this->type) + numberInFountain) >= STRAY_FAIRY_TOTAL) { this->actionFunc = func_80A3A398; - switch (this->unk_147) { - case ENELFGRP_1: - if (CHECK_WEEKEVENTREG(WEEKEVENTREG_23_02)) { - func_80A396B0(this, 1); + switch (this->type) { + case ENELFGRP_TYPE_POWER: + if (CHECK_WEEKEVENTREG(WEEKEVENTREG_OBTAINED_GREAT_SPIN_ATTACK)) { + EnElfgrp_SetCutscene(this, 1); } else { - this->unk_14A |= 4; + this->stateFlags |= ELFGRP_STATE_2; } break; - case ENELFGRP_2: + case ENELFGRP_TYPE_WISDOM: if (gSaveContext.save.saveInfo.playerData.isDoubleMagicAcquired == true) { - func_80A396B0(this, 1); + EnElfgrp_SetCutscene(this, 1); } break; - case ENELFGRP_3: + case ENELFGRP_TYPE_COURAGE: if (gSaveContext.save.saveInfo.playerData.doubleDefense) { - func_80A396B0(this, 1); + EnElfgrp_SetCutscene(this, 1); } break; - case ENELFGRP_4: + case ENELFGRP_TYPE_KINDNESS: if (INV_CONTENT(ITEM_SWORD_GREAT_FAIRY) == ITEM_SWORD_GREAT_FAIRY) { - func_80A396B0(this, 1); + EnElfgrp_SetCutscene(this, 1); } else { - this->unk_14A |= 0x10; + this->stateFlags |= ELFGRP_STATE_4; } break; default: break; } - } else if (func_80A39BD0(play, this->unk_147)) { + } else if (EnElfgrp_GetHeldFairiesCount(play, this->type)) { this->actionFunc = func_80A3A7FC; - this->actor.textId = (this->unk_147 * 3) + 0x581; + this->actor.textId = (this->type * 3) + 0x581; } else { this->actionFunc = func_80A3A8F8; - if ((gSaveContext.save.saveInfo.weekEventReg[9] & this->unk_146)) { - this->actor.textId = (this->unk_147 * 3) + 0x580; + + if ((gSaveContext.save.saveInfo.weekEventReg[9] & this->talkedOnceFlag)) { // talked for first time + this->actor.textId = (this->type * 3) + 0x580; } else { - this->actor.textId = (this->unk_147 * 3) + 0x57F; + this->actor.textId = (this->type * 3) + 0x57F; } } break; - default: - sp24 = func_80A39C1C(play, 0); - this->unk_146 = ENELFGRP_1; - if (sp24 >= 25) { + default: // ENELFGRP_TYPE_MAGIC + numberInFountain = EnElfgrp_GetFountainFairiesCount(play, ENELFGRP_TYPE_MAGIC); + this->talkedOnceFlag = 1 << ENELFGRP_TYPE_MAGIC; + + if (numberInFountain >= STRAY_FAIRY_TOTAL) { this->actionFunc = func_80A3A520; - if ((this->actor.home.rot.z != 0) && Flags_GetSwitch(play, this->actor.home.rot.z)) { - this->actionFunc = func_80A3A600; + + if ((ENELFGRP_GET_SWITCHFLAG_ROT(&this->actor) != 0) && + Flags_GetSwitch(play, ENELFGRP_GET_SWITCHFLAG_ROT(&this->actor))) { + this->actionFunc = EnElfgrp_DoNothing; } else if (INV_CONTENT(ITEM_MASK_GREAT_FAIRY) == ITEM_MASK_GREAT_FAIRY) { - func_80A396B0(this, 4); + EnElfgrp_SetCutscene(this, 4); } else if (INV_CONTENT(ITEM_MASK_DEKU) != ITEM_MASK_DEKU) { - func_80A396B0(this, 5); + EnElfgrp_SetCutscene(this, 5); } else { - this->unk_14A |= 2; - func_80A396B0(this, 6); + this->stateFlags |= ELFGRP_STATE_1; + EnElfgrp_SetCutscene(this, 6); } } else if (CHECK_WEEKEVENTREG(WEEKEVENTREG_08_80)) { - func_80A39DC8(this, play, 24, 0); + EnElfgrp_SpawnStrayFairies(this, play, STRAY_FAIRY_TOTAL - 1, SPAWNED_STRAY_FAIRY_TYPE_PRESENT); this->actionFunc = func_80A3A398; + if (INV_CONTENT(ITEM_MASK_DEKU) == ITEM_MASK_DEKU) { if (INV_CONTENT(ITEM_MASK_GREAT_FAIRY) == ITEM_MASK_GREAT_FAIRY) { - func_80A396B0(this, 2); + EnElfgrp_SetCutscene(this, 2); } else { - func_80A396B0(this, 3); - this->unk_14A |= 2; + EnElfgrp_SetCutscene(this, 3); + this->stateFlags |= ELFGRP_STATE_1; } } else if (gSaveContext.save.saveInfo.playerData.isMagicAcquired == true) { - func_80A396B0(this, 1); + EnElfgrp_SetCutscene(this, 1); } } else { - func_80A39DC8(this, play, 24, 0); + EnElfgrp_SpawnStrayFairies(this, play, STRAY_FAIRY_TOTAL - 1, SPAWNED_STRAY_FAIRY_TYPE_PRESENT); this->actionFunc = func_80A3A8F8; - if ((gSaveContext.save.saveInfo.weekEventReg[9] & this->unk_146)) { + if ((gSaveContext.save.saveInfo.weekEventReg[9] & this->talkedOnceFlag)) { this->actor.textId = 0x580; } else { this->actor.textId = 0x578; @@ -181,116 +225,119 @@ void EnElfgrp_Init(Actor* thisx, PlayState* play) { void EnElfgrp_Destroy(Actor* thisx, PlayState* play) { } -s32 func_80A39BD0(PlayState* play, s32 arg2) { - if ((arg2 < 1) || (arg2 >= 5)) { +// Number of Stray Fairies currently held by Player +s32 EnElfgrp_GetHeldFairiesCount(PlayState* play, s32 type) { + if ((type <= ENELFGRP_TYPE_MAGIC) || (type > ENELFGRP_TYPE_KINDNESS)) { return 0; } - return (((void)0, gSaveContext.save.saveInfo.inventory.strayFairies[arg2 - 1]) - func_80A39C1C(play, arg2)) + 10; + // Number in fountain originally + total number collected - number currently in fountain + return (STRAY_FAIRY_TOTAL - STRAY_FAIRY_SCATTERED_TOTAL) + + ((void)0, gSaveContext.save.saveInfo.inventory.strayFairies[type - 1]) - + EnElfgrp_GetFountainFairiesCount(play, type); } -s32 func_80A39C1C(PlayState* play, s32 arg1) { - // the permanentSceneFlags access here is in the form - // struct { - // u32 clockTown : 1; - // u32 fountains[4] : 5; - // } FairyFountains; - // where arg1 is: - // 0: clocktown - // 1: woodfall, - // 2: snowhead, - // 3: great bay, - // 4: stone tower - // clocktown is handled separately, and then the fountains are looked up as array indexing +// Number of Stray Fairies in currently in Fountain +s32 EnElfgrp_GetFountainFairiesCount(PlayState* play, s32 type) { + s32 numberInFountain; - s32 temp_v1; - - if ((arg1 < 0) || (arg1 >= 5)) { + if ((type < ENELFGRP_TYPE_MAGIC) || (type > ENELFGRP_TYPE_KINDNESS)) { return 0; } - if (arg1 == 0) { + if (type == ENELFGRP_TYPE_MAGIC) { if (gSaveContext.save.saveInfo.permanentSceneFlags[play->sceneId].unk_14 & 1) { - return 25; + return STRAY_FAIRY_TOTAL; + } else { + return STRAY_FAIRY_TOTAL - 1; } - return 24; } - temp_v1 = (gSaveContext.save.saveInfo.permanentSceneFlags[play->sceneId].unk_14 >> (((arg1 - 1) * 5) + 1)) & 0x1F; - if (temp_v1 < 10) { - temp_v1 = 10; - } else if (temp_v1 > 25) { - temp_v1 = 25; + numberInFountain = + (gSaveContext.save.saveInfo.permanentSceneFlags[play->sceneId].unk_14 >> (((type - 1) * 5) + 1)) & 0x1F; + if (numberInFountain < STRAY_FAIRY_TOTAL - STRAY_FAIRY_SCATTERED_TOTAL) { + numberInFountain = STRAY_FAIRY_TOTAL - STRAY_FAIRY_SCATTERED_TOTAL; + } else if (numberInFountain > STRAY_FAIRY_TOTAL) { + numberInFountain = STRAY_FAIRY_TOTAL; } - return temp_v1; + return numberInFountain; } -void func_80A39CD4(PlayState* play, s32 arg1, s32 arg2) { - if ((arg1 < 0) || (arg1 > 4) || (arg2 < 10) || (arg2 > 25)) { +// Update number of Stray Fairies in Fountain +void EnElfgrp_SetFountainFairiesCount(PlayState* play, s32 type, s32 newCount) { + if ((type < ENELFGRP_TYPE_MAGIC) || (type > ENELFGRP_TYPE_KINDNESS) || + (newCount < (STRAY_FAIRY_TOTAL - STRAY_FAIRY_SCATTERED_TOTAL)) || (newCount > STRAY_FAIRY_TOTAL)) { return; } - if (arg1 == 0) { - if (arg2 == 25) { + if (type == ENELFGRP_TYPE_MAGIC) { + if (newCount == STRAY_FAIRY_TOTAL) { gSaveContext.save.saveInfo.permanentSceneFlags[play->sceneId].unk_14 |= 1; } else { gSaveContext.save.saveInfo.permanentSceneFlags[play->sceneId].unk_14 &= ~1; } } else { - gSaveContext.save.saveInfo.permanentSceneFlags[play->sceneId].unk_14 &= ~(0x1F << ((arg1 * 5) - 4)); - gSaveContext.save.saveInfo.permanentSceneFlags[play->sceneId].unk_14 |= arg2 << ((arg1 * 5) - 4); + gSaveContext.save.saveInfo.permanentSceneFlags[play->sceneId].unk_14 &= ~(0x1F << ((type * 5) - 4)); + gSaveContext.save.saveInfo.permanentSceneFlags[play->sceneId].unk_14 |= newCount << ((type * 5) - 4); } } -void func_80A39DC8(EnElfgrp* this, PlayState* play, s32 arg2, s32 arg3) { +void EnElfgrp_SpawnStrayFairies(EnElfgrp* this, PlayState* play, s32 count, s32 fairyType) { s32 pad; s32 i; - Actor* elforg; - s32 params; - Vec3f sp6C; + Actor* strayFairy; + s32 strayFairyParams; + Vec3f spawnCenterPos; Player* player = GET_PLAYER(play); - if (arg3 == 0) { - this->unk_14A |= 8; + if (fairyType == 0) { + this->stateFlags |= ELFGRP_STATE_3; } - if (arg3 == 0) { - sp6C = this->actor.world.pos; - sp6C.y += 20.0f; - params = STRAY_FAIRY_PARAMS(0, this->unk_147, STRAY_FAIRY_TYPE_FAIRY_FOUNTAIN); + if (fairyType == 0) { + spawnCenterPos = this->actor.world.pos; + spawnCenterPos.y += 20.0f; + strayFairyParams = STRAY_FAIRY_PARAMS(0, this->type, STRAY_FAIRY_TYPE_FAIRY_FOUNTAIN); } else { - sp6C = player->actor.world.pos; - sp6C.y += 20.0f; - params = STRAY_FAIRY_PARAMS(0, this->unk_147, STRAY_FAIRY_TYPE_TURN_IN_TO_FAIRY_FOUNTAIN); + spawnCenterPos = player->actor.world.pos; + spawnCenterPos.y += 20.0f; + strayFairyParams = STRAY_FAIRY_PARAMS(0, this->type, STRAY_FAIRY_TYPE_RETURNING_TO_FOUNTAIN); } - for (i = 0; i < arg2; i++) { - elforg = Actor_Spawn(&play->actorCtx, play, ACTOR_EN_ELFORG, Rand_CenteredFloat(20.0f) + sp6C.x, sp6C.y, - Rand_CenteredFloat(20.0f) + sp6C.z, 0, 0, 0, params); - if (elforg == NULL) { + for (i = 0; i < count; i++) { + strayFairy = + Actor_Spawn(&play->actorCtx, play, ACTOR_EN_ELFORG, Rand_CenteredFloat(20.0f) + spawnCenterPos.x, + spawnCenterPos.y, Rand_CenteredFloat(20.0f) + spawnCenterPos.z, 0, 0, 0, strayFairyParams); + + if (strayFairy == NULL) { continue; } - elforg->home.pos.x = this->actor.home.pos.x; - elforg->home.pos.y = this->actor.home.pos.y + 20.0f; - elforg->home.pos.z = this->actor.home.pos.z; + strayFairy->home.pos.x = this->actor.home.pos.x; + strayFairy->home.pos.y = this->actor.home.pos.y + 20.0f; + strayFairy->home.pos.z = this->actor.home.pos.z; } } -s32 func_80A39F50(PlayState* play) { +/** + * Tell any spawned Stray Fairies to come to the Fountain center. + * + * @return s32 always 0 + */ +s32 EnElfgrp_SummonStrayFairies(PlayState* play) { Actor* itemAction = play->actorCtx.actorLists[ACTORCAT_ITEMACTION].first; - EnElforg* elfOrg; + EnElforg* strayFairy; while (itemAction != NULL) { if ((itemAction->id != ACTOR_EN_ELFORG) || ((STRAY_FAIRY_TYPE(itemAction) != STRAY_FAIRY_TYPE_FAIRY_FOUNTAIN) && - (STRAY_FAIRY_TYPE(itemAction) != STRAY_FAIRY_TYPE_TURN_IN_TO_FAIRY_FOUNTAIN))) { + (STRAY_FAIRY_TYPE(itemAction) != STRAY_FAIRY_TYPE_RETURNING_TO_FOUNTAIN))) { itemAction = itemAction->next; continue; } - elfOrg = (EnElforg*)itemAction; - if (!(elfOrg->strayFairyFlags & STRAY_FAIRY_FLAG_MOVES_QUICKLY_TO_HOME)) { - elfOrg->strayFairyFlags |= STRAY_FAIRY_FLAG_MOVES_QUICKLY_TO_HOME; + strayFairy = (EnElforg*)itemAction; + if (!(strayFairy->strayFairyFlags & STRAY_FAIRY_FLAG_MOVES_QUICKLY_TO_HOME)) { + strayFairy->strayFairyFlags |= STRAY_FAIRY_FLAG_MOVES_QUICKLY_TO_HOME; } itemAction = itemAction->next; } @@ -298,50 +345,58 @@ s32 func_80A39F50(PlayState* play) { return 0; } -s32 func_80A39FBC(PlayState* play) { +/** + * Make the Stray Fairies in the fountain spin quickly when healing Player. + * + * @return s32 time to spend in healing action. + */ +s32 EnElfgrp_SpinStrayFairies(PlayState* play) { Actor* itemAction = play->actorCtx.actorLists[ACTORCAT_ITEMACTION].first; - EnElforg* elfOrg; - s32 phi_v1 = 30; + EnElforg* strayFairy; + s32 timer = 30; while (itemAction != NULL) { if ((itemAction->id != ACTOR_EN_ELFORG) || ((STRAY_FAIRY_TYPE(itemAction) != STRAY_FAIRY_TYPE_FAIRY_FOUNTAIN) && - (STRAY_FAIRY_TYPE(itemAction) != STRAY_FAIRY_TYPE_TURN_IN_TO_FAIRY_FOUNTAIN))) { + (STRAY_FAIRY_TYPE(itemAction) != STRAY_FAIRY_TYPE_RETURNING_TO_FOUNTAIN))) { itemAction = itemAction->next; continue; } - elfOrg = (EnElforg*)itemAction; - if (!(elfOrg->strayFairyFlags & STRAY_FAIRY_FLAG_CIRCLES_QUICKLY_IN_FOUNTAIN)) { - elfOrg->strayFairyFlags |= STRAY_FAIRY_FLAG_CIRCLES_QUICKLY_IN_FOUNTAIN; - if (phi_v1 >= 100) { - return phi_v1; + strayFairy = (EnElforg*)itemAction; + if (!(strayFairy->strayFairyFlags & STRAY_FAIRY_FLAG_CIRCLES_QUICKLY_IN_FOUNTAIN)) { + strayFairy->strayFairyFlags |= STRAY_FAIRY_FLAG_CIRCLES_QUICKLY_IN_FOUNTAIN; + if (timer >= 100) { + return timer; } - elfOrg->secondaryTimer = phi_v1; - phi_v1 += 5; + strayFairy->secondaryTimer = timer; + timer += 5; } itemAction = itemAction->next; } - return phi_v1; + return timer; } -void func_80A3A044(PlayState* play) { +/** + * Tell the Stray Fairies to disappear, before reviving the Great Fairy + */ +void EnElfgrp_VanishStrayFairies(PlayState* play) { Actor* itemAction = play->actorCtx.actorLists[ACTORCAT_ITEMACTION].first; - EnElforg* elfOrg; + EnElforg* strayFairy; while (itemAction != NULL) { if ((itemAction->id != ACTOR_EN_ELFORG) || ((STRAY_FAIRY_TYPE(itemAction) != STRAY_FAIRY_TYPE_FAIRY_FOUNTAIN) && - (STRAY_FAIRY_TYPE(itemAction) != STRAY_FAIRY_TYPE_TURN_IN_TO_FAIRY_FOUNTAIN))) { + (STRAY_FAIRY_TYPE(itemAction) != STRAY_FAIRY_TYPE_RETURNING_TO_FOUNTAIN))) { itemAction = itemAction->next; continue; } - elfOrg = (EnElforg*)itemAction; - elfOrg->actor.home.rot.x = 0x14; - elfOrg->strayFairyFlags |= STRAY_FAIRY_FLAG_SPARKLES_AND_SHRINKS; + strayFairy = (EnElforg*)itemAction; + STRAY_FAIRY_SPARKLE_COUNT(&strayFairy->actor) = 20; + strayFairy->strayFairyFlags |= STRAY_FAIRY_FLAG_SPARKLES_AND_SHRINKS; itemAction = itemAction->next; } @@ -349,68 +404,70 @@ void func_80A3A044(PlayState* play) { void func_80A3A0AC(EnElfgrp* this, PlayState* play) { if (!Cutscene_IsCueInChannel(play, CS_CMD_ACTOR_CUE_100)) { - this->actionFunc = func_80A3A600; + this->actionFunc = EnElfgrp_DoNothing; CutsceneManager_Stop(this->actor.csId); } } void func_80A3A0F4(EnElfgrp* this, PlayState* play) { - if (this->unk_144 == 10) { + if (this->timer == 10) { Audio_PlaySfx(NA_SE_SY_WHITE_OUT_T); - if (ENELFGRP_GET(&this->actor) < ENELFGRP_4) { + if (ENELFGRP_GET_TYPE(&this->actor) < ENELFGRP_TYPE_KINDNESS) { Actor_Spawn(&play->actorCtx, play, ACTOR_DEMO_EFFECT, this->actor.world.pos.x, this->actor.world.pos.y + 30.0f, this->actor.world.pos.z, 0, 0, 0, - ENELFGRP_GET(&this->actor) + ENELFGRP_4); - } else { + ENELFGRP_GET_TYPE(&this->actor) + DEMO_EFFECT_TYPE_LIGHT_BASE); + } else { // ENELFGRP_TYPE_KINDNESS Actor_Spawn(&play->actorCtx, play, ACTOR_DEMO_EFFECT, this->actor.world.pos.x, - this->actor.world.pos.y + 30.0f, this->actor.world.pos.z, 0, 0, 0, 4); + this->actor.world.pos.y + 30.0f, this->actor.world.pos.z, 0, 0, 0, + DEMO_EFFECT_TYPE_LIGHT_DARK_YELLOW); } } - if ((this->unk_144 > 10) && (this->unk_14A & 1)) { + if ((this->timer > 10) && (this->stateFlags & ELFGRP_STATE_0)) { Actor_PlaySfx_Flagged(&this->actor, NA_SE_EV_FAIRY_GROUP_FRY - SFX_FLAG); } - if (this->unk_144 == 0) { + if (this->timer == 0) { this->actionFunc = func_80A3A0AC; } } void func_80A3A210(EnElfgrp* this, PlayState* play) { - if (this->unk_144 == 0) { + if (this->timer == 0) { this->actionFunc = func_80A3A0F4; - func_80A3A044(play); - this->unk_144 = 30; + EnElfgrp_VanishStrayFairies(play); + this->timer = 30; } - if (this->unk_14A & 1) { + if (this->stateFlags & ELFGRP_STATE_0) { Actor_PlaySfx_Flagged(&this->actor, NA_SE_EV_FAIRY_GROUP_FRY - SFX_FLAG); } } void func_80A3A274(EnElfgrp* this, PlayState* play) { if (Cutscene_IsCueInChannel(play, CS_CMD_ACTOR_CUE_100)) { - if (this->unk_14A & 1) { + if (this->stateFlags & ELFGRP_STATE_0) { Actor_PlaySfx_Flagged(&this->actor, NA_SE_PL_CHIBI_FAIRY_HEAL - SFX_FLAG); } switch (play->csCtx.actorCues[Cutscene_GetCueChannel(play, CS_CMD_ACTOR_CUE_100)]->id) { case 2: - if (!(this->unk_14A & 1)) { - if (this->unk_147 == ENELFGRP_0) { - func_80A39DC8(this, play, 1, 1); + if (!(this->stateFlags & ELFGRP_STATE_0)) { + if (this->type == ENELFGRP_TYPE_MAGIC) { // Clock Town + EnElfgrp_SpawnStrayFairies(this, play, 1, SPAWNED_STRAY_FAIRY_TYPE_RETURNING); } else { - func_80A39DC8(this, play, func_80A39BD0(play, this->unk_147), 1); + EnElfgrp_SpawnStrayFairies(this, play, EnElfgrp_GetHeldFairiesCount(play, this->type), + SPAWNED_STRAY_FAIRY_TYPE_RETURNING); } - this->unk_14A |= 1; - func_80A39CD4(play, this->unk_147, 25); + this->stateFlags |= ELFGRP_STATE_0; + EnElfgrp_SetFountainFairiesCount(play, this->type, STRAY_FAIRY_TOTAL); } break; case 3: - func_80A39F50(play); + EnElfgrp_SummonStrayFairies(play); this->actionFunc = func_80A3A210; - this->unk_144 = 90; + this->timer = 90; break; default: @@ -423,28 +480,30 @@ void func_80A3A398(EnElfgrp* this, PlayState* play) { if (CutsceneManager_IsNext(this->actor.csId)) { CutsceneManager_StartWithPlayerCs(this->actor.csId, &this->actor); this->actionFunc = func_80A3A274; - Flags_UnsetSwitch(play, ENELFGRP_GET_FE00(&this->actor)); - if (this->unk_14A & 2) { + Flags_UnsetSwitch(play, ENELFGRP_GET_SWITCHFLAG_PARAMS(&this->actor)); + + if (this->stateFlags & ELFGRP_STATE_1) { Item_Give(play, ITEM_MASK_GREAT_FAIRY); } - if ((this->unk_14A & 4) != 0) { - SET_WEEKEVENTREG(WEEKEVENTREG_23_02); + if (this->stateFlags & ELFGRP_STATE_2) { + SET_WEEKEVENTREG(WEEKEVENTREG_OBTAINED_GREAT_SPIN_ATTACK); } - if (this->unk_14A & 0x10) { + if (this->stateFlags & ELFGRP_STATE_4) { Item_Give(play, ITEM_SWORD_GREAT_FAIRY); } - this->unk_14A &= ~8; + + this->stateFlags &= ~ELFGRP_STATE_3; } else if (this->actor.xzDistToPlayer < 350.0f) { CutsceneManager_Queue(this->actor.csId); } } void func_80A3A484(EnElfgrp* this, PlayState* play) { - if (this->unk_144 == 0) { + if (this->timer == 0) { this->actionFunc = func_80A3A0F4; - this->unk_144 = 30; + this->timer = 30; } } @@ -454,51 +513,51 @@ void func_80A3A4AC(EnElfgrp* this, PlayState* play) { if (cueId == 3) { this->actionFunc = func_80A3A484; - this->unk_144 = 90; + this->timer = 90; } } } void func_80A3A520(EnElfgrp* this, PlayState* play) { if (Cutscene_IsCueInChannel(play, CS_CMD_ACTOR_CUE_103)) { - this->actionFunc = func_80A3A600; + this->actionFunc = EnElfgrp_DoNothing; } else if (CutsceneManager_IsNext(this->actor.csId)) { CutsceneManager_StartWithPlayerCs(this->actor.csId, &this->actor); this->actionFunc = func_80A3A4AC; - Flags_SetSwitch(play, ENELFGRP_GET_FE00(&this->actor)); + Flags_SetSwitch(play, ENELFGRP_GET_SWITCHFLAG_PARAMS(&this->actor)); - if (this->unk_14A & 2) { + if (this->stateFlags & ELFGRP_STATE_1) { Item_Give(play, ITEM_MASK_GREAT_FAIRY); } - if (this->actor.home.rot.z != 0) { - Flags_SetSwitch(play, this->actor.home.rot.z); + if (ENELFGRP_GET_SWITCHFLAG_ROT(&this->actor) != 0) { + Flags_SetSwitch(play, ENELFGRP_GET_SWITCHFLAG_ROT(&this->actor)); } } else if (this->actor.xzDistToPlayer < 350.0f) { CutsceneManager_Queue(this->actor.csId); } } -void func_80A3A600(EnElfgrp* this, PlayState* play) { +void EnElfgrp_DoNothing(EnElfgrp* this, PlayState* play) { } -void func_80A3A610(EnElfgrp* this, PlayState* play) { +void EnElfgrp_HealPlayer(EnElfgrp* this, PlayState* play) { Player* player = GET_PLAYER(play); - if (this->unk_144 == 60) { + if (this->timer == 60) { Magic_Add(play, MAGIC_FILL_TO_CAPACITY); - gSaveContext.healthAccumulator = 320; + gSaveContext.healthAccumulator = 0x140; } - if (this->unk_144 > 0) { + if (this->timer > 0) { player->actor.freezeTimer = 100; player->stateFlags1 |= PLAYER_STATE1_20000000; Actor_PlaySfx(&this->actor, NA_SE_EV_FAIRY_GROUP_HEAL - SFX_FLAG); } else { player->actor.freezeTimer = 0; player->stateFlags1 &= ~PLAYER_STATE1_20000000; - this->actionFunc = func_80A3A600; - this->unk_14A |= 8; + this->actionFunc = EnElfgrp_DoNothing; + this->stateFlags |= ELFGRP_STATE_3; } } @@ -509,9 +568,9 @@ void func_80A3A6F4(EnElfgrp* this, PlayState* play) { if (Actor_TextboxIsClosing(&this->actor, play)) { player->actor.freezeTimer = 100; player->stateFlags1 |= PLAYER_STATE1_20000000; - this->unk_144 = func_80A39FBC(play); - this->actionFunc = func_80A3A610; - this->unk_14A &= ~8; + this->timer = EnElfgrp_SpinStrayFairies(play); + this->actionFunc = EnElfgrp_HealPlayer; + this->stateFlags &= ~ELFGRP_STATE_3; } } @@ -521,25 +580,27 @@ void func_80A3A77C(EnElfgrp* this, PlayState* play) { player->actor.freezeTimer = 100; player->stateFlags1 |= PLAYER_STATE1_20000000; if (Actor_TextboxIsClosing(&this->actor, play)) { - this->unk_144 = func_80A39FBC(play); - this->actionFunc = func_80A3A610; - this->unk_14A &= ~8; + this->timer = EnElfgrp_SpinStrayFairies(play); + this->actionFunc = EnElfgrp_HealPlayer; + this->stateFlags &= ~ELFGRP_STATE_3; } } void func_80A3A7FC(EnElfgrp* this, PlayState* play) { - s32 temp_s0; + s32 curTotalFairies; if (Actor_ProcessTalkRequest(&this->actor, &play->state)) { - gSaveContext.save.saveInfo.weekEventReg[9] |= this->unk_146; + gSaveContext.save.saveInfo.weekEventReg[9] |= this->talkedOnceFlag; this->actionFunc = func_80A3A6F4; - temp_s0 = func_80A39BD0(play, this->unk_147); - func_80A39DC8(this, play, temp_s0, 1); - temp_s0 += func_80A39C1C(play, this->unk_147); - if (temp_s0 > 25) { - temp_s0 = 25; + + curTotalFairies = EnElfgrp_GetHeldFairiesCount(play, this->type); + EnElfgrp_SpawnStrayFairies(this, play, curTotalFairies, SPAWNED_STRAY_FAIRY_TYPE_RETURNING); + curTotalFairies += EnElfgrp_GetFountainFairiesCount(play, this->type); + if (curTotalFairies > STRAY_FAIRY_TOTAL) { + curTotalFairies = STRAY_FAIRY_TOTAL; } - func_80A39CD4(play, this->unk_147, temp_s0); + + EnElfgrp_SetFountainFairiesCount(play, this->type, curTotalFairies); } else if (this->actor.xzDistToPlayer < 280.0f) { this->actor.flags |= ACTOR_FLAG_10000; Actor_OfferTalk(&this->actor, play, 300.0f); @@ -551,13 +612,13 @@ void func_80A3A8F8(EnElfgrp* this, PlayState* play) { Player* player = GET_PLAYER(play); if (Actor_ProcessTalkRequest(&this->actor, &play->state)) { - gSaveContext.save.saveInfo.weekEventReg[9] |= this->unk_146; + gSaveContext.save.saveInfo.weekEventReg[9] |= this->talkedOnceFlag; this->actionFunc = func_80A3A6F4; return; } - if (this->unk_147 != ENELFGRP_0) { - if (func_80A39BD0(play, this->unk_147) > 0) { + if (this->type != ENELFGRP_TYPE_MAGIC) { + if (EnElfgrp_GetHeldFairiesCount(play, this->type) > 0) { this->actionFunc = func_80A3A7FC; return; } @@ -570,7 +631,7 @@ void func_80A3A8F8(EnElfgrp* this, PlayState* play) { player->stateFlags1 |= PLAYER_STATE1_20000000; Message_StartTextbox(play, this->actor.textId, &this->actor); this->actionFunc = func_80A3A77C; - gSaveContext.save.saveInfo.weekEventReg[9] |= this->unk_146; + gSaveContext.save.saveInfo.weekEventReg[9] |= this->talkedOnceFlag; } else { this->actor.flags |= ACTOR_FLAG_10000; Actor_OfferTalk(&this->actor, play, 100.0f); @@ -585,11 +646,11 @@ void EnElfgrp_Update(Actor* thisx, PlayState* play) { this->actionFunc(this, play); - if (this->unk_14A & 8) { + if (this->stateFlags & ELFGRP_STATE_3) { Actor_PlaySfx(&this->actor, NA_SE_EV_FAIRY_GROUP_FRY - SFX_FLAG); } - if (this->unk_144 != 0) { - this->unk_144--; + if (this->timer != 0) { + this->timer--; } } diff --git a/src/overlays/actors/ovl_En_Elfgrp/z_en_elfgrp.h b/src/overlays/actors/ovl_En_Elfgrp/z_en_elfgrp.h index 692a76d826..d9767fb2fa 100644 --- a/src/overlays/actors/ovl_En_Elfgrp/z_en_elfgrp.h +++ b/src/overlays/actors/ovl_En_Elfgrp/z_en_elfgrp.h @@ -2,29 +2,32 @@ #define Z_EN_ELFGRP_H #include "global.h" +#include "overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.h" struct EnElfgrp; typedef void (*EnElfgrpActionFunc)(struct EnElfgrp*, PlayState*); -#define ENELFGRP_GET(thisx) ((thisx)->params & 0xF) -#define ENELFGRP_GET_FE00(thisx) (((thisx)->params & 0xFE00) >> 9) +#define ENELFGRP_GET_TYPE(thisx) ((thisx)->params & 0xF) //!< Same type as Great Fairies +#define ENELFGRP_GET_SWITCHFLAG_PARAMS(thisx) (((thisx)->params & 0xFE00) >> 9) +#define ENELFGRP_GET_SWITCHFLAG_ROT(thisx) ((thisx)->home.rot.z) -typedef enum { - /* 0 */ ENELFGRP_0, - /* 2 */ ENELFGRP_1, - /* 2 */ ENELFGRP_2, - /* 3 */ ENELFGRP_3, - /* 4 */ ENELFGRP_4 -} EnElfgrpParam; +typedef enum ElfgrpType { + /* 0 */ ENELFGRP_TYPE_MAGIC = GREAT_FAIRY_TYPE_MAGIC, + /* 1 */ ENELFGRP_TYPE_POWER = GREAT_FAIRY_TYPE_POWER, + /* 2 */ ENELFGRP_TYPE_WISDOM = GREAT_FAIRY_TYPE_WISDOM, + /* 3 */ ENELFGRP_TYPE_COURAGE = GREAT_FAIRY_TYPE_COURAGE, + /* 4 */ ENELFGRP_TYPE_KINDNESS = GREAT_FAIRY_TYPE_KINDNESS, + /* 5 */ ENELFGRP_TYPE_MAX +} ElfgrpType; typedef struct EnElfgrp { /* 0x000 */ Actor actor; - /* 0x144 */ s16 unk_144; - /* 0x146 */ u8 unk_146; - /* 0x147 */ u8 unk_147; - /* 0x148 */ s8 unk_148; - /* 0x14A */ u16 unk_14A; + /* 0x144 */ s16 timer; + /* 0x146 */ u8 talkedOnceFlag; + /* 0x147 */ u8 type; + /* 0x148 */ s8 unk_148; // set and not used + /* 0x14A */ u16 stateFlags; /* 0x14C */ EnElfgrpActionFunc actionFunc; } EnElfgrp; // size = 0x150 diff --git a/src/overlays/actors/ovl_En_Elforg/z_en_elforg.c b/src/overlays/actors/ovl_En_Elforg/z_en_elforg.c index f57f8e0662..27dc844e77 100644 --- a/src/overlays/actors/ovl_En_Elforg/z_en_elforg.c +++ b/src/overlays/actors/ovl_En_Elforg/z_en_elforg.c @@ -96,7 +96,7 @@ void EnElforg_Init(Actor* thisx, PlayState* play) { case STRAY_FAIRY_TYPE_FAIRY_FOUNTAIN: case STRAY_FAIRY_TYPE_BUBBLE: case STRAY_FAIRY_TYPE_CHEST: - case STRAY_FAIRY_TYPE_TURN_IN_TO_FAIRY_FOUNTAIN: + case STRAY_FAIRY_TYPE_RETURNING_TO_FOUNTAIN: break; default: @@ -121,7 +121,7 @@ void EnElforg_Init(Actor* thisx, PlayState* play) { this->targetDistanceFromHome = Rand_ZeroFloat(100.0f) + 50.0f; break; - case STRAY_FAIRY_TYPE_TURN_IN_TO_FAIRY_FOUNTAIN: + case STRAY_FAIRY_TYPE_RETURNING_TO_FOUNTAIN: EnElforg_InitializeParams(this); this->actionFunc = EnElforg_TurnInFairy; this->secondaryTimer = 60; @@ -324,6 +324,7 @@ void EnElforg_TurnInFairy(EnElforg* this, PlayState* play) { void EnElforg_QuicklyCircleFairyFountain(EnElforg* this, PlayState* play) { SkelAnime_Update(&this->skelAnime); EnElforg_MoveToTargetFairyFountain(this, &this->actor.home.pos); + if (this->secondaryTimer <= 30) { this->actionFunc = EnElforg_TurnInFairy; } @@ -367,9 +368,9 @@ void EnElforg_FreeFloatingFairyFountain(EnElforg* this, PlayState* play) { if (this->strayFairyFlags & STRAY_FAIRY_FLAG_SPARKLES_AND_SHRINKS) { // This happens right before the Great Fairy appears once all // Stray Fairies are saved. - if (this->actor.home.rot.x > 0) { + if (STRAY_FAIRY_SPARKLE_COUNT(&this->actor) > 0) { EnElforg_SpawnSparkles(this, play, 10); - this->actor.home.rot.x--; + STRAY_FAIRY_SPARKLE_COUNT(&this->actor)--; } Actor_SetScale(&this->actor, this->actor.scale.x * 0.9f); @@ -383,22 +384,24 @@ void EnElforg_CirclePlayer(EnElforg* this, PlayState* play) { s32 pad; Actor* playerActor = &GET_PLAYER(play)->actor; Player* player = GET_PLAYER(play); - f32 distanceFromPlayer; + f32 orbitRadius; if (GET_PLAYER_FORM == PLAYER_FORM_GORON) { - distanceFromPlayer = 40.0f; + orbitRadius = 40.0f; } else { - distanceFromPlayer = 20.0f; + orbitRadius = 20.0f; } - this->actor.world.pos.x = (Math_SinS(this->timer * 0x1000) * distanceFromPlayer) + playerActor->world.pos.x; - this->actor.world.pos.z = (Math_CosS(this->timer * 0x1000) * distanceFromPlayer) + playerActor->world.pos.z; + this->actor.world.pos.x = (Math_SinS(this->timer * 0x1000) * orbitRadius) + playerActor->world.pos.x; + this->actor.world.pos.z = (Math_CosS(this->timer * 0x1000) * orbitRadius) + playerActor->world.pos.z; this->actor.world.pos.y = player->bodyPartsPos[PLAYER_BODYPART_WAIST].y; + EnElforg_SpawnSparkles(this, play, 16); } void EnElforg_FairyCollected(EnElforg* this, PlayState* play) { EnElforg_CirclePlayer(this, play); + if (this->timer > 80) { Actor_Kill(&this->actor); return; @@ -424,8 +427,10 @@ void EnElforg_ClockTownFairyCollected(EnElforg* this, PlayState* play) { Player* player = GET_PLAYER(play); EnElforg_CirclePlayer(this, play); + player->actor.freezeTimer = 100; player->stateFlags1 |= PLAYER_STATE1_20000000; + if (Actor_TextboxIsClosing(&this->actor, play)) { player->actor.freezeTimer = 0; player->stateFlags1 &= ~PLAYER_STATE1_20000000; @@ -451,6 +456,7 @@ void EnElforg_FreeFloating(EnElforg* this, PlayState* play) { Player* player = GET_PLAYER(play); SkelAnime_Update(&this->skelAnime); + if (Player_GetMask(play) == PLAYER_MASK_GREAT_FAIRY) { pos = player->bodyPartsPos[PLAYER_BODYPART_WAIST]; this->targetSpeedXZ = 5.0f; @@ -461,10 +467,12 @@ void EnElforg_FreeFloating(EnElforg* this, PlayState* play) { } scaledYDistance = this->actor.playerHeightRel - (this->actor.shape.yOffset * this->actor.scale.y); + if (!Player_InCsMode(play)) { if ((this->actor.xzDistToPlayer < 30.0f) && (scaledYDistance < 12.0f) && (scaledYDistance > -68.0f)) { EnElforg_SetupFairyCollected(this, play); Health_ChangeBy(play, 0x30); + switch (STRAY_FAIRY_TYPE(&this->actor)) { case STRAY_FAIRY_TYPE_COLLECTIBLE: Flags_SetCollectible(play, STRAY_FAIRY_FLAG(&this->actor)); @@ -493,7 +501,8 @@ void EnElforg_FreeFloating(EnElforg* this, PlayState* play) { gSaveContext.save.saveInfo.inventory.strayFairies[gSaveContext.dungeonIndex]++; // You found a Stray Fairy! Message_StartTextbox(play, 0x11, NULL); - if (gSaveContext.save.saveInfo.inventory.strayFairies[(void)0, gSaveContext.dungeonIndex] >= 15) { + if (gSaveContext.save.saveInfo.inventory.strayFairies[(void)0, gSaveContext.dungeonIndex] >= + STRAY_FAIRY_SCATTERED_TOTAL) { Audio_PlayFanfare(NA_BGM_GET_ITEM | 0x900); } } @@ -502,6 +511,7 @@ void EnElforg_FreeFloating(EnElforg* this, PlayState* play) { Actor_UpdateBgCheckInfo(play, &this->actor, 20.0f, 20.0f, 20.0f, UPDBGCHECKINFO_FLAG_1 | UPDBGCHECKINFO_FLAG_2 | UPDBGCHECKINFO_FLAG_4); func_80ACCBB8(this, play); + if (Player_GetMask(play) == PLAYER_MASK_GREAT_FAIRY) { if (!(this->strayFairyFlags & STRAY_FAIRY_FLAG_GREAT_FAIRYS_MASK_EQUIPPED)) { Audio_PlaySfx(NA_SE_SY_FAIRY_MASK_SUCCESS); @@ -627,6 +637,7 @@ void EnElforg_Draw(Actor* thisx, PlayState* play) { OPEN_DISPS(play->state.gfxCtx); Gfx_SetupDL25_Xlu(play->state.gfxCtx); + switch (this->area) { case STRAY_FAIRY_AREA_WOODFALL: AnimatedMat_Draw(play, Lib_SegmentedToVirtual(gStrayFairyWoodfallTexAnim)); @@ -644,7 +655,7 @@ void EnElforg_Draw(Actor* thisx, PlayState* play) { AnimatedMat_Draw(play, Lib_SegmentedToVirtual(gStrayFairyStoneTowerTexAnim)); break; - default: + default: // STRAY_FAIRY_AREA_CLOCK_TOWN AnimatedMat_Draw(play, Lib_SegmentedToVirtual(gStrayFairyClockTownTexAnim)); break; } diff --git a/src/overlays/actors/ovl_En_Elforg/z_en_elforg.h b/src/overlays/actors/ovl_En_Elforg/z_en_elforg.h index 798982b09a..7bb8672b12 100644 --- a/src/overlays/actors/ovl_En_Elforg/z_en_elforg.h +++ b/src/overlays/actors/ovl_En_Elforg/z_en_elforg.h @@ -2,36 +2,41 @@ #define Z_EN_ELFORG_H #include "global.h" +#include "overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.h" #include "objects/gameplay_keep/gameplay_keep.h" #define STRAY_FAIRY_TYPE(thisx) ((thisx)->params & 0xF) #define STRAY_FAIRY_GET_NON_DUNGEON_AREA(thisx) (((thisx)->params & 0x1C0) >> 6) #define STRAY_FAIRY_FLAG(thisx) (((thisx)->params & 0xFE00) >> 9) -#define STRAY_FAIRY_PARAMS(flag, nonDungeonArea, type) (((flag & 0x7F) << 9) | ((nonDungeonArea & 7) << 6) | (type & 0xF)) +#define STRAY_FAIRY_SPARKLE_COUNT(thisx) ((thisx)->home.rot.x) + +//! @note `nonDungeonArea` does not always use the enum +#define STRAY_FAIRY_PARAMS(flag, nonDungeonArea, type) ((((flag) & 0x7F) << 9) | (((nonDungeonArea) & 7) << 6) | ((type) & 0xF)) #define STRAY_FAIRY_FLAG_MOVES_QUICKLY_TO_HOME (1 << 0) #define STRAY_FAIRY_FLAG_SPARKLES_AND_SHRINKS (1 << 1) #define STRAY_FAIRY_FLAG_CIRCLES_QUICKLY_IN_FOUNTAIN (1 << 2) #define STRAY_FAIRY_FLAG_GREAT_FAIRYS_MASK_EQUIPPED (1 << 3) -typedef enum { - /* 0 */ STRAY_FAIRY_TYPE_FREE_FLOATING, // The ones just floating around - /* 1 */ STRAY_FAIRY_TYPE_FAIRY_FOUNTAIN, // The ones already present when you enter a Fairy Fountain - /* 2 */ STRAY_FAIRY_TYPE_BUBBLE, // The ones trapped in bubbles - /* 3 */ STRAY_FAIRY_TYPE_CLOCK_TOWN, // The free-floating Stray Fairies in Clock Town - /* 4 */ STRAY_FAIRY_TYPE_ENEMY, // The ones trapped inside enemies - /* 5 */ STRAY_FAIRY_TYPE_COLLIDER, // Unused in retail. The fairy is hidden until the collider is hit - /* 6 */ STRAY_FAIRY_TYPE_CHEST, // The ones in treasure chests - /* 7 */ STRAY_FAIRY_TYPE_COLLECTIBLE, // The ones in boxes, pots, beehives, etc. - /* 8 */ STRAY_FAIRY_TYPE_TURN_IN_TO_FAIRY_FOUNTAIN // The ones you "turn in" by walking into a Fairy Fountain +typedef enum StrayFairyType { + /* 0 */ STRAY_FAIRY_TYPE_FREE_FLOATING, // The ones just floating around + /* 1 */ STRAY_FAIRY_TYPE_FAIRY_FOUNTAIN, // The ones already present when you enter a Fairy Fountain + /* 2 */ STRAY_FAIRY_TYPE_BUBBLE, // The ones trapped in bubbles + /* 3 */ STRAY_FAIRY_TYPE_CLOCK_TOWN, // The free-floating Stray Fairies in Clock Town + /* 4 */ STRAY_FAIRY_TYPE_ENEMY, // The ones trapped inside enemies + /* 5 */ STRAY_FAIRY_TYPE_COLLIDER, // Unused in retail. The fairy is hidden until the collider is hit + /* 6 */ STRAY_FAIRY_TYPE_CHEST, // The ones in treasure chests + /* 7 */ STRAY_FAIRY_TYPE_COLLECTIBLE, // The ones in boxes, pots, beehives, etc. + /* 8 */ STRAY_FAIRY_TYPE_RETURNING_TO_FOUNTAIN // The ones you "turn in" by walking into a Fairy Fountain } StrayFairyType; -typedef enum { - /* 0 */ STRAY_FAIRY_AREA_CLOCK_TOWN, - /* 1 */ STRAY_FAIRY_AREA_WOODFALL, - /* 2 */ STRAY_FAIRY_AREA_SNOWHEAD, - /* 3 */ STRAY_FAIRY_AREA_GREAT_BAY, - /* 4 */ STRAY_FAIRY_AREA_STONE_TOWER, +// Corresponds to the Great Fairy types +typedef enum StrayFairyArea { + /* 0 */ STRAY_FAIRY_AREA_CLOCK_TOWN = GREAT_FAIRY_TYPE_MAGIC, + /* 1 */ STRAY_FAIRY_AREA_WOODFALL = GREAT_FAIRY_TYPE_POWER, + /* 2 */ STRAY_FAIRY_AREA_SNOWHEAD = GREAT_FAIRY_TYPE_WISDOM, + /* 3 */ STRAY_FAIRY_AREA_GREAT_BAY = GREAT_FAIRY_TYPE_COURAGE, + /* 4 */ STRAY_FAIRY_AREA_STONE_TOWER = GREAT_FAIRY_TYPE_KINDNESS, /* 5 */ STRAY_FAIRY_AREA_MAX } StrayFairyArea; diff --git a/src/overlays/actors/ovl_En_M_Thunder/z_en_m_thunder.c b/src/overlays/actors/ovl_En_M_Thunder/z_en_m_thunder.c index d6f34a256b..b09f8f54d5 100644 --- a/src/overlays/actors/ovl_En_M_Thunder/z_en_m_thunder.c +++ b/src/overlays/actors/ovl_En_M_Thunder/z_en_m_thunder.c @@ -143,7 +143,7 @@ void EnMThunder_Init(Actor* thisx, PlayState* play) { player->stateFlags2 &= ~PLAYER_STATE2_20000; this->isCharging = false; - if (CHECK_WEEKEVENTREG(WEEKEVENTREG_23_02)) { + if (CHECK_WEEKEVENTREG(WEEKEVENTREG_OBTAINED_GREAT_SPIN_ATTACK)) { player->unk_B08 = 1.0f; this->collider.info.toucher.damage = sDamages[this->type + ENMTHUNDER_TYPE_MAX]; this->subtype = ENMTHUNDER_SUBTYPE_SPIN_GREAT; diff --git a/src/overlays/actors/ovl_Obj_Flowerpot/z_obj_flowerpot.c b/src/overlays/actors/ovl_Obj_Flowerpot/z_obj_flowerpot.c index aca30fe926..cd86326595 100644 --- a/src/overlays/actors/ovl_Obj_Flowerpot/z_obj_flowerpot.c +++ b/src/overlays/actors/ovl_Obj_Flowerpot/z_obj_flowerpot.c @@ -255,7 +255,7 @@ void func_80A1BA44(ObjFlowerpot* this, PlayState* play) { } EffectSsKakera_Spawn(play, &spC4, &spB8, &spC4, -600, phi_s0, 30, 0, 0, (Rand_ZeroOne() * 12.0f) + 16.6f, - phi_s1, 0, 35, -1, ACTOR_DEMO_GETITEM, object_flowerpot_DL_0015B0); + phi_s1, 0, 35, -1, OBJECT_FLOWERPOT, object_flowerpot_DL_0015B0); } spD0.y += 20.0f; @@ -298,7 +298,7 @@ void func_80A1BD80(ObjFlowerpot* this, PlayState* play) { } EffectSsKakera_Spawn(play, &spBC, &spB0, &spBC, -240, phi_s0, 40, 0, 0, (Rand_ZeroOne() * 20.0f) + 10.6f, 0, 0, - 42, -1, ACTOR_DEMO_GETITEM, object_flowerpot_DL_0015B0); + 42, -1, OBJECT_FLOWERPOT, object_flowerpot_DL_0015B0); } spBC.y = this->actor.world.pos.y + this->actor.depthInWater; @@ -338,7 +338,7 @@ void func_80A1C0FC(ObjFlowerpot* this, PlayState* play) { Math_Vec3f_Sum(&spB8, &spC4, &spB8); EffectSsKakera_Spawn(play, &spB8, &spAC, &spB8, -100, 64, 40, 0, 0, (Rand_ZeroOne() * 16.0f) + 14.0f, 0, 0, 80, - -1, ACTOR_DEMO_GETITEM, object_flowerpot_DL_0014F0); + -1, OBJECT_FLOWERPOT, object_flowerpot_DL_0014F0); } } @@ -365,7 +365,7 @@ void func_80A1C328(ObjFlowerpot* this, PlayState* play) { Math_Vec3f_Sum(&spB8, &spC4, &spB8); EffectSsKakera_Spawn(play, &spB8, &spAC, &spB8, -80, 64, 44, 0, 0, (Rand_ZeroOne() * 16.0f) + 14.0f, 0, 0, 80, - -1, ACTOR_DEMO_GETITEM, object_flowerpot_DL_0014F0); + -1, OBJECT_FLOWERPOT, object_flowerpot_DL_0014F0); } } diff --git a/src/overlays/actors/ovl_Obj_Lightblock/z_obj_lightblock.c b/src/overlays/actors/ovl_Obj_Lightblock/z_obj_lightblock.c index 6a6937e7e4..f8ee482df0 100644 --- a/src/overlays/actors/ovl_Obj_Lightblock/z_obj_lightblock.c +++ b/src/overlays/actors/ovl_Obj_Lightblock/z_obj_lightblock.c @@ -5,6 +5,7 @@ */ #include "z_obj_lightblock.h" +#include "overlays/actors/ovl_Demo_Effect/z_demo_effect.h" #include "objects/object_lightblock/object_lightblock.h" #define FLAGS 0x00000000 @@ -15,12 +16,12 @@ void ObjLightblock_Init(Actor* thisx, PlayState* play); void ObjLightblock_Destroy(Actor* thisx, PlayState* play); void ObjLightblock_Update(Actor* thisx, PlayState* play); void ObjLightblock_Draw(Actor* thisx, PlayState* play); -void func_80AF3AC8(ObjLightblock* this); -void func_80AF3ADC(ObjLightblock* this, PlayState* play); -void func_80AF3B8C(ObjLightblock* this); -void func_80AF3BA0(ObjLightblock* this, PlayState* play); -void func_80AF3C18(ObjLightblock* this); -void func_80AF3C34(ObjLightblock* this, PlayState* play); +void ObjLightblock_SetupWait(ObjLightblock* this); +void ObjLightblock_Wait(ObjLightblock* this, PlayState* play); +void ObjLightblock_SetupPlayCutscene(ObjLightblock* this); +void ObjLightblock_PlayCutscene(ObjLightblock* this, PlayState* play); +void ObjLightblock_SetupFadeAway(ObjLightblock* this); +void ObjLightblock_FadeAway(ObjLightblock* this, PlayState* play); ActorInit Obj_Lightblock_InitVars = { ACTOR_OBJ_LIGHTBLOCK, @@ -54,17 +55,17 @@ static ColliderCylinderInit sCylinderInit = { { 84, 120, 0, { 0, 0, 0 } }, }; -typedef struct { +typedef struct LightblockTypeVars { /* 0x0 */ f32 scale; /* 0x4 */ s16 radius; /* 0x6 */ s16 height; /* 0x8 */ s16 yShift; - /* 0xC */ s32 params; + /* 0xC */ s32 effectParams; } LightblockTypeVars; // size = 0x10 static LightblockTypeVars sLightblockTypeVars[] = { - { 0.1f, 76, 80, 19, 2 }, - { (1.0f / 6), 126, 144, 19, 3 }, + { 0.1f, 76, 80, 19, DEMO_EFFECT_TIMEWARP_LIGHTBLOCK_LARGE }, + { (1.0f / 6.0f), 126, 144, 19, DEMO_EFFECT_TIMEWARP_LIGHTBLOCK_VERY_LARGE }, }; static InitChainEntry sInitChain[] = { @@ -76,11 +77,11 @@ static InitChainEntry sInitChain[] = { extern Gfx D_801AEF88[]; extern Gfx D_801AEFA0[]; -void func_80AF3910(ObjLightblock* this, PlayState* play) { +void ObjLightblock_SpawnEffect(ObjLightblock* this, PlayState* play) { LightblockTypeVars* typeVars = &sLightblockTypeVars[LIGHTBLOCK_TYPE(&this->dyna.actor)]; Actor_Spawn(&play->actorCtx, play, ACTOR_DEMO_EFFECT, this->dyna.actor.world.pos.x, this->dyna.actor.world.pos.y, - this->dyna.actor.world.pos.z, 0, 0, 0, typeVars->params); + this->dyna.actor.world.pos.z, 0, 0, 0, typeVars->effectParams); } void ObjLightblock_Init(Actor* thisx, PlayState* play) { @@ -104,7 +105,7 @@ void ObjLightblock_Init(Actor* thisx, PlayState* play) { this->collider.dim.height = typeVars->height; this->collider.dim.yShift = typeVars->yShift; this->alpha = 255; - func_80AF3AC8(this); + ObjLightblock_SetupWait(this); } void ObjLightblock_Destroy(Actor* thisx, PlayState* play) { @@ -114,11 +115,14 @@ void ObjLightblock_Destroy(Actor* thisx, PlayState* play) { Collider_DestroyCylinder(play, &this->collider); } -void func_80AF3AC8(ObjLightblock* this) { - this->actionFunc = func_80AF3ADC; +void ObjLightblock_SetupWait(ObjLightblock* this) { + this->actionFunc = ObjLightblock_Wait; } -void func_80AF3ADC(ObjLightblock* this, PlayState* play) { +/** + * Wait for a single collision from a Light Arrow or 8 frames of Mirror Shield ray collision. + */ +void ObjLightblock_Wait(ObjLightblock* this, PlayState* play) { if (this->collider.base.acFlags & AC_HIT) { this->collider.base.acFlags &= ~AC_HIT; // light arrows @@ -135,39 +139,36 @@ void func_80AF3ADC(ObjLightblock* this, PlayState* play) { if (this->collisionCounter >= 8) { CutsceneManager_Queue(this->dyna.actor.csId); - func_80AF3B8C(this); + ObjLightblock_SetupPlayCutscene(this); } else { CollisionCheck_SetAC(play, &play->colChkCtx, &this->collider.base); } } -void func_80AF3B8C(ObjLightblock* this) { - this->actionFunc = func_80AF3BA0; +void ObjLightblock_SetupPlayCutscene(ObjLightblock* this) { + this->actionFunc = ObjLightblock_PlayCutscene; } -void func_80AF3BA0(ObjLightblock* this, PlayState* play) { +void ObjLightblock_PlayCutscene(ObjLightblock* this, PlayState* play) { if (CutsceneManager_IsNext(this->dyna.actor.csId)) { CutsceneManager_StartWithPlayerCs(this->dyna.actor.csId, &this->dyna.actor); Flags_SetSwitch(play, LIGHTBLOCK_DESTROYED(&this->dyna.actor)); - func_80AF3910(this, play); - func_80AF3C18(this); + ObjLightblock_SpawnEffect(this, play); + ObjLightblock_SetupFadeAway(this); } else { CutsceneManager_Queue(this->dyna.actor.csId); } } -void func_80AF3C18(ObjLightblock* this) { +void ObjLightblock_SetupFadeAway(ObjLightblock* this) { this->timer = 80; - this->actionFunc = func_80AF3C34; + this->actionFunc = ObjLightblock_FadeAway; } -void func_80AF3C34(ObjLightblock* this, PlayState* play) { - s8 csId; - +void ObjLightblock_FadeAway(ObjLightblock* this, PlayState* play) { this->timer--; if (this->timer <= 0) { - csId = this->dyna.actor.csId; - CutsceneManager_Stop(csId); + CutsceneManager_Stop(this->dyna.actor.csId); Actor_Kill(&this->dyna.actor); return; } diff --git a/src/overlays/actors/ovl_player_actor/z_player.c b/src/overlays/actors/ovl_player_actor/z_player.c index d01dbd3be9..07e6915919 100644 --- a/src/overlays/actors/ovl_player_actor/z_player.c +++ b/src/overlays/actors/ovl_player_actor/z_player.c @@ -10374,7 +10374,7 @@ void func_80840EC0(Player* this, PlayState* play) { // Spin attack size void func_80840F34(Player* this) { - Math_StepToF(&this->unk_B08, (CHECK_WEEKEVENTREG(WEEKEVENTREG_23_02)) ? 1.0f : 0.5f, 0.02f); + Math_StepToF(&this->unk_B08, CHECK_WEEKEVENTREG(WEEKEVENTREG_OBTAINED_GREAT_SPIN_ATTACK) ? 1.0f : 0.5f, 0.02f); } s32 func_80840F90(PlayState* play, Player* this, CsCmdActorCue* cue, f32 arg3, s16 arg4, s32 arg5) { diff --git a/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_map.c b/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_map.c index b4ed531f82..ec1ca83ec9 100644 --- a/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_map.c +++ b/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_map.c @@ -19,7 +19,7 @@ void KaleidoScope_DrawDungeonStrayFairyCount(PlayState* play) { OPEN_DISPS(play->state.gfxCtx); // Get digits for max number of stray fairies - counterDigits[1] = 15; + counterDigits[1] = STRAY_FAIRY_SCATTERED_TOTAL; counterDigits[0] = counterDigits[1] / 10; counterDigits[1] -= (s16)(counterDigits[0] * 10); diff --git a/tools/disasm/functions.txt b/tools/disasm/functions.txt index c1137d3b22..8a60d1f667 100644 --- a/tools/disasm/functions.txt +++ b/tools/disasm/functions.txt @@ -6263,17 +6263,17 @@ 0x808CD238:("EnVm_Draw",), 0x808CD740:("DemoEffect_Init",), 0x808CD8E8:("DemoEffect_Destroy",), - 0x808CD940:("func_808CD940",), - 0x808CD998:("func_808CD998",), - 0x808CDAD0:("func_808CDAD0",), - 0x808CDBDC:("func_808CDBDC",), - 0x808CDCEC:("func_808CDCEC",), - 0x808CDD70:("func_808CDD70",), - 0x808CDDE0:("func_808CDDE0",), + 0x808CD940:("DemoEffect_WaitForObject",), + 0x808CD998:("DemoEffect_SetupTimewarp",), + 0x808CDAD0:("DemoEffect_SetPerVertexAlpha",), + 0x808CDBDC:("DemoEffect_FinishTimewarp",), + 0x808CDCEC:("DemoEffect_StartTimewarp",), + 0x808CDD70:("DemoEffect_ShrinkLight",), + 0x808CDDE0:("DemoEffect_ExpandLight",), 0x808CDE54:("DemoEffect_Update",), - 0x808CDE78:("func_808CDE78",), - 0x808CDFF8:("func_808CDFF8",), - 0x808CE078:("func_808CE078",), + 0x808CDE78:("DemoEffect_OverrideLimbDrawTimewarp",), + 0x808CDFF8:("DemoEffect_DrawTimewarp",), + 0x808CE078:("DemoEffect_DrawLight",), 0x808CE450:("DemoKankyo_SetupAction",), 0x808CE45C:("func_808CE45C",), 0x808CF06C:("func_808CF06C",), @@ -9573,9 +9573,9 @@ 0x80A07740:("func_80A07740",), 0x80A0A8A0:("BgDyYoseizo_Init",), 0x80A0A95C:("BgDyYoseizo_Destroy",), - 0x80A0A96C:("func_80A0A96C",), - 0x80A0A9E4:("func_80A0A9E4",), - 0x80A0AA40:("func_80A0AA40",), + 0x80A0A96C:("BgDyYoseizo_UpdateEyes",), + 0x80A0A9E4:("BgDyYoseizo_Bob",), + 0x80A0AA40:("BgDyYoseizo_SpawnEffects",), 0x80A0AD50:("func_80A0AD50",), 0x80A0AE1C:("func_80A0AE1C",), 0x80A0AFDC:("func_80A0AFDC",), @@ -9587,14 +9587,14 @@ 0x80A0B5F0:("func_80A0B5F0",), 0x80A0B75C:("func_80A0B75C",), 0x80A0B834:("func_80A0B834",), - 0x80A0B8CC:("func_80A0B8CC",), + 0x80A0B8CC:("BgDyYoseizo_TrainPlayer",), 0x80A0BB08:("func_80A0BB08",), 0x80A0BC84:("BgDyYoseizo_Update",), - 0x80A0BCD8:("func_80A0BCD8",), - 0x80A0BD40:("func_80A0BD40",), - 0x80A0BE60:("func_80A0BE60",), - 0x80A0BF70:("func_80A0BF70",), - 0x80A0C270:("func_80A0C270",), + 0x80A0BCD8:("BgDyYoseizo_OverrideLimbDraw",), + 0x80A0BD40:("BgDyYoseizo_Draw",), + 0x80A0BE60:("BgDyYoseizo_SpawnEffect",), + 0x80A0BF70:("BgDyYoseizo_UpdateEffects",), + 0x80A0C270:("BgDyYoseizo_DrawEffects",), 0x80A0C780:("EnBoj05_Init",), 0x80A0C790:("EnBoj05_Destroy",), 0x80A0C7A0:("EnBoj05_Update",), @@ -10266,16 +10266,16 @@ 0x80A38FB4:("EnRu_OverrideLimbdraw",), 0x80A390F8:("EnRu_PostLimbdraw",), 0x80A39204:("EnRu_Draw",), - 0x80A396B0:("func_80A396B0",), + 0x80A396B0:("EnElfgrp_SetCutscene",), 0x80A3970C:("EnElfgrp_Init",), 0x80A39BC0:("EnElfgrp_Destroy",), - 0x80A39BD0:("func_80A39BD0",), - 0x80A39C1C:("func_80A39C1C",), - 0x80A39CD4:("func_80A39CD4",), - 0x80A39DC8:("func_80A39DC8",), - 0x80A39F50:("func_80A39F50",), - 0x80A39FBC:("func_80A39FBC",), - 0x80A3A044:("func_80A3A044",), + 0x80A39BD0:("EnElfgrp_GetHeldFairiesCount",), + 0x80A39C1C:("EnElfgrp_GetFountainFairiesCount",), + 0x80A39CD4:("EnElfgrp_SetFountainFairiesCount",), + 0x80A39DC8:("EnElfgrp_SpawnStrayFairies",), + 0x80A39F50:("EnElfgrp_SummonStrayFairies",), + 0x80A39FBC:("EnElfgrp_SpinStrayFairies",), + 0x80A3A044:("EnElfgrp_VanishStrayFairies",), 0x80A3A0AC:("func_80A3A0AC",), 0x80A3A0F4:("func_80A3A0F4",), 0x80A3A210:("func_80A3A210",), @@ -10284,8 +10284,8 @@ 0x80A3A484:("func_80A3A484",), 0x80A3A4AC:("func_80A3A4AC",), 0x80A3A520:("func_80A3A520",), - 0x80A3A600:("func_80A3A600",), - 0x80A3A610:("func_80A3A610",), + 0x80A3A600:("EnElfgrp_DoNothing",), + 0x80A3A610:("EnElfgrp_HealPlayer",), 0x80A3A6F4:("func_80A3A6F4",), 0x80A3A77C:("func_80A3A77C",), 0x80A3A7FC:("func_80A3A7FC",), @@ -10546,8 +10546,8 @@ 0x80A4F4C8:("func_80A4F4C8",), 0x80A4FA40:("DemoGetitem_Init",), 0x80A4FB00:("DemoGetitem_Destroy",), - 0x80A4FB10:("func_80A4FB10",), - 0x80A4FB68:("func_80A4FB68",), + 0x80A4FB10:("DemoGetitem_Wait",), + 0x80A4FB68:("DemoGetitem_PerformCutsceneActions",), 0x80A4FCCC:("DemoGetitem_Update",), 0x80A4FCF0:("DemoGetitem_Draw",), 0x80A4FDD0:("func_80A4FDD0",), @@ -10752,8 +10752,8 @@ 0x80A61040:("BgSpoutFire_Draw",), 0x80A612B0:("EnDyExtra_Destroy",), 0x80A612C0:("EnDyExtra_Init",), - 0x80A61334:("func_80A61334",), - 0x80A613C8:("func_80A613C8",), + 0x80A61334:("EnDyExtra_WaitForTrigger",), + 0x80A613C8:("EnDyExtra_Fall",), 0x80A61470:("EnDyExtra_Update",), 0x80A614C4:("EnDyExtra_Draw",), 0x80A61810:("EnBal_Init",), @@ -12656,15 +12656,15 @@ 0x80AF3144:("EnTest7_Update",), 0x80AF31D0:("func_80AF31D0",), 0x80AF3248:("EnTest7_Draw",), - 0x80AF3910:("func_80AF3910",), + 0x80AF3910:("ObjLightblock_SpawnEffect",), 0x80AF397C:("ObjLightblock_Init",), 0x80AF3A80:("ObjLightblock_Destroy",), - 0x80AF3AC8:("func_80AF3AC8",), - 0x80AF3ADC:("func_80AF3ADC",), - 0x80AF3B8C:("func_80AF3B8C",), - 0x80AF3BA0:("func_80AF3BA0",), - 0x80AF3C18:("func_80AF3C18",), - 0x80AF3C34:("func_80AF3C34",), + 0x80AF3AC8:("ObjLightblock_SetupWait",), + 0x80AF3ADC:("ObjLightblock_Wait",), + 0x80AF3B8C:("ObjLightblock_SetupPlayCutscene",), + 0x80AF3BA0:("ObjLightblock_PlayCutscene",), + 0x80AF3C18:("ObjLightblock_SetupFadeAway",), + 0x80AF3C34:("ObjLightblock_FadeAway",), 0x80AF3CC0:("ObjLightblock_Update",), 0x80AF3CE4:("ObjLightblock_Draw",), 0x80AF3F70:("func_80AF3F70",), diff --git a/tools/disasm/variables.txt b/tools/disasm/variables.txt index 417e27b770..5aaa2f1d0b 100644 --- a/tools/disasm/variables.txt +++ b/tools/disasm/variables.txt @@ -10574,27 +10574,11 @@ 0x80A0A88C:("D_80A0A88C","UNK_TYPE4","",0x4), 0x80A0A890:("D_80A0A890","UNK_TYPE4","",0x4), 0x80A0C4A0:("Bg_Dy_Yoseizo_InitVars","UNK_TYPE1","",0x1), - 0x80A0C4C0:("D_80A0C4C0","UNK_TYPE4","",0x4), - 0x80A0C4C4:("D_80A0C4C4","UNK_TYPE4","",0x4), - 0x80A0C4C8:("D_80A0C4C8","UNK_TYPE4","",0x4), - 0x80A0C4CC:("D_80A0C4CC","UNK_TYPE4","",0x4), - 0x80A0C4D0:("D_80A0C4D0","UNK_TYPE4","",0x4), - 0x80A0C4D8:("D_80A0C4D8","UNK_TYPE4","",0x4), - 0x80A0C4DC:("D_80A0C4DC","UNK_TYPE4","",0x4), - 0x80A0C4E0:("D_80A0C4E0","UNK_TYPE4","",0x4), - 0x80A0C4E4:("D_80A0C4E4","UNK_TYPE1","",0x1), - 0x80A0C4F8:("D_80A0C4F8","UNK_TYPE1","",0x1), - 0x80A0C50C:("D_80A0C50C","UNK_TYPE1","",0x1), - 0x80A0C514:("D_80A0C514","UNK_TYPE1","",0x1), - 0x80A0C540:("D_80A0C540","f32","",0x4), - 0x80A0C544:("D_80A0C544","f32","",0x4), - 0x80A0C548:("D_80A0C548","f32","",0x4), - 0x80A0C54C:("D_80A0C54C","f32","",0x4), - 0x80A0C550:("D_80A0C550","f32","",0x4), - 0x80A0C554:("D_80A0C554","f32","",0x4), - 0x80A0C558:("D_80A0C558","f32","",0x4), - 0x80A0C55C:("D_80A0C55C","f32","",0x4), - 0x80A0C560:("D_80A0C560","f32","",0x4), + 0x80A0C4C0:("sAnimations","AnimationHeader*","9",0x24), + 0x80A0C4E4:("sEffectPrimColors","Color_RGB8","6",0x12), + 0x80A0C4F8:("sEffectEnvColors","Color_RGB8","6",0x12), + 0x80A0C50C:("sMouthTextures","UNK_TYPE1","2",0x8), + 0x80A0C514:("sStretchFactors","f32","8",0x20), 0x80A0C7C0:("En_Boj_05_InitVars","UNK_TYPE1","",0x1), 0x80A10860:("sAnimationsBombShopkeeper","UNK_PTR","",0x4), 0x80A10890:("En_Sob1_InitVars","UNK_TYPE1","",0x1), diff --git a/tools/weekeventregconvert.py b/tools/weekeventregconvert.py index 0bde4a5ce9..35757a022f 100755 --- a/tools/weekeventregconvert.py +++ b/tools/weekeventregconvert.py @@ -189,7 +189,7 @@ weekEventReg = { (22 << 8) | 0x40: "WEEKEVENTREG_22_40", (22 << 8) | 0x80: "WEEKEVENTREG_22_80", (23 << 8) | 0x01: "WEEKEVENTREG_23_01", - (23 << 8) | 0x02: "WEEKEVENTREG_23_02", + (23 << 8) | 0x02: "WEEKEVENTREG_OBTAINED_GREAT_SPIN_ATTACK", (23 << 8) | 0x04: "WEEKEVENTREG_23_04", (23 << 8) | 0x08: "WEEKEVENTREG_23_08", (23 << 8) | 0x10: "WEEKEVENTREG_23_10", diff --git a/undefined_syms.txt b/undefined_syms.txt index 45307fc872..010f94c053 100644 --- a/undefined_syms.txt +++ b/undefined_syms.txt @@ -191,14 +191,6 @@ D_050089D0 = 0x050089D0; D_060002C8 = 0x060002C8; D_060005C4 = 0x060005C4; -// ovl_Bg_Dy_Yoseizo - -D_06008090 = 0x06008090; -D_0600D1B0 = 0x0600D1B0; -D_0600D228 = 0x0600D228; -D_0601C6F4 = 0x0601C6F4; -D_0601C8B4 = 0x0601C8B4; - // ovl_Bg_Lotus D_06000A20 = 0x06000A20;