Shipwright/soh/src/overlays/actors/ovl_Boss_Mo/z_boss_mo.c

3616 lines
155 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* File: z_boss_mo.c
* Overlay: ovl_Boss_Mo
* Description: Morpha
*/
#include "z_boss_mo.h"
#include "objects/object_mo/object_mo.h"
#include "overlays/actors/ovl_Door_Warp1/z_door_warp1.h"
#include "objects/gameplay_keep/gameplay_keep.h"
#include "vt.h"
#include "soh/frame_interpolation.h"
#include <string.h>
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_2 | ACTOR_FLAG_4 | ACTOR_FLAG_5)
#define MO_WATER_LEVEL(globalCtx) globalCtx->colCtx.colHeader->waterBoxes[0].ySurface
#define HAS_LINK(tent) \
((tent != NULL) && \
((tent->work[MO_TENT_ACTION_STATE] == MO_TENT_GRAB) || (tent->work[MO_TENT_ACTION_STATE] == MO_TENT_SHAKE)))
typedef struct {
/* 0x00 */ Vec3f pos;
/* 0x0C */ Vec3f vel;
/* 0x18 */ Vec3f accel;
/* 0x24 */ u8 type;
/* 0x25 */ u8 timer;
/* 0x26 */ u8 stopTimer;
/* 0x28 */ s16 unk_28; // unused?
/* 0x2A */ s16 alpha;
/* 0x2C */ s16 rippleMode;
/* 0x2E */ s16 maxAlpha;
/* 0x30 */ f32 scale;
/* 0x30 */ f32 fwork[2];
/* 0x3C */ Vec3f* targetPos;
u32 epoch;
} BossMoEffect; // size = 0x40
#define MO_FX_MAX_SIZE 0
#define MO_FX_SHIMMER 0
#define MO_FX_SUCTION 0
#define MO_FX_SPREAD_RATE 1
#define MO_FX_STRETCH 1
#define MO_FX_MAX_SCALE 1
void BossMo_Init(Actor* thisx, GlobalContext* globalCtx);
void BossMo_Destroy(Actor* thisx, GlobalContext* globalCtx);
void BossMo_UpdateCore(Actor* thisx, GlobalContext* globalCtx);
void BossMo_UpdateTent(Actor* thisx, GlobalContext* globalCtx);
void BossMo_DrawCore(Actor* thisx, GlobalContext* globalCtx);
void BossMo_DrawTent(Actor* thisx, GlobalContext* globalCtx);
void BossMo_Reset(void);
void BossMo_UpdateEffects(BossMo* this, GlobalContext* globalCtx);
void BossMo_DrawEffects(BossMoEffect* effect, GlobalContext* globalCtx);
void BossMo_SetupTentacle(BossMo* this, GlobalContext* globalCtx);
void BossMo_Tentacle(BossMo* this, GlobalContext* globalCtx);
void BossMo_Unknown(void);
typedef enum {
/* 0 */ MO_FX_NONE,
/* 1 */ MO_FX_SMALL_RIPPLE,
/* 2 */ MO_FX_BIG_RIPPLE,
/* 3 */ MO_FX_DROPLET,
/* 4 */ MO_FX_SPLASH,
/* 5 */ MO_FX_SPLASH_TRAIL,
/* 6 */ MO_FX_WET_SPOT,
/* 7 */ MO_FX_BUBBLE
} BossMoEffectType;
typedef enum {
/* 0 */ MO_TENT_READY,
/* 1 */ MO_TENT_SWING,
/* 2 */ MO_TENT_ATTACK,
/* 3 */ MO_TENT_CURL,
/* 4 */ MO_TENT_GRAB,
/* 5 */ MO_TENT_SHAKE,
/* 10 */ MO_TENT_WAIT = 10,
/* 11 */ MO_TENT_SPAWN,
/* 100 */ MO_TENT_CUT = 100,
/* 101 */ MO_TENT_RETREAT,
/* 102 */ MO_TENT_DESPAWN,
/* 200 */ MO_TENT_DEATH_START = 200,
/* 201 */ MO_TENT_DEATH_1,
/* 202 */ MO_TENT_DEATH_2,
/* 203 */ MO_TENT_DEATH_3,
/* 205 */ MO_TENT_DEATH_5 = 205,
/* 206 */ MO_TENT_DEATH_6
} BossMoTentState;
typedef enum {
/* -11 */ MO_CORE_UNUSED = -11,
/* 0 */ MO_CORE_MOVE = 0,
/* 1 */ MO_CORE_MAKE_TENT,
/* 2 */ MO_CORE_UNDERWATER,
/* 5 */ MO_CORE_STUNNED = 5,
/* 10 */ MO_CORE_ATTACK = 10,
/* 11 */ MO_CORE_RETREAT,
/* 20 */ MO_CORE_INTRO_WAIT = 20,
/* 21 */ MO_CORE_INTRO_REVEAL
} BossMoCoreState;
typedef enum {
/* 0 */ MO_BATTLE,
/* 1 */ MO_INTRO_WAIT,
/* 2 */ MO_INTRO_START,
/* 3 */ MO_INTRO_SWIM,
/* 4 */ MO_INTRO_REVEAL,
/* 5 */ MO_INTRO_FINISH,
/* 100 */ MO_DEATH_START = 100,
/* 101 */ MO_DEATH_DRAIN_WATER_1,
/* 102 */ MO_DEATH_DRAIN_WATER_2,
/* 103 */ MO_DEATH_CEILING,
/* 104 */ MO_DEATH_DROPLET,
/* 105 */ MO_DEATH_FINISH,
/* 150 */ MO_DEATH_MO_CORE_BURST = 150
} BossMoCsState;
const ActorInit Boss_Mo_InitVars = {
ACTOR_BOSS_MO,
ACTORCAT_BOSS,
FLAGS,
OBJECT_MO,
sizeof(BossMo),
(ActorFunc)BossMo_Init,
(ActorFunc)BossMo_Destroy,
(ActorFunc)BossMo_UpdateTent,
(ActorFunc)BossMo_DrawTent,
(ActorResetFunc)BossMo_Reset,
};
static BossMo* sMorphaCore = NULL;
static BossMo* sMorphaTent1 = NULL;
static BossMo* sMorphaTent2 = NULL;
static f32 sFlatWidth[41] = {
15.0f, 12.0f, 9.0f, 6.5f, 4.8f, 4.0f, 3.4f, 3.1f, 3.0f, 3.1f, 3.2f, 3.4f, 3.6f, 3.8f,
4.0f, 4.6f, 5.1f, 5.5f, 6.1f, 6.6f, 7.3f, 7.7f, 8.4f, 8.5f, 8.7f, 8.8f, 8.8f, 8.7f,
8.6f, 8.3f, 8.2f, 8.1f, 7.2f, 6.7f, 5.9f, 4.9f, 2.7f, 0.0f, 0.0f, 0.0f, 0.0f,
};
#include "z_boss_mo_colchk.c"
static BossMoEffect sEffects[300];
static s32 sBossGanonSeed1;
static s32 sBossGanonSeed2;
static s32 sBossGanonSeed3;
void BossMo_InitRand(s32 seedInit0, s32 seedInit1, s32 seedInit2) {
sBossGanonSeed1 = seedInit0;
sBossGanonSeed2 = seedInit1;
sBossGanonSeed3 = seedInit2;
}
f32 BossMo_RandZeroOne(void) {
// Wichmann-Hill algorithm
f32 randFloat;
sBossGanonSeed1 = (sBossGanonSeed1 * 171) % 30269;
sBossGanonSeed2 = (sBossGanonSeed2 * 172) % 30307;
sBossGanonSeed3 = (sBossGanonSeed3 * 170) % 30323;
randFloat = (sBossGanonSeed1 / 30269.0f) + (sBossGanonSeed2 / 30307.0f) + (sBossGanonSeed3 / 30323.0f);
while (randFloat >= 1.0f) {
randFloat -= 1.0f;
}
return fabsf(randFloat);
}
s32 BossMo_NearLand(Vec3f* pos, f32 margin) {
if (450.0f - margin <= fabsf(pos->x)) {
return true;
}
if (450.0f - margin <= fabsf(pos->z)) {
return true;
}
if ((fabsf(pos->x - 180.0f) < 90.0f + margin) || (fabsf(pos->x - -180.0f) < 90.0f + margin)) {
if (fabsf(pos->z - 180.0f) < 90.0f + margin) {
return true;
}
if (fabsf(pos->z - -180.0f) < 90.0f + margin) {
return true;
}
}
return false;
}
void BossMo_SpawnRipple(BossMoEffect* effect, Vec3f* pos, f32 scale, f32 maxScale, s16 maxAlpha, s16 partLimit,
u8 type) {
static Vec3f zeroVec = { 0.0f, 0.0f, 0.0f };
s16 i;
for (i = 0; i < partLimit; i++, effect++) {
if (effect->type == MO_FX_NONE) {
effect->stopTimer = 0;
effect->type = type;
effect->pos = *pos;
effect->vel = zeroVec;
effect->accel = zeroVec;
effect->scale = scale * 0.0025f;
effect->fwork[MO_FX_MAX_SIZE] = maxScale * 0.0025f;
if (scale > 300.0f) {
effect->alpha = 0;
effect->maxAlpha = maxAlpha;
effect->rippleMode = 0;
effect->fwork[MO_FX_SPREAD_RATE] = (effect->fwork[MO_FX_MAX_SIZE] - effect->scale) * 0.05f;
} else {
effect->alpha = maxAlpha;
effect->rippleMode = 1;
effect->fwork[MO_FX_SPREAD_RATE] = (effect->fwork[MO_FX_MAX_SIZE] - effect->scale) * 0.1f;
}
effect->epoch++;
break;
}
}
}
void BossMo_SpawnDroplet(s16 type, BossMoEffect* effect, Vec3f* pos, Vec3f* vel, f32 scale) {
s16 i;
Vec3f gravity = { 0.0f, -1.0f, 0.0f };
for (i = 0; i < 290; i++, effect++) {
if (effect->type == MO_FX_NONE) {
effect->type = type;
effect->pos = *pos;
effect->vel = *vel;
effect->accel = gravity;
if (type == MO_FX_SPLASH_TRAIL) {
effect->accel.y = 0.0f;
}
effect->scale = scale;
effect->fwork[MO_FX_SPREAD_RATE] = 1.0f;
effect->stopTimer = 0;
effect->epoch++;
break;
}
}
}
void BossMo_SpawnStillDroplet(BossMoEffect* effect, Vec3f* pos, f32 scale) {
s16 i;
Vec3f zeroVec = { 0.0f, 0.0f, 0.0f };
for (i = 0; i < 290; i++, effect++) {
if (effect->type == MO_FX_NONE) {
effect->type = MO_FX_DROPLET;
effect->stopTimer = 2;
effect->pos = *pos;
effect->vel = zeroVec;
effect->accel = zeroVec;
effect->scale = scale;
effect->fwork[MO_FX_SPREAD_RATE] = 1.0f;
effect->epoch++;
break;
}
}
}
void BossMo_SpawnBubble(BossMoEffect* effect, Vec3f* pos, Vec3f* vel, Vec3f* accel, f32 scale, Vec3f* targetPos) {
s16 i;
for (i = 0; i < 280; i++, effect++) {
if (effect->type == MO_FX_NONE) {
effect->type = MO_FX_BUBBLE;
effect->stopTimer = 0;
effect->pos = *pos;
effect->vel = *vel;
effect->accel = *accel;
effect->scale = scale;
effect->fwork[MO_FX_SUCTION] = 0.0f;
effect->targetPos = targetPos;
if (targetPos == NULL) {
effect->alpha = 255;
} else {
effect->alpha = 0;
}
effect->timer = 0;
effect->epoch++;
break;
}
}
}
static s16 sCurlRot[41] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 8, 8, 8, 9, 9, 9,
9, 9, 9, 12, 15, 15, 15, 15, 15, 15, 15, 20, 20, 20, 0, 0, 0, 0, 0, 0,
};
static s16 sGrabRot[41] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -5, -5, -5,
0, 5, 10, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0,
};
static s16 sAttackRot[41] = {
0, 5, 6, 7, 8, 8, 7, 6, 6, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
static InitChainEntry sInitChain[] = {
ICHAIN_U8(targetMode, 5, ICHAIN_CONTINUE),
ICHAIN_S8(naviEnemyId, 0x25, ICHAIN_CONTINUE),
ICHAIN_F32_DIV1000(gravity, 0, ICHAIN_CONTINUE),
ICHAIN_F32(targetArrowOffset, 0, ICHAIN_STOP),
};
static Vec3f sAudioZeroVec = { 0.0f, 0.0f, 0.0f };
static u8 sTentSpawnIndex[21] = { 0, 1, 2, 3, 4, 15, 19, 5, 14, 16, 17, 18, 6, 13, 20, 7, 12, 11, 10, 9, 8 };
static Vec2f sTentSpawnPos[21] = {
{ -360.0f, -360.0f }, { -180.0f, -360.0f }, { 0.0f, -360.0f }, { 180.0f, -360.0f }, { 360.0f, -360.0f },
{ -360.0f, -180.0f }, { 0.0f, -180.0f }, { 360.0f, -180.0f }, { -360.0f, 0.0f }, { -180.0f, 0.0f },
{ 0.0f, 0.0f }, { 180.0f, 0.0f }, { 360.0f, 0.0f }, { -360.0f, 180.0f }, { 0.0f, 180.0f },
{ 360.0f, 180.0f }, { -360.0f, 360.0f }, { -180.0f, 360.0f }, { 0.0f, 360.0f }, { 180.0f, 360.0f },
{ 360.0f, 360.0f },
};
static f32 sTentWidth[41] = {
3.56f, 3.25f, 2.96f, 2.69f, 2.44f, 2.21f, 2.0f, 1.81f, 1.64f, 1.49f, 1.36f, 1.25f, 1.16f, 1.09f,
1.04f, 1.01f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f, 0.98f, 0.95f, 0.9f, 0.8f, 0.6f, 1.0f, 1.0f, 1.0f, 1.0f,
};
static f32 sDropletWidth[41] = {
0.0f, 2.95804f, 4.123106f, 4.974937f, 5.656854f, 6.22495f, 6.708204f, 7.123903f, 7.483315f,
7.794229f, 8.062258f, 8.291562f, 8.485281f, 8.645808f, 8.774964f, 8.87412f, 8.944272f, 8.9861f,
9.0f, 8.9861f, 8.944272f, 8.87412f, 8.774964f, 8.645808f, 8.485281f, 8.291562f, 8.062258f,
7.794229f, 7.483315f, 7.123903f, 6.708204f, 6.22495f, 5.656854f, 4.974937f, 4.123106f, 2.95804f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
}; // These are sqrt(9^2 - (i/2 - 9)^2), a sphere of radius 9.
void BossMo_Init(Actor* thisx, GlobalContext* globalCtx2) {
GlobalContext* globalCtx = globalCtx2;
BossMo* this = (BossMo*)thisx;
u16 i;
Actor_ProcessInitChain(&this->actor, sInitChain);
ActorShape_Init(&this->actor.shape, 0.0f, NULL, 0.0f);
if (this->actor.params != BOSSMO_TENTACLE) {
Flags_SetSwitch(globalCtx, 0x14);
sMorphaCore = this;
MO_WATER_LEVEL(globalCtx) = this->waterLevel = MO_WATER_LEVEL(globalCtx);
globalCtx->roomCtx.unk_74[0] = 0xA0;
globalCtx->specialEffects = sEffects;
for (i = 0; i < ARRAY_COUNT(sEffects); i++) {
sEffects[i].type = MO_FX_NONE;
sEffects[i].epoch++;
}
this->actor.world.pos.x = 200.0f;
this->actor.world.pos.y = MO_WATER_LEVEL(globalCtx) + 50.0f;
this->fwork[MO_TENT_SWING_SIZE_X] = 5.0f;
this->drawActor = true;
this->actor.colChkInfo.health = 20;
this->actor.colChkInfo.mass = 0;
this->actor.params = 0;
Actor_SetScale(&this->actor, 0.01f);
Collider_InitCylinder(globalCtx, &this->coreCollider);
Collider_SetCylinder(globalCtx, &this->coreCollider, &this->actor, &sCylinderInit);
if (Flags_GetClear(globalCtx, globalCtx->roomCtx.curRoom.num)) {
Actor_Kill(&this->actor);
Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_DOOR_WARP1, 0.0f, -280.0f, 0.0f, 0,
0, 0, WARP_DUNGEON_ADULT);
Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_ITEM_B_HEART, -200.0f, -280.0f, 0.0f, 0, 0, 0, 0);
globalCtx->roomCtx.unk_74[0] = 0xFF;
MO_WATER_LEVEL(globalCtx) = -500;
return;
}
if (gSaveContext.eventChkInf[7] & 0x10) {
Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_BOSS);
this->tentMaxAngle = 5.0f;
this->timers[0] = 50;
} else {
this->csState = MO_INTRO_WAIT;
this->work[MO_TENT_ACTION_STATE] = MO_CORE_INTRO_WAIT;
this->actor.world.pos.x = 1000.0f;
this->timers[0] = 60;
}
sMorphaTent1 = (BossMo*)Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_BOSS_MO,
this->actor.world.pos.x, this->actor.world.pos.y,
this->actor.world.pos.z, 0, 0, 0, BOSSMO_TENTACLE);
this->actor.draw = BossMo_DrawCore;
this->actor.update = BossMo_UpdateCore;
Actor_ChangeCategory(globalCtx, &globalCtx->actorCtx, &this->actor, ACTORCAT_BOSS);
} else {
Actor_SetScale(&this->actor, 0.01f);
BossMo_SetupTentacle(this, globalCtx);
this->actor.colChkInfo.mass = 0xFF;
MO_WATER_LEVEL(globalCtx) = -50;
this->waterTexAlpha = 90.0f;
this->actor.world.pos.y = MO_WATER_LEVEL(globalCtx);
this->actor.prevPos = this->targetPos = this->actor.world.pos;
Collider_InitJntSph(globalCtx, &this->tentCollider);
Collider_SetJntSph(globalCtx, &this->tentCollider, &this->actor, &sJntSphInit, this->tentElements);
this->tentMaxAngle = 1.0f;
}
}
void BossMo_Destroy(Actor* thisx, GlobalContext* globalCtx) {
s32 pad;
BossMo* this = (BossMo*)thisx;
if (this->actor.params >= BOSSMO_TENTACLE) {
Collider_DestroyJntSph(globalCtx, &this->tentCollider);
} else {
Collider_DestroyCylinder(globalCtx, &this->coreCollider);
}
}
void BossMo_SetupTentacle(BossMo* this, GlobalContext* globalCtx) {
this->actionFunc = BossMo_Tentacle;
this->work[MO_TENT_ACTION_STATE] = MO_TENT_WAIT;
this->timers[0] = 50 + (s16)Rand_ZeroFloat(20.0f);
}
void BossMo_Tentacle(BossMo* this, GlobalContext* globalCtx) {
s16 tentXrot;
s16 sp1B4 = 0;
s32 buttons;
Player* player = GET_PLAYER(globalCtx);
s16 indS0;
s16 indS1;
Camera* camera1;
Camera* camera2;
BossMo* otherTent = (BossMo*)this->otherTent;
f32 maxSwingRateX;
f32 maxSwingLagX;
f32 maxSwingSizeX;
f32 maxSwingRateZ;
f32 maxSwingLagZ;
f32 maxSwingSizeZ;
f32 swingRateAccel;
f32 swingSizeAccel;
s16 rippleCount;
s16 indT5;
Vec3f ripplePos;
f32 randAngle;
f32 randFloat;
f32 tempf1;
f32 tempf2;
f32 sin;
f32 cos;
f32 temp;
f32 dx;
f32 dy;
f32 dz;
Vec3f sp138;
Vec3f sp12C;
Vec3f sp120;
s32 pad11C;
s32 pad118;
s32 pad114;
s32 pad110;
s32 pad10C;
s32 pad108;
Vec3f spFC;
Vec3f spF0;
f32 padEC;
Vec3f spE0;
Vec3f spD4;
Vec3f spC8;
if (this->work[MO_TENT_ACTION_STATE] <= MO_TENT_DEATH_3) {
this->actor.world.pos.y = MO_WATER_LEVEL(globalCtx);
}
if ((this->work[MO_TENT_ACTION_STATE] == MO_TENT_READY) ||
(this->work[MO_TENT_ACTION_STATE] >= MO_TENT_DEATH_START) ||
(this->work[MO_TENT_ACTION_STATE] == MO_TENT_RETREAT) || (this->work[MO_TENT_ACTION_STATE] == MO_TENT_SWING) ||
(this->work[MO_TENT_ACTION_STATE] == MO_TENT_SHAKE)) {
if (this->work[MO_TENT_ACTION_STATE] == MO_TENT_READY) {
if (sMorphaCore->csState != MO_BATTLE) {
maxSwingRateX = 2000.0f;
maxSwingLagX = 3000.0f;
maxSwingSizeX = 1000.0f;
maxSwingRateZ = 1500.0f;
maxSwingLagZ = 2500.0f;
maxSwingSizeZ = 1000.0f;
swingRateAccel = 10.0f;
swingSizeAccel = 10.0f;
} else {
maxSwingRateX = 2000.0f;
maxSwingLagX = 3000.0f;
maxSwingSizeX = 1000.0f;
maxSwingRateZ = 1500.0f;
maxSwingLagZ = 2500.0f;
maxSwingSizeZ = 1000.0f;
swingRateAccel = 20.0f;
swingSizeAccel = 30.0f;
}
} else if (this->work[MO_TENT_ACTION_STATE] == MO_TENT_SWING) {
maxSwingRateX = 2500.0f;
maxSwingLagX = -1000.0f;
maxSwingSizeX = 3000.0f;
maxSwingRateZ = 1500.0f;
maxSwingLagZ = 2500.0f;
maxSwingSizeZ = 0.0;
swingRateAccel = 30.0f;
swingSizeAccel = 60.0f;
if (((this->sfxTimer % 16) == 0) && (this->timers[0] < 30)) {
Audio_PlaySoundIncreasinglyTransposed(&this->tentTipPos, NA_SE_EN_MOFER_WAVE, gMorphaTransposeTable);
}
} else if (this->work[MO_TENT_ACTION_STATE] == MO_TENT_SHAKE) {
if (this->timers[0] > 40) {
maxSwingRateX = 1300.0f;
maxSwingLagX = -3200.0f;
maxSwingSizeX = 7000.0f;
maxSwingRateZ = 800.0f;
maxSwingLagZ = 2500.0f;
maxSwingSizeZ = 5000.0f;
swingRateAccel = 30.0f;
swingSizeAccel = 60.0f;
if ((this->sfxTimer % 32) == 0) {
Audio_PlaySoundIncreasinglyTransposed(&this->tentTipPos, NA_SE_EN_MOFER_WAVE,
gMorphaTransposeTable);
func_800AA000(0, 100, 5, 2);
func_8002F7DC(&player->actor, NA_SE_VO_LI_FREEZE + player->ageProperties->unk_92);
}
} else {
maxSwingRateX = 2000.0f;
maxSwingLagX = -1000.0f;
maxSwingSizeX = 5000.0f;
maxSwingRateZ = 1500.0f;
maxSwingLagZ = 2500.0f;
maxSwingSizeZ = 100.0f;
swingRateAccel = 70.0f;
swingSizeAccel = 70.0f;
if ((this->sfxTimer % 16) == 0) {
Audio_PlaySoundIncreasinglyTransposed(&this->tentTipPos, NA_SE_EN_MOFER_WAVE,
gMorphaTransposeTable);
func_800AA000(0, 160, 5, 4);
func_8002F7DC(&player->actor, NA_SE_VO_LI_FREEZE + player->ageProperties->unk_92);
}
}
} else if (this->work[MO_TENT_ACTION_STATE] == MO_TENT_RETREAT) {
maxSwingRateX = 1300.0f;
maxSwingLagX = 3200.0f;
maxSwingSizeX = 7000.0f;
maxSwingRateZ = 800.0f;
maxSwingLagZ = 2500.0f;
maxSwingSizeZ = 5000.0f;
swingRateAccel = 30.0f;
swingSizeAccel = 30.0f;
} else if (this->work[MO_TENT_ACTION_STATE] >= MO_TENT_DEATH_START) {
maxSwingRateX = -400.0f;
maxSwingLagX = -3200.0f;
maxSwingSizeX = 0.0f;
maxSwingRateZ = 2300.0f;
maxSwingLagZ = 3200.0f;
maxSwingSizeZ = 1000.0;
swingRateAccel = 30.0f;
swingSizeAccel = 60.0f;
}
Math_ApproachF(&this->fwork[MO_TENT_SWING_RATE_X], maxSwingRateX, 1.0f, swingRateAccel);
Math_ApproachF(&this->fwork[MO_TENT_SWING_LAG_X], maxSwingLagX, 1.0f, 30.0f);
Math_ApproachF(&this->fwork[MO_TENT_SWING_SIZE_X], maxSwingSizeX, 1.0f, swingSizeAccel);
Math_ApproachF(&this->fwork[MO_TENT_SWING_RATE_Z], maxSwingRateZ, 1.0f, swingRateAccel);
Math_ApproachF(&this->fwork[MO_TENT_SWING_LAG_Z], maxSwingLagZ, 1.0f, 30.0f);
Math_ApproachF(&this->fwork[MO_TENT_SWING_SIZE_Z], maxSwingSizeZ, 1.0f, swingSizeAccel);
this->xSwing += (s16)this->fwork[MO_TENT_SWING_RATE_X];
this->zSwing += (s16)this->fwork[MO_TENT_SWING_RATE_Z];
}
switch (this->work[MO_TENT_ACTION_STATE]) {
case MO_TENT_WAIT:
this->actor.flags &= ~ACTOR_FLAG_0;
if (this == sMorphaTent2) {
this->work[MO_TENT_ACTION_STATE] = MO_TENT_SPAWN;
this->timers[0] = 70;
this->actor.shape.rot.y = this->actor.yawTowardsPlayer;
}
break;
case MO_TENT_SPAWN:
this->drawActor = true;
this->baseBubblesTimer = 20;
if (this->timers[0] < 20) {
Math_ApproachF(&this->tentRippleSize, 0.15f, 0.5f, 0.01);
Math_ApproachF(&this->baseAlpha, 150.0f, 1.0f, 5.0f);
if (this->baseAlpha >= 150.0f) {
this->work[MO_TENT_ACTION_STATE] = MO_TENT_READY;
this->timers[0] = 60;
}
}
if (this->timers[0] > 50) {
rippleCount = 1;
} else if (this->timers[0] > 40) {
rippleCount = 3;
} else if (this->timers[0] > 30) {
rippleCount = 5;
} else if (this->timers[0] > 20) {
rippleCount = 8;
} else {
rippleCount = 3;
}
for (indS1 = 0; indS1 < rippleCount; indS1++) {
randFloat = Rand_ZeroFloat(50.0f);
randAngle = Rand_ZeroFloat(0x10000);
ripplePos = this->actor.world.pos;
ripplePos.x += sinf(randAngle) * randFloat;
ripplePos.z += cosf(randAngle) * randFloat;
ripplePos.y = MO_WATER_LEVEL(globalCtx);
BossMo_SpawnRipple(globalCtx->specialEffects, &ripplePos, 40.0f, 110.0f, 80, 290, MO_FX_SMALL_RIPPLE);
}
break;
case MO_TENT_READY:
case MO_TENT_SWING:
if (sMorphaCore->csState == MO_BATTLE) {
func_80078914(&this->tentTipPos, NA_SE_EN_MOFER_APPEAR - SFX_FLAG);
}
Math_ApproachF(&this->waterLevelMod, -5.0f, 0.1f, 0.4f);
for (indS1 = 0; indS1 < 41; indS1++) {
sin = Math_SinS(((s16)this->fwork[MO_TENT_SWING_LAG_X] * indS1) + this->xSwing);
tempf1 = this->fwork[MO_TENT_SWING_SIZE_X] * (indS1 * 0.025f * sin);
cos = Math_SinS(((s16)this->fwork[MO_TENT_SWING_LAG_Z] * indS1) + this->zSwing);
tempf2 = this->fwork[MO_TENT_SWING_SIZE_Z] * (indS1 * 0.025f * cos);
Math_ApproachF(&this->tentStretch[indS1].y, this->fwork[MO_TENT_MAX_STRETCH] * 5.0f, 0.1f, 0.4f);
if (indS1 == 28) {
sp1B4 = this->tentRot[indS1].x;
}
Math_ApproachS(&this->tentRot[indS1].x, tempf1, 1.0f / this->tentMaxAngle, this->tentSpeed);
Math_ApproachS(&this->tentRot[indS1].z, tempf2, 1.0f / this->tentMaxAngle, this->tentSpeed);
}
this->targetPos = this->actor.world.pos;
Math_ApproachF(&this->actor.speedXZ, 0.75f, 1.0f, 0.04f);
if (this->work[MO_TENT_ACTION_STATE] == MO_TENT_SWING) {
Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer + this->attackAngleMod, 0xA,
0x1F4);
}
Math_ApproachF(&this->fwork[MO_TENT_MAX_STRETCH], 1.0f, 0.5f, 0.04);
if (sMorphaCore->csState != MO_BATTLE) {
Math_ApproachF(&this->tentMaxAngle, 1.0f, 1.0f, 0.001f);
Math_ApproachF(&this->tentSpeed, 240.0f, 1.0f, 3.0);
} else {
Math_ApproachF(&this->tentMaxAngle, 1.0f, 1.0f, 0.002f);
Math_ApproachF(&this->tentSpeed, 400.0f, 1.0f, 6.0f);
}
if (this->work[MO_TENT_ACTION_STATE] == MO_TENT_READY) {
if ((this->timers[0] == 0) && !HAS_LINK(otherTent)) {
this->work[MO_TENT_ACTION_STATE] = MO_TENT_SWING;
this->timers[0] = 50;
Audio_ResetIncreasingTranspose();
this->attackAngleMod = Rand_CenteredFloat(0x1000);
}
} else {
tentXrot = this->tentRot[28].x;
if ((this->timers[0] == 0) && (tentXrot >= 0) && (sp1B4 < 0)) {
this->work[MO_TENT_ACTION_STATE] = MO_TENT_ATTACK;
if (this == sMorphaTent1) {
this->timers[0] = 175;
} else {
this->timers[0] = 55;
}
}
}
break;
case MO_TENT_ATTACK:
this->actor.flags |= ACTOR_FLAG_24;
func_80078914(&this->tentTipPos, NA_SE_EN_MOFER_ATTACK - SFX_FLAG);
Math_ApproachF(&this->waterLevelMod, -5.0f, 0.1f, 0.4f);
for (indS1 = 0; indS1 < 41; indS1++) {
Math_ApproachF(&this->tentStretch[indS1].y,
this->fwork[MO_TENT_MAX_STRETCH] * ((((40 - indS1) * 25.0f) / 100.0f) + 5.0f), 0.5f,
0.7f);
Math_ApproachS(&this->tentRot[indS1].x, sAttackRot[indS1] * 0x100, 1.0f / this->tentMaxAngle,
this->tentSpeed);
Math_ApproachS(&this->tentRot[indS1].z, 0, 1.0f / this->tentMaxAngle, this->tentSpeed);
}
this->targetPos = this->actor.world.pos;
Math_ApproachF(&this->tentMaxAngle, 0.5f, 1.0f, 0.01);
Math_ApproachF(&this->tentSpeed, 160.0f, 1.0f, 50.0f);
if ((this->timers[0] == 0) || (this->linkHitTimer != 0)) {
dx = this->tentPos[22].x - player->actor.world.pos.x;
dy = this->tentPos[22].y - player->actor.world.pos.y;
dz = this->tentPos[22].z - player->actor.world.pos.z;
if ((fabsf(dy) < 50.0f) && !HAS_LINK(otherTent) && (sqrtf(SQ(dx) + SQ(dy) + SQ(dz)) < 120.0f)) {
this->tentMaxAngle = .001f;
this->work[MO_TENT_ACTION_STATE] = MO_TENT_CURL;
this->timers[0] = 40;
this->tentSpeed = 0;
if ((s16)(this->actor.shape.rot.y - this->actor.yawTowardsPlayer) >= 0) {
this->linkToLeft = false;
} else {
this->linkToLeft = true;
}
} else {
this->tentMaxAngle = .001f;
this->work[MO_TENT_ACTION_STATE] = MO_TENT_READY;
this->tentSpeed = 0;
this->fwork[MO_TENT_SWING_RATE_X] = 0;
this->fwork[MO_TENT_SWING_RATE_Z] = 0;
this->fwork[MO_TENT_SWING_SIZE_X] = 0;
this->fwork[MO_TENT_SWING_SIZE_Z] = 0;
this->timers[0] = 30;
if ((fabsf(player->actor.world.pos.x - this->actor.world.pos.x) > 300.0f) ||
(player->actor.world.pos.y < MO_WATER_LEVEL(globalCtx)) || HAS_LINK(otherTent) ||
(fabsf(player->actor.world.pos.z - this->actor.world.pos.z) > 300.0f)) {
this->work[MO_TENT_ACTION_STATE] = MO_TENT_RETREAT;
this->timers[0] = 75;
}
}
}
break;
case MO_TENT_CURL:
case MO_TENT_GRAB:
Math_ApproachF(&this->waterLevelMod, -5.0f, 0.1f, 0.4f);
if (this->timers[0] == 125) {
this->tentMaxAngle = .001f;
this->tentSpeed = 0;
}
for (indS1 = 0; indS1 < 41; indS1++) {
if (this->timers[0] > 25) {
if (!this->linkToLeft) {
Math_ApproachS(&this->tentRot[indS1].z, sCurlRot[indS1] * 0x100, 1.0f / this->tentMaxAngle,
this->tentSpeed);
} else {
Math_ApproachS(&this->tentRot[indS1].z, sCurlRot[indS1] * -0x100, 1.0f / this->tentMaxAngle,
this->tentSpeed);
}
} else {
if (!this->linkToLeft) {
Math_ApproachS(&this->tentRot[indS1].z, sGrabRot[indS1] * 0x100, 1.0f / this->tentMaxAngle,
this->tentSpeed);
} else {
Math_ApproachS(&this->tentRot[indS1].z, sGrabRot[indS1] * -0x100, 1.0f / this->tentMaxAngle,
this->tentSpeed);
}
}
}
Math_ApproachF(&this->tentMaxAngle, 0.1f, 1.0f, 0.01f);
Math_ApproachF(&this->tentSpeed, 960.0f, 1.0f, 30.0f);
if (this->timers[0] >= 30) {
Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 5, 0xC8);
}
if (this->work[MO_TENT_ACTION_STATE] == MO_TENT_CURL) {
if ((this->timers[0] >= 5) && (this->linkHitTimer != 0) && (player->actor.parent == NULL)) {
if (globalCtx->grabPlayer(globalCtx, player)) {
player->actor.parent = &this->actor;
this->work[MO_TENT_ACTION_STATE] = MO_TENT_GRAB;
func_80078914(&this->tentTipPos, NA_SE_EN_MOFER_CATCH);
Audio_PlaySoundGeneral(NA_SE_VO_LI_DAMAGE_S, &player->actor.projectedPos, 4, &D_801333E0,
&D_801333E0, &D_801333E8);
} else {
this->work[MO_TENT_ACTION_STATE] = MO_TENT_READY;
this->tentMaxAngle = .001f;
this->tentSpeed = 0;
this->fwork[MO_TENT_SWING_SIZE_Z] = 0;
this->fwork[MO_TENT_SWING_SIZE_X] = 0;
this->fwork[MO_TENT_SWING_RATE_Z] = 0;
this->fwork[MO_TENT_SWING_RATE_X] = 0;
this->timers[0] = 30;
}
}
if (this->timers[0] == 4) {
this->work[MO_TENT_ACTION_STATE] = MO_TENT_READY;
this->tentMaxAngle = .001f;
this->tentSpeed = 0;
this->fwork[MO_TENT_SWING_SIZE_Z] = 0;
this->fwork[MO_TENT_SWING_SIZE_X] = 0;
this->fwork[MO_TENT_SWING_RATE_Z] = 0;
this->fwork[MO_TENT_SWING_RATE_X] = 0;
this->timers[0] = 30;
}
}
if (this->work[MO_TENT_ACTION_STATE] == MO_TENT_GRAB) {
player->unk_850 = 0xA;
player->actor.speedXZ = player->actor.velocity.y = 0;
Math_ApproachF(&player->actor.world.pos.x, this->grabPosRot.pos.x, 0.5f, 20.0f);
Math_ApproachF(&player->actor.world.pos.y, this->grabPosRot.pos.y, 0.5f, 20.0f);
Math_ApproachF(&player->actor.world.pos.z, this->grabPosRot.pos.z, 0.5f, 20.0f);
Math_ApproachS(&player->actor.shape.rot.x, this->grabPosRot.rot.x, 2, 0x7D0);
Math_ApproachS(&player->actor.shape.rot.y, this->grabPosRot.rot.y, 2, 0x7D0);
Math_ApproachS(&player->actor.shape.rot.z, this->grabPosRot.rot.z, 2, 0x7D0);
if (this->timers[0] == 0) {
camera1 = Gameplay_GetCamera(globalCtx, MAIN_CAM);
this->work[MO_TENT_ACTION_STATE] = MO_TENT_SHAKE;
this->tentMaxAngle = .001f;
this->fwork[MO_TENT_SWING_RATE_X] = this->fwork[MO_TENT_SWING_RATE_Z] =
this->fwork[MO_TENT_SWING_SIZE_X] = this->fwork[MO_TENT_SWING_SIZE_Z] = this->tentSpeed = 0;
this->timers[0] = 150;
this->mashCounter = 0;
this->sfxTimer = 30;
Audio_ResetIncreasingTranspose();
func_80064520(globalCtx, &globalCtx->csCtx);
this->csCamera = Gameplay_CreateSubCamera(globalCtx);
Gameplay_ChangeCameraStatus(globalCtx, MAIN_CAM, CAM_STAT_WAIT);
Gameplay_ChangeCameraStatus(globalCtx, this->csCamera, CAM_STAT_ACTIVE);
this->cameraEye = camera1->eye;
this->cameraAt = camera1->at;
this->cameraYaw = Math_FAtan2F(this->cameraEye.x - this->actor.world.pos.x,
this->cameraEye.z - this->actor.world.pos.z);
this->cameraYawRate = 0;
goto tent_shake;
}
}
break;
tent_shake:
case MO_TENT_SHAKE:
if (this->timers[0] == 138) {
ShrinkWindow_SetVal(0);
Interface_ChangeAlpha(0xB);
}
if ((this->timers[0] % 8) == 0) {
globalCtx->damagePlayer(globalCtx, -1);
}
Math_ApproachF(&this->waterLevelMod, -5.0f, 0.1f, 0.4f);
sp1B4 = this->tentRot[15].x;
buttons = globalCtx->state.input[0].press.button;
if (CHECK_BTN_ALL(buttons, BTN_A) || CHECK_BTN_ALL(buttons, BTN_B)) {
this->mashCounter++;
}
for (indS1 = 0; indS1 < 41; indS1++) {
if (indS1 < 20) {
sin = Math_SinS(((s16)this->fwork[MO_TENT_SWING_LAG_X] * indS1) + this->xSwing);
tempf1 = this->fwork[MO_TENT_SWING_SIZE_X] * (indS1 * 0.025f * sin);
cos = Math_SinS(((s16)this->fwork[MO_TENT_SWING_LAG_Z] * indS1) + this->zSwing);
tempf2 = this->fwork[MO_TENT_SWING_SIZE_Z] * (indS1 * 0.025f * cos);
temp = ((((40 - indS1) * 25.0f) / 100.0f) + 5.0f);
Math_ApproachF(&this->tentStretch[indS1].y, this->fwork[MO_TENT_MAX_STRETCH] * temp, 0.1f, 0.1f);
Math_ApproachS(&this->tentRot[indS1].x, tempf1, 1.0f / this->tentMaxAngle, this->tentSpeed);
Math_ApproachS(&this->tentRot[indS1].z, tempf2, 1.0f / this->tentMaxAngle, this->tentSpeed);
}
}
player->unk_850 = 0xA;
player->actor.world.pos.x = this->grabPosRot.pos.x;
player->actor.world.pos.y = this->grabPosRot.pos.y;
player->actor.world.pos.z = this->grabPosRot.pos.z;
player->actor.world.rot.x = player->actor.shape.rot.x = this->grabPosRot.rot.x;
player->actor.world.rot.y = player->actor.shape.rot.y = this->grabPosRot.rot.y;
player->actor.world.rot.z = player->actor.shape.rot.z = this->grabPosRot.rot.z;
player->actor.velocity.y = 0;
player->actor.speedXZ = 0;
Math_ApproachF(&this->fwork[MO_TENT_MAX_STRETCH], 1.0f, 0.5f, 0.01);
Math_ApproachF(&this->tentMaxAngle, 0.5f, 1.0f, 0.005f);
Math_ApproachF(&this->tentSpeed, 480.0f, 1.0f, 10.0f);
Math_ApproachF(&this->tentPulse, 0.3f, 0.5f, 0.03f);
if ((this->mashCounter >= 40) || (this->timers[0] == 0)) {
tentXrot = this->tentRot[15].x;
if ((tentXrot < 0) && (sp1B4 >= 0)) {
this->work[MO_TENT_ACTION_STATE] = MO_TENT_RETREAT;
this->work[MO_TENT_INVINC_TIMER] = 50;
if (&this->actor == player->actor.parent) {
player->unk_850 = 0x65;
player->actor.parent = NULL;
player->csMode = 0;
if (this->timers[0] == 0) {
func_8002F6D4(globalCtx, &this->actor, 20.0f, this->actor.shape.rot.y + 0x8000, 10.0f, 0);
}
}
this->timers[0] = 75;
}
}
if (this->csCamera != 0) {
sp138.x = 0;
sp138.y = 100.0f;
sp138.z = 200.0f;
this->cameraYaw -= this->cameraYawRate;
Math_ApproachF(&this->cameraYawRate, 0.01, 1.0f, 0.002f);
Matrix_RotateY(this->cameraYaw, MTXMODE_NEW);
Matrix_MultVec3f(&sp138, &sp12C);
Math_ApproachF(&this->cameraEye.x, this->actor.world.pos.x + sp12C.x, 0.1f, 10.0f);
Math_ApproachF(&this->cameraEye.y, this->actor.world.pos.y + sp12C.y, 0.1f, 10.0f);
Math_ApproachF(&this->cameraEye.z, this->actor.world.pos.z + sp12C.z, 0.1f, 10.0f);
Math_ApproachF(&this->cameraAt.x, player->actor.world.pos.x, 0.5f, 50.0f);
Math_ApproachF(&this->cameraAt.y, player->actor.world.pos.y, 0.5f, 50.0f);
Math_ApproachF(&this->cameraAt.z, player->actor.world.pos.z, 0.5f, 50.0f);
Gameplay_CameraSetAtEye(globalCtx, this->csCamera, &this->cameraAt, &this->cameraEye);
}
break;
case MO_TENT_CUT:
func_80078914(&this->tentTipPos, NA_SE_EV_WATER_WALL - SFX_FLAG);
if (&this->actor == player->actor.parent) {
player->unk_850 = 0x65;
player->actor.parent = NULL;
player->csMode = 0;
}
Math_ApproachF(&this->tentRippleSize, 0.15f, 0.5f, 0.01);
if (this->meltIndex < 41) {
for (indS0 = 0; indS0 < 10; indS0++) {
sp120 = this->tentPos[this->meltIndex];
sp120.x += Rand_CenteredFloat(30.0f);
sp120.y += Rand_CenteredFloat(30.0f);
sp120.z += Rand_CenteredFloat(30.0f);
BossMo_SpawnStillDroplet(globalCtx->specialEffects, &sp120, Rand_ZeroFloat(0.1f) + .2f);
}
this->meltIndex++;
}
Math_ApproachF(&this->cutScale, 0.0, 1.0f, 0.2f);
if ((this->meltIndex >= 41) || (this->timers[0] == 0)) {
this->work[MO_TENT_ACTION_STATE] = MO_TENT_RETREAT;
this->timers[0] = 75;
this->tentMaxAngle = 0.005f;
this->tentSpeed = 50.0f;
this->fwork[MO_TENT_SWING_SIZE_X] = 7000.0f;
this->fwork[MO_TENT_SWING_SIZE_Z] = 5000.0f;
}
break;
case MO_TENT_RETREAT:
if (this->csCamera != 0) {
Math_ApproachF(&this->cameraAt.x, player->actor.world.pos.x, 0.5f, 50.0f);
Math_ApproachF(&this->cameraAt.y, player->actor.world.pos.y, 0.5f, 50.0f);
Math_ApproachF(&this->cameraAt.z, player->actor.world.pos.z, 0.5f, 50.0f);
Gameplay_CameraSetAtEye(globalCtx, this->csCamera, &this->cameraAt, &this->cameraEye);
if (player->actor.world.pos.y <= 42.0f) {
camera2 = Gameplay_GetCamera(globalCtx, MAIN_CAM);
camera2->eye = this->cameraEye;
camera2->eyeNext = this->cameraEye;
camera2->at = this->cameraAt;
func_800C08AC(globalCtx, this->csCamera, 0);
this->csCamera = 0;
func_80064534(globalCtx, &globalCtx->csCtx);
}
}
for (indS1 = 0; indS1 < 41; indS1++) {
sin = Math_SinS(((s16)this->fwork[MO_TENT_SWING_LAG_X] * indS1) + this->xSwing);
tempf1 = (indS1 * 0.025f * sin * this->fwork[MO_TENT_SWING_SIZE_X]) * this->fwork[MO_TENT_MAX_STRETCH];
cos = Math_SinS(((s16)this->fwork[MO_TENT_SWING_LAG_Z] * indS1) + this->zSwing);
tempf2 = (indS1 * 0.025f * cos * this->fwork[MO_TENT_SWING_SIZE_Z]) * this->fwork[MO_TENT_MAX_STRETCH];
Math_ApproachF(&this->tentStretch[indS1].y, this->fwork[MO_TENT_MAX_STRETCH] * 5.0f, 0.5f, 0.2f);
Math_ApproachS(&this->tentRot[indS1].x, tempf1, 1.0f / this->tentMaxAngle, this->tentSpeed);
Math_ApproachS(&this->tentRot[indS1].z, tempf2, 1.0f / this->tentMaxAngle, this->tentSpeed);
}
Math_ApproachF(&this->fwork[MO_TENT_MAX_STRETCH], 0, 0.5f, 0.02f);
Math_ApproachF(&this->tentMaxAngle, 0.5f, 1.0f, 0.01);
Math_ApproachF(&this->tentSpeed, 320.0f, 1.0f, 50.0f);
if (this->timers[0] == 0) {
this->actor.flags &= ~ACTOR_FLAG_0;
Math_ApproachF(&this->baseAlpha, 0.0, 1.0f, 5.0f);
for (indS1 = 0; indS1 < 40; indS1++) {
if (sMorphaTent2 && sMorphaTent2->tentSpawnPos) {}
indT5 = Rand_ZeroFloat(20.9f);
indS0 = sTentSpawnIndex[indT5];
spFC.x = 0;
spFC.y = 0;
spFC.z = 0;
Matrix_RotateY((player->actor.world.rot.y / (f32)0x8000) * M_PI, MTXMODE_NEW);
Matrix_MultVec3f(&spFC, &spF0);
spF0.x = player->actor.world.pos.x + spF0.x;
spF0.z = player->actor.world.pos.z + spF0.z;
if ((fabsf(spF0.x - sTentSpawnPos[indS0].x) <= 320) &&
(fabsf(spF0.z - sTentSpawnPos[indS0].y) <= 320) &&
((sMorphaTent2 == NULL) || (sMorphaTent2->tentSpawnPos != indS0))) {
this->targetPos.x = sTentSpawnPos[indS0].x;
this->targetPos.z = sTentSpawnPos[indS0].y;
this->tentSpawnPos = indS0;
this->timers[0] = (s16)Rand_ZeroFloat(20.0f) + 30;
this->work[MO_TENT_ACTION_STATE] = MO_TENT_DESPAWN;
break;
}
}
}
if ((this == sMorphaTent1) && (sMorphaCore->hitCount >= 3) && (sMorphaTent2 == NULL)) {
sMorphaTent2 =
(BossMo*)Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_BOSS_MO, this->actor.world.pos.x,
this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, 0, BOSSMO_TENTACLE);
sMorphaTent2->tentSpawnPos = this->tentSpawnPos;
if (sMorphaTent2->tentSpawnPos > 10) {
sMorphaTent2->tentSpawnPos--;
} else {
sMorphaTent2->tentSpawnPos++;
}
sMorphaTent2->targetPos.x = sTentSpawnPos[sMorphaTent2->tentSpawnPos].x;
sMorphaTent2->targetPos.z = sTentSpawnPos[sMorphaTent2->tentSpawnPos].y;
sMorphaTent2->timers[0] = 100;
sMorphaTent2->work[MO_TENT_ACTION_STATE] = MO_TENT_DESPAWN;
sMorphaTent2->otherTent = &sMorphaTent1->actor;
sMorphaTent1->otherTent = &sMorphaTent2->actor;
}
break;
case MO_TENT_DESPAWN:
this->actor.flags &= ~ACTOR_FLAG_0;
Math_ApproachF(&this->baseAlpha, 0, 1.0f, 5.0f);
if ((this->baseAlpha <= 0.5f) && (this->timers[0] == 0)) {
this->meltIndex = 0;
this->actor.world.pos.x = this->targetPos.x;
this->actor.world.pos.z = this->targetPos.z;
this->actor.prevPos = this->actor.world.pos;
this->cutScale = 1.0f;
this->cutIndex = this->meltIndex;
this->work[MO_TENT_ACTION_STATE] = MO_TENT_WAIT;
this->timers[0] = (s16)Rand_ZeroFloat(20.0f) + 10;
this->tentSpeed = 0;
this->fwork[MO_TENT_SWING_RATE_X] = 0;
this->fwork[MO_TENT_SWING_RATE_Z] = 0;
this->fwork[MO_TENT_SWING_SIZE_X] = 0;
this->fwork[MO_TENT_SWING_SIZE_Z] = 0;
this->tentMaxAngle = .001f;
}
break;
case MO_TENT_DEATH_START:
this->actor.shape.rot.y = 0x4000;
break;
case MO_TENT_DEATH_3:
this->baseBubblesTimer = 20;
Math_ApproachF(&sMorphaCore->waterLevel, -300.0f, 0.1f, 0.8f);
this->actor.flags &= ~ACTOR_FLAG_0;
for (indS1 = 0; indS1 < 41; indS1++) {
sin = Math_SinS(((s16)this->fwork[MO_TENT_SWING_LAG_X] * indS1) + this->xSwing);
tempf1 = this->fwork[MO_TENT_SWING_SIZE_X] * (indS1 * 0.025f * sin);
cos = Math_SinS(((s16)this->fwork[MO_TENT_SWING_LAG_Z] * indS1) + this->zSwing);
tempf2 = this->fwork[MO_TENT_SWING_SIZE_Z] * (indS1 * 0.025f * cos);
Math_ApproachF(&this->tentStretch[indS1].y, this->fwork[MO_TENT_MAX_STRETCH] * 5.0f, 0.1f, 0.4f);
Math_ApproachS(&this->tentRot[indS1].x, tempf1, 1.0f / this->tentMaxAngle, this->tentSpeed);
Math_ApproachS(&this->tentRot[indS1].z, tempf2, 1.0f / this->tentMaxAngle, this->tentSpeed);
}
this->actor.speedXZ = 0.0;
Math_ApproachF(&this->fwork[MO_TENT_MAX_STRETCH], 4.3f, 0.5f, 0.04);
Math_ApproachF(&this->tentPulse, 1.3f, 0.5f, 0.05f);
break;
case MO_TENT_DEATH_1:
this->baseBubblesTimer = 20;
this->actor.shape.rot.y = 0x4000;
this->actor.shape.rot.x = -0x8000;
this->actor.world.pos.y = sMorphaCore->waterLevel + 650.0f;
Math_ApproachF(&sMorphaCore->waterLevel, -300.0f, 0.1f, 1.3f);
for (indS1 = 0; indS1 < 41; indS1++) {
sin = Math_SinS(((s16)this->fwork[MO_TENT_SWING_LAG_X] * indS1) + this->xSwing);
tempf1 = this->fwork[MO_TENT_SWING_SIZE_X] * (indS1 * 0.025f * sin);
cos = Math_SinS(((s16)this->fwork[MO_TENT_SWING_LAG_Z] * indS1) + this->zSwing);
tempf2 = this->fwork[MO_TENT_SWING_SIZE_Z] * (indS1 * 0.025f * cos);
Math_ApproachF(&this->tentStretch[indS1].y, this->fwork[MO_TENT_MAX_STRETCH] * 5.0f, 0.1f, 0.4f);
Math_ApproachS(&this->tentRot[indS1].x, tempf1, 1.0f / this->tentMaxAngle, this->tentSpeed);
Math_ApproachS(&this->tentRot[indS1].z, tempf2, 1.0f / this->tentMaxAngle, this->tentSpeed);
}
this->actor.speedXZ = 0.0;
Math_ApproachF(&this->tentPulse, 1.3f, 0.5f, 0.05f);
break;
case MO_TENT_DEATH_2:
this->baseBubblesTimer = 20;
Math_ApproachF(&sMorphaCore->waterLevel, -295.0f, 0.1f, 1.3f);
this->actor.world.pos.y = sMorphaCore->waterLevel + 650.0f;
for (indS1 = 0; indS1 < 41; indS1++) {
sin = Math_SinS(((s16)this->fwork[MO_TENT_SWING_LAG_X] * indS1) + this->xSwing);
tempf1 = this->fwork[MO_TENT_SWING_SIZE_X] * (indS1 * 0.025f * sin);
cos = Math_SinS(((s16)this->fwork[MO_TENT_SWING_LAG_Z] * indS1) + this->zSwing);
tempf2 = this->fwork[MO_TENT_SWING_SIZE_Z] * (indS1 * 0.025f * cos);
Math_ApproachF(&this->tentStretch[indS1].y, this->fwork[MO_TENT_MAX_STRETCH] * 5.0f, 0.1f, 0.4f);
Math_ApproachS(&this->tentRot[indS1].x, tempf1, 1.0f / this->tentMaxAngle, this->tentSpeed);
Math_ApproachS(&this->tentRot[indS1].z, tempf2, 1.0f / this->tentMaxAngle, this->tentSpeed);
}
this->actor.speedXZ = 0.0;
this->noBubbles--;
Math_ApproachF(&this->fwork[MO_TENT_MAX_STRETCH], 0.1f, 0.1f, 0.03);
Math_ApproachF(&this->tentPulse, 0.02f, 0.5f, 0.015f);
if ((this->timers[0] > 0) && (this->timers[0] < 40)) {
Math_ApproachF(&this->actor.scale.x, 0.035f, 0.05f, this->flattenRate);
if (this->timers[0] == 1) {
this->flattenRate = 0.0;
}
} else if (this->timers[0] == 0) {
Math_ApproachF(&this->actor.scale.x, .001f, 0.05f, this->flattenRate);
}
Math_ApproachF(&this->flattenRate, 0.00045f, 0.1f, 0.00001f);
break;
case MO_TENT_DEATH_5:
for (indS1 = 0; indS1 < 41; indS1++) {
if (this->timers[0] != 0) {
Math_ApproachF(&this->tentStretch[indS1].y, this->fwork[MO_TENT_MAX_STRETCH] * 5.0f, 0.05f,
this->tentSpeed);
} else {
Math_ApproachF(&this->tentStretch[indS1].y, this->fwork[MO_TENT_MAX_STRETCH] * 5.0f, 0.3f, 100.0f);
}
this->tentRot[indS1].x = this->tentRot[indS1].z = 0;
}
this->tentPulse = 0.0;
if (this->timers[0] != 0) {
this->actor.world.pos.y = sMorphaCore->waterLevel + 650.0f;
this->fwork[MO_TENT_MAX_STRETCH] = 0.5f;
Math_ApproachF(&this->actor.scale.x, 0.0015f, 0.05f, this->tentMaxAngle);
Math_ApproachF(&this->tentMaxAngle, 0.00035f, 1.0f, 0.0000175f);
Math_ApproachF(&this->tentSpeed, 0.1f, 1.0f, 0.005f);
this->actor.velocity.y = 0.0;
} else {
this->fwork[MO_TENT_MAX_STRETCH] = 0.2f;
this->fwork[MO_TENT_MAX_STRETCH] += Math_SinS(this->work[MO_TENT_MOVE_TIMER] * 0x2000) * 0.05f;
padEC = Math_CosS(this->work[MO_TENT_MOVE_TIMER] * 0x2000) * 0.0005f;
Math_ApproachF(&this->actor.scale.x, 0.002f + padEC, 0.5f, 0.0005f);
this->actor.world.pos.y += this->actor.velocity.y;
this->actor.velocity.y -= 1.0f;
if (this->actor.world.pos.y < -250.0f) {
this->actor.world.pos.y = -250.0f;
this->actor.velocity.y = 0.0;
this->drawActor = false;
this->work[MO_TENT_ACTION_STATE] = MO_TENT_DEATH_6;
this->timers[0] = 60;
func_80078914(&this->tentTipPos, NA_SE_EN_MOFER_CORE_JUMP);
for (indS1 = 0; indS1 < 300; indS1++) {
spC8.x = 0.0;
spC8.y = 0.0;
spC8.z = indS1 * 0.03f;
Matrix_RotateY(indS1 * 0.23f, MTXMODE_NEW);
Matrix_MultVec3f(&spC8, &spE0);
spE0.y = Rand_ZeroFloat(7.0f) + 4.0f;
spD4 = this->actor.world.pos;
spD4.x += spE0.x * 3.0f;
spD4.y += (spE0.y * 3.0f) - 30.0f;
if (spD4.y < -280.0f) {
spD4.y = -280.0f;
}
spD4.z += spE0.z * 3.0f;
BossMo_SpawnDroplet(MO_FX_DROPLET, (BossMoEffect*)globalCtx->specialEffects, &spD4, &spE0,
((300 - indS1) * .0015f) + 0.13f);
}
Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_DOOR_WARP1,
this->actor.world.pos.x, -280.0f, this->actor.world.pos.z, 0, 0, 0,
WARP_DUNGEON_ADULT);
Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_ITEM_B_HEART, this->actor.world.pos.x + 200.0f,
-280.0f, this->actor.world.pos.z, 0, 0, 0, 0);
Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_BOSS_CLEAR);
Flags_SetClear(globalCtx, globalCtx->roomCtx.curRoom.num);
}
}
break;
case MO_TENT_DEATH_6:
break;
}
this->actor.scale.y = this->actor.scale.z = this->actor.scale.x;
if (((this->work[MO_TENT_ACTION_STATE] == MO_TENT_ATTACK) ||
(this->work[MO_TENT_ACTION_STATE] == MO_TENT_DEATH_2) || (this->work[MO_TENT_ACTION_STATE] == MO_TENT_CURL) ||
(this->work[MO_TENT_ACTION_STATE] == MO_TENT_GRAB)) &&
(Rand_ZeroOne() < 0.8f) && (this->actor.scale.x > 0.001f)) {
Vec3f pos;
Vec3f velocity = { 0.0f, 0.0f, 0.0f };
f32 scale;
f32 temp;
if (this->work[MO_TENT_ACTION_STATE] >= MO_TENT_DEATH_2) {
indS1 = 38;
scale = Rand_ZeroFloat(0.1f) + 0.1f;
pos.y = this->tentPos[indS1].y;
} else {
indS1 = (s16)Rand_ZeroFloat(20.0f) + 18;
scale = Rand_ZeroFloat(0.02f) + .05f;
pos.y = this->tentPos[indS1].y - 10.0f;
}
temp = (this->actor.scale.x * 100.0f) * 20.0f;
pos.x = this->tentPos[indS1].x + Rand_CenteredFloat(temp);
pos.z = this->tentPos[indS1].z + Rand_CenteredFloat(temp);
BossMo_SpawnDroplet(MO_FX_DROPLET, (BossMoEffect*)globalCtx->specialEffects, &pos, &velocity, scale);
}
}
void BossMo_TentCollisionCheck(BossMo* this, GlobalContext* globalCtx) {
s16 i1;
for (i1 = 0; i1 < ARRAY_COUNT(this->tentElements); i1++) {
if (this->tentCollider.elements[i1].info.bumperFlags & BUMP_HIT) {
s16 i2;
ColliderInfo* hurtbox;
for (i2 = 0; i2 < 19; i2++) {
this->tentCollider.elements[i2].info.bumperFlags &= ~BUMP_HIT;
this->tentCollider.elements[i2].info.toucherFlags &= ~TOUCH_HIT;
}
hurtbox = this->tentCollider.elements[i1].info.acHitInfo;
this->work[MO_TENT_INVINC_TIMER] = 5;
if (hurtbox->toucher.dmgFlags & 0x00020000) {
func_80078914(&this->tentTipPos, NA_SE_EN_MOFER_CUT);
this->cutIndex = 15;
this->meltIndex = this->cutIndex + 1;
this->work[MO_TENT_ACTION_STATE] = MO_TENT_CUT;
this->timers[0] = 40;
this->cutScale = 1.0f;
} else if (hurtbox->toucher.dmgFlags & 0x0D800600) {
this->linkHitTimer = 5;
}
this->tentRippleSize = 0.2f;
for (i2 = 0; i2 < 10; i2++) {
Vec3f pos;
Vec3f velocity;
velocity.x = Rand_CenteredFloat(8.0f);
velocity.y = Rand_ZeroFloat(7.0f) + 4.0f;
velocity.z = Rand_CenteredFloat(8.0f);
pos = this->tentPos[2 * i1];
pos.x += velocity.x * 3.0f;
pos.z += velocity.z * 3.0f;
BossMo_SpawnDroplet(MO_FX_DROPLET, (BossMoEffect*)globalCtx->specialEffects, &pos, &velocity,
Rand_ZeroFloat(0.08f) + 0.13f);
}
break;
} else if (this->tentCollider.elements[i1].info.toucherFlags & TOUCH_HIT) {
this->tentCollider.elements[i1].info.toucherFlags &= ~TOUCH_HIT;
this->linkHitTimer = 5;
break;
}
}
}
void BossMo_IntroCs(BossMo* this, GlobalContext* globalCtx) {
static Vec3f cutsceneTargets[6] = {
{ -360.0f, -190.0f, 0.0f }, { 250.0f, -190.0f, 0.0f }, { 300.0f, -120.0f, -278.0f },
{ 180.0f, -80.0f, -340.0f }, { 180.0f, 0.0f, -340.0f }, { 180.0f, 60.0f, -230.0f },
};
u8 sp9F = 0;
f32 dx;
f32 dy;
f32 dz;
f32 tempX;
f32 tempY;
s32 pad84;
f32 sp80;
f32 sp7C;
f32 sp78;
Player* player = GET_PLAYER(globalCtx);
Camera* camera = Gameplay_GetCamera(globalCtx, MAIN_CAM);
Vec3f bubblePos;
Vec3f bubblePos2;
Camera* camera2;
f32 pad50;
f32 pad4C;
f32 pad48;
if (this->csState < MO_INTRO_REVEAL) {
this->cameraZoom = 80.0f;
}
switch (this->csState) {
case MO_INTRO_WAIT:
if (this->timers[0] == 1) {
Message_StartTextbox(globalCtx, 0x403F, NULL);
}
if (((fabsf(player->actor.world.pos.z - 180.0f) < 40.0f) &&
(fabsf(player->actor.world.pos.x - 180.0f) < 40.0f)) ||
((fabsf(player->actor.world.pos.z - -180.0f) < 40.0f) &&
(fabsf(player->actor.world.pos.x - 180.0f) < 40.0f)) ||
((fabsf(player->actor.world.pos.z - 180.0f) < 40.0f) &&
(fabsf(player->actor.world.pos.x - -180.0f) < 40.0f)) ||
((fabsf(player->actor.world.pos.z - -180.0f) < 40.0f) &&
(fabsf(player->actor.world.pos.x - -180.0f) < 40.0f))) {
// checks if Link is on one of the four platforms
func_80064520(globalCtx, &globalCtx->csCtx);
func_8002DF54(globalCtx, &this->actor, 8);
this->csCamera = Gameplay_CreateSubCamera(globalCtx);
Gameplay_ChangeCameraStatus(globalCtx, MAIN_CAM, CAM_STAT_WAIT);
Gameplay_ChangeCameraStatus(globalCtx, this->csCamera, CAM_STAT_ACTIVE);
this->actor.speedXZ = 0.0f;
this->csState = MO_INTRO_START;
this->timers[2] = 50;
this->work[MO_TENT_VAR_TIMER] = this->work[MO_TENT_MOVE_TIMER] = 0;
this->actor.world.rot.y = 0x721A;
sMorphaTent1->work[MO_TENT_ACTION_STATE] = MO_TENT_READY;
sMorphaTent1->timers[0] = 30000;
Audio_QueueSeqCmd(0x1 << 28 | SEQ_PLAYER_BGM_MAIN << 24 | 0x3200FF);
Message_CloseTextbox(globalCtx);
} else {
break;
}
case MO_INTRO_START:
player->actor.world.pos.x = 180.0f;
player->actor.world.pos.z = -130.0f;
player->actor.shape.rot.y = player->actor.world.rot.y = 0;
player->actor.speedXZ = 0.0f;
this->cameraEye.x = -424.0f;
this->cameraEye.y = -190.0f;
this->cameraEye.z = 180.0f;
this->cameraAt.x = player->actor.world.pos.x;
this->cameraAt.y = -330.0f;
this->cameraAt.z = 0.0f;
if (this->timers[2] == 0) {
this->csState = MO_INTRO_SWIM;
this->work[MO_TENT_MOVE_TIMER] = 0;
} else if (this->timers[2] < 50) {
bubblePos.x = (this->cameraEye.x + 20.0f) + 10.0f;
bubblePos.y = -250.0f;
bubblePos.z = this->cameraEye.z;
EffectSsBubble_Spawn(globalCtx, &bubblePos, 0.0f, 10.0f, 50.0f, Rand_ZeroFloat(0.05f) + 0.13f);
}
if (this->timers[2] == 40) {
func_80078914(&sAudioZeroVec, NA_SE_EN_MOFER_BUBLE_DEMO);
}
break;
case MO_INTRO_SWIM:
Math_ApproachF(&this->cameraYawShake, 0.1f, 1.0f, 0.002f);
this->targetPos = cutsceneTargets[this->targetIndex];
if (this->targetIndex == 5) {
tempY = Math_SinS(this->work[MO_TENT_MOVE_TIMER] * 0x500) * 20.0f;
} else {
tempY = Math_SinS(this->work[MO_TENT_MOVE_TIMER] * 0x500) * 5.0f;
}
dx = this->targetPos.x - this->cameraEye.x;
dy = this->targetPos.y - this->cameraEye.y + tempY;
dz = this->targetPos.z - this->cameraEye.z;
tempY = Math_FAtan2F(dx, dz);
tempX = Math_FAtan2F(dy, sqrtf(SQ(dx) + SQ(dz)));
Math_ApproachS(&this->actor.world.rot.y, tempY * (0x8000 / M_PI), 5, this->cameraYawRate);
Math_ApproachS(&this->actor.world.rot.x, tempX * (0x8000 / M_PI), 5, this->cameraYawRate);
if (this->work[MO_TENT_MOVE_TIMER] == 150) {
this->cameraAtVel.x = fabsf(this->cameraAt.x - player->actor.world.pos.x);
this->cameraAtVel.y = fabsf(this->cameraAt.y - player->actor.world.pos.y);
this->cameraAtVel.z = fabsf(this->cameraAt.z - player->actor.world.pos.z);
}
if (this->work[MO_TENT_MOVE_TIMER] >= 150) {
Math_ApproachF(&this->cameraAt.x, player->actor.world.pos.x, 0.1f,
this->cameraAtVel.x * this->cameraSpeedMod);
Math_ApproachF(&this->cameraAt.y, player->actor.world.pos.y + 50.0f, 0.1f,
this->cameraAtVel.y * this->cameraSpeedMod);
Math_ApproachF(&this->cameraAt.z, player->actor.world.pos.z, 0.1f,
this->cameraAtVel.z * this->cameraSpeedMod);
Math_ApproachF(&this->cameraSpeedMod, 0.02f, 1.0f, 0.001f);
}
if (this->work[MO_TENT_MOVE_TIMER] == 190) {
func_80078914(&sAudioZeroVec, NA_SE_EN_MOFER_BUBLE_DEMO);
}
if ((this->work[MO_TENT_MOVE_TIMER] > 150) && (this->work[MO_TENT_MOVE_TIMER] < 180)) {
bubblePos2.x = (this->cameraEye.x + 20.0f) + 10.0f;
bubblePos2.y = -250.0f;
bubblePos2.z = this->cameraEye.z;
EffectSsBubble_Spawn(globalCtx, &bubblePos2, 0.0f, 10.0f, 50.0f, Rand_ZeroFloat(0.05f) + 0.13f);
}
sp7C = (f32)0x1000;
sp78 = 0.1f;
if ((this->work[MO_TENT_MOVE_TIMER] > 100) && (this->work[MO_TENT_MOVE_TIMER] < 220)) {
sp80 = 0.0f;
} else if (this->work[MO_TENT_MOVE_TIMER] > 350) {
sp80 = 2.0f;
sp78 = 0.4f;
} else if (this->work[MO_TENT_MOVE_TIMER] > 220) {
sp80 = 7.0f;
sp78 = 0.3f;
sp7C = (f32)0x2000;
} else {
sp80 = 4.0f;
}
if (this->work[MO_TENT_MOVE_TIMER] > 250) {
Math_ApproachF(&this->fwork[MO_CORE_INTRO_WATER_ALPHA], 100.0f, 1.0f, 1.0f);
}
if (this->targetIndex < 5) {
if (sqrtf(SQ(dx) + SQ(dz) + SQ(dy)) < 40.0f) {
this->targetIndex++;
this->cameraYawRate = 0.0f;
}
} else {
sp80 = 1.5f;
sp7C = (f32)0x600;
}
Math_ApproachF(&this->actor.speedXZ, sp80, 1.0f, sp78);
Math_ApproachF(&this->cameraYawRate, sp7C, 1.0f, 128.0f);
if (this->work[MO_TENT_MOVE_TIMER] == 525) {
func_8002DF54(globalCtx, &this->actor, 2);
}
if (this->work[MO_TENT_MOVE_TIMER] > 540) {
this->csState = MO_INTRO_REVEAL;
func_8002DF54(globalCtx, &this->actor, 1);
sMorphaTent1->drawActor = true;
player->actor.world.pos.x = 180.0f;
player->actor.world.pos.z = -210.0f;
player->actor.world.rot.y = -0x8000;
player->actor.shape.rot.y = player->actor.world.rot.y;
this->cameraYawShake = 0.0f;
sMorphaTent1->baseAlpha = 150.0;
this->actor.speedXZ = 0.0f;
this->timers[2] = 200;
this->cameraZoom = 60.0f;
this->actor.world.pos = sMorphaTent1->actor.world.pos;
this->work[MO_TENT_ACTION_STATE] = MO_CORE_INTRO_REVEAL;
this->actor.flags &= ~ACTOR_FLAG_0;
sMorphaTent1->actor.flags |= ACTOR_FLAG_0;
} else {
sMorphaTent1->xSwing = 0xCEC;
sMorphaTent1->fwork[MO_TENT_SWING_RATE_X] = 0.0f;
sMorphaTent1->fwork[MO_TENT_SWING_LAG_X] = 1000.0f;
sMorphaTent1->fwork[MO_TENT_SWING_SIZE_X] = 2500.0f;
break;
}
case MO_INTRO_REVEAL:
if (this->timers[2] >= 160) {
this->cameraEye.x = 150.0f;
this->cameraEye.y = 60.0f;
this->cameraEye.z = -230.0f;
this->cameraAt.x = 170.0f;
this->cameraAt.y = 40.0;
this->cameraAt.z = -280.0f;
sMorphaTent1->xSwing = 0xCEC;
sMorphaTent1->fwork[MO_TENT_SWING_RATE_X] = 0.0f;
sMorphaTent1->fwork[MO_TENT_SWING_LAG_X] = 1000.0f;
sMorphaTent1->fwork[MO_TENT_SWING_SIZE_X] = 2500.0f;
if (this->timers[2] == 160) {
this->cameraNextAt.y = 65.0f;
this->cameraNextAt.z = -280.0f;
this->cameraEyeVel.x = fabsf(this->cameraEye.x - 150.0f) * 0.1f;
this->cameraEyeVel.y = fabsf(this->cameraEye.y - 60.0f) * 0.1f;
this->cameraEyeVel.z = fabsf(this->cameraEye.z - -260.0f) * 0.1f;
this->cameraNextEye.x = 150.0f;
this->cameraNextEye.y = 60.0f;
this->cameraNextEye.z = -260.0f;
this->cameraNextAt.x = 155.0f;
this->cameraAtMaxVel.x = this->cameraAtMaxVel.y = this->cameraAtMaxVel.z = 0.1f;
this->cameraAtVel.x = fabsf(this->cameraAt.x - this->cameraNextAt.x) * 0.1f;
this->cameraAtVel.y = fabsf(this->cameraAt.y - this->cameraNextAt.y) * 0.1f;
this->cameraAtVel.z = fabsf(this->cameraAt.z - this->cameraNextAt.z) * 0.1f;
this->cameraEyeMaxVel.x = this->cameraEyeMaxVel.y = this->cameraEyeMaxVel.z = 0.1f;
this->cameraSpeedMod = 0.0f;
this->cameraAccel = 0.01f;
this->tentMaxAngle = 0.001f;
this->tentSpeed = 0.0f;
sp9F = 1;
}
} else {
sp9F = 1;
}
if (this->timers[2] == 50) {
this->cameraNextAt.x = 160.0f;
this->cameraNextAt.y = 58.0f;
this->cameraNextAt.z = -247.0f;
this->cameraEyeVel.x = fabsf(this->cameraEye.x - 111.0f) * 0.1f;
this->cameraEyeVel.y = fabsf(this->cameraEye.y - 133.0f) * 0.1f;
this->cameraEyeVel.z = fabsf(this->cameraEye.z - -191.0f) * 0.1f;
this->csState = MO_INTRO_FINISH;
this->timers[2] = 110;
this->cameraNextEye.x = 111.0f;
this->cameraNextEye.y = 133.0f;
this->cameraNextEye.z = -191.0f;
this->cameraAtVel.x = fabsf(this->cameraAt.x - this->cameraNextAt.x) * 0.1f;
this->cameraAtVel.y = fabsf(this->cameraAt.y - this->cameraNextAt.y) * 0.1f;
this->cameraAtVel.z = fabsf(this->cameraAt.z - this->cameraNextAt.z) * 0.1f;
this->cameraEyeMaxVel.y = 0.03f;
this->cameraAtMaxVel.y = 0.03f;
this->cameraSpeedMod = 0.0f;
this->cameraAccel = 0.01f;
}
if (this->timers[2] == 150) {
Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_BOSS);
}
if (this->timers[2] == 130) {
TitleCard_InitBossName(globalCtx, &globalCtx->actorCtx.titleCtx,
SEGMENTED_TO_VIRTUAL(gMorphaTitleCardTex), 160, 180, 128, 40, true);
gSaveContext.eventChkInf[7] |= 0x10;
}
break;
case MO_INTRO_FINISH:
sp9F = 1;
this->cameraNextEye.x = 111.0f;
this->cameraNextEye.y = 133.0f;
this->cameraNextEye.z = -191.0f;
this->cameraNextAt.x = 160.0f;
this->cameraNextAt.y = 58.0f;
this->cameraNextAt.z = -247.0f;
if (this->timers[2] == 100) {
sMorphaTent1->work[MO_TENT_ACTION_STATE] = MO_TENT_RETREAT;
sMorphaTent1->timers[0] = 50;
}
if (this->timers[2] == 20) {
camera2 = Gameplay_GetCamera(globalCtx, MAIN_CAM);
camera2->eye = this->cameraEye;
camera2->eyeNext = this->cameraEye;
camera2->at = this->cameraAt;
func_800C08AC(globalCtx, this->csCamera, 0);
this->csState = this->csCamera = MO_BATTLE;
func_80064534(globalCtx, &globalCtx->csCtx);
func_8002DF54(globalCtx, &this->actor, 7);
}
break;
}
if (sMorphaTent1->work[MO_TENT_ACTION_STATE] == MO_TENT_READY) {
sMorphaTent1->actor.world.pos.x = 180.0f;
sMorphaTent1->actor.world.pos.z = -360.0f;
sMorphaTent1->actor.prevPos = sMorphaTent1->actor.world.pos;
sMorphaTent1->actor.speedXZ = 0.0f;
sMorphaTent1->actor.shape.rot.y = sMorphaTent1->actor.yawTowardsPlayer;
}
if (this->csCamera != 0) {
if (sp9F) {
Math_ApproachF(&this->cameraEye.x, this->cameraNextEye.x, this->cameraEyeMaxVel.x,
this->cameraEyeVel.x * this->cameraSpeedMod);
Math_ApproachF(&this->cameraEye.y, this->cameraNextEye.y, this->cameraEyeMaxVel.y,
this->cameraEyeVel.y * this->cameraSpeedMod);
Math_ApproachF(&this->cameraEye.z, this->cameraNextEye.z, this->cameraEyeMaxVel.z,
this->cameraEyeVel.z * this->cameraSpeedMod);
Math_ApproachF(&this->cameraAt.x, this->cameraNextAt.x, this->cameraAtMaxVel.x,
this->cameraAtVel.x * this->cameraSpeedMod);
Math_ApproachF(&this->cameraAt.y, this->cameraNextAt.y, this->cameraAtMaxVel.y,
this->cameraAtVel.y * this->cameraSpeedMod);
Math_ApproachF(&this->cameraAt.z, this->cameraNextAt.z, this->cameraAtMaxVel.z,
this->cameraAtVel.z * this->cameraSpeedMod);
Math_ApproachF(&this->cameraSpeedMod, 1.0f, 1.0f, this->cameraAccel);
} else if (this->csState < MO_INTRO_REVEAL) {
func_8002D908(&this->actor);
this->cameraEye.x += this->actor.velocity.x;
this->cameraEye.y += this->actor.velocity.y;
this->cameraEye.z += this->actor.velocity.z;
}
this->cameraUp.x = this->cameraUp.z =
sinf(this->work[MO_TENT_VAR_TIMER] * 0.03f) * this->cameraYawShake * (-2.0f);
this->cameraUp.y = 1.0f;
Gameplay_CameraSetAtEyeUp(globalCtx, this->csCamera, &this->cameraAt, &this->cameraEye, &this->cameraUp);
camera->eye = this->cameraEye;
camera->eyeNext = this->cameraEye;
camera->at = this->cameraAt;
Gameplay_CameraSetFov(globalCtx, this->csCamera, this->cameraZoom);
}
if ((this->csState > MO_INTRO_START) && (this->work[MO_TENT_MOVE_TIMER] > 540)) {
func_80078914(&sMorphaTent1->tentTipPos, NA_SE_EN_MOFER_APPEAR - SFX_FLAG);
} else if (this->csState >= MO_INTRO_START) {
func_80078914(&sAudioZeroVec, NA_SE_EN_MOFER_MOVE_DEMO - SFX_FLAG);
}
}
void BossMo_DeathCs(BossMo* this, GlobalContext* globalCtx) {
s16 i;
s16 one;
f32 dx;
f32 dz;
f32 sp80;
f32 sp7C;
Vec3f sp70;
Vec3f sp64;
Camera* camera = Gameplay_GetCamera(globalCtx, MAIN_CAM);
Vec3f velocity;
Vec3f pos;
switch (this->csState) {
case MO_DEATH_START:
func_80064520(globalCtx, &globalCtx->csCtx);
func_8002DF54(globalCtx, &this->actor, 8);
this->csCamera = Gameplay_CreateSubCamera(globalCtx);
Gameplay_ChangeCameraStatus(globalCtx, MAIN_CAM, CAM_STAT_WAIT);
Gameplay_ChangeCameraStatus(globalCtx, this->csCamera, CAM_STAT_ACTIVE);
this->csState = MO_DEATH_MO_CORE_BURST;
this->cameraEye = camera->eye;
this->timers[0] = 90;
dx = this->actor.world.pos.x - this->cameraEye.x;
dz = this->actor.world.pos.z - this->cameraEye.z;
this->cameraYaw = Math_FAtan2F(dx, dz);
this->cameraDist = sqrtf(SQ(dx) + SQ(dz));
this->cameraYawRate = 0.0f;
case MO_DEATH_MO_CORE_BURST:
this->baseAlpha = 0.0f;
if (this->timers[0] & 4) {
sp80 = 0.005f;
sp7C = 0.015f;
} else {
sp80 = 0.015f;
sp7C = 0.005f;
}
Math_ApproachF(&this->actor.scale.x, sp80, 0.5f, 0.002f);
this->actor.scale.z = this->actor.scale.x;
Math_ApproachF(&this->actor.scale.y, sp7C, 0.5f, 0.002f);
this->cameraYaw += this->cameraYawRate;
if (this->timers[0] >= 30) {
Math_ApproachF(&this->cameraYawRate, 0.05f, 1.0f, 0.002f);
} else {
Math_ApproachF(&this->cameraYawRate, 0.0f, 1.0f, 0.002f);
}
Math_ApproachF(&this->actor.world.pos.y, 150.0f, 0.05f, 5.0f);
Math_ApproachF(&this->cameraEye.y, 100.0f, 0.05f, 2.0f);
this->cameraAt = this->cameraNextAt = this->actor.world.pos;
if (this->timers[0] > 20) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_MOFER_DEAD - SFX_FLAG);
}
if (this->timers[0] == 20) {
for (i = 0; i < 300; i++) {
velocity.x = Rand_CenteredFloat(10.0f);
velocity.y = Rand_CenteredFloat(10.0f);
velocity.z = Rand_CenteredFloat(10.0f);
pos = this->actor.world.pos;
pos.x += 2.0f * velocity.x;
pos.y += 2.0f * velocity.y;
pos.z += 2.0f * velocity.z;
BossMo_SpawnDroplet(MO_FX_DROPLET, (BossMoEffect*)globalCtx->specialEffects, &pos, &velocity,
Rand_ZeroFloat(0.08f) + 0.13f);
}
this->drawActor = false;
this->actor.flags &= ~ACTOR_FLAG_0;
Audio_PlayActorSound2(&this->actor, NA_SE_EN_MOFER_CORE_JUMP);
SoundSource_PlaySfxAtFixedWorldPos(globalCtx, &this->actor.world.pos, 70, NA_SE_EN_MOFER_LASTVOICE);
}
if (this->timers[0] == 0) {
this->csState = MO_DEATH_DRAIN_WATER_1;
this->cameraDist = 490.0f;
this->actor.world.pos.y = -1000.0f;
this->fwork[MO_TENT_SWING_SIZE_X] = 15.0f;
this->cameraYaw = 0.0f;
this->cameraEye.x = 490.0f;
this->cameraEye.y = 50.0f;
this->cameraEye.z = 0.0f;
this->cameraAt.x = 0;
this->cameraAt.y = -100.0f;
this->cameraAt.z = 0.0f;
this->work[MO_TENT_VAR_TIMER] = this->work[MO_TENT_MOVE_TIMER] = 0;
this->cameraAtMaxVel.y = 0.05f;
this->cameraAtVel.y = 4.0f;
this->cameraSpeedMod = 0.0f;
this->cameraAccel = 0.02f;
this->cameraNextAt.y = 320.0f;
this->timers[0] = 100;
sMorphaTent1->drawActor = true;
sMorphaTent1->work[MO_TENT_ACTION_STATE] = MO_TENT_DEATH_3;
sMorphaTent1->actor.shape.rot.x = 0;
sMorphaTent1->actor.world.pos.x = 0.0f;
sMorphaTent1->actor.world.pos.y = -50.0f;
sMorphaTent1->actor.world.pos.z = 0.0f;
sMorphaTent1->fwork[MO_TENT_MAX_STRETCH] = 1.0f;
sMorphaTent1->tentPulse = 0.2f;
sMorphaCore->waterLevel = -50.0f;
sMorphaTent1->flattenRate = 0.0f;
sMorphaTent1->noBubbles = 0;
for (i = 0; i < 41; i++) {
sMorphaTent1->tentStretch[i].y = 5.0f;
}
sMorphaTent1->fwork[MO_TENT_SWING_RATE_X] = -400.0f;
sMorphaTent1->fwork[MO_TENT_SWING_LAG_X] = -3200.0f;
sMorphaTent1->fwork[MO_TENT_SWING_SIZE_X] = .0f;
sMorphaTent1->fwork[MO_TENT_SWING_RATE_Z] = 3000.0f;
sMorphaTent1->fwork[MO_TENT_SWING_LAG_Z] = 2500.0f;
sMorphaTent1->fwork[MO_TENT_SWING_SIZE_Z] = 4000.0f;
sMorphaTent1->tentMaxAngle = 1.0f;
sMorphaTent1->tentSpeed = 20480.0f;
sMorphaTent1->baseAlpha = 150.0f;
sMorphaTent1->cutIndex = sMorphaTent1->meltIndex = 0;
sMorphaTent1->cutScale = 1.0f;
Actor_SetScale(&sMorphaTent1->actor, 0.01f);
}
break;
case MO_DEATH_DRAIN_WATER_1:
if (this->timers[0] == 0) {
this->csState = MO_DEATH_DRAIN_WATER_2;
this->cameraAt.y = -200.0f;
this->cameraNextAt.y = 320.0f;
this->cameraAtMaxVel.y = 0.05f;
this->cameraAtVel.y = 4.0f;
this->cameraSpeedMod = 0.0f;
this->cameraAccel = 0.0f;
sMorphaTent1->work[MO_TENT_ACTION_STATE] = MO_TENT_DEATH_1;
this->timers[0] = 125;
sMorphaTent1->fwork[MO_TENT_MAX_STRETCH] = 3.7000003f;
this->cameraYaw = 0.5f;
this->cameraDist = 200.0f;
return;
}
break;
case MO_DEATH_DRAIN_WATER_2:
if (this->timers[0] == 0) {
this->cameraAccel = 0.02f;
sMorphaTent1->work[MO_TENT_ACTION_STATE] = MO_TENT_DEATH_2;
this->csState = MO_DEATH_CEILING;
sMorphaTent1->timers[0] = 120;
this->timers[0] = 150;
}
case MO_DEATH_CEILING:
Math_ApproachF(&this->cameraYaw, 0.0f, 0.05f, 0.0029999996f);
Math_ApproachF(&this->cameraDist, 490.0f, 0.1f, 1.0f);
if (this->timers[0] == 0) {
this->csState = MO_DEATH_DROPLET;
this->timers[0] = 140;
this->cameraYawRate = 0.0f;
this->cameraSpeed = 0.0f;
}
break;
case MO_DEATH_DROPLET:
if (this->timers[0] == 30) {
sMorphaTent1->work[MO_TENT_ACTION_STATE] = MO_TENT_DEATH_5;
sMorphaTent1->timers[0] = 30;
sMorphaTent1->tentMaxAngle = 0.0f;
sMorphaTent1->tentSpeed = sMorphaTent1->tentMaxAngle;
}
if (this->timers[0] == 0) {
if (-100.0f < this->cameraEye.y) {
Math_ApproachF(&this->cameraEye.y, sMorphaTent1->actor.world.pos.y - 100.0f, 0.1f, 2000.0f);
} else {
Math_ApproachF(&this->cameraEye.y, -200.0f, 0.1f, 2000.0f);
}
Math_ApproachF(&this->cameraAt.y, (sMorphaTent1->actor.world.pos.y - 50.0f) + 30.0f, 0.5f, 2000.0f);
this->cameraNextAt.y = this->cameraAt.y;
} else {
Math_ApproachF(&this->cameraEye.y, 300.0f, 0.05f, this->cameraSpeed);
}
Math_ApproachF(&this->cameraYaw, -M_PI / 2.0f, 0.05f, this->cameraYawRate);
Math_ApproachF(&this->cameraSpeed, 3.0f, 1.0f, 0.05f);
Math_ApproachF(&this->cameraYawRate, 0.012999999f, 1.0f, 0.0005f);
if (sMorphaTent1->work[MO_TENT_ACTION_STATE] == MO_TENT_DEATH_6) {
Math_ApproachF(&this->cameraDist, 200.0f, 0.02f, this->cameraSpeed);
if (sMorphaTent1->timers[0] == 0) {
this->csState = MO_DEATH_FINISH;
camera->eye = this->cameraEye;
camera->eyeNext = this->cameraEye;
camera->at = this->cameraAt;
func_800C08AC(globalCtx, this->csCamera, 0);
this->csCamera = 0;
func_80064534(globalCtx, &globalCtx->csCtx);
func_8002DF54(globalCtx, &this->actor, 7);
sMorphaTent1->actor.world.pos.y = -1000.0f;
}
} else {
Math_ApproachF(&this->cameraDist, 150.0f, 0.05f, this->cameraSpeed);
}
break;
case MO_DEATH_FINISH:
break;
}
if ((this->csState > MO_DEATH_START) && (this->csState < MO_DEATH_FINISH)) {
if (this->work[MO_TENT_MOVE_TIMER] < 500) {
func_80078914(&sAudioZeroVec, NA_SE_EN_MOFER_APPEAR - SFX_FLAG);
}
if ((this->work[MO_TENT_MOVE_TIMER] < 490) && (this->work[MO_TENT_MOVE_TIMER] > 230)) {
func_80078914(&sAudioZeroVec, NA_SE_EV_DROP_FALL - SFX_FLAG);
}
if (this->work[MO_TENT_MOVE_TIMER] < 220) {
func_80078914(&sAudioZeroVec, NA_SE_EV_SCOOPUP_WATER - SFX_FLAG);
}
}
if (sMorphaCore->waterLevel < -200.0f) {
globalCtx->roomCtx.unk_74[0]++;
if (globalCtx->roomCtx.unk_74[0] >= 0xFF) {
globalCtx->roomCtx.unk_74[0] = 0xFF;
}
}
if (sMorphaCore->waterLevel < -250.0f) {
Math_ApproachF(&sMorphaTent1->waterTexAlpha, 0.0f, 1.0f, 3.0f);
}
Math_ApproachF(&this->fwork[MO_TENT_SWING_SIZE_X], 0.0f, 0.1f, 0.05f);
sp70.x = this->cameraDist;
sp70.y = 0.0f;
sp70.z = 0.0f;
Matrix_RotateY(this->cameraYaw, MTXMODE_NEW);
Matrix_MultVec3f(&sp70, &sp64);
this->cameraEye.x = sp64.x + this->cameraAt.x;
this->cameraEye.z = sp64.z + this->cameraAt.z;
one = 1; // Super fake, but it works
if (this->csCamera != 0) {
if (one) {
Math_ApproachF(&this->cameraAt.y, this->cameraNextAt.y, this->cameraAtMaxVel.y,
this->cameraAtVel.y * this->cameraSpeedMod);
Math_ApproachF(&this->cameraSpeedMod, 1.0f, 1.0f, this->cameraAccel);
}
Gameplay_CameraSetAtEye(globalCtx, this->csCamera, &this->cameraAt, &this->cameraEye);
}
}
void BossMo_CoreCollisionCheck(BossMo* this, GlobalContext* globalCtx) {
s16 i;
Player* player = GET_PLAYER(globalCtx);
osSyncPrintf(VT_FGCOL(YELLOW));
osSyncPrintf("Core_Damage_check START\n");
if (this->coreCollider.base.atFlags & AT_HIT) {
this->coreCollider.base.atFlags &= ~AT_HIT;
if (this->work[MO_TENT_ACTION_STATE] == MO_CORE_UNDERWATER) {
this->work[MO_CORE_WAIT_IN_WATER] = true;
this->timers[0] = 150;
}
}
if (this->coreCollider.base.acFlags & AC_HIT) {
ColliderInfo* hurtbox = this->coreCollider.info.acHitInfo;
// "hit!!"
osSyncPrintf("Core_Damage_check 当り!!\n");
this->coreCollider.base.acFlags &= ~AC_HIT;
if ((hurtbox->toucher.dmgFlags & 0x00020000) && (this->work[MO_TENT_ACTION_STATE] == MO_CORE_ATTACK)) {
this->work[MO_TENT_ACTION_STATE] = MO_CORE_RETREAT;
}
// "hit 2 !!"
osSyncPrintf("Core_Damage_check 当り 2 \n");
if ((this->work[MO_TENT_ACTION_STATE] != MO_CORE_UNDERWATER) && (this->work[MO_TENT_INVINC_TIMER] == 0)) {
u8 damage = CollisionCheck_GetSwordDamage(hurtbox->toucher.dmgFlags);
if ((damage != 0) && (this->work[MO_TENT_ACTION_STATE] < MO_CORE_ATTACK)) {
// "sword hit !!"
osSyncPrintf("Core_Damage_check 剣 当り!!\n");
this->work[MO_TENT_ACTION_STATE] = MO_CORE_STUNNED;
this->timers[0] = 25;
this->actor.speedXZ = 15.0f;
this->actor.world.rot.y = this->actor.yawTowardsPlayer + 0x8000;
this->work[MO_CORE_DMG_FLASH_TIMER] = 15;
Audio_PlayActorSound2(&this->actor, NA_SE_EN_MOFER_CORE_DAMAGE);
this->actor.colChkInfo.health -= damage;
this->hitCount++;
if ((s8)this->actor.colChkInfo.health <= 0) {
if (((sMorphaTent1->csCamera == 0) && (sMorphaTent2 == NULL)) ||
((sMorphaTent1->csCamera == 0) && (sMorphaTent2 != NULL) && (sMorphaTent2->csCamera == 0))) {
Enemy_StartFinishingBlow(globalCtx, &this->actor);
Audio_QueueSeqCmd(0x1 << 28 | SEQ_PLAYER_BGM_MAIN << 24 | 0x100FF);
this->csState = MO_DEATH_START;
sMorphaTent1->drawActor = false;
sMorphaTent1->work[MO_TENT_ACTION_STATE] = MO_TENT_DEATH_START;
sMorphaTent1->baseAlpha = 0.0f;
if (sMorphaTent2 != NULL) {
sMorphaTent2->tent2KillTimer = 1;
}
if (player->actor.parent != NULL) {
player->unk_850 = 0x65;
player->actor.parent = NULL;
player->csMode = 0;
}
} else {
this->actor.colChkInfo.health = 1;
}
}
this->work[MO_TENT_INVINC_TIMER] = 10;
} else if (!(hurtbox->toucher.dmgFlags & 0x00100000) && (hurtbox->toucher.dmgFlags & 0x80)) {
if (this->work[MO_TENT_ACTION_STATE] >= MO_CORE_ATTACK) {
func_80078914(&sMorphaTent1->tentTipPos, NA_SE_EN_MOFER_CUT);
sMorphaTent1->cutIndex = this->work[MO_CORE_POS_IN_TENT];
sMorphaTent1->meltIndex = sMorphaTent1->cutIndex + 1;
sMorphaTent1->cutScale = 1.0f;
sMorphaTent1->work[MO_TENT_ACTION_STATE] = MO_TENT_CUT;
sMorphaTent1->timers[0] = 40;
sMorphaTent1->actor.flags &= ~ACTOR_FLAG_0;
if (player->actor.parent == &sMorphaTent1->actor) {
player->unk_850 = 0x65;
player->actor.parent = NULL;
player->csMode = 0;
}
}
this->work[MO_TENT_ACTION_STATE] = MO_CORE_STUNNED;
this->timers[0] = 30;
this->work[MO_TENT_INVINC_TIMER] = 10;
this->actor.speedXZ = 0.0f;
}
for (i = 0; i < 10; i++) {
Vec3f pos;
Vec3f velocity;
velocity.x = Rand_CenteredFloat(4.0f);
velocity.y = Rand_ZeroFloat(2.0f) + 3.0f;
velocity.z = Rand_CenteredFloat(4.0f);
pos = this->actor.world.pos;
pos.x += (velocity.x * 3.0f);
pos.z += (velocity.z * 3.0f);
BossMo_SpawnDroplet(MO_FX_DROPLET, (BossMoEffect*)globalCtx->specialEffects, &pos, &velocity,
Rand_ZeroFloat(0.08f) + 0.13f);
}
}
}
// "end !!"
osSyncPrintf("Core_Damage_check 終わり \n");
osSyncPrintf(VT_RST);
}
void BossMo_Core(BossMo* this, GlobalContext* globalCtx) {
static f32 coreBulge[11] = {
0.1f, 0.15f, 0.2f, 0.3f, 0.4f, 0.43f, 0.4f, 0.3f, 0.2f, 0.15f, 0.1f,
};
u8 nearLand;
s16 i; // not on stack
Player* player = GET_PLAYER(globalCtx); // not on stack
f32 spDC;
f32 spD8;
f32 spD4;
f32 spD0;
f32 spCC;
s32 padC8;
s32 temp; // not on stack
f32 xScaleTarget; // not on stack
f32 yScaleTarget;
Vec3f effectPos;
Vec3f effectVelocity;
Vec3f effectAccel;
s32 pad94;
s32 pad90;
s16 j;
s16 index; // not on stack
f32 sp88;
s32 pad84;
f32 sp80;
f32 sp7C;
Vec3f sp70;
Vec3f sp64;
f32 sp60;
f32 sp5C;
f32 sp58;
this->waterTex1x += -1.0f;
this->waterTex1y += -1.0f;
this->waterTex2x = this->waterTex2x;
this->waterTex2y++;
Math_ApproachF(&this->baseAlpha, 255.0f, 1.0f, 10.0f);
if ((this->csState != MO_BATTLE) && (this->csState < MO_DEATH_START)) {
BossMo_IntroCs(this, globalCtx);
if (this->work[MO_TENT_ACTION_STATE] == MO_CORE_INTRO_WAIT) {
this->actor.flags &= ~ACTOR_FLAG_0;
return;
}
} else if (this->csState >= MO_DEATH_START) {
BossMo_DeathCs(this, globalCtx);
return;
}
if ((this->work[MO_TENT_ACTION_STATE] < MO_CORE_ATTACK) && (this->work[MO_TENT_ACTION_STATE] >= MO_CORE_MOVE) &&
(this->actor.world.pos.y > MO_WATER_LEVEL(globalCtx))) {
if (this->actor.velocity.y > 0.0f) {
xScaleTarget = 0.005f;
yScaleTarget = 0.015f;
} else {
xScaleTarget = 0.015f;
yScaleTarget = 0.005f;
}
} else {
xScaleTarget = yScaleTarget = 0.008f;
}
Math_ApproachF(&this->actor.scale.x, xScaleTarget, 0.2f, 0.001f);
this->actor.scale.z = this->actor.scale.x;
Math_ApproachF(&this->actor.scale.y, yScaleTarget, 0.2f, 0.001f);
this->work[MO_CORE_DRAW_SHADOW] = BossMo_NearLand(&this->actor.world.pos, 15.0f);
nearLand = BossMo_NearLand(&this->actor.world.pos, 0.0f);
if ((player->actor.world.pos.y < (MO_WATER_LEVEL(globalCtx) - 50.0f)) &&
((this->work[MO_TENT_ACTION_STATE] == MO_CORE_MOVE) ||
(this->work[MO_TENT_ACTION_STATE] == MO_CORE_MAKE_TENT))) {
this->work[MO_TENT_ACTION_STATE] = MO_CORE_UNDERWATER;
this->actor.speedXZ = 0.0f;
this->work[MO_CORE_WAIT_IN_WATER] = 0;
}
switch (this->work[MO_TENT_ACTION_STATE]) {
case MO_CORE_MOVE:
this->actor.flags |= ACTOR_FLAG_0;
if ((this->timers[0] == 0) &&
((sMorphaTent1->work[MO_TENT_ACTION_STATE] == MO_TENT_WAIT) ||
(sMorphaTent1->work[MO_TENT_ACTION_STATE] == MO_TENT_READY)) &&
(this->actor.world.pos.y < MO_WATER_LEVEL(globalCtx))) {
this->actor.speedXZ = 0.0f;
this->work[MO_TENT_ACTION_STATE] = MO_CORE_MAKE_TENT;
if (sMorphaTent1->work[MO_TENT_ACTION_STATE] == MO_TENT_WAIT) {
sMorphaTent1->work[MO_TENT_ACTION_STATE] = MO_TENT_SPAWN;
sMorphaTent1->timers[0] = 70;
sMorphaTent1->actor.shape.rot.y = sMorphaTent1->actor.yawTowardsPlayer;
}
}
break;
case MO_CORE_MAKE_TENT:
if ((sMorphaTent1->work[MO_TENT_ACTION_STATE] == MO_TENT_DESPAWN) ||
(sMorphaTent1->work[MO_TENT_ACTION_STATE] == MO_TENT_WAIT)) {
this->work[MO_TENT_ACTION_STATE] = MO_CORE_MOVE;
this->timers[0] = 70;
}
if (sMorphaTent1->work[MO_TENT_ACTION_STATE] == MO_TENT_CUT) {
this->work[MO_TENT_ACTION_STATE] = MO_CORE_ATTACK;
this->work[MO_CORE_POS_IN_TENT] = 0;
this->timers[0] = 0;
}
if (sMorphaTent1->work[MO_TENT_ACTION_STATE] == MO_TENT_ATTACK) {
this->work[MO_TENT_ACTION_STATE] = MO_CORE_ATTACK;
this->work[MO_CORE_POS_IN_TENT] = 0;
this->timers[0] = 0;
this->actor.speedXZ = 0.0f;
}
break;
case MO_CORE_UNDERWATER:
if (player->actor.world.pos.y >= MO_WATER_LEVEL(globalCtx)) {
this->work[MO_TENT_ACTION_STATE] = MO_CORE_MOVE;
this->actor.speedXZ = 0.0f;
}
break;
case MO_CORE_STUNNED:
this->actor.flags |= ACTOR_FLAG_0;
if (this->timers[0] == 0) {
this->work[MO_TENT_ACTION_STATE] = MO_CORE_MOVE;
this->timers[0] = 30;
}
if (this->actor.world.pos.y < MO_WATER_LEVEL(globalCtx)) {
this->work[MO_TENT_ACTION_STATE] = MO_CORE_MAKE_TENT;
this->timers[0] = 50;
this->actor.speedXZ = 0.0f;
}
break;
case MO_CORE_UNUSED:
break;
}
if (this->timers[0] == 0) {
switch (this->work[MO_TENT_ACTION_STATE]) {
case MO_CORE_ATTACK:
this->actor.flags |= ACTOR_FLAG_0;
this->work[MO_CORE_POS_IN_TENT]++;
if (sMorphaTent1->work[MO_TENT_ACTION_STATE] == MO_TENT_ATTACK) {
temp = (s16)(Math_SinS(this->work[MO_TENT_MOVE_TIMER] * 0x300) * 10.0f) + 15;
if (this->work[MO_CORE_POS_IN_TENT] >= temp) {
this->work[MO_CORE_POS_IN_TENT] = temp;
}
}
if ((sMorphaTent1->work[MO_TENT_ACTION_STATE] != MO_TENT_ATTACK) &&
(sMorphaTent1->work[MO_TENT_ACTION_STATE] != MO_TENT_CUT)) {
this->work[MO_TENT_ACTION_STATE] = MO_CORE_RETREAT;
this->timers[0] = 0;
}
break;
case MO_CORE_RETREAT:
this->work[MO_CORE_POS_IN_TENT]--;
if (this->work[MO_CORE_POS_IN_TENT] <= 0) {
this->work[MO_TENT_ACTION_STATE] = MO_CORE_MAKE_TENT;
this->timers[0] = 100;
this->tentSpeed = 0.0f;
this->actor.speedXZ = 0.0f;
}
this->timers[0] = 0;
break;
case MO_CORE_INTRO_REVEAL:
this->actor.flags &= ~ACTOR_FLAG_0;
this->work[MO_CORE_POS_IN_TENT]++;
temp = (s16)(Math_SinS(this->work[MO_TENT_MOVE_TIMER] * 0x500) * 10.0f) + 15;
if (this->work[MO_CORE_POS_IN_TENT] >= temp) {
this->work[MO_CORE_POS_IN_TENT] = temp;
}
if (sMorphaTent1->work[MO_TENT_ACTION_STATE] != MO_TENT_READY) {
this->work[MO_TENT_ACTION_STATE] = MO_CORE_RETREAT;
this->timers[0] = 0;
}
break;
}
}
if (this->work[MO_TENT_ACTION_STATE] >= MO_CORE_ATTACK) {
if (this->work[MO_CORE_POS_IN_TENT] < 0) {
this->work[MO_CORE_POS_IN_TENT] = 0;
} else if (this->work[MO_CORE_POS_IN_TENT] >= 41) {
this->work[MO_CORE_POS_IN_TENT] = 40;
}
index = (300 - (this->work[MO_CORE_POS_IN_TENT] * 2) + sMorphaTent1->widthIndex) % 300;
sp88 = sMorphaTent1->tentWidth[index] * sTentWidth[this->work[MO_CORE_POS_IN_TENT]];
for (j = -5; j < 6; j++) {
index = (this->work[MO_CORE_POS_IN_TENT] + j) - 2;
if ((0 <= index) && (index < 41)) {
Math_ApproachF(&sMorphaTent1->tentScale[index].x, ((coreBulge[j + 5] * 300.0f) / 100.0f) + sp88, 0.75f,
5.0f);
}
}
this->targetPos.x = sMorphaTent1->tentPos[this->work[MO_CORE_POS_IN_TENT]].x;
this->targetPos.y = sMorphaTent1->tentPos[this->work[MO_CORE_POS_IN_TENT]].y;
this->targetPos.z = sMorphaTent1->tentPos[this->work[MO_CORE_POS_IN_TENT]].z;
if (this->work[MO_CORE_POS_IN_TENT] <= 1) {
this->targetPos.y -= 20.0f;
}
Math_ApproachF(&this->actor.world.pos.x, this->targetPos.x, 0.5f, this->actor.speedXZ);
Math_ApproachF(&this->actor.world.pos.y, this->targetPos.y, 0.5f, this->actor.speedXZ);
Math_ApproachF(&this->actor.world.pos.z, this->targetPos.z, 0.5f, this->actor.speedXZ);
Math_ApproachF(&this->actor.speedXZ, 30.0f, 1.0f, 1.0f);
} else {
switch (this->work[MO_TENT_ACTION_STATE]) {
case MO_CORE_MOVE:
sp80 = Math_SinS(this->work[MO_TENT_VAR_TIMER] * 0x800) * 100.0f;
sp7C = Math_CosS(this->work[MO_TENT_VAR_TIMER] * 0x800) * 100.0f;
Math_ApproachF(&this->actor.world.pos.x, sMorphaTent1->targetPos.x + sp80, 0.05f, this->actor.speedXZ);
Math_ApproachF(&this->actor.world.pos.z, sMorphaTent1->targetPos.z + sp7C, 0.05f, this->actor.speedXZ);
Math_ApproachF(&this->actor.speedXZ, 10.0f, 1.0f, 0.5f);
break;
case MO_CORE_STUNNED:
this->actor.velocity.x = Math_SinS(this->actor.world.rot.y) * this->actor.speedXZ;
this->actor.velocity.z = Math_CosS(this->actor.world.rot.y) * this->actor.speedXZ;
this->actor.world.pos.x += this->actor.velocity.x;
this->actor.world.pos.z += this->actor.velocity.z;
break;
}
if ((this->work[MO_TENT_ACTION_STATE] == MO_CORE_MOVE) ||
(this->work[MO_TENT_ACTION_STATE] == MO_CORE_STUNNED)) {
this->actor.world.pos.y += this->actor.velocity.y;
this->actor.velocity.y -= 1.0f;
Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 50.0f, 20.0f, 100.0f, 1);
effectVelocity.x = effectVelocity.y = effectVelocity.z = 0.0f;
for (i = 0; i < 1; i++) {
effectPos.x = Rand_CenteredFloat(20.0f) + this->actor.world.pos.x;
effectPos.y = Rand_CenteredFloat(20.0f) + this->actor.world.pos.y;
effectPos.z = Rand_CenteredFloat(20.0f) + this->actor.world.pos.z;
BossMo_SpawnDroplet(MO_FX_DROPLET, (BossMoEffect*)globalCtx->specialEffects, &effectPos,
&effectVelocity, Rand_ZeroFloat(0.02f) + 0.05f);
};
if (nearLand) {
if (this->actor.world.pos.y <= 10) {
this->actor.world.pos.y = 10;
this->actor.velocity.y = -0.01f;
if (this->timers[1] != 0) {
if (this->timers[1] == 1) {
this->actor.velocity.y = 6.0f;
}
} else {
this->timers[1] = 2;
Audio_PlayActorSound2(&this->actor, NA_SE_EN_MOFER_CORE_LAND);
for (i = 0; i < 10; i++) {
effectVelocity.x = Rand_CenteredFloat(4.0f);
effectVelocity.y = Rand_ZeroFloat(2.0f) + 3.0f;
effectVelocity.z = Rand_CenteredFloat(4.0f);
effectPos = this->actor.world.pos;
effectPos.x += effectVelocity.x;
effectPos.z += effectVelocity.z;
BossMo_SpawnDroplet(MO_FX_DROPLET, (BossMoEffect*)globalCtx->specialEffects, &effectPos,
&effectVelocity, Rand_ZeroFloat(0.08f) + 0.13f);
}
effectVelocity.x = effectVelocity.y = effectVelocity.z = 0.0f;
effectPos = this->actor.world.pos;
effectPos.y = 0.0f;
BossMo_SpawnDroplet(MO_FX_DROPLET, (BossMoEffect*)globalCtx->specialEffects, &effectPos,
&effectVelocity, 0.4f);
}
}
} else if (this->actor.world.pos.y < MO_WATER_LEVEL(globalCtx)) {
this->actor.velocity.y = BossMo_NearLand(&this->actor.world.pos, 40.0f) ? 15.0f : 6.0f;
if ((this->actor.world.pos.y + 15.0f) >= MO_WATER_LEVEL(globalCtx)) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_MOFER_CORE_JUMP);
}
}
} else if (this->work[MO_TENT_ACTION_STATE] >= MO_CORE_MOVE) {
if (this->actor.world.pos.y < MO_WATER_LEVEL(globalCtx)) {
if (this->work[MO_TENT_ACTION_STATE] == MO_CORE_MAKE_TENT) {
this->targetPos.x = sMorphaTent1->targetPos.x;
this->targetPos.y = sMorphaTent1->actor.world.pos.y - 40.0f;
this->targetPos.z = sMorphaTent1->targetPos.z;
Math_ApproachF(&this->actor.speedXZ, 10.0f, 1.0f, 0.5f);
} else if (this->work[MO_TENT_ACTION_STATE] == MO_CORE_UNDERWATER) {
switch (this->work[MO_CORE_WAIT_IN_WATER]) {
case false:
this->targetPos = player->actor.world.pos;
this->targetPos.y += 30.0f;
sp70.x = 0.0f;
sp70.y = 0.0f;
sp70.z = 100.0f;
Matrix_RotateY((player->actor.world.rot.y / (f32)0x8000) * M_PI, MTXMODE_NEW);
Matrix_MultVec3f(&sp70, &sp64);
this->targetPos.x = player->actor.world.pos.x + sp64.x;
this->targetPos.y = player->actor.world.pos.y + 30.0f;
this->targetPos.z = player->actor.world.pos.z + sp64.z;
Math_ApproachF(&this->actor.speedXZ, 10.0f, 1.0f, 1.0f);
if (this->timers[0] == 0) {
this->work[MO_CORE_WAIT_IN_WATER] = true;
this->timers[0] = (s16)Rand_ZeroFloat(50.0f) + 50;
}
break;
case true:
Math_ApproachF(&this->actor.speedXZ, 1.0f, 1.0f, 0.5f);
if (this->timers[0] == 0) {
this->work[MO_CORE_WAIT_IN_WATER] = false;
this->timers[0] = (s16)Rand_ZeroFloat(20.0f) + 20;
Audio_PlayActorSound2(&this->actor, NA_SE_EN_MOFER_CORE_MOVE_WT);
}
break;
}
}
this->targetPos.x += Math_SinS(this->work[MO_TENT_MOVE_TIMER] * 3096.0f) * 30.0f;
this->targetPos.y += Math_SinS(this->work[MO_TENT_MOVE_TIMER] * 2096.0f) * 30.0f;
this->targetPos.z += Math_SinS(this->work[MO_TENT_MOVE_TIMER] * 2796.0f) * 30.0f;
this->tentMaxAngle = 5.0f;
this->tentSpeed = 4000.0f;
spDC = this->targetPos.x - this->actor.world.pos.x;
spD8 = this->targetPos.y - this->actor.world.pos.y;
spD4 = this->targetPos.z - this->actor.world.pos.z;
spCC = (s16)(Math_FAtan2F(spDC, spD4) * (0x8000 / M_PI));
spD0 = (s16)(Math_FAtan2F(spD8, sqrtf(SQ(spDC) + SQ(spD4))) * (0x8000 / M_PI));
Math_ApproachS(&this->actor.world.rot.y, spCC, this->tentMaxAngle, this->tentSpeed);
Math_ApproachS(&this->actor.world.rot.x, spD0, this->tentMaxAngle, this->tentSpeed);
func_8002D908(&this->actor);
} else {
this->actor.world.pos.y += this->actor.velocity.y;
this->actor.velocity.y -= 1.0f;
}
func_8002D7EC(&this->actor);
temp = (this->actor.world.pos.y < -200.0f) ? 5 : 1;
this->actor.world.pos.y -= 20.0f;
Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 50.0f, 20.0f, 100.0f, temp);
this->actor.world.pos.y += 20.0f;
}
}
if ((this->actor.world.pos.y < MO_WATER_LEVEL(globalCtx)) && (MO_WATER_LEVEL(globalCtx) <= this->actor.prevPos.y)) {
if (this->actor.velocity.y < -5.0f) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_MOFER_CORE_JUMP);
} else {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_MOFER_CORE_SMJUMP);
}
if ((this->timers[3] != 0) || ((sMorphaTent1->fwork[MO_TENT_MAX_STRETCH] > 0.2f) &&
(fabsf(this->actor.world.pos.x - sMorphaTent1->actor.world.pos.x) < 30.0f) &&
(fabsf(this->actor.world.pos.z - sMorphaTent1->actor.world.pos.z) < 30.0f))) {
// This space intentionally left blank.
} else {
this->timers[3] = 8;
for (i = 0; i < 10; i++) {
sp5C = Rand_ZeroFloat(3.14f);
sp60 = Rand_ZeroFloat(0.6f) + 1.6f;
effectVelocity.x = Math_SinS(((i * (f32)0x10000) / 10.0f) + sp5C) * sp60;
effectVelocity.z = Math_CosS(((i * (f32)0x10000) / 10.0f) + sp5C) * sp60;
effectVelocity.y = Rand_ZeroFloat(0.3f) + 3.0f;
effectPos = this->actor.world.pos;
effectPos.x += effectVelocity.x * 3.0f;
effectPos.y = MO_WATER_LEVEL(globalCtx);
effectPos.z += effectVelocity.z * 3.0f;
BossMo_SpawnDroplet(MO_FX_SPLASH, (BossMoEffect*)globalCtx->specialEffects, &effectPos, &effectVelocity,
Rand_ZeroFloat(0.075f) + 0.15f);
}
effectPos = this->actor.world.pos;
effectPos.y = MO_WATER_LEVEL(globalCtx);
BossMo_SpawnRipple(globalCtx->specialEffects, &effectPos, 100.0f, 800.0f, 100, 290, MO_FX_SMALL_RIPPLE);
BossMo_SpawnRipple(globalCtx->specialEffects, &effectPos, 50.0f, 600.0f, 70, 290, MO_FX_SMALL_RIPPLE);
BossMo_SpawnRipple(globalCtx->specialEffects, &effectPos, 0, 400.0f, 50, 290, MO_FX_SMALL_RIPPLE);
}
}
if ((this->actor.world.pos.y < MO_WATER_LEVEL(globalCtx)) || (this->work[MO_TENT_ACTION_STATE] >= MO_CORE_ATTACK)) {
for (i = 0; i < 3; i++) {
effectAccel.x = effectAccel.z = 0.0f;
effectVelocity.x = effectVelocity.y = effectVelocity.z = 0.0f;
if (this->work[MO_TENT_ACTION_STATE] >= MO_CORE_ATTACK) {
effectAccel.y = 0.0f;
sp58 = 10.0f;
} else {
effectAccel.y = 0.1f;
sp58 = 20.0f;
}
effectPos.x = Rand_CenteredFloat(sp58) + this->actor.world.pos.x;
effectPos.y = Rand_CenteredFloat(sp58) + this->actor.world.pos.y;
effectPos.z = Rand_CenteredFloat(sp58) + this->actor.world.pos.z;
BossMo_SpawnBubble(globalCtx->specialEffects, &effectPos, &effectVelocity, &effectAccel,
Rand_ZeroFloat(0.05f) + 0.1f, NULL);
}
}
BossMo_CoreCollisionCheck(this, globalCtx);
}
void BossMo_UpdateCore(Actor* thisx, GlobalContext* globalCtx) {
s32 pad;
BossMo* this = (BossMo*)thisx;
s16 i;
Player* player = GET_PLAYER(globalCtx);
osSyncPrintf("CORE mode = <%d>\n", this->work[MO_TENT_ACTION_STATE]);
if (sMorphaTent2 == NULL) {
MO_WATER_LEVEL(globalCtx) = sMorphaTent1->waterLevelMod + (s16)this->waterLevel;
} else {
MO_WATER_LEVEL(globalCtx) = sMorphaTent2->waterLevelMod + ((s16)this->waterLevel + sMorphaTent1->waterLevelMod);
}
this->actor.flags |= ACTOR_FLAG_9;
this->actor.focus.pos = this->actor.world.pos;
this->work[MO_TENT_VAR_TIMER]++;
if (this->work[MO_CORE_DMG_FLASH_TIMER] != 0) {
this->work[MO_CORE_DMG_FLASH_TIMER]--;
}
if (this->work[MO_TENT_INVINC_TIMER] != 0) {
this->work[MO_TENT_INVINC_TIMER]--;
}
this->work[MO_TENT_MOVE_TIMER]++;
for (i = 0; i < ARRAY_COUNT(this->timers); i++) {
if (this->timers[i] != 0) {
this->timers[i]--;
}
}
BossMo_Core(this, globalCtx);
Collider_UpdateCylinder(&this->actor, &this->coreCollider);
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->coreCollider.base);
if ((this->work[MO_TENT_ACTION_STATE] != MO_CORE_STUNNED) ||
(this->actor.world.pos.y < MO_WATER_LEVEL(globalCtx))) {
CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->coreCollider.base);
} else {
CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->coreCollider.base);
}
BossMo_UpdateEffects(this, globalCtx);
if (player->actor.parent != NULL) {
this->actor.flags &= ~ACTOR_FLAG_0;
}
BossMo_Unknown();
}
void BossMo_UpdateTent(Actor* thisx, GlobalContext* globalCtx) {
s16 i;
s16 index;
s32 pad;
BossMo* this = (BossMo*)thisx;
Player* player = GET_PLAYER(globalCtx);
f32 phi_f0;
if ((this == sMorphaTent2) && (this->tent2KillTimer != 0)) {
this->tent2KillTimer++;
this->actor.draw = NULL;
if (this->tent2KillTimer > 20) {
Actor_Kill(&this->actor);
Audio_StopSfxByPos(&this->tentTipPos);
sMorphaTent2 = NULL;
}
return;
}
SkinMatrix_Vec3fMtxFMultXYZW(&globalCtx->viewProjectionMtxF, &this->tentPos[40], &this->tentTipPos,
&this->actor.projectedW);
osSyncPrintf("MO : Move mode = <%d>\n", this->work[MO_TENT_ACTION_STATE]);
Math_ApproachS(&player->actor.shape.rot.x, 0, 5, 0x3E8);
Math_ApproachS(&player->actor.shape.rot.z, 0, 5, 0x3E8);
this->work[MO_TENT_VAR_TIMER]++;
this->sfxTimer++;
this->work[MO_TENT_MOVE_TIMER]++;
this->widthIndex++;
if (this->widthIndex >= 300) {
this->widthIndex = 0;
}
this->pulsePhase -= 3000;
index = this->widthIndex;
this->tentWidth[index] = (Math_SinS(this->pulsePhase) * this->tentPulse) + (1.0f + this->tentPulse);
for (i = 0; i < 41; i++) {
if (this->work[MO_TENT_ACTION_STATE] >= MO_TENT_DEATH_START) {
if (this->work[MO_TENT_ACTION_STATE] >= MO_TENT_DEATH_1) {
if (this->work[MO_TENT_ACTION_STATE] == MO_TENT_DEATH_5) {
phi_f0 = (this->timers[0] != 0) ? sFlatWidth[i] : sDropletWidth[i];
Math_ApproachF(&this->tentScale[i].x, phi_f0, 0.5f, 100.0f);
} else {
index = ((this->widthIndex + (i * 2)) + 220) % 300;
phi_f0 = this->tentWidth[index] + SQ(sTentWidth[i]);
Math_ApproachF(&this->tentScale[i].x, phi_f0, 0.5f, 0.3f);
}
} else {
index = ((this->widthIndex - (i * 2)) + 300) % 300;
phi_f0 = this->tentWidth[index] * sTentWidth[i];
this->tentScale[i].x = phi_f0;
}
} else {
index = ((this->widthIndex - (i * 2)) + 300) % 300;
phi_f0 = this->tentWidth[index] * sTentWidth[i];
Math_ApproachF(&this->tentScale[i].x, phi_f0, 0.5f, 0.3f);
}
phi_f0 = Math_SinS((this->work[MO_TENT_VAR_TIMER] * 12000.0f) + (i * 20000.0f));
this->tentRipple[i].x = (1.0f * phi_f0) * this->tentRippleSize;
this->tentScale[i].y = this->tentScale[i].z = this->tentScale[i].x;
this->tentRipple[i].y = this->tentRipple[i].z = this->tentRipple[i].x;
}
Math_ApproachF(&this->tentRippleSize, 0.0f, 0.1f, 0.005f);
Math_ApproachF(&this->tentPulse, 0.2f, 0.5f, 0.01f);
this->actionFunc(this, globalCtx);
for (i = 0; i < ARRAY_COUNT(this->timers); i++) {
if (this->timers[i] != 0) {
this->timers[i]--;
}
}
Math_ApproachS(&this->actor.world.rot.y, this->actor.yawTowardsPlayer, 0xA, 0xC8);
Actor_MoveForward(&this->actor);
Math_ApproachF(&this->actor.speedXZ, 0.0, 1.0f, 0.02f);
if (BossMo_NearLand(&this->actor.world.pos, 40)) {
this->actor.world.pos = this->actor.prevPos;
}
if ((this->work[MO_TENT_VAR_TIMER] % 8) == 0) {
f32 rippleScale;
Vec3f pos = this->actor.world.pos;
if (this->work[MO_TENT_ACTION_STATE] < MO_TENT_DEATH_START) {
rippleScale = 400.0f;
} else {
rippleScale = 0.0;
if (this->work[MO_TENT_ACTION_STATE] >= MO_TENT_DEATH_1) {
pos = this->tentPos[38];
}
}
BossMo_SpawnRipple(globalCtx->specialEffects, &pos, rippleScale, rippleScale * 3.0f, this->baseAlpha * 0.6666f,
300, MO_FX_BIG_RIPPLE);
}
if (this->baseBubblesTimer != 0) {
Vec3f sp88;
Vec3f sp7C;
Vec3f bubblePos;
Vec3f zeroVec = { 0.0f, 0.0f, 0.0f };
s32 pad;
this->baseBubblesTimer--;
sp88.x = 0.0;
sp88.y = 0.0;
sp88.z = 100.0f;
Matrix_RotateY(Rand_ZeroFloat(2.0f * M_PI), MTXMODE_NEW);
Matrix_MultVec3f(&sp88, &sp7C);
if ((this->work[MO_TENT_ACTION_STATE] >= MO_TENT_DEATH_1) &&
(this->work[MO_TENT_ACTION_STATE] != MO_TENT_DEATH_3)) {
i = 38;
} else {
i = 0;
if (this->work[MO_TENT_ACTION_STATE] < MO_TENT_CUT) {
func_80078914(&this->tentTipPos, NA_SE_EN_MOFER_CORE_ROLL - SFX_FLAG);
}
}
bubblePos.x = this->tentPos[i].x + sp7C.x;
bubblePos.y = (MO_WATER_LEVEL(globalCtx) - 40.0f) + Rand_ZeroFloat(20.0f);
bubblePos.z = this->tentPos[i].z + sp7C.z;
BossMo_SpawnBubble(globalCtx->specialEffects, &bubblePos, &zeroVec, &zeroVec, Rand_ZeroFloat(0.05f) + 0.2f,
&this->tentPos[i]);
}
if (this->work[MO_CORE_DMG_FLASH_TIMER] != 0) {
this->work[MO_CORE_DMG_FLASH_TIMER]--;
}
if (this->work[MO_TENT_INVINC_TIMER] != 0) {
this->work[MO_TENT_INVINC_TIMER]--;
}
if (this->linkHitTimer != 0) {
this->linkHitTimer--;
}
if (this->drawActor) {
BossMo_TentCollisionCheck(this, globalCtx);
if ((this->work[MO_TENT_INVINC_TIMER] == 0) && (this->work[MO_TENT_ACTION_STATE] != MO_TENT_GRAB) &&
(this->work[MO_TENT_ACTION_STATE] != MO_TENT_SHAKE)) {
BossMo* otherTent = (BossMo*)this->otherTent;
if (!HAS_LINK(otherTent) && (this->cutIndex == 0)) {
CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->tentCollider.base);
CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->tentCollider.base);
}
}
if (this->cutIndex == 0) {
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->tentCollider.base);
}
}
this->work[MO_TENT_BASE_TEX1_X]++;
this->work[MO_TENT_BASE_TEX1_Y]++;
this->work[MO_TENT_BASE_TEX2_X] -= 3;
this->work[MO_TENT_BASE_TEX2_Y]++;
Math_ApproachZeroF(&this->waterLevelMod, 0.1f, 0.2f);
}
void BossMo_UpdateTentColliders(BossMo* this, s32 item, ColliderJntSph* tentCollider, Vec3f* center) {
tentCollider->elements[item].dim.worldSphere.center.x = center->x;
tentCollider->elements[item].dim.worldSphere.center.y = center->y;
tentCollider->elements[item].dim.worldSphere.center.z = center->z;
if (this->work[MO_TENT_ACTION_STATE] <= MO_TENT_SHAKE) {
tentCollider->elements[item].dim.worldSphere.radius =
tentCollider->elements[item].dim.modelSphere.radius * tentCollider->elements[item].dim.scale;
} else {
tentCollider->elements[item].dim.worldSphere.radius = 0;
}
}
static Gfx* sTentDLists[41] = {
gMorphaTentaclePart0DL, gMorphaTentaclePart1DL, gMorphaTentaclePart2DL, gMorphaTentaclePart3DL,
gMorphaTentaclePart4DL, gMorphaTentaclePart5DL, gMorphaTentaclePart6DL, gMorphaTentaclePart7DL,
gMorphaTentaclePart8DL, gMorphaTentaclePart9DL, gMorphaTentaclePart10DL, gMorphaTentaclePart11DL,
gMorphaTentaclePart12DL, gMorphaTentaclePart13DL, gMorphaTentaclePart14DL, gMorphaTentaclePart15DL,
gMorphaTentaclePart16DL, gMorphaTentaclePart17DL, gMorphaTentaclePart18DL, gMorphaTentaclePart19DL,
gMorphaTentaclePart20DL, gMorphaTentaclePart21DL, gMorphaTentaclePart22DL, gMorphaTentaclePart23DL,
gMorphaTentaclePart24DL, gMorphaTentaclePart25DL, gMorphaTentaclePart26DL, gMorphaTentaclePart27DL,
gMorphaTentaclePart28DL, gMorphaTentaclePart29DL, gMorphaTentaclePart30DL, gMorphaTentaclePart31DL,
gMorphaTentaclePart32DL, gMorphaTentaclePart33DL, gMorphaTentaclePart34DL, gMorphaTentaclePart35DL,
gMorphaTentaclePart36DL, gMorphaTentaclePart37DL, gMorphaTentaclePart38DL, gMorphaTentaclePart39DL,
gMorphaTentaclePart40DL,
};
void BossMo_DrawTentacle(BossMo* this, GlobalContext* globalCtx) {
static Vec3f zeroVec = { 0.0f, 0.0f, 0.0f };
s16 i;
s16 notCut;
s16 index;
Mtx* matrix = Graph_Alloc(globalCtx->state.gfxCtx, 41 * sizeof(Mtx));
f32 phi_f20;
f32 phi_f22;
Vec3f sp110;
static s32 epoch = 0;
epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx);
sp110.x = globalCtx->envCtx.dirLight1.params.dir.x;
sp110.y = globalCtx->envCtx.dirLight1.params.dir.y;
sp110.z = globalCtx->envCtx.dirLight1.params.dir.z;
Matrix_Push();
gDPPipeSync(POLY_XLU_DISP++);
gSPSegment(POLY_XLU_DISP++, 0x0C, matrix);
Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, MTXMODE_NEW);
Matrix_RotateY((this->actor.shape.rot.y / (f32)0x8000) * M_PI, MTXMODE_APPLY);
Matrix_RotateX((this->actor.shape.rot.x / (f32)0x8000) * M_PI, MTXMODE_APPLY);
BossMo_InitRand(1, 29100, 9786);
for (i = 0; i < 41; i++, matrix++) {
FrameInterpolation_RecordOpenChild("Morpha Tentacle", epoch + i * 25);
s32 pad;
s32 pad2;
if (i < 2) {
Matrix_Push();
Matrix_Scale(0.0f, 0.0f, 0.0f, MTXMODE_APPLY);
notCut = true;
} else {
if (i >= 3) {
Matrix_Translate(0.0f, this->tentStretch[i - 2].y, 0.0f, MTXMODE_APPLY);
Matrix_RotateX((this->tentRot[i - 2].x / (f32)0x8000) * M_PI, MTXMODE_APPLY);
Matrix_RotateZ((this->tentRot[i - 2].z / (f32)0x8000) * M_PI, MTXMODE_APPLY);
}
Matrix_Push();
Matrix_Scale((this->tentScale[i - 2].x + this->tentRipple[i - 2].x) * this->actor.scale.x,
(this->tentScale[i - 2].y + this->tentRipple[i - 2].y) * this->actor.scale.y,
(this->tentScale[i - 2].z + this->tentRipple[i - 2].z) * this->actor.scale.z, MTXMODE_APPLY);
notCut = true;
if ((i >= this->cutIndex) && (this->meltIndex >= i)) {
Matrix_Scale(this->cutScale, this->cutScale, this->cutScale, MTXMODE_APPLY);
notCut = false;
}
}
index = ((this->widthIndex - (i * 2)) + 300) % 300;
if (this->work[MO_TENT_ACTION_STATE] < MO_TENT_DEATH_START) {
Matrix_RotateY((((this->tentWidth[index] - 1.0f - this->tentPulse) * 1000) / 1000.0f) *
this->fwork[MO_TENT_MAX_STRETCH],
MTXMODE_APPLY);
}
Matrix_RotateX(M_PI / 2.0f, MTXMODE_APPLY);
MATRIX_TOMTX(matrix);
gSPMatrix(POLY_XLU_DISP++, matrix, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
if (i == 0) {
func_8002EB44(&this->tentPos[i], &globalCtx->view.eye, &sp110, globalCtx->state.gfxCtx);
}
if (i == 0) {
gSPDisplayList(POLY_XLU_DISP++, gMorphaTentacleBaseDL);
} else {
gSPDisplayList(POLY_XLU_DISP++, sTentDLists[i]);
}
Matrix_Pop();
if ((i >= 2) && notCut && (i < (this->noBubbles + 38))) {
if ((this->work[MO_TENT_ACTION_STATE] == MO_TENT_DEATH_1) ||
(this->work[MO_TENT_ACTION_STATE] == MO_TENT_DEATH_2)) {
phi_f20 = this->work[MO_TENT_MOVE_TIMER] & 3;
phi_f20 *= -15.0f;
phi_f22 = ((0.18f + BossMo_RandZeroOne() * 0.1f) * this->actor.scale.x) * 100.0f;
} else {
phi_f20 = 0.0f;
phi_f22 = (((BossMo_RandZeroOne() * (0.08f)) + .08f) * this->actor.scale.x) * 100.0f;
}
Matrix_Push();
Matrix_Translate(((BossMo_RandZeroOne() - 0.5f) * 10.0f) * this->tentScale[i - 2].x,
((BossMo_RandZeroOne() - 0.5f) * 3.0f) + phi_f20,
((BossMo_RandZeroOne() - 0.5f) * 10.0f) * this->tentScale[i - 2].z, MTXMODE_APPLY);
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
Matrix_Scale(phi_f22, phi_f22, 1.0f, MTXMODE_APPLY);
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, gMorphaBubbleDL);
Matrix_Pop();
}
Matrix_MultVec3f(&zeroVec, &this->tentPos[i]);
if (i == 36) {
Matrix_MultVec3f(&zeroVec, &this->actor.focus.pos);
}
if (i == 24) {
MtxF sp98;
Vec3f sp8C = { -16.0f, 13.0f, 30.0f };
Vec3s sp84;
Matrix_Push();
if (this->linkToLeft) {
sp8C.x *= -1.0f;
}
Matrix_MultVec3f(&sp8C, &this->grabPosRot.pos);
Matrix_RotateX(-35 * M_PI / 64, MTXMODE_APPLY);
Matrix_Get(&sp98);
Matrix_MtxFToYXZRotS(&sp98, &sp84, 0);
this->grabPosRot.rot.x = sp84.x;
this->grabPosRot.rot.y = sp84.y;
this->grabPosRot.rot.z = sp84.z;
Matrix_Pop();
}
if ((i < 38) && ((i & 1) == 1)) {
BossMo_UpdateTentColliders(this, i / 2, &this->tentCollider, &this->tentPos[i]);
}
FrameInterpolation_RecordCloseChild();
}
Matrix_Pop();
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
void BossMo_DrawWater(BossMo* this, GlobalContext* globalCtx) {
s32 pad;
OPEN_DISPS(globalCtx->state.gfxCtx);
Matrix_Push();
func_80093D84(globalCtx->state.gfxCtx);
Matrix_Translate(0.0f, MO_WATER_LEVEL(globalCtx), 0.0f, MTXMODE_NEW);
gSPSegment(POLY_XLU_DISP++, 0x0D,
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, (s16)this->waterTex1x, (s16)this->waterTex1y, 32, 32, 1,
(s16)this->waterTex2x, (s16)this->waterTex2y, 32, 32));
gDPPipeSync(POLY_XLU_DISP++);
gDPSetPrimColor(POLY_XLU_DISP++, 0xFF, 0xFF, 200, 255, 255, (s8)sMorphaTent1->waterTexAlpha);
gDPSetEnvColor(POLY_XLU_DISP++, 0, 100, 255, 80);
Matrix_Scale(0.5f, 1.0f, 0.5f, MTXMODE_APPLY);
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gMorphaWaterDL);
Matrix_Pop();
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
void BossMo_DrawCore(Actor* thisx, GlobalContext* globalCtx) {
s32 pad;
BossMo* this = (BossMo*)thisx;
OPEN_DISPS(globalCtx->state.gfxCtx);
if (this->actor.world.pos.y > MO_WATER_LEVEL(globalCtx)) {
BossMo_DrawWater(this, globalCtx);
}
if (this->drawActor) {
func_80093D84(globalCtx->state.gfxCtx);
gSPSegment(POLY_XLU_DISP++, 0x08,
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, sMorphaTent1->work[MO_TENT_VAR_TIMER] * 3,
sMorphaTent1->work[MO_TENT_VAR_TIMER] * 3, 32, 32, 1,
sMorphaTent1->work[MO_TENT_VAR_TIMER] * -3,
sMorphaTent1->work[MO_TENT_VAR_TIMER] * -3, 32, 32));
gSPSegment(POLY_XLU_DISP++, 0x09,
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, sMorphaTent1->work[MO_TENT_VAR_TIMER] * 5, 0, 32, 32, 1,
0, sMorphaTent1->work[MO_TENT_VAR_TIMER] * -10, 32, 32));
Matrix_RotateX(this->work[MO_TENT_MOVE_TIMER] * 0.5f, MTXMODE_APPLY);
Matrix_RotateZ(this->work[MO_TENT_MOVE_TIMER] * 0.8f, MTXMODE_APPLY);
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gDPSetPrimColor(POLY_XLU_DISP++, 0x80, 0x80, 255, 255, 255, (s8)this->baseAlpha);
func_8002ED80(&this->actor, globalCtx, 0);
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(gMorphaCoreMembraneDL));
gDPPipeSync(POLY_XLU_DISP++);
gDPSetEnvColor(POLY_XLU_DISP++, 0, 220, 255, 128);
if ((this->work[MO_CORE_DMG_FLASH_TIMER] % 2) != 0) {
gDPSetPrimColor(POLY_XLU_DISP++, 0x80, 0x80, 255, 60, 0, 255);
} else {
gDPSetPrimColor(POLY_XLU_DISP++, 0x80, 0x80, 255, 255, 255, 255);
}
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(gMorphaCoreNucleusDL));
if ((this->work[MO_CORE_DRAW_SHADOW] && (this->actor.world.pos.y >= 0.0f)) ||
(this->actor.world.pos.y < MO_WATER_LEVEL(globalCtx))) {
f32 groundLevel;
s16 shadowAlpha;
if (this->actor.world.pos.y < MO_WATER_LEVEL(globalCtx)) {
groundLevel = -280.0f;
shadowAlpha = 100;
} else {
groundLevel = 0.0f;
shadowAlpha = 160;
}
func_80094044(globalCtx->state.gfxCtx);
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 0, 0, 0, shadowAlpha);
Matrix_Translate(this->actor.world.pos.x, groundLevel, this->actor.world.pos.z, MTXMODE_NEW);
Matrix_Scale(0.23f, 1.0f, 0.23f, MTXMODE_APPLY);
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(gCircleShadowDL));
}
}
if (this->actor.world.pos.y < MO_WATER_LEVEL(globalCtx)) {
BossMo_DrawWater(this, globalCtx);
}
if ((this->csCamera != 0) && (this->csState < MO_INTRO_REVEAL)) {
f32 sp8C;
f32 sp88;
f32 sp84;
f32 temp;
f32 sp7C;
f32 sp78;
Vec3f sp6C;
Vec3f sp60;
func_80093D84(globalCtx->state.gfxCtx);
gDPSetPrimColor(POLY_XLU_DISP++, 0xFF, 0xFF, 200, 255, 255, (s8)this->fwork[MO_CORE_INTRO_WATER_ALPHA]);
gDPSetEnvColor(POLY_XLU_DISP++, 0, 100, 255, (s8)this->fwork[MO_CORE_INTRO_WATER_ALPHA]);
gSPSegment(POLY_XLU_DISP++, 0x0D,
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, (s16)sMorphaTent1->waterTex1x,
(s16)sMorphaTent1->waterTex1y, 32, 32, 1, (s16)sMorphaTent1->waterTex2x,
(s16)sMorphaTent1->waterTex2y, 32, 32));
sp8C = this->cameraAt.x - this->cameraEye.x;
sp88 = this->cameraAt.y - this->cameraEye.y;
sp84 = this->cameraAt.z - this->cameraEye.z;
temp = SQ(sp8C) + SQ(sp84);
sp7C = Math_FAtan2F(sp8C, sp84);
sp78 = -Math_FAtan2F(sp88, sqrtf(temp));
sp6C.x = 0.0f;
sp6C.y = 0.0f;
sp6C.z = 10.0f;
Matrix_RotateY(sp7C, MTXMODE_NEW);
Matrix_RotateX(sp78, MTXMODE_APPLY);
Matrix_MultVec3f(&sp6C, &sp60);
sp8C = sp60.x + this->cameraEye.x;
sp88 = sp60.y + this->cameraEye.y;
sp84 = sp60.z + this->cameraEye.z;
Matrix_Translate(sp8C, sp88, sp84, MTXMODE_NEW);
Matrix_RotateY(sp7C, MTXMODE_APPLY);
Matrix_RotateX(sp78, MTXMODE_APPLY);
Matrix_RotateZ(-(0.01f * this->work[MO_TENT_VAR_TIMER]), MTXMODE_APPLY);
Matrix_RotateZ(0.1f * this->work[MO_TENT_VAR_TIMER], MTXMODE_APPLY);
Matrix_Scale(0.825f, 1.175f, 0.825f, MTXMODE_APPLY);
Matrix_RotateZ(-(this->work[MO_TENT_VAR_TIMER] * 0.1f), MTXMODE_APPLY);
Matrix_RotateX(M_PI / 2.0f, MTXMODE_APPLY);
Matrix_Scale(0.05f, 1.0f, 0.05f, MTXMODE_APPLY);
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gMorphaWaterDL);
}
CLOSE_DISPS(globalCtx->state.gfxCtx);
BossMo_DrawEffects(globalCtx->specialEffects, globalCtx);
}
void BossMo_DrawTent(Actor* thisx, GlobalContext* globalCtx) {
s32 pad;
BossMo* this = (BossMo*)thisx;
u16 scroll;
OPEN_DISPS(globalCtx->state.gfxCtx);
func_80093D18(globalCtx->state.gfxCtx);
gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, (s8)(this->baseAlpha * 1.5f));
gDPSetEnvColor(POLY_OPA_DISP++, 150, 150, 150, 0);
func_80093D84(globalCtx->state.gfxCtx);
gSPSegment(POLY_XLU_DISP++, 0x08,
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, this->work[MO_TENT_BASE_TEX1_X],
this->work[MO_TENT_BASE_TEX1_Y], 32, 32, 1, this->work[MO_TENT_BASE_TEX2_X],
this->work[MO_TENT_BASE_TEX2_Y], 32, 32));
gDPSetPrimColor(POLY_XLU_DISP++, 0xFF, 0xFF, 200, 255, 255, (s8)((this->baseAlpha * 12.0f) / 10.0f));
gDPSetEnvColor(POLY_XLU_DISP++, 0, 100, 255, (s8)this->baseAlpha);
scroll = (s16)(Math_SinS(this->work[MO_TENT_VAR_TIMER] * 0xB00) * 30.0f) + 350;
gSPTexture(POLY_XLU_DISP++, scroll, scroll, 0, G_TX_RENDERTILE, G_ON);
if (this->drawActor) {
BossMo_DrawTentacle(this, globalCtx);
}
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
void BossMo_UpdateEffects(BossMo* this, GlobalContext* globalCtx) {
BossMoEffect* effect = globalCtx->specialEffects;
s16 i;
Vec3f* targetPos;
f32 dx;
f32 dz;
Vec3f bubbleSpeed = { 0.0f, 0.0f, 0.0f };
Vec3f bubbleVel;
for (i = 0; i < ARRAY_COUNT(sEffects); i++, effect++) {
if (effect->type != MO_FX_NONE) {
effect->timer++;
if (effect->stopTimer == 0) {
effect->pos.x += effect->vel.x;
effect->pos.y += effect->vel.y;
effect->pos.z += effect->vel.z;
effect->vel.x += effect->accel.x;
effect->vel.y += effect->accel.y;
effect->vel.z += effect->accel.z;
} else {
effect->stopTimer--;
}
if (effect->type <= MO_FX_BIG_RIPPLE) {
if (this->csState >= MO_DEATH_START) {
effect->pos.y = MO_WATER_LEVEL(globalCtx);
}
Math_ApproachF(&effect->scale, effect->fwork[MO_FX_MAX_SIZE], 0.2f, effect->fwork[MO_FX_SPREAD_RATE]);
if (effect->rippleMode == 0) {
effect->alpha += 15;
if (effect->alpha >= effect->maxAlpha) {
effect->alpha = effect->maxAlpha;
effect->rippleMode++;
}
} else {
effect->alpha -= 5;
if (effect->alpha <= 0) {
effect->alpha = 0;
effect->type = MO_FX_NONE;
}
}
} else if (effect->type == MO_FX_BUBBLE) {
if (effect->targetPos == NULL) {
if ((effect->accel.y > 0.0f) && (effect->pos.y >= MO_WATER_LEVEL(globalCtx))) {
effect->type = MO_FX_NONE;
} else {
if (effect->vel.y > 2.0f) {
effect->vel.y = 2.0f;
}
effect->alpha -= 20;
if (effect->alpha <= 0) {
effect->alpha = 0;
effect->type = MO_FX_NONE;
}
}
} else {
if ((effect->timer % 4) == 0) {
targetPos = effect->targetPos;
dx = targetPos->x - effect->pos.x;
dz = targetPos->z - effect->pos.z;
bubbleSpeed.z = effect->fwork[MO_FX_SUCTION];
Matrix_RotateY(Math_FAtan2F(dx, dz), MTXMODE_NEW);
Matrix_MultVec3f(&bubbleSpeed, &bubbleVel);
effect->vel.x = bubbleVel.x;
effect->vel.z = bubbleVel.z;
}
Math_ApproachF(&effect->fwork[MO_FX_SUCTION], 5.0f, 1.0f, 0.5f);
if (effect->timer > 20) {
effect->alpha -= 30;
effect->accel.y = 1.5f;
if ((effect->alpha <= 0) || (effect->pos.y >= MO_WATER_LEVEL(globalCtx))) {
effect->alpha = 0;
effect->type = MO_FX_NONE;
}
} else {
effect->alpha += 30;
if (effect->alpha >= 255) {
effect->alpha = 255;
}
}
}
} else if ((effect->type == MO_FX_DROPLET) || (effect->type == MO_FX_SPLASH) ||
(effect->type == MO_FX_SPLASH_TRAIL) || (effect->type == MO_FX_WET_SPOT)) {
f32 shimmer = (effect->timer & 6) ? 80.0f : 200.0f;
Math_ApproachF(&effect->fwork[MO_FX_SHIMMER], shimmer, 1.0f, 80.0f);
if (effect->type == MO_FX_WET_SPOT) {
Math_ApproachF(&effect->scale, effect->fwork[MO_FX_MAX_SCALE], 0.1f, 0.6f);
effect->alpha -= 15;
if (effect->alpha <= 0) {
effect->alpha = 0;
effect->type = MO_FX_NONE;
}
} else {
effect->alpha = effect->fwork[MO_FX_SHIMMER];
if (effect->type == MO_FX_SPLASH_TRAIL) {
Math_ApproachF(&effect->scale, 0.0f, 1.0f, 0.02f);
if (effect->scale <= 0.0f) {
effect->type = MO_FX_NONE;
}
} else {
if (effect->type == MO_FX_SPLASH) {
Vec3f velocity = { 0.0f, 0.0f, 0.0f };
BossMo_SpawnDroplet(MO_FX_SPLASH_TRAIL, (BossMoEffect*)globalCtx->specialEffects,
&effect->pos, &velocity, effect->scale);
}
if (effect->vel.y < -20.0f) {
effect->vel.y = -20.0f;
effect->accel.y = 0.0f;
}
if (effect->stopTimer == 0) {
if (effect->vel.y < -5.0f) {
Math_ApproachF(&effect->fwork[MO_FX_STRETCH], 5.0f, 0.1f, 0.15f);
}
} else if (effect->stopTimer == 1) {
effect->vel.x = Rand_CenteredFloat(3.0f);
effect->vel.z = Rand_CenteredFloat(3.0f);
effect->accel.y = -1.0f;
}
if ((effect->pos.y <= -280.0f) || ((1.0f >= effect->pos.y) && (effect->pos.y >= -20.0f) &&
BossMo_NearLand(&effect->pos, 0.0f))) {
effect->accel.y = 0.0f;
effect->vel.z = 0.0f;
effect->vel.y = 0.0f;
effect->vel.x = 0.0f;
if (effect->pos.y <= -280.0f) {
effect->pos.y = -280.0f;
} else {
effect->pos.y = 0.0f;
}
effect->type = MO_FX_WET_SPOT;
effect->alpha = 150;
effect->fwork[MO_FX_STRETCH] = (effect->scale * 15.0f) * 0.15f;
} else if (effect->pos.y <= MO_WATER_LEVEL(globalCtx)) {
Vec3f pos = effect->pos;
pos.y = MO_WATER_LEVEL(globalCtx);
if (effect->type == MO_FX_SPLASH) {
BossMo_SpawnRipple(globalCtx->specialEffects, &pos, 60.0f, 160.0f, 80, 290,
MO_FX_SMALL_RIPPLE);
} else {
BossMo_SpawnRipple(globalCtx->specialEffects, &pos, 40.0f, 110.0f, 80, 290,
MO_FX_SMALL_RIPPLE);
}
effect->type = MO_FX_NONE;
}
}
}
}
}
}
}
void BossMo_DrawEffects(BossMoEffect* effect, GlobalContext* globalCtx) {
u8 flag = 0;
s16 i;
s32 pad;
GraphicsContext* gfxCtx = globalCtx->state.gfxCtx;
BossMoEffect* effectHead = effect;
OPEN_DISPS(gfxCtx);
Matrix_Push();
for (i = 0; i < ARRAY_COUNT(sEffects); i++, effect++) {
if (effect->type == MO_FX_BIG_RIPPLE) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (flag == 0) {
func_80094BC4(gfxCtx);
gDPSetEnvColor(POLY_XLU_DISP++, 155, 155, 255, 0);
flag++;
}
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, effect->alpha);
Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW);
Matrix_Scale(effect->scale, 1.0f, effect->scale, MTXMODE_APPLY);
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gEffWaterRippleDL);
FrameInterpolation_RecordCloseChild();
}
}
effect = effectHead;
flag = 0;
for (i = 0; i < ARRAY_COUNT(sEffects); i++, effect++) {
if (effect->type == MO_FX_SMALL_RIPPLE) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (flag == 0) {
func_80093D84(globalCtx->state.gfxCtx);
gDPSetEnvColor(POLY_XLU_DISP++, 155, 155, 255, 0);
flag++;
}
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, effect->alpha);
Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW);
Matrix_Scale(effect->scale, 1.0f, effect->scale, MTXMODE_APPLY);
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gEffShockwaveDL);
FrameInterpolation_RecordCloseChild();
}
}
effect = effectHead;
flag = 0;
for (i = 0; i < ARRAY_COUNT(sEffects); i++, effect++) {
if (((effect->type == MO_FX_DROPLET) || (effect->type == MO_FX_SPLASH)) ||
(effect->type == MO_FX_SPLASH_TRAIL)) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (flag == 0) {
POLY_XLU_DISP = Gfx_CallSetupDL(POLY_XLU_DISP, 0);
gSPSegment(POLY_XLU_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(gDust1Tex));
gSPDisplayList(POLY_XLU_DISP++, gMorphaDropletMaterialDL);
gDPSetEnvColor(POLY_XLU_DISP++, 250, 250, 255, 0);
flag++;
}
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, (s16)effect->fwork[MO_FX_SHIMMER], (s16)effect->fwork[MO_FX_SHIMMER],
255, effect->alpha);
Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW);
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
Matrix_Scale(effect->scale / effect->fwork[MO_FX_STRETCH], effect->fwork[MO_FX_STRETCH] * effect->scale,
1.0f, MTXMODE_APPLY);
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gMorphaDropletModelDL);
FrameInterpolation_RecordCloseChild();
}
}
effect = effectHead;
flag = 0;
for (i = 0; i < ARRAY_COUNT(sEffects); i++, effect++) {
if (effect->type == MO_FX_WET_SPOT) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (flag == 0) {
func_80094044(gfxCtx);
gSPSegment(POLY_XLU_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(gDust1Tex));
gDPSetEnvColor(POLY_XLU_DISP++, 250, 250, 255, 0);
gSPDisplayList(POLY_XLU_DISP++, gMorphaDropletMaterialDL);
flag++;
}
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, (s16)effect->fwork[MO_FX_SHIMMER], (s16)effect->fwork[MO_FX_SHIMMER],
0xFF, effect->alpha);
Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW);
Matrix_Scale(effect->scale, 1.0f, effect->scale, MTXMODE_APPLY);
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gMorphaWetSpotModelDL);
FrameInterpolation_RecordCloseChild();
}
}
effect = effectHead;
flag = 0;
for (i = 0; i < ARRAY_COUNT(sEffects); i++, effect++) {
if (effect->type == MO_FX_BUBBLE) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (flag == 0) {
func_80093D18(globalCtx->state.gfxCtx);
gDPSetEnvColor(POLY_OPA_DISP++, 150, 150, 150, 0);
flag++;
}
gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, effect->alpha);
Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW);
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
Matrix_Scale(effect->scale, effect->scale, 1.0f, MTXMODE_APPLY);
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, gMorphaBubbleDL);
FrameInterpolation_RecordCloseChild();
}
}
Matrix_Pop();
CLOSE_DISPS(gfxCtx);
}
void BossMo_Unknown(void) {
// Appears to be a test function for sound effects.
static Vec3f zeroVec = { 0.0f, 0.0f, 0.0f };
static u16 unkSfx[] = {
NA_SE_PL_WALK_GROUND,
NA_SE_PL_WALK_GROUND,
NA_SE_PL_WALK_GROUND,
NA_SE_PL_WALK_SAND,
NA_SE_PL_WALK_CONCRETE,
NA_SE_PL_WALK_DIRT,
NA_SE_PL_WALK_WATER0,
NA_SE_PL_WALK_WATER1,
NA_SE_PL_WALK_WATER2,
NA_SE_PL_WALK_MAGMA,
NA_SE_PL_WALK_GRASS,
NA_SE_PL_WALK_GLASS,
NA_SE_PL_WALK_LADDER,
NA_SE_PL_WALK_GLASS,
NA_SE_PL_WALK_WALL,
NA_SE_PL_WALK_HEAVYBOOTS,
NA_SE_PL_WALK_ICE,
NA_SE_PL_JUMP,
NA_SE_PL_JUMP,
NA_SE_PL_JUMP_SAND,
NA_SE_PL_JUMP_CONCRETE,
NA_SE_PL_JUMP_DIRT,
NA_SE_PL_JUMP_WATER0,
NA_SE_PL_JUMP_WATER1,
NA_SE_PL_JUMP_WATER2,
NA_SE_PL_JUMP_MAGMA,
NA_SE_PL_JUMP_GRASS,
NA_SE_PL_JUMP_GLASS,
NA_SE_PL_JUMP_LADDER,
NA_SE_PL_JUMP_GLASS,
NA_SE_PL_JUMP_HEAVYBOOTS,
NA_SE_PL_JUMP_ICE,
NA_SE_PL_LAND,
NA_SE_PL_LAND,
NA_SE_PL_LAND_SAND,
NA_SE_PL_LAND_CONCRETE,
NA_SE_PL_LAND_DIRT,
NA_SE_PL_LAND_WATER0,
NA_SE_PL_LAND_WATER1,
NA_SE_PL_LAND_WATER2,
NA_SE_PL_LAND_MAGMA,
NA_SE_PL_LAND_GRASS,
NA_SE_PL_LAND_GLASS,
NA_SE_PL_LAND_LADDER,
NA_SE_PL_LAND_GLASS,
NA_SE_PL_LAND_HEAVYBOOTS,
NA_SE_PL_LAND_ICE,
NA_SE_PL_SLIPDOWN,
NA_SE_PL_CLIMB_CLIFF,
NA_SE_PL_CLIMB_CLIFF,
NA_SE_PL_SIT_ON_HORSE,
NA_SE_PL_GET_OFF_HORSE,
NA_SE_PL_TAKE_OUT_SHIELD,
NA_SE_PL_TAKE_OUT_SHIELD,
NA_SE_PL_TAKE_OUT_SHIELD,
NA_SE_PL_TAKE_OUT_SHIELD,
NA_SE_PL_TAKE_OUT_SHIELD,
NA_SE_PL_TAKE_OUT_SHIELD,
NA_SE_PL_CHANGE_ARMS,
NA_SE_PL_CHANGE_ARMS,
NA_SE_PL_CHANGE_ARMS,
NA_SE_PL_CHANGE_ARMS,
NA_SE_PL_CHANGE_ARMS,
NA_SE_PL_CHANGE_ARMS,
NA_SE_PL_CATCH_BOOMERANG,
NA_SE_EV_DIVE_INTO_WATER,
NA_SE_EV_JUMP_OUT_WATER,
NA_SE_PL_SWIM,
NA_SE_PL_THROW,
NA_SE_PL_BODY_BOUND,
NA_SE_PL_ROLL,
NA_SE_PL_SKIP,
NA_SE_PL_BODY_HIT,
NA_SE_PL_DAMAGE,
NA_SE_PL_SLIP,
NA_SE_PL_SLIP,
NA_SE_PL_SLIP,
NA_SE_PL_SLIP_SAND,
NA_SE_PL_SLIP_CONCRETE,
NA_SE_PL_SLIP_DIRT,
NA_SE_PL_SLIP_WATER0,
NA_SE_PL_SLIP_WATER1,
NA_SE_PL_SLIP_WATER2,
NA_SE_PL_SLIP_MAGMA,
NA_SE_PL_SLIP_GRASS,
NA_SE_PL_SLIP_GLASS,
NA_SE_PL_SLIP_LADDER,
NA_SE_PL_SLIP_GLASS,
NA_SE_PL_SLIP_HEAVYBOOTS,
NA_SE_PL_SLIP_ICE,
NA_SE_PL_BOUND,
NA_SE_PL_BOUND,
NA_SE_PL_BOUND_SAND,
NA_SE_PL_BOUND_CONCRETE,
NA_SE_PL_BOUND_DIRT,
NA_SE_PL_BOUND_WATER0,
NA_SE_PL_BOUND_WATER1,
NA_SE_PL_BOUND_WATER2,
NA_SE_PL_BOUND_MAGMA,
NA_SE_PL_BOUND_GRASS,
NA_SE_PL_BOUND_WOOD,
NA_SE_PL_BOUND_LADDER,
NA_SE_PL_BOUND_WOOD,
NA_SE_PL_BOUND_HEAVYBOOTS,
NA_SE_PL_BOUND_ICE,
NA_SE_PL_FACE_UP,
NA_SE_PL_DIVE_BUBBLE,
NA_SE_PL_MOVE_BUBBLE,
NA_SE_PL_METALEFFECT_KID,
NA_SE_PL_METALEFFECT_ADULT,
NA_SE_PL_SPARK - SFX_FLAG,
NA_SE_IT_SWORD_IMPACT,
NA_SE_IT_SWORD_SWING,
NA_SE_IT_SWORD_PUTAWAY,
NA_SE_IT_SWORD_PICKOUT,
NA_SE_IT_ARROW_SHOT,
NA_SE_IT_BOOMERANG_THROW,
NA_SE_IT_SHIELD_BOUND,
NA_SE_IT_SHIELD_BOUND,
NA_SE_IT_BOW_DRAW,
NA_SE_IT_SHIELD_REFLECT_SW,
NA_SE_IT_ARROW_STICK_HRAD,
NA_SE_IT_HAMMER_HIT,
NA_SE_IT_HOOKSHOT_CHAIN - SFX_FLAG,
NA_SE_IT_SHIELD_REFLECT_MG,
NA_SE_IT_BOMB_IGNIT - SFX_FLAG,
NA_SE_IT_BOMB_EXPLOSION,
NA_SE_IT_BOMB_UNEXPLOSION,
NA_SE_IT_BOOMERANG_FLY - SFX_FLAG,
NA_SE_IT_SWORD_STRIKE,
NA_SE_IT_HAMMER_SWING,
NA_SE_IT_HOOKSHOT_REFLECT,
NA_SE_IT_ARROW_STICK_CRE,
NA_SE_IT_ARROW_STICK_CRE,
NA_SE_IT_ARROW_STICK_OBJ,
NA_SE_PL_WALK_GROUND - SFX_FLAG,
NA_SE_PL_WALK_GROUND - SFX_FLAG,
NA_SE_IT_SWORD_SWING_HARD,
NA_SE_IT_WALL_HIT_HARD,
NA_SE_IT_WALL_HIT_SOFT,
NA_SE_IT_WALL_HIT_SOFT,
NA_SE_IT_STONE_HIT,
NA_SE_IT_WOODSTICK_BROKEN,
NA_SE_IT_LASH,
NA_SE_IT_SHIELD_POSTURE,
NA_SE_IT_SLING_SHOT,
NA_SE_IT_SLING_DRAW,
NA_SE_IT_SWORD_CHARGE - SFX_FLAG,
NA_SE_IT_ROLLING_CUT,
NA_SE_IT_SWORD_STRIKE_HARD,
NA_SE_IT_SLING_REFLECT,
NA_SE_IT_SHIELD_REMOVE,
NA_SE_IT_HOOKSHOT_READY,
NA_SE_IT_HOOKSHOT_RECEIVE,
NA_SE_IT_HOOKSHOT_STICK_OBJ,
NA_SE_IT_SWORD_REFLECT_MG,
NA_SE_IT_DEKU,
NA_SE_IT_BOW_FLICK,
NA_SE_IT_BOW_FLICK,
NA_SE_IT_BOW_FLICK,
NA_SE_IT_BOMBCHU_MOVE,
NA_SE_IT_SHIELD_CHARGE_LV1,
NA_SE_IT_SHIELD_CHARGE_LV2,
NA_SE_IT_SHIELD_CHARGE_LV3,
NA_SE_IT_SLING_FLICK,
NA_SE_IT_SWORD_STICK_STN,
NA_SE_IT_REFLECTION_WOOD,
NA_SE_IT_SHIELD_REFLECT_MG2,
NA_SE_IT_MAGIC_ARROW_SHOT,
NA_SE_IT_EXPLOSION_FRAME,
NA_SE_IT_EXPLOSION_ICE,
NA_SE_IT_YOBI19 - SFX_FLAG,
NA_SE_FISHING_REEL_SLOW2 - SFX_FLAG,
NA_SE_OC_DOOR_OPEN,
NA_SE_EV_DOOR_CLOSE,
NA_SE_EV_EXPLOSION,
NA_SE_EV_HORSE_WALK,
NA_SE_EV_HORSE_RUN,
NA_SE_EV_HORSE_NEIGH,
NA_SE_EV_RIVER_STREAM - SFX_FLAG,
NA_SE_EV_WATER_WALL_BIG - SFX_FLAG,
NA_SE_EV_DIVE_WATER,
NA_SE_EV_OUT_OF_WATER,
NA_SE_EV_ROCK_SLIDE - SFX_FLAG,
NA_SE_EV_MAGMA_LEVEL - SFX_FLAG,
NA_SE_EV_MAGMA_LEVEL - SFX_FLAG,
NA_SE_EV_BRIDGE_OPEN - SFX_FLAG,
NA_SE_EV_BRIDGE_CLOSE - SFX_FLAG,
NA_SE_EV_BRIDGE_OPEN_STOP,
NA_SE_EV_BRIDGE_CLOSE_STOP,
NA_SE_EV_WALL_BROKEN,
NA_SE_EV_CHICKEN_CRY_N,
NA_SE_EV_CHICKEN_CRY_A,
NA_SE_EV_CHICKEN_CRY_M,
NA_SE_EV_SLIDE_DOOR_OPEN,
NA_SE_EV_FOOT_SWITCH,
NA_SE_EV_HORSE_GROAN,
NA_SE_EV_BOMB_DROP_WATER,
NA_SE_EV_BOMB_DROP_WATER,
NA_SE_EV_HORSE_JUMP,
NA_SE_EV_HORSE_LAND,
NA_SE_EV_HORSE_SLIP,
NA_SE_EV_FAIRY_DASH,
NA_SE_EV_SLIDE_DOOR_CLOSE,
NA_SE_EV_STONE_BOUND,
NA_SE_EV_STONE_STATUE_OPEN - SFX_FLAG,
NA_SE_EV_TBOX_UNLOCK,
NA_SE_EV_TBOX_OPEN,
NA_SE_SY_TIMER - SFX_FLAG,
NA_SE_EV_FLAME_IGNITION,
NA_SE_EV_SPEAR_HIT,
NA_SE_EV_ELEVATOR_MOVE - SFX_FLAG,
NA_SE_EV_WARP_HOLE - SFX_FLAG,
NA_SE_EV_LINK_WARP,
NA_SE_EV_PILLAR_SINK - SFX_FLAG,
NA_SE_EV_WATER_WALL - SFX_FLAG,
NA_SE_EV_RIVER_STREAM_S - SFX_FLAG,
NA_SE_EV_RIVER_STREAM_F - SFX_FLAG,
NA_SE_EV_HORSE_LAND2,
NA_SE_EV_HORSE_SANDDUST,
NA_SE_EV_BOMB_BOUND,
NA_SE_EV_BOMB_BOUND,
NA_SE_EV_WATERDROP - SFX_FLAG,
NA_SE_EV_TORCH - SFX_FLAG,
NA_SE_EV_MAGMA_LEVEL_M - SFX_FLAG,
NA_SE_EV_FIRE_PILLAR - SFX_FLAG,
NA_SE_EV_FIRE_PLATE - SFX_FLAG,
NA_SE_EV_BLOCK_BOUND,
NA_SE_EV_METALDOOR_SLIDE - SFX_FLAG,
NA_SE_EV_METALDOOR_STOP,
NA_SE_EV_BLOCK_SHAKE,
NA_SE_EV_BOX_BREAK,
NA_SE_EV_HAMMER_SWITCH,
NA_SE_EV_MAGMA_LEVEL_L - SFX_FLAG,
NA_SE_EV_SPEAR_FENCE,
NA_SE_EV_GANON_HORSE_NEIGH,
NA_SE_EV_GANON_HORSE_GROAN,
NA_SE_EV_FANTOM_WARP_S,
NA_SE_EV_FANTOM_WARP_L - SFX_FLAG,
NA_SE_EV_FOUNTAIN - SFX_FLAG,
NA_SE_EV_KID_HORSE_WALK,
NA_SE_EV_KID_HORSE_RUN,
NA_SE_EV_KID_HORSE_NEIGH,
NA_SE_EV_KID_HORSE_GROAN,
NA_SE_EV_WHITE_OUT,
NA_SE_EV_LIGHT_GATHER - SFX_FLAG,
NA_SE_EV_TREE_CUT,
NA_SE_EV_WATERDROP,
NA_SE_EV_TORCH,
NA_SE_PL_WALK_GROUND - SFX_FLAG,
NA_SE_PL_WALK_GROUND - SFX_FLAG,
NA_SE_EN_DODO_J_WALK,
NA_SE_EN_DODO_J_CRY,
NA_SE_EN_DODO_J_FIRE - SFX_FLAG,
NA_SE_EN_DODO_J_DAMAGE,
NA_SE_EN_DODO_J_DEAD,
NA_SE_EN_DODO_K_CRY,
NA_SE_EN_DODO_K_DAMAGE,
NA_SE_EN_DODO_K_DEAD,
NA_SE_EN_DODO_K_WALK,
NA_SE_EN_DODO_K_FIRE - SFX_FLAG,
NA_SE_EN_GOMA_WALK,
NA_SE_EN_GOMA_HIGH,
NA_SE_EN_GOMA_CLIM,
NA_SE_EN_GOMA_DOWN,
NA_SE_EN_GOMA_CRY1,
NA_SE_EN_GOMA_CRY2,
NA_SE_EN_GOMA_DAM1,
NA_SE_EN_GOMA_DAM2,
NA_SE_EN_GOMA_DEAD,
NA_SE_EN_GOMA_UNARI,
NA_SE_EN_GOMA_EGG1,
NA_SE_EN_GOMA_EGG2,
NA_SE_EN_GOMA_JR_WALK,
NA_SE_EN_GOMA_JR_CRY,
NA_SE_EN_GOMA_JR_DAM1,
NA_SE_EN_GOMA_JR_DAM2,
NA_SE_EN_GOMA_JR_DEAD,
NA_SE_EN_GOMA_DEMO_EYE,
NA_SE_EN_GOMA_LAST - SFX_FLAG,
NA_SE_EN_GOMA_UNARI2,
NA_SE_EN_DODO_M_CRY,
NA_SE_EN_DODO_M_DEAD,
NA_SE_EN_DODO_M_MOVE,
NA_SE_EN_DODO_M_DOWN,
NA_SE_EN_DODO_M_UP,
NA_SE_EN_DODO_M_GND,
NA_SE_EN_RIZA_CRY,
NA_SE_EN_RIZA_ATTACK,
NA_SE_EN_RIZA_DAMAGE,
NA_SE_EN_RIZA_WARAU,
NA_SE_EN_RIZA_DEAD,
NA_SE_EN_RIZA_WALK,
NA_SE_EN_RIZA_JUMP,
NA_SE_EN_RIZA_ONGND,
NA_SE_EN_RIZA_DOWN,
NA_SE_EN_STAL_WARAU,
NA_SE_EN_STAL_SAKEBI,
NA_SE_EN_STAL_DAMAGE,
NA_SE_EN_STAL_DEAD,
NA_SE_EN_STAL_JUMP,
NA_SE_EN_STAL_WALK,
NA_SE_EN_RIZA_DOWN,
NA_SE_EN_FFLY_ATTACK,
NA_SE_EN_FFLY_FLY,
NA_SE_EN_FFLY_DEAD,
NA_SE_EN_AMOS_WALK,
NA_SE_EN_AMOS_WAVE,
NA_SE_EN_AMOS_DEAD,
NA_SE_EN_AMOS_DAMAGE,
NA_SE_EN_AMOS_VOICE,
NA_SE_EN_DODO_K_COLI,
NA_SE_EN_DODO_K_COLI2,
NA_SE_EN_DODO_K_ROLL - SFX_FLAG,
NA_SE_EN_DODO_K_BREATH - SFX_FLAG,
NA_SE_EN_DODO_K_DRINK,
NA_SE_EN_DODO_K_DOWN - SFX_FLAG,
NA_SE_EN_DODO_K_OTAKEBI,
NA_SE_EN_DODO_K_END,
NA_SE_EN_DODO_K_LAST - SFX_FLAG,
NA_SE_EN_DODO_K_LAVA,
NA_SE_EN_DODO_J_BREATH - SFX_FLAG,
NA_SE_EN_DODO_J_TAIL,
NA_SE_EN_RIZA_DOWN,
NA_SE_EN_DEKU_MOUTH,
NA_SE_EN_DEKU_ATTACK,
NA_SE_EN_DEKU_DAMAGE,
NA_SE_EN_DEKU_DEAD,
NA_SE_EN_DEKU_JR_MOUTH,
NA_SE_EN_DEKU_JR_ATTACK,
NA_SE_EN_DEKU_JR_DEAD,
NA_SE_EN_DODO_M_GND,
NA_SE_EN_TAIL_FLY - SFX_FLAG,
NA_SE_EN_TAIL_CRY,
NA_SE_EN_STALTU_DOWN,
NA_SE_EN_STALTU_UP,
NA_SE_EN_STALTU_LAUGH,
NA_SE_EN_STALTU_DAMAGE,
NA_SE_EN_STAL_JUMP,
NA_SE_EN_DODO_M_GND,
NA_SE_EN_TEKU_DEAD,
NA_SE_EN_TEKU_WALK,
NA_SE_EN_PO_KANTERA,
NA_SE_EN_PO_FLY - SFX_FLAG,
NA_SE_EN_PO_AWAY - SFX_FLAG,
NA_SE_EN_PO_APPEAR,
NA_SE_EN_PO_DISAPPEAR,
NA_SE_EN_PO_DAMAGE,
NA_SE_EN_PO_DEAD,
NA_SE_EN_PO_DEAD2,
NA_SE_EN_EXTINCT,
NA_SE_EN_NUTS_UP,
NA_SE_EN_NUTS_DOWN,
NA_SE_EN_NUTS_THROW,
NA_SE_EN_NUTS_WALK,
NA_SE_EN_NUTS_DAMAGE,
NA_SE_EN_NUTS_DEAD,
NA_SE_EN_STALTU_ROLL,
NA_SE_EN_STALWALL_DEAD,
NA_SE_EN_TEKU_DAMAGE,
NA_SE_EN_FALL_AIM,
NA_SE_EN_FALL_UP,
NA_SE_EN_FALL_CATCH,
NA_SE_EN_FALL_LAND,
NA_SE_EN_FALL_WALK,
NA_SE_EN_FALL_DAMAGE,
NA_SE_EN_BIRI_FLY,
NA_SE_EN_BIRI_JUMP,
NA_SE_EN_BIRI_SPARK - SFX_FLAG,
NA_SE_EN_FANTOM_TRANSFORM,
NA_SE_EN_FANTOM_TRANSFORM,
NA_SE_EN_FANTOM_THUNDER,
NA_SE_EN_FANTOM_SPARK,
NA_SE_EN_FANTOM_FLOAT - SFX_FLAG,
NA_SE_EN_FANTOM_MASIC1,
NA_SE_EN_FANTOM_MASIC2,
NA_SE_EN_FANTOM_FIRE - SFX_FLAG,
NA_SE_EN_FANTOM_HIT_THUNDER,
NA_SE_EN_FANTOM_ATTACK,
NA_SE_EN_FANTOM_STICK,
NA_SE_EN_FANTOM_EYE,
NA_SE_EN_FANTOM_LAST,
NA_SE_EN_FANTOM_THUNDER_GND,
NA_SE_EN_FANTOM_DAMAGE,
NA_SE_EN_FANTOM_DEAD,
NA_SE_EN_FANTOM_LAUGH,
NA_SE_EN_FANTOM_DAMAGE2,
NA_SE_EN_FANTOM_VOICE,
NA_SE_EN_MORIBLIN_WALK,
NA_SE_EN_MORIBLIN_SLIDE,
NA_SE_EN_MORIBLIN_ATTACK,
NA_SE_EN_MORIBLIN_VOICE,
NA_SE_EN_MORIBLIN_SPEAR_AT,
NA_SE_EN_MORIBLIN_SPEAR_NORM,
NA_SE_EN_MORIBLIN_DEAD,
NA_SE_EN_NUTS_THROW,
NA_SE_EN_OCTAROCK_FLOAT,
NA_SE_EN_OCTAROCK_JUMP,
NA_SE_EN_OCTAROCK_LAND,
NA_SE_EN_OCTAROCK_SINK,
NA_SE_EN_OCTAROCK_BUBLE,
NA_SE_PL_WALK_GROUND - SFX_FLAG,
NA_SE_PL_WALK_GROUND - SFX_FLAG,
NA_SE_PL_WALK_GROUND - SFX_FLAG,
NA_SE_PL_WALK_GROUND - SFX_FLAG,
NA_SE_PL_WALK_GROUND - SFX_FLAG,
NA_SE_PL_WALK_GROUND - SFX_FLAG,
NA_SE_PL_WALK_GROUND - SFX_FLAG,
NA_SE_SY_WIN_OPEN,
NA_SE_SY_WIN_CLOSE,
NA_SE_SY_CORRECT_CHIME,
NA_SE_SY_GET_RUPY,
NA_SE_SY_MESSAGE_WOMAN,
NA_SE_SY_MESSAGE_MAN,
NA_SE_SY_ERROR,
NA_SE_SY_TRE_BOX_APPEAR,
NA_SE_SY_TRE_BOX_APPEAR,
NA_SE_SY_DECIDE,
NA_SE_SY_CURSOR,
NA_SE_SY_CANCEL,
NA_SE_SY_HP_RECOVER,
NA_SE_SY_ATTENTION_ON,
NA_SE_SY_ATTENTION_ON,
NA_SE_PL_WALK_GROUND - SFX_FLAG,
NA_SE_SY_LOCK_ON,
NA_SE_SY_LOCK_ON,
NA_SE_SY_LOCK_OFF,
NA_SE_SY_LOCK_ON_HUMAN,
NA_SE_SY_CAMERA_ZOOM_UP,
NA_SE_SY_CAMERA_ZOOM_DOWN,
NA_SE_SY_ATTENTION_ON_OLD,
NA_SE_SY_ATTENTION_URGENCY,
NA_SE_SY_MESSAGE_PASS,
NA_SE_PL_WALK_GROUND - SFX_FLAG,
NA_SE_PL_WALK_GROUND - SFX_FLAG,
NA_SE_PL_WALK_GROUND - SFX_FLAG,
NA_SE_SY_PIECE_OF_HEART,
NA_SE_SY_GET_ITEM,
NA_SE_SY_WIN_SCROLL_LEFT,
NA_SE_SY_WIN_SCROLL_RIGHT,
NA_SE_SY_OCARINA_ERROR,
NA_SE_SY_CAMERA_ZOOM_UP_2,
NA_SE_SY_CAMERA_ZOOM_DOWN_2,
NA_SE_SY_GLASSMODE_ON,
NA_SE_SY_GLASSMODE_OFF,
NA_SE_SY_ATTENTION_ON,
NA_SE_SY_ATTENTION_URGENCY,
NA_SE_OC_OCARINA,
NA_SE_PL_WALK_GROUND - SFX_FLAG,
NA_SE_PL_LAND - SFX_FLAG,
NA_SE_VO_LI_SWORD_N,
NA_SE_VO_LI_SWORD_N,
NA_SE_VO_LI_SWORD_N,
NA_SE_VO_LI_SWORD_N,
NA_SE_VO_LI_SWORD_N,
NA_SE_VO_LI_SWORD_N,
NA_SE_VO_LI_SWORD_N,
NA_SE_VO_LI_SWORD_L,
NA_SE_VO_LI_SWORD_L,
NA_SE_VO_LI_MAGIC_ATTACK,
NA_SE_VO_LI_LASH,
NA_SE_VO_LI_HANG,
NA_SE_VO_LI_AUTO_JUMP,
NA_SE_VO_LI_CLIMB_END,
NA_SE_VO_LI_CLIMB_END,
NA_SE_VO_LI_CLIMB_END,
NA_SE_VO_LI_CLIMB_END,
NA_SE_VO_LI_DAMAGE_S,
NA_SE_VO_LI_DAMAGE_S,
NA_SE_VO_LI_FALL_L,
NA_SE_VO_LI_FALL_S,
NA_SE_VO_LI_FALL_L,
NA_SE_VO_LI_FALL_L,
NA_SE_VO_LI_BREATH_REST,
NA_SE_VO_LI_BREATH_REST,
NA_SE_VO_LI_DOWN,
NA_SE_VO_LI_TAKEN_AWAY,
NA_SE_VO_LI_HELD,
NA_SE_VO_NAVY_HELLO,
NA_SE_VO_NAVY_HEAR,
NA_SE_VO_NAVY_ENEMY,
NA_SE_VO_NAVY_HELLO,
NA_SE_VO_NAVY_HEAR,
NA_SE_VO_NAVY_ENEMY,
NA_SE_VO_TA_SLEEP,
NA_SE_EN_VALVAISA_APPEAR - SFX_FLAG,
NA_SE_EN_VALVAISA_ROAR,
NA_SE_EN_VALVAISA_MAHI1,
NA_SE_EN_VALVAISA_MAHI2,
NA_SE_EN_VALVAISA_KNOCKOUT,
NA_SE_EN_VALVAISA_DAMAGE1,
NA_SE_EN_VALVAISA_DAMAGE2,
NA_SE_EN_VALVAISA_ROCK,
NA_SE_EN_VALVAISA_LAND,
NA_SE_EN_VALVAISA_DEAD,
NA_SE_EN_VALVAISA_BURN - SFX_FLAG,
NA_SE_EN_VALVAISA_FIRE - SFX_FLAG,
NA_SE_EN_VALVAISA_LAND2,
NA_SE_EN_MONBLIN_HAM_LAND,
NA_SE_EN_MONBLIN_HAM_DOWN,
NA_SE_EN_MONBLIN_HAM_UP,
NA_SE_EN_REDEAD_CRY,
NA_SE_EN_REDEAD_AIM,
NA_SE_EN_REDEAD_DAMAGE,
NA_SE_EN_RIZA_DOWN,
NA_SE_EN_REDEAD_DEAD,
NA_SE_EN_REDEAD_ATTACK,
NA_SE_EN_PO_LAUGH,
NA_SE_EN_PO_CRY,
NA_SE_EN_PO_ROLL,
NA_SE_EN_PO_LAUGH2,
NA_SE_EN_MOFER_APPEAR - SFX_FLAG,
NA_SE_EN_MOFER_ATTACK - SFX_FLAG,
NA_SE_EN_MOFER_WAVE,
NA_SE_EN_MOFER_CATCH,
NA_SE_EN_MOFER_CORE_DAMAGE,
NA_SE_EN_MOFER_CUT,
NA_SE_EN_MOFER_MOVE_DEMO - SFX_FLAG,
NA_SE_EN_MOFER_BUBLE_DEMO,
NA_SE_EN_MOFER_CORE_JUMP,
NA_SE_EN_GOLON_WAKE_UP,
NA_SE_EN_GOLON_SIT_DOWN,
NA_SE_EN_DODO_M_GND,
NA_SE_EN_DEADHAND_BITE,
NA_SE_EN_DEADHAND_WALK,
NA_SE_EN_DEADHAND_GRIP,
NA_SE_PL_WALK_GROUND - SFX_FLAG,
NA_SE_PL_WALK_GROUND - SFX_FLAG,
NA_SE_PL_WALK_GROUND - SFX_FLAG,
NA_SE_PL_WALK_GROUND - SFX_FLAG,
NA_SE_PL_WALK_GROUND - SFX_FLAG,
NA_SE_PL_WALK_GROUND - SFX_FLAG,
};
if (BREG(32) != 0) {
BREG(32)--;
Audio_QueueSeqCmd(0x1 << 28 | SEQ_PLAYER_BGM_MAIN << 24 | 0x100FF);
func_80078914(&zeroVec, unkSfx[BREG(33)]);
}
if (BREG(34) != 0) {
BREG(34) = 0;
Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | (u16)BREG(35));
}
}
void BossMo_Reset(void) {
sMorphaCore = NULL;
sMorphaTent1 = NULL;
sMorphaTent2 = NULL;
memset(sEffects, 0, sizeof(sEffects));
sBossGanonSeed1 = 0;
sBossGanonSeed2 = 0;
sBossGanonSeed3 = 0;
}