From bbbf657b4b15ee2c7dbf76ef34df5170ff6fd475 Mon Sep 17 00:00:00 2001 From: mzxrules Date: Sun, 21 Feb 2021 09:25:53 -0500 Subject: z_en_peehat (#660) * decomp most of En_Peehat * z_en_peehat code decomp'd and OK * complete data migration * first pass at documentation * minor code clean-up * documentation pass * fix spec (hopefully), implement some of petrie's suggestions * implement requested changes * fix compiler warnings * implement fig's changes * implement roman's changes --- src/overlays/actors/ovl_En_Peehat/z_en_peehat.c | 1053 +++++++++++++++++++++-- src/overlays/actors/ovl_En_Peehat/z_en_peehat.h | 35 +- 2 files changed, 1016 insertions(+), 72 deletions(-) (limited to 'src') diff --git a/src/overlays/actors/ovl_En_Peehat/z_en_peehat.c b/src/overlays/actors/ovl_En_Peehat/z_en_peehat.c index 5385b049d..43c46d8ac 100644 --- a/src/overlays/actors/ovl_En_Peehat/z_en_peehat.c +++ b/src/overlays/actors/ovl_En_Peehat/z_en_peehat.c @@ -1,21 +1,52 @@ #include "z_en_peehat.h" +#include "overlays/actors/ovl_En_Bom/z_en_bom.h" +#include "overlays/effects/ovl_Effect_Ss_Hahen/z_eff_ss_hahen.h" #define FLAGS 0x01000015 #define THIS ((EnPeehat*)thisx) +#define GROUND_HOVER_HEIGHT 75.0f +#define MAX_LARVA 3 + void EnPeehat_Init(Actor* thisx, GlobalContext* globalCtx); void EnPeehat_Destroy(Actor* thisx, GlobalContext* globalCtx); void EnPeehat_Update(Actor* thisx, GlobalContext* globalCtx); void EnPeehat_Draw(Actor* thisx, GlobalContext* globalCtx); -extern UNK_TYPE D_06000350; -extern UNK_TYPE D_060005C4; -extern UNK_TYPE D_06000844; -extern UNK_TYPE D_060009C4; -extern UNK_TYPE D_06001C80; +void EnPeehat_Ground_SetStateGround(EnPeehat* this); +void EnPeehat_Flying_SetStateGround(EnPeehat* this); +void EnPeehat_Larva_SetStateSeekPlayer(EnPeehat* this); +void EnPeehat_Ground_StateGround(EnPeehat* this, GlobalContext* globalCtx); +void EnPeehat_Ground_SetStateRise(EnPeehat* this); +void EnPeehat_Flying_StateGrounded(EnPeehat* this, GlobalContext* globalCtx); +void EnPeehat_Flying_SetStateRise(EnPeehat* this); +void EnPeehat_Flying_StateFly(EnPeehat* this, GlobalContext* globalCtx); +void EnPeehat_Flying_SetStateLanding(EnPeehat* this); +void EnPeehat_Ground_StateRise(EnPeehat* this, GlobalContext* globalCtx); +void EnPeehat_Ground_SetStateHover(EnPeehat* this); +void EnPeehat_Flying_StateRise(EnPeehat* this, GlobalContext* globalCtx); +void EnPeehat_Ground_StateSeekPlayer(EnPeehat* this, GlobalContext* globalCtx); +void EnPeehat_Ground_SetStateReturnHome(EnPeehat* this); +void EnPeehat_Ground_SetStateLanding(EnPeehat* this); +void EnPeehat_Larva_StateSeekPlayer(EnPeehat* this, GlobalContext* globalCtx); +void EnPeehat_SetStateAttackRecoil(EnPeehat* this); +void EnPeehat_Ground_StateLanding(EnPeehat* this, GlobalContext* globalCtx); +void EnPeehat_Flying_StateLanding(EnPeehat* this, GlobalContext* globalCtx); +void EnPeehat_Ground_StateHover(EnPeehat* this, GlobalContext* globalCtx); +void EnPeehat_Ground_StateReturnHome(EnPeehat* this, GlobalContext* globalCtx); +void EnPeehat_StateAttackRecoil(EnPeehat* this, GlobalContext* globalCtx); +void EnPeehat_StateBoomerangStunned(EnPeehat* this, GlobalContext* globalCtx); +void EnPeehat_Adult_StateDie(EnPeehat* this, GlobalContext* globalCtx); +void EnPeehat_SetStateExplode(EnPeehat* this); +void EnPeehat_StateExplode(EnPeehat* this, GlobalContext* globalCtx); + +extern SkeletonHeader D_06001C80; +extern AnimationHeader D_060009C4; +extern AnimationHeader D_06000844; +extern AnimationHeader D_060005C4; +extern AnimationHeader D_06000350; -/* const ActorInit En_Peehat_InitVars = { ACTOR_EN_PEEHAT, ACTORCAT_ENEMY, @@ -28,7 +59,7 @@ const ActorInit En_Peehat_InitVars = { (ActorFunc)EnPeehat_Draw, }; -static ColliderCylinderInit D_80AD2740 = { +static ColliderCylinderInit sCylinderInit = { { COLTYPE_WOOD, AT_NONE, @@ -48,27 +79,7 @@ static ColliderCylinderInit D_80AD2740 = { { 50, 160, -70, { 0, 0, 0 } }, }; -static ColliderQuadInit D_80AD27A0 = { - { - COLTYPE_METAL, - AT_ON | AT_TYPE_ENEMY, - AC_ON | AC_HARD | AC_TYPE_PLAYER, - OC1_NONE, - OC2_NONE, - COLSHAPE_QUAD, - }, - { - ELEMTYPE_UNK0, - { 0xFFCFFFFF, 0x00, 0x10 }, - { 0xFFCFFFFF, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_ON, - OCELEM_NONE, - }, - { { { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } } }, -}; - -static ColliderJntSphElementInit D_80AD276C[1] = { +static ColliderJntSphElementInit sJntSphElemInit[1] = { { { ELEMTYPE_UNK0, @@ -82,7 +93,7 @@ static ColliderJntSphElementInit D_80AD276C[1] = { }, }; -static ColliderJntSphInit D_80AD2790 = { +static ColliderJntSphInit sJntSphInit = { { COLTYPE_HIT6, AT_NONE, @@ -92,85 +103,985 @@ static ColliderJntSphInit D_80AD2790 = { COLSHAPE_JNTSPH, }, 1, - D_80AD276C, + sJntSphElemInit, }; -*/ -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80ACF4A0.s") -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/EnPeehat_Init.s") +static ColliderQuadInit sQuadInit = { + { + COLTYPE_METAL, + AT_ON | AT_TYPE_ENEMY, + AC_ON | AC_HARD | AC_TYPE_PLAYER, + OC1_NONE, + OC2_NONE, + COLSHAPE_QUAD, + }, + { + ELEMTYPE_UNK0, + { 0xFFCFFFFF, 0x00, 0x10 }, + { 0xFFCFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_NONE, + }, + { { { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } } }, +}; + +typedef enum { + /* 00 */ PEAHAT_DMG_EFF_ATTACK = 0, + /* 06 */ PEAHAT_DMG_EFF_LIGHT_ICE_ARROW = 6, + /* 12 */ PEAHAT_DMG_EFF_FIRE = 12, + /* 13 */ PEAHAT_DMG_EFF_HOOKSHOT = 13, + /* 14 */ PEAHAT_DMG_EFF_BOOMERANG = 14, + /* 15 */ PEAHAT_DMG_EFF_NUT = 15 +} DamageEffect; + +static DamageTable sDamageTable = { + /* Deku nut */ DMG_ENTRY(0, PEAHAT_DMG_EFF_NUT), + /* Deku stick */ DMG_ENTRY(2, PEAHAT_DMG_EFF_ATTACK), + /* Slingshot */ DMG_ENTRY(1, PEAHAT_DMG_EFF_ATTACK), + /* Explosive */ DMG_ENTRY(2, PEAHAT_DMG_EFF_ATTACK), + /* Boomerang */ DMG_ENTRY(0, PEAHAT_DMG_EFF_BOOMERANG), + /* Normal arrow */ DMG_ENTRY(2, PEAHAT_DMG_EFF_ATTACK), + /* Hammer swing */ DMG_ENTRY(2, PEAHAT_DMG_EFF_ATTACK), + /* Hookshot */ DMG_ENTRY(2, PEAHAT_DMG_EFF_HOOKSHOT), + /* Kokiri sword */ DMG_ENTRY(1, PEAHAT_DMG_EFF_ATTACK), + /* Master sword */ DMG_ENTRY(2, PEAHAT_DMG_EFF_ATTACK), + /* Giant's Knife */ DMG_ENTRY(4, PEAHAT_DMG_EFF_ATTACK), + /* Fire arrow */ DMG_ENTRY(4, PEAHAT_DMG_EFF_FIRE), + /* Ice arrow */ DMG_ENTRY(2, PEAHAT_DMG_EFF_ATTACK), + /* Light arrow */ DMG_ENTRY(2, PEAHAT_DMG_EFF_ATTACK), + /* Unk arrow 1 */ DMG_ENTRY(2, PEAHAT_DMG_EFF_ATTACK), + /* Unk arrow 2 */ DMG_ENTRY(2, PEAHAT_DMG_EFF_ATTACK), + /* Unk arrow 3 */ DMG_ENTRY(2, PEAHAT_DMG_EFF_ATTACK), + /* Fire magic */ DMG_ENTRY(3, PEAHAT_DMG_EFF_FIRE), + /* Ice magic */ DMG_ENTRY(0, PEAHAT_DMG_EFF_LIGHT_ICE_ARROW), + /* Light magic */ DMG_ENTRY(0, PEAHAT_DMG_EFF_LIGHT_ICE_ARROW), + /* Shield */ DMG_ENTRY(0, PEAHAT_DMG_EFF_ATTACK), + /* Mirror Ray */ DMG_ENTRY(0, PEAHAT_DMG_EFF_ATTACK), + /* Kokiri spin */ DMG_ENTRY(1, PEAHAT_DMG_EFF_ATTACK), + /* Giant spin */ DMG_ENTRY(4, PEAHAT_DMG_EFF_ATTACK), + /* Master spin */ DMG_ENTRY(2, PEAHAT_DMG_EFF_ATTACK), + /* Kokiri jump */ DMG_ENTRY(2, PEAHAT_DMG_EFF_ATTACK), + /* Giant jump */ DMG_ENTRY(8, PEAHAT_DMG_EFF_ATTACK), + /* Master jump */ DMG_ENTRY(4, PEAHAT_DMG_EFF_ATTACK), + /* Unknown 1 */ DMG_ENTRY(0, PEAHAT_DMG_EFF_ATTACK), + /* Unblockable */ DMG_ENTRY(0, PEAHAT_DMG_EFF_ATTACK), + /* Hammer jump */ DMG_ENTRY(4, PEAHAT_DMG_EFF_ATTACK), + /* Unknown 2 */ DMG_ENTRY(0, PEAHAT_DMG_EFF_ATTACK), +}; + +typedef enum { + /* 00 */ PEAHAT_STATE_DYING, + /* 01 */ PEAHAT_STATE_EXPLODE, + /* 03 */ PEAHAT_STATE_3 = 3, + /* 04 */ PEAHAT_STATE_4, + /* 05 */ PEAHAT_STATE_FLY, + /* 07 */ PEAHAT_STATE_ATTACK_RECOIL = 7, + /* 08 */ PEAHAT_STATE_8, + /* 09 */ PEAHAT_STATE_9, + /* 10 */ PEAHAT_STATE_LANDING, + /* 12 */ PEAHAT_STATE_RETURN_HOME = 12, + /* 13 */ PEAHAT_STATE_STUNNED, + /* 14 */ PEAHAT_STATE_SEEK_PLAYER, + /* 15 */ PEAHAT_STATE_15 +} PeahatState; + +static InitChainEntry sInitChain[] = { + ICHAIN_F32(targetArrowOffset, 700, ICHAIN_STOP), +}; + +void EnPeehat_SetupAction(EnPeehat* this, EnPeehatActionFunc actionFunc) { + this->actionFunc = actionFunc; +} + +void EnPeehat_Init(Actor* thisx, GlobalContext* globalCtx) { + EnPeehat* this = THIS; + + Actor_ProcessInitChain(thisx, sInitChain); + Actor_SetScale(thisx, 36.0f * 0.001f); + SkelAnime_Init(globalCtx, &this->skelAnime, &D_06001C80, &D_060009C4, this->jointTable, this->morphTable, 24); + ActorShape_Init(&this->actor.shape, 100.0f, ActorShadow_DrawCircle, 27.0f); + this->actor.focus.pos = this->actor.world.pos; + this->unk2D4 = 0; + this->actor.world.rot.y = 0; + this->actor.colChkInfo.mass = MASS_HEAVY; + this->actor.colChkInfo.health = 6; + this->actor.colChkInfo.damageTable = &sDamageTable; + this->actor.floorHeight = this->actor.world.pos.y; + Collider_InitCylinder(globalCtx, &this->colCylinder); + Collider_SetCylinder(globalCtx, &this->colCylinder, thisx, &sCylinderInit); + Collider_InitQuad(globalCtx, &this->colQuad); + Collider_SetQuad(globalCtx, &this->colQuad, thisx, &sQuadInit); + Collider_InitJntSph(globalCtx, &this->colJntSph); + Collider_SetJntSph(globalCtx, &this->colJntSph, thisx, &sJntSphInit, this->colJntSphItemList); + + this->actor.naviEnemyId = 0x48; + this->xzDistToRise = 740.0f; + this->xzDistMax = 1200.0f; + this->actor.uncullZoneForward = 4000.0f; + this->actor.uncullZoneScale = 800.0f; + this->actor.uncullZoneDownward = 1800.0f; + switch (this->actor.params) { + case PEAHAT_TYPE_GROUNDED: + EnPeehat_Ground_SetStateGround(this); + break; + case PEAHAT_TYPE_FLYING: + this->actor.uncullZoneForward = 4200.0f; + this->xzDistToRise = 2800.0f; + this->xzDistMax = 1400.0f; + EnPeehat_Flying_SetStateGround(this); + this->actor.flags &= ~1; + break; + case PEAHAT_TYPE_LARVA: + this->actor.scale.x = this->actor.scale.z = 0.006f; + this->actor.scale.y = 0.003f; + this->colCylinder.dim.radius = 25; + this->colCylinder.dim.height = 15; + this->colCylinder.dim.yShift = -5; + this->colCylinder.info.bumper.dmgFlags = 0x1F824; + this->colQuad.base.atFlags = AT_ON | AT_TYPE_ENEMY; + this->colQuad.base.acFlags = AC_ON | AC_TYPE_PLAYER; + this->actor.naviEnemyId = 0x49; // Larva + EnPeehat_Larva_SetStateSeekPlayer(this); + break; + } +} + +void EnPeehat_Destroy(Actor* thisx, GlobalContext* globalCtx) { + EnPeehat* this = THIS; + EnPeehat* parent; + + Collider_DestroyCylinder(globalCtx, &this->colCylinder); + Collider_DestroyJntSph(globalCtx, &this->colJntSph); + + // If PEAHAT_TYPE_LARVA, decrement total larva spawned + if (this->actor.params > 0) { + parent = (EnPeehat*)this->actor.parent; + if (parent != NULL && parent->actor.update != NULL) { + parent->unk2FA--; + } + } +} + +void EnPeehat_SpawnDust(GlobalContext* globalCtx, EnPeehat* this, Vec3f* pos, f32 arg3, s32 arg4, f32 arg5, f32 arg6) { + Vec3f dustPos; + Vec3f dustVel = { 0.0f, 8.0f, 0.0f }; + Vec3f dustAccel = { 0.0f, -1.5f, 0.0f }; + f32 rot; // radians + s32 pScale; + + rot = (Rand_ZeroOne() - 0.5f) * 6.28f; + dustPos.y = this->actor.floorHeight; + dustPos.x = Math_SinF(rot) * arg3 + pos->x; + dustPos.z = Math_CosF(rot) * arg3 + pos->z; + dustAccel.x = (Rand_ZeroOne() - 0.5f) * arg5; + dustAccel.z = (Rand_ZeroOne() - 0.5f) * arg5; + dustVel.y += (Rand_ZeroOne() - 0.5f) * 4.0f; + pScale = (Rand_ZeroOne() * 5 + 12) * arg6; + EffectSsHahen_Spawn(globalCtx, &dustPos, &dustVel, &dustAccel, arg4, pScale, HAHEN_OBJECT_DEFAULT, 10, NULL); +} + +/** + * Handles being hit when on the ground + */ +void EnPeehat_HitWhenGrounded(EnPeehat* this, GlobalContext* globalCtx) { + this->colCylinder.base.acFlags &= ~AC_HIT; + if ((globalCtx->gameplayFrames & 0xF) == 0) { + Vec3f itemDropPos = this->actor.world.pos; + itemDropPos.y += 70.0f; + Item_DropCollectibleRandom(globalCtx, &this->actor, &itemDropPos, 0x40); + Item_DropCollectibleRandom(globalCtx, &this->actor, &itemDropPos, 0x40); + Item_DropCollectibleRandom(globalCtx, &this->actor, &itemDropPos, 0x40); + this->unk2D4 = 240; + } else { + s32 i; + this->colCylinder.base.acFlags &= ~AC_HIT; + for (i = MAX_LARVA - this->unk2FA; i > 0; i--) { + Actor* larva = + Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_EN_PEEHAT, + Rand_CenteredFloat(25.0f) + this->actor.world.pos.x, + Rand_CenteredFloat(25.0f) + (this->actor.world.pos.y + 50.0f), + Rand_CenteredFloat(25.0f) + this->actor.world.pos.z, 0, 0, 0, PEAHAT_TYPE_LARVA); + if (larva != NULL) { + larva->velocity.y = 6.0f; + larva->shape.rot.y = larva->world.rot.y = Rand_CenteredFloat(0xFFFF); + this->unk2FA++; + } + } + this->unk2D4 = 8; + } + Audio_PlayActorSound2(&this->actor, NA_SE_EN_PIHAT_DAMAGE); +} + +void EnPeehat_Ground_SetStateGround(EnPeehat* this) { + Animation_Change(&this->skelAnime, &D_060009C4, 0.0f, 3.0f, Animation_GetLastFrame(&D_060009C4), 2, 0.0f); + this->seekPlayerTimer = 600; + this->unk2D4 = 0; + this->unk2FA = 0; + this->state = PEAHAT_STATE_3; + this->colCylinder.base.acFlags &= ~AC_HIT; + EnPeehat_SetupAction(this, EnPeehat_Ground_StateGround); +} + +void EnPeehat_Ground_StateGround(EnPeehat* this, GlobalContext* globalCtx) { + if (gSaveContext.nightFlag == 0) { + this->actor.flags |= 1; + if (this->riseDelayTimer == 0) { + if (this->actor.xzDistToPlayer < this->xzDistToRise) { + EnPeehat_Ground_SetStateRise(this); + } + } else { + Math_SmoothStepToF(&this->actor.shape.yOffset, -1000.0f, 1.0f, 10.0f, 0.0f); + this->riseDelayTimer--; + } + } else { + this->actor.flags &= ~1; + Math_SmoothStepToF(&this->actor.shape.yOffset, -1000.0f, 1.0f, 50.0f, 0.0f); + if (this->unk2D4 != 0) { + this->unk2D4--; + if (this->unk2D4 & 4) { + Math_SmoothStepToF(&this->scaleShift, 0.205f, 1.0f, 0.235f, 0.0f); + } else { + Math_SmoothStepToF(&this->scaleShift, 0.0f, 1.0f, 0.005f, 0.0f); + } + } else if (this->colCylinder.base.acFlags & AC_HIT) { + EnPeehat_HitWhenGrounded(this, globalCtx); + } + } +} + +void EnPeehat_Flying_SetStateGround(EnPeehat* this) { + Animation_Change(&this->skelAnime, &D_060009C4, 0.0f, 3.0f, Animation_GetLastFrame(&D_060009C4), 2, 0.0f); + this->seekPlayerTimer = 400; + this->unk2D4 = 0; + this->unk2FA = 0; // @bug: overwrites number of child larva spawned, allowing for more than MAX_LARVA spawns + this->state = PEAHAT_STATE_4; + EnPeehat_SetupAction(this, EnPeehat_Flying_StateGrounded); +} + +void EnPeehat_Flying_StateGrounded(EnPeehat* this, GlobalContext* globalCtx) { + if (gSaveContext.nightFlag == 0) { + if (this->actor.xzDistToPlayer < this->xzDistToRise) { + EnPeehat_Flying_SetStateRise(this); + } + } else { + Math_SmoothStepToF(&this->actor.shape.yOffset, -1000.0f, 1.0f, 50.0f, 0.0f); + if (this->unk2D4 != 0) { + this->unk2D4--; + if (this->unk2D4 & 4) { + Math_SmoothStepToF(&this->scaleShift, 0.205f, 1.0f, 0.235f, 0.0f); + } else { + Math_SmoothStepToF(&this->scaleShift, 0.0f, 1.0f, 0.005f, 0.0f); + } + } else if (this->colCylinder.base.acFlags & AC_HIT) { + EnPeehat_HitWhenGrounded(this, globalCtx); + } + } +} + +void EnPeehat_Flying_SetStateFly(EnPeehat* this) { + Animation_PlayLoop(&this->skelAnime, &D_060005C4); + this->state = PEAHAT_STATE_FLY; + EnPeehat_SetupAction(this, EnPeehat_Flying_StateFly); +} + +void EnPeehat_Flying_StateFly(EnPeehat* this, GlobalContext* globalCtx) { + Audio_PlayActorSound2(&this->actor, NA_SE_EN_PIHAT_FLY - SFX_FLAG); + SkelAnime_Update(&this->skelAnime); + if ((gSaveContext.nightFlag != 0) || this->xzDistToRise < this->actor.xzDistToPlayer) { + EnPeehat_Flying_SetStateLanding(this); + } else if (this->actor.xzDistToPlayer < this->xzDistMax) { + if (this->unk2FA < MAX_LARVA && (globalCtx->gameplayFrames & 7) == 0) { + Actor* larva = Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_EN_PEEHAT, + Rand_CenteredFloat(25.0f) + this->actor.world.pos.x, + Rand_CenteredFloat(5.0f) + this->actor.world.pos.y, + Rand_CenteredFloat(25.0f) + this->actor.world.pos.z, 0, 0, 0, 1); + if (larva != NULL) { + larva->shape.rot.y = larva->world.rot.y = Rand_CenteredFloat(0xFFFF); + this->unk2FA++; + } + } + } + this->bladeRot += this->bladeRotVel; +} + +void EnPeehat_Ground_SetStateRise(EnPeehat* this) { + f32 lastFrame; + + lastFrame = Animation_GetLastFrame(&D_060009C4); + if (this->state != PEAHAT_STATE_STUNNED) { + Animation_Change(&this->skelAnime, &D_060009C4, 0.0f, 3.0f, lastFrame, 2, 0.0f); + } + this->state = PEAHAT_STATE_8; + this->animTimer = lastFrame; + Audio_PlayActorSound2(&this->actor, NA_SE_EN_PIHAT_UP); + EnPeehat_SetupAction(this, EnPeehat_Ground_StateRise); +} + +void EnPeehat_Ground_StateRise(EnPeehat* this, GlobalContext* globalCtx) { + Math_SmoothStepToF(&this->actor.shape.yOffset, 0.0f, 1.0f, 50.0f, 0.0f); + if (Math_SmoothStepToS(&this->bladeRotVel, 4000, 1, 800, 0) == 0) { + if (this->animTimer != 0) { + this->animTimer--; + if (this->skelAnime.playSpeed == 0.0f) { + if (this->animTimer == 0) { + this->animTimer = 40; + this->skelAnime.playSpeed = 1.0f; + } + } + } + if (SkelAnime_Update(&this->skelAnime) || this->animTimer == 0) { + EnPeehat_Ground_SetStateHover(this); + } else { + this->actor.world.pos.y += 6.5f; + } + if (this->actor.world.pos.y - this->actor.floorHeight < 80.0f) { + Vec3f pos = this->actor.world.pos; + pos.y = this->actor.floorHeight; + func_80033480(globalCtx, &pos, 90.0f, 1, 0x96, 100, 1); + } + } + EnPeehat_SpawnDust(globalCtx, this, &this->actor.world.pos, 75.0f, 2, 1.05f, 2.0f); + Math_SmoothStepToF(&this->scaleShift, 0.075f, 1.0f, 0.005f, 0.0f); + this->bladeRot += this->bladeRotVel; +} + +void EnPeehat_Flying_SetStateRise(EnPeehat* this) { + f32 lastFrame; + + lastFrame = Animation_GetLastFrame(&D_060009C4); + if (this->state != PEAHAT_STATE_STUNNED) { + Animation_Change(&this->skelAnime, &D_060009C4, 0.0f, 3.0f, lastFrame, 2, 0.0f); + } + this->state = PEAHAT_STATE_9; + this->animTimer = lastFrame; + Audio_PlayActorSound2(&this->actor, NA_SE_EN_PIHAT_UP); + EnPeehat_SetupAction(this, EnPeehat_Flying_StateRise); +} + +void EnPeehat_Flying_StateRise(EnPeehat* this, GlobalContext* globalCtx) { + Math_SmoothStepToF(&this->actor.shape.yOffset, 0.0f, 1.0f, 50.0f, 0.0f); + if (Math_SmoothStepToS(&this->bladeRotVel, 4000, 1, 800, 0) == 0) { + if (this->animTimer != 0) { + this->animTimer--; + if (this->skelAnime.playSpeed == 0.0f) { + if (this->animTimer == 0) { + this->animTimer = 40; + this->skelAnime.playSpeed = 1.0f; + } + } + } + if (SkelAnime_Update(&this->skelAnime) || this->animTimer == 0) { + this->unk2FA = 0; // @bug: overwrites number of child larva spawned, allowing for more than MAX_LARVA spawns + EnPeehat_Flying_SetStateFly(this); + } else { + this->actor.world.pos.y += 18.0f; + } + if (this->actor.world.pos.y - this->actor.floorHeight < 80.0f) { + Vec3f pos = this->actor.world.pos; + pos.y = this->actor.floorHeight; + func_80033480(globalCtx, &pos, 90.0f, 1, 0x96, 100, 1); + } + } + EnPeehat_SpawnDust(globalCtx, this, &this->actor.world.pos, 75.0f, 2, 1.05f, 2.0f); + Math_SmoothStepToF(&this->scaleShift, 0.075f, 1.0f, 0.005f, 0.0f); + this->bladeRot += this->bladeRotVel; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/EnPeehat_Destroy.s") +void EnPeehat_Ground_SetStateSeekPlayer(EnPeehat* this) { + Animation_PlayLoop(&this->skelAnime, &D_060005C4); + this->state = PEAHAT_STATE_SEEK_PLAYER; + this->unk2E0 = 0.0f; + EnPeehat_SetupAction(this, EnPeehat_Ground_StateSeekPlayer); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80ACF788.s") +void EnPeehat_Ground_StateSeekPlayer(EnPeehat* this, GlobalContext* globalCtx) { + Player* player = PLAYER; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80ACF920.s") + Math_SmoothStepToF(&this->actor.speedXZ, 3.0f, 1.0f, 0.25f, 0.0f); + Math_SmoothStepToF(&this->actor.world.pos.y, this->actor.floorHeight + 80.0f, 1.0f, 3.0f, 0.0f); + if (this->seekPlayerTimer <= 0) { + EnPeehat_Ground_SetStateLanding(this); + this->riseDelayTimer = 40; + } else { + this->seekPlayerTimer--; + } + if ((gSaveContext.nightFlag == 0) && + (Math_Vec3f_DistXZ(&this->actor.home.pos, &player->actor.world.pos) < this->xzDistMax)) { + Math_SmoothStepToS(&this->actor.world.rot.y, this->actor.yawTowardsPlayer, 1, 1000, 0); + if (this->unk2FA != 0) { + this->actor.shape.rot.y += 0x1C2; + } else { + this->actor.shape.rot.y -= 0x1C2; + } + } else { + EnPeehat_Ground_SetStateReturnHome(this); + } + SkelAnime_Update(&this->skelAnime); + Math_SmoothStepToS(&this->bladeRotVel, 4000, 1, 500, 0); + this->bladeRot += this->bladeRotVel; + Math_SmoothStepToF(&this->scaleShift, 0.075f, 1.0f, 0.005f, 0.0f); + Audio_PlayActorSound2(&this->actor, NA_SE_EN_PIHAT_FLY - SFX_FLAG); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80ACFB34.s") +void EnPeehat_Larva_SetStateSeekPlayer(EnPeehat* this) { + Animation_PlayLoop(&this->skelAnime, &D_060005C4); + this->state = PEAHAT_STATE_SEEK_PLAYER; + this->unk2D4 = 0; + EnPeehat_SetupAction(this, EnPeehat_Larva_StateSeekPlayer); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80ACFBCC.s") +void EnPeehat_Larva_StateSeekPlayer(EnPeehat* this, GlobalContext* globalCtx) { + f32 speedXZ = 5.3f; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80ACFD20.s") + if (this->actor.xzDistToPlayer <= 5.3f) { + speedXZ = this->actor.xzDistToPlayer + 0.0005f; + } + if (this->actor.parent != NULL && this->actor.parent->update == NULL) { + this->actor.parent = NULL; + } + this->actor.speedXZ = speedXZ; + if (this->actor.world.pos.y - this->actor.floorHeight >= 70.0f) { + Math_SmoothStepToF(&this->actor.velocity.y, -1.3f, 1.0f, 0.5f, 0.0f); + } else { + Math_SmoothStepToF(&this->actor.velocity.y, -0.135f, 1.0f, 0.05f, 0.0f); + } + if (this->unk2D4 == 0) { + Math_SmoothStepToS(&this->actor.world.rot.y, this->actor.yawTowardsPlayer, 1, 830, 0); + } else { + this->unk2D4--; + } + this->actor.shape.rot.y += 0x15E; + SkelAnime_Update(&this->skelAnime); + Math_SmoothStepToS(&this->bladeRotVel, 4000, 1, 500, 0); + this->bladeRot += this->bladeRotVel; + Math_SmoothStepToF(&this->scaleShift, 0.075f, 1.0f, 0.005f, 0.0f); + Audio_PlayActorSound2(&this->actor, NA_SE_EN_PIHAT_SM_FLY - SFX_FLAG); + if (this->colQuad.base.atFlags & AT_BOUNCED) { + this->actor.colChkInfo.health = 0; + this->colQuad.base.acFlags = this->colQuad.base.acFlags & ~AC_BOUNCED; + EnPeehat_SetStateAttackRecoil(this); + } else if ((this->colQuad.base.atFlags & AT_HIT) || (this->colCylinder.base.acFlags & AC_HIT) || + (this->actor.bgCheckFlags & 1)) { + Player* player = PLAYER; + this->colQuad.base.atFlags &= ~AT_HIT; + if (!(this->colCylinder.base.acFlags & AC_HIT) && &player->actor == this->colQuad.base.at) { + if (Rand_ZeroOne() > 0.5f) { + this->actor.world.rot.y += 0x2000; + } else { + this->actor.world.rot.y -= 0x2000; + } + this->unk2D4 = 40; + } else if (this->colCylinder.base.acFlags & AC_HIT || this->actor.bgCheckFlags & 1) { + Vec3f zeroVec = { 0, 0, 0 }; + s32 i; + for (i = 4; i >= 0; i--) { + Vec3f pos; + pos.x = Rand_CenteredFloat(20.0f) + this->actor.world.pos.x; + pos.y = Rand_CenteredFloat(10.0f) + this->actor.world.pos.y; + pos.z = Rand_CenteredFloat(20.0f) + this->actor.world.pos.z; + EffectSsDeadDb_Spawn(globalCtx, &pos, &zeroVec, &zeroVec, 40, 7, 255, 255, 255, 255, 255, 0, 0, 1, 9, + 1); + } + } + if (&player->actor != this->colQuad.base.at || this->colCylinder.base.acFlags & AC_HIT) { + if (!(this->actor.bgCheckFlags & 1)) { + EffectSsDeadSound_SpawnStationary(globalCtx, &this->actor.projectedPos, NA_SE_EN_PIHAT_SM_DEAD, 1, 1, + 40); + } + Item_DropCollectibleRandom(globalCtx, &this->actor, &this->actor.world.pos, 0x20); + Actor_Kill(&this->actor); + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80ACFDAC.s") +void EnPeehat_Ground_SetStateLanding(EnPeehat* this) { + this->state = PEAHAT_STATE_LANDING; + Animation_PlayOnce(&this->skelAnime, &D_06000350); + EnPeehat_SetupAction(this, EnPeehat_Ground_StateLanding); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80ACFEB0.s") +void EnPeehat_Ground_StateLanding(EnPeehat* this, GlobalContext* globalCtx) { + Math_SmoothStepToF(&this->actor.shape.yOffset, -1000.0f, 1.0f, 50.0f, 0.0f); + Math_SmoothStepToF(&this->actor.speedXZ, 0.0f, 1.0f, 1.0f, 0.0f); + Math_SmoothStepToS(&this->actor.shape.rot.x, 0, 1, 50, 0); + if (SkelAnime_Update(&this->skelAnime)) { + EnPeehat_Ground_SetStateGround(this); + this->actor.world.pos.y = this->actor.floorHeight; + Audio_PlayActorSound2(&this->actor, NA_SE_EN_PIHAT_LAND); + } else if (this->actor.floorHeight < this->actor.world.pos.y) { + Math_SmoothStepToF(&this->actor.world.pos.y, this->actor.floorHeight, 0.3f, 3.5f, 0.25f); + if (this->actor.world.pos.y - this->actor.floorHeight < 60.0f) { + Vec3f pos = this->actor.world.pos; + pos.y = this->actor.floorHeight; + func_80033480(globalCtx, &pos, 80.0f, 1, 150, 100, 1); + EnPeehat_SpawnDust(globalCtx, this, &pos, 75.0f, 2, 1.05f, 2.0f); + } + } + Math_SmoothStepToS(&this->bladeRotVel, 0, 1, 100, 0); + this->bladeRot += this->bladeRotVel; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80ACFEF8.s") +void EnPeehat_Flying_SetStateLanding(EnPeehat* this) { + Animation_PlayOnce(&this->skelAnime, &D_06000350); + this->state = PEAHAT_STATE_LANDING; + EnPeehat_SetupAction(this, EnPeehat_Flying_StateLanding); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD0070.s") +void EnPeehat_Flying_StateLanding(EnPeehat* this, GlobalContext* globalCtx) { + Math_SmoothStepToF(&this->actor.shape.yOffset, -1000.0f, 1.0f, 50.0f, 0.0f); + Math_SmoothStepToF(&this->actor.speedXZ, 0.0f, 1.0f, 1.0f, 0.0f); + Math_SmoothStepToS(&this->actor.shape.rot.x, 0, 1, 50, 0); + if (SkelAnime_Update(&this->skelAnime)) { + EnPeehat_Flying_SetStateGround(this); + Audio_PlayActorSound2(&this->actor, NA_SE_EN_PIHAT_LAND); + this->actor.world.pos.y = this->actor.floorHeight; + } else if (this->actor.floorHeight < this->actor.world.pos.y) { + Math_SmoothStepToF(&this->actor.world.pos.y, this->actor.floorHeight, 0.3f, 13.5f, 0.25f); + if (this->actor.world.pos.y - this->actor.floorHeight < 60.0f) { + Vec3f pos = this->actor.world.pos; + pos.y = this->actor.floorHeight; + func_80033480(globalCtx, &pos, 80.0f, 1, 150, 100, 1); + EnPeehat_SpawnDust(globalCtx, this, &pos, 75.0f, 2, 1.05f, 2.0f); + } + } + Math_SmoothStepToS(&this->bladeRotVel, 0, 1, 100, 0); + this->bladeRot += this->bladeRotVel; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD0118.s") +void EnPeehat_Ground_SetStateHover(EnPeehat* this) { + Animation_PlayLoop(&this->skelAnime, &D_060005C4); + this->actor.speedXZ = Rand_ZeroOne() * 0.5f + 2.5f; + this->unk2D4 = Rand_ZeroOne() * 10 + 10; + this->state = PEAHAT_STATE_15; + EnPeehat_SetupAction(this, EnPeehat_Ground_StateHover); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD02E4.s") +void EnPeehat_Ground_StateHover(EnPeehat* this, GlobalContext* globalCtx) { + f32 cos; + Player* player = PLAYER; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD038C.s") + // hover but don't gain altitude + if (this->actor.world.pos.y - this->actor.floorHeight > 75.0f) { + this->actor.world.pos.y -= 1.0f; + } + this->actor.world.pos.y += Math_CosF(this->unk2E0) * 1.4f; + cos = Math_CosF(this->unk2E0) * 0.18f; + this->unk2E0 += ((0.0f <= cos) ? cos : -cos) + 0.07f; + this->unk2D4--; + if (this->unk2D4 <= 0) { + this->actor.speedXZ = Rand_ZeroOne() * 0.5f + 2.5f; + this->unk2D4 = Rand_ZeroOne() * 10.0f + 10.0f; + this->unk2F4 = (Rand_ZeroOne() - 0.5f) * 1000.0f; + } + SkelAnime_Update(&this->skelAnime); + this->actor.world.rot.y += this->unk2F4; + if (this->seekPlayerTimer <= 0) { + EnPeehat_Ground_SetStateLanding(this); + this->riseDelayTimer = 40; + } else { + this->seekPlayerTimer--; + } + this->actor.shape.rot.y += 0x15E; + // if daytime, and the player is close to the initial spawn position + if ((gSaveContext.nightFlag == 0) && + Math_Vec3f_DistXZ(&this->actor.home.pos, &player->actor.world.pos) < this->xzDistMax) { + this->actor.world.rot.y = this->actor.yawTowardsPlayer; + EnPeehat_Ground_SetStateSeekPlayer(this); + this->unk2FA = globalCtx->gameplayFrames & 1; + } else { + EnPeehat_Ground_SetStateReturnHome(this); + } + Math_SmoothStepToS(&this->bladeRotVel, 4000, 1, 500, 0); + this->bladeRot += this->bladeRotVel; + Math_SmoothStepToF(&this->scaleShift, 0.075f, 1.0f, 0.005f, 0.0f); + Audio_PlayActorSound2(&this->actor, NA_SE_EN_PIHAT_FLY - SFX_FLAG); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD0558.s") +void EnPeehat_Ground_SetStateReturnHome(EnPeehat* this) { + this->state = PEAHAT_STATE_RETURN_HOME; + this->actor.speedXZ = 2.5f; + EnPeehat_SetupAction(this, EnPeehat_Ground_StateReturnHome); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD05A8.s") +void EnPeehat_Ground_StateReturnHome(EnPeehat* this, GlobalContext* globalCtx) { + f32 cos; + s16 yRot; + Player* player; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD0720.s") + player = PLAYER; + if (this->actor.world.pos.y - this->actor.floorHeight > 75.0f) { + this->actor.world.pos.y -= 1.0f; + } else { + this->actor.world.pos.y += 1.0f; + } + this->actor.world.pos.y += Math_CosF(this->unk2E0) * 1.4f; + cos = Math_CosF(this->unk2E0) * 0.18f; + this->unk2E0 += ((0.0f <= cos) ? cos : -cos) + 0.07f; + yRot = Math_Vec3f_Yaw(&this->actor.world.pos, &this->actor.home.pos); + Math_SmoothStepToS(&this->actor.world.rot.y, yRot, 1, 600, 0); + Math_SmoothStepToS(&this->actor.shape.rot.x, 4500, 1, 600, 0); + this->actor.shape.rot.y += 0x15E; + this->bladeRot += this->bladeRotVel; + if (Math_Vec3f_DistXZ(&this->actor.world.pos, &this->actor.home.pos) < 2.0f) { + EnPeehat_Ground_SetStateLanding(this); + this->riseDelayTimer = 60; + } + if (gSaveContext.nightFlag == 0 && + Math_Vec3f_DistXZ(&this->actor.home.pos, &player->actor.world.pos) < this->xzDistMax) { + this->seekPlayerTimer = 400; + EnPeehat_Ground_SetStateSeekPlayer(this); + this->unk2FA = (globalCtx->gameplayFrames & 1); + } + Audio_PlayActorSound2(&this->actor, NA_SE_EN_PIHAT_FLY - SFX_FLAG); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD076C.s") +void EnPeehat_SetStateAttackRecoil(EnPeehat* this) { + Animation_MorphToPlayOnce(&this->skelAnime, &D_06000844, -4.0f); + this->state = PEAHAT_STATE_ATTACK_RECOIL; + this->actor.speedXZ = -9.0f; + this->actor.world.rot.y = this->actor.yawTowardsPlayer; + EnPeehat_SetupAction(this, EnPeehat_StateAttackRecoil); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD0B3C.s") +void EnPeehat_StateAttackRecoil(EnPeehat* this, GlobalContext* globalCtx) { + this->bladeRot += this->bladeRotVel; + SkelAnime_Update(&this->skelAnime); + this->actor.speedXZ += 0.5f; + if (this->actor.speedXZ == 0.0f) { + // Is PEAHAT_TYPE_LARVA + if (this->actor.params > 0) { + Vec3f zeroVec = { 0, 0, 0 }; + s32 i; + for (i = 4; i >= 0; i--) { + Vec3f pos; + pos.x = Rand_CenteredFloat(20.0f) + this->actor.world.pos.x; + pos.y = Rand_CenteredFloat(10.0f) + this->actor.world.pos.y; + pos.z = Rand_CenteredFloat(20.0f) + this->actor.world.pos.z; + EffectSsDeadDb_Spawn(globalCtx, &pos, &zeroVec, &zeroVec, 40, 7, 255, 255, 255, 255, 255, 0, 0, 1, 9, + 1); + } + Actor_Kill(&this->actor); + } else { + EnPeehat_Ground_SetStateSeekPlayer(this); + // Is PEAHAT_TYPE_GROUNDED + if (this->actor.params < 0) { + this->unk2FA = (this->unk2FA != 0) ? 0 : 1; + } + } + } + Audio_PlayActorSound2(&this->actor, NA_SE_EN_PIHAT_FLY - SFX_FLAG); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD0B84.s") +void EnPeehat_SetStateBoomerangStunned(EnPeehat* this) { + this->state = PEAHAT_STATE_STUNNED; + if (this->actor.floorHeight < this->actor.world.pos.y) { + this->actor.speedXZ = -9.0f; + } + this->bladeRotVel = 0; + this->actor.world.rot.y = this->actor.yawTowardsPlayer; + Actor_SetColorFilter(&this->actor, 0, 200, 0, 80); + Audio_PlayActorSound2(&this->actor, NA_SE_EN_GOMA_JR_FREEZE); + EnPeehat_SetupAction(this, EnPeehat_StateBoomerangStunned); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD0D3C.s") +void EnPeehat_StateBoomerangStunned(EnPeehat* this, GlobalContext* globalCtx) { + Math_SmoothStepToF(&this->actor.speedXZ, 0.0f, 1.0f, 1.0f, 0.0f); + Math_SmoothStepToF(&this->actor.world.pos.y, this->actor.floorHeight, 1.0f, 8.0f, 0.0f); + if (this->actor.colorFilterTimer == 0) { + EnPeehat_Ground_SetStateRise(this); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD0D84.s") +void EnPeehat_Adult_SetStateDie(EnPeehat* this) { + this->bladeRotVel = 0; + this->isStateDieFirstUpdate = 1; + this->actor.speedXZ = 0.0f; + Actor_SetColorFilter(&this->actor, 0x4000, 255, 0, 8); + this->state = PEAHAT_STATE_DYING; + this->scaleShift = 0.0f; + this->actor.world.rot.y = this->actor.yawTowardsPlayer; + EnPeehat_SetupAction(this, EnPeehat_Adult_StateDie); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD0F38.s") +void EnPeehat_Adult_StateDie(EnPeehat* this, GlobalContext* globalCtx) { + if (this->isStateDieFirstUpdate) { + this->unk2D4--; + if (this->unk2D4 <= 0 || this->actor.colChkInfo.health == 0) { + Animation_MorphToPlayOnce(&this->skelAnime, &D_06000844, -4.0f); + this->bladeRotVel = 4000; + this->unk2D4 = 14; + this->actor.speedXZ = 0; + this->actor.velocity.y = 6; + this->isStateDieFirstUpdate = 0; + this->actor.shape.rot.z = this->actor.shape.rot.x = 0; + } else if (this->actor.colorFilterTimer & 4) { + Math_SmoothStepToF(&this->scaleShift, 0.205f, 1.0f, 0.235f, 0); + } else { + Math_SmoothStepToF(&this->scaleShift, 0, 1.0f, 0.005f, 0); + } + } else { + SkelAnime_Update(&this->skelAnime); + this->bladeRot += this->bladeRotVel; + Math_SmoothStepToS(&this->bladeRotVel, 4000, 1, 250, 0); + if (this->actor.colChkInfo.health == 0) { + this->actor.scale.x -= 0.0015f; + Actor_SetScale(&this->actor, this->actor.scale.x); + } + if (Math_SmoothStepToF(&this->actor.world.pos.y, this->actor.floorHeight + 88.5f, 1.0f, 3.0f, 0.0f) == 0.0f && + this->actor.world.pos.y - this->actor.floorHeight < 59.0f) { + Vec3f pos = this->actor.world.pos; + pos.y = this->actor.floorHeight; + func_80033480(globalCtx, &pos, 80.0f, 1, 150, 100, 1); + EnPeehat_SpawnDust(globalCtx, this, &pos, 75.0f, 2, 1.05f, 2.0f); + } + if (this->actor.speedXZ < 0) { + this->actor.speedXZ += 0.25f; + } + this->unk2D4--; + if (this->unk2D4 <= 0) { + if (this->actor.colChkInfo.health == 0) { + EnPeehat_SetStateExplode(this); + // if PEAHAT_TYPE_GROUNDED + } else if (this->actor.params < 0) { + EnPeehat_Ground_SetStateHover(this); + this->riseDelayTimer = 60; + } else { + EnPeehat_Flying_SetStateFly(this); + } + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD0FC8.s") +void EnPeehat_SetStateExplode(EnPeehat* this) { + Animation_PlayLoop(&this->skelAnime, &D_060005C4); + this->state = PEAHAT_STATE_EXPLODE; + this->animTimer = 5; + this->unk2E0 = 0.0f; + EnPeehat_SetupAction(this, &EnPeehat_StateExplode); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD1220.s") +void EnPeehat_StateExplode(EnPeehat* this, GlobalContext* globalCtx) { + EnBom* bomb; + s32 pad[2]; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD1258.s") + if (this->animTimer == 5) { + bomb = (EnBom*)Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_BOM, this->actor.world.pos.x, + this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, 0x602, 0); + if (bomb != NULL) { + bomb->timer = 0; + } + } + this->animTimer--; + if (this->animTimer == 0) { + Item_DropCollectibleRandom(globalCtx, &this->actor, &this->actor.world.pos, 0x40); + Item_DropCollectibleRandom(globalCtx, &this->actor, &this->actor.world.pos, 0x40); + Item_DropCollectibleRandom(globalCtx, &this->actor, &this->actor.world.pos, 0x40); + Actor_Kill(&this->actor); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD1440.s") +void EnPeehat_Adult_CollisionCheck(EnPeehat* this, GlobalContext* globalCtx) { + if ((this->colCylinder.base.acFlags & AC_BOUNCED) || (this->colQuad.base.acFlags & AC_BOUNCED)) { + this->colQuad.base.acFlags &= ~AC_BOUNCED; + this->colCylinder.base.acFlags &= ~AC_BOUNCED; + this->colJntSph.base.acFlags &= ~AC_HIT; + } else if (this->colJntSph.base.acFlags & AC_HIT) { + this->colJntSph.base.acFlags &= ~AC_HIT; + func_8003573C(&this->actor, &this->colJntSph, 1); + if (this->actor.colChkInfo.damageEffect == PEAHAT_DMG_EFF_NUT || + this->actor.colChkInfo.damageEffect == PEAHAT_DMG_EFF_LIGHT_ICE_ARROW) { + return; + } + if (this->actor.colChkInfo.damageEffect == PEAHAT_DMG_EFF_HOOKSHOT) { + this->actor.colChkInfo.health = 0; + } else if (this->actor.colChkInfo.damageEffect == PEAHAT_DMG_EFF_BOOMERANG) { + if (this->state != PEAHAT_STATE_STUNNED) { + EnPeehat_SetStateBoomerangStunned(this); + } + return; + } else { + Actor_ApplyDamage(&this->actor); + Actor_SetColorFilter(&this->actor, 0x4000, 255, 0, 8); + Audio_PlayActorSound2(&this->actor, NA_SE_EN_PIHAT_DAMAGE); + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD14A0.s") + if (this->actor.colChkInfo.damageEffect == PEAHAT_DMG_EFF_FIRE) { + Vec3f pos; + s32 i; + for (i = 4; i >= 0; i--) { + pos.x = Rand_CenteredFloat(20.0f) + this->actor.world.pos.x; + pos.y = Rand_ZeroOne() * 25.0f + this->actor.world.pos.y; + pos.z = Rand_CenteredFloat(20.0f) + this->actor.world.pos.z; + EffectSsEnFire_SpawnVec3f(globalCtx, &this->actor, &pos, 70, 0, 0, -1); + } + Actor_SetColorFilter(&this->actor, 0x4000, 200, 0, 100); + } + if (this->actor.colChkInfo.health == 0) { + EnPeehat_Adult_SetStateDie(this); + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD167C.s") +void EnPeehat_Update(Actor* thisx, GlobalContext* globalCtx) { + EnPeehat* this = THIS; + s32 i; + Player* player = PLAYER; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD1700.s") + // If Adult Peahat + if (thisx->params <= 0) { + EnPeehat_Adult_CollisionCheck(this, globalCtx); + } + if (thisx->colChkInfo.damageEffect != PEAHAT_DMG_EFF_LIGHT_ICE_ARROW) { + if (thisx->speedXZ != 0.0f || thisx->velocity.y != 0.0f) { + Actor_MoveForward(thisx); + Actor_UpdateBgCheckInfo(globalCtx, thisx, 25.0f, 30.0f, 30.0f, 5); + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD177C.s") + this->actionFunc(this, globalCtx); + if ((globalCtx->gameplayFrames & 0x7F) == 0) { + this->jiggleRotInc = (Rand_ZeroOne() * 0.25f) + 0.5f; + } + this->jiggleRot += this->jiggleRotInc; + } + // if PEAHAT_TYPE_GROUNDED + if (thisx->params < 0) { + // Set the Z-Target point on the Peahat's weak point + thisx->focus.pos.x = this->colJntSph.elements[0].dim.worldSphere.center.x; + thisx->focus.pos.y = this->colJntSph.elements[0].dim.worldSphere.center.y; + thisx->focus.pos.z = this->colJntSph.elements[0].dim.worldSphere.center.z; + if (this->state == PEAHAT_STATE_SEEK_PLAYER) { + Math_SmoothStepToS(&thisx->shape.rot.x, 6000, 1, 300, 0); + } else { + Math_SmoothStepToS(&thisx->shape.rot.x, 0, 1, 300, 0); + } + } else { + thisx->focus.pos = thisx->world.pos; + } + Collider_UpdateCylinder(thisx, &this->colCylinder); + if (thisx->colChkInfo.health > 0) { + // If Adult Peahat + if (thisx->params <= 0) { + CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->colCylinder.base); + CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->colJntSph.base); + if (thisx->colorFilterTimer == 0 || !(thisx->colorFilterParams & 0x4000)) { + if (this->state != PEAHAT_STATE_EXPLODE) { + CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->colJntSph.base); + } + } + } + if (thisx->params != PEAHAT_TYPE_FLYING && this->colQuad.base.atFlags & AT_HIT) { + this->colQuad.base.atFlags &= ~AT_HIT; + if (&player->actor == this->colQuad.base.at) { + EnPeehat_SetStateAttackRecoil(this); + } + } + } + if (this->state == PEAHAT_STATE_15 || this->state == PEAHAT_STATE_SEEK_PLAYER || this->state == PEAHAT_STATE_FLY || + this->state == PEAHAT_STATE_RETURN_HOME || this->state == PEAHAT_STATE_EXPLODE) { + if (thisx->params != PEAHAT_TYPE_FLYING) { + CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->colQuad.base); + CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->colQuad.base); + } + // if PEAHAT_TYPE_GROUNDED + if (thisx->params < 0 && (thisx->flags & 0x40)) { + for (i = 1; i >= 0; i--) { + Vec3f posResult; + CollisionPoly* poly = NULL; + s32 bgId; + Vec3f* posB = &this->bladeTip[i]; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD17E8.s") + if (BgCheck_EntityLineTest1(&globalCtx->colCtx, &thisx->world.pos, posB, &posResult, &poly, true, true, + false, true, &bgId) == true) { + func_80033480(globalCtx, &posResult, 0.0f, 1, 300, 150, 1); + EnPeehat_SpawnDust(globalCtx, this, &posResult, 0.0f, 3, 1.05f, 1.5f); + } + } + } else if (thisx->params != PEAHAT_TYPE_FLYING) { + CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->colCylinder.base); + } + } else { + CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->colCylinder.base); + } + Math_SmoothStepToF(&this->scaleShift, 0.0f, 1.0f, 0.001f, 0.0f); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD1AA8.s") +s32 EnPeehat_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, + void* thisx) { + EnPeehat* this = THIS; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD1B00.s") + if (limbIndex == 4) { + rot->x = -this->bladeRot; + } + if (limbIndex == 3 || (limbIndex == 23 && (this->state == PEAHAT_STATE_DYING || this->state == PEAHAT_STATE_3 || + this->state == PEAHAT_STATE_4))) { + OPEN_DISPS(globalCtx->state.gfxCtx, "../z_en_peehat.c", 1946); + Matrix_Push(); + Matrix_Scale(1.0f, 1.0f, 1.0f, MTXMODE_APPLY); + Matrix_RotateX(this->jiggleRot * 0.115f, MTXMODE_APPLY); + Matrix_RotateY(this->jiggleRot * 0.13f, MTXMODE_APPLY); + Matrix_RotateZ(this->jiggleRot * 0.1f, MTXMODE_APPLY); + Matrix_Scale(1.0f - this->scaleShift, this->scaleShift + 1.0f, 1.0f - this->scaleShift, MTXMODE_APPLY); + Matrix_RotateZ(-(this->jiggleRot * 0.1f), MTXMODE_APPLY); + Matrix_RotateY(-(this->jiggleRot * 0.13f), MTXMODE_APPLY); + Matrix_RotateX(-(this->jiggleRot * 0.115f), MTXMODE_APPLY); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_en_peehat.c", 1959), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, *dList); + Matrix_Pull(); + CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_en_peehat.c", 1963); + return true; + } + return false; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD1BD8.s") +void EnPeehat_PostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) { + static Vec3f peahatBladeTip[] = { { 0.0f, 0.0f, 5500.0f }, { 0.0f, 0.0f, -5500.0f } }; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/EnPeehat_Update.s") + EnPeehat* this = THIS; + f32 damageYRot; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD2224.s") + if (limbIndex == 4) { + Matrix_MultVec3f(&peahatBladeTip[0], &this->bladeTip[0]); + Matrix_MultVec3f(&peahatBladeTip[1], &this->bladeTip[1]); + return; + } + // is Adult Peahat + if (limbIndex == 3 && this->actor.params <= 0) { + damageYRot = 0.0f; + OPEN_DISPS(globalCtx->state.gfxCtx, "../z_en_peehat.c", 1981); + Matrix_Push(); + Matrix_Translate(-1000.0f, 0.0f, 0.0f, MTXMODE_APPLY); + Collider_UpdateSpheres(0, &this->colJntSph); + Matrix_Translate(500.0f, 0.0f, 0.0f, MTXMODE_APPLY); + if (this->actor.colorFilterTimer != 0 && (this->actor.colorFilterParams & 0x4000)) { + damageYRot = Math_SinS(this->actor.colorFilterTimer * 0x4E20) * 0.35f; + } + Matrix_RotateY(3.2f + damageYRot, MTXMODE_APPLY); + Matrix_Scale(0.3f, 0.2f, 0.2f, MTXMODE_APPLY); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_en_peehat.c", 1990), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, *dList); + Matrix_Pull(); + CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_en_peehat.c", 1994); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/func_80AD2438.s") +void EnPeehat_Draw(Actor* thisx, GlobalContext* globalCtx) { + static Vec3f D_80AD285C[] = { + { 0.0f, 0.0f, -4500.0f }, { -4500.0f, 0.0f, 0.0f }, { 4500.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 4500.0f } + }; + EnPeehat* this = THIS; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Peehat/EnPeehat_Draw.s") + func_80093D18(globalCtx->state.gfxCtx); + SkelAnime_DrawOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, EnPeehat_OverrideLimbDraw, + EnPeehat_PostLimbDraw, this); + if (this->actor.speedXZ != 0.0f || this->actor.velocity.y != 0.0f) { + Matrix_MultVec3f(&D_80AD285C[0], &this->colQuad.dim.quad[1]); + Matrix_MultVec3f(&D_80AD285C[1], &this->colQuad.dim.quad[0]); + Matrix_MultVec3f(&D_80AD285C[2], &this->colQuad.dim.quad[3]); + Matrix_MultVec3f(&D_80AD285C[3], &this->colQuad.dim.quad[2]); + Collider_SetQuadVertices(&this->colQuad, &this->colQuad.dim.quad[0], &this->colQuad.dim.quad[1], + &this->colQuad.dim.quad[2], &this->colQuad.dim.quad[3]); + } +} diff --git a/src/overlays/actors/ovl_En_Peehat/z_en_peehat.h b/src/overlays/actors/ovl_En_Peehat/z_en_peehat.h index c2dc45ddd..c04c61ea3 100644 --- a/src/overlays/actors/ovl_En_Peehat/z_en_peehat.h +++ b/src/overlays/actors/ovl_En_Peehat/z_en_peehat.h @@ -4,11 +4,44 @@ #include "ultra64.h" #include "global.h" +typedef enum { + /* -1 */ PEAHAT_TYPE_GROUNDED = -1, + /* 0 */ PEAHAT_TYPE_FLYING = 0, + /* 1 */ PEAHAT_TYPE_LARVA = 1 +} PeahatType; + struct EnPeehat; +typedef void (*EnPeehatActionFunc)(struct EnPeehat*, GlobalContext*); + typedef struct EnPeehat { /* 0x0000 */ Actor actor; - /* 0x014C */ char unk_14C[0x2E0]; + /* 0x014C */ SkelAnime skelAnime; + /* 0x0190 */ Vec3s jointTable[24]; + /* 0x0220 */ Vec3s morphTable[24]; + /* 0x02B0 */ s32 state; + /* 0x02B4 */ s32 isStateDieFirstUpdate; + /* 0x02B8 */ EnPeehatActionFunc actionFunc; + /* 0x02BC */ Vec3f bladeTip[2]; // used to simulate the peahat's blades "digging up" earth + /* 0x02D4 */ s32 unk2D4; + /* 0x02D8 */ f32 xzDistMax; // max xz dist to follow Link (PEAHAT_TYPE_GROUNDED) or spawn larva (PEAHAT_TYPE_FLYING) + /* 0x02DC */ f32 xzDistToRise; // xz dist needed to rise from the ground + /* 0x02E0 */ f32 unk2E0; // rot? + /* 0x02E4 */ f32 jiggleRot; + /* 0x02E8 */ f32 jiggleRotInc; + /* 0x02EC */ f32 scaleShift; // 0.0f for no distortion. used for "jiggle" effect when stabbed on ground + /* 0x02F0 */ s16 bladeRotVel; // spinning blades rotational velocity + /* 0x02F2 */ s16 bladeRot; // spinning blades rotation component + /* 0x02F4 */ s16 unk2F4; + /* 0x02F6 */ s16 riseDelayTimer; // countdown timer until peahat is allowed to rise up from the ground + /* 0x02F8 */ s16 seekPlayerTimer; // number of frames the peahat should seek the player before landing to rest + /* 0x02FA */ s16 unk2FA; // larva count (PEAHAT_TYPE_FLYING, PEAHAT_TYPE_GROUNDED), + // shape rotation direction (PEAHAT_TYPE_GROUNDED) + /* 0x02FC */ s16 animTimer; + /* 0x0300 */ ColliderCylinder colCylinder; + /* 0x034C */ ColliderJntSph colJntSph; + /* 0x036C */ ColliderJntSphElement colJntSphItemList[1]; + /* 0x03AC */ ColliderQuad colQuad; } EnPeehat; // size = 0x042C extern const ActorInit En_Peehat_InitVars; -- cgit v1.2.3