Shipwright/soh/src/overlays/actors/ovl_En_Honotrap/z_en_honotrap.c

543 lines
19 KiB
C

/**
* File: z_en_honotrap.c
* Overlay: ovl_En_Honotrap
* Description: Fake eye switches and Dampe flames
*/
#include "z_en_honotrap.h"
#include "objects/gameplay_keep/gameplay_keep.h"
#include "objects/gameplay_dangeon_keep/gameplay_dangeon_keep.h"
#define FLAGS ACTOR_FLAG_4
#define HONOTRAP_AT_ACTIVE (1 << 0)
#define HONOTRAP_AC_ACTIVE (1 << 1)
#define HONOTRAP_OC_ACTIVE (1 << 2)
typedef enum {
/* 0 */ HONOTRAP_EYE_OPEN,
/* 1 */ HONOTRAP_EYE_HALF,
/* 2 */ HONOTRAP_EYE_CLOSE,
/* 3 */ HONOTRAP_EYE_SHUT
} EnHonotrapEyeState;
void EnHonotrap_Init(Actor* thisx, GlobalContext* globalCtx);
void EnHonotrap_Destroy(Actor* thisx, GlobalContext* globalCtx);
void EnHonotrap_Update(Actor* thisx, GlobalContext* globalCtx);
void EnHonotrap_Draw(Actor* thisx, GlobalContext* globalCtx);
void EnHonotrap_SetupEyeIdle(EnHonotrap* this);
void EnHonotrap_EyeIdle(EnHonotrap* this, GlobalContext* globalCtx);
void EnHonotrap_SetupEyeOpen(EnHonotrap* this);
void EnHonotrap_EyeOpen(EnHonotrap* this, GlobalContext* globalCtx);
void EnHonotrap_SetupEyeAttack(EnHonotrap* this);
void EnHonotrap_EyeAttack(EnHonotrap* this, GlobalContext* globalCtx);
void EnHonotrap_SetupEyeClose(EnHonotrap* this);
void EnHonotrap_EyeClose(EnHonotrap* this, GlobalContext* globalCtx);
void EnHonotrap_SetupFlame(EnHonotrap* this);
void EnHonotrap_Flame(EnHonotrap* this, GlobalContext* globalCtx);
void EnHonotrap_SetupFlameDrop(EnHonotrap* this);
void EnHonotrap_FlameDrop(EnHonotrap* this, GlobalContext* globalCtx);
void EnHonotrap_SetupFlameMove(EnHonotrap* this);
void EnHonotrap_FlameMove(EnHonotrap* this, GlobalContext* globalCtx);
void EnHonotrap_SetupFlameChase(EnHonotrap* this);
void EnHonotrap_FlameChase(EnHonotrap* this, GlobalContext* globalCtx);
void EnHonotrap_SetupFlameVanish(EnHonotrap* this);
void EnHonotrap_FlameVanish(EnHonotrap* this, GlobalContext* globalCtx);
const ActorInit En_Honotrap_InitVars = {
ACTOR_EN_HONOTRAP,
ACTORCAT_PROP,
FLAGS,
OBJECT_GAMEPLAY_DANGEON_KEEP,
sizeof(EnHonotrap),
(ActorFunc)EnHonotrap_Init,
(ActorFunc)EnHonotrap_Destroy,
(ActorFunc)EnHonotrap_Update,
(ActorFunc)EnHonotrap_Draw,
NULL,
};
static ColliderTrisElementInit sTrisElementsInit[2] = {
{
{
ELEMTYPE_UNK4,
{ 0x00000000, 0x00, 0x00 },
{ 0x0001F824, 0x00, 0x00 },
TOUCH_NONE,
BUMP_ON,
OCELEM_NONE,
},
{ { { 0.0f, 23.0f, 8.5f }, { -23.0f, 0.0f, 8.5f }, { 0.0f, -23.0f, 8.5f } } },
},
{
{
ELEMTYPE_UNK0,
{ 0x00000000, 0x00, 0x00 },
{ 0x0001F824, 0x00, 0x00 },
TOUCH_NONE,
BUMP_ON,
OCELEM_NONE,
},
{ { { 0.0f, 23.0f, 8.5f }, { 0.0f, -23.0f, 8.5f }, { 23.0f, 0.0f, 8.5f } } },
},
};
static ColliderTrisInit sTrisInit = {
{
COLTYPE_NONE,
AT_NONE,
AC_ON | AC_TYPE_PLAYER,
OC1_NONE,
OC2_NONE,
COLSHAPE_TRIS,
},
2,
sTrisElementsInit,
};
static ColliderCylinderInit sCylinderInit = {
{
COLTYPE_NONE,
AT_ON | AT_TYPE_ENEMY,
AC_ON | AC_TYPE_PLAYER,
OC1_ON | OC1_TYPE_ALL,
OC2_TYPE_2,
COLSHAPE_CYLINDER,
},
{
ELEMTYPE_UNK0,
{ 0xFFCFFFFF, 0x01, 0x04 },
{ 0x00100000, 0x00, 0x00 },
TOUCH_ON | TOUCH_SFX_NONE,
BUMP_ON,
OCELEM_ON,
},
{ 10, 25, 0, { 0, 0, 0 } },
};
static CollisionCheckInfoInit sColChkInfoInit = { 0, 9, 23, 1 };
static InitChainEntry sInitChain[] = {
ICHAIN_F32(uncullZoneForward, 1000, ICHAIN_CONTINUE),
ICHAIN_F32(uncullZoneScale, 500, ICHAIN_CONTINUE),
ICHAIN_F32(uncullZoneDownward, 1000, ICHAIN_STOP),
};
void EnHonotrap_FlameCollisionCheck(EnHonotrap* this, GlobalContext* globalCtx) {
s32 pad[3];
Collider_UpdateCylinder(&this->actor, &this->collider.cyl);
CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->collider.cyl.base);
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->collider.cyl.base);
CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider.cyl.base);
this->colChkFlags |= HONOTRAP_AT_ACTIVE;
this->colChkFlags |= HONOTRAP_AC_ACTIVE;
this->colChkFlags |= HONOTRAP_OC_ACTIVE;
}
void EnHonotrap_GetNormal(Vec3f* normal, Vec3f* vec) {
f32 mag = Math3D_Vec3fMagnitude(vec);
if (mag < 0.001f) {
osSyncPrintf("Warning : vector size zero (%s %d)\n", __FILE__, __LINE__, normal);
normal->x = normal->y = 0.0f;
normal->z = 1.0f;
} else {
normal->x = vec->x * (1.0f / mag);
normal->y = vec->y * (1.0f / mag);
normal->z = vec->z * (1.0f / mag);
}
}
void EnHonotrap_InitEye(Actor* thisx, GlobalContext* globalCtx) {
s32 pad;
EnHonotrap* this = (EnHonotrap*)thisx;
s32 i;
s32 j;
Vec3f* vtx;
Vec3f triangle[3];
f32 cos;
f32 sin;
Actor_SetScale(thisx, 0.1f);
sin = Math_SinS(thisx->home.rot.y);
cos = Math_CosS(thisx->home.rot.y);
Collider_InitTris(globalCtx, &this->collider.tris);
Collider_SetTris(globalCtx, &this->collider.tris, thisx, &sTrisInit, this->collider.elements);
for (i = 0; i < 2; i++) {
for (j = 0, vtx = triangle; j < 3; j++, vtx++) {
Vec3f* baseVtx = &sTrisInit.elements[i].dim.vtx[j];
vtx->x = baseVtx->z * sin + baseVtx->x * cos;
vtx->y = baseVtx->y;
vtx->z = baseVtx->z * cos - baseVtx->x * sin;
Math_Vec3f_Sum(vtx, &thisx->world.pos, vtx);
}
Collider_SetTrisVertices(&this->collider.tris, i, &triangle[0], &triangle[1], &triangle[2]);
}
EnHonotrap_SetupEyeIdle(this);
Actor_SetFocus(thisx, 0.0f);
}
void EnHonotrap_InitFlame(Actor* thisx, GlobalContext* globalCtx) {
s32 pad;
EnHonotrap* this = (EnHonotrap*)thisx;
Actor_SetScale(&this->actor, 0.0001f);
Collider_InitCylinder(globalCtx, &this->collider.cyl);
Collider_SetCylinder(globalCtx, &this->collider.cyl, &this->actor, &sCylinderInit);
Collider_UpdateCylinder(&this->actor, &this->collider.cyl);
this->actor.minVelocityY = -1.0f;
CollisionCheck_SetInfo(&this->actor.colChkInfo, NULL, &sColChkInfoInit);
ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 30.0f);
this->actor.shape.shadowAlpha = 128;
this->targetPos = GET_PLAYER(globalCtx)->actor.world.pos;
this->targetPos.y += 10.0f;
this->flameScroll = Rand_ZeroOne() * 511.0f;
EnHonotrap_SetupFlame(this);
Audio_PlayActorSound2(&this->actor, NA_SE_EV_FLAME_IGNITION);
if (this->actor.params == HONOTRAP_FLAME_DROP) {
this->actor.room = -1;
this->collider.cyl.dim.radius = 12;
this->collider.cyl.dim.height = 30;
this->actor.shape.yOffset = -1000.0f;
}
}
void EnHonotrap_Init(Actor* thisx, GlobalContext* globalCtx) {
Actor_ProcessInitChain(thisx, sInitChain);
if (thisx->params == HONOTRAP_EYE) {
EnHonotrap_InitEye(thisx, globalCtx);
} else {
EnHonotrap_InitFlame(thisx, globalCtx);
}
}
void EnHonotrap_Destroy(Actor* thisx, GlobalContext* globalCtx) {
s32 pad;
EnHonotrap* this = (EnHonotrap*)thisx;
if (this->actor.params == HONOTRAP_EYE) {
Collider_DestroyTris(globalCtx, &this->collider.tris);
} else {
Collider_DestroyCylinder(globalCtx, &this->collider.cyl);
}
}
void EnHonotrap_SetupEyeIdle(EnHonotrap* this) {
this->actionFunc = EnHonotrap_EyeIdle;
this->eyeState = HONOTRAP_EYE_SHUT;
}
void EnHonotrap_EyeIdle(EnHonotrap* this, GlobalContext* globalCtx) {
if (this->actor.child != NULL) {
this->timer = 200;
} else if ((this->timer <= 0) && (this->actor.xzDistToPlayer < 750.0f) && (0.0f > this->actor.yDistToPlayer) &&
(this->actor.yDistToPlayer > -700.0f) &&
(-0x4000 < (this->actor.yawTowardsPlayer - this->actor.shape.rot.y)) &&
((this->actor.yawTowardsPlayer - this->actor.shape.rot.y) < 0x4000)) {
EnHonotrap_SetupEyeOpen(this);
}
}
void EnHonotrap_SetupEyeOpen(EnHonotrap* this) {
this->actionFunc = EnHonotrap_EyeOpen;
Actor_SetColorFilter(&this->actor, 0x4000, 0xFF, 0, 0x28);
this->timer = 30;
Audio_PlayActorSound2(&this->actor, NA_SE_EV_RED_EYE);
}
void EnHonotrap_EyeOpen(EnHonotrap* this, GlobalContext* globalCtx) {
f32 cos;
f32 sin;
this->eyeState--;
if (this->eyeState <= HONOTRAP_EYE_OPEN) {
EnHonotrap_SetupEyeAttack(this);
sin = Math_SinS(this->actor.shape.rot.y);
cos = Math_CosS(this->actor.shape.rot.y);
Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_EN_HONOTRAP,
(sin * 12.0f) + this->actor.home.pos.x, this->actor.home.pos.y - 10.0f,
(cos * 12.0f) + this->actor.home.pos.z, this->actor.home.rot.x, this->actor.home.rot.y,
this->actor.home.rot.z, HONOTRAP_FLAME_MOVE);
}
}
void EnHonotrap_SetupEyeAttack(EnHonotrap* this) {
this->actionFunc = EnHonotrap_EyeAttack;
this->eyeState = HONOTRAP_EYE_OPEN;
}
void EnHonotrap_EyeAttack(EnHonotrap* this, GlobalContext* globalCtx) {
if (this->timer <= 0) {
EnHonotrap_SetupEyeClose(this);
}
}
void EnHonotrap_SetupEyeClose(EnHonotrap* this) {
this->actionFunc = EnHonotrap_EyeClose;
}
void EnHonotrap_EyeClose(EnHonotrap* this, GlobalContext* globalCtx) {
this->eyeState++;
if (this->eyeState >= HONOTRAP_EYE_SHUT) {
EnHonotrap_SetupEyeIdle(this);
this->timer = 200;
}
}
void EnHonotrap_SetupFlame(EnHonotrap* this) {
this->actionFunc = EnHonotrap_Flame;
}
void EnHonotrap_Flame(EnHonotrap* this, GlobalContext* globalCtx) {
s32 pad;
s32 ready =
Math_StepToF(&this->actor.scale.x, (this->actor.params == HONOTRAP_FLAME_MOVE) ? 0.004f : 0.0048f, 0.0006f);
this->actor.scale.z = this->actor.scale.y = this->actor.scale.x;
if (ready) {
if (this->actor.params == HONOTRAP_FLAME_MOVE) {
EnHonotrap_SetupFlameMove(this);
} else {
EnHonotrap_SetupFlameDrop(this);
}
}
}
void EnHonotrap_SetupFlameDrop(EnHonotrap* this) {
this->timer = 40;
this->actor.velocity.y = 1.0f;
this->actor.velocity.x = 2.0f * Math_SinS(this->actor.world.rot.y);
this->actor.velocity.z = 2.0f * Math_CosS(this->actor.world.rot.y);
this->actionFunc = EnHonotrap_FlameDrop;
}
void EnHonotrap_FlameDrop(EnHonotrap* this, GlobalContext* globalCtx) {
if ((this->collider.cyl.base.atFlags & AT_HIT) || (this->timer <= 0)) {
if ((this->collider.cyl.base.atFlags & AT_HIT) && !(this->collider.cyl.base.atFlags & AT_BOUNCED)) {
func_8002F71C(globalCtx, &this->actor, 5.0f, this->actor.yawTowardsPlayer, 0.0f);
}
this->actor.velocity.x = this->actor.velocity.y = this->actor.velocity.z = 0.0f;
EnHonotrap_SetupFlameVanish(this);
} else {
if (this->actor.velocity.y > 0.0f) {
this->actor.world.pos.x += this->actor.velocity.x;
this->actor.world.pos.z += this->actor.velocity.z;
Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 7.0f, 12.0f, 0.0f, 5);
}
if (!Math_StepToF(&this->actor.world.pos.y, this->actor.floorHeight + 1.0f, this->actor.velocity.y)) {
this->actor.velocity.y += 1.0f;
} else {
this->actor.velocity.y = 0.0f;
}
EnHonotrap_FlameCollisionCheck(this, globalCtx);
}
}
void EnHonotrap_SetupFlameMove(EnHonotrap* this) {
f32 distFrac;
this->actionFunc = EnHonotrap_FlameMove;
distFrac = 1.0f / (Actor_WorldDistXYZToPoint(&this->actor, &this->targetPos) + 1.0f);
this->actor.velocity.x = (this->targetPos.x - this->actor.world.pos.x) * distFrac;
this->actor.velocity.y = (this->targetPos.y - this->actor.world.pos.y) * distFrac;
this->actor.velocity.z = (this->targetPos.z - this->actor.world.pos.z) * distFrac;
this->speedMod = 0.0f;
this->timer = 160;
}
void EnHonotrap_FlameMove(EnHonotrap* this, GlobalContext* globalCtx) {
s32 pad;
Vec3f speed;
s32 ready;
Math_StepToF(&this->speedMod, 13.0f, 0.5f);
speed.x = fabsf(this->speedMod * this->actor.velocity.x);
speed.y = fabsf(this->speedMod * this->actor.velocity.y);
speed.z = fabsf(this->speedMod * this->actor.velocity.z);
ready = true;
ready &= Math_StepToF(&this->actor.world.pos.x, this->targetPos.x, speed.x);
ready &= Math_StepToF(&this->actor.world.pos.y, this->targetPos.y, speed.y);
ready &= Math_StepToF(&this->actor.world.pos.z, this->targetPos.z, speed.z);
Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 7.0f, 10.0f, 0.0f, 0x1D);
if (this->collider.tris.base.atFlags & AT_BOUNCED) {
Player* player = GET_PLAYER(globalCtx);
Vec3f shieldNorm;
Vec3f tempVel;
Vec3f shieldVec;
shieldVec.x = -player->shieldMf.xz;
shieldVec.y = -player->shieldMf.yz;
shieldVec.z = -player->shieldMf.zz;
EnHonotrap_GetNormal(&shieldNorm, &shieldVec);
tempVel = this->actor.velocity;
Math3D_Vec3fReflect(&tempVel, &shieldNorm, &this->actor.velocity);
this->actor.speedXZ = this->speedMod * 0.5f;
this->actor.world.rot.y = Math_Atan2S(this->actor.velocity.z, this->actor.velocity.x);
EnHonotrap_SetupFlameVanish(this);
} else if (this->collider.tris.base.atFlags & AT_HIT) {
this->actor.velocity.y = this->actor.speedXZ = 0.0f;
EnHonotrap_SetupFlameVanish(this);
} else if (this->timer <= 0) {
EnHonotrap_SetupFlameVanish(this);
} else {
EnHonotrap_FlameCollisionCheck(this, globalCtx);
if (ready) {
EnHonotrap_SetupFlameChase(this);
}
}
}
void EnHonotrap_SetupFlameChase(EnHonotrap* this) {
this->actionFunc = EnHonotrap_FlameChase;
this->actor.velocity.x = this->actor.velocity.y = this->actor.velocity.z = this->actor.speedXZ = 0.0f;
this->actor.world.rot.x = this->actor.world.rot.y = this->actor.world.rot.z = 0;
this->timer = 100;
}
void EnHonotrap_FlameChase(EnHonotrap* this, GlobalContext* globalCtx) {
s32 pad;
Math_ScaledStepToS(&this->actor.world.rot.y, this->actor.yawTowardsPlayer, 0x300);
Math_StepToF(&this->actor.speedXZ, 3.0f, 0.1f);
this->actor.gravity = (-this->actor.yDistToPlayer < 10.0f) ? 0.08f : -0.08f;
func_8002D868(&this->actor);
if (this->actor.velocity.y > 1.0f) {
this->actor.velocity.y = 1.0f;
}
this->actor.velocity.y *= 0.95f;
func_8002D7EC(&this->actor);
Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 7.0f, 10.0f, 0.0f, 0x1D);
if (this->collider.cyl.base.atFlags & AT_BOUNCED) {
Player* player = GET_PLAYER(globalCtx);
Vec3s shieldRot;
Matrix_MtxFToYXZRotS(&player->shieldMf, &shieldRot, false);
this->actor.world.rot.y = ((shieldRot.y * 2) - this->actor.world.rot.y) + 0x8000;
EnHonotrap_SetupFlameVanish(this);
} else if (this->collider.cyl.base.atFlags & AT_HIT) {
this->actor.speedXZ *= 0.1f;
this->actor.velocity.y *= 0.1f;
EnHonotrap_SetupFlameVanish(this);
} else if ((this->actor.bgCheckFlags & 8) || (this->timer <= 0)) {
EnHonotrap_SetupFlameVanish(this);
} else {
EnHonotrap_FlameCollisionCheck(this, globalCtx);
}
}
void EnHonotrap_SetupFlameVanish(EnHonotrap* this) {
this->actionFunc = EnHonotrap_FlameVanish;
}
void EnHonotrap_FlameVanish(EnHonotrap* this, GlobalContext* globalCtx) {
s32 pad;
s32 ready = Math_StepToF(&this->actor.scale.x, 0.0001f, 0.00015f);
this->actor.scale.z = this->actor.scale.y = this->actor.scale.x;
Actor_MoveForward(&this->actor);
Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 7.0f, 10.0f, 0.0f, 0x1D);
if (ready) {
Actor_Kill(&this->actor);
}
}
void EnHonotrap_Update(Actor* thisx, GlobalContext* globalCtx) {
static Vec3f velocity = { 0.0f, 0.0f, 0.0f };
static Vec3f accel = { 0.0f, 0.1f, 0.0f };
s32 pad;
EnHonotrap* this = (EnHonotrap*)thisx;
if (this->timer > 0) {
this->timer--;
}
if (this->actor.params == HONOTRAP_EYE) {
if ((this->actor.child != NULL) && (this->actor.child->update == NULL)) {
this->actor.child = NULL;
}
} else {
this->colChkFlags = 0;
this->bobPhase += 0x640;
this->actor.shape.yOffset = (Math_SinS(this->bobPhase) * 1000.0f) + 600.0f;
Actor_SetFocus(&this->actor, 5.0f);
Audio_PlayActorSound2(&this->actor, NA_SE_EV_BURN_OUT - SFX_FLAG);
}
this->actionFunc(this, globalCtx);
if (this->actor.params == HONOTRAP_EYE) {
if (this->collider.tris.base.acFlags & AC_HIT) {
EffectSsBomb2_SpawnLayered(globalCtx, &this->actor.world.pos, &velocity, &accel, 15, 8);
Actor_Kill(&this->actor);
} else if (this->eyeState < HONOTRAP_EYE_SHUT) {
this->collider.tris.base.acFlags &= ~AC_HIT;
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->collider.tris.base);
}
}
}
void EnHonotrap_DrawEye(Actor* thisx, GlobalContext* globalCtx) {
static void* eyeTextures[] = {
gEyeSwitchSilverOpenTex,
gEyeSwitchSilverHalfTex,
gEyeSwitchSilverClosedTex,
gEyeSwitchSilverClosedTex,
};
EnHonotrap* this = (EnHonotrap*)thisx;
OPEN_DISPS(globalCtx->state.gfxCtx);
func_80093D18(globalCtx->state.gfxCtx);
gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(eyeTextures[this->eyeState]));
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, gEyeSwitch2DL);
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
void EnHonotrap_DrawFlame(Actor* thisx, GlobalContext* globalCtx) {
s32 pad;
EnHonotrap* this = (EnHonotrap*)thisx;
OPEN_DISPS(globalCtx->state.gfxCtx);
func_80093D84(globalCtx->state.gfxCtx);
this->flameScroll -= 20;
this->flameScroll &= 0x1FF;
gSPSegment(POLY_XLU_DISP++, 0x08,
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, 0, 0x20, 0x40, 1, 0, this->flameScroll, 0x20, 0x80));
gDPSetPrimColor(POLY_XLU_DISP++, 0x80, 0x80, 255, 200, 0, 255);
gDPSetEnvColor(POLY_XLU_DISP++, 255, 0, 0, 0);
Matrix_RotateY((s16)(Camera_GetCamDirYaw(GET_ACTIVE_CAM(globalCtx)) - this->actor.shape.rot.y + 0x8000) *
(M_PI / 0x8000),
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 EnHonotrap_Draw(Actor* thisx, GlobalContext* globalCtx) {
switch (thisx->params) {
case HONOTRAP_EYE:
EnHonotrap_DrawEye(thisx, globalCtx);
break;
case HONOTRAP_FLAME_MOVE:
case HONOTRAP_FLAME_DROP:
EnHonotrap_DrawFlame(thisx, globalCtx);
break;
}
}