diff --git a/assets/xml/objects/object_bigokuta.xml b/assets/xml/objects/object_bigokuta.xml index b6783c15d4..653853c928 100644 --- a/assets/xml/objects/object_bigokuta.xml +++ b/assets/xml/objects/object_bigokuta.xml @@ -1,58 +1,58 @@  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spec b/spec index e93108ad14..9ce450602c 100644 --- a/spec +++ b/spec @@ -3431,8 +3431,7 @@ beginseg name "ovl_En_Bigokuta" compress include "build/src/overlays/actors/ovl_En_Bigokuta/z_en_bigokuta.o" - include "build/data/ovl_En_Bigokuta/ovl_En_Bigokuta.data.o" - include "build/data/ovl_En_Bigokuta/ovl_En_Bigokuta.reloc.o" + include "build/src/overlays/actors/ovl_En_Bigokuta/ovl_En_Bigokuta_reloc.o" endseg beginseg diff --git a/src/overlays/actors/ovl_En_Bigokuta/z_en_bigokuta.c b/src/overlays/actors/ovl_En_Bigokuta/z_en_bigokuta.c index 65ef97e26c..1ecc3d380e 100644 --- a/src/overlays/actors/ovl_En_Bigokuta/z_en_bigokuta.c +++ b/src/overlays/actors/ovl_En_Bigokuta/z_en_bigokuta.c @@ -5,6 +5,7 @@ */ #include "z_en_bigokuta.h" +#include "assets/objects/object_bigokuta/object_bigokuta.h" #define FLAGS 0x00000005 @@ -15,7 +16,21 @@ void EnBigokuta_Destroy(Actor* thisx, GlobalContext* globalCtx); void EnBigokuta_Update(Actor* thisx, GlobalContext* globalCtx); void EnBigokuta_Draw(Actor* thisx, GlobalContext* globalCtx); -#if 0 +void func_80AC2B4C(GlobalContext* globalCtx, EnBigokuta* this); +void EnBigokuta_SetupIdle(EnBigokuta* this); +void EnBigokuta_Idle(EnBigokuta* this, GlobalContext* globalCtx); +void EnBigokuta_SetupRise(EnBigokuta* this, GlobalContext* globalCtx); +void EnBigokuta_RiseOutOfWater(EnBigokuta* this, GlobalContext* globalCtx); +void EnBigokuta_SetupIdleAboveWater(EnBigokuta* this); +void EnBigokuta_IdleAboveWater(EnBigokuta* this, GlobalContext* globalCtx); +void EnBigokuta_SetupSuckInPlayer(EnBigokuta* this, GlobalContext* globalCtx); +void EnBigokuta_SuckInPlayer(EnBigokuta* this, GlobalContext* globalCtx); +void EnBigokuta_SetupHoldPlayer(EnBigokuta* this); +void EnBigokuta_HoldPlayer(EnBigokuta* this, GlobalContext* globalCtx); +void EnBigokuta_PlayDeathCutscene(EnBigokuta* this, GlobalContext* globalCtx); +void EnBigokuta_SetupDeathEffects(EnBigokuta* this); +void EnBigokuta_PlayDeathEffects(EnBigokuta* this, GlobalContext* globalCtx); + const ActorInit En_Bigokuta_InitVars = { ACTOR_EN_BIGOKUTA, ACTORCAT_BOSS, @@ -28,25 +43,54 @@ const ActorInit En_Bigokuta_InitVars = { (ActorFunc)EnBigokuta_Draw, }; -// static ColliderCylinderInit sCylinderInit = { -static ColliderCylinderInit D_80AC4530 = { - { COLTYPE_HARD, AT_NONE, AC_ON | AC_HARD | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1, COLSHAPE_CYLINDER, }, - { ELEMTYPE_UNK0, { 0x00000000, 0x00, 0x00 }, { 0xF7CFC74F, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_ON, }, +typedef enum { + BIGOCTO_DRAWEFFECT_ICE = 10, + BIGOCTO_DRAWEFFECT_LIGHT_ORBS = 20, +} EnBigokutaDrawEffect; + +static ColliderCylinderInit sShellCylinderInit = { + { + COLTYPE_HARD, + AT_NONE, + AC_ON | AC_HARD | AC_TYPE_PLAYER, + OC1_ON | OC1_TYPE_ALL, + OC2_TYPE_1, + COLSHAPE_CYLINDER, + }, + { + ELEMTYPE_UNK0, + { 0x00000000, 0x00, 0x00 }, + { 0xF7CFC74F, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, { 75, 125, 0, { 0, 0, 0 } }, }; -// static ColliderCylinderInit sCylinderInit = { -static ColliderCylinderInit D_80AC455C = { - { COLTYPE_HIT0, AT_NONE, AC_ON | AC_TYPE_PLAYER, OC1_NONE, OC2_TYPE_1, COLSHAPE_CYLINDER, }, - { ELEMTYPE_UNK0, { 0x00000000, 0x00, 0x00 }, { 0x000038B0, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_NONE, }, +static ColliderCylinderInit sBodyCylinderInit = { + { + COLTYPE_HIT0, + AT_NONE, + AC_ON | AC_TYPE_PLAYER, + OC1_NONE, + OC2_TYPE_1, + COLSHAPE_CYLINDER, + }, + { + ELEMTYPE_UNK0, + { 0x00000000, 0x00, 0x00 }, + { 0x000038B0, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_NONE, + }, { 70, 125, 0, { 0, 0, 0 } }, }; -// sColChkInfoInit -static CollisionCheckInfoInit D_80AC4588 = { 4, 130, 120, MASS_HEAVY }; +static CollisionCheckInfoInit sColChkInfoInit = { 4, 130, 120, MASS_HEAVY }; -// static InitChainEntry sInitChain[] = { -static InitChainEntry D_80AC4590[] = { +static InitChainEntry sInitChain[] = { ICHAIN_F32(uncullZoneForward, 2500, ICHAIN_CONTINUE), ICHAIN_F32(targetArrowOffset, 2000, ICHAIN_CONTINUE), ICHAIN_U8(targetMode, 2, ICHAIN_CONTINUE), @@ -54,73 +98,585 @@ static InitChainEntry D_80AC4590[] = { ICHAIN_VEC3F_DIV1000(scale, 33, ICHAIN_STOP), }; -#endif +void EnBigokuta_Init(Actor* thisx, GlobalContext* globalCtx) { + EnBigokuta* this = THIS; -extern ColliderCylinderInit D_80AC4530; -extern ColliderCylinderInit D_80AC455C; -extern CollisionCheckInfoInit D_80AC4588; -extern InitChainEntry D_80AC4590[]; + Actor_ProcessInitChain(&this->actor, sInitChain); + SkelAnime_InitFlex(globalCtx, &this->skelAnime, &gBigOctoSkel, &gBigOctoIdleAnim, this->jointTable, + this->morphTable, BIGOKUTA_LIMB_MAX); -extern UNK_TYPE D_06000444; -extern UNK_TYPE D_06000A74; -extern UNK_TYPE D_060014B8; + Collider_InitAndSetCylinder(globalCtx, &this->shellCollider, &this->actor, &sShellCylinderInit); + Collider_InitAndSetCylinder(globalCtx, &this->bodyCollider, &this->actor, &sBodyCylinderInit); + CollisionCheck_SetInfo(&this->actor.colChkInfo, NULL, &sColChkInfoInit); + this->cutscene = ActorCutscene_GetAdditionalCutscene(this->actor.cutscene); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/EnBigokuta_Init.s") + if (gSaveContext.weekEventReg[20] & 2 || + ((this->actor.params != 0xFF) && Flags_GetSwitch(globalCtx, this->actor.params))) { + Actor_MarkForDeath(&this->actor); + } else { + this->actor.world.pos.y -= 99.0f; + EnBigokuta_SetupIdle(this); + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/EnBigokuta_Destroy.s") + this->camAt.x = (Math_SinS(this->actor.home.rot.y) * 66.0f) + this->actor.world.pos.x; + this->camAt.y = (this->actor.home.pos.y - 49.5f) + 42.899998f; + this->camAt.z = (Math_CosS(this->actor.home.rot.y) * 66.0f) + this->actor.world.pos.z; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC28B4.s") + this->unkFunc = func_80AC2B4C; // set but never called +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC299C.s") +void EnBigokuta_Destroy(Actor* thisx, GlobalContext* globalCtx) { + EnBigokuta* this = THIS; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC2A1C.s") + Collider_DestroyCylinder(globalCtx, &this->shellCollider); + Collider_DestroyCylinder(globalCtx, &this->bodyCollider); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC2A7C.s") +void EnBigokuta_SetupCutsceneCamera(EnBigokuta* this, GlobalContext* globalCtx, Vec3f* at, Vec3f* eye) { + s16 angle; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC2B4C.s") + ActorCutscene_Start(this->actor.cutscene, &this->actor); + this->camId = ActorCutscene_GetCurrentCamera(this->actor.cutscene); + Play_CameraSetAtEye(globalCtx, this->camId, at, eye); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC2B98.s") + angle = BINANG_SUB(Actor_YawToPoint(&this->actor, eye), this->actor.home.rot.y); + if (angle > 0) { + angle = BINANG_ADD(this->actor.home.rot.y, 0x1800); + } else { + angle = BINANG_SUB(this->actor.home.rot.y, 0x1800); + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC2C30.s") + this->camEye.x = (Math_SinS(angle) * 250.0f) + this->camAt.x; + this->camEye.y = this->camAt.y + 100.0f; + this->camEye.z = (Math_CosS(angle) * 250.0f) + this->camAt.z; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC2C84.s") +void EnBigokuta_MoveCamera(EnBigokuta* this, GlobalContext* globalCtx) { + Camera* camera = Play_GetCamera(globalCtx, this->camId); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC2CE8.s") + Math_Vec3f_StepTo(&camera->eye, &this->camEye, 20.0f); + Math_Vec3f_StepTo(&camera->at, &this->camAt, 20.0f); + Play_CameraSetAtEye(globalCtx, this->camId, &camera->at, &camera->eye); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC2DAC.s") +void EnBigokuta_ResetCamera(EnBigokuta* this, GlobalContext* globalCtx) { + Camera* camera; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC2EBC.s") + if (this->camId != 0) { + camera = Play_GetCamera(globalCtx, this->camId); + Play_CameraSetAtEye(globalCtx, 0, &camera->at, &camera->eye); + this->camId = 0; + ActorCutscene_Stop(this->actor.cutscene); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC2F20.s") +void EnBigokuta_ShootPlayer(EnBigokuta* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC2F64.s") + if (&this->actor == player->actor.parent) { + player->actor.parent = NULL; + player->unk_AE8 = 100; + player->actor.velocity.y = 0.0f; + player->actor.world.pos.x += 20.0f * Math_SinS(this->actor.home.rot.y); + player->actor.world.pos.z += 20.0f * Math_CosS(this->actor.home.rot.y); + func_800B8D50(globalCtx, &this->actor, 10.0f, this->actor.home.rot.y, 10.0f, 4); + } + EnBigokuta_ResetCamera(this, globalCtx); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC3054.s") +void func_80AC2B4C(GlobalContext* globalCtx, EnBigokuta* this) { + func_8013A530(globalCtx, &this->actor, 3, &this->actor.focus.pos, &this->actor.shape.rot, 280.0f, 1800.0f, -1); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC30EC.s") +s32 EnBigokuta_IsInWater(EnBigokuta* this, GlobalContext* globalCtx) { + WaterBox* box; + s32 bgId; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC31EC.s") + this->actor.floorHeight = BgCheck_EntityRaycastFloor5(&globalCtx->colCtx, &this->actor.floorPoly, &bgId, + &this->actor, &this->actor.world.pos); + if (!WaterBox_GetSurface1_2(globalCtx, &globalCtx->colCtx, this->actor.world.pos.x, this->actor.world.pos.z, + &this->actor.home.pos.y, &box) || + (this->actor.home.pos.y <= this->actor.floorHeight)) { + return false; + } else { + return true; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC33A4.s") +void EnBigokuta_SpawnRipple(EnBigokuta* this, GlobalContext* globalCtx) { + Vec3f ripplePos; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC33C0.s") + ripplePos.x = this->actor.world.pos.x; + ripplePos.y = this->actor.home.pos.y; + ripplePos.z = this->actor.world.pos.z; + EffectSsGRipple_Spawn(globalCtx, &ripplePos, 1000, 1400, 0); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC3460.s") +void EnBigokuta_SetupIdle(EnBigokuta* this) { + Animation_Change(&this->skelAnime, &gBigOctoIdleAnim, 0.5f, 0.0f, 0.0f, 1, -3.0f); + this->actionFunc = EnBigokuta_Idle; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC34A8.s") +void EnBigokuta_Idle(EnBigokuta* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC35E8.s") + SkelAnime_Update(&this->skelAnime); + Math_StepToF(&this->actor.world.pos.y, this->actor.home.pos.y - 99.0f, 2.5f); + Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 5, 0x1000); + if ((this->actor.xzDistToPlayer < 300.0f) && ((player->actor.world.pos.y - this->actor.home.pos.y) < 100.0f)) { + EnBigokuta_SetupRise(this, globalCtx); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC3650.s") +void EnBigokuta_SetupRise(EnBigokuta* this, GlobalContext* globalCtx) { + Vec3f splashPos; + s32 i; + s16 angle = 0; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC3930.s") + Animation_PlayOnce(&this->skelAnime, &gBigOctoRiseOutOfWaterAnim); + splashPos.y = this->actor.home.pos.y; + for (i = 0; i < 8; i++) { + splashPos.x = Math_SinS(angle) * 70.0f + this->actor.world.pos.x; + splashPos.z = Math_CosS(angle) * 70.0f + this->actor.world.pos.z; + EffectSsGSplash_Spawn(globalCtx, &splashPos, NULL, NULL, 0, Rand_S16Offset(1000, 200)); + angle = BINANG_ADD(angle, 0x2000); + } + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_DAIOCTA_LAND); + this->actionFunc = EnBigokuta_RiseOutOfWater; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC39A0.s") +void EnBigokuta_RiseOutOfWater(EnBigokuta* this, GlobalContext* globalCtx) { + Math_StepToF(&this->actor.world.pos.y, this->actor.home.pos.y - 16.5f, 15.0f); + if (SkelAnime_Update(&this->skelAnime)) { + EnBigokuta_SetupIdleAboveWater(this); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/EnBigokuta_Update.s") +void EnBigokuta_SetupIdleAboveWater(EnBigokuta* this) { + Animation_MorphToLoop(&this->skelAnime, &gBigOctoIdleAnim, -5.0f); + this->actionFunc = EnBigokuta_IdleAboveWater; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC3D48.s") +void EnBigokuta_IdleAboveWater(EnBigokuta* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + Math_StepToF(&this->actor.world.pos.y, this->actor.home.pos.y - 16.5f, 2.5f); + Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 5, 0x1000); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/func_80AC4204.s") + if ((this->actor.xzDistToPlayer > 400.0f) || (this->actor.playerHeightRel > 200.0f)) { + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_DAIOCTA_SINK); + EnBigokuta_SetupIdle(this); + } else if ((this->actor.xzDistToPlayer < 200.0f) && globalCtx->grabPlayer(globalCtx, GET_PLAYER(globalCtx))) { + EnBigokuta_SetupSuckInPlayer(this, globalCtx); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bigokuta/EnBigokuta_Draw.s") +void EnBigokuta_UpdateOrSetupCam(EnBigokuta* this, GlobalContext* globalCtx) { + if (this->actor.cutscene != -1) { + if (this->camId != 0) { + EnBigokuta_MoveCamera(this, globalCtx); + } else if (ActorCutscene_GetCanPlayNext(this->actor.cutscene)) { + Camera* camera = Play_GetCamera(globalCtx, 0); + + EnBigokuta_SetupCutsceneCamera(this, globalCtx, &camera->at, &camera->eye); + } else { + ActorCutscene_SetIntentToPlay(this->actor.cutscene); + } + } +} + +void EnBigokuta_SetupSuckInPlayer(EnBigokuta* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + + player->actor.parent = &this->actor; + this->actor.shape.rot.y = this->actor.yawTowardsPlayer; + Math_Vec3f_Copy(&this->playerPos, &player->actor.world.pos); + this->timer = 0; + + Animation_Change(&this->skelAnime, &gBigOctoIdleAnim, 1.0f, 12.0f, 12.0f, 2, -3.0f); + ActorCutscene_SetIntentToPlay(this->actor.cutscene); + + this->playerHoldPos.x = (Math_SinS(this->actor.shape.rot.y) * 66.0f) + this->actor.world.pos.x; + this->playerHoldPos.y = (this->actor.home.pos.y - 49.5f) + 42.899998f; + this->playerHoldPos.z = (Math_CosS(this->actor.shape.rot.y) * 66.0f) + this->actor.world.pos.z; + + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_SLIME_DEAD); + this->actionFunc = EnBigokuta_SuckInPlayer; +} + +void EnBigokuta_SuckInPlayer(EnBigokuta* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + + EnBigokuta_UpdateOrSetupCam(this, globalCtx); + SkelAnime_Update(&this->skelAnime); + Math_StepToF(&this->actor.world.pos.y, this->actor.home.pos.y - 49.5f, 10.0f); + + if (this->timer < 9) { + this->timer++; + } + + player->unk_AE8 = 0; + Math_Vec3f_Copy(&player->actor.world.pos, &this->playerPos); + if (Math_Vec3f_StepTo(&player->actor.world.pos, &this->playerHoldPos, sqrtf(this->timer) * 5.0f) < 0.1f) { + s16 rotY = this->actor.shape.rot.y; + + if (Math_ScaledStepToS(&this->actor.shape.rot.y, this->actor.home.rot.y, 0x800)) { + EnBigokuta_SetupHoldPlayer(this); + } + + this->playerHoldPos.x = (Math_SinS(this->actor.shape.rot.y) * 66.0f) + this->actor.world.pos.x; + this->playerHoldPos.y = (this->actor.home.pos.y - 49.5f) + 42.899998f; + this->playerHoldPos.z = (Math_CosS(this->actor.shape.rot.y) * 66.0f) + this->actor.world.pos.z; + + Math_Vec3f_Copy(&player->actor.world.pos, &this->playerHoldPos); + Math_Vec3f_Copy(&this->playerPos, &player->actor.world.pos); + player->actor.shape.rot.y += BINANG_SUB(this->actor.shape.rot.y, rotY); + } else { + Math_Vec3f_Copy(&this->playerPos, &player->actor.world.pos); + player->actor.velocity.y = 0.0f; + } +} + +void EnBigokuta_SetupHoldPlayer(EnBigokuta* this) { + this->timer = 12; + this->actionFunc = EnBigokuta_HoldPlayer; +} + +void EnBigokuta_HoldPlayer(EnBigokuta* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + + this->timer--; + if (this->timer >= 0) { + EnBigokuta_UpdateOrSetupCam(this, globalCtx); + Math_Vec3f_Copy(&player->actor.world.pos, &this->playerHoldPos); + + if (this->timer == 0) { + EnBigokuta_ShootPlayer(this, globalCtx); + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_DAIOCTA_REVERSE); + } + } else if (this->timer == -24) { + EnBigokuta_SetupIdleAboveWater(this); + } +} + +void EnBigokuta_SetupDeathCutscene(EnBigokuta* this) { + ActorCutscene_SetIntentToPlay(this->cutscene); + this->timer = 0; + this->bodyCollider.base.acFlags &= ~AC_ON; + this->actionFunc = EnBigokuta_PlayDeathCutscene; +} + +void EnBigokuta_PlayDeathCutscene(EnBigokuta* this, GlobalContext* globalCtx) { + Player* player; + + this->actor.colorFilterTimer = Animation_GetLastFrame(&gBigOctoDeathAnim); + + if (this->timer != 0) { + this->timer--; + if (this->timer == 0) { + this->drawEffect = 0; + this->drawEffectAlpha = 0.0f; + Actor_SpawnIceEffects(globalCtx, &this->actor, this->limbPos, ARRAY_COUNT(this->limbPos), 2, 0.5f, 0.35f); + EnBigokuta_SetupDeathEffects(this); + } + } else if (ActorCutscene_GetCanPlayNext(this->cutscene)) { + ActorCutscene_Start(this->cutscene, &this->actor); + + if (!(gSaveContext.eventInf[4] & 2) && !(gSaveContext.eventInf[3] & 0x20)) { + func_800B724C(globalCtx, &this->actor, 7); + } else { + player = GET_PLAYER(globalCtx); + player->stateFlags1 |= 0x20; + } + + if (this->drawEffect == BIGOCTO_DRAWEFFECT_ICE) { + this->timer = 3; + } else { + EnBigokuta_SetupDeathEffects(this); + } + } else { + ActorCutscene_SetIntentToPlay(this->cutscene); + } +} + +void EnBigokuta_SetupDeathEffects(EnBigokuta* this) { + Animation_MorphToPlayOnce(&this->skelAnime, &gBigOctoDeathAnim, -5.0f); + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_DAIOCTA_DEAD2); + this->actor.flags &= ~1; + this->timer = 10; + this->actionFunc = EnBigokuta_PlayDeathEffects; +} + +void EnBigokuta_PlayDeathEffects(EnBigokuta* this, GlobalContext* globalCtx) { + static Vec3f D_80AC45A4 = { 0.0f, -0.5f, 0.0f }; + static Color_RGBA8 D_80AC45B0 = { 255, 255, 255, 255 }; + static Color_RGBA8 D_80AC45B4 = { 100, 255, 255, 255 }; + static Color_RGBA8 D_80AC45B8 = { 150, 150, 150, 0 }; + + if (SkelAnime_Update(&this->skelAnime)) { + this->actor.world.pos.y -= 0.2f; + + if (this->timer > 0) { + this->timer--; + + if (this->timer == 6) { + Vec3f dustPos; + + dustPos.x = this->actor.world.pos.x; + dustPos.y = this->actor.world.pos.y + 150.0f; + dustPos.z = this->actor.world.pos.z; + + func_800B0DE0(globalCtx, &dustPos, &gZeroVec3f, &gZeroVec3f, &D_80AC45B0, &D_80AC45B4, 1200, 20); + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_OCTAROCK_DEAD2); + } + } else { + this->actor.world.pos.y -= 0.2f; + + if (Math_StepToF(&this->actor.scale.y, 0.001f, 0.001f)) { + s32 i; + Vec3f bubbleVel; + Vec3f bubblePos; + + SoundSource_PlaySfxAtFixedWorldPos(globalCtx, &this->actor.world.pos, 50, NA_SE_EN_COMMON_WATER_MID); + bubblePos.y = this->actor.world.pos.y; + + for (i = 0; i < 20; i++) { + bubbleVel.x = randPlusMinusPoint5Scaled(10.0f); + bubbleVel.y = Rand_ZeroFloat(5.5f) + 5.5f; + bubbleVel.z = randPlusMinusPoint5Scaled(10.0f); + bubblePos.x = this->actor.world.pos.x + (2.0f * bubbleVel.x); + bubblePos.z = this->actor.world.pos.z + (2.0f * bubbleVel.z); + + EffectSsDtBubble_SpawnCustomColor(globalCtx, &bubblePos, &bubbleVel, &D_80AC45A4, &D_80AC45B0, + &D_80AC45B8, Rand_S16Offset(150, 50), 25, 0); + } + + if (this->actor.params != 0xFF) { + Flags_SetSwitch(globalCtx, this->actor.params); + } + + ActorCutscene_Stop(this->cutscene); + Actor_MarkForDeath(&this->actor); + + if (!(gSaveContext.eventInf[4] & 2) && !(gSaveContext.eventInf[3] & 0x20)) { + func_800B724C(globalCtx, &this->actor, 6); + } else { + Player* player = GET_PLAYER(globalCtx); + + player->stateFlags1 &= ~0x20; + } + } + + if (this->drawEffectAlpha > 0.0f) { + this->drawEffectAlpha = this->actor.scale.y * 30.30303f; + } + } + } else { + Math_StepToF(&this->actor.world.pos.y, this->actor.home.pos.y - 16.5f, 15.0f); + } +} + +s32 EnBigokuta_IsNearSwampBoat(EnBigokuta* this, GlobalContext* globalCtx) { + this->actor.child = SubS_FindActor(globalCtx, NULL, ACTORCAT_BG, ACTOR_BG_INGATE); + + if ((this->actor.child != NULL) && (Actor_XZDistanceBetweenActors(&this->actor, this->actor.child) < 250.0f)) { + return true; + } else { + return false; + } +} + +void EnBigokuta_CheckOneHitKill(EnBigokuta* this, GlobalContext* globalCtx) { + if ((this->bodyCollider.base.acFlags & AC_ON) && + ((this->bodyCollider.base.acFlags & AC_HIT) || + ((globalCtx->sceneNum == SCENE_20SICHITAI || globalCtx->sceneNum == SCENE_20SICHITAI2) && + EnBigokuta_IsNearSwampBoat(this, globalCtx)))) { + Enemy_StartFinishingBlow(globalCtx, &this->actor); + + if (this->bodyCollider.base.acFlags & AC_HIT) { + if (this->bodyCollider.info.acHitInfo->toucher.dmgFlags & 0x1000) { // Ice Arrow + this->drawEffect = BIGOCTO_DRAWEFFECT_ICE; + this->drawEffectScale = 1.2f; + this->drawEffectSteamScale = 1.8000001f; + this->drawEffectAlpha = 1.0f; + } else if (this->bodyCollider.info.acHitInfo->toucher.dmgFlags & 0x2000) { // Light Arrow + this->drawEffect = BIGOCTO_DRAWEFFECT_LIGHT_ORBS; + this->drawEffectScale = 1.2f; + this->drawEffectAlpha = 4.0f; + Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_CLEAR_TAG, + this->bodyCollider.info.bumper.hitPos.x, this->bodyCollider.info.bumper.hitPos.y, + this->bodyCollider.info.bumper.hitPos.z, 0, 0, 0, CLEAR_TAG_LARGE_LIGHT_RAYS); + } + } + + this->bodyCollider.base.acFlags &= ~AC_HIT; + Actor_SetColorFilter(&this->actor, 0x4000, 255, 0, Animation_GetLastFrame(&gBigOctoDeathAnim)); + EnBigokuta_ShootPlayer(this, globalCtx); + EnBigokuta_SetupDeathCutscene(this); + } +} + +void EnBigokuta_Update(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + EnBigokuta* this = THIS; + + if (!EnBigokuta_IsInWater(this, globalCtx)) { + Actor_MarkForDeath(&this->actor); + return; + } + + if (globalCtx->gameplayFrames % 7 == 0) { + EnBigokuta_SpawnRipple(this, globalCtx); + } + + EnBigokuta_CheckOneHitKill(this, globalCtx); + this->actionFunc(this, globalCtx); + + if ((this->bodyCollider.base.acFlags & AC_ON)) { + this->shellCollider.dim.pos.x = Math_SinS(this->actor.shape.rot.y) * -20.0f + this->actor.world.pos.x; + this->shellCollider.dim.pos.y = this->actor.world.pos.y; + this->shellCollider.dim.pos.z = Math_CosS(this->actor.shape.rot.y) * -20.0f + this->actor.world.pos.z; + + this->bodyCollider.dim.pos.x = this->shellCollider.dim.pos.x; + this->bodyCollider.dim.pos.y = this->shellCollider.dim.pos.y; + this->bodyCollider.dim.pos.z = this->shellCollider.dim.pos.z; + + CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->bodyCollider.base); + CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->shellCollider.base); + CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->shellCollider.base); + Actor_SetFocus(&this->actor, 82.5f); + } + + if (this->drawEffectAlpha > 0.0f) { + if (this->drawEffect != BIGOCTO_DRAWEFFECT_ICE) { + Math_StepToF(&this->drawEffectAlpha, 0.0f, 0.05f); + this->drawEffectScale = (this->drawEffectAlpha + 1.0f) * 0.6f; + this->drawEffectScale = CLAMP_MAX(this->drawEffectScale, 1.2f); + } else if (!Math_StepToF(&this->drawEffectSteamScale, 1.2f, 0.030000001f)) { + func_800B9010(&this->actor, NA_SE_EV_ICE_FREEZE - SFX_FLAG); + } + } +} + +s32 EnBigokuta_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, + Actor* thisx, Gfx** gfx) { + if (limbIndex == BIGOKUTA_LIMB_HEAD) { + EnBigokuta* this = THIS; + s32 envColor; + s16 rotX; + f32 lastFrame; + + if (this->actionFunc == EnBigokuta_PlayDeathEffects) { + lastFrame = Animation_GetLastFrame(&gBigOctoDeathAnim); + envColor = ((255.0f / lastFrame) * (lastFrame - this->skelAnime.curFrame)); + } else { + envColor = 255; + } + gDPPipeSync((*gfx)++); + gDPSetEnvColor((*gfx)++, envColor, envColor, envColor, envColor); + + if (this->actionFunc == EnBigokuta_SuckInPlayer) { + rotX = (s16)(this->timer * 6144.0f * (1 / 9.0f)); + rot->x -= rotX; + } else if (this->actionFunc == EnBigokuta_HoldPlayer) { + if (this->timer == 1) { + rotX = 0; + } else if (this->timer == 0) { + rotX = -0xC00; + } else if (this->timer > 0) { + rotX = 0x1800; + } else { + rotX = ((this->timer + 0x18) * 0.041666668f * -6144.0f); + } + rot->x -= rotX; + } + } else if (limbIndex == BIGOKUTA_LIMB_SNOUT_CENTER) { + EnBigokuta* this = THIS; + + if (this->actionFunc == EnBigokuta_PlayDeathEffects) { + if (this->timer < 5) { + Matrix_Scale(1.0f, 1.0f, (this->timer * 0.2f * 0.25f) + 1.0f, MTXMODE_APPLY); + } else if (this->timer < 8) { + f32 time = (this->timer - 5) * (1 / 12.0f); + + Matrix_Scale(1.0f + time, 1.0f + time, 1.25f - time, MTXMODE_APPLY); + } else { + Matrix_Scale(1.25f - ((this->timer - 8) * 0.125f), 1.25f - ((this->timer - 8) * 0.125f), 1.0f, + MTXMODE_APPLY); + } + } else if (this->actionFunc == EnBigokuta_SuckInPlayer) { + f32 sin = sin_rad(this->timer * (M_PI / 3.0f)) * 0.5f; + + Matrix_Scale(((this->timer * (2 / 90.0f)) * (0.5f + sin)) + 1.0f, + ((this->timer * (2 / 90.0f)) * (0.5f - sin)) + 1.0f, 1.0f - ((this->timer * 0.3f) / 9.0f), + MTXMODE_APPLY); + } else if (this->actionFunc == EnBigokuta_HoldPlayer && this->timer != 1) { + if (this->timer == 0) { + Matrix_Scale(0.9f, 0.9f, 1.15f, MTXMODE_APPLY); + } else if (this->timer > 0) { + f32 sin = sin_rad(this->timer * (M_PI / 3.0f)) * 0.5f; + + Matrix_Scale(((0.5f + sin) * 0.2f) + 1.0f, ((0.5f - sin) * 0.2f) + 1.0f, 0.7f, MTXMODE_APPLY); + } else { + Matrix_Scale(1.0f - ((this->timer + 0x18) * 0.2f * 0.041666668f), + 1.0f - ((this->timer + 0x18) * 0.2f * 0.041666668f), + ((this->timer + 0x18) * 0.3f * 0.041666668f) + 1.0f, MTXMODE_APPLY); + } + } + } + return false; +} + +void EnBigokuta_PostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx, + Gfx** gfx) { + static s8 D_80AC45BC[] = { + -1, -1, -1, 0, -1, 1, -1, 2, -1, 3, 8, 4, -1, 5, -1, -1, -1, -1, 6, 7, + }; + static Vec3f D_80AC45D0[] = { + { 0.0f, 2000.0f, 1000.0f }, { 0.0f, 2000.0f, -2000.0f }, { 1700.0f, 700.0f, -600.0f }, + { -1700.0f, 700.0f, -600.0f }, { 0.0f, 500.0f, -2500.0f }, + }; + EnBigokuta* this = THIS; + s32 i; + s8 limbPosIndex = D_80AC45BC[limbIndex]; + + if (limbPosIndex != -1) { + if (limbPosIndex < 6) { + Matrix_GetStateTranslationAndScaledX(800.0f, &this->limbPos[limbPosIndex]); + } else if (limbPosIndex < 8) { + Matrix_GetStateTranslation(&this->limbPos[limbPosIndex]); + } else { + for (i = 0; i < ARRAY_COUNT(D_80AC45D0); i++) { + Matrix_MultiplyVector3fByState(&D_80AC45D0[i], &this->limbPos[limbPosIndex + i]); + } + } + } +} + +void EnBigokuta_Draw(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + EnBigokuta* this = THIS; + Gfx* gfx; + + OPEN_DISPS(globalCtx->state.gfxCtx); + if ((this->actionFunc != EnBigokuta_PlayDeathEffects) || (this->timer != 0)) { + Scene_SetRenderModeXlu(globalCtx, 0, 1); + gfx = POLY_OPA_DISP; + gSPDisplayList(&gfx[0], &sSetupDL[6 * 25]); + gDPSetEnvColor(&gfx[1], 255, 255, 255, 255); + POLY_OPA_DISP = SkelAnime_DrawFlex(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, + this->skelAnime.dListCount, EnBigokuta_OverrideLimbDraw, + EnBigokuta_PostLimbDraw, &this->actor, &gfx[2]); + } else { + Scene_SetRenderModeXlu(globalCtx, 1, 2); + gfx = POLY_XLU_DISP; + gSPDisplayList(&gfx[0], &sSetupDL[6 * 25]); + gDPSetEnvColor(&gfx[1], 0, 0, 0, (this->actor.scale.y * 7727.273f)); + POLY_XLU_DISP = + SkelAnime_DrawFlex(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, + this->skelAnime.dListCount, NULL, EnBigokuta_PostLimbDraw, &this->actor, &gfx[2]); + } + + func_800BE680(globalCtx, &this->actor, this->limbPos, ARRAY_COUNT(this->limbPos), this->drawEffectScale, + this->drawEffectSteamScale, this->drawEffectAlpha, this->drawEffect); + CLOSE_DISPS(globalCtx->state.gfxCtx); +} diff --git a/src/overlays/actors/ovl_En_Bigokuta/z_en_bigokuta.h b/src/overlays/actors/ovl_En_Bigokuta/z_en_bigokuta.h index 40b23d63cc..ac0cb01581 100644 --- a/src/overlays/actors/ovl_En_Bigokuta/z_en_bigokuta.h +++ b/src/overlays/actors/ovl_En_Bigokuta/z_en_bigokuta.h @@ -6,12 +6,53 @@ struct EnBigokuta; typedef void (*EnBigokutaActionFunc)(struct EnBigokuta*, GlobalContext*); +typedef void (*EnBigokutaUnkFunc)(GlobalContext*, struct EnBigokuta*); + +typedef enum { + /* 00 */ BIGOKUTA_LIMB_NONE, + /* 01 */ BIGOKUTA_LIMB_BODY, + /* 02 */ BIGOKUTA_LIMB_ARM_BASE_RIGHT_FRONT, + /* 03 */ BIGOKUTA_LIMB_ARM_END_RIGHT_FRONT, + /* 04 */ BIGOKUTA_LIMB_ARM_BASE_LEFT_FRONT, + /* 05 */ BIGOKUTA_LIMB_ARM_END_LEFT_FRONT, + /* 06 */ BIGOKUTA_LIMB_ARM_BASE_RIGHT_BACK, + /* 07 */ BIGOKUTA_LIMB_ARM_END_RIGHT_BACK, + /* 08 */ BIGOKUTA_LIMB_ARM_BASE_LEFT_BACK, + /* 09 */ BIGOKUTA_LIMB_ARM_END_LEFT_BACK, + /* 10 */ BIGOKUTA_LIMB_HEAD, + /* 11 */ BIGOKUTA_LIMB_TENTACLE_BASE_LEFT, + /* 12 */ BIGOKUTA_LIMB_TENTACLE_TIP_LEFT, + /* 13 */ BIGOKUTA_LIMB_TENTACLE_BASE_RIGHT, + /* 14 */ BIGOKUTA_LIMB_TENTACLE_TIP_RIGHT, + /* 15 */ BIGOKUTA_LIMB_WEAK_POINT_LEFT, + /* 16 */ BIGOKUTA_LIMB_WEAK_POINT_RIGHT, + /* 17 */ BIGOKUTA_LIMB_SNOUT_CENTER, + /* 18 */ BIGOKUTA_LIMB_SNOUT_RIGHT, + /* 19 */ BIGOKUTA_LIMB_SNOUT_LEFT, + /* 20 */ BIGOKUTA_LIMB_MAX +} ObjectBigokutaLimbs; typedef struct EnBigokuta { /* 0x0000 */ Actor actor; - /* 0x0144 */ char unk_144[0x48]; + /* 0x0144 */ EnBigokutaUnkFunc unkFunc; // possibly something to do with photographing + /* 0x0148 */ SkelAnime skelAnime; /* 0x018C */ EnBigokutaActionFunc actionFunc; - /* 0x0190 */ char unk_190[0x268]; + /* 0x0190 */ u8 drawEffect; + /* 0x0192 */ s16 timer; + /* 0x0194 */ s16 camId; + /* 0x0196 */ s16 cutscene; + /* 0x0198 */ Vec3s jointTable[BIGOKUTA_LIMB_MAX]; + /* 0x0210 */ Vec3s morphTable[BIGOKUTA_LIMB_MAX]; + /* 0x0288 */ f32 drawEffectAlpha; + /* 0x028C */ f32 drawEffectScale; + /* 0x0290 */ f32 drawEffectSteamScale; // only affects DRAWEFFECT_ICE + /* 0x0294 */ Vec3f playerPos; + /* 0x02A0 */ Vec3f playerHoldPos; + /* 0x02AC */ Vec3f camAt; + /* 0x02B8 */ Vec3f camEye; + /* 0x02C4 */ Vec3f limbPos[13]; + /* 0x0360 */ ColliderCylinder shellCollider; + /* 0x03AC */ ColliderCylinder bodyCollider; } EnBigokuta; // size = 0x3F8 extern const ActorInit En_Bigokuta_InitVars; diff --git a/tools/disasm/functions.txt b/tools/disasm/functions.txt index 6ca4f0cbdd..a07ccca4ce 100644 --- a/tools/disasm/functions.txt +++ b/tools/disasm/functions.txt @@ -11912,33 +11912,33 @@ 0x80AC24A8:("func_80AC24A8",), 0x80AC26F0:("EnBigokuta_Init",), 0x80AC2874:("EnBigokuta_Destroy",), - 0x80AC28B4:("func_80AC28B4",), - 0x80AC299C:("func_80AC299C",), - 0x80AC2A1C:("func_80AC2A1C",), - 0x80AC2A7C:("func_80AC2A7C",), + 0x80AC28B4:("EnBigokuta_SetupCutsceneCamera",), + 0x80AC299C:("EnBigokuta_MoveCamera",), + 0x80AC2A1C:("EnBigokuta_ResetCamera",), + 0x80AC2A7C:("EnBigokuta_ShootPlayer",), 0x80AC2B4C:("func_80AC2B4C",), - 0x80AC2B98:("func_80AC2B98",), - 0x80AC2C30:("func_80AC2C30",), - 0x80AC2C84:("func_80AC2C84",), - 0x80AC2CE8:("func_80AC2CE8",), - 0x80AC2DAC:("func_80AC2DAC",), - 0x80AC2EBC:("func_80AC2EBC",), - 0x80AC2F20:("func_80AC2F20",), - 0x80AC2F64:("func_80AC2F64",), - 0x80AC3054:("func_80AC3054",), - 0x80AC30EC:("func_80AC30EC",), - 0x80AC31EC:("func_80AC31EC",), - 0x80AC33A4:("func_80AC33A4",), - 0x80AC33C0:("func_80AC33C0",), - 0x80AC3460:("func_80AC3460",), - 0x80AC34A8:("func_80AC34A8",), - 0x80AC35E8:("func_80AC35E8",), - 0x80AC3650:("func_80AC3650",), - 0x80AC3930:("func_80AC3930",), - 0x80AC39A0:("func_80AC39A0",), + 0x80AC2B98:("EnBigokuta_IsInWater",), + 0x80AC2C30:("EnBigokuta_SpawnRipple",), + 0x80AC2C84:("EnBigokuta_SetupIdle",), + 0x80AC2CE8:("EnBigokuta_Idle",), + 0x80AC2DAC:("EnBigokuta_SetupRise",), + 0x80AC2EBC:("EnBigokuta_RiseOutOfWater",), + 0x80AC2F20:("EnBigokuta_SetupIdleAboveWater",), + 0x80AC2F64:("EnBigokuta_IdleAboveWater",), + 0x80AC3054:("EnBigokuta_UpdateOrSetupCam",), + 0x80AC30EC:("EnBigokuta_SetupSuckInPlayer",), + 0x80AC31EC:("EnBigokuta_SuckInPlayer",), + 0x80AC33A4:("EnBigokuta_SetupHoldPlayer",), + 0x80AC33C0:("EnBigokuta_HoldPlayer",), + 0x80AC3460:("EnBigokuta_SetupDeathCutscene",), + 0x80AC34A8:("EnBigokuta_PlayDeathCutscene",), + 0x80AC35E8:("EnBigokuta_SetupDeathEffects",), + 0x80AC3650:("EnBigokuta_PlayDeathEffects",), + 0x80AC3930:("EnBigokuta_IsNearSwampBoat",), + 0x80AC39A0:("EnBigokuta_CheckOneHitKill",), 0x80AC3B2C:("EnBigokuta_Update",), - 0x80AC3D48:("func_80AC3D48",), - 0x80AC4204:("func_80AC4204",), + 0x80AC3D48:("EnBigokuta_OverrideLimbDraw",), + 0x80AC4204:("EnBigokuta_PostLimbDraw",), 0x80AC42F8:("EnBigokuta_Draw",), 0x80AC48F0:("BgIcefloe_Init",), 0x80AC4A04:("BgIcefloe_Destroy",), diff --git a/undefined_syms.txt b/undefined_syms.txt index 971cc4c7aa..adce7821d0 100644 --- a/undefined_syms.txt +++ b/undefined_syms.txt @@ -1253,13 +1253,6 @@ D_06001398 = 0x06001398; D_06000074 = 0x06000074; D_06001E60 = 0x06001E60; -// ovl_En_Bigokuta - -D_06000444 = 0x06000444; -D_06000A74 = 0x06000A74; -D_060014B8 = 0x060014B8; -D_06006BC0 = 0x06006BC0; - // ovl_En_Bigpamet D_06000440 = 0x06000440;