1
0
Fork 0
mirror of https://github.com/zeldaret/oot.git synced 2025-08-28 09:51:28 +00:00

Document Dampé

This commit is contained in:
Pablo 2025-08-05 00:30:41 +02:00
parent 4c2a451b9c
commit 66c34b1c30
2 changed files with 82 additions and 53 deletions

View file

@ -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);

View file

@ -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;