From ffc67c3e0adf8fbc81618299a68b52efe31dd08b Mon Sep 17 00:00:00 2001 From: Isghj <42048411+isghj5@users.noreply.github.com> Date: Sun, 19 Apr 2026 09:35:39 -0700 Subject: [PATCH] `EnPr2` Skullfish documented (#1830) * Pr2: some docs, first struct pass * Pr2: Most functions named * Pr2: more docs * Pr2: object documented * Pr2: object documented * Pr2: format * Pr2: more docs, format * Pr2: requested changes * Pr2: requested changes * Pr2: forgot prz used the object too * Pr2: more skelton limb enum changes * Pr2: removed old comment --- assets/xml/objects/object_pr.xml | 39 +- .../actors/ovl_En_Encount1/z_en_encount1.c | 16 +- .../actors/ovl_En_Encount1/z_en_encount1.h | 10 +- src/overlays/actors/ovl_En_Pr2/z_en_pr2.c | 671 +++++++++--------- src/overlays/actors/ovl_En_Pr2/z_en_pr2.h | 86 ++- src/overlays/actors/ovl_En_Prz/z_en_prz.c | 12 +- src/overlays/actors/ovl_En_Prz/z_en_prz.h | 4 +- tools/disasm/n64-us/functions.txt | 22 +- 8 files changed, 460 insertions(+), 400 deletions(-) diff --git a/assets/xml/objects/object_pr.xml b/assets/xml/objects/object_pr.xml index b4f743fdef..ed5d289c8f 100644 --- a/assets/xml/objects/object_pr.xml +++ b/assets/xml/objects/object_pr.xml @@ -31,6 +31,7 @@ + @@ -41,22 +42,26 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/src/overlays/actors/ovl_En_Encount1/z_en_encount1.c b/src/overlays/actors/ovl_En_Encount1/z_en_encount1.c index 310da3bec2..5e6981fc03 100644 --- a/src/overlays/actors/ovl_En_Encount1/z_en_encount1.c +++ b/src/overlays/actors/ovl_En_Encount1/z_en_encount1.c @@ -31,15 +31,15 @@ ActorProfile En_Encount1_Profile = { static s16 sActorIds[] = { ACTOR_EN_GRASSHOPPER, // EN_ENCOUNT1_GRASSHOPPER ACTOR_EN_WALLMAS, // EN_ENCOUNT1_WALLMASTER - ACTOR_EN_PR2, // EN_ENCOUNT1_SKULLFISH - ACTOR_EN_PR2, // EN_ENCOUNT1_SKULLFISH_2 + ACTOR_EN_PR2, // EN_ENCOUNT1_SKULLFISH_RESPAWNING + ACTOR_EN_PR2, // EN_ENCOUNT1_SKULLFISH_PATHING }; static s16 sActorParams[] = { DRAGONFLY_PARAMS(DRAGONFLY_TYPE_GROWS_WHEN_SPAWNED), // EN_ENCOUNT1_GRASSHOPPER WALLMASTER_PARAMS(WALLMASTER_TYPE_TIMER_ONLY, 0, false), // EN_ENCOUNT1_WALLMASTER - ENPR2_PARAMS(1, 0), // EN_ENCOUNT1_SKULLFISH - ENPR2_PARAMS(3, 0) // EN_ENCOUNT1_SKULLFISH_2 + ENPR2_PARAMS(PR2_TYPE_SPAWNED, 0), // EN_ENCOUNT1_SKULLFISH_RESPAWNING + ENPR2_PARAMS(PR2_TYPE_PATHING, 0) // EN_ENCOUNT1_SKULLFISH_PATHING }; void EnEncount1_Init(Actor* thisx, PlayState* play) { @@ -54,7 +54,7 @@ void EnEncount1_Init(Actor* thisx, PlayState* play) { this->spawnActiveMax = ENENCOUNT1_GET_SPAWN_ACTIVE_MAX(&this->actor); this->spawnTotalMax = ENENCOUNT1_GET_SPAWN_TOTAL_MAX(&this->actor); this->spawnTimeMin = ENENCOUNT1_GET_SPAWN_TIME_MIN(&this->actor); - this->spawnUnusedProp = ENENCOUNT1_GET_SPAWN_UNUSED_PROP(&this->actor); + this->spawnDropTable = ENENCOUNT1_GET_SPAWN_DROP_ID(&this->actor); this->spawnDistanceMax = (ENENCOUNT1_GET_SPAWN_DISTANCE_MAX(&this->actor) * 40.0f) + 120.0f; if (this->spawnTotalMax >= ENENCOUNT1_SPAWNS_TOTAL_MAX_INFINITE) { @@ -63,7 +63,7 @@ void EnEncount1_Init(Actor* thisx, PlayState* play) { if (ENENCOUNT1_GET_SPAWN_DISTANCE_MAX(&this->actor) < 0) { this->spawnDistanceMax = -1.0f; } - if (this->type == EN_ENCOUNT1_SKULLFISH_2) { + if (this->type == EN_ENCOUNT1_SKULLFISH_PATHING) { this->pathIndex = ENENCOUNT1_GET_PATH_INDEX(&this->actor); this->path = SubS_GetPathByIndex(play, this->pathIndex, ENENCOUNT1_PATH_INDEX_NONE); this->spawnTotalMax = -1; @@ -122,7 +122,7 @@ void EnEncount1_SpawnActor(EnEncount1* this, PlayState* play) { Math_Vec3f_Copy(&spawnPos, &player->actor.world.pos); break; - case EN_ENCOUNT1_SKULLFISH: + case EN_ENCOUNT1_SKULLFISH_RESPAWNING: scale = Rand_CenteredFloat(250.0f) + 500.0f; rotY = player->actor.shape.rot.y; spawnPos.x = player->actor.world.pos.x + (Math_SinS(rotY) * scale) + Rand_CenteredFloat(40.0f); @@ -135,7 +135,7 @@ void EnEncount1_SpawnActor(EnEncount1* this, PlayState* play) { } break; - case EN_ENCOUNT1_SKULLFISH_2: + case EN_ENCOUNT1_SKULLFISH_PATHING: if ((this->path != NULL) && !SubS_CopyPointFromPath(this->path, 0, &spawnPos)) { Actor_Kill(&this->actor); } diff --git a/src/overlays/actors/ovl_En_Encount1/z_en_encount1.h b/src/overlays/actors/ovl_En_Encount1/z_en_encount1.h index 0eb675272a..d60b271245 100644 --- a/src/overlays/actors/ovl_En_Encount1/z_en_encount1.h +++ b/src/overlays/actors/ovl_En_Encount1/z_en_encount1.h @@ -8,19 +8,19 @@ #define ENENCOUNT1_GET_TYPE(thisx) (((thisx)->params >> 11) & 0x1F) #define ENENCOUNT1_GET_SPAWN_ACTIVE_MAX(thisx) (((thisx)->params >> 6) & 0x1F) #define ENENCOUNT1_GET_SPAWN_TOTAL_MAX(thisx) ((thisx)->params & 0x3F) -#define ENENCOUNT1_GET_PATH_INDEX(thisx) ((thisx)->params & 0x3F) // Used only by EN_ENCOUNT1_SKULLFISH_2 which doesn't use SpawnTotalMax +#define ENENCOUNT1_GET_PATH_INDEX(thisx) ((thisx)->params & 0x3F) // Used only by EN_ENCOUNT1_SKULLFISH_PATHING which doesn't use SpawnTotalMax #define ENENCOUNT1_PATH_INDEX_NONE 0x3F #define ENENCOUNT1_GET_SPAWN_TIME_MIN(thisx) ((thisx)->world.rot.x) // Time to wait between spawning -#define ENENCOUNT1_GET_SPAWN_UNUSED_PROP(thisx) ((thisx)->world.rot.y) // Unused spawn property +#define ENENCOUNT1_GET_SPAWN_DROP_ID(thisx) ((thisx)->world.rot.y) // Read from EnPr2, index to drop table array #define ENENCOUNT1_GET_SPAWN_DISTANCE_MAX(thisx) ((thisx)->world.rot.z) // Negative means infinite distance typedef enum EnEncount1Enemy { /* 0 */ EN_ENCOUNT1_GRASSHOPPER, /* 1 */ EN_ENCOUNT1_WALLMASTER, - /* 2 */ EN_ENCOUNT1_SKULLFISH, - /* 3 */ EN_ENCOUNT1_SKULLFISH_2 + /* 2 */ EN_ENCOUNT1_SKULLFISH_RESPAWNING, + /* 3 */ EN_ENCOUNT1_SKULLFISH_PATHING // path required } EnEncount1Enemy; struct EnEncount1; @@ -39,7 +39,7 @@ typedef struct EnEncount1 { /* 0x156 */ s16 timer; /* 0x158 */ s16 spawnTimeMin; /* 0x15A */ s16 pathIndex; - /* 0x15C */ s32 spawnUnusedProp; + /* 0x15C */ s32 spawnDropTable; // unused by us, passed to EnPr2 /* 0x160 */ f32 spawnDistanceMax; } EnEncount1; // size = 0x164 diff --git a/src/overlays/actors/ovl_En_Pr2/z_en_pr2.c b/src/overlays/actors/ovl_En_Pr2/z_en_pr2.c index 654ca783f0..57bb0a65b7 100644 --- a/src/overlays/actors/ovl_En_Pr2/z_en_pr2.c +++ b/src/overlays/actors/ovl_En_Pr2/z_en_pr2.c @@ -14,48 +14,53 @@ void EnPr2_Destroy(Actor* thisx, PlayState* play); void EnPr2_Update(Actor* thisx, PlayState* play); void EnPr2_Draw(Actor* thisx, PlayState* play); -void func_80A745C4(EnPr2* this); -void func_80A745FC(EnPr2* this, PlayState* play); -void func_80A74888(EnPr2* this); -void func_80A748E8(EnPr2* this, PlayState* play); -void func_80A74DEC(EnPr2* this, PlayState* play); -void func_80A74E90(EnPr2* this, PlayState* play); -void func_80A751B4(EnPr2* this); -void func_80A75310(EnPr2* this, PlayState* play); +void EnPr2_SetupFollowPath(EnPr2* this); +void EnPr2_FollowPath(EnPr2* this, PlayState* play); +void EnPr2_SetupIdle(EnPr2* this); +void EnPr2_Idle(EnPr2* this, PlayState* play); +void EnPr2_SetupAttack(EnPr2* this, PlayState* play); +void EnPr2_Attack(EnPr2* this, PlayState* play); +void EnPr2_SetupDie(EnPr2* this); +void EnPr2_Die(EnPr2* this, PlayState* play); + +typedef enum EnPr2DamageEffect { + /* 0x0 */ PR2_DMGEFF_NONE, + /* 0xF */ PR2_DMGEFF_BREAK = 0xF, +} EnPr2DamageEffect; static DamageTable sDamageTable = { - /* Deku Nut */ DMG_ENTRY(0, 0x0), - /* Deku Stick */ DMG_ENTRY(0, 0x0), - /* Horse trample */ DMG_ENTRY(0, 0x0), - /* Explosives */ DMG_ENTRY(1, 0xF), - /* Zora boomerang */ DMG_ENTRY(1, 0xF), - /* Normal arrow */ DMG_ENTRY(1, 0xF), - /* UNK_DMG_0x06 */ DMG_ENTRY(0, 0x0), - /* Hookshot */ DMG_ENTRY(1, 0xF), - /* Goron punch */ DMG_ENTRY(0, 0x0), - /* Sword */ DMG_ENTRY(0, 0x0), - /* Goron pound */ DMG_ENTRY(0, 0x0), - /* Fire arrow */ DMG_ENTRY(1, 0xF), - /* Ice arrow */ DMG_ENTRY(1, 0xF), - /* Light arrow */ DMG_ENTRY(2, 0xF), - /* Goron spikes */ DMG_ENTRY(0, 0x0), - /* Deku spin */ DMG_ENTRY(0, 0x0), - /* Deku bubble */ DMG_ENTRY(1, 0xF), - /* Deku launch */ DMG_ENTRY(0, 0x0), - /* UNK_DMG_0x12 */ DMG_ENTRY(0, 0x0), - /* Zora barrier */ DMG_ENTRY(1, 0xF), - /* Normal shield */ DMG_ENTRY(0, 0x0), - /* Light ray */ DMG_ENTRY(0, 0x0), - /* Thrown object */ DMG_ENTRY(0, 0x0), - /* Zora punch */ DMG_ENTRY(1, 0xF), - /* Spin attack */ DMG_ENTRY(0, 0x0), - /* Sword beam */ DMG_ENTRY(0, 0x0), - /* Normal Roll */ DMG_ENTRY(0, 0x0), - /* UNK_DMG_0x1B */ DMG_ENTRY(0, 0x0), - /* UNK_DMG_0x1C */ DMG_ENTRY(0, 0x0), - /* Unblockable */ DMG_ENTRY(0, 0x0), - /* UNK_DMG_0x1E */ DMG_ENTRY(0, 0x0), - /* Powder Keg */ DMG_ENTRY(1, 0xF), + /* Deku Nut */ DMG_ENTRY(0, PR2_DMGEFF_NONE), + /* Deku Stick */ DMG_ENTRY(0, PR2_DMGEFF_NONE), + /* Horse trample */ DMG_ENTRY(0, PR2_DMGEFF_NONE), + /* Explosives */ DMG_ENTRY(1, PR2_DMGEFF_BREAK), + /* Zora boomerang */ DMG_ENTRY(1, PR2_DMGEFF_BREAK), + /* Normal arrow */ DMG_ENTRY(1, PR2_DMGEFF_BREAK), + /* UNK_DMG_0x06 */ DMG_ENTRY(0, PR2_DMGEFF_NONE), + /* Hookshot */ DMG_ENTRY(1, PR2_DMGEFF_BREAK), + /* Goron punch */ DMG_ENTRY(0, PR2_DMGEFF_NONE), + /* Sword */ DMG_ENTRY(0, PR2_DMGEFF_NONE), + /* Goron pound */ DMG_ENTRY(0, PR2_DMGEFF_NONE), + /* Fire arrow */ DMG_ENTRY(1, PR2_DMGEFF_BREAK), + /* Ice arrow */ DMG_ENTRY(1, PR2_DMGEFF_BREAK), + /* Light arrow */ DMG_ENTRY(2, PR2_DMGEFF_BREAK), + /* Goron spikes */ DMG_ENTRY(0, PR2_DMGEFF_NONE), + /* Deku spin */ DMG_ENTRY(0, PR2_DMGEFF_NONE), + /* Deku bubble */ DMG_ENTRY(1, PR2_DMGEFF_BREAK), + /* Deku launch */ DMG_ENTRY(0, PR2_DMGEFF_NONE), + /* UNK_DMG_0x12 */ DMG_ENTRY(0, PR2_DMGEFF_NONE), + /* Zora barrier */ DMG_ENTRY(1, PR2_DMGEFF_BREAK), + /* Normal shield */ DMG_ENTRY(0, PR2_DMGEFF_NONE), + /* Light ray */ DMG_ENTRY(0, PR2_DMGEFF_NONE), + /* Thrown object */ DMG_ENTRY(0, PR2_DMGEFF_NONE), + /* Zora punch */ DMG_ENTRY(1, PR2_DMGEFF_BREAK), + /* Spin attack */ DMG_ENTRY(0, PR2_DMGEFF_NONE), + /* Sword beam */ DMG_ENTRY(0, PR2_DMGEFF_NONE), + /* Normal Roll */ DMG_ENTRY(0, PR2_DMGEFF_NONE), + /* UNK_DMG_0x1B */ DMG_ENTRY(0, PR2_DMGEFF_NONE), + /* UNK_DMG_0x1C */ DMG_ENTRY(0, PR2_DMGEFF_NONE), + /* Unblockable */ DMG_ENTRY(0, PR2_DMGEFF_NONE), + /* UNK_DMG_0x1E */ DMG_ENTRY(0, PR2_DMGEFF_NONE), + /* Powder Keg */ DMG_ENTRY(1, PR2_DMGEFF_BREAK), }; static ColliderCylinderInit sCylinderInit = { @@ -91,25 +96,26 @@ ActorProfile En_Pr2_Profile = { }; typedef enum EnPr2Animation { - /* 0 */ ENPR2_ANIM_0, - /* 1 */ ENPR2_ANIM_1, - /* 2 */ ENPR2_ANIM_2, - /* 3 */ ENPR2_ANIM_MAX + /* 0 */ PR2_ANIM_SWIM, + /* 1 */ PR2_ANIM_ATTACK, + /* 2 */ PR2_ANIM_DIE, + /* 3 */ PR2_ANIM_MAX } EnPr2Animation; -static AnimationHeader* sAnimations[ENPR2_ANIM_MAX] = { - &object_pr_Anim_004340, // ENPR2_ANIM_0 - &object_pr_Anim_004274, // ENPR2_ANIM_1 - &object_pr_Anim_003904, // ENPR2_ANIM_2 +static AnimationHeader* sAnimations[PR2_ANIM_MAX] = { + &gSkullFishSwimAnim, // PR2_ANIM_SWIM + &gSkullFishAttackAnim, // PR2_ANIM_ATTACK + &gSkullFishDieAnim, // PR2_ANIM_DIE }; -static u8 sAnimationModes[ENPR2_ANIM_MAX] = { - ANIMMODE_LOOP, // ENPR2_ANIM_0 - ANIMMODE_LOOP, // ENPR2_ANIM_1 - ANIMMODE_ONCE, // ENPR2_ANIM_2 +static u8 sAnimationModes[PR2_ANIM_MAX] = { + ANIMMODE_LOOP, // PR2_ANIM_SWIM + ANIMMODE_LOOP, // PR2_ANIM_ATTACK + ANIMMODE_ONCE, // PR2_ANIM_DIE }; -s16 D_80A75C3C[] = { +// ... ? why not just lshift the index by 4? +static s16 sDropTables[] = { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, }; @@ -118,65 +124,68 @@ void EnPr2_Init(Actor* thisx, PlayState* play) { this->actor.attentionRangeType = ATTENTION_RANGE_3; this->actor.hintId = TATL_HINT_ID_SKULLFISH; - this->unk_1EC = 255; + this->primColor = 255; this->actor.colChkInfo.health = 1; this->actor.colChkInfo.damageTable = &sDamageTable; - SkelAnime_InitFlex(play, &this->skelAnime, &object_pr_Skel_004188, &object_pr_Anim_004340, this->jointTable, - this->morphTable, OBJECT_PR_2_LIMB_MAX); - this->unk_1E0 = ENPR2_GET_F(&this->actor); + SkelAnime_InitFlex(play, &this->skelAnime, &gSkullFishSkel, &gSkullFishSwimAnim, this->jointTable, this->morphTable, + PR_2_LIMB_MAX); + this->type = ENPR2_GET_TYPE(&this->actor); this->actor.colChkInfo.mass = 10; - Math_Vec3f_Copy(&this->unk_228, &this->actor.home.pos); + Math_Vec3f_Copy(&this->newHome, &this->actor.home.pos); - if (this->unk_1E0 == 2) { - this->unk_208 = ENPR2_GET_FF0(&this->actor) * 20.0f; + if (this->type == PR2_TYPE_RESIDENT) { + this->agroDistance = ENPR2_GET_AGRO_DISTANCE(&this->actor) * 20.0f; } - this->unk_1F4 = 255; + + this->alpha = 255; this->actor.shape.yOffset = 500.0f; this->actor.shape.shadowScale = 12.0f; - if (this->unk_1E0 < 10) { + if (this->type < PR2_TYPE_BROKEN) { // regular spawns ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 19.0f); Collider_InitAndSetCylinder(play, &this->collider, &this->actor, &sCylinderInit); - this->unk_218 = -1; - this->unk_204 = 0.0f; + this->dropID = -1; + this->scale = 0.0f; + // spawned by EnEncount1 if (this->actor.parent != NULL) { - Actor* parent = this->actor.parent; + Actor* encount1 = this->actor.parent; - if (parent->update != NULL) { - if (parent->world.rot.y != 0) { - this->unk_218 = parent->world.rot.y - 1; + if (encount1->update != NULL) { + if (ENPR2_GETY_PARENT_DROP_ID(encount1) != 0) { + this->dropID = ENPR2_GETY_PARENT_DROP_ID(encount1) - 1; } } - } else if (this->actor.world.rot.z != 0) { - this->unk_218 = this->actor.world.rot.z - 1; + } else if (ENPR2_GETZ_DROP_ID(thisx) != 0) { + this->dropID = ENPR2_GETZ_DROP_ID(thisx) - 1; this->actor.world.rot.z = 0; } - if (this->unk_1E0 == 3) { + if (this->type == PR2_TYPE_PATHING) { if (this->actor.parent != NULL) { - Actor* parent = this->actor.parent; + Actor* encount1 = this->actor.parent; - if (parent->update != NULL) { - this->pathIndex = ((EnEncount1*)parent)->pathIndex; + if (encount1->update != NULL) { + this->pathIndex = ((EnEncount1*)encount1)->pathIndex; this->path = SubS_GetPathByIndex(play, this->pathIndex, ENPR2_PATH_INDEX_NONE); - this->unk_208 = parent->world.rot.z * 20.0f; - if (this->unk_208 < 20.0f) { - this->unk_208 = 20.0f; + this->agroDistance = ENPR2_GETZ_PARENT_AGRO_DISTANCE(encount1) * 20.0f; + if (this->agroDistance < 20.0f) { + this->agroDistance = 20.0f; } } - func_80A745C4(this); + EnPr2_SetupFollowPath(this); } else { Actor_Kill(&this->actor); return; } } else { - func_80A74888(this); + EnPr2_SetupIdle(this); } - } else { - this->unk_204 = 0.02f; - func_80A751B4(this); + } else { // type > PR2_TYPE_BROKEN + // these are broken pieces floating after death + this->scale = 0.02f; + EnPr2_SetupDie(this); } Actor_UpdateBgCheckInfo(play, &this->actor, 0.0f, 20.0f, 20.0f, @@ -184,6 +193,7 @@ void EnPr2_Init(Actor* thisx, PlayState* play) { UPDBGCHECKINFO_FLAG_10); if (!(this->actor.bgCheckFlags & (BGCHECKFLAG_WATER | BGCHECKFLAG_WATER_TOUCH))) { + // no spawning in air Actor_Kill(&this->actor); } } @@ -191,7 +201,7 @@ void EnPr2_Init(Actor* thisx, PlayState* play) { void EnPr2_Destroy(Actor* thisx, PlayState* play) { EnPr2* this = (EnPr2*)thisx; - if (this->unk_1E0 < 10) { + if (this->type < PR2_TYPE_BROKEN) { Collider_DestroyCylinder(play, &this->collider); } @@ -204,7 +214,7 @@ void EnPr2_Destroy(Actor* thisx, PlayState* play) { } } -s32 func_80A7429C(EnPr2* this, PlayState* play) { +s32 EnPr2_IsOnScreen(EnPr2* this, PlayState* play) { Player* player = GET_PLAYER(play); s16 screenPosX; s16 screenPosY; @@ -218,37 +228,38 @@ s32 func_80A7429C(EnPr2* this, PlayState* play) { } if (!(player->stateFlags1 & PLAYER_STATE1_8000000)) { + // player is NOT swimming? return false; } else { return true; } } -void func_80A7436C(EnPr2* this, s16 arg1) { - s16 sp2E = arg1 - this->actor.world.rot.y; +void EnPr2_HandleYaw(EnPr2* this, s16 targetYRot) { + s16 yawDiff = targetYRot - this->actor.world.rot.y; - if (sp2E > 10000) { - sp2E = 10000; - } else if (sp2E < -10000) { - sp2E = -10000; + if (yawDiff > 10000) { + yawDiff = 10000; + } else if (yawDiff < -10000) { + yawDiff = -10000; } - Math_ApproachF(&this->actor.world.pos.y, this->unk_21C.y, 0.3f, 5.0f); + Math_ApproachF(&this->actor.world.pos.y, this->waypointPos.y, 0.3f, 5.0f); - if (fabsf(this->actor.world.pos.y - this->unk_21C.y) > 10.0f) { - Math_SmoothStepToS(&this->actor.world.rot.x, Math_Vec3f_Pitch(&this->actor.world.pos, &this->unk_21C) * 0.3f, - 20, 0x1388, 0x1F4); + if (fabsf(this->actor.world.pos.y - this->waypointPos.y) > 10.0f) { + Math_SmoothStepToS(&this->actor.world.rot.x, + Math_Vec3f_Pitch(&this->actor.world.pos, &this->waypointPos) * 0.3f, 20, 0x1388, 0x1F4); } else { Math_SmoothStepToS(&this->actor.world.rot.x, 0, 20, 0x1388, 0x1F4); } - if (fabsf(this->actor.world.rot.y - arg1) < 30.0f) { - Math_ApproachZeroF(&this->unk_1FC, 0.5f, 20.0f); + if (fabsf(this->actor.world.rot.y - targetYRot) < 30.0f) { + Math_ApproachZeroF(&this->slowLimbYaw, 0.5f, 20.0f); } else { - Math_ApproachF(&this->unk_1FC, sp2E, 0.5f, 3000.0f); + Math_ApproachF(&this->slowLimbYaw, yawDiff, 0.5f, 3000.0f); } - Math_SmoothStepToS(&this->actor.world.rot.y, arg1, 1, 0x7D0, 300); + Math_SmoothStepToS(&this->actor.world.rot.y, targetYRot, 1, 0x7D0, 300); } void EnPr2_ChangeAnim(EnPr2* this, s32 animIndex) { @@ -256,132 +267,137 @@ void EnPr2_ChangeAnim(EnPr2* this, s32 animIndex) { this->animIndex = animIndex; this->animEndFrame = Animation_GetLastFrame(sAnimations[animIndex]); - if (this->animIndex == ENPR2_ANIM_MAX) { + if (this->animIndex == PR2_ANIM_MAX) { playSpeed = 0.0f; } Animation_Change(&this->skelAnime, sAnimations[animIndex], playSpeed, 0.0f, this->animEndFrame, sAnimationModes[animIndex], 0.0f); } -void func_80A745C4(EnPr2* this) { - EnPr2_ChangeAnim(this, ENPR2_ANIM_0); - this->unk_1D4 = 0; - this->actionFunc = func_80A745FC; +void EnPr2_SetupFollowPath(EnPr2* this) { + EnPr2_ChangeAnim(this, PR2_ANIM_SWIM); + this->state = PR2_STATE_PATHING; + this->actionFunc = EnPr2_FollowPath; } -void func_80A745FC(EnPr2* this, PlayState* play) { +void EnPr2_FollowPath(EnPr2* this, PlayState* play) { f32 x; f32 y; f32 z; - f32 sqrtXYZ; + f32 waypointDist; - if (fabsf(this->actor.world.rot.y - this->unk_1EE) < 200.0f) { + if (fabsf(this->actor.world.rot.y - this->yawTowardsWaypoint) < 200.0f) { SkelAnime_Update(&this->skelAnime); } Actor_PlaySfx(&this->actor, NA_SE_EN_PIRANHA_EXIST - SFX_FLAG); - Math_ApproachF(&this->unk_204, 0.02f, 0.1f, 0.005f); + Math_ApproachF(&this->scale, 0.02f, 0.1f, 0.005f); - if (this->path->customValue < this->unk_1D0) { + if (this->path->customValue < this->waypoint) { Math_ApproachF(&this->actor.speed, 5.0f, 0.3f, 1.0f); } else { Math_ApproachF(&this->actor.speed, 10.0f, 0.3f, 1.0f); } - if ((this->path != NULL) && !SubS_CopyPointFromPath(this->path, this->unk_1D0, &this->unk_21C)) { + if ((this->path != NULL) && !SubS_CopyPointFromPath(this->path, this->waypoint, &this->waypointPos)) { Actor_Kill(&this->actor); } - Math_ApproachF(&this->actor.world.pos.y, this->unk_21C.y, 0.3f, 5.0f); + Math_ApproachF(&this->actor.world.pos.y, this->waypointPos.y, 0.3f, 5.0f); - if (fabsf(this->actor.world.pos.y - this->unk_21C.y) > 10.0f) { - Math_SmoothStepToS(&this->actor.world.rot.x, Math_Vec3f_Pitch(&this->actor.world.pos, &this->unk_21C) * 0.3f, - 20, 0x1388, 0x1F4); + if (fabsf(this->actor.world.pos.y - this->waypointPos.y) > 10.0f) { + Math_SmoothStepToS(&this->actor.world.rot.x, + Math_Vec3f_Pitch(&this->actor.world.pos, &this->waypointPos) * 0.3f, 20, 0x1388, 0x1F4); } else { Math_SmoothStepToS(&this->actor.world.rot.x, 0, 20, 0x1388, 0x1F4); } - x = this->actor.world.pos.x - this->unk_21C.x; - y = this->actor.world.pos.y - this->unk_21C.y; - z = this->actor.world.pos.z - this->unk_21C.z; - sqrtXYZ = sqrtf(SQ(x) + SQ(y) + SQ(z)); + x = this->actor.world.pos.x - this->waypointPos.x; + y = this->actor.world.pos.y - this->waypointPos.y; + z = this->actor.world.pos.z - this->waypointPos.z; + waypointDist = sqrtf(SQ(x) + SQ(y) + SQ(z)); - if (sqrtXYZ < (Rand_ZeroFloat(20.0f) + 15.0f)) { - this->unk_1D0++; - Math_Vec3f_Copy(&this->unk_228, &this->actor.world.pos); - if (this->unk_1D0 >= this->path->count) { - this->unk_1E0 = 2; - func_80A74888(this); + if (waypointDist < (Rand_ZeroFloat(20.0f) + 15.0f)) { + this->waypoint++; + Math_Vec3f_Copy(&this->newHome, &this->actor.world.pos); + if (this->waypoint >= this->path->count) { + // destination reached + this->type = PR2_TYPE_RESIDENT; + EnPr2_SetupIdle(this); } } - this->unk_1EE = Math_Vec3f_Yaw(&this->actor.world.pos, &this->unk_21C); - func_80A7436C(this, this->unk_1EE); + this->yawTowardsWaypoint = Math_Vec3f_Yaw(&this->actor.world.pos, &this->waypointPos); + EnPr2_HandleYaw(this, this->yawTowardsWaypoint); } -void func_80A74888(EnPr2* this) { - EnPr2_ChangeAnim(this, ENPR2_ANIM_0); - this->unk_1DA = 2; - this->unk_1D8 = 0; - Math_Vec3f_Copy(&this->unk_21C, &this->unk_228); - this->unk_1D4 = 1; - this->actionFunc = func_80A748E8; +void EnPr2_SetupIdle(EnPr2* this) { + EnPr2_ChangeAnim(this, PR2_ANIM_SWIM); + this->idleTimer = 2; + this->mainTimer = 0; + Math_Vec3f_Copy(&this->waypointPos, &this->newHome); + this->state = PR2_STATE_IDLE; + this->actionFunc = EnPr2_Idle; } -void func_80A748E8(EnPr2* this, PlayState* play) { +void EnPr2_Idle(EnPr2* this, PlayState* play) { Player* player = GET_PLAYER(play); - f32 temp_f12; - f32 temp_f2; + f32 deltaX; // reused for both dist-to-player and dist-to-home + f32 deltaZ; f32 sqrtXZ; - s32 sp4C = false; - s32 sp48 = false; - Vec3f sp3C; + s32 changingCourse = false; + s32 swimmingStraight = false; + Vec3f targetPos; - Math_ApproachF(&this->unk_204, 0.02f, 0.1f, 0.005f); + Math_ApproachF(&this->scale, 0.02f, 0.1f, 0.005f); Actor_PlaySfx(&this->actor, NA_SE_EN_PIRANHA_EXIST - SFX_FLAG); - if (fabsf(this->actor.world.rot.y - this->unk_1EE) < 200.0f) { - sp48 = true; + if (fabsf(this->actor.world.rot.y - this->yawTowardsWaypoint) < 200.0f) { + swimmingStraight = true; SkelAnime_Update(&this->skelAnime); } - if (this->unk_1F4 != 255) { + if (this->alpha != 255) { // dying this->actor.speed = 0.0f; - Math_SmoothStepToS(&this->unk_1F4, 0, 1, 30, 100); - if (this->unk_1F4 < 2) { + Math_SmoothStepToS(&this->alpha, 0, 1, 30, 100); + if (this->alpha < 2) { Actor_Kill(&this->actor); } } else { - switch (this->unk_1E0) { - case 1: - if (this->unk_1DC == 0) { - sp4C = true; - func_80A74DEC(this, play); - } else if (!func_80A7429C(this, play) && (this->unk_1F4 == 255)) { - this->unk_1F4 = 254; + switch (this->type) { + case PR2_TYPE_SPAWNED: + if (this->targetingTimer == 0) { + changingCourse = true; + EnPr2_SetupAttack(this, play); + } else if (!EnPr2_IsOnScreen(this, play) && (this->alpha == 255)) { + // despawn if not on screen + this->alpha = 254; // triggers actor kill above } break; - case 2: - if (this->unk_1DE == 0) { - temp_f2 = player->actor.world.pos.x - this->unk_228.x; - temp_f12 = player->actor.world.pos.z - this->unk_228.z; - sqrtXZ = sqrtf(SQ(temp_f2) + SQ(temp_f12)); + case PR2_TYPE_RESIDENT: + if (this->returnHomeTimer == 0) { + // distance diff from player to home + deltaX = player->actor.world.pos.x - this->newHome.x; + deltaZ = player->actor.world.pos.z - this->newHome.z; + sqrtXZ = sqrtf(SQ(deltaX) + SQ(deltaZ)); - if (sp48 && (player->stateFlags1 & PLAYER_STATE1_8000000) && (sqrtXZ < this->unk_208)) { - sp4C = true; - func_80A74DEC(this, play); + if (swimmingStraight && (player->stateFlags1 & PLAYER_STATE1_8000000) && + (sqrtXZ < this->agroDistance)) { + changingCourse = true; + EnPr2_SetupAttack(this, play); } } else { - temp_f2 = this->actor.world.pos.x - this->unk_228.x; - temp_f12 = this->actor.world.pos.z - this->unk_228.z; - sqrtXZ = sqrtf(SQ(temp_f2) + SQ(temp_f12)); + // distance diff from current pos to home + deltaX = this->actor.world.pos.x - this->newHome.x; + deltaZ = this->actor.world.pos.z - this->newHome.z; + sqrtXZ = sqrtf(SQ(deltaX) + SQ(deltaZ)); if (sqrtXZ > 20.0f) { - this->unk_1DE = 5; - sp4C = true; - this->unk_1DC = 0; - Math_Vec3f_Copy(&this->unk_21C, &this->unk_228); + this->returnHomeTimer = 5; + changingCourse = true; + this->targetingTimer = 0; + Math_Vec3f_Copy(&this->waypointPos, &this->newHome); Math_ApproachF(&this->actor.speed, 3.0f, 0.3f, 0.2f); } } @@ -391,227 +407,231 @@ void func_80A748E8(EnPr2* this, PlayState* play) { break; } - if (!sp4C) { - this->unk_21C.y = this->actor.world.pos.y; - if (this->unk_1DA != 0) { - if ((Rand_ZeroOne() < 0.3f) && !this->unk_1D6) { - this->unk_1D6 = true; + // if we already plan to change behavior, ignore this expensive maintanence code + if (!changingCourse) { + this->waypointPos.y = this->actor.world.pos.y; + if (this->idleTimer != 0) { + if ((Rand_ZeroOne() < 0.3f) && !this->bubbleToggle) { + this->bubbleToggle = true; } Math_ApproachZeroF(&this->actor.speed, 0.1f, 0.2f); - if (this->unk_1DA == 1) { - this->unk_1D8 = Rand_S16Offset(100, 100); - Math_Vec3f_Copy(&sp3C, &this->unk_228); - sp3C.x += Rand_CenteredFloat(300.0f); - sp3C.z += Rand_CenteredFloat(300.0f); - Math_Vec3f_Copy(&this->unk_21C, &sp3C); + if (this->idleTimer == 1) { + this->mainTimer = Rand_S16Offset(100, 100); + Math_Vec3f_Copy(&targetPos, &this->newHome); + targetPos.x += Rand_CenteredFloat(300.0f); + targetPos.z += Rand_CenteredFloat(300.0f); + Math_Vec3f_Copy(&this->waypointPos, &targetPos); } } else { Math_ApproachF(&this->actor.speed, 2.0f, 0.3f, 0.2f); - Math_Vec3f_Copy(&sp3C, &this->actor.world.pos); - sp3C.x += Math_SinS(this->actor.world.rot.y) * 20.0f; - sp3C.z += Math_CosS(this->actor.world.rot.y) * 20.0f; - if (fabsf(this->actor.world.rot.y - this->unk_1EE) < 100.0f) { - if (BgCheck_SphVsFirstPoly(&play->colCtx, &sp3C, 20.0f) || + Math_Vec3f_Copy(&targetPos, &this->actor.world.pos); + targetPos.x += Math_SinS(this->actor.world.rot.y) * 20.0f; + targetPos.z += Math_CosS(this->actor.world.rot.y) * 20.0f; + if (fabsf(this->actor.world.rot.y - this->yawTowardsWaypoint) < 100.0f) { + if (BgCheck_SphVsFirstPoly(&play->colCtx, &targetPos, 20.0f) || (this->actor.bgCheckFlags & BGCHECKFLAG_WALL)) { - this->unk_1DC = 0; - this->unk_1F2++; - Math_Vec3f_Copy(&this->unk_21C, &this->unk_228); - if (this->unk_1F2 > 10) { - this->unk_1F0 += 0x2000; + this->targetingTimer = 0; + this->wallCollisionCounter++; + Math_Vec3f_Copy(&this->waypointPos, &this->newHome); + if (this->wallCollisionCounter > 10) { + this->wallCollisionAngleAdjustment += 0x2000; } } else { - Math_SmoothStepToS(&this->unk_1F0, 0, 1, 0x3E8, 0x64); - this->unk_1F2 = 0; + Math_SmoothStepToS(&this->wallCollisionAngleAdjustment, 0, 1, 0x3E8, 0x64); + this->wallCollisionCounter = 0; } } - if ((this->unk_1D8 == 0) || ((fabsf(this->unk_21C.x - this->actor.world.pos.x) < 10.0f) && - (fabsf(this->unk_21C.z - this->actor.world.pos.z) < 10.0f))) { - this->unk_1DA = Rand_S16Offset(20, 30); + if ((this->mainTimer == 0) || ((fabsf(this->waypointPos.x - this->actor.world.pos.x) < 10.0f) && + (fabsf(this->waypointPos.z - this->actor.world.pos.z) < 10.0f))) { + this->idleTimer = Rand_S16Offset(20, 30); } } } - if (this->unk_1DA == 0) { - this->unk_1EE = Math_Vec3f_Yaw(&this->actor.world.pos, &this->unk_21C) + this->unk_1F0; - func_80A7436C(this, this->unk_1EE); + if (this->idleTimer == 0) { + this->yawTowardsWaypoint = + Math_Vec3f_Yaw(&this->actor.world.pos, &this->waypointPos) + this->wallCollisionAngleAdjustment; + EnPr2_HandleYaw(this, this->yawTowardsWaypoint); } } } -void func_80A74DEC(EnPr2* this, PlayState* play) { +void EnPr2_SetupAttack(EnPr2* this, PlayState* play) { Player* player = GET_PLAYER(play); - this->unk_1F0 = 0; - EnPr2_ChangeAnim(this, ENPR2_ANIM_1); + this->wallCollisionAngleAdjustment = 0; + EnPr2_ChangeAnim(this, PR2_ANIM_ATTACK); Actor_PlaySfx(&this->actor, NA_SE_EN_PIRANHA_ATTACK); - Math_Vec3f_Copy(&this->unk_21C, &player->actor.world.pos); + Math_Vec3f_Copy(&this->waypointPos, &player->actor.world.pos); - this->unk_1EE = Math_Vec3f_Yaw(&this->actor.world.pos, &this->unk_21C); - this->unk_20C = Rand_ZeroFloat(30.0f); - this->unk_1DC = 0; - this->unk_1D8 = 70; - this->unk_1D4 = 2; - this->actionFunc = func_80A74E90; + this->yawTowardsWaypoint = Math_Vec3f_Yaw(&this->actor.world.pos, &this->waypointPos); + this->randomTargetHeightOffset = Rand_ZeroFloat(30.0f); + this->targetingTimer = 0; + this->mainTimer = 3.5 * 20; + this->state = PR2_STATE_ATTACKING; + this->actionFunc = EnPr2_Attack; } -void func_80A74E90(EnPr2* this, PlayState* play) { +void EnPr2_Attack(EnPr2* this, PlayState* play) { Player* player = GET_PLAYER(play); WaterBox* waterBox; - Math_ApproachF(&this->unk_204, 0.02f, 0.1f, 0.005f); - if ((this->unk_1D8 == 0) || !(player->stateFlags1 & PLAYER_STATE1_8000000) || (this->unk_1E0 == 0)) { - func_80A74888(this); + Math_ApproachF(&this->scale, 0.02f, 0.1f, 0.005f); + if ((this->mainTimer == 0) || !(player->stateFlags1 & PLAYER_STATE1_8000000) || (this->type == PR2_TYPE_PASSIVE)) { + EnPr2_SetupIdle(this); return; } - if (this->unk_1F4 != 255) { + if (this->alpha != 255) { // dying this->actor.speed = 0.0f; - Math_SmoothStepToS(&this->unk_1F4, 0, 1, 30, 100); - if (this->unk_1F4 < 2) { + Math_SmoothStepToS(&this->alpha, 0, 1, 30, 100); + if (this->alpha < 2) { Actor_Kill(&this->actor); } } else { SkelAnime_Update(&this->skelAnime); - if ((this->unk_1DC == 0) && (fabsf(this->actor.world.rot.y - this->unk_1EE) < 200.0f)) { - Math_Vec3f_Copy(&this->unk_21C, &player->actor.world.pos); + if ((this->targetingTimer == 0) && (fabsf(this->actor.world.rot.y - this->yawTowardsWaypoint) < 200.0f)) { + Math_Vec3f_Copy(&this->waypointPos, &player->actor.world.pos); } - if ((Rand_ZeroOne() < 0.3f) && !this->unk_1D6) { - this->unk_1D6 = true; - this->unk_20C = Rand_ZeroFloat(30.0f); + if ((Rand_ZeroOne() < 0.3f) && !this->bubbleToggle) { + this->bubbleToggle = true; + this->randomTargetHeightOffset = Rand_ZeroFloat(30.0f); } - this->unk_21C.y = player->actor.world.pos.y + 30.0f + this->unk_20C; + this->waypointPos.y = player->actor.world.pos.y + 30.0f + this->randomTargetHeightOffset; Math_ApproachF(&this->actor.speed, 5.0f, 0.3f, 1.0f); - this->unk_1F0 = 0; + this->wallCollisionAngleAdjustment = 0; - if (this->unk_1E0 == 2) { - f32 temp_f2 = this->actor.world.pos.x - this->unk_228.x; - f32 temp_f12 = this->actor.world.pos.z - this->unk_228.z; - f32 sqrtXZ = sqrtf(SQ(temp_f2) + SQ(temp_f12)); + if (this->type == PR2_TYPE_RESIDENT) { + f32 deltaX = this->actor.world.pos.x - this->newHome.x; + f32 deltaZ = this->actor.world.pos.z - this->newHome.z; + f32 homeDistance = sqrtf(SQ(deltaX) + SQ(deltaZ)); - if (this->unk_208 < sqrtXZ) { - this->unk_1DE = 20; - func_80A74888(this); + if (homeDistance > this->agroDistance) { + this->returnHomeTimer = 20; + EnPr2_SetupIdle(this); return; } } else { - Math_Vec3f_Copy(&this->unk_228, &this->actor.world.pos); + // home moves to follow player, like scuttlebug + Math_Vec3f_Copy(&this->newHome, &this->actor.world.pos); } - if (WaterBox_GetSurface1(play, &play->colCtx, this->actor.world.pos.x, this->actor.world.pos.z, &this->unk_200, - &waterBox)) { - if (this->unk_21C.y > (this->unk_200 - 40.0f)) { - this->unk_21C.y = this->unk_200 - 40.0f; + if (WaterBox_GetSurface1(play, &play->colCtx, this->actor.world.pos.x, this->actor.world.pos.z, + &this->waterSurfaceHeight, &waterBox)) { + if (this->waypointPos.y > (this->waterSurfaceHeight - 40.0f)) { + this->waypointPos.y = this->waterSurfaceHeight - 40.0f; } } - if ((this->unk_1E0 == 1) && !func_80A7429C(this, play)) { - if (this->unk_1F4 == 255) { - this->unk_1F4 = 254; + if ((this->type == PR2_TYPE_SPAWNED) && !EnPr2_IsOnScreen(this, play)) { + if (this->alpha == 255) { + this->alpha = 254; // triggers actor kill at top of this function } } else { if (this->collider.base.atFlags & AT_HIT) { - this->unk_1DC = Rand_S16Offset(30, 30); - this->unk_1D8 = 100; - if (this->unk_1E0 != 2) { - func_80A74888(this); + this->targetingTimer = Rand_S16Offset(30, 30); + this->mainTimer = 5 * 20; + if (this->type != PR2_TYPE_RESIDENT) { + EnPr2_SetupIdle(this); } } - this->unk_1EE = Math_Vec3f_Yaw(&this->actor.world.pos, &this->unk_21C); - func_80A7436C(this, this->unk_1EE); + this->yawTowardsWaypoint = Math_Vec3f_Yaw(&this->actor.world.pos, &this->waypointPos); + EnPr2_HandleYaw(this, this->yawTowardsWaypoint); } } } -void func_80A751B4(EnPr2* this) { - this->unk_1EC = 0; +void EnPr2_SetupDie(EnPr2* this) { + this->primColor = 0; this->actor.flags |= ACTOR_FLAG_LOCK_ON_DISABLED; this->actor.flags &= ~ACTOR_FLAG_ATTENTION_ENABLED; - if (this->unk_1E0 < 10) { - EnPr2_ChangeAnim(this, ENPR2_ANIM_2); + if (this->type < PR2_TYPE_BROKEN) { + EnPr2_ChangeAnim(this, PR2_ANIM_DIE); } else { - this->animEndFrame = Animation_GetLastFrame(&object_pr_Anim_003904); - Animation_Change(&this->skelAnime, &object_pr_Anim_003904, 1.0f, this->animEndFrame, this->animEndFrame, + this->animEndFrame = Animation_GetLastFrame(&gSkullFishDieAnim); + Animation_Change(&this->skelAnime, &gSkullFishDieAnim, 1.0f, this->animEndFrame, this->animEndFrame, ANIMMODE_ONCE, 0.0f); - this->unk_1D8 = Rand_S16Offset(20, 30); - this->unk_1E4 = 0x4000; + this->mainTimer = Rand_S16Offset(20, 30); + this->targetZRot = 0x4000; if (Rand_ZeroOne() < 0.5f) { - this->unk_1E4 = -0x4000; + this->targetZRot = -0x4000; } - this->unk_1E6 = this->actor.world.rot.y; + this->targetYRot = this->actor.world.rot.y; this->actor.shape.rot.x = this->actor.world.rot.x; this->actor.shape.rot.y = this->actor.world.rot.y; this->actor.shape.rot.z = this->actor.world.rot.z; - this->unk_1D8 = 30; + this->mainTimer = 1.5 * 20; this->actor.speed = Rand_ZeroFloat(0.5f); this->actor.world.rot.y = Rand_CenteredFloat(0x8000); } Actor_SetColorFilter(&this->actor, COLORFILTER_COLORFLAG_RED, 255, COLORFILTER_BUFFLAG_OPA, 10); - this->unk_1D4 = 3; - this->actionFunc = func_80A75310; + this->state = PR2_STATE_DEAD; + this->actionFunc = EnPr2_Die; } -void func_80A75310(EnPr2* this, PlayState* play) { - s32 temp; +void EnPr2_Die(EnPr2* this, PlayState* play) { + s32 nearSurface; f32 curFrame; WaterBox* waterBox; SkelAnime_Update(&this->skelAnime); - if (this->unk_1E0 < 10) { + if (this->type < PR2_TYPE_BROKEN) { s32 i; curFrame = this->skelAnime.curFrame; if (curFrame >= this->animEndFrame) { - for (i = 0; i < ARRAY_COUNT(this->unk_234); i++) { - Actor_Spawn(&play->actorCtx, play, ACTOR_EN_PR2, this->unk_234[i].x, this->unk_234[i].y, - this->unk_234[i].z, this->actor.world.rot.x, this->actor.world.rot.y, - this->actor.world.rot.z, i + 10); + // spawn LIMB_COUNT EnPr2, one for each limb, to draw floating pieces + for (i = 0; i < ARRAY_COUNT(this->limbPos); i++) { + Actor_Spawn(&play->actorCtx, play, ACTOR_EN_PR2, this->limbPos[i].x, this->limbPos[i].y, + this->limbPos[i].z, this->actor.world.rot.x, this->actor.world.rot.y, + this->actor.world.rot.z, i + PR2_TYPE_BROKEN); } Actor_Kill(&this->actor); return; } } else { - Vec3f sp64; + Vec3f bubblePos; + nearSurface = false; - temp = false; Math_SmoothStepToS(&this->actor.shape.rot.x, 0, 5, 0x2710, 0x3E8); - Math_SmoothStepToS(&this->actor.shape.rot.z, this->unk_1E4, 5, 0x2710, 0x3E8); - Math_SmoothStepToS(&this->actor.shape.rot.y, this->unk_1E6, 5, 0x2710, 0x3E8); + Math_SmoothStepToS(&this->actor.shape.rot.z, this->targetZRot, 5, 0x2710, 0x3E8); + Math_SmoothStepToS(&this->actor.shape.rot.y, this->targetYRot, 5, 0x2710, 0x3E8); - if ((Rand_ZeroOne() < 0.3f) && !this->unk_1D6) { - this->unk_1D6 = true; + if ((Rand_ZeroOne() < 0.3f) && !this->bubbleToggle) { + this->bubbleToggle = true; } - if (WaterBox_GetSurface1(play, &play->colCtx, this->actor.world.pos.x, this->actor.world.pos.z, &this->unk_200, - &waterBox)) { - if (this->actor.world.pos.y >= (this->unk_200 - 15.0f)) { - temp = true; + if (WaterBox_GetSurface1(play, &play->colCtx, this->actor.world.pos.x, this->actor.world.pos.z, + &this->waterSurfaceHeight, &waterBox)) { + if (this->actor.world.pos.y >= (this->waterSurfaceHeight - 15.0f)) { + nearSurface = true; } else { - Math_ApproachF(&this->actor.world.pos.y, this->unk_200 - 15.0f, 0.3f, 1.0f); + Math_ApproachF(&this->actor.world.pos.y, this->waterSurfaceHeight - 15.0f, 0.3f, 1.0f); } } - if ((this->unk_1D8 == 0) || temp) { + if ((this->mainTimer == 0) || nearSurface) { s32 i; - Math_SmoothStepToS(&this->unk_1F4, 0, 1, 15, 50); + Math_SmoothStepToS(&this->alpha, 0, 1, 15, 50); - if (this->unk_1F4 < 2) { + if (this->alpha < 2) { for (i = 0; i < 10; i++) { - Math_Vec3f_Copy(&sp64, &this->actor.world.pos); + Math_Vec3f_Copy(&bubblePos, &this->actor.world.pos); - sp64.x += Rand_CenteredFloat(20.0f); - sp64.y += Rand_CenteredFloat(5.0f); - sp64.z += Rand_CenteredFloat(20.0f); + bubblePos.x += Rand_CenteredFloat(20.0f); + bubblePos.y += Rand_CenteredFloat(5.0f); + bubblePos.z += Rand_CenteredFloat(20.0f); - EffectSsBubble_Spawn(play, &sp64, 0.0f, 5.0f, 5.0f, Rand_ZeroFloat(0.03f) + 0.07f); + EffectSsBubble_Spawn(play, &bubblePos, 0.0f, 5.0f, 5.0f, Rand_ZeroFloat(0.03f) + 0.07f); } Actor_Kill(&this->actor); @@ -620,25 +640,27 @@ void func_80A75310(EnPr2* this, PlayState* play) { } } -void func_80A755D8(EnPr2* this, PlayState* play) { - s32 temp_v0; +void EnPr2_ApplyDamage(EnPr2* this, PlayState* play) { + s32 pad; if (this->collider.base.acFlags & AC_HIT) { Actor_ApplyDamage(&this->actor); - if ((this->actor.colChkInfo.health <= 0) && (this->unk_1D4 != 3)) { + + if ((this->actor.colChkInfo.health <= 0) && (this->state != PR2_STATE_DEAD)) { Enemy_StartFinishingBlow(play, &this->actor); this->actor.speed = 0.0f; Actor_PlaySfx(&this->actor, NA_SE_EN_PIRANHA_DEAD); - if (this->unk_218 >= 0) { - Item_DropCollectibleRandom(play, NULL, &this->actor.world.pos, D_80A75C3C[this->unk_218]); + if (this->dropID > -1) { + Item_DropCollectibleRandom(play, NULL, &this->actor.world.pos, sDropTables[this->dropID]); } this->actor.colChkInfo.health = 0; - func_80A751B4(this); + EnPr2_SetupDie(this); } } + // against mikau shield? if (this->collider.base.atFlags & AT_BOUNCED) { this->actor.speed = -10.0f; } @@ -648,45 +670,45 @@ void EnPr2_Update(Actor* thisx, PlayState* play) { EnPr2* this = (EnPr2*)thisx; f32 rand; - Actor_SetScale(&this->actor, this->unk_204); + Actor_SetScale(&this->actor, this->scale); this->actionFunc(this, play); - DECR(this->unk_1DA); - DECR(this->unk_1D8); - DECR(this->unk_1DC); - DECR(this->unk_1DE); + DECR(this->idleTimer); + DECR(this->mainTimer); + DECR(this->targetingTimer); + DECR(this->returnHomeTimer); Actor_SetFocus(&this->actor, 10.0f); - func_80A755D8(this, play); + EnPr2_ApplyDamage(this, play); Actor_MoveWithGravity(&this->actor); Actor_UpdateBgCheckInfo(play, &this->actor, 0, 10.0f, 20.0f, UPDBGCHECKINFO_FLAG_1 | UPDBGCHECKINFO_FLAG_2 | UPDBGCHECKINFO_FLAG_4 | UPDBGCHECKINFO_FLAG_8 | UPDBGCHECKINFO_FLAG_10); - if (this->unk_1D6) { + if (this->bubbleToggle) { s32 i; - Vec3f sp58; - f32 rand; + Vec3f bubblePos; + f32 bubbleScale; - Math_Vec3f_Copy(&sp58, &this->unk_270); - this->unk_1D6 = false; + Math_Vec3f_Copy(&bubblePos, &this->limbJawPos); + this->bubbleToggle = false; - sp58.x += Rand_CenteredFloat(20.0f); - sp58.y += Rand_CenteredFloat(5.0f); - sp58.z += Rand_CenteredFloat(20.0f); + bubblePos.x += Rand_CenteredFloat(20.0f); + bubblePos.y += Rand_CenteredFloat(5.0f); + bubblePos.z += Rand_CenteredFloat(20.0f); for (i = 0; i < 2; i++) { - rand = Rand_ZeroFloat(0.03f) + 0.07f; - EffectSsBubble_Spawn(play, &sp58, 0, 5.0f, 5.0f, rand); + bubbleScale = Rand_ZeroFloat(0.03f) + 0.07f; + EffectSsBubble_Spawn(play, &bubblePos, 0, 5.0f, 5.0f, bubbleScale); } } - if ((this->unk_1F4 == 255) && (this->unk_1E0 < 10)) { + if ((this->alpha == 255) && (this->type < PR2_TYPE_BROKEN)) { this->actor.shape.rot.x = this->actor.world.rot.x; this->actor.shape.rot.y = this->actor.world.rot.y; this->actor.shape.rot.z = this->actor.world.rot.z; - if (this->unk_1D4 != 3) { + if (this->state != PR2_STATE_DEAD) { Collider_UpdateCylinder(&this->actor, &this->collider); CollisionCheck_SetOC(play, &play->colChkCtx, &this->collider.base); CollisionCheck_SetAC(play, &play->colChkCtx, &this->collider.base); @@ -698,11 +720,13 @@ void EnPr2_Update(Actor* thisx, PlayState* play) { s32 EnPr2_OverrideLimbDrawOpa(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, Actor* thisx) { EnPr2* this = (EnPr2*)thisx; - if (this->unk_1E0 < 10) { - if (limbIndex == OBJECT_PR_2_LIMB_02) { - rot->y += TRUNCF_BINANG(this->unk_1FC) * -1; + if (this->type < PR2_TYPE_BROKEN) { + if (limbIndex == PR_2_LIMB_SKULL) { + rot->y += TRUNCF_BINANG(this->slowLimbYaw) * -1; } - } else if ((limbIndex + 10) != this->unk_1E0) { + } else if (this->type != limbIndex + PR2_TYPE_BROKEN) { + // after death we spawn one actor per floating limb: + // only draw the one limb we represent, NULL the rest *dList = NULL; } return false; @@ -711,12 +735,15 @@ s32 EnPr2_OverrideLimbDrawOpa(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f void EnPr2_PostLimbDrawOpa(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx) { EnPr2* this = (EnPr2*)thisx; - if (this->unk_1E0 < 10) { - if (limbIndex == OBJECT_PR_2_LIMB_02) { + if (this->type < PR2_TYPE_BROKEN) { + if (limbIndex == PR_2_LIMB_SKULL) { + // why use a matrix to save the limb pos? is there no faster method? + // also we always store limb pos in the array, why have a secondary copy? Matrix_Translate(0.0f, 0.0f, 0.0f, MTXMODE_APPLY); - Matrix_MultZero(&this->unk_270); + Matrix_MultZero(&this->limbJawPos); } - Matrix_MultZero(&this->unk_234[limbIndex]); + + Matrix_MultZero(&this->limbPos[limbIndex]); } } @@ -724,11 +751,13 @@ s32 EnPr2_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* p Gfx** gfx) { EnPr2* this = (EnPr2*)thisx; - if (this->unk_1E0 < 10) { - if (limbIndex == OBJECT_PR_2_LIMB_02) { - rot->y += TRUNCF_BINANG(this->unk_1FC) * -1; + if (this->type < PR2_TYPE_BROKEN) { + if (limbIndex == PR_2_LIMB_SKULL) { + rot->y += TRUNCF_BINANG(this->slowLimbYaw) * -1; } - } else if ((limbIndex + 10) != this->unk_1E0) { + } else if ((limbIndex + PR2_TYPE_BROKEN) != this->type) { + // if this is floating limbs, only draw the one this instance represents + // IE if we are drawing the floating jaw, then 10 + 2 matches this->type, all other limbs are NULL *dList = NULL; } return false; @@ -741,19 +770,19 @@ void EnPr2_Draw(Actor* thisx, PlayState* play) { Gfx_SetupDL25_Opa(play->state.gfxCtx); - if (this->unk_1F4 == 255) { + if (this->alpha == 255) { gDPPipeSync(POLY_OPA_DISP++); - gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, this->unk_1EC, this->unk_1EC, this->unk_1EC, 255); - gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, this->unk_1F4); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, this->primColor, this->primColor, this->primColor, 255); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, this->alpha); - Scene_SetRenderModeXlu(play, 0, 1); + Scene_SetRenderModeXlu(play, 0, 0x1); SkelAnime_DrawFlexOpa(play, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount, EnPr2_OverrideLimbDrawOpa, EnPr2_PostLimbDrawOpa, &this->actor); } else { gDPPipeSync(POLY_XLU_DISP++); - gDPSetEnvColor(POLY_XLU_DISP++, 0, 0, 0, this->unk_1F4); + gDPSetEnvColor(POLY_XLU_DISP++, 0, 0, 0, this->alpha); - Scene_SetRenderModeXlu(play, 1, 2); + Scene_SetRenderModeXlu(play, 1, 0x2); POLY_XLU_DISP = SkelAnime_DrawFlex(play, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount, EnPr2_OverrideLimbDraw, NULL, &this->actor, POLY_XLU_DISP); diff --git a/src/overlays/actors/ovl_En_Pr2/z_en_pr2.h b/src/overlays/actors/ovl_En_Pr2/z_en_pr2.h index 0b96ec0882..f03eb56e62 100644 --- a/src/overlays/actors/ovl_En_Pr2/z_en_pr2.h +++ b/src/overlays/actors/ovl_En_Pr2/z_en_pr2.h @@ -8,50 +8,76 @@ struct EnPr2; typedef void (*EnPr2ActionFunc)(struct EnPr2*, PlayState*); -#define ENPR2_GET_F(thisx) ((thisx)->params & 0xF) -#define ENPR2_GET_FF0(thisx) (((thisx)->params >> 4) & 0xFF) +#define ENPR2_GET_TYPE(thisx) ((thisx)->params & 0xF) +// only used for type PR2_TYPE_RESIDENT (agro distance is 1/20th of final units) +#define ENPR2_GET_AGRO_DISTANCE(thisx) (((thisx)->params >> 4) & 0xFF) + +// only if we are NOT spawned by a parent actor +// where dropID is an index to an array of droptables +#define ENPR2_GETZ_DROP_ID(thisx) ((thisx)->world.rot.z) +// only if we are spawned by En_Encount1 +#define ENPR2_GETY_PARENT_DROP_ID(parent) ((parent)->world.rot.y) +// agro distance is 1/20th of final distance +#define ENPR2_GETZ_PARENT_AGRO_DISTANCE(parent) ((parent)->world.rot.z) #define ENPR2_PATH_INDEX_NONE 0x3F -#define ENPR2_PARAMS(paramF, paramFF0) (((paramF) & 0xF) | (((paramFF0) << 4) & 0xFF0)) +#define ENPR2_PARAMS(type, agroDistance) (((type) & 0xF) | (((agroDistance) << 4) & 0xFF0)) + +typedef enum EnPr2Type { + /* 00 */ PR2_TYPE_PASSIVE, // does not attack, used as a hazard around the cape heartpiece likelike + /* 01 */ PR2_TYPE_SPAWNED, // called from Encount1 as part of endless spawn + /* 02 */ PR2_TYPE_RESIDENT, // regular spawn and remain in the world + /* 03 */ PR2_TYPE_PATHING, // spawned by Encount1 in GBT so they swim out of a waterway + // all types above 10 are limb based, for drawing the dead fish parts after being broken + // where each type is 10 + limb number + /* 10 */ PR2_TYPE_BROKEN = 10 +} EnPr2Type; + +typedef enum EnPr2State { + /* 00 */ PR2_STATE_PATHING, + /* 01 */ PR2_STATE_IDLE, + /* 02 */ PR2_STATE_ATTACKING, + /* 03 */ PR2_STATE_DEAD, +} EnPr2State; typedef struct EnPr2 { /* 0x000 */ Actor actor; /* 0x144 */ SkelAnime skelAnime; - /* 0x188 */ Vec3s jointTable[OBJECT_PR_2_LIMB_MAX]; - /* 0x1A6 */ Vec3s morphTable[OBJECT_PR_2_LIMB_MAX]; + /* 0x188 */ Vec3s jointTable[PR_2_LIMB_MAX]; + /* 0x1A6 */ Vec3s morphTable[PR_2_LIMB_MAX]; /* 0x1C4 */ EnPr2ActionFunc actionFunc; /* 0x1C8 */ s16 pathIndex; /* 0x1CC */ Path* path; - /* 0x1D0 */ s32 unk_1D0; - /* 0x1D4 */ s16 unk_1D4; - /* 0x1D6 */ s16 unk_1D6; - /* 0x1D8 */ s16 unk_1D8; - /* 0x1DA */ s16 unk_1DA; - /* 0x1DC */ s16 unk_1DC; - /* 0x1DE */ s16 unk_1DE; - /* 0x1E0 */ s16 unk_1E0; + /* 0x1D0 */ s32 waypoint; + /* 0x1D4 */ s16 state; + /* 0x1D6 */ s16 bubbleToggle; + /* 0x1D8 */ s16 mainTimer; + /* 0x1DA */ s16 idleTimer; // control some idle behaviors, like when to change directions + /* 0x1DC */ s16 targetingTimer; // on zero, attack attempt on player + /* 0x1DE */ s16 returnHomeTimer; // frames until attacking player acceptable again + /* 0x1E0 */ s16 type; /* 0x1E2 */ UNK_TYPE1 unk1E2[2]; - /* 0x1E4 */ s16 unk_1E4; - /* 0x1E6 */ s16 unk_1E6; + /* 0x1E4 */ s16 targetZRot; + /* 0x1E6 */ s16 targetYRot; /* 0x1E8 */ UNK_TYPE1 unk1E8[4]; - /* 0x1EC */ s16 unk_1EC; - /* 0x1EE */ s16 unk_1EE; - /* 0x1F0 */ s16 unk_1F0; - /* 0x1F2 */ s16 unk_1F2; - /* 0x1F4 */ s16 unk_1F4; + /* 0x1EC */ s16 primColor; // r and g and b, all same var, set to all black on death + /* 0x1EE */ s16 yawTowardsWaypoint; + /* 0x1F0 */ s16 wallCollisionAngleAdjustment; + /* 0x1F2 */ s16 wallCollisionCounter; + /* 0x1F4 */ s16 alpha; /* 0x1F8 */ f32 animEndFrame; - /* 0x1FC */ f32 unk_1FC; - /* 0x200 */ f32 unk_200; - /* 0x204 */ f32 unk_204; - /* 0x208 */ f32 unk_208; - /* 0x20C */ f32 unk_20C; + /* 0x1FC */ f32 slowLimbYaw; + /* 0x200 */ f32 waterSurfaceHeight; + /* 0x204 */ f32 scale; + /* 0x208 */ f32 agroDistance; + /* 0x20C */ f32 randomTargetHeightOffset; // causes him to bob up and down as he attacks /* 0x210 */ s32 animIndex; /* 0x214 */ UNK_TYPE1 unk214[4]; - /* 0x218 */ s32 unk_218; - /* 0x21C */ Vec3f unk_21C; - /* 0x228 */ Vec3f unk_228; - /* 0x234 */ Vec3f unk_234[5]; - /* 0x270 */ Vec3f unk_270; + /* 0x218 */ s32 dropID; + /* 0x21C */ Vec3f waypointPos; + /* 0x228 */ Vec3f newHome; + /* 0x234 */ Vec3f limbPos[5]; + /* 0x270 */ Vec3f limbJawPos; /* 0x27C */ ColliderCylinder collider; } EnPr2; // size = 0x2C8 diff --git a/src/overlays/actors/ovl_En_Prz/z_en_prz.c b/src/overlays/actors/ovl_En_Prz/z_en_prz.c index eedc72bc16..83d882dd44 100644 --- a/src/overlays/actors/ovl_En_Prz/z_en_prz.c +++ b/src/overlays/actors/ovl_En_Prz/z_en_prz.c @@ -111,8 +111,8 @@ void EnPrz_Init(Actor* thisx, PlayState* play) { this->actor.colChkInfo.damageTable = &sDamageTable; this->actor.colChkInfo.health = 1; - SkelAnime_InitFlex(play, &this->skelAnime, &object_pr_Skel_004188, &object_pr_Anim_004340, this->jointTable, - this->morphTable, OBJECT_PR_2_LIMB_MAX); + SkelAnime_InitFlex(play, &this->skelAnime, &gSkullFishSkel, &gSkullFishSwimAnim, this->jointTable, this->morphTable, + PR_2_LIMB_MAX); this->unk_1E6 = ENPRZ_GET(&this->actor); this->actor.shape.yOffset = 500.0f; @@ -139,8 +139,8 @@ typedef enum EnPrzAnimation { } EnPrzAnimation; static AnimationHeader* sAnimations[ENPRZ_ANIM_MAX] = { - &object_pr_Anim_004340, // ENPRZ_ANIM_0 - &object_pr_Anim_004274, // ENPRZ_ANIM_1 + &gSkullFishSwimAnim, // ENPRZ_ANIM_0 + &gSkullFishAttackAnim, // ENPRZ_ANIM_1 }; static u8 sAnimationModes[ENPRZ_ANIM_MAX] = { @@ -499,7 +499,7 @@ void EnPrz_Update(Actor* thisx, PlayState* play) { s32 EnPrz_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, Actor* thisx) { EnPrz* this = (EnPrz*)thisx; - if (limbIndex == OBJECT_PR_2_LIMB_02) { + if (limbIndex == PR_2_LIMB_SKULL) { rot->y += TRUNCF_BINANG(this->unk_218) * -100; } return false; @@ -509,7 +509,7 @@ void EnPrz_PostLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, Vec3f sZeroVec = { 0.0f, 0.0f, 0.0f }; EnPrz* this = (EnPrz*)thisx; - if (limbIndex == OBJECT_PR_2_LIMB_02) { + if (limbIndex == PR_2_LIMB_SKULL) { Matrix_Translate(0.0f, 0.0f, 0.0f, MTXMODE_APPLY); Matrix_MultVec3f(&sZeroVec, &this->unk_1CC); } diff --git a/src/overlays/actors/ovl_En_Prz/z_en_prz.h b/src/overlays/actors/ovl_En_Prz/z_en_prz.h index ec8df1eb50..9f47458e14 100644 --- a/src/overlays/actors/ovl_En_Prz/z_en_prz.h +++ b/src/overlays/actors/ovl_En_Prz/z_en_prz.h @@ -13,8 +13,8 @@ typedef void (*EnPrzActionFunc)(struct EnPrz*, PlayState*); typedef struct EnPrz { /* 0x000 */ Actor actor; /* 0x144 */ SkelAnime skelAnime; - /* 0x188 */ Vec3s jointTable[OBJECT_PR_2_LIMB_MAX]; - /* 0x1A6 */ Vec3s morphTable[OBJECT_PR_2_LIMB_MAX]; + /* 0x188 */ Vec3s jointTable[PR_2_LIMB_MAX]; + /* 0x1A6 */ Vec3s morphTable[PR_2_LIMB_MAX]; /* 0x1C4 */ EnPrzActionFunc actionFunc; /* 0x1C8 */ u8 unk_1C8; /* 0x1CC */ Vec3f unk_1CC; diff --git a/tools/disasm/n64-us/functions.txt b/tools/disasm/n64-us/functions.txt index 233ebbca80..2b35b88eb8 100644 --- a/tools/disasm/n64-us/functions.txt +++ b/tools/disasm/n64-us/functions.txt @@ -11014,18 +11014,18 @@ EnDno_OverrideLimbDraw = 0x80A7361C; // type:func EnDno_PostLimbDraw = 0x80A73654; // type:func EnPr2_Init = 0x80A73FA0; // type:func EnPr2_Destroy = 0x80A7422C; // type:func -func_80A7429C = 0x80A7429C; // type:func -func_80A7436C = 0x80A7436C; // type:func +EnPr2_IsOnScreen = 0x80A7429C; // type:func +EnPr2_HandleYaw = 0x80A7436C; // type:func EnPr2_ChangeAnim = 0x80A74510; // type:func -func_80A745C4 = 0x80A745C4; // type:func -func_80A745FC = 0x80A745FC; // type:func -func_80A74888 = 0x80A74888; // type:func -func_80A748E8 = 0x80A748E8; // type:func -func_80A74DEC = 0x80A74DEC; // type:func -func_80A74E90 = 0x80A74E90; // type:func -func_80A751B4 = 0x80A751B4; // type:func -func_80A75310 = 0x80A75310; // type:func -func_80A755D8 = 0x80A755D8; // type:func +EnPr2_SetupFollowPath = 0x80A745C4; // type:func +EnPr2_FollowPath = 0x80A745FC; // type:func +EnPr2_SetupIdle = 0x80A74888; // type:func +EnPr2_Idle = 0x80A748E8; // type:func +EnPr2_SetupAttack = 0x80A74DEC; // type:func +EnPr2_Attack = 0x80A74E90; // type:func +EnPr2_SetupDie = 0x80A751B4; // type:func +EnPr2_Die = 0x80A75310; // type:func +EnPr2_ApplyDamage = 0x80A755D8; // type:func EnPr2_Update = 0x80A756A8; // type:func EnPr2_OverrideLimbDrawOpa = 0x80A758E8; // type:func EnPr2_PostLimbDrawOpa = 0x80A75950; // type:func