mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2024-08-13 17:03:47 -04:00
39cc86c260
subrepo: subdir: "soh" merged: "ba904bbd0" upstream: origin: "https://github.com/HarbourMasters/soh.git" branch: "master" commit: "ba904bbd0" git-subrepo: version: "0.4.1" origin: "???" commit: "???"
1085 lines
45 KiB
C
1085 lines
45 KiB
C
#include "z_en_peehat.h"
|
|
#include "objects/object_peehat/object_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 (ACTOR_FLAG_0 | ACTOR_FLAG_2 | ACTOR_FLAG_4 | ACTOR_FLAG_24)
|
|
|
|
#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);
|
|
|
|
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);
|
|
|
|
const ActorInit En_Peehat_InitVars = {
|
|
ACTOR_EN_PEEHAT,
|
|
ACTORCAT_ENEMY,
|
|
FLAGS,
|
|
OBJECT_PEEHAT,
|
|
sizeof(EnPeehat),
|
|
(ActorFunc)EnPeehat_Init,
|
|
(ActorFunc)EnPeehat_Destroy,
|
|
(ActorFunc)EnPeehat_Update,
|
|
(ActorFunc)EnPeehat_Draw,
|
|
NULL,
|
|
};
|
|
|
|
static ColliderCylinderInit sCylinderInit = {
|
|
{
|
|
COLTYPE_WOOD,
|
|
AT_NONE,
|
|
AC_ON | AC_TYPE_PLAYER,
|
|
OC1_ON | OC1_TYPE_PLAYER,
|
|
OC2_TYPE_1,
|
|
COLSHAPE_CYLINDER,
|
|
},
|
|
{
|
|
ELEMTYPE_UNK0,
|
|
{ 0x00000000, 0x00, 0x00 },
|
|
{ 0xFFCFFFFF, 0x00, 0x00 },
|
|
TOUCH_NONE,
|
|
BUMP_ON | BUMP_HOOKABLE,
|
|
OCELEM_ON,
|
|
},
|
|
{ 50, 160, -70, { 0, 0, 0 } },
|
|
};
|
|
|
|
static ColliderJntSphElementInit sJntSphElemInit[1] = {
|
|
{
|
|
{
|
|
ELEMTYPE_UNK0,
|
|
{ 0x00000000, 0x00, 0x00 },
|
|
{ 0xFFCFFFFF, 0x00, 0x00 },
|
|
TOUCH_NONE,
|
|
BUMP_ON,
|
|
OCELEM_ON,
|
|
},
|
|
{ 0, { { 0, 0, 0 }, 20 }, 100 },
|
|
},
|
|
};
|
|
|
|
static ColliderJntSphInit sJntSphInit = {
|
|
{
|
|
COLTYPE_HIT6,
|
|
AT_NONE,
|
|
AC_ON | AC_TYPE_PLAYER,
|
|
OC1_ON | OC1_TYPE_PLAYER,
|
|
OC2_TYPE_1,
|
|
COLSHAPE_JNTSPH,
|
|
},
|
|
1,
|
|
sJntSphElemInit,
|
|
};
|
|
|
|
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 = (EnPeehat*)thisx;
|
|
|
|
Actor_ProcessInitChain(&this->actor, sInitChain);
|
|
Actor_SetScale(&this->actor, 36.0f * 0.001f);
|
|
SkelAnime_Init(globalCtx, &this->skelAnime, &gPeehatSkel, &gPeehatRisingAnim, 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, &this->actor, &sCylinderInit);
|
|
Collider_InitQuad(globalCtx, &this->colQuad);
|
|
Collider_SetQuad(globalCtx, &this->colQuad, &this->actor, &sQuadInit);
|
|
Collider_InitJntSph(globalCtx, &this->colJntSph);
|
|
Collider_SetJntSph(globalCtx, &this->colJntSph, &this->actor, &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 &= ~ACTOR_FLAG_0;
|
|
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 = (EnPeehat*)thisx;
|
|
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, &gPeehatRisingAnim, 0.0f, 3.0f, Animation_GetLastFrame(&gPeehatRisingAnim),
|
|
ANIMMODE_ONCE, 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 (IS_DAY) {
|
|
this->actor.flags |= ACTOR_FLAG_0;
|
|
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 &= ~ACTOR_FLAG_0;
|
|
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, &gPeehatRisingAnim, 0.0f, 3.0f, Animation_GetLastFrame(&gPeehatRisingAnim),
|
|
ANIMMODE_ONCE, 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 (IS_DAY) {
|
|
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, &gPeehatFlyingAnim);
|
|
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 (!IS_DAY || 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 = Animation_GetLastFrame(&gPeehatRisingAnim);
|
|
|
|
if (this->state != PEAHAT_STATE_STUNNED) {
|
|
Animation_Change(&this->skelAnime, &gPeehatRisingAnim, 0.0f, 3.0f, lastFrame, ANIMMODE_ONCE, 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(&gPeehatRisingAnim);
|
|
if (this->state != PEAHAT_STATE_STUNNED) {
|
|
Animation_Change(&this->skelAnime, &gPeehatRisingAnim, 0.0f, 3.0f, lastFrame, ANIMMODE_ONCE, 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) {
|
|
//! @bug: overwrites number of child larva spawned, allowing for more than MAX_LARVA spawns
|
|
this->unk2FA = 0;
|
|
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;
|
|
}
|
|
|
|
void EnPeehat_Ground_SetStateSeekPlayer(EnPeehat* this) {
|
|
Animation_PlayLoop(&this->skelAnime, &gPeehatFlyingAnim);
|
|
this->state = PEAHAT_STATE_SEEK_PLAYER;
|
|
this->unk2E0 = 0.0f;
|
|
EnPeehat_SetupAction(this, EnPeehat_Ground_StateSeekPlayer);
|
|
}
|
|
|
|
void EnPeehat_Ground_StateSeekPlayer(EnPeehat* this, GlobalContext* globalCtx) {
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
|
|
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 (IS_DAY && (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);
|
|
}
|
|
|
|
void EnPeehat_Larva_SetStateSeekPlayer(EnPeehat* this) {
|
|
Animation_PlayLoop(&this->skelAnime, &gPeehatFlyingAnim);
|
|
this->state = PEAHAT_STATE_SEEK_PLAYER;
|
|
this->unk2D4 = 0;
|
|
EnPeehat_SetupAction(this, EnPeehat_Larva_StateSeekPlayer);
|
|
}
|
|
|
|
void EnPeehat_Larva_StateSeekPlayer(EnPeehat* this, GlobalContext* globalCtx) {
|
|
f32 speedXZ = 5.3f;
|
|
|
|
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 = GET_PLAYER(globalCtx);
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
void EnPeehat_Ground_SetStateLanding(EnPeehat* this) {
|
|
this->state = PEAHAT_STATE_LANDING;
|
|
Animation_PlayOnce(&this->skelAnime, &gPeehatLandingAnim);
|
|
EnPeehat_SetupAction(this, EnPeehat_Ground_StateLanding);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
void EnPeehat_Flying_SetStateLanding(EnPeehat* this) {
|
|
Animation_PlayOnce(&this->skelAnime, &gPeehatLandingAnim);
|
|
this->state = PEAHAT_STATE_LANDING;
|
|
EnPeehat_SetupAction(this, EnPeehat_Flying_StateLanding);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
void EnPeehat_Ground_SetStateHover(EnPeehat* this) {
|
|
Animation_PlayLoop(&this->skelAnime, &gPeehatFlyingAnim);
|
|
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);
|
|
}
|
|
|
|
void EnPeehat_Ground_StateHover(EnPeehat* this, GlobalContext* globalCtx) {
|
|
f32 cos;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
|
|
// 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 (IS_DAY && 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);
|
|
}
|
|
|
|
void EnPeehat_Ground_SetStateReturnHome(EnPeehat* this) {
|
|
this->state = PEAHAT_STATE_RETURN_HOME;
|
|
this->actor.speedXZ = 2.5f;
|
|
EnPeehat_SetupAction(this, EnPeehat_Ground_StateReturnHome);
|
|
}
|
|
|
|
void EnPeehat_Ground_StateReturnHome(EnPeehat* this, GlobalContext* globalCtx) {
|
|
f32 cos;
|
|
s16 yRot;
|
|
Player* player;
|
|
|
|
player = GET_PLAYER(globalCtx);
|
|
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 (IS_DAY && 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);
|
|
}
|
|
|
|
void EnPeehat_SetStateAttackRecoil(EnPeehat* this) {
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &gPeehatRecoilAnim, -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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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, &gPeehatRecoilAnim, -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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void EnPeehat_SetStateExplode(EnPeehat* this) {
|
|
Animation_PlayLoop(&this->skelAnime, &gPeehatFlyingAnim);
|
|
this->state = PEAHAT_STATE_EXPLODE;
|
|
this->animTimer = 5;
|
|
this->unk2E0 = 0.0f;
|
|
EnPeehat_SetupAction(this, EnPeehat_StateExplode);
|
|
}
|
|
|
|
void EnPeehat_StateExplode(EnPeehat* this, GlobalContext* globalCtx) {
|
|
EnBom* bomb;
|
|
s32 pad[2];
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
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;
|
|
Actor_SetDropFlagJntSph(&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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
void EnPeehat_Update(Actor* thisx, GlobalContext* globalCtx) {
|
|
EnPeehat* this = (EnPeehat*)thisx;
|
|
s32 i;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
|
|
// 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);
|
|
}
|
|
|
|
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 & ACTOR_FLAG_6)) {
|
|
for (i = 1; i >= 0; i--) {
|
|
Vec3f posResult;
|
|
CollisionPoly* poly = NULL;
|
|
s32 bgId;
|
|
Vec3f* posB = &this->bladeTip[i];
|
|
|
|
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);
|
|
}
|
|
|
|
s32 EnPeehat_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot,
|
|
void* thisx) {
|
|
EnPeehat* this = (EnPeehat*)thisx;
|
|
|
|
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_Pop();
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_en_peehat.c", 1963);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
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 } };
|
|
|
|
EnPeehat* this = (EnPeehat*)thisx;
|
|
f32 damageYRot;
|
|
|
|
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_Pop();
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_en_peehat.c", 1994);
|
|
}
|
|
}
|
|
|
|
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 = (EnPeehat*)thisx;
|
|
|
|
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]);
|
|
}
|
|
}
|