diff --git a/assets/xml/objects/object_boss07.xml b/assets/xml/objects/object_boss07.xml
index 2d3aa4fa11..7c5d702c8f 100644
--- a/assets/xml/objects/object_boss07.xml
+++ b/assets/xml/objects/object_boss07.xml
@@ -4,7 +4,7 @@
-
+
@@ -154,14 +154,14 @@
-
+
-
+
diff --git a/include/z64subs.h b/include/z64subs.h
index 4b51e47b3b..60a71127bd 100644
--- a/include/z64subs.h
+++ b/include/z64subs.h
@@ -177,7 +177,7 @@ s32 SubS_LineSegVsPlane(Vec3f* point, Vec3s* rot, Vec3f* unitVec, Vec3f* linePoi
Actor* SubS_FindActorCustom(struct PlayState* play, Actor* actor, Actor* actorListStart, u8 actorCategory, s16 actorId, void* verifyData, VerifyFindActorFunc verifyActorFunc);
s32 SubS_OfferTalkExchangeCustom(Actor* actor, struct PlayState* play, f32 xzRange, f32 yRange, s32 exchangeItemAction, void* data, VerifyTalkExchangeActorFunc verifyActorFunc);
-s32 SubS_ActorAndPlayerFaceEachOther(struct PlayState* play, Actor* actor, void* data);
+s32 SubS_ArePlayerAndActorFacing(struct PlayState* play, Actor* actor, void* data);
s32 SubS_OfferTalkExchangeFacing(Actor* actor, struct PlayState* play, f32 xzRange, f32 yRange, s32 exchangeItemAction, s16 playerYawRange, s16 actorYawRange);
s32 SubS_TrackPointStep(Vec3f* worldPos, Vec3f* focusPos, s16 shapeYRot, Vec3f* yawTarget, Vec3f* pitchTarget, s16* headZRotStep, s16* headXRotStep, s16* torsoZRotStep, s16* torsoXRotStep, u16 headZRotStepMax, u16 headXRotStepMax, u16 torsoZRotStepMax, u16 torsoXRotStepMax);
diff --git a/linker_scripts/final/undefined_syms.ld b/linker_scripts/final/undefined_syms.ld
index 80e2ce2d0f..de8f5fe595 100644
--- a/linker_scripts/final/undefined_syms.ld
+++ b/linker_scripts/final/undefined_syms.ld
@@ -21,84 +21,10 @@ D_01000000 = 0x01000000;
// segment 0x04
-D_04023348 = 0x04023348;
-D_040233B8 = 0x040233B8;
-D_04023428 = 0x04023428;
-D_0406AB30 = 0x0406AB30;
-
// segment 0x05
// segment 0x06
-// ovl_Boss_07
-
-D_06000194 = 0x06000194;
-D_06000428 = 0x06000428;
-D_06000D0C = 0x06000D0C;
-D_06002C40 = 0x06002C40;
-D_06002D84 = 0x06002D84;
-D_060031E4 = 0x060031E4;
-D_06003854 = 0x06003854;
-D_06003A64 = 0x06003A64;
-D_060099A0 = 0x060099A0;
-D_06009C7C = 0x06009C7C;
-D_06009EA8 = 0x06009EA8;
-D_0600A194 = 0x0600A194;
-D_0600A400 = 0x0600A400;
-D_0600A6AC = 0x0600A6AC;
-D_0600AE40 = 0x0600AE40;
-D_0600AFB0 = 0x0600AFB0;
-D_0600B020 = 0x0600B020;
-D_0600C7D8 = 0x0600C7D8;
-D_0600CEE8 = 0x0600CEE8;
-D_060149A0 = 0x060149A0;
-D_06016090 = 0x06016090;
-D_06017DE0 = 0x06017DE0;
-D_06019328 = 0x06019328;
-D_06019C58 = 0x06019C58;
-D_06019E48 = 0x06019E48;
-D_0601DEB4 = 0x0601DEB4;
-D_06022BB4 = 0x06022BB4;
-D_06023DAC = 0x06023DAC;
-D_06025018 = 0x06025018;
-D_06025878 = 0x06025878;
-D_06026204 = 0x06026204;
-D_060269EC = 0x060269EC;
-D_06026EA0 = 0x06026EA0;
-D_06027270 = 0x06027270;
-D_0602EE50 = 0x0602EE50;
-D_0602EEC8 = 0x0602EEC8;
-D_0602EEF8 = 0x0602EEF8;
-D_0602EF68 = 0x0602EF68;
-D_0602EF88 = 0x0602EF88;
-D_0602EFE8 = 0x0602EFE8;
-D_0602F640 = 0x0602F640;
-D_0602F840 = 0x0602F840;
-D_06030C40 = 0x06030C40;
-D_06032040 = 0x06032040;
-D_060335F0 = 0x060335F0;
-D_06033F80 = 0x06033F80;
-D_06034E64 = 0x06034E64;
-D_060358C4 = 0x060358C4;
-D_06036A7C = 0x06036A7C;
-D_06037ADC = 0x06037ADC;
-D_0603918C = 0x0603918C;
-D_0603B330 = 0x0603B330;
-D_0603C4E0 = 0x0603C4E0;
-D_0603CBD0 = 0x0603CBD0;
-D_0603D224 = 0x0603D224;
-D_0603D7F0 = 0x0603D7F0;
-D_0603DD1C = 0x0603DD1C;
-D_0603DD30 = 0x0603DD30;
-D_0603ED30 = 0x0603ED30;
-D_0603F130 = 0x0603F130;
-D_06040130 = 0x06040130;
-D_06040930 = 0x06040930;
-D_06040B30 = 0x06040B30;
-D_06041B30 = 0x06041B30;
-D_06042330 = 0x06042330;
-D_06043330 = 0x06043330;
-
// segment 0x07
// segment 0x08
diff --git a/spec b/spec
index 4e609fb379..3d0b8d3678 100644
--- a/spec
+++ b/spec
@@ -2510,9 +2510,7 @@ beginseg
name "ovl_Boss_07"
compress
include "$(BUILD_DIR)/src/overlays/actors/ovl_Boss_07/z_boss_07.o"
- include "$(BUILD_DIR)/data/ovl_Boss_07/ovl_Boss_07.data.o"
- include "$(BUILD_DIR)/data/ovl_Boss_07/ovl_Boss_07.bss.o"
- include "$(BUILD_DIR)/data/ovl_Boss_07/ovl_Boss_07.reloc.o"
+ include "$(BUILD_DIR)/src/overlays/actors/ovl_Boss_07/ovl_Boss_07_reloc.o"
endseg
beginseg
diff --git a/src/code/z_sub_s.c b/src/code/z_sub_s.c
index 28832cf6a8..3f5b111c6f 100644
--- a/src/code/z_sub_s.c
+++ b/src/code/z_sub_s.c
@@ -1553,7 +1553,7 @@ s32 SubS_OfferTalkExchangeCustom(Actor* actor, PlayState* play, f32 xzRange, f32
return canAccept;
}
-s32 SubS_ActorAndPlayerFaceEachOther(PlayState* play, Actor* actor, void* data) {
+s32 SubS_ArePlayerAndActorFacing(PlayState* play, Actor* actor, void* data) {
Player* player = GET_PLAYER(play);
Vec3s* yawRanges = (Vec3s*)data;
s16 playerYaw = ABS(BINANG_SUB(Actor_WorldYawTowardActor(&player->actor, actor), player->actor.shape.rot.y));
@@ -1579,7 +1579,7 @@ s32 SubS_OfferTalkExchangeFacing(Actor* actor, PlayState* play, f32 xzRange, f32
yawRanges.x = playerYawRange;
yawRanges.y = actorYawRange;
return SubS_OfferTalkExchangeCustom(actor, play, xzRange, yRange, exchangeItemAction, &yawRanges,
- SubS_ActorAndPlayerFaceEachOther);
+ SubS_ArePlayerAndActorFacing);
}
/**
diff --git a/src/overlays/actors/ovl_Boss_01/z_boss_01.c b/src/overlays/actors/ovl_Boss_01/z_boss_01.c
index 8c69764f4c..e655f3150a 100644
--- a/src/overlays/actors/ovl_Boss_01/z_boss_01.c
+++ b/src/overlays/actors/ovl_Boss_01/z_boss_01.c
@@ -236,8 +236,8 @@ typedef enum {
// Deals damage and has no special effect.
/* 0xD */ ODOLWA_DMGEFF_DAMAGE,
- // Deals damage and checks the timer that tracks how long Odolwa should be in his damaged state. If the timer is 7
- // or more, it will reset the timer to 20 frames keep Odolwa in the damaged state for longer. If the timer is 6 or
+ // Deals damage and checks the timer that tracks how long Odolwa should be in his damaged state. If the timer is 5
+ // or more, it will reset the timer to 20 frames keep Odolwa in the damaged state for longer. If the timer is 4 or
// less, it will disable Odolwa's collision for 20 frames to ensure he can jump away without taking further damage.
/* 0xE */ ODOLWA_DMGEFF_DAMAGE_TIMER_CHECK,
@@ -958,16 +958,15 @@ void Boss01_Destroy(Actor* thisx, PlayState* play) {
* Checks every explosive actor to see if Odolwa is close enough to any of them. If he is, then he'll jump.
*/
void Boss01_JumpAwayFromExplosive(Boss01* this, PlayState* play) {
- Actor* explosive = play->actorCtx.actorLists[ACTORCAT_EXPLOSIVES].first;
+ Actor* explosive;
- while (explosive != NULL) {
+ for (explosive = play->actorCtx.actorLists[ACTORCAT_EXPLOSIVES].first; explosive != NULL;
+ explosive = explosive->next) {
if (sqrtf(SQ(explosive->world.pos.x - this->actor.world.pos.x) +
SQ(explosive->world.pos.y - this->actor.world.pos.y) +
SQ(explosive->world.pos.z - this->actor.world.pos.z)) < 150.0f) {
Boss01_SetupJump(this, play, false);
}
-
- explosive = explosive->next;
}
}
@@ -1224,7 +1223,7 @@ void Boss01_SummonBugsCutscene(Boss01* this, PlayState* play) {
pos.z = Rand_CenteredFloat(200.0f) + (this->actor.world.pos.z + offset.z);
Audio_PlaySfx(NA_SE_PL_DEKUNUTS_DROP_BOMB);
Actor_Spawn(&play->actorCtx, play, ACTOR_BOSS_01, pos.x, 1200.0f, pos.z, 0, Rand_ZeroFloat(0x10000),
- 0, ODOLWA_TYPE_BUG);
+ 0, ODOLWA_PARAMS(ODOLWA_TYPE_BUG));
}
}
@@ -1424,7 +1423,7 @@ void Boss01_Wait(Boss01* this, PlayState* play) {
case ODOLWA_WAIT_ARM_SWING_DANCE:
case ODOLWA_WAIT_THRUST_ATTACK:
Actor_Spawn(&play->actorCtx, play, ACTOR_BOSS_01, pos.x, pos.y, pos.z, 0, Rand_ZeroFloat(0x10000), 0,
- ODOLWA_TYPE_BUG);
+ ODOLWA_PARAMS(ODOLWA_TYPE_BUG));
break;
case ODOLWA_WAIT_SIDE_TO_SIDE_DANCE:
@@ -1906,9 +1905,9 @@ void Boss01_ShieldBash(Boss01* this, PlayState* play) {
* function will transition him to that state and start a 20 frame timer; when this timer reaches 0, he will recover and
* jump away. However, if he is already in the "damaged" state, and if the player attacked him with an attack that has
* the ODOLWA_DMGEFF_DAMAGE_TIMER_CHECK damage effect, then one of two things will happen:
- * - If the attack hit while his current action timer is 7 or more, the timer will be set to 20 again; this will keep
+ * - If the attack hit while his current action timer is 5 or more, the timer will be set to 20 again; this will keep
* Odolwa in the "damaged" state for longer and allow the player to attack him more.
- * - If the attack hit while his current action timer is 6 or less, Odolwa will disable all of his collision for 20
+ * - If the attack hit while his current action timer is 4 or less, Odolwa will disable all of his collision for 20
* frames to ensure that the player cannot hit him with subsequent attacks.
*/
void Boss01_SetupDamaged(Boss01* this, PlayState* play, u8 damageEffect) {
@@ -2150,8 +2149,8 @@ void Boss01_DeathCutscene(Boss01* this, PlayState* play) {
this->subCamAt.z = mainCam->at.z;
diffX = this->subCamEye.x - this->actor.world.pos.x;
diffZ = this->subCamEye.z - this->actor.world.pos.z;
- this->deathCsInitialSubCamRot = Math_Atan2F_XY(diffZ, diffX);
- this->deathCsSubCamRot = -0.5f;
+ this->deathCsInitialSubCamRotY = Math_Atan2F_XY(diffZ, diffX);
+ this->deathCsSubCamRotY = -0.5f;
FALLTHROUGH;
case ODOLWA_DEATH_CS_STATE_PLAY_ANIM_AND_FALL_FORWARD:
if (this->cutsceneTimer < 15) {
@@ -2170,11 +2169,11 @@ void Boss01_DeathCutscene(Boss01* this, PlayState* play) {
}
FALLTHROUGH;
case ODOLWA_DEATH_CS_STATE_BURST_INTO_FLAMES_AND_SHRINK:
- Math_ApproachF(&this->deathCsSubCamRot, 1.3f, 0.1f, 0.008f);
+ Math_ApproachF(&this->deathCsSubCamRotY, 1.3f, 0.1f, 0.008f);
subCamOffset.x = 0.0f;
subCamOffset.y = 30.0f;
subCamOffset.z = 300.0f;
- Matrix_RotateYF(this->deathCsInitialSubCamRot + this->deathCsSubCamRot, MTXMODE_NEW);
+ Matrix_RotateYF(this->deathCsInitialSubCamRotY + this->deathCsSubCamRotY, MTXMODE_NEW);
Matrix_MultVec3f(&subCamOffset, &this->subCamEyeNext);
this->subCamEyeNext.x += this->pelvisPos.x;
this->subCamEyeNext.y += this->pelvisPos.y;
@@ -2327,7 +2326,7 @@ void Boss01_Thaw(Boss01* this, PlayState* play) {
* Returns true if Odolwa's model is rotated such that he is looking at the player *and* if the player's model is
* rotated such that they are looking at Odolwa.
*/
-s32 Boss01_ArePlayerAndOdolwaFacing(Boss01* this, PlayState* play) {
+s32 Boss01_ArePlayerAndActorFacing(Boss01* this, PlayState* play) {
Player* player = GET_PLAYER(play);
if ((ABS_ALT(BINANG_SUB(this->actor.yawTowardsPlayer, this->actor.shape.rot.y)) < 0x3000) &&
@@ -2440,7 +2439,7 @@ void Boss01_Update(Actor* thisx, PlayState* play2) {
// normally evades attacks, so long as the player is far enough to the side or behind him.
if (this->canGuardOrEvade &&
((player->unk_D57 != 0) || ((player->unk_ADC != 0) && (this->actor.xzDistToPlayer <= 120.0f))) &&
- Boss01_ArePlayerAndOdolwaFacing(this, play)) {
+ Boss01_ArePlayerAndActorFacing(this, play)) {
if ((Rand_ZeroOne() < 0.25f) && (this->actionFunc != Boss01_Guard)) {
Boss01_SetupJump(this, play, false);
this->disableCollisionTimer = 10;
@@ -2458,10 +2457,10 @@ void Boss01_Update(Actor* thisx, PlayState* play2) {
if (((this->frameCounter & (this->afterimageSpawnFrameMask - 1)) == 0) && (this->afterimageSpawnFrameMask != 0)) {
s16 afterimageTimer = (this->actionFunc == Boss01_SpinAttack) ? 4 : 10;
s32 pad;
- Boss01* child =
- (Boss01*)Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_BOSS_01, this->actor.world.pos.x,
- this->actor.world.pos.y, this->actor.world.pos.z, this->actor.world.rot.x,
- this->actor.world.rot.y, afterimageTimer, ODOLWA_TYPE_AFTERIMAGE);
+ Boss01* child = (Boss01*)Actor_SpawnAsChild(
+ &play->actorCtx, &this->actor, play, ACTOR_BOSS_01, this->actor.world.pos.x, this->actor.world.pos.y,
+ this->actor.world.pos.z, this->actor.world.rot.x, this->actor.world.rot.y, afterimageTimer,
+ ODOLWA_PARAMS(ODOLWA_TYPE_AFTERIMAGE));
if (child != NULL) {
for (i = 0; i < ODOLWA_LIMB_MAX; i++) {
@@ -2804,22 +2803,22 @@ static s8 sLimbToBodyParts[] = {
void Boss01_PostLimbDraw(PlayState* play2, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx) {
Boss01* this = THIS;
PlayState* play = play2;
- s8 index;
+ s8 bodyPartIndex;
Vec3f pos;
if (limbIndex == ODOLWA_LIMB_HEAD) {
Matrix_MultZero(&this->actor.focus.pos);
}
- index = sLimbToBodyParts[limbIndex];
- if (index > BODYPART_NONE) {
- Matrix_MultZero(&this->bodyPartsPos[index]);
+ bodyPartIndex = sLimbToBodyParts[limbIndex];
+ if (bodyPartIndex > BODYPART_NONE) {
+ Matrix_MultZero(&this->bodyPartsPos[bodyPartIndex]);
}
- index = sLimbToColliderBodyParts[limbIndex];
- if (index > BODYPART_NONE) {
- Matrix_MultVec3f(&sLimbColliderOffsets[index], &pos);
- Boss01_SetColliderSphere(index, &this->bodyCollider, &pos);
+ bodyPartIndex = sLimbToColliderBodyParts[limbIndex];
+ if (bodyPartIndex > BODYPART_NONE) {
+ Matrix_MultVec3f(&sLimbColliderOffsets[bodyPartIndex], &pos);
+ Boss01_SetColliderSphere(bodyPartIndex, &this->bodyCollider, &pos);
}
if (limbIndex == ODOLWA_LIMB_PELVIS) {
@@ -3041,7 +3040,7 @@ void Boss01_FillShadowTex(Boss01* this, u8* tex, f32 weight) {
baseY = (u16)((s32)startVec.y * 64);
if (sShadowSizes[i] == ODOLWA_SHADOW_SIZE_EXTRA_LARGE) {
- for (y = 0, addY = -0x180; y < ARRAY_COUNT(sShadowExtraLargeMap); y++, addY += 0x40) {
+ for (y = 0, addY = -384; y < ARRAY_COUNT(sShadowExtraLargeMap); y++, addY += 64) {
for (x = -sShadowExtraLargeMap[y]; x < sShadowExtraLargeMap[y]; x++) {
index = baseX + x + baseY + addY;
if ((index >= 0) && (index < ODOLWA_SHADOW_TEX_SIZE)) {
@@ -3050,7 +3049,7 @@ void Boss01_FillShadowTex(Boss01* this, u8* tex, f32 weight) {
}
}
} else if (sShadowSizes[i] == ODOLWA_SHADOW_SIZE_LARGE) {
- for (y = 0, addY = -0x100; y < ARRAY_COUNT(sShadowLargeMap); y++, addY += 0x40) {
+ for (y = 0, addY = -256; y < ARRAY_COUNT(sShadowLargeMap); y++, addY += 64) {
for (x = -sShadowLargeMap[y]; x < sShadowLargeMap[y]; x++) {
index = baseX + x + baseY + addY;
if ((index >= 0) && (index < ODOLWA_SHADOW_TEX_SIZE)) {
@@ -3059,7 +3058,7 @@ void Boss01_FillShadowTex(Boss01* this, u8* tex, f32 weight) {
}
}
} else if (sShadowSizes[i] == ODOLWA_SHADOW_SIZE_MEDIUM) {
- for (y = 0, addY = -0xC0; y < ARRAY_COUNT(sShadowMediumMap); y++, addY += 0x40) {
+ for (y = 0, addY = -192; y < ARRAY_COUNT(sShadowMediumMap); y++, addY += 64) {
for (x = -sShadowMediumMap[y]; x < sShadowMediumMap[y] - 1; x++) {
index = baseX + x + baseY + addY;
if ((index >= 0) && (index < ODOLWA_SHADOW_TEX_SIZE)) {
@@ -3068,7 +3067,7 @@ void Boss01_FillShadowTex(Boss01* this, u8* tex, f32 weight) {
}
}
} else {
- for (y = 0, addY = -0x80; y < ARRAY_COUNT(sShadowSmallMap); y++, addY += 0x40) {
+ for (y = 0, addY = -128; y < ARRAY_COUNT(sShadowSmallMap); y++, addY += 64) {
for (x = -sShadowSmallMap[y]; x < sShadowSmallMap[y] - 1; x++) {
index = baseX + x + baseY + addY;
if ((index >= 0) && (index < ODOLWA_SHADOW_TEX_SIZE)) {
diff --git a/src/overlays/actors/ovl_Boss_01/z_boss_01.h b/src/overlays/actors/ovl_Boss_01/z_boss_01.h
index 68363208a9..9eb433cc2a 100644
--- a/src/overlays/actors/ovl_Boss_01/z_boss_01.h
+++ b/src/overlays/actors/ovl_Boss_01/z_boss_01.h
@@ -8,6 +8,7 @@ struct Boss01;
#define ODOLWA_GET_TYPE(thisx) ((thisx)->params)
#define ODOLWA_GET_AFTERIMAGE_DESPAWN_TIMER(thisx) ((thisx)->world.rot.z)
+#define ODOLWA_PARAMS(type) (type)
#define ODOLWA_SHADOW_TEX_WIDTH 64
#define ODOLWA_SHADOW_TEX_HEIGHT 64
@@ -85,7 +86,7 @@ typedef struct Boss01 {
/* 0x14E */ s16 timers[3];
/* 0x154 */ f32 animMorphFrames1;
/* 0x158 */ f32 animMorphFrames2;
- /* 0x15C */ s16 damagedTimer;
+ /* 0x15C */ s16 damagedTimer; // TODO: Revisit this name when the equivalent Player variables are named
/* 0x15E */ s16 damagedFlashTimer;
/* 0x160 */ u8 isPerformingVerticalSlash; // set, but never checked
/* 0x160 */ u8 landedFromJump;
@@ -133,8 +134,8 @@ typedef struct Boss01 {
/* 0x9F0 */ Vec3f subCamAt;
/* 0x9FC */ Vec3f subCamUp;
/* 0xA08 */ Vec3f subCamEyeNext;
- /* 0xA14 */ f32 deathCsInitialSubCamRot;
- /* 0xA18 */ f32 deathCsSubCamRot;
+ /* 0xA14 */ f32 deathCsInitialSubCamRotY;
+ /* 0xA18 */ f32 deathCsSubCamRotY;
/* 0xA1C */ f32 subCamVelocity;
/* 0xA20 */ f32 deathShrinkSpeed;
/* 0xA24 */ f32 screenShakeOffsetY;
diff --git a/src/overlays/actors/ovl_Boss_07/z_boss_07.c b/src/overlays/actors/ovl_Boss_07/z_boss_07.c
index b38cc72d2b..639543f867 100644
--- a/src/overlays/actors/ovl_Boss_07/z_boss_07.c
+++ b/src/overlays/actors/ovl_Boss_07/z_boss_07.c
@@ -2,236 +2,630 @@
* File: z_boss_07.c
* Overlay: ovl_Boss_07
* Description: Majora
+ *
+ * This actor is responsible for handling everything related to the final boss battle with Majora's Mask and its various
+ * forms. To be more specific, this actor handles the following things:
+ * - Majora's Mask, including the dynamically-moving tentacles
+ * - Majora's Incarnation
+ * - Majora's Wrath, including the dynamically-moving whips
+ * - The floating boss remains (Odolwa, Goht, Gyorg, and Twinmold) that fly around and attack the player
+ * - The projectiles that both the boss remains and Majora's Incarnation fire at the player
+ * - The spinning tops that Majora's Wrath can throw
+ * - The afterimages that follow Majora's Incarnation around as it runs
+ * - An invisible "battle handler" that updates the flame effects, manages the lens flare, handles the cutscene where
+ * the boss remains are activated, etc.
+ * - An invisible "battle initializer" that spawns Majora's Mask and the "battle handler", resets the effects, etc.
*/
+#include "prevent_bss_reordering.h"
#include "z_boss_07.h"
#include "z64shrink_window.h"
+#include "attributes.h"
+#include "assets/objects/gameplay_keep/gameplay_keep.h"
+#include "overlays/actors/ovl_En_Bom/z_en_bom.h"
+#include "overlays/actors/ovl_En_Clear_Tag/z_en_clear_tag.h"
+#include "overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.h"
+#include "overlays/effects/ovl_Effect_Ss_Hahen/z_eff_ss_hahen.h"
#define FLAGS (ACTOR_FLAG_ATTENTION_ENABLED | ACTOR_FLAG_HOSTILE | ACTOR_FLAG_10 | ACTOR_FLAG_20)
#define THIS ((Boss07*)thisx)
-void Boss07_Init(Actor* thisx, PlayState* play);
-void Boss07_Destroy(Actor* thisx, PlayState* play);
-void Boss07_Update(Actor* thisx, PlayState* play);
-void Boss07_Draw(Actor* thisx, PlayState* play);
+#define MAJORA_TENTACLE_COUNT 25
+#define MAJORA_WHIP_LENGTH 44
+#define MAJORA_EFFECT_COUNT 50
-void func_809F5E88(Boss07* this, PlayState* play);
-void func_809F65F4(Boss07* this, PlayState* play);
-void func_809F748C(Boss07* this, PlayState* play);
-void func_809F76D0(Boss07* this, PlayState* play);
-void func_809F77A8(Boss07* this, PlayState* play);
-void func_809F7968(Boss07* this, PlayState* play);
-void func_809F7BC4(Boss07* this, PlayState* play);
-void func_809F805C(Boss07* this, PlayState* play);
-void func_809F86B8(Boss07* this, PlayState* play);
-void func_809F87C8(Boss07* this, PlayState* play);
-void func_809F8908(Boss07* this, PlayState* play);
-void func_809F8B1C(Boss07* this, PlayState* play);
-void func_809F8D04(Boss07* this, PlayState* play);
-void func_809F8EC8(Boss07* this, PlayState* play);
-void func_809F91D4(Boss07* this, PlayState* play);
-void func_809FCCCC(Boss07* this, PlayState* play);
-void func_809FD710(Boss07* this, PlayState* play);
-void func_809FD89C(Boss07* this, PlayState* play);
-void func_809FDAB0(Boss07* this, PlayState* play);
-void func_809FDF54(Boss07* this, PlayState* play);
-void func_809FE0E4(Boss07* this, PlayState* play);
-void func_809FE348(Boss07* this, PlayState* play);
-void func_809FE524(Boss07* this, PlayState* play);
-void func_809FE734(Boss07* this, PlayState* play);
-void func_809FFA80(Boss07* this, PlayState* play);
-void func_809FFEAC(Boss07* this, PlayState* play);
-void func_80A00274(Boss07* this, PlayState* play);
-void func_80A00554(Boss07* this, PlayState* play);
-void func_80A00720(Boss07* this, PlayState* play);
-void func_80A01750(Boss07* this, PlayState* play);
-void func_80A0264C(Boss07* this, PlayState* play);
-void func_80A04890(Boss07* this, PlayState* play);
-void func_80A04E5C(Boss07* this, PlayState* play);
-void func_80A05608(Boss07* this, PlayState* play);
-void func_80A05B50(Boss07* this, PlayState* play);
-void func_80A05DDC(Boss07* this, PlayState* play);
+typedef struct MajoraEffect {
+ /* 0x00 */ u8 type;
+ /* 0x02 */ s16 texScroll;
+ /* 0x04 */ Vec3f pos;
+ /* 0x10 */ Vec3f velocity;
+ /* 0x1C */ Vec3f accel;
+ /* 0x28 */ UNK_TYPE1 unk28[4];
+ /* 0x2C */ s16 alpha;
+ /* 0x2E */ UNK_TYPE1 unk2E[2];
+ /* 0x30 */ s16 isFadingAway;
+ /* 0x34 */ f32 scale;
+ /* 0x38 */ UNK_TYPE1 unk38[0x10];
+} MajoraEffect; // size = 0x48
-#if 0
-// static DamageTable sDamageTable = {
-static DamageTable D_80A07980 = {
- /* Deku Nut */ DMG_ENTRY(0, 0x0),
- /* Deku Stick */ DMG_ENTRY(1, 0xF),
- /* Horse trample */ DMG_ENTRY(0, 0x0),
- /* Explosives */ DMG_ENTRY(2, 0xF),
- /* Zora boomerang */ DMG_ENTRY(1, 0xF),
- /* Normal arrow */ DMG_ENTRY(1, 0xF),
- /* UNK_DMG_0x06 */ DMG_ENTRY(0, 0x0),
- /* Hookshot */ DMG_ENTRY(0, 0x0),
- /* Goron punch */ DMG_ENTRY(1, 0xF),
- /* Sword */ DMG_ENTRY(1, 0xF),
- /* Goron pound */ DMG_ENTRY(1, 0xF),
- /* Fire arrow */ DMG_ENTRY(2, 0x2),
- /* Ice arrow */ DMG_ENTRY(2, 0x3),
- /* Light arrow */ DMG_ENTRY(2, 0x4),
- /* Goron spikes */ DMG_ENTRY(1, 0xF),
- /* Deku spin */ DMG_ENTRY(1, 0xF),
- /* Deku bubble */ DMG_ENTRY(1, 0xF),
- /* Deku launch */ DMG_ENTRY(1, 0xF),
- /* UNK_DMG_0x12 */ DMG_ENTRY(0, 0x0),
- /* Zora barrier */ DMG_ENTRY(0, 0x0),
- /* Normal shield */ DMG_ENTRY(0, 0x0),
- /* Light ray */ DMG_ENTRY(0, 0x0),
- /* Thrown object */ DMG_ENTRY(1, 0xF),
- /* Zora punch */ DMG_ENTRY(1, 0xF),
- /* Spin attack */ DMG_ENTRY(2, 0xF),
- /* Sword beam */ DMG_ENTRY(2, 0x9),
- /* Normal Roll */ DMG_ENTRY(0, 0x0),
- /* UNK_DMG_0x1B */ DMG_ENTRY(0, 0x0),
- /* UNK_DMG_0x1C */ DMG_ENTRY(0, 0x0),
- /* Unblockable */ DMG_ENTRY(0, 0x0),
- /* UNK_DMG_0x1E */ DMG_ENTRY(0, 0x0),
- /* Powder Keg */ DMG_ENTRY(2, 0xF),
+typedef enum MajorasWrathDamageEffect {
+ // Named because everything with this effect is ignored thanks to `CollisionCheck_SetATvsAC`.
+ /* 0x0 */ MAJORAS_WRATH_DMGEFF_IMMUNE,
+
+ // Stuns and surrounds Wrath with fire.
+ /* 0x2 */ MAJORAS_WRATH_DMGEFF_FIRE = 2,
+
+ // Stuns and surrounds Wrath with ice that shatters after a short time.
+ /* 0x3 */ MAJORAS_WRATH_DMGEFF_FREEZE,
+
+ // Stuns and surrounds Wrath with yellow light orbs.
+ /* 0x4 */ MAJORAS_WRATH_DMGEFF_LIGHT_ORB,
+
+ // Deals damage and surrounds Wrath with blue light orbs.
+ /* 0x9 */ MAJORAS_WRATH_DMGEFF_BLUE_LIGHT_ORB = 9,
+
+ // Stuns and surrounds Wrath with electric sparks.
+ /* 0xA */ MAJORAS_WRATH_DMGEFF_ELECTRIC_SPARKS,
+
+ // When an attack with this effect hits Wrath while it is either stunned or currently playing its damaged animation,
+ // it sets the `damagedTimer` to 15 frames, which is longer than the usual 5 frames.
+ /* 0xC */ MAJORAS_WRATH_DMGEFF_EXPLOSIVE = 0xC,
+
+ // Deals damage and has no special effect.
+ /* 0xD */ MAJORAS_WRATH_DMGEFF_DAMAGE_NONE,
+
+ // When an attack with this effect hits Wrath while it is currently playing its damaged animation, it checks to see
+ // if the attack landed within the last 4 frames of the animation. If so, it will restart Wrath's damaged animation.
+ // Otherwise, it will set the `disableCollisionTimer` to 30 frames.
+ /* 0xE */ MAJORAS_WRATH_DMGEFF_ANIM_FRAME_CHECK,
+
+ // Stuns and has no special effect.
+ /* 0xF */ MAJORAS_WRATH_DMGEFF_STUN_NONE
+} MajorasWrathDamageEffect;
+
+typedef enum MajorasIncarnationDamageEffect {
+ // Named because everything with this effect is ignored thanks to `CollisionCheck_SetATvsAC`.
+ /* 0x0 */ MAJORAS_INCARNATION_DMGEFF_IMMUNE,
+
+ // Deals damage and surrounds Incarnation with fire.
+ /* 0x2 */ MAJORAS_INCARNATION_DMGEFF_FIRE = 2,
+
+ // Deals damage and surrounds Incarnation with ice that shatters after a short time.
+ /* 0x3 */ MAJORAS_INCARNATION_DMGEFF_FREEZE,
+
+ // Deals damage and surrounds Incarnation with yellow light orbs.
+ /* 0x4 */ MAJORAS_INCARNATION_DMGEFF_LIGHT_ORB,
+
+ // Deals damage and surrounds Incarnation with blue light orbs.
+ /* 0x9 */ MAJORAS_INCARNATION_DMGEFF_BLUE_LIGHT_ORB = 9,
+
+ // Deals damage and surrounds Incarnation with electric sparks.
+ /* 0xA */ MAJORAS_INCARNATION_DMGEFF_ELECTRIC_SPARKS,
+
+ // When an attack with this effect hits Incarnation while it is either stunned or currently playing its damaged
+ // animation, it sets the `damagedTimer` to 15 frames, which is longer than the usual 5 frames.
+ /* 0xC */ MAJORAS_INCARNATION_DMGEFF_EXPLOSIVE = 0xC,
+
+ // Named after the only attack that uses it. Behaves exactly like `MAJORAS_INCARNATION_DMGEFF_NONE`.
+ /* 0xD */ MAJORAS_INCARNATION_DMGEFF_SPIN_ATTACK,
+
+ // When an attack with this effect hits Incarnation while it is currently playing its damaged animation, it checks
+ // to see if the attack landed within the last 4 frames of the animation. If so, it will restart Incarnation's
+ // damaged animation. Otherwise, it will set the `damagedTimer` and `disableCollisionTimer` to 30 frames.
+ /* 0xE */ MAJORAS_INCARNATION_DMGEFF_ANIM_FRAME_CHECK,
+
+ // Deals damage with no special effect.
+ /* 0xF */ MAJORAS_INCARNATION_DMGEFF_NONE
+} MajorasIncarnationDamageEffect;
+
+// All of these damage effects (except `MAJORAS_MASK_DMGEFF_IMMUNE`) behave in exactly the same way. Therefore, these
+// are all named based on the types of attacks that use them.
+typedef enum MajorasMaskDamageEffect {
+ // Named because everything with this effect is ignored thanks to `CollisionCheck_SetATvsAC`.
+ /* 0x0 */ MAJORAS_MASK_DMGEFF_IMMUNE,
+ /* 0x2 */ MAJORAS_MASK_DMGEFF_FIRE_ARROW = 2,
+ /* 0x3 */ MAJORAS_MASK_DMGEFF_ICE_ARROW,
+ /* 0x4 */ MAJORAS_MASK_DMGEFF_LIGHT_ARROW,
+ /* 0x9 */ MAJORAS_MASK_DMGEFF_SWORD_BEAM = 9,
+ /* 0xF */ MAJORAS_MASK_DMGEFF_DAMAGE = 0xF
+} MajorasMaskDamageEffect;
+
+// All of these damage effects (except `REMAINS_DMGEFF_IMMUNE`) behave in exactly the same way. Therefore, these are all
+// named based on the types of attacks that use them.
+typedef enum RemainsDamageEffect {
+ // Named because everything with this effect is ignored thanks to `CollisionCheck_SetATvsAC`.
+ /* 0x0 */ REMAINS_DMGEFF_IMMUNE,
+ /* 0x2 */ REMAINS_DMGEFF_FIRE_ARROW = 2,
+ /* 0x3 */ REMAINS_DMGEFF_ICE_ARROW,
+ /* 0x4 */ REMAINS_DMGEFF_LIGHT_ARROW,
+ /* 0x9 */ REMAINS_DMGEFF_SWORD_BEAM = 9,
+ /* 0xD */ REMAINS_DMGEFF_SPIN_ATTACK = 0xD,
+ /* 0xE */ REMAINS_DMGEFF_OTHER,
+ /* 0xF */ REMAINS_DMGEFF_DAMAGE
+} RemainsDamageEffect;
+
+typedef enum TopDamageEffect {
+ // Named because everything with this effect is ignored thanks to `CollisionCheck_SetATvsAC`.
+ /* 0x0 */ TOP_DMGEFF_IMMUNE,
+
+ // If an attack with this effect hits the top, the top's speed is set to -15. However, if the player is currently in
+ // Fierce Diety form when the attack lands, the speed will be set to -30, and the top will be bounced into the air.
+ /* 0xA */ TOP_DMGEFF_REVERSE_DIRECTION = 0xA,
+
+ // If an attack with this effect hits the top, the top is bounced into the air and knocked backwards away from the
+ // source of the damage.
+ /* 0xB */ TOP_DMGEFF_BOUNCE_BACK_FROM_DAMAGE,
+
+ // If an attack with this effect hits the top, the top is knocked backwards away from the player. The speed that the
+ // top is knocked backwards depends on the player's speed when the top is hit.
+ /* 0xC */ TOP_DMGEFF_KNOCKED_BACK_FROM_PLAYER,
+
+ // If an attack with this effect hits the top, the player is quickly pushed backwards.
+ /* 0xD */ TOP_DMGEFF_PUSH_BACK_PLAYER,
+
+ // If an attack with this effect hits the top, it will not react in any way.
+ /* 0xE */ TOP_DMGEFF_NO_REACTION_E,
+
+ // If an attack with this effect hits the top, it will not react in any way.
+ /* 0xF */ TOP_DMGEFF_NO_REACTION_F
+} TopDamageEffect;
+
+typedef enum MajoraEffectType {
+ /* 0 */ MAJORA_EFFECT_NONE,
+ /* 1 */ MAJORA_EFFECT_FLAME
+} MajoraEffectType;
+
+typedef enum MajorasWrathAttackSubAction {
+ /* 0 */ MAJORAS_WRATH_ATTACK_SUB_ACTION_QUICK_WHIP,
+ /* 1 */ MAJORAS_WRATH_ATTACK_SUB_ACTION_FLURRY,
+ /* 2 */ MAJORAS_WRATH_ATTACK_SUB_ACTION_DOUBLE_WHIP,
+ /* 3 */ MAJORAS_WRATH_ATTACK_SUB_ACTION_LONG_WHIP,
+ /* 4 */ MAJORAS_WRATH_ATTACK_SUB_ACTION_SPIN_ATTACK,
+ /* 5 */ MAJORAS_WRATH_ATTACK_SUB_ACTION_TAUNT,
+ /* 6 */ MAJORAS_WRATH_ATTACK_SUB_ACTION_THREE_HIT,
+ /* 7 */ MAJORAS_WRATH_ATTACK_SUB_ACTION_WHIP_ATTACK_MAX,
+ /* 7 */ MAJORAS_WRATH_ATTACK_SUB_ACTION_KICK = 7,
+} MajorasWrathAttackSubAction;
+
+typedef enum MajorasIncarnationTauntSubAction {
+ /* 0 */ MAJORAS_INCARNATION_TAUNT_SUB_ACTION_DANCE_1,
+ /* 1 */ MAJORAS_INCARNATION_TAUNT_SUB_ACTION_DANCE_2,
+ /* 2 */ MAJORAS_INCARNATION_TAUNT_SUB_ACTION_JUMP,
+ /* 3 */ MAJORAS_INCARNATION_TAUNT_SUB_ACTION_MAX
+} MajorasIncarnationTauntSubAction;
+
+typedef enum MajorasMaskSpinAttackSubAction {
+ /* 0 */ MAJORAS_MASK_SPIN_ATTACK_SUB_ACTION_WIND_UP,
+ /* 1 */ MAJORAS_MASK_SPIN_ATTACK_SUB_ACTION_ATTACK,
+ /* 2 */ MAJORAS_MASK_SPIN_ATTACK_SUB_ACTION_END,
+} MajorasMaskSpinAttackSubAction;
+
+typedef enum MajorasMaskFireBeamSubAction {
+ /* 0 */ MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_CHARGE_UP,
+ /* 1 */ MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_FIRE_EYE_BEAMS,
+ /* 2 */ MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_GROW_FOCUS_LIGHT_ORB,
+ /* 3 */ MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_BEAM_ACTIVE,
+ /* 4 */ MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_BEAM_REFLECTED,
+ /* 5 */ MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_END,
+ /* 6 */ MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_MAX
+} MajorasMaskFireBeamSubAction;
+
+typedef enum ProjectileSubAction {
+ /* 0 */ PROJECTILE_SUB_ACTION_SPAWN,
+ /* 1 */ PROJECTILE_SUB_ACTION_FLY,
+} ProjectileSubAction;
+
+typedef enum RemainsMoveSubAction {
+ /* 0 */ REMAINS_MOVE_SUB_ACTION_WAIT,
+ /* 1 */ REMAINS_MOVE_SUB_ACTION_FLY,
+ /* 2 */ REMAINS_MOVE_SUB_ACTION_DIE,
+ /* 3 */ REMAINS_MOVE_SUB_ACTION_DEAD,
+ /* 10 */ REMAINS_MOVE_SUB_ACTION_DAMAGED = 10,
+ /* 20 */ REMAINS_MOVE_SUB_ACTION_DETACH_FROM_WALL = 20
+} RemainsMoveSubAction;
+
+typedef enum RemainsIntroSubAction {
+ /* 0 */ REMAINS_INTRO_CS_SUB_ACTION_WAIT,
+ /* 1 */ REMAINS_INTRO_CS_SUB_ACTION_FLY,
+ /* 2 */ REMAINS_INTRO_CS_SUB_ACTION_ATTACH_WAIT,
+ /* 3 */ REMAINS_INTRO_CS_SUB_ACTION_ATTACH_TO_WALL
+} RemainsIntroSubAction;
+
+typedef enum TopMoveSubAction {
+ /* 0 */ TOP_MOVE_SUB_ACTION_AIRBORNE,
+ /* 1 */ TOP_MOVE_SUB_ACTION_GROUNDED,
+} TopMoveSubAction;
+
+typedef enum MajorasMaskIntroCsState {
+ /* 0 */ MAJORAS_MASK_INTRO_CS_STATE_WAITING_FOR_PLAYER_OR_DONE,
+ /* 1 */ MAJORAS_MASK_INTRO_CS_STATE_LOOK_AT_PLAYER,
+ /* 2 */ MAJORAS_MASK_INTRO_CS_STATE_REMAINS_ATTACH_TO_WALL,
+ /* 3 */ MAJORAS_MASK_INTRO_CS_STATE_WAKE_UP,
+ /* 4 */ MAJORAS_MASK_INTRO_CS_STATE_DETACH_FROM_WALL
+} MajorasMaskIntroCsState;
+
+typedef enum MajorasMaskDeathCsState {
+ /* 0 */ MAJORAS_MASK_DEATH_CS_STATE_STARTED,
+ /* 1 */ MAJORAS_MASK_DEATH_CS_STATE_PLAYING,
+ /* 2 */ MAJORAS_MASK_DEATH_CS_STATE_SPAWN_INCARNATION,
+} MajorasMaskDeathCsState;
+
+typedef enum MajorasIncarnationIntroCsState {
+ /* 0 */ MAJORAS_INCARNATION_INTRO_CS_STATE_STARTING_OR_DONE,
+ /* 1 */ MAJORAS_INCARNATION_INTRO_CS_STATE_UPDATE_SUBCAM,
+ /* 2 */ MAJORAS_INCARNATION_INTRO_CS_STATE_GROW_LEFT_LEG,
+ /* 3 */ MAJORAS_INCARNATION_INTRO_CS_STATE_GROW_OTHER_LIMBS,
+ /* 4 */ MAJORAS_INCARNATION_INTRO_CS_STATE_GROW_EYESTALK,
+ /* 5 */ MAJORAS_INCARNATION_INTRO_CS_STATE_DANCE
+} MajorasIncarnationIntroCsState;
+
+typedef enum MajorasIncarnationDeathCsState {
+ /* 0 */ MAJORAS_INCARNATION_DEATH_CS_STATE_STARTED,
+ /* 1 */ MAJORAS_INCARNATION_DEATH_CS_STATE_PLAY_FINAL_HIT_ANIM,
+ /* 2 */ MAJORAS_INCARNATION_DEATH_CS_STATE_PUMP_UP_RIGHT_ARM,
+ /* 3 */ MAJORAS_INCARNATION_DEATH_CS_STATE_PUMP_UP_LEFT_ARM,
+ /* 4 */ MAJORAS_INCARNATION_DEATH_CS_STATE_PUMP_UP_LEGS,
+ /* 10 */ MAJORAS_INCARNATION_DEATH_CS_STATE_PLAY_DAMAGED_ANIM = 10
+} MajorasIncarnationDeathCsState;
+
+typedef enum MajorasWrathIntroCsState {
+ /* 0 */ MAJORAS_WRATH_INTRO_CS_STATE_STARTING_OR_DONE,
+ /* 1 */ MAJORAS_WRATH_INTRO_CS_STATE_PLAYING
+} MajorasWrathIntroCsState;
+
+typedef enum MajorasWrathDeathCsState {
+ /* 0 */ MAJORAS_WRATH_DEATH_CS_STATE_STARTED,
+ /* 1 */ MAJORAS_WRATH_DEATH_CS_STATE_UPDATE_SUBCAM,
+ /* 2 */ MAJORAS_WRATH_DEATH_CS_STATE_SPIN_AROUND,
+ /* 4 */ MAJORAS_WRATH_DEATH_CS_STATE_FLOAT = 4
+} MajorasWrathDeathCsState;
+
+typedef enum MajorasWrathShadowSize {
+ /* 0 */ MAJORAS_WRATH_SHADOW_SIZE_MEDIUM,
+ /* 1 */ MAJORAS_WRATH_SHADOW_SIZE_LARGE,
+ /* 2 */ MAJORAS_WRATH_SHADOW_SIZE_EXTRA_LARGE,
+ /* 3 */ MAJORAS_WRATH_SHADOW_SIZE_SMALL
+} MajorasWrathShadowSize;
+
+typedef enum MajoraDrawDmgEffState {
+ /* 0 */ MAJORA_DRAW_DMGEFF_STATE_NONE,
+ /* 1 */ MAJORA_DRAW_DMGEFF_STATE_FIRE_INIT,
+ /* 2 */ MAJORA_DRAW_DMGEFF_STATE_FIRE_ACTIVE,
+ /* 10 */ MAJORA_DRAW_DMGEFF_STATE_FROZEN_INIT = 10,
+ /* 11 */ MAJORA_DRAW_DMGEFF_STATE_FROZEN_ACTIVE,
+ /* 20 */ MAJORA_DRAW_DMGEFF_STATE_LIGHT_ORB_INIT = 20,
+ /* 21 */ MAJORA_DRAW_DMGEFF_STATE_LIGHT_ORB_ACTIVE,
+ /* 30 */ MAJORA_DRAW_DMGEFF_STATE_BLUE_LIGHT_ORB_INIT = 30,
+ /* 40 */ MAJORA_DRAW_DMGEFF_STATE_ELECTRIC_SPARKS_INIT = 40,
+ /* 41 */ MAJORA_DRAW_DMGEFF_STATE_ELECTRIC_SPARKS_ACTIVE
+} MajoraDrawDmgEffState;
+
+typedef enum BattleHandlerRemainsCsState {
+ /* 0 */ BATTLE_HANDLER_REMAINS_CS_STATE_WAITING_FOR_MAJORAS_MASK,
+ /* 1 */ BATTLE_HANDLER_REMAINS_CS_STATE_STARTED,
+ /* 2 */ BATTLE_HANDLER_REMAINS_CS_STATE_ACTIVATE_ODOLWA,
+ /* 3 */ BATTLE_HANDLER_REMAINS_CS_STATE_ACTIVATE_GYORG,
+ /* 4 */ BATTLE_HANDLER_REMAINS_CS_STATE_ACTIVATE_GOHT,
+ /* 5 */ BATTLE_HANDLER_REMAINS_CS_STATE_ACTIVATE_TWINMOLD,
+ /* 6 */ BATTLE_HANDLER_REMAINS_CS_STATE_DONE
+} BattleHandlerRemainsCsState;
+
+typedef enum MajorasMaskTentacleState {
+ /* 0 */ MAJORAS_MASK_TENTACLE_STATE_DEFAULT,
+ /* 1 */ MAJORAS_MASK_TENTACLE_STATE_FIRING_BEAM,
+ /* 2 */ MAJORAS_MASK_TENTACLE_STATE_DEATH
+} MajorasMaskTentacleState;
+
+typedef enum MajorasMaskSpinAttackRetargetState {
+ // The mask targets a random position at least 100 units off the ground, making it hard to hit the player.
+ /* 0 */ MAJORAS_MASK_SPIN_ATTACK_RETARGET_PASSIVE,
+
+ // The mask targets a point 10 units above the player's current position for up to 20 frames.
+ /* 1 */ MAJORAS_MASK_SPIN_ATTACK_RETARGET_ACTIVE,
+} MajorasMaskSpinAttackRetargetState;
+
+typedef enum MajorasMaskEyeTexture {
+ /* 0 */ MAJORAS_MASK_EYE_NORMAL,
+ /* 1 */ MAJORAS_MASK_EYE_DULL
+} MajorasMaskEyeTexture;
+
+typedef enum MajorasIncarnationDustSpawnPos {
+ /* 0 */ MAJORAS_INCARNATION_DUST_SPAWN_POS_FEET,
+ /* 1 */ MAJORAS_INCARNATION_DUST_SPAWN_POS_FOCUS
+} MajorasIncarnationDustSpawnPos;
+
+typedef enum MajorasIncarnationLimbPumpState {
+ /* 0 */ MAJORAS_INCARNATION_LIMB_PUMP_STATE_NONE,
+ /* 1 */ MAJORAS_INCARNATION_LIMB_PUMP_STATE_ARMS,
+ /* 2 */ MAJORAS_INCARNATION_LIMB_PUMP_STATE_LEGS
+} MajorasIncarnationLimbPumpState;
+
+typedef enum MajorasWrathHand {
+ /* 0 */ MAJORAS_WRATH_HAND_RIGHT,
+ /* 1 */ MAJORAS_WRATH_HAND_LEFT
+} MajorasWrathHand;
+
+void Boss07_Init(Actor* thisx, PlayState* play2);
+void Boss07_Destroy(Actor* thisx, PlayState* play2);
+
+void Boss07_Wrath_Update(Actor* thisx, PlayState* play2);
+void Boss07_IncarnationAfterimage_Update(Actor* thisx, PlayState* play2);
+void Boss07_Incarnation_Update(Actor* thisx, PlayState* play2);
+void Boss07_Mask_Update(Actor* thisx, PlayState* play2);
+void Boss07_Projectile_Update(Actor* thisx, PlayState* play2);
+void Boss07_Remains_Update(Actor* thisx, PlayState* play2);
+void Boss07_Top_Update(Actor* thisx, PlayState* play2);
+void Boss07_BattleHandler_Update(Actor* thisx, PlayState* play2);
+
+void Boss07_Wrath_Draw(Actor* thisx, PlayState* play2);
+void Boss07_IncarnationAfterimage_Draw(Actor* thisx, PlayState* play2);
+void Boss07_Incarnation_Draw(Actor* thisx, PlayState* play2);
+void Boss07_Mask_Draw(Actor* thisx, PlayState* play2);
+void Boss07_Projectile_Draw(Actor* thisx, PlayState* play2);
+void Boss07_Remains_Draw(Actor* thisx, PlayState* play2);
+void Boss07_Top_Draw(Actor* thisx, PlayState* play2);
+void Boss07_BattleHandler_Draw(Actor* thisx, PlayState* play2);
+
+void Boss07_Wrath_SetupIntroCutscene(Boss07* this, PlayState* play);
+void Boss07_Wrath_IntroCutscene(Boss07* this, PlayState* play);
+void Boss07_Wrath_DeathCutscene(Boss07* this, PlayState* play);
+void Boss07_Wrath_SetupIdle(Boss07* this, PlayState* play, s16 idleTimer);
+void Boss07_Wrath_Idle(Boss07* this, PlayState* play);
+void Boss07_Wrath_SetupJump(Boss07* this, PlayState* play);
+void Boss07_Wrath_StartJump(Boss07* this, PlayState* play);
+void Boss07_Wrath_Jump(Boss07* this, PlayState* play);
+void Boss07_Wrath_SetupFlip(Boss07* this, PlayState* play);
+void Boss07_Wrath_Flip(Boss07* this, PlayState* play);
+void Boss07_Wrath_Sidestep(Boss07* this, PlayState* play);
+void Boss07_Wrath_SetupAttack(Boss07* this, PlayState* play);
+void Boss07_Wrath_Attack(Boss07* this, PlayState* play);
+void Boss07_Wrath_SetupTryGrab(Boss07* this, PlayState* play);
+void Boss07_Wrath_TryGrab(Boss07* this, PlayState* play);
+void Boss07_Wrath_ThrowPlayer(Boss07* this, PlayState* play);
+void Boss07_Wrath_SetupShock(Boss07* this, PlayState* play);
+void Boss07_Wrath_ShockWhip(Boss07* this, PlayState* play);
+void Boss07_Wrath_ShockStunned(Boss07* this, PlayState* play);
+void Boss07_Wrath_SetupThrowTop(Boss07* this, PlayState* play);
+void Boss07_Wrath_ThrowTop(Boss07* this, PlayState* play);
+void Boss07_Wrath_Stunned(Boss07* this, PlayState* play);
+void Boss07_Wrath_Damaged(Boss07* this, PlayState* play);
+void Boss07_Wrath_GenShadowTex(u8* tex, Boss07* this, PlayState* play);
+void Boss07_Wrath_DrawShadowTex(u8* tex, Boss07* this, PlayState* play);
+
+void Boss07_Incarnation_SetupIntroCutscene(Boss07* this, PlayState* play);
+void Boss07_Incarnation_IntroCutscene(Boss07* this, PlayState* play);
+void Boss07_Incarnation_SetupTaunt(Boss07* this, PlayState* play);
+void Boss07_Incarnation_Taunt(Boss07* this, PlayState* play);
+void Boss07_Incarnation_Stunned(Boss07* this, PlayState* play);
+void Boss07_Incarnation_Damaged(Boss07* this, PlayState* play);
+void Boss07_Incarnation_SetupRun(Boss07* this, PlayState* play);
+void Boss07_Incarnation_Run(Boss07* this, PlayState* play);
+void Boss07_Incarnation_SetupAttack(Boss07* this, PlayState* play);
+void Boss07_Incarnation_Attack(Boss07* this, PlayState* play);
+void Boss07_Incarnation_SetupSquattingDance(Boss07* this, PlayState* play);
+void Boss07_Incarnation_SquattingDance(Boss07* this, PlayState* play);
+void Boss07_Incarnation_SetupMoonwalk(Boss07* this, PlayState* play);
+void Boss07_Incarnation_Moonwalk(Boss07* this, PlayState* play);
+void Boss07_Incarnation_SetupPirouette(Boss07* this, PlayState* play);
+void Boss07_Incarnation_Pirouette(Boss07* this, PlayState* play);
+void Boss07_Incarnation_DeathCutscene(Boss07* this, PlayState* play);
+
+void Boss07_Mask_SetupIdle(Boss07* this, PlayState* play);
+void Boss07_Mask_Idle(Boss07* this, PlayState* play);
+void Boss07_Mask_SetupSpinAttack(Boss07* this, PlayState* play);
+void Boss07_Mask_SpinAttack(Boss07* this, PlayState* play);
+void Boss07_Mask_Stunned(Boss07* this, PlayState* play);
+void Boss07_Mask_Damaged(Boss07* this, PlayState* play);
+void Boss07_Mask_SetupFireBeam(Boss07* this, PlayState* play);
+void Boss07_Mask_FireBeam(Boss07* this, PlayState* play);
+void Boss07_Mask_SetupIntroCutscene(Boss07* this, PlayState* play);
+void Boss07_Mask_IntroCutscene(Boss07* this, PlayState* play);
+void Boss07_Mask_SetupDeathCutscene(Boss07* this, PlayState* play);
+void Boss07_Mask_DeathCutscene(Boss07* this, PlayState* play);
+
+void Boss07_Remains_SetupIntroCutscene(Boss07* this, PlayState* play);
+void Boss07_Remains_IntroCutscene(Boss07* this, PlayState* play);
+void Boss07_Remains_SetupMove(Boss07* this, PlayState* play);
+void Boss07_Remains_Move(Boss07* this, PlayState* play);
+void Boss07_Remains_SetupStunned(Boss07* this, PlayState* play);
+void Boss07_Remains_Stunned(Boss07* this, PlayState* play);
+
+void Boss07_Top_SetupThrown(Boss07* this, PlayState* play);
+void Boss07_Top_Thrown(Boss07* this, PlayState* play);
+void Boss07_Top_SetupMove(Boss07* this, PlayState* play);
+void Boss07_Top_Move(Boss07* this, PlayState* play);
+
+void Boss07_BattleHandler_UpdateEffects(PlayState* play);
+void Boss07_BattleHandler_DrawEffects(PlayState* play);
+
+static s16 sProjectileEnvColors[4][3] = {
+ { 255, 255, 100 },
+ { 255, 100, 100 },
+ { 100, 255, 100 },
+ { 100, 100, 255 },
};
-// static DamageTable sDamageTable = {
-static DamageTable D_80A079A0 = {
- /* Deku Nut */ DMG_ENTRY(0, 0x0),
- /* Deku Stick */ DMG_ENTRY(1, 0xF),
- /* Horse trample */ DMG_ENTRY(0, 0x0),
- /* Explosives */ DMG_ENTRY(1, 0xC),
- /* Zora boomerang */ DMG_ENTRY(1, 0xF),
- /* Normal arrow */ DMG_ENTRY(1, 0xF),
- /* UNK_DMG_0x06 */ DMG_ENTRY(0, 0x0),
- /* Hookshot */ DMG_ENTRY(0, 0x0),
- /* Goron punch */ DMG_ENTRY(1, 0xE),
- /* Sword */ DMG_ENTRY(1, 0xE),
- /* Goron pound */ DMG_ENTRY(1, 0xF),
- /* Fire arrow */ DMG_ENTRY(2, 0x2),
- /* Ice arrow */ DMG_ENTRY(2, 0x3),
- /* Light arrow */ DMG_ENTRY(2, 0x4),
- /* Goron spikes */ DMG_ENTRY(1, 0xF),
- /* Deku spin */ DMG_ENTRY(1, 0xF),
- /* Deku bubble */ DMG_ENTRY(1, 0xF),
- /* Deku launch */ DMG_ENTRY(1, 0xF),
- /* UNK_DMG_0x12 */ DMG_ENTRY(0, 0x0),
- /* Zora barrier */ DMG_ENTRY(0, 0xA),
- /* Normal shield */ DMG_ENTRY(0, 0x0),
- /* Light ray */ DMG_ENTRY(0, 0x0),
- /* Thrown object */ DMG_ENTRY(1, 0xF),
- /* Zora punch */ DMG_ENTRY(1, 0xF),
- /* Spin attack */ DMG_ENTRY(1, 0xD),
- /* Sword beam */ DMG_ENTRY(2, 0x9),
- /* Normal Roll */ DMG_ENTRY(0, 0x0),
- /* UNK_DMG_0x1B */ DMG_ENTRY(0, 0x0),
- /* UNK_DMG_0x1C */ DMG_ENTRY(0, 0x0),
- /* Unblockable */ DMG_ENTRY(0, 0x0),
- /* UNK_DMG_0x1E */ DMG_ENTRY(0, 0x0),
- /* Powder Keg */ DMG_ENTRY(4, 0xC),
+static s16 sProjectilePrimColors[4][3] = {
+ { 255, 255, 255 },
+ { 255, 255, 255 },
+ { 255, 255, 255 },
+ { 255, 255, 255 },
};
-// static DamageTable sDamageTable = {
-static DamageTable D_80A079C0 = {
- /* Deku Nut */ DMG_ENTRY(0, 0x0),
- /* Deku Stick */ DMG_ENTRY(1, 0xE),
- /* Horse trample */ DMG_ENTRY(0, 0x0),
- /* Explosives */ DMG_ENTRY(1, 0xC),
- /* Zora boomerang */ DMG_ENTRY(1, 0xF),
- /* Normal arrow */ DMG_ENTRY(1, 0xF),
- /* UNK_DMG_0x06 */ DMG_ENTRY(0, 0x0),
- /* Hookshot */ DMG_ENTRY(0, 0x0),
- /* Goron punch */ DMG_ENTRY(1, 0xE),
- /* Sword */ DMG_ENTRY(1, 0xE),
- /* Goron pound */ DMG_ENTRY(1, 0xF),
- /* Fire arrow */ DMG_ENTRY(2, 0x2),
- /* Ice arrow */ DMG_ENTRY(2, 0x3),
- /* Light arrow */ DMG_ENTRY(2, 0x4),
- /* Goron spikes */ DMG_ENTRY(1, 0xE),
- /* Deku spin */ DMG_ENTRY(1, 0xE),
- /* Deku bubble */ DMG_ENTRY(1, 0xF),
- /* Deku launch */ DMG_ENTRY(1, 0xE),
- /* UNK_DMG_0x12 */ DMG_ENTRY(0, 0x0),
- /* Zora barrier */ DMG_ENTRY(0, 0xA),
- /* Normal shield */ DMG_ENTRY(0, 0x0),
- /* Light ray */ DMG_ENTRY(0, 0x0),
- /* Thrown object */ DMG_ENTRY(1, 0xF),
- /* Zora punch */ DMG_ENTRY(1, 0xE),
- /* Spin attack */ DMG_ENTRY(1, 0xD),
- /* Sword beam */ DMG_ENTRY(2, 0x9),
- /* Normal Roll */ DMG_ENTRY(0, 0x0),
- /* UNK_DMG_0x1B */ DMG_ENTRY(0, 0x0),
- /* UNK_DMG_0x1C */ DMG_ENTRY(0, 0x0),
- /* Unblockable */ DMG_ENTRY(0, 0x0),
- /* UNK_DMG_0x1E */ DMG_ENTRY(0, 0x0),
- /* Powder Keg */ DMG_ENTRY(2, 0xC),
+static DamageTable sMajorasMaskDamageTable = {
+ /* Deku Nut */ DMG_ENTRY(0, MAJORAS_MASK_DMGEFF_IMMUNE),
+ /* Deku Stick */ DMG_ENTRY(1, MAJORAS_MASK_DMGEFF_DAMAGE),
+ /* Horse trample */ DMG_ENTRY(0, MAJORAS_MASK_DMGEFF_IMMUNE),
+ /* Explosives */ DMG_ENTRY(2, MAJORAS_MASK_DMGEFF_DAMAGE),
+ /* Zora boomerang */ DMG_ENTRY(1, MAJORAS_MASK_DMGEFF_DAMAGE),
+ /* Normal arrow */ DMG_ENTRY(1, MAJORAS_MASK_DMGEFF_DAMAGE),
+ /* UNK_DMG_0x06 */ DMG_ENTRY(0, MAJORAS_MASK_DMGEFF_IMMUNE),
+ /* Hookshot */ DMG_ENTRY(0, MAJORAS_MASK_DMGEFF_IMMUNE),
+ /* Goron punch */ DMG_ENTRY(1, MAJORAS_MASK_DMGEFF_DAMAGE),
+ /* Sword */ DMG_ENTRY(1, MAJORAS_MASK_DMGEFF_DAMAGE),
+ /* Goron pound */ DMG_ENTRY(1, MAJORAS_MASK_DMGEFF_DAMAGE),
+ /* Fire arrow */ DMG_ENTRY(2, MAJORAS_MASK_DMGEFF_FIRE_ARROW),
+ /* Ice arrow */ DMG_ENTRY(2, MAJORAS_MASK_DMGEFF_ICE_ARROW),
+ /* Light arrow */ DMG_ENTRY(2, MAJORAS_MASK_DMGEFF_LIGHT_ARROW),
+ /* Goron spikes */ DMG_ENTRY(1, MAJORAS_MASK_DMGEFF_DAMAGE),
+ /* Deku spin */ DMG_ENTRY(1, MAJORAS_MASK_DMGEFF_DAMAGE),
+ /* Deku bubble */ DMG_ENTRY(1, MAJORAS_MASK_DMGEFF_DAMAGE),
+ /* Deku launch */ DMG_ENTRY(1, MAJORAS_MASK_DMGEFF_DAMAGE),
+ /* UNK_DMG_0x12 */ DMG_ENTRY(0, MAJORAS_MASK_DMGEFF_IMMUNE),
+ /* Zora barrier */ DMG_ENTRY(0, MAJORAS_MASK_DMGEFF_IMMUNE),
+ /* Normal shield */ DMG_ENTRY(0, MAJORAS_MASK_DMGEFF_IMMUNE),
+ /* Light ray */ DMG_ENTRY(0, MAJORAS_MASK_DMGEFF_IMMUNE),
+ /* Thrown object */ DMG_ENTRY(1, MAJORAS_MASK_DMGEFF_DAMAGE),
+ /* Zora punch */ DMG_ENTRY(1, MAJORAS_MASK_DMGEFF_DAMAGE),
+ /* Spin attack */ DMG_ENTRY(2, MAJORAS_MASK_DMGEFF_DAMAGE),
+ /* Sword beam */ DMG_ENTRY(2, MAJORAS_MASK_DMGEFF_SWORD_BEAM),
+ /* Normal Roll */ DMG_ENTRY(0, MAJORAS_MASK_DMGEFF_IMMUNE),
+ /* UNK_DMG_0x1B */ DMG_ENTRY(0, MAJORAS_MASK_DMGEFF_IMMUNE),
+ /* UNK_DMG_0x1C */ DMG_ENTRY(0, MAJORAS_MASK_DMGEFF_IMMUNE),
+ /* Unblockable */ DMG_ENTRY(0, MAJORAS_MASK_DMGEFF_IMMUNE),
+ /* UNK_DMG_0x1E */ DMG_ENTRY(0, MAJORAS_MASK_DMGEFF_IMMUNE),
+ /* Powder Keg */ DMG_ENTRY(2, MAJORAS_MASK_DMGEFF_DAMAGE),
};
-// static DamageTable sDamageTable = {
-static DamageTable D_80A079E0 = {
- /* Deku Nut */ DMG_ENTRY(0, 0x0),
- /* Deku Stick */ DMG_ENTRY(1, 0xF),
- /* Horse trample */ DMG_ENTRY(0, 0x0),
- /* Explosives */ DMG_ENTRY(2, 0xE),
- /* Zora boomerang */ DMG_ENTRY(1, 0xF),
- /* Normal arrow */ DMG_ENTRY(1, 0xF),
- /* UNK_DMG_0x06 */ DMG_ENTRY(0, 0x0),
- /* Hookshot */ DMG_ENTRY(0, 0x0),
- /* Goron punch */ DMG_ENTRY(1, 0xE),
- /* Sword */ DMG_ENTRY(1, 0xE),
- /* Goron pound */ DMG_ENTRY(1, 0xF),
- /* Fire arrow */ DMG_ENTRY(2, 0x2),
- /* Ice arrow */ DMG_ENTRY(2, 0x3),
- /* Light arrow */ DMG_ENTRY(2, 0x4),
- /* Goron spikes */ DMG_ENTRY(1, 0xF),
- /* Deku spin */ DMG_ENTRY(1, 0xF),
- /* Deku bubble */ DMG_ENTRY(1, 0xF),
- /* Deku launch */ DMG_ENTRY(1, 0xF),
- /* UNK_DMG_0x12 */ DMG_ENTRY(0, 0x0),
- /* Zora barrier */ DMG_ENTRY(0, 0x0),
- /* Normal shield */ DMG_ENTRY(0, 0x0),
- /* Light ray */ DMG_ENTRY(0, 0x0),
- /* Thrown object */ DMG_ENTRY(1, 0xF),
- /* Zora punch */ DMG_ENTRY(1, 0xF),
- /* Spin attack */ DMG_ENTRY(1, 0xD),
- /* Sword beam */ DMG_ENTRY(2, 0x9),
- /* Normal Roll */ DMG_ENTRY(0, 0x0),
- /* UNK_DMG_0x1B */ DMG_ENTRY(0, 0x0),
- /* UNK_DMG_0x1C */ DMG_ENTRY(0, 0x0),
- /* Unblockable */ DMG_ENTRY(0, 0x0),
- /* UNK_DMG_0x1E */ DMG_ENTRY(0, 0x0),
- /* Powder Keg */ DMG_ENTRY(2, 0xE),
+static DamageTable sMajorasIncarnationDamageTable = {
+ /* Deku Nut */ DMG_ENTRY(0, MAJORAS_INCARNATION_DMGEFF_IMMUNE),
+ /* Deku Stick */ DMG_ENTRY(1, MAJORAS_INCARNATION_DMGEFF_NONE),
+ /* Horse trample */ DMG_ENTRY(0, MAJORAS_INCARNATION_DMGEFF_IMMUNE),
+ /* Explosives */ DMG_ENTRY(1, MAJORAS_INCARNATION_DMGEFF_EXPLOSIVE),
+ /* Zora boomerang */ DMG_ENTRY(1, MAJORAS_INCARNATION_DMGEFF_NONE),
+ /* Normal arrow */ DMG_ENTRY(1, MAJORAS_INCARNATION_DMGEFF_NONE),
+ /* UNK_DMG_0x06 */ DMG_ENTRY(0, MAJORAS_INCARNATION_DMGEFF_IMMUNE),
+ /* Hookshot */ DMG_ENTRY(0, MAJORAS_INCARNATION_DMGEFF_IMMUNE),
+ /* Goron punch */ DMG_ENTRY(1, MAJORAS_INCARNATION_DMGEFF_ANIM_FRAME_CHECK),
+ /* Sword */ DMG_ENTRY(1, MAJORAS_INCARNATION_DMGEFF_ANIM_FRAME_CHECK),
+ /* Goron pound */ DMG_ENTRY(1, MAJORAS_INCARNATION_DMGEFF_NONE),
+ /* Fire arrow */ DMG_ENTRY(2, MAJORAS_INCARNATION_DMGEFF_FIRE),
+ /* Ice arrow */ DMG_ENTRY(2, MAJORAS_INCARNATION_DMGEFF_FREEZE),
+ /* Light arrow */ DMG_ENTRY(2, MAJORAS_INCARNATION_DMGEFF_LIGHT_ORB),
+ /* Goron spikes */ DMG_ENTRY(1, MAJORAS_INCARNATION_DMGEFF_NONE),
+ /* Deku spin */ DMG_ENTRY(1, MAJORAS_INCARNATION_DMGEFF_NONE),
+ /* Deku bubble */ DMG_ENTRY(1, MAJORAS_INCARNATION_DMGEFF_NONE),
+ /* Deku launch */ DMG_ENTRY(1, MAJORAS_INCARNATION_DMGEFF_NONE),
+ /* UNK_DMG_0x12 */ DMG_ENTRY(0, MAJORAS_INCARNATION_DMGEFF_IMMUNE),
+ /* Zora barrier */ DMG_ENTRY(0, MAJORAS_INCARNATION_DMGEFF_ELECTRIC_SPARKS),
+ /* Normal shield */ DMG_ENTRY(0, MAJORAS_INCARNATION_DMGEFF_IMMUNE),
+ /* Light ray */ DMG_ENTRY(0, MAJORAS_INCARNATION_DMGEFF_IMMUNE),
+ /* Thrown object */ DMG_ENTRY(1, MAJORAS_INCARNATION_DMGEFF_NONE),
+ /* Zora punch */ DMG_ENTRY(1, MAJORAS_INCARNATION_DMGEFF_NONE),
+ /* Spin attack */ DMG_ENTRY(1, MAJORAS_INCARNATION_DMGEFF_SPIN_ATTACK),
+ /* Sword beam */ DMG_ENTRY(2, MAJORAS_INCARNATION_DMGEFF_BLUE_LIGHT_ORB),
+ /* Normal Roll */ DMG_ENTRY(0, MAJORAS_INCARNATION_DMGEFF_IMMUNE),
+ /* UNK_DMG_0x1B */ DMG_ENTRY(0, MAJORAS_INCARNATION_DMGEFF_IMMUNE),
+ /* UNK_DMG_0x1C */ DMG_ENTRY(0, MAJORAS_INCARNATION_DMGEFF_IMMUNE),
+ /* Unblockable */ DMG_ENTRY(0, MAJORAS_INCARNATION_DMGEFF_IMMUNE),
+ /* UNK_DMG_0x1E */ DMG_ENTRY(0, MAJORAS_INCARNATION_DMGEFF_IMMUNE),
+ /* Powder Keg */ DMG_ENTRY(4, MAJORAS_INCARNATION_DMGEFF_EXPLOSIVE),
};
-// static DamageTable sDamageTable = {
-static DamageTable D_80A07A00 = {
- /* Deku Nut */ DMG_ENTRY(0, 0x0),
- /* Deku Stick */ DMG_ENTRY(1, 0xD),
- /* Horse trample */ DMG_ENTRY(1, 0xE),
- /* Explosives */ DMG_ENTRY(1, 0xB),
- /* Zora boomerang */ DMG_ENTRY(1, 0xF),
- /* Normal arrow */ DMG_ENTRY(1, 0xF),
- /* UNK_DMG_0x06 */ DMG_ENTRY(0, 0x0),
- /* Hookshot */ DMG_ENTRY(1, 0xE),
- /* Goron punch */ DMG_ENTRY(1, 0xE),
- /* Sword */ DMG_ENTRY(1, 0xD),
- /* Goron pound */ DMG_ENTRY(0, 0x0),
- /* Fire arrow */ DMG_ENTRY(1, 0xE),
- /* Ice arrow */ DMG_ENTRY(1, 0xE),
- /* Light arrow */ DMG_ENTRY(1, 0xE),
- /* Goron spikes */ DMG_ENTRY(1, 0xC),
- /* Deku spin */ DMG_ENTRY(1, 0xF),
- /* Deku bubble */ DMG_ENTRY(1, 0xF),
- /* Deku launch */ DMG_ENTRY(1, 0xF),
- /* UNK_DMG_0x12 */ DMG_ENTRY(0, 0x0),
- /* Zora barrier */ DMG_ENTRY(0, 0x0),
- /* Normal shield */ DMG_ENTRY(1, 0xD),
- /* Light ray */ DMG_ENTRY(1, 0xD),
- /* Thrown object */ DMG_ENTRY(1, 0xE),
- /* Zora punch */ DMG_ENTRY(1, 0xE),
- /* Spin attack */ DMG_ENTRY(1, 0xA),
- /* Sword beam */ DMG_ENTRY(1, 0xA),
- /* Normal Roll */ DMG_ENTRY(0, 0x0),
- /* UNK_DMG_0x1B */ DMG_ENTRY(0, 0x0),
- /* UNK_DMG_0x1C */ DMG_ENTRY(0, 0x0),
- /* Unblockable */ DMG_ENTRY(0, 0x0),
- /* UNK_DMG_0x1E */ DMG_ENTRY(0, 0x0),
- /* Powder Keg */ DMG_ENTRY(2, 0xB),
+static DamageTable sMajorasWrathDamageTable = {
+ /* Deku Nut */ DMG_ENTRY(0, MAJORAS_WRATH_DMGEFF_IMMUNE),
+ /* Deku Stick */ DMG_ENTRY(1, MAJORAS_WRATH_DMGEFF_ANIM_FRAME_CHECK),
+ /* Horse trample */ DMG_ENTRY(0, MAJORAS_WRATH_DMGEFF_IMMUNE),
+ /* Explosives */ DMG_ENTRY(1, MAJORAS_WRATH_DMGEFF_EXPLOSIVE),
+ /* Zora boomerang */ DMG_ENTRY(1, MAJORAS_WRATH_DMGEFF_STUN_NONE),
+ /* Normal arrow */ DMG_ENTRY(1, MAJORAS_WRATH_DMGEFF_STUN_NONE),
+ /* UNK_DMG_0x06 */ DMG_ENTRY(0, MAJORAS_WRATH_DMGEFF_IMMUNE),
+ /* Hookshot */ DMG_ENTRY(0, MAJORAS_WRATH_DMGEFF_IMMUNE),
+ /* Goron punch */ DMG_ENTRY(1, MAJORAS_WRATH_DMGEFF_ANIM_FRAME_CHECK),
+ /* Sword */ DMG_ENTRY(1, MAJORAS_WRATH_DMGEFF_ANIM_FRAME_CHECK),
+ /* Goron pound */ DMG_ENTRY(1, MAJORAS_WRATH_DMGEFF_STUN_NONE),
+ /* Fire arrow */ DMG_ENTRY(2, MAJORAS_WRATH_DMGEFF_FIRE),
+ /* Ice arrow */ DMG_ENTRY(2, MAJORAS_WRATH_DMGEFF_FREEZE),
+ /* Light arrow */ DMG_ENTRY(2, MAJORAS_WRATH_DMGEFF_LIGHT_ORB),
+ /* Goron spikes */ DMG_ENTRY(1, MAJORAS_WRATH_DMGEFF_ANIM_FRAME_CHECK),
+ /* Deku spin */ DMG_ENTRY(1, MAJORAS_WRATH_DMGEFF_ANIM_FRAME_CHECK),
+ /* Deku bubble */ DMG_ENTRY(1, MAJORAS_WRATH_DMGEFF_STUN_NONE),
+ /* Deku launch */ DMG_ENTRY(1, MAJORAS_WRATH_DMGEFF_ANIM_FRAME_CHECK),
+ /* UNK_DMG_0x12 */ DMG_ENTRY(0, MAJORAS_WRATH_DMGEFF_IMMUNE),
+ /* Zora barrier */ DMG_ENTRY(0, MAJORAS_WRATH_DMGEFF_ELECTRIC_SPARKS),
+ /* Normal shield */ DMG_ENTRY(0, MAJORAS_WRATH_DMGEFF_IMMUNE),
+ /* Light ray */ DMG_ENTRY(0, MAJORAS_WRATH_DMGEFF_IMMUNE),
+ /* Thrown object */ DMG_ENTRY(1, MAJORAS_WRATH_DMGEFF_STUN_NONE),
+ /* Zora punch */ DMG_ENTRY(1, MAJORAS_WRATH_DMGEFF_ANIM_FRAME_CHECK),
+ /* Spin attack */ DMG_ENTRY(1, MAJORAS_WRATH_DMGEFF_DAMAGE_NONE),
+ /* Sword beam */ DMG_ENTRY(2, MAJORAS_WRATH_DMGEFF_BLUE_LIGHT_ORB),
+ /* Normal Roll */ DMG_ENTRY(0, MAJORAS_WRATH_DMGEFF_IMMUNE),
+ /* UNK_DMG_0x1B */ DMG_ENTRY(0, MAJORAS_WRATH_DMGEFF_IMMUNE),
+ /* UNK_DMG_0x1C */ DMG_ENTRY(0, MAJORAS_WRATH_DMGEFF_IMMUNE),
+ /* Unblockable */ DMG_ENTRY(0, MAJORAS_WRATH_DMGEFF_IMMUNE),
+ /* UNK_DMG_0x1E */ DMG_ENTRY(0, MAJORAS_WRATH_DMGEFF_IMMUNE),
+ /* Powder Keg */ DMG_ENTRY(2, MAJORAS_WRATH_DMGEFF_EXPLOSIVE),
+};
+
+static DamageTable sRemainsDamageTable = {
+ /* Deku Nut */ DMG_ENTRY(0, REMAINS_DMGEFF_IMMUNE),
+ /* Deku Stick */ DMG_ENTRY(1, REMAINS_DMGEFF_DAMAGE),
+ /* Horse trample */ DMG_ENTRY(0, REMAINS_DMGEFF_IMMUNE),
+ /* Explosives */ DMG_ENTRY(2, REMAINS_DMGEFF_OTHER),
+ /* Zora boomerang */ DMG_ENTRY(1, REMAINS_DMGEFF_DAMAGE),
+ /* Normal arrow */ DMG_ENTRY(1, REMAINS_DMGEFF_DAMAGE),
+ /* UNK_DMG_0x06 */ DMG_ENTRY(0, REMAINS_DMGEFF_IMMUNE),
+ /* Hookshot */ DMG_ENTRY(0, REMAINS_DMGEFF_IMMUNE),
+ /* Goron punch */ DMG_ENTRY(1, REMAINS_DMGEFF_OTHER),
+ /* Sword */ DMG_ENTRY(1, REMAINS_DMGEFF_OTHER),
+ /* Goron pound */ DMG_ENTRY(1, REMAINS_DMGEFF_DAMAGE),
+ /* Fire arrow */ DMG_ENTRY(2, REMAINS_DMGEFF_FIRE_ARROW),
+ /* Ice arrow */ DMG_ENTRY(2, REMAINS_DMGEFF_ICE_ARROW),
+ /* Light arrow */ DMG_ENTRY(2, REMAINS_DMGEFF_LIGHT_ARROW),
+ /* Goron spikes */ DMG_ENTRY(1, REMAINS_DMGEFF_DAMAGE),
+ /* Deku spin */ DMG_ENTRY(1, REMAINS_DMGEFF_DAMAGE),
+ /* Deku bubble */ DMG_ENTRY(1, REMAINS_DMGEFF_DAMAGE),
+ /* Deku launch */ DMG_ENTRY(1, REMAINS_DMGEFF_DAMAGE),
+ /* UNK_DMG_0x12 */ DMG_ENTRY(0, REMAINS_DMGEFF_IMMUNE),
+ /* Zora barrier */ DMG_ENTRY(0, REMAINS_DMGEFF_IMMUNE),
+ /* Normal shield */ DMG_ENTRY(0, REMAINS_DMGEFF_IMMUNE),
+ /* Light ray */ DMG_ENTRY(0, REMAINS_DMGEFF_IMMUNE),
+ /* Thrown object */ DMG_ENTRY(1, REMAINS_DMGEFF_DAMAGE),
+ /* Zora punch */ DMG_ENTRY(1, REMAINS_DMGEFF_DAMAGE),
+ /* Spin attack */ DMG_ENTRY(1, REMAINS_DMGEFF_SPIN_ATTACK),
+ /* Sword beam */ DMG_ENTRY(2, REMAINS_DMGEFF_SWORD_BEAM),
+ /* Normal Roll */ DMG_ENTRY(0, REMAINS_DMGEFF_IMMUNE),
+ /* UNK_DMG_0x1B */ DMG_ENTRY(0, REMAINS_DMGEFF_IMMUNE),
+ /* UNK_DMG_0x1C */ DMG_ENTRY(0, REMAINS_DMGEFF_IMMUNE),
+ /* Unblockable */ DMG_ENTRY(0, REMAINS_DMGEFF_IMMUNE),
+ /* UNK_DMG_0x1E */ DMG_ENTRY(0, REMAINS_DMGEFF_IMMUNE),
+ /* Powder Keg */ DMG_ENTRY(2, REMAINS_DMGEFF_OTHER),
+};
+
+static DamageTable sTopDamageTable = {
+ /* Deku Nut */ DMG_ENTRY(0, TOP_DMGEFF_IMMUNE),
+ /* Deku Stick */ DMG_ENTRY(1, TOP_DMGEFF_PUSH_BACK_PLAYER),
+ /* Horse trample */ DMG_ENTRY(1, TOP_DMGEFF_NO_REACTION_E),
+ /* Explosives */ DMG_ENTRY(1, TOP_DMGEFF_BOUNCE_BACK_FROM_DAMAGE),
+ /* Zora boomerang */ DMG_ENTRY(1, TOP_DMGEFF_NO_REACTION_F),
+ /* Normal arrow */ DMG_ENTRY(1, TOP_DMGEFF_NO_REACTION_F),
+ /* UNK_DMG_0x06 */ DMG_ENTRY(0, TOP_DMGEFF_IMMUNE),
+ /* Hookshot */ DMG_ENTRY(1, TOP_DMGEFF_NO_REACTION_E),
+ /* Goron punch */ DMG_ENTRY(1, TOP_DMGEFF_NO_REACTION_E),
+ /* Sword */ DMG_ENTRY(1, TOP_DMGEFF_PUSH_BACK_PLAYER),
+ /* Goron pound */ DMG_ENTRY(0, TOP_DMGEFF_IMMUNE),
+ /* Fire arrow */ DMG_ENTRY(1, TOP_DMGEFF_NO_REACTION_E),
+ /* Ice arrow */ DMG_ENTRY(1, TOP_DMGEFF_NO_REACTION_E),
+ /* Light arrow */ DMG_ENTRY(1, TOP_DMGEFF_NO_REACTION_E),
+ /* Goron spikes */ DMG_ENTRY(1, TOP_DMGEFF_KNOCKED_BACK_FROM_PLAYER),
+ /* Deku spin */ DMG_ENTRY(1, TOP_DMGEFF_NO_REACTION_F),
+ /* Deku bubble */ DMG_ENTRY(1, TOP_DMGEFF_NO_REACTION_F),
+ /* Deku launch */ DMG_ENTRY(1, TOP_DMGEFF_NO_REACTION_F),
+ /* UNK_DMG_0x12 */ DMG_ENTRY(0, TOP_DMGEFF_IMMUNE),
+ /* Zora barrier */ DMG_ENTRY(0, TOP_DMGEFF_IMMUNE),
+ /* Normal shield */ DMG_ENTRY(1, TOP_DMGEFF_PUSH_BACK_PLAYER),
+ /* Light ray */ DMG_ENTRY(1, TOP_DMGEFF_PUSH_BACK_PLAYER),
+ /* Thrown object */ DMG_ENTRY(1, TOP_DMGEFF_NO_REACTION_E),
+ /* Zora punch */ DMG_ENTRY(1, TOP_DMGEFF_NO_REACTION_E),
+ /* Spin attack */ DMG_ENTRY(1, TOP_DMGEFF_REVERSE_DIRECTION),
+ /* Sword beam */ DMG_ENTRY(1, TOP_DMGEFF_REVERSE_DIRECTION),
+ /* Normal Roll */ DMG_ENTRY(0, TOP_DMGEFF_IMMUNE),
+ /* UNK_DMG_0x1B */ DMG_ENTRY(0, TOP_DMGEFF_IMMUNE),
+ /* UNK_DMG_0x1C */ DMG_ENTRY(0, TOP_DMGEFF_IMMUNE),
+ /* Unblockable */ DMG_ENTRY(0, TOP_DMGEFF_IMMUNE),
+ /* UNK_DMG_0x1E */ DMG_ENTRY(0, TOP_DMGEFF_IMMUNE),
+ /* Powder Keg */ DMG_ENTRY(2, TOP_DMGEFF_BOUNCE_BACK_FROM_DAMAGE),
};
ActorProfile Boss_07_Profile = {
@@ -242,500 +636,7210 @@ ActorProfile Boss_07_Profile = {
/**/ sizeof(Boss07),
/**/ Boss07_Init,
/**/ Boss07_Destroy,
- /**/ Boss07_Update,
- /**/ Boss07_Draw,
+ /**/ Boss07_Wrath_Update,
+ /**/ Boss07_Wrath_Draw,
};
-// static ColliderJntSphElementInit sJntSphElementsInit[11] = {
-static ColliderJntSphElementInit D_80A07A40[11] = {
+// The limbs referenced here are not used. The spheres are positioned manually by Boss07_Wrath_PostLimbDraw.
+static ColliderJntSphElementInit sWrathBodyColliderJntSphElementsInit[MAJORAS_WRATH_COLLIDER_BODYPART_MAX] = {
{
- { ELEM_MATERIAL_UNK3, { 0xF7CFFFFF, 0x00, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
- { 0, { { 0, 0, 0 }, 20 }, 100 },
+ {
+ ELEM_MATERIAL_UNK3,
+ { 0xF7CFFFFF, 0x00, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
+ { MAJORAS_WRATH_LIMB_NONE, { { 0, 0, 0 }, 20 }, 100 },
},
{
- { ELEM_MATERIAL_UNK3, { 0xF7CFFFFF, 0x00, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
- { 1, { { 0, 0, 0 }, 30 }, 100 },
+ {
+ ELEM_MATERIAL_UNK3,
+ { 0xF7CFFFFF, 0x00, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
+ { MAJORAS_WRATH_LIMB_ROOT, { { 0, 0, 0 }, 30 }, 100 },
},
{
- { ELEM_MATERIAL_UNK3, { 0xF7CFFFFF, 0x00, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
- { 1, { { 0, 0, 0 }, 25 }, 100 },
+ {
+ ELEM_MATERIAL_UNK3,
+ { 0xF7CFFFFF, 0x00, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
+ { MAJORAS_WRATH_LIMB_ROOT, { { 0, 0, 0 }, 25 }, 100 },
},
{
- { ELEM_MATERIAL_UNK3, { 0xF7CFFFFF, 0x00, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
- { 1, { { 0, 0, 0 }, 15 }, 100 },
+ {
+ ELEM_MATERIAL_UNK3,
+ { 0xF7CFFFFF, 0x00, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
+ { MAJORAS_WRATH_LIMB_ROOT, { { 0, 0, 0 }, 15 }, 100 },
},
{
- { ELEM_MATERIAL_UNK3, { 0xF7CFFFFF, 0x00, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
- { 1, { { 0, 0, 0 }, 15 }, 100 },
+ {
+ ELEM_MATERIAL_UNK3,
+ { 0xF7CFFFFF, 0x00, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
+ { MAJORAS_WRATH_LIMB_ROOT, { { 0, 0, 0 }, 15 }, 100 },
},
{
- { ELEM_MATERIAL_UNK3, { 0xF7CFFFFF, 0x00, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
- { 1, { { 0, 0, 0 }, 15 }, 100 },
+ {
+ ELEM_MATERIAL_UNK3,
+ { 0xF7CFFFFF, 0x00, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
+ { MAJORAS_WRATH_LIMB_ROOT, { { 0, 0, 0 }, 15 }, 100 },
},
{
- { ELEM_MATERIAL_UNK3, { 0xF7CFFFFF, 0x00, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
- { 1, { { 0, 0, 0 }, 15 }, 100 },
+ {
+ ELEM_MATERIAL_UNK3,
+ { 0xF7CFFFFF, 0x00, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
+ { MAJORAS_WRATH_LIMB_ROOT, { { 0, 0, 0 }, 15 }, 100 },
},
{
- { ELEM_MATERIAL_UNK3, { 0xF7CFFFFF, 0x00, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
- { 1, { { 0, 0, 0 }, 15 }, 150 },
+ {
+ ELEM_MATERIAL_UNK3,
+ { 0xF7CFFFFF, 0x00, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
+ { MAJORAS_WRATH_LIMB_ROOT, { { 0, 0, 0 }, 15 }, 150 },
},
{
- { ELEM_MATERIAL_UNK3, { 0xF7CFFFFF, 0x00, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
- { 1, { { 0, 0, 0 }, 15 }, 150 },
+ {
+ ELEM_MATERIAL_UNK3,
+ { 0xF7CFFFFF, 0x00, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
+ { MAJORAS_WRATH_LIMB_ROOT, { { 0, 0, 0 }, 15 }, 150 },
},
{
- { ELEM_MATERIAL_UNK3, { 0xF7CFFFFF, 0x00, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
- { 1, { { 0, 0, 0 }, 15 }, 150 },
+ {
+ ELEM_MATERIAL_UNK3,
+ { 0xF7CFFFFF, 0x00, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
+ { MAJORAS_WRATH_LIMB_ROOT, { { 0, 0, 0 }, 15 }, 150 },
},
{
- { ELEM_MATERIAL_UNK3, { 0xF7CFFFFF, 0x00, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
- { 1, { { 0, 0, 0 }, 15 }, 150 },
+ {
+ ELEM_MATERIAL_UNK3,
+ { 0xF7CFFFFF, 0x00, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
+ { MAJORAS_WRATH_LIMB_ROOT, { { 0, 0, 0 }, 15 }, 150 },
},
};
-// static ColliderJntSphInit sJntSphInit = {
-static ColliderJntSphInit D_80A07BCC = {
- { COL_MATERIAL_HIT3, AT_ON | AT_TYPE_ENEMY, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_PLAYER, OC2_TYPE_1, COLSHAPE_JNTSPH, },
- ARRAY_COUNT(sJntSphElementsInit), D_80A07A40, // sJntSphElementsInit,
+static ColliderJntSphInit sWrathBodyColliderJntSphInit = {
+ {
+ COL_MATERIAL_HIT3,
+ AT_ON | AT_TYPE_ENEMY,
+ AC_ON | AC_TYPE_PLAYER,
+ OC1_ON | OC1_TYPE_PLAYER,
+ OC2_TYPE_1,
+ COLSHAPE_JNTSPH,
+ },
+ ARRAY_COUNT(sWrathBodyColliderJntSphElementsInit),
+ sWrathBodyColliderJntSphElementsInit,
};
-// static ColliderCylinderInit sCylinderInit = {
-static ColliderCylinderInit D_80A07BDC = {
- { COL_MATERIAL_METAL, AT_ON | AT_TYPE_ENEMY, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1, COLSHAPE_CYLINDER, },
- { ELEM_MATERIAL_UNK2, { 0xF7CFFFFF, 0x00, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
+static ColliderCylinderInit sWrathCylinderInit = {
+ {
+ COL_MATERIAL_METAL,
+ AT_ON | AT_TYPE_ENEMY,
+ AC_ON | AC_TYPE_PLAYER,
+ OC1_ON | OC1_TYPE_ALL,
+ OC2_TYPE_1,
+ COLSHAPE_CYLINDER,
+ },
+ {
+ ELEM_MATERIAL_UNK2,
+ { 0xF7CFFFFF, 0x00, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
{ 80, 200, 0, { 0, 0, 0 } },
};
-// static ColliderJntSphElementInit sJntSphElementsInit[1] = {
-static ColliderJntSphElementInit D_80A07C08[1] = {
+// The limbs referenced here are not used. The spheres are positioned manually by Boss07_Wrath_PostLimbDraw.
+static ColliderJntSphElementInit sWrathKickColliderJntSphElementsInit[MAJORAS_WARTH_KICK_COLLIDER_MAX] = {
{
- { ELEM_MATERIAL_UNK3, { 0xF7CFFFFF, 0x04, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_HARD, ACELEM_ON, OCELEM_ON, },
- { 0, { { 0, 0, 0 }, 36 }, 200 },
+ {
+ ELEM_MATERIAL_UNK3,
+ { 0xF7CFFFFF, 0x04, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_HARD,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
+ { MAJORAS_WRATH_LIMB_NONE, { { 0, 0, 0 }, 36 }, 200 },
},
};
-// static ColliderJntSphInit sJntSphInit = {
-static ColliderJntSphInit D_80A07C2C = {
- { COL_MATERIAL_HIT3, AT_ON | AT_TYPE_ENEMY, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_PLAYER, OC2_TYPE_1, COLSHAPE_JNTSPH, },
- ARRAY_COUNT(sJntSphElementsInit), D_80A07C08, // sJntSphElementsInit,
+static ColliderJntSphInit sWrathKickColliderJntSphInit = {
+ {
+ COL_MATERIAL_HIT3,
+ AT_ON | AT_TYPE_ENEMY,
+ AC_ON | AC_TYPE_PLAYER,
+ OC1_ON | OC1_TYPE_PLAYER,
+ OC2_TYPE_1,
+ COLSHAPE_JNTSPH,
+ },
+ ARRAY_COUNT(sWrathKickColliderJntSphElementsInit),
+ sWrathKickColliderJntSphElementsInit,
};
-// static ColliderQuadInit sQuadInit = {
-static ColliderQuadInit D_80A07C3C = {
- { COL_MATERIAL_METAL, AT_ON | AT_TYPE_ENEMY, AC_ON | AC_HARD | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1, COLSHAPE_QUAD, },
- { ELEM_MATERIAL_UNK2, { 0xF7CFFFFF, 0x04, 0x00 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
+static ColliderQuadInit sMaskFrontQuadInit = {
+ {
+ COL_MATERIAL_METAL,
+ AT_ON | AT_TYPE_ENEMY,
+ AC_ON | AC_HARD | AC_TYPE_PLAYER,
+ OC1_ON | OC1_TYPE_ALL,
+ OC2_TYPE_1,
+ COLSHAPE_QUAD,
+ },
+ {
+ ELEM_MATERIAL_UNK2,
+ { 0xF7CFFFFF, 0x04, 0x00 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
{ { { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } } },
};
-// static ColliderQuadInit sQuadInit = {
-static ColliderQuadInit D_80A07C8C = {
- { COL_MATERIAL_HIT3, AT_ON | AT_TYPE_ENEMY, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1, COLSHAPE_QUAD, },
- { ELEM_MATERIAL_UNK2, { 0xF7CFFFFF, 0x04, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
+static ColliderQuadInit sMaskBackQuadInit = {
+ {
+ COL_MATERIAL_HIT3,
+ AT_ON | AT_TYPE_ENEMY,
+ AC_ON | AC_TYPE_PLAYER,
+ OC1_ON | OC1_TYPE_ALL,
+ OC2_TYPE_1,
+ COLSHAPE_QUAD,
+ },
+ {
+ ELEM_MATERIAL_UNK2,
+ { 0xF7CFFFFF, 0x04, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
{ { { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } } },
};
-// static ColliderJntSphElementInit sJntSphElementsInit[11] = {
-static ColliderJntSphElementInit D_80A07CDC[11] = {
+// The limbs referenced here are not used. The spheres are positioned manually by Boss07_Incarnation_PostLimbDraw.
+static ColliderJntSphElementInit sIncarnationBodyJntSphElementsInit[MAJORAS_INCARNATION_COLLIDER_BODYPART_MAX] = {
{
- { ELEM_MATERIAL_UNK3, { 0xF7CFFFFF, 0x00, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
- { 0, { { 0, 0, 0 }, 25 }, 100 },
+ {
+ ELEM_MATERIAL_UNK3,
+ { 0xF7CFFFFF, 0x00, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
+ { MAJORAS_INCARNATION_LIMB_NONE, { { 0, 0, 0 }, 25 }, 100 },
},
{
- { ELEM_MATERIAL_UNK3, { 0xF7CFFFFF, 0x00, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
- { 1, { { 0, 0, 0 }, 40 }, 100 },
+ {
+ ELEM_MATERIAL_UNK3,
+ { 0xF7CFFFFF, 0x00, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
+ { MAJORAS_INCARNATION_LIMB_ROOT, { { 0, 0, 0 }, 40 }, 100 },
},
{
- { ELEM_MATERIAL_UNK3, { 0xF7CFFFFF, 0x00, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
- { 1, { { 0, 0, 0 }, 0 }, 0 },
+ {
+ ELEM_MATERIAL_UNK3,
+ { 0xF7CFFFFF, 0x00, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
+ { MAJORAS_INCARNATION_LIMB_ROOT, { { 0, 0, 0 }, 0 }, 0 },
},
{
- { ELEM_MATERIAL_UNK3, { 0xF7CFFFFF, 0x00, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
- { 1, { { 0, 0, 0 }, 15 }, 100 },
+ {
+ ELEM_MATERIAL_UNK3,
+ { 0xF7CFFFFF, 0x00, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
+ { MAJORAS_INCARNATION_LIMB_ROOT, { { 0, 0, 0 }, 15 }, 100 },
},
{
- { ELEM_MATERIAL_UNK3, { 0xF7CFFFFF, 0x00, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
- { 1, { { 0, 0, 0 }, 15 }, 100 },
+ {
+ ELEM_MATERIAL_UNK3,
+ { 0xF7CFFFFF, 0x00, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
+ { MAJORAS_INCARNATION_LIMB_ROOT, { { 0, 0, 0 }, 15 }, 100 },
},
{
- { ELEM_MATERIAL_UNK3, { 0xF7CFFFFF, 0x00, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
- { 1, { { 0, 0, 0 }, 15 }, 100 },
+ {
+ ELEM_MATERIAL_UNK3,
+ { 0xF7CFFFFF, 0x00, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
+ { MAJORAS_INCARNATION_LIMB_ROOT, { { 0, 0, 0 }, 15 }, 100 },
},
{
- { ELEM_MATERIAL_UNK3, { 0xF7CFFFFF, 0x00, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
- { 1, { { 0, 0, 0 }, 15 }, 100 },
+ {
+ ELEM_MATERIAL_UNK3,
+ { 0xF7CFFFFF, 0x00, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
+ { MAJORAS_INCARNATION_LIMB_ROOT, { { 0, 0, 0 }, 15 }, 100 },
},
{
- { ELEM_MATERIAL_UNK3, { 0xF7CFFFFF, 0x00, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
- { 1, { { 0, 0, 0 }, 15 }, 150 },
+ {
+ ELEM_MATERIAL_UNK3,
+ { 0xF7CFFFFF, 0x00, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
+ { MAJORAS_INCARNATION_LIMB_ROOT, { { 0, 0, 0 }, 15 }, 150 },
},
{
- { ELEM_MATERIAL_UNK3, { 0xF7CFFFFF, 0x00, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
- { 1, { { 0, 0, 0 }, 15 }, 150 },
+ {
+ ELEM_MATERIAL_UNK3,
+ { 0xF7CFFFFF, 0x00, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
+ { MAJORAS_INCARNATION_LIMB_ROOT, { { 0, 0, 0 }, 15 }, 150 },
},
{
- { ELEM_MATERIAL_UNK3, { 0xF7CFFFFF, 0x00, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
- { 1, { { 0, 0, 0 }, 15 }, 150 },
+ {
+ ELEM_MATERIAL_UNK3,
+ { 0xF7CFFFFF, 0x00, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
+ { MAJORAS_INCARNATION_LIMB_ROOT, { { 0, 0, 0 }, 15 }, 150 },
},
{
- { ELEM_MATERIAL_UNK3, { 0xF7CFFFFF, 0x00, 0x10 }, { 0xF7CEFFFE, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
- { 1, { { 0, 0, 0 }, 15 }, 150 },
+ {
+ ELEM_MATERIAL_UNK3,
+ { 0xF7CFFFFF, 0x00, 0x10 },
+ { 0xF7CEFFFE, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
+ { MAJORAS_INCARNATION_LIMB_ROOT, { { 0, 0, 0 }, 15 }, 150 },
},
};
-// static ColliderJntSphInit sJntSphInit = {
-static ColliderJntSphInit D_80A07E68 = {
- { COL_MATERIAL_HIT3, AT_ON | AT_TYPE_ENEMY, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_PLAYER, OC2_TYPE_1, COLSHAPE_JNTSPH, },
- ARRAY_COUNT(sJntSphElementsInit), D_80A07CDC, // sJntSphElementsInit,
+static ColliderJntSphInit sIncarnationBodyColliderJntSphInit = {
+ {
+ COL_MATERIAL_HIT3,
+ AT_ON | AT_TYPE_ENEMY,
+ AC_ON | AC_TYPE_PLAYER,
+ OC1_ON | OC1_TYPE_PLAYER,
+ OC2_TYPE_1,
+ COLSHAPE_JNTSPH,
+ },
+ ARRAY_COUNT(sIncarnationBodyJntSphElementsInit),
+ sIncarnationBodyJntSphElementsInit,
};
-// static ColliderCylinderInit sCylinderInit = {
-static ColliderCylinderInit D_80A07E78 = {
- { COL_MATERIAL_NONE, AT_ON | AT_TYPE_ENEMY, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1, COLSHAPE_CYLINDER, },
- { ELEM_MATERIAL_UNK0, { 0xF7CFFFFF, 0x04, 0x10 }, { 0x00300000, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON, OCELEM_ON, },
+static ColliderCylinderInit sProjectileCylinderInit = {
+ {
+ COL_MATERIAL_NONE,
+ AT_ON | AT_TYPE_ENEMY,
+ AC_ON | AC_TYPE_PLAYER,
+ OC1_ON | OC1_TYPE_ALL,
+ OC2_TYPE_1,
+ COLSHAPE_CYLINDER,
+ },
+ {
+ ELEM_MATERIAL_UNK0,
+ { 0xF7CFFFFF, 0x04, 0x10 },
+ { 0x00300000, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON,
+ OCELEM_ON,
+ },
{ 15, 30, -15, { 0, 0, 0 } },
};
-// static ColliderCylinderInit sCylinderInit = {
-static ColliderCylinderInit D_80A07EA4 = {
- { COL_MATERIAL_METAL, AT_ON | AT_TYPE_ENEMY, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1, COLSHAPE_CYLINDER, },
- { ELEM_MATERIAL_UNK0, { 0xF7CFFFFF, 0x04, 0x10 }, { 0xF7CFFFFF, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON | ACELEM_HOOKABLE, OCELEM_ON, },
+static ColliderCylinderInit sRemainsCylinderInit = {
+ {
+ COL_MATERIAL_METAL,
+ AT_ON | AT_TYPE_ENEMY,
+ AC_ON | AC_TYPE_PLAYER,
+ OC1_ON | OC1_TYPE_ALL,
+ OC2_TYPE_1,
+ COLSHAPE_CYLINDER,
+ },
+ {
+ ELEM_MATERIAL_UNK0,
+ { 0xF7CFFFFF, 0x04, 0x10 },
+ { 0xF7CFFFFF, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON | ACELEM_HOOKABLE,
+ OCELEM_ON,
+ },
{ 50, 100, -50, { 0, 0, 0 } },
};
-// static ColliderCylinderInit sCylinderInit = {
-static ColliderCylinderInit D_80A07ED0 = {
- { COL_MATERIAL_METAL, AT_ON | AT_TYPE_ENEMY, AC_ON | AC_HARD | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1, COLSHAPE_CYLINDER, },
- { ELEM_MATERIAL_UNK0, { 0xF7CFFFFF, 0x04, 0x10 }, { 0xF7FFFFFF, 0x00, 0x00 }, ATELEM_ON | ATELEM_SFX_NORMAL, ACELEM_ON | ACELEM_HOOKABLE, OCELEM_ON, },
+static ColliderCylinderInit sTopCylinderInit = {
+ {
+ COL_MATERIAL_METAL,
+ AT_ON | AT_TYPE_ENEMY,
+ AC_ON | AC_HARD | AC_TYPE_PLAYER,
+ OC1_ON | OC1_TYPE_ALL,
+ OC2_TYPE_1,
+ COLSHAPE_CYLINDER,
+ },
+ {
+ ELEM_MATERIAL_UNK0,
+ { 0xF7CFFFFF, 0x04, 0x10 },
+ { 0xF7FFFFFF, 0x00, 0x00 },
+ ATELEM_ON | ATELEM_SFX_NORMAL,
+ ACELEM_ON | ACELEM_HOOKABLE,
+ OCELEM_ON,
+ },
{ 40, 20, 15, { 0, 0, 0 } },
};
-#endif
-
-extern DamageTable D_80A07980;
-extern DamageTable D_80A079A0;
-extern DamageTable D_80A079C0;
-extern DamageTable D_80A079E0;
-extern DamageTable D_80A07A00;
-extern ColliderJntSphElementInit D_80A07A40[11];
-extern ColliderJntSphInit D_80A07BCC;
-extern ColliderCylinderInit D_80A07BDC;
-extern ColliderJntSphElementInit D_80A07C08[1];
-extern ColliderJntSphInit D_80A07C2C;
-extern ColliderQuadInit D_80A07C3C;
-extern ColliderQuadInit D_80A07C8C;
-extern ColliderJntSphElementInit D_80A07CDC[11];
-extern ColliderJntSphInit D_80A07E68;
-extern ColliderCylinderInit D_80A07E78;
-extern ColliderCylinderInit D_80A07EA4;
-extern ColliderCylinderInit D_80A07ED0;
-
-extern UNK_TYPE D_06000194;
-extern UNK_TYPE D_06000428;
-extern UNK_TYPE D_06000D0C;
-extern UNK_TYPE D_06002C40;
-extern UNK_TYPE D_06002D84;
-extern UNK_TYPE D_06003854;
-extern UNK_TYPE D_06003A64;
-extern UNK_TYPE D_06009C7C;
-extern UNK_TYPE D_06009EA8;
-extern UNK_TYPE D_0600A194;
-extern UNK_TYPE D_0600A400;
-extern UNK_TYPE D_0600AE40;
-extern UNK_TYPE D_0600AFB0;
-extern UNK_TYPE D_0600B020;
-extern UNK_TYPE D_0600C7D8;
-extern UNK_TYPE D_0600CEE8;
-extern UNK_TYPE D_060149A0;
-extern UNK_TYPE D_06019E48;
-extern UNK_TYPE D_0601DEB4;
-extern UNK_TYPE D_06022BB4;
-extern UNK_TYPE D_06023DAC;
-extern UNK_TYPE D_06025018;
-extern UNK_TYPE D_06025878;
-extern UNK_TYPE D_060269EC;
-extern UNK_TYPE D_06026EA0;
-extern UNK_TYPE D_06027270;
-extern UNK_TYPE D_0602EEC8;
-extern UNK_TYPE D_0602EF68;
-extern UNK_TYPE D_0602EFE8;
-extern UNK_TYPE D_0602F640;
-extern UNK_TYPE D_0602F840;
-extern UNK_TYPE D_06033F80;
-extern UNK_TYPE D_0603B330;
-extern UNK_TYPE D_0603CBD0;
-extern UNK_TYPE D_0603D7F0;
-extern UNK_TYPE D_0603DD1C;
-extern UNK_TYPE D_06040930;
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F4980.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F49A0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F49C0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F4AE8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F4BB0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F4C40.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F4CBC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F4D10.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F4D54.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F4FAC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F4FF8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F51E8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F52CC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F536C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F5494.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/Boss07_Init.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/Boss07_Destroy.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F5E14.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F5E88.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F64F4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F65F4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F7400.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F748C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F7688.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F76D0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F77A8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F783C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F7968.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F7AB4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F7BC4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F7D2C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F805C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F8658.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F86B8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F87C8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F8908.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F8AB0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F8B1C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F8D04.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F8DEC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F8E68.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F8EC8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F91D4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F9280.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F93DC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F94AC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F99C4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F9CEC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809F9E94.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/Boss07_Update.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FAA44.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FB114.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FB504.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FB55C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FB728.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FB7D4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FBB9C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FBF94.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/Boss07_Draw.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FC4C0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FC8B0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FC960.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FCBC8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FCC70.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FCCCC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FD5F8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FD710.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FD818.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FD89C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FD984.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FDAB0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FDB2C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FDBA0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FDEDC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FDF54.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FE068.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FE0E4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FE2D4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FE348.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FE4B0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FE524.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FE6B0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FE734.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FEE70.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FF0E4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FF12C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FF5CC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FF678.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FF6B0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FF810.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FF900.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FFA04.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FFA80.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FFE64.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_809FFEAC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A0021C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A00274.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A00484.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A00554.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A006D0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A006F4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A00720.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A016E4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A01750.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A025AC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A0264C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A02B30.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A02C54.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A03238.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A036C4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A03868.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A03F18.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A03F5C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A0434C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A045A8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A04768.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A04878.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A04890.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A04DE0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A04E5C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A055E0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A05608.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A05694.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A057A0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A05AF8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A05B50.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A05C88.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A05DDC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A06500.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A06990.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A06C64.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A06E24.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A06F48.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A07604.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A07638.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Boss_07/func_80A07740.s")
+Vec3f sMajoraSfxPos;
+
+static u8 sHeartbeatTimer;
+static s32 sWhipLength;
+
+Boss07* sMajorasWrath;
+Boss07* sMajoraBattleHandler;
+Boss07* sMajorasMask;
+Boss07* sMajoraRemains[MAJORA_REMAINS_TYPE_MAX];
+
+static u8 sKillAllProjectiles;
+static u8 sMusicStartTimer;
+
+MajoraEffect sMajoraEffects[MAJORA_EFFECT_COUNT];
+
+s32 sMajoraRandSeed1;
+s32 sMajoraRandSeed2;
+s32 sMajoraRandSeed3;
+
+void Boss07_Remains_PlayDamageSfx(Boss07* this) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_FOLLOWERS_DAMAGE);
+}
+
+void Boss07_InitRand(s32 seedInit1, s32 seedInit2, s32 seedInit3) {
+ sMajoraRandSeed1 = seedInit1;
+ sMajoraRandSeed2 = seedInit2;
+ sMajoraRandSeed3 = seedInit3;
+}
+
+f32 Boss07_RandZeroOne(void) {
+ // Wichmann-Hill algorithm
+ f32 randFloat;
+
+ sMajoraRandSeed1 = (sMajoraRandSeed1 * 171) % 30269;
+ sMajoraRandSeed2 = (sMajoraRandSeed2 * 172) % 30307;
+ sMajoraRandSeed3 = (sMajoraRandSeed3 * 170) % 30323;
+
+ randFloat = (sMajoraRandSeed1 / 30269.0f) + (sMajoraRandSeed2 / 30307.0f) + (sMajoraRandSeed3 / 30323.0f);
+
+ while (randFloat >= 1.0f) {
+ randFloat -= 1.0f;
+ }
+
+ return fabsf(randFloat);
+}
+
+void Boss07_SpawnFlameEffect(PlayState* play, Vec3f* pos, Vec3f* velocity, Vec3f* accel, f32 scale) {
+ s32 i;
+ MajoraEffect* effect = (MajoraEffect*)play->specialEffects;
+
+ for (i = 0; i < MAJORA_EFFECT_COUNT; i++, effect++) {
+ if (effect->type == MAJORA_EFFECT_NONE) {
+ effect->type = MAJORA_EFFECT_FLAME;
+ effect->pos = *pos;
+ effect->velocity = *velocity;
+ effect->accel = *accel;
+ effect->scale = scale / 1000.0f;
+ effect->isFadingAway = false;
+ effect->alpha = 0;
+ effect->texScroll = Rand_ZeroFloat(1000.0f);
+ break;
+ }
+ }
+}
+
+/**
+ * Manually sets the position of a sphere collider to a specific position.
+ */
+void Boss07_SetColliderSphere(s32 index, ColliderJntSph* collider, Vec3f* pos) {
+ collider->elements[index].dim.worldSphere.center.x = pos->x;
+ collider->elements[index].dim.worldSphere.center.y = pos->y;
+ collider->elements[index].dim.worldSphere.center.z = pos->z;
+ collider->elements[index].dim.worldSphere.radius =
+ collider->elements[index].dim.modelSphere.radius * collider->elements[index].dim.scale;
+}
+
+/**
+ * Returns true if this actor's model is rotated such that it is looking at the player *and* if the player's model is
+ * rotated such that they are looking at this actor.
+ */
+s32 Boss07_ArePlayerAndActorFacing(Boss07* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+
+ if ((ABS_ALT(BINANG_SUB(this->actor.yawTowardsPlayer, this->actor.shape.rot.y)) < 0x3000) &&
+ (ABS_ALT(BINANG_SUB(this->actor.yawTowardsPlayer, BINANG_ROT180(player->actor.shape.rot.y))) < 0x3000)) {
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Can be called repeatedly to gradually reduce the actor's speed to zero. If the actor is touching a wall or ceiling,
+ * though, it will immediately set the speed to zero.
+ */
+void Boss07_SmoothStop(Boss07* this, f32 maxStep) {
+ Math_ApproachZeroF(&this->actor.speed, 1.0f, maxStep);
+
+ if (this->actor.bgCheckFlags & (BGCHECKFLAG_WALL | BGCHECKFLAG_CEILING)) {
+ this->actor.speed = 0.0f;
+ }
+}
+
+void Boss07_RandXZ(Vec3f* dst, f32 length) {
+ Matrix_RotateYF(Rand_ZeroFloat(2 * M_PIf), MTXMODE_NEW);
+ Matrix_MultVecZ(length, dst);
+}
+
+void Boss07_Incarnation_SpawnDust(Boss07* this, PlayState* play, u8 dustSpawnFrameMask, u8 spawnPos) {
+ static Color_RGBA8 sDustPrimColor = { 60, 50, 20, 255 };
+ static Color_RGBA8 sDustEnvColor = { 40, 30, 30, 255 };
+ u8 i;
+
+ if (!(this->frameCounter & dustSpawnFrameMask) && ((dustSpawnFrameMask == 0) || (this->actor.speed > 1.0f))) {
+ for (i = 0; i < MAJORAS_INCARNATION_FOOT_MAX; i++) {
+ Vec3f pos;
+ Vec3f velocity;
+ Vec3f accel;
+
+ velocity.x = Rand_CenteredFloat(5.0f);
+ velocity.y = Rand_ZeroFloat(2.0f) + 1.0f;
+ velocity.z = Rand_CenteredFloat(5.0f);
+
+ accel.x = accel.z = 0.0f;
+ accel.y = -0.1f;
+
+ pos.y = Rand_ZeroFloat(10.0f) + 3.0f;
+
+ if ((u32)spawnPos != MAJORAS_INCARNATION_DUST_SPAWN_POS_FEET) {
+ pos.x = this->actor.focus.pos.x + Rand_CenteredFloat(150.0f);
+ pos.z = this->actor.focus.pos.z + Rand_CenteredFloat(150.0f);
+ } else {
+ pos.z = this->incarnationFeetPos[i].z + Rand_CenteredFloat(20.0f);
+ pos.x = this->incarnationFeetPos[i].x + Rand_CenteredFloat(20.0f);
+ }
+
+ func_800B0EB0(play, &pos, &velocity, &accel, &sDustPrimColor, &sDustEnvColor,
+ Rand_ZeroFloat(150.0f) + 350.0f, 10, Rand_ZeroFloat(5.0f) + 14.0f);
+ }
+ }
+}
+
+void Boss07_MovePlayerFromCenter(PlayState* play) {
+ Player* player = GET_PLAYER(play);
+
+ if (SQXZ(player->actor.world.pos) < SQ(80.0f)) {
+ player->actor.world.pos.z = 90.0f;
+ }
+}
+
+void Boss07_Wrath_SpawnDustAtPos(PlayState* play, Vec3f* spawnPos, u8 count) {
+ static Color_RGBA8 sDustPrimColor = { 60, 50, 20, 255 };
+ static Color_RGBA8 sDustEnvColor = { 40, 30, 30, 255 };
+ u8 i;
+
+ for (i = 0; i < count; i++) {
+ Vec3f pos;
+ Vec3f velocity;
+ Vec3f accel;
+
+ velocity.x = Rand_CenteredFloat(3.0f);
+ velocity.y = Rand_ZeroFloat(2.0f) + 1.0f;
+ velocity.z = Rand_CenteredFloat(3.0f);
+
+ accel.x = accel.z = 0.0f;
+ accel.y = -0.1f;
+
+ pos.x = spawnPos->x + Rand_CenteredFloat(30.0f);
+ pos.y = spawnPos->y + 15.0f + Rand_CenteredFloat(30.0f);
+ pos.z = spawnPos->z + Rand_CenteredFloat(30.0f);
+
+ func_800B0EB0(play, &pos, &velocity, &accel, &sDustPrimColor, &sDustEnvColor, Rand_ZeroFloat(50.0f) + 100.0f,
+ 10, Rand_ZeroFloat(5.0f) + 14.0f);
+ }
+}
+
+void Boss07_Wrath_ChooseJump(Boss07* this, PlayState* play, u8 canCancelCurrentJump) {
+ Player* player = GET_PLAYER(play);
+
+ if ((this->damagedTimer == 0) &&
+ (((this->actionFunc != Boss07_Wrath_Flip) && (this->actionFunc != Boss07_Wrath_StartJump) &&
+ (this->actionFunc != Boss07_Wrath_Jump)) ||
+ canCancelCurrentJump)) {
+ if (Rand_ZeroOne() < 0.5f) {
+ Boss07_Wrath_SetupFlip(this, play);
+ } else {
+ Boss07_Wrath_SetupJump(this, play);
+ }
+
+ this->disableCollisionTimer = 10;
+ this->whipWrapEndOffset = 0;
+
+ if (&this->actor == player->actor.parent) {
+ player->av2.actionVar2 = 101;
+ player->actor.parent = NULL;
+ player->csAction = PLAYER_CSACTION_NONE;
+ }
+ }
+}
+
+void Boss07_Wrath_JumpAwayFromExplosive(Boss07* this, PlayState* play) {
+ Actor* explosive;
+
+ for (explosive = play->actorCtx.actorLists[ACTORCAT_EXPLOSIVES].first; explosive != NULL;
+ explosive = explosive->next) {
+ f32 dx = explosive->world.pos.x - this->actor.world.pos.x;
+ f32 dy = explosive->world.pos.y - this->actor.world.pos.y;
+ f32 dz = explosive->world.pos.z - this->actor.world.pos.z;
+
+ if (sqrtf(SQ(dx) + SQ(dy) + SQ(dz)) < 200.0f) {
+ Boss07_Wrath_ChooseJump(this, play, false);
+ break;
+ }
+ }
+}
+
+void Boss07_Wrath_BombWhip(Vec3f* bombPos, Vec3f* pos, Vec3f* velocity) {
+ s32 i;
+ f32 push;
+ f32 dx;
+ f32 dy;
+ f32 dz;
+ Vec3f impulse;
+
+ impulse.x = 0.0f;
+
+ for (i = 0; i < sWhipLength; i++, pos++, velocity++) {
+ dx = pos->x - bombPos->x;
+ dy = pos->y - bombPos->y;
+ dz = pos->z - bombPos->z;
+
+ if (sqrtf(SQ(dx) + SQ(dy) + SQ(dz)) < 300.0f) {
+ push = 300.0f - sqrtf(SQ(dx) + SQ(dy) + SQ(dz));
+ push = CLAMP_MAX(push, 200.0f);
+ impulse.y = push;
+ impulse.z = push;
+
+ Matrix_RotateYF(Math_Atan2F_XY(dz, dx), MTXMODE_NEW);
+ Matrix_MultVec3f(&impulse, velocity);
+ }
+ }
+}
+
+void Boss07_Wrath_CheckBombWhips(Boss07* this, PlayState* play) {
+ Actor* explosive;
+
+ for (explosive = play->actorCtx.actorLists[ACTORCAT_EXPLOSIVES].first; explosive != NULL;
+ explosive = explosive->next) {
+ if (explosive->params == BOMB_TYPE_EXPLOSION) {
+ Boss07_Wrath_BombWhip(&explosive->world.pos, this->rightWhip.pos, this->rightWhip.velocity);
+ Boss07_Wrath_BombWhip(&explosive->world.pos, this->leftWhip.pos, this->leftWhip.velocity);
+ }
+ }
+}
+
+static Vec3f sRemainsStartTargetOffset[MAJORA_REMAINS_TYPE_MAX] = {
+ { 70.0f, 70.0f, -70.0f }, // MAJORA_REMAINS_TYPE_ODOLWA
+ { 24.0f, 88.0f, -70.0f }, // MAJORA_REMAINS_TYPE_GYORG
+ { -24.0f, 88.0f, -70.0f }, // MAJORA_REMAINS_TYPE_GOHT
+ { -70.0f, 70.0f, -70.0f }, // MAJORA_REMAINS_TYPE_TWINMOLD
+};
+
+// y value here is y-rotation, not position
+static Vec3s sRemainsEndTarget[MAJORA_REMAINS_TYPE_MAX] = {
+ { 712, 0xD500, -416 }, // MAJORA_REMAINS_TYPE_ODOLWA
+ { -712, 0x2B00, -420 }, // MAJORA_REMAINS_TYPE_GYORG
+ { 702, 0xAB00, 415 }, // MAJORA_REMAINS_TYPE_GOHT
+ { -712, 0x5500, 416 }, // MAJORA_REMAINS_TYPE_TWINMOLD
+};
+
+void Boss07_Init(Actor* thisx, PlayState* play2) {
+ static s16 sMajoraRemainsParams[MAJORA_REMAINS_TYPE_MAX] = {
+ MAJORA_PARAMS(MAJORA_TYPE_REMAINS + MAJORA_REMAINS_TYPE_ODOLWA),
+ MAJORA_PARAMS(MAJORA_TYPE_REMAINS + MAJORA_REMAINS_TYPE_GYORG),
+ MAJORA_PARAMS(MAJORA_TYPE_REMAINS + MAJORA_REMAINS_TYPE_GOHT),
+ MAJORA_PARAMS(MAJORA_TYPE_REMAINS + MAJORA_REMAINS_TYPE_TWINMOLD),
+ };
+ PlayState* play = play2;
+ Boss07* this = THIS;
+ s32 i;
+
+ if (MAJORA_GET_TYPE(&this->actor) == MAJORA_TYPE_BATTLE_HANDLER) {
+ this->actor.update = Boss07_BattleHandler_Update;
+ this->actor.draw = Boss07_BattleHandler_Draw;
+ this->actor.flags &= ~ACTOR_FLAG_ATTENTION_ENABLED;
+ sMajoraBattleHandler = this;
+ sKillAllProjectiles = false;
+ play->envCtx.lightSettingOverride = 0;
+ play->envCtx.lightBlendOverride = LIGHT_BLEND_OVERRIDE_FULL_CONTROL;
+ return;
+ }
+
+ if (MAJORA_GET_TYPE(&this->actor) == MAJORA_TYPE_BATTLE_INIT) {
+ this->actor.params = MAJORA_TYPE_MASK;
+ Actor_Spawn(&play->actorCtx, play, ACTOR_BOSS_07, this->actor.world.pos.x, this->actor.world.pos.y,
+ this->actor.world.pos.z, 0, 0, 0, MAJORA_PARAMS(MAJORA_TYPE_BATTLE_HANDLER));
+ play->specialEffects = (void*)sMajoraEffects;
+
+ for (i = 0; i < MAJORA_EFFECT_COUNT; i++) {
+ sMajoraEffects[i].type = MAJORA_EFFECT_NONE;
+ }
+
+ for (i = 0; i < MAJORA_REMAINS_TYPE_MAX; i++) {
+ sMajoraRemains[i] = NULL;
+ }
+ }
+
+ this->actor.attentionRangeType = ATTENTION_RANGE_5;
+ this->actor.colChkInfo.mass = MASS_HEAVY;
+ this->actor.gravity = -2.5f;
+
+ if (MAJORA_GET_TYPE(thisx) >= MAJORA_TYPE_REMAINS) {
+ this->actor.update = Boss07_Remains_Update;
+ this->actor.draw = Boss07_Remains_Draw;
+
+ sMajoraRemains[MAJORA_GET_TYPE(thisx) - MAJORA_TYPE_REMAINS] = this;
+
+ if (CHECK_EVENTINF(EVENTINF_INTRO_CS_WATCHED_MAJORA)) {
+ Actor_SetScale(&this->actor, 0.03f);
+ this->actor.world.pos.x = sRemainsEndTarget[MAJORA_GET_TYPE(&this->actor) - MAJORA_TYPE_REMAINS].x;
+ this->actor.world.pos.y = 370.0f;
+ this->actor.world.pos.z = sRemainsEndTarget[MAJORA_GET_TYPE(&this->actor) - MAJORA_TYPE_REMAINS].z;
+ this->actor.shape.rot.y = sRemainsEndTarget[MAJORA_GET_TYPE(&this->actor) - MAJORA_TYPE_REMAINS].y;
+ Boss07_Remains_SetupMove(this, play);
+ } else {
+ Boss07_Remains_SetupIntroCutscene(this, play);
+ }
+
+ this->actor.flags &= ~ACTOR_FLAG_ATTENTION_ENABLED;
+ this->actor.colChkInfo.damageTable = &sRemainsDamageTable;
+ return;
+ }
+
+ if (MAJORA_GET_TYPE(&this->actor) == MAJORA_TYPE_TOP) {
+ static EffectTireMarkInit sTopTireMarkInit = { 0, 40, { 0, 0, 15, 200 } };
+
+ this->actor.update = Boss07_Top_Update;
+ this->actor.draw = Boss07_Top_Draw;
+ Boss07_Top_SetupThrown(this, play);
+ this->actor.colChkInfo.damageTable = &sTopDamageTable;
+ ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 9.0f + KREG(55));
+ this->actor.shape.shadowAlpha = 180;
+ Collider_InitAndSetCylinder(play, &this->generalCollider, &this->actor, &sTopCylinderInit);
+ Effect_Add(play, &this->effectIndex, EFFECT_TIRE_MARK, 0, 0, &sTopTireMarkInit);
+ this->actor.flags &= ~ACTOR_FLAG_ATTENTION_ENABLED;
+ return;
+ }
+
+ if ((MAJORA_GET_TYPE(&this->actor) == MAJORA_TYPE_PROJECTILE_REMAINS) ||
+ (MAJORA_GET_TYPE(&this->actor) == MAJORA_TYPE_PROJECTILE_INCARNATION)) {
+ this->actor.update = Boss07_Projectile_Update;
+ this->actor.draw = Boss07_Projectile_Draw;
+ this->actor.flags &= ~ACTOR_FLAG_ATTENTION_ENABLED;
+ Collider_InitAndSetCylinder(play, &this->generalCollider, &this->actor, &sProjectileCylinderInit);
+ Actor_ChangeCategory(play, &play->actorCtx, &this->actor, ACTORCAT_ENEMY);
+ this->projectileColorIndex = Rand_ZeroFloat(ARRAY_COUNT(sProjectileEnvColors) - 0.01f);
+ return;
+ }
+
+ if ((MAJORA_GET_TYPE(&this->actor) == MAJORA_TYPE_MASK) ||
+ (MAJORA_GET_TYPE(&this->actor) == MAJORA_TYPE_MASK_UNK)) {
+ this->actor.colChkInfo.damageTable = &sMajorasMaskDamageTable;
+ ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 15.0f);
+ SkelAnime_Init(play, &this->skelAnime, &gMajorasMaskSkel, &gMajorasMaskFloatingAnim, this->jointTable,
+ this->morphTable, MAJORAS_MASK_LIMB_MAX);
+
+ if (MAJORA_GET_TYPE(&this->actor) == MAJORA_TYPE_MASK) {
+ static EffectTireMarkInit sMaskTireMarkInit = { 0, 40, { 0, 0, 15, 200 } };
+
+ this->actor.update = Boss07_Mask_Update;
+ this->actor.draw = Boss07_Mask_Draw;
+ Effect_Add(play, &this->effectIndex, EFFECT_TIRE_MARK, 0, 0, &sMaskTireMarkInit);
+ sMajorasMask = this;
+
+ if (CHECK_EVENTINF(EVENTINF_INTRO_CS_WATCHED_MAJORA)) {
+ this->actor.world.pos.x = 0.0f;
+ this->actor.world.pos.y = sREG(17) + 277.0f;
+ this->actor.world.pos.z = -922.5f;
+ Boss07_Mask_SetupIdle(this, play);
+ this->targetPos.x = 0.0f;
+ this->targetPos.y = 200.0f;
+ this->targetPos.z = 0.0f;
+ this->speedToTarget = 0.0f;
+ this->timers[0] = 50;
+ this->timers[2] = 200;
+ this->bgCheckTimer = 50;
+ this->actor.flags |= ACTOR_FLAG_ATTENTION_ENABLED;
+ sMusicStartTimer = 20;
+ } else {
+ Boss07_Mask_SetupIntroCutscene(this, play);
+ }
+
+ Collider_InitAndSetQuad(play, &this->maskFrontCollider, &this->actor, &sMaskFrontQuadInit);
+ Collider_InitAndSetQuad(play, &this->maskBackCollider, &this->actor, &sMaskBackQuadInit);
+ this->actor.colChkInfo.health = 14;
+
+ for (i = 0; i < MAJORA_REMAINS_TYPE_MAX; i++) {
+ Actor_Spawn(&play->actorCtx, play, ACTOR_BOSS_07, 0.0f, 0.0f, 0.0f, 0, 0, 0, sMajoraRemainsParams[i]);
+ }
+ }
+ return;
+ }
+
+ if ((MAJORA_GET_TYPE(&this->actor) == MAJORA_TYPE_INCARNATION) ||
+ (MAJORA_GET_TYPE(&this->actor) == MAJORA_TYPE_INCARNATION_AFTERIMAGE)) {
+ Actor_SetScale(&this->actor, 15.0f * 0.001f);
+ SkelAnime_InitFlex(play, &this->skelAnime, &gMajorasIncarnationSkel, &gMajorasIncarnationTauntDance1Anim,
+ this->jointTable, this->morphTable, MAJORAS_INCARNATION_LIMB_MAX);
+
+ if (MAJORA_GET_TYPE(&this->actor) == MAJORA_TYPE_INCARNATION_AFTERIMAGE) {
+ this->timers[0] = this->actor.world.rot.z;
+ this->actor.world.rot.z = 0;
+ this->actor.update = Boss07_IncarnationAfterimage_Update;
+ this->actor.draw = Boss07_IncarnationAfterimage_Draw;
+ this->actor.flags &= ~ACTOR_FLAG_ATTENTION_ENABLED;
+ } else {
+ this->actor.colChkInfo.damageTable = &sMajorasIncarnationDamageTable;
+ this->actor.colChkInfo.health = 30;
+ this->actor.update = Boss07_Incarnation_Update;
+ this->actor.draw = Boss07_Incarnation_Draw;
+ Collider_InitAndSetJntSph(play, &this->bodyCollider, &this->actor, &sIncarnationBodyColliderJntSphInit,
+ this->bodyColliderElements);
+ ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 80.0f);
+ this->subCamId = this->actor.shape.rot.z;
+
+ if (this->subCamId != SUB_CAM_ID_DONE) {
+ Boss07_Incarnation_SetupIntroCutscene(this, play);
+ } else {
+ Boss07_Incarnation_SetupTaunt(this, play);
+ this->lightSettingsMode = 1;
+
+ for (i = 0; i < MAJORAS_INCARNATION_GROW_BODYPART_MAX; i++) {
+ this->incarnationIntroBodyPartsScale[i] = 1.0f;
+ }
+
+ play->envCtx.lightBlend = 0.0f;
+ }
+
+ this->incarnationArmScale = 1.0f;
+ this->incarnationLegScale = 1.0f;
+ this->incarnationMaskScaleY = 1.0f;
+ this->incarnationMaskScaleX = 1.0f;
+ }
+ return;
+ }
+
+ sMajorasWrath = this;
+ this->actor.colChkInfo.health = 40;
+ this->actor.colChkInfo.damageTable = &sMajorasWrathDamageTable;
+ Actor_SetScale(&this->actor, 0.01f);
+ this->subCamId = this->actor.shape.rot.z;
+
+ if (this->subCamId != SUB_CAM_ID_DONE) {
+ Boss07_Wrath_SetupIntroCutscene(this, play);
+ } else {
+ Boss07_Wrath_SetupIdle(this, play, 50);
+ this->whipLengthScale = 1.0f;
+ SEQCMD_PLAY_SEQUENCE(SEQ_PLAYER_BGM_MAIN, 0, NA_BGM_MAJORAS_WRATH | SEQ_FLAG_ASYNC);
+ }
+
+ SkelAnime_InitFlex(play, &this->skelAnime, &gMajorasWrathSkel, &gMajorasWrathIdleAnim, this->jointTable,
+ this->morphTable, MAJORAS_WRATH_LIMB_MAX);
+ Collider_InitAndSetJntSph(play, &this->bodyCollider, &this->actor, &sWrathBodyColliderJntSphInit,
+ this->bodyColliderElements);
+ Collider_InitAndSetJntSph(play, &this->kickCollider, &this->actor, &sWrathKickColliderJntSphInit,
+ this->kickColliderElements);
+ Collider_InitAndSetCylinder(play, &this->unusedCollider, &this->actor, &sWrathCylinderInit);
+
+ this->leftWhip.mobility = this->rightWhip.mobility = 0.7f;
+ this->leftWhip.deceleration = this->rightWhip.deceleration = 2.0f;
+ this->leftWhip.gravity = this->rightWhip.gravity = -15.0f;
+ this->leftWhip.tension = this->rightWhip.tension = 0.0f;
+
+ sWhipLength = MAJORA_WHIP_LENGTH;
+ this->incarnationArmScale = 1.0f;
+}
+
+void Boss07_Destroy(Actor* thisx, PlayState* play2) {
+ PlayState* play = play2;
+ Boss07* this = THIS;
+
+ switch (this->actor.params) {
+ //! @bug this should be MAJORAS_MASK
+ case MAJORA_TYPE_WRATH:
+ Collider_DestroyQuad(play, &this->maskFrontCollider);
+ Collider_DestroyQuad(play, &this->maskBackCollider);
+ FALLTHROUGH;
+ case MAJORA_TYPE_TOP:
+ Effect_Destroy(play, this->effectIndex);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Boss07_Wrath_SetupIntroCutscene(Boss07* this, PlayState* play) {
+ this->actionFunc = Boss07_Wrath_IntroCutscene;
+ Animation_MorphToLoop(&this->skelAnime, &gMajorasWrathHeavyBreathingAnim, 0.0f);
+ this->actor.flags &= ~ACTOR_FLAG_ATTENTION_ENABLED;
+ this->cutsceneHeadRot.x = 0x7F00;
+ this->damagedTimer = 20;
+ this->incarnationWrathTransitionScale = 0x1400;
+}
+
+typedef struct MajorasWrathIntroCutsceneCamPoints {
+ /* 0x0 */ f32 eyeY;
+ /* 0x4 */ f32 eyeZ;
+ /* 0x8 */ f32 atY;
+} MajorasWrathIntroCutsceneCamPoints; // size = 0xC
+
+void Boss07_Wrath_IntroCutscene(Boss07* this, PlayState* play) {
+ // sCamPoints reads playerForm in a different order than the enum
+ static MajorasWrathIntroCutsceneCamPoints sCamPoints[PLAYER_FORM_MAX] = {
+ { 40.0f, 400.0f, 110.0f }, // PLAYER_FORM_HUMAN
+ { 80.0f, 450.0f, 110.0f }, // PLAYER_FORM_GORON
+ { 100.0f, 400.0f, 110.0f }, // PLAYER_FORM_FIERCE_DEITY
+ { 60.0f, 390.0f, 110.0f }, // PLAYER_FORM_ZORA
+ { 30.0f, 430.0f, 110.0f }, // PLAYER_FORM_DEKU
+ };
+
+ this->damagedTimer = 20;
+ SkelAnime_Update(&this->skelAnime);
+ this->cutsceneTimer++;
+ Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, MTXMODE_NEW);
+ Matrix_RotateYS(this->actor.shape.rot.y, MTXMODE_APPLY);
+
+ switch (this->cutsceneState) {
+ case MAJORAS_WRATH_INTRO_CS_STATE_STARTING_OR_DONE:
+ this->cutsceneTimer = 0;
+ this->cutsceneState = MAJORAS_WRATH_INTRO_CS_STATE_PLAYING;
+ this->subCamAtNext.z = 0.f;
+ this->subCamEyeNext.x = 0.0;
+ this->subCamEyeNext.y = KREG(17) + 100.0f - 30.0f + 80.0f;
+ this->subCamEyeNext.z = KREG(18) + 270.0f - 150.0f + 30.0f - 50.0f;
+ this->subCamAtNext.x = 0.0f;
+ this->subCamAtNext.y = 180.0f;
+ FALLTHROUGH;
+ case MAJORAS_WRATH_INTRO_CS_STATE_PLAYING:
+ if (this->cutsceneTimer < 40) {
+ sHeartbeatTimer = 3;
+ }
+
+ if (this->cutsceneTimer > 20) {
+ if (this->cutsceneTimer == 21) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_GROW_HEAD_OLD);
+ }
+
+ Math_ApproachS(&this->cutsceneHeadRot.x, 0, 5, 0x1000);
+ this->cutsceneHeadRot.y =
+ Math_SinS(this->cutsceneTimer * 0x1000) * this->incarnationWrathTransitionScale;
+ this->cutsceneHeadRot.z =
+ Math_SinS(this->cutsceneTimer * 0xB00) * this->incarnationWrathTransitionScale * 0.5f;
+
+ if (this->cutsceneTimer > 40) {
+ Math_ApproachZeroF(&this->incarnationWrathTransitionScale, 1.0f, 200.0f);
+ }
+ }
+
+ if (this->cutsceneTimer > 60) {
+ s32 camPointIndex = 0;
+ Player* player = GET_PLAYER(play);
+
+ if (player->transformation == PLAYER_FORM_GORON) {
+ camPointIndex = 1;
+ } else if (player->transformation == PLAYER_FORM_FIERCE_DEITY) {
+ camPointIndex = 2;
+ } else if (player->transformation == PLAYER_FORM_ZORA) {
+ camPointIndex = 3;
+ } else if (player->transformation == PLAYER_FORM_DEKU) {
+ camPointIndex = 4;
+ }
+
+ Math_ApproachF(&this->subCamEyeNext.y, sCamPoints[camPointIndex].eyeY, 0.075f,
+ this->subCamVelocity * 7.0f);
+ Math_ApproachF(&this->subCamEyeNext.z, sCamPoints[camPointIndex].eyeZ, 0.075f,
+ this->subCamVelocity * 17.0f);
+ Math_ApproachF(&this->subCamAtNext.y, sCamPoints[camPointIndex].atY, 0.075f,
+ this->subCamVelocity * 7.0f);
+ Math_ApproachF(&this->subCamVelocity, 1.0f, 1.0f, 0.01f);
+
+ if (this->cutsceneTimer == 70) {
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasWrathIntroAnim, -15.0f);
+ this->animEndFrame = Animation_GetLastFrame(&gMajorasWrathIntroAnim);
+ Audio_PlaySfx_AtPosWithVolume(&this->actor.projectedPos, NA_SE_EV_ICE_PILLAR_RISING, 1.0f);
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_SHOUT);
+ }
+
+ if (this->cutsceneTimer >= 110) {
+ Math_ApproachF(&this->whipLengthScale, 1.0f, 1.0f, 0.05f);
+ this->leftWhip.mobility = this->rightWhip.mobility = 0.01f * 80;
+ this->leftWhip.deceleration = this->rightWhip.deceleration = 1.0f;
+ }
+
+ if (this->cutsceneTimer == 127) {
+ this->whipLengthScale = 1.0f;
+ }
+
+ if (this->cutsceneTimer == 120) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST3_ROD_HOP2_OLD);
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_LAST3_VOICE_KICK_OLD);
+ Audio_SetSfxVolumeTransition(&gSfxVolume, 0.0f, 60);
+ }
+
+ if (this->cutsceneTimer == 112) {
+ SEQCMD_PLAY_SEQUENCE(SEQ_PLAYER_BGM_MAIN, 0, NA_BGM_MAJORAS_WRATH | SEQ_FLAG_ASYNC);
+ }
+
+ if (this->cutsceneTimer == 137) {
+ TitleCard_InitBossName(&play->state, &play->actorCtx.titleCtx,
+ Lib_SegmentedToVirtual(&gMajorasWrathTitleCardTex), 160, 180, 128, 40);
+ }
+
+ if (Animation_OnFrame(&this->skelAnime, this->animEndFrame)) {
+ s32 i;
+ Camera* mainCam = Play_GetCamera(play, CAM_ID_MAIN);
+
+ this->cutsceneState = MAJORAS_WRATH_INTRO_CS_STATE_STARTING_OR_DONE;
+ Boss07_Wrath_SetupIdle(this, play, 50);
+ mainCam->eye = this->subCamEye;
+ mainCam->eyeNext = this->subCamEye;
+ mainCam->at = this->subCamAt;
+ func_80169AFC(play, this->subCamId, 0);
+ this->subCamId = SUB_CAM_ID_DONE;
+ Cutscene_StopManual(play, &play->csCtx);
+ Player_SetCsActionWithHaltedActors(play, &this->actor, PLAYER_CSACTION_END);
+ this->actor.flags |= ACTOR_FLAG_ATTENTION_ENABLED;
+ Play_DisableMotionBlur();
+
+ if (sMajoraRemains[MAJORA_REMAINS_TYPE_ODOLWA] != NULL) {
+ for (i = 0; i < MAJORA_REMAINS_TYPE_MAX; i++) {
+ Actor_ChangeCategory(play, &play->actorCtx, &sMajoraRemains[i]->actor, ACTORCAT_BOSS);
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ Matrix_MultVec3f(&this->subCamEyeNext, &this->subCamEye);
+ Matrix_MultVec3f(&this->subCamAtNext, &this->subCamAt);
+
+ if (this->subCamId != SUB_CAM_ID_DONE) {
+ ShrinkWindow_Letterbox_SetSizeTarget(27);
+ Play_SetCameraAtEye(play, this->subCamId, &this->subCamAt, &this->subCamEye);
+ }
+}
+
+void Boss07_Wrath_SetupDeathCutscene(Boss07* this, PlayState* play) {
+ s32 i;
+
+ SEQCMD_STOP_SEQUENCE(SEQ_PLAYER_BGM_MAIN, 1);
+ Boss07_MovePlayerFromCenter(play);
+ this->actionFunc = Boss07_Wrath_DeathCutscene;
+
+ this->leftWhip.mobility = this->rightWhip.mobility = 0.7f;
+ this->leftWhip.deceleration = this->rightWhip.deceleration = 2.0f;
+ this->leftWhip.tension = this->rightWhip.tension = 0.0f;
+ this->leftWhip.gravity = this->rightWhip.gravity = -15.0f;
+
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasWrathDeathAnim, 0.0f);
+ this->actor.flags &= ~ACTOR_FLAG_ATTENTION_ENABLED;
+ this->cutsceneState = MAJORAS_WRATH_DEATH_CS_STATE_STARTED;
+ this->cutsceneTimer = 0;
+
+ if (sMajoraRemains[MAJORA_REMAINS_TYPE_ODOLWA] != NULL) {
+ for (i = 0; i < MAJORA_REMAINS_TYPE_MAX; i++) {
+ sMajoraRemains[i]->subAction = REMAINS_MOVE_SUB_ACTION_DIE;
+ }
+ }
+
+ this->damagedTimer = 1000;
+}
+
+void Boss07_Wrath_DeathCutscene(Boss07* this, PlayState* play) {
+ s32 i;
+ s32 isCamCloseUp = false;
+ Vec3f subCamEyeOffset;
+ Vec3f subCamAtOffset = { 0.0f, 0.0f, 0.0f };
+ // clang-format off
+ f32 subCamMaxStepOffset = 0.0f; \
+ f32 subCamScale = 0.1f;
+ // clang-format on
+ Camera* mainCam = Play_GetCamera(play, CAM_ID_MAIN);
+
+ this->damagedTimer = 1000;
+ Boss07_SmoothStop(this, 1.0f);
+
+ switch (this->cutsceneState) {
+ case MAJORAS_WRATH_DEATH_CS_STATE_STARTED:
+ if (CutsceneManager_GetCurrentCsId() != CS_ID_NONE) {
+ break;
+ }
+
+ Cutscene_StartManual(play, &play->csCtx);
+ Player_SetCsActionWithHaltedActors(play, &this->actor, PLAYER_CSACTION_1);
+ this->subCamId = Play_CreateSubCamera(play);
+ Play_ChangeCameraStatus(play, CAM_ID_MAIN, CAM_STATUS_WAIT);
+ Play_ChangeCameraStatus(play, this->subCamId, CAM_STATUS_ACTIVE);
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST3_DEAD_ROD);
+ FALLTHROUGH;
+ case MAJORAS_WRATH_DEATH_CS_STATE_UPDATE_SUBCAM:
+ this->cutsceneTimer = 0;
+ this->cutsceneState = MAJORAS_WRATH_DEATH_CS_STATE_SPIN_AROUND;
+ this->subCamEye.x = mainCam->eye.x;
+ this->subCamEye.y = mainCam->eye.y;
+ this->subCamEye.z = mainCam->eye.z;
+ this->subCamAt.x = mainCam->at.x;
+ this->subCamAt.y = mainCam->at.y;
+ this->subCamAt.z = mainCam->at.z;
+ this->subCamRotY = this->actor.shape.rot.y * M_PIf / 0x8000;
+ this->subCamAngularVelocity = this->subCamVelocity = sMajoraBattleHandler->lensFlareScale = 0.0f;
+ Boss07_InitRand(1, 0x71AC, 0x263A);
+
+ for (i = 0; i < ARRAY_COUNT(this->deathLightScale); i++) {
+ this->deathLightScale[i] = Boss07_RandZeroOne() - 1.0f;
+ }
+
+ Play_EnableMotionBlur(150);
+ FALLTHROUGH;
+ case MAJORAS_WRATH_DEATH_CS_STATE_SPIN_AROUND:
+ if (this->cutsceneTimer == 20) {
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_LAST2_WALK2_OLD);
+ }
+
+ if (this->cutsceneTimer == 40) {
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_LAST2_WALK2_OLD);
+ }
+
+ if (this->cutsceneTimer == 60) {
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_LAST2_WALK2_OLD);
+ }
+
+ if (this->cutsceneTimer == 80) {
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_LAST2_WALK2_OLD);
+ }
+
+ subCamEyeOffset.x = 0.0f;
+ subCamEyeOffset.y = -90.0f;
+ subCamEyeOffset.z = 350.0f;
+ this->subCamAtNext.x = this->actor.focus.pos.x;
+ this->subCamAtNext.y = this->actor.focus.pos.y - 40.0f;
+ this->subCamAtNext.z = this->actor.focus.pos.z;
+
+ if ((this->cutsceneTimer >= 50) && (this->cutsceneTimer < 80)) {
+ if (this->cutsceneTimer == 50) {
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_LAST3_DEAD_WIND1_OLD);
+ }
+
+ subCamEyeOffset.x = 30.0f;
+ subCamEyeOffset.z = 120.0f;
+ this->subCamAtNext.y = this->actor.focus.pos.y - 40.0f + 30.0f;
+ subCamMaxStepOffset = 200.0f;
+ subCamScale = 1.0f;
+ } else if ((this->cutsceneTimer >= 80) && (this->cutsceneTimer < 110)) {
+ if (this->cutsceneTimer == 80) {
+ this->skelAnime.curFrame -= 30.0f;
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_LAST3_DEAD_WIND2_OLD);
+ }
+
+ subCamEyeOffset.x = -10.0f;
+ subCamEyeOffset.z = 150.0f;
+ this->subCamAtNext.y = this->actor.focus.pos.y - 40.0f - 60.0f;
+ subCamMaxStepOffset = 200.0f;
+ subCamScale = 1.0f;
+ } else if ((this->cutsceneTimer >= 110) && (this->cutsceneTimer < 140)) {
+ if (this->cutsceneTimer == 110) {
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_LAST3_DEAD_WIND3_OLD);
+ }
+
+ subCamEyeOffset.x = -70.0f;
+ subCamEyeOffset.z = 110.0f;
+ this->subCamAtNext.y = this->actor.focus.pos.y - 40.0f + 30.0f;
+ subCamMaxStepOffset = 200.0f;
+ subCamScale = 1.0f;
+ }
+
+ if (this->cutsceneTimer < (u32)(sREG(15) + 140)) {
+ break;
+ }
+
+ this->cutsceneState = MAJORAS_WRATH_DEATH_CS_STATE_FLOAT;
+ this->subCamEyeModY = sREG(16) + 270.0f + 50.0f;
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_LAST3_DEAD_FLOAT);
+ FALLTHROUGH;
+ case MAJORAS_WRATH_DEATH_CS_STATE_FLOAT:
+ if ((this->cutsceneTimer >= (u32)(sREG(90) + 260)) && (this->cutsceneTimer < (u32)(sREG(91) + 370))) {
+ isCamCloseUp = KREG(14) + 1;
+ this->subCamRotY = this->actor.shape.rot.y * M_PIf / 0x8000;
+
+ subCamEyeOffset.x = 0.0f;
+ subCamEyeOffset.y = this->subCamEyeModY + -190.0f;
+ subCamEyeOffset.z = sREG(17) + 390.0f - 380.0f;
+
+ this->subCamAtNext.x = this->actor.focus.pos.x;
+ this->subCamAtNext.y = this->actor.focus.pos.y - 40.0f - 60.0f + sREG(18) + 130.0f;
+ this->subCamAtNext.z = this->actor.focus.pos.z;
+
+ Math_ApproachF(&this->subCamEyeModY, sREG(19) + 240.0f, 0.05f, 1.0f + (sREG(20) * 0.1f));
+ subCamMaxStepOffset = 2000.0f;
+ subCamScale = 1.0f;
+
+ this->maxDecayPixels = KREG(81) + 10;
+ this->disableShadow = true;
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EV_BURN_OUT - SFX_FLAG);
+ } else {
+ subCamEyeOffset.x = 0.0f;
+ subCamEyeOffset.y = -190.0f;
+ subCamEyeOffset.z = 390.0f;
+ this->subCamAtNext.x = this->actor.focus.pos.x;
+ this->subCamAtNext.y = this->actor.focus.pos.y - 40.0f - 60.0f;
+ this->subCamAtNext.z = this->actor.focus.pos.z;
+ this->maxDecayPixels = 0;
+
+ if (this->cutsceneTimer > 330) {
+ subCamMaxStepOffset = 2000.0f;
+ subCamScale = 1.0f;
+ }
+
+ Math_ApproachZeroF(&this->actor.world.pos.x, 0.1f, this->subCamVelocity);
+ Math_ApproachZeroF(&this->actor.world.pos.z, 0.1f, this->subCamVelocity);
+ Math_ApproachF(&this->subCamVelocity, 5.0f, 1.0f, 0.1f);
+ }
+
+ if (this->cutsceneTimer >= 260) {
+ f32 deathLightScaleTarget;
+ f32 deathLightScaleMaxStep;
+ s16 screenFillAlpha;
+
+ if (this->cutsceneTimer == 260) {
+ Audio_PlaySfx_AtPosWithVolumeTransition(&sMajoraSfxPos, NA_SE_EN_LAST3_DEAD_LIGHTS_OLD, 60);
+ }
+
+ play->envCtx.fillScreen = true;
+ play->envCtx.screenFillColor[0] = play->envCtx.screenFillColor[1] = play->envCtx.screenFillColor[2] =
+ 255;
+
+ if (this->cutsceneTimer < 350) {
+ deathLightScaleTarget = 0.5f;
+ deathLightScaleMaxStep = 0.02f;
+ play->envCtx.screenFillColor[3] = 0;
+ } else {
+ deathLightScaleTarget = 5.0f;
+ deathLightScaleMaxStep = 0.1f;
+ screenFillAlpha = (this->cutsceneTimer * 2) - 700;
+ if (screenFillAlpha > 250) {
+ screenFillAlpha = 250;
+ }
+
+ play->envCtx.screenFillColor[3] = screenFillAlpha;
+
+ if (this->cutsceneTimer == 400) {
+ Audio_SetSfxVolumeTransition(&gSfxVolume, 0.0f, 90);
+ }
+ if (this->cutsceneTimer == (u32)(KREG(94) + 440)) {
+ play->nextEntrance = ENTRANCE(TERMINA_FIELD, 0);
+ gSaveContext.nextCutsceneIndex = 0xFFF7;
+ play->transitionTrigger = TRANS_TRIGGER_START;
+ }
+ }
+ if (this->cutsceneTimer > 300) {
+ sMajoraBattleHandler->lensFlareOn = true;
+ Math_ApproachF(&sMajoraBattleHandler->lensFlareScale, 30.0f, 0.1f, 1.5f);
+ sMajoraBattleHandler->lensFlarePos = this->bodyPartsPos[MAJORAS_WRATH_BODYPART_PELVIS];
+ Math_ApproachF(&this->deathOrbScale, 1.0f, 0.1f, 0.05f);
+
+ for (i = 0; i < ARRAY_COUNT(this->deathLightScale); i++) {
+ Math_ApproachF(&this->deathLightScale[i], deathLightScaleTarget, 1.0f, deathLightScaleMaxStep);
+ }
+
+ Math_ApproachF(&play->envCtx.lightBlend, 1.0f, 1.0f, 0.1f);
+ }
+ }
+
+ this->subCamRotY += this->subCamAngularVelocity;
+ this->subCamAngularVelocity += 0.0004f;
+ if (this->subCamAngularVelocity > 0.02f) {
+ this->subCamAngularVelocity = 0.02f;
+ }
+
+ if (this->cutsceneTimer >= (u32)(sREG(93) + 180)) {
+ Vec3f hahenVelocity = { 0.0f, 10.0f, 0.0f };
+ Vec3f hahenAccel = { 0.0f, -0.5f, 0.0f };
+ Vec3f hahenPos;
+ f32 cameraShakeMagnitude;
+
+ Audio_PlaySfx(NA_SE_EV_EARTHQUAKE_LAST2 - SFX_FLAG);
+
+ if (!isCamCloseUp) {
+ cameraShakeMagnitude = 2.0f;
+ } else {
+ cameraShakeMagnitude = (KREG(53) * 0.01f) + 0.2f;
+ }
+
+ subCamAtOffset.x = Math_SinS(this->cutsceneTimer * 0x7000) * cameraShakeMagnitude;
+ subCamAtOffset.y = Math_SinS(this->cutsceneTimer * 0x5000) * cameraShakeMagnitude * 2.5f;
+ subCamAtOffset.z = Math_CosS(this->cutsceneTimer * 0x8000) * cameraShakeMagnitude;
+
+ for (i = 0; i < 2; i++) {
+ hahenPos.x = Rand_CenteredFloat(500.0f) + this->actor.world.pos.x;
+ hahenPos.y = Rand_ZeroFloat(50.0f) + this->actor.world.pos.y + 200.0f;
+ hahenPos.z = Rand_CenteredFloat(500.0f) + this->actor.world.pos.z;
+ EffectSsHahen_Spawn(play, &hahenPos, &hahenVelocity, &hahenAccel, 0, Rand_ZeroFloat(5.0f) + 20.0f,
+ HAHEN_OBJECT_DEFAULT, 10, NULL);
+ }
+ }
+
+ if (this->cutsceneTimer >= (u32)(sREG(94) + 290)) {
+ this->maxDecayPixels = KREG(86) + 25;
+ Math_ApproachZeroF(&this->whipLengthScale, 1.0f, 0.015f);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ Matrix_RotateYF(this->subCamRotY, MTXMODE_NEW);
+ Matrix_MultVec3f(&subCamEyeOffset, &this->subCamEyeNext);
+ this->subCamEyeNext.x += this->actor.focus.pos.x;
+ this->subCamEyeNext.y += this->actor.focus.pos.y;
+ this->subCamEyeNext.z += this->actor.focus.pos.z;
+
+ Math_ApproachF(&this->subCamEye.x, this->subCamEyeNext.x, subCamScale, 40.0f + subCamMaxStepOffset);
+ Math_ApproachF(&this->subCamEye.y, this->subCamEyeNext.y, subCamScale, 40.0f + subCamMaxStepOffset);
+ Math_ApproachF(&this->subCamEye.z, this->subCamEyeNext.z, subCamScale, 40.0f + subCamMaxStepOffset);
+
+ Math_ApproachF(&this->subCamAt.x, this->subCamAtNext.x, subCamScale, 70.0f + subCamMaxStepOffset);
+ Math_ApproachF(&this->subCamAt.y, this->subCamAtNext.y, subCamScale, 70.0f + subCamMaxStepOffset);
+ Math_ApproachF(&this->subCamAt.z, this->subCamAtNext.z, subCamScale, 70.0f + subCamMaxStepOffset);
+
+ if (this->subCamId != SUB_CAM_ID_DONE) {
+ Vec3f subCamAt;
+
+ subCamAt.x = this->subCamAt.x + subCamAtOffset.x;
+ subCamAt.y = this->subCamAt.y + subCamAtOffset.y;
+ subCamAt.z = this->subCamAt.z + subCamAtOffset.z;
+ Play_SetCameraAtEye(play, this->subCamId, &subCamAt, &this->subCamEye);
+ }
+
+ SkelAnime_Update(&this->skelAnime);
+ this->cutsceneTimer++;
+}
+
+void Boss07_Wrath_SetupIdle(Boss07* this, PlayState* play, s16 idleTimer) {
+ this->actionFunc = Boss07_Wrath_Idle;
+ Animation_MorphToLoop(&this->skelAnime, &gMajorasWrathIdleAnim, -10.0f);
+
+ if (idleTimer != 0) {
+ this->timers[0] = idleTimer;
+ } else {
+ this->timers[0] = Rand_ZeroFloat(30.0f);
+ }
+
+ this->actor.flags |= ACTOR_FLAG_ATTENTION_ENABLED;
+}
+
+void Boss07_Wrath_Idle(Boss07* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+
+ SkelAnime_Update(&this->skelAnime);
+ Boss07_SmoothStop(this, 2.0f);
+
+ this->rightWhip.mobility = this->leftWhip.mobility = 0.7f;
+ this->rightWhip.gravity = this->leftWhip.gravity = -15.0f;
+ this->rightWhip.deceleration = this->leftWhip.deceleration = 2.0f;
+ this->leftWhip.tension = this->rightWhip.tension = 0.0f;
+
+ if ((this->actor.xzDistToPlayer <= 200.0f) && (player->actor.world.pos.y < 10.0f)) {
+ if (Rand_ZeroOne() < 0.3f) {
+ this->actor.xzDistToPlayer = 250.0f;
+ }
+
+ Boss07_Wrath_SetupAttack(this, play);
+ } else if (this->timers[0] == 0) {
+ if (KREG(78) == 1) {
+ Boss07_Wrath_SetupThrowTop(this, play);
+ } else if ((s8)this->actor.colChkInfo.health >= 28) {
+ Boss07_Wrath_SetupAttack(this, play);
+ } else if (((s8)this->actor.colChkInfo.health <= 12) && (Rand_ZeroOne() < 0.65f)) {
+ Boss07_Wrath_SetupThrowTop(this, play);
+ } else if (Rand_ZeroOne() < 0.3f) {
+ Boss07_Wrath_SetupTryGrab(this, play);
+ } else {
+ Boss07_Wrath_SetupAttack(this, play);
+ }
+ }
+
+ Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 0xA, 0x1000);
+ this->canEvade = true;
+}
+
+void Boss07_Wrath_SetupJump(Boss07* this, PlayState* play) {
+ this->actionFunc = Boss07_Wrath_StartJump;
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasWrathBackflipAnim, -5.0f);
+ this->frameCounter = 0;
+}
+
+void Boss07_Wrath_StartJump(Boss07* this, PlayState* play) {
+ SkelAnime_Update(&this->skelAnime);
+ this->leftWhip.mobility = this->rightWhip.mobility = 0.7f;
+ this->leftWhip.deceleration = this->rightWhip.deceleration = 2.0f;
+ this->leftWhip.gravity = this->rightWhip.gravity = -15.0f;
+ this->leftWhip.tension = this->rightWhip.tension = 0.0f;
+
+ if (this->frameCounter == 1) {
+ this->actor.velocity.y = 35.0f;
+ this->actor.world.rot.y = Math_Atan2F_XY(-this->actor.world.pos.z, -this->actor.world.pos.x) * (0x8000 / M_PIf);
+ this->actionFunc = Boss07_Wrath_Jump;
+ this->actor.speed = 20.0f;
+ }
+}
+
+void Boss07_Wrath_Jump(Boss07* this, PlayState* play) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_MIBOSS_JUMP2 - SFX_FLAG);
+
+ if (this->frameCounter == 13) {
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_LAST3_VOICE_LAUGH_OLD);
+ }
+
+ SkelAnime_Update(&this->skelAnime);
+
+ if (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND) {
+ Boss07_Wrath_SetupIdle(this, play, 1);
+ this->landSfxTimer = 5;
+ }
+
+ Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 3, 0x4000);
+}
+
+void Boss07_Wrath_SetupFlip(Boss07* this, PlayState* play) {
+ Vec3f direction;
+ Vec3f targetPos;
+ s16 yawDiff;
+
+ this->actionFunc = Boss07_Wrath_Flip;
+ this->actor.velocity.y = 25.0f;
+ direction.x = 0.0f - this->actor.world.pos.x;
+ direction.z = 0.0f - this->actor.world.pos.z;
+
+ yawDiff = this->actor.yawTowardsPlayer - (s16)(Math_Atan2F_XY(direction.z, direction.x) * (0x8000 / M_PIf));
+ if (yawDiff < 0) {
+ direction.x = 200.0f;
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasWrathFlipLeftAnim, -5.0f);
+ } else {
+ direction.x = -200.0f;
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasWrathFlipRightAnim, -5.0f);
+ }
+
+ Matrix_RotateYS(this->actor.yawTowardsPlayer, MTXMODE_NEW);
+ Matrix_MultVecX(direction.x, &targetPos);
+ direction.x = targetPos.x - this->actor.world.pos.x;
+ direction.z = targetPos.z - this->actor.world.pos.z;
+ this->actor.world.rot.y = Math_Atan2F_XY(direction.z, direction.x) * (0x8000 / M_PIf);
+ this->frameCounter = 0;
+ this->actor.speed = 17.0f;
+}
+
+void Boss07_Wrath_Flip(Boss07* this, PlayState* play) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_MIBOSS_JUMP2 - SFX_FLAG);
+ SkelAnime_Update(&this->skelAnime);
+ this->leftWhip.mobility = this->rightWhip.mobility = 0.7f;
+ this->leftWhip.deceleration = this->rightWhip.deceleration = 2.0f;
+ this->leftWhip.gravity = this->rightWhip.gravity = -15.0f;
+ this->leftWhip.tension = this->rightWhip.tension = 0.0f;
+
+ if ((this->frameCounter == 10) && (Rand_ZeroOne() < 0.5f)) {
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_LAST3_VOICE_LAUGH_OLD);
+ }
+
+ if ((this->actor.velocity.y < 0.0f) && (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND)) {
+ if (Rand_ZeroOne() < 0.3f) {
+ Boss07_Wrath_ChooseJump(this, play, true);
+ } else {
+ Boss07_Wrath_SetupIdle(this, play, 1);
+ this->actor.speed = 5.0f;
+ }
+
+ this->landSfxTimer = 5;
+ }
+
+ Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 3, 0x4000);
+}
+
+void Boss07_Wrath_SetupSidestep(Boss07* this, PlayState* play) {
+ Vec3f direction;
+ s16 yawDiff;
+
+ this->actionFunc = Boss07_Wrath_Sidestep;
+ Animation_MorphToLoop(&this->skelAnime, &gMajorasWrathSidestepAnim, -5.0f);
+ direction.x = -this->actor.world.pos.x;
+ direction.z = -this->actor.world.pos.z;
+ yawDiff = this->actor.yawTowardsPlayer - (s16)(Math_Atan2F_XY(direction.z, direction.x) * (0x8000 / M_PIf));
+ Matrix_RotateYS(this->actor.shape.rot.y, MTXMODE_NEW);
+
+ if (yawDiff < 0) {
+ this->skelAnime.playSpeed = 1.0f;
+ direction.x = 300.0f;
+ } else {
+ this->skelAnime.playSpeed = -1.0f;
+ direction.x = -300.0f;
+ }
+
+ Matrix_MultVecX(direction.x, &this->targetPos);
+ this->targetPos.x += this->actor.world.pos.x;
+ this->targetPos.z += this->actor.world.pos.z;
+ this->timers[1] = 21;
+ this->disableCollisionTimer = 10;
+ this->speedToTarget = 0.0f;
+ this->sfxTimer = 0;
+}
+
+void Boss07_Wrath_Sidestep(Boss07* this, PlayState* play) {
+ SkelAnime_Update(&this->skelAnime);
+
+ if (this->frameCounter == 20) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST3_VOICE_KICK_OLD);
+ }
+
+ this->sfxTimer++;
+ if ((this->sfxTimer % 16) == 0) {
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_LAST2_WALK2_OLD);
+ }
+
+ this->leftWhip.mobility = this->rightWhip.mobility = 0.7f;
+ this->leftWhip.deceleration = this->rightWhip.deceleration = 2.0f;
+ this->leftWhip.gravity = this->rightWhip.gravity = -15.0f;
+ this->leftWhip.tension = this->rightWhip.tension = 0.0f;
+
+ Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 0xA, 0x1000);
+ Math_ApproachF(&this->actor.world.pos.x, this->targetPos.x, 0.8f, this->speedToTarget);
+ Math_ApproachF(&this->actor.world.pos.z, this->targetPos.z, 0.8f, this->speedToTarget);
+ Math_ApproachF(&this->speedToTarget, 20.0f, 1.0f, 10.0f);
+
+ if (this->timers[1] == 0) {
+ if (Rand_ZeroOne() < 0.3f) {
+ Boss07_Wrath_SetupSidestep(this, play);
+ } else {
+ Boss07_Wrath_SetupIdle(this, play, 1);
+ }
+ }
+}
+
+void Boss07_Wrath_SetupAttack(Boss07* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+
+ this->actionFunc = Boss07_Wrath_Attack;
+ this->timers[1] = 0;
+
+ if (player->stateFlags3 & PLAYER_STATE3_100) {
+ this->subAction = MAJORAS_WRATH_ATTACK_SUB_ACTION_SPIN_ATTACK;
+ } else if (this->actor.xzDistToPlayer <= 300.0f) {
+ if (this->actor.xzDistToPlayer <= 200.0f) {
+ this->subAction = MAJORAS_WRATH_ATTACK_SUB_ACTION_KICK;
+ } else {
+ this->subAction = MAJORAS_WRATH_ATTACK_SUB_ACTION_SPIN_ATTACK;
+ }
+ } else {
+ this->subAction = Rand_ZeroFloat(MAJORAS_WRATH_ATTACK_SUB_ACTION_WHIP_ATTACK_MAX - 0.01f);
+
+ if (((s8)this->actor.colChkInfo.health >= 28) &&
+ ((this->subAction == MAJORAS_WRATH_ATTACK_SUB_ACTION_FLURRY) ||
+ (this->subAction == MAJORAS_WRATH_ATTACK_SUB_ACTION_DOUBLE_WHIP))) {
+ this->subAction = MAJORAS_WRATH_ATTACK_SUB_ACTION_QUICK_WHIP;
+ }
+ }
+
+ switch (this->subAction) {
+ case MAJORAS_WRATH_ATTACK_SUB_ACTION_QUICK_WHIP:
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasWrathShortSingleWhipAttackAnim, -5.0f);
+ this->animEndFrame = Animation_GetLastFrame(&gMajorasWrathShortSingleWhipAttackAnim);
+ break;
+
+ case MAJORAS_WRATH_ATTACK_SUB_ACTION_FLURRY:
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasWrathWhipFlurryAttackAnim, -5.0f);
+ this->animEndFrame = Animation_GetLastFrame(&gMajorasWrathWhipFlurryAttackAnim);
+ break;
+
+ case MAJORAS_WRATH_ATTACK_SUB_ACTION_DOUBLE_WHIP:
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasWrathDoubleWhipAttackAnim, -5.0f);
+ this->animEndFrame = Animation_GetLastFrame(&gMajorasWrathDoubleWhipAttackAnim);
+ break;
+
+ case MAJORAS_WRATH_ATTACK_SUB_ACTION_LONG_WHIP:
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasWrathLongSingleWhipAttackAnim, -5.0f);
+ this->animEndFrame = Animation_GetLastFrame(&gMajorasWrathLongSingleWhipAttackAnim);
+ break;
+
+ case MAJORAS_WRATH_ATTACK_SUB_ACTION_SPIN_ATTACK:
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasWrathSpinAttackAnim, -5.0f);
+ this->animEndFrame = Animation_GetLastFrame(&gMajorasWrathSpinAttackAnim);
+ Boss07_RandXZ(&this->targetPos, 650.0f);
+ this->speedToTarget = 0.0f;
+ break;
+
+ case MAJORAS_WRATH_ATTACK_SUB_ACTION_TAUNT:
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasWrathTauntAnim, -5.0f);
+ this->animEndFrame = Animation_GetLastFrame(&gMajorasWrathTauntAnim);
+ break;
+
+ case MAJORAS_WRATH_ATTACK_SUB_ACTION_THREE_HIT:
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasWrathThreeAttackComboAnim, -5.0f);
+ this->animEndFrame = Animation_GetLastFrame(&gMajorasWrathThreeAttackComboAnim);
+ break;
+
+ case MAJORAS_WRATH_ATTACK_SUB_ACTION_KICK:
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasWrathKickAnim, -5.0f);
+ this->animEndFrame = Animation_GetLastFrame(&gMajorasWrathKickAnim);
+ break;
+
+ default:
+ break;
+ }
+
+ this->frameCounter = 0;
+}
+
+void Boss07_Wrath_Attack(Boss07* this, PlayState* play) {
+ SkelAnime_Update(&this->skelAnime);
+ Boss07_SmoothStop(this, 2.0f);
+ this->leftWhip.mobility = this->rightWhip.mobility = 0.01f * 80;
+ this->leftWhip.gravity = this->rightWhip.gravity = -5.0f;
+ this->leftWhip.tension = this->rightWhip.tension = 0.0f;
+ this->leftWhip.deceleration = this->rightWhip.deceleration = 1.0f;
+
+ if (this->frameCounter > 20) {
+ this->canEvade = true;
+ }
+
+ switch (this->subAction) {
+ case MAJORAS_WRATH_ATTACK_SUB_ACTION_QUICK_WHIP:
+ if (this->frameCounter == (s16)(KREG(92) + 1)) {
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_LAST3_VOICE_ROD_OLD);
+ }
+
+ if ((this->frameCounter >= 15) && (this->frameCounter < 18)) {
+ this->rightWhip.tension = 500.0f;
+ }
+
+ if (this->frameCounter == 9) {
+ this->whipCrackTimer = 11;
+ }
+
+ if (this->frameCounter == 1) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST3_ROD_HOP_OLD);
+ }
+
+ if (this->frameCounter == 10) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST3_ROD_WIND_OLD);
+ }
+ break;
+
+ case MAJORAS_WRATH_ATTACK_SUB_ACTION_FLURRY:
+ if (this->frameCounter == (s16)(KREG(91) + 3)) {
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_LAST3_VOICE_THROW_OLD);
+ }
+
+ if ((this->frameCounter >= 8) && (this->frameCounter <= 55)) {
+ this->leftWhip.tension = this->rightWhip.tension = 300.0f;
+
+ if ((((this->frameCounter + 2) % 4) == 0) && (Rand_ZeroOne() < 0.5f)) {
+ Audio_PlaySfx(NA_SE_EN_LAST3_ROD_FLOOR_OLD);
+ }
+
+ if ((this->frameCounter % 4) == 0) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST3_ROD_WIND_OLD);
+ }
+
+ Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 0xA, 0x1000);
+ }
+ break;
+
+ case MAJORAS_WRATH_ATTACK_SUB_ACTION_DOUBLE_WHIP:
+ if (this->frameCounter == (s16)(KREG(84) + 5)) {
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_LAST3_VOICE_ROD_OLD);
+ }
+
+ if ((this->frameCounter >= 32) && (this->frameCounter <= 38)) {
+ this->rightWhip.tension = 300.0f;
+ this->leftWhip.tension = 300.0f;
+ }
+
+ if (this->frameCounter == 28) {
+ this->whipCrackTimer = 11;
+ }
+
+ if (this->frameCounter == 10) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST3_ROD_HOP_OLD);
+ }
+
+ if (this->frameCounter == 32) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST3_ROD_WIND_OLD);
+ }
+ break;
+
+ case MAJORAS_WRATH_ATTACK_SUB_ACTION_LONG_WHIP:
+ if (this->frameCounter == (s16)(KREG(84) + 5)) {
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_LAST3_VOICE_ROD_OLD);
+ }
+
+ if ((this->frameCounter > 30) && (this->frameCounter <= 35)) {
+ this->rightWhip.tension = 1200.0f;
+ }
+
+ if (this->frameCounter == 23) {
+ this->whipCrackTimer = 11;
+ }
+
+ Math_ApproachF(&this->wrathLeanRotY, -0.1f, 0.5f, 0.1f);
+ Math_ApproachF(&this->wrathLeanRotX, 0.3f, 0.5f, 0.1f);
+
+ if (this->frameCounter == 5) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST3_ROD_HOP_OLD);
+ }
+
+ if (this->frameCounter == 30) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST3_ROD_WIND_OLD);
+ }
+ break;
+
+ case MAJORAS_WRATH_ATTACK_SUB_ACTION_SPIN_ATTACK:
+ if ((this->frameCounter > 16) && (this->frameCounter <= 40)) {
+ this->leftWhip.tension = this->rightWhip.tension = 200.0f;
+
+ if ((this->frameCounter % 8) == 0) {
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_LAST3_VOICE_KOMA_OLD);
+ }
+
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST3_ROD_DANCE_OLD - SFX_FLAG);
+ Math_ApproachF(&this->actor.world.pos.x, this->targetPos.x, 0.1f, this->speedToTarget);
+ Math_ApproachF(&this->actor.world.pos.z, this->targetPos.z, 0.1f, this->speedToTarget);
+ Math_ApproachF(&this->speedToTarget, 20.0f, 1.0f, 4.0f);
+ Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 5, 0x2000);
+ this->canEvade = false;
+ }
+ break;
+
+ case MAJORAS_WRATH_ATTACK_SUB_ACTION_KICK:
+ this->canEvade = false;
+ if (this->frameCounter == 3) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST3_VOICE_KICK_OLD);
+ }
+ break;
+
+ case MAJORAS_WRATH_ATTACK_SUB_ACTION_TAUNT:
+ this->rightWhip.mobility = this->leftWhip.mobility = 0.7f;
+ this->leftWhip.gravity = this->rightWhip.gravity = -15.0f;
+ Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 0xA, 0x1000);
+ this->canEvade = true;
+ break;
+
+ case MAJORAS_WRATH_ATTACK_SUB_ACTION_THREE_HIT:
+ if (this->frameCounter == (s16)(KREG(85) + 5)) {
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_LAST3_VOICE_ROD_OLD);
+ }
+
+ if ((this->frameCounter >= 14) && (this->frameCounter < 19)) {
+ this->rightWhip.tension = 150.0f;
+ }
+
+ if ((this->frameCounter >= 23) && (this->frameCounter < 29)) {
+ this->leftWhip.tension = 200.0f;
+ }
+
+ if ((this->frameCounter >= 43) && (this->frameCounter < 49)) {
+ this->rightWhip.tension = 200.0f;
+ }
+
+ Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 0xA, 0x1000);
+
+ if (this->frameCounter == 20) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST3_ROD_HOP_OLD);
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_LAST3_VOICE_ROD_OLD);
+ }
+
+ if (this->frameCounter == 5) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST3_ROD_HOP2_OLD);
+ }
+
+ if (this->frameCounter == 41) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST3_ROD_WIND_OLD);
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_LAST3_VOICE_ROD_OLD);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (Animation_OnFrame(&this->skelAnime, this->animEndFrame) || (this->timers[1] == 1)) {
+ Boss07_Wrath_SetupIdle(this, play, 0);
+ }
+}
+
+void Boss07_Wrath_SetupTryGrab(Boss07* this, PlayState* play) {
+ this->actionFunc = Boss07_Wrath_TryGrab;
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasWrathGrabAnim, -5.0f);
+ this->animEndFrame = Animation_GetLastFrame(&gMajorasWrathGrabAnim);
+ this->frameCounter = 0;
+}
+
+void Boss07_Wrath_TryGrab(Boss07* this, PlayState* play) {
+ SkelAnime_Update(&this->skelAnime);
+ Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer - 0x800, 3, 0x2000);
+ Boss07_SmoothStop(this, 2.0f);
+ this->leftWhip.mobility = this->rightWhip.mobility = 0.01f * 80;
+ this->leftWhip.deceleration = this->rightWhip.deceleration = 1.0f;
+ this->leftWhip.tension = this->rightWhip.tension = 0.0f;
+ this->rightWhip.gravity = -5.0f;
+ this->leftWhip.gravity = -15.0f;
+
+ if ((this->frameCounter >= 14) && (this->frameCounter <= 18)) {
+ this->rightWhip.tension = 500.0f;
+ }
+
+ if (this->frameCounter >= 18) {
+ Boss07_Wrath_SetupIdle(this, play, Rand_ZeroFloat(20.0f) + 20.0f);
+ Audio_PlaySfx(NA_SE_EN_LAST3_ROD_MID_OLD);
+ }
+}
+
+void Boss07_Wrath_GrabPlayer(Boss07* this, PlayState* play) {
+ PlayerImpactType playerImpactType;
+ Player* player = GET_PLAYER(play);
+
+ SkelAnime_Update(&this->skelAnime);
+ Boss07_SmoothStop(this, 2.0f);
+ player->actor.world.pos = this->whipGrabPos;
+ this->actor.flags &= ~ACTOR_FLAG_ATTENTION_ENABLED;
+ this->whipCollisionTimer = 20;
+ this->whipWrapStartIndex++;
+
+ if (this->frameCounter > (s16)((MAJORA_WHIP_LENGTH + 2) - this->whipWrapEndOffset)) {
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_LAST3_VOICE_THROW_OLD);
+ Audio_PlaySfx(NA_SE_EN_LAST3_COIL_ATTACK_OLD);
+ this->actionFunc = Boss07_Wrath_ThrowPlayer;
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasWrathThrowAnim, -5.0f);
+ this->animEndFrame = Animation_GetLastFrame(&gMajorasWrathThrowAnim);
+ this->frameCounter = 0;
+ }
+
+ if ((Actor_GetPlayerImpact(play, 1000.0f, &this->actor.world.pos, &playerImpactType) >= 0.0f) &&
+ (playerImpactType == PLAYER_IMPACT_ZORA_BARRIER)) {
+ Boss07_Wrath_SetupShock(this, play);
+ }
+}
+
+void Boss07_Wrath_ThrowPlayer(Boss07* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+ f32 speed;
+ f32 velocityY;
+ PlayerImpactType playerImpactType;
+
+ SkelAnime_Update(&this->skelAnime);
+ this->whipCollisionTimer = 20;
+
+ if (this->frameCounter == 6) {
+ this->whipWrapEndOffset = 0;
+
+ if (&this->actor == player->actor.parent) {
+ player->av2.actionVar2 = 101;
+ player->actor.parent = NULL;
+ player->csAction = PLAYER_CSACTION_NONE;
+
+ if (player->transformation == PLAYER_FORM_DEKU) {
+ speed = 23.0f;
+ velocityY = 20.0f;
+ } else if (player->transformation == PLAYER_FORM_GORON) {
+ speed = 15.0f;
+ velocityY = 10.0f;
+ } else if (player->transformation == PLAYER_FORM_FIERCE_DEITY) {
+ speed = 10.0f;
+ velocityY = 3.0f;
+ } else {
+ speed = 20.0f;
+ velocityY = 15.0f;
+ }
+
+ func_800B8D50(play, NULL, speed, this->actor.yawTowardsPlayer + 0x9000, velocityY, 0x10);
+ }
+ }
+
+ if (this->frameCounter < 7) {
+ player->actor.world.pos = this->whipGrabPos;
+
+ if ((Actor_GetPlayerImpact(play, 1000.0f, &this->actor.world.pos, &playerImpactType) >= 0.0f) &&
+ (playerImpactType == PLAYER_IMPACT_ZORA_BARRIER)) {
+ Boss07_Wrath_SetupShock(this, play);
+ }
+ }
+
+ if (Animation_OnFrame(&this->skelAnime, this->animEndFrame)) {
+ Boss07_Wrath_SetupIdle(this, play, 0);
+ }
+}
+
+void Boss07_Wrath_SetupShock(Boss07* this, PlayState* play) {
+ s32 whipShockIndex;
+ s32 whipShockIndexMax;
+
+ this->actionFunc = Boss07_Wrath_ShockWhip;
+
+ whipShockIndex = this->whipWrapEndOffset + 10;
+ this->whipShockMaxIndex = this->whipShockMinIndex = whipShockIndex;
+
+ whipShockIndexMax = sWhipLength - 1;
+ if (whipShockIndexMax < whipShockIndex) {
+ this->whipShockMaxIndex = this->whipShockMinIndex = whipShockIndexMax;
+ }
+
+ this->frameCounter = 0;
+ Audio_PlaySfx(NA_SE_EV_ELECTRIC_EXPLOSION);
+}
+
+void Boss07_Wrath_ShockWhip(Boss07* this, PlayState* play) {
+ s32 i;
+ Player* player = GET_PLAYER(play);
+
+ SkelAnime_Update(&this->skelAnime);
+ Boss07_SmoothStop(this, 2.0f);
+ player->actor.world.pos = this->whipGrabPos;
+ this->actor.flags &= ~ACTOR_FLAG_ATTENTION_ENABLED;
+ this->whipCollisionTimer = 20;
+
+ if (this->frameCounter <= (s16)((MAJORA_WHIP_LENGTH + 2) - this->whipWrapEndOffset)) {
+ this->whipWrapStartIndex++;
+ }
+
+ for (i = 0; i < 4; i++) {
+ if (this->whipShockMinIndex != 0) {
+ this->whipShockMinIndex--;
+ }
+ }
+
+ if (this->whipShockMinIndex == 0) {
+ Math_ApproachF(&play->envCtx.lightBlend, 1.0f, 1.0f, 0.3f);
+ Math_ApproachF(&this->shockOrbScale, 5.0f, 0.5f, 3.0f);
+ Audio_PlaySfx(NA_SE_EN_BIRI_SPARK - SFX_FLAG);
+ } else {
+ this->shockOrbScale = 0.01f;
+ }
+
+ if (this->shockOrbScale > 4.0f) {
+ this->actionFunc = Boss07_Wrath_ShockStunned;
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasWrathStunAnim, -10.0f);
+ this->animEndFrame = Animation_GetLastFrame(&gMajorasWrathStunAnim);
+ this->whipWrapEndOffset = 0;
+
+ if (&this->actor == player->actor.parent) {
+ player->av2.actionVar2 = 101;
+ player->actor.parent = NULL;
+ player->csAction = PLAYER_CSACTION_NONE;
+ }
+
+ Actor_Spawn(&play->actorCtx, play, ACTOR_EN_CLEAR_TAG, this->actor.focus.pos.x, this->actor.focus.pos.y - 10.0f,
+ this->actor.focus.pos.z, 0, 0, 0, CLEAR_TAG_PARAMS(CLEAR_TAG_LARGE_LIGHT_RAYS));
+ this->frameCounter = 0;
+ }
+}
+
+void Boss07_Wrath_ShockStunned(Boss07* this, PlayState* play) {
+ s32 i;
+
+ SkelAnime_Update(&this->skelAnime);
+ this->whipCollisionTimer = 20;
+
+ for (i = 0; i < 2; i++) {
+ DECR(this->whipShockMaxIndex);
+ }
+
+ if (this->frameCounter < 70) {
+ Math_ApproachF(&this->shockOrbScale, 5.0f, 0.5f, 3.0f);
+ Math_ApproachF(&this->shockSparkScale, 2.5f, 0.5f, 2.0f);
+ Audio_PlaySfx(NA_SE_EN_BIRI_SPARK - SFX_FLAG);
+ Math_ApproachF(&play->envCtx.lightBlend, 1.0f, 1.0f, 0.3f);
+ }
+
+ if (Animation_OnFrame(&this->skelAnime, this->animEndFrame)) {
+ Boss07_Wrath_ChooseJump(this, play, true);
+ }
+}
+
+void Boss07_Wrath_SetupStunned(Boss07* this, PlayState* play) {
+ if (this->actionFunc != Boss07_Wrath_Stunned) {
+ this->actionFunc = Boss07_Wrath_Stunned;
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasWrathStunAnim, -10.0f);
+ this->animEndFrame = Animation_GetLastFrame(&gMajorasWrathStunAnim);
+ }
+
+ this->disableCollisionTimer = 10;
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST3_VOICE_DAMAGE_OLD);
+}
+
+void Boss07_Wrath_SetupThrowTop(Boss07* this, PlayState* play) {
+ this->actionFunc = Boss07_Wrath_ThrowTop;
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasWrathThrowTopAnim, -5.0f);
+ this->animEndFrame = Animation_GetLastFrame(&gMajorasWrathThrowTopAnim);
+ this->frameCounter = 0;
+}
+
+void Boss07_Wrath_ThrowTop(Boss07* this, PlayState* play) {
+ this->whipCollisionTimer = 20;
+
+ if (this->frameCounter < (s16)(KREG(40) + 14)) {
+ this->whipTopIndex += 6;
+
+ if (this->whipTopIndex > MAJORA_WHIP_LENGTH) {
+ this->whipTopIndex = MAJORA_WHIP_LENGTH;
+ }
+ }
+
+ if (this->frameCounter == 8) {
+ Actor_Spawn(&play->actorCtx, play, ACTOR_BOSS_07, this->actor.world.pos.x, this->actor.world.pos.y,
+ this->actor.world.pos.z, 0, 0, 0, MAJORA_PARAMS(MAJORA_TYPE_TOP));
+ }
+
+ //! FAKE:
+ if (1) {}
+
+ if (this->frameCounter == 10) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST3_ROD_WIND_OLD);
+ }
+
+ if (this->frameCounter == (s16)(KREG(40) + 18)) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST3_VOICE_KOMA_OLD);
+ }
+
+ if ((this->frameCounter < (s16)(KREG(40) + 14)) || (this->frameCounter > (s16)(KREG(41) + 17))) {
+ SkelAnime_Update(&this->skelAnime);
+ }
+
+ if ((this->frameCounter >= (s16)(KREG(40) + 14)) &&
+ ((this->frameCounter <= (s16)(KREG(41) + 17)) || (this->frameCounter >= (s16)(KREG(42) + 21)))) {
+ this->whipTopIndex -= KREG(39) + 5;
+
+ if (this->whipTopIndex < 0) {
+ this->whipTopIndex = 0;
+ }
+ }
+
+ Math_ApproachS(&this->actor.shape.rot.y, KREG(8) * 0x100 + this->actor.yawTowardsPlayer + 0xF00, 3, 0x2000);
+ Boss07_SmoothStop(this, 2.0f);
+
+ this->leftWhip.mobility = this->rightWhip.mobility = 0.01f * 80;
+ this->leftWhip.deceleration = this->rightWhip.deceleration = 1.0f;
+ this->leftWhip.tension = this->rightWhip.tension = 0.0f;
+ this->rightWhip.gravity = -5.0f;
+ this->leftWhip.gravity = -15.0f;
+
+ if ((this->frameCounter >= (s16)(KREG(43) + 12)) && (this->frameCounter <= (s16)(KREG(44) + 17))) {
+ this->rightWhip.tension = KREG(6) + 500.0f;
+ }
+
+ if (this->frameCounter >= (s16)(KREG(45) + 36)) {
+ Boss07_Wrath_SetupIdle(this, play, Rand_ZeroFloat(20.0f) + 20.0f);
+ }
+}
+
+void Boss07_Wrath_Stunned(Boss07* this, PlayState* play) {
+ SkelAnime_Update(&this->skelAnime);
+
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_COMMON_WEAKENED - SFX_FLAG);
+ Boss07_SmoothStop(this, 2.0f);
+
+ this->leftWhip.mobility = this->rightWhip.mobility = 0.7f;
+ this->leftWhip.gravity = this->rightWhip.gravity = -15.0f;
+ this->leftWhip.tension = this->rightWhip.tension = 0.0f;
+ this->leftWhip.deceleration = this->rightWhip.deceleration = 2.0f;
+
+ if (Animation_OnFrame(&this->skelAnime, this->animEndFrame)) {
+ Boss07_Wrath_ChooseJump(this, play, true);
+ }
+}
+
+void Boss07_Wrath_SetupDamaged(Boss07* this, PlayState* play, u8 damage, u8 dmgEffect) {
+ if ((s8)this->actor.colChkInfo.health >= 0) {
+ this->actor.colChkInfo.health -= damage;
+ }
+
+ if ((s8)this->actor.colChkInfo.health <= 0) {
+ if (KREG(19) != 0) {
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_LAST3_VOICE_DEAD_OLD);
+ } else {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST3_VOICE_DEAD_OLD);
+ }
+
+ this->shouldStartDeath = true;
+ Enemy_StartFinishingBlow(play, &this->actor);
+ } else {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST3_VOICE_DAMAGE2_OLD);
+
+ if (this->actionFunc != Boss07_Wrath_Damaged) {
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasWrathDamagedAnim, -10.0f);
+ this->actionFunc = Boss07_Wrath_Damaged;
+ this->animEndFrame = Animation_GetLastFrame(&gMajorasWrathDamagedAnim);
+ this->sfxTimer = 0;
+ } else if (dmgEffect == MAJORAS_WRATH_DMGEFF_ANIM_FRAME_CHECK) {
+ if (this->skelAnime.curFrame <= (this->animEndFrame - 5.0f)) {
+ this->disableCollisionTimer = 30;
+ } else {
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasWrathDamagedAnim, -5.0f);
+ }
+ }
+ }
+}
+
+void Boss07_Wrath_Damaged(Boss07* this, PlayState* play) {
+ SkelAnime_Update(&this->skelAnime);
+ this->sfxTimer++;
+
+ if ((this->sfxTimer % 16) == 0) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_WALK2_OLD);
+ }
+
+ Boss07_SmoothStop(this, 2.0f);
+
+ this->leftWhip.mobility = this->rightWhip.mobility = 0.7f;
+ this->leftWhip.gravity = this->rightWhip.gravity = -15.0f;
+ this->leftWhip.deceleration = this->rightWhip.deceleration = 2.0f;
+ this->leftWhip.tension = this->rightWhip.tension = 0.0f;
+
+ if (Animation_OnFrame(&this->skelAnime, this->animEndFrame)) {
+ Boss07_Wrath_ChooseJump(this, play, true);
+ }
+}
+
+void Boss07_Wrath_CheckWhipCollisions(Vec3f* whipPos, f32 tension, Boss07* this, PlayState* play) {
+ s32 i;
+ PlayerImpactType playerImpactType = -1;
+ Player* player = GET_PLAYER(play);
+ f32 dx;
+ f32 dy;
+ f32 dz;
+ Vec3f hitPos;
+
+ if ((tension >= 50.0f) && (this->whipCollisionTimer == 0)) {
+ Actor* prop;
+
+ for (prop = play->actorCtx.actorLists[ACTORCAT_PROP].first; prop != NULL; prop = prop->next) {
+ if (prop->id == ACTOR_OBJ_TSUBO) {
+ for (i = 10; i < sWhipLength; i += 3) {
+ dx = prop->world.pos.x - whipPos[i].x;
+ dy = prop->world.pos.y + 10.0f - whipPos[i].y;
+ dz = prop->world.pos.z - whipPos[i].z;
+
+ if (sqrtf(SQ(dx) + SQ(dy) + SQ(dz)) < (KREG(38) + 60.0f)) {
+ ((ObjTsubo*)prop)->unk_19B = true;
+ Boss07_Wrath_SpawnDustAtPos(play, &prop->world.pos, 10);
+ }
+ }
+ }
+ }
+ }
+
+ if ((tension >= 50.0f) && (this->whipCollisionTimer == 0) &&
+ (!(player->stateFlags3 & PLAYER_STATE3_100) ||
+ (this->subAction == MAJORAS_WRATH_ATTACK_SUB_ACTION_SPIN_ATTACK))) {
+ if ((Actor_GetPlayerImpact(play, 1000.0f, &this->actor.world.pos, &playerImpactType) >= 0.0f) &&
+ (playerImpactType != PLAYER_IMPACT_ZORA_BARRIER)) {
+ playerImpactType = -1;
+ }
+
+ for (i = 10; i < sWhipLength; i += 3) {
+ dx = player->actor.world.pos.x - whipPos[i].x;
+ dy = player->actor.world.pos.y + 30.0f - whipPos[i].y;
+ dz = player->actor.world.pos.z - whipPos[i].z;
+
+ dy *= 1.75f;
+
+ if (sqrtf(SQ(dx) + SQ(dy) + SQ(dz)) < 140.0f) {
+ if ((this->actionFunc == Boss07_Wrath_TryGrab) && (playerImpactType != PLAYER_IMPACT_ZORA_BARRIER) &&
+ !(player->stateFlags3 & PLAYER_STATE3_1000) && (this->actor.xzDistToPlayer >= 520.0f) &&
+ (this->actor.xzDistToPlayer <= 900.0f)) {
+ if (play->grabPlayer(play, player)) {
+ f32 dx;
+ f32 dy;
+ f32 dz;
+ f32 distToPlayerXZ;
+
+ player->actor.parent = &this->actor;
+ AudioSfx_PlaySfx(NA_SE_VO_LI_DAMAGE_S, &player->actor.projectedPos, 4,
+ &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
+ this->whipWrapStartIndex = 0;
+ this->whipWrapEndOffset = ((this->actor.xzDistToPlayer - 300.0f) / 22.0f) + 10.0f;
+
+ dx = player->actor.world.pos.x - this->rightWhip.basePos.x;
+ dy = player->actor.world.pos.y - this->rightWhip.basePos.y + 50.0f;
+ dz = player->actor.world.pos.z - this->rightWhip.basePos.z;
+ distToPlayerXZ = sqrtf(SQ(dx) + SQ(dz));
+
+ this->whipWrapRotY = Math_Atan2F_XY(dz, dx);
+ this->whipWrapRotX = -Math_Atan2F_XY(distToPlayerXZ, dy);
+ this->actionFunc = Boss07_Wrath_GrabPlayer;
+ this->frameCounter = 0;
+ this->rightWhip.tension = 0.0f;
+ Audio_PlaySfx(NA_SE_EN_LAST3_GET_LINK_OLD);
+ }
+ } else if ((player->stateFlags1 & PLAYER_STATE1_400000) && Boss07_ArePlayerAndActorFacing(this, play)) {
+ player->pushedSpeed = 10.0f;
+ player->pushedYaw = this->actor.yawTowardsPlayer;
+ Audio_PlaySfx(NA_SE_IT_SHIELD_BOUND);
+ this->whipCollisionTimer = 4;
+ } else {
+ func_800B8D50(play, NULL, 5.0f, this->actor.shape.rot.y, 0.0f, 8);
+ this->whipCollisionTimer = 20;
+ }
+
+ hitPos = player->actor.world.pos;
+
+ hitPos.x += Rand_CenteredFloat(30.0f);
+ hitPos.y += Rand_CenteredFloat(30.0f) + 20.0f;
+ hitPos.z += Rand_CenteredFloat(30.0f);
+
+ EffectSsHitmark_SpawnFixedScale(play, 0, &hitPos);
+ Boss07_Wrath_SpawnDustAtPos(play, &player->actor.world.pos, 7);
+ break;
+ }
+ }
+ }
+}
+
+void Boss07_Wrath_UpdateDamage(Boss07* this, PlayState* play) {
+ s32 i;
+ s32 j;
+ u8 damage;
+ Player* player = GET_PLAYER(play);
+
+ if (this->damagedTimer != 0) {
+ return;
+ }
+
+ if (this->kickCollider.elements[MAJORAS_WARTH_KICK_COLLIDER_RIGHT_FOOT].base.atElemFlags & ATELEM_HIT) {
+ this->kickCollider.elements[MAJORAS_WARTH_KICK_COLLIDER_RIGHT_FOOT].base.atElemFlags &= ~ATELEM_HIT;
+ player->pushedYaw = this->actor.yawTowardsPlayer;
+ player->pushedSpeed = 20.0f;
+ Boss07_Wrath_SpawnDustAtPos(play, &player->actor.world.pos, 12);
+ Audio_PlaySfx(NA_SE_IT_HOOKSHOT_STICK_OBJ);
+ }
+
+ for (i = 0; i < ARRAY_COUNT(this->bodyColliderElements); i++) {
+ if (!(this->bodyCollider.elements[i].base.acElemFlags & ACELEM_HIT)) {
+ continue;
+ }
+
+ for (j = 0; j < ARRAY_COUNT(this->bodyColliderElements); j++) {
+ this->bodyCollider.elements[j].base.acElemFlags &= ~ACELEM_HIT;
+ }
+
+ if (this->drawDmgEffType == ACTOR_DRAW_DMGEFF_FROZEN_NO_SFX) {
+ this->drawDmgEffTimer = 0;
+ }
+
+ switch (this->actor.colChkInfo.damageEffect) {
+ case MAJORAS_WRATH_DMGEFF_FREEZE:
+ this->drawDmgEffState = MAJORA_DRAW_DMGEFF_STATE_FROZEN_INIT;
+ break;
+
+ case MAJORAS_WRATH_DMGEFF_FIRE:
+ this->drawDmgEffState = MAJORA_DRAW_DMGEFF_STATE_FIRE_INIT;
+ break;
+
+ case MAJORAS_WRATH_DMGEFF_LIGHT_ORB:
+ this->drawDmgEffState = MAJORA_DRAW_DMGEFF_STATE_LIGHT_ORB_INIT;
+ Actor_Spawn(&play->actorCtx, play, ACTOR_EN_CLEAR_TAG, this->actor.focus.pos.x, this->actor.focus.pos.y,
+ this->actor.focus.pos.z, 0, 0, 0, CLEAR_TAG_PARAMS(CLEAR_TAG_LARGE_LIGHT_RAYS));
+ break;
+
+ case MAJORAS_WRATH_DMGEFF_ELECTRIC_SPARKS:
+ this->drawDmgEffState = MAJORA_DRAW_DMGEFF_STATE_ELECTRIC_SPARKS_INIT;
+ Actor_PlaySfx(&this->actor, NA_SE_EN_COMMON_FREEZE);
+ break;
+
+ case MAJORAS_WRATH_DMGEFF_BLUE_LIGHT_ORB:
+ this->drawDmgEffState = MAJORA_DRAW_DMGEFF_STATE_BLUE_LIGHT_ORB_INIT;
+ Actor_Spawn(&play->actorCtx, play, ACTOR_EN_CLEAR_TAG, this->actor.focus.pos.x, this->actor.focus.pos.y,
+ this->actor.focus.pos.z, 0, 0, 3, CLEAR_TAG_PARAMS(CLEAR_TAG_LARGE_LIGHT_RAYS));
+ break;
+
+ default:
+ break;
+ }
+
+ damage = this->actor.colChkInfo.damage;
+
+ if ((this->actionFunc == Boss07_Wrath_Stunned) || (this->actionFunc == Boss07_Wrath_Damaged)) {
+ if ((this->actionFunc == Boss07_Wrath_Stunned) &&
+ (this->actor.colChkInfo.damageEffect != MAJORAS_WRATH_DMGEFF_ANIM_FRAME_CHECK) &&
+ (this->actor.colChkInfo.damageEffect != MAJORAS_WRATH_DMGEFF_DAMAGE_NONE) &&
+ (this->actor.colChkInfo.damageEffect != MAJORAS_WRATH_DMGEFF_BLUE_LIGHT_ORB) &&
+ (this->actor.colChkInfo.damageEffect != MAJORAS_WRATH_DMGEFF_EXPLOSIVE)) {
+ Boss07_Wrath_SetupStunned(this, play);
+ this->damagedTimer = 6;
+ } else {
+ this->damagedFlashTimer = 15;
+ this->damagedTimer = (this->actor.colChkInfo.damageEffect == MAJORAS_WRATH_DMGEFF_EXPLOSIVE) ? 15 : 5;
+ Boss07_Wrath_SetupDamaged(this, play, damage, this->actor.colChkInfo.damageEffect);
+ }
+ } else {
+ this->damagedTimer = 15;
+ Boss07_Wrath_SetupStunned(this, play);
+ this->whipWrapEndOffset = 0;
+
+ if (&this->actor == player->actor.parent) {
+ player->av2.actionVar2 = 101;
+ player->actor.parent = NULL;
+ player->csAction = PLAYER_CSACTION_NONE;
+ }
+ }
+ break;
+ }
+}
+
+/**
+ * Spawns two ice shards on all of Majora's Wrath's body parts that fly off in random directions.
+ */
+void Boss07_Wrath_Thaw(Boss07* this, PlayState* play) {
+ static Color_RGBA8 sIcePrimColor = { 170, 255, 255, 255 };
+ static Color_RGBA8 sIceEnvColor = { 200, 200, 255, 255 };
+ static Vec3f sIceAccel = { 0.0f, -1.0f, 0.0f };
+ Vec3f pos;
+ Vec3f velocity;
+ s32 i;
+
+ SoundSource_PlaySfxAtFixedWorldPos(play, &this->bodyPartsPos[MAJORAS_WRATH_BODYPART_HEAD], 30, NA_SE_EV_ICE_BROKEN);
+
+ for (i = 0; i < MAJORAS_WRATH_BODYPART_MAX * 2; i++) {
+ velocity.x = Rand_CenteredFloat(7.0f);
+ velocity.z = Rand_CenteredFloat(7.0f);
+ velocity.y = Rand_ZeroFloat(6.0f) + 4.0f;
+
+ pos.x = this->bodyPartsPos[i / 2].x + velocity.x;
+ pos.y = this->bodyPartsPos[i / 2].y + velocity.y;
+ pos.z = this->bodyPartsPos[i / 2].z + velocity.z;
+
+ EffectSsEnIce_Spawn(play, &pos, Rand_ZeroFloat(1.0f) + 1.5f, &velocity, &sIceAccel, &sIcePrimColor,
+ &sIceEnvColor, 30);
+ }
+}
+
+void Boss07_UpdateDamageEffects(Boss07* this, PlayState* play) {
+ DECR(this->drawDmgEffTimer);
+
+ switch (this->drawDmgEffState) {
+ case MAJORA_DRAW_DMGEFF_STATE_NONE:
+ this->drawDmgEffType = ACTOR_DRAW_DMGEFF_FIRE;
+ this->drawDmgEffTimer = 0;
+ this->drawDmgEffAlpha = 0.0f;
+ break;
+
+ case MAJORA_DRAW_DMGEFF_STATE_FIRE_INIT:
+ this->drawDmgEffType = ACTOR_DRAW_DMGEFF_FIRE;
+ this->drawDmgEffTimer = 40;
+ this->drawDmgEffAlpha = 1.0f;
+ this->drawDmgEffScale = 0.0f;
+ this->drawDmgEffState++;
+ Actor_SetColorFilter(&this->actor, COLORFILTER_COLORFLAG_RED, 120, COLORFILTER_BUFFLAG_OPA, 60);
+ FALLTHROUGH;
+ case MAJORA_DRAW_DMGEFF_STATE_FIRE_ACTIVE:
+ if (this->drawDmgEffTimer == 0) {
+ Math_ApproachZeroF(&this->drawDmgEffAlpha, 1.0f, 0.02f);
+ if (this->drawDmgEffAlpha == 0.0f) {
+ this->drawDmgEffState = MAJORA_DRAW_DMGEFF_STATE_NONE;
+ }
+ } else {
+ Math_ApproachF(&this->drawDmgEffScale, 1.0f, 0.1f, 0.5f);
+ }
+ break;
+
+ case MAJORA_DRAW_DMGEFF_STATE_FROZEN_INIT:
+ this->drawDmgEffType = ACTOR_DRAW_DMGEFF_FROZEN_SFX;
+ this->drawDmgEffTimer = 40;
+ this->drawDmgEffAlpha = 1.0f;
+ this->drawDmgEffFrozenSteamScale = 1.0f;
+ this->drawDmgEffScale = 0.0f;
+ this->drawDmgEffState++;
+ FALLTHROUGH;
+ case MAJORA_DRAW_DMGEFF_STATE_FROZEN_ACTIVE:
+ if (this->drawDmgEffTimer == 0) {
+ Boss07_Wrath_Thaw(this, play);
+ this->drawDmgEffState = MAJORA_DRAW_DMGEFF_STATE_NONE;
+ break;
+ }
+
+ if (this->drawDmgEffTimer == 50) {
+ this->drawDmgEffType = ACTOR_DRAW_DMGEFF_FROZEN_NO_SFX;
+ }
+
+ Math_ApproachF(&this->drawDmgEffScale, 1.0f, 1.0f, 0.08f);
+ Math_ApproachF(&this->drawDmgEffFrozenSteamScale, 1.0f, 0.05f, 0.05f);
+ break;
+
+ case MAJORA_DRAW_DMGEFF_STATE_LIGHT_ORB_INIT:
+ this->drawDmgEffType = ACTOR_DRAW_DMGEFF_LIGHT_ORBS;
+ this->drawDmgEffTimer = 40;
+ this->drawDmgEffScale = 1.0f;
+ goto lightOrbInitCommon;
+
+ case MAJORA_DRAW_DMGEFF_STATE_BLUE_LIGHT_ORB_INIT:
+ this->drawDmgEffType = ACTOR_DRAW_DMGEFF_BLUE_LIGHT_ORBS;
+ this->drawDmgEffTimer = 40;
+ this->drawDmgEffScale = 3.0f;
+ lightOrbInitCommon:
+ this->drawDmgEffAlpha = 1.0f;
+ this->drawDmgEffState = MAJORA_DRAW_DMGEFF_STATE_LIGHT_ORB_ACTIVE;
+ FALLTHROUGH;
+ case MAJORA_DRAW_DMGEFF_STATE_LIGHT_ORB_ACTIVE:
+ if (this->drawDmgEffTimer == 0) {
+ Math_ApproachZeroF(&this->drawDmgEffScale, 1.0f, 0.03f);
+ if (this->drawDmgEffScale == 0.0f) {
+ this->drawDmgEffState = MAJORA_DRAW_DMGEFF_STATE_NONE;
+ this->drawDmgEffAlpha = 0.0f;
+ }
+ } else {
+ Math_ApproachF(&this->drawDmgEffScale, 1.5f, 0.5f, 0.5f);
+ }
+ break;
+
+ case MAJORA_DRAW_DMGEFF_STATE_ELECTRIC_SPARKS_INIT:
+ this->drawDmgEffType = ACTOR_DRAW_DMGEFF_ELECTRIC_SPARKS_SMALL;
+ this->drawDmgEffTimer = 50;
+ this->drawDmgEffAlpha = 1.0f;
+ this->drawDmgEffScale = (KREG(18) * 0.1f) + 1.0f;
+ this->drawDmgEffState++;
+ FALLTHROUGH;
+ case MAJORA_DRAW_DMGEFF_STATE_ELECTRIC_SPARKS_ACTIVE:
+ if (this->drawDmgEffTimer == 0) {
+ Math_ApproachZeroF(&this->drawDmgEffScale, 1.0f, 0.05f);
+ if (this->drawDmgEffScale == 0.0f) {
+ this->drawDmgEffState = MAJORA_DRAW_DMGEFF_STATE_NONE;
+ this->drawDmgEffAlpha = 0.0f;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Boss07_Wrath_Update(Actor* thisx, PlayState* play2) {
+ PlayState* play = play2;
+ Boss07* this = THIS;
+ s32 i;
+ Player* player = GET_PLAYER(play);
+
+ play->envCtx.lightSetting = 2;
+ play->envCtx.prevLightSetting = 0;
+ this->actor.hintId = TATL_HINT_ID_MAJORAS_WRATH;
+ Math_ApproachF(&play->envCtx.lightBlend, 0.0f, 1.0f, 0.03f);
+ this->shouldUpdateTentaclesOrWhips = true;
+ Math_Vec3f_Copy(&sMajoraSfxPos, &this->actor.projectedPos);
+
+ if (KREG(63) == 0) {
+ this->canEvade = false;
+ this->frameCounter++;
+ Actor_SetScale(&this->actor, 0.015f);
+ Math_ApproachZeroF(&this->wrathLeanRotY, 1.0f, 0.02f);
+ Math_ApproachZeroF(&this->wrathLeanRotX, 1.0f, 0.02f);
+
+ for (i = 0; i < ARRAY_COUNT(this->timers); i++) {
+ DECR(this->timers[i]);
+ }
+
+ DECR(this->whipCollisionTimer);
+ DECR(this->disableCollisionTimer);
+ DECR(this->damagedTimer);
+ DECR(this->damagedFlashTimer);
+ DECR(this->landSfxTimer);
+
+ Math_ApproachZeroF(&this->shockOrbScale, 1.0f, 0.2f);
+ Math_ApproachZeroF(&this->shockSparkScale, 1.0f, 0.04f);
+
+ this->actionFunc(this, play);
+
+ Actor_MoveWithGravity(&this->actor);
+ Actor_UpdateBgCheckInfo(play, &this->actor, 50.0f, 100.0f, 100.0f,
+ UPDBGCHECKINFO_FLAG_1 | UPDBGCHECKINFO_FLAG_4);
+
+ if (this->whipCrackTimer != 0) {
+ this->whipCrackTimer--;
+
+ if ((this->actionFunc == Boss07_Wrath_Attack) && (this->whipCrackTimer == 0)) {
+ Audio_PlaySfx(NA_SE_EN_LAST3_ROD_FLOOR_OLD);
+ }
+ }
+ } else {
+ sWhipLength = 45;
+ }
+
+ Boss07_Wrath_CheckWhipCollisions(this->rightWhip.pos, this->rightWhip.tension, this, play);
+ Boss07_Wrath_CheckWhipCollisions(this->leftWhip.pos, this->leftWhip.tension, this, play);
+
+ if (this->disableCollisionTimer != 0) {
+ for (i = 0; i < ARRAY_COUNT(this->bodyColliderElements); i++) {
+ this->bodyCollider.elements[i].base.acElemFlags &= ~ACELEM_HIT;
+ }
+ }
+
+ Boss07_Wrath_UpdateDamage(this, play);
+
+ if (this->damagedTimer != 0) {
+ this->whipTopIndex = 0;
+ }
+
+ CollisionCheck_SetOC(play, &play->colChkCtx, &this->bodyCollider.base);
+ CollisionCheck_SetAC(play, &play->colChkCtx, &this->bodyCollider.base);
+
+ if ((this->actionFunc == Boss07_Wrath_Attack) && (this->subAction == MAJORAS_WRATH_ATTACK_SUB_ACTION_KICK) &&
+ (this->frameCounter >= 6)) {
+ CollisionCheck_SetAT(play, &play->colChkCtx, &this->kickCollider.base);
+ } else {
+ if (this->canEvade && Boss07_ArePlayerAndActorFacing(this, play)) {
+ if ((player->unk_D57 == 4) && (player->heldItemAction != PLAYER_IA_BOW_LIGHT)) {
+ if ((this->actor.xzDistToPlayer >= 400.0f) && (Rand_ZeroOne() < 0.5f)) {
+ Boss07_Wrath_SetupSidestep(this, play);
+ } else {
+ Boss07_Wrath_ChooseJump(this, play, false);
+ }
+ }
+
+ if ((player->unk_ADC != 0) && (this->actor.xzDistToPlayer <= 150.0f)) {
+ Boss07_Wrath_ChooseJump(this, play, false);
+ }
+ }
+
+ if ((this->actionFunc != Boss07_Wrath_Stunned) && (this->actionFunc != Boss07_Wrath_Damaged)) {
+ if ((player->stateFlags3 & PLAYER_STATE3_1000) && !(player->stateFlags3 & PLAYER_STATE3_80000) &&
+ (this->actor.xzDistToPlayer <= 250.0f)) {
+ Boss07_Wrath_ChooseJump(this, play, false);
+ }
+ }
+ }
+
+ if (this->canEvade) {
+ Boss07_Wrath_JumpAwayFromExplosive(this, play);
+ }
+
+ Boss07_Wrath_CheckBombWhips(this, play);
+
+ if (KREG(88) || this->shouldStartDeath) {
+ KREG(88) = false;
+ this->shouldStartDeath = false;
+ Boss07_Wrath_SetupDeathCutscene(this, play);
+ }
+
+ if (this->maxDecayPixels != 0) {
+ u16* earTex = SEGMENTED_TO_K0(gMajorasWrathEarTex);
+ u16* stripesTex = SEGMENTED_TO_K0(gMajoraStripesTex);
+ u16* mouthTex = SEGMENTED_TO_K0(gMajorasWrathMouthTex);
+ u16* bloodshotEyeTex = SEGMENTED_TO_K0(gMajoraBloodshotEyeTex);
+ u16* eyeTex = SEGMENTED_TO_K0(gMajorasWrathEyeTex);
+ u16* maskTex = SEGMENTED_TO_K0(gMajorasMaskWithNormalEyesTex);
+ u16* veinsTex = SEGMENTED_TO_K0(gMajoraVeinsTex);
+ u16* handTex = SEGMENTED_TO_K0(gMajoraHandTex);
+ u16* bodyTex = SEGMENTED_TO_K0(gMajoraBodyTex);
+
+ for (i = 0; i < this->maxDecayPixels; i++) {
+ s32 rand32x64;
+ s32 rand32x16;
+ s32 rand32x32;
+ s32 rand16x16;
+
+ rand16x16 = Rand_ZeroFloat((16 * 16) - 0.01f);
+ rand32x16 = Rand_ZeroFloat((32 * 16) - 0.01f);
+ rand32x32 = Rand_ZeroFloat((32 * 32) - 0.01f);
+ rand32x64 = Rand_ZeroFloat((32 * 64) - 0.01f);
+
+ earTex[rand16x16] = stripesTex[rand32x16] = mouthTex[rand32x32] = bloodshotEyeTex[rand32x32] =
+ eyeTex[rand32x64] = maskTex[rand32x64] = veinsTex[rand32x64] = handTex[rand32x64] = bodyTex[rand32x64] =
+ 0;
+ }
+ }
+
+ Boss07_UpdateDamageEffects(this, play);
+
+ if ((this->landSfxTimer == 1) || (this->landSfxTimer == 4)) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_WALK2_OLD);
+ }
+
+ if ((player->actor.world.pos.y > 100.0f) && (player->actor.world.pos.z < (KREG(82) + -850.0f))) {
+ player->actor.world.pos.z = KREG(82) + -850.0f;
+ }
+
+ if (player->actor.world.pos.y < -300.0f) {
+ player->actor.world.pos.x = player->actor.world.pos.y = player->actor.world.pos.z = 0.0f;
+ }
+}
+
+/**
+ * The whip physics model works by first assuming each point moves freely, using its current velocity and various forces
+ * to find the next position. Then, starting from the base of the whip, each point is moved away from the previous point
+ * until it is a fixed distance away. The new velocity of each point is found from the scaled difference between its
+ * updated position and previous position. The forces applied are
+ * - deceleration, which reduces the magnitude of each velocity component by a fixed amount (or to zero if smaller)
+ * - gravity, which applies to the y-component of velocity
+ * - tension, an outward force that makes the whip "crack"
+ * - additional forces for special movements like wrapping around Link
+ * The scaling factor of the velocity is the whip's mobility--how well movements at the base are transmitted to the
+ * ends.
+ *
+ * The algorithm used to implement this physics model is as follows:
+ * - Set the position of the 0th point to the position of Wrath's hand (base)
+ * - Move each component of each point's velocity towards 0 by deceleration. Set that component to zero if the magnitude
+ * is less than deceleration.
+ * - Calculate the tension force. This points away from Wrath's hand (baserot) for whip movements and towards Link when
+ * grabbed
+ * - Calculate shaping forces. These are the forces from Wrath's hand on the whip base and the force that wraps the whip
+ * around Link. Set tension to 0 for the latter segments.
+ * - Calculate the provisional position of the point by applying the velocity, forces, and gravity. For the y-component,
+ * set a minimum of 2 to not clip through the floor.
+ * - Subtract the current position of the previous point along the whip from the calculated position to get the relative
+ * vector between them
+ * - Set this vector's rotation to the previous point's rot (used by draw so the segments connect).
+ * - Calculate a new vector with the same direction and length 22*scale. Add this to the previous point's position to
+ * get the final position of the point.
+ * - For grab and throw movements, update the position of the grab point.
+ * - The point's final velocity is the difference between its current and previous positions, scaled by mobility and
+ * with each component's magnitude capped at 200.
+ */
+
+void Boss07_Wrath_UpdateWhips(Boss07* this, PlayState* play, Vec3f* base, Vec3f* pos, Vec3f* rot, Vec3f* velocity,
+ f32 gravity, f32 mobility, f32 deceleration, f32 tension, Vec3s* baseRot, s16 grabIndex,
+ f32 scale, s32 hand) {
+ s32 i;
+ s32 j;
+ f32 segPitch;
+ f32 segYaw;
+ f32 tempY;
+ s32 pad;
+ Vec3f tempPos;
+ Vec3f baseSegVec = { 0.0f, 0.0f, 0.0f };
+ Vec3f offsetVec;
+ Vec3f segVec;
+ Vec3f handForce;
+ Vec3f shapeForce;
+ Vec3f tensForce;
+ Vec3f* firstVelocity = velocity;
+
+ // sets the fixed length of each whip segment
+ baseSegVec.z = 22.0f * scale;
+
+ for (i = 0; i < (s16)sWhipLength; i++, velocity++) {
+ if (i == 0) {
+ pos[0] = *base;
+ } else {
+ Math_ApproachF(&velocity->x, 0.0f, 1.0f, deceleration);
+ Math_ApproachF(&velocity->y, 0.0f, 1.0f, deceleration);
+ Math_ApproachF(&velocity->z, 0.0f, 1.0f, deceleration);
+ }
+ }
+
+ offsetVec.z = 20.0f;
+
+ // calculates rotation away from Wrath's hand
+ Matrix_RotateYS(baseRot->y, MTXMODE_NEW);
+ Matrix_RotateXS(baseRot->x, MTXMODE_APPLY);
+ Matrix_RotateZS(baseRot->z, MTXMODE_APPLY);
+ Matrix_RotateYS(0x4000, MTXMODE_APPLY);
+
+ Matrix_MultVecZ(offsetVec.z, &handForce);
+
+ if (grabIndex != 0) {
+ offsetVec.z = 200.0f;
+ // replaces the tension direction with the direction from Wrath's hand to Link
+ Matrix_RotateYF(this->whipWrapRotY, MTXMODE_NEW);
+ Matrix_RotateXFApply(this->whipWrapRotX);
+ } else {
+ offsetVec.z = tension;
+ }
+
+ Matrix_MultVecZ(offsetVec.z, &tensForce);
+
+ pos++;
+ rot++;
+ velocity = firstVelocity + 1;
+ j = 0;
+
+ for (i = 1; i < (s16)sWhipLength; i++, velocity++, pos++, rot++) {
+ if (i < 6) {
+ // keeps the whip outward from Wrath's hand near the base
+ shapeForce.x = (6 - i) * handForce.x * 0.2f;
+ shapeForce.y = (6 - i) * handForce.y * 0.2f;
+ shapeForce.z = (6 - i) * handForce.z * 0.2f;
+ } else if (grabIndex != 0) {
+ // wraps the whip around Link
+ if ((i >= grabIndex) && (i < (s16)(grabIndex + this->whipWrapStartIndex))) {
+ shapeForce.y = 0.0f;
+ shapeForce.x = sinf(this->actor.yawTowardsPlayer * M_PIf / 0x8000 + (j * 1.4f)) * 100.0f;
+ shapeForce.z = cosf(this->actor.yawTowardsPlayer * M_PIf / 0x8000 + (j * 1.4f)) * 100.0f;
+ tensForce = gZeroVec3f;
+ j++;
+ }
+ } else {
+ shapeForce = gZeroVec3f;
+ }
+
+ // Advances the physics one frame to find the provisional position relative to the previous point
+ tempPos.x = pos->x + velocity->x - (pos - 1)->x + shapeForce.x + tensForce.x;
+ tempY = pos->y + velocity->y + gravity + shapeForce.y + tensForce.y;
+ if (tempY < 2.0f) {
+ tempY = 2.0f;
+ }
+
+ tempPos.y = tempY - (pos - 1)->y;
+ tempPos.z = pos->z + velocity->z - (pos - 1)->z + shapeForce.z + tensForce.z;
+
+ // calculates the rotation angles from the previous point
+ segYaw = Math_Atan2F_XY(tempPos.z, tempPos.x);
+ segPitch = -Math_Atan2F_XY(sqrtf(SQXZ(tempPos)), tempPos.y);
+ (rot - 1)->y = segYaw;
+ (rot - 1)->x = segPitch;
+
+ // Sets the position to be in the same direction as the provisional position relative to the previous point, but
+ // a fixed distance away
+ Matrix_RotateYF(segYaw, MTXMODE_NEW);
+ Matrix_RotateXFApply(segPitch);
+ Matrix_MultVecZ(baseSegVec.z, &segVec);
+
+ tempPos.x = pos->x;
+ tempPos.y = pos->y;
+ tempPos.z = pos->z;
+
+ pos->x = (pos - 1)->x + segVec.x;
+ pos->y = (pos - 1)->y + segVec.y;
+ pos->z = (pos - 1)->z + segVec.z;
+
+ if ((i != 0) && (i == grabIndex)) {
+ // Updates the grab point for when Link is grabbed
+ offsetVec.x = 15.0f;
+ offsetVec.y = -30.0f;
+ offsetVec.z = -12.0f;
+ Matrix_MultVec3f(&offsetVec, &segVec);
+ this->whipGrabPos.x = pos->x + segVec.x;
+ this->whipGrabPos.y = pos->y + segVec.y;
+ this->whipGrabPos.z = pos->z + segVec.z;
+ } else if ((hand == MAJORAS_WRATH_HAND_RIGHT) && (this->actionFunc == Boss07_Wrath_ThrowTop)) {
+ // Updates the grab point when throwing a top
+ if (i == (KREG(90) + sWhipLength - this->whipTopIndex + 1)) {
+ offsetVec.x = KREG(60);
+ offsetVec.y = KREG(61);
+ offsetVec.z = KREG(62);
+ Matrix_MultVec3f(&offsetVec, &segVec);
+ this->whipGrabPos.x = pos->x + segVec.x;
+ this->whipGrabPos.y = pos->y + segVec.y;
+ this->whipGrabPos.z = pos->z + segVec.z;
+ }
+ }
+
+ // calculates the velocity for the next frame
+ velocity->x = (pos->x - tempPos.x) * mobility;
+ velocity->y = (pos->y - tempPos.y) * mobility;
+ velocity->z = (pos->z - tempPos.z) * mobility;
+
+ if (velocity->x > 200.0f) {
+ velocity->x = 200.0f;
+ }
+
+ if (velocity->x < -200.0f) {
+ velocity->x = -200.0f;
+ }
+
+ if (velocity->y > 200.0f) {
+ velocity->y = 200.0f;
+ }
+
+ if (velocity->y < -200.0f) {
+ velocity->y = -200.0f;
+ }
+
+ if (velocity->z > 200.0f) {
+ velocity->z = 200.0f;
+ }
+
+ if (velocity->z < -200.0f) {
+ velocity->z = -200.0f;
+ }
+ }
+}
+
+void Boss07_Wrath_DrawWhip(Boss07* this, PlayState* play, Vec3f* pos, Vec3f* rot, f32 lengthScale, s32 hand) {
+ s32 topSegIndex;
+ s32 i;
+ f32 thicknessScale;
+ s32 pad[2];
+ Vec3f* prevPos = pos;
+ Vec3f* prevRot = rot;
+
+ OPEN_DISPS(play->state.gfxCtx);
+
+ Gfx_SetupDL25_Opa(play->state.gfxCtx);
+ gSPDisplayList(POLY_OPA_DISP++, gMajorasMaskWhipShadowMaterialDL);
+ gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, sREG(48) + 45, 35, 75, 255);
+ topSegIndex = (hand == MAJORAS_WRATH_HAND_RIGHT) ? this->whipTopIndex : 0;
+
+ for (i = 0; i < (sWhipLength - topSegIndex) - 1; i++, pos++, rot++) {
+ Matrix_Translate(pos->x, 0.0f, pos->z, MTXMODE_NEW);
+ Matrix_Scale(1.0f, 0.0f, 1.0f, MTXMODE_APPLY);
+ Matrix_RotateYF(rot->y, MTXMODE_APPLY);
+ Matrix_RotateXFApply(rot->x);
+ thicknessScale = (i > 24) ? 0.025f : ((f32)(24 - i) * 1 * 0.001f) + 0.025f;
+ Matrix_Scale(thicknessScale, thicknessScale, ((2 * lengthScale) + 0.5f) * 0.01f, MTXMODE_APPLY);
+ MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, play->state.gfxCtx);
+ gSPDisplayList(POLY_OPA_DISP++, gMajorasWrathWhipModelDL);
+ }
+
+ pos = prevPos;
+ rot = prevRot;
+ gSPDisplayList(POLY_OPA_DISP++, gMajorasWrathWhipMaterialDL);
+ gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 155, 155, 80, 255);
+
+ for (i = 0; i < (sWhipLength - topSegIndex) - 1; i++, pos++, rot++) {
+ Matrix_Translate(pos->x, pos->y, pos->z, MTXMODE_NEW);
+ Matrix_RotateYF(rot->y, MTXMODE_APPLY);
+ Matrix_RotateXFApply(rot->x);
+ thicknessScale = (i > 24) ? 0.025f : ((f32)(24 - i) * 1 * 0.001f) + 0.025f;
+ Matrix_Scale(thicknessScale, thicknessScale, ((2 * lengthScale) + 0.5f) * 0.01f, MTXMODE_APPLY);
+ MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, play->state.gfxCtx);
+ gSPDisplayList(POLY_OPA_DISP++, gMajorasWrathWhipModelDL);
+ }
+
+ CLOSE_DISPS(play->state.gfxCtx);
+}
+
+s32 Boss07_Wrath_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, Actor* thisx) {
+ Boss07* this = THIS;
+
+ if (limbIndex == MAJORAS_WRATH_LIMB_HEAD) {
+ rot->x += this->cutsceneHeadRot.y;
+ rot->y += this->cutsceneHeadRot.x;
+ rot->z += this->cutsceneHeadRot.z;
+ }
+
+ return false;
+}
+
+static s8 sWrathLimbToColliderBodyParts[] = {
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_NONE
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_ROOT
+ MAJORAS_WRATH_COLLIDER_BODYPART_PELVIS, // MAJORAS_WRATH_LIMB_PELVIS
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_LEFT_LEG_ROOT
+ MAJORAS_WRATH_COLLIDER_BODYPART_LEFT_THIGH, // MAJORAS_WRATH_LIMB_LEFT_THIGH
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_LEFT_LOWER_LEG_ROOT
+ MAJORAS_WRATH_COLLIDER_BODYPART_LEFT_SHIN, // MAJORAS_WRATH_LIMB_LEFT_SHIN
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_LEFT_FOOT
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_RIGHT_LEG_ROOT
+ MAJORAS_WRATH_COLLIDER_BODYPART_RIGHT_THIGH, // MAJORAS_WRATH_LIMB_RIGHT_THIGH
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_RIGHT_LOWER_LEG_ROOT
+ MAJORAS_WRATH_COLLIDER_BODYPART_RIGHT_SHIN, // MAJORAS_WRATH_LIMB_RIGHT_SHIN
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_RIGHT_FOOT
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_TORSO_ROOT
+ MAJORAS_WRATH_COLLIDER_BODYPART_TORSO, // MAJORAS_WRATH_LIMB_TORSO
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_RIGHT_ARM_ROOT
+ MAJORAS_WRATH_COLLIDER_BODYPART_RIGHT_UPPER_ARM, // MAJORAS_WRATH_LIMB_RIGHT_UPPER_ARM
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_RIGHT_LOWER_ARM_ROOT
+ MAJORAS_WRATH_COLLIDER_BODYPART_RIGHT_FOREARM, // MAJORAS_WRATH_LIMB_RIGHT_FOREARM
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_RIGHT_HAND
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_LEFT_ARM_ROOT
+ MAJORAS_WRATH_COLLIDER_BODYPART_LEFT_UPPER_ARM, // MAJORAS_WRATH_LIMB_LEFT_UPPER_ARM
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_LEFT_LOWER_ARM_ROOT
+ MAJORAS_WRATH_COLLIDER_BODYPART_LEFT_FOREARM, // MAJORAS_WRATH_LIMB_LEFT_FOREARM
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_LEFT_HAND
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_HEAD_ROOT
+ MAJORAS_WRATH_COLLIDER_BODYPART_HEAD, // MAJORAS_WRATH_LIMB_HEAD
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_THIRD_EYE
+ BODYPART_NONE, // Doesn't correspond to a real limb on Majora's Wrath
+ BODYPART_NONE, // Doesn't correspond to a real limb on Majora's Wrath
+};
+
+static Vec3f sWrathLimbColliderOffsets[MAJORAS_WRATH_COLLIDER_BODYPART_MAX] = {
+ { 1000.0f, 0.0f, 500.0f }, // MAJORAS_WRATH_COLLIDER_BODYPART_HEAD
+ { 2000.0f, 0.0f, 0.0f }, // MAJORAS_WRATH_COLLIDER_BODYPART_TORSO
+ { 1000.0f, 0.0f, 500.0f }, // MAJORAS_WRATH_COLLIDER_BODYPART_PELVIS
+ { 2000.0f, 0.0f, 0.0f }, // MAJORAS_WRATH_COLLIDER_BODYPART_LEFT_UPPER_ARM
+ { 2000.0f, 0.0f, 0.0f }, // MAJORAS_WRATH_COLLIDER_BODYPART_LEFT_FOREARM
+ { 2000.0f, 0.0f, 0.0f }, // MAJORAS_WRATH_COLLIDER_BODYPART_RIGHT_UPPER_ARM
+ { 2000.0f, 0.0f, 0.0f }, // MAJORAS_WRATH_COLLIDER_BODYPART_RIGHT_FOREARM
+ { 2000.0f, 0.0f, 0.0f }, // MAJORAS_WRATH_COLLIDER_BODYPART_LEFT_THIGH
+ { 2000.0f, 0.0f, 0.0f }, // MAJORAS_WRATH_COLLIDER_BODYPART_LEFT_SHIN
+ { 2000.0f, 0.0f, 0.0f }, // MAJORAS_WRATH_COLLIDER_BODYPART_RIGHT_THIGH
+ { 2000.0f, 0.0f, 0.0f }, // MAJORAS_WRATH_COLLIDER_BODYPART_RIGHT_SHIN
+};
+
+static s8 sWrathLimbToBodyParts[] = {
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_NONE
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_ROOT
+ MAJORAS_WRATH_BODYPART_PELVIS, // MAJORAS_WRATH_LIMB_PELVIS
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_LEFT_LEG_ROOT
+ MAJORAS_WRATH_BODYPART_LEFT_THIGH, // MAJORAS_WRATH_LIMB_LEFT_THIGH
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_LEFT_LOWER_LEG_ROOT
+ MAJORAS_WRATH_BODYPART_LEFT_SHIN, // MAJORAS_WRATH_LIMB_LEFT_SHIN
+ MAJORAS_WRATH_BODYPART_LEFT_FOOT, // MAJORAS_WRATH_LIMB_LEFT_FOOT
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_RIGHT_LEG_ROOT
+ MAJORAS_WRATH_BODYPART_RIGHT_THIGH, // MAJORAS_WRATH_LIMB_RIGHT_THIGH
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_RIGHT_LOWER_LEG_ROOT
+ MAJORAS_WRATH_BODYPART_RIGHT_SHIN, // MAJORAS_WRATH_LIMB_RIGHT_SHIN
+ MAJORAS_WRATH_BODYPART_RIGHT_FOOT, // MAJORAS_WRATH_LIMB_RIGHT_FOOT
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_TORSO_ROOT
+ MAJORAS_WRATH_BODYPART_TORSO, // MAJORAS_WRATH_LIMB_TORSO
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_RIGHT_ARM_ROOT
+ MAJORAS_WRATH_BODYPART_RIGHT_UPPER_ARM, // MAJORAS_WRATH_LIMB_RIGHT_UPPER_ARM
+ MAJORAS_WRATH_BODYPART_RIGHT_LOWER_ARM_ROOT, // MAJORAS_WRATH_LIMB_RIGHT_LOWER_ARM_ROOT
+ MAJORAS_WRATH_BODYPART_RIGHT_FOREARM, // MAJORAS_WRATH_LIMB_RIGHT_FOREARM
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_RIGHT_HAND
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_LEFT_ARM_ROOT
+ MAJORAS_WRATH_BODYPART_LEFT_UPPER_ARM, // MAJORAS_WRATH_LIMB_LEFT_UPPER_ARM
+ MAJORAS_WRATH_BODYPART_LEFT_LOWER_ARM_ROOT, // MAJORAS_WRATH_LIMB_LEFT_LOWER_ARM_ROOT
+ MAJORAS_WRATH_BODYPART_LEFT_FOREARM, // MAJORAS_WRATH_LIMB_LEFT_FOREARM
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_LEFT_HAND
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_HEAD_ROOT
+ MAJORAS_WRATH_BODYPART_HEAD, // MAJORAS_WRATH_LIMB_HEAD
+ BODYPART_NONE, // MAJORAS_WRATH_LIMB_THIRD_EYE
+ BODYPART_NONE, // Doesn't correspond to a real limb on Majora's Wrath
+ BODYPART_NONE, // Doesn't correspond to a real limb on Majora's Wrath
+};
+
+void Boss07_Wrath_PostLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx) {
+ static Vec3f sWhipOffset = { 1000.0f, 100.0f, 0.0f };
+ Boss07* this = THIS;
+ s8 bodyPartIndex;
+ Vec3f colliderPos;
+ MtxF curMtxF;
+
+ bodyPartIndex = sWrathLimbToBodyParts[limbIndex];
+ if (bodyPartIndex > BODYPART_NONE) {
+ Matrix_MultZero(&this->bodyPartsPos[bodyPartIndex]);
+ }
+
+ bodyPartIndex = sWrathLimbToColliderBodyParts[limbIndex];
+ if (bodyPartIndex > BODYPART_NONE) {
+ if (this->disableCollisionTimer != 0) {
+ Matrix_MultVecZ(100000.0f, &colliderPos);
+ } else {
+ Matrix_MultVec3f(&sWrathLimbColliderOffsets[bodyPartIndex], &colliderPos);
+ }
+
+ Boss07_SetColliderSphere(bodyPartIndex, &this->bodyCollider, &colliderPos);
+ }
+
+ if (limbIndex == MAJORAS_WRATH_LIMB_HEAD) {
+ Matrix_MultZero(&this->actor.focus.pos);
+ }
+
+ if (limbIndex == MAJORAS_WRATH_LIMB_RIGHT_HAND) {
+ Matrix_MultVec3f(&sWhipOffset, &this->rightWhip.basePos);
+ }
+
+ if (limbIndex == MAJORAS_WRATH_LIMB_RIGHT_LOWER_ARM_ROOT) {
+ Matrix_Get(&curMtxF);
+ Matrix_MtxFToYXZRot(&curMtxF, &this->rightWhip.baseRot, false);
+ }
+
+ if (limbIndex == MAJORAS_WRATH_LIMB_LEFT_HAND) {
+ Matrix_MultVec3f(&sWhipOffset, &this->leftWhip.basePos);
+ }
+
+ if (limbIndex == MAJORAS_WRATH_LIMB_LEFT_LOWER_ARM_ROOT) {
+ Matrix_Get(&curMtxF);
+ Matrix_MtxFToYXZRot(&curMtxF, &this->leftWhip.baseRot, false);
+ }
+
+ if (limbIndex == MAJORAS_WRATH_LIMB_RIGHT_FOOT) {
+ Matrix_MultZero(&colliderPos);
+ Boss07_SetColliderSphere(MAJORAS_WARTH_KICK_COLLIDER_RIGHT_FOOT, &this->kickCollider, &colliderPos);
+ }
+}
+
+void Boss07_Wrath_TransformLimbDraw(PlayState* play, s32 limbIndex, Actor* thisx) {
+ Boss07* this = THIS;
+
+ // This code allows the `incarnationArmScale` to scale up almost all of Wrath's limbs. However, in the final game,
+ // this variable is always set to 1.0f for Wrath, meaning that this code effectively does nothing.
+ if ((limbIndex == MAJORAS_WRATH_LIMB_PELVIS) || (limbIndex == MAJORAS_WRATH_LIMB_LEFT_THIGH) ||
+ (limbIndex == MAJORAS_WRATH_LIMB_LEFT_SHIN) || (limbIndex == MAJORAS_WRATH_LIMB_LEFT_FOOT) ||
+ (limbIndex == MAJORAS_WRATH_LIMB_RIGHT_THIGH) || (limbIndex == MAJORAS_WRATH_LIMB_RIGHT_SHIN) ||
+ (limbIndex == MAJORAS_WRATH_LIMB_RIGHT_FOOT) || (limbIndex == MAJORAS_WRATH_LIMB_RIGHT_UPPER_ARM) ||
+ (limbIndex == MAJORAS_WRATH_LIMB_RIGHT_FOREARM) || (limbIndex == MAJORAS_WRATH_LIMB_RIGHT_HAND) ||
+ (limbIndex == MAJORAS_WRATH_LIMB_LEFT_UPPER_ARM) || (limbIndex == MAJORAS_WRATH_LIMB_LEFT_FOREARM) ||
+ (limbIndex == MAJORAS_WRATH_LIMB_LEFT_HAND) || (limbIndex == MAJORAS_WRATH_LIMB_HEAD)) {
+ Matrix_Scale(1.0f, this->incarnationArmScale, this->incarnationArmScale, MTXMODE_APPLY);
+ }
+}
+
+void Boss07_Wrath_DrawShocks(Boss07* this, PlayState* play) {
+ s32 i;
+ GraphicsContext* gfxCtx;
+
+ OPEN_DISPS(gfxCtx = play->state.gfxCtx);
+
+ if ((this->shockOrbScale > 0.0f) || (this->shockSparkScale > 0.0f)) {
+ Gfx_SetupDL25_Xlu(play->state.gfxCtx);
+ gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, 255);
+ gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 0, 0);
+
+ if (this->shockOrbScale > 0.0f) {
+ gSPDisplayList(POLY_XLU_DISP++, gLightOrbMaterial1DL);
+
+ for (i = 0; i < MAJORAS_WRATH_BODYPART_MAX; i++) {
+ Matrix_Translate(this->bodyPartsPos[i].x, this->bodyPartsPos[i].y, this->bodyPartsPos[i].z,
+ MTXMODE_NEW);
+ Matrix_ReplaceRotation(&play->billboardMtxF);
+ Matrix_Scale(this->shockOrbScale, this->shockOrbScale, this->shockOrbScale, MTXMODE_APPLY);
+ Matrix_RotateZF(Rand_ZeroFloat(2.0f * M_PIf), MTXMODE_APPLY);
+ MATRIX_FINALIZE_AND_LOAD(POLY_XLU_DISP++, gfxCtx);
+ gSPDisplayList(POLY_XLU_DISP++, gLightOrbModelDL);
+ }
+
+ for (i = this->whipShockMaxIndex; i >= this->whipShockMinIndex; i--) {
+ Matrix_Translate(this->rightWhip.pos[i].x, this->rightWhip.pos[i].y, this->rightWhip.pos[i].z,
+ MTXMODE_NEW);
+ Matrix_ReplaceRotation(&play->billboardMtxF);
+ Matrix_Scale(1.5f, 1.5f, 1.5f, MTXMODE_APPLY);
+ Matrix_RotateZF(Rand_ZeroFloat(2.0f * M_PIf), MTXMODE_APPLY);
+ MATRIX_FINALIZE_AND_LOAD(POLY_XLU_DISP++, gfxCtx);
+ gSPDisplayList(POLY_XLU_DISP++, gLightOrbModelDL);
+ }
+ }
+
+ if (this->shockSparkScale > 0.0f) {
+ gSPDisplayList(POLY_XLU_DISP++, gLightOrbMaterial2DL);
+
+ for (i = 0; i < MAJORAS_WRATH_BODYPART_MAX * 2; i++) {
+ Matrix_Translate(this->bodyPartsPos[i / 2].x + Rand_CenteredFloat(30.0f),
+ this->bodyPartsPos[i / 2].y + Rand_CenteredFloat(30.0f),
+ this->bodyPartsPos[i / 2].z + Rand_CenteredFloat(30.0f), MTXMODE_NEW);
+ Matrix_Scale(this->shockSparkScale, this->shockSparkScale, this->shockSparkScale, MTXMODE_APPLY);
+ Matrix_RotateXFApply(Rand_ZeroFloat(2.0f * M_PIf));
+ Matrix_RotateZF(Rand_ZeroFloat(2.0f * M_PIf), MTXMODE_APPLY);
+ MATRIX_FINALIZE_AND_LOAD(POLY_XLU_DISP++, gfxCtx);
+ gSPDisplayList(POLY_XLU_DISP++, gLightOrbModelDL);
+ }
+ }
+ }
+
+ CLOSE_DISPS(gfxCtx);
+}
+
+void Boss07_Wrath_DrawDeathLights(Boss07* this, PlayState* play, Vec3f* pos) {
+ s32 i;
+ f32 scale;
+ f32 yOffset;
+ GraphicsContext* gfxCtx;
+ s16* color;
+
+ OPEN_DISPS(gfxCtx = play->state.gfxCtx);
+
+ if (this->deathOrbScale > 0.0f) {
+ Boss07_InitRand(1, 0x71B8, 0x263A);
+ POLY_XLU_DISP = Gfx_SetupDL(POLY_XLU_DISP, 20);
+ gDPSetCombineMode(POLY_XLU_DISP++, G_CC_PRIMITIVE, G_CC_PRIMITIVE);
+
+ for (i = 0; i < ARRAY_COUNT(this->deathLightScale); i++) {
+ color = sProjectileEnvColors[0];
+ gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, color[0], color[1], color[2], 40);
+ yOffset = (Boss07_RandZeroOne() * 40.0f) - 30.0f;
+ Matrix_Translate(this->bodyPartsPos[MAJORAS_WRATH_BODYPART_PELVIS].x,
+ this->bodyPartsPos[MAJORAS_WRATH_BODYPART_PELVIS].y - 30.0f + 50.0f + yOffset + 25.0f,
+ this->bodyPartsPos[MAJORAS_WRATH_BODYPART_PELVIS].z, MTXMODE_NEW);
+ Matrix_Translate(pos->x, pos->y + yOffset, pos->z, MTXMODE_NEW);
+ Matrix_RotateYF(Boss07_RandZeroOne() * M_PIf * 2.0f, MTXMODE_APPLY);
+ Matrix_RotateXFApply(-250.0f * 0.0001f * yOffset);
+ Matrix_RotateZF(Boss07_RandZeroOne() * M_PIf * 2.0f, MTXMODE_APPLY);
+
+ if (this->deathLightScale[i] > 0.0f) {
+ Matrix_Scale(this->deathLightScale[i], 1.0f, 12.0f, MTXMODE_APPLY);
+ MATRIX_FINALIZE_AND_LOAD(POLY_XLU_DISP++, gfxCtx);
+ gSPDisplayList(POLY_XLU_DISP++, gMajorasWrathDeathLightModelDL);
+ }
+ }
+
+ Gfx_SetupDL25_Xlu(play->state.gfxCtx);
+ gSPDisplayList(POLY_XLU_DISP++, gLightOrbMaterial1DL);
+ gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, (u8)(220 + sREG(18)), (u8)(170 + sREG(16)));
+ gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, (u8)(100 + sREG(22)), 128);
+
+ Matrix_Translate(this->bodyPartsPos[MAJORAS_WRATH_BODYPART_PELVIS].x,
+ this->bodyPartsPos[MAJORAS_WRATH_BODYPART_PELVIS].y,
+ this->bodyPartsPos[MAJORAS_WRATH_BODYPART_PELVIS].z, MTXMODE_NEW);
+ Matrix_ReplaceRotation(&play->billboardMtxF);
+ Matrix_RotateZS(play->gameplayFrames * 0x80, MTXMODE_APPLY);
+ scale = (sREG(17) + 800) * 0.01f * this->deathOrbScale;
+ Matrix_Scale(scale, scale, 1.0f, MTXMODE_APPLY);
+ MATRIX_FINALIZE_AND_LOAD(POLY_XLU_DISP++, play->state.gfxCtx);
+ gSPDisplayList(POLY_XLU_DISP++, gLightOrbModelDL);
+ }
+
+ CLOSE_DISPS(gfxCtx);
+}
+
+void Boss07_BattleHandler_DrawIntroPlayerLightOrb(Boss07* this, PlayState* play) {
+ s32 pad;
+ GraphicsContext* gfxCtx;
+ f32 yOffset;
+ f32 zOffset;
+ Player* player;
+
+ OPEN_DISPS(gfxCtx = play->state.gfxCtx);
+
+ player = GET_PLAYER(play);
+
+ if (this->introPlayerOrbScale > 0.0f) {
+ Gfx_SetupDL25_Xlu(play->state.gfxCtx);
+ gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, (u8)(sREG(52) + 255));
+ gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 0, 0);
+ gSPDisplayList(POLY_XLU_DISP++, gLightOrbMaterial1DL);
+
+ if (player->transformation == PLAYER_FORM_GORON) {
+ yOffset = -10.0f;
+ zOffset = -20.0f;
+ } else {
+ yOffset = zOffset = 0.0f;
+ }
+
+ if (player->transformation == PLAYER_FORM_FIERCE_DEITY) {
+ yOffset -= 43.0f;
+ }
+
+ Matrix_Translate(player->actor.world.pos.x,
+ player->actor.world.pos.y + Player_GetHeight(player) - 20.0f + yOffset + sREG(60),
+ player->actor.world.pos.z + sREG(61) - 15.0f + zOffset, MTXMODE_NEW);
+ Matrix_ReplaceRotation(&play->billboardMtxF);
+
+ Matrix_Scale(this->introPlayerOrbScale, this->introPlayerOrbScale, this->introPlayerOrbScale, MTXMODE_APPLY);
+ Matrix_RotateZS(play->gameplayFrames * 0x40, MTXMODE_APPLY);
+ MATRIX_FINALIZE_AND_LOAD(POLY_XLU_DISP++, gfxCtx);
+ gSPDisplayList(POLY_XLU_DISP++, gLightOrbModelDL);
+ }
+
+ CLOSE_DISPS(gfxCtx);
+}
+
+void Boss07_Wrath_Draw(Actor* thisx, PlayState* play2) {
+ PlayState* play = play2;
+ Boss07* this = THIS;
+ u8* tex = GRAPH_ALLOC(play->state.gfxCtx, MAJORAS_WRATH_SHADOW_TEX_SIZE);
+
+ OPEN_DISPS(play->state.gfxCtx);
+
+ Gfx_SetupDL25_Opa(play->state.gfxCtx);
+ Gfx_SetupDL25_Xlu(play->state.gfxCtx);
+
+ if ((this->damagedFlashTimer % 2) != 0) {
+ POLY_OPA_DISP = Gfx_SetFog(POLY_OPA_DISP, 255, 0, 0, 255, 900, 1099);
+ }
+
+ Matrix_RotateYF(this->wrathLeanRotY, MTXMODE_APPLY);
+ Matrix_RotateXFApply(this->wrathLeanRotX);
+ SkelAnime_DrawTransformFlexOpa(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
+ this->skelAnime.dListCount, Boss07_Wrath_OverrideLimbDraw, Boss07_Wrath_PostLimbDraw,
+ Boss07_Wrath_TransformLimbDraw, &this->actor);
+ POLY_OPA_DISP = Play_SetFog(play, POLY_OPA_DISP);
+
+ if (((KREG(63) == 0) || (KREG(63) == 2)) && this->shouldUpdateTentaclesOrWhips) {
+ Boss07_Wrath_UpdateWhips(this, play, &this->rightWhip.basePos, this->rightWhip.pos, this->rightWhip.rot,
+ this->rightWhip.velocity, this->rightWhip.gravity, this->rightWhip.mobility,
+ this->rightWhip.deceleration, this->rightWhip.tension, &this->rightWhip.baseRot,
+ this->whipWrapEndOffset, this->whipLengthScale, MAJORAS_WRATH_HAND_RIGHT);
+ Boss07_Wrath_UpdateWhips(this, play, &this->leftWhip.basePos, this->leftWhip.pos, this->leftWhip.rot,
+ this->leftWhip.velocity, this->leftWhip.gravity, this->leftWhip.mobility,
+ this->leftWhip.deceleration, this->leftWhip.tension, &this->leftWhip.baseRot, 0,
+ this->whipLengthScale, MAJORAS_WRATH_HAND_LEFT);
+ }
+
+ Boss07_Wrath_DrawWhip(this, play, this->rightWhip.pos, this->rightWhip.rot, this->whipLengthScale,
+ MAJORAS_WRATH_HAND_RIGHT);
+ Boss07_Wrath_DrawWhip(this, play, this->leftWhip.pos, this->leftWhip.rot, this->whipLengthScale,
+ MAJORAS_WRATH_HAND_LEFT);
+
+ if (!this->disableShadow) {
+ Boss07_Wrath_GenShadowTex(tex, this, play);
+ Boss07_Wrath_DrawShadowTex(tex, this, play);
+ }
+
+ Boss07_Wrath_DrawShocks(this, play);
+
+ {
+ Vec3f lightsPos;
+
+ lightsPos.x = this->bodyPartsPos[MAJORAS_WRATH_BODYPART_PELVIS].x;
+ lightsPos.y = this->bodyPartsPos[MAJORAS_WRATH_BODYPART_PELVIS].y - 30.0f + 50.0f;
+ lightsPos.z = this->bodyPartsPos[MAJORAS_WRATH_BODYPART_PELVIS].z;
+ Boss07_Wrath_DrawDeathLights(this, play, &lightsPos);
+ }
+
+ Actor_DrawDamageEffects(play, &this->actor, this->bodyPartsPos, MAJORAS_WRATH_BODYPART_MAX, this->drawDmgEffScale,
+ this->drawDmgEffFrozenSteamScale, this->drawDmgEffAlpha, this->drawDmgEffType);
+ this->shouldUpdateTentaclesOrWhips = false;
+
+ CLOSE_DISPS(play->state.gfxCtx);
+}
+
+/**
+ * These four arrays encode circular shadow maps of various sizes. For an array of length N, the shadow map is N rows
+ * tall, and each entry in the array describes the start and end point of the shadow within a given row (the exact
+ * values of the start and end points are determined by the loops within Boss07_Wrath_FillShadowTex). To illustrate
+ * using the sShadowSmallMap as an example:
+ * -3 -2 -1 0 1
+ * -------------
+ * 0 0 1 0 0
+ * 0 1 1 1 0
+ * 1 1 1 1 1
+ * 1 1 1 1 1
+ * 0 1 1 1 0
+ * 0 0 1 0 0
+ */
+static s32 sShadowSmallMap[] = {
+ 1, 2, 3, 3, 2, 1,
+};
+
+static s32 sShadowMediumMap[] = {
+ 2, 3, 4, 4, 4, 3, 2,
+};
+
+static s32 sShadowLargeMap[] = {
+ 2, 3, 4, 4, 4, 4, 3, 2,
+};
+
+static s32 sShadowExtraLargeMap[] = {
+ 2, 4, 5, 5, 6, 6, 6, 6, 5, 5, 4, 2,
+};
+
+static s32 sParentShadowBodyParts[MAJORAS_WRATH_BODYPART_MAX] = {
+ MAJORAS_WRATH_BODYPART_TORSO, // MAJORAS_WRATH_BODYPART_HEAD
+ BODYPART_NONE, // MAJORAS_WRATH_BODYPART_TORSO
+ MAJORAS_WRATH_BODYPART_TORSO, // MAJORAS_WRATH_BODYPART_PELVIS
+ MAJORAS_WRATH_BODYPART_TORSO, // MAJORAS_WRATH_BODYPART_LEFT_UPPER_ARM
+ MAJORAS_WRATH_BODYPART_LEFT_UPPER_ARM, // MAJORAS_WRATH_BODYPART_LEFT_LOWER_ARM_ROOT
+ MAJORAS_WRATH_BODYPART_LEFT_LOWER_ARM_ROOT, // MAJORAS_WRATH_BODYPART_LEFT_FOREARM
+ MAJORAS_WRATH_BODYPART_TORSO, // MAJORAS_WRATH_BODYPART_RIGHT_UPPER_ARM
+ MAJORAS_WRATH_BODYPART_RIGHT_UPPER_ARM, // MAJORAS_WRATH_BODYPART_RIGHT_LOWER_ARM_ROOT
+ MAJORAS_WRATH_BODYPART_RIGHT_LOWER_ARM_ROOT, // MAJORAS_WRATH_BODYPART_RIGHT_FOREARM
+ MAJORAS_WRATH_BODYPART_PELVIS, // MAJORAS_WRATH_BODYPART_RIGHT_THIGH
+ MAJORAS_WRATH_BODYPART_RIGHT_THIGH, // MAJORAS_WRATH_BODYPART_RIGHT_SHIN
+ MAJORAS_WRATH_BODYPART_RIGHT_SHIN, // MAJORAS_WRATH_BODYPART_RIGHT_FOOT
+ MAJORAS_WRATH_BODYPART_PELVIS, // MAJORAS_WRATH_BODYPART_LEFT_THIGH
+ MAJORAS_WRATH_BODYPART_LEFT_THIGH, // MAJORAS_WRATH_BODYPART_LEFT_SHIN
+ MAJORAS_WRATH_BODYPART_LEFT_SHIN // MAJORAS_WRATH_BODYPART_LEFT_FOOT
+};
+
+static u8 sShadowSizes[MAJORAS_WRATH_BODYPART_MAX] = {
+ MAJORAS_WRATH_SHADOW_SIZE_SMALL, // MAJORAS_WRATH_BODYPART_HEAD
+ MAJORAS_WRATH_SHADOW_SIZE_EXTRA_LARGE, // MAJORAS_WRATH_BODYPART_TORSO
+ MAJORAS_WRATH_SHADOW_SIZE_EXTRA_LARGE, // MAJORAS_WRATH_BODYPART_PELVIS
+ MAJORAS_WRATH_SHADOW_SIZE_LARGE, // MAJORAS_WRATH_BODYPART_LEFT_UPPER_ARM
+ MAJORAS_WRATH_SHADOW_SIZE_SMALL, // MAJORAS_WRATH_BODYPART_LEFT_LOWER_ARM_ROOT
+ MAJORAS_WRATH_SHADOW_SIZE_SMALL, // MAJORAS_WRATH_BODYPART_LEFT_FOREARM
+ MAJORAS_WRATH_SHADOW_SIZE_LARGE, // MAJORAS_WRATH_BODYPART_RIGHT_UPPER_ARM
+ MAJORAS_WRATH_SHADOW_SIZE_SMALL, // MAJORAS_WRATH_BODYPART_RIGHT_LOWER_ARM_ROOT
+ MAJORAS_WRATH_SHADOW_SIZE_SMALL, // MAJORAS_WRATH_BODYPART_RIGHT_FOREARM
+ MAJORAS_WRATH_SHADOW_SIZE_LARGE, // MAJORAS_WRATH_BODYPART_RIGHT_THIGH
+ MAJORAS_WRATH_SHADOW_SIZE_MEDIUM, // MAJORAS_WRATH_BODYPART_RIGHT_SHIN
+ MAJORAS_WRATH_SHADOW_SIZE_SMALL, // MAJORAS_WRATH_BODYPART_RIGHT_FOOT
+ MAJORAS_WRATH_SHADOW_SIZE_LARGE, // MAJORAS_WRATH_BODYPART_LEFT_THIGH
+ MAJORAS_WRATH_SHADOW_SIZE_MEDIUM, // MAJORAS_WRATH_BODYPART_LEFT_SHIN
+ MAJORAS_WRATH_SHADOW_SIZE_SMALL, // MAJORAS_WRATH_BODYPART_LEFT_FOOT
+};
+
+void Boss07_Wrath_FillShadowTex(Boss07* this, u8* tex, f32 weight) {
+ s32 index;
+ s32 i;
+ s32 baseX;
+ s32 baseY;
+ s32 x;
+ s32 y = 0;
+ s32 addY;
+ Vec3f lerp;
+ Vec3f pos;
+ Vec3f startVec;
+
+ for (i = 0; i < MAJORAS_WRATH_BODYPART_MAX; i++) {
+ // TODO: match with a continue
+ if ((weight == 0.0f) || ((y = sParentShadowBodyParts[i]) > BODYPART_NONE)) {
+ if (weight > 0.0f) {
+ VEC3F_LERPIMPDST(&lerp, &this->bodyPartsPos[i], &this->bodyPartsPos[y], weight);
+
+ pos.x = lerp.x - this->actor.world.pos.x;
+ pos.y = lerp.y - this->actor.world.pos.y + 76.0f + 30.0f + 30.0f + 100.0f;
+ pos.z = lerp.z - this->actor.world.pos.z;
+ } else {
+ pos.x = this->bodyPartsPos[i].x - this->actor.world.pos.x;
+ pos.y = this->bodyPartsPos[i].y - this->actor.world.pos.y + 76.0f + 30.0f + 30.0f + 100.0f;
+ pos.z = this->bodyPartsPos[i].z - this->actor.world.pos.z;
+ }
+
+ Matrix_MultVec3f(&pos, &startVec);
+
+ startVec.x *= 0.2f;
+ startVec.y *= 0.2f;
+
+ baseX = (u16)(s32)(startVec.x + 32.0f);
+ baseY = (u16)((s32)startVec.y * 64);
+
+ if (sShadowSizes[i] == MAJORAS_WRATH_SHADOW_SIZE_EXTRA_LARGE) {
+ for (y = 0, addY = -384; y < ARRAY_COUNT(sShadowExtraLargeMap); y++, addY += 64) {
+ for (x = -sShadowExtraLargeMap[y]; x < sShadowExtraLargeMap[y]; x++) {
+ index = baseX + x + baseY + addY;
+ if ((index >= 0) && (index < MAJORAS_WRATH_SHADOW_TEX_SIZE)) {
+ tex[index] = 255;
+ }
+ }
+ }
+ } else if (sShadowSizes[i] == MAJORAS_WRATH_SHADOW_SIZE_LARGE) {
+ for (y = 0, addY = -256; y < ARRAY_COUNT(sShadowLargeMap); y++, addY += 64) {
+ for (x = -sShadowLargeMap[y]; x < sShadowLargeMap[y]; x++) {
+ index = baseX + x + baseY + addY;
+ if ((index >= 0) && (index < MAJORAS_WRATH_SHADOW_TEX_SIZE)) {
+ tex[index] = 255;
+ }
+ }
+ }
+ } else if (sShadowSizes[i] == MAJORAS_WRATH_SHADOW_SIZE_MEDIUM) {
+ for (y = 0, addY = -192; y < ARRAY_COUNT(sShadowMediumMap); y++, addY += 64) {
+ for (x = -sShadowMediumMap[y]; x < sShadowMediumMap[y] - 1; x++) {
+ index = baseX + x + baseY + addY;
+ if ((index >= 0) && (index < MAJORAS_WRATH_SHADOW_TEX_SIZE)) {
+ tex[index] = 255;
+ }
+ }
+ }
+ } else {
+ for (y = 0, addY = -128; y < ARRAY_COUNT(sShadowSmallMap); y++, addY += 64) {
+ for (x = -sShadowSmallMap[y]; x < sShadowSmallMap[y] - 1; x++) {
+ index = baseX + x + baseY + addY;
+ if ((index >= 0) && (index < MAJORAS_WRATH_SHADOW_TEX_SIZE)) {
+ tex[index] = 255;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void Boss07_Wrath_GenShadowTex(u8* tex, Boss07* this, PlayState* play) {
+ s32* iter = (s32*)tex;
+ s32 i;
+
+ for (i = 0; i < (s32)(MAJORAS_WRATH_SHADOW_TEX_SIZE / sizeof(s32)); i++, iter++) {
+ *iter = 0;
+ }
+
+ Matrix_RotateXFNew(1.0f);
+
+ for (i = 0; i <= 5; i++) {
+ Boss07_Wrath_FillShadowTex(this, tex, i / 5.0f);
+ }
+}
+
+/**
+ * Draws Wrath's dynamic shadow underneath it.
+ */
+void Boss07_Wrath_DrawShadowTex(u8* tex, Boss07* this, PlayState* play) {
+ s32 pad[2];
+ f32 alpha;
+ GraphicsContext* gfxCtx = play->state.gfxCtx;
+
+ OPEN_DISPS(gfxCtx);
+
+ Gfx_SetupDL25_Opa(play->state.gfxCtx);
+
+ alpha = (400.0f - this->actor.world.pos.y) * (1.0f / 400.0f);
+ alpha = CLAMP_MIN(alpha, 0.0f);
+ alpha = CLAMP_MAX(alpha, 1.0f);
+
+ gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 0, 0, 0, (s8)(alpha * 80.0f));
+ gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 0);
+ Matrix_Translate(this->actor.world.pos.x, this->actor.floorHeight, this->actor.world.pos.z - 20.0f, MTXMODE_NEW);
+ Matrix_Scale(1.75f, 1.0f, 1.75f, MTXMODE_APPLY);
+ MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, play->state.gfxCtx);
+ gSPDisplayList(POLY_OPA_DISP++, gMajorasWrathShadowMaterialDL);
+ gDPLoadTextureBlock(POLY_OPA_DISP++, tex, G_IM_FMT_I, G_IM_SIZ_8b, MAJORAS_WRATH_SHADOW_TEX_WIDTH,
+ MAJORAS_WRATH_SHADOW_TEX_HEIGHT, 0, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, 6,
+ 6, G_TX_NOLOD, G_TX_NOLOD);
+ gSPDisplayList(POLY_OPA_DISP++, gMajorasWrathShadowModelDL);
+
+ CLOSE_DISPS(gfxCtx);
+}
+
+void Boss07_Incarnation_AvoidPlayer(Boss07* this) {
+ s32 rotOffset = (Rand_ZeroOne() < 0.5f) ? 0x4000 : -0x4000;
+
+ Matrix_RotateYS(this->actor.yawTowardsPlayer + rotOffset, MTXMODE_NEW);
+ Matrix_MultVecZ(200.0f, &this->targetPos);
+ this->timers[1] = 30;
+ this->targetPos.x += this->actor.world.pos.x;
+ this->targetPos.z += this->actor.world.pos.z;
+ this->speedToTarget = 0x4E20;
+}
+
+void Boss07_Incarnation_SetupIntroCutscene(Boss07* this, PlayState* play) {
+ this->actionFunc = Boss07_Incarnation_IntroCutscene;
+ Animation_MorphToLoop(&this->skelAnime, &gMajorasIncarnationJerkingAnim, 0.0f);
+ this->actor.flags &= ~ACTOR_FLAG_ATTENTION_ENABLED;
+ this->cutsceneHeadRot.x = 0x6E00;
+}
+
+void Boss07_Incarnation_IntroCutscene(Boss07* this, PlayState* play) {
+ s32 i;
+ f32 targetFactor;
+
+ SkelAnime_Update(&this->skelAnime);
+
+ this->cutsceneTimer++;
+ Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, MTXMODE_NEW);
+ Matrix_RotateYS(this->actor.shape.rot.y, MTXMODE_APPLY);
+ targetFactor = Math_SinS(this->frameCounter * 0x4500) * 0.3f;
+
+ switch (this->cutsceneState) {
+ case MAJORAS_INCARNATION_INTRO_CS_STATE_STARTING_OR_DONE:
+ this->cutsceneTimer = 0;
+ this->cutsceneState = MAJORAS_INCARNATION_INTRO_CS_STATE_UPDATE_SUBCAM;
+ this->subCamAtNext.z = 0.0f;
+ FALLTHROUGH;
+ case MAJORAS_INCARNATION_INTRO_CS_STATE_UPDATE_SUBCAM:
+ this->cutsceneState = MAJORAS_INCARNATION_INTRO_CS_STATE_GROW_LEFT_LEG;
+ this->cutsceneTimer = 0;
+ this->subCamEyeNext.x = 70.0f;
+ this->subCamEyeNext.y = 70.0f;
+ this->subCamEyeNext.z = 150.0f;
+ this->subCamAtNext.x = 20.0f;
+ this->subCamAtNext.y = 80.0f;
+ break;
+
+ case MAJORAS_INCARNATION_INTRO_CS_STATE_GROW_LEFT_LEG:
+ if (this->cutsceneTimer >= 20) {
+ if (this->cutsceneTimer == 20) {
+ this->incarnationIntroBodyPartsScaleTarget[MAJORAS_INCARNATION_GROW_BODYPART_LEFT_LEG] = 1.0f;
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST1_TRANSFORM);
+ }
+
+ Math_ApproachF(
+ &this->incarnationIntroBodyPartsScale[MAJORAS_INCARNATION_GROW_BODYPART_LEFT_LEG],
+ 1.0f + (this->incarnationIntroBodyPartsScaleTarget[MAJORAS_INCARNATION_GROW_BODYPART_LEFT_LEG] *
+ targetFactor),
+ 1.0f, 0.5f);
+ }
+
+ if (this->cutsceneTimer > 40) {
+ this->cutsceneState = MAJORAS_INCARNATION_INTRO_CS_STATE_GROW_OTHER_LIMBS;
+ this->cutsceneTimer = 0;
+ }
+ break;
+
+ case MAJORAS_INCARNATION_INTRO_CS_STATE_GROW_OTHER_LIMBS:
+ Math_ApproachF(&this->subCamEyeNext.x, 0.0f, 0.05f, this->subCamVelocity * 40.0f);
+ Math_ApproachF(&this->subCamEyeNext.y, 100.0f, 0.05f, this->subCamVelocity * 30.0f);
+ Math_ApproachF(&this->subCamEyeNext.z, 270.0f, 0.05f, this->subCamVelocity * 150.0f);
+ Math_ApproachF(&this->subCamAtNext.x, 0.0f, 0.05f, this->subCamVelocity * 20.0f);
+ Math_ApproachF(&this->subCamAtNext.y, 100.0f, 0.05f, this->subCamVelocity * 20.0f);
+ Math_ApproachF(&this->subCamVelocity, 0.05f, 1.0f, 0.002f);
+
+ if (this->cutsceneTimer >= 20) {
+ if (this->cutsceneTimer == 20) {
+ this->incarnationIntroBodyPartsScaleTarget[MAJORAS_INCARNATION_GROW_BODYPART_RIGHT_LEG] = 1.0f;
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST1_TRANSFORM);
+ }
+
+ Math_ApproachF(
+ &this->incarnationIntroBodyPartsScale[MAJORAS_INCARNATION_GROW_BODYPART_RIGHT_LEG],
+ 1.0f + (this->incarnationIntroBodyPartsScaleTarget[MAJORAS_INCARNATION_GROW_BODYPART_RIGHT_LEG] *
+ targetFactor),
+ 1.0f, 0.5f);
+ }
+
+ if (this->cutsceneTimer >= 50) {
+ if (this->cutsceneTimer == 50) {
+ this->incarnationIntroBodyPartsScaleTarget[MAJORAS_INCARNATION_GROW_BODYPART_LEFT_ARM] = 1.0f;
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST1_TRANSFORM);
+ }
+
+ Math_ApproachF(
+ &this->incarnationIntroBodyPartsScale[MAJORAS_INCARNATION_GROW_BODYPART_LEFT_ARM],
+ 1.0f + (this->incarnationIntroBodyPartsScaleTarget[MAJORAS_INCARNATION_GROW_BODYPART_LEFT_ARM] *
+ targetFactor),
+ 1.0f, 0.5f);
+ }
+
+ if (this->cutsceneTimer >= 60) {
+ if (this->cutsceneTimer == 60) {
+ this->incarnationIntroBodyPartsScaleTarget[MAJORAS_INCARNATION_GROW_BODYPART_RIGHT_ARM] = 1.0f;
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST1_TRANSFORM);
+ }
+
+ Math_ApproachF(
+ &this->incarnationIntroBodyPartsScale[MAJORAS_INCARNATION_GROW_BODYPART_RIGHT_ARM],
+ 1.0f + (this->incarnationIntroBodyPartsScaleTarget[MAJORAS_INCARNATION_GROW_BODYPART_RIGHT_ARM] *
+ targetFactor),
+ 1.0f, 0.5f);
+ }
+
+ if (this->cutsceneTimer == 80) {
+ this->cutsceneState = MAJORAS_INCARNATION_INTRO_CS_STATE_GROW_EYESTALK;
+ this->cutsceneTimer = 0;
+ for (i = 0; i < MAJORAS_INCARNATION_GROW_BODYPART_MAX; i++) {
+ this->incarnationIntroBodyPartsScale[i] = 1.0f;
+ }
+ }
+ break;
+
+ case MAJORAS_INCARNATION_INTRO_CS_STATE_GROW_EYESTALK:
+ this->subCamEyeNext.x = 0.0f;
+ this->subCamEyeNext.y = 120.0f;
+ this->subCamEyeNext.z = 140.0f;
+ this->subCamAtNext.y = 170.0f;
+
+ if (this->cutsceneTimer >= 10) {
+ // This code reuses the scale target for `MAJORAS_INCARNATION_GROW_BODYPART_LEFT_LEG` to control the
+ // rotation of Incarnation's eyestalk. It doesn't matter which scale target it reused, however, because
+ // none of them are currently being used by their intended limbs.
+ if (this->cutsceneTimer == 10) {
+ this->incarnationIntroBodyPartsScaleTarget[MAJORAS_INCARNATION_GROW_BODYPART_LEFT_LEG] = 1.0f;
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST1_GROW_HEAD);
+ }
+
+ Math_ApproachS(&this->cutsceneHeadRot.x,
+ this->incarnationIntroBodyPartsScaleTarget[MAJORAS_INCARNATION_GROW_BODYPART_LEFT_LEG] *
+ targetFactor * 0x6000,
+ 1, 0x4000);
+ }
+
+ if (this->cutsceneTimer == 30) {
+ this->cutsceneState = MAJORAS_INCARNATION_INTRO_CS_STATE_DANCE;
+ this->cutsceneTimer = 0;
+ this->subCamVelocity = 0.0f;
+ this->animEndFrame = 1000.0f;
+ Play_DisableMotionBlur();
+ }
+ break;
+
+ case MAJORAS_INCARNATION_INTRO_CS_STATE_DANCE:
+ if (this->cutsceneTimer == 20) {
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasIncarnationIntroDanceAnim, 0.0f);
+ this->animEndFrame = Animation_GetLastFrame(&gMajorasIncarnationIntroDanceAnim);
+ }
+
+ if (this->cutsceneTimer >= 20) {
+ sREG(28) = this->cutsceneTimer;
+
+ if ((this->cutsceneTimer == (u32)(KREG(16) + 28)) || (this->cutsceneTimer == (u32)(KREG(17) + 60))) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_VOICE_UAUOO2_OLD);
+ }
+
+ if ((this->cutsceneTimer == (u32)(KREG(18) + 38)) || (this->cutsceneTimer == (u32)(KREG(19) + 48)) ||
+ (this->cutsceneTimer == (u32)(KREG(20) + 68)) || (this->cutsceneTimer == (u32)(KREG(21) + 78))) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_GYM_B_OLD);
+ }
+
+ if (this->cutsceneTimer == (u32)(KREG(38) + 93)) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_UAUOO_OLD);
+ }
+ }
+
+ if (this->cutsceneTimer == 45) {
+ TitleCard_InitBossName(&play->state, &play->actorCtx.titleCtx,
+ Lib_SegmentedToVirtual(&gMajorasIncarnationTitleCardTex), 160, 180, 128, 40);
+ }
+
+ if (this->cutsceneTimer == 20) {
+ SEQCMD_PLAY_SEQUENCE(SEQ_PLAYER_BGM_MAIN, 0, NA_BGM_MAJORAS_INCARNATION | SEQ_FLAG_ASYNC);
+ this->lightSettingsMode = 1;
+ play->envCtx.lightBlend = 0.0f;
+ }
+
+ Math_ApproachF(&this->subCamEyeNext.x, -80.0f, 0.05f, this->subCamVelocity * 80.0f);
+ Math_ApproachF(&this->subCamEyeNext.y, 20.0f, 0.05f, this->subCamVelocity * 60.0f);
+ Math_ApproachF(&this->subCamEyeNext.z, 220.0f, 0.05f, this->subCamVelocity * 180.0f);
+ Math_ApproachF(&this->subCamAtNext.y, 110.0f, 0.05f, this->subCamVelocity * 80.0f);
+ Math_ApproachF(&this->subCamVelocity, 0.1f, 1.0f, 0.005f);
+
+ if (Animation_OnFrame(&this->skelAnime, this->animEndFrame)) {
+ Camera* mainCam = Play_GetCamera(play, CAM_ID_MAIN);
+
+ this->cutsceneState = MAJORAS_INCARNATION_INTRO_CS_STATE_STARTING_OR_DONE;
+ Boss07_Incarnation_SetupTaunt(this, play);
+ mainCam->eye = this->subCamEye;
+ mainCam->eyeNext = this->subCamEye;
+ mainCam->at = this->subCamAt;
+ func_80169AFC(play, this->subCamId, 0);
+ this->subCamId = SUB_CAM_ID_DONE;
+ Cutscene_StopManual(play, &play->csCtx);
+ Player_SetCsActionWithHaltedActors(play, &this->actor, PLAYER_CSACTION_END);
+ this->actor.flags |= ACTOR_FLAG_ATTENTION_ENABLED;
+ }
+ break;
+ }
+
+ for (i = 0; i < MAJORAS_INCARNATION_GROW_BODYPART_MAX; i++) {
+ Math_ApproachZeroF(&this->incarnationIntroBodyPartsScaleTarget[i], 0.5f, 0.1f);
+ }
+
+ Matrix_MultVec3f(&this->subCamEyeNext, &this->subCamEye);
+ Matrix_MultVec3f(&this->subCamAtNext, &this->subCamAt);
+
+ if (this->subCamId != SUB_CAM_ID_DONE) {
+ ShrinkWindow_Letterbox_SetSizeTarget(27);
+ Play_SetCameraAtEye(play, this->subCamId, &this->subCamAt, &this->subCamEye);
+ }
+}
+
+void Boss07_Incarnation_SetupTaunt(Boss07* this, PlayState* play) {
+ static AnimationHeader* sTauntAnimations[] = {
+ &gMajorasIncarnationTauntDance1Anim,
+ &gMajorasIncarnationTauntDance2Anim,
+ &gMajorasIncarnationTauntJumpAnim,
+ };
+
+ this->actionFunc = Boss07_Incarnation_Taunt;
+ this->subAction = Rand_ZeroFloat(MAJORAS_INCARNATION_TAUNT_SUB_ACTION_MAX - 0.001f);
+ Animation_MorphToLoop(&this->skelAnime, sTauntAnimations[this->subAction], -10.0f);
+ this->actor.flags |= ACTOR_FLAG_ATTENTION_ENABLED;
+ this->timers[0] = Rand_ZeroFloat(50.0f) + 50.0f;
+}
+
+void Boss07_Incarnation_Taunt(Boss07* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+
+ if (this->subAction < MAJORAS_INCARNATION_TAUNT_SUB_ACTION_JUMP) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_WAIT_OLD - SFX_FLAG);
+ } else if ((this->subAction == MAJORAS_INCARNATION_TAUNT_SUB_ACTION_JUMP) &&
+ Animation_OnFrame(&this->skelAnime, 5.0f)) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_JUMP_OLD);
+ }
+
+ SkelAnime_Update(&this->skelAnime);
+ Boss07_SmoothStop(this, 2.0f);
+ Math_ApproachS(&this->actor.world.rot.y, this->actor.yawTowardsPlayer, 5, 0x2000);
+
+ if ((this->timers[0] == 0) || (player->unk_D57 == 4) || (this->actor.xzDistToPlayer <= 300.0f)) {
+ Boss07_Incarnation_SetupRun(this, play);
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_VOICE_SURPRISED_OLD);
+ }
+
+ Boss07_Incarnation_SpawnDust(this, play, 1, MAJORAS_INCARNATION_DUST_SPAWN_POS_FEET);
+}
+
+void Boss07_Incarnation_SetupStunned(Boss07* this, PlayState* play, s16 stunTime) {
+ if (this->actionFunc != Boss07_Incarnation_Stunned) {
+ this->actionFunc = Boss07_Incarnation_Stunned;
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasIncarnationFallOverStartAnim, -10.0f);
+ this->animEndFrame = Animation_GetLastFrame(&gMajorasIncarnationFallOverStartAnim);
+ }
+
+ this->disableCollisionTimer = 10;
+ this->timers[0] = stunTime;
+ this->timers[1] = 12;
+}
+
+void Boss07_Incarnation_Stunned(Boss07* this, PlayState* play) {
+ this->actor.shape.shadowAlpha = 0;
+ SkelAnime_Update(&this->skelAnime);
+ Boss07_SmoothStop(this, 1.0f);
+
+ if (this->timers[1] == 1) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_HIPLOOP_LAND);
+ }
+
+ if (Animation_OnFrame(&this->skelAnime, this->animEndFrame)) {
+ Animation_MorphToLoop(&this->skelAnime, &gMajorasIncarnationFallOverLoopAnim, -5.0f);
+ this->animEndFrame = 1000.0f;
+ }
+
+ if (this->animEndFrame == 1000.0f) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_BIRD_OLD - SFX_FLAG);
+ }
+
+ if (this->timers[0] == 0) {
+ Boss07_Incarnation_SetupTaunt(this, play);
+ }
+
+ Boss07_Incarnation_SpawnDust(this, play, 1, MAJORAS_INCARNATION_DUST_SPAWN_POS_FOCUS);
+}
+
+void Boss07_Incarnation_SetupDamaged(Boss07* this, PlayState* play, u8 damage, u8 dmgEffect) {
+ if (this->actionFunc != Boss07_Incarnation_Damaged) {
+ this->actionFunc = Boss07_Incarnation_Damaged;
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasIncarnationDamagedAnim, -2.0f);
+ this->animEndFrame = Animation_GetLastFrame(&gMajorasIncarnationDamagedAnim);
+ } else if (dmgEffect == MAJORAS_INCARNATION_DMGEFF_ANIM_FRAME_CHECK) {
+ if (this->skelAnime.curFrame <= (this->animEndFrame - 5.0f)) {
+ this->disableCollisionTimer = 30;
+ this->damagedTimer = 30;
+ } else {
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasIncarnationDamagedAnim, -2.0f);
+ }
+ }
+
+ if (this->actor.colChkInfo.health != 0) {
+ this->actor.colChkInfo.health -= damage;
+
+ if ((s8)this->actor.colChkInfo.health <= 0) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_DEAD_OLD);
+ this->shouldStartDeath = true;
+ this->damagedTimer = 100;
+ this->disableCollisionTimer = 100;
+ Enemy_StartFinishingBlow(play, &this->actor);
+ return;
+ }
+ }
+
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_DAMAGE2_OLD);
+}
+
+void Boss07_Incarnation_Damaged(Boss07* this, PlayState* play) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_BIRD2_OLD - SFX_FLAG);
+ SkelAnime_Update(&this->skelAnime);
+ Boss07_SmoothStop(this, 2.0f);
+
+ if (Animation_OnFrame(&this->skelAnime, this->animEndFrame)) {
+ Boss07_Incarnation_SetupRun(this, play);
+ }
+
+ Boss07_Incarnation_SpawnDust(this, play, 1, MAJORAS_INCARNATION_DUST_SPAWN_POS_FEET);
+}
+
+void Boss07_Incarnation_SetupRun(Boss07* this, PlayState* play) {
+ Animation_MorphToLoop(&this->skelAnime, &gMajorasIncarnationRunAnim, -2.0f);
+ this->actionFunc = Boss07_Incarnation_Run;
+ this->timers[0] = Rand_ZeroFloat(100.0f) + 150.0f;
+ Boss07_Incarnation_AvoidPlayer(this);
+}
+
+void Boss07_Incarnation_Run(Boss07* this, PlayState* play) {
+ f32 dx;
+ f32 dz;
+ PlayerImpactType playerImpactType;
+
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_WALK_OLD - SFX_FLAG);
+ this->miscTimer++;
+
+ if (this->miscTimer >= 2) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_WALK2_OLD);
+ this->miscTimer = 0;
+ }
+
+ SkelAnime_Update(&this->skelAnime);
+
+ if ((Actor_GetPlayerImpact(play, 5.0f, &this->actor.world.pos, &playerImpactType) >= 0.0f) &&
+ (playerImpactType == PLAYER_IMPACT_GORON_GROUND_POUND)) {
+ Boss07_Incarnation_SetupStunned(this, play, 50);
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_DAMAGE_OLD);
+ } else {
+ dx = this->targetPos.x - this->actor.world.pos.x;
+ dz = this->targetPos.z - this->actor.world.pos.z;
+
+ if ((this->timers[1] == 0) || (SQ(dx) + SQ(dz) < 30000.0f)) { // dist ~ 173.2
+ if (Rand_ZeroOne() < 0.3f) {
+ f32 rand = Rand_ZeroOne();
+
+ if (rand < 0.25f) {
+ Boss07_Incarnation_SetupAttack(this, play);
+ } else if (rand < 0.5f) {
+ Boss07_Incarnation_SetupSquattingDance(this, play);
+ } else if (rand < 0.75f) {
+ Boss07_Incarnation_SetupMoonwalk(this, play);
+ } else if (rand < 1.0f) {
+ Boss07_Incarnation_SetupPirouette(this, play);
+ }
+ } else if (Rand_ZeroOne() < 0.01f) {
+ Boss07_Incarnation_SetupStunned(this, play, 50);
+ } else {
+ Boss07_RandXZ(&this->targetPos, 500.0f);
+ this->timers[1] = Rand_ZeroFloat(50.0f) + 20.0f;
+ this->speedToTarget = 0.0f;
+ }
+ }
+
+ Math_ApproachS(&this->actor.world.rot.y, Math_Atan2S(dx, dz), 5, this->speedToTarget);
+ Math_ApproachF(&this->speedToTarget, 0xFA0, 1.0f, 0x1F4);
+ Math_ApproachF(&this->actor.speed, 25.0f, 1.0f, 20.0f);
+
+ if (this->timers[0] == 0) {
+ Boss07_Incarnation_SetupTaunt(this, play);
+ }
+
+ if ((this->actor.xzDistToPlayer < 200.0f) && (this->timers[2] == 0)) {
+ Boss07_Incarnation_AvoidPlayer(this);
+ this->timers[0] = 50;
+ this->timers[2] = 50;
+ }
+
+ Boss07_Incarnation_SpawnDust(this, play, 3, MAJORAS_INCARNATION_DUST_SPAWN_POS_FEET);
+ this->fireTimer = 5;
+ }
+}
+
+void Boss07_Incarnation_SetupAttack(Boss07* this, PlayState* play) {
+ this->actionFunc = Boss07_Incarnation_Attack;
+ Animation_MorphToLoop(&this->skelAnime, &gMajorasIncarnationEnergyBallAttackAnim, -5.0f);
+ this->timers[0] = Rand_ZeroFloat(50.0f) + 30.0f;
+ this->eyeBeamsLengthScale = 0.0f;
+}
+
+void Boss07_Incarnation_Attack(Boss07* this, PlayState* play) {
+ SkelAnime_Update(&this->skelAnime);
+ Boss07_SmoothStop(this, 3.0f);
+ Math_ApproachS(&this->actor.world.rot.y, this->actor.yawTowardsPlayer, 3, 0x3000);
+
+ if (Animation_OnFrame(&this->skelAnime, 4.0f)) {
+ Actor_Spawn(&play->actorCtx, play, ACTOR_BOSS_07, this->incarnationLeftHandPos.x,
+ this->incarnationLeftHandPos.y, this->incarnationLeftHandPos.z, 0, 0, 0,
+ MAJORA_PARAMS(MAJORA_TYPE_PROJECTILE_INCARNATION));
+ }
+
+ if (Animation_OnFrame(&this->skelAnime, 9.0f)) {
+ Actor_Spawn(&play->actorCtx, play, ACTOR_BOSS_07, this->incarnationRightHandPos.x,
+ this->incarnationRightHandPos.y, this->incarnationRightHandPos.z, 0, 0, 0,
+ MAJORA_PARAMS(MAJORA_TYPE_PROJECTILE_INCARNATION));
+ }
+
+ if (this->timers[0] == 0) {
+ Boss07_Incarnation_SetupRun(this, play);
+ }
+
+ Boss07_Incarnation_SpawnDust(this, play, 1, MAJORAS_INCARNATION_DUST_SPAWN_POS_FEET);
+}
+
+void Boss07_Incarnation_SetupSquattingDance(Boss07* this, PlayState* play) {
+ this->actionFunc = Boss07_Incarnation_SquattingDance;
+ Animation_MorphToLoop(&this->skelAnime, &gMajorasIncarnationSquattingDanceAnim, -5.0f);
+ this->timers[0] = Rand_ZeroFloat(100.0f) + 100.0f;
+ this->timers[1] = 0;
+ this->cutsceneTimer = 0;
+}
+
+void Boss07_Incarnation_SquattingDance(Boss07* this, PlayState* play) {
+ SkelAnime_Update(&this->skelAnime);
+
+ // This uses `cutsceneTimer` to count how many loops of the dancing animation Majora's Incarnation completes.
+ // Specifically, it's incremented every time Incarnation reaches the 5th frame of its animation.
+ if (Animation_OnFrame(&this->skelAnime, 5.0f)) {
+ if ((this->cutsceneTimer % 2) == 0) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_VOICE_UAUOO1_OLD);
+ } else {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_VOICE_UAUOO2_OLD);
+ }
+
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_LAST2_JUMP_OLD);
+ this->cutsceneTimer++;
+ }
+
+ Math_ApproachF(&this->actor.speed, KREG(67) + 10.0f, 1.0f, 3.0f);
+
+ if (this->timers[1] == 0) {
+ if ((this->frameCounter == 0) && (Rand_ZeroOne() < 0.7f)) {
+ if (Rand_ZeroOne() < 0.75f) {
+ this->topPrecessionVelocity = Rand_CenteredFloat(0x10000);
+ } else {
+ this->topPrecessionVelocity = this->actor.yawTowardsPlayer;
+ }
+ }
+
+ if (this->actor.bgCheckFlags & BGCHECKFLAG_WALL) {
+ this->timers[1] = 20;
+ this->topPrecessionVelocity = this->actor.yawTowardsPlayer;
+ }
+ }
+
+ Math_ApproachS(&this->actor.world.rot.y, this->topPrecessionVelocity, 0xA, 0x1800);
+
+ if ((this->timers[0] == 0) || (this->actor.xzDistToPlayer <= 200.0f)) {
+ Boss07_Incarnation_SetupRun(this, play);
+
+ if (this->timers[0] != 0) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_VOICE_SURPRISED_OLD);
+ }
+ }
+
+ Boss07_Incarnation_SpawnDust(this, play, 7, MAJORAS_INCARNATION_DUST_SPAWN_POS_FEET);
+}
+
+void Boss07_Incarnation_SetupMoonwalk(Boss07* this, PlayState* play) {
+ this->actionFunc = Boss07_Incarnation_Moonwalk;
+ Animation_MorphToLoop(&this->skelAnime, &gMajorasIncarnationMoonwalkAnim, -10.0f);
+ this->timers[0] = Rand_ZeroFloat(50.0f) + 70.0f;
+ this->timers[1] = 0;
+}
+
+void Boss07_Incarnation_Moonwalk(Boss07* this, PlayState* play) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_MOONWALK_OLD - SFX_FLAG);
+ SkelAnime_Update(&this->skelAnime);
+ Math_ApproachF(&this->actor.speed, -10.0f + KREG(69), 1.0f, 3.0f);
+
+ if (this->timers[1] == 0) {
+ if ((this->frameCounter == 0) && (Rand_ZeroOne() < 0.5f)) {
+ if (Rand_ZeroOne() < 0.75f) {
+ this->topPrecessionVelocity = Rand_CenteredFloat(0x10000);
+ } else {
+ this->topPrecessionVelocity = this->actor.yawTowardsPlayer + 0x8000;
+ }
+ }
+
+ if (this->actor.bgCheckFlags & BGCHECKFLAG_WALL) {
+ this->timers[1] = 20;
+ this->topPrecessionVelocity = this->actor.yawTowardsPlayer + 0x8000;
+ }
+ }
+
+ Math_ApproachS(&this->actor.world.rot.y, this->topPrecessionVelocity, 0xA, 0x1000);
+
+ if (this->timers[0] == 0) {
+ Boss07_Incarnation_SetupRun(this, play);
+ }
+
+ Boss07_Incarnation_SpawnDust(this, play, 7, MAJORAS_INCARNATION_DUST_SPAWN_POS_FEET);
+}
+
+void Boss07_Incarnation_SetupPirouette(Boss07* this, PlayState* play) {
+ this->actionFunc = Boss07_Incarnation_Pirouette;
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasIncarnationPirouetteAnim, -10.0f);
+ this->timers[0] = Rand_ZeroFloat(70.0f) + 70.0f;
+ this->timers[1] = 0;
+}
+
+void Boss07_Incarnation_Pirouette(Boss07* this, PlayState* play) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_BALLET_OLD - SFX_FLAG);
+ SkelAnime_Update(&this->skelAnime);
+ Math_ApproachF(&this->actor.speed, 10.0f + KREG(69), 1.0f, 1.0f);
+
+ if (this->timers[1] == 0) {
+ if (((this->frameCounter % 64) == 0) && (Rand_ZeroOne() < 0.5f)) {
+ if (Rand_ZeroOne() < 0.75f) {
+ this->topPrecessionVelocity = Rand_CenteredFloat(0x10000);
+ } else {
+ this->topPrecessionVelocity = this->actor.yawTowardsPlayer;
+ }
+ }
+
+ if (this->actor.bgCheckFlags & BGCHECKFLAG_WALL) {
+ this->timers[1] = 20;
+ this->topPrecessionVelocity = this->actor.yawTowardsPlayer;
+ }
+ }
+
+ Math_ApproachS(&this->actor.world.rot.y, this->topPrecessionVelocity, 0xA, 0x1000);
+
+ if ((this->timers[0] == 0) || (this->actor.xzDistToPlayer <= 200.0f)) {
+ Boss07_Incarnation_SetupRun(this, play);
+
+ if (this->timers[0] != 0) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_VOICE_SURPRISED_OLD);
+ }
+ }
+
+ this->actor.shape.rot.y += 0x2000;
+}
+
+void Boss07_Incarnation_SetupDeathCutscene(Boss07* this, PlayState* play) {
+ this->actionFunc = Boss07_Incarnation_DeathCutscene;
+ Boss07_MovePlayerFromCenter(play);
+ Animation_MorphToPlayOnce(&this->skelAnime, &gMajorasIncarnationDamagedAnim, -2.0f);
+ this->animEndFrame = Animation_GetLastFrame(&gMajorasIncarnationDamagedAnim);
+ this->cutsceneState = MAJORAS_INCARNATION_DEATH_CS_STATE_STARTED;
+ this->cutsceneTimer = 0;
+ this->actor.flags &= ~ACTOR_FLAG_ATTENTION_ENABLED;
+ this->damagedTimer = 20;
+}
+
+void Boss07_Incarnation_DeathCutscene(Boss07* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+ u8 limbPumpState = MAJORAS_INCARNATION_LIMB_PUMP_STATE_NONE;
+
+ this->damagedTimer = 20;
+ this->cutsceneTimer++;
+ SkelAnime_Update(&this->skelAnime);
+ Boss07_SmoothStop(this, 3.0f);
+
+ switch (this->cutsceneState) {
+ case MAJORAS_INCARNATION_DEATH_CS_STATE_STARTED:
+ if (CutsceneManager_GetCurrentCsId() != CS_ID_NONE) {
+ break;
+ }
+
+ Cutscene_StartManual(play, &play->csCtx);
+ Player_SetCsActionWithHaltedActors(play, &this->actor, PLAYER_CSACTION_WAIT);
+ this->subCamId = Play_CreateSubCamera(play);
+ Play_ChangeCameraStatus(play, CAM_ID_MAIN, CAM_STATUS_WAIT);
+ Play_ChangeCameraStatus(play, this->subCamId, CAM_STATUS_ACTIVE);
+ this->cutsceneTimer = 0;
+ this->cutsceneState = MAJORAS_INCARNATION_DEATH_CS_STATE_PLAY_DAMAGED_ANIM;
+ Play_EnableMotionBlur(150);
+ FALLTHROUGH;
+ case MAJORAS_INCARNATION_DEATH_CS_STATE_PLAY_DAMAGED_ANIM:
+ sHeartbeatTimer = 5;
+ this->subCamEyeNext.x = 0.0f;
+ this->subCamEyeNext.y = 30.0f;
+ this->subCamEyeNext.z = 210.0f;
+ this->subCamAtNext.x = 0.0f;
+ this->subCamAtNext.y = 150.0f;
+ this->subCamAtNext.z = 0.0f;
+ Math_ApproachF(&this->actor.world.pos.x, 0.0f, 0.1f, 5.0f);
+ Math_ApproachF(&this->actor.world.pos.z, 0.0f, 0.1f, 5.0f);
+
+ if (Animation_OnFrame(&this->skelAnime, this->animEndFrame)) {
+ this->cutsceneTimer = 0;
+ this->cutsceneState = MAJORAS_INCARNATION_DEATH_CS_STATE_PLAY_FINAL_HIT_ANIM;
+ Animation_MorphToLoop(&this->skelAnime, &gMajorasIncarnationFinalHitAnim, -5.0f);
+ }
+ break;
+
+ case MAJORAS_INCARNATION_DEATH_CS_STATE_PLAY_FINAL_HIT_ANIM:
+ sHeartbeatTimer = 5;
+ this->subCamAtNext.y = (Math_SinS(this->cutsceneTimer * 0x700) * 15.0f) + 150.0f;
+
+ if (this->cutsceneTimer == 40) {
+ this->cutsceneTimer = 0;
+ this->cutsceneState = MAJORAS_INCARNATION_DEATH_CS_STATE_PUMP_UP_RIGHT_ARM;
+
+ this->subCamEyeNext.x = -30.0f;
+ this->subCamEyeNext.y = 120.0f;
+ this->subCamEyeNext.z = 110.0f;
+
+ this->subCamAtNext.x = -70.0f;
+ this->subCamAtNext.y = 150.0f;
+ this->subCamAtNext.z = -20.0f;
+
+ this->incarnationWrathTransitionScale = 1.0f;
+ this->incarnationWrathTransitionAmplitude = 0.4f;
+ Animation_MorphToLoop(&this->skelAnime, &gMajorasIncarnationPumpingUpAnim, -5.0f);
+ this->actor.shape.rot.y = 0;
+ this->actor.world.rot.y = this->actor.shape.rot.y;
+ Math_ApproachF(&this->actor.world.pos.x, 0.0f, 1.0f, 200.0f);
+ Math_ApproachF(&this->actor.world.pos.z, 0.0f, 1.0f, 200.0f);
+
+ player->actor.world.pos.x = this->actor.world.pos.x;
+ player->actor.world.pos.z = this->actor.world.pos.z + 300.0f;
+ player->actor.world.rot.y = player->actor.shape.rot.y = -0x8000;
+
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_PUMP_UP_OLD);
+ }
+ break;
+
+ case MAJORAS_INCARNATION_DEATH_CS_STATE_PUMP_UP_RIGHT_ARM:
+ sHeartbeatTimer = 5;
+ limbPumpState = MAJORAS_INCARNATION_LIMB_PUMP_STATE_ARMS;
+
+ if (this->cutsceneTimer == 40) {
+ this->cutsceneTimer = 0;
+ this->cutsceneState = MAJORAS_INCARNATION_DEATH_CS_STATE_PUMP_UP_LEFT_ARM;
+
+ this->subCamEyeNext.x = 30.0f;
+ this->subCamEyeNext.y = 120.0f;
+ this->subCamEyeNext.z = 110.0f;
+
+ this->subCamAtNext.x = 50.0f;
+ this->subCamAtNext.y = 150.0f;
+ this->subCamAtNext.z = -20.0f;
+
+ this->incarnationWrathTransitionScale = 1.0f;
+ this->incarnationWrathTransitionAmplitude = 0.4f;
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_PUMP_UP_OLD);
+ }
+ break;
+
+ case MAJORAS_INCARNATION_DEATH_CS_STATE_PUMP_UP_LEFT_ARM:
+ sHeartbeatTimer = 5;
+ limbPumpState = MAJORAS_INCARNATION_LIMB_PUMP_STATE_ARMS;
+
+ if (this->cutsceneTimer == 40) {
+ this->cutsceneTimer = 0;
+ this->cutsceneState = MAJORAS_INCARNATION_DEATH_CS_STATE_PUMP_UP_LEGS;
+
+ this->subCamEyeNext.x = 0.0f;
+ this->subCamEyeNext.y = 90.0f;
+ this->subCamEyeNext.z = 110.0f;
+
+ this->subCamAtNext.x = 0.0f;
+ this->subCamAtNext.y = 90.0f;
+ this->subCamAtNext.z = 0.0f;
+
+ this->incarnationWrathTransitionScale = 1.0f;
+ this->incarnationWrathTransitionAmplitude = 0.4f;
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_PUMP_UP_OLD);
+ }
+ break;
+
+ case MAJORAS_INCARNATION_DEATH_CS_STATE_PUMP_UP_LEGS:
+ sHeartbeatTimer = 5;
+ limbPumpState = MAJORAS_INCARNATION_LIMB_PUMP_STATE_LEGS;
+
+ if (this->cutsceneTimer == 10) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_PUMP_UP_OLD);
+ }
+
+ if (this->cutsceneTimer == 40) {
+ Actor_Spawn(&play->actorCtx, play, ACTOR_BOSS_07, this->actor.world.pos.x, this->actor.world.pos.y,
+ this->actor.world.pos.z, 0, 0, this->subCamId, MAJORA_PARAMS(MAJORA_TYPE_WRATH));
+ Actor_Kill(&this->actor);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, MTXMODE_NEW);
+ Matrix_RotateYS(this->actor.shape.rot.y, MTXMODE_APPLY);
+ Matrix_MultVec3f(&this->subCamEyeNext, &this->subCamEye);
+ Matrix_MultVec3f(&this->subCamAtNext, &this->subCamAt);
+
+ if (limbPumpState == MAJORAS_INCARNATION_LIMB_PUMP_STATE_ARMS) {
+ this->incarnationArmScale =
+ (Math_SinS(this->cutsceneTimer * 0x3000) * this->incarnationWrathTransitionAmplitude) +
+ this->incarnationWrathTransitionScale;
+ Math_ApproachF(&this->incarnationWrathTransitionScale, 2.0f, 1.0f, 0.05f);
+ Math_ApproachZeroF(&this->incarnationWrathTransitionAmplitude, 1.0f, 0.01f);
+ } else if (limbPumpState == MAJORAS_INCARNATION_LIMB_PUMP_STATE_LEGS) {
+ this->incarnationLegScale =
+ (Math_SinS(this->cutsceneTimer * 0x3000) * this->incarnationWrathTransitionAmplitude) +
+ this->incarnationWrathTransitionScale;
+ Math_ApproachF(&this->incarnationWrathTransitionScale, 2.0f, 1.0f, 0.05f);
+ Math_ApproachZeroF(&this->incarnationWrathTransitionAmplitude, 1.0f, 0.01f);
+ }
+
+ this->incarnationMaskScaleY = (Math_SinS(this->cutsceneTimer * 0x2000) * 0.1f) + 1.0f;
+ this->incarnationMaskScaleX = (Math_CosS(this->cutsceneTimer * 0x2000) * 0.1f) + 1.0f;
+
+ if (this->subCamId != SUB_CAM_ID_DONE) {
+ ShrinkWindow_Letterbox_SetSizeTarget(27);
+ Play_SetCameraAtEye(play, this->subCamId, &this->subCamAt, &this->subCamEye);
+ }
+}
+
+void Boss07_Incarnation_UpdateDamage(Boss07* this, PlayState* play) {
+ s32 i;
+ s32 j;
+ u8 damage;
+
+ if (this->damagedTimer != 0) {
+ return;
+ }
+
+ for (i = 0; i < ARRAY_COUNT(this->bodyColliderElements); i++) {
+ if (!(this->bodyCollider.elements[i].base.acElemFlags & ACELEM_HIT)) {
+ continue;
+ }
+
+ for (j = 0; j < ARRAY_COUNT(this->bodyColliderElements); j++) {
+ this->bodyCollider.elements[j].base.acElemFlags &= ~ACELEM_HIT;
+ }
+
+ if (this->drawDmgEffType == ACTOR_DRAW_DMGEFF_FROZEN_NO_SFX) {
+ this->drawDmgEffTimer = 0;
+ }
+
+ switch (this->actor.colChkInfo.damageEffect) {
+ case MAJORAS_INCARNATION_DMGEFF_FREEZE:
+ this->drawDmgEffState = MAJORA_DRAW_DMGEFF_STATE_FROZEN_INIT;
+ break;
+
+ case MAJORAS_INCARNATION_DMGEFF_FIRE:
+ this->drawDmgEffState = MAJORA_DRAW_DMGEFF_STATE_FIRE_INIT;
+ break;
+
+ case MAJORAS_INCARNATION_DMGEFF_LIGHT_ORB:
+ this->drawDmgEffState = MAJORA_DRAW_DMGEFF_STATE_LIGHT_ORB_INIT;
+ Actor_Spawn(&play->actorCtx, play, ACTOR_EN_CLEAR_TAG, this->actor.focus.pos.x, this->actor.focus.pos.y,
+ this->actor.focus.pos.z, 0, 0, 0, CLEAR_TAG_PARAMS(CLEAR_TAG_LARGE_LIGHT_RAYS));
+ break;
+
+ case MAJORAS_INCARNATION_DMGEFF_ELECTRIC_SPARKS:
+ this->drawDmgEffState = MAJORA_DRAW_DMGEFF_STATE_ELECTRIC_SPARKS_INIT;
+ Actor_PlaySfx(&this->actor, NA_SE_EN_COMMON_FREEZE);
+ break;
+
+ case MAJORAS_INCARNATION_DMGEFF_BLUE_LIGHT_ORB:
+ this->drawDmgEffState = MAJORA_DRAW_DMGEFF_STATE_BLUE_LIGHT_ORB_INIT;
+ Actor_Spawn(&play->actorCtx, play, ACTOR_EN_CLEAR_TAG, this->actor.focus.pos.x, this->actor.focus.pos.y,
+ this->actor.focus.pos.z, 0, 0, 3, CLEAR_TAG_PARAMS(CLEAR_TAG_LARGE_LIGHT_RAYS));
+ break;
+
+ default:
+ break;
+ }
+
+ if ((this->actionFunc == Boss07_Incarnation_Stunned) || (this->actionFunc == Boss07_Incarnation_Damaged)) {
+ this->damagedTimer = (this->actor.colChkInfo.damageEffect == MAJORAS_INCARNATION_DMGEFF_EXPLOSIVE) ? 15 : 5;
+ damage = this->actor.colChkInfo.damage;
+ Boss07_Incarnation_SetupDamaged(this, play, damage, this->actor.colChkInfo.damageEffect);
+ this->damagedFlashTimer = 15;
+ } else {
+ this->damagedTimer = 15;
+ Boss07_Incarnation_SetupStunned(this, play, 150);
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_DAMAGE_OLD);
+ }
+ break;
+ }
+}
+
+void Boss07_IncarnationAfterimage_Update(Actor* thisx, PlayState* play2) {
+ PlayState* play = play2;
+ Boss07* this = THIS;
+
+ if (DECR(this->timers[0]) == 0) {
+ Actor_Kill(&this->actor);
+ }
+}
+
+void Boss07_Incarnation_Update(Actor* thisx, PlayState* play2) {
+ PlayState* play = play2;
+ Boss07* this = THIS;
+ s32 i;
+ s32 pad;
+
+ this->actor.hintId = TATL_HINT_ID_MAJORAS_INCARNATION;
+ this->frameCounter++;
+ Math_Vec3f_Copy(&sMajoraSfxPos, &this->actor.projectedPos);
+
+ if (this->lightSettingsMode == 1) {
+ static u8 sPrevLightSettings[] = { 1, 0, 3, 0, 4, 0, 5, 0 };
+ static u8 sLightSettings[] = { 0, 3, 0, 4, 0, 5, 0, 1 };
+
+ Math_ApproachF(&play->envCtx.lightBlend, 1.0f, 1.0f, 0.1f);
+
+ if (play->envCtx.lightBlend == 1.0f) {
+ play->envCtx.lightBlend = 0.0f;
+ this->lightSettingsIndex++;
+
+ if (this->lightSettingsIndex >= ARRAY_COUNT(sLightSettings)) {
+ this->lightSettingsIndex = 0;
+ }
+ }
+
+ play->envCtx.prevLightSetting = sPrevLightSettings[this->lightSettingsIndex];
+ play->envCtx.lightSetting = sLightSettings[this->lightSettingsIndex];
+ }
+
+ Math_ApproachF(&play->envCtx.lightBlend, 0.0f, 1.0f, 0.03f);
+
+ if (KREG(63) == 0) {
+ this->canEvade = false;
+ this->actor.shape.shadowAlpha = 130;
+
+ for (i = 0; i < ARRAY_COUNT(this->timers); i++) {
+ DECR(this->timers[i]);
+ }
+
+ DECR(this->damagedTimer);
+ DECR(this->damagedFlashTimer);
+ DECR(this->disableCollisionTimer);
+ DECR(this->fireTimer);
+
+ Math_ApproachZeroF(&this->shockSparkScale, 1.0f, 0.04f);
+
+ this->actionFunc(this, play);
+
+ Actor_MoveWithGravity(&this->actor);
+ Actor_UpdateBgCheckInfo(play, &this->actor, 50.0f, 200.0f, 100.0f,
+ UPDBGCHECKINFO_FLAG_1 | UPDBGCHECKINFO_FLAG_4);
+
+ if (this->shouldStartDeath || KREG(88)) {
+ KREG(88) = false;
+ this->shouldStartDeath = false;
+ SEQCMD_STOP_SEQUENCE(SEQ_PLAYER_BGM_MAIN, 1);
+ Boss07_Incarnation_SetupDeathCutscene(this, play);
+ }
+ }
+
+ if (this->disableCollisionTimer != 0) {
+ for (i = 0; i < ARRAY_COUNT(this->bodyColliderElements); i++) {
+ this->bodyCollider.elements[i].base.acElemFlags &= ~ACELEM_HIT;
+ }
+ }
+
+ Boss07_Incarnation_UpdateDamage(this, play);
+ CollisionCheck_SetOC(play, &play->colChkCtx, &this->bodyCollider.base);
+ CollisionCheck_SetAC(play, &play->colChkCtx, &this->bodyCollider.base);
+
+ if (this->actionFunc != Boss07_Incarnation_Pirouette) {
+ Math_ApproachS(&this->actor.shape.rot.y, this->actor.world.rot.y, 1, 0x1000);
+ }
+
+ // This code uses `fireTimer` to determine whether or not to spawn afterimages. While Incarnation is running,
+ // `Boss07_Incarnation_Run` will constantly set `fireTimer` to 5, so this will spawn afterimages every other frame.
+ // Once it stops running, this will continue to spawn afterimages every other frame until `fireTimer` reaches 0.
+ if ((this->fireTimer != 0) && !(this->frameCounter & 1)) {
+ Boss07* afterimage =
+ (Boss07*)Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_BOSS_07, this->actor.world.pos.x,
+ this->actor.world.pos.y, this->actor.world.pos.z, this->actor.world.rot.x,
+ this->actor.world.rot.y, 7, MAJORA_PARAMS(MAJORA_TYPE_INCARNATION_AFTERIMAGE));
+
+ if (afterimage != NULL) {
+ for (i = 0; i < MAJORAS_INCARNATION_LIMB_MAX; i++) {
+ afterimage->skelAnime.jointTable[i] = this->skelAnime.jointTable[i];
+ }
+ }
+ }
+
+ Boss07_UpdateDamageEffects(this, play);
+}
+
+void Boss07_IncarnationAfterimage_Draw(Actor* thisx, PlayState* play2) {
+ PlayState* play = play2;
+ Boss07* this = THIS;
+ Boss07* parent = (Boss07*)this->actor.parent;
+
+ OPEN_DISPS(play->state.gfxCtx);
+
+ Gfx_SetupDL25_Opa(play->state.gfxCtx);
+ POLY_OPA_DISP = Gfx_SetFog(POLY_OPA_DISP, 0, 0, 100, 155, 900, 1099);
+ SkelAnime_DrawFlexOpa(play, parent->skelAnime.skeleton, this->skelAnime.jointTable, parent->skelAnime.dListCount,
+ NULL, NULL, &this->actor);
+ POLY_OPA_DISP = Play_SetFog(play, POLY_OPA_DISP);
+
+ CLOSE_DISPS(play->state.gfxCtx);
+}
+
+s32 Boss07_Incarnation_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot,
+ Actor* thisx) {
+ Boss07* this = THIS;
+
+ if (limbIndex == MAJORAS_INCARNATION_LIMB_EYESTALK) {
+ rot->y += this->cutsceneHeadRot.x;
+ }
+
+ return false;
+}
+
+static s8 sIncarnationLimbToColliderBodyParts[] = {
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_NONE
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_ROOT
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_WRAPPER
+ MAJORAS_INCARNATION_COLLIDER_BODYPART_MASK, // MAJORAS_INCARNATION_LIMB_MASK
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_RIGHT_LEG_ROOT
+ MAJORAS_INCARNATION_COLLIDER_BODYPART_RIGHT_THIGH, // MAJORAS_INCARNATION_LIMB_RIGHT_THIGH
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_RIGHT_LOWER_LEG_ROOT
+ MAJORAS_INCARNATION_COLLIDER_BODYPART_RIGHT_SHIN, // MAJORAS_INCARNATION_LIMB_RIGHT_SHIN
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_RIGHT_FOOT
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_RIGHT_ARM_ROOT
+ MAJORAS_INCARNATION_COLLIDER_BODYPART_RIGHT_UPPER_ARM, // MAJORAS_INCARNATION_LIMB_RIGHT_UPPER_ARM
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_RIGHT_LOWER_ARM_ROOT
+ MAJORAS_INCARNATION_COLLIDER_BODYPART_RIGHT_FOREARM, // MAJORAS_INCARNATION_LIMB_RIGHT_FOREARM
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_RIGHT_HAND
+ MAJORAS_INCARNATION_COLLIDER_BODYPART_MASK, // MAJORAS_INCARNATION_LIMB_LEFT_ARM_ROOT
+ MAJORAS_INCARNATION_COLLIDER_BODYPART_LEFT_UPPER_ARM, // MAJORAS_INCARNATION_LIMB_LEFT_UPPER_ARM
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_LEFT_LOWER_ARM_ROOT
+ MAJORAS_INCARNATION_COLLIDER_BODYPART_LEFT_FOREARM, // MAJORAS_INCARNATION_LIMB_LEFT_FOREARM
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_LEFT_HAND
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_LEFT_LEG_ROOT
+ MAJORAS_INCARNATION_COLLIDER_BODYPART_LEFT_THIGH, // MAJORAS_INCARNATION_LIMB_LEFT_THIGH
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_LEFT_LOWER_LEG_ROOT
+ MAJORAS_INCARNATION_COLLIDER_BODYPART_LEFT_SHIN, // MAJORAS_INCARNATION_LIMB_LEFT_SHIN
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_LEFT_FOOT
+ MAJORAS_INCARNATION_COLLIDER_BODYPART_EYESTALK, // MAJORAS_INCARNATION_LIMB_EYESTALK
+ BODYPART_NONE, // Doesn't correspond to a real limb on Majora's Incarnation
+ BODYPART_NONE, // Doesn't correspond to a real limb on Majora's Incarnation
+ BODYPART_NONE, // Doesn't correspond to a real limb on Majora's Incarnation
+ BODYPART_NONE, // Doesn't correspond to a real limb on Majora's Incarnation
+ BODYPART_NONE, // Doesn't correspond to a real limb on Majora's Incarnation
+};
+
+static s8 sIncarnationLimbToPumpBodyParts[] = {
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_NONE
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_ROOT
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_WRAPPER
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_MASK
+ MAJORAS_INCARNATION_GROW_BODYPART_RIGHT_LEG, // MAJORAS_INCARNATION_LIMB_RIGHT_LEG_ROOT
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_RIGHT_THIGH
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_RIGHT_LOWER_LEG_ROOT
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_RIGHT_SHIN
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_RIGHT_FOOT
+ MAJORAS_INCARNATION_GROW_BODYPART_RIGHT_ARM, // MAJORAS_INCARNATION_LIMB_RIGHT_ARM_ROOT
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_RIGHT_UPPER_ARM
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_RIGHT_LOWER_ARM_ROOT
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_RIGHT_FOREARM
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_RIGHT_HAND
+ MAJORAS_INCARNATION_GROW_BODYPART_LEFT_ARM, // MAJORAS_INCARNATION_LIMB_LEFT_ARM_ROOT
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_LEFT_UPPER_ARM
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_LEFT_LOWER_ARM_ROOT
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_LEFT_FOREARM
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_LEFT_HAND
+ MAJORAS_INCARNATION_GROW_BODYPART_LEFT_LEG, // MAJORAS_INCARNATION_LIMB_LEFT_LEG_ROOT
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_LEFT_THIGH
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_LEFT_LOWER_LEG_ROOT
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_LEFT_SHIN
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_LEFT_FOOT
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_EYESTALK
+ BODYPART_NONE, // Doesn't correspond to a real limb on Majora's Incarnation
+ BODYPART_NONE, // Doesn't correspond to a real limb on Majora's Incarnation
+ BODYPART_NONE, // Doesn't correspond to a real limb on Majora's Incarnation
+ BODYPART_NONE, // Doesn't correspond to a real limb on Majora's Incarnation
+ BODYPART_NONE, // Doesn't correspond to a real limb on Majora's Incarnation
+};
+
+static Vec3f sIncarnationLimbColliderOffsets[MAJORAS_INCARNATION_COLLIDER_BODYPART_MAX] = {
+ { 2000.0f, 0.0f, 0.0f }, // MAJORAS_INCARNATION_COLLIDER_BODYPART_EYESTALK
+ { 3500.0f, -1000.0f, 0.0f }, // MAJORAS_INCARNATION_COLLIDER_BODYPART_MASK
+ { 100000.0f, 100000.0f, 100000.0f }, // MAJORAS_INCARNATION_COLLIDER_BODYPART_ROOM_ORIGIN
+ { 4000.0f, 0.0f, 0.0f }, // MAJORAS_INCARNATION_COLLIDER_BODYPART_LEFT_UPPER_ARM
+ { 4000.0f, 0.0f, 0.0f }, // MAJORAS_INCARNATION_COLLIDER_BODYPART_LEFT_FOREARM
+ { 4000.0f, 0.0f, 0.0f }, // MAJORAS_INCARNATION_COLLIDER_BODYPART_RIGHT_UPPER_ARM
+ { 4000.0f, 0.0f, 0.0f }, // MAJORAS_INCARNATION_COLLIDER_BODYPART_RIGHT_FOREARM
+ { 4000.0f, 0.0f, 0.0f }, // MAJORAS_INCARNATION_COLLIDER_BODYPART_LEFT_THIGH
+ { 4000.0f, 0.0f, 0.0f }, // MAJORAS_INCARNATION_COLLIDER_BODYPART_LEFT_SHIN
+ { 4000.0f, 0.0f, 0.0f }, // MAJORAS_INCARNATION_COLLIDER_BODYPART_RIGHT_THIGH
+ { 4000.0f, 0.0f, 0.0f }, // MAJORAS_INCARNATION_COLLIDER_BODYPART_RIGHT_SHIN
+};
+
+static s8 sIncarnationLimbToBodyParts[] = {
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_NONE
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_ROOT
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_WRAPPER
+ MAJORAS_INCARNATION_BODYPART_LEFT_ARM_ROOT, // MAJORAS_INCARNATION_LIMB_MASK
+ MAJORAS_INCARNATION_BODYPART_RIGHT_LEG_ROOT, // MAJORAS_INCARNATION_LIMB_RIGHT_LEG_ROOT
+ MAJORAS_INCARNATION_BODYPART_RIGHT_THIGH, // MAJORAS_INCARNATION_LIMB_RIGHT_THIGH
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_RIGHT_LOWER_LEG_ROOT
+ MAJORAS_INCARNATION_BODYPART_RIGHT_SHIN, // MAJORAS_INCARNATION_LIMB_RIGHT_SHIN
+ MAJORAS_INCARNATION_BODYPART_RIGHT_FOOT, // MAJORAS_INCARNATION_LIMB_RIGHT_FOOT
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_RIGHT_ARM_ROOT
+ MAJORAS_INCARNATION_BODYPART_RIGHT_UPPER_ARM, // MAJORAS_INCARNATION_LIMB_RIGHT_UPPER_ARM
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_RIGHT_LOWER_ARM_ROOT
+ MAJORAS_INCARNATION_BODYPART_RIGHT_FOREARM, // MAJORAS_INCARNATION_LIMB_RIGHT_FOREARM
+ MAJORAS_INCARNATION_BODYPART_RIGHT_HAND, // MAJORAS_INCARNATION_LIMB_RIGHT_HAND
+ MAJORAS_INCARNATION_BODYPART_LEFT_ARM_ROOT, // MAJORAS_INCARNATION_LIMB_LEFT_ARM_ROOT
+ MAJORAS_INCARNATION_BODYPART_LEFT_UPPER_ARM, // MAJORAS_INCARNATION_LIMB_LEFT_UPPER_ARM
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_LEFT_LOWER_ARM_ROOT
+ MAJORAS_INCARNATION_BODYPART_LEFT_FOREARM, // MAJORAS_INCARNATION_LIMB_LEFT_FOREARM
+ MAJORAS_INCARNATION_BODYPART_LEFT_HAND, // MAJORAS_INCARNATION_LIMB_LEFT_HAND
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_LEFT_LEG_ROOT
+ MAJORAS_INCARNATION_BODYPART_LEFT_THIGH, // MAJORAS_INCARNATION_LIMB_LEFT_THIGH
+ BODYPART_NONE, // MAJORAS_INCARNATION_LIMB_LEFT_LOWER_LEG_ROOT
+ MAJORAS_INCARNATION_BODYPART_LEFT_SHIN, // MAJORAS_INCARNATION_LIMB_LEFT_SHIN
+ MAJORAS_INCARNATION_BODYPART_LEFT_FOOT, // MAJORAS_INCARNATION_LIMB_LEFT_FOOT
+ MAJORAS_INCARNATION_BODYPART_EYESTALK, // MAJORAS_INCARNATION_LIMB_EYESTALK
+ BODYPART_NONE, // Doesn't correspond to a real limb on Majora's Incarnation
+ BODYPART_NONE, // Doesn't correspond to a real limb on Majora's Incarnation
+ BODYPART_NONE, // Doesn't correspond to a real limb on Majora's Incarnation
+ BODYPART_NONE, // Doesn't correspond to a real limb on Majora's Incarnation
+ BODYPART_NONE, // Doesn't correspond to a real limb on Majora's Incarnation
+};
+
+void Boss07_Incarnation_PostLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx) {
+ Boss07* this = THIS;
+ Vec3f colliderPos;
+ s8 bodyPartIndex;
+
+ if (limbIndex == MAJORAS_INCARNATION_LIMB_EYESTALK) {
+ Matrix_MultZero(&this->actor.focus.pos);
+ }
+
+ bodyPartIndex = sIncarnationLimbToBodyParts[limbIndex];
+ if (bodyPartIndex > BODYPART_NONE) {
+ Matrix_MultZero(&this->bodyPartsPos[bodyPartIndex]);
+ }
+
+ bodyPartIndex = sIncarnationLimbToColliderBodyParts[limbIndex];
+ if (bodyPartIndex > BODYPART_NONE) {
+ if (this->disableCollisionTimer != 0) {
+ Matrix_MultVecZ(100000.0f, &colliderPos);
+ } else {
+ Matrix_MultVec3f(&sIncarnationLimbColliderOffsets[bodyPartIndex], &colliderPos);
+ }
+
+ Boss07_SetColliderSphere(bodyPartIndex, &this->bodyCollider, &colliderPos);
+ }
+
+ if (limbIndex == MAJORAS_INCARNATION_LIMB_RIGHT_FOOT) {
+ Matrix_MultZero(&this->incarnationFeetPos[MAJORAS_INCARNATION_FOOT_RIGHT]);
+ }
+
+ if (limbIndex == MAJORAS_INCARNATION_LIMB_LEFT_FOOT) {
+ Matrix_MultZero(&this->incarnationFeetPos[MAJORAS_INCARNATION_FOOT_LEFT]);
+ }
+
+ if (limbIndex == MAJORAS_INCARNATION_LIMB_RIGHT_HAND) {
+ Matrix_MultZero(&this->incarnationRightHandPos);
+ }
+
+ if (limbIndex == MAJORAS_INCARNATION_LIMB_LEFT_HAND) {
+ Matrix_MultZero(&this->incarnationLeftHandPos);
+ }
+
+ bodyPartIndex = sIncarnationLimbToPumpBodyParts[limbIndex];
+ if (bodyPartIndex > BODYPART_NONE) {
+ Matrix_Scale(this->incarnationIntroBodyPartsScale[bodyPartIndex],
+ this->incarnationIntroBodyPartsScale[bodyPartIndex],
+ this->incarnationIntroBodyPartsScale[bodyPartIndex], MTXMODE_APPLY);
+ }
+}
+
+void Boss07_Incarnation_TransformLimbDraw(PlayState* play, s32 limbIndex, Actor* thisx) {
+ Boss07* this = THIS;
+
+ if (limbIndex == MAJORAS_INCARNATION_LIMB_MASK) {
+ Matrix_Scale(this->incarnationMaskScaleX, this->incarnationMaskScaleY, 1.0f, MTXMODE_APPLY);
+ }
+
+ if ((limbIndex == MAJORAS_INCARNATION_LIMB_RIGHT_UPPER_ARM) ||
+ (limbIndex == MAJORAS_INCARNATION_LIMB_RIGHT_FOREARM) || (limbIndex == MAJORAS_INCARNATION_LIMB_RIGHT_HAND) ||
+ (limbIndex == MAJORAS_INCARNATION_LIMB_LEFT_UPPER_ARM) ||
+ (limbIndex == MAJORAS_INCARNATION_LIMB_LEFT_FOREARM) || (limbIndex == MAJORAS_INCARNATION_LIMB_LEFT_HAND)) {
+ Matrix_Scale(1.0f, this->incarnationArmScale, this->incarnationArmScale, MTXMODE_APPLY);
+ }
+
+ if ((limbIndex == MAJORAS_INCARNATION_LIMB_RIGHT_THIGH) || (limbIndex == MAJORAS_INCARNATION_LIMB_RIGHT_SHIN) ||
+ (limbIndex == MAJORAS_INCARNATION_LIMB_RIGHT_FOOT) || (limbIndex == MAJORAS_INCARNATION_LIMB_LEFT_THIGH) ||
+ (limbIndex == MAJORAS_INCARNATION_LIMB_LEFT_SHIN) || (limbIndex == MAJORAS_INCARNATION_LIMB_LEFT_FOOT)) {
+ Matrix_Scale(1.0f, this->incarnationLegScale, this->incarnationLegScale, MTXMODE_APPLY);
+ }
+}
+
+void Boss07_Incarnation_Draw(Actor* thisx, PlayState* play2) {
+ PlayState* play = play2;
+ Boss07* this = THIS;
+
+ OPEN_DISPS(play->state.gfxCtx);
+
+ Gfx_SetupDL25_Opa(play->state.gfxCtx);
+ Gfx_SetupDL25_Xlu(play->state.gfxCtx);
+
+ if ((this->damagedFlashTimer % 2) != 0) {
+ POLY_OPA_DISP = Gfx_SetFog(POLY_OPA_DISP, 255, 0, 0, 255, 900, 1099);
+ }
+
+ SkelAnime_DrawTransformFlexOpa(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
+ this->skelAnime.dListCount, Boss07_Incarnation_OverrideLimbDraw,
+ Boss07_Incarnation_PostLimbDraw, Boss07_Incarnation_TransformLimbDraw, &this->actor);
+ POLY_OPA_DISP = Play_SetFog(play, POLY_OPA_DISP);
+ Actor_DrawDamageEffects(play, &this->actor, this->bodyPartsPos, MAJORAS_INCARNATION_BODYPART_MAX,
+ this->drawDmgEffScale, this->drawDmgEffFrozenSteamScale, this->drawDmgEffAlpha,
+ this->drawDmgEffType);
+
+ CLOSE_DISPS(play->state.gfxCtx);
+}
+
+void Boss07_Mask_SetupIdle(Boss07* this, PlayState* play) {
+ this->actionFunc = Boss07_Mask_Idle;
+ Animation_MorphToLoop(&this->skelAnime, &gMajorasMaskFloatingAnim, -20.0f);
+ this->timers[2] = Rand_ZeroFloat(150.0f) + 60.0f;
+ this->tentacleLengthScale = 1.0f;
+}
+
+void Boss07_Mask_Idle(Boss07* this, PlayState* play) {
+ s16 targetRotX;
+ s16 targetRotY;
+ f32 dx;
+ f32 dy;
+ f32 dz;
+ f32 distToTargetXZ;
+ Player* player = GET_PLAYER(play);
+
+ SkelAnime_Update(&this->skelAnime);
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST1_FLOAT_OLD - SFX_FLAG);
+
+ if (this->timers[0] == 0) {
+ if (this->timers[2] == 0) {
+ if (((s8)this->actor.colChkInfo.health <= 8) && (player->transformation != PLAYER_FORM_FIERCE_DEITY) &&
+ (Rand_ZeroOne() < 0.75f)) {
+ Boss07_Mask_SetupFireBeam(this, play);
+ } else {
+ Boss07_Mask_SetupSpinAttack(this, play);
+ }
+ } else if (Rand_ZeroOne() < 0.15f) {
+ this->flySpeedTarget = 2.0f;
+ this->timers[0] = Rand_ZeroFloat(50.0f) + 30.0f;
+ } else {
+ Boss07_RandXZ(&this->targetPos, 500.0f);
+ this->targetPos.y = Rand_ZeroFloat(350.0f) + 100.0f;
+ this->timers[0] = Rand_ZeroFloat(50.0f) + 20.0f;
+ this->speedToTarget = 0.0f;
+ this->flySpeedTarget = Rand_ZeroFloat(12.0f) + 3.0f;
+ }
+ }
+
+ dx = this->targetPos.x - this->actor.world.pos.x;
+ dy = this->targetPos.y - this->actor.world.pos.y;
+ dz = this->targetPos.z - this->actor.world.pos.z;
+ targetRotY = Math_Atan2S(dx, dz);
+ distToTargetXZ = sqrtf(SQ(dx) + SQ(dz));
+ targetRotX = Math_Atan2S(dy, distToTargetXZ);
+ targetRotX += (s16)(Math_SinS(this->frameCounter * 0x1388) * 0xFA0);
+
+ Math_ApproachS(&this->actor.world.rot.y, targetRotY, 0xA, this->speedToTarget);
+ Math_ApproachS(&this->actor.world.rot.x, targetRotX, 5, this->speedToTarget);
+ Math_ApproachF(&this->speedToTarget, 0x7D0, 1.0f, 0x64);
+ Math_ApproachF(&this->actor.speed, this->flySpeedTarget, 1.0f, 1.0f);
+
+ if (this->timers[1] != 0) {
+ Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 3, 0x3000);
+ } else if (this->flySpeedTarget < 7.0f) {
+ Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 0xA, 0x2000);
+ } else {
+ Math_ApproachS(&this->actor.shape.rot.y, this->actor.world.rot.y, 5, 0x2000);
+ }
+
+ if ((player->unk_D57 == 4) && (Rand_ZeroOne() < 0.8f)) {
+ this->timers[1] = 20;
+ }
+
+ Math_ApproachS(&this->actor.shape.rot.x, 0, 0xA, 0x200);
+ Math_ApproachS(&this->actor.shape.rot.z, 0, 0xA, 0x400);
+
+ if (this->shouldStartDeath || KREG(88)) {
+ KREG(88) = false;
+ this->shouldStartDeath = false;
+ SEQCMD_STOP_SEQUENCE(SEQ_PLAYER_BGM_MAIN, 1);
+ Boss07_Mask_SetupDeathCutscene(this, play);
+ }
+}
+
+void Boss07_Mask_SetupSpinAttack(Boss07* this, PlayState* play) {
+ this->actionFunc = Boss07_Mask_SpinAttack;
+ this->subAction = MAJORAS_MASK_SPIN_ATTACK_SUB_ACTION_WIND_UP;
+ this->cutsceneState = MAJORAS_MASK_SPIN_ATTACK_RETARGET_PASSIVE;
+ this->timers[0] = 30;
+ this->angularVelocity = 0;
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST1_ATTACK_OLD);
+}
+
+void Boss07_Mask_SpinAttack(Boss07* this, PlayState* play) {
+ s16 targetRotX;
+ s16 targetRotY;
+ f32 dx;
+ f32 dy;
+ f32 dz;
+ f32 distToTargetXZ;
+ Player* player = GET_PLAYER(play);
+
+ this->actor.shape.rot.z -= this->angularVelocity;
+
+ switch (this->subAction) {
+ case MAJORAS_MASK_SPIN_ATTACK_SUB_ACTION_WIND_UP:
+ Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 0xA, 0x1000);
+ Boss07_SmoothStop(this, 1.0f);
+ Math_ApproachS(&this->actor.shape.rot.x, -0x4000, 0xA, 0x100);
+ Math_ApproachS(&this->angularVelocity, 0x2000, 1, 0x100);
+
+ if (this->timers[0] == 0) {
+ this->subAction = MAJORAS_MASK_SPIN_ATTACK_SUB_ACTION_ATTACK;
+ this->actor.world.rot.x = 0;
+ this->actor.world.rot.y = this->actor.yawTowardsPlayer;
+ this->timers[0] = 100;
+ this->timers[1] = 20;
+ this->speedToTarget = 0.0f;
+ }
+ break;
+
+ case MAJORAS_MASK_SPIN_ATTACK_SUB_ACTION_ATTACK:
+ Math_ApproachS(&this->actor.shape.rot.x, -0x4000, 0xA, 0x400);
+ Math_ApproachS(&this->angularVelocity, 0x2000, 1, 0x200);
+
+ if (this->timers[1] != 0) {
+ this->targetPos.x = player->actor.world.pos.x;
+ this->targetPos.y = player->actor.world.pos.y + 10.0f;
+ this->targetPos.z = player->actor.world.pos.z;
+ } else {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST1_ROLLING_OLD - SFX_FLAG);
+ }
+
+ dx = this->targetPos.x - this->actor.world.pos.x;
+ dy = this->targetPos.y - this->actor.world.pos.y;
+ dz = this->targetPos.z - this->actor.world.pos.z;
+ targetRotY = Math_Atan2S(dx, dz);
+ distToTargetXZ = sqrtf(SQ(dx) + SQ(dz));
+ targetRotX = Math_Atan2S(dy, distToTargetXZ);
+ Math_ApproachS(&this->actor.world.rot.y, targetRotY, 0xA, this->speedToTarget);
+ Math_ApproachS(&this->actor.world.rot.x, targetRotX, 0xA, this->speedToTarget);
+ Math_ApproachF(&this->speedToTarget, 0xBB8, 1.0f, 0x64);
+ Math_ApproachF(&this->actor.speed, 20.0f, 1.0f, 2.0f);
+
+ // This uses `cutsceneState` to determine if Majora's Mask should try to passively avoid the player with its
+ // spin or if it should actively try to attack them. Note that the Mask will always attempt to attack the
+ // player immediately after the spin attack starts; this code will only run after it has approached the
+ // player at least once.
+ if (((this->cutsceneState == MAJORAS_MASK_SPIN_ATTACK_RETARGET_PASSIVE) && (distToTargetXZ < 100.0f)) ||
+ (this->timers[0] == 0)) {
+ if (Rand_ZeroOne() < 0.25f) {
+ this->subAction = MAJORAS_MASK_SPIN_ATTACK_SUB_ACTION_END;
+ this->timers[0] = 30;
+ } else {
+ Boss07_RandXZ(&this->targetPos, 500.0f);
+ this->targetPos.y = Rand_ZeroFloat(100.0f) + 100.0f;
+
+ if (Rand_ZeroOne() < 0.3f) {
+ this->timers[1] = 20;
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST1_ATTACK_2ND_OLD);
+ this->cutsceneState = MAJORAS_MASK_SPIN_ATTACK_RETARGET_ACTIVE;
+ } else {
+ this->timers[1] = 0;
+ this->cutsceneState = MAJORAS_MASK_SPIN_ATTACK_RETARGET_PASSIVE;
+ }
+
+ this->timers[0] = 50;
+ this->speedToTarget = 0.0f;
+ }
+ }
+ break;
+
+ case MAJORAS_MASK_SPIN_ATTACK_SUB_ACTION_END:
+ Math_ApproachS(&this->angularVelocity, 0, 1, 0x100);
+ Math_ApproachS(&this->actor.world.rot.x, 0x2000, 0xA, 0x7D0);
+ Boss07_SmoothStop(this, 0.5f);
+ if (this->timers[0] == 0) {
+ Boss07_Mask_SetupIdle(this, play);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Boss07_Mask_SetupStunned(Boss07* this, PlayState* play) {
+ this->actionFunc = Boss07_Mask_Stunned;
+ Animation_MorphToLoop(&this->skelAnime, &gMajorasMaskJerkingAnim, -10.0f);
+ this->timers[0] = 100;
+ this->speedToTarget = 0.0f;
+}
+
+void Boss07_Mask_Stunned(Boss07* this, PlayState* play) {
+ SkelAnime_Update(&this->skelAnime);
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_COMMON_WEAKENED - SFX_FLAG);
+ Boss07_SmoothStop(this, 0.5f);
+ Math_ApproachS(&this->actor.shape.rot.x, -0x1000 + 0x4B0 * Math_SinS(this->frameCounter * 0xBB8), 5, 0x800);
+ Math_ApproachS(&this->actor.shape.rot.z, -0x1000 + 0x3E8 * Math_SinS(this->frameCounter * 0x9C4), 5, 0x800);
+
+ if (this->actor.world.pos.y > 51.0f) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST1_FALL_OLD - SFX_FLAG);
+ }
+
+ Math_ApproachF(&this->actor.world.pos.y, 50.0f + 10.0f * Math_SinS(this->frameCounter * 0x5DC), 0.1f,
+ this->speedToTarget);
+ Math_ApproachF(&this->speedToTarget, 15.0f, 1.0f, 1.0f);
+
+ if ((this->timers[0] > 30) || ((this->timers[0] & 2) != 0)) {
+ this->maskEyeTexIndex = MAJORAS_MASK_EYE_DULL;
+ }
+
+ if (this->timers[0] == 0) {
+ Boss07_Mask_SetupIdle(this, play);
+ this->timers[2] = 100;
+ }
+}
+
+void Boss07_Mask_SetupDamaged(Boss07* this, PlayState* play, u8 damage, Actor* hitActor) {
+ Player* player = GET_PLAYER(play);
+
+ this->actionFunc = Boss07_Mask_Damaged;
+ this->timers[0] = 40;
+
+ if ((u32)damage != 0) {
+ this->actor.speed = 30.0f;
+ this->actor.world.rot.y = this->actor.yawTowardsPlayer + 0x8000;
+ this->angularVelocity = 0x1500;
+ } else {
+ if (player->stateFlags3 & PLAYER_STATE3_200) {
+ this->actor.speed = 20.0f;
+ this->actor.velocity.y = 20.0f;
+ } else {
+ this->actor.speed = 13.0f;
+ this->actor.velocity.y = 10.0f;
+
+ if (hitActor != NULL) {
+ this->actor.world.rot.y = hitActor->world.rot.y;
+ }
+ }
+
+ this->angularVelocity = 0x1000;
+ }
+
+ this->actor.colChkInfo.health -= damage;
+
+ if ((s8)this->actor.colChkInfo.health <= 0) {
+ this->timers[0] = 30;
+ }
+
+ this->timers[1] = 30;
+}
+
+void Boss07_Mask_Damaged(Boss07* this, PlayState* play) {
+ this->damagedTimer = 20;
+ SkelAnime_Update(&this->skelAnime);
+
+ if (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND) {
+ Boss07_SmoothStop(this, 1.0f);
+ Math_ApproachS(&this->actor.shape.rot.x, -0x4000, 1, 0x1000);
+ Math_ApproachS(&this->angularVelocity, 0, 1, 0x100);
+ } else {
+ this->actor.shape.rot.x += 0x2000;
+ }
+
+ this->actor.shape.rot.z += this->angularVelocity;
+
+ if ((this->timers[0] > 30) || ((this->timers[0] & 2) != 0)) {
+ this->maskEyeTexIndex = MAJORAS_MASK_EYE_DULL;
+ }
+
+ if ((this->timers[0] == 15) && ((s8)this->actor.colChkInfo.health < 10)) {
+ this->startRemainsCs = true;
+ }
+
+ if (this->timers[0] == 0) {
+ Boss07_Mask_SetupIdle(this, play);
+
+ if ((s8)this->actor.colChkInfo.health <= 0) {
+ this->shouldStartDeath = true;
+ Enemy_StartFinishingBlow(play, &this->actor);
+ AudioSfx_StopByPos(&this->actor.projectedPos);
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST1_DEAD_OLD);
+ } else {
+ this->targetPos.x = this->actor.world.pos.x;
+ this->targetPos.y = 200.0f;
+ this->targetPos.z = this->actor.world.pos.z;
+ this->actor.world.rot.x = 0x3000;
+ this->timers[0] = 50;
+ this->timers[2] = 100;
+ this->flySpeedTarget = 6.0f;
+ this->speedToTarget = 0.0f;
+ }
+ }
+}
+
+void Boss07_Mask_StopBeam(Boss07* this) {
+ this->eyeBeamsLengthScale = 0.0f;
+ this->eyeBeamsFocusOrbScale = 0.0f;
+ this->beamLengthScale = 0.0f;
+ this->beamBaseScale = 0.0f;
+ this->reflectedBeamLengthScale = 0.0f;
+}
+
+void Boss07_Mask_SetupFireBeam(Boss07* this, PlayState* play) {
+ this->actionFunc = Boss07_Mask_FireBeam;
+ this->subAction = MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_CHARGE_UP;
+ this->timers[0] = 30;
+ this->speedToTarget = 0.0f;
+}
+
+void Boss07_Mask_FireBeam(Boss07* this, PlayState* play) {
+ f32 dx;
+ f32 dz;
+ f32 dy;
+ f32 distXYZ;
+ f32 yOffset;
+ s16 rotScale;
+ s16 i;
+ Vec3f diff;
+ Vec3f transformedDiff;
+ Player* player = GET_PLAYER(play);
+ CollisionPoly* poly;
+ Vec3f beamTireMarkPos;
+ u8 beamIsTouchingPoly = false;
+ s32 bgId;
+
+ this->damagedTimer = 20;
+ Boss07_SmoothStop(this, 0.5f);
+ Math_ApproachF(&this->actor.world.pos.y, 300.0f, 0.05f, 1.0f);
+ Math_ApproachS(&this->actor.shape.rot.z, 0, 0xA, 0x400);
+
+ if ((player->focusActor != NULL) && (player->stateFlags1 & PLAYER_STATE1_400000)) {
+ yOffset = (player->transformation == PLAYER_FORM_HUMAN) ? 20 : 30.0f;
+ } else {
+ yOffset = (player->transformation == PLAYER_FORM_HUMAN) ? 8.0f : 15.0f;
+ }
+
+ rotScale = (player->stateFlags1 & PLAYER_STATE1_400000) ? 1 : 10;
+ Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, rotScale, this->speedToTarget);
+ dx = player->actor.world.pos.x - this->actor.world.pos.x;
+ dy = player->actor.world.pos.y - this->actor.world.pos.y + yOffset;
+ dz = player->actor.world.pos.z - this->actor.world.pos.z;
+ Math_ApproachS(&this->actor.shape.rot.x, -Math_Atan2S(dy, sqrtf(SQ(dx) + SQ(dz))), rotScale, this->speedToTarget);
+ Math_ApproachF(&this->speedToTarget, 0xFA0, 1.0f, 0xC8);
+ this->tentacleState = MAJORAS_MASK_TENTACLE_STATE_FIRING_BEAM;
+
+ switch (this->subAction) {
+ case MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_CHARGE_UP:
+ if (this->timers[0] == 25) {
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EN_LAST1_BLOW_OLD);
+ }
+
+ if (this->timers[0] == 0) {
+ this->subAction = MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_FIRE_EYE_BEAMS;
+ this->timers[0] = 6;
+ this->beamBaseScale = 1.0f;
+ }
+ break;
+
+ case MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_FIRE_EYE_BEAMS:
+ Math_ApproachF(&this->eyeBeamsLengthScale, 1.0f, 1.0f, 0.2f);
+
+ if (this->timers[0] == 0) {
+ this->subAction = MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_GROW_FOCUS_LIGHT_ORB;
+ this->timers[0] = 8;
+ }
+ break;
+
+ case MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_GROW_FOCUS_LIGHT_ORB:
+ Audio_PlaySfx(NA_SE_EN_LAST1_BEAM_OLD - SFX_FLAG);
+ Math_ApproachF(&this->eyeBeamsFocusOrbScale, 1.0f, 0.2f, 0.2f);
+
+ if (this->timers[0] == 0) {
+ this->subAction = MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_BEAM_ACTIVE;
+ this->timers[0] = 100;
+ }
+ break;
+
+ case MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_BEAM_ACTIVE:
+ case MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_BEAM_REFLECTED:
+ Audio_PlaySfx(NA_SE_EN_LAST1_BEAM_OLD - SFX_FLAG);
+ FALLTHROUGH;
+ case MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_END:
+ Math_ApproachF(&this->eyeBeamsFocusOrbScale, 1.0f, 0.2f, 0.2f);
+ dx = player->actor.world.pos.x - this->beamStartPos.x;
+ dy = player->actor.world.pos.y - this->beamStartPos.y + 20.0f;
+ dz = player->actor.world.pos.z - this->beamStartPos.z;
+ distXYZ = sqrtf(SQ(dx) + SQ(dy) + SQ(dz));
+ Math_ApproachF(&this->beamLengthScale, distXYZ * 0.2f, 1.0f, 7.0f);
+
+ if (BgCheck_EntityLineTest1(&play->colCtx, &this->beamStartPos, &this->beamEndPos, &beamTireMarkPos, &poly,
+ true, true, true, true, &bgId) &&
+ (this->subAction != MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_END)) {
+ Vec3f flamePos;
+ Vec3f flameVelocity;
+ Vec3f flameAccel;
+
+ flamePos.x = Rand_CenteredFloat(20.0f) + beamTireMarkPos.x;
+ flamePos.y = Rand_CenteredFloat(20.0f) + beamTireMarkPos.y;
+ flamePos.z = Rand_CenteredFloat(20.0f) + beamTireMarkPos.z;
+
+ flameVelocity.x = 0.0f;
+ flameVelocity.y = 6.0f;
+ flameVelocity.z = 0.0f;
+
+ flameAccel.x = flameVelocity.x * -0.05f;
+ flameAccel.y = flameVelocity.y * -0.05f;
+ flameAccel.z = flameVelocity.z * -0.05f;
+
+ Boss07_SpawnFlameEffect(play, &flamePos, &flameVelocity, &flameAccel, Rand_ZeroFloat(10.0f) + 25.0f);
+ beamIsTouchingPoly = true;
+ }
+
+ diff.x = player->actor.world.pos.x - this->beamStartPos.x;
+ diff.y = player->actor.world.pos.y - this->beamStartPos.y + 10.0f;
+ diff.z = player->actor.world.pos.z - this->beamStartPos.z;
+ Matrix_RotateXS(-this->actor.shape.rot.x, MTXMODE_NEW);
+ Matrix_RotateYS(-this->actor.shape.rot.y, MTXMODE_APPLY);
+ Matrix_MultVec3f(&diff, &transformedDiff);
+
+ if ((fabsf(transformedDiff.x) < 20.0f) && (fabsf(transformedDiff.y) < 50.0f) &&
+ (transformedDiff.z > 40.0f) && (transformedDiff.z <= (this->beamLengthScale * 20))) {
+ if (Player_HasMirrorShieldEquipped(play) && (player->transformation == PLAYER_FORM_HUMAN) &&
+ (player->stateFlags1 & PLAYER_STATE1_400000) &&
+ (BINANG_ROT180(player->actor.shape.rot.y - this->actor.shape.rot.y) < 0x2000) &&
+ (BINANG_ROT180(player->actor.shape.rot.y - this->actor.shape.rot.y) > -0x2000)) {
+ Vec3s reflectedBeamRot;
+
+ this->beamLengthScale = distXYZ * 0.05f;
+ Math_ApproachF(&this->reflectedBeamLengthScale, distXYZ * 0.2f, 1.0f, 7.0f);
+ Matrix_MtxFToYXZRot(&player->shieldMf, &reflectedBeamRot, 0);
+ reflectedBeamRot.y += 0x8000;
+ reflectedBeamRot.x = -reflectedBeamRot.x;
+
+ if (this->subAction == MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_BEAM_ACTIVE) {
+ this->subAction = MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_BEAM_REFLECTED;
+ this->reflectedBeamPitch = reflectedBeamRot.x;
+ this->reflectedBeamYaw = reflectedBeamRot.y;
+ } else {
+ player->pushedYaw = this->actor.yawTowardsPlayer;
+ player->pushedSpeed = this->beamBaseScale * 0.5f;
+
+ sMajoraBattleHandler->lensFlareOn = true;
+ sMajoraBattleHandler->lensFlareScale = this->beamBaseScale * 30.0f;
+ sMajoraBattleHandler->lensFlarePos = this->beamEndPos;
+
+ Math_ApproachS(&this->reflectedBeamPitch, reflectedBeamRot.x, 2, 0x2000);
+ Math_ApproachS(&this->reflectedBeamYaw, reflectedBeamRot.y, 2, 0x2000);
+
+ diff.x = this->actor.world.pos.x - this->beamEndPos.x;
+ diff.y = this->actor.world.pos.y - this->beamEndPos.y;
+ diff.z = this->actor.world.pos.z - this->beamEndPos.z;
+ distXYZ = sqrtf(SQXYZ(diff));
+
+ Matrix_RotateXS(-this->reflectedBeamPitch, MTXMODE_NEW);
+ Matrix_RotateYS(-this->reflectedBeamYaw, MTXMODE_APPLY);
+ Matrix_Push();
+ Matrix_MultVec3f(&diff, &transformedDiff);
+
+ if ((fabsf(transformedDiff.x) < 60.0f) && (fabsf(transformedDiff.y) < 60.0f) &&
+ (transformedDiff.z > 40.0f) &&
+ (transformedDiff.z <= (this->reflectedBeamLengthScale * 16.666668f)) &&
+ (this->subAction != MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_END)) {
+ s32 j;
+ Vec3f flamePos;
+ Vec3f flameVelocity;
+ Vec3f flameAccel;
+
+ this->beamDamageTimer += 2;
+ this->reflectedBeamLengthScale = distXYZ * 0.062f;
+
+ if (this->beamDamageTimer < 10) {
+ flamePos.x = this->actor.world.pos.x + Rand_CenteredFloat(40.0f);
+ flamePos.y = this->actor.world.pos.y + Rand_CenteredFloat(40.0f);
+ flamePos.z = this->actor.world.pos.z + Rand_CenteredFloat(40.0f);
+
+ flameVelocity.x = 0.0f;
+ flameVelocity.y = 6.0f;
+ flameVelocity.z = 0.0f;
+
+ flameAccel.x = flameVelocity.x * -0.05f;
+ flameAccel.y = flameVelocity.y * -0.05f;
+ flameAccel.z = flameVelocity.z * -0.05f;
+
+ Boss07_SpawnFlameEffect(play, &flamePos, &flameVelocity, &flameAccel,
+ Rand_ZeroFloat(10.0f) + 25.0f);
+ this->damagedFlashTimer |= 10;
+ } else {
+ this->damagedTimer = 50;
+ this->damagedFlashTimer = 15;
+ AudioSfx_StopByPos(&this->actor.projectedPos);
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST1_DAMAGE2_OLD);
+ Boss07_Mask_SetupDamaged(this, play, 2, NULL);
+ Boss07_Mask_StopBeam(this);
+
+ for (j = 0; j < 20; j++) {
+ flamePos.x = this->actor.world.pos.x + Rand_CenteredFloat(50.0f);
+ flamePos.y = this->actor.world.pos.y + Rand_CenteredFloat(50.0f);
+ flamePos.z = this->actor.world.pos.z + Rand_CenteredFloat(50.0f);
+
+ flameVelocity.x = Rand_CenteredFloat(20.0f);
+ flameVelocity.y = Rand_CenteredFloat(20.0f);
+ flameVelocity.z = Rand_CenteredFloat(20.0f);
+
+ flameAccel.x = flameVelocity.x * -0.05f;
+ flameAccel.y = flameVelocity.y * -0.05f;
+ flameAccel.z = flameVelocity.z * -0.05f;
+
+ Boss07_SpawnFlameEffect(play, &flamePos, &flameVelocity, &flameAccel,
+ Rand_ZeroFloat(10.0f) + 25.0f);
+ }
+
+ if ((s8)this->actor.colChkInfo.health <= 0) {
+ this->fireTimer = 200;
+ } else {
+ this->fireTimer = 60;
+ }
+ }
+ }
+
+ Matrix_Pop();
+
+ for (i = 0; i < MAJORA_REMAINS_TYPE_MAX; i++) {
+ if (sMajoraRemains[i]->subAction >= REMAINS_MOVE_SUB_ACTION_DIE) {
+ continue;
+ }
+
+ diff.x = sMajoraRemains[i]->actor.world.pos.x - this->beamEndPos.x;
+ diff.y = sMajoraRemains[i]->actor.world.pos.y - this->beamEndPos.y;
+ diff.z = sMajoraRemains[i]->actor.world.pos.z - this->beamEndPos.z;
+ distXYZ = sqrtf(SQXYZ(diff));
+ Matrix_MultVec3f(&diff, &transformedDiff);
+
+ if ((fabsf(transformedDiff.x) < 60.0f) && (fabsf(transformedDiff.y) < 60.0f) &&
+ (transformedDiff.z > 40.0f) &&
+ (transformedDiff.z <= (this->reflectedBeamLengthScale * 16.666668f)) &&
+ (this->subAction != MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_END)) {
+ s32 j;
+ Vec3f flamePos;
+ Vec3f flameVelocity;
+ Vec3f flameAccel;
+
+ this->beamDamageTimer += 2;
+ this->reflectedBeamLengthScale = distXYZ * 0.062f;
+
+ if (this->beamDamageTimer < 5) {
+ flamePos.x = sMajoraRemains[i]->actor.world.pos.x + Rand_CenteredFloat(40.0f);
+ flamePos.y = sMajoraRemains[i]->actor.world.pos.y + Rand_CenteredFloat(40.0f);
+ flamePos.z = sMajoraRemains[i]->actor.world.pos.z + Rand_CenteredFloat(40.0f);
+
+ flameVelocity.x = 0.0f;
+ flameVelocity.y = 6.0f;
+ flameVelocity.z = 0.0f;
+
+ flameAccel.x = flameVelocity.x * -0.05f;
+ flameAccel.y = flameVelocity.y * -0.05f;
+ flameAccel.z = flameVelocity.z * -0.05f;
+
+ Boss07_SpawnFlameEffect(play, &flamePos, &flameVelocity, &flameAccel,
+ Rand_ZeroFloat(10.0f) + 25.0f);
+ sMajoraRemains[i]->damagedFlashTimer |= 10;
+ } else {
+ sMajoraRemains[i]->subAction = REMAINS_MOVE_SUB_ACTION_DIE;
+ sMajoraRemains[i]->fireTimer = 60;
+ Actor_PlaySfx(&this->actor, NA_SE_EN_FOLLOWERS_DEAD);
+
+ for (j = 0; j < 20; j++) {
+ flamePos.x = sMajoraRemains[i]->actor.world.pos.x + Rand_CenteredFloat(50.0f);
+ flamePos.y = sMajoraRemains[i]->actor.world.pos.y + Rand_CenteredFloat(50.0f);
+ flamePos.z = sMajoraRemains[i]->actor.world.pos.z + Rand_CenteredFloat(50.0f);
+
+ flameVelocity.x = Rand_CenteredFloat(20.0f);
+ flameVelocity.y = Rand_CenteredFloat(20.0f);
+ flameVelocity.z = Rand_CenteredFloat(20.0f);
+
+ flameAccel.x = flameVelocity.x * -0.05f;
+ flameAccel.y = flameVelocity.y * -0.05f;
+ flameAccel.z = flameVelocity.z * -0.05f;
+
+ Boss07_SpawnFlameEffect(play, &flamePos, &flameVelocity, &flameAccel,
+ Rand_ZeroFloat(10.0f) + 25.0f);
+ }
+ }
+ }
+ }
+
+ if (BgCheck_EntityLineTest1(&play->colCtx, &this->beamEndPos, &this->reflectedBeamEndPos,
+ &beamTireMarkPos, &poly, true, true, true, true, &bgId) &&
+ (this->subAction != MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_END)) {
+ Vec3f flamePos;
+ Vec3f flameVelocity;
+ Vec3f flameAccel;
+
+ beamIsTouchingPoly = true;
+
+ flamePos.x = Rand_CenteredFloat(20.0f) + beamTireMarkPos.x;
+ flamePos.y = Rand_CenteredFloat(20.0f) + beamTireMarkPos.y;
+ flamePos.z = Rand_CenteredFloat(20.0f) + beamTireMarkPos.z;
+
+ flameVelocity.x = 0.0f;
+ flameVelocity.y = 6.0f;
+ flameVelocity.z = 0.0f;
+
+ flameAccel.x = flameVelocity.x * -0.05f;
+ flameAccel.y = flameVelocity.y * -0.05f;
+ flameAccel.z = flameVelocity.z * -0.05f;
+
+ Boss07_SpawnFlameEffect(play, &flamePos, &flameVelocity, &flameAccel,
+ Rand_ZeroFloat(10.0f) + 25.0f);
+ }
+ }
+ } else if (!player->bodyIsBurning && (this->subAction != MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_END)) {
+ s32 j;
+
+ func_800B8D50(play, &this->actor, 5.0f, this->actor.shape.rot.y, 0.0f, 0x10);
+
+ for (j = 0; j < ARRAY_COUNT(player->bodyFlameTimers); j++) {
+ player->bodyFlameTimers[j] = Rand_S16Offset(0, 200);
+ }
+
+ player->bodyIsBurning = true;
+ Player_PlaySfx(player, player->ageProperties->voiceSfxIdOffset + NA_SE_VO_LI_DEMO_DAMAGE);
+ }
+ }
+
+ if (beamIsTouchingPoly) {
+ if (beamTireMarkPos.y == 0.0f) {
+ dx = this->prevBeamTireMarkPos.x - beamTireMarkPos.x;
+ dz = this->prevBeamTireMarkPos.z - beamTireMarkPos.z;
+ func_800AE930(&play->colCtx, Effect_GetByIndex(this->effectIndex), &beamTireMarkPos, 15.0f,
+ Math_Atan2S(dx, dz), poly, bgId);
+ this->beamTireMarkEnabled = true;
+ }
+
+ this->prevBeamTireMarkPos = beamTireMarkPos;
+ }
+
+ if (this->subAction != MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_END) {
+ if (this->timers[0] == 0) {
+ this->subAction = MAJORAS_MASK_FIRE_BEAM_SUB_ACTION_END;
+ this->timers[0] = 20;
+ }
+ } else {
+ Math_ApproachZeroF(&this->beamBaseScale, 1.0f, 0.05f);
+
+ if (this->timers[0] == 0) {
+ Boss07_Mask_SetupIdle(this, play);
+ this->timers[2] = 100;
+ Boss07_Mask_StopBeam(this);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Boss07_Mask_SetupIntroCutscene(Boss07* this, PlayState* play) {
+ this->actionFunc = Boss07_Mask_IntroCutscene;
+ this->actor.world.pos.x = 0.0f;
+ this->actor.world.pos.y = 300.0f;
+ this->actor.world.pos.z = -922.5f;
+ this->motionBlurAlpha = KREG(75) + 150;
+ Play_EnableMotionBlur(this->motionBlurAlpha);
+}
+
+static Vec3s sRemainsAttachSubCamEyes[MAJORA_REMAINS_TYPE_MAX] = {
+ { 616, 402, -46 }, // MAJORA_REMAINS_TYPE_ODOLWA
+ { -622, 380, -86 }, // MAJORA_REMAINS_TYPE_GYORG
+ { 400, 300, 463 }, // MAJORA_REMAINS_TYPE_GOHT
+ { -400, 470, 496 }, // MAJORA_REMAINS_TYPE_TWINMOLD
+};
+
+static Vec3s sRemainsAttachSubCamAts[MAJORA_REMAINS_TYPE_MAX] = {
+ { 646, 394, -150 }, // MAJORA_REMAINS_TYPE_ODOLWA
+ { -648, 380, -190 }, // MAJORA_REMAINS_TYPE_GYORG
+ { 502, 321, 438 }, // MAJORA_REMAINS_TYPE_GOHT
+ { -500, 445, 468 }, // MAJORA_REMAINS_TYPE_TWINMOLD
+};
+
+void Boss07_Mask_IntroCutscene(Boss07* this, PlayState* play) {
+ f32 subCamAtYOffset = 0.0f;
+ Player* player = GET_PLAYER(play);
+
+ this->cutsceneTimer++;
+ R_MOTION_BLUR_ALPHA = this->motionBlurAlpha;
+ this->maskEyeTexIndex = MAJORAS_MASK_EYE_DULL;
+
+ switch (this->cutsceneState) {
+ case MAJORAS_MASK_INTRO_CS_STATE_WAITING_FOR_PLAYER_OR_DONE:
+ this->actor.world.pos.x = 0.0f;
+ this->actor.world.pos.y = 277.0f;
+ this->actor.world.pos.z = -922.5f;
+
+ if (!((player->actor.world.pos.z < 700.0f) && (CutsceneManager_GetCurrentCsId() == CS_ID_NONE))) {
+ break;
+ }
+
+ Cutscene_StartManual(play, &play->csCtx);
+ Player_SetCsActionWithHaltedActors(play, &this->actor, PLAYER_CSACTION_WAIT);
+ this->subCamId = Play_CreateSubCamera(play);
+ Play_ChangeCameraStatus(play, CAM_ID_MAIN, CAM_STATUS_WAIT);
+ Play_ChangeCameraStatus(play, this->subCamId, CAM_STATUS_ACTIVE);
+ this->cutsceneTimer = 0;
+ this->cutsceneState = MAJORAS_MASK_INTRO_CS_STATE_LOOK_AT_PLAYER;
+ this->motionBlurAlpha = KREG(76) + 150;
+ FALLTHROUGH;
+ case MAJORAS_MASK_INTRO_CS_STATE_LOOK_AT_PLAYER:
+ if (this->cutsceneTimer >= 20) {
+ Audio_PlaySfx_2(NA_SE_EV_LIGHT_GATHER - SFX_FLAG);
+ Math_ApproachF(&sMajoraBattleHandler->introPlayerOrbScale, sREG(50) + 1.0f, 0.05f, sREG(51) + 0.05f);
+ }
+
+ if (this->cutsceneTimer == 35) {
+ Player_SetCsActionWithHaltedActors(play, &this->actor, PLAYER_CSACTION_15);
+ }
+
+ player->actor.world.pos.x = 0.0f;
+ player->actor.world.pos.z = 700.0f;
+ player->actor.shape.rot.y = -0x8000;
+ player->actor.world.rot.y = player->actor.shape.rot.y;
+
+ this->subCamEye.x = 0.0f;
+ this->subCamEye.y = Player_GetHeight(player) + player->actor.world.pos.y - 24.0f;
+ this->subCamEye.z = player->actor.world.pos.z - 60.0f;
+
+ this->subCamAt.x = player->actor.world.pos.x;
+ this->subCamAt.y = Player_GetHeight(player) + player->actor.world.pos.y - 20.0f;
+ this->subCamAt.z = player->actor.world.pos.z;
+
+ if (player->transformation == PLAYER_FORM_FIERCE_DEITY) {
+ this->subCamAt.y -= 30.0f;
+ }
+
+ if (this->cutsceneTimer == 75) {
+ this->cutsceneTimer = 0;
+ this->cutsceneState = MAJORAS_MASK_INTRO_CS_STATE_REMAINS_ATTACH_TO_WALL;
+ this->subCamEye.x = player->actor.world.pos.x;
+ this->subCamEye.y = player->actor.world.pos.y + 20.0f;
+ this->subCamEye.z = player->actor.world.pos.z - 60.0f + 120.0f;
+ this->subCamAt.x = player->actor.world.pos.x;
+ this->subCamAt.y = player->actor.world.pos.y + 24.0f + 5.0f;
+ this->subCamAt.z = player->actor.world.pos.z;
+ }
+
+ break;
+
+ case MAJORAS_MASK_INTRO_CS_STATE_REMAINS_ATTACH_TO_WALL:
+ this->motionBlurAlpha = KREG(77) + 150;
+
+ if (this->cutsceneTimer >= 20) {
+ Math_ApproachZeroF(&sMajoraBattleHandler->introPlayerOrbScale, 1.0f, 0.05f);
+ }
+
+ if (this->cutsceneTimer == 20) {
+ sMajoraRemains[MAJORA_REMAINS_TYPE_ODOLWA]->subAction = REMAINS_INTRO_CS_SUB_ACTION_FLY;
+ sMajoraRemains[MAJORA_REMAINS_TYPE_GYORG]->subAction = REMAINS_INTRO_CS_SUB_ACTION_FLY;
+ sMajoraRemains[MAJORA_REMAINS_TYPE_GOHT]->subAction = REMAINS_INTRO_CS_SUB_ACTION_FLY;
+ sMajoraRemains[MAJORA_REMAINS_TYPE_TWINMOLD]->subAction = REMAINS_INTRO_CS_SUB_ACTION_FLY;
+ }
+
+ if (this->cutsceneTimer == 0) {
+ Player_SetCsActionWithHaltedActors(play, &this->actor, PLAYER_CSACTION_WAIT);
+ }
+
+ if (this->cutsceneTimer == 120) {
+ Player_SetCsActionWithHaltedActors(play, &this->actor, PLAYER_CSACTION_21);
+ }
+
+ if (this->cutsceneTimer > 30) {
+ Math_ApproachF(&this->subCamAt.y, player->actor.world.pos.y + 24.0f + 20.0f, 0.05f,
+ this->subCamVelocity);
+ Math_ApproachF(&this->subCamVelocity, 1.0f, 1.0f, 0.01f);
+ }
+
+ if (this->cutsceneTimer >= 160) {
+ if (this->cutsceneTimer == 160) {
+ sMajoraRemains[MAJORA_REMAINS_TYPE_ODOLWA]->subAction = REMAINS_INTRO_CS_SUB_ACTION_ATTACH_WAIT;
+ sMajoraRemains[MAJORA_REMAINS_TYPE_GYORG]->subAction = REMAINS_INTRO_CS_SUB_ACTION_ATTACH_WAIT;
+ sMajoraRemains[MAJORA_REMAINS_TYPE_GOHT]->subAction = REMAINS_INTRO_CS_SUB_ACTION_ATTACH_WAIT;
+ sMajoraRemains[MAJORA_REMAINS_TYPE_TWINMOLD]->subAction = REMAINS_INTRO_CS_SUB_ACTION_ATTACH_WAIT;
+ }
+
+ if (this->cutsceneTimer == 161) {
+ sMajoraRemains[MAJORA_REMAINS_TYPE_ODOLWA]->subAction = REMAINS_INTRO_CS_SUB_ACTION_ATTACH_TO_WALL;
+ }
+
+ // This code uses `sfxTimer` as an index to track which of the remains is currently attaching itself to
+ // the wall. The index is used to update the camera's position and orientation, and as it increases,
+ // this code will also signal to the appropriate remains to start attaching to the wall.
+ if ((this->cutsceneTimer == 180) || (this->cutsceneTimer == 200) || (this->cutsceneTimer == 220)) {
+ this->sfxTimer++;
+ sMajoraRemains[this->sfxTimer]->subAction = REMAINS_INTRO_CS_SUB_ACTION_ATTACH_TO_WALL;
+ }
+
+ this->subCamEye.x = sRemainsAttachSubCamEyes[this->sfxTimer].x;
+ this->subCamEye.y = sRemainsAttachSubCamEyes[this->sfxTimer].y;
+ this->subCamEye.z = sRemainsAttachSubCamEyes[this->sfxTimer].z;
+ this->subCamAt.x = sRemainsAttachSubCamAts[this->sfxTimer].x;
+ this->subCamAt.y = sRemainsAttachSubCamAts[this->sfxTimer].y;
+ this->subCamAt.z = sRemainsAttachSubCamAts[this->sfxTimer].z;
+
+ if (this->cutsceneTimer == 250) {
+ this->cutsceneState = MAJORAS_MASK_INTRO_CS_STATE_WAKE_UP;
+ this->cutsceneTimer = 0;
+
+ this->subCamEye.x = this->actor.world.pos.x;
+ this->subCamEye.y = this->actor.world.pos.y;
+ this->subCamEye.z = 300.0f;
+
+ this->subCamAt.x = this->actor.world.pos.x;
+ this->subCamAt.y = this->actor.world.pos.y;
+ this->subCamAt.z = this->actor.world.pos.z;
+
+ Boss07_Remains_SetupMove(sMajoraRemains[MAJORA_REMAINS_TYPE_ODOLWA], play);
+ Boss07_Remains_SetupMove(sMajoraRemains[MAJORA_REMAINS_TYPE_GYORG], play);
+ Boss07_Remains_SetupMove(sMajoraRemains[MAJORA_REMAINS_TYPE_GOHT], play);
+ Boss07_Remains_SetupMove(sMajoraRemains[MAJORA_REMAINS_TYPE_TWINMOLD], play);
+ this->subCamVelocity = 0.0f;
+ sMajoraBattleHandler->introPlayerOrbScale = 0.0f;
+ SEQCMD_STOP_SEQUENCE(SEQ_PLAYER_BGM_MAIN, 10);
+ }
+ }
+ break;
+
+ case MAJORAS_MASK_INTRO_CS_STATE_WAKE_UP:
+ this->motionBlurAlpha = KREG(78) + 150;
+
+ if (this->cutsceneTimer >= 15) {
+ Math_ApproachF(&this->subCamEye.z, -700.0f, 0.4f, 100.0f);
+ }
+
+ if (this->cutsceneTimer >= 55) {
+ if (this->cutsceneTimer == 55) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_B_PAMET_BREAK);
+ }
+
+ this->maskEyeTexIndex = MAJORAS_MASK_EYE_NORMAL;
+ }
+
+ if (this->cutsceneTimer >= 75) {
+ s32 i;
+ Vec3f hahenVelocity = { 0.0f, 0.0f, 0.0f };
+ Vec3f hahenAccel = { 0.0f, -0.5f, 0.0f };
+ Vec3f hahenPos;
+
+ if (this->cutsceneTimer == 75) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST1_DEMO_WALL);
+ }
+
+ subCamAtYOffset = 2.0f * (this->cutsceneTimer % 2);
+
+ if ((this->cutsceneTimer % 2) != 0) {
+ this->actor.world.pos.x += 2.0f;
+ } else {
+ this->actor.world.pos.x -= 2.0f;
+ }
+
+ for (i = 0; i < 3; i++) {
+ hahenPos.x = this->actor.world.pos.x + Rand_CenteredFloat(110.0f);
+ hahenPos.y = this->actor.world.pos.y + Rand_CenteredFloat(110.0f);
+ hahenPos.z = this->actor.world.pos.z + 10.0f;
+ EffectSsHahen_Spawn(play, &hahenPos, &hahenVelocity, &hahenAccel, 0,
+ (Rand_ZeroOne() * 5.0f) + 10.0f, HAHEN_OBJECT_DEFAULT, 10, NULL);
+ }
+ }
+
+ if (this->cutsceneTimer == 110) {
+ this->cutsceneState = MAJORAS_MASK_INTRO_CS_STATE_DETACH_FROM_WALL;
+ this->cutsceneTimer = 0;
+
+ this->subCamEye.x = this->actor.world.pos.x + 200.0f;
+ this->subCamEye.y = this->actor.world.pos.y;
+ this->subCamEye.z = this->actor.world.pos.z + 400.0f;
+
+ player->actor.world.pos.z = 0.0f;
+ Player_SetCsActionWithHaltedActors(play, &this->actor, PLAYER_CSACTION_1);
+ this->motionBlurAlpha = KREG(74) + 200;
+ }
+ break;
+
+ case MAJORAS_MASK_INTRO_CS_STATE_DETACH_FROM_WALL:
+ this->maskEyeTexIndex = MAJORAS_MASK_EYE_NORMAL;
+
+ if (this->cutsceneTimer >= 10) {
+ Math_ApproachS(&this->motionBlurAlpha, KREG(72), 1, KREG(73) + 2);
+
+ if (this->cutsceneTimer == 10) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST1_DEMO_BREAK);
+ }
+
+ SkelAnime_Update(&this->skelAnime);
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST1_FLOAT_OLD - SFX_FLAG);
+ Math_ApproachF(&this->tentacleLengthScale, 1.0f, 1.0f, 0.02f);
+ Math_ApproachF(&this->actor.world.pos.z, -642.5f, 0.05f, 30.0f);
+ Math_ApproachF(&this->actor.world.pos.y, 350.0f, 0.03f, 2.0f);
+
+ if (this->cutsceneTimer == 55) {
+ TitleCard_InitBossName(&play->state, &play->actorCtx.titleCtx,
+ Lib_SegmentedToVirtual(&gMajorasMaskTitleCardTex), 160, 180, 128, 40);
+ }
+
+ if (this->cutsceneTimer == 30) {
+ SEQCMD_PLAY_SEQUENCE(SEQ_PLAYER_BGM_MAIN, 0, NA_BGM_MAJORAS_MASK | SEQ_FLAG_ASYNC);
+ }
+
+ if (this->cutsceneTimer > 100) {
+ Math_ApproachF(&this->subCamEye.x, player->actor.world.pos.x + 40.0f, 0.1f,
+ this->subCamVelocity * 20.0f);
+ Math_ApproachF(&this->subCamEye.y, player->actor.world.pos.y + 10.0f, 0.1f,
+ this->subCamVelocity * 20.0f);
+ Math_ApproachF(&this->subCamEye.z, player->actor.world.pos.z + 90.0f, 0.1f,
+ this->subCamVelocity * 60.0f);
+ Math_ApproachF(&this->subCamVelocity, 1.0f, 1.0f, 0.03f);
+ }
+
+ if (this->cutsceneTimer == 175) {
+ Camera* mainCam = Play_GetCamera(play, CAM_ID_MAIN);
+
+ this->cutsceneState = MAJORAS_MASK_INTRO_CS_STATE_WAITING_FOR_PLAYER_OR_DONE;
+ Boss07_Mask_SetupIdle(this, play);
+ this->timers[0] = 50;
+ this->timers[2] = 200;
+ this->bgCheckTimer = 50;
+ this->targetPos.x = 0.0f;
+ this->targetPos.y = 200.0f;
+ this->targetPos.z = 0.0f;
+ this->speedToTarget = 0.0f;
+ mainCam->eye = this->subCamEye;
+ mainCam->eyeNext = this->subCamEye;
+ mainCam->at = this->subCamAt;
+ func_80169AFC(play, this->subCamId, 0);
+ this->subCamId = SUB_CAM_ID_DONE;
+ Cutscene_StopManual(play, &play->csCtx);
+ Player_SetCsActionWithHaltedActors(play, &this->actor, PLAYER_CSACTION_END);
+ this->actor.flags |= ACTOR_FLAG_ATTENTION_ENABLED;
+ SET_EVENTINF(EVENTINF_INTRO_CS_WATCHED_MAJORA);
+ Play_DisableMotionBlur();
+ }
+ } else if ((this->cutsceneTimer % 2) != 0) {
+ this->actor.world.pos.x += 2.0f;
+ } else {
+ this->actor.world.pos.x -= 2.0f;
+ }
+
+ Math_ApproachF(&this->subCamAt.x, this->actor.world.pos.x, 0.05f, 10.0f);
+ Math_ApproachF(&this->subCamAt.y, this->actor.world.pos.y, 0.05f, 10.0f);
+ Math_ApproachF(&this->subCamAt.z, this->actor.world.pos.z, 0.05f, 10.0f);
+ break;
+
+ default:
+ break;
+ }
+ if (this->subCamId != SUB_CAM_ID_DONE) {
+ Vec3f subCamAt;
+
+ ShrinkWindow_Letterbox_SetSizeTarget(27);
+ subCamAt.x = this->subCamAt.x;
+ subCamAt.y = this->subCamAt.y + subCamAtYOffset;
+ subCamAt.z = this->subCamAt.z;
+ Play_SetCameraAtEye(play, this->subCamId, &subCamAt, &this->subCamEye);
+ }
+}
+
+void Boss07_Mask_SetupDeathCutscene(Boss07* this, PlayState* play) {
+ this->actionFunc = Boss07_Mask_DeathCutscene;
+ Animation_MorphToLoop(&this->skelAnime, &gMajorasMaskJerkingAnim, -10.0f);
+ this->actor.world.rot.y = this->actor.shape.rot.y =
+ Math_Atan2F_XY(-this->actor.world.pos.z, -this->actor.world.pos.x) * (0x8000 / M_PIf);
+ this->cutsceneState = MAJORAS_MASK_DEATH_CS_STATE_STARTED;
+ this->cutsceneTimer = 0;
+ this->actor.flags &= ~ACTOR_FLAG_ATTENTION_ENABLED;
+ this->damagedTimer = 20;
+}
+
+void Boss07_Mask_DeathCutscene(Boss07* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+ Vec3f subCamAtTarget;
+ Vec3f subCamEye;
+
+ this->cutsceneTimer++;
+ this->damagedTimer = 20;
+ this->maskEyeTexIndex = MAJORAS_MASK_EYE_DULL;
+ SkelAnime_Update(&this->skelAnime);
+ Boss07_SmoothStop(this, 0.5f);
+
+ Math_ApproachF(&this->actor.world.pos.x, 0.0f, 0.05f, 5.0f);
+ Math_ApproachF(&this->actor.world.pos.z, 0.0f, 0.05f, 5.0f);
+ Math_ApproachF(&this->actor.world.pos.y, 130.0f, 0.05f, 3.0f);
+
+ Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, MTXMODE_NEW);
+ Matrix_RotateYS(this->actor.shape.rot.y, MTXMODE_APPLY);
+
+ switch (this->cutsceneState) {
+ case MAJORAS_MASK_DEATH_CS_STATE_STARTED:
+ if (CutsceneManager_GetCurrentCsId() == CS_ID_NONE) {
+ Cutscene_StartManual(play, &play->csCtx);
+ Player_SetCsActionWithHaltedActors(play, &this->actor, PLAYER_CSACTION_1);
+ this->subCamId = Play_CreateSubCamera(play);
+ Play_ChangeCameraStatus(play, CAM_ID_MAIN, CAM_STATUS_WAIT);
+ Play_ChangeCameraStatus(play, this->subCamId, CAM_STATUS_ACTIVE);
+ this->cutsceneTimer = 0;
+ this->cutsceneState = MAJORAS_MASK_DEATH_CS_STATE_PLAYING;
+ this->subCamAtNext.z = 0.0f;
+ this->fireTimer = 120;
+ Play_EnableMotionBlur(150);
+
+ this->subCamEyeNext.x = 0.0f;
+ this->subCamEyeNext.y = -30.0f;
+ this->subCamEyeNext.z = 270.0f;
+
+ this->subCamAtNext.x = 0.0f;
+ this->subCamAtNext.y = -30.0f;
+
+ Matrix_MultVec3f(&this->subCamEyeNext, &this->subCamEye);
+ Matrix_MultVec3f(&this->subCamAtNext, &this->subCamAt);
+ } else {
+ break;
+ }
+ FALLTHROUGH;
+ case MAJORAS_MASK_DEATH_CS_STATE_PLAYING:
+ player->actor.world.pos.x = 0.0f;
+ player->actor.world.pos.z = BREG(87) + 250.0f;
+ player->actor.world.rot.y = player->actor.shape.rot.y = -0x8000;
+
+ this->tentacleState = MAJORAS_MASK_TENTACLE_STATE_DEATH;
+
+ if (this->cutsceneTimer > 60) {
+ Math_ApproachS(&this->actor.shape.rot.x, 0, 0xA, 0x200);
+ Math_ApproachS(&this->actor.shape.rot.z, 0, 0xA, 0x200);
+ Math_ApproachZeroF(&this->tentacleLengthScale, 1.0f, 0.01f);
+ } else {
+ this->actor.shape.rot.x += 0x1000;
+ this->actor.shape.rot.z += 0x1200;
+ Math_ApproachZeroF(&this->tentacleLengthScale, 1.0f, 0.005f);
+ }
+
+ if (this->cutsceneTimer > 130) {
+ this->cutsceneState = MAJORAS_MASK_DEATH_CS_STATE_SPAWN_INCARNATION;
+ } else {
+ break;
+ }
+ FALLTHROUGH;
+ case MAJORAS_MASK_DEATH_CS_STATE_SPAWN_INCARNATION:
+ Actor_Spawn(&play->actorCtx, play, ACTOR_BOSS_07, 0.0f, 0.0f, 0.0f, 0, this->actor.shape.rot.y,
+ this->subCamId, MAJORA_PARAMS(MAJORA_TYPE_INCARNATION));
+ Actor_Kill(&this->actor);
+ break;
+
+ default:
+ break;
+ }
+
+ Matrix_MultVec3f(&this->subCamEyeNext, &this->subCamEye);
+ Matrix_MultVec3f(&this->subCamAtNext, &subCamAtTarget);
+
+ Math_ApproachF(&this->subCamAt.x, subCamAtTarget.x, 0.1f, 10.0f);
+ Math_ApproachF(&this->subCamAt.y, subCamAtTarget.y, 0.1f, 10.0f);
+ Math_ApproachF(&this->subCamAt.z, subCamAtTarget.z, 0.1f, 10.0f);
+
+ if (this->subCamId != SUB_CAM_ID_DONE) {
+ ShrinkWindow_Letterbox_SetSizeTarget(27);
+ subCamEye = this->subCamEye;
+ if (subCamEye.y < 30.0f) {
+ subCamEye.y = 30.0f;
+ }
+
+ Play_SetCameraAtEye(play, this->subCamId, &this->subCamAt, &subCamEye);
+ }
+}
+
+void Boss07_Mask_UpdateDamage(Boss07* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+ ColliderElement* acHitElem;
+ u8 damage;
+ Actor* hitActor;
+
+ if (this->damagedTimer == 0) {
+ if (this->maskFrontCollider.base.acFlags & AC_HIT) {
+ this->maskFrontCollider.base.acFlags &= ~AC_HIT;
+ this->maskShakeTimer = 7;
+ }
+
+ if (this->maskBackCollider.base.acFlags & AC_HIT) {
+ this->maskBackCollider.base.acFlags &= ~AC_HIT;
+ this->maskShakeTimer = 15;
+
+ if ((this->actionFunc == Boss07_Mask_Stunned) || (player->stateFlags3 & PLAYER_STATE3_200)) {
+ hitActor = this->maskBackCollider.base.ac;
+ acHitElem = this->maskBackCollider.elem.acHitElem;
+ damage = (acHitElem->atDmgInfo.dmgFlags & ~0x8300000) ? this->actor.colChkInfo.damage : 0;
+ this->damagedTimer = 50;
+ this->damagedFlashTimer = 15;
+ AudioSfx_StopByPos(&this->actor.projectedPos);
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST1_DAMAGE2_OLD);
+ Boss07_Mask_SetupDamaged(this, play, damage, hitActor);
+ } else {
+ this->damagedTimer = 15;
+ AudioSfx_StopByPos(&this->actor.projectedPos);
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST1_DAMAGE1_OLD);
+ Boss07_Mask_SetupStunned(this, play);
+ }
+ }
+ }
+}
+
+void Boss07_Mask_Update(Actor* thisx, PlayState* play2) {
+ PlayState* play = play2;
+ Boss07* this = THIS;
+ s32 i;
+ Player* player = GET_PLAYER(play);
+ Vec3f topLeftVertex;
+ Vec3f bottomLeftVertex;
+ Vec3f topRightVertex;
+ Vec3f bottomRightVertex;
+ Vec3f temp;
+ f32 backColliderXY;
+
+ this->actor.hintId = TATL_HINT_ID_MAJORAS_MASK;
+
+ if (sMusicStartTimer != 0) {
+ sMusicStartTimer--;
+ if (sMusicStartTimer == 0) {
+ SEQCMD_PLAY_SEQUENCE(SEQ_PLAYER_BGM_MAIN, 0, NA_BGM_MAJORAS_MASK | SEQ_FLAG_ASYNC);
+ }
+ }
+
+ Math_Vec3f_Copy(&sMajoraSfxPos, &this->actor.projectedPos);
+
+ if ((sMajoraBattleHandler == NULL) || (sMajoraBattleHandler->subCamId == SUB_CAM_ID_DONE)) {
+ this->shouldUpdateTentaclesOrWhips = true;
+ play->envCtx.lightSetting = 2;
+ play->envCtx.prevLightSetting = 0;
+ Math_ApproachF(&play->envCtx.lightBlend, this->beamBaseScale, 1.0f, 0.1f);
+ this->frameCounter++;
+
+ if (KREG(63) == 0) {
+ this->canEvade = false;
+ this->maskEyeTexIndex = MAJORAS_MASK_EYE_NORMAL;
+ this->tentacleState = MAJORAS_MASK_TENTACLE_STATE_DEFAULT;
+ Actor_SetScale(&this->actor, 0.1f);
+ this->actor.focus.pos = this->actor.world.pos;
+
+ for (i = 0; i < ARRAY_COUNT(this->timers); i++) {
+ DECR(this->timers[i]);
+ }
+
+ DECR(this->maskShakeTimer);
+ DECR(this->damagedTimer);
+ DECR(this->damagedFlashTimer);
+ DECR(this->fireTimer);
+ DECR(this->beamDamageTimer);
+
+ this->beamTireMarkEnabled = false;
+
+ this->actionFunc(this, play);
+
+ if (!this->beamTireMarkEnabled && this->prevBeamTireMarkEnabled) {
+ func_800AEF44(Effect_GetByIndex(this->effectIndex));
+ }
+
+ this->prevBeamTireMarkEnabled = this->beamTireMarkEnabled;
+
+ if (this->actionFunc != Boss07_Mask_IntroCutscene) {
+ if (this->actionFunc != Boss07_Mask_Damaged) {
+ Actor_UpdateVelocityWithoutGravity(&this->actor);
+ Actor_UpdatePos(&this->actor);
+ } else {
+ if (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND) {
+ this->actor.velocity.y = 0.0f;
+ }
+
+ Actor_MoveWithGravity(&this->actor);
+ }
+
+ if (this->bgCheckTimer == 0) {
+ Actor_UpdateBgCheckInfo(play, &this->actor, 50.0f, 60.0f, 100.0f,
+ UPDBGCHECKINFO_FLAG_1 | UPDBGCHECKINFO_FLAG_4);
+ } else {
+ this->bgCheckTimer--;
+ }
+ }
+ } else {
+ this->actor.colChkInfo.health = 0;
+ }
+
+ Boss07_Mask_UpdateDamage(this, play);
+ Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, MTXMODE_NEW);
+ Matrix_RotateYS(this->actor.shape.rot.y, MTXMODE_APPLY);
+ Matrix_RotateXS(this->actor.shape.rot.x, MTXMODE_APPLY);
+ Matrix_RotateZS(this->actor.shape.rot.z, MTXMODE_APPLY);
+
+ temp.x = -55.0f;
+ temp.y = 55.0f;
+ temp.z = 10.0f;
+ Matrix_MultVec3f(&temp, &topLeftVertex);
+
+ temp.x = -55.0f;
+ temp.y = -55.0f;
+ Matrix_MultVec3f(&temp, &bottomLeftVertex);
+
+ temp.x = 55.0f;
+ temp.y = 55.0f;
+ Matrix_MultVec3f(&temp, &topRightVertex);
+
+ temp.x = 55.0f;
+ temp.y = -55.0f;
+ Matrix_MultVec3f(&temp, &bottomRightVertex);
+
+ Collider_SetQuadVertices(&this->maskFrontCollider, &topLeftVertex, &bottomLeftVertex, &topRightVertex,
+ &bottomRightVertex);
+
+ backColliderXY = (player->stateFlags3 & PLAYER_STATE3_200) ? 70.0f : 40.0f;
+
+ temp.x = -backColliderXY;
+ temp.y = backColliderXY;
+ temp.z = -10.0f;
+ Matrix_MultVec3f(&temp, &topLeftVertex);
+
+ temp.x = -backColliderXY;
+ temp.y = -backColliderXY;
+ Matrix_MultVec3f(&temp, &bottomLeftVertex);
+
+ temp.x = backColliderXY;
+ temp.y = backColliderXY;
+ Matrix_MultVec3f(&temp, &topRightVertex);
+
+ temp.x = backColliderXY;
+ temp.y = -backColliderXY;
+ Matrix_MultVec3f(&temp, &bottomRightVertex);
+
+ Collider_SetQuadVertices(&this->maskBackCollider, &topLeftVertex, &bottomLeftVertex, &topRightVertex,
+ &bottomRightVertex);
+
+ if (player->stateFlags3 & PLAYER_STATE3_200) {
+ CollisionCheck_SetAC(play, &play->colChkCtx, &this->maskBackCollider.base);
+ } else {
+ if ((this->actionFunc != Boss07_Mask_Stunned) && (this->actionFunc != Boss07_Mask_Damaged)) {
+ CollisionCheck_SetAC(play, &play->colChkCtx, &this->maskFrontCollider.base);
+ }
+
+ CollisionCheck_SetAC(play, &play->colChkCtx, &this->maskBackCollider.base);
+
+ if (this->actionFunc == Boss07_Mask_SpinAttack) {
+ CollisionCheck_SetAT(play, &play->colChkCtx, &this->maskFrontCollider.base);
+ CollisionCheck_SetAT(play, &play->colChkCtx, &this->maskBackCollider.base);
+ }
+ }
+
+ if (this->fireTimer != 0) {
+ Vec3f flamePos;
+ Vec3f flameVelocity;
+ Vec3f flameAccel;
+ f32 flamePosRandScale = (this->actionFunc == Boss07_Mask_DeathCutscene) ? 130.0f : 80.0f;
+
+ flamePos.x = Rand_CenteredFloat(flamePosRandScale) + this->actor.world.pos.x;
+ flamePos.y = Rand_CenteredFloat(flamePosRandScale) + this->actor.world.pos.y;
+ flamePos.z = Rand_CenteredFloat(flamePosRandScale) + this->actor.world.pos.z;
+
+ flameVelocity.x = 0.0f;
+ flameVelocity.y = 5.0f;
+ flameVelocity.z = 0.0f;
+
+ flameAccel.x = flameVelocity.x * -0.05f;
+ flameAccel.y = flameVelocity.y * -0.05f;
+ flameAccel.z = flameVelocity.z * -0.05f;
+
+ Boss07_SpawnFlameEffect(play, &flamePos, &flameVelocity, &flameAccel, Rand_ZeroFloat(10.0f) + 25.0f);
+ Audio_PlaySfx_AtPos(&sMajoraSfxPos, NA_SE_EV_BURN_OUT - SFX_FLAG);
+ }
+ }
+}
+
+void Boss07_Mask_UpdateTentacles(Boss07* this, PlayState* play, Vec3f* base, Vec3f* pos, Vec3f* rot, Vec3f* velocity,
+ Vec3f* baseForce, f32 lengthScale, u8 isMovingBackwards, f32 rotZ) {
+ s32 i;
+ f32 gravity;
+ f32 segPitch;
+ f32 segYaw;
+ f32 tempY;
+ f32 temp;
+ Vec3f tempPos;
+ Vec3f baseSegVec = { 0.0f, 0.0f, 0.0f };
+ Vec3f segVec;
+ Vec3f shapeForce;
+ Vec3f* firstVelocity = velocity;
+
+ if (this->tentacleState != MAJORAS_MASK_TENTACLE_STATE_DEFAULT) {
+ for (i = 0; i < MAJORA_TENTACLE_LENGTH; i++) {
+ Matrix_Push();
+
+ Matrix_RotateZF(rotZ, MTXMODE_APPLY);
+ baseSegVec.x = Math_SinS((2 * i + this->frameCounter) * 0x1600) * 10;
+ baseSegVec.y = 10.0f;
+ baseSegVec.z = 0.0f;
+
+ Matrix_MultVec3f(&baseSegVec, &segVec);
+ pos[i].x += segVec.x;
+ pos[i].y += segVec.y;
+ pos[i].z += segVec.z;
+
+ Matrix_Pop();
+ }
+ }
+
+ for (i = 0; i < MAJORA_TENTACLE_LENGTH; i++, velocity++) {
+ if (i == 0) {
+ pos[0] = *base;
+ continue;
+ }
+
+ Math_ApproachF(&velocity->x, 0.0f, 1.0f, 1.0f);
+ Math_ApproachF(&velocity->y, 0.0f, 1.0f, 1.0f);
+ Math_ApproachF(&velocity->z, 0.0f, 1.0f, 1.0f);
+ }
+
+ pos++;
+ rot++;
+ velocity = firstVelocity + 1;
+ baseSegVec.x = baseSegVec.y = 0.0f;
+ baseSegVec.z = lengthScale * 23.0f;
+
+ for (i = 1; i < MAJORA_TENTACLE_LENGTH; i++, velocity++, pos++, rot++) {
+ if (i < MAJORA_TENTACLE_LENGTH / 2) {
+ shapeForce.x = baseForce->x * (MAJORA_TENTACLE_LENGTH / 2 - i) * 0.2f;
+ shapeForce.y = baseForce->y * (MAJORA_TENTACLE_LENGTH / 2 - i) * 0.2f;
+ shapeForce.z = baseForce->z * (MAJORA_TENTACLE_LENGTH / 2 - i) * 0.2f;
+ } else {
+ shapeForce = gZeroVec3f;
+ }
+
+ // Advances the physics one frame to find the provisional position relative to the previous point
+ tempPos.x = pos->x + velocity->x - (pos - 1)->x + shapeForce.x;
+
+ if (this->tentacleState != MAJORAS_MASK_TENTACLE_STATE_DEFAULT) {
+ gravity = 0.0f;
+ } else if (isMovingBackwards && ((this->actor.world.pos.y - 30.0f) < (pos - 1)->y)) {
+ gravity = -30.0f;
+ } else {
+ gravity = -3.0f - ((i & 7) * 0.05f);
+ }
+
+ tempY = pos->y + velocity->y + gravity + shapeForce.y;
+ if (tempY < 2.0f) {
+ tempY = 2.0f;
+ }
+
+ tempPos.y = tempY - (pos - 1)->y;
+ tempPos.z = pos->z + velocity->z - (pos - 1)->z + shapeForce.x;
+
+ // calculates the rotation angles from the previous point
+ segYaw = Math_Atan2F_XY(tempPos.z, tempPos.x);
+ temp = sqrtf(SQXZ(tempPos));
+ segPitch = -Math_Atan2F_XY(temp, tempPos.y);
+ (rot - 1)->y = segYaw;
+ (rot - 1)->x = segPitch;
+
+ // Sets the position to be in the same direction as the provisional position relative to the previous point, but
+ // a fixed distance away
+ Matrix_RotateYF(segYaw, MTXMODE_NEW);
+ Matrix_RotateXFApply(segPitch);
+ Matrix_MultVecZ(baseSegVec.z, &segVec);
+
+ tempPos.x = pos->x;
+ tempPos.y = pos->y;
+ tempPos.z = pos->z;
+
+ pos->x = (pos - 1)->x + segVec.x;
+ pos->y = (pos - 1)->y + segVec.y;
+ pos->z = (pos - 1)->z + segVec.z;
+
+ // calculates the velocity for the next frame
+ velocity->x = (pos->x - tempPos.x) * 0.85f;
+ velocity->y = (pos->y - tempPos.y) * 0.85f;
+ velocity->z = (pos->z - tempPos.z) * 0.85f;
+ }
+}
+
+void Boss07_Mask_DrawTentacles(Boss07* this, PlayState* play, Vec3f* pos, Vec3f* rot, f32 lengthScale, f32 rotZ) {
+ s32 i;
+ f32 thicknessScale;
+
+ OPEN_DISPS(play->state.gfxCtx);
+
+ for (i = 0; i < MAJORA_TENTACLE_LENGTH - 1; i++, pos++, rot++) {
+ Matrix_Translate(pos->x, pos->y, pos->z, MTXMODE_NEW);
+ Matrix_RotateYF(rot->y, MTXMODE_APPLY);
+ Matrix_RotateXFApply(rot->x);
+ Matrix_RotateZF(rotZ, MTXMODE_APPLY);
+
+ if (i <= (MAJORA_TENTACLE_LENGTH - 1) / 2) {
+ thicknessScale = 0.035f;
+ } else {
+ thicknessScale = 0.035f - (i - (MAJORA_TENTACLE_LENGTH - 1) / 2) * 60.0f * 0.0001f;
+ }
+
+ Matrix_Scale(thicknessScale, thicknessScale, lengthScale * 0.01f * 2.3f, MTXMODE_APPLY);
+ MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, play->state.gfxCtx);
+ gSPDisplayList(POLY_OPA_DISP++, gMajorasMaskTentacleModelDL);
+ }
+
+ CLOSE_DISPS(play->state.gfxCtx);
+}
+
+void Boss07_Mask_DrawBeam(Boss07* this, PlayState* play) {
+ s32 pad[4];
+
+ OPEN_DISPS(play->state.gfxCtx);
+
+ if (this->actionFunc == Boss07_Mask_FireBeam) {
+ gSPSegment(POLY_XLU_DISP++, 0x0C,
+ Gfx_TexScroll(play->state.gfxCtx, 0, (this->frameCounter * -15) & 0xFF, 32, 64));
+ gDPPipeSync(POLY_XLU_DISP++);
+ gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 60, 200);
+ gDPSetEnvColor(POLY_XLU_DISP++, 255, 0, 0, 128);
+ Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, MTXMODE_NEW);
+ Matrix_RotateYS(this->actor.shape.rot.y, MTXMODE_APPLY);
+ Matrix_RotateXS(this->actor.shape.rot.x, MTXMODE_APPLY);
+ Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY);
+
+ Matrix_Push();
+ {
+ Matrix_Push();
+ {
+ Matrix_Push();
+ {
+ Matrix_Translate(250.0f, 0.0f, 200.0f, MTXMODE_APPLY);
+ Matrix_RotateYS(-0xA00, MTXMODE_APPLY);
+ Matrix_Scale(this->beamBaseScale * 0.05f, this->beamBaseScale * 0.05f,
+ this->eyeBeamsLengthScale * 0.05f, MTXMODE_APPLY);
+ MATRIX_FINALIZE_AND_LOAD(POLY_XLU_DISP++, play->state.gfxCtx);
+ gSPDisplayList(POLY_XLU_DISP++, gMajorasMaskBeamDL);
+ }
+ Matrix_Pop();
+
+ Matrix_Translate(-250.0f, 0.0f, 200.0f, MTXMODE_APPLY);
+ Matrix_RotateYS(0xA00, MTXMODE_APPLY);
+ Matrix_Scale(this->beamBaseScale * 0.05f, this->beamBaseScale * 0.05f,
+ this->eyeBeamsLengthScale * 0.05f, MTXMODE_APPLY);
+ MATRIX_FINALIZE_AND_LOAD(POLY_XLU_DISP++, play->state.gfxCtx);
+ gSPDisplayList(POLY_XLU_DISP++, gMajorasMaskBeamDL);
+ gSPDisplayList(POLY_XLU_DISP++, gLightOrbMaterial1DL);
+ }
+ Matrix_Pop();
+
+ Matrix_Translate(0.0f, 0.0f, 1200.0f, MTXMODE_APPLY);
+ Matrix_ReplaceRotation(&play->billboardMtxF);
+ Matrix_Scale(this->eyeBeamsFocusOrbScale * 40.0f * this->beamBaseScale,
+ this->eyeBeamsFocusOrbScale * 40.0f * this->beamBaseScale, 0.0f, MTXMODE_APPLY);
+ Matrix_RotateZS(this->frameCounter * 0x100, MTXMODE_APPLY);
+ MATRIX_FINALIZE_AND_LOAD(POLY_XLU_DISP++, play->state.gfxCtx);
+ gSPDisplayList(POLY_XLU_DISP++, gLightOrbModelDL);
+ gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 60, sREG(89) + 80);
+ Matrix_Scale(6.0f, 6.0f, 0.0f, MTXMODE_APPLY);
+ Matrix_RotateZS(0x4000, MTXMODE_APPLY);
+ MATRIX_FINALIZE_AND_LOAD(POLY_XLU_DISP++, play->state.gfxCtx);
+ gSPDisplayList(POLY_XLU_DISP++, gLightOrbModelDL);
+ gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 60, 200);
+ }
+ Matrix_Pop();
+
+ Matrix_Translate(0.0f, 0.0f, 1150.0f, MTXMODE_APPLY);
+ Matrix_MultZero(&this->beamStartPos);
+ Matrix_Scale(this->beamBaseScale * 0.05f, this->beamBaseScale * 0.05f, (this->beamLengthScale * 0.01f) - 0.01f,
+ MTXMODE_APPLY);
+ MATRIX_FINALIZE_AND_LOAD(POLY_XLU_DISP++, play->state.gfxCtx);
+ gSPDisplayList(POLY_XLU_DISP++, gMajorasMaskBeamDL);
+ Matrix_MultVecZ(20100.0f, &this->beamEndPos);
+
+ if (this->reflectedBeamLengthScale > 0.0f) {
+ Vec3f lightOrbPos;
+
+ Matrix_MultVecZ(20000.0f, &lightOrbPos);
+ Matrix_Translate(this->beamEndPos.x, this->beamEndPos.y, this->beamEndPos.z, MTXMODE_NEW);
+ Matrix_RotateYS(this->reflectedBeamYaw, MTXMODE_APPLY);
+ Matrix_RotateXS(this->reflectedBeamPitch, MTXMODE_APPLY);
+ Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY);
+ Matrix_Scale(this->beamBaseScale * 0.05f, this->beamBaseScale * 0.05f,
+ this->reflectedBeamLengthScale * 0.01f, MTXMODE_APPLY);
+ MATRIX_FINALIZE_AND_LOAD(POLY_XLU_DISP++, play->state.gfxCtx);
+ gSPDisplayList(POLY_XLU_DISP++, gMajorasMaskBeamDL);
+
+ Matrix_MultVecZ(20100.0f, &this->reflectedBeamEndPos);
+ Matrix_Translate(lightOrbPos.x, lightOrbPos.y, lightOrbPos.z, MTXMODE_NEW);
+ Matrix_ReplaceRotation(&play->billboardMtxF);
+ Matrix_Scale(this->beamBaseScale * 5.0f, this->beamBaseScale * 5.0f, 0.0f, MTXMODE_APPLY);
+ Matrix_RotateZS(this->frameCounter * 0x100, MTXMODE_APPLY);
+ MATRIX_FINALIZE_AND_LOAD(POLY_XLU_DISP++, play->state.gfxCtx);
+ gSPDisplayList(POLY_XLU_DISP++, gLightOrbMaterial1DL);
+ gSPDisplayList(POLY_XLU_DISP++, gLightOrbModelDL);
+ }
+ }
+
+ CLOSE_DISPS(play->state.gfxCtx);
+}
+
+void Boss07_Mask_PostLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx) {
+ Boss07* this = THIS;
+
+ if (limbIndex == MAJORAS_MASK_LIMB_FACE) {
+ Matrix_MultVecX(500.0f, &this->tentacleBasePos);
+ }
+}
+
+void Boss07_Mask_Draw(Actor* thisx, PlayState* play2) {
+ static TexturePtr sMaskEyeTextures[] = { gMajorasMaskWithNormalEyesTex, gMajorasMaskWithDullEyesTex };
+ PlayState* play = play2;
+ Boss07* this = THIS;
+ f32 shakeScale;
+ f32 rotX;
+ f32 rotY;
+ f32 rotZ;
+ f32 lengthScale;
+ s32 i;
+ s32 isMovingBackwards;
+ Vec3f offsetVec;
+ Vec3f tentacleOffset;
+ Vec3f baseForce;
+
+ OPEN_DISPS(play->state.gfxCtx);
+
+ Gfx_SetupDL25_Opa(play->state.gfxCtx);
+ Gfx_SetupDL25_Xlu(play->state.gfxCtx);
+
+ shakeScale = this->maskShakeTimer * (M_PIf / 4.0f) * 0.06666667f;
+ rotX = Math_SinS(this->maskShakeTimer * 0x3500) * shakeScale * 0.5f;
+ rotY = Math_SinS(this->maskShakeTimer * 0x4500) * shakeScale;
+ Matrix_RotateYF(rotY, MTXMODE_APPLY);
+ Matrix_RotateXFApply(rotX);
+
+ if ((this->damagedFlashTimer % 2) != 0) {
+ POLY_OPA_DISP = Gfx_SetFog(POLY_OPA_DISP, 255, 0, 0, 255, 900, 1099);
+ }
+
+ gSPSegment(POLY_OPA_DISP++, 0x08, Lib_SegmentedToVirtual(sMaskEyeTextures[this->maskEyeTexIndex]));
+ SkelAnime_DrawOpa(play, this->skelAnime.skeleton, this->skelAnime.jointTable, NULL, Boss07_Mask_PostLimbDraw,
+ &this->actor);
+ POLY_OPA_DISP = Play_SetFog(play, POLY_OPA_DISP);
+ gSPDisplayList(POLY_OPA_DISP++, gMajorasMaskTentacleMaterialDL);
+ gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 155, 155, 80, 255);
+
+ isMovingBackwards = ((this->actionFunc == Boss07_Mask_Idle) &&
+ (ABS_ALT((s16)(this->actor.world.rot.y - this->actor.shape.rot.y)) > 0x4000))
+ ? true
+ : false;
+
+ Matrix_RotateYS(this->actor.shape.rot.y, MTXMODE_NEW);
+ Matrix_RotateXS(this->actor.shape.rot.x, MTXMODE_APPLY);
+ Matrix_RotateZS(this->actor.shape.rot.z, MTXMODE_APPLY);
+ Matrix_MultVecZ(-3.0f, &baseForce);
+
+ offsetVec.x = 0.0f;
+ offsetVec.y = 20.0f;
+ offsetVec.z = -2.0f;
+ rotZ = 0.0f;
+
+ for (i = 0; i < MAJORA_TENTACLE_COUNT; i++) {
+ Matrix_Push();
+ Matrix_Push();
+ Matrix_RotateZF(rotZ, MTXMODE_APPLY);
+ Matrix_MultVec3f(&offsetVec, &tentacleOffset);
+
+ this->tentacles[i].base.x = this->tentacleBasePos.x + tentacleOffset.x;
+ this->tentacles[i].base.y = this->tentacleBasePos.y + tentacleOffset.y;
+ this->tentacles[i].base.z = this->tentacleBasePos.z + tentacleOffset.z;
+ lengthScale = (1 - (i * 0.008f)) * this->tentacleLengthScale;
+
+ Matrix_Pop();
+
+ if (this->shouldUpdateTentaclesOrWhips) {
+ Boss07_Mask_UpdateTentacles(this, play, &this->tentacles[i].base, this->tentacles[i].pos,
+ this->tentacles[i].rot, this->tentacles[i].velocity, &baseForce, lengthScale,
+ isMovingBackwards, rotZ);
+ }
+
+ Boss07_Mask_DrawTentacles(this, play, this->tentacles[i].pos, this->tentacles[i].rot, lengthScale, i * 0.9f);
+ rotZ += 0.5f;
+ offsetVec.y += 1.0f;
+
+ Matrix_Pop();
+ }
+
+ Boss07_Mask_DrawBeam(this, play);
+ this->shouldUpdateTentaclesOrWhips = false;
+
+ CLOSE_DISPS(play->state.gfxCtx);
+}
+
+void Boss07_Projectile_Update(Actor* thisx, PlayState* play2) {
+ s32 i;
+ f32 dx;
+ f32 dy;
+ f32 dz;
+ f32 distToPlayerXZ;
+ PlayState* play = play2;
+ Boss07* this = THIS;
+ Player* player = GET_PLAYER(play);
+
+ this->frameCounter++;
+
+ if (MAJORA_GET_TYPE(&this->actor) == MAJORA_TYPE_PROJECTILE_REMAINS) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_FOLLOWERS_BEAM - SFX_FLAG);
+ }
+
+ if (KREG(63) == 0) {
+ Actor_SetScale(&this->actor, 3.5f);
+
+ if (this->subAction == PROJECTILE_SUB_ACTION_SPAWN) {
+ dx = player->actor.world.pos.x - this->actor.world.pos.x;
+ dy = player->actor.world.pos.y - this->actor.world.pos.y + 20.0f;
+ dz = player->actor.world.pos.z - this->actor.world.pos.z;
+
+ this->actor.world.rot.y = Math_Atan2S(dx, dz);
+ distToPlayerXZ = sqrtf(SQ(dx) + SQ(dz));
+ this->actor.world.rot.x = Math_Atan2S(dy, distToPlayerXZ);
+ this->subAction = PROJECTILE_SUB_ACTION_FLY;
+ this->actor.speed = 30.0f;
+ Actor_ChangeCategory(play, &play->actorCtx, &this->actor, ACTORCAT_ENEMY);
+ if (MAJORA_GET_TYPE(&this->actor) == MAJORA_TYPE_PROJECTILE_INCARNATION) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST2_FIRE_OLD);
+ }
+ }
+
+ for (i = 0; i < ARRAY_COUNT(this->timers); i++) {
+ DECR(this->timers[i]);
+ }
+
+ Actor_UpdateVelocityWithoutGravity(&this->actor);
+ Actor_UpdatePos(&this->actor);
+ Actor_UpdateBgCheckInfo(play, &this->actor, 50.0f, 31.0f, 100.0f,
+ UPDBGCHECKINFO_FLAG_1 | UPDBGCHECKINFO_FLAG_2 | UPDBGCHECKINFO_FLAG_4);
+ this->actor.shape.rot.z += 0x1200;
+
+ if ((this->actor.bgCheckFlags & (BGCHECKFLAG_GROUND | BGCHECKFLAG_WALL | BGCHECKFLAG_CEILING)) ||
+ (this->generalCollider.base.atFlags & AT_HIT) || (this->generalCollider.base.atFlags & AT_HIT) ||
+ sKillAllProjectiles) {
+ Actor_Kill(&this->actor);
+ Actor_Spawn(&play->actorCtx, play, ACTOR_EN_CLEAR_TAG, this->actor.world.pos.x, this->actor.world.pos.y,
+ this->actor.world.pos.z, 0, 0, this->projectileColorIndex,
+ CLEAR_TAG_PARAMS(CLEAR_TAG_SMALL_LIGHT_RAYS));
+ }
+
+ Collider_UpdateCylinder(&this->actor, &this->generalCollider);
+ CollisionCheck_SetAT(play, &play->colChkCtx, &this->generalCollider.base);
+ CollisionCheck_SetAC(play, &play->colChkCtx, &this->generalCollider.base);
+ }
+}
+
+void Boss07_Projectile_Draw(Actor* thisx, PlayState* play2) {
+ PlayState* play = play2;
+ Boss07* this = THIS;
+
+ OPEN_DISPS(play->state.gfxCtx);
+
+ Gfx_SetupDL25_Xlu(play->state.gfxCtx);
+ gDPPipeSync(POLY_XLU_DISP++);
+ gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, sProjectilePrimColors[this->projectileColorIndex][0],
+ sProjectilePrimColors[this->projectileColorIndex][1],
+ sProjectilePrimColors[this->projectileColorIndex][2], 255);
+ gDPSetEnvColor(POLY_XLU_DISP++, sProjectileEnvColors[this->projectileColorIndex][0],
+ sProjectileEnvColors[this->projectileColorIndex][1],
+ sProjectileEnvColors[this->projectileColorIndex][2], 128);
+ Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, MTXMODE_NEW);
+ Matrix_Scale(this->actor.scale.x, this->actor.scale.y, 0.0f, MTXMODE_APPLY);
+ Matrix_ReplaceRotation(&play->billboardMtxF);
+ Matrix_RotateZS(this->actor.shape.rot.z, MTXMODE_APPLY);
+ MATRIX_FINALIZE_AND_LOAD(POLY_XLU_DISP++, play->state.gfxCtx);
+ gSPDisplayList(POLY_XLU_DISP++, gLightOrbMaterial1DL);
+ gSPDisplayList(POLY_XLU_DISP++, gLightOrbModelDL);
+
+ CLOSE_DISPS(play->state.gfxCtx);
+}
+
+void Boss07_Remains_UpdateDamage(Boss07* this, PlayState* play) {
+ Vec3f knockbackMovement;
+ ColliderElement* acHitElem;
+
+ if ((this->damagedTimer == 0) && (this->generalCollider.base.acFlags & AC_HIT)) {
+ this->generalCollider.base.acFlags &= ~AC_HIT;
+ this->damagedTimer = 15;
+ acHitElem = this->generalCollider.elem.acHitElem;
+
+ //! @bug The hookshot has a damage effect of 0 (`REMAINS_DMGEFF_IMMUNE`) and a damage value of 0; due to
+ //! `CollisionCheck_SetATvsAC`, the hookshot passes through the remains. In other words, it's impossible for the
+ //! following check to be true in the final game because the hookshot can't even register a hit.
+ if (acHitElem->atDmgInfo.dmgFlags & DMG_HOOKSHOT) {
+ Boss07_Remains_SetupStunned(this, play);
+ } else {
+ u8 damage = this->actor.colChkInfo.damage;
+
+ this->actor.colChkInfo.health -= damage;
+ this->damagedFlashTimer = 15;
+ this->actionFunc = Boss07_Remains_Move;
+
+ if ((s8)this->actor.colChkInfo.health <= 0) {
+ this->subAction = REMAINS_MOVE_SUB_ACTION_DIE;
+ this->burnOnLanding = true;
+ Enemy_StartFinishingBlow(play, &this->actor);
+ Actor_PlaySfx(&this->actor, NA_SE_EN_FOLLOWERS_DEAD);
+ } else {
+ this->subAction = REMAINS_MOVE_SUB_ACTION_DAMAGED;
+ this->timers[0] = 15;
+ Boss07_Remains_PlayDamageSfx(this);
+ }
+
+ Matrix_RotateYS(this->actor.yawTowardsPlayer, MTXMODE_NEW);
+ Matrix_MultVecZ(-20.0f, &knockbackMovement);
+ this->knockbackMovementX = knockbackMovement.x;
+ this->knockbackMovementZ = knockbackMovement.z;
+ }
+ }
+}
+
+void Boss07_Remains_SetupIntroCutscene(Boss07* this, PlayState* play) {
+ this->actionFunc = Boss07_Remains_IntroCutscene;
+}
+
+void Boss07_Remains_IntroCutscene(Boss07* this, PlayState* play) {
+ f32 dx;
+ f32 dy;
+ f32 dz;
+ f32 yOffset;
+ s32 pad;
+ f32 speedToTargetTarget;
+ f32 speedToTargetMaxStep;
+ f32 speedTarget;
+ f32 speedMaxStep;
+ s16 targetRotX;
+ s16 targetRotY;
+ Player* player = GET_PLAYER(play);
+
+ switch (this->subAction) {
+ case REMAINS_INTRO_CS_SUB_ACTION_WAIT:
+ Actor_SetScale(&this->actor, 0.0f);
+ this->actor.world.pos.x = player->actor.world.pos.x;
+ this->actor.world.pos.y = player->actor.world.pos.y + 30.0f;
+ this->actor.world.pos.z = player->actor.world.pos.z;
+
+ if (player->transformation == PLAYER_FORM_FIERCE_DEITY) {
+ this->actor.world.pos.y += 30.0f + KREG(48);
+ }
+
+ this->targetPos.x = sRemainsStartTargetOffset[MAJORA_GET_TYPE(&this->actor) - MAJORA_TYPE_REMAINS].x +
+ player->actor.world.pos.x;
+ this->targetPos.y = sRemainsStartTargetOffset[MAJORA_GET_TYPE(&this->actor) - MAJORA_TYPE_REMAINS].y +
+ player->actor.world.pos.y;
+ this->targetPos.z = sRemainsStartTargetOffset[MAJORA_GET_TYPE(&this->actor) - MAJORA_TYPE_REMAINS].z +
+ player->actor.world.pos.z;
+
+ dx = this->targetPos.x - this->actor.world.pos.x;
+ dy = this->targetPos.y - this->actor.world.pos.y;
+ dz = this->targetPos.z - this->actor.world.pos.z;
+ this->actor.world.rot.y = Math_Atan2S(dx, dz);
+ this->actor.world.rot.x = Math_Atan2S(dy, sqrtf(SQ(dx) + SQ(dz)));
+ this->miscTimer = Rand_ZeroFloat(100.0f);
+ break;
+
+ case REMAINS_INTRO_CS_SUB_ACTION_FLY:
+ this->cutsceneTimer++;
+ this->miscTimer++;
+ this->introRemainsOrbRot += 0x200;
+ Math_ApproachF(&this->eyeBeamsLengthScale, 1.2f, 1.0f, 0.1f);
+ Math_ApproachF(&this->actor.scale.x, 0.004f, 0.5f, 0.0002f);
+ this->actor.scale.y = this->actor.scale.z = this->actor.scale.x;
+
+ if (this->cutsceneTimer > 90) {
+ this->targetPos.x = sRemainsEndTarget[MAJORA_GET_TYPE(&this->actor) - MAJORA_TYPE_REMAINS].x;
+ this->targetPos.y = 370.0f;
+ this->targetPos.z = sRemainsEndTarget[MAJORA_GET_TYPE(&this->actor) - MAJORA_TYPE_REMAINS].z;
+ speedTarget = 20.0f;
+ speedMaxStep = 0.5f;
+ speedToTargetTarget = 0x1000;
+ speedToTargetMaxStep = 0x190;
+ yOffset = 0.0f;
+ } else {
+ yOffset = Math_SinS(this->miscTimer * 0x300) * 20.0f;
+ speedTarget = 1.0f;
+ speedMaxStep = 0.1f;
+ speedToTargetTarget = 0x5DC;
+ speedToTargetMaxStep = 0x64;
+ }
+
+ dx = this->targetPos.x - this->actor.world.pos.x;
+ dy = this->targetPos.y - this->actor.world.pos.y + yOffset;
+ dz = this->targetPos.z - this->actor.world.pos.z;
+ targetRotY = Math_Atan2S(dx, dz);
+ targetRotX = Math_Atan2S(dy, sqrtf(SQ(dx) + SQ(dz)));
+ Math_ApproachS(&this->actor.world.rot.y, targetRotY, 5, this->speedToTarget);
+ Math_ApproachS(&this->actor.world.rot.x, targetRotX, 5, this->speedToTarget);
+ Math_ApproachF(&this->speedToTarget, speedToTargetTarget, 1.0f, speedToTargetMaxStep);
+ Math_ApproachF(&this->actor.speed, speedTarget, 1.0f, speedMaxStep);
+ Actor_UpdateVelocityWithoutGravity(&this->actor);
+ Actor_UpdatePos(&this->actor);
+ this->actor.shape.rot = this->actor.world.rot;
+ break;
+
+ case REMAINS_INTRO_CS_SUB_ACTION_ATTACH_WAIT:
+ Actor_SetScale(&this->actor, 0.0f);
+ this->eyeBeamsLengthScale = 0.0f;
+ this->actor.speed = 0.0f;
+ this->actor.world.pos.x = sRemainsEndTarget[MAJORA_GET_TYPE(&this->actor) - MAJORA_TYPE_REMAINS].x * 0.6f;
+ this->actor.world.pos.y = 370.0f;
+ this->actor.world.pos.z = sRemainsEndTarget[MAJORA_GET_TYPE(&this->actor) - MAJORA_TYPE_REMAINS].z * 0.6f;
+ this->actor.shape.rot.y = sRemainsEndTarget[MAJORA_GET_TYPE(&this->actor) - MAJORA_TYPE_REMAINS].y;
+ this->sfxTimer = 0;
+ break;
+
+ case REMAINS_INTRO_CS_SUB_ACTION_ATTACH_TO_WALL:
+ this->sfxTimer++;
+ if (this->sfxTimer == 10) {
+ Actor_PlaySfx(&this->actor, NA_SE_EN_FOLLOWERS_STAY);
+ }
+
+ Actor_SetScale(&this->actor, 0.03f);
+ Math_ApproachF(&this->actor.world.pos.x,
+ sRemainsEndTarget[MAJORA_GET_TYPE(&this->actor) - MAJORA_TYPE_REMAINS].x, 0.5f, 40.0f);
+ Math_ApproachF(&this->actor.world.pos.z,
+ sRemainsEndTarget[MAJORA_GET_TYPE(&this->actor) - MAJORA_TYPE_REMAINS].z, 0.5f, 22.0f);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Boss07_Remains_SetupMove(Boss07* this, PlayState* play) {
+ this->actionFunc = Boss07_Remains_Move;
+ this->actor.gravity = -0.75f;
+ ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 40.0f);
+ Collider_InitAndSetCylinder(play, &this->generalCollider, &this->actor, &sRemainsCylinderInit);
+ this->actor.colChkInfo.health = 5;
+ this->subAction = REMAINS_MOVE_SUB_ACTION_WAIT;
+}
+
+void Boss07_Remains_Move(Boss07* this, PlayState* play) {
+ s16 targetRotX;
+ s16 targetRotY;
+ f32 dx;
+ f32 dy;
+ f32 dz;
+ s32 pad;
+
+ switch (this->subAction) {
+ case REMAINS_MOVE_SUB_ACTION_DETACH_FROM_WALL:
+ Actor_PlaySfx(&this->actor, NA_SE_EV_MUJURA_FOLLOWERS_FLY - SFX_FLAG);
+ this->timers[0] = 80;
+ this->timers[2] = 100.0f + Rand_ZeroFloat(100.0f);
+ this->flySpeedTarget = 5.0f;
+ this->actor.speed = 5.0f;
+ this->targetPos = gZeroVec3f;
+ this->actor.world.rot.y = Math_Atan2S(-this->actor.world.pos.x, -this->actor.world.pos.z);
+ this->subAction = REMAINS_MOVE_SUB_ACTION_FLY;
+ this->bgCheckTimer = 100;
+ this->generalCollider.base.colMaterial = COL_MATERIAL_HIT3;
+ this->actor.flags |= (ACTOR_FLAG_ATTENTION_ENABLED | ACTOR_FLAG_HOOKSHOT_PULLS_ACTOR);
+ Actor_PlaySfx(&this->actor, NA_SE_EN_LAST1_DEMO_BREAK);
+ break;
+
+ case REMAINS_MOVE_SUB_ACTION_FLY:
+ Actor_PlaySfx(&this->actor, NA_SE_EV_MUJURA_FOLLOWERS_FLY - SFX_FLAG);
+ if (this->timers[2] == 0) {
+ this->tryFireProjectile = true;
+ this->timers[2] = Rand_ZeroFloat(200.0f) + 100.0f;
+ }
+
+ if (this->timers[0] == 0) {
+ if (Rand_ZeroOne() < 0.35f) {
+ this->flySpeedTarget = 1.0f;
+ this->timers[0] = Rand_ZeroFloat(50.0f) + 30.0f;
+ } else {
+ Boss07_RandXZ(&this->targetPos, 500.0f);
+ this->targetPos.y = Rand_ZeroFloat(350.0f) + 100.0f;
+ this->timers[0] = Rand_ZeroFloat(50.0f) + 20.0f;
+ this->speedToTarget = 0.0f;
+ this->flySpeedTarget = Rand_ZeroFloat(5.0f) + 5.0f;
+ }
+ }
+
+ dx = this->targetPos.x - this->actor.world.pos.x;
+ dy = this->targetPos.y - this->actor.world.pos.y;
+ dz = this->targetPos.z - this->actor.world.pos.z;
+ targetRotY = Math_Atan2S(dx, dz);
+ targetRotX = Math_Atan2S(dy, sqrtf(SQ(dx) + SQ(dz)));
+ targetRotX += (s16)(Math_SinS(this->frameCounter * 0x1388) * 0xFA0);
+
+ Math_ApproachS(&this->actor.world.rot.y, targetRotY, 0xA, this->speedToTarget);
+ Math_ApproachS(&this->actor.world.rot.x, targetRotX, 5, this->speedToTarget);
+ Math_ApproachF(&this->speedToTarget, 0x7D0, 1.0f, 0x64);
+ Math_ApproachF(&this->actor.speed, this->flySpeedTarget, 1.0f, 1.0f);
+
+ if ((this->flySpeedTarget < 8.0f) && !Play_InCsMode(play)) {
+ Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 0xA, 0x1000);
+ } else {
+ Math_ApproachS(&this->actor.shape.rot.y, this->actor.world.rot.y, 0xA, 0x1000);
+ }
+
+ Actor_UpdateVelocityWithoutGravity(&this->actor);
+ Actor_UpdatePos(&this->actor);
+
+ if (this->bgCheckTimer == 0) {
+ Actor_UpdateBgCheckInfo(play, &this->actor, 50.0f, 100.0f, 100,
+ UPDBGCHECKINFO_FLAG_1 | UPDBGCHECKINFO_FLAG_4);
+ } else {
+ this->bgCheckTimer--;
+ }
+
+ Boss07_Remains_UpdateDamage(this, play);
+ break;
+
+ case REMAINS_MOVE_SUB_ACTION_DIE:
+ Math_ApproachS(&this->actor.shape.rot.x, -0x4000, 1, 0x500);
+ Actor_MoveWithGravity(&this->actor);
+ Actor_UpdateBgCheckInfo(play, &this->actor, 50.0f, 100.0f, 100.0f,
+ UPDBGCHECKINFO_FLAG_1 | UPDBGCHECKINFO_FLAG_4);
+
+ if (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND) {
+ if (this->burnOnLanding) {
+ this->fireTimer |= 4;
+ }
+
+ Math_ApproachF(&this->actor.scale.z, 0.0f, 1.0f, 0.001f);
+
+ if (this->actor.scale.z == 0.0f) {
+ this->subAction = REMAINS_MOVE_SUB_ACTION_DEAD;
+ this->actor.draw = NULL;
+ this->actor.flags &= ~ACTOR_FLAG_ATTENTION_ENABLED;
+ }
+
+ Boss07_SmoothStop(this, 2.0f);
+ } else {
+ this->actor.shape.rot.z += 0x200;
+ }
+ break;
+
+ case REMAINS_MOVE_SUB_ACTION_DAMAGED:
+ Actor_MoveWithGravity(&this->actor);
+ this->actor.world.pos.y -= 50.0f;
+ this->actor.prevPos.y -= 50.0f;
+
+ Actor_UpdateBgCheckInfo(play, &this->actor, 35.0f, 60.0f, 60.0f,
+ UPDBGCHECKINFO_FLAG_1 | UPDBGCHECKINFO_FLAG_4);
+
+ this->actor.world.pos.y += 50.0f;
+ this->actor.prevPos.y += 50.0f;
+
+ if (this->timers[0] == 0) {
+ this->subAction = REMAINS_MOVE_SUB_ACTION_FLY;
+ }
+ break;
+
+ case REMAINS_MOVE_SUB_ACTION_WAIT:
+ default:
+ break;
+ }
+
+ if (this->subAction < REMAINS_MOVE_SUB_ACTION_DIE) {
+ Collider_UpdateCylinder(&this->actor, &this->generalCollider);
+ CollisionCheck_SetAC(play, &play->colChkCtx, &this->generalCollider.base);
+ CollisionCheck_SetAT(play, &play->colChkCtx, &this->generalCollider.base);
+ }
+
+ if (this->tryFireProjectile) {
+ this->tryFireProjectile = false;
+
+ if (Boss07_ArePlayerAndActorFacing(this, play) && (sMajorasMask->actionFunc != Boss07_Mask_FireBeam)) {
+ Actor_Spawn(&play->actorCtx, play, ACTOR_BOSS_07, this->actor.world.pos.x, this->actor.world.pos.y,
+ this->actor.world.pos.z, 0, 0, 0, MAJORA_PARAMS(MAJORA_TYPE_PROJECTILE_REMAINS));
+ }
+ }
+
+ if (this->fireTimer != 0) {
+ Vec3f flamePos;
+ Vec3f flameVelocity;
+ Vec3f flameAccel;
+
+ flamePos.x = Rand_CenteredFloat(80.0f) + this->actor.world.pos.x;
+ flamePos.z = Rand_CenteredFloat(80.0f) + this->actor.world.pos.z;
+
+ if (this->burnOnLanding) {
+ flameAccel.x = flameAccel.z = 0.0f;
+ flameAccel.y = 0.03f;
+ flamePos.y = Rand_ZeroFloat(10.0f) + this->actor.world.pos.y;
+ EffectSsKFire_Spawn(play, &flamePos, &gZeroVec3f, &flameAccel, Rand_ZeroFloat(30.0f) + 30.0f, 0);
+ Actor_PlaySfx(&this->actor, NA_SE_EN_COMMON_EXTINCT_LEV - SFX_FLAG);
+ } else {
+ flamePos.y = (Rand_ZeroFloat(30.0f) + this->actor.world.pos.y) - 15.0f;
+
+ flameVelocity.x = 0.0f;
+ flameVelocity.y = 5.0f;
+ flameVelocity.z = 0.0f;
+
+ flameAccel.x = flameVelocity.x * -0.05f;
+ flameAccel.y = flameVelocity.y * -0.05f;
+ flameAccel.z = flameVelocity.z * -0.05f;
+
+ Boss07_SpawnFlameEffect(play, &flamePos, &flameVelocity, &flameAccel, Rand_ZeroFloat(10.0f) + 25.0f);
+ Actor_PlaySfx(&this->actor, NA_SE_EV_BURN_OUT - SFX_FLAG);
+ }
+ }
+}
+
+void Boss07_Remains_SetupStunned(Boss07* this, PlayState* play) {
+ this->actionFunc = Boss07_Remains_Stunned;
+ this->timers[0] = 50;
+ this->actor.speed = 0.0f;
+}
+
+void Boss07_Remains_Stunned(Boss07* this, PlayState* play) {
+ Boss07_Remains_UpdateDamage(this, play);
+ Collider_UpdateCylinder(&this->actor, &this->generalCollider);
+ CollisionCheck_SetAC(play, &play->colChkCtx, &this->generalCollider.base);
+ CollisionCheck_SetOC(play, &play->colChkCtx, &this->generalCollider.base);
+
+ if (this->timers[0] == 0) {
+ this->actionFunc = Boss07_Remains_Move;
+ this->subAction = REMAINS_MOVE_SUB_ACTION_FLY;
+ }
+}
+
+void Boss07_Remains_Update(Actor* thisx, PlayState* play2) {
+ PlayState* play = play2;
+ Boss07* this = THIS;
+ s32 i;
+
+ this->frameCounter++;
+
+ for (i = 0; i < ARRAY_COUNT(this->timers); i++) {
+ DECR(this->timers[i]);
+ }
+
+ DECR(this->fireTimer);
+ DECR(this->damagedTimer);
+ DECR(this->damagedFlashTimer);
+
+ this->actionFunc(this, play);
+
+ this->actor.focus.pos = this->actor.world.pos;
+ this->actor.world.pos.x += this->knockbackMovementX;
+ this->actor.world.pos.z += this->knockbackMovementZ;
+
+ Math_ApproachZeroF(&this->knockbackMovementX, 1.0f, 1.0f);
+ Math_ApproachZeroF(&this->knockbackMovementZ, 1.0f, 1.0f);
+}
+
+void Boss07_Remains_Draw(Actor* thisx, PlayState* play2) {
+ PlayState* play = play2;
+ Boss07* this = THIS;
+ f32 shakeScale;
+ f32 rotX;
+ s32 pad;
+
+ OPEN_DISPS(play->state.gfxCtx);
+
+ Gfx_SetupDL25_Opa(play->state.gfxCtx);
+
+ if ((this->damagedFlashTimer % 2) != 0) {
+ POLY_OPA_DISP = Gfx_SetFog(POLY_OPA_DISP, 255, 0, 0, 255, 900, 1099);
+ }
+
+ shakeScale = this->damagedTimer * (M_PIf / 4.0f) * 0.06666667f;
+ rotX = Math_SinS(this->damagedTimer * 0x3500) * shakeScale * 0.5f;
+ Matrix_RotateYF(Math_SinS(this->damagedTimer * 0x4500) * shakeScale, MTXMODE_APPLY);
+ Matrix_RotateXFApply(rotX);
+ MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, play->state.gfxCtx);
+
+ switch (MAJORA_GET_TYPE(&this->actor)) {
+ case MAJORA_TYPE_REMAINS + MAJORA_REMAINS_TYPE_ODOLWA:
+ gSPDisplayList(POLY_OPA_DISP++, gBossMaskOdolwaDL);
+ break;
+
+ case MAJORA_TYPE_REMAINS + MAJORA_REMAINS_TYPE_GYORG:
+ gSPDisplayList(POLY_OPA_DISP++, gBossMaskGyorgDL);
+ break;
+
+ case MAJORA_TYPE_REMAINS + MAJORA_REMAINS_TYPE_GOHT:
+ gSPDisplayList(POLY_OPA_DISP++, gBossMaskGohtDL);
+ break;
+
+ case MAJORA_TYPE_REMAINS + MAJORA_REMAINS_TYPE_TWINMOLD:
+ gSPDisplayList(POLY_OPA_DISP++, gBossMaskTwinmoldDL);
+ break;
+
+ default:
+ break;
+ }
+
+ POLY_OPA_DISP = Play_SetFog(play, POLY_OPA_DISP);
+
+ if (this->actionFunc == Boss07_Remains_IntroCutscene) {
+ gDPPipeSync(POLY_XLU_DISP++);
+ gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 200, 200);
+ gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 100, 128);
+
+ Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, MTXMODE_NEW);
+ Matrix_Scale(this->eyeBeamsLengthScale, this->eyeBeamsLengthScale, 0.0f, MTXMODE_APPLY);
+ Matrix_ReplaceRotation(&play->billboardMtxF);
+ Matrix_RotateZS(this->introRemainsOrbRot, MTXMODE_APPLY);
+ MATRIX_FINALIZE_AND_LOAD(POLY_XLU_DISP++, play->state.gfxCtx);
+ gSPDisplayList(POLY_XLU_DISP++, gLightOrbMaterial1DL);
+ gSPDisplayList(POLY_XLU_DISP++, gLightOrbModelDL);
+ }
+
+ CLOSE_DISPS(play->state.gfxCtx);
+}
+
+void Boss07_Top_SetupThrown(Boss07* this, PlayState* play) {
+ this->actionFunc = Boss07_Top_Thrown;
+ this->actor.gravity = 0.0f;
+ this->topSpinAngularVelocity = (sREG(42) * 0.01f) + 0.9f;
+ this->timers[0] = 200;
+}
+
+void Boss07_Top_Thrown(Boss07* this, PlayState* play) {
+ if (sMajorasWrath->actionFunc == Boss07_Wrath_ThrowTop) {
+ Math_Vec3f_Copy(&this->actor.world.pos, &sMajorasWrath->whipGrabPos);
+ this->actor.world.pos.y -= 25.0f + sREG(78);
+ }
+
+ Actor_UpdateBgCheckInfo(play, &this->actor, 40.0f, 50.0f, 80.0f, UPDBGCHECKINFO_FLAG_1);
+
+ if ((sMajorasWrath->frameCounter >= (s16)(KREG(50) + 21)) || (sMajorasWrath->damagedTimer != 0)) {
+ Boss07_Top_SetupMove(this, play);
+ } else if (this->actor.bgCheckFlags & BGCHECKFLAG_WALL) {
+ Boss07_Top_SetupMove(this, play);
+ this->actor.speed = -15.0f;
+ CollisionCheck_SpawnShieldParticles(play, &this->actor.focus.pos);
+ Actor_PlaySfx(&this->actor, NA_SE_IT_SHIELD_REFLECT_SW);
+ }
+}
+
+void Boss07_Top_SetupMove(Boss07* this, PlayState* play) {
+ this->actionFunc = Boss07_Top_Move;
+ this->actor.gravity = -2.0f;
+
+ if (sMajorasWrath->damagedTimer != 0) {
+ this->timers[0] = sREG(47) + 80;
+ this->timers[1] = sREG(77) + 150;
+ } else {
+ this->timers[0] = sREG(47) + 300;
+ this->timers[1] = sREG(77) + 370;
+ this->actor.velocity.y = (sREG(43) * 0.1f) + 15.0f;
+ this->actor.speed = (sREG(44) * 0.1f) + -3.0f;
+ }
+
+ this->actor.world.rot.y = (sREG(45) * 0x1000) + sMajorasWrath->actor.shape.rot.y;
+ this->actor.shape.rot.z = Rand_ZeroFloat((f32)(sREG(29) + 10) * 0x100);
+}
+
+void Boss07_Top_Move(Boss07* this, PlayState* play) {
+ f32 dx;
+ f32 dz;
+
+ Audio_PlaySfx_AtPosWithFreq(&this->actor.projectedPos, NA_SE_EN_LAST3_KOMA_OLD - SFX_FLAG,
+ this->topSpinAngularVelocity * 1.1111112f);
+ Actor_MoveWithGravity(&this->actor);
+ this->actor.world.pos.x += this->knockbackMovementX;
+ this->actor.world.pos.z += this->knockbackMovementZ;
+ Actor_UpdateBgCheckInfo(play, &this->actor, 40.0f, 40.0f, 80.0f, UPDBGCHECKINFO_FLAG_1 | UPDBGCHECKINFO_FLAG_4);
+
+ if ((this->disableCollisionTimer == 0) && (this->actor.bgCheckFlags & BGCHECKFLAG_WALL)) {
+ this->disableCollisionTimer = 10;
+ if (this->topSpinAngularVelocity > 0.01f) {
+ if (this->topSpinAngularVelocity < 0.45f) {
+ this->actor.speed *= -1.0f;
+ } else {
+ this->actor.speed = -10.0f;
+ }
+
+ CollisionCheck_SpawnShieldParticles(play, &this->actor.focus.pos);
+ Actor_PlaySfx(&this->actor, NA_SE_IT_SHIELD_REFLECT_SW);
+ }
+ }
+
+ if (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND) {
+ if (this->timers[0] < (s16)(sREG(24) + 70)) {
+ if (this->timers[0] >= (s16)(sREG(25) + 35)) {
+ Math_ApproachZeroF(&this->actor.speed, 1.0f, (sREG(17) * 0.01f) + 0.1f);
+ Math_ApproachS(&this->actor.shape.rot.z, (sREG(19) * 0x800) + 0x2000, 1, sREG(18) + 0x1A0);
+ Math_ApproachZeroF(&this->topSpinAngularVelocity, 1.0f, (sREG(16) * 0.0001f) + 0.005f);
+ Math_ApproachS(&this->topPrecessionVelocity, (sREG(20) * 0x800) + 0x2000, 1, (sREG(21) * 16) + 0xC0);
+ } else if (this->timers[0] == 0) {
+ Math_ApproachZeroF(&this->actor.speed, 1.0f, (sREG(26) * 0.01f) + 0.5f);
+ Math_ApproachS(&this->actor.shape.rot.z, (sREG(19) * 0x800) + 0x2000, 1, 0x800);
+ Math_ApproachZeroF(&this->topSpinAngularVelocity, 1.0f, (sREG(27) * 0.001f) + 0.024f);
+ Math_ApproachS(&this->topPrecessionVelocity, 0, 2, sREG(28) + 106);
+ } else {
+ Math_ApproachF(&this->actor.speed, sREG(22) + 10.0f, 1.0f, (sREG(23) * 0.01f) + 0.6f);
+ Math_ApproachS(&this->actor.shape.rot.z, (sREG(19) * 0x800) + 0x2000, 1, sREG(18) + 0x410);
+ Math_ApproachZeroF(&this->topSpinAngularVelocity, 1.0f, (sREG(16) * 0.0001f) + 0.005f);
+ Math_ApproachS(&this->topPrecessionVelocity, (sREG(29) * 0x800) - 0x800, 1, (sREG(30) * 16) + 0x340);
+ }
+
+ this->actor.world.rot.y += this->topPrecessionVelocity;
+ } else {
+ Math_ApproachS(&this->actor.world.rot.y, this->actor.yawTowardsPlayer, 0xA, 0x300);
+ Math_ApproachF(&this->actor.speed, (sREG(48) * 0.1f) + 2.0f + 8.0f, 1.0f,
+ (sREG(46) * 0.01f) + 0.100000024f + 0.2f);
+ }
+
+ Math_ApproachZeroF(&this->knockbackMovementX, 1.0f, 1.0f);
+ Math_ApproachZeroF(&this->knockbackMovementZ, 1.0f, 1.0f);
+
+ if (this->actor.velocity.y < (sREG(40) + -2.0f)) {
+ this->actor.velocity.y *= -(0.5f + (sREG(41) * 0.01f));
+ Actor_PlaySfx(&this->actor, NA_SE_IT_SHIELD_REFLECT_SW);
+ CollisionCheck_SpawnShieldParticles(play, &this->actor.world.pos);
+ this->actor.speed *= 0.5f + (sREG(57) * 0.01f);
+ } else {
+ this->actor.velocity.y = -0.5f;
+ }
+
+ dx = this->actor.prevPos.x - this->actor.world.pos.x;
+ dz = this->actor.prevPos.z - this->actor.world.pos.z;
+ func_800AE930(&play->colCtx, Effect_GetByIndex(this->effectIndex), &this->actor.world.pos, 3.0f,
+ Math_Atan2S(dx, dz), this->actor.floorPoly, this->actor.floorBgId);
+ this->subAction = TOP_MOVE_SUB_ACTION_GROUNDED;
+ } else if (this->subAction != TOP_MOVE_SUB_ACTION_AIRBORNE) {
+ this->subAction = TOP_MOVE_SUB_ACTION_AIRBORNE;
+ func_800AEF44(Effect_GetByIndex(this->effectIndex));
+ }
+
+ this->actor.shape.rot.y = this->actor.world.rot.y;
+
+ if (this->timers[1] == 0) {
+ EnBom* bomb =
+ (EnBom*)Actor_Spawn(&play->actorCtx, play, ACTOR_EN_BOM, this->actor.world.pos.x,
+ this->actor.world.pos.y + 25.0f, this->actor.world.pos.z, 0, 0, 0, BOMB_TYPE_BODY);
+
+ if (bomb != NULL) {
+ bomb->timer = 0;
+ }
+
+ Actor_Kill(&this->actor);
+ } else if (this->timers[1] == 25) {
+ this->damagedFlashTimer = 25;
+ Actor_ChangeCategory(play, &play->actorCtx, &this->actor, ACTORCAT_EXPLOSIVES);
+ }
+}
+
+void Boss07_Top_CheckTopCollision(Boss07* this, PlayState* play) {
+ s32 i;
+ Boss07* top;
+ f32 dx;
+ f32 dy;
+ f32 dz;
+
+ if (this->disableCollisionTimer == 0) {
+ for (top = (Boss07*)play->actorCtx.actorLists[ACTORCAT_BOSS].first; top != NULL;
+ top = (Boss07*)top->actor.next) {
+ if ((this != top) && (MAJORA_GET_TYPE(&top->actor) == MAJORA_TYPE_TOP) &&
+ (top->disableCollisionTimer == 0)) {
+ dx = top->actor.world.pos.x - this->actor.world.pos.x;
+ dy = top->actor.world.pos.y - this->actor.world.pos.y;
+ dz = top->actor.world.pos.z - this->actor.world.pos.z;
+
+ if (sqrtf(SQ(dx) + SQ(dy) + SQ(dz)) < (sREG(28) + 50.0f)) {
+ top->disableCollisionTimer = this->disableCollisionTimer = 10;
+ this->actor.world.rot.y = Math_Atan2S(dx, dz);
+ top->actor.world.rot.y = this->actor.world.rot.y + 0x7FFF;
+
+ if (this->timers[0] > 0) {
+ this->actor.speed = -10.0f;
+ } else {
+ this->actor.speed = -5.0f;
+ this->topSpinAngularVelocity = (sREG(89) * 0.01f) + 0.2f;
+ this->topPrecessionVelocity = 0x800;
+ }
+
+ if (top->timers[0] > 0) {
+ top->actor.speed = -10.0f;
+ } else {
+ top->actor.speed = -5.0f;
+ top->topSpinAngularVelocity = (sREG(89) * 0.01f) + 0.2f;
+ top->topPrecessionVelocity = 0x800;
+ }
+
+ CollisionCheck_SpawnShieldParticles(play, &this->actor.focus.pos);
+ CollisionCheck_SpawnShieldParticles(play, &top->actor.focus.pos);
+
+ if (this->timers[0] > 80) {
+ this->actor.shape.rot.z = Rand_CenteredFloat((f32)(sREG(29) + 20) * 0x100);
+ for (i = 0; i < 5; i++) {
+ DECR(this->timers[0]);
+ DECR(this->timers[1]);
+ }
+ }
+
+ if (top->timers[0] > 80) {
+ top->actor.shape.rot.z = Rand_CenteredFloat((f32)(sREG(29) + 20) * 0x100);
+ for (i = 0; i < 5; i++) {
+ DECR(top->timers[0]);
+ DECR(top->timers[1]);
+ }
+ }
+
+ Actor_PlaySfx(&this->actor, NA_SE_IT_SHIELD_REFLECT_SW);
+ break;
+ }
+ }
+ }
+ }
+}
+
+void Boss07_Top_UpdateDamage(Boss07* this, PlayState* play) {
+ PlayerImpactType playerImpactType;
+ s32 hit = false;
+ Player* player = GET_PLAYER(play);
+ s32 pad[3];
+
+ if (this->generalCollider.base.acFlags & AC_HIT) {
+ this->generalCollider.base.acFlags &= ~AC_HIT;
+
+ if (this->damagedTimer == 0) {
+ this->damagedTimer = 5;
+
+ if ((this->actor.colChkInfo.damageEffect == TOP_DMGEFF_PUSH_BACK_PLAYER) ||
+ (this->actor.colChkInfo.damageEffect == TOP_DMGEFF_REVERSE_DIRECTION)) {
+ if (this->actor.colChkInfo.damageEffect == TOP_DMGEFF_PUSH_BACK_PLAYER) {
+ player->pushedYaw = this->actor.yawTowardsPlayer;
+ player->pushedSpeed = 20.0f;
+ }
+
+ if (this->timers[0] > 40) {
+ this->actor.world.rot.y = this->actor.yawTowardsPlayer;
+
+ if (player->transformation == PLAYER_FORM_FIERCE_DEITY) {
+ this->actor.speed = -30.0f;
+ this->actor.velocity.y = 10.0f;
+
+ if ((s16)(sREG(47) + 100) < this->timers[0]) {
+ this->timers[0] = sREG(47) + 100;
+ this->timers[1] = sREG(77) + 170;
+ }
+ } else if (this->actor.colChkInfo.damageEffect == TOP_DMGEFF_REVERSE_DIRECTION) {
+ this->actor.speed = -15.0f;
+ } else {
+ this->actor.speed = -7.0f;
+ }
+ }
+ } else if (this->actor.colChkInfo.damageEffect == TOP_DMGEFF_KNOCKED_BACK_FROM_PLAYER) {
+ this->actor.world.rot.y = this->actor.yawTowardsPlayer;
+ this->actor.speed = 2.0f * -player->actor.speed;
+ hit = true;
+ } else if (this->actor.colChkInfo.damageEffect == TOP_DMGEFF_BOUNCE_BACK_FROM_DAMAGE) {
+ this->actor.world.rot.y =
+ Math_Atan2S(this->generalCollider.base.ac->world.pos.x - this->actor.world.pos.x,
+ this->generalCollider.base.ac->world.pos.z - this->actor.world.pos.z);
+ this->actor.speed = -20.0f;
+ this->actor.velocity.y = sREG(55) + 15.0f;
+ hit = true;
+ }
+ }
+ }
+
+ if (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND) {
+ if ((Actor_GetPlayerImpact(play, 5.0f, &this->actor.world.pos, &playerImpactType) >= 0.0f) &&
+ (playerImpactType == PLAYER_IMPACT_GORON_GROUND_POUND)) {
+ this->actor.world.rot.y = this->actor.yawTowardsPlayer;
+ this->actor.velocity.y = sREG(55) + 25.0f;
+ hit = true;
+ }
+ }
+
+ if (hit && (this->timers[0] > 90)) {
+ this->actor.shape.rot.z = Rand_CenteredFloat((f32)(sREG(29) + 30) * 0x100);
+ this->timers[0] = Rand_ZeroFloat(10.0f) + 70.0f;
+ this->timers[1] = this->timers[0] + 70;
+ }
+}
+
+void Boss07_Top_Update(Actor* thisx, PlayState* play2) {
+ PlayState* play = play2;
+ Boss07* this = THIS;
+
+ this->frameCounter++;
+
+ DECR(this->timers[0]);
+ DECR(this->timers[1]);
+ DECR(this->damagedFlashTimer);
+ DECR(this->damagedTimer);
+ DECR(this->disableCollisionTimer);
+
+ this->actionFunc(this, play);
+
+ Math_Vec3f_Copy(&this->actor.focus.pos, &this->actor.world.pos);
+ this->actor.focus.pos.y += 25.0f;
+ Boss07_Top_UpdateDamage(this, play);
+ Collider_UpdateCylinder(&this->actor, &this->generalCollider);
+ CollisionCheck_SetAC(play, &play->colChkCtx, &this->generalCollider.base);
+ CollisionCheck_SetAT(play, &play->colChkCtx, &this->generalCollider.base);
+ Boss07_Top_CheckTopCollision(this, play);
+
+ this->topSpinAngle -= this->topSpinAngularVelocity;
+ if (this->topSpinAngle < -2.0f * M_PIf) {
+ this->topSpinAngle += 2.0f * M_PIf;
+ }
+
+ if (sMajorasWrath->actionFunc == Boss07_Wrath_DeathCutscene) {
+ Actor_Kill(&this->actor);
+ }
+
+ Math_ApproachF(&this->actor.scale.x, (sREG(77) * 0.001f) + 0.06f, 1.0f, 0.012f);
+ Actor_SetScale(&this->actor, this->actor.scale.x);
+}
+
+void Boss07_Top_Draw(Actor* thisx, PlayState* play2) {
+ PlayState* play = play2;
+ Boss07* this = THIS;
+
+ OPEN_DISPS(play->state.gfxCtx);
+
+ Gfx_SetupDL25_Opa(play->state.gfxCtx);
+
+ if ((this->damagedFlashTimer % 2) != 0) {
+ POLY_OPA_DISP = Gfx_SetFog(POLY_OPA_DISP, 255, 0, 0, 255, 780, 1099);
+ }
+
+ Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, MTXMODE_NEW);
+ Matrix_RotateYS(this->actor.shape.rot.y, MTXMODE_APPLY);
+ Matrix_RotateZS(this->actor.shape.rot.z, MTXMODE_APPLY);
+ Matrix_RotateYF(this->topSpinAngle, MTXMODE_APPLY);
+ Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY);
+ MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, play->state.gfxCtx);
+ gSPDisplayList(POLY_OPA_DISP++, gMajorasWrathSpinningTopDL);
+ POLY_OPA_DISP = Play_SetFog(play, POLY_OPA_DISP);
+
+ CLOSE_DISPS(play->state.gfxCtx);
+}
+
+void Boss07_BattleHandler_Update(Actor* thisx, PlayState* play2) {
+ PlayState* play = play2;
+ Boss07* this = THIS;
+
+ Boss07_BattleHandler_UpdateEffects(play);
+
+ if (sHeartbeatTimer != 0) {
+ sHeartbeatTimer--;
+ Audio_PlaySfx(NA_SE_EN_LAST2_HEARTBEAT_OLD - SFX_FLAG);
+ }
+
+ if (this->lensFlareOn) {
+ gCustomLensFlare1On = true;
+ gCustomLensFlare1Pos = this->lensFlarePos;
+ D_801F4E44 = this->lensFlareScale;
+ D_801F4E48 = 10.0f;
+ D_801F4E4C = 0;
+ this->lensFlareOn = false;
+ } else {
+ gCustomLensFlare1On = false;
+ }
+
+ this->cutsceneTimer++;
+
+ switch (this->cutsceneState) {
+ case BATTLE_HANDLER_REMAINS_CS_STATE_WAITING_FOR_MAJORAS_MASK:
+ if ((sMajorasMask != NULL) && sMajorasMask->startRemainsCs) {
+ this->cutsceneState = BATTLE_HANDLER_REMAINS_CS_STATE_STARTED;
+ this->cutsceneTimer = 0;
+ }
+ break;
+
+ case BATTLE_HANDLER_REMAINS_CS_STATE_STARTED:
+ if (CutsceneManager_GetCurrentCsId() != CS_ID_NONE) {
+ break;
+ }
+
+ Cutscene_StartManual(play, &play->csCtx);
+ Player_SetCsActionWithHaltedActors(play, &this->actor, PLAYER_CSACTION_WAIT);
+ this->subCamId = Play_CreateSubCamera(play);
+ Play_ChangeCameraStatus(play, CAM_ID_MAIN, CAM_STATUS_WAIT);
+ Play_ChangeCameraStatus(play, this->subCamId, CAM_STATUS_ACTIVE);
+ this->cutsceneTimer = 0;
+ this->cutsceneState = BATTLE_HANDLER_REMAINS_CS_STATE_ACTIVATE_ODOLWA;
+ Play_EnableMotionBlur(150);
+ this->subCamEye.x = sMajoraRemains[MAJORA_REMAINS_TYPE_ODOLWA]->actor.world.pos.x * 0.7f;
+ this->subCamEye.y = sMajoraRemains[MAJORA_REMAINS_TYPE_ODOLWA]->actor.world.pos.y * 0.7f;
+ this->subCamEye.z = sMajoraRemains[MAJORA_REMAINS_TYPE_ODOLWA]->actor.world.pos.z * 0.7f;
+ FALLTHROUGH;
+ case BATTLE_HANDLER_REMAINS_CS_STATE_ACTIVATE_ODOLWA:
+ if (this->cutsceneTimer == 20) {
+ sMajoraRemains[MAJORA_REMAINS_TYPE_ODOLWA]->subAction = REMAINS_MOVE_SUB_ACTION_DETACH_FROM_WALL;
+ }
+
+ this->subCamAt.x = sMajoraRemains[MAJORA_REMAINS_TYPE_ODOLWA]->actor.world.pos.x;
+ this->subCamAt.y = sMajoraRemains[MAJORA_REMAINS_TYPE_ODOLWA]->actor.world.pos.y;
+ this->subCamAt.z = sMajoraRemains[MAJORA_REMAINS_TYPE_ODOLWA]->actor.world.pos.z;
+
+ if (this->cutsceneTimer != 40) {
+ break;
+ }
+
+ this->cutsceneState = BATTLE_HANDLER_REMAINS_CS_STATE_ACTIVATE_GYORG;
+ this->cutsceneTimer = 0;
+ this->subCamEye.x = sMajoraRemains[MAJORA_REMAINS_TYPE_GYORG]->actor.world.pos.x * 0.7f;
+ this->subCamEye.y = sMajoraRemains[MAJORA_REMAINS_TYPE_GYORG]->actor.world.pos.y * 0.7f;
+ this->subCamEye.z = sMajoraRemains[MAJORA_REMAINS_TYPE_GYORG]->actor.world.pos.z * 0.7f;
+ FALLTHROUGH;
+ case BATTLE_HANDLER_REMAINS_CS_STATE_ACTIVATE_GYORG:
+ if (this->cutsceneTimer == 20) {
+ sMajoraRemains[MAJORA_REMAINS_TYPE_GYORG]->subAction = REMAINS_MOVE_SUB_ACTION_DETACH_FROM_WALL;
+ }
+
+ this->subCamAt.x = sMajoraRemains[MAJORA_REMAINS_TYPE_GYORG]->actor.world.pos.x;
+ this->subCamAt.y = sMajoraRemains[MAJORA_REMAINS_TYPE_GYORG]->actor.world.pos.y;
+ this->subCamAt.z = sMajoraRemains[MAJORA_REMAINS_TYPE_GYORG]->actor.world.pos.z;
+
+ if (this->cutsceneTimer != 40) {
+ break;
+ }
+
+ this->cutsceneState = BATTLE_HANDLER_REMAINS_CS_STATE_ACTIVATE_GOHT;
+ this->cutsceneTimer = 0;
+ this->subCamEye.x = sMajoraRemains[MAJORA_REMAINS_TYPE_GOHT]->actor.world.pos.x * 0.7f;
+ this->subCamEye.y = sMajoraRemains[MAJORA_REMAINS_TYPE_GOHT]->actor.world.pos.y * 0.7f;
+ this->subCamEye.z = sMajoraRemains[MAJORA_REMAINS_TYPE_GOHT]->actor.world.pos.z * 0.7f;
+ FALLTHROUGH;
+ case BATTLE_HANDLER_REMAINS_CS_STATE_ACTIVATE_GOHT:
+ if (this->cutsceneTimer == 20) {
+ sMajoraRemains[MAJORA_REMAINS_TYPE_GOHT]->subAction = REMAINS_MOVE_SUB_ACTION_DETACH_FROM_WALL;
+ }
+
+ this->subCamAt.x = sMajoraRemains[MAJORA_REMAINS_TYPE_GOHT]->actor.world.pos.x;
+ this->subCamAt.y = sMajoraRemains[MAJORA_REMAINS_TYPE_GOHT]->actor.world.pos.y;
+ this->subCamAt.z = sMajoraRemains[MAJORA_REMAINS_TYPE_GOHT]->actor.world.pos.z;
+
+ if (this->cutsceneTimer != 40) {
+ break;
+ }
+
+ this->cutsceneState = BATTLE_HANDLER_REMAINS_CS_STATE_ACTIVATE_TWINMOLD;
+ this->cutsceneTimer = 0;
+ this->subCamEye.x = sMajoraRemains[MAJORA_REMAINS_TYPE_TWINMOLD]->actor.world.pos.x * 0.7f;
+ this->subCamEye.y = sMajoraRemains[MAJORA_REMAINS_TYPE_TWINMOLD]->actor.world.pos.y * 0.7f;
+ this->subCamEye.z = sMajoraRemains[MAJORA_REMAINS_TYPE_TWINMOLD]->actor.world.pos.z * 0.7f;
+ FALLTHROUGH;
+ case BATTLE_HANDLER_REMAINS_CS_STATE_ACTIVATE_TWINMOLD:
+ if (this->cutsceneTimer == 20) {
+ sMajoraRemains[MAJORA_REMAINS_TYPE_TWINMOLD]->subAction = REMAINS_MOVE_SUB_ACTION_DETACH_FROM_WALL;
+ }
+
+ this->subCamAt.x = sMajoraRemains[MAJORA_REMAINS_TYPE_TWINMOLD]->actor.world.pos.x;
+ this->subCamAt.y = sMajoraRemains[MAJORA_REMAINS_TYPE_TWINMOLD]->actor.world.pos.y;
+ this->subCamAt.z = sMajoraRemains[MAJORA_REMAINS_TYPE_TWINMOLD]->actor.world.pos.z;
+
+ if (this->cutsceneTimer == 40) {
+ Camera* mainCam = Play_GetCamera(play, CAM_ID_MAIN);
+ s32 i;
+
+ this->cutsceneState = BATTLE_HANDLER_REMAINS_CS_STATE_DONE;
+ this->cutsceneTimer = 0;
+ mainCam->eye = this->subCamEye;
+ mainCam->eyeNext = this->subCamEye;
+ mainCam->at = this->subCamAt;
+ func_80169AFC(play, this->subCamId, 0);
+ this->subCamId = SUB_CAM_ID_DONE;
+ Cutscene_StopManual(play, &play->csCtx);
+ Player_SetCsActionWithHaltedActors(play, &this->actor, PLAYER_CSACTION_END);
+ Play_DisableMotionBlur();
+
+ for (i = 0; i < MAJORA_REMAINS_TYPE_MAX; i++) {
+ Actor_ChangeCategory(play, &play->actorCtx, &sMajoraRemains[i]->actor, ACTORCAT_ENEMY);
+ }
+ }
+ break;
+
+ case BATTLE_HANDLER_REMAINS_CS_STATE_DONE:
+ default:
+ break;
+ }
+
+ if (this->subCamId != SUB_CAM_ID_DONE) {
+ if (this->cutsceneTimer < 20) {
+ s32 i;
+
+ for (i = 0; i < MAJORA_REMAINS_TYPE_MAX; i++) {
+ if ((this->cutsceneTimer % 2) != 0) {
+ sMajoraRemains[i]->actor.world.pos.x += 2.0f;
+ sMajoraRemains[i]->actor.world.pos.z += 2.0f;
+ } else {
+ sMajoraRemains[i]->actor.world.pos.x -= 2.0f;
+ sMajoraRemains[i]->actor.world.pos.z -= 2.0f;
+ }
+ }
+ }
+
+ ShrinkWindow_Letterbox_SetSizeTarget(27);
+ Play_SetCameraAtEye(play, this->subCamId, &this->subCamAt, &this->subCamEye);
+ }
+}
+
+void Boss07_BattleHandler_Draw(Actor* thisx, PlayState* play2) {
+ PlayState* play = play2;
+ Boss07* this = THIS;
+
+ Boss07_BattleHandler_DrawEffects(play);
+ Boss07_BattleHandler_DrawIntroPlayerLightOrb(this, play);
+}
+
+void Boss07_BattleHandler_UpdateEffects(PlayState* play) {
+ MajoraEffect* effect = (MajoraEffect*)play->specialEffects;
+ s32 i;
+
+ for (i = 0; i < MAJORA_EFFECT_COUNT; i++, effect++) {
+ if (effect->type != MAJORA_EFFECT_NONE) {
+ effect->texScroll++;
+
+ 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;
+
+ if (effect->type == MAJORA_EFFECT_FLAME) {
+ if (effect->isFadingAway) {
+ effect->alpha -= (i & 7) + 13;
+ if (effect->alpha <= 0) {
+ effect->alpha = 0;
+ effect->type = MAJORA_EFFECT_NONE;
+ }
+ } else {
+ effect->alpha += 300;
+ if (effect->alpha >= 255) {
+ effect->alpha = 255;
+ effect->isFadingAway++;
+ }
+ }
+ }
+ }
+ }
+}
+
+void Boss07_BattleHandler_DrawEffects(PlayState* play) {
+ MajoraEffect* effect = (MajoraEffect*)play->specialEffects;
+ GraphicsContext* gfxCtx = play->state.gfxCtx;
+ s32 i;
+
+ OPEN_DISPS(gfxCtx);
+
+ Gfx_SetupDL25_Xlu(play->state.gfxCtx);
+
+ for (i = 0; i < MAJORA_EFFECT_COUNT; i++, effect++) {
+ if (effect->type > MAJORA_EFFECT_NONE) {
+ gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 200, 20, 0, effect->alpha);
+ gDPPipeSync(POLY_XLU_DISP++);
+ gDPSetEnvColor(POLY_XLU_DISP++, 255, 215, 255, 128);
+ gSPSegment(POLY_XLU_DISP++, 0x08,
+ Gfx_TwoTexScroll(play->state.gfxCtx, G_TX_RENDERTILE, (3 * effect->texScroll) & 0x7F,
+ (15 * -effect->texScroll) & 0xFF, 32, 64, 1, 0, 0, 32, 32));
+ Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW);
+ Matrix_ReplaceRotation(&play->billboardMtxF);
+ Matrix_Scale(effect->scale, effect->scale, 1.0f, MTXMODE_APPLY);
+ MATRIX_FINALIZE_AND_LOAD(POLY_XLU_DISP++, gfxCtx);
+ gSPDisplayList(POLY_XLU_DISP++, gMajorasMaskFireDL);
+ }
+ }
+
+ CLOSE_DISPS(gfxCtx);
+}
diff --git a/src/overlays/actors/ovl_Boss_07/z_boss_07.h b/src/overlays/actors/ovl_Boss_07/z_boss_07.h
index d17e3b1723..16eb5d95bd 100644
--- a/src/overlays/actors/ovl_Boss_07/z_boss_07.h
+++ b/src/overlays/actors/ovl_Boss_07/z_boss_07.h
@@ -2,15 +2,299 @@
#define Z_BOSS_07_H
#include "global.h"
+#include "assets/objects/object_boss07/object_boss07.h"
struct Boss07;
-typedef void (*Boss07ActionFunc)(struct Boss07*, PlayState*);
+#define MAJORA_TENTACLE_LENGTH 10
+#define MAJORA_TENTACLE_COUNT_MAX 100
+#define MAJORA_WHIP_LENGTH_MAX 50
+#define MAJORA_DEATH_LIGHT_COUNT 30
+
+#define MAJORA_LIMB_COUNT MAX((s32)MAJORAS_MASK_LIMB_MAX, MAX((s32)MAJORAS_INCARNATION_LIMB_MAX, (s32)MAJORAS_WRATH_LIMB_MAX))
+
+#define MAJORAS_WRATH_SHADOW_TEX_WIDTH 64
+#define MAJORAS_WRATH_SHADOW_TEX_HEIGHT 64
+#define MAJORAS_WRATH_SHADOW_TEX_SIZE ((s32)sizeof(u8[MAJORAS_WRATH_SHADOW_TEX_HEIGHT][MAJORAS_WRATH_SHADOW_TEX_WIDTH]))
+
+#define MAJORA_GET_TYPE(thisx) ((thisx)->params)
+#define MAJORA_PARAMS(type) (type)
+
+typedef void (*Boss07ActionFunc)(struct Boss07*, struct PlayState*);
+
+typedef enum MajoraType {
+ /* 0 */ MAJORA_TYPE_BATTLE_INIT, // initializes effects, spawns the battle handler, etc. Becomes `MAJORA_TYPE_MASK` after one frame.
+ /* 10 */ MAJORA_TYPE_MASK = 10,
+ /* 11 */ MAJORA_TYPE_MASK_UNK, // immediately crashes if spawned
+ /* 20 */ MAJORA_TYPE_INCARNATION = 20,
+ /* 21 */ MAJORA_TYPE_INCARNATION_AFTERIMAGE,
+ /* 30 */ MAJORA_TYPE_WRATH = 30,
+ /* 100 */ MAJORA_TYPE_PROJECTILE_REMAINS = 100,
+ /* 101 */ MAJORA_TYPE_PROJECTILE_INCARNATION,
+ /* 150 */ MAJORA_TYPE_BATTLE_HANDLER = 150, // handles effects, lens flare, the Remains activation cutscene, etc.
+ /* 180 */ MAJORA_TYPE_TOP = 180,
+ /* 200 */ MAJORA_TYPE_REMAINS = 200
+} MajoraType;
+
+typedef enum MajoraRemainsType {
+ /* 0 */ MAJORA_REMAINS_TYPE_ODOLWA,
+ /* 1 */ MAJORA_REMAINS_TYPE_GYORG,
+ /* 2 */ MAJORA_REMAINS_TYPE_GOHT,
+ /* 3 */ MAJORA_REMAINS_TYPE_TWINMOLD,
+ /* 4 */ MAJORA_REMAINS_TYPE_MAX
+} MajoraRemainsType;
+
+typedef struct MajoraTentacle {
+ /* 0x00 */ Vec3f base;
+ /* 0x0C */ Vec3f pos[MAJORA_TENTACLE_LENGTH];
+ /* 0x84 */ Vec3f rot[MAJORA_TENTACLE_LENGTH];
+ /* 0xFC */ Vec3f velocity[MAJORA_TENTACLE_LENGTH];
+} MajoraTentacle; // size = 0x174
+
+typedef struct MajoraWhip {
+ /* 0x000 */ Vec3s baseRot;
+ /* 0x008 */ f32 gravity;
+ /* 0x00C */ f32 mobility;
+ /* 0x010 */ f32 deceleration;
+ /* 0x014 */ f32 tension;
+ /* 0x018 */ Vec3f basePos;
+ /* 0x024 */ Vec3f pos[MAJORA_WHIP_LENGTH_MAX];
+ /* 0x27C */ Vec3f rot[MAJORA_WHIP_LENGTH_MAX];
+ /* 0x4D4 */ Vec3f velocity[MAJORA_WHIP_LENGTH_MAX];
+ /* 0x72C */ f32 unk_72C[MAJORA_WHIP_LENGTH_MAX];
+} MajoraWhip; // size = 0x7F4
+
+typedef enum MajorasWrathBodyPart {
+ /* 0 */ MAJORAS_WRATH_BODYPART_HEAD,
+ /* 1 */ MAJORAS_WRATH_BODYPART_TORSO,
+ /* 2 */ MAJORAS_WRATH_BODYPART_PELVIS,
+ /* 3 */ MAJORAS_WRATH_BODYPART_LEFT_UPPER_ARM,
+ // This body part is redundant; it's located at the exact same position as `MAJORAS_WRATH_BODYPART_LEFT_FOREARM`.
+ /* 4 */ MAJORAS_WRATH_BODYPART_LEFT_LOWER_ARM_ROOT,
+ /* 5 */ MAJORAS_WRATH_BODYPART_LEFT_FOREARM,
+ /* 6 */ MAJORAS_WRATH_BODYPART_RIGHT_UPPER_ARM,
+ // This body part is redundant; it's located at the exact same position as `MAJORAS_WRATH_BODYPART_RIGHT_FOREARM`.
+ /* 7 */ MAJORAS_WRATH_BODYPART_RIGHT_LOWER_ARM_ROOT,
+ /* 8 */ MAJORAS_WRATH_BODYPART_RIGHT_FOREARM,
+ /* 9 */ MAJORAS_WRATH_BODYPART_RIGHT_THIGH,
+ /* 10 */ MAJORAS_WRATH_BODYPART_RIGHT_SHIN,
+ /* 11 */ MAJORAS_WRATH_BODYPART_RIGHT_FOOT,
+ /* 12 */ MAJORAS_WRATH_BODYPART_LEFT_THIGH,
+ /* 13 */ MAJORAS_WRATH_BODYPART_LEFT_SHIN,
+ /* 14 */ MAJORAS_WRATH_BODYPART_LEFT_FOOT,
+ /* 15 */ MAJORAS_WRATH_BODYPART_MAX
+} MajorasWrathBodyPart;
+
+typedef enum MajorasIncarnationBodyPart {
+ /* 0 */ MAJORAS_INCARNATION_BODYPART_EYESTALK,
+ // This body part is redundant; it's located at the exact same position as `MAJORAS_INCARNATION_BODYPART_LEFT_UPPER_ARM`.
+ // Additionally, the developers used this index for both the mask limb and the left arm root limb; since the left arm
+ // root limb has a larger `limbIndex` than the mask limb, that's the limb this body part ends up attached to.
+ /* 1 */ MAJORAS_INCARNATION_BODYPART_LEFT_ARM_ROOT,
+ // This body part is redundant; it's located at the exact same position as `MAJORAS_INCARNATION_BODYPART_RIGHT_THIGH`.
+ /* 2 */ MAJORAS_INCARNATION_BODYPART_RIGHT_LEG_ROOT,
+ /* 3 */ MAJORAS_INCARNATION_BODYPART_LEFT_UPPER_ARM,
+ /* 4 */ MAJORAS_INCARNATION_BODYPART_LEFT_FOREARM,
+ /* 5 */ MAJORAS_INCARNATION_BODYPART_LEFT_HAND,
+ /* 6 */ MAJORAS_INCARNATION_BODYPART_RIGHT_UPPER_ARM,
+ /* 7 */ MAJORAS_INCARNATION_BODYPART_RIGHT_FOREARM,
+ /* 8 */ MAJORAS_INCARNATION_BODYPART_RIGHT_HAND,
+ /* 9 */ MAJORAS_INCARNATION_BODYPART_RIGHT_THIGH,
+ /* 10 */ MAJORAS_INCARNATION_BODYPART_RIGHT_SHIN,
+ /* 11 */ MAJORAS_INCARNATION_BODYPART_RIGHT_FOOT,
+ /* 12 */ MAJORAS_INCARNATION_BODYPART_LEFT_THIGH,
+ /* 13 */ MAJORAS_INCARNATION_BODYPART_LEFT_SHIN,
+ /* 14 */ MAJORAS_INCARNATION_BODYPART_LEFT_FOOT,
+ /* 15 */ MAJORAS_INCARNATION_BODYPART_MAX
+} MajorasIncarnationBodyPart;
+
+#define MAJORA_BODYPART_MAX MAX((s32)MAJORAS_WRATH_BODYPART_MAX, (s32)MAJORAS_INCARNATION_BODYPART_MAX)
+
+typedef enum MajorasWrathColliderBodyPart {
+ /* 0 */ MAJORAS_WRATH_COLLIDER_BODYPART_HEAD,
+ /* 1 */ MAJORAS_WRATH_COLLIDER_BODYPART_TORSO,
+ /* 2 */ MAJORAS_WRATH_COLLIDER_BODYPART_PELVIS,
+ /* 3 */ MAJORAS_WRATH_COLLIDER_BODYPART_LEFT_UPPER_ARM,
+ /* 4 */ MAJORAS_WRATH_COLLIDER_BODYPART_LEFT_FOREARM,
+ /* 5 */ MAJORAS_WRATH_COLLIDER_BODYPART_RIGHT_UPPER_ARM,
+ /* 6 */ MAJORAS_WRATH_COLLIDER_BODYPART_RIGHT_FOREARM,
+ /* 7 */ MAJORAS_WRATH_COLLIDER_BODYPART_LEFT_THIGH,
+ /* 8 */ MAJORAS_WRATH_COLLIDER_BODYPART_LEFT_SHIN,
+ /* 9 */ MAJORAS_WRATH_COLLIDER_BODYPART_RIGHT_THIGH,
+ /* 10 */ MAJORAS_WRATH_COLLIDER_BODYPART_RIGHT_SHIN,
+ /* 11 */ MAJORAS_WRATH_COLLIDER_BODYPART_MAX
+} MajorasWrathColliderBodyPart;
+
+typedef enum MajorasIncarnationColliderBodyPart {
+ /* 0 */ MAJORAS_INCARNATION_COLLIDER_BODYPART_EYESTALK,
+ // The developers used this index for both the mask limb and the left arm root limb; since the left arm
+ // root limb has a larger `limbIndex` than the mask limb, that's the limb this body part ends up initially
+ // attached to. However, the developers seemingly accounted for this by offsetting the collider such that
+ // it actually appears attached to the mask limb instead.
+ /* 1 */ MAJORAS_INCARNATION_COLLIDER_BODYPART_MASK,
+ // This collider is positioned at the room origin because it isn't attached to any of Incarnation's limbs
+ // within `sLimbToColliderBodyParts`; since the memory for an actor's instance is zeroed out before it's
+ // used, and since this collider isn't attached to any limbs, its position will remain stuck at (0, 0, 0).
+ // It seems like the developers *tried* to work around this by giving this collider a massive offset within
+ // `sLimbColliderOffsets`, but it doesn't work because the offset is only applied if the collider actually
+ // corresponds to a limb.
+ /* 2 */ MAJORAS_INCARNATION_COLLIDER_BODYPART_ROOM_ORIGIN,
+ /* 3 */ MAJORAS_INCARNATION_COLLIDER_BODYPART_LEFT_UPPER_ARM,
+ /* 4 */ MAJORAS_INCARNATION_COLLIDER_BODYPART_LEFT_FOREARM,
+ /* 5 */ MAJORAS_INCARNATION_COLLIDER_BODYPART_RIGHT_UPPER_ARM,
+ /* 6 */ MAJORAS_INCARNATION_COLLIDER_BODYPART_RIGHT_FOREARM,
+ /* 7 */ MAJORAS_INCARNATION_COLLIDER_BODYPART_LEFT_THIGH,
+ /* 8 */ MAJORAS_INCARNATION_COLLIDER_BODYPART_LEFT_SHIN,
+ /* 9 */ MAJORAS_INCARNATION_COLLIDER_BODYPART_RIGHT_THIGH,
+ /* 10 */ MAJORAS_INCARNATION_COLLIDER_BODYPART_RIGHT_SHIN,
+ /* 11 */ MAJORAS_INCARNATION_COLLIDER_BODYPART_MAX
+} MajorasIncarnationColliderBodyPart;
+
+#define MAJORA_COLLIDER_BODYPART_MAX MAX((s32)MAJORAS_WRATH_COLLIDER_BODYPART_MAX, (s32)MAJORAS_INCARNATION_COLLIDER_BODYPART_MAX)
+
+typedef enum MajorasIncarnationGrowBodyPart {
+ /* 0 */ MAJORAS_INCARNATION_GROW_BODYPART_RIGHT_ARM,
+ /* 1 */ MAJORAS_INCARNATION_GROW_BODYPART_LEFT_ARM,
+ /* 2 */ MAJORAS_INCARNATION_GROW_BODYPART_RIGHT_LEG,
+ /* 3 */ MAJORAS_INCARNATION_GROW_BODYPART_LEFT_LEG,
+ /* 4 */ MAJORAS_INCARNATION_GROW_BODYPART_MAX
+} MajorasIncarnationGrowBodyPart;
+
+typedef enum MajorasIncarnationFoot {
+ /* 0 */ MAJORAS_INCARNATION_FOOT_RIGHT,
+ /* 1 */ MAJORAS_INCARNATION_FOOT_LEFT,
+ /* 2 */ MAJORAS_INCARNATION_FOOT_MAX
+} MajorasIncarnationFoot;
+
+typedef enum MajorasWrathKickCollider {
+ /* 0 */ MAJORAS_WARTH_KICK_COLLIDER_RIGHT_FOOT,
+ /* 1 */ MAJORAS_WARTH_KICK_COLLIDER_MAX
+} MajorasWrathKickCollider;
typedef struct Boss07 {
/* 0x0000 */ Actor actor;
/* 0x0144 */ Boss07ActionFunc actionFunc;
- /* 0x0148 */ char unk_148[0xAAD8];
+ /* 0x0148 */ u8 shouldStartDeath;
+ /* 0x0149 */ u8 shouldUpdateTentaclesOrWhips;
+ /* 0x014A */ u8 lightSettingsMode;
+ /* 0x014B */ u8 lightSettingsIndex;
+ /* 0x014C */ s16 frameCounter;
+ /* 0x014E */ u8 subAction;
+ /* 0x014F */ u8 whipCrackTimer;
+ /* 0x0150 */ s16 timers[3];
+ /* 0x0156 */ s16 landSfxTimer;
+ /* 0x0158 */ s16 disableCollisionTimer;
+ /* 0x015A */ s16 whipCollisionTimer;
+ /* 0x015C */ s16 damagedTimer; // TODO: Revisit this name when the equivalent Player variables are named
+ /* 0x015E */ s16 damagedFlashTimer;
+ /* 0x0160 */ s16 motionBlurAlpha;
+ /* 0x0164 */ Vec3f targetPos;
+ /* 0x0170 */ f32 speedToTarget;
+ /* 0x0174 */ u8 canEvade;
+ /* 0x0178 */ f32 topSpinAngle;
+ /* 0x017C */ f32 topSpinAngularVelocity;
+ /* 0x0180 */ s16 topPrecessionVelocity; // also used as a target rotation for Incarnation's various dance moves
+ /* 0x0184 */ f32 wrathLeanRotY;
+ /* 0x0188 */ f32 wrathLeanRotX;
+ /* 0x018C */ f32 flySpeedTarget;
+ /* 0x0190 */ SkelAnime skelAnime;
+ /* 0x01D4 */ f32 animEndFrame;
+ /* 0x01D8 */ s32 maxDecayPixels;
+ /* 0x01DC */ Vec3s jointTable[MAJORA_LIMB_COUNT];
+ /* 0x0284 */ Vec3s morphTable[MAJORA_LIMB_COUNT];
+ /* 0x032C */ f32 shockOrbScale;
+ /* 0x0330 */ f32 shockSparkScale;
+ /* 0x0334 */ Vec3f bodyPartsPos[MAJORA_BODYPART_MAX];
+ /* 0x03E8 */ ColliderJntSph bodyCollider;
+ /* 0x0408 */ ColliderJntSphElement bodyColliderElements[MAJORA_COLLIDER_BODYPART_MAX];
+ /* 0x06C8 */ ColliderJntSph kickCollider;
+ /* 0x06E8 */ ColliderJntSphElement kickColliderElements[MAJORAS_WARTH_KICK_COLLIDER_MAX];
+ /* 0x0728 */ ColliderCylinder unusedCollider;
+ /* 0x0774 */ u8 startRemainsCs;
+ /* 0x0778 */ s32 whipTopIndex; // unlike other index variables, this is an index from the *end* of the whip, not from the beginning of it.
+ /* 0x077C */ f32 whipLengthScale;
+ /* 0x0780 */ s32 whipShockMaxIndex;
+ /* 0x0784 */ s32 whipShockMinIndex;
+ /* 0x0788 */ MajoraWhip rightWhip;
+ /* 0x0F7C */ s16 whipWrapStartIndex;
+ /* 0x0F7E */ s16 whipWrapEndOffset;
+ /* 0x0F80 */ Vec3f whipGrabPos;
+ /* 0x0F8C */ f32 whipWrapRotY;
+ /* 0x0F90 */ f32 whipWrapRotX;
+ /* 0x0F94 */ MajoraWhip leftWhip;
+ /* 0x1788 */ Vec3f incarnationFeetPos[MAJORAS_INCARNATION_FOOT_MAX];
+ /* 0x17A0 */ Vec3f incarnationLeftHandPos;
+ /* 0x17AC */ Vec3f incarnationRightHandPos;
+ /* 0x17B8 */ f32 incarnationIntroBodyPartsScale[MAJORAS_INCARNATION_GROW_BODYPART_MAX];
+ /* 0x17C8 */ f32 incarnationIntroBodyPartsScaleTarget[MAJORAS_INCARNATION_GROW_BODYPART_MAX];
+ /* 0x17D8 */ Vec3s cutsceneHeadRot;
+ /* 0x17E0 */ f32 incarnationArmScale; // also has some unused functionality to scale most of Wrath's limbs, see `Boss07_Wrath_TransformLimbDraw`
+ /* 0x17E4 */ f32 incarnationLegScale;
+ /* 0x17E8 */ f32 incarnationWrathTransitionScale;
+ /* 0x17E8 */ f32 incarnationWrathTransitionAmplitude;
+ /* 0x17F0 */ f32 incarnationMaskScaleY;
+ /* 0x17F4 */ f32 incarnationMaskScaleX;
+ /* 0x17F8 */ f32 drawDmgEffScale;
+ /* 0x17FC */ f32 drawDmgEffFrozenSteamScale;
+ /* 0x1800 */ f32 drawDmgEffAlpha;
+ /* 0x1804 */ u8 drawDmgEffType;
+ /* 0x1805 */ u8 drawDmgEffState; // see `MajoraDrawDmgEffState`
+ /* 0x1806 */ s16 drawDmgEffTimer;
+ /* 0x1808 */ u8 lensFlareOn;
+ /* 0x180c */ f32 lensFlareScale;
+ /* 0x1810 */ Vec3f lensFlarePos;
+ /* 0x181C */ s16 projectileColorIndex;
+ /* 0x1820 */ ColliderCylinder generalCollider;
+ /* 0x186C */ s16 maskShakeTimer;
+ /* 0x1870 */ f32 tentacleLengthScale;
+ /* 0x1874 */ u8 tentacleState; // see `MajorasMaskTentacleState`
+ /* 0x1878 */ Vec3f tentacleBasePos;
+ /* 0x1884 */ s32 maskEyeTexIndex; // see `MajorasMaskEyeTexture`
+ /* 0x1888 */ u8 bgCheckTimer;
+ /* 0x188C */ f32 eyeBeamsLengthScale; // also used as a scale for the light orbs that surround the Remains during the intro cutscene
+ /* 0x1890 */ f32 eyeBeamsFocusOrbScale;
+ /* 0x1894 */ f32 beamLengthScale;
+ /* 0x1898 */ f32 beamBaseScale;
+ /* 0x189C */ Vec3f beamStartPos;
+ /* 0x18A8 */ Vec3f beamEndPos;
+ /* 0x18B4 */ Vec3f reflectedBeamEndPos;
+ /* 0x18C0 */ f32 reflectedBeamLengthScale;
+ /* 0x18C4 */ s16 reflectedBeamPitch;
+ /* 0x18C6 */ s16 reflectedBeamYaw;
+ /* 0x18C8 */ s16 introRemainsOrbRot;
+ /* 0x18CC */ f32 knockbackMovementX;
+ /* 0x18D0 */ f32 knockbackMovementZ;
+ /* 0x18D4 */ s16 angularVelocity;
+ /* 0x18D6 */ s16 fireTimer; // also used as a timer for spawning afterimages in `Boss07_Incarnation_Update`
+ /* 0x18D8 */ s16 beamDamageTimer;
+ /* 0x18DA */ u8 burnOnLanding;
+ /* 0x18DB */ u8 tryFireProjectile;
+ /* 0x18DC */ s32 effectIndex;
+ /* 0x18E0 */ Vec3f prevBeamTireMarkPos;
+ /* 0x18EC */ u8 beamTireMarkEnabled;
+ /* 0x18ED */ u8 prevBeamTireMarkEnabled;
+ /* 0x18F0 */ ColliderQuad maskFrontCollider;
+ /* 0x1970 */ ColliderQuad maskBackCollider;
+ /* 0x19F0 */ MajoraTentacle tentacles[MAJORA_TENTACLE_COUNT_MAX];
+ /* 0xAB40 */ s16 miscTimer; // used for making the remains bob up and down in the intro and for Incarnation running SFX
+ /* 0xAB44 */ f32 introPlayerOrbScale;
+ /* 0xAB48 */ u8 disableShadow;
+ /* 0xAB4C */ f32 deathOrbScale;
+ /* 0xAB50 */ f32 deathLightScale[MAJORA_DEATH_LIGHT_COUNT];
+ /* 0xABC8 */ u32 cutsceneTimer; // also used as an animation loop count in `Boss07_Incarnation_Hopak`
+ /* 0xABCC */ s32 sfxTimer; // also used as an index in `Boss07_Mask_IntroCutscene`
+ /* 0xABD0 */ s16 cutsceneState; // also used to control whether Majora's Mask should target the player or avoid them in `Boss07_Mask_SpinAttack`
+ /* 0xABD2 */ s16 subCamId;
+ /* 0xABD4 */ Vec3f subCamEye;
+ /* 0xABE0 */ Vec3f subCamAt;
+ /* 0xABEC */ Vec3f subCamEyeNext;
+ /* 0xABF8 */ Vec3f subCamAtNext;
+ /* 0xAC04 */ f32 subCamRotY;
+ /* 0xAC08 */ f32 subCamAngularVelocity;
+ /* 0xAC0C */ f32 subCamVelocity;
+ /* 0xAC10 */ UNK_TYPE1 unkAC10[4];
+ /* 0xAC14 */ f32 subCamEyeModY;
+ /* 0xAC18 */ UNK_TYPE1 unkAC18[8];
} Boss07; // size = 0xAC20
#endif // Z_BOSS_07_H
diff --git a/src/overlays/actors/ovl_Boss_Hakugin/z_boss_hakugin.c b/src/overlays/actors/ovl_Boss_Hakugin/z_boss_hakugin.c
index 75d4d14f6f..924ed022d0 100644
--- a/src/overlays/actors/ovl_Boss_Hakugin/z_boss_hakugin.c
+++ b/src/overlays/actors/ovl_Boss_Hakugin/z_boss_hakugin.c
@@ -3603,7 +3603,7 @@ void BossHakugin_FillShadowTex(BossHakugin* this, u8* tex, f32 weight) {
baseY = (u16)((s32)startVec.y * 64);
if (sShadowSizes[i] == GOHT_SHADOW_SIZE_EXTRA_LARGE) {
- for (y = 0, addY = -0x180; y < ARRAY_COUNT(sShadowExtraLargeMap); y++, addY += 0x40) {
+ for (y = 0, addY = -384; y < ARRAY_COUNT(sShadowExtraLargeMap); y++, addY += 64) {
for (x = -sShadowExtraLargeMap[y]; x < sShadowExtraLargeMap[y]; x++) {
index = baseX + x + baseY + addY;
if ((index >= 0) && (index < GOHT_SHADOW_TEX_SIZE)) {
@@ -3612,7 +3612,7 @@ void BossHakugin_FillShadowTex(BossHakugin* this, u8* tex, f32 weight) {
}
}
} else if (sShadowSizes[i] == GOHT_SHADOW_SIZE_LARGE) {
- for (y = 0, addY = -0x100; y < ARRAY_COUNT(sShadowLargeMap); y++, addY += 0x40) {
+ for (y = 0, addY = -256; y < ARRAY_COUNT(sShadowLargeMap); y++, addY += 64) {
for (x = -sShadowLargeMap[y]; x < sShadowLargeMap[y]; x++) {
index = baseX + x + baseY + addY;
if ((index >= 0) && (index < GOHT_SHADOW_TEX_SIZE)) {
@@ -3621,7 +3621,7 @@ void BossHakugin_FillShadowTex(BossHakugin* this, u8* tex, f32 weight) {
}
}
} else if (sShadowSizes[i] == GOHT_SHADOW_SIZE_MEDIUM) {
- for (y = 0, addY = -0xC0; y < ARRAY_COUNT(sShadowMediumMap); y++, addY += 0x40) {
+ for (y = 0, addY = -192; y < ARRAY_COUNT(sShadowMediumMap); y++, addY += 64) {
for (x = -sShadowMediumMap[y]; x < sShadowMediumMap[y]; x++) {
index = baseX + x + baseY + addY;
if ((index >= 0) && (index < GOHT_SHADOW_TEX_SIZE)) {
@@ -3630,7 +3630,7 @@ void BossHakugin_FillShadowTex(BossHakugin* this, u8* tex, f32 weight) {
}
}
} else {
- for (y = 0, addY = -0x80; y < ARRAY_COUNT(sShadowSmallMap); y++, addY += 0x40) {
+ for (y = 0, addY = -128; y < ARRAY_COUNT(sShadowSmallMap); y++, addY += 64) {
for (x = -sShadowSmallMap[y]; x < sShadowSmallMap[y]; x++) {
index = baseX + x + baseY + addY;
if ((index >= 0) && (index < GOHT_SHADOW_TEX_SIZE)) {
diff --git a/src/overlays/actors/ovl_En_Sda/z_en_sda.c b/src/overlays/actors/ovl_En_Sda/z_en_sda.c
index d73817fefb..9ff542fcab 100644
--- a/src/overlays/actors/ovl_En_Sda/z_en_sda.c
+++ b/src/overlays/actors/ovl_En_Sda/z_en_sda.c
@@ -146,10 +146,10 @@ void func_809469C0(Player* player, u8* shadowTexture, f32 arg2) {
temp_t1 = sp7C.y * 64.0f;
if (D_80947AEC[i] == 2) {
- for (j = 0, phi_a3 = -0x180; j < 12; j++, phi_a3 += 0x40) {
+ for (j = 0, phi_a3 = -384; j < 12; j++, phi_a3 += 64) {
for (phi_a0 = -D_80947A98[j]; phi_a0 < D_80947A98[j]; phi_a0++) {
temp_v1 = temp_t0 + phi_a0;
- if ((temp_v1 >= 0) && (temp_v1 < 0x40)) {
+ if ((temp_v1 >= 0) && (temp_v1 < 64)) {
temp_v0 = temp_t1 + phi_a3;
if ((temp_v0 >= 0) && (temp_v0 < 0x1000)) {
shadowTexture[temp_v1 + temp_v0] = 255;
@@ -158,10 +158,10 @@ void func_809469C0(Player* player, u8* shadowTexture, f32 arg2) {
}
}
} else if (D_80947AEC[i] == 1) {
- for (j = 0, phi_a3 = -0x100; j < 8; j++, phi_a3 += 0x40) {
+ for (j = 0, phi_a3 = -256; j < 8; j++, phi_a3 += 64) {
for (phi_a0 = -D_80947A88[j]; phi_a0 < D_80947A88[j]; phi_a0++) {
temp_v1 = temp_t0 + phi_a0;
- if ((temp_v1 >= 0) && (temp_v1 < 0x40)) {
+ if ((temp_v1 >= 0) && (temp_v1 < 64)) {
temp_v0 = temp_t1 + phi_a3;
if ((temp_v0 >= 0) && (temp_v0 < 0x1000)) {
shadowTexture[temp_v1 + temp_v0] = 255;
@@ -170,10 +170,10 @@ void func_809469C0(Player* player, u8* shadowTexture, f32 arg2) {
}
}
} else if (D_80947AEC[i] == 0) {
- for (j = 0, phi_a3 = -0xC0; j < 7; j++, phi_a3 += 0x40) {
+ for (j = 0, phi_a3 = -192; j < 7; j++, phi_a3 += 64) {
for (phi_a0 = -D_80947A78[j]; phi_a0 < D_80947A78[j] - 1; phi_a0++) {
temp_v1 = temp_t0 + phi_a0;
- if ((temp_v1 >= 0) && (temp_v1 < 0x40)) {
+ if ((temp_v1 >= 0) && (temp_v1 < 64)) {
temp_v0 = temp_t1 + phi_a3;
if ((temp_v0 >= 0) && (temp_v0 < 0x1000)) {
shadowTexture[temp_v1 + temp_v0] = 255;
@@ -182,10 +182,10 @@ void func_809469C0(Player* player, u8* shadowTexture, f32 arg2) {
}
}
} else if (D_80947AEC[i] == 4) {
- for (j = 0, phi_a3 = -0x1C0; j < 14; j++, phi_a3 += 0x40) {
+ for (j = 0, phi_a3 = -448; j < 14; j++, phi_a3 += 64) {
for (phi_a0 = -D_80947AB0[j]; phi_a0 < D_80947AB0[j]; phi_a0++) {
temp_v1 = temp_t0 + phi_a0;
- if ((temp_v1 >= 0) && (temp_v1 < 0x40)) {
+ if ((temp_v1 >= 0) && (temp_v1 < 64)) {
temp_v0 = temp_t1 + phi_a3;
if ((temp_v0 >= 0) && (temp_v0 < 0x1000)) {
shadowTexture[temp_v1 + temp_v0] = 255;
@@ -194,10 +194,10 @@ void func_809469C0(Player* player, u8* shadowTexture, f32 arg2) {
}
}
} else {
- for (j = 0, phi_a3 = -0x80; j < 6; j++, phi_a3 += 0x40) {
+ for (j = 0, phi_a3 = -128; j < 6; j++, phi_a3 += 64) {
for (phi_a0 = -D_80947A6C[j]; phi_a0 < D_80947A6C[j] - 1; phi_a0++) {
temp_v1 = temp_t0 + phi_a0;
- if ((temp_v1 >= 0) && (temp_v1 < 0x40)) {
+ if ((temp_v1 >= 0) && (temp_v1 < 64)) {
temp_v0 = temp_t1 + phi_a3;
if ((temp_v0 >= 0) && (temp_v0 < 0x1000)) {
shadowTexture[temp_v1 + temp_v0] = 255;
diff --git a/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.c b/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.c
index 9eba40d48a..bd54aab4a3 100644
--- a/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.c
+++ b/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.c
@@ -473,10 +473,9 @@ void func_809289E4(ObjTsubo* this, PlayState* play) {
//! player->currentMask, but in this case is garbage in the collider
Player_PlaySfx((Player*)&this->actor, NA_SE_PL_PULL_UP_POT);
func_80928D6C(this);
- } else if ((this->unk_19B != 0) ||
- (acHit && (this->cylinderCollider.elem.acHitElem->atDmgInfo.dmgFlags & 0x058BFFBC))) {
+ } else if (this->unk_19B || (acHit && (this->cylinderCollider.elem.acHitElem->atDmgInfo.dmgFlags & 0x058BFFBC))) {
typeData = &sPotTypeData[type];
- this->unk_19B = 0;
+ this->unk_19B = false;
if ((this->actor.bgCheckFlags & BGCHECKFLAG_WATER) && (this->actor.depthInWater > 15.0f)) {
typeData->breakPot3(this, play);
} else {
diff --git a/tools/disasm/functions.txt b/tools/disasm/functions.txt
index f0ad68b595..e6967ab906 100644
--- a/tools/disasm/functions.txt
+++ b/tools/disasm/functions.txt
@@ -2707,7 +2707,7 @@
0x8013E5CC:("SubS_LineSegVsPlane",),
0x8013E640:("SubS_FindActorCustom",),
0x8013E748:("SubS_OfferTalkExchangeCustom",),
- 0x8013E7C0:("SubS_ActorAndPlayerFaceEachOther",),
+ 0x8013E7C0:("SubS_ArePlayerAndActorFacing",),
0x8013E8F8:("SubS_OfferTalkExchangeFacing",),
0x8013E950:("SubS_TrackPointStep",),
0x8013EC10:("Rumble_Update",),
@@ -9267,7 +9267,7 @@
0x809D441C:("Boss01_SetupStunned",),
0x809D4464:("Boss01_Stunned",),
0x809D44C0:("Boss01_Thaw",),
- 0x809D4668:("Boss01_ArePlayerAndOdolwaFacing",),
+ 0x809D4668:("Boss01_ArePlayerAndActorFacing",),
0x809D46E4:("Boss01_Update",),
0x809D519C:("Boss01_DrawSwordTrail",),
0x809D5584:("Boss01_OverrideLimbDraw",),
@@ -9435,142 +9435,142 @@
0x809F2EE8:("Boss06_CurtainDestroyed",),
0x809F2F0C:("Boss06_Update",),
0x809F334C:("Boss06_Draw",),
- 0x809F4980:("func_809F4980",),
- 0x809F49A0:("func_809F49A0",),
- 0x809F49C0:("func_809F49C0",),
- 0x809F4AE8:("func_809F4AE8",),
- 0x809F4BB0:("func_809F4BB0",),
- 0x809F4C40:("func_809F4C40",),
- 0x809F4CBC:("func_809F4CBC",),
- 0x809F4D10:("func_809F4D10",),
- 0x809F4D54:("func_809F4D54",),
- 0x809F4FAC:("func_809F4FAC",),
- 0x809F4FF8:("func_809F4FF8",),
- 0x809F51E8:("func_809F51E8",),
- 0x809F52CC:("func_809F52CC",),
- 0x809F536C:("func_809F536C",),
- 0x809F5494:("func_809F5494",),
+ 0x809F4980:("Boss07_Remains_PlayDamageSfx",),
+ 0x809F49A0:("Boss07_InitRand",),
+ 0x809F49C0:("Boss07_RandZeroOne",),
+ 0x809F4AE8:("Boss07_SpawnFlameEffect",),
+ 0x809F4BB0:("Boss07_SetColliderSphere",),
+ 0x809F4C40:("Boss07_ArePlayerAndActorFacing",),
+ 0x809F4CBC:("Boss07_SmoothStop",),
+ 0x809F4D10:("Boss07_RandXZ",),
+ 0x809F4D54:("Boss07_Incarnation_SpawnDust",),
+ 0x809F4FAC:("Boss07_MovePlayer",),
+ 0x809F4FF8:("Boss07_Wrath_SpawnDustAtPos",),
+ 0x809F51E8:("Boss07_Wrath_ChooseJump",),
+ 0x809F52CC:("Boss07_Wrath_JumpAwayFromExplosive",),
+ 0x809F536C:("Boss07_Wrath_BombWhip",),
+ 0x809F5494:("Boss07_Wrath_CheckBombWhips",),
0x809F552C:("Boss07_Init",),
0x809F5DA0:("Boss07_Destroy",),
- 0x809F5E14:("func_809F5E14",),
- 0x809F5E88:("func_809F5E88",),
- 0x809F64F4:("func_809F64F4",),
- 0x809F65F4:("func_809F65F4",),
- 0x809F7400:("func_809F7400",),
- 0x809F748C:("func_809F748C",),
- 0x809F7688:("func_809F7688",),
- 0x809F76D0:("func_809F76D0",),
- 0x809F77A8:("func_809F77A8",),
- 0x809F783C:("func_809F783C",),
- 0x809F7968:("func_809F7968",),
- 0x809F7AB4:("func_809F7AB4",),
- 0x809F7BC4:("func_809F7BC4",),
- 0x809F7D2C:("func_809F7D2C",),
- 0x809F805C:("func_809F805C",),
- 0x809F8658:("func_809F8658",),
- 0x809F86B8:("func_809F86B8",),
- 0x809F87C8:("func_809F87C8",),
- 0x809F8908:("func_809F8908",),
- 0x809F8AB0:("func_809F8AB0",),
- 0x809F8B1C:("func_809F8B1C",),
- 0x809F8D04:("func_809F8D04",),
- 0x809F8DEC:("func_809F8DEC",),
- 0x809F8E68:("func_809F8E68",),
- 0x809F8EC8:("func_809F8EC8",),
- 0x809F91D4:("func_809F91D4",),
- 0x809F9280:("func_809F9280",),
- 0x809F93DC:("func_809F93DC",),
- 0x809F94AC:("func_809F94AC",),
- 0x809F99C4:("func_809F99C4",),
- 0x809F9CEC:("func_809F9CEC",),
- 0x809F9E94:("func_809F9E94",),
- 0x809FA1B4:("Boss07_Update",),
- 0x809FAA44:("func_809FAA44",),
- 0x809FB114:("func_809FB114",),
- 0x809FB504:("func_809FB504",),
- 0x809FB55C:("func_809FB55C",),
- 0x809FB728:("func_809FB728",),
- 0x809FB7D4:("func_809FB7D4",),
- 0x809FBB9C:("func_809FBB9C",),
- 0x809FBF94:("func_809FBF94",),
- 0x809FC1C8:("Boss07_Draw",),
- 0x809FC4C0:("func_809FC4C0",),
- 0x809FC8B0:("func_809FC8B0",),
- 0x809FC960:("func_809FC960",),
- 0x809FCBC8:("func_809FCBC8",),
- 0x809FCC70:("func_809FCC70",),
- 0x809FCCCC:("func_809FCCCC",),
- 0x809FD5F8:("func_809FD5F8",),
- 0x809FD710:("func_809FD710",),
- 0x809FD818:("func_809FD818",),
- 0x809FD89C:("func_809FD89C",),
- 0x809FD984:("func_809FD984",),
- 0x809FDAB0:("func_809FDAB0",),
- 0x809FDB2C:("func_809FDB2C",),
- 0x809FDBA0:("func_809FDBA0",),
- 0x809FDEDC:("func_809FDEDC",),
- 0x809FDF54:("func_809FDF54",),
- 0x809FE068:("func_809FE068",),
- 0x809FE0E4:("func_809FE0E4",),
- 0x809FE2D4:("func_809FE2D4",),
- 0x809FE348:("func_809FE348",),
- 0x809FE4B0:("func_809FE4B0",),
- 0x809FE524:("func_809FE524",),
- 0x809FE6B0:("func_809FE6B0",),
- 0x809FE734:("func_809FE734",),
- 0x809FEE70:("func_809FEE70",),
- 0x809FF0E4:("func_809FF0E4",),
- 0x809FF12C:("func_809FF12C",),
- 0x809FF5CC:("func_809FF5CC",),
- 0x809FF678:("func_809FF678",),
- 0x809FF6B0:("func_809FF6B0",),
- 0x809FF810:("func_809FF810",),
- 0x809FF900:("func_809FF900",),
- 0x809FFA04:("func_809FFA04",),
- 0x809FFA80:("func_809FFA80",),
- 0x809FFE64:("func_809FFE64",),
- 0x809FFEAC:("func_809FFEAC",),
- 0x80A0021C:("func_80A0021C",),
- 0x80A00274:("func_80A00274",),
- 0x80A00484:("func_80A00484",),
- 0x80A00554:("func_80A00554",),
- 0x80A006D0:("func_80A006D0",),
- 0x80A006F4:("func_80A006F4",),
- 0x80A00720:("func_80A00720",),
- 0x80A016E4:("func_80A016E4",),
- 0x80A01750:("func_80A01750",),
- 0x80A025AC:("func_80A025AC",),
- 0x80A0264C:("func_80A0264C",),
- 0x80A02B30:("func_80A02B30",),
- 0x80A02C54:("func_80A02C54",),
- 0x80A03238:("func_80A03238",),
- 0x80A036C4:("func_80A036C4",),
- 0x80A03868:("func_80A03868",),
- 0x80A03F18:("func_80A03F18",),
- 0x80A03F5C:("func_80A03F5C",),
- 0x80A0434C:("func_80A0434C",),
- 0x80A045A8:("func_80A045A8",),
- 0x80A04768:("func_80A04768",),
- 0x80A04878:("func_80A04878",),
- 0x80A04890:("func_80A04890",),
- 0x80A04DE0:("func_80A04DE0",),
- 0x80A04E5C:("func_80A04E5C",),
- 0x80A055E0:("func_80A055E0",),
- 0x80A05608:("func_80A05608",),
- 0x80A05694:("func_80A05694",),
- 0x80A057A0:("func_80A057A0",),
- 0x80A05AF8:("func_80A05AF8",),
- 0x80A05B50:("func_80A05B50",),
- 0x80A05C88:("func_80A05C88",),
- 0x80A05DDC:("func_80A05DDC",),
- 0x80A06500:("func_80A06500",),
- 0x80A06990:("func_80A06990",),
- 0x80A06C64:("func_80A06C64",),
- 0x80A06E24:("func_80A06E24",),
- 0x80A06F48:("func_80A06F48",),
- 0x80A07604:("func_80A07604",),
- 0x80A07638:("func_80A07638",),
- 0x80A07740:("func_80A07740",),
+ 0x809F5E14:("Boss07_Wrath_SetupIntroCutscene",),
+ 0x809F5E88:("Boss07_Wrath_IntroCutscene",),
+ 0x809F64F4:("Boss07_Wrath_SetupDeathCutscene",),
+ 0x809F65F4:("Boss07_Wrath_DeathCutscene",),
+ 0x809F7400:("Boss07_Wrath_SetupIdle",),
+ 0x809F748C:("Boss07_Wrath_Idle",),
+ 0x809F7688:("Boss07_Wrath_SetupJump",),
+ 0x809F76D0:("Boss07_Wrath_StartJump",),
+ 0x809F77A8:("Boss07_Wrath_Jump",),
+ 0x809F783C:("Boss07_Wrath_SetupFlip",),
+ 0x809F7968:("Boss07_Wrath_Flip",),
+ 0x809F7AB4:("Boss07_Wrath_SetupSidestep",),
+ 0x809F7BC4:("Boss07_Wrath_Sidestep",),
+ 0x809F7D2C:("Boss07_Wrath_SetupAttack",),
+ 0x809F805C:("Boss07_Wrath_Attack",),
+ 0x809F8658:("Boss07_Wrath_SetupTryGrab",),
+ 0x809F86B8:("Boss07_Wrath_TryGrab",),
+ 0x809F87C8:("Boss07_Wrath_GrabPlayer",),
+ 0x809F8908:("Boss07_Wrath_ThrowPlayer",),
+ 0x809F8AB0:("Boss07_Wrath_SetupShock",),
+ 0x809F8B1C:("Boss07_Wrath_ShockWhip",),
+ 0x809F8D04:("Boss07_Wrath_ShockStunned",),
+ 0x809F8DEC:("Boss07_Wrath_SetupStunned",),
+ 0x809F8E68:("Boss07_Wrath_SetupThrowTop",),
+ 0x809F8EC8:("Boss07_Wrath_ThrowTop",),
+ 0x809F91D4:("Boss07_Wrath_Stunned",),
+ 0x809F9280:("Boss07_Wrath_SetupDamaged",),
+ 0x809F93DC:("Boss07_Wrath_Damaged",),
+ 0x809F94AC:("Boss07_Wrath_CheckWhipCollisions",),
+ 0x809F99C4:("Boss07_Wrath_UpdateDamage",),
+ 0x809F9CEC:("Boss07_Wrath_Thaw",),
+ 0x809F9E94:("Boss07_UpdateDamageEffects",),
+ 0x809FA1B4:("Boss07_Wrath_Update",),
+ 0x809FAA44:("Boss07_Wrath_UpdateWhips",),
+ 0x809FB114:("Boss07_Wrath_DrawWhip",),
+ 0x809FB504:("Boss07_Wrath_OverrideLimbDraw",),
+ 0x809FB55C:("Boss07_Wrath_PostLimbDraw",),
+ 0x809FB728:("Boss07_Wrath_TransformLimbDraw",),
+ 0x809FB7D4:("Boss07_Wrath_DrawShocks",),
+ 0x809FBB9C:("Boss07_Wrath_DrawDeathLights",),
+ 0x809FBF94:("Boss07_BattleHandler_DrawIntroPlayerLightOrb",),
+ 0x809FC1C8:("Boss07_Wrath_Draw",),
+ 0x809FC4C0:("Boss07_Wrath_FillShadowTex",),
+ 0x809FC8B0:("Boss07_Wrath_GenShadowTex",),
+ 0x809FC960:("Boss07_Wrath_DrawShadowTex",),
+ 0x809FCBC8:("Boss07_Incarnation_AvoidPlayer",),
+ 0x809FCC70:("Boss07_Incarnation_SetupIntroCutscene",),
+ 0x809FCCCC:("Boss07_Incarnation_IntroCutscene",),
+ 0x809FD5F8:("Boss07_Incarnation_SetupTaunt",),
+ 0x809FD710:("Boss07_Incarnation_Taunt",),
+ 0x809FD818:("Boss07_Incarnation_SetupStunned",),
+ 0x809FD89C:("Boss07_Incarnation_Stunned",),
+ 0x809FD984:("Boss07_Incarnation_SetupDamaged",),
+ 0x809FDAB0:("Boss07_Incarnation_Damaged",),
+ 0x809FDB2C:("Boss07_Incarnation_SetupRun",),
+ 0x809FDBA0:("Boss07_Incarnation_Run",),
+ 0x809FDEDC:("Boss07_Incarnation_SetupAttack",),
+ 0x809FDF54:("Boss07_Incarnation_Attack",),
+ 0x809FE068:("Boss07_Incarnation_SetupSquattingDance",),
+ 0x809FE0E4:("Boss07_Incarnation_SquattingDance",),
+ 0x809FE2D4:("Boss07_Incarnation_SetupMoonwalk",),
+ 0x809FE348:("Boss07_Incarnation_Moonwalk",),
+ 0x809FE4B0:("Boss07_Incarnation_SetupPirouette",),
+ 0x809FE524:("Boss07_Incarnation_Pirouette",),
+ 0x809FE6B0:("Boss07_Incarnation_SetupDeathCutscene",),
+ 0x809FE734:("Boss07_Incarnation_DeathCutscene",),
+ 0x809FEE70:("Boss07_Incarnation_UpdateDamage",),
+ 0x809FF0E4:("Boss07_IncarnationAfterimage_Update",),
+ 0x809FF12C:("Boss07_Incarnation_Update",),
+ 0x809FF5CC:("Boss07_IncarnationAfterimage_Draw",),
+ 0x809FF678:("Boss07_Incarnation_OverrideLimbDraw",),
+ 0x809FF6B0:("Boss07_Incarnation_PostLimbDraw",),
+ 0x809FF810:("Boss07_Incarnation_TransformLimbDraw",),
+ 0x809FF900:("Boss07_Incarnation_Draw",),
+ 0x809FFA04:("Boss07_Mask_SetupIdle",),
+ 0x809FFA80:("Boss07_Mask_Idle",),
+ 0x809FFE64:("Boss07_Mask_SetupSpinAttack",),
+ 0x809FFEAC:("Boss07_Mask_SpinAttack",),
+ 0x80A0021C:("Boss07_Mask_SetupStunned",),
+ 0x80A00274:("Boss07_Mask_Stunned",),
+ 0x80A00484:("Boss07_Mask_SetupDamaged",),
+ 0x80A00554:("Boss07_Mask_Damaged",),
+ 0x80A006D0:("Boss07_Mask_StopBeam",),
+ 0x80A006F4:("Boss07_Mask_SetupFireBeam",),
+ 0x80A00720:("Boss07_Mask_FireBeam",),
+ 0x80A016E4:("Boss07_Mask_SetupIntroCutscene",),
+ 0x80A01750:("Boss07_Mask_IntroCutscene",),
+ 0x80A025AC:("Boss07_Mask_SetupDeathCutscene",),
+ 0x80A0264C:("Boss07_Mask_DeathCutscene",),
+ 0x80A02B30:("Boss07_Mask_UpdateDamage",),
+ 0x80A02C54:("Boss07_Mask_Update",),
+ 0x80A03238:("Boss07_Mask_UpdateTentacles",),
+ 0x80A036C4:("Boss07_Mask_DrawTentacles",),
+ 0x80A03868:("Boss07_Mask_DrawBeam",),
+ 0x80A03F18:("Boss07_Mask_PostLimbDraw",),
+ 0x80A03F5C:("Boss07_Mask_Draw",),
+ 0x80A0434C:("Boss07_Projectile_Update",),
+ 0x80A045A8:("Boss07_Projectile_Draw",),
+ 0x80A04768:("Boss07_Remains_UpdateDamage",),
+ 0x80A04878:("Boss07_Remains_SetupIntroCutscene",),
+ 0x80A04890:("Boss07_Remains_IntroCutscene",),
+ 0x80A04DE0:("Boss07_Remains_SetupMove",),
+ 0x80A04E5C:("Boss07_Remains_Move",),
+ 0x80A055E0:("Boss07_Remains_SetupStunned",),
+ 0x80A05608:("Boss07_Remains_Stunned",),
+ 0x80A05694:("Boss07_Remains_Update",),
+ 0x80A057A0:("Boss07_Remains_Draw",),
+ 0x80A05AF8:("Boss07_Top_SetupThrown",),
+ 0x80A05B50:("Boss07_Top_Thrown",),
+ 0x80A05C88:("Boss07_Top_SetupMove",),
+ 0x80A05DDC:("Boss07_Top_Move",),
+ 0x80A06500:("Boss07_Top_CheckTopCollision",),
+ 0x80A06990:("Boss07_Top_UpdateDamage",),
+ 0x80A06C64:("Boss07_Top_Update",),
+ 0x80A06E24:("Boss07_Top_Draw",),
+ 0x80A06F48:("Boss07_BattleHandler_Update",),
+ 0x80A07604:("Boss07_BattleHandler_Draw",),
+ 0x80A07638:("Boss07_BattleHandler_UpdateEffects",),
+ 0x80A07740:("Boss07_BattleHandler_DrawEffects",),
0x80A0A8A0:("BgDyYoseizo_Init",),
0x80A0A95C:("BgDyYoseizo_Destroy",),
0x80A0A96C:("BgDyYoseizo_UpdateEyes",),
diff --git a/tools/disasm/variables.txt b/tools/disasm/variables.txt
index bb6aaf9930..57aa4a263b 100644
--- a/tools/disasm/variables.txt
+++ b/tools/disasm/variables.txt
@@ -10180,78 +10180,66 @@
0x809F4974:("sBoss06Seed1","UNK_TYPE4","",0x4),
0x809F4978:("sBoss06Seed2","UNK_TYPE4","",0x4),
0x809F497C:("sBoss06Seed3","UNK_TYPE4","",0x4),
- 0x80A07950:("D_80A07950","UNK_TYPE2","",0x2),
- 0x80A07952:("D_80A07952","UNK_TYPE2","",0x2),
- 0x80A07954:("D_80A07954","UNK_TYPE2","",0x2),
- 0x80A07968:("D_80A07968","UNK_TYPE1","",0x1),
- 0x80A07980:("D_80A07980","UNK_TYPE1","",0x1),
- 0x80A079A0:("D_80A079A0","UNK_TYPE1","",0x1),
- 0x80A079C0:("D_80A079C0","UNK_TYPE1","",0x1),
- 0x80A079E0:("D_80A079E0","UNK_TYPE1","",0x1),
- 0x80A07A00:("D_80A07A00","UNK_TYPE1","",0x1),
- 0x80A07A20:("Boss_07_Profile","UNK_TYPE1","",0x1),
- 0x80A07A40:("D_80A07A40","UNK_TYPE1","",0x1),
- 0x80A07A8C:("D_80A07A8C","UNK_TYPE2","",0x2),
- 0x80A07A90:("D_80A07A90","UNK_TYPE2","",0x2),
- 0x80A07BCC:("D_80A07BCC","UNK_TYPE1","",0x1),
- 0x80A07BDC:("D_80A07BDC","UNK_TYPE1","",0x1),
- 0x80A07C08:("D_80A07C08","UNK_TYPE1","",0x1),
- 0x80A07C2C:("D_80A07C2C","UNK_TYPE1","",0x1),
- 0x80A07C3C:("D_80A07C3C","UNK_TYPE1","",0x1),
- 0x80A07C8C:("D_80A07C8C","UNK_TYPE1","",0x1),
- 0x80A07CDC:("D_80A07CDC","UNK_TYPE1","",0x1),
- 0x80A07E68:("D_80A07E68","UNK_TYPE1","",0x1),
- 0x80A07E78:("D_80A07E78","UNK_TYPE1","",0x1),
- 0x80A07EA4:("D_80A07EA4","UNK_TYPE1","",0x1),
- 0x80A07ED0:("D_80A07ED0","UNK_TYPE1","",0x1),
- 0x80A07EFC:("D_80A07EFC","UNK_TYPE1","",0x1),
- 0x80A07F00:("D_80A07F00","UNK_TYPE1","",0x1),
- 0x80A07F04:("D_80A07F04","UNK_TYPE1","",0x1),
- 0x80A07F08:("D_80A07F08","UNK_TYPE1","",0x1),
- 0x80A07F0C:("D_80A07F0C","UNK_TYPE1","",0x1),
- 0x80A07F3C:("D_80A07F3C","UNK_TYPE1","",0x1),
- 0x80A07F54:("D_80A07F54","UNK_TYPE2","",0x2),
- 0x80A07F5C:("D_80A07F5C","EffectTireMarkInit","",0x8),
- 0x80A07F64:("D_80A07F64","EffectTireMarkInit","",0x8),
- 0x80A07F6C:("D_80A07F6C","UNK_TYPE4","",0x4),
- 0x80A07FA8:("D_80A07FA8","UNK_TYPE4","",0x4),
- 0x80A07FB4:("D_80A07FB4","UNK_TYPE4","",0x4),
- 0x80A07FC0:("D_80A07FC0","UNK_TYPE4","",0x4),
- 0x80A07FCC:("D_80A07FCC","UNK_TYPE1","",0x1),
- 0x80A07FD0:("D_80A07FD0","UNK_TYPE1","",0x1),
- 0x80A07FD4:("D_80A07FD4","UNK_TYPE1","",0x1),
- 0x80A07FE0:("D_80A07FE0","UNK_TYPE4","",0x4),
- 0x80A07FEC:("D_80A07FEC","UNK_TYPE1","",0x1),
- 0x80A07FF8:("D_80A07FF8","UNK_TYPE1","",0x1),
- 0x80A07FFC:("D_80A07FFC","UNK_TYPE1","",0x1),
- 0x80A07FFD:("D_80A07FFD","UNK_TYPE1","",0x1),
- 0x80A07FFE:("D_80A07FFE","UNK_TYPE1","",0x1),
- 0x80A07FFF:("D_80A07FFF","UNK_TYPE1","",0x1),
- 0x80A08002:("D_80A08002","UNK_TYPE1","",0x1),
- 0x80A08004:("D_80A08004","UNK_TYPE1","",0x1),
- 0x80A08006:("D_80A08006","UNK_TYPE1","",0x1),
- 0x80A0800C:("D_80A0800C","UNK_TYPE1","",0x1),
- 0x80A08090:("D_80A08090","UNK_TYPE1","",0x1),
- 0x80A080B0:("D_80A080B0","UNK_TYPE1","",0x1),
- 0x80A080BC:("D_80A080BC","UNK_TYPE4","",0x4),
- 0x80A080D4:("D_80A080D4","UNK_TYPE4","",0x4),
- 0x80A080F0:("D_80A080F0","UNK_TYPE4","",0x4),
- 0x80A08110:("D_80A08110","UNK_TYPE4","",0x4),
- 0x80A08140:("D_80A08140","UNK_TYPE4","",0x4),
- 0x80A0817C:("D_80A0817C","UNK_TYPE1","",0x1),
- 0x80A0818C:("D_80A0818C","UNK_TYPE1","",0x1),
- 0x80A08198:("D_80A08198","UNK_TYPE1","",0x1),
- 0x80A081A0:("D_80A081A0","UNK_TYPE1","",0x1),
- 0x80A081A8:("D_80A081A8","UNK_TYPE1","",0x1),
- 0x80A081C8:("D_80A081C8","UNK_TYPE1","",0x1),
- 0x80A081E8:("D_80A081E8","UNK_TYPE1","",0x1),
- 0x80A0826C:("D_80A0826C","UNK_TYPE1","",0x1),
- 0x80A0828C:("D_80A0828C","UNK_TYPE1","",0x1),
- 0x80A082A4:("D_80A082A4","UNK_TYPE1","",0x1),
- 0x80A082BC:("D_80A082BC","UNK_TYPE4","",0x4),
- 0x80A082C8:("D_80A082C8","UNK_TYPE4","",0x4),
- 0x80A082D4:("D_80A082D4","UNK_TYPE4","",0x4),
- 0x80A082E0:("D_80A082E0","UNK_TYPE1","",0x1),
+ 0x80A07950:("sProjectileEnvColors","s16","[4][3]",0x18),
+ 0x80A07968:("sProjectilePrimColors","s16","[4][3]",0x18),
+ 0x80A07980:("sMajorasMaskDamageTable","DamageTable","",0x20),
+ 0x80A079A0:("sMajorasIncarnationDamageTable","DamageTable","",0x20),
+ 0x80A079C0:("sMajorasWrathDamageTable","DamageTable","",0x20),
+ 0x80A079E0:("sRemainsDamageTable","DamageTable","",0x20),
+ 0x80A07A00:("sTopDamageTable","DamageTable","",0x20),
+ 0x80A07A20:("Boss_07_Profile","ActorProfile","",0x20),
+ 0x80A07A40:("sWrathBodyColliderJntSphElementsInit","ColliderJntSphElementInit","[11]",0x18C),
+ 0x80A07BCC:("sWrathBodyColliderJntSphInit","ColliderJntSphInit","",0x10),
+ 0x80A07BDC:("sWrathCylinderInit","ColliderCylinderInit","",0x2C),
+ 0x80A07C08:("sWrathKickColliderJntSphElementsInit","ColliderJntSphElementInit","[1]",0x24),
+ 0x80A07C2C:("sWrathKickColliderJntSphInit","ColliderJntSphInit","",0x10),
+ 0x80A07C3C:("sMaskFrontQuadInit","ColliderQuadInit","",0x50),
+ 0x80A07C8C:("sMaskBackQuadInit","ColliderQuadInit","",0x50),
+ 0x80A07CDC:("sIncarnationBodyJntSphElementsInit","ColliderJntSphElementInit","[11]",0x18C),
+ 0x80A07E68:("sIncarnationBodyColliderJntSphInit","ColliderJntSphInit","",0x10),
+ 0x80A07E78:("sProjectileCylinderInit","ColliderCylinderInit","",0x2C),
+ 0x80A07EA4:("sRemainsCylinderInit","ColliderCylinderInit","",0x2C),
+ 0x80A07ED0:("sTopCylinderInit","ColliderCylinderInit","",0x2C),
+ 0x80A07EFC:("sDustPrimColor","Color_RGBA8","",0x4),
+ 0x80A07F00:("sDustEnvColor","Color_RGBA8","",0x4),
+ 0x80A07F04:("sDustPrimColor","Color_RGBA8","",0x4),
+ 0x80A07F08:("sDustEnvColor","Color_RGBA8","",0x4),
+ 0x80A07F0C:("sRemainsStartTargetOffset","Vec3f","[4]",0x30),
+ 0x80A07F3C:("sRemainsEndTarget","Vec3s","[4]",0x18),
+ 0x80A07F54:("sMajoraRemainsParams","s16","[4]",0x8),
+ 0x80A07F5C:("sTopTireMarkInit","EffectTireMarkInit","",0x8),
+ 0x80A07F64:("sMaskTireMarkInit","EffectTireMarkInit","",0x8),
+ 0x80A07F6C:("sCamPoints","MajorasWrathIntroCutsceneCamPoints","[5]",0x3C),
+ 0x80A07FA8:("subCamAtOffset","Vec3f","",0xC),
+ 0x80A07FB4:("hahenVelocity","Vec3f","",0xC),
+ 0x80A07FC0:("hahenAccel","Vec3f","",0xC),
+ 0x80A07FCC:("sIcePrimColor","Color_RGBA8","",0x4),
+ 0x80A07FD0:("sIceEnvColor","Color_RGBA8","",0x4),
+ 0x80A07FD4:("sIceAccel","Vec3f","",0xC),
+ 0x80A07FE0:("baseSegVec","Vec3f","",0xC),
+ 0x80A07FEC:("sWrathLimbToColliderBodyParts","s8","[30]",0x1E),
+ 0x80A0800C:("sWrathLimbColliderOffsets","Vec3f","[11]",0x84),
+ 0x80A08090:("sWrathLimbToBodyParts","s8","[30]",0x1E),
+ 0x80A080B0:("sWhipOffset","Vec3f","",0xC),
+ 0x80A080BC:("sShadowSmallMap","s32","[6]",0x18),
+ 0x80A080D4:("sShadowMediumMap","s32","[7]",0x1C),
+ 0x80A080F0:("sShadowLargeMap","s32","[8]",0x20),
+ 0x80A08110:("sShadowExtraLargeMap","s32","[12]",0x38),
+ 0x80A08140:("sParentShadowBodyParts","s32","[15]",0x3C),
+ 0x80A0817C:("sShadowSizes","u8","[15]",0xE),
+ 0x80A0818C:("sTauntAnimations","AnimationHeader*","[3]",0xC),
+ 0x80A08198:("sPrevLightSettings","u8","[8]",0x8),
+ 0x80A081A0:("sLightSettings","u8","[8]",0x8),
+ 0x80A081A8:("sIncarnationLimbToColliderBodyParts","s8","[30]",0x1E),
+ 0x80A081C8:("sIncarnationLimbToPumpBodyParts","s8","[30]",0x1E),
+ 0x80A081E8:("sIncarnationLimbColliderOffsets","Vec3f","[11]",0x84),
+ 0x80A0826C:("sIncarnationLimbToBodyParts","s8","[30]",0x1E),
+ 0x80A0828C:("sRemainsAttachSubCamEyes","Vec3s","[4]",0x18),
+ 0x80A082A4:("sRemainsAttachSubCamAts","Vec3s","[4]",0x18),
+ 0x80A082BC:("hahenVelocity","Vec3f","",0xC),
+ 0x80A082C8:("hahenAccel","Vec3f","",0xC),
+ 0x80A082D4:("baseSegVec","Vec3f","",0xC),
+ 0x80A082E0:("sMaskEyeTextures","UNK_TYPE1","",0x1),
0x80A082F0:("D_80A082F0","f32","",0x4),
0x80A082F4:("D_80A082F4","f32","",0x4),
0x80A082F8:("D_80A082F8","f32","",0x4),
@@ -10428,22 +10416,19 @@
0x80A08794:("D_80A08794","f32","",0x4),
0x80A08798:("D_80A08798","f32","",0x4),
0x80A09740:("D_80A09740","UNK_TYPE1","",0x1),
- 0x80A09A40:("D_80A09A40","UNK_TYPE1","",0x1),
- 0x80A09A4C:("D_80A09A4C","UNK_TYPE1","",0x1),
- 0x80A09A50:("D_80A09A50","UNK_TYPE4","",0x4),
- 0x80A09A54:("D_80A09A54","UNK_TYPE4","",0x4),
- 0x80A09A58:("D_80A09A58","UNK_TYPE4","",0x4),
- 0x80A09A5C:("D_80A09A5C","UNK_TYPE4","",0x4),
- 0x80A09A60:("D_80A09A60","UNK_TYPE4","",0x4),
- 0x80A09A64:("D_80A09A64","UNK_TYPE4","",0x4),
- 0x80A09A68:("D_80A09A68","UNK_TYPE4","",0x4),
- 0x80A09A6C:("D_80A09A6C","UNK_TYPE4","",0x4),
- 0x80A09A70:("D_80A09A70","UNK_TYPE1","",0x1),
- 0x80A09A71:("D_80A09A71","UNK_TYPE1","",0x1),
- 0x80A09A78:("D_80A09A78","UNK_TYPE1","",0x1),
- 0x80A0A888:("D_80A0A888","UNK_TYPE4","",0x4),
- 0x80A0A88C:("D_80A0A88C","UNK_TYPE4","",0x4),
- 0x80A0A890:("D_80A0A890","UNK_TYPE4","",0x4),
+ 0x80A09A40:("sMajoraSfxPos","Vec3f","",0xC),
+ 0x80A09A4C:("sHeartbeatTimer","u8","",0x1),
+ 0x80A09A50:("sWhipLength","s32","",0x4),
+ 0x80A09A54:("sMajorasWrath","Boss07*","",0x4),
+ 0x80A09A58:("sMajoraBattleHandler","Boss07*","",0x4),
+ 0x80A09A5C:("sMajorasMask","Boss07*","",0x4),
+ 0x80A09A60:("sMajoraRemains","Boss07*","[4]",0x10),
+ 0x80A09A70:("sKillAllProjectiles","u8","",0x1),
+ 0x80A09A71:("sMusicStartTimer","u8","",0x1),
+ 0x80A09A78:("sMajoraEffects","MajoraEffect","[50]",0xE10),
+ 0x80A0A888:("sMajoraRandSeed1","s32","",0x4),
+ 0x80A0A88C:("sMajoraRandSeed2","s32","",0x4),
+ 0x80A0A890:("sMajoraRandSeed3","s32","",0x4),
0x80A0C4A0:("Bg_Dy_Yoseizo_Profile","UNK_TYPE1","",0x1),
0x80A0C4C0:("sAnimations","AnimationHeader*","9",0x24),
0x80A0C4E4:("sEffectPrimColors","Color_RGB8","6",0x12),
diff --git a/tools/sizes/code_functions.csv b/tools/sizes/code_functions.csv
index b1caa1f084..e42994022a 100644
--- a/tools/sizes/code_functions.csv
+++ b/tools/sizes/code_functions.csv
@@ -2221,7 +2221,7 @@ asm/non_matchings/code/z_sub_s/SubS_ConstructPlane.s,SubS_ConstructPlane,0x8013E
asm/non_matchings/code/z_sub_s/SubS_LineSegVsPlane.s,SubS_LineSegVsPlane,0x8013E5CC,0x1D
asm/non_matchings/code/z_sub_s/SubS_FindActorCustom.s,SubS_FindActorCustom,0x8013E640,0x42
asm/non_matchings/code/z_sub_s/SubS_OfferTalkExchangeCustom.s,SubS_OfferTalkExchangeCustom,0x8013E748,0x1E
-asm/non_matchings/code/z_sub_s/SubS_ActorAndPlayerFaceEachOther.s,SubS_ActorAndPlayerFaceEachOther,0x8013E7C0,0x4E
+asm/non_matchings/code/z_sub_s/SubS_ArePlayerAndActorFacing.s,SubS_ArePlayerAndActorFacing,0x8013E7C0,0x4E
asm/non_matchings/code/z_sub_s/SubS_OfferTalkExchangeFacing.s,SubS_OfferTalkExchangeFacing,0x8013E8F8,0x16
asm/non_matchings/code/z_sub_s/SubS_TrackPointStep.s,SubS_TrackPointStep,0x8013E950,0xB0
asm/non_matchings/code/code_8013EC10/Rumble_Update.s,Rumble_Update,0x8013EC10,0xD