From 12b995093fa0b3430669dbbf39321399422d5744 Mon Sep 17 00:00:00 2001 From: Isghj <42048411+isghj5@users.noreply.github.com> Date: Wed, 25 May 2022 19:19:38 -0700 Subject: [PATCH] `EnNwc` OK and three objects documented (`object_niw` and `object_nwc` and `object_hs`) and some Actor docs( `EnNiw` and `EnAttackNiw` and `EnHg`) (#715) * EnNwc: OK and some Niw Docs * Update src/overlays/actors/ovl_En_Nwc/z_en_nwc.c Co-authored-by: Parker Burnett * Update src/overlays/actors/ovl_En_Nwc/z_en_nwc.c Co-authored-by: Parker Burnett * Update src/overlays/actors/ovl_En_Nwc/z_en_nwc.c Co-authored-by: Parker Burnett * EnNwc: Overwrite->Override * EnAttackNiw: fix merges * AttackNiw and Niw: some docs * formater pass * EnNwc: fixed savecontext change * Niw and Attackniw: more docs * Apply suggestions from code review Co-authored-by: Anghelo Carvajal * Nwc,Niw: requested doc changes * Nwc: extracted and marked broken texture * Apply suggestions from code review Co-authored-by: Derek Hensley * EnNwc: more requested changes * Nwc: more requested changes * Apply suggestions from code review Co-authored-by: Derek Hensley * EnHs: object_hs documented, some ovl_En_Hs docs * EnHs: animation names * EnHs: some text docs * EnHs: fear anim changed to shivering now that we know it was used in OOT * EnHs: more docs and format pass * Apply suggestions from code review Co-authored-by: Derek Hensley * EnHs: more docs and updates to var name changes * Niw,Nwc,Hs: added description to object files * Hs: changed from playerOffset to offset Co-authored-by: Isghj8 Co-authored-by: Parker Burnett Co-authored-by: Anghelo Carvajal Co-authored-by: Derek Hensley --- assets/xml/objects/object_hs.xml | 62 +- assets/xml/objects/object_niw.xml | 66 +- assets/xml/objects/object_nwc.xml | 46 +- include/functions.h | 2 +- spec | 3 +- .../ovl_En_Attack_Niw/z_en_attack_niw.c | 479 +++++++------ .../ovl_En_Attack_Niw/z_en_attack_niw.h | 83 +-- src/overlays/actors/ovl_En_Hs/z_en_hs.c | 168 ++--- src/overlays/actors/ovl_En_Hs/z_en_hs.h | 22 +- src/overlays/actors/ovl_En_Niw/z_en_niw.c | 641 +++++++++--------- src/overlays/actors/ovl_En_Niw/z_en_niw.h | 99 +-- src/overlays/actors/ovl_En_Nwc/z_en_nwc.c | 506 +++++++++++++- src/overlays/actors/ovl_En_Nwc/z_en_nwc.h | 28 +- tools/disasm/functions.txt | 52 +- 14 files changed, 1411 insertions(+), 846 deletions(-) diff --git a/assets/xml/objects/object_hs.xml b/assets/xml/objects/object_hs.xml index 0d36c4ff1a..ae025f327c 100644 --- a/assets/xml/objects/object_hs.xml +++ b/assets/xml/objects/object_hs.xml @@ -1,8 +1,9 @@  + - - - + + + @@ -13,35 +14,38 @@ - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + diff --git a/assets/xml/objects/object_niw.xml b/assets/xml/objects/object_niw.xml index e494265608..0e533fb6e6 100644 --- a/assets/xml/objects/object_niw.xml +++ b/assets/xml/objects/object_niw.xml @@ -1,38 +1,40 @@  + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/assets/xml/objects/object_nwc.xml b/assets/xml/objects/object_nwc.xml index 77b395b581..8c67159cef 100644 --- a/assets/xml/objects/object_nwc.xml +++ b/assets/xml/objects/object_nwc.xml @@ -1,29 +1,57 @@  + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + diff --git a/include/functions.h b/include/functions.h index e3f700d723..0e12b35a5f 100644 --- a/include/functions.h +++ b/include/functions.h @@ -3498,7 +3498,7 @@ void func_801A0238(s32 arg0, s32 arg1); // void func_801A05F0(void); void func_801A0654(Vec3f* arg0, u16 sfxId, s32 arg2); void func_801A0810(Vec3f* arg0, u16 sfxId, u8 arg2); -// void func_801A0868(void); +void func_801A0868(Vec3f* pos, u16 sfxId, u8 val); // void func_801A09D4(void); // void Audio_SplitBgmChannels(void); // void func_801A0E44(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5, UNK_TYPE4 param_6, UNK_TYPE4 param_7); diff --git a/spec b/spec index a92016e254..5cb8e71236 100644 --- a/spec +++ b/spec @@ -1510,8 +1510,7 @@ beginseg name "ovl_En_Nwc" compress include "build/src/overlays/actors/ovl_En_Nwc/z_en_nwc.o" - include "build/data/ovl_En_Nwc/ovl_En_Nwc.data.o" - include "build/data/ovl_En_Nwc/ovl_En_Nwc.reloc.o" + include "build/src/overlays/actors/ovl_En_Nwc/ovl_En_Nwc_reloc.o" endseg beginseg diff --git a/src/overlays/actors/ovl_En_Attack_Niw/z_en_attack_niw.c b/src/overlays/actors/ovl_En_Attack_Niw/z_en_attack_niw.c index b100f692ff..548e1e68df 100644 --- a/src/overlays/actors/ovl_En_Attack_Niw/z_en_attack_niw.c +++ b/src/overlays/actors/ovl_En_Attack_Niw/z_en_attack_niw.c @@ -1,7 +1,7 @@ /* * File: z_en_attack_niw.c * Overlay: ovl_En_Attack_Niw - * Description: Attacking cucco + * Description: Attacking Cucco */ #include "z_en_attack_niw.h" @@ -16,9 +16,9 @@ void EnAttackNiw_Destroy(Actor* thisx, GlobalContext* globalCtx); void EnAttackNiw_Update(Actor* thisx, GlobalContext* globalCtx); void EnAttackNiw_Draw(Actor* thisx, GlobalContext* globalCtx); -void func_80958634(EnAttackNiw* this, GlobalContext* globalCtx); -void func_80958974(EnAttackNiw* this, GlobalContext* globalCtx); -void func_80958BE4(EnAttackNiw* this, GlobalContext* globalCtx); +void EnAttackNiw_EnterViewFromOffscreen(EnAttackNiw* this, GlobalContext* globalCtx); +void EnAttackNiw_AimAtPlayer(EnAttackNiw* this, GlobalContext* globalCtx); +void EnAttackNiw_FlyAway(EnAttackNiw* this, GlobalContext* globalCtx); const ActorInit En_Attack_Niw_InitVars = { ACTOR_EN_ATTACK_NIW, @@ -43,289 +43,305 @@ void EnAttackNiw_Init(Actor* thisx, GlobalContext* globalCtx) { Actor_ProcessInitChain(&this->actor, sInitChain); ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 25.0f); - SkelAnime_InitFlex(globalCtx, &this->skelAnime, &object_niw_Skel_002530, &object_niw_Anim_0000E8, this->jointTable, - this->morphTable, OBJECT_NIW_LIMB_MAX); + SkelAnime_InitFlex(globalCtx, &this->skelAnime, &gNiwSkeleton, &gNiwIdleAnim, this->jointTable, this->morphTable, + NIW_LIMB_MAX); + // probably copy pasted from EnNiw, which has this same code, but AttackNiw has no params if (this->actor.params < 0) { - this->actor.params = 0; + this->actor.params = ATTACK_NIW_REGULAR; } Actor_SetScale(&this->actor, 0.01f); this->actor.gravity = 0.0f; - this->unk_290.x = randPlusMinusPoint5Scaled(100.0f); - this->unk_290.y = randPlusMinusPoint5Scaled(10.0f); - this->unk_290.z = randPlusMinusPoint5Scaled(100.0f); + this->randomTargetCenterOffset.x = randPlusMinusPoint5Scaled(100.0f); + this->randomTargetCenterOffset.y = randPlusMinusPoint5Scaled(10.0f); + this->randomTargetCenterOffset.z = randPlusMinusPoint5Scaled(100.0f); Actor_SetScale(&this->actor, 0.01f); - this->actor.flags &= ~ACTOR_FLAG_1; + this->actor.flags &= ~ACTOR_FLAG_1; // Unnecessary: this actor does not start with this flag this->actor.shape.rot.y = this->actor.world.rot.y = (Rand_ZeroOne() - 0.5f) * 60000.0f; - this->actionFunc = func_80958634; + this->actionFunc = EnAttackNiw_EnterViewFromOffscreen; } void EnAttackNiw_Destroy(Actor* thisx, GlobalContext* globalCtx) { EnAttackNiw* this = THIS; EnNiw* parent = (EnNiw*)this->actor.parent; - if ((thisx->parent != NULL) && (thisx->parent->update != NULL)) { - if (parent->unk290 > 0) { - parent->unk290--; + if (this->actor.parent != NULL && this->actor.parent->update != NULL) { + if (parent->attackNiwCount > 0) { + parent->attackNiwCount--; } } } -void func_80958228(EnAttackNiw* this, GlobalContext* globalCtx, s16 arg2) { - if (this->unk_24C == 0) { - if (arg2 == 0) { - this->unk_25C = 0.0f; +/** + * Summary: instead of using SkelAnime animations AttackNiw modifies head+wings directly to create animations + * + * EnNiw has its own version of this function, probably copy paste since AttackNiw only uses two animationState (2/5) + */ +void EnAttackNiw_AnimateWingHead(EnAttackNiw* this, GlobalContext* globalCtx, s16 animationState) { + if (this->unkTimer24C == 0) { + if (animationState == 0) { + this->targetBodyRotY = 0.0f; } else { - this->unk_25C = -10000.0f; + this->targetBodyRotY = -10000.0f; } - this->unk_286++; - this->unk_24C = 3; - if ((this->unk_286 % 2) == 0) { - this->unk_25C = 0.0f; - if (arg2 == 0) { - this->unk_24C = Rand_ZeroFloat(30.0f); + + this->clearRotYToggleTimer++; + this->unkTimer24C = 3; + if ((this->clearRotYToggleTimer % 2) == 0) { + this->targetBodyRotY = 0.0f; + if (animationState == 0) { + this->unkTimer24C = Rand_ZeroFloat(30.0f); } } } - if (this->unk_250 == 0) { - this->unk_28A++; - this->unk_28A &= 1; + if (this->unkTimer250 == 0) { + this->unkToggle28A++; + this->unkToggle28A &= 1; - switch (arg2) { - case 0: - this->unk_264 = 0.0f; - this->unk_260 = 0.0f; + switch (animationState) { // only case 2 and 5 are ever called in AttackNiw + case NIW_ANIMATION_STILL: + this->targetLeftWingRotZ = 0.0f; + this->targetRightWingRotZ = 0.0f; break; - case 1: - this->unk_250 = 3; - this->unk_264 = 7000.0f; - this->unk_260 = 7000.0f; - if (this->unk_28A == 0) { - this->unk_264 = 0.0f; - this->unk_260 = 0.0f; + case NIW_ANIMATION_HEAD_PECKING: + this->unkTimer250 = 3; + this->targetLeftWingRotZ = 7000.0f; + this->targetRightWingRotZ = 7000.0f; + if (this->unkToggle28A == 0) { + this->targetLeftWingRotZ = 0.0f; + this->targetRightWingRotZ = 0.0f; } break; - case 2: - this->unk_250 = 2; - this->unk_264 = -10000.0f; - this->unk_260 = -10000.0f; - this->unk_278 = 25000.0f; - this->unk_270 = 25000.0f; - this->unk_27C = 6000.0f; - this->unk_274 = 6000.0f; - if (this->unk_28A == 0) { - this->unk_270 = 8000.0f; - this->unk_278 = 8000.0f; + case NIW_ANIMATION_PECKING_AND_WAVING: + this->unkTimer250 = 2; + this->targetLeftWingRotZ = -10000.0f; + this->targetRightWingRotZ = -10000.0f; + this->targetLeftWingRotY = 25000.0f; + this->targetRightWingRotY = 25000.0f; + this->targetLeftWingRotX = 6000.0f; + this->targetRightWingRotX = 6000.0f; + if (this->unkToggle28A == 0) { + this->targetRightWingRotY = 8000.0f; + this->targetLeftWingRotY = 8000.0f; } break; - case 3: - this->unk_250 = 2; - this->unk_270 = 10000.0f; - this->unk_278 = 10000.0f; - if (this->unk_28A == 0) { - this->unk_270 = 3000.0f; - this->unk_278 = 3000.0f; + case NIW_ANIMATION_PECKING_AND_FORFLAPPING: + this->unkTimer250 = 2; + this->targetRightWingRotY = 10000.0f; + this->targetLeftWingRotY = 10000.0f; + if (this->unkToggle28A == 0) { + this->targetRightWingRotY = 3000.0f; + this->targetLeftWingRotY = 3000.0f; } break; - case 4: - this->unk_24E = 5; - this->unk_24C = this->unk_24E; + case NIW_ANIMATION_FREEZE: + this->unusedTimer24E = 5; + this->unkTimer24C = this->unusedTimer24E; break; - case 5: - this->unk_250 = 5; - this->unk_270 = 14000.0f; - this->unk_278 = 14000.0f; - if (this->unk_28A == 0) { - this->unk_270 = 10000.0f; - this->unk_278 = 10000.0f; + case NIW_ANIMATION_PECKING_SLOW_FORFLAPPING: + this->unkTimer250 = 5; + this->targetRightWingRotY = 14000.0f; + this->targetLeftWingRotY = 14000.0f; + if (this->unkToggle28A == 0) { + this->targetRightWingRotY = 10000.0f; + this->targetLeftWingRotY = 10000.0f; } break; } } - if (this->unk_280 != this->unk_2B8) { - Math_ApproachF(&this->unk_2B8, this->unk_280, 0.5f, 4000.0f); + if (this->targetHeadRotZ != this->headRotZ) { + Math_ApproachF(&this->headRotZ, this->targetHeadRotZ, 0.5f, 4000.0f); } - if (this->unk_25C != this->unk_2B4) { - Math_ApproachF(&this->unk_2B4, this->unk_25C, 0.5f, 4000.0f); + if (this->targetBodyRotY != this->upperBodyRotY) { + Math_ApproachF(&this->upperBodyRotY, this->targetBodyRotY, 0.5f, 4000.0f); } - if (this->unk_264 != this->unk_29C) { - Math_ApproachF(&this->unk_29C, this->unk_264, 0.8f, 7000.0f); + if (this->targetLeftWingRotZ != this->leftWingRotZ) { + Math_ApproachF(&this->leftWingRotZ, this->targetLeftWingRotZ, 0.8f, 7000.0f); } - if (this->unk_278 != this->unk_2A0) { - Math_ApproachF(&this->unk_2A0, this->unk_278, 0.8f, 7000.0f); + if (this->targetLeftWingRotY != this->leftWingRotY) { + Math_ApproachF(&this->leftWingRotY, this->targetLeftWingRotY, 0.8f, 7000.0f); } - if (this->unk_27C != this->unk_2A4) { - Math_ApproachF(&this->unk_2A4, this->unk_27C, 0.8f, 7000.0f); + if (this->targetLeftWingRotX != this->leftWingRotX) { + Math_ApproachF(&this->leftWingRotX, this->targetLeftWingRotX, 0.8f, 7000.0f); } - if (this->unk_260 != this->unk_2A8) { - Math_ApproachF(&this->unk_2A8, this->unk_260, 0.8f, 7000.0f); + if (this->targetRightWingRotZ != this->rightWingRotZ) { + Math_ApproachF(&this->rightWingRotZ, this->targetRightWingRotZ, 0.8f, 7000.0f); } - if (this->unk_270 != this->unk_2AC) { - Math_ApproachF(&this->unk_2AC, this->unk_270, 0.8f, 7000.0f); + if (this->targetRightWingRotY != this->rightWingRotY) { + Math_ApproachF(&this->rightWingRotY, this->targetRightWingRotY, 0.8f, 7000.0f); } - if (this->unk_274 != this->unk_2B0) { - Math_ApproachF(&this->unk_2B0, this->unk_274, 0.8f, 7000.0f); + if (this->targetRightWingRotX != this->rightWingRotX) { + Math_ApproachF(&this->rightWingRotX, this->targetRightWingRotX, 0.8f, 7000.0f); } } -s32 func_809585B0(EnAttackNiw* this, GlobalContext* globalCtx) { - s16 sp1E; - s16 sp1C; +s32 EnAttackNiw_IsOnScreen(EnAttackNiw* this, GlobalContext* globalCtx) { + s16 posX; + s16 posY; - Actor_SetFocus(&this->actor, this->unk_2DC); - Actor_GetScreenPos(globalCtx, &this->actor, &sp1E, &sp1C); + Actor_SetFocus(&this->actor, this->targetHeight); + Actor_GetScreenPos(globalCtx, &this->actor, &posX, &posY); - if ((this->actor.projectedPos.z < -20.0f) || (sp1E < 0) || (sp1E > SCREEN_WIDTH) || (sp1C < 0) || - (sp1C > SCREEN_HEIGHT)) { + if ((this->actor.projectedPos.z < -20.0f) || (posX < 0) || (posX > SCREEN_WIDTH) || (posY < 0) || + (posY > SCREEN_HEIGHT)) { return false; } return true; } -void func_80958634(EnAttackNiw* this, GlobalContext* globalCtx) { - s16 sp4E; - s16 sp4C; - Vec3f temp; - Vec3f sp34; +void EnAttackNiw_EnterViewFromOffscreen(EnAttackNiw* this, GlobalContext* globalCtx) { + s16 posX; + s16 posY; + Vec3f viewOffset; + Vec3f flightTarget; s32 pad; this->actor.speedXZ = 10.0f; - temp.x = (this->unk_290.x + globalCtx->view.at.x) - globalCtx->view.eye.x; - temp.y = (this->unk_290.y + globalCtx->view.at.y) - globalCtx->view.eye.y; - temp.z = (this->unk_290.z + globalCtx->view.at.z) - globalCtx->view.eye.z; + // randomTargetCenterOffset is set in _Init, only needs to be set once + // but the view is moving, so now we need to re-calculate the spot in space + viewOffset.x = this->randomTargetCenterOffset.x + globalCtx->view.at.x - globalCtx->view.eye.x; + viewOffset.y = this->randomTargetCenterOffset.y + globalCtx->view.at.y - globalCtx->view.eye.y; + viewOffset.z = this->randomTargetCenterOffset.z + globalCtx->view.at.z - globalCtx->view.eye.z; - sp34.x = globalCtx->view.at.x + temp.x; - sp34.y = globalCtx->view.at.y + temp.y; - sp34.z = globalCtx->view.at.z + temp.z; + // this is the 3D spot in space where the cucco is trying to fly into (until it lands or gets close) + flightTarget.x = globalCtx->view.at.x + viewOffset.x; + flightTarget.y = globalCtx->view.at.y + viewOffset.y; + flightTarget.z = globalCtx->view.at.z + viewOffset.z; - this->unk_2CC = Math_Vec3f_Yaw(&this->actor.world.pos, &sp34); - this->unk_2C8 = Math_Vec3f_Pitch(&this->actor.world.pos, &sp34) * -1.0f; + this->targetRotY = Math_Vec3f_Yaw(&this->actor.world.pos, &flightTarget); + this->targetRotX = Math_Vec3f_Pitch(&this->actor.world.pos, &flightTarget) * -1.0f; - Math_SmoothStepToS(&this->actor.world.rot.y, this->unk_2CC, 5, this->unk_2D4, 0); - Math_SmoothStepToS(&this->actor.world.rot.x, this->unk_2C8, 5, this->unk_2D4, 0); - Math_ApproachF(&this->unk_2D4, 5000.0f, 1.0f, 100.0f); + Math_SmoothStepToS(&this->actor.world.rot.y, this->targetRotY, 5, this->rotStep, 0); + Math_SmoothStepToS(&this->actor.world.rot.x, this->targetRotX, 5, this->rotStep, 0); + Math_ApproachF(&this->rotStep, 5000.0f, 1.0f, 100.0f); - Actor_SetFocus(&this->actor, this->unk_2DC); - Actor_GetScreenPos(globalCtx, &this->actor, &sp4E, &sp4C); + Actor_SetFocus(&this->actor, this->targetHeight); + Actor_GetScreenPos(globalCtx, &this->actor, &posX, &posY); - if (this->actor.bgCheckFlags & 8) { - this->unk_2CC = this->actor.yawTowardsPlayer; - this->unk_2C8 = this->actor.world.rot.x - 3000.0f; - this->unk_252 = 0; - this->unk_254 = 100; - this->unk_2D4 = 0.0f; - this->unk_27C = 0.0f; - this->unk_274 = 0.0f; - this->unk_250 = this->unk_252; - this->unk_24E = this->unk_252; - this->unk_24C = this->unk_252; + if (this->actor.bgCheckFlags & 8) { // touching a wall + this->targetRotY = this->actor.yawTowardsPlayer; + this->targetRotX = this->actor.world.rot.x - 3000.0f; + this->hopTimer = 0; + this->randomAngleChangeTimer = 100; + this->rotStep = 0.0f; + this->targetLeftWingRotX = 0.0f; + this->targetRightWingRotX = 0.0f; + this->unkTimer250 = this->hopTimer; + this->unusedTimer24E = this->hopTimer; + this->unkTimer24C = this->hopTimer; this->actor.gravity = -0.2f; - this->unk_280 = 0.0f; - this->actionFunc = func_80958974; - this->unk_2D8 = 5.0f; - } else if (((this->actor.projectedPos.z > 0.0f) && (fabsf(sp34.x - this->actor.world.pos.x) < 50.0f) && - (fabsf(sp34.y - this->actor.world.pos.y) < 50.0f) && - (fabsf(sp34.z - this->actor.world.pos.z) < 50.0f)) || - (this->actor.bgCheckFlags & 1)) { - this->unk_252 = 0; - this->unk_250 = this->unk_252; - this->unk_24E = this->unk_252; - this->unk_24C = this->unk_252; - this->unk_2D4 = 0.0f; - this->unk_274 = 0.0f; - this->unk_27C = 0.0f; - this->unk_2CC = this->actor.yawTowardsPlayer; - this->unk_2C8 = this->actor.world.rot.x - 2000.0f; - this->actor.gravity = -0.2f; - this->unk_280 = 0.0f; - this->actionFunc = func_80958974; - this->unk_2D8 = 5.0f; - } else { - this->unk_24C = 10; - this->unk_25C = -10000.0f; - this->unk_280 = -3000.0f; - func_80958228(this, globalCtx, 2); + this->targetHeadRotZ = 0.0f; + this->actionFunc = EnAttackNiw_AimAtPlayer; + this->targetXZSpeed = 5.0f; + + } else if (((this->actor.projectedPos.z > 0.0f) && (fabsf(flightTarget.x - this->actor.world.pos.x) < 50.0f) && + (fabsf(flightTarget.y - this->actor.world.pos.y) < 50.0f) && + (fabsf(flightTarget.z - this->actor.world.pos.z) < 50.0f)) || + (this->actor.bgCheckFlags & 1)) { // touching ground or with close distance of target + // reset state + this->hopTimer = 0; + this->unkTimer250 = this->hopTimer; + this->unusedTimer24E = this->hopTimer; + this->unkTimer24C = this->hopTimer; + this->rotStep = 0.0f; + this->targetRightWingRotX = 0.0f; + this->targetLeftWingRotX = 0.0f; + + this->targetRotY = this->actor.yawTowardsPlayer; // start turn to face player + this->targetRotX = this->actor.world.rot.x - 2000.0f; // bank into the turn + this->actor.gravity = -0.2f; // start gentle decent (no longer flying without gravity) + this->targetHeadRotZ = 0.0f; + this->actionFunc = EnAttackNiw_AimAtPlayer; + this->targetXZSpeed = 5.0f; + + } else { // keep flying at the flightTarget for now + this->unkTimer24C = 10; + this->targetBodyRotY = -10000.0f; + this->targetHeadRotZ = -3000.0f; + EnAttackNiw_AnimateWingHead(this, globalCtx, NIW_ANIMATION_PECKING_AND_WAVING); } } -void func_80958974(EnAttackNiw* this, GlobalContext* globalCtx) { - if (!func_809585B0(this, globalCtx)) { +void EnAttackNiw_AimAtPlayer(EnAttackNiw* this, GlobalContext* globalCtx) { + if (!EnAttackNiw_IsOnScreen(this, globalCtx)) { Actor_MarkForDeath(&this->actor); return; } - if (this->actor.bgCheckFlags & 1) { - if (this->unk_252 == 0) { - this->unk_252 = 3; + if (this->actor.bgCheckFlags & 1) { // touching floor + if (this->hopTimer == 0) { + this->hopTimer = 3; this->actor.velocity.y = 3.5f; } - if (this->actor.gravity != -2.0f) { - this->unk_2CC = this->actor.yawTowardsPlayer; - this->unk_25A = 50; - this->unk_254 = 100; - this->unk_270 = 14000.0f; - this->unk_278 = 14000.0f; - this->unk_274 = 0.0f; - this->unk_27C = 0.0f; - this->unk_260 = 0.0f; - this->unk_264 = 0.0f; - this->unk_2C8 = 0.0f; + if (this->actor.gravity != -2.0f) { // first landing + this->targetRotY = this->actor.yawTowardsPlayer; + this->unkTimer25A = 50; + this->randomAngleChangeTimer = 100; + this->targetRightWingRotY = 14000.0f; + this->targetLeftWingRotY = 14000.0f; + this->targetRightWingRotX = 0.0f; + this->targetLeftWingRotX = 0.0f; + this->targetRightWingRotZ = 0.0f; + this->targetLeftWingRotZ = 0.0f; + this->targetRotX = 0.0f; this->actor.gravity = -2.0f; } } - if (this->unk_254 == 50) { - this->unk_2CC = randPlusMinusPoint5Scaled(200.0f) + this->actor.yawTowardsPlayer; + if (this->randomAngleChangeTimer == 50) { + this->targetRotY = randPlusMinusPoint5Scaled(200.0f) + this->actor.yawTowardsPlayer; } - Math_SmoothStepToS(&this->actor.world.rot.y, this->unk_2CC, 2, this->unk_2D4, 0); - Math_SmoothStepToS(&this->actor.world.rot.x, this->unk_2C8, 2, this->unk_2D4, 0); - Math_ApproachF(&this->unk_2D4, 10000.0f, 1.0f, 1000.0f); - Math_ApproachF(&this->actor.speedXZ, this->unk_2D8, 0.9f, 1.0f); + Math_SmoothStepToS(&this->actor.world.rot.y, this->targetRotY, 2, this->rotStep, 0); + Math_SmoothStepToS(&this->actor.world.rot.x, this->targetRotX, 2, this->rotStep, 0); + Math_ApproachF(&this->rotStep, 10000.0f, 1.0f, 1000.0f); + Math_ApproachF(&this->actor.speedXZ, this->targetXZSpeed, 0.9f, 1.0f); - if ((this->actor.gravity == -2.0f) && (this->unk_25A == 0) && - ((this->actor.bgCheckFlags & 8) || (this->unk_254 == 0))) { - this->unk_2D8 = 0.0f; + if (this->actor.gravity == -2.0f && this->unkTimer25A == 0 && + (this->actor.bgCheckFlags & 8 || this->randomAngleChangeTimer == 0)) { + this->targetXZSpeed = 0.0f; this->actor.gravity = 0.0f; - this->unk_2D4 = 0.0f; - this->unk_2C8 = this->actor.world.rot.x - 5000.0f; - this->actionFunc = func_80958BE4; - } else if (this->actor.bgCheckFlags & 1) { - func_80958228(this, globalCtx, 5); + this->rotStep = 0.0f; + this->targetRotX = this->actor.world.rot.x - 5000.0f; + this->actionFunc = EnAttackNiw_FlyAway; + + } else if (this->actor.bgCheckFlags & 1) { // touching floor + EnAttackNiw_AnimateWingHead(this, globalCtx, NIW_ANIMATION_PECKING_SLOW_FORFLAPPING); + } else { - func_80958228(this, globalCtx, 2); + EnAttackNiw_AnimateWingHead(this, globalCtx, NIW_ANIMATION_PECKING_AND_WAVING); } } -void func_80958BE4(EnAttackNiw* this, GlobalContext* globalCtx) { - if (!func_809585B0(this, globalCtx)) { +void EnAttackNiw_FlyAway(EnAttackNiw* this, GlobalContext* globalCtx) { + if (!EnAttackNiw_IsOnScreen(this, globalCtx)) { Actor_MarkForDeath(&this->actor); return; } - Math_SmoothStepToS(&this->actor.world.rot.x, this->unk_2C8, 5, this->unk_2D4, 0); - Math_ApproachF(&this->unk_2D4, 5000.0f, 1.0f, 100.0f); + Math_SmoothStepToS(&this->actor.world.rot.x, this->targetRotX, 5, this->rotStep, 0); + Math_ApproachF(&this->rotStep, 5000.0f, 1.0f, 100.0f); Math_ApproachF(&this->actor.velocity.y, 5.0f, 0.3f, 1.0f); - func_80958228(this, globalCtx, 2); + EnAttackNiw_AnimateWingHead(this, globalCtx, NIW_ANIMATION_PECKING_AND_WAVING); } void EnAttackNiw_Update(Actor* thisx, GlobalContext* globalCtx) { @@ -334,37 +350,17 @@ void EnAttackNiw_Update(Actor* thisx, GlobalContext* globalCtx) { EnNiw* parent; Player* player = GET_PLAYER(globalCtx); s32 pad2; - Vec3f sp30; + Vec3f splashPos; - this->unk_284++; + this->unusedCounter284++; - if (this->unk_24C != 0) { - this->unk_24C--; - } - - if (this->unk_250 != 0) { - this->unk_250--; - } - - if (this->unk_252 != 0) { - this->unk_252--; - } - - if (this->unk_256 != 0) { - this->unk_256--; - } - - if (this->unk_258 != 0) { - this->unk_258--; - } - - if (this->unk_254 != 0) { - this->unk_254--; - } - - if (this->unk_25A != 0) { - this->unk_25A--; - } + DECR(this->unkTimer24C); + DECR(this->unkTimer250); + DECR(this->hopTimer); + DECR(this->crySfxTimer); + DECR(this->flutterSfxTimer); + DECR(this->randomAngleChangeTimer); + DECR(this->unkTimer25A); this->actor.shape.rot = this->actor.world.rot; this->actor.shape.shadowScale = 15.0f; @@ -373,45 +369,48 @@ void EnAttackNiw_Update(Actor* thisx, GlobalContext* globalCtx) { Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 20.0f, 20.0f, 60.0f, 0x1D); - if (this->actionFunc == func_80958634) { + if (this->actionFunc == EnAttackNiw_EnterViewFromOffscreen) { Actor_MoveWithoutGravity(&this->actor); } else { Actor_MoveWithGravity(&this->actor); } - if (this->actor.floorHeight <= -32000.0f) { + if (this->actor.floorHeight <= BGCHECK_Y_MIN) { // under the world Actor_MarkForDeath(&this->actor); - } else if ((this->actor.bgCheckFlags & 0x20) && (this->actionFunc != func_80958BE4)) { - Math_Vec3f_Copy(&sp30, &this->actor.world.pos); - sp30.y += this->actor.depthInWater; - EffectSsGSplash_Spawn(globalCtx, &sp30, NULL, NULL, 0, 400); - this->unk_2D4 = 0.0f; + } else if ((this->actor.bgCheckFlags & 0x20) && // on or below water + (this->actionFunc != EnAttackNiw_FlyAway)) { + Math_Vec3f_Copy(&splashPos, &this->actor.world.pos); + splashPos.y += this->actor.depthInWater; + EffectSsGSplash_Spawn(globalCtx, &splashPos, NULL, NULL, 0, 400); + this->rotStep = 0.0f; this->actor.gravity = 0.0f; - this->unk_2D8 = 0.0f; - this->unk_2C8 = this->actor.world.rot.x - 5000.0f; - this->actionFunc = func_80958BE4; + this->targetXZSpeed = 0.0f; + this->targetRotX = this->actor.world.rot.x - 5000.0f; + this->actionFunc = EnAttackNiw_FlyAway; + } else { - f32 temp = 20.0f; + f32 viewOffset = 20.0f; label: - if (this->actor.xyzDistToPlayerSq < SQ(temp)) { + if (this->actor.xyzDistToPlayerSq < SQ(viewOffset)) { parent = (EnNiw*)this->actor.parent; if ((this->actor.parent->update != NULL) && (this->actor.parent != NULL) && (parent != NULL) && - (parent->unusedTimer25E == 0) && (player->invincibilityTimer == 0)) { + (parent->unkAttackNiwTimer == 0) && (player->invincibilityTimer == 0)) { + // this updates some player values based on what we pass, need player decomp to know what this is doing func_800B8D50(globalCtx, &this->actor, 2.0f, this->actor.world.rot.y, 0.0f, 0x10); - parent->unusedTimer25E = 70; + parent->unkAttackNiwTimer = 70; } } - if (this->unk_256 == 0) { - this->unk_256 = 30; + if (this->crySfxTimer == 0) { + this->crySfxTimer = 30; Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_CHICKEN_CRY_A); } - if (this->unk_258 == 0) { - this->unk_258 = 7; + if (this->flutterSfxTimer == 0) { + this->flutterSfxTimer = 7; Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_CHICKEN_FLUTTER); } } @@ -421,24 +420,24 @@ s32 EnAttackNiw_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** Actor* thisx) { EnAttackNiw* this = THIS; - if (limbIndex == OBJECT_NIW_LIMB_0D) { - rot->y += (s16)this->unk_2B4; + if (limbIndex == NIW_LIMB_UPPER_BODY) { + rot->y += (s16)this->upperBodyRotY; } - if (limbIndex == OBJECT_NIW_LIMB_0F) { - rot->z += (s16)this->unk_2B8; + if (limbIndex == NIW_LIMB_HEAD) { + rot->z += (s16)this->headRotZ; } - if (limbIndex == OBJECT_NIW_LIMB_0B) { - rot->x += (s16)this->unk_2B0; - rot->y += (s16)this->unk_2AC; - rot->z += (s16)this->unk_2A8; + if (limbIndex == NIW_LIMB_RIGHT_WING_ROOT) { + rot->x += (s16)this->rightWingRotX; + rot->y += (s16)this->rightWingRotY; + rot->z += (s16)this->rightWingRotZ; } - if (limbIndex == OBJECT_NIW_LIMB_07) { - rot->x += (s16)this->unk_2A4; - rot->y += (s16)this->unk_2A0; - rot->z += (s16)this->unk_29C; + if (limbIndex == NIW_LIMB_LEFT_WING_ROOT) { + rot->x += (s16)this->leftWingRotX; + rot->y += (s16)this->leftWingRotY; + rot->z += (s16)this->leftWingRotZ; } return false; } diff --git a/src/overlays/actors/ovl_En_Attack_Niw/z_en_attack_niw.h b/src/overlays/actors/ovl_En_Attack_Niw/z_en_attack_niw.h index 4d3243ef5c..c4dcaf8d0e 100644 --- a/src/overlays/actors/ovl_En_Attack_Niw/z_en_attack_niw.h +++ b/src/overlays/actors/ovl_En_Attack_Niw/z_en_attack_niw.h @@ -11,49 +11,52 @@ typedef void (*EnAttackNiwActionFunc)(struct EnAttackNiw*, GlobalContext*); typedef struct EnAttackNiw { /* 0x000 */ Actor actor; /* 0x144 */ SkelAnime skelAnime; - /* 0x188 */ Vec3s jointTable[OBJECT_NIW_LIMB_MAX]; - /* 0x1E8 */ Vec3s morphTable[OBJECT_NIW_LIMB_MAX]; + /* 0x188 */ Vec3s jointTable[NIW_LIMB_MAX]; + /* 0x1E8 */ Vec3s morphTable[NIW_LIMB_MAX]; /* 0x248 */ EnAttackNiwActionFunc actionFunc; - /* 0x24C */ s16 unk_24C; - /* 0x24E */ s16 unk_24E; - /* 0x250 */ s16 unk_250; - /* 0x252 */ s16 unk_252; - /* 0x254 */ s16 unk_254; - /* 0x256 */ s16 unk_256; - /* 0x258 */ s16 unk_258; - /* 0x25A */ s16 unk_25A; - /* 0x25C */ f32 unk_25C; - /* 0x260 */ f32 unk_260; - /* 0x264 */ f32 unk_264; - /* 0x268 */ UNK_TYPE1 unk268[8]; - /* 0x270 */ f32 unk_270; - /* 0x274 */ f32 unk_274; - /* 0x278 */ f32 unk_278; - /* 0x27C */ f32 unk_27C; - /* 0x280 */ f32 unk_280; - /* 0x284 */ s16 unk_284; - /* 0x286 */ s16 unk_286; - /* 0x288 */ UNK_TYPE1 unk288[2]; - /* 0x28A */ s16 unk_28A; - /* 0x28C */ UNK_TYPE1 unk28C[4]; - /* 0x290 */ Vec3f unk_290; - /* 0x29C */ f32 unk_29C; - /* 0x2A0 */ f32 unk_2A0; - /* 0x2A4 */ f32 unk_2A4; - /* 0x2A8 */ f32 unk_2A8; - /* 0x2AC */ f32 unk_2AC; - /* 0x2B0 */ f32 unk_2B0; - /* 0x2B4 */ f32 unk_2B4; - /* 0x2B8 */ f32 unk_2B8; - /* 0x2BC */ UNK_TYPE1 unk2BC[0xC]; - /* 0x2C8 */ f32 unk_2C8; - /* 0x2CC */ f32 unk_2CC; - /* 0x2D0 */ UNK_TYPE1 unk2D0[4]; - /* 0x2D4 */ f32 unk_2D4; - /* 0x2D8 */ f32 unk_2D8; - /* 0x2DC */ f32 unk_2DC; + /* 0x24C */ s16 unkTimer24C; // control behavior in _UpdateRotations + /* 0x24E */ s16 unusedTimer24E; // set never read + /* 0x250 */ s16 unkTimer250; // control behavior in _UpdateRotations + /* 0x252 */ s16 hopTimer; + /* 0x254 */ s16 randomAngleChangeTimer; + /* 0x256 */ s16 crySfxTimer; + /* 0x258 */ s16 flutterSfxTimer; + /* 0x25A */ s16 unkTimer25A; // set to 50 in run at player, locks fly away without water? + /* 0x25C */ f32 targetBodyRotY; + /* 0x260 */ f32 targetRightWingRotZ; + /* 0x264 */ f32 targetLeftWingRotZ; + /* 0x268 */ f32 unusedRotations[2]; // in EnNiw this is an array of targetRot + /* 0x270 */ f32 targetRightWingRotY; + /* 0x274 */ f32 targetRightWingRotX; + /* 0x278 */ f32 targetLeftWingRotY; + /* 0x27C */ f32 targetLeftWingRotX; + /* 0x280 */ f32 targetHeadRotZ; + /* 0x284 */ s16 unusedCounter284; // incremented in _Update, never read + /* 0x286 */ s16 clearRotYToggleTimer; + /* 0x288 */ UNK_TYPE1 pad288[2]; + /* 0x28A */ s16 unkToggle28A; + /* 0x28C */ UNK_TYPE1 pad28C[4]; + /* 0x290 */ Vec3f randomTargetCenterOffset; // see EnAttackNiw_EnterViewFromOffscreen + /* 0x29C */ f32 leftWingRotZ; + /* 0x2A0 */ f32 leftWingRotY; + /* 0x2A4 */ f32 leftWingRotX; + /* 0x2A8 */ f32 rightWingRotZ; + /* 0x2AC */ f32 rightWingRotY; + /* 0x2B0 */ f32 rightWingRotX; + /* 0x2B4 */ f32 upperBodyRotY; + /* 0x2B8 */ f32 headRotZ; + /* 0x2BC */ UNK_TYPE1 pad2BC[0xC]; // unused rotations? + /* 0x2C8 */ f32 targetRotX; + /* 0x2CC */ f32 targetRotY; + /* 0x2D0 */ UNK_TYPE1 pad2D0[4]; + /* 0x2D4 */ f32 rotStep; + /* 0x2D8 */ f32 targetXZSpeed; + /* 0x2DC */ f32 targetHeight; // never set, but sent to Actor_SetFocus } EnAttackNiw; // size = 0x2E0 extern const ActorInit En_Attack_Niw_InitVars; + +#define ATTACK_NIW_REGULAR 0 // spawned by EnNiw + #endif // Z_EN_ATTACK_NIW_H diff --git a/src/overlays/actors/ovl_En_Hs/z_en_hs.c b/src/overlays/actors/ovl_En_Hs/z_en_hs.c index e15e3adb3c..5e886bcc01 100644 --- a/src/overlays/actors/ovl_En_Hs/z_en_hs.c +++ b/src/overlays/actors/ovl_En_Hs/z_en_hs.c @@ -18,8 +18,8 @@ void EnHs_Draw(Actor* thisx, GlobalContext* globalCtx); void func_80952FE0(EnHs* this, GlobalContext* globalCtx); void func_80953098(EnHs* this, GlobalContext* globalCtx); void func_80953180(EnHs* this, GlobalContext* globalCtx); -void func_809532C0(EnHs* this, GlobalContext* globalCtx); -void func_809532D0(EnHs* this, GlobalContext* globalCtx); +void EnHs_DoNothing(EnHs* this, GlobalContext* globalCtx); +void EnHs_SceneTransitToBunnyHoodDialogue(EnHs* this, GlobalContext* globalCtx); void func_80953354(EnHs* this, GlobalContext* globalCtx); void func_8095345C(EnHs* this, GlobalContext* globalCtx); @@ -61,12 +61,12 @@ void func_80952C50(EnHs* this, GlobalContext* globalCtx) { Player* player = GET_PLAYER(globalCtx); s32 i; - for (i = 0; i < ARRAY_COUNT(this->unk_2A4); i++) { - Math_Vec3f_Copy(&this->unk_2A4[i], &player->actor.world.pos); + for (i = 0; i < ARRAY_COUNT(this->nwcPos); i++) { + Math_Vec3f_Copy(&this->nwcPos[i], &player->actor.world.pos); } - this->actor.home.rot.x = 0; - this->actor.home.rot.z = 0; + this->actor.home.rot.x = 0; // reset adult transformed count + this->actor.home.rot.z = 0; // reset chick count } void EnHs_Init(Actor* thisx, GlobalContext* globalCtx) { @@ -74,17 +74,19 @@ void EnHs_Init(Actor* thisx, GlobalContext* globalCtx) { EnHs* this = THIS; ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 36.0f); - SkelAnime_InitFlex(globalCtx, &this->skelAnime, &object_hs_Skel_006260, &object_hs_Anim_0005C0, this->jointTable, - this->morphTable, OBJECT_HS_LIMB_MAX); - Animation_PlayLoop(&this->skelAnime, &object_hs_Anim_0005C0); + SkelAnime_InitFlex(globalCtx, &this->skelAnime, &gHsSkeleton, &gHsIdleAnim, this->jointTable, this->morphTable, + OBJECT_HS_LIMB_MAX); + Animation_PlayLoop(&this->skelAnime, &gHsIdleAnim); Collider_InitAndSetCylinder(globalCtx, &this->collider, &this->actor, &sCylinderInit); this->actor.colChkInfo.mass = MASS_IMMOVABLE; Actor_SetScale(&this->actor, 0.01f); this->actionFunc = func_8095345C; + if (globalCtx->curSpawn == 1) { this->actor.flags |= ACTOR_FLAG_10000; } - this->unk_2A0 = 0; + + this->stateFlags = 0; this->actor.targetMode = 6; func_80952C50(this, globalCtx); } @@ -102,56 +104,56 @@ void func_80952DFC(GlobalContext* globalCtx) { func_80151BB4(globalCtx, 0x10); } -void func_80952E50(Vec3f* dst, Vec3f src, f32 arg2) { - Vec3f sp1C; - f32 temp_f0; +void EnHs_UpdateChickPos(Vec3f* dst, Vec3f src, f32 offset) { + Vec3f diff; + f32 distance; - Math_Vec3f_Diff(&src, dst, &sp1C); + Math_Vec3f_Diff(&src, dst, &diff); - temp_f0 = SQ(sp1C.x) + SQ(sp1C.z); + distance = SQ(diff.x) + SQ(diff.z); // gets un-squared after we check if we are too close - if (SQ(arg2) > temp_f0) { + if (SQ(offset) > distance) { return; } - temp_f0 = sqrtf(temp_f0); - sp1C.x *= (temp_f0 - arg2) / temp_f0; - sp1C.z *= (temp_f0 - arg2) / temp_f0; + distance = sqrtf(distance); + diff.x *= (distance - offset) / distance; + diff.z *= (distance - offset) / distance; - dst->x += sp1C.x; - dst->z += sp1C.z; + dst->x += diff.x; + dst->z += diff.z; } void func_80952F00(EnHs* this, GlobalContext* globalCtx) { Player* player = GET_PLAYER(globalCtx); s32 i; - f32 phi_f20; + f32 offset; - if (this->actor.home.rot.z >= 20) { - phi_f20 = 15.0f; + if (this->actor.home.rot.z >= 20) { // current chick count >= 10 + offset = 15.0f; } else { - phi_f20 = 10.0f; + offset = 10.0f; } - func_80952E50(&this->unk_2A4[0], player->actor.world.pos, phi_f20); + EnHs_UpdateChickPos(&this->nwcPos[0], player->actor.world.pos, offset); - for (i = 1; i < ARRAY_COUNT(this->unk_2A4); i++) { - func_80952E50(&this->unk_2A4[i], this->unk_2A4[i - 1], phi_f20); + for (i = 1; i < ARRAY_COUNT(this->nwcPos); i++) { + EnHs_UpdateChickPos(&this->nwcPos[i], this->nwcPos[i - 1], offset); } } void func_80952FE0(EnHs* this, GlobalContext* globalCtx) { - if (this->unk_2A2 < 40) { - Math_SmoothStepToS(&this->unk_294.y, 0x1F40, 6, 0x1838, 0x64); - } else if (this->unk_2A2 < 80) { - Math_SmoothStepToS(&this->unk_294.y, -0x1F40, 6, 0x1838, 0x64); + if (this->stateTimer < 40) { + Math_SmoothStepToS(&this->headRot.y, 0x1F40, 6, 0x1838, 0x64); + } else if (this->stateTimer < 80) { + Math_SmoothStepToS(&this->headRot.y, -0x1F40, 6, 0x1838, 0x64); } else { this->actionFunc = func_80953180; - this->unk_2A0 &= ~4; + this->stateFlags &= ~4; func_80151938(globalCtx, 0x33F6); func_80952DFC(globalCtx); } - this->unk_2A2++; + this->stateTimer++; } void func_80953098(EnHs* this, GlobalContext* globalCtx) { @@ -159,10 +161,10 @@ void func_80953098(EnHs* this, GlobalContext* globalCtx) { this->actor.parent = NULL; this->actionFunc = func_8095345C; this->actor.flags |= ACTOR_FLAG_10000; - this->unk_2A0 |= 0x10; + this->stateFlags |= 0x10; func_800B8500(&this->actor, globalCtx, 1000.0f, 1000.0f, -1); } else { - this->unk_2A0 |= 8; + this->stateFlags |= 8; if (INV_CONTENT(ITEM_MASK_BUNNY) == ITEM_MASK_BUNNY) { Actor_PickUp(&this->actor, globalCtx, GI_RUPEE_RED, 10000.0f, 50.0f); } else { @@ -174,31 +176,31 @@ void func_80953098(EnHs* this, GlobalContext* globalCtx) { void func_80953180(EnHs* this, GlobalContext* globalCtx) { if ((Message_GetState(&globalCtx->msgCtx) == 5) && Message_ShouldAdvance(globalCtx)) { switch (globalCtx->msgCtx.currentTextId) { - case 0x33F4: - case 0x33F6: + case 0x33F4: // text: laughing that they are all roosters (!) + case 0x33F6: // text: Grog regrets not being able to see his chicks reach adult hood func_801477B4(globalCtx); this->actionFunc = func_8095345C; break; - case 0x33F7: + case 0x33F7: // text: notice his chicks are grown up, happy, wants to give you bunny hood this->actor.flags &= ~ACTOR_FLAG_10000; func_801477B4(globalCtx); this->actionFunc = func_80953098; func_80953098(this, globalCtx); break; - case 0x33F9: + case 0x33F9: // text: laughing that they are all roosters (.) this->actor.flags &= ~ACTOR_FLAG_10000; func_801477B4(globalCtx); this->actionFunc = func_8095345C; break; - case 0x33F5: + case 0x33F5: // He heard from his gramps (?) the moon is going to fall globalCtx->msgCtx.unk11F10 = 0; this->actionFunc = func_80952FE0; - this->unk_2A2 = 0; - this->unk_294.z = 0; - this->unk_2A0 |= 4; + this->stateTimer = 0; + this->headRot.z = 0; + this->stateFlags |= 4; break; default: @@ -209,34 +211,34 @@ void func_80953180(EnHs* this, GlobalContext* globalCtx) { } } -void func_809532C0(EnHs* this, GlobalContext* globalCtx) { +void EnHs_DoNothing(EnHs* this, GlobalContext* globalCtx) { } -void func_809532D0(EnHs* this, GlobalContext* globalCtx) { - if (DECR(this->unk_2A2) == 0) { - globalCtx->nextEntranceIndex = globalCtx->setupExitList[ENHS_GET_F(&this->actor)]; +void EnHs_SceneTransitToBunnyHoodDialogue(EnHs* this, GlobalContext* globalCtx) { + if (DECR(this->stateTimer) == 0) { + globalCtx->nextEntranceIndex = globalCtx->setupExitList[HS_GET_EXIT_INDEX(&this->actor)]; globalCtx->sceneLoadFlag = 0x14; gSaveContext.save.weekEventReg[25] |= 8; - this->actionFunc = func_809532C0; + this->actionFunc = EnHs_DoNothing; } } void func_80953354(EnHs* this, GlobalContext* globalCtx) { if (!Play_InCsMode(globalCtx)) { func_800B7298(globalCtx, &this->actor, 7); - this->actionFunc = func_809532D0; + this->actionFunc = EnHs_SceneTransitToBunnyHoodDialogue; } } void func_809533A0(EnHs* this, GlobalContext* globalCtx) { u16 sp1E; - if ((globalCtx->curSpawn == 1) && !(this->unk_2A0 & 0x20)) { + if ((globalCtx->curSpawn == 1) && !(this->stateFlags & 0x20)) { sp1E = 0x33F7; - this->unk_2A0 |= 0x20; - } else if (this->unk_2A0 & 0x10) { + this->stateFlags |= 0x20; + } else if (this->stateFlags & 0x10) { sp1E = 0x33F9; - this->unk_2A0 &= ~0x10; + this->stateFlags &= ~0x10; } else if (gSaveContext.save.weekEventReg[25] & 8) { sp1E = 0x33F4; } else { @@ -254,21 +256,21 @@ void func_8095345C(EnHs* this, GlobalContext* globalCtx) { if (Actor_ProcessTalkRequest(&this->actor, &globalCtx->state)) { this->actionFunc = func_80953180; func_809533A0(this, globalCtx); - if (this->unk_2A0 & 8) { + if (this->stateFlags & 8) { func_80952DFC(globalCtx); - this->unk_2A0 &= ~8; + this->stateFlags &= ~8; } - } else if (this->actor.home.rot.x >= 20) { + } else if (this->actor.home.rot.x >= 20) { // chicks turned adult >= 10 this->actionFunc = func_80953354; - this->unk_2A2 = 40; + this->stateTimer = 40; } else if (CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_10000)) { func_800B8500(&this->actor, globalCtx, 1000.0f, 1000.0f, -1); - this->unk_2A0 |= 1; + this->stateFlags |= 1; } else if ((this->actor.xzDistToPlayer < 120.0f) && Player_IsFacingActor(&this->actor, 0x2000, globalCtx)) { func_800B8614(&this->actor, globalCtx, 130.0f); - this->unk_2A0 |= 1; + this->stateFlags |= 1; } else { - this->unk_2A0 &= ~1; + this->stateFlags &= ~1; } } @@ -290,17 +292,17 @@ void EnHs_Update(Actor* thisx, GlobalContext* globalCtx) { func_80952F00(this, globalCtx); - if (this->unk_2A0 & 4) { - Math_SmoothStepToS(&this->unk_294.x, 0, 6, 0x1838, 0x64); - Math_SmoothStepToS(&this->unk_29A.x, 0, 6, 0x1838, 0x64); - Math_SmoothStepToS(&this->unk_29A.y, 0, 6, 0x1838, 0x64); - } else if (this->unk_2A0 & 1) { - func_800E9250(globalCtx, &this->actor, &this->unk_294, &this->unk_29A, this->actor.focus.pos); + if (this->stateFlags & 4) { + Math_SmoothStepToS(&this->headRot.x, 0, 6, 0x1838, 0x64); + Math_SmoothStepToS(&this->unusedRot.x, 0, 6, 0x1838, 0x64); + Math_SmoothStepToS(&this->unusedRot.y, 0, 6, 0x1838, 0x64); + } else if (this->stateFlags & 1) { + func_800E9250(globalCtx, &this->actor, &this->headRot, &this->unusedRot, this->actor.focus.pos); } else { - Math_SmoothStepToS(&this->unk_294.x, 0x3200, 6, 0x1838, 0x64); - Math_SmoothStepToS(&this->unk_294.y, 0, 6, 0x1838, 0x64); - Math_SmoothStepToS(&this->unk_29A.x, 0, 6, 0x1838, 0x64); - Math_SmoothStepToS(&this->unk_29A.y, 0, 6, 0x1838, 0x64); + Math_SmoothStepToS(&this->headRot.x, 0x3200, 6, 0x1838, 0x64); + Math_SmoothStepToS(&this->headRot.y, 0, 6, 0x1838, 0x64); + Math_SmoothStepToS(&this->unusedRot.x, 0, 6, 0x1838, 0x64); + Math_SmoothStepToS(&this->unusedRot.y, 0, 6, 0x1838, 0x64); } } @@ -308,29 +310,33 @@ s32 EnHs_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, EnHs* this = THIS; switch (limbIndex) { - case OBJECT_HS_LIMB_09: - rot->x += this->unk_294.y; - rot->z += this->unk_294.x; + case HS_LIMB_HEAD: + rot->x += this->headRot.y; + rot->z += this->headRot.x; break; - case OBJECT_HS_LIMB_0A: - rot->x += this->unk_294.y; - rot->z += this->unk_294.x; + case HS_LIMB_HAIR_SPIKES: + rot->x += this->headRot.y; + rot->z += this->headRot.x; break; - case OBJECT_HS_LIMB_0B: + case HS_LIMB_HIDDEN_HAIR: + // for some reason this hair is always removed here in the Override limb + // if you do re-enable, make sure you add the head rot like above *dList = NULL; return false; + // these two limbs both have empty enddisplaylist, they do nothing + // at the same time (params == HS_TYPE_UNK1) is always false, because vanilla params is 0xFE01 case OBJECT_HS_LIMB_0C: - if (this->actor.params == ENHS_1) { + if (this->actor.params == HS_TYPE_UNK1) { *dList = NULL; return false; } break; case OBJECT_HS_LIMB_0D: - if (this->actor.params == ENHS_1) { + if (this->actor.params == HS_TYPE_UNK1) { *dList = NULL; return false; } @@ -342,7 +348,7 @@ s32 EnHs_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, void EnHs_PostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx) { EnHs* this = THIS; - if (limbIndex == OBJECT_HS_LIMB_09) { + if (limbIndex == HS_LIMB_HEAD) { Matrix_MultiplyVector3fByState(&D_8095393C, &this->actor.focus.pos); } } diff --git a/src/overlays/actors/ovl_En_Hs/z_en_hs.h b/src/overlays/actors/ovl_En_Hs/z_en_hs.h index 0a50ee3607..62fc1d2a14 100644 --- a/src/overlays/actors/ovl_En_Hs/z_en_hs.h +++ b/src/overlays/actors/ovl_En_Hs/z_en_hs.h @@ -8,9 +8,17 @@ struct EnHs; typedef void (*EnHsActionFunc)(struct EnHs*, GlobalContext*); -#define ENHS_GET_F(thisx) ((thisx)->params & 0xF) +#define HS_GET_EXIT_INDEX(thisx) ((thisx)->params & 0xF) -#define ENHS_1 1 +#define HS_TYPE_UNK1 1 + +// params mystery: Vanilla Grog is 0xFE01 +// 0xFE00 space is never checked in Grog code +// at the same time, type UNK1 is only checked directly with params == 1, no &F +// so HS_TYPE_UNK1 is never valid and is unused, as 0xFE00 is still present even if its not doing anything else + +// The count of [chicks following the player] is stored in [this->actor.home.rot.z] (incremented by 2) +// The count of [chicks transformed into adult] is stored in [this->actor.home.rot.x] (incremented by 2) typedef struct EnHs { /* 0x0000 */ Actor actor; @@ -18,11 +26,11 @@ typedef struct EnHs { /* 0x0190 */ SkelAnime skelAnime; /* 0x01D4 */ Vec3s jointTable[OBJECT_HS_LIMB_MAX]; /* 0x0234 */ Vec3s morphTable[OBJECT_HS_LIMB_MAX]; - /* 0x0294 */ Vec3s unk_294; - /* 0x029A */ Vec3s unk_29A; - /* 0x02A0 */ u16 unk_2A0; - /* 0x02A2 */ s16 unk_2A2; - /* 0x02A4 */ Vec3f unk_2A4[20]; + /* 0x0294 */ Vec3s headRot; + /* 0x029A */ Vec3s unusedRot; // probably not chest, as chest is same limb as lower body + /* 0x02A0 */ u16 stateFlags; + /* 0x02A2 */ s16 stateTimer; // reused for different actionFunc + /* 0x02A4 */ Vec3f nwcPos[20]; // actual chick position are even values, odd values seem to be extra values for smoother chain /* 0x0394 */ EnHsActionFunc actionFunc; } EnHs; // size = 0x398 diff --git a/src/overlays/actors/ovl_En_Niw/z_en_niw.c b/src/overlays/actors/ovl_En_Niw/z_en_niw.c index f6e398a33d..e3be9ae03d 100644 --- a/src/overlays/actors/ovl_En_Niw/z_en_niw.c +++ b/src/overlays/actors/ovl_En_Niw/z_en_niw.c @@ -5,7 +5,7 @@ */ #include "z_en_niw.h" -#include "objects/object_niw/object_niw.h" +#include "overlays/actors/ovl_En_Attack_Niw/z_en_attack_niw.h" #define FLAGS (ACTOR_FLAG_10 | ACTOR_FLAG_800000) @@ -30,12 +30,23 @@ void EnNiw_Held(EnNiw* this, GlobalContext* globalCtx); void EnNiw_UpdateFeather(EnNiw* this, GlobalContext* globalCtx); void EnNiw_DrawFeathers(EnNiw* this, GlobalContext* globalCtx); void EnNiw_CheckRage(EnNiw* this, GlobalContext* globalCtx); -void func_80891320(EnNiw* this, GlobalContext* globalCtx, s16 arg2); +void EnNiw_AnimateWingHead(EnNiw* this, GlobalContext* globalCtx, s16 animationState); void EnNiw_SpawnFeather(EnNiw* this, Vec3f* pos, Vec3f* vel, Vec3f* accel, f32 scale); -// turned on during cucco storm, but not read by anything? -// maybe read by En_Attack_Niw -s16 D_80893460 = false; +s16 sCuccoStormActive = false; + +// why wouldnt they just use actionFunc? +enum EnNiwState { + /* 0 */ NIW_STATE_IDLE, + /* 1 */ NIW_STATE_ANGRY1, // 1/2/3 are stages of summoning cucco storm + /* 2 */ NIW_STATE_ANGRY2, + /* 3 */ NIW_STATE_ANGRY3, + /* 4 */ NIW_STATE_HELD, + /* 5 */ NIW_STATE_FALLING, + /* 6 */ NIW_STATE_SWIMMING, + /* 7 */ NIW_STATE_RUNNING, + /* 8 */ NIW_STATE_HOPPING, +}; const ActorInit En_Niw_InitVars = { ACTOR_EN_NIW, @@ -49,15 +60,11 @@ const ActorInit En_Niw_InitVars = { (ActorFunc)EnNiw_Draw, }; -static f32 D_80893484[] = { - 5000.0f, - -5000.0f, -}; -static f32 D_80893486[] = { - 5000.0f, - 3000.0f, - 4000.0f, -}; +static f32 sHeadRotations[] = { 5000.0f, -5000.0f }; + +static f32 sRunningAngles[] = { 5000.0f, 3000.0f }; + +static f32 sUnusedValue = 4000.0f; static ColliderCylinderInit sCylinderInit = { { @@ -109,8 +116,8 @@ void EnNiw_Init(Actor* thisx, GlobalContext* globalCtx) { EnNiw* this = THIS; Vec3f dTemp = D_808934C4; - if (this->actor.params < 0) { // all neg values become zero - this->actor.params = ENNIW_TYPE_REGULAR; + if (this->actor.params < 0) { // all scene spawned cucco are (-1) + this->actor.params = NIW_TYPE_REGULAR; } Math_Vec3f_Copy(&this->unk2BC, &dTemp); @@ -122,32 +129,36 @@ void EnNiw_Init(Actor* thisx, GlobalContext* globalCtx) { ActorShape_Init(&thisx->shape, 0.0f, ActorShadow_DrawCircle, 25.0f); - SkelAnime_InitFlex(globalCtx, &this->skelanime, &object_niw_Skel_002530, &object_niw_Anim_0000E8, this->jointTable, - this->morphTable, ENNIW_LIMBCOUNT); + SkelAnime_InitFlex(globalCtx, &this->skelanime, &gNiwSkeleton, &gNiwIdleAnim, this->jointTable, this->morphTable, + NIW_LIMB_MAX); Math_Vec3f_Copy(&this->unk2A4, &this->actor.world.pos); Math_Vec3f_Copy(&this->unk2B0, &this->actor.world.pos); this->unk308 = 10.0f; Actor_SetScale(&this->actor, 0.01f); - if (this->niwType == ENNIW_TYPE_UNK1) { + if (this->niwType == NIW_TYPE_UNK1) { + // @Bug this unused variant is broken and crashes on spawn (EnNiw_Update expects a parent, NULL) + // if modified to change niwType to TYPE_REGULAR here, new size is smaller than normal + // theory: was meant to be a small hand held cucco for grog to show the player Actor_SetScale(&this->actor, (BREG(86) / 10000.0f) + 0.004f); } // random health between 10-20 + // health at zero triggers cucco storm not death this->actor.colChkInfo.health = Rand_ZeroFloat(9.99f) + 10.0f; this->actor.colChkInfo.mass = MASS_IMMOVABLE; - if (this->niwType == ENNIW_TYPE_REGULAR) { + if (this->niwType == NIW_TYPE_REGULAR) { Collider_InitAndSetCylinder(globalCtx, &this->collider, &this->actor, &sCylinderInit); } - if (this->niwType == ENNIW_TYPE_UNK2) { - Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_CHICKEN_CRY_M); // crow + if (this->niwType == NIW_TYPE_HELD) { + Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_CHICKEN_CRY_M); this->sfxTimer1 = 30; - this->unkTimer250 = 30; + this->heldTimer = 30; this->actor.flags &= ~ACTOR_FLAG_1; // targetable OFF - this->unknownState28E = 4; + this->niwState = NIW_STATE_HELD; this->actionFunc = EnNiw_Held; this->actor.speedXZ = 0.0f; this->unk2BC.z = 0.0f; @@ -161,105 +172,119 @@ void EnNiw_Init(Actor* thisx, GlobalContext* globalCtx) { void EnNiw_Destroy(Actor* thisx, GlobalContext* globalCtx) { EnNiw* this = THIS; - if (this->niwType == ENNIW_TYPE_REGULAR) { + if (this->niwType == NIW_TYPE_REGULAR) { Collider_DestroyCylinder(globalCtx, &this->collider); } } -void func_80891320(EnNiw* this, GlobalContext* globalCtx, s16 arg2) { - f32 tempOne = 1.0f; +/** + * Summary: instead of using SkelAnime animations, Niw modifies head+wings directly to create animations + * + * AttackNiw has a copy of this function that it barely uses + */ +void EnNiw_AnimateWingHead(EnNiw* this, GlobalContext* globalCtx, s16 animationState) { + f32 tempOne = 1.0f; // hopefully fake match, but no luck if (this->unkTimer24C == 0) { - if (arg2 == 0) { - this->unk264[0] = 0.0f; + // targetLimbRots[0] is bodyRotY + if (animationState == NIW_ANIMATION_STILL) { + this->targetLimbRots[0] = 0.0f; } else { - this->unk264[0] = (-10000.0f) * tempOne; + this->targetLimbRots[0] = -10000.0f * tempOne; } + this->unk292 += 1; this->unkTimer24C = 3; if ((this->unk292 % 2) == 0) { - this->unk264[0] = 0.0f; - if (arg2 == 0) { + this->targetLimbRots[0] = 0.0f; + if (animationState == NIW_ANIMATION_STILL) { this->unkTimer24C = Rand_ZeroFloat(30.0f); } } } + if (this->unkTimer24E == 0) { - this->unk296++; - this->unk296 &= 1; - switch (arg2) { - case 0: - this->unk264[2] = 0.0f; - this->unk264[1] = 0.0f; + this->unkToggle296++; + this->unkToggle296 &= 1; + + switch (animationState) { + case NIW_ANIMATION_STILL: + this->targetLimbRots[2] = 0.0f; // both wingRotZ + this->targetLimbRots[1] = 0.0f; break; - case 1: + case NIW_ANIMATION_HEAD_PECKING: this->unkTimer24E = 3; - this->unk264[2] = 7000.0f * tempOne; - this->unk264[1] = 7000.0f * tempOne; - if (this->unk296 == 0) { - this->unk264[2] = 0.0f; - this->unk264[1] = 0.0f; + this->targetLimbRots[2] = 7000.0f * tempOne; // both wingRotZ + this->targetLimbRots[1] = 7000.0f * tempOne; + if (this->unkToggle296 == 0) { + this->targetLimbRots[2] = 0.0f; // both wingRotZ + this->targetLimbRots[1] = 0.0f; } break; - case 2: + + case NIW_ANIMATION_PECKING_AND_WAVING: this->unkTimer24E = 2; - this->unk264[2] = -10000.0f; - this->unk264[1] = -10000.0f; - this->unk264[7] = 25000.0f; - this->unk264[5] = 25000.0f; - this->unk264[8] = 6000.0f; - this->unk264[6] = 6000.0f; - if (this->unk296 == 0) { - this->unk264[7] = 8000.0f; - this->unk264[5] = 8000.0f; + this->targetLimbRots[2] = -10000.0f; // both wingRotZ + this->targetLimbRots[1] = -10000.0f; + this->targetLimbRots[7] = 25000.0f; // both wingRotY + this->targetLimbRots[5] = 25000.0f; + this->targetLimbRots[8] = 6000.0f; // both wingRotX + this->targetLimbRots[6] = 6000.0f; + if (this->unkToggle296 == 0) { + this->targetLimbRots[7] = 8000.0f; // both wingRotY + this->targetLimbRots[5] = 8000.0f; } break; - case 3: + + case NIW_ANIMATION_PECKING_AND_FORFLAPPING: this->unkTimer24E = 2; - this->unk264[5] = 10000.0f; - this->unk264[7] = 10000.0f; - if (this->unk296 == 0) { - this->unk264[5] = 3000.0f; - this->unk264[7] = 3000.0f; + this->targetLimbRots[5] = 10000.0f; // both wingRotY + this->targetLimbRots[7] = 10000.0f; + if (this->unkToggle296 == 0) { + this->targetLimbRots[5] = 3000.0f; // both wingRotY + this->targetLimbRots[7] = 3000.0f; } break; - case 4: + + case NIW_ANIMATION_FREEZE: this->unkTimer24C = 5; break; - case 5: + + case NIW_ANIMATION_PECKING_SLOW_FORFLAPPING: this->unkTimer24E = 5; - this->unk264[5] = 14000.0f; - this->unk264[7] = 14000.0f; - if (this->unk296 == 0) { - this->unk264[5] = 10000.0f; - this->unk264[7] = 10000.0f; + this->targetLimbRots[5] = 14000.0f; // both wingRotY + this->targetLimbRots[7] = 14000.0f; + if (this->unkToggle296 == 0) { + this->targetLimbRots[5] = 10000.0f; // both wingRotY + this->targetLimbRots[7] = 10000.0f; } break; } } - if (this->unk264[9] != this->limbFRot) { - Math_ApproachF(&this->limbFRot, this->unk264[9], 0.5f, 4000.0f); + + if (this->targetLimbRots[9] != this->headRotY) { + Math_ApproachF(&this->headRotY, this->targetLimbRots[9], 0.5f, 4000.0f); } - if (this->unk264[0] != this->limbDRot) { - Math_ApproachF(&this->limbDRot, this->unk264[0], 0.5f, 4000.0f); + if (this->targetLimbRots[0] != this->upperBodyRotY) { + Math_ApproachF(&this->upperBodyRotY, this->targetLimbRots[0], 0.5f, 4000.0f); } - if (this->unk264[2] != this->limb7Rotz) { - Math_ApproachF(&this->limb7Rotz, this->unk264[2], 0.8f, 7000.0f); + if (this->targetLimbRots[2] != this->leftWingRotZ) { + Math_ApproachF(&this->leftWingRotZ, this->targetLimbRots[2], 0.8f, 7000.0f); } - if (this->unk264[7] != this->limb7Roty) { - Math_ApproachF(&this->limb7Roty, this->unk264[7], 0.8f, 7000.0f); + if (this->targetLimbRots[7] != this->leftWingRotY) { + Math_ApproachF(&this->leftWingRotY, this->targetLimbRots[7], 0.8f, 7000.0f); } - if (this->unk264[8] != this->limb7Rotx) { - Math_ApproachF(&this->limb7Rotx, this->unk264[8], 0.8f, 7000.0f); + if (this->targetLimbRots[8] != this->leftWingRotX) { + Math_ApproachF(&this->leftWingRotX, this->targetLimbRots[8], 0.8f, 7000.0f); } - if (this->unk264[1] != this->limbBRotz) { - Math_ApproachF(&this->limbBRotz, this->unk264[1], 0.8f, 7000.0f); + if (this->targetLimbRots[1] != this->rightWingRotZ) { + Math_ApproachF(&this->rightWingRotZ, this->targetLimbRots[1], 0.8f, 7000.0f); } - if (this->unk264[5] != this->limbBRoty) { - Math_ApproachF(&this->limbBRoty, this->unk264[5], 0.8f, 7000.0f); + if (this->targetLimbRots[5] != this->rightWingRotY) { + Math_ApproachF(&this->rightWingRotY, this->targetLimbRots[5], 0.8f, 7000.0f); } - if (this->unk264[6] != this->limbBRotx) { - Math_ApproachF(&this->limbBRotx, this->unk264[6], 0.8f, 7000.0f); + if (this->targetLimbRots[6] != this->rightWingRotX) { + Math_ApproachF(&this->rightWingRotX, this->targetLimbRots[6], 0.8f, 7000.0f); } } @@ -270,7 +295,7 @@ void EnNiw_SpawnAttackNiw(EnNiw* this, GlobalContext* globalCtx) { Vec3f newNiwPos; Actor* attackNiw; - if ((this->unkTimer252 == 0) && (this->unk290 < 7)) { + if (this->attackNiwSpawnTimer == 0 && this->attackNiwCount < 7) { xView = globalCtx->view.at.x - globalCtx->view.eye.x; yView = globalCtx->view.at.y - globalCtx->view.eye.y; zView = globalCtx->view.at.z - globalCtx->view.eye.z; @@ -278,54 +303,57 @@ void EnNiw_SpawnAttackNiw(EnNiw* this, GlobalContext* globalCtx) { newNiwPos.y = randPlusMinusPoint5Scaled(0.3f) + (globalCtx->view.eye.y + 50.0f + (yView * 0.5f)); newNiwPos.z = ((Rand_ZeroOne() - 0.5f) * zView) + globalCtx->view.eye.z; attackNiw = Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_EN_ATTACK_NIW, newNiwPos.x, - newNiwPos.y, newNiwPos.z, 0, 0, 0, 0); + newNiwPos.y, newNiwPos.z, 0, 0, 0, ATTACK_NIW_REGULAR); - if (attackNiw) { - this->unk290++; - this->unkTimer252 = 10; + if (attackNiw != NULL) { + this->attackNiwCount++; + this->attackNiwSpawnTimer = 10; } } } -void func_808917F8(EnNiw* this, GlobalContext* globalCtx, s32 arg2) { - f32 phi_f2; +void EnNiw_UpdateRunning(EnNiw* this, GlobalContext* globalCtx, s32 isStormCucco) { + f32 runningDirection; f32 targetRotY; - f32* D_8089348CPtr = D_80893486; + f32* runningAngles = sRunningAngles; - if (this->unkTimer250 == 0) { - this->unkTimer250 = 3; - if (this->actor.bgCheckFlags & 1) { - // hit floor - this->actor.velocity.y = 3.5f; // hop up? + if (this->hopTimer == 0) { + this->hopTimer = 3; + if (this->actor.bgCheckFlags & 1) { // hit floor + this->actor.velocity.y = 3.5f; // hopping up while running away } } - if (this->unkTimer252 == 0) { - this->unk29A++; - this->unk29A &= 1; - this->unkTimer252 = 5; + + if (this->runningDirectionTimer == 0) { + this->isRunningRight++; + this->isRunningRight &= 1; + this->runningDirectionTimer = 5; } - if (this->unk29A == 0) { - phi_f2 = D_8089348CPtr[arg2]; + + if (this->isRunningRight == false) { + runningDirection = runningAngles[isStormCucco]; } else { - phi_f2 = -D_8089348CPtr[arg2]; + runningDirection = -runningAngles[isStormCucco]; } - if (arg2 == 1 && (this->unkTimer254 == 0 || (this->actor.bgCheckFlags & 8))) { - this->unkTimer254 = 150; + + if (isStormCucco == true && + (this->runAwayTimer == 0 || (this->actor.bgCheckFlags & 8))) { // bgCheckFlags 8: hit a wall + this->runAwayTimer = 150; if (this->yawTimer == 0) { this->yawTimer = 70; this->yawTowardsPlayer = this->actor.yawTowardsPlayer; } } - targetRotY = this->yawTowardsPlayer + phi_f2; + + targetRotY = this->yawTowardsPlayer + runningDirection; Math_SmoothStepToS(&this->actor.world.rot.y, targetRotY, 3, this->unk300, 0); Math_ApproachF(&this->unk300, 3000.0f, 1.0f, 500.0f); - func_80891320(this, globalCtx, 5); + EnNiw_AnimateWingHead(this, globalCtx, NIW_ANIMATION_PECKING_SLOW_FORFLAPPING); } void EnNiw_SetupIdle(EnNiw* this) { - Animation_Change(&this->skelanime, &object_niw_Anim_0000E8, 1.0f, 0.0f, - Animation_GetLastFrame(&object_niw_Anim_0000E8), 0, -10.0f); - this->unknownState28E = 0; + Animation_Change(&this->skelanime, &gNiwIdleAnim, 1.0f, 0.0f, Animation_GetLastFrame(&gNiwIdleAnim), 0, -10.0f); + this->niwState = NIW_STATE_IDLE; this->actionFunc = EnNiw_Idle; } @@ -334,40 +362,39 @@ void EnNiw_Idle(EnNiw* this, GlobalContext* globalCtx) { f32 posZ2; f32 posX1 = randPlusMinusPoint5Scaled(100.0f); f32 posZ1 = randPlusMinusPoint5Scaled(100.0f); - s16 s16tmp; + s16 nextAnimation; - if (this->niwType == ENNIW_TYPE_REGULAR) { - if (Actor_HasParent(&this->actor, globalCtx)) { - // picked up + if (this->niwType == NIW_TYPE_REGULAR) { + if (Actor_HasParent(&this->actor, globalCtx)) { // picked up Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_CHICKEN_CRY_M); // crow this->sfxTimer1 = 30; - this->unkTimer250 = 30; + this->heldTimer = 30; this->actor.flags &= ~ACTOR_FLAG_1; // targetable OFF - this->unknownState28E = 4; + this->niwState = NIW_STATE_HELD; this->actor.speedXZ = 0.0f; this->actionFunc = EnNiw_Held; return; } else { Actor_LiftActor(&this->actor, globalCtx); } - } else { - this->unkTimer252 = 10; + } else { // NIW_TYPE_UNK1 || NIW_TYPE_HELD + this->unkIdleTimer2 = 10; } - s16tmp = 0; - if (this->unkTimer252 != 0) { + nextAnimation = NIW_ANIMATION_STILL; // probably a scoped variable here, where their scope was different + if (this->unkIdleTimer2 != 0) { if (Rand_ZeroFloat(3.99f) < 1.0f) { - this->unk2EA++; - this->unk2EA &= 1; + this->headRotationToggle++; + this->headRotationToggle &= 1; } - Math_ApproachF(&this->unk264[9], D_80893484[this->unk2EA], 0.5f, 4000.0f); + + Math_ApproachF(&this->targetLimbRots[9], sHeadRotations[this->headRotationToggle], 0.5f, 4000.0f); // head rot } - if ((this->unkTimer252 == 0) && (this->unkTimer250 == 0)) { + if (this->unkIdleTimer2 == 0 && this->unkIdleTimer == 0) { this->unk298++; - if (this->unk298 > 7) { - this->unkTimer252 = Rand_ZeroFloat(30.0f); + this->unkIdleTimer2 = Rand_ZeroFloat(30.0f); this->unk298 = Rand_ZeroFloat(3.99f); if (posX1 < 0.0f) { @@ -385,17 +412,17 @@ void EnNiw_Idle(EnNiw* this, GlobalContext* globalCtx) { this->unk2B0.z = this->unk2A4.z + posZ1; } else { - this->unkTimer250 = 4; - if (this->actor.bgCheckFlags & 1) { + this->unkIdleTimer = 4; + if (this->actor.bgCheckFlags & 1) { // hit floor this->actor.speedXZ = 0.0f; - this->actor.velocity.y = 3.5f; + this->actor.velocity.y = 3.5f; // hopping up and down } } } - if (this->unkTimer250 != 0) { - Math_ApproachZeroF(&this->unk264[9], 0.5f, 4000.0f); - s16tmp = 1; + if (this->unkIdleTimer != 0) { + Math_ApproachZeroF(&this->targetLimbRots[9], 0.5f, 4000.0f); // head rot + nextAnimation = NIW_ANIMATION_HEAD_PECKING; Math_ApproachF(&this->actor.world.pos.x, this->unk2B0.x, 1.0f, this->unk300); Math_ApproachF(&this->actor.world.pos.z, this->unk2B0.z, 1.0f, this->unk300); Math_ApproachF(&this->unk300, 3.0f, 1.0f, 0.3f); @@ -411,33 +438,34 @@ void EnNiw_Idle(EnNiw* this, GlobalContext* globalCtx) { } if ((posX2 == 0.0f) && (posZ2 == 0.0f)) { - this->unkTimer250 = 0; + this->unkIdleTimer = 0; this->unk298 = 7; } Math_SmoothStepToS(&this->actor.world.rot.y, Math_Atan2S(posX2, posZ2), 3, this->unk304, 0); Math_ApproachF(&this->unk304, 10000.0f, 1.0f, 1000.0f); } - func_80891320(this, globalCtx, s16tmp); + + EnNiw_AnimateWingHead(this, globalCtx, nextAnimation); } void EnNiw_Held(EnNiw* this, GlobalContext* globalCtx) { Vec3f vec3fcopy = D_808934DC; s16 rotZ; - if (this->unkTimer250 == 0) { + if (this->heldTimer == 0) { this->unk29E = 2; - this->unkTimer250 = (s32)(Rand_ZeroFloat(1.0f) * 10.0f) + 10; + this->heldTimer = (s32)(Rand_ZeroFloat(1.0f) * 10.0f) + 10; } this->actor.shape.rot.x = (s16)randPlusMinusPoint5Scaled(5000.0f) + this->actor.world.rot.x; this->actor.shape.rot.y = (s16)randPlusMinusPoint5Scaled(5000.0f) + this->actor.world.rot.y; this->actor.shape.rot.z = (s16)randPlusMinusPoint5Scaled(5000.0f) + this->actor.world.rot.z; - if (this->niwType == ENNIW_TYPE_REGULAR) { + if (this->niwType == NIW_TYPE_REGULAR) { if (Actor_HasNoParent(&this->actor, globalCtx)) { this->actor.shape.rot.z = 0; rotZ = this->actor.shape.rot.z; - this->unknownState28E = 5; + this->niwState = NIW_STATE_FALLING; this->actor.flags |= ACTOR_FLAG_1; // targetable ON this->actionFunc = EnNiw_Thrown; this->actor.shape.rot.y = rotZ; @@ -449,9 +477,9 @@ void EnNiw_Held(EnNiw* this, GlobalContext* globalCtx) { this->actor.velocity.y = 8.0f; this->actor.speedXZ = 4.0f; this->actor.gravity = -2.0f; - this->unknownState28E = 5; + this->niwState = NIW_STATE_FALLING; this->unk2EC = 0; - this->niwType = ENNIW_TYPE_REGULAR; + this->niwType = NIW_TYPE_REGULAR; this->actor.shape.rot.y = rotZ; this->actor.shape.rot.x = rotZ; Collider_InitAndSetCylinder(globalCtx, &this->collider, &this->actor, &sCylinderInit); @@ -459,29 +487,29 @@ void EnNiw_Held(EnNiw* this, GlobalContext* globalCtx) { this->actor.flags |= ACTOR_FLAG_1; // targetable ON this->actionFunc = EnNiw_Thrown; } - func_80891320(this, globalCtx, 2); + + EnNiw_AnimateWingHead(this, globalCtx, NIW_ANIMATION_PECKING_AND_WAVING); } -// action function: recently thrown, and also hopping on the floor void EnNiw_Thrown(EnNiw* this, GlobalContext* globalCtx) { if (this->unk2EC == 0) { - if (this->actor.bgCheckFlags & 1) { + if (this->actor.bgCheckFlags & 1) { // hit floor this->unk2EC = 1; - this->unkTimer252 = 80; // hop timer + this->hoppingTimer = 80; // hop timer this->actor.speedXZ = 0.0f; this->actor.velocity.y = 4.0f; } else { return; // wait until back on floor } } else { - if (this->actor.bgCheckFlags & 1) { + if (this->actor.bgCheckFlags & 1) { // hit floor this->sfxTimer1 = 0; this->actor.velocity.y = 4.0f; // vertical hop this->unk29E = 1; } - if (this->unkTimer252 == 0) { - this->unkTimer254 = 100; - this->unkTimer250 = 0; + if (this->hoppingTimer == 0) { + this->runAwayTimer = 100; + this->heldTimer = 0; this->unk2EC = 0; EnNiw_SetupRunAway(this); return; @@ -493,20 +521,19 @@ void EnNiw_Thrown(EnNiw* this, GlobalContext* globalCtx) { Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_CHICKEN_CRY_M); // crow this->sfxTimer1 = 30; this->unk2EC = 0; - this->unkTimer250 = 30; + this->heldTimer = 30; this->actor.flags &= ~ACTOR_FLAG_1; // targetable OFF - this->unknownState28E = 4; + this->niwState = NIW_STATE_HELD; this->actionFunc = EnNiw_Held; this->actor.speedXZ = 0.0f; } else { - if (this->unkTimer252 > 5) { + if (this->hoppingTimer > 5) { Actor_LiftActor(&this->actor, globalCtx); } - func_80891320(this, globalCtx, 2); + EnNiw_AnimateWingHead(this, globalCtx, NIW_ANIMATION_PECKING_AND_WAVING); } } -// action func: swimming and flying away after swimming void EnNiw_Swimming(EnNiw* this, GlobalContext* globalCtx) { Vec3f ripplePos; @@ -517,73 +544,74 @@ void EnNiw_Swimming(EnNiw* this, GlobalContext* globalCtx) { } this->actor.speedXZ = 2.0f; - if (this->actor.bgCheckFlags & 0x20) { - // still touching water + if (this->actor.bgCheckFlags & 0x20) { // touching water this->actor.gravity = 0.0f; if (this->actor.depthInWater > 15.0f) { this->actor.world.pos.y += 2.0f; } - if (this->unkTimer250 == 0) { - this->unkTimer250 = 30; + if (this->swimRippleTimer == 0) { + this->swimRippleTimer = 30; Math_Vec3f_Copy(&ripplePos, &this->actor.world.pos); ripplePos.y += this->actor.depthInWater; EffectSsGRipple_Spawn(globalCtx, &ripplePos, 100, 500, 30); } - if (this->actor.bgCheckFlags & 8) { - this->actor.velocity.y = 10.0f; + if (this->actor.bgCheckFlags & 8) { // hit a wall + this->actor.velocity.y = 10.0f; // fly up in straight line this->actor.speedXZ = 1.0f; } } else { this->actor.gravity = -2.0f; - if (this->actor.bgCheckFlags & 8) { - // has hit a wall - this->actor.velocity.y = 10.0f; // to the moon + if (this->actor.bgCheckFlags & 8) { // hit a wall + this->actor.velocity.y = 10.0f; // fly up in straight line this->actor.speedXZ = 1.0f; this->actor.gravity = 0.0f; } else { this->actor.speedXZ = 4.0f; } - if (this->actor.bgCheckFlags & 1) { + if (this->actor.bgCheckFlags & 1) { // hit floor this->actor.gravity = -2.0f; - this->unkTimer254 = 100; - this->unkTimer250 = 0; + this->runAwayTimer = 100; + this->swimRippleTimer = 0; this->actor.velocity.y = 0.0f; if (!this->isStormActive) { EnNiw_SetupRunAway(this); } else { - this->unknownState28E = 3; + this->niwState = NIW_STATE_ANGRY3; this->actionFunc = EnNiw_CuccoStorm; } } } - func_80891320(this, globalCtx, 2); + + EnNiw_AnimateWingHead(this, globalCtx, NIW_ANIMATION_PECKING_AND_WAVING); } void EnNiw_Trigger(EnNiw* this, GlobalContext* globalCtx) { - s32 value; + s32 state; + + // Possible Fake Match: the weird way this state is set if (1) { - value = 1; + state = NIW_STATE_ANGRY1; } - this->unkTimer252 = 10; - this->unknownState28E = this->unk29C = value; + this->cuccoStormTimer = 10; + this->niwState = this->nextAnimation = state; // NIW_ANIMATION_HEAD_PECKING this->actionFunc = EnNiw_Upset; } void EnNiw_Upset(EnNiw* this, GlobalContext* globalCtx) { // assumption: CuccoStorm is split into smaller parts because it used to be a cutscene in OOT this->sfxTimer1 = 100; - if (this->unkTimer252 == 0) { - this->unkTimer252 = 60; + if (this->cuccoStormTimer == 0) { + this->cuccoStormTimer = 60; this->unkTimer24C = 10; - this->unk29C = 4; - this->unknownState28E = 2; + this->nextAnimation = NIW_ANIMATION_FREEZE; + this->niwState = NIW_STATE_ANGRY2; this->actionFunc = EnNiw_SetupCuccoStorm; } - func_80891320(this, globalCtx, this->unk29C); + EnNiw_AnimateWingHead(this, globalCtx, this->nextAnimation); } // the long crow with head back before they descend @@ -591,45 +619,46 @@ void EnNiw_SetupCuccoStorm(EnNiw* this, GlobalContext* globalCtx) { f32 viewY; this->sfxTimer1 = 100; - if (this->unkTimer252 == 40) { + if (this->cuccoStormTimer == 40) { viewY = 14000.0f; - this->unk264[0] = 10000.0f; - this->unk264[7] = this->unk264[5] = viewY; - this->unk264[6] = 0.0f; - this->unk264[8] = 0.0f; - this->unk264[1] = 0.0f; - this->unk264[2] = 0.0f; + this->targetLimbRots[0] = 10000.0f; // body rot + this->targetLimbRots[7] = this->targetLimbRots[5] = viewY; + this->targetLimbRots[6] = 0.0f; + this->targetLimbRots[8] = 0.0f; + this->targetLimbRots[1] = 0.0f; + this->targetLimbRots[2] = 0.0f; this->unkTimer24C = 10; - Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_CHICKEN_CRY_M); // crow + Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_CHICKEN_CRY_M); } - if (this->unkTimer252 == 0) { - this->unkTimer252 = 10; + + if (this->cuccoStormTimer == 0) { + this->cuccoStormTimer = 10; this->yawTowardsPlayer = this->actor.yawTowardsPlayer; this->actor.flags &= ~ACTOR_FLAG_1; // targetable OFF - this->unknownState28E = 3; + this->niwState = NIW_STATE_ANGRY3; this->actionFunc = EnNiw_CuccoStorm; } - func_80891320(this, globalCtx, this->unk29C); + + EnNiw_AnimateWingHead(this, globalCtx, this->nextAnimation); } void EnNiw_CuccoStorm(EnNiw* this, GlobalContext* globalCtx) { EnNiw_SpawnAttackNiw(this, globalCtx); - if (this->unkTimer252 == 1) { + if (this->cuccoStormTimer == 1) { // not countdown to 0? mistype? this->actor.speedXZ = 3.0f; - this->unk29A = Rand_ZeroFloat(1.99f); - this->unkTimer250 = 0; - this->unkTimer24E = this->unkTimer250; - this->unkTimer24C = this->unkTimer250; + this->isRunningRight = Rand_ZeroFloat(1.99f); + this->generalTimer1 = 0; + this->unkTimer24E = this->generalTimer1; + this->unkTimer24C = this->generalTimer1; } else { - func_808917F8(this, globalCtx, 1); + EnNiw_UpdateRunning(this, globalCtx, true); } } void EnNiw_SetupRunAway(EnNiw* this) { - Animation_Change(&this->skelanime, &object_niw_Anim_0000E8, 1.0f, 0.0f, - Animation_GetLastFrame(&object_niw_Anim_0000E8), 0, -10.0f); - this->unk29A = Rand_ZeroFloat(1.99f); - this->unknownState28E = 7; + Animation_Change(&this->skelanime, &gNiwIdleAnim, 1.0f, 0.0f, Animation_GetLastFrame(&gNiwIdleAnim), 0, -10.0f); + this->isRunningRight = Rand_ZeroFloat(1.99f); + this->niwState = NIW_STATE_RUNNING; this->actionFunc = EnNiw_RunAway; this->actor.speedXZ = 4.0f; } @@ -641,22 +670,21 @@ void EnNiw_RunAway(EnNiw* this, GlobalContext* globalCtx) { f32 dX; f32 dZ; - if (this->unkTimer254 == 0) { + if (this->runAwayTimer == 0) { this->unk2A4.x = this->unk2B0.x = this->actor.world.pos.x; this->unk2A4.y = this->unk2B0.y = this->actor.world.pos.y; this->unk2A4.z = this->unk2B0.z = this->actor.world.pos.z; - - this->unkTimer252 = this->unkTimer250 = this->unk298 = 0; + this->generalTimer2 = this->generalTimer1 = this->unk298 = 0; this->unk300 = this->unk304 = 0; - this->actor.speedXZ = 0; - - this->unk264[8] = 0; - this->unk264[6] = 0; - this->unk264[5] = 0; - this->unk264[7] = 0; + this->targetLimbRots[8] = 0; + this->targetLimbRots[6] = 0; + this->targetLimbRots[5] = 0; + this->targetLimbRots[7] = 0; Math_Vec3f_Copy(&this->unk2BC, &tempVec3f); + EnNiw_SetupIdle(this); + } else { if (this->unk2BC.x != 90000.0f) { dX = this->actor.world.pos.x - this->unk2BC.x; @@ -666,25 +694,27 @@ void EnNiw_RunAway(EnNiw* this, GlobalContext* globalCtx) { dZ = this->actor.world.pos.z - player->actor.world.pos.z; } this->yawTowardsPlayer = Math_Atan2S(dX, dZ); - func_808917F8(this, globalCtx, 0); - func_80891320(this, globalCtx, 2); + EnNiw_UpdateRunning(this, globalCtx, false); + EnNiw_AnimateWingHead(this, globalCtx, NIW_ANIMATION_PECKING_AND_WAVING); } } void EnNiw_LandBeforeIdle(EnNiw* this, GlobalContext* globalCtx) { - if (this->actor.bgCheckFlags & 1) { + if (this->actor.bgCheckFlags & 1) { // hit floor EnNiw_SetupIdle(this); } } void EnNiw_CheckRage(EnNiw* this, GlobalContext* globalCtx) { - if (!this->isStormActive && (this->unkTimer260 == 0) && (this->niwType == ENNIW_TYPE_REGULAR)) { - if ((this->unknownState28E != 7) && (this->unk2BC.x != 90000.0f)) { - this->unkTimer260 = 10; + if (!this->isStormActive && this->iframeTimer == 0 && this->niwType == NIW_TYPE_REGULAR) { + + // is this used? this is before we even know if we've been hit + if (this->niwState != NIW_STATE_RUNNING && this->unk2BC.x != 90000.0f) { + this->iframeTimer = 10; this->sfxTimer1 = 30; this->unk29E = 1; Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_CHICKEN_CRY_M); // crow - this->unkTimer254 = 100; + this->runAwayTimer = 100; this->unk2EC = 0; EnNiw_SetupRunAway(this); } @@ -696,32 +726,32 @@ void EnNiw_CheckRage(EnNiw* this, GlobalContext* globalCtx) { this->actor.colChkInfo.health--; } - if ((!D_80893460) && (this->actor.colChkInfo.health == 0)) { - // now you've done it - this->unkTimer254 = 100; - D_80893460 = true; + if (!sCuccoStormActive && this->actor.colChkInfo.health == 0) { + this->runAwayTimer = 100; // main cucco will run away after storm starts + sCuccoStormActive = true; this->unk298 = 0; this->sfxTimer1 = 10000; this->unk2A4.x = this->unk2B0.x = this->actor.world.pos.x; this->unk2A4.y = this->unk2B0.y = this->actor.world.pos.y; this->unk2A4.z = this->unk2B0.z = this->actor.world.pos.z; - this->unkTimer252 = this->unkTimer250 = this->unk298; + this->generalTimer2 = this->generalTimer1 = this->unk298; - this->unk264[8] = 0.0f; - this->unk264[6] = 0.0f; - this->unk264[5] = 0.0f; - this->unk264[7] = 0.0f; + this->targetLimbRots[8] = 0.0f; + this->targetLimbRots[6] = 0.0f; + this->targetLimbRots[5] = 0.0f; + this->targetLimbRots[7] = 0.0f; this->isStormActive = true; this->actionFunc = EnNiw_Trigger; this->unk304 = 0.0f; this->unk300 = 0.0f; this->actor.speedXZ = 0.0f; + } else { - this->unkTimer260 = 10; + this->iframeTimer = 10; this->sfxTimer1 = 30; this->unk29E = 1; Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_CHICKEN_CRY_M); // crow - this->unkTimer254 = 100; + this->runAwayTimer = 100; this->unk2EC = 0; EnNiw_SetupRunAway(this); } @@ -737,10 +767,9 @@ void EnNiw_Update(Actor* thisx, GlobalContext* globalCtx) { s16 pad1; s16 featherCount; Vec3f pos; - Vec3f spB8; - Vec3f spAC; - s32 pad2[9]; - s16 temp29C; + Vec3f vel; + Vec3f accel; + s32 pad2[10]; f32 featherScale; f32 viewAtToEyeNormY; f32 floorHeight; @@ -749,16 +778,16 @@ void EnNiw_Update(Actor* thisx, GlobalContext* globalCtx) { this->unusedCounter28C++; - if (this->niwType == ENNIW_TYPE_UNK1) { + if (this->niwType == NIW_TYPE_UNK1) { this->actor.shape.rot.y = this->actor.world.rot.y = this->actor.parent->shape.rot.y; } - if (this->unknownState28E != 0) { - this->unk264[9] = 0.0f; + if (this->niwState != NIW_STATE_IDLE) { + this->targetLimbRots[9] = 0.0f; // head rot } if (this->unk29E != 0) { - featherCount = ENNIW_FEATHERCOUNT; + featherCount = NIW_FEATHER_COUNT; if (this->unk29E == 2) { featherCount = 4; } @@ -768,20 +797,20 @@ void EnNiw_Update(Actor* thisx, GlobalContext* globalCtx) { pos.z = randPlusMinusPoint5Scaled(10.0f) + this->actor.world.pos.z; featherScale = Rand_ZeroFloat(6.0f) + 6.0f; - if ((this->unk29E == 2) && (this->unk308 != 0)) { + if (this->unk29E == 2 && this->unk308 != 0) { pos.y += 10.0f; } if (this->unk308 == 0) { featherScale = Rand_ZeroFloat(2.0f) + 2.0f; } - spB8.x = randPlusMinusPoint5Scaled(3.0f); - spB8.y = (Rand_ZeroFloat(2.0f) * 0.5f) + 2.0f; - spB8.z = randPlusMinusPoint5Scaled(3.0f); - spAC.z = spAC.x = 0.0f; - spAC.y = -0.15000000596f; + vel.x = randPlusMinusPoint5Scaled(3.0f); + vel.y = Rand_ZeroFloat(2.0f) * 0.5f + 2.0f; + vel.z = randPlusMinusPoint5Scaled(3.0f); + accel.z = accel.x = 0.0f; + accel.y = -0.15f; - EnNiw_SpawnFeather(this, &pos, &spB8, &spAC, featherScale); + EnNiw_SpawnFeather(this, &pos, &vel, &accel, featherScale); } this->unk29E = 0; } @@ -790,15 +819,15 @@ void EnNiw_Update(Actor* thisx, GlobalContext* globalCtx) { DECR(this->unkTimer24C); DECR(this->unkTimer24E); - DECR(this->unkTimer250); - DECR(this->unkTimer252); - DECR(this->unkTimer254); + DECR(this->generalTimer1); + DECR(this->generalTimer2); + DECR(this->runAwayTimer); DECR(this->sfxTimer1); DECR(this->flutterSfxTimer); DECR(this->unusedTimer25A); DECR(this->yawTimer); - DECR(this->unusedTimer25E); - DECR(this->unkTimer260); + DECR(this->unkAttackNiwTimer); + DECR(this->iframeTimer); this->actor.shape.rot = this->actor.world.rot; this->actor.shape.shadowScale = 15.0f; @@ -808,7 +837,7 @@ void EnNiw_Update(Actor* thisx, GlobalContext* globalCtx) { Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 20.0f, 20.0f, 60.0f, 0x1F); - // if cucco is off the map? + // if cucco is off the map if (this->actor.floorHeight <= BGCHECK_Y_MIN || this->actor.floorHeight >= BGCHECK_Y_MAX) { Vec3f viewAtToEye; @@ -820,7 +849,7 @@ void EnNiw_Update(Actor* thisx, GlobalContext* globalCtx) { this->actor.world.pos.x = this->actor.home.pos.x; this->actor.world.pos.z = this->actor.home.pos.z; - this->actor.world.pos.y = (this->actor.home.pos.y + globalCtx->view.eye.y) + (viewAtToEyeNormY * 160.0f); + this->actor.world.pos.y = this->actor.home.pos.y + globalCtx->view.eye.y + (viewAtToEyeNormY * 160.0f); if (this->actor.world.pos.y < this->actor.home.pos.y) { this->actor.world.pos.y = this->actor.home.pos.y + 300.0f; @@ -833,75 +862,74 @@ void EnNiw_Update(Actor* thisx, GlobalContext* globalCtx) { this->unk304 = 0.0f; this->unk300 = 0.0f; - this->unusedFloat2FC = 0.0f; + this->unusedFloat2FC = 0.0f; // assigned here but never used after this->unusedFloat2F8 = 0.0f; this->unusedFloat2F4 = 0.0f; - this->limbBRotx = 0.0f; - this->limbBRoty = 0.0f; - this->limbBRotz = 0.0f; - this->limb7Rotx = 0.0f; - this->limb7Roty = 0.0f; - this->limb7Rotz = 0.0f; - this->limbDRot = 0.0f; - this->limbFRot = 0.0f; + this->rightWingRotX = 0.0f; + this->rightWingRotY = 0.0f; + this->rightWingRotZ = 0.0f; + this->leftWingRotX = 0.0f; + this->leftWingRotY = 0.0f; + this->leftWingRotZ = 0.0f; + this->upperBodyRotY = 0.0f; + this->headRotY = 0.0f; // clang-format off - this->isStormActive = this->unusedCounter28C = this->unk292 = this->unk29E = this->unk298 = this->unk29A = this->unk29C = 0; + this->isStormActive = this->unusedCounter28C = this->unk292 = this->unk29E = this->unk298 = this->isRunningRight = this->nextAnimation = 0; // clang-format on for (i = 0; i < 10; i++) { - this->unk264[i] = 0.0f; + this->targetLimbRots[i] = 0.0f; } - this->unknownState28E = 8; + this->niwState = NIW_STATE_HOPPING; this->isStormActive = false; this->actionFunc = EnNiw_LandBeforeIdle; return; + } - } else if ((this->actor.bgCheckFlags & 0x20) && (this->actor.depthInWater > 15.0f) && - (this->unknownState28E != 6)) { + if ((this->actor.bgCheckFlags & 0x20) && // touching water + this->actor.depthInWater > 15.0f && this->niwState != NIW_STATE_SWIMMING) { this->actor.velocity.y = 0.0f; this->actor.gravity = 0.0f; Math_Vec3f_Copy(&pos, &this->actor.world.pos); pos.y += this->actor.depthInWater; - this->unkTimer250 = 30; + this->swimRippleTimer = 30; EffectSsGSplash_Spawn(globalCtx, &pos, 0, 0, 0, 400); - this->unkTimer252 = 0; - this->unknownState28E = 6; + this->generalTimer2 = 0; + this->niwState = NIW_STATE_SWIMMING; this->actionFunc = EnNiw_Swimming; + return; + } - } else { - if (this->isStormActive && (this->actor.xyzDistToPlayerSq < (SQ(dist))) && (player->invincibilityTimer == 0)) { - func_800B8D50(globalCtx, &this->actor, 2.0f, this->actor.world.rot.y, 0.0f, 0x10); + if (this->isStormActive && (this->actor.xyzDistToPlayerSq < SQ(dist)) && player->invincibilityTimer == 0) { + func_800B8D50(globalCtx, &this->actor, 2.0f, this->actor.world.rot.y, 0.0f, 0x10); + } + + EnNiw_CheckRage(this, globalCtx); + if (this->flutterSfxTimer == 0 && this->niwState == NIW_STATE_HELD) { + this->flutterSfxTimer = 7; + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_CHICKEN_FLUTTER); + } + + if (this->sfxTimer1 == 0) { + if (this->niwState != NIW_STATE_IDLE) { + this->sfxTimer1 = 30; + Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_CHICKEN_CRY_A); + } else { + this->sfxTimer1 = 300; + Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_CHICKEN_CRY_N); } + } - EnNiw_CheckRage(this, globalCtx); - if ((this->flutterSfxTimer == 0) && (this->unknownState28E == 4)) { - this->flutterSfxTimer = 7; - Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_CHICKEN_FLUTTER); - } + if (!this->isStormActive && this->niwType == NIW_TYPE_REGULAR) { + Collider_UpdateCylinder(&this->actor, &this->collider); + CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->collider.base); - if (this->sfxTimer1 == 0) { - if (this->unknownState28E != 0) { - this->sfxTimer1 = 30; - Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_CHICKEN_CRY_A); // attack cluck - } else { - this->sfxTimer1 = 300; - Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_CHICKEN_CRY_N); // cluck - } - } + if (globalCtx) {} - if (!this->isStormActive) { - if (this->niwType == ENNIW_TYPE_REGULAR) { - Collider_UpdateCylinder(&this->actor, &this->collider); - CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->collider.base); - - if (globalCtx) {} - - if ((this->unknownState28E != 4) && (this->unknownState28E != 5)) { - CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider.base); - } - } + if (this->niwState != NIW_STATE_HELD && this->niwState != NIW_STATE_FALLING) { + CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider.base); } } } @@ -909,21 +937,21 @@ void EnNiw_Update(Actor* thisx, GlobalContext* globalCtx) { s32 EnNiw_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, Actor* thisx) { EnNiw* this = THIS; - if (limbIndex == 13) { - rot->y += (s16)this->limbDRot; + if (limbIndex == NIW_LIMB_UPPER_BODY) { + rot->y += (s16)this->upperBodyRotY; } - if (limbIndex == 15) { - rot->y += (s16)this->limbFRot; + if (limbIndex == NIW_LIMB_HEAD) { + rot->y += (s16)this->headRotY; } - if (limbIndex == 11) { - rot->x += (s16)this->limbBRotx; - rot->y += (s16)this->limbBRoty; - rot->z += (s16)this->limbBRotz; + if (limbIndex == NIW_LIMB_RIGHT_WING_ROOT) { + rot->x += (s16)this->rightWingRotX; + rot->y += (s16)this->rightWingRotY; + rot->z += (s16)this->rightWingRotZ; } - if (limbIndex == 7) { - rot->x += (s16)this->limb7Rotx; - rot->y += (s16)this->limb7Roty; - rot->z += (s16)this->limb7Rotz; + if (limbIndex == NIW_LIMB_LEFT_WING_ROOT) { + rot->x += (s16)this->leftWingRotX; + rot->y += (s16)this->leftWingRotY; + rot->z += (s16)this->leftWingRotZ; } return false; } @@ -939,7 +967,7 @@ void EnNiw_Draw(Actor* thisx, GlobalContext* globalCtx) { void EnNiw_SpawnFeather(EnNiw* this, Vec3f* pos, Vec3f* vel, Vec3f* accel, f32 scale) { s16 i; - EnNiwFeather* feather = this->feathers; + EnNiwFeather* feather = &this->feathers[0]; for (i = 0; i < ARRAY_COUNT(this->feathers); i++, feather++) { if (feather->isEnabled == false) { @@ -957,7 +985,7 @@ void EnNiw_SpawnFeather(EnNiw* this, Vec3f* pos, Vec3f* vel, Vec3f* accel, f32 s } void EnNiw_UpdateFeather(EnNiw* this, GlobalContext* globalCtx) { - EnNiwFeather* feather = this->feathers; + EnNiwFeather* feather = &this->feathers[0]; f32 featherVelocityGoal = 0.05f; s16 i; @@ -988,7 +1016,6 @@ void EnNiw_UpdateFeather(EnNiw* this, GlobalContext* globalCtx) { } } -// feather draw function void EnNiw_DrawFeathers(EnNiw* this, GlobalContext* globalCtx) { GraphicsContext* gfxCtx = globalCtx->state.gfxCtx; u8 isMaterialApplied = false; diff --git a/src/overlays/actors/ovl_En_Niw/z_en_niw.h b/src/overlays/actors/ovl_En_Niw/z_en_niw.h index 5a03215bcb..7c8b3e07e8 100644 --- a/src/overlays/actors/ovl_En_Niw/z_en_niw.h +++ b/src/overlays/actors/ovl_En_Niw/z_en_niw.h @@ -2,6 +2,7 @@ #define Z_EN_NIW_H #include "global.h" +#include "objects/object_niw/object_niw.h" struct EnNiw; @@ -19,55 +20,67 @@ typedef struct { /* 0x0034 */ u8 timer; } EnNiwFeather; // size = 0x38 -#define ENNIW_LIMBCOUNT 16 -#define ENNIW_FEATHERCOUNT 20 +#define NIW_FEATHER_COUNT 20 typedef struct EnNiw { /* 0x000 */ Actor actor; /* 0x144 */ SkelAnime skelanime; - /* 0x188 */ Vec3s jointTable[ENNIW_LIMBCOUNT]; - /* 0x1E8 */ Vec3s morphTable[ENNIW_LIMBCOUNT]; + /* 0x188 */ Vec3s jointTable[NIW_LIMB_MAX]; + /* 0x1E8 */ Vec3s morphTable[NIW_LIMB_MAX]; /* 0x248 */ EnNiwActionFunc actionFunc; - /* 0x24C */ s16 unkTimer24C; + /* 0x24C */ s16 unkTimer24C; // set to 10, checked in mystery func /* 0x24E */ s16 unkTimer24E; - /* 0x250 */ s16 unkTimer250; - /* 0x252 */ s16 unkTimer252; - /* 0x254 */ s16 unkTimer254; + /* 0x250 */ union { + s16 generalTimer1; // default name for reset/decr + s16 hopTimer; // every 3 frames while running/idling + s16 swimRippleTimer; // how often swimming cucco spawns ripples + s16 heldTimer; // timer until updating unk29E + s16 unkIdleTimer; // not sure what _Idle is doing with it yet + }; + /* 0x252 */ union { + s16 generalTimer2; // default name for reset/decr + s16 hoppingTimer; // hopping after being thrown before running + s16 attackNiwSpawnTimer; // delay between re-attempting to spawn more attack_niw + s16 runningDirectionTimer; // delay between direction changes when running + s16 cuccoStormTimer; // delay between stages of summoning the storm + s16 unkIdleTimer2; // not sure what _Idle is doing with it yet + }; + /* 0x254 */ s16 runAwayTimer; /* 0x256 */ s16 sfxTimer1; /* 0x258 */ s16 flutterSfxTimer; /* 0x25A */ s16 unusedTimer25A; - /* 0x25C */ s16 yawTimer; // every 70 frames rechecks yawToPlayer - /* 0x25E */ s16 unusedTimer25E; - /* 0x260 */ s16 unkTimer260; - /* 0x264 */ f32 unk264[10]; + /* 0x25C */ s16 yawTimer; // every 70 frames rechecks yawToPlayer + /* 0x25E */ s16 unkAttackNiwTimer; // every 70 frames, updates some player unk values + /* 0x260 */ s16 iframeTimer; + /* 0x264 */ f32 targetLimbRots[10]; /* 0x28C */ s16 unusedCounter28C; - /* 0x28E */ s16 unknownState28E; - /* 0x290 */ s16 unk290; + /* 0x28E */ s16 niwState; + /* 0x290 */ s16 attackNiwCount; /* 0x292 */ s16 unk292; /* 0x294 */ s16 pad294; - /* 0x296 */ s16 unk296; + /* 0x296 */ s16 unkToggle296; /* 0x298 */ s16 unk298; - /* 0x29C */ s16 unk29A; - /* 0x29C */ u16 unk29C; - /* 0x29E */ s16 unk29E; - /* 0x2A0 */ s16 isStormActive; + /* 0x29C */ s16 isRunningRight; // toggle (direction cucco is turning while running) + /* 0x29C */ u16 nextAnimation; + /* 0x29E */ s16 unk29E; // three states 0/1/2 + /* 0x2A0 */ s16 isStormActive; // we have a data value shared between all cucco, this shouldn't need to exist /* 0x2A2 */ s16 niwType; /* 0x2A4 */ Vec3f unk2A4; /* 0x2B0 */ Vec3f unk2B0; - /* 0x2BC */ Vec3f unk2BC; - /* 0x2C8 */ f32 limb7Rotz; - /* 0x2CC */ f32 limb7Roty; - /* 0x2D0 */ f32 limb7Rotx; - /* 0x2D4 */ f32 limbBRotz; - /* 0x2D8 */ f32 limbBRoty; - /* 0x2DC */ f32 limbBRotx; - /* 0x2E0 */ f32 limbDRot; - /* 0x2E4 */ f32 limbFRot; + /* 0x2BC */ Vec3f unk2BC; // init from data (90000 on all three) + /* 0x2C8 */ f32 leftWingRotZ; + /* 0x2CC */ f32 leftWingRotY; + /* 0x2D0 */ f32 leftWingRotX; + /* 0x2D4 */ f32 rightWingRotZ; + /* 0x2D8 */ f32 rightWingRotY; + /* 0x2DC */ f32 rightWingRotX; + /* 0x2E0 */ f32 upperBodyRotY; + /* 0x2E4 */ f32 headRotY; /* 0x2E8 */ s16 yawTowardsPlayer; - /* 0x2EA */ s16 unk2EA; + /* 0x2EA */ s16 headRotationToggle; /* 0x2EC */ s16 unk2EC; /* 0x2EE */ UNK_TYPE1 pad2EE[0x6]; - /* 0x2F4 */ f32 unusedFloat2F4; + /* 0x2F4 */ f32 unusedFloat2F4; // set in EnNiw_Update if Cucco falls off map, never read /* 0x2F8 */ f32 unusedFloat2F8; /* 0x2FC */ f32 unusedFloat2FC; /* 0x300 */ f32 unk300; @@ -75,16 +88,26 @@ typedef struct EnNiw { /* 0x308 */ f32 unk308; /* 0x30C */ s32 pad30C; /* 0x310 */ ColliderCylinder collider; - /* 0x35C */ EnNiwFeather feathers[ENNIW_FEATHERCOUNT]; + /* 0x35C */ EnNiwFeather feathers[NIW_FEATHER_COUNT]; } EnNiw; // size = 0x7BC // in init, any value below zero becomes zero -// however, in vanilla, only 0xFFFF (-1) exists -#define ENNIW_TYPE_VANILLA 0xFFFF -#define ENNIW_TYPE_REGULAR 0 -#define ENNIW_TYPE_UNK1 1 -#define ENNIW_TYPE_UNK2 2 -// the attacking cuccos are not here, they are a different actor: -// ovl_En_Attack_Niw +// however, in vanilla, only 0xFFFF (-1) exists in scene spawns, actors can spawn 0x0 +#define NIW_TYPE_VANILLA 0xFFFF +#define NIW_TYPE_REGULAR 0 +#define NIW_TYPE_UNK1 1 +#define NIW_TYPE_HELD 2 // spawns held by the bomber kid in east clock town during hide and seek +// the attacking cuccos are not here, they are a different actor: [ ovl_En_Attack_Niw ] + +typedef enum { + /* 0 */ NIW_ANIMATION_STILL, + /* 1 */ NIW_ANIMATION_HEAD_PECKING, // forward and backward, feeding + /* 2 */ NIW_ANIMATION_PECKING_AND_WAVING, // wings move along their axis, like human hand waving + /* 3 */ NIW_ANIMATION_PECKING_AND_FORFLAPPING, // (unused) low (yaw based) flapping, forward and back + /* 4 */ NIW_ANIMATION_FREEZE, // used during Cucco Storm + /* 5 */ NIW_ANIMATION_PECKING_SLOW_FORFLAPPING, // wing speed half that of 3 + +} EnNiwHeadAndWingAnimationState; + #endif // Z_EN_NIW_H diff --git a/src/overlays/actors/ovl_En_Nwc/z_en_nwc.c b/src/overlays/actors/ovl_En_Nwc/z_en_nwc.c index 4c0fdce1ef..8d254b7287 100644 --- a/src/overlays/actors/ovl_En_Nwc/z_en_nwc.c +++ b/src/overlays/actors/ovl_En_Nwc/z_en_nwc.c @@ -2,9 +2,14 @@ * File: z_en_nwc.c * Overlay: ovl_En_Nwc * Description: Cucco chick + * + * This actor requires object_niw to be present for the transformation during Breman Mask March + * EnHs (Grog) must also be present to maintain the count of the EnNwc in the march */ #include "z_en_nwc.h" +#include "overlays/actors/ovl_En_Niw/z_en_niw.h" +#include "objects/object_nwc/object_nwc.h" #define FLAGS (ACTOR_FLAG_10) @@ -15,15 +20,27 @@ void EnNwc_Destroy(Actor* thisx, GlobalContext* globalCtx); void EnNwc_Update(Actor* thisx, GlobalContext* globalCtx); void EnNwc_Draw(Actor* thisx, GlobalContext* globalCtx); -void func_809448A4(EnNwc* this, GlobalContext* globalCtx); -void func_809449D0(EnNwc* this, GlobalContext* globalCtx); -void func_80944A50(EnNwc* this, GlobalContext* globalCtx); -void func_80944E44(EnNwc* this, GlobalContext* globalCtx); -void func_80944EFC(EnNwc* this, GlobalContext* globalCtx); -void func_80944FA8(EnNwc* this, GlobalContext* globalCtx); -void func_8094506C(EnNwc* this, GlobalContext* globalCtx); +void EnNwc_LoadNiwSkeleton(EnNwc* this, GlobalContext* globalCtx); +void EnNwc_CrowAtTheEnd(EnNwc* this, GlobalContext* globalCtx); +void EnNwc_Follow(EnNwc* this, GlobalContext* globalCtx); +void EnNwc_HopForward(EnNwc* this, GlobalContext* globalCtx); +void EnNwc_RunAway(EnNwc* this, GlobalContext* globalCtx); +void EnNwc_Turn(EnNwc* this, GlobalContext* globalCtx); +void EnNwc_CheckForBreman(EnNwc* this, GlobalContext* globalCtx); + +void EnNwc_DrawAdultBody(Actor* thisx, GlobalContext* globalCtx); +s32 EnNwc_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, Actor* thisx); +EnHs* EnNwc_FindGrog(GlobalContext* globalCtx); + +enum EnNiwState { + /* -1 */ NWC_STATE_NIW_LOADED = -1, // set after loading object_niw + /* 0 */ NWC_STATE_CHECK_BREMAN = 0, // checking for breman mask + /* 1 */ NWC_STATE_TURNING, // turning to face a new direction to explore + /* 2 */ NWC_STATE_HOPPING_FORWARD, // hopping to go explore + /* 3 */ NWC_STATE_FOLLOWING, // following the player + /* 4 */ NWC_STATE_RUNNING, // running from the player after failed breman march +}; -#if 0 const ActorInit En_Nwc_InitVars = { ACTOR_EN_NWC, ACTORCAT_PROP, @@ -36,47 +53,474 @@ const ActorInit En_Nwc_InitVars = { (ActorFunc)EnNwc_Draw, }; -#endif +Color_RGBA8 sPrimColor = { 255, 255, 255, 255 }; -extern UNK_TYPE D_060000E8; -extern UNK_TYPE D_060002E8; +Color_RGBA8 sEnvColor = { 80, 80, 80, 255 }; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Nwc/EnNwc_Init.s") +void EnNwc_Init(Actor* thisx, GlobalContext* globalCtx) { + s32 niwObjectIndex; + EnNwc* this = THIS; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Nwc/EnNwc_Destroy.s") + niwObjectIndex = Object_GetIndex(&globalCtx->objectCtx, OBJECT_NIW); + if (niwObjectIndex < 0) { + // niw object does not exist, we need it for tranformation, despawn + Actor_MarkForDeath(&this->actor); + return; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Nwc/func_80944320.s") + if (gSaveContext.save.weekEventReg[25] & 8) { + // if breman mask was already used, replace with adult EnNiw + Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_NIW, this->actor.world.pos.x, this->actor.world.pos.y, + this->actor.world.pos.z, 0, this->actor.world.rot.y, 0, NIW_TYPE_REGULAR); + Actor_MarkForDeath(&this->actor); + return; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Nwc/func_80944554.s") + this->niwObjectIndex = niwObjectIndex; + this->nwcObjectIndex = this->actor.objBankIndex; + this->grog = EnNwc_FindGrog(globalCtx); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Nwc/func_80944590.s") + this->footRotY = this->footRotZ = 0; + Actor_SetScale(&this->actor, 0.01f); + this->actionFunc = EnNwc_LoadNiwSkeleton; + this->hasGrownUp = false; + ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 6.0f); + this->actor.velocity.y = 0.0f; + this->actor.terminalVelocity = -9.0f; + this->actor.gravity = -1.0f; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Nwc/func_809445D4.s") +void EnNwc_Destroy(Actor* thisx, GlobalContext* globalCtx) { + EnNwc* this = THIS; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Nwc/func_80944630.s") +void EnNwc_SpawnDust(EnNwc* this, GlobalContext* globalCtx) { + Vec3f pos; + Vec3f vec5; + Vec3f vel; + Vec3f accel; + s16 yaw; + s16 pitch; + Vec3f eye = GET_ACTIVE_CAM(globalCtx)->eye; + s32 i; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Nwc/func_809447A8.s") + yaw = Math_Vec3f_Yaw(&eye, &this->actor.world.pos); + pitch = -Math_Vec3f_Pitch(&eye, &this->actor.world.pos); + vec5.x = this->actor.world.pos.x - 5.0f * Math_SinS(yaw) * Math_CosS(pitch); + vec5.y = this->actor.world.pos.y - 5.0f * Math_SinS(pitch); + vec5.z = this->actor.world.pos.z - 5.0f * Math_CosS(yaw) * Math_CosS(pitch); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Nwc/func_80944818.s") + for (i = 0; i < 5; i++) { + vel.x = randPlusMinusPoint5Scaled(4.0f); + vel.y = randPlusMinusPoint5Scaled(4.0f); + vel.z = randPlusMinusPoint5Scaled(4.0f); + accel.x = -vel.x * 0.1f; + accel.y = -vel.y * 0.1f; + accel.z = -vel.z * 0.1f; + pos.x = vec5.x + vel.x; + pos.y = vec5.y + vel.y; + pos.z = vec5.z + vel.z; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Nwc/func_809448A4.s") + func_800B0F80(globalCtx, &pos, &vel, &accel, &sPrimColor, &sEnvColor, 300, 30, 10); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Nwc/func_809449D0.s") +EnHs* EnNwc_FindGrog(GlobalContext* globalCtx) { + Actor* grogSearch = globalCtx->actorCtx.actorLists[ACTORCAT_NPC].first; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Nwc/func_80944A50.s") + while (grogSearch != NULL) { + if (grogSearch->id == ACTOR_EN_HS) { + return (EnHs*)grogSearch; + } + grogSearch = grogSearch->next; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Nwc/func_80944E44.s") + return NULL; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Nwc/func_80944EFC.s") +s32 EnNwc_PlayerReleasedBremanMarch(EnNwc* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Nwc/func_80944FA8.s") + // Weird: home.rot.x holds count of chicks having transformed into adult. + // Weird: Its incremented by 1 unlike chicks following, so it should max at 10. + if (this->grog->actor.home.rot.x >= 20) { + return false; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Nwc/func_8094506C.s") + if (player->stateFlags3 & 0x20000000) { // breman mask march + return false; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Nwc/EnNwc_Update.s") + return true; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Nwc/EnNwc_Draw.s") +/** + * Summary: Checks 1) if grog exists, 2) player is using breman mask, 3) and within range. + * Used to identify if the chick should be captured by breman mask. + */ +s32 EnNwc_IsFound(EnNwc* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Nwc/func_8094529C.s") + if (this->grog == NULL) { + return false; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Nwc/func_80945310.s") + if (player->stateFlags3 & 0x20000000 && // breman mask march + this->actor.xzDistToPlayer < 100.0f) { + return true; + } + + return false; +} + +void EnNwc_ChangeState(EnNwc* this, s16 newState) { + this->actor.speedXZ = 0.0f; + switch (newState) { + case NWC_STATE_CHECK_BREMAN: + this->stateTimer = 10; + this->actionFunc = EnNwc_CheckForBreman; + break; + case NWC_STATE_TURNING: + this->stateTimer = Rand_ZeroFloat(20.0f) + 15.0f; + this->actionFunc = EnNwc_Turn; + this->fallingRotY = (s16)(s32)randPlusMinusPoint5Scaled(65536.0f); + break; + case NWC_STATE_HOPPING_FORWARD: + this->stateTimer = Rand_ZeroFloat(20.0f) + 15.0f; + this->actionFunc = EnNwc_HopForward; + break; + case NWC_STATE_FOLLOWING: + this->actionFunc = EnNwc_Follow; + this->transformTimer = 0; + this->randomRot = (s16)(s32)randPlusMinusPoint5Scaled(10000.0f); + break; + case NWC_STATE_RUNNING: + this->actor.world.rot.y = this->actor.home.rot.z * 0x3000 & 0xFFFF; // Fake Match?: & 0xFFFF + this->actor.shape.rot.y = this->actor.world.rot.y; + this->stateTimer = Rand_ZeroFloat(40.0f) + 120.0f; + this->actionFunc = EnNwc_RunAway; + break; + } + + this->state = newState; +} + +/** + * Summary: Changes the current actor state + * If previously random behavior -> check if breman mask is active + * If previously checking for breman -> select random (NWC_STATE_TURNING, NWC_STATE_HOPPING_FORWARD) + */ +void EnNwc_ToggleState(EnNwc* this) { + this->actor.speedXZ = 0.0f; + if (this->state != NWC_STATE_CHECK_BREMAN) { + EnNwc_ChangeState(this, NWC_STATE_CHECK_BREMAN); + } else { + EnNwc_ChangeState(this, Rand_ZeroFloat(2.0f) + 1.0f); + } +} + +void EnNwc_CheckFound(EnNwc* this, GlobalContext* globalCtx) { + if (EnNwc_IsFound(this, globalCtx)) { + u8 currentChickCount = (this->grog->actor.home.rot.z / 2); + + if (currentChickCount > 9) { + currentChickCount = 9; + } + + // save our current chick order + this->actor.home.rot.z = this->grog->actor.home.rot.z + 1; + + // if < 10 chicks, increment grog's chick counter + if (this->grog->actor.home.rot.z < 20) { + this->grog->actor.home.rot.z += 2; + } + + EnNwc_ChangeState(this, NWC_STATE_FOLLOWING); + func_801A0868(&D_801DB4A4, NA_SE_SY_CHICK_JOIN_CHIME, currentChickCount); + } +} + +void EnNwc_LoadNiwSkeleton(EnNwc* this, GlobalContext* globalCtx) { + if (Object_IsLoaded(&globalCtx->objectCtx, this->niwObjectIndex)) { + gSegments[6] = PHYSICAL_TO_VIRTUAL(globalCtx->objectCtx.status[this->niwObjectIndex].segment); + + SkelAnime_InitFlex(globalCtx, &this->niwSkeleton, &gNiwSkeleton, &gNiwIdleAnim, this->jointTable, + this->morphTable, NIW_LIMB_MAX); + Animation_Change(&this->niwSkeleton, &gNiwIdleAnim, 1.0f, 0.0f, Animation_GetLastFrame(&gNiwIdleAnim), 0, 0.0f); + + gSegments[6] = PHYSICAL_TO_VIRTUAL(globalCtx->objectCtx.status[this->nwcObjectIndex].segment); + this->state = NWC_STATE_NIW_LOADED; + EnNwc_ToggleState(this); + } +} + +void EnNwc_CrowAtTheEnd(EnNwc* this, GlobalContext* globalCtx) { + // I guess grog handles the scene transit? + Math_SmoothStepToS(&this->upperBodyRotY, 0x2710, 2, 0x1B58, 0x3E8); + Math_SmoothStepToS(&this->footRotZ, 0, 2, 0x1B58, 0x3E8); + Math_SmoothStepToS(&this->footRotY, 0x36B0, 2, 0x1B58, 0x3E8); +} + +/** + * Summary: Controls the Chick when following Breman Mask. + * + * ActionFunc for NWC Type: NWC_STATE_FOLLOWING + */ +void EnNwc_Follow(EnNwc* this, GlobalContext* globalCtx) { + Vec3f* chickCoords = this->grog->nwcPos; + Vec3f targetVector; + s32 pad; + s16 newRotY; + + this->stateTimer++; + if (this->hasGrownUp & 1) { + s16 targetUpperBodyRot = 0; + s16 targetFootRot = 0; + + if (this->actor.speedXZ > 0.0f) { + if (this->stateTimer & 4) { + targetFootRot = 0x1B58; + targetUpperBodyRot = -0x2710; + } + if ((this->stateTimer & 3) == 3) { + this->actor.velocity.y = 2.0f; // hop up and down + } + } + Math_SmoothStepToS(&this->footRotZ, targetFootRot, 2, 0x1B58, 0x3E8); + Math_SmoothStepToS(&this->upperBodyRotY, targetUpperBodyRot, 2, 0x1B58, 0x3E8); + + } else { // NOT grown up + if ((this->stateTimer & 3) == 3 && this->stateTimer & 20) { + this->actor.velocity.y = 2.0f; // hop up and down + } + if ((this->stateTimer & 0x1B) == 24) { + Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_CHICK_SONG); + } + } + + if (this->grog->actor.home.rot.z >= 20 && // all 10 chicks have been found + (this->hasGrownUp & 1) == false) { + this->transformTimer += 2; + if (this->transformTimer >= (s32)(s16)((this->actor.home.rot.z * 0x1E) + 0x1E)) { + // it is our turn to transform + this->hasGrownUp |= 1; + this->grog->actor.home.rot.x += 2; // increment grog's adult tranformation counter + EnNwc_SpawnDust(this, globalCtx); + Actor_SetScale(&this->actor, 0.002f); + Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_CHICK_TO_CHICKEN); + } + } + + Math_Vec3f_Diff(&chickCoords[this->actor.home.rot.z], &this->actor.world.pos, &targetVector); + if (SQXZ(targetVector) < SQ(5.0f)) { // too close to keep moving, stop + this->actor.speedXZ = 0.0f; + + // first nwc in the line follows player, the rest follow the previous one + if (this->actor.home.rot.z == 1) { + newRotY = this->actor.yawTowardsPlayer; + } else { + // for some reason the array is 10 * 2, incremented by 2, so this is "index - 1" + newRotY = Math_Vec3f_Yaw(&this->actor.world.pos, &chickCoords[this->actor.home.rot.z - 2]); + } + + } else { // not too close: keep moving + this->randomRot += (s16)randPlusMinusPoint5Scaled(1500.0f); + if (this->randomRot > 0x1388) { + this->randomRot = 0x1388; + } else if (this->randomRot < -0x1388) { + this->randomRot = -0x1388; + } + this->actor.speedXZ = 2.0f; + newRotY = Math_Vec3f_Yaw(&this->actor.world.pos, &chickCoords[this->actor.home.rot.z]) + this->randomRot; + } + + this->actor.world.rot.y = newRotY; + Math_SmoothStepToS(&this->actor.shape.rot.y, this->actor.world.rot.y, 2, 0xBB8, 0xC8); + + if (EnNwc_PlayerReleasedBremanMarch(this, globalCtx)) { + this->grog->actor.home.rot.x = 0; // reset adult count + this->grog->actor.home.rot.z = 0; // reset chick follow count + + EnNwc_ChangeState(this, NWC_STATE_RUNNING); + + if (this->hasGrownUp & 1) { + EnNwc_SpawnDust(this, globalCtx); + } + + this->hasGrownUp &= ~1; + Actor_SetScale(&this->actor, 0.01f); + } + + if (this->actor.scale.x < 0.01f) { + this->actor.scale.x += 0.002f; + Actor_SetScale(&this->actor, this->actor.scale.x); + } + + if (this->grog->actor.home.rot.x >= 20) { // all chicks have turned into adult cucco, stop and crow + Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_CHICKEN_CRY_M); + this->actionFunc = EnNwc_CrowAtTheEnd; + this->actor.speedXZ = 0.0f; + Actor_SetScale(&this->actor, 0.01f); + } +} + +/** + * Summary: Chick is Walking (Hopping) in a straight line. + * + * ActionFunc for NWC Type: NWC_STATE_HOPPING_FORWARD + */ +void EnNwc_HopForward(EnNwc* this, GlobalContext* globalCtx) { + if (DECR(this->stateTimer) == 0) { + EnNwc_ToggleState(this); + return; + } + + if ((this->stateTimer & 3) == 3) { + this->actor.velocity.y = 2.0f; // hop up and down + } + if ((this->stateTimer & 0xB) == 8) { + Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_CHICK_SONG); + } + + // they only move forward while off the ground, which gives the visual of them hopping to move + if (this->actor.bgCheckFlags & 0x1) { // touching floor + this->actor.speedXZ = 0.0f; + } else { + this->actor.speedXZ = 2.0f; + } +} + +/** + * Summary: Chick is Running Away from player (Breman Mask was dropped). + * + * ActionFunc for NWC Type: NWC_STATE_RUNNING + */ +void EnNwc_RunAway(EnNwc* this, GlobalContext* globalCtx) { + if (DECR(this->stateTimer) == 0) { + EnNwc_ToggleState(this); + return; + } + + if ((this->stateTimer & 3) == 3) { + this->actor.velocity.y = 2.0f; // hop up and down + } + if ((this->stateTimer & 0xB) == 8) { + Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_CHICK_SONG); + } + + this->actor.speedXZ = 2.0f; + if (this->actor.bgCheckFlags & 0x8) { // touching wall + EnNwc_ToggleState(this); + } +} + +/** + * Summary: Chick is turning to face a new direction. + * + * ActionFunc for NWC Type: NWC_STATE_TURNING + */ +void EnNwc_Turn(EnNwc* this, GlobalContext* globalCtx) { + if (DECR(this->stateTimer) == 0) { + EnNwc_ToggleState(this); + return; + } + + if ((this->stateTimer & 7) == 7) { + this->actor.velocity.y = 2.0f; // vertical hop + } + + if ((this->stateTimer & 0xB) == 8) { + Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_CHICK_SONG); + } + + // they only rotate when off the ground, giving the visual that they turn by hopping + if (!(this->actor.bgCheckFlags & 0x1)) { // NOT touching floor + Math_SmoothStepToS(&this->actor.shape.rot.y, this->fallingRotY, 0xA, 0x1000, 0x800); + this->actor.world.rot.y = this->actor.shape.rot.y; + } +} + +/** + * Summary: Chick is standing still. + * Looking around, can see the player with the Breman Mask + * + * ActionFunc for NWC Type: NWC_STATE_CHECK_BREMAN + */ +void EnNwc_CheckForBreman(EnNwc* this, GlobalContext* globalCtx) { + if (DECR(this->stateTimer) == 0) { + EnNwc_ToggleState(this); + } + + EnNwc_CheckFound(this, globalCtx); +} + +void EnNwc_Update(Actor* thisx, GlobalContext* globalCtx) { + EnNwc* this = THIS; + + Actor_MoveWithGravity(&this->actor); + Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 10.0f, 10.0f, 10.0f, 5); + this->actionFunc(this, globalCtx); + if (this->hasGrownUp & 1) { + this->actor.objBankIndex = this->niwObjectIndex; + this->actor.draw = EnNwc_DrawAdultBody; + this->actor.shape.shadowScale = 15.0f; + } else { + this->actor.objBankIndex = this->nwcObjectIndex; + this->actor.draw = EnNwc_Draw; + this->actor.shape.shadowScale = 6.0f; + } + + if (DECR(this->blinkTimer) == 0) { + this->blinkTimer = Rand_S16Offset(0x3C, 0x3C); + } + + if (this->blinkTimer == 1 || this->blinkTimer == 3) { + this->blinkState = true; + } else { + this->blinkState = false; + } +} + +void EnNwc_Draw(Actor* thisx, GlobalContext* globalCtx) { + TexturePtr eyeTextures[] = { gNwcEyeOpenTex, gNwcEyeClosedTex }; + EnNwc* this = THIS; + Gfx* dispHead; + + OPEN_DISPS(globalCtx->state.gfxCtx); + + func_8012C28C(globalCtx->state.gfxCtx); + + dispHead = POLY_OPA_DISP; + + gSPSegment(&dispHead[0], 0x08, Lib_SegmentedToVirtual(eyeTextures[this->blinkState])); + + gSPMatrix(&dispHead[1], Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + + gSPDisplayList(&dispHead[2], &gNwcBodyDL); + + POLY_OPA_DISP = &dispHead[3]; + + CLOSE_DISPS(globalCtx->state.gfxCtx); +} + +s32 EnNwc_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, Actor* thisx) { + EnNwc* this = THIS; + + if (limbIndex == NIW_LIMB_UPPER_BODY) { + rot->y += this->upperBodyRotY; + } + if (limbIndex == NIW_LIMB_RIGHT_WING_ROOT || limbIndex == NIW_LIMB_LEFT_WING_ROOT) { + rot->y += this->footRotY; + rot->z += this->footRotZ; + } + + return false; +} + +void EnNwc_DrawAdultBody(Actor* thisx, GlobalContext* globalCtx) { + EnNwc* this = THIS; + + func_8012C28C(globalCtx->state.gfxCtx); + SkelAnime_DrawFlexOpa(globalCtx, this->niwSkeleton.skeleton, this->niwSkeleton.jointTable, + this->niwSkeleton.dListCount, EnNwc_OverrideLimbDraw, NULL, &this->actor); +} diff --git a/src/overlays/actors/ovl_En_Nwc/z_en_nwc.h b/src/overlays/actors/ovl_En_Nwc/z_en_nwc.h index ccdfb59bb0..3815852af4 100644 --- a/src/overlays/actors/ovl_En_Nwc/z_en_nwc.h +++ b/src/overlays/actors/ovl_En_Nwc/z_en_nwc.h @@ -2,15 +2,37 @@ #define Z_EN_NWC_H #include "global.h" +#include "objects/object_niw/object_niw.h" +#include "overlays/actors/ovl_En_Hs/z_en_hs.h" // grog + struct EnNwc; typedef void (*EnNwcActionFunc)(struct EnNwc*, GlobalContext*); typedef struct EnNwc { - /* 0x0000 */ Actor actor; - /* 0x0144 */ char unk_144[0x120]; - /* 0x0264 */ EnNwcActionFunc actionFunc; + /* 0x000 */ Actor actor; + /* 0x144 */ SkelAnime niwSkeleton; // this skeleton is for when the chicks grow up into adults during the breman march + /* 0x188 */ Vec3s jointTable[NIW_LIMB_MAX]; + /* 0x1E8 */ Vec3s morphTable[NIW_LIMB_MAX]; + /* 0x248 */ s8 niwObjectIndex; + /* 0x249 */ s8 nwcObjectIndex; + /* 0x24A */ s16 blinkState; + /* 0x24C */ s16 blinkTimer; + /* 0x250 */ EnHs* grog; + /* 0x254 */ s16 stateTimer; // count frames to next state change + /* 0x256 */ union { + s16 mixedValue256; // default name for reset + s16 transformTimer; // frames since transformation sequence started + s16 fallingRotY; // target rotation if off the ground in state 1 + }; + /* 0x258 */ s16 randomRot; + /* 0x25A */ s16 state; + /* 0x25C */ u16 hasGrownUp; // treated as both a boolean and a flag variable (0x1) + /* 0x25E */ s16 footRotY; + /* 0x260 */ s16 footRotZ; + /* 0x262 */ s16 upperBodyRotY; + /* 0x264 */ EnNwcActionFunc actionFunc; } EnNwc; // size = 0x268 extern const ActorInit En_Nwc_InitVars; diff --git a/tools/disasm/functions.txt b/tools/disasm/functions.txt index c4f1a053b7..e552ca3367 100644 --- a/tools/disasm/functions.txt +++ b/tools/disasm/functions.txt @@ -5424,9 +5424,9 @@ 0x808908D0:("func_808908D0",), 0x80891060:("EnNiw_Init",), 0x808912E8:("EnNiw_Destroy",), - 0x80891320:("func_80891320",), + 0x80891320:("EnNiw_AnimateWingHead",), 0x808916B0:("EnNiw_SpawnAttackNiw",), - 0x808917F8:("func_808917F8",), + 0x808917F8:("EnNiw_UpdateRunning",), 0x80891974:("EnNiw_SetupIdle",), 0x808919E8:("EnNiw_Idle",), 0x80891D78:("EnNiw_Held",), @@ -7514,24 +7514,24 @@ 0x80943EE4:("EnDaiku_Draw",), 0x809441E0:("EnNwc_Init",), 0x80944310:("EnNwc_Destroy",), - 0x80944320:("func_80944320",), - 0x80944554:("func_80944554",), - 0x80944590:("func_80944590",), - 0x809445D4:("func_809445D4",), - 0x80944630:("func_80944630",), - 0x809447A8:("func_809447A8",), - 0x80944818:("func_80944818",), - 0x809448A4:("func_809448A4",), - 0x809449D0:("func_809449D0",), - 0x80944A50:("func_80944A50",), - 0x80944E44:("func_80944E44",), - 0x80944EFC:("func_80944EFC",), - 0x80944FA8:("func_80944FA8",), - 0x8094506C:("func_8094506C",), + 0x80944320:("EnNwc_SpawnDust",), + 0x80944554:("EnNwc_FindGrog",), + 0x80944590:("EnNwc_PlayerReleasedBremanMarch",), + 0x809445D4:("EnNwc_IsFound",), + 0x80944630:("EnNwc_ChangeState",), + 0x809447A8:("EnNwc_ToggleState",), + 0x80944818:("EnNwc_CheckFound",), + 0x809448A4:("EnNwc_LoadNiwSkeleton",), + 0x809449D0:("EnNwc_CrowAtTheEnd",), + 0x80944A50:("EnNwc_Follow",), + 0x80944E44:("EnNwc_HopForward",), + 0x80944EFC:("EnNwc_RunAway",), + 0x80944FA8:("EnNwc_Turn",), + 0x8094506C:("EnNwc_CheckForBreman",), 0x809450C0:("EnNwc_Update",), 0x809451D8:("EnNwc_Draw",), - 0x8094529C:("func_8094529C",), - 0x80945310:("func_80945310",), + 0x8094529C:("EnNwc_OverrideLimbDraw",), + 0x80945310:("EnNwc_DrawAdultBody",), 0x809454F0:("ItemInbox_Init",), 0x80945524:("ItemInbox_Destroy",), 0x80945534:("ItemInbox_Idle",), @@ -7641,13 +7641,13 @@ 0x80952CC8:("EnHs_Init",), 0x80952DD0:("EnHs_Destroy",), 0x80952DFC:("func_80952DFC",), - 0x80952E50:("func_80952E50",), + 0x80952E50:("EnHs_UpdateChickPos",), 0x80952F00:("func_80952F00",), 0x80952FE0:("func_80952FE0",), 0x80953098:("func_80953098",), 0x80953180:("func_80953180",), - 0x809532C0:("func_809532C0",), - 0x809532D0:("func_809532D0",), + 0x809532C0:("EnHs_DoNothing",), + 0x809532D0:("EnHs_SceneTransitToBunnyHoodDialogue",), 0x80953354:("func_80953354",), 0x809533A0:("func_809533A0",), 0x8095345C:("func_8095345C",), @@ -7680,11 +7680,11 @@ 0x80956954:("EnKanban_Draw",), 0x809580C0:("EnAttackNiw_Init",), 0x809581F4:("EnAttackNiw_Destroy",), - 0x80958228:("func_80958228",), - 0x809585B0:("func_809585B0",), - 0x80958634:("func_80958634",), - 0x80958974:("func_80958974",), - 0x80958BE4:("func_80958BE4",), + 0x80958228:("EnAttackNiw_AnimateWingHead",), + 0x809585B0:("EnAttackNiw_IsOnScreen",), + 0x80958634:("EnAttackNiw_EnterViewFromOffscreen",), + 0x80958974:("EnAttackNiw_AimAtPlayer",), + 0x80958BE4:("EnAttackNiw_FlyAway",), 0x80958CA8:("EnAttackNiw_Update",), 0x80958F6C:("EnAttackNiw_OverrideLimbDraw",), 0x8095909C:("EnAttackNiw_Draw",),