Shipwright/soh/src/overlays/actors/ovl_En_Siofuki/z_en_siofuki.c

313 lines
11 KiB
C

/*
* File: z_en_siofuki.c
* Overlay: ovl_En_Siofuki
* Description: Water Spout
*/
#include "z_en_siofuki.h"
#include "objects/object_siofuki/object_siofuki.h"
#define FLAGS (ACTOR_FLAG_4 | ACTOR_FLAG_5)
void EnSiofuki_Init(Actor* thisx, GlobalContext* globalCtx);
void EnSiofuki_Destroy(Actor* thisx, GlobalContext* globalCtx);
void EnSiofuki_Update(Actor* thisx, GlobalContext* globalCtx);
void EnSiofuki_Draw(Actor* thisx, GlobalContext* globalCtx);
void func_80AFC34C(EnSiofuki* this, GlobalContext* globalCtx);
void func_80AFC544(EnSiofuki* this, GlobalContext* globalCtx);
void func_80AFC478(EnSiofuki* this, GlobalContext* globalCtx);
const ActorInit En_Siofuki_InitVars = {
ACTOR_EN_SIOFUKI,
ACTORCAT_BG,
FLAGS,
OBJECT_SIOFUKI,
sizeof(EnSiofuki),
(ActorFunc)EnSiofuki_Init,
(ActorFunc)EnSiofuki_Destroy,
(ActorFunc)EnSiofuki_Update,
(ActorFunc)EnSiofuki_Draw,
NULL,
};
static InitChainEntry sInitChain[] = {
ICHAIN_VEC3F_DIV1000(scale, 100, ICHAIN_STOP),
};
void EnSiofuki_Init(Actor* thisx, GlobalContext* globalCtx) {
EnSiofuki* this = (EnSiofuki*)thisx;
s32 type;
CollisionHeader* colHeader = NULL;
s32 pad;
if ((thisx->room == 10) && Flags_GetSwitch(globalCtx, 0x1E)) {
Actor_Kill(thisx);
return;
}
Actor_ProcessInitChain(thisx, sInitChain);
DynaPolyActor_Init(&this->dyna, DPM_PLAYER);
CollisionHeader_GetVirtual(&object_siofuki_Col_000D78, &colHeader);
this->dyna.bgId = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, thisx, colHeader);
this->sfxFlags |= 1;
type = ((u16)thisx->params >> 0xC) & 0xF;
if (!((type == 0) || (type == 1))) {
Actor_Kill(thisx);
return;
}
this->initPosY = thisx->world.pos.y;
this->unk_174 = 35.0f;
this->unk_170 = -6058.0f + this->unk_174;
if (thisx->shape.rot.x != 0) {
this->maxHeight = thisx->shape.rot.x * 40.0f;
this->currentHeight = this->maxHeight;
}
this->activeTime = 0;
if (thisx->shape.rot.y != 0) {
this->activeTime = thisx->shape.rot.y;
}
if (thisx->shape.rot.z != 0) {
thisx->scale.x = thisx->shape.rot.z * (1.0f / 1.73f) * 0.1f;
thisx->scale.z = thisx->shape.rot.z * 0.5f * 0.1f;
}
thisx->world.rot.x = 0;
thisx->world.rot.y = 0;
thisx->world.rot.z = 0;
thisx->shape.rot.x = 0;
thisx->shape.rot.y = 0;
thisx->shape.rot.z = 0;
type = ((u16)thisx->params >> 0xC) & 0xF;
if (type == EN_SIOFUKI_RAISING) {
this->currentHeight = 10.0f;
this->targetHeight = 10.0f;
this->actionFunc = func_80AFC34C;
} else if (type == EN_SIOFUKI_LOWERING) {
if (Flags_GetTreasure(globalCtx, (u16)thisx->params & 0x3F)) {
this->currentHeight = -45.0f;
this->targetHeight = -45.0f;
this->actionFunc = func_80AFC544;
} else {
this->targetHeight = this->currentHeight;
this->actionFunc = func_80AFC478;
}
}
}
void EnSiofuki_Destroy(Actor* thisx, GlobalContext* globalCtx) {
EnSiofuki* this = (EnSiofuki*)thisx;
DynaPoly_DeleteBgActor(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId);
}
void func_80AFBDC8(EnSiofuki* this, GlobalContext* globalCtx) {
this->oscillation = sinf((globalCtx->gameplayFrames & 0x1F) / 32.0f * M_PI * 2.0f) * 4.0f;
this->unk_170 = this->unk_174 * 10.0f + -6058.0f - this->oscillation * 10.0f;
this->unk_174 = 35.0f;
this->dyna.actor.world.pos.y = this->initPosY + this->currentHeight + this->oscillation;
}
void func_80AFBE8C(EnSiofuki* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
f32 dX;
f32 dY;
f32 dZ;
s16 angle;
s16 dAngle;
f32 dist2d;
f32 speedScale;
dX = player->actor.world.pos.x - this->dyna.actor.world.pos.x;
dY = player->actor.world.pos.y - this->dyna.actor.world.pos.y;
dZ = player->actor.world.pos.z - this->dyna.actor.world.pos.z;
if ((dX > (this->dyna.actor.scale.x * -346.0f)) && (dX < (this->dyna.actor.scale.x * 346.0f)) &&
(dZ > (this->dyna.actor.scale.z * -400.0f)) && (dZ < (this->dyna.actor.scale.z * 400.0f)) && (dY < 0.0f)) {
if (func_8004356C(&this->dyna)) {
if (this->splashTimer <= 0) {
EffectSsGSplash_Spawn(globalCtx, &player->actor.world.pos, NULL, NULL, 1, 1);
this->splashTimer = 10;
} else {
this->splashTimer--;
}
this->applySpeed = false;
this->appliedSpeed = 0.0f;
this->targetAppliedSpeed = 0.0f;
} else {
dist2d = sqrtf(SQ(dX) + SQ(dZ));
this->applySpeed = true;
this->splashTimer = 0;
angle = Math_FAtan2F(dX, dZ) * (0x8000 / M_PI);
dAngle = (player->actor.world.rot.y ^ 0x8000) - angle;
player->actor.gravity = 0.0f;
player->actor.velocity.y = 0.0f;
Math_SmoothStepToF(&player->actor.world.pos.y, this->dyna.actor.world.pos.y, 0.5f, 4.0f, 1.0f);
if ((dAngle < 0x4000) && (dAngle > -0x4000)) {
this->appliedYaw = player->actor.world.rot.y ^ 0x8000;
speedScale = dist2d / (this->dyna.actor.scale.x * 40.0f * 10.0f);
speedScale = CLAMP_MIN(speedScale, 0.0f);
speedScale = CLAMP_MAX(speedScale, 1.0f);
player->linearVelocity *= speedScale;
Math_ApproachF(&this->targetAppliedSpeed, 3.0f, 1.0f, 1.0f);
Math_ApproachF(&this->appliedSpeed, this->targetAppliedSpeed, 1.0f, 0.3f * speedScale);
} else {
this->appliedYaw = player->actor.world.rot.y;
player->linearVelocity /= 2.0f;
Math_ApproachF(&this->targetAppliedSpeed, 3.0f, 1.0f, 1.0f);
Math_ApproachF(&this->appliedSpeed, this->targetAppliedSpeed, 1.0f, 0.1f);
}
player->windDirection = this->appliedYaw;
player->windSpeed = this->appliedSpeed;
}
} else {
if (this->applySpeed) {
player->linearVelocity = this->appliedSpeed + player->linearVelocity;
player->currentYaw = this->appliedYaw;
}
this->targetAppliedSpeed = 0.0f;
this->appliedSpeed = 0.0f;
this->applySpeed = false;
}
}
void func_80AFC1D0(EnSiofuki* this, GlobalContext* globalCtx) {
Math_SmoothStepToF(&this->currentHeight, this->targetHeight, 0.8f, 3.0f, 0.01f);
}
void func_80AFC218(EnSiofuki* this, GlobalContext* globalCtx) {
func_80AFBDC8(this, globalCtx);
func_80AFBE8C(this, globalCtx);
func_80AFC1D0(this, globalCtx);
this->timer--;
if (this->timer < 0) {
Flags_UnsetSwitch(globalCtx, ((u16)this->dyna.actor.params >> 6) & 0x3F);
switch (((u16)this->dyna.actor.params >> 0xC) & 0xF) {
case EN_SIOFUKI_RAISING:
this->targetHeight = 10.0f;
this->actionFunc = func_80AFC34C;
break;
case EN_SIOFUKI_LOWERING:
this->targetHeight = this->maxHeight;
this->actionFunc = func_80AFC478;
break;
}
} else {
func_8002F994(&this->dyna.actor, this->timer);
}
if (((((u16)this->dyna.actor.params >> 0xC) & 0xF) == EN_SIOFUKI_LOWERING) &&
Flags_GetTreasure(globalCtx, (u16)this->dyna.actor.params & 0x3F)) {
this->currentHeight = -45.0f;
this->targetHeight = -45.0f;
Flags_UnsetSwitch(globalCtx, ((u16)this->dyna.actor.params >> 6) & 0x3F);
this->actionFunc = func_80AFC544;
}
}
void func_80AFC34C(EnSiofuki* this, GlobalContext* globalCtx) {
func_80AFBDC8(this, globalCtx);
func_80AFBE8C(this, globalCtx);
func_80AFC1D0(this, globalCtx);
if (Flags_GetSwitch(globalCtx, ((u16)this->dyna.actor.params >> 6) & 0x3F)) {
this->targetHeight = 400.0f;
this->timer = 300;
this->actionFunc = func_80AFC218;
}
}
void func_80AFC3C8(EnSiofuki* this, GlobalContext* globalCtx) {
func_80AFBDC8(this, globalCtx);
func_80AFBE8C(this, globalCtx);
func_80AFC1D0(this, globalCtx);
this->timer--;
if (this->timer < 0) {
this->timer = this->activeTime * 20;
this->targetHeight = -45.0f;
this->actionFunc = func_80AFC218;
}
if (Flags_GetTreasure(globalCtx, (u16)this->dyna.actor.params & 0x3F)) {
this->currentHeight = -45.0f;
this->targetHeight = -45.0f;
this->actionFunc = func_80AFC544;
}
}
void func_80AFC478(EnSiofuki* this, GlobalContext* globalCtx) {
func_80AFBDC8(this, globalCtx);
func_80AFBE8C(this, globalCtx);
func_80AFC1D0(this, globalCtx);
if (((u16)this->dyna.actor.params >> 0xC & 0xF) == EN_SIOFUKI_LOWERING) {
if (Flags_GetSwitch(globalCtx, ((u16)this->dyna.actor.params >> 6) & 0x3F)) {
this->timer = 20;
this->actionFunc = func_80AFC3C8;
OnePointCutscene_Init(globalCtx, 5010, 40, &this->dyna.actor, MAIN_CAM);
}
if (Flags_GetTreasure(globalCtx, (u16)this->dyna.actor.params & 0x3F)) {
this->currentHeight = -45.0f;
this->targetHeight = -45.0f;
this->actionFunc = func_80AFC544;
}
}
}
void func_80AFC544(EnSiofuki* this, GlobalContext* globalCtx) {
func_80AFBDC8(this, globalCtx);
func_80AFC1D0(this, globalCtx);
}
void EnSiofuki_Update(Actor* thisx, GlobalContext* globalCtx) {
EnSiofuki* this = (EnSiofuki*)thisx;
this->actionFunc(this, globalCtx);
}
void EnSiofuki_Draw(Actor* thisx, GlobalContext* globalCtx) {
EnSiofuki* this = (EnSiofuki*)thisx;
u32 x;
u32 y;
u32 gameplayFrames = globalCtx->gameplayFrames;
OPEN_DISPS(globalCtx->state.gfxCtx);
func_80093D84(globalCtx->state.gfxCtx);
Matrix_Translate(0.0f, this->unk_170, 0.0f, MTXMODE_APPLY);
Matrix_Scale(1.0f, 1.0f, 1.0f, MTXMODE_APPLY);
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
x = gameplayFrames * 15;
y = gameplayFrames * -15;
gSPSegment(POLY_XLU_DISP++, 0x08, Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, x, y, 64, 64, 1, x, y, 64, 64));
gSPDisplayList(POLY_XLU_DISP++, object_siofuki_DL_000B70);
CLOSE_DISPS(globalCtx->state.gfxCtx);
if (this->sfxFlags & 1) {
f32 heightRatio;
switch (((u16)thisx->params >> 0xC) & 0xF) {
case EN_SIOFUKI_RAISING:
heightRatio = (this->currentHeight - 10.0f) / (400.0f - 10.0f);
func_800F436C(&thisx->projectedPos, NA_SE_EV_FOUNTAIN - SFX_FLAG, 1.0f + heightRatio);
break;
case EN_SIOFUKI_LOWERING:
if (this->currentHeight > -35.0f) {
heightRatio = (this->currentHeight - -35.0f) / (this->maxHeight - -35.0f);
func_800F436C(&thisx->projectedPos, NA_SE_EV_FOUNTAIN - SFX_FLAG, 1.0f + heightRatio);
}
break;
}
}
}