diff --git a/assets/xml/objects/gameplay_keep.xml b/assets/xml/objects/gameplay_keep.xml
index 354c710bbf..ee2bed429a 100644
--- a/assets/xml/objects/gameplay_keep.xml
+++ b/assets/xml/objects/gameplay_keep.xml
@@ -915,18 +915,23 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/include/functions.h b/include/functions.h
index 99e030cde6..41f3308ebb 100644
--- a/include/functions.h
+++ b/include/functions.h
@@ -3146,7 +3146,7 @@ void AudioSfx_LowerSfxSettingsReverb(Vec3f* pos, s8 isReverbLowered);
// void func_8019F7D8(void);
// void func_8019F830(void);
void func_8019F88C(Vec3f* arg0, u16 sfxId, UNK_TYPE arg2);
-// void func_8019F900(void);
+void func_8019F900(Vec3f* pos, u8 chargeLevel);
// void func_8019FA18(void);
void func_8019FAD8(Vec3f* param_1, u16 sfxId, f32 param_3);
void func_8019FB0C(Vec3f* arg0, u16 sfxId, f32 arg2, s32 arg3);
diff --git a/spec b/spec
index 9ad5e4cca9..e2ea0c1b33 100644
--- a/spec
+++ b/spec
@@ -984,8 +984,7 @@ beginseg
name "ovl_En_M_Thunder"
compress
include "build/src/overlays/actors/ovl_En_M_Thunder/z_en_m_thunder.o"
- include "build/data/ovl_En_M_Thunder/ovl_En_M_Thunder.data.o"
- include "build/data/ovl_En_M_Thunder/ovl_En_M_Thunder.reloc.o"
+ include "build/src/overlays/actors/ovl_En_M_Thunder/ovl_En_M_Thunder_reloc.o"
endseg
beginseg
diff --git a/src/overlays/actors/ovl_Eff_Dust/z_eff_dust.c b/src/overlays/actors/ovl_Eff_Dust/z_eff_dust.c
index b2d896a14c..c517ad007a 100644
--- a/src/overlays/actors/ovl_Eff_Dust/z_eff_dust.c
+++ b/src/overlays/actors/ovl_Eff_Dust/z_eff_dust.c
@@ -71,7 +71,7 @@ void EffDust_Init(Actor* thisx, PlayState* play) {
this->dz = 0.8f;
this->scalingFactor = 0.5f;
break;
- case EFF_DUST_TYPE_2:
+ case EFF_DUST_TYPE_SPIN_ATTACK_CHARGE:
case EFF_DUST_TYPE_3:
this->actionFunc = func_80919230;
this->actor.draw = func_809199FC;
@@ -203,7 +203,7 @@ void func_80919230(EffDust* this, PlayState* play) {
if (this->distanceTraveled[i] >= 1.0f) {
theta = randPlusMinusPoint5Scaled(0x10000);
switch (this->actor.params) {
- case EFF_DUST_TYPE_2:
+ case EFF_DUST_TYPE_SPIN_ATTACK_CHARGE:
this->initialPositions[i].x = (Rand_ZeroOne() * 4500.0f) + 700.0f;
if (this->initialPositions[i].x > 3000.0f) {
this->initialPositions[i].y = (3000.0f * Rand_ZeroOne()) * Math_SinS(theta);
diff --git a/src/overlays/actors/ovl_Eff_Dust/z_eff_dust.h b/src/overlays/actors/ovl_Eff_Dust/z_eff_dust.h
index ec864ea4d7..d73b5ce0ea 100644
--- a/src/overlays/actors/ovl_Eff_Dust/z_eff_dust.h
+++ b/src/overlays/actors/ovl_Eff_Dust/z_eff_dust.h
@@ -24,7 +24,7 @@ typedef struct EffDust {
typedef enum {
/* 0x0 */ EFF_DUST_TYPE_0,
/* 0x1 */ EFF_DUST_TYPE_1,
- /* 0x2 */ EFF_DUST_TYPE_2,
+ /* 0x2 */ EFF_DUST_TYPE_SPIN_ATTACK_CHARGE,
/* 0x3 */ EFF_DUST_TYPE_3,
/* 0x4 */ EFF_DUST_TYPE_4,
/* 0x5 */ EFF_DUST_TYPE_5
diff --git a/src/overlays/actors/ovl_En_M_Thunder/z_en_m_thunder.c b/src/overlays/actors/ovl_En_M_Thunder/z_en_m_thunder.c
index b509cf7899..fbfb170408 100644
--- a/src/overlays/actors/ovl_En_M_Thunder/z_en_m_thunder.c
+++ b/src/overlays/actors/ovl_En_M_Thunder/z_en_m_thunder.c
@@ -6,6 +6,8 @@
#include "z_en_m_thunder.h"
#include "z64rumble.h"
+#include "overlays/actors/ovl_Eff_Dust/z_eff_dust.h"
+#include "objects/gameplay_keep/gameplay_keep.h"
#define FLAGS (ACTOR_FLAG_10)
@@ -16,7 +18,17 @@ void EnMThunder_Destroy(Actor* thisx, PlayState* play);
void EnMThunder_Update(Actor* thisx, PlayState* play);
void EnMThunder_Draw(Actor* thisx, PlayState* play);
-#if 0
+void EnMThunder_UnkType_Update(Actor* thisx, PlayState* play);
+
+void EnMThunder_AdjustLights(PlayState* play, f32 arg1);
+
+void EnMThunder_Charge(EnMThunder* this, PlayState* play);
+void EnMThunder_Spin_Attack(EnMThunder* this, PlayState* play);
+void EnMThunder_SwordBeam_Attack(EnMThunder* this, PlayState* play);
+void EnMThunder_UnkType_Attack(EnMThunder* this, PlayState* play);
+
+#define ENMTHUNDER_TYPE_MAX 4
+
const ActorInit En_M_Thunder_InitVars = {
ACTOR_EN_M_THUNDER,
ACTORCAT_ITEMACTION,
@@ -29,39 +41,533 @@ const ActorInit En_M_Thunder_InitVars = {
(ActorFunc)EnMThunder_Draw,
};
-// static ColliderCylinderInit sCylinderInit = {
-static ColliderCylinderInit D_808B7120 = {
- { COLTYPE_NONE, AT_ON | AT_TYPE_PLAYER, AC_NONE, OC1_NONE, OC2_TYPE_1, COLSHAPE_CYLINDER, },
- { ELEMTYPE_UNK2, { 0x01000000, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_ON | TOUCH_SFX_NONE, BUMP_ON, OCELEM_ON, },
+static ColliderCylinderInit sCylinderInit = {
+ {
+ COLTYPE_NONE,
+ AT_ON | AT_TYPE_PLAYER,
+ AC_NONE,
+ OC1_NONE,
+ OC2_TYPE_1,
+ COLSHAPE_CYLINDER,
+ },
+ {
+ ELEMTYPE_UNK2,
+ { 0x01000000, 0x00, 0x00 },
+ { 0xF7CFFFFF, 0x00, 0x00 },
+ TOUCH_ON | TOUCH_SFX_NONE,
+ BUMP_ON,
+ OCELEM_ON,
+ },
{ 200, 200, 0, { 0, 0, 0 } },
};
-#endif
+static u8 sDamages[] = {
+ 1, 2, 3, 4, // Regular
+ 1, 2, 3, 4, // Great Spin
+};
-extern ColliderCylinderInit D_808B7120;
+static u16 sChargingSfxIds[] = {
+ NA_SE_IT_ROLLING_CUT_LV2, // ENMTHUNDER_SUBTYPE_SPIN_GREAT
+ NA_SE_IT_ROLLING_CUT_LV1, // ENMTHUNDER_SUBTYPE_SPIN_REGULAR
+ NA_SE_IT_ROLLING_CUT_LV2, // ENMTHUNDER_SUBTYPE_SWORDBEAM_GREAT
+ NA_SE_IT_ROLLING_CUT_LV1, // ENMTHUNDER_SUBTYPE_SWORDBEAM_REGULAR
+};
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_M_Thunder/func_808B53C0.s")
+static f32 sScales[] = { 0.1f, 0.15f, 0.2f, 0.25f, 0.3f, 0.25f, 0.2f, 0.15f, 0.0f };
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_M_Thunder/EnMThunder_Init.s")
+typedef enum {
+ /* 0 */ ENMTHUNDER_SUBTYPE_SPIN_GREAT,
+ /* 1 */ ENMTHUNDER_SUBTYPE_SPIN_REGULAR,
+ /* 2 */ ENMTHUNDER_SUBTYPE_SWORDBEAM_GREAT,
+ /* 3 */ ENMTHUNDER_SUBTYPE_SWORDBEAM_REGULAR
+} EnMThunderSubType;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_M_Thunder/EnMThunder_Destroy.s")
+void EnMThunder_UnkType_Setup(EnMThunder* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_M_Thunder/func_808B5890.s")
+ this->actor.update = EnMThunder_UnkType_Update;
+ this->isCharging = false;
+ this->subtype = ENMTHUNDER_SUBTYPE_SPIN_REGULAR;
+ this->scaleTarget = 2;
+ this->actionFunc = EnMThunder_UnkType_Attack;
+ this->timer = 8;
+ this->lightColorFrac = 1.0f;
+ AudioSfx_PlaySfx(NA_SE_IT_ROLLING_CUT_LV1, &player->actor.projectedPos, 4, &gSfxDefaultFreqAndVolScale,
+ &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
+ this->actor.child = NULL;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_M_Thunder/func_808B58CC.s")
+void EnMThunder_Init(Actor* thisx, PlayState* play) {
+ s32 pad;
+ EnMThunder* this = THIS;
+ Player* player = GET_PLAYER(play);
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_M_Thunder/func_808B5984.s")
+ Collider_InitCylinder(play, &this->collider);
+ Collider_SetCylinder(play, &this->collider, &this->actor, &sCylinderInit);
+ this->type = ENMTHUNDER_GET_TYPE(&this->actor);
+ Lights_PointNoGlowSetInfo(&this->lightInfo, this->actor.world.pos.x, this->actor.world.pos.y,
+ this->actor.world.pos.z, 255, 255, 255, 0);
+ this->lightNode = LightContext_InsertLight(play, &play->lightCtx, &this->lightInfo);
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_M_Thunder/func_808B5EEC.s")
+ if (this->type == ENMTHUNDER_TYPE_UNK) {
+ EnMThunder_UnkType_Setup(this, play);
+ return;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_M_Thunder/func_808B5F68.s")
+ this->collider.dim.radius = 0;
+ this->collider.dim.height = 40;
+ this->collider.dim.yShift = -20;
+ this->timer = 8;
+ this->scroll = 0.0f;
+ this->actor.world.pos = player->bodyPartsPos[0];
+ this->lightColorFrac = 0.0f;
+ this->adjustLightsArg1 = 0.0f;
+ this->actor.shape.rot.y = player->actor.shape.rot.y + 0x8000;
+ this->actor.shape.rot.x = -this->actor.world.rot.x;
+ this->actor.room = -1;
+ Actor_SetScale(&this->actor, 0.1f);
+ this->isCharging = false;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_M_Thunder/func_808B60D4.s")
+ if (player->stateFlags2 & PLAYER_STATE2_20000) {
+ if (!gSaveContext.save.playerData.isMagicAcquired || (gSaveContext.magicState != MAGIC_STATE_IDLE) ||
+ ((ENMTHUNDER_GET_MAGIC_COST(&this->actor) != 0) &&
+ !Magic_Consume(play, ENMTHUNDER_GET_MAGIC_COST(&this->actor), MAGIC_CONSUME_NOW))) {
+ AudioSfx_PlaySfx(NA_SE_IT_ROLLING_CUT, &player->actor.projectedPos, 4, &gSfxDefaultFreqAndVolScale,
+ &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
+ AudioSfx_PlaySfx(NA_SE_IT_SWORD_SWING_HARD, &player->actor.projectedPos, 4, &gSfxDefaultFreqAndVolScale,
+ &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
+ Actor_MarkForDeath(&this->actor);
+ return;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_M_Thunder/func_808B6310.s")
+ player->stateFlags2 &= ~PLAYER_STATE2_20000;
+ this->isCharging = false;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_M_Thunder/EnMThunder_Update.s")
+ if (gSaveContext.save.weekEventReg[23] & 2) {
+ player->unk_B08[0] = 1.0f;
+ this->collider.info.toucher.damage = sDamages[this->type + ENMTHUNDER_TYPE_MAX];
+ this->subtype = ENMTHUNDER_SUBTYPE_SPIN_GREAT;
+ if (this->type == ENMTHUNDER_TYPE_GREAT_FAIRY_SWORD) {
+ this->scaleTarget = 6;
+ } else if (this->type == ENMTHUNDER_TYPE_GILDED_SWORD) {
+ this->scaleTarget = 4;
+ } else {
+ this->scaleTarget = 3;
+ }
+ } else {
+ player->unk_B08[0] = 0.5f;
+ this->collider.info.toucher.damage = sDamages[this->type];
+ this->subtype = ENMTHUNDER_SUBTYPE_SPIN_REGULAR;
+ if (this->type == ENMTHUNDER_TYPE_GREAT_FAIRY_SWORD) {
+ this->scaleTarget = 4;
+ } else if (this->type == ENMTHUNDER_TYPE_GILDED_SWORD) {
+ this->scaleTarget = 3;
+ } else {
+ this->scaleTarget = 2;
+ }
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_M_Thunder/func_808B65BC.s")
+ if (player->meleeWeaponAnimation < PLAYER_MWA_SPIN_ATTACK_1H) {
+ this->subtype += ENMTHUNDER_SUBTYPE_SWORDBEAM_GREAT;
+ this->actionFunc = EnMThunder_SwordBeam_Attack;
+ this->timer = 1;
+ this->scaleTarget = 12;
+ this->collider.info.toucher.dmgFlags = DMG_SWORD_BEAM;
+ this->collider.info.toucher.damage = 3;
+ } else {
+ this->actionFunc = EnMThunder_Spin_Attack;
+ this->timer = 8;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_M_Thunder/EnMThunder_Draw.s")
+ AudioSfx_PlaySfx(NA_SE_IT_ROLLING_CUT_LV1, &player->actor.projectedPos, 4, &gSfxDefaultFreqAndVolScale,
+ &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
+
+ this->lightColorFrac = 1.0f;
+ } else {
+ this->actionFunc = EnMThunder_Charge;
+ }
+
+ this->actor.child = NULL;
+}
+
+void EnMThunder_Destroy(Actor* thisx, PlayState* play) {
+ EnMThunder* this = THIS;
+
+ if (this->isCharging) {
+ Magic_Reset(play);
+ }
+
+ Collider_DestroyCylinder(play, &this->collider);
+ EnMThunder_AdjustLights(play, 0.0f);
+ LightContext_RemoveLight(play, &play->lightCtx, this->lightNode);
+}
+
+void EnMThunder_AdjustLights(PlayState* play, f32 arg1) {
+ func_800FD2B4(play, arg1, 850.0f, 0.2f, 0.0f);
+}
+
+void EnMThunder_Spin_AttackNoMagic(EnMThunder* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+
+ if (player->stateFlags2 & PLAYER_STATE2_20000) {
+ if (player->meleeWeaponAnimation >= PLAYER_MWA_SPIN_ATTACK_1H) {
+ AudioSfx_PlaySfx(NA_SE_IT_ROLLING_CUT, &player->actor.projectedPos, 4, &gSfxDefaultFreqAndVolScale,
+ &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
+ AudioSfx_PlaySfx(NA_SE_IT_SWORD_SWING_HARD, &player->actor.projectedPos, 4, &gSfxDefaultFreqAndVolScale,
+ &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
+ }
+ Actor_MarkForDeath(&this->actor);
+ } else if (!(player->stateFlags1 & PLAYER_STATE1_1000)) {
+ Actor_MarkForDeath(&this->actor);
+ }
+}
+
+void EnMThunder_Charge(EnMThunder* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+ Actor* child = this->actor.child;
+
+ this->unk1B0 = player->unk_B08[0];
+ this->actor.world.pos = player->bodyPartsPos[0];
+ this->actor.shape.rot.y = player->actor.shape.rot.y + 0x8000;
+
+ if (!this->isCharging && (player->unk_B08[0] >= 0.1f)) {
+ if ((gSaveContext.magicState != MAGIC_STATE_IDLE) ||
+ ((ENMTHUNDER_GET_MAGIC_COST(&this->actor) != 0) &&
+ !Magic_Consume(play, ENMTHUNDER_GET_MAGIC_COST(&this->actor), MAGIC_CONSUME_WAIT_PREVIEW))) {
+ EnMThunder_Spin_AttackNoMagic(this, play);
+ this->actionFunc = EnMThunder_Spin_AttackNoMagic;
+ this->chargingAlpha = 0;
+ this->adjustLightsArg1 = 0.0f;
+ this->lightColorFrac = 0.0f;
+ return;
+ }
+ this->isCharging = true;
+ }
+
+ if (player->unk_B08[0] >= 0.1f) {
+ Rumble_Request(0.0f, (s32)(player->unk_B08[0] * 150.0f), 2, (s32)(player->unk_B08[0] * 150.0f));
+ }
+
+ if (player->stateFlags2 & PLAYER_STATE2_20000) {
+ if ((child != NULL) && (child->update != NULL)) {
+ child->parent = NULL;
+ }
+
+ if (player->unk_B08[0] <= 0.15f) {
+ if ((player->unk_B08[0] >= 0.1f) && (player->meleeWeaponAnimation >= PLAYER_MWA_SPIN_ATTACK_1H)) {
+ AudioSfx_PlaySfx(NA_SE_IT_ROLLING_CUT, &player->actor.projectedPos, 4, &gSfxDefaultFreqAndVolScale,
+ &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
+ AudioSfx_PlaySfx(NA_SE_IT_SWORD_SWING_HARD, &player->actor.projectedPos, 4, &gSfxDefaultFreqAndVolScale,
+ &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
+ }
+ Actor_MarkForDeath(&this->actor);
+ return;
+ }
+
+ player->stateFlags2 &= ~PLAYER_STATE2_20000;
+
+ if (ENMTHUNDER_GET_MAGIC_COST(&this->actor) != 0) {
+ gSaveContext.magicState = MAGIC_STATE_CONSUME_SETUP;
+ }
+
+ if (player->unk_B08[0] < 0.85f) {
+ this->collider.info.toucher.damage = sDamages[this->type];
+ this->subtype = ENMTHUNDER_SUBTYPE_SPIN_REGULAR;
+ if (this->type == ENMTHUNDER_TYPE_GREAT_FAIRY_SWORD) {
+ this->scaleTarget = 4;
+ } else if (this->type == ENMTHUNDER_TYPE_GILDED_SWORD) {
+ this->scaleTarget = 3;
+ } else {
+ this->scaleTarget = 2;
+ }
+ } else {
+ this->collider.info.toucher.damage = sDamages[this->type + ENMTHUNDER_TYPE_MAX];
+ this->subtype = ENMTHUNDER_SUBTYPE_SPIN_GREAT;
+ if (this->type == ENMTHUNDER_TYPE_GREAT_FAIRY_SWORD) {
+ this->scaleTarget = 6;
+ } else if (this->type == ENMTHUNDER_TYPE_GILDED_SWORD) {
+ this->scaleTarget = 4;
+ } else {
+ this->scaleTarget = 3;
+ }
+ }
+
+ if (player->meleeWeaponAnimation < PLAYER_MWA_SPIN_ATTACK_1H) {
+ this->subtype += ENMTHUNDER_SUBTYPE_SWORDBEAM_GREAT;
+ this->actionFunc = EnMThunder_SwordBeam_Attack;
+ this->timer = 1;
+ } else {
+ this->actionFunc = EnMThunder_Spin_Attack;
+ this->timer = 8;
+ }
+
+ AudioSfx_PlaySfx(sChargingSfxIds[this->subtype], &player->actor.projectedPos, 4, &gSfxDefaultFreqAndVolScale,
+ &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
+
+ this->lightColorFrac = 1.0f;
+
+ return;
+ }
+
+ if (!(player->stateFlags1 & PLAYER_STATE1_1000)) {
+ if (this->actor.child != NULL) {
+ this->actor.child->parent = NULL;
+ }
+ Actor_MarkForDeath(&this->actor);
+ return;
+ }
+
+ if (player->unk_B08[0] > 0.15f) {
+ this->chargingAlpha = 255;
+ if (this->actor.child == NULL) {
+ Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_EFF_DUST, this->actor.world.pos.x,
+ this->actor.world.pos.y, this->actor.world.pos.z, 0, this->actor.shape.rot.y, 0,
+ EFF_DUST_TYPE_SPIN_ATTACK_CHARGE);
+ }
+ this->adjustLightsArg1 += (((player->unk_B08[0] - 0.15f) * 1.5f) - this->adjustLightsArg1) * 0.5f;
+ } else if (player->unk_B08[0] > .1f) {
+ this->chargingAlpha = (s32)((player->unk_B08[0] - .1f) * 255.0f * 20.0f);
+ this->lightColorFrac = (player->unk_B08[0] - .1f) * 10.0f;
+ } else {
+ this->chargingAlpha = 0;
+ }
+
+ if (player->unk_B08[0] > 0.85f) {
+ func_8019F900(&player->actor.projectedPos, 2);
+ } else if (player->unk_B08[0] > 0.15f) {
+ func_8019F900(&player->actor.projectedPos, 1);
+ } else if (player->unk_B08[0] > 0.1f) {
+ func_8019F900(&player->actor.projectedPos, 0);
+ }
+
+ if (Play_InCsMode(play)) {
+ Actor_MarkForDeath(&this->actor);
+ }
+}
+
+void func_808B5EEC(EnMThunder* this, PlayState* play) {
+ if (this->timer < 2) {
+ if (this->chargingAlpha < 40) {
+ this->chargingAlpha = 0;
+ } else {
+ this->chargingAlpha -= 40;
+ }
+ }
+
+ this->scroll += 2.0f * this->alphaFrac;
+
+ if (this->adjustLightsArg1 < this->lightColorFrac) {
+ this->adjustLightsArg1 = F32_LERPIMP(this->adjustLightsArg1, this->lightColorFrac, 0.1f);
+ } else {
+ this->adjustLightsArg1 = this->lightColorFrac;
+ }
+}
+
+void EnMThunder_Spin_Attack(EnMThunder* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+
+ if (Math_StepToF(&this->lightColorFrac, 0.0f, 0.0625f)) {
+ Actor_MarkForDeath(&this->actor);
+ } else {
+ Math_SmoothStepToF(&this->actor.scale.x, (s32)this->scaleTarget, 0.6f, 0.8f, 0.0f);
+ Actor_SetScale(&this->actor, this->actor.scale.x);
+ this->collider.dim.radius = this->actor.scale.x * 30.0f;
+ Collider_UpdateCylinder(&this->actor, &this->collider);
+ CollisionCheck_SetAT(play, &play->colChkCtx, &this->collider.base);
+ }
+
+ if (this->timer > 0) {
+ this->actor.world.pos.x = player->bodyPartsPos[0].x;
+ this->actor.world.pos.z = player->bodyPartsPos[0].z;
+ this->timer--;
+ }
+
+ if (this->lightColorFrac > (6.0f / 10.0f)) {
+ this->alphaFrac = 1.0f;
+ } else {
+ this->alphaFrac = this->lightColorFrac * (10.0f / 6.0f);
+ }
+
+ func_808B5EEC(this, play);
+
+ if (Play_InCsMode(play)) {
+ Actor_MarkForDeath(&this->actor);
+ }
+}
+
+void EnMThunder_SwordBeam_Attack(EnMThunder* this, PlayState* play) {
+ s32 pad[2];
+ f32 sp2C;
+
+ if (this->lightColorFrac > (9.0f / 10.0f)) {
+ this->alphaFrac = 1.0f;
+ } else {
+ this->alphaFrac = this->lightColorFrac * (10.0f / 9.0f);
+ }
+
+ if (Math_StepToF(&this->lightColorFrac, 0.0f, 0.05f)) {
+ Actor_MarkForDeath(&this->actor);
+ } else {
+ sp2C = -80.0f * Math_CosS(this->actor.world.rot.x);
+
+ this->actor.world.pos.x += sp2C * Math_SinS(this->actor.shape.rot.y);
+ this->actor.world.pos.z += sp2C * Math_CosS(this->actor.shape.rot.y);
+ this->actor.world.pos.y += -80.0f * Math_SinS(this->actor.world.rot.x);
+
+ Math_SmoothStepToF(&this->actor.scale.x, this->scaleTarget, 0.6f, 2.0f, 0.0f);
+ Actor_SetScale(&this->actor, this->actor.scale.x);
+
+ this->collider.dim.radius = this->actor.scale.x * 5.0f;
+
+ this->collider.dim.pos.x = this->actor.world.pos.x;
+ this->collider.dim.pos.y = this->actor.world.pos.y;
+ this->collider.dim.pos.z = this->actor.world.pos.z;
+
+ this->collider.dim.pos.x =
+ (Math_SinS(this->actor.shape.rot.y) * -5.0f * this->actor.scale.x) + this->actor.world.pos.x;
+ this->collider.dim.pos.y = this->actor.world.pos.y;
+ this->collider.dim.pos.z =
+ (Math_CosS(this->actor.shape.rot.y) * -5.0f * this->actor.scale.z) + this->actor.world.pos.z;
+
+ CollisionCheck_SetAT(play, &play->colChkCtx, &this->collider.base);
+ }
+
+ if (this->timer > 0) {
+ this->timer--;
+ }
+
+ func_808B5EEC(this, play);
+}
+
+void EnMThunder_UnkType_Attack(EnMThunder* this, PlayState* play) {
+ if (Math_StepToF(&this->lightColorFrac, 0.0f, 0.0625f)) {
+ Actor_MarkForDeath(&this->actor);
+ } else {
+ Math_SmoothStepToF(&this->actor.scale.x, (s32)this->scaleTarget, 0.6f, 0.8f, 0.0f);
+ Actor_SetScale(&this->actor, this->actor.scale.x);
+ }
+
+ if (this->lightColorFrac > (6.0f / 10.0f)) {
+ this->alphaFrac = 1.0f;
+ } else {
+ this->alphaFrac = this->lightColorFrac * (10.0f / 6.0f);
+ }
+
+ func_808B5EEC(this, play);
+}
+
+void EnMThunder_Update(Actor* thisx, PlayState* play) {
+ EnMThunder* this = THIS;
+
+ this->actionFunc(this, play);
+ EnMThunder_AdjustLights(play, this->adjustLightsArg1);
+ Lights_PointNoGlowSetInfo(&this->lightInfo, this->actor.world.pos.x, this->actor.world.pos.y,
+ this->actor.world.pos.z, this->lightColorFrac * 255.0f, this->lightColorFrac * 255.0f,
+ this->lightColorFrac * 100.0f, this->lightColorFrac * 800.0f);
+}
+
+void EnMThunder_UnkType_Update(Actor* thisx, PlayState* play) {
+ EnMThunder* this = THIS;
+
+ this->actionFunc(this, play);
+ Lights_PointNoGlowSetInfo(&this->lightInfo, this->actor.world.pos.x, this->actor.world.pos.y,
+ this->actor.world.pos.z, this->lightColorFrac * 255.0f, this->lightColorFrac * 255.0f,
+ this->lightColorFrac * 100.0f, this->lightColorFrac * 800.0f);
+}
+
+void EnMThunder_Draw(Actor* thisx, PlayState* play2) {
+ PlayState* play = play2;
+ EnMThunder* this = THIS;
+ Player* player = GET_PLAYER(play);
+ f32 scale;
+ s32 y2Scroll;
+
+ OPEN_DISPS(play->state.gfxCtx);
+
+ func_8012C2DC(play->state.gfxCtx);
+ Matrix_Scale(0.02f, 0.02f, 0.02f, MTXMODE_APPLY);
+
+ gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
+
+ switch (this->subtype) {
+ case ENMTHUNDER_SUBTYPE_SPIN_GREAT:
+ case ENMTHUNDER_SUBTYPE_SPIN_REGULAR:
+ gSPSegment(POLY_XLU_DISP++, 0x08,
+ Gfx_TwoTexScroll(play->state.gfxCtx, 0, 0xFF - ((u16)(s32)(this->scroll * 30.0f) & 0xFF), 0, 64,
+ 32, 1, 0xFF - ((u16)(s32)(this->scroll * 20.0f) & 0xFF), 0, 8, 8));
+ break;
+
+ case ENMTHUNDER_SUBTYPE_SWORDBEAM_GREAT:
+ case ENMTHUNDER_SUBTYPE_SWORDBEAM_REGULAR:
+ gSPSegment(POLY_XLU_DISP++, 0x08,
+ Gfx_TwoTexScroll(play->state.gfxCtx, 0, 0, 0, 16, 64, 1, 0,
+ 0x1FF - ((u16)(s32)(this->scroll * 10.0f) & 0x1FF), 32, 128));
+ break;
+
+ default:
+ break;
+ }
+
+ switch (this->subtype) {
+ case ENMTHUNDER_SUBTYPE_SPIN_GREAT:
+ gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, 255, 255, 170, (u16)(this->alphaFrac * 255.0f));
+ gSPDisplayList(POLY_XLU_DISP++, gGreatSpinAttackDiskDL);
+ gSPDisplayList(POLY_XLU_DISP++, gGreatSpinAttackCylinderDL);
+ break;
+
+ case ENMTHUNDER_SUBTYPE_SPIN_REGULAR:
+ gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, 170, 255, 255, (u16)(this->alphaFrac * 255.0f));
+ gSPDisplayList(POLY_XLU_DISP++, gSpinAttackDiskDL);
+ gSPDisplayList(POLY_XLU_DISP++, gSpinAttackCylinderDL);
+ break;
+
+ case ENMTHUNDER_SUBTYPE_SWORDBEAM_REGULAR:
+ gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, 170, 255, 255, (u16)(this->alphaFrac * 255.0f));
+ gDPSetEnvColor(POLY_XLU_DISP++, 0, 100, 255, 128);
+ gSPDisplayList(POLY_XLU_DISP++, gSwordBeamDL);
+ break;
+
+ case ENMTHUNDER_SUBTYPE_SWORDBEAM_GREAT:
+ gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, 0, 255, 255, (u16)(this->alphaFrac * 255.0f));
+ gDPSetEnvColor(POLY_XLU_DISP++, 200, 200, 200, 128);
+ gSPDisplayList(POLY_XLU_DISP++, gSwordBeamDL);
+ break;
+
+ default:
+ break;
+ }
+
+ Matrix_Mult(&player->mf_CC4, MTXMODE_NEW);
+
+ if (this->type == ENMTHUNDER_TYPE_GILDED_SWORD) {
+ Matrix_Translate(0.0f, 220.0f, 0.0f, MTXMODE_APPLY);
+ Matrix_Scale(-1.2f, -0.8f, -0.6f, MTXMODE_APPLY);
+ Matrix_RotateXS(0x4000, MTXMODE_APPLY);
+ } else {
+ Matrix_Translate(0.0f, 220.0f, 0.0f, MTXMODE_APPLY);
+ Matrix_Scale(-0.7f, -0.6f, -0.4f, MTXMODE_APPLY);
+ Matrix_RotateXS(0x4000, MTXMODE_APPLY);
+ }
+
+ if (this->unk1B0 >= 0.85f) {
+ scale = (sScales[play->gameplayFrames & 7] * 6.0f) + 1.0f;
+ gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, 255, 255, 170, this->chargingAlpha);
+ gDPSetEnvColor(POLY_XLU_DISP++, 255, 100, 0, 128);
+ y2Scroll = 40;
+ } else {
+ scale = (sScales[play->gameplayFrames & 7] * 2.0f) + 1.0f;
+ gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, 170, 255, 255, this->chargingAlpha);
+ gDPSetEnvColor(POLY_XLU_DISP++, 0, 100, 255, 128);
+ y2Scroll = 20;
+ }
+
+ Matrix_Scale(1.0f, scale, scale, MTXMODE_APPLY);
+
+ gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
+ gSPSegment(POLY_XLU_DISP++, 0x09,
+ Gfx_TwoTexScroll(play->state.gfxCtx, 0, (play->gameplayFrames * 5) & 0xFF, 0, 32, 32, 1,
+ (play->gameplayFrames * 20) & 0xFF, (play->gameplayFrames * y2Scroll) & 0xFF, 8, 8));
+ gSPDisplayList(POLY_XLU_DISP++, gSpinAttackChargingDL);
+
+ CLOSE_DISPS(play->state.gfxCtx);
+}
diff --git a/src/overlays/actors/ovl_En_M_Thunder/z_en_m_thunder.h b/src/overlays/actors/ovl_En_M_Thunder/z_en_m_thunder.h
index 14d0227704..7ac851e920 100644
--- a/src/overlays/actors/ovl_En_M_Thunder/z_en_m_thunder.h
+++ b/src/overlays/actors/ovl_En_M_Thunder/z_en_m_thunder.h
@@ -5,13 +5,36 @@
struct EnMThunder;
+#define ENMTHUNDER_GET_TYPE(thisx) ((thisx)->params & 0xFF)
+#define ENMTHUNDER_GET_MAGIC_COST(thisx) (((thisx)->params & 0xFF00) >> 8)
+
+typedef enum {
+ /* 0x00 */ ENMTHUNDER_TYPE_KOKIRI_SWORD,
+ /* 0x01 */ ENMTHUNDER_TYPE_RAZOR_SWORD,
+ /* 0x02 */ ENMTHUNDER_TYPE_GILDED_SWORD,
+ /* 0x03 */ ENMTHUNDER_TYPE_GREAT_FAIRY_SWORD,
+ /* 0x80 */ ENMTHUNDER_TYPE_UNK = 0x80
+} EnMThunderType;
+
typedef void (*EnMThunderActionFunc)(struct EnMThunder*, PlayState*);
typedef struct EnMThunder {
/* 0x000 */ Actor actor;
- /* 0x144 */ char unk_144[0x74];
+ /* 0x144 */ ColliderCylinder collider;
+ /* 0x190 */ LightNode* lightNode;
+ /* 0x194 */ LightInfo lightInfo;
+ /* 0x1A4 */ f32 lightColorFrac;
+ /* 0x1A8 */ f32 alphaFrac;
+ /* 0x1AC */ f32 scroll;
+ /* 0x1B0 */ f32 unk1B0;
+ /* 0x1B4 */ f32 adjustLightsArg1;
/* 0x1B8 */ EnMThunderActionFunc actionFunc;
- /* 0x1BC */ char unk_1BC[0x8];
+ /* 0x1BC */ u16 timer;
+ /* 0x1BE */ u8 subtype;
+ /* 0x1BF */ u8 type;
+ /* 0x1C0 */ u8 chargingAlpha;
+ /* 0x1C1 */ u8 scaleTarget;
+ /* 0x1C2 */ u8 isCharging;
} EnMThunder; // size = 0x1C4
extern const ActorInit En_M_Thunder_InitVars;
diff --git a/src/overlays/actors/ovl_En_St/z_en_st.c b/src/overlays/actors/ovl_En_St/z_en_st.c
index 7d0dcbf114..ecc2b85b22 100644
--- a/src/overlays/actors/ovl_En_St/z_en_st.c
+++ b/src/overlays/actors/ovl_En_St/z_en_st.c
@@ -260,8 +260,8 @@ void func_808A54B0(EnSt* this, PlayState* play) {
}
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, 170, 255, 255, (u8)(255 * temp_f0));
- gSPDisplayList(POLY_XLU_DISP++, gameplay_keep_DL_025850);
- gSPDisplayList(POLY_XLU_DISP++, gameplay_keep_DL_025970);
+ gSPDisplayList(POLY_XLU_DISP++, gSpinAttackDiskDL);
+ gSPDisplayList(POLY_XLU_DISP++, gSpinAttackCylinderDL);
CLOSE_DISPS(play->state.gfxCtx);
}
diff --git a/tools/disasm/functions.txt b/tools/disasm/functions.txt
index ef47869a5d..a465f75992 100644
--- a/tools/disasm/functions.txt
+++ b/tools/disasm/functions.txt
@@ -5947,18 +5947,18 @@
0x808B5230:("EnMFire1_Init",),
0x808B5294:("EnMFire1_Destroy",),
0x808B52C0:("EnMFire1_Update",),
- 0x808B53C0:("func_808B53C0",),
+ 0x808B53C0:("EnMThunder_UnkType_Setup",),
0x808B545C:("EnMThunder_Init",),
0x808B5820:("EnMThunder_Destroy",),
- 0x808B5890:("func_808B5890",),
- 0x808B58CC:("func_808B58CC",),
- 0x808B5984:("func_808B5984",),
+ 0x808B5890:("EnMThunder_AdjustLights",),
+ 0x808B58CC:("EnMThunder_Spin_AttackNoMagic",),
+ 0x808B5984:("EnMThunder_Charge",),
0x808B5EEC:("func_808B5EEC",),
- 0x808B5F68:("func_808B5F68",),
- 0x808B60D4:("func_808B60D4",),
- 0x808B6310:("func_808B6310",),
+ 0x808B5F68:("EnMThunder_Spin_Attack",),
+ 0x808B60D4:("EnMThunder_SwordBeam_Attack",),
+ 0x808B6310:("EnMThunder_UnkType_Attack",),
0x808B63E8:("EnMThunder_Update",),
- 0x808B65BC:("func_808B65BC",),
+ 0x808B65BC:("EnMThunder_UnkType_Update",),
0x808B677C:("EnMThunder_Draw",),
0x808B7360:("BgBreakwall_SetupAction",),
0x808B736C:("func_808B736C",),