Shipwright/soh/src/overlays/actors/ovl_En_Karebaba/z_en_karebaba.c

543 lines
19 KiB
C

/**
* File: z_en_karebaba.c
* Overlay: ovl_En_Karebaba
* Description: Withered Deku Baba
*/
#include "z_en_karebaba.h"
#include "objects/object_dekubaba/object_dekubaba.h"
#include "objects/gameplay_keep/gameplay_keep.h"
#include "overlays/effects/ovl_Effect_Ss_Hahen/z_eff_ss_hahen.h"
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_2)
void EnKarebaba_Init(Actor* thisx, PlayState* play);
void EnKarebaba_Destroy(Actor* thisx, PlayState* play);
void EnKarebaba_Update(Actor* thisx, PlayState* play);
void EnKarebaba_Draw(Actor* thisx, PlayState* play);
void EnKarebaba_SetupGrow(EnKarebaba* this);
void EnKarebaba_SetupIdle(EnKarebaba* this);
void EnKarebaba_Grow(EnKarebaba* this, PlayState* play);
void EnKarebaba_Idle(EnKarebaba* this, PlayState* play);
void EnKarebaba_Awaken(EnKarebaba* this, PlayState* play);
void EnKarebaba_Spin(EnKarebaba* this, PlayState* play);
void EnKarebaba_Dying(EnKarebaba* this, PlayState* play);
void EnKarebaba_DeadItemDrop(EnKarebaba* this, PlayState* play);
void EnKarebaba_Retract(EnKarebaba* this, PlayState* play);
void EnKarebaba_Dead(EnKarebaba* this, PlayState* play);
void EnKarebaba_Regrow(EnKarebaba* this, PlayState* play);
void EnKarebaba_Upright(EnKarebaba* this, PlayState* play);
const ActorInit En_Karebaba_InitVars = {
ACTOR_EN_KAREBABA,
ACTORCAT_ENEMY,
FLAGS,
OBJECT_DEKUBABA,
sizeof(EnKarebaba),
(ActorFunc)EnKarebaba_Init,
(ActorFunc)EnKarebaba_Destroy,
(ActorFunc)EnKarebaba_Update,
(ActorFunc)EnKarebaba_Draw,
NULL,
};
static ColliderCylinderInit sBodyColliderInit = {
{
COLTYPE_HARD,
AT_NONE,
AC_ON | AC_TYPE_PLAYER,
OC1_NONE,
OC2_TYPE_1,
COLSHAPE_CYLINDER,
},
{
ELEMTYPE_UNK0,
{ 0x00000000, 0x00, 0x00 },
{ 0xFFCFFFFF, 0x00, 0x00 },
TOUCH_NONE,
BUMP_ON,
OCELEM_NONE,
},
{ 7, 25, 0, { 0, 0, 0 } },
};
static ColliderCylinderInit sHeadColliderInit = {
{
COLTYPE_HARD,
AT_ON | AT_TYPE_ENEMY,
AC_NONE,
OC1_ON | OC1_TYPE_ALL,
OC2_TYPE_1,
COLSHAPE_CYLINDER,
},
{
ELEMTYPE_UNK0,
{ 0xFFCFFFFF, 0x00, 0x08 },
{ 0x00000000, 0x00, 0x00 },
TOUCH_ON | TOUCH_SFX_HARD,
BUMP_NONE,
OCELEM_ON,
},
{ 4, 25, 0, { 0, 0, 0 } },
};
static CollisionCheckInfoInit sColCheckInfoInit = { 1, 15, 80, MASS_HEAVY };
static InitChainEntry sInitChain[] = {
ICHAIN_F32(targetArrowOffset, 2500, ICHAIN_CONTINUE),
ICHAIN_U8(targetMode, 1, ICHAIN_CONTINUE),
ICHAIN_S8(naviEnemyId, 0x09, ICHAIN_STOP),
};
void EnKarebaba_Init(Actor* thisx, PlayState* play) {
EnKarebaba* this = (EnKarebaba*)thisx;
Actor_ProcessInitChain(&this->actor, sInitChain);
ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 22.0f);
SkelAnime_Init(play, &this->skelAnime, &gDekuBabaSkel, &gDekuBabaFastChompAnim, this->jointTable,
this->morphTable, 8);
Collider_InitCylinder(play, &this->bodyCollider);
Collider_SetCylinder(play, &this->bodyCollider, &this->actor, &sBodyColliderInit);
Collider_UpdateCylinder(&this->actor, &this->bodyCollider);
Collider_InitCylinder(play, &this->headCollider);
Collider_SetCylinder(play, &this->headCollider, &this->actor, &sHeadColliderInit);
Collider_UpdateCylinder(&this->actor, &this->headCollider);
CollisionCheck_SetInfo(&this->actor.colChkInfo, DamageTable_Get(1), &sColCheckInfoInit);
this->boundFloor = NULL;
if (this->actor.params == 0) {
EnKarebaba_SetupGrow(this);
} else {
EnKarebaba_SetupIdle(this);
}
}
void EnKarebaba_Destroy(Actor* thisx, PlayState* play) {
EnKarebaba* this = (EnKarebaba*)thisx;
Collider_DestroyCylinder(play, &this->bodyCollider);
Collider_DestroyCylinder(play, &this->headCollider);
}
void EnKarebaba_ResetCollider(EnKarebaba* this) {
this->bodyCollider.dim.radius = 7;
this->bodyCollider.dim.height = 25;
this->bodyCollider.base.colType = COLTYPE_HARD;
this->bodyCollider.base.acFlags |= AC_HARD;
this->bodyCollider.info.bumper.dmgFlags = ~0x00300000;
this->headCollider.dim.height = 25;
}
void EnKarebaba_SetupGrow(EnKarebaba* this) {
Actor_SetScale(&this->actor, 0.0f);
this->actor.shape.rot.x = -0x4000;
this->actionFunc = EnKarebaba_Grow;
this->actor.world.pos.y = this->actor.home.pos.y + 14.0f;
}
void EnKarebaba_SetupIdle(EnKarebaba* this) {
Actor_SetScale(&this->actor, 0.005f);
this->actor.shape.rot.x = -0x4000;
this->actionFunc = EnKarebaba_Idle;
this->actor.world.pos.y = this->actor.home.pos.y + 14.0f;
}
void EnKarebaba_SetupAwaken(EnKarebaba* this) {
Animation_Change(&this->skelAnime, &gDekuBabaFastChompAnim, 4.0f, 0.0f,
Animation_GetLastFrame(&gDekuBabaFastChompAnim), ANIMMODE_LOOP, -3.0f);
Audio_PlayActorSound2(&this->actor, NA_SE_EN_DUMMY482);
this->actionFunc = EnKarebaba_Awaken;
}
void EnKarebaba_SetupUpright(EnKarebaba* this) {
if (this->actionFunc != EnKarebaba_Spin) {
Actor_SetScale(&this->actor, 0.01f);
this->bodyCollider.base.colType = COLTYPE_HIT6;
this->bodyCollider.base.acFlags &= ~AC_HARD;
this->bodyCollider.info.bumper.dmgFlags = !LINK_IS_ADULT ? 0x07C00710 : 0x0FC00710;
this->bodyCollider.dim.radius = 15;
this->bodyCollider.dim.height = 80;
this->headCollider.dim.height = 80;
}
this->actor.params = 40;
this->actionFunc = EnKarebaba_Upright;
}
void EnKarebaba_SetupSpin(EnKarebaba* this) {
this->actor.params = 40;
this->actionFunc = EnKarebaba_Spin;
}
void EnKarebaba_SetupDying(EnKarebaba* this) {
this->actor.params = 0;
this->actor.gravity = -0.8f;
this->actor.velocity.y = 4.0f;
this->actor.world.rot.y = this->actor.shape.rot.y + 0x8000;
this->actor.speedXZ = 3.0f;
Audio_PlayActorSound2(&this->actor, NA_SE_EN_DEKU_JR_DEAD);
this->actor.flags |= ACTOR_FLAG_4 | ACTOR_FLAG_5;
this->actionFunc = EnKarebaba_Dying;
gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_WITHERED_DEKU_BABA]++;
}
void EnKarebaba_SetupDeadItemDrop(EnKarebaba* this, PlayState* play) {
Actor_SetScale(&this->actor, 0.03f);
this->actor.shape.rot.x -= 0x4000;
this->actor.shape.yOffset = 1000.0f;
this->actor.gravity = 0.0f;
this->actor.velocity.y = 0.0f;
this->actor.shape.shadowScale = 3.0f;
Actor_ChangeCategory(play, &play->actorCtx, &this->actor, ACTORCAT_MISC);
this->actor.params = 200;
this->actor.flags &= ~ACTOR_FLAG_5;
this->actionFunc = EnKarebaba_DeadItemDrop;
}
void EnKarebaba_SetupRetract(EnKarebaba* this) {
Animation_Change(&this->skelAnime, &gDekuBabaFastChompAnim, -3.0f, Animation_GetLastFrame(&gDekuBabaFastChompAnim),
0.0f, ANIMMODE_ONCE, -3.0f);
EnKarebaba_ResetCollider(this);
this->actionFunc = EnKarebaba_Retract;
}
void EnKarebaba_SetupDead(EnKarebaba* this) {
Animation_Change(&this->skelAnime, &gDekuBabaFastChompAnim, 0.0f, 0.0f, 0.0f, ANIMMODE_ONCE, 0.0f);
EnKarebaba_ResetCollider(this);
this->actor.shape.rot.x = -0x4000;
this->actor.params = 200;
this->actor.parent = NULL;
this->actor.shape.shadowScale = 0.0f;
Math_Vec3f_Copy(&this->actor.world.pos, &this->actor.home.pos);
this->actionFunc = EnKarebaba_Dead;
}
void EnKarebaba_SetupRegrow(EnKarebaba* this) {
this->actor.shape.yOffset = 0.0f;
this->actor.shape.shadowScale = 22.0f;
this->headCollider.dim.radius = sHeadColliderInit.dim.radius;
Actor_SetScale(&this->actor, 0.0f);
this->actionFunc = EnKarebaba_Regrow;
}
void EnKarebaba_Grow(EnKarebaba* this, PlayState* play) {
f32 scale;
this->actor.params++;
scale = this->actor.params * 0.05f;
Actor_SetScale(&this->actor, 0.005f * scale);
this->actor.world.pos.y = this->actor.home.pos.y + (14.0f * scale);
if (this->actor.params == 20) {
EnKarebaba_SetupIdle(this);
}
}
void EnKarebaba_Idle(EnKarebaba* this, PlayState* play) {
if (this->actor.xzDistToPlayer < 200.0f && fabsf(this->actor.yDistToPlayer) < 30.0f) {
EnKarebaba_SetupAwaken(this);
}
}
void EnKarebaba_Awaken(EnKarebaba* this, PlayState* play) {
SkelAnime_Update(&this->skelAnime);
Math_StepToF(&this->actor.scale.x, 0.01f, 0.0005f);
this->actor.scale.y = this->actor.scale.z = this->actor.scale.x;
if (Math_StepToF(&this->actor.world.pos.y, this->actor.home.pos.y + 60.0f, 5.0f)) {
EnKarebaba_SetupUpright(this);
}
this->actor.shape.rot.y += 0x1999;
EffectSsHahen_SpawnBurst(play, &this->actor.home.pos, 3.0f, 0, 12, 5, 1, HAHEN_OBJECT_DEFAULT, 10, NULL);
}
void EnKarebaba_Upright(EnKarebaba* this, PlayState* play) {
Player* player = GET_PLAYER(play);
SkelAnime_Update(&this->skelAnime);
if (this->actor.params != 0) {
this->actor.params--;
}
if (Animation_OnFrame(&this->skelAnime, 0.0f) || Animation_OnFrame(&this->skelAnime, 12.0f)) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_DEKU_JR_MOUTH);
}
if (this->bodyCollider.base.acFlags & AC_HIT) {
EnKarebaba_SetupDying(this);
Enemy_StartFinishingBlow(play, &this->actor);
} else if (Math_Vec3f_DistXZ(&this->actor.home.pos, &player->actor.world.pos) > 240.0f) {
EnKarebaba_SetupRetract(this);
} else if (this->actor.params == 0) {
EnKarebaba_SetupSpin(this);
}
}
void EnKarebaba_Spin(EnKarebaba* this, PlayState* play) {
s32 value;
f32 cos60;
if (this->actor.params != 0) {
this->actor.params--;
}
SkelAnime_Update(&this->skelAnime);
if (Animation_OnFrame(&this->skelAnime, 0.0f) || Animation_OnFrame(&this->skelAnime, 12.0f)) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_DEKU_JR_MOUTH);
}
value = 20 - this->actor.params;
value = 20 - ABS(value);
if (value > 10) {
value = 10;
}
this->headCollider.dim.radius = sHeadColliderInit.dim.radius + (value * 2);
this->actor.shape.rot.x = 0xC000 - (value * 0x100);
this->actor.shape.rot.y += value * 0x2C0;
this->actor.world.pos.y = (Math_SinS(this->actor.shape.rot.x) * -60.0f) + this->actor.home.pos.y;
cos60 = Math_CosS(this->actor.shape.rot.x) * 60.0f;
this->actor.world.pos.x = (Math_SinS(this->actor.shape.rot.y) * cos60) + this->actor.home.pos.x;
this->actor.world.pos.z = (Math_CosS(this->actor.shape.rot.y) * cos60) + this->actor.home.pos.z;
if (this->bodyCollider.base.acFlags & AC_HIT) {
EnKarebaba_SetupDying(this);
Enemy_StartFinishingBlow(play, &this->actor);
} else if (this->actor.params == 0) {
EnKarebaba_SetupUpright(this);
}
}
void EnKarebaba_Dying(EnKarebaba* this, PlayState* play) {
static Vec3f zeroVec = { 0.0f, 0.0f, 0.0f };
s32 i;
Vec3f position;
Vec3f rotation;
Math_StepToF(&this->actor.speedXZ, 0.0f, 0.1f);
if (this->actor.params == 0) {
Math_ScaledStepToS(&this->actor.shape.rot.x, 0x4800, 0x71C);
EffectSsHahen_SpawnBurst(play, &this->actor.world.pos, 3.0f, 0, 12, 5, 1, HAHEN_OBJECT_DEFAULT, 10, NULL);
if (this->actor.scale.x > 0.005f && ((this->actor.bgCheckFlags & 2) || (this->actor.bgCheckFlags & 8))) {
this->actor.scale.x = this->actor.scale.y = this->actor.scale.z = 0.0f;
this->actor.speedXZ = 0.0f;
this->actor.flags &= ~(ACTOR_FLAG_0 | ACTOR_FLAG_2);
EffectSsHahen_SpawnBurst(play, &this->actor.world.pos, 3.0f, 0, 12, 5, 15, HAHEN_OBJECT_DEFAULT, 10,
NULL);
}
if (this->actor.bgCheckFlags & 2) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_DODO_M_GND);
this->actor.params = 1;
}
} else if (this->actor.params == 1) {
Math_Vec3f_Copy(&position, &this->actor.world.pos);
rotation.z = Math_SinS(this->actor.shape.rot.x) * 20.0f;
rotation.x = -20.0f * Math_CosS(this->actor.shape.rot.x) * Math_SinS(this->actor.shape.rot.y);
rotation.y = -20.0f * Math_CosS(this->actor.shape.rot.x) * Math_CosS(this->actor.shape.rot.y);
for (i = 0; i < 4; i++) {
func_800286CC(play, &position, &zeroVec, &zeroVec, 500, 50);
position.x += rotation.x;
position.y += rotation.z;
position.z += rotation.y;
}
func_800286CC(play, &this->actor.home.pos, &zeroVec, &zeroVec, 500, 100);
EnKarebaba_SetupDeadItemDrop(this, play);
}
}
void EnKarebaba_DeadItemDrop(EnKarebaba* this, PlayState* play) {
if (this->actor.params != 0) {
this->actor.params--;
}
if (Actor_HasParent(&this->actor, play) || this->actor.params == 0) {
EnKarebaba_SetupDead(this);
} else {
func_8002F554(&this->actor, play, GI_STICKS_1);
}
}
void EnKarebaba_Retract(EnKarebaba* this, PlayState* play) {
SkelAnime_Update(&this->skelAnime);
Math_StepToF(&this->actor.scale.x, 0.005f, 0.0005f);
this->actor.scale.y = this->actor.scale.z = this->actor.scale.x;
if (Math_StepToF(&this->actor.world.pos.y, this->actor.home.pos.y + 14.0f, 5.0f)) {
EnKarebaba_SetupIdle(this);
}
this->actor.shape.rot.y += 0x1999;
EffectSsHahen_SpawnBurst(play, &this->actor.home.pos, 3.0f, 0, 12, 5, 1, HAHEN_OBJECT_DEFAULT, 10, NULL);
}
void EnKarebaba_Dead(EnKarebaba* this, PlayState* play) {
SkelAnime_Update(&this->skelAnime);
if (this->actor.params != 0) {
this->actor.params--;
}
if (this->actor.params == 0) {
EnKarebaba_SetupRegrow(this);
}
}
void EnKarebaba_Regrow(EnKarebaba* this, PlayState* play) {
f32 scaleFactor;
this->actor.params++;
scaleFactor = this->actor.params * 0.05f;
Actor_SetScale(&this->actor, 0.005f * scaleFactor);
this->actor.world.pos.y = this->actor.home.pos.y + (14.0f * scaleFactor);
if (this->actor.params == 20) {
this->actor.flags &= ~ACTOR_FLAG_4;
this->actor.flags |= ACTOR_FLAG_0 | ACTOR_FLAG_2;
Actor_ChangeCategory(play, &play->actorCtx, &this->actor, ACTORCAT_ENEMY);
EnKarebaba_SetupIdle(this);
}
}
void EnKarebaba_Update(Actor* thisx, PlayState* play) {
s32 pad;
EnKarebaba* this = (EnKarebaba*)thisx;
f32 height;
this->actionFunc(this, play);
if (this->actionFunc != EnKarebaba_Dead) {
if (this->actionFunc == EnKarebaba_Dying) {
Actor_MoveForward(&this->actor);
Actor_UpdateBgCheckInfo(play, &this->actor, 10.0f, 15.0f, 10.0f, 5);
} else {
Actor_UpdateBgCheckInfo(play, &this->actor, 0.0f, 0.0f, 0.0f, 4);
if (this->boundFloor == NULL) {
this->boundFloor = this->actor.floorPoly;
}
}
if (this->actionFunc != EnKarebaba_Dying && this->actionFunc != EnKarebaba_DeadItemDrop) {
if (this->actionFunc != EnKarebaba_Regrow && this->actionFunc != EnKarebaba_Grow) {
CollisionCheck_SetAT(play, &play->colChkCtx, &this->headCollider.base);
CollisionCheck_SetAC(play, &play->colChkCtx, &this->bodyCollider.base);
}
CollisionCheck_SetOC(play, &play->colChkCtx, &this->headCollider.base);
Actor_SetFocus(&this->actor, (this->actor.scale.x * 10.0f) / 0.01f);
height = this->actor.home.pos.y + 40.0f;
this->actor.focus.pos.x = this->actor.home.pos.x;
this->actor.focus.pos.y = CLAMP_MAX(this->actor.focus.pos.y, height);
this->actor.focus.pos.z = this->actor.home.pos.z;
}
}
}
void EnKarebaba_DrawBaseShadow(EnKarebaba* this, PlayState* play) {
MtxF mf;
OPEN_DISPS(play->state.gfxCtx);
func_80094044(play->state.gfxCtx);
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 0, 0, 0, 255);
func_80038A28(this->boundFloor, this->actor.home.pos.x, this->actor.home.pos.y, this->actor.home.pos.z, &mf);
Matrix_Mult(&mf, MTXMODE_NEW);
Matrix_Scale(0.15f, 1.0f, 0.15f, MTXMODE_APPLY);
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(play->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gCircleShadowDL);
CLOSE_DISPS(play->state.gfxCtx);
}
void EnKarebaba_Draw(Actor* thisx, PlayState* play) {
static Color_RGBA8 black = { 0, 0, 0, 0 };
static Gfx* stemDLists[] = { gDekuBabaStemTopDL, gDekuBabaStemMiddleDL, gDekuBabaStemBaseDL };
static Vec3f zeroVec = { 0.0f, 0.0f, 0.0f };
EnKarebaba* this = (EnKarebaba*)thisx;
s32 i;
s32 stemSections;
f32 scale;
OPEN_DISPS(play->state.gfxCtx);
func_80093D18(play->state.gfxCtx);
if (this->actionFunc == EnKarebaba_DeadItemDrop) {
if (this->actor.params > 40 || (this->actor.params & 1)) {
Matrix_Translate(0.0f, 0.0f, 200.0f, MTXMODE_APPLY);
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(play->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, gDekuBabaStickDropDL);
}
} else if (this->actionFunc != EnKarebaba_Dead) {
func_80026230(play, &black, 1, 2);
SkelAnime_DrawOpa(play, this->skelAnime.skeleton, this->skelAnime.jointTable, NULL, NULL, NULL);
Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, MTXMODE_NEW);
if ((this->actionFunc == EnKarebaba_Regrow) || (this->actionFunc == EnKarebaba_Grow)) {
scale = this->actor.params * 0.0005f;
} else {
scale = 0.01f;
}
Matrix_Scale(scale, scale, scale, MTXMODE_APPLY);
Matrix_RotateZYX(this->actor.shape.rot.x, this->actor.shape.rot.y, 0, MTXMODE_APPLY);
if (this->actionFunc == EnKarebaba_Dying) {
stemSections = 2;
} else {
stemSections = 3;
}
for (i = 0; i < stemSections; i++) {
Matrix_Translate(0.0f, 0.0f, -2000.0f, MTXMODE_APPLY);
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(play->state.gfxCtx),
G_MTX_LOAD | G_MTX_NOPUSH | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, stemDLists[i]);
if (i == 0 && this->actionFunc == EnKarebaba_Dying) {
Matrix_MultVec3f(&zeroVec, &this->actor.focus.pos);
}
}
func_80026608(play);
}
func_80026230(play, &black, 1, 2);
Matrix_Translate(this->actor.home.pos.x, this->actor.home.pos.y, this->actor.home.pos.z, MTXMODE_NEW);
if (this->actionFunc != EnKarebaba_Grow) {
scale = 0.01f;
}
Matrix_Scale(scale, scale, scale, MTXMODE_APPLY);
Matrix_RotateY(this->actor.home.rot.y * (M_PI / 0x8000), MTXMODE_APPLY);
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(play->state.gfxCtx),
G_MTX_LOAD | G_MTX_NOPUSH | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, gDekuBabaBaseLeavesDL);
if (this->actionFunc == EnKarebaba_Dying) {
Matrix_RotateZYX(-0x4000, (s16)(this->actor.shape.rot.y - this->actor.home.rot.y), 0, MTXMODE_APPLY);
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(play->state.gfxCtx),
G_MTX_LOAD | G_MTX_NOPUSH | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, gDekuBabaStemBaseDL);
}
func_80026608(play);
CLOSE_DISPS(play->state.gfxCtx);
if (this->boundFloor != NULL) {
EnKarebaba_DrawBaseShadow(this, play);
}
}