Shipwright/soh/src/overlays/actors/ovl_Bg_Haka_Gate/z_bg_haka_gate.c

381 lines
14 KiB
C

/*
* File: z_bg_haka_gate.c
* Overlay: ovl_Bg_Haka_Gate
* Description: Truth Spinner Puzzle (Shadow Temple)
*/
#include "z_bg_haka_gate.h"
#include "objects/gameplay_keep/gameplay_keep.h"
#include "objects/object_haka_objects/object_haka_objects.h"
#define FLAGS 0
// general purpose timer
#define vTimer actionVar1
// variables for turning the statue. Deg10 rotations are in tenths of a degree
#define vTurnDirection actionVar1
#define vTurnRateDeg10 actionVar2
#define vTurnAngleDeg10 actionVar3
#define vRotYDeg10 actionVar4
#define vInitTurnAngle actionVar5
// opening angle for floor
#define vOpenAngle actionVar2
// variables for the skull flames
#define vFlameScale actionVar3
#define vIsSkullOfTruth actionVar4
#define vScrollTimer actionVar5
#define SKULL_OF_TRUTH_FOUND 100
void BgHakaGate_Init(Actor* thisx, GlobalContext* globalCtx);
void BgHakaGate_Destroy(Actor* thisx, GlobalContext* globalCtx);
void BgHakaGate_Update(Actor* thisx, GlobalContext* globalCtx);
void BgHakaGate_Draw(Actor* this, GlobalContext* globalCtx);
void BgHakaGate_Reset(void);
void BgHakaGate_DoNothing(BgHakaGate* this, GlobalContext* globalCtx);
void BgHakaGate_StatueInactive(BgHakaGate* this, GlobalContext* globalCtx);
void BgHakaGate_StatueIdle(BgHakaGate* this, GlobalContext* globalCtx);
void BgHakaGate_StatueTurn(BgHakaGate* this, GlobalContext* globalCtx);
void BgHakaGate_FloorClosed(BgHakaGate* this, GlobalContext* globalCtx);
void BgHakaGate_FloorOpen(BgHakaGate* this, GlobalContext* globalCtx);
void BgHakaGate_GateWait(BgHakaGate* this, GlobalContext* globalCtx);
void BgHakaGate_GateOpen(BgHakaGate* this, GlobalContext* globalCtx);
void BgHakaGate_SkullOfTruth(BgHakaGate* this, GlobalContext* globalCtx);
void BgHakaGate_FalseSkull(BgHakaGate* this, GlobalContext* globalCtx);
static s16 sSkullOfTruthRotY = 0x100;
static u8 sBgPoEventPuzzleState = 1;
static f32 sStatueDistToPlayer = 0;
static s16 sStatueRotY;
const ActorInit Bg_Haka_Gate_InitVars = {
ACTOR_BG_HAKA_GATE,
ACTORCAT_PROP,
FLAGS,
OBJECT_HAKA_OBJECTS,
sizeof(BgHakaGate),
(ActorFunc)BgHakaGate_Init,
(ActorFunc)BgHakaGate_Destroy,
(ActorFunc)BgHakaGate_Update,
(ActorFunc)BgHakaGate_Draw,
(ActorResetFunc)BgHakaGate_Reset,
};
static InitChainEntry sInitChain[] = {
ICHAIN_VEC3F_DIV1000(scale, 100, ICHAIN_STOP),
};
void BgHakaGate_Init(Actor* thisx, GlobalContext* globalCtx) {
s32 pad;
BgHakaGate* this = (BgHakaGate*)thisx;
CollisionHeader* colHeader = NULL;
Actor_ProcessInitChain(thisx, sInitChain);
this->switchFlag = (thisx->params >> 8) & 0xFF;
thisx->params &= 0xFF;
DynaPolyActor_Init(&this->dyna, DPM_UNK);
if (thisx->params == BGHAKAGATE_SKULL) {
if (sSkullOfTruthRotY != 0x100) {
this->actionFunc = BgHakaGate_FalseSkull;
} else if (ABS(thisx->shape.rot.y) < 0x4000) {
if ((Rand_ZeroOne() * 3.0f) < sBgPoEventPuzzleState) {
this->vIsSkullOfTruth = true;
sSkullOfTruthRotY = thisx->shape.rot.y + 0x8000;
if (Flags_GetSwitch(globalCtx, this->switchFlag)) {
this->actionFunc = BgHakaGate_DoNothing;
} else {
this->actionFunc = BgHakaGate_SkullOfTruth;
}
} else {
sBgPoEventPuzzleState++;
this->actionFunc = BgHakaGate_FalseSkull;
}
} else {
this->actionFunc = BgHakaGate_FalseSkull;
}
this->vScrollTimer = Rand_ZeroOne() * 20.0f;
thisx->flags |= ACTOR_FLAG_4;
if (Flags_GetSwitch(globalCtx, this->switchFlag)) {
this->vFlameScale = 350;
}
} else {
if (thisx->params == BGHAKAGATE_STATUE) {
CollisionHeader_GetVirtual(&object_haka_objects_Col_0131C4, &colHeader);
this->vTimer = 0;
sStatueDistToPlayer = 0.0f;
if (Flags_GetSwitch(globalCtx, this->switchFlag)) {
this->actionFunc = BgHakaGate_StatueInactive;
} else {
this->actionFunc = BgHakaGate_StatueIdle;
}
} else if (thisx->params == BGHAKAGATE_FLOOR) {
CollisionHeader_GetVirtual(&object_haka_objects_Col_010E10, &colHeader);
if (Flags_GetSwitch(globalCtx, this->switchFlag)) {
this->actionFunc = BgHakaGate_DoNothing;
} else {
this->actionFunc = BgHakaGate_FloorClosed;
}
} else { // BGHAKAGATE_GATE
CollisionHeader_GetVirtual(&object_haka_objects_Col_00A938, &colHeader);
if (Flags_GetSwitch(globalCtx, this->switchFlag)) {
this->actionFunc = BgHakaGate_DoNothing;
thisx->world.pos.y += 80.0f;
} else {
thisx->flags |= ACTOR_FLAG_4;
Actor_SetFocus(thisx, 30.0f);
this->actionFunc = BgHakaGate_GateWait;
}
}
this->dyna.bgId = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, thisx, colHeader);
}
}
void BgHakaGate_Destroy(Actor* thisx, GlobalContext* globalCtx) {
s32 pad;
BgHakaGate* this = (BgHakaGate*)thisx;
DynaPoly_DeleteBgActor(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId);
if (this->dyna.actor.params == BGHAKAGATE_STATUE) {
sSkullOfTruthRotY = 0x100;
sBgPoEventPuzzleState = 1;
}
}
void BgHakaGate_DoNothing(BgHakaGate* this, GlobalContext* globalCtx) {
}
void BgHakaGate_StatueInactive(BgHakaGate* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
if (this->dyna.unk_150 != 0.0f) {
player->stateFlags2 &= ~0x10;
this->dyna.unk_150 = 0.0f;
}
}
void BgHakaGate_StatueIdle(BgHakaGate* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
s32 linkDirection;
f32 forceDirection;
if (this->dyna.unk_150 != 0.0f) {
if (this->vTimer == 0) {
this->vInitTurnAngle = this->dyna.actor.shape.rot.y - this->dyna.actor.yawTowardsPlayer;
sStatueDistToPlayer = this->dyna.actor.xzDistToPlayer;
forceDirection = (this->dyna.unk_150 >= 0.0f) ? 1.0f : -1.0f;
linkDirection = ((s16)(this->dyna.actor.yawTowardsPlayer - player->actor.shape.rot.y) > 0) ? -1 : 1;
this->vTurnDirection = linkDirection * forceDirection;
this->actionFunc = BgHakaGate_StatueTurn;
} else {
player->stateFlags2 &= ~0x10;
this->dyna.unk_150 = 0.0f;
if (this->vTimer != 0) {
this->vTimer--;
}
}
} else {
if (sBgPoEventPuzzleState == SKULL_OF_TRUTH_FOUND) {
this->actionFunc = BgHakaGate_StatueInactive;
} else {
this->vTimer = 0;
}
}
}
void BgHakaGate_StatueTurn(BgHakaGate* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
s32 turnFinished;
s16 turnAngle;
this->vTurnRateDeg10++;
this->vTurnRateDeg10 = CLAMP_MAX(this->vTurnRateDeg10, 10);
turnFinished = Math_StepToS(&this->vTurnAngleDeg10, 600, this->vTurnRateDeg10);
turnAngle = this->vTurnAngleDeg10 * this->vTurnDirection;
this->dyna.actor.shape.rot.y = (this->vRotYDeg10 + turnAngle) * 0.1f * (0x10000 / 360.0f);
if ((player->stateFlags2 & 0x10) && (sStatueDistToPlayer > 0.0f)) {
player->actor.world.pos.x =
this->dyna.actor.home.pos.x +
(Math_SinS(this->dyna.actor.shape.rot.y - this->vInitTurnAngle) * sStatueDistToPlayer);
player->actor.world.pos.z =
this->dyna.actor.home.pos.z +
(Math_CosS(this->dyna.actor.shape.rot.y - this->vInitTurnAngle) * sStatueDistToPlayer);
} else {
sStatueDistToPlayer = 0.0f;
}
sStatueRotY = this->dyna.actor.shape.rot.y;
if (turnFinished) {
player->stateFlags2 &= ~0x10;
this->vRotYDeg10 = (this->vRotYDeg10 + turnAngle) % 3600;
this->vTurnRateDeg10 = CVar_GetS32("gFasterBlockPush", 0) * 2;
this->vTurnAngleDeg10 = 0;
this->vTimer = 5 - ((CVar_GetS32("gFasterBlockPush", 0) * 3) / 5);
this->actionFunc = BgHakaGate_StatueIdle;
this->dyna.unk_150 = 0.0f;
}
func_8002F974(&this->dyna.actor, NA_SE_EV_ROCK_SLIDE - SFX_FLAG);
}
void BgHakaGate_FloorClosed(BgHakaGate* this, GlobalContext* globalCtx) {
if ((sStatueDistToPlayer > 1.0f) && (sStatueRotY != 0)) {
Player* player = GET_PLAYER(globalCtx);
f32 radialDist;
f32 angDist;
f32 cos = Math_CosS(sStatueRotY);
f32 sin = Math_SinS(sStatueRotY);
f32 dx = player->actor.world.pos.x - this->dyna.actor.world.pos.x;
f32 dz = player->actor.world.pos.z - this->dyna.actor.world.pos.z;
radialDist = dx * cos - dz * sin;
angDist = dx * sin + dz * cos;
if ((radialDist > 110.0f) || (fabsf(angDist) > 40.0f)) {
s16 yawDiff = sSkullOfTruthRotY - sStatueRotY;
sStatueDistToPlayer = 0.0f;
if (ABS(yawDiff) < 0x80) {
Flags_SetSwitch(globalCtx, this->switchFlag);
sBgPoEventPuzzleState = SKULL_OF_TRUTH_FOUND;
this->actionFunc = BgHakaGate_DoNothing;
} else {
func_80078884(NA_SE_SY_ERROR);
Audio_PlayActorSound2(&this->dyna.actor, NA_SE_EV_GROUND_GATE_OPEN);
func_8003EBF8(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId);
this->vTimer = 60;
this->actionFunc = BgHakaGate_FloorOpen;
}
}
}
}
void BgHakaGate_FloorOpen(BgHakaGate* this, GlobalContext* globalCtx) {
if (this->vTimer != 0) {
this->vTimer--;
}
if (this->vTimer == 0) {
if (Math_ScaledStepToS(&this->vOpenAngle, 0, 0x800)) {
func_8003EC50(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId);
this->actionFunc = BgHakaGate_FloorClosed;
}
} else {
Math_ScaledStepToS(&this->vOpenAngle, 0x3000, 0x800);
}
}
void BgHakaGate_GateWait(BgHakaGate* this, GlobalContext* globalCtx) {
if (Flags_GetSwitch(globalCtx, this->switchFlag)) {
OnePointCutscene_Attention(globalCtx, &this->dyna.actor);
this->actionFunc = BgHakaGate_GateOpen;
}
}
void BgHakaGate_GateOpen(BgHakaGate* this, GlobalContext* globalCtx) {
if (Math_StepToF(&this->dyna.actor.world.pos.y, this->dyna.actor.home.pos.y + 80.0f, 1.0f)) {
Audio_PlayActorSound2(&this->dyna.actor, NA_SE_EV_METALDOOR_STOP);
this->dyna.actor.flags &= ~ACTOR_FLAG_4;
this->actionFunc = BgHakaGate_DoNothing;
} else {
func_8002F974(&this->dyna.actor, NA_SE_EV_METALDOOR_SLIDE - SFX_FLAG);
}
}
void BgHakaGate_SkullOfTruth(BgHakaGate* this, GlobalContext* globalCtx) {
if (Flags_GetSwitch(globalCtx, this->switchFlag) && Math_StepToS(&this->vFlameScale, 350, 20)) {
this->actionFunc = BgHakaGate_DoNothing;
}
}
void BgHakaGate_FalseSkull(BgHakaGate* this, GlobalContext* globalCtx) {
if (Flags_GetSwitch(globalCtx, this->switchFlag)) {
Math_StepToS(&this->vFlameScale, 350, 20);
}
if (globalCtx->actorCtx.unk_03) {
this->dyna.actor.flags |= ACTOR_FLAG_7;
} else {
this->dyna.actor.flags &= ~ACTOR_FLAG_7;
}
}
void BgHakaGate_Update(Actor* thisx, GlobalContext* globalCtx) {
s32 pad;
BgHakaGate* this = (BgHakaGate*)thisx;
this->actionFunc(this, globalCtx);
if (this->dyna.actor.params == BGHAKAGATE_SKULL) {
this->vScrollTimer++;
}
}
void BgHakaGate_DrawFlame(BgHakaGate* this, GlobalContext* globalCtx) {
Actor* thisx = &this->dyna.actor;
f32 scale;
if (this->vFlameScale > 0) {
OPEN_DISPS(globalCtx->state.gfxCtx);
func_80093D84(globalCtx->state.gfxCtx);
gSPSegment(POLY_XLU_DISP++, 0x08,
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, 0, 0x20, 0x40, 1, 0,
(this->vScrollTimer * -20) & 0x1FF, 0x20, 0x80));
gDPSetPrimColor(POLY_XLU_DISP++, 0x80, 0x80, 255, 255, 0, 255);
gDPSetEnvColor(POLY_XLU_DISP++, 255, 0, 0, 0);
Matrix_Translate(thisx->world.pos.x, thisx->world.pos.y + 15.0f, thisx->world.pos.z, MTXMODE_NEW);
Matrix_RotateY(Camera_GetCamDirYaw(GET_ACTIVE_CAM(globalCtx)) * (M_PI / 0x8000), MTXMODE_APPLY);
scale = this->vFlameScale * 0.00001f;
Matrix_Scale(scale, scale, scale, MTXMODE_APPLY);
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gEffFire1DL);
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
}
void BgHakaGate_Draw(Actor* thisx, GlobalContext* globalCtx) {
static Gfx* displayLists[] = {
object_haka_objects_DL_012270,
object_haka_objects_DL_010A10,
object_haka_objects_DL_00A860,
object_haka_objects_DL_00F1B0,
};
BgHakaGate* this = (BgHakaGate*)thisx;
MtxF currentMtxF;
if (CHECK_FLAG_ALL(thisx->flags, ACTOR_FLAG_7)) {
Gfx_DrawDListXlu(globalCtx, object_haka_objects_DL_00F1B0);
} else {
func_80093D18(globalCtx->state.gfxCtx);
if (thisx->params == BGHAKAGATE_FLOOR) {
OPEN_DISPS(globalCtx->state.gfxCtx);
Matrix_Get(&currentMtxF);
Matrix_Translate(0.0f, 0.0f, -2000.0f, MTXMODE_APPLY);
Matrix_RotateX(this->vOpenAngle * (M_PI / 0x8000), MTXMODE_APPLY);
Matrix_Translate(0.0f, 0.0f, 2000.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++, object_haka_objects_DL_010A10);
Matrix_Put(&currentMtxF);
Matrix_Translate(0.0f, 0.0f, 2000.0f, MTXMODE_APPLY);
Matrix_RotateX(-this->vOpenAngle * (M_PI / 0x8000), MTXMODE_APPLY);
Matrix_Translate(0.0f, 0.0f, -2000.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++, object_haka_objects_DL_010C10);
CLOSE_DISPS(globalCtx->state.gfxCtx);
} else {
Gfx_DrawDListOpa(globalCtx, displayLists[thisx->params]);
}
}
if (thisx->params == BGHAKAGATE_SKULL) {
BgHakaGate_DrawFlame(this, globalCtx);
}
}
void BgHakaGate_Reset(void) {
sStatueRotY = 0;
}