diff --git a/src/overlays/actors/ovl_En_Po_Relay/z_en_po_relay.c b/src/overlays/actors/ovl_En_Po_Relay/z_en_po_relay.c index b1f81b70d7..d783c5184b 100644 --- a/src/overlays/actors/ovl_En_Po_Relay/z_en_po_relay.c +++ b/src/overlays/actors/ovl_En_Po_Relay/z_en_po_relay.c @@ -22,8 +22,7 @@ #include "play_state.h" #include "player.h" #include "save.h" - -#include "assets/objects/object_tk/object_tk.h" +#include "array_count.h" #define FLAGS \ (ACTOR_FLAG_ATTENTION_ENABLED | ACTOR_FLAG_FRIENDLY | ACTOR_FLAG_UPDATE_CULLING_DISABLED | \ @@ -42,7 +41,7 @@ void EnPoRelay_Talk2(EnPoRelay* this, PlayState* play); void EnPoRelay_DisappearAndReward(EnPoRelay* this, PlayState* play); void EnPoRelay_SetupIdle(EnPoRelay* this); -static Vec3s D_80AD8C30[] = { +static Vec3s sPathPoints[] = { { 0xFFC4, 0xFDEE, 0xF47A }, { 0x0186, 0xFE0C, 0xF47A }, { 0x0186, 0xFE0C, 0xF0F6 }, { 0x00D2, 0xFDEE, 0xF0F6 }, { 0x00D2, 0xFD9E, 0xEEDA }, { 0x023A, 0xFDC6, 0xEEDA }, { 0x023A, 0xFDC6, 0xED18 }, { 0x00D2, 0xFDC6, 0xED18 }, { 0x00D2, 0xFDC6, 0xEBCE }, { 0x00D2, 0xFDC6, 0xEAA2 }, { 0x023A, 0xFDC6, 0xEAA2 }, { 0x023A, 0xFDC6, 0xEBB0 }, @@ -84,23 +83,31 @@ static ColliderCylinderInit sCylinderInit = { { 30, 52, 0, { 0, 0, 0 } }, }; -static s32 D_80AD8D24 = 0; +static s32 sAlreadySpawned = 0; static InitChainEntry sInitChain[] = { ICHAIN_S8(naviEnemyId, NAVI_ENEMY_DAMPES_GHOST, ICHAIN_CONTINUE), ICHAIN_F32(lockOnArrowOffset, 1500, ICHAIN_STOP), }; -static Vec3f D_80AD8D30 = { 0.0f, 1.5f, 0.0f }; +static Vec3f sDissapearParticlesVelocity = { 0.0f, 1.5f, 0.0f }; -static Vec3f D_80AD8D3C = { 0.0f, 0.0f, 0.0f }; +static Vec3f sDissapearParticlesAccel = { 0.0f, 0.0f, 0.0f }; -static Vec3f D_80AD8D48 = { 0.0f, 1200.0f, 0.0f }; +// the offset (in model space) from the position of the lantern limb and the position of the actual light +static Vec3f sLanternLightOffset = { 0.0f, 1200.0f, 0.0f }; + +typedef enum DampeEyes { + /* 0 */ DAMPE_EYES_FULLY_OPEN, + /* 1 */ DAMPE_EYES_HALF_OPEN, + /* 2 */ DAMPE_EYES_CLOSED, + /* 3 */ DAMPE_EYES_MAX +} DampeEyes; static void* sEyesTextures[] = { - gDampeEyeOpenTex, - gDampeEyeHalfTex, - gDampeEyeClosedTex, + gDampeEyeOpenTex, // DAMPE_EYES_FULLY_OPEN + gDampeEyeHalfTex, // DAMPE_EYES_HALF_OPEN + gDampeEyeClosedTex, // DAMPE_EYES_CLOSED }; void EnPoRelay_Init(Actor* thisx, PlayState* play) { @@ -109,18 +116,18 @@ void EnPoRelay_Init(Actor* thisx, PlayState* play) { Actor_ProcessInitChain(&this->actor, sInitChain); ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 42.0f); - SkelAnime_InitFlex(play, &this->skelAnime, &gDampeSkel, &gDampeFloatAnim, this->jointTable, this->morphTable, 18); + SkelAnime_InitFlex(play, &this->skelAnime, &gDampeSkel, &gDampeFloatAnim, this->jointTable, this->morphTable, LIMB_OBJECT_TK_00BE40_MAX); Collider_InitCylinder(play, &this->collider); Collider_SetCylinder(play, &this->collider, &this->actor, &sCylinderInit); this->lightNode = LightContext_InsertLight(play, &play->lightCtx, &this->lightInfo); Lights_PointNoGlowSetInfo(&this->lightInfo, this->actor.home.pos.x, this->actor.home.pos.y, this->actor.home.pos.z, 255, 255, 255, 200); this->lightColor.a = 255; - temp = 1; - if (D_80AD8D24 != 0) { + temp = true; + if (sAlreadySpawned) { Actor_Kill(&this->actor); } else { - D_80AD8D24 = temp; + sAlreadySpawned = temp; Actor_SetTextWithPrefix(play, &this->actor, 65); this->textId = this->actor.textId; EnPoRelay_SetupIdle(this); @@ -136,9 +143,12 @@ void EnPoRelay_Destroy(Actor* thisx, PlayState* play) { } void EnPoRelay_SetupIdle(EnPoRelay* this) { - this->unk_195 = 32; + this->bobTimer = 32; this->pathIndex = 0; + + // does not despawn upon room transitions this->actor.room = -1; + this->actor.shape.rot.y = 0; this->actor.world.rot.y = -0x8000; this->actor.colChkInfo.mass = MASS_HEAVY; @@ -154,11 +164,11 @@ void EnPoRelay_Vec3sToVec3f(Vec3f* dest, Vec3s* src) { void EnPoRelay_SetupRace(EnPoRelay* this) { Vec3f vec; - EnPoRelay_Vec3sToVec3f(&vec, &D_80AD8C30[this->pathIndex]); + EnPoRelay_Vec3sToVec3f(&vec, &sPathPoints[this->pathIndex]); this->actionTimer = ((s16)(this->actor.shape.rot.y - this->actor.world.rot.y - 0x8000) >> 0xB) % 32U; Interface_SetTimer(0); this->hookshotSlotFull = INV_CONTENT(ITEM_HOOKSHOT) != ITEM_NONE; - this->unk_19A = Actor_WorldYawTowardPoint(&this->actor, &vec); + this->yawTowardsNode = Actor_WorldYawTowardPoint(&this->actor, &vec); this->actor.flags |= ACTOR_FLAG_LOCK_ON_DISABLED; Actor_PlaySfx(&this->actor, NA_SE_EN_PO_LAUGH); this->actionFunc = EnPoRelay_Race; @@ -172,8 +182,8 @@ void EnPoRelay_SetupEndRace(EnPoRelay* this) { } void EnPoRelay_CorrectY(EnPoRelay* this) { - Math_StepToF(&this->actor.home.pos.y, D_80AD8C30[(this->pathIndex >= 28) ? 27 : this->pathIndex].y + 45.0f, 2.0f); - this->actor.world.pos.y = Math_SinS(this->unk_195 * 0x800) * 8.0f + this->actor.home.pos.y; + Math_StepToF(&this->actor.home.pos.y, sPathPoints[(this->pathIndex >= ARRAY_COUNT(sPathPoints)) ? ARRAY_COUNT(sPathPoints) - 1 : this->pathIndex].y + 45.0f, 2.0f); + this->actor.world.pos.y = Math_SinS(this->bobTimer * 0x800) * 8.0f + this->actor.home.pos.y; } void EnPoRelay_Idle(EnPoRelay* this, PlayState* play) { @@ -208,6 +218,9 @@ void EnPoRelay_Race(EnPoRelay* this, PlayState* play) { if (this->actionTimer != 0) { this->actionTimer--; } + + // 3% chance of throwing a flame every 32 frames (1.6 seconds), if it fails + // it checks again the next frame without waiting the 32 frames if (this->actionTimer == 0 && Rand_ZeroOne() < 0.03f) { this->actionTimer = 32; if (this->pathIndex < 23) { @@ -221,14 +234,18 @@ void EnPoRelay_Race(EnPoRelay* this, PlayState* play) { } speedXZ = 30.0f * multiplier; Actor_Spawn(&play->actorCtx, play, ACTOR_EN_HONOTRAP, - Math_CosS(this->unk_19A) * speedXZ + this->actor.world.pos.x, this->actor.world.pos.y, - Math_SinS(this->unk_19A) * speedXZ + this->actor.world.pos.z, 0, - (this->unk_19A + 0x8000) - (0x2000 * multiplier), 0, HONOTRAP_TYPE_FLAME_DROP); + Math_CosS(this->yawTowardsNode) * speedXZ + this->actor.world.pos.x, this->actor.world.pos.y, + Math_SinS(this->yawTowardsNode) * speedXZ + this->actor.world.pos.z, 0, + (this->yawTowardsNode + 0x8000) - (0x2000 * multiplier), 0, HONOTRAP_TYPE_FLAME_DROP); } } - Math_SmoothStepToS(&this->actor.world.rot.y, this->unk_19A, 2, 0x1000, 0x100); + Math_SmoothStepToS(&this->actor.world.rot.y, this->yawTowardsNode, 2, 0x1000, 0x100); this->actor.shape.rot.y = this->actor.world.rot.y + (this->actionTimer * 0x800) + 0x8000; if (this->pathIndex < 23) { + //! @bug Dampé's speed is directly proportional to the player's speed when more than 300 units away from the player + //! and not in the branching paths, so if the player is going backwards; + //! by HESSing, backwalking, etc., Dampé will also move backwards, away from the next node in the path rather than towards it + // If the player travels along a different path to Dampé that converges later if ((Math3D_PointInSquare2D(660.0f, 840.0f, -4480.0f, -3760.0f, player->actor.world.pos.x, player->actor.world.pos.z) != 0) || @@ -253,21 +270,27 @@ void EnPoRelay_Race(EnPoRelay* this, PlayState* play) { } else { Math_ApproachF(&this->actor.speed, 3.5f, 0.5f, 1.5f); } - EnPoRelay_Vec3sToVec3f(&vec, &D_80AD8C30[this->pathIndex]); + EnPoRelay_Vec3sToVec3f(&vec, &sPathPoints[this->pathIndex]); if (Actor_WorldDistXZToPoint(&this->actor, &vec) < 40.0f) { this->pathIndex++; - EnPoRelay_Vec3sToVec3f(&vec, &D_80AD8C30[this->pathIndex]); - if (this->pathIndex == 28) { + EnPoRelay_Vec3sToVec3f(&vec, &sPathPoints[this->pathIndex]); + if (this->pathIndex == ARRAY_COUNT(sPathPoints)) { EnPoRelay_SetupEndRace(this); + + // first door } else if (this->pathIndex == 9) { Flags_SetSwitch(play, 0x35); + + // second door } else if (this->pathIndex == 17) { Flags_SetSwitch(play, 0x36); + + // third door } else if (this->pathIndex == 25) { Flags_SetSwitch(play, 0x37); } } - this->unk_19A = Actor_WorldYawTowardPoint(&this->actor, &vec); + this->yawTowardsNode = Actor_WorldYawTowardPoint(&this->actor, &vec); Actor_PlaySfx_Flagged(&this->actor, NA_SE_EN_PO_AWAY - SFX_FLAG); } @@ -289,7 +312,7 @@ void EnPoRelay_Talk2(EnPoRelay* this, PlayState* play) { Math_ScaledStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 0x100); if (Message_GetState(&play->msgCtx) == TEXT_STATE_EVENT) { if (Message_ShouldAdvance(play)) { - if (this->hookshotSlotFull != 0) { + if (this->hookshotSlotFull) { Actor_SetTextWithPrefix(play, &this->actor, 0x2E); } else { Actor_SetTextWithPrefix(play, &this->actor, 0x2D); @@ -324,35 +347,35 @@ void EnPoRelay_DisappearAndReward(EnPoRelay* this, PlayState* play) { vec.x = (Math_SinS(Camera_GetCamDirYaw(GET_ACTIVE_CAM(play)) + 0x4800) * 23.0f) + this->actor.world.pos.x; vec.z = (Math_CosS(Camera_GetCamDirYaw(GET_ACTIVE_CAM(play)) + 0x4800) * 23.0f) + this->actor.world.pos.z; } - EffectSsDeadDb_Spawn(play, &vec, &D_80AD8D30, &D_80AD8D3C, this->actionTimer * 10 + 80, 0, 255, 255, 255, 255, + EffectSsDeadDb_Spawn(play, &vec, &sDissapearParticlesVelocity, &sDissapearParticlesAccel, this->actionTimer * 10 + 80, 0, 255, 255, 255, 255, 0, 0, 255, 1, 9, true); vec.x = (this->actor.world.pos.x + this->actor.world.pos.x) - vec.x; vec.z = (this->actor.world.pos.z + this->actor.world.pos.z) - vec.z; - EffectSsDeadDb_Spawn(play, &vec, &D_80AD8D30, &D_80AD8D3C, this->actionTimer * 10 + 80, 0, 255, 255, 255, 255, + EffectSsDeadDb_Spawn(play, &vec, &sDissapearParticlesVelocity, &sDissapearParticlesAccel, this->actionTimer * 10 + 80, 0, 255, 255, 255, 255, 0, 0, 255, 1, 9, true); vec.x = this->actor.world.pos.x; vec.z = this->actor.world.pos.z; - EffectSsDeadDb_Spawn(play, &vec, &D_80AD8D30, &D_80AD8D3C, this->actionTimer * 10 + 80, 0, 255, 255, 255, 255, + EffectSsDeadDb_Spawn(play, &vec, &sDissapearParticlesVelocity, &sDissapearParticlesAccel, this->actionTimer * 10 + 80, 0, 255, 255, 255, 255, 0, 0, 255, 1, 9, true); if (this->actionTimer == 1) { Actor_PlaySfx(&this->actor, NA_SE_EN_EXTINCT); } } if (Math_StepToF(&this->actor.scale.x, 0.0f, 0.001f) != 0) { - if (this->hookshotSlotFull != 0) { - Vec3f sp60; + if (this->hookshotSlotFull) { + Vec3f posAtGround; s32 pad1; - sp60.x = this->actor.world.pos.x; - sp60.y = this->actor.floorHeight; - sp60.z = this->actor.world.pos.z; + posAtGround.x = this->actor.world.pos.x; + posAtGround.y = this->actor.floorHeight; + posAtGround.z = this->actor.world.pos.z; if (gSaveContext.timerSeconds < HIGH_SCORE(HS_DAMPE_RACE)) { HIGH_SCORE(HS_DAMPE_RACE) = gSaveContext.timerSeconds; } if (!Flags_GetCollectible(play, this->actor.params) && (gSaveContext.timerSeconds <= 60)) { - Item_DropCollectible2(play, &sp60, (this->actor.params << 8) + (0x4000 | ITEM00_HEART_PIECE)); + Item_DropCollectible2(play, &posAtGround, (this->actor.params << 8) + (0x4000 | ITEM00_HEART_PIECE)); } else { - Actor_Spawn(&play->actorCtx, play, ACTOR_EN_ITEM00, sp60.x, sp60.y, sp60.z, 0, 0, 0, 2); + Actor_Spawn(&play->actorCtx, play, ACTOR_EN_ITEM00, posAtGround.x, posAtGround.y, posAtGround.z, 0, 0, 0, 2); } } else { Flags_SetTempClear(play, 4); @@ -377,27 +400,30 @@ void EnPoRelay_Update(Actor* thisx, PlayState* play) { Collider_UpdateCylinder(&this->actor, &this->collider); CollisionCheck_SetOC(play, &play->colChkCtx, &this->collider.base); Actor_SetFocus(&this->actor, 50.0f); - if (this->unk_195 != 0) { - this->unk_195 -= 1; + if (this->bobTimer != 0) { + this->bobTimer -= 1; } - if (this->unk_195 == 0) { - this->unk_195 = 32; + if (this->bobTimer == 0) { + this->bobTimer = 32; } this->eyeTextureIdx++; - if (this->eyeTextureIdx == 3) { - this->eyeTextureIdx = 0; + if (this->eyeTextureIdx == DAMPE_EYES_MAX) { + this->eyeTextureIdx = DAMPE_EYES_FULLY_OPEN; } } void EnPoRelay_PostLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) { EnPoRelay* this = (EnPoRelay*)thisx; - if (limbIndex == 14) { + // lantern + if (limbIndex == LIMB_OBJECT_TK_00BDCC) { f32 rand; Vec3f vec; OPEN_DISPS(play->state.gfxCtx, "../z_en_po_relay.c", 885); rand = Rand_ZeroOne(); + + // lantern can be from a light orange to pure white this->lightColor.r = (s16)(rand * 30.0f) + 225; this->lightColor.g = (s16)(rand * 100.0f) + 155; this->lightColor.b = (s16)(rand * 160.0f) + 95; @@ -405,10 +431,12 @@ void EnPoRelay_PostLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* gDPSetEnvColor(POLY_OPA_DISP++, this->lightColor.r, this->lightColor.g, this->lightColor.b, 128); gSPDisplayList(POLY_OPA_DISP++, gDampeLanternDL); CLOSE_DISPS(play->state.gfxCtx, "../z_en_po_relay.c", 901); - Matrix_MultVec3f(&D_80AD8D48, &vec); + Matrix_MultVec3f(&sLanternLightOffset, &vec); Lights_PointNoGlowSetInfo(&this->lightInfo, vec.x, vec.y, vec.z, this->lightColor.r, this->lightColor.g, this->lightColor.b, 200); - } else if (limbIndex == 8) { + + // halo + } else if (limbIndex == LIMB_OBJECT_TK_00BD84) { OPEN_DISPS(play->state.gfxCtx, "../z_en_po_relay.c", 916); MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, play->state.gfxCtx, "../z_en_po_relay.c", 918); gSPDisplayList(POLY_OPA_DISP++, gDampeHaloDL); diff --git a/src/overlays/actors/ovl_En_Po_Relay/z_en_po_relay.h b/src/overlays/actors/ovl_En_Po_Relay/z_en_po_relay.h index 483208f9f0..bf5d9a5c34 100644 --- a/src/overlays/actors/ovl_En_Po_Relay/z_en_po_relay.h +++ b/src/overlays/actors/ovl_En_Po_Relay/z_en_po_relay.h @@ -4,6 +4,7 @@ #include "ultra64.h" #include "actor.h" #include "light.h" +#include "assets/objects/object_tk/object_tk.h" struct EnPoRelay; @@ -14,14 +15,14 @@ typedef struct EnPoRelay { /* 0x014C */ SkelAnime skelAnime; /* 0x0190 */ EnPoRelayActionFunc actionFunc; /* 0x0194 */ u8 hookshotSlotFull; - /* 0x0195 */ u8 unk_195; + /* 0x0195 */ u8 bobTimer; // used for the up & down bobbing /* 0x0196 */ s16 actionTimer; - /* 0x0198 */ s16 pathIndex; - /* 0x019A */ s16 unk_19A; - /* 0x019C */ u16 textId; + /* 0x0198 */ s16 pathIndex; // current (upcoming) node of the path + /* 0x019A */ s16 yawTowardsNode; // yaw towards the current (upcoming) node of the path + /* 0x019C */ u16 textId; // mirrors actor.textId /* 0x019E */ u16 eyeTextureIdx; - /* 0x01A0 */ Vec3s jointTable[18]; - /* 0x020C */ Vec3s morphTable[18]; + /* 0x01A0 */ Vec3s jointTable[LIMB_OBJECT_TK_00BE40_MAX]; + /* 0x020C */ Vec3s morphTable[LIMB_OBJECT_TK_00BE40_MAX]; /* 0x0278 */ Color_RGBA8 lightColor; /* 0x027C */ LightNode* lightNode; /* 0x0280 */ LightInfo lightInfo;