diff options
| author | petrie911 <69443847+petrie911@users.noreply.github.com> | 2021-04-05 18:08:45 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-04-06 01:08:45 +0200 |
| commit | d47528ee591c0093dd704fa82f5bfe15d9435158 (patch) | |
| tree | a5ee6fa5260f78abb230ad8f0320960494bc6ec5 /src | |
| parent | b72ba754a262b76e5d1521d2eec60aa73e3c3300 (diff) | |
Bongo Bongo (ovl_Boss_Sst) (#458)
* First pass
* Darkmeiro decompilation
Bg_Gnd_Darkmeiro decompiled, matched, and documented.
* give this a shot
* fix conflict
* one more try
* more matching fun
* fun with bongo
* clean this up later
* found the matching versions
* diff.py has escaped?
* now with more docs
* Now with floor and more docs
* one more thing
* incremental progress
* It's Bongo time
* one little thing
* merge ZAP
* update
* camera
* gfx now in their own file
* now with more object decomp
* name animations
* now shiftable
* missed some. also DECR
* opd merge
* start xml
* now with xml asset extraction
* format
* cleanup
* removed union
Co-authored-by: Kelebek1 <eeeedddccc@hotmail.co.uk>
Co-authored-by: petrie911 <pmontag@DESKTOP-LG8A167.localdomain>
Diffstat (limited to 'src')
| -rw-r--r-- | src/overlays/actors/ovl_Bg_Sst_Floor/z_bg_sst_floor.c | 129 | ||||
| -rw-r--r-- | src/overlays/actors/ovl_Bg_Sst_Floor/z_bg_sst_floor.h | 11 | ||||
| -rw-r--r-- | src/overlays/actors/ovl_Boss_Sst/z_boss_sst.c | 3803 | ||||
| -rw-r--r-- | src/overlays/actors/ovl_Boss_Sst/z_boss_sst.h | 50 | ||||
| -rw-r--r-- | src/overlays/actors/ovl_Boss_Sst/z_boss_sst_colchk.c | 352 |
5 files changed, 3732 insertions, 613 deletions
diff --git a/src/overlays/actors/ovl_Bg_Sst_Floor/z_bg_sst_floor.c b/src/overlays/actors/ovl_Bg_Sst_Floor/z_bg_sst_floor.c index 290f41f2a..128708f3d 100644 --- a/src/overlays/actors/ovl_Bg_Sst_Floor/z_bg_sst_floor.c +++ b/src/overlays/actors/ovl_Bg_Sst_Floor/z_bg_sst_floor.c @@ -1,15 +1,23 @@ +/* + * File: z_bg_sst_floor.c + * Overlay: ovl_Bg_Sst_Floor + * Description: Bongo Bongo's drum + */ + #include "z_bg_sst_floor.h" +#include "objects/object_sst/object_sst.h" #define FLAGS 0x00000030 #define THIS ((BgSstFloor*)thisx) -void BgSstFloor_Init(Actor* thisx, GlobalContext* globalCtx); -void BgSstFloor_Destroy(Actor* thisx, GlobalContext* globalCtx); -void BgSstFloor_Update(Actor* thisx, GlobalContext* globalCtx); -void BgSstFloor_Draw(Actor* thisx, GlobalContext* globalCtx); +void BgSstFloor_Init(BgSstFloor* this, GlobalContext* globalCtx); +void BgSstFloor_Destroy(BgSstFloor* this, GlobalContext* globalCtx); +void BgSstFloor_Update(BgSstFloor* this, GlobalContext* globalCtx); +void BgSstFloor_Draw(BgSstFloor* this, GlobalContext* globalCtx); + +static s32 sUnkValues[] = { 0, 0, 0 }; // Unused, probably a zero vector -/* const ActorInit Bg_Sst_Floor_InitVars = { ACTOR_BG_SST_FLOOR, ACTORCAT_BG, @@ -21,11 +29,112 @@ const ActorInit Bg_Sst_Floor_InitVars = { (ActorFunc)BgSstFloor_Update, (ActorFunc)BgSstFloor_Draw, }; -*/ -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Bg_Sst_Floor/BgSstFloor_Init.s") -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Bg_Sst_Floor/BgSstFloor_Destroy.s") +static InitChainEntry sInitChain[] = { + ICHAIN_VEC3F_DIV1000(scale.x, 100, ICHAIN_STOP), +}; + +void BgSstFloor_Init(BgSstFloor* thisx, GlobalContext* globalCtx) { + s32 pad; + BgSstFloor* this = THIS; + CollisionHeader* colHeader = NULL; + + Actor_ProcessInitChain(&this->dyna.actor, sInitChain); + DynaPolyActor_Init(&this->dyna, DPM_PLAYER); + CollisionHeader_GetVirtual(&gBongoDrumCol, &colHeader); + this->dyna.bgId = + DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->dyna.actor, colHeader); +} + +void BgSstFloor_Destroy(BgSstFloor* thisx, GlobalContext* globalCtx) { + s32 pad; + BgSstFloor* this = THIS; + + DynaPoly_DeleteBgActor(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId); +} + +void BgSstFloor_Update(BgSstFloor* thisx, GlobalContext* globalCtx) { + s32 pad; + BgSstFloor* this = THIS; + Player* player = PLAYER; + CollisionHeader* colHeader = SEGMENTED_TO_VIRTUAL(&gBongoDrumCol); + + colHeader->vtxList = SEGMENTED_TO_VIRTUAL(colHeader->vtxList); + + if (1) {} + + if (func_80043590(&this->dyna) && (this->dyna.actor.yDistToPlayer < 1000.0f)) { + Camera_ChangeSetting(globalCtx->cameraPtrs[MAIN_CAM], CAM_SET_BOSS_SHADES); + } else { + Camera_ChangeSetting(globalCtx->cameraPtrs[MAIN_CAM], CAM_SET_DUNGEON0); + } + + if (func_8004356C(&this->dyna) && (player->fallDistance > 1000.0f)) { + this->dyna.actor.params = 1; + Audio_PlayActorSound2(&this->dyna.actor, NA_SE_EN_SHADEST_TAIKO_HIGH); + } + + if (this->dyna.actor.params == BONGOFLOOR_HIT) { + Actor* item00 = globalCtx->actorCtx.actorLists[ACTORCAT_MISC].head; + f32 distFromRim; + f32 xzDist; + + this->drumAmp = 80; + this->dyna.actor.params = BONGOFLOOR_REST; + this->drumPhase = 28; + + if (func_8004356C(&this->dyna) && !(player->stateFlags1 & 0x6000)) { + distFromRim = 600.0f - this->dyna.actor.xzDistToPlayer; + if (distFromRim > 0.0f) { + if (distFromRim > 350.0f) { + distFromRim = 350.0f; + } + player->actor.bgCheckFlags &= ~1; + player->actor.velocity.y = 9.0f * distFromRim * (1.0f / 350.0f); + } + } + + while (item00 != NULL) { + if ((item00->id == ACTOR_EN_ITEM00) && (item00->world.pos.y == 0.0f)) { + xzDist = Actor_WorldDistXZToActor(&this->dyna.actor, item00); + distFromRim = 600.0f - xzDist; + if (xzDist < 600.0f) { + if (distFromRim > 350.0f) { + distFromRim = 350.0f; + } + item00->bgCheckFlags &= ~3; + item00->velocity.y = 9.0f * distFromRim * (1.0f / 350.0f); + } + } + item00 = item00->next; + } + } + this->drumHeight = sinf(this->drumPhase * (M_PI / 2)) * (-this->drumAmp); + Math_StepToS(&this->drumAmp, 0, 5); + + colHeader->vtxList[1].y = colHeader->vtxList[0].y = colHeader->vtxList[2].y = + colHeader->vtxList[3].y = colHeader->vtxList[4].y = colHeader->vtxList[7].y = + colHeader->vtxList[9].y = colHeader->vtxList[11].y = colHeader->vtxList[13].y = + this->dyna.actor.home.pos.y + this->drumHeight; + + if (this->drumPhase != 0) { + this->drumPhase--; + } + if (1) {} + func_8003EE6C(globalCtx, &globalCtx->colCtx.dyna); +} + +void BgSstFloor_Draw(BgSstFloor* thisx, GlobalContext* globalCtx) { + BgSstFloor* this = THIS; + + OPEN_DISPS(globalCtx->state.gfxCtx, "../z_bg_sst_floor.c", 277); + func_80093D18(globalCtx->state.gfxCtx); + Matrix_Scale(1.0f, this->drumHeight * -0.0025f, 1.0f, MTXMODE_APPLY); + + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_bg_sst_floor.c", 283), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Bg_Sst_Floor/BgSstFloor_Update.s") + gSPDisplayList(POLY_OPA_DISP++, gBongoDrumDL); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Bg_Sst_Floor/BgSstFloor_Draw.s") + CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_bg_sst_floor.c", 287); +} diff --git a/src/overlays/actors/ovl_Bg_Sst_Floor/z_bg_sst_floor.h b/src/overlays/actors/ovl_Bg_Sst_Floor/z_bg_sst_floor.h index 43b4453a3..992e41f9c 100644 --- a/src/overlays/actors/ovl_Bg_Sst_Floor/z_bg_sst_floor.h +++ b/src/overlays/actors/ovl_Bg_Sst_Floor/z_bg_sst_floor.h @@ -7,10 +7,17 @@ struct BgSstFloor; typedef struct BgSstFloor { - /* 0x0000 */ Actor actor; - /* 0x014C */ char unk_14C[0x20]; + /* 0x0000 */ DynaPolyActor dyna; + /* 0x014C */ s16 drumPhase; + /* 0x0166 */ s16 drumAmp; + /* 0x0168 */ s16 drumHeight; } BgSstFloor; // size = 0x016C +typedef enum { + /* 0 */ BONGOFLOOR_REST, + /* 1 */ BONGOFLOOR_HIT +} BgSstFloorParams; + extern const ActorInit Bg_Sst_Floor_InitVars; #endif diff --git a/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.c b/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.c index 4d5ab239c..2fe71b65c 100644 --- a/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.c +++ b/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.c @@ -1,15 +1,240 @@ +/* + * File: z_boss_sst.c + * Overlay: ovl_Boss_Sst + * Description: Bongo Bongo + */ + #include "z_boss_sst.h" +#include "objects/object_sst/object_sst.h" +#include "objects/gameplay_keep/gameplay_keep.h" +#include "overlays/actors/ovl_Bg_Sst_Floor/z_bg_sst_floor.h" #define FLAGS 0x00000435 #define THIS ((BossSst*)thisx) +#define vParity actionVar +#define vVanish actionVar + +#define LEFT 0 +#define RIGHT 1 +#define OTHER_HAND(hand) ((BossSst*)hand->actor.child) +#define HAND_STATE(hand) sHandState[hand->actor.params] + +#define ROOM_CENTER_X -50.0f +#define ROOM_CENTER_Y 0.0f +#define ROOM_CENTER_Z 0.0f + +typedef enum { + /* 0 */ HAND_WAIT, + /* 1 */ HAND_BEAT, + /* 2 */ HAND_RETREAT, + /* 3 */ HAND_SLAM, + /* 4 */ HAND_SWEEP, + /* 5 */ HAND_PUNCH, + /* 6 */ HAND_CLAP, + /* 7 */ HAND_GRAB, + /* 8 */ HAND_DAMAGED, + /* 9 */ HAND_FROZEN, + /* 10 */ HAND_BREAK_ICE, + /* 11 */ HAND_DEATH +} BossSstHandState; + +typedef enum { + /* 0 */ BONGO_NULL, + /* 1 */ BONGO_ICE, + /* 2 */ BONGO_SHOCKWAVE, + /* 3 */ BONGO_SHADOW +} BossSstEffectMode; + void BossSst_Init(Actor* thisx, GlobalContext* globalCtx); void BossSst_Destroy(Actor* thisx, GlobalContext* globalCtx); -void BossSst_Update(Actor* thisx, GlobalContext* globalCtx); -void BossSst_Draw(Actor* thisx, GlobalContext* globalCtx); +void BossSst_UpdateHand(Actor* thisx, GlobalContext* globalCtx); +void BossSst_UpdateHead(Actor* thisx, GlobalContext* globalCtx); +void BossSst_DrawHand(Actor* thisx, GlobalContext* globalCtx); +void BossSst_DrawHead(Actor* thisx, GlobalContext* globalCtx); +void BossSst_UpdateEffect(Actor* thisx, GlobalContext* globalCtx); +void BossSst_DrawEffect(Actor* thisx, GlobalContext* globalCtx); + +void BossSst_HeadSfx(BossSst* this, u16 sfxId); + +void BossSst_HeadSetupLurk(BossSst* this); +void BossSst_HeadLurk(BossSst* this, GlobalContext* globalCtx); +void BossSst_HeadSetupIntro(BossSst* this, GlobalContext* globalCtx); +void BossSst_HeadIntro(BossSst* this, GlobalContext* globalCtx); +void BossSst_HeadSetupNeutral(BossSst* this); +void BossSst_HeadNeutral(BossSst* this, GlobalContext* globalCtx); +void BossSst_HeadWait(BossSst* this, GlobalContext* globalCtx); + +void BossSst_HeadSetupDamagedHand(BossSst* this, s32 bothHands); +void BossSst_HeadDamagedHand(BossSst* this, GlobalContext* globalCtx); +void BossSst_HeadSetupReadyCharge(BossSst* this); +void BossSst_HeadReadyCharge(BossSst* this, GlobalContext* globalCtx); +void BossSst_HeadSetupCharge(BossSst* this); +void BossSst_HeadCharge(BossSst* this, GlobalContext* globalCtx); +void BossSst_HeadSetupEndCharge(BossSst* this); +void BossSst_HeadEndCharge(BossSst* this, GlobalContext* globalCtx); + +void BossSst_HeadSetupFrozenHand(BossSst* this); +void BossSst_HeadFrozenHand(BossSst* this, GlobalContext* globalCtx); +void BossSst_HeadSetupUnfreezeHand(BossSst* this); +void BossSst_HeadUnfreezeHand(BossSst* this, GlobalContext* globalCtx); + +void BossSst_HeadStunned(BossSst* this, GlobalContext* globalCtx); +void BossSst_HeadSetupVulnerable(BossSst* this); +void BossSst_HeadVulnerable(BossSst* this, GlobalContext* globalCtx); +void BossSst_HeadDamage(BossSst* this, GlobalContext* globalCtx); +void BossSst_HeadSetupRecover(BossSst* this); +void BossSst_HeadRecover(BossSst* this, GlobalContext* globalCtx); + +void BossSst_HeadDeath(BossSst* this, GlobalContext* globalCtx); +void BossSst_HeadSetupThrash(BossSst* this); +void BossSst_HeadThrash(BossSst* this, GlobalContext* globalCtx); +void BossSst_HeadSetupDarken(BossSst* this); +void BossSst_HeadDarken(BossSst* this, GlobalContext* globalCtx); +void BossSst_HeadSetupFall(BossSst* this); +void BossSst_HeadFall(BossSst* this, GlobalContext* globalCtx); +void BossSst_HeadSetupMelt(BossSst* this); +void BossSst_HeadMelt(BossSst* this, GlobalContext* globalCtx); +void BossSst_HeadSetupFinish(BossSst* this); +void BossSst_HeadFinish(BossSst* this, GlobalContext* globalCtx); + +void BossSst_HandGrabPlayer(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandReleasePlayer(BossSst* this, GlobalContext* globalCtx, s32 dropPlayer); +void BossSst_HandSelectAttack(BossSst* this); +void BossSst_HandSetDamage(BossSst* this, s32 damage); +void BossSst_HandSetInvulnerable(BossSst* this, s32 isInv); + +void BossSst_HandSetupWait(BossSst* this); +void BossSst_HandWait(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandSetupDownbeat(BossSst* this); +void BossSst_HandDownbeat(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandSetupOffbeat(BossSst* this); +void BossSst_HandOffbeat(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandSetupDownbeatEnd(BossSst* this); +void BossSst_HandDownbeatEnd(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandSetupOffbeatEnd(BossSst* this); +void BossSst_HandOffbeatEnd(BossSst* this, GlobalContext* globalCtx); + +void BossSst_HandReadySlam(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandSetupSlam(BossSst* this); +void BossSst_HandSlam(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandEndSlam(BossSst* this, GlobalContext* globalCtx); + +void BossSst_HandReadySweep(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandSetupSweep(BossSst* this); +void BossSst_HandSweep(BossSst* this, GlobalContext* globalCtx); + +void BossSst_HandReadyPunch(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandSetupPunch(BossSst* this); +void BossSst_HandPunch(BossSst* this, GlobalContext* globalCtx); + +void BossSst_HandReadyClap(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandSetupClap(BossSst* this); +void BossSst_HandClap(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandSetupEndClap(BossSst* this); +void BossSst_HandEndClap(BossSst* this, GlobalContext* globalCtx); + +void BossSst_HandReadyGrab(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandSetupGrab(BossSst* this); +void BossSst_HandGrab(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandSetupCrush(BossSst* this); +void BossSst_HandCrush(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandSetupEndCrush(BossSst* this); +void BossSst_HandEndCrush(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandSetupSwing(BossSst* this); +void BossSst_HandSwing(BossSst* this, GlobalContext* globalCtx); + +void BossSst_HandSetupRetreat(BossSst* this); +void BossSst_HandRetreat(BossSst* this, GlobalContext* globalCtx); + +void BossSst_HandSetupReel(BossSst* this); +void BossSst_HandReel(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandSetupReadyShake(BossSst* this); +void BossSst_HandReadyShake(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandSetupShake(BossSst* this); +void BossSst_HandShake(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandSetupReadyCharge(BossSst* this); +void BossSst_HandReadyCharge(BossSst* this, GlobalContext* globalCtx); + +void BossSst_HandSetupFrozen(BossSst* this); +void BossSst_HandFrozen(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandSetupReadyBreakIce(BossSst* this); +void BossSst_HandReadyBreakIce(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandSetupBreakIce(BossSst* this); +void BossSst_HandBreakIce(BossSst* this, GlobalContext* globalCtx); + +void BossSst_HandStunned(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandDamage(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandSetupRecover(BossSst* this); +void BossSst_HandRecover(BossSst* this, GlobalContext* globalCtx); + +void BossSst_HandSetupThrash(BossSst* this); +void BossSst_HandThrash(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandSetupDarken(BossSst* this); +void BossSst_HandDarken(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandSetupFall(BossSst* this); +void BossSst_HandFall(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandSetupMelt(BossSst* this); +void BossSst_HandMelt(BossSst* this, GlobalContext* globalCtx); +void BossSst_HandSetupFinish(BossSst* this); +void BossSst_HandFinish(BossSst* this, GlobalContext* globalCtx); + +void BossSst_SpawnHeadShadow(BossSst* this); +void BossSst_SpawnHandShadow(BossSst* this); +void BossSst_SpawnShockwave(BossSst* this); +void BossSst_SpawnIceCrystal(BossSst* this, s32 index); +void BossSst_SpawnIceShard(BossSst* this); +void BossSst_IceShatter(BossSst* this); + +#include "overlays/ovl_Boss_Sst/ovl_Boss_Sst.c" + +static BossSst* sHead; +static BossSst* sHands[2]; +static BgSstFloor* sFloor; + +static Vec3f sRoomCenter = { ROOM_CENTER_X, ROOM_CENTER_Y, ROOM_CENTER_Z }; +static Vec3f sHandOffsets[2]; +static s16 sHandYawOffsets[2]; + +static s16 sCutsceneCamera; +static Vec3f sCameraAt = { ROOM_CENTER_X + 50.0f, ROOM_CENTER_Y + 0.0f, ROOM_CENTER_Z + 0.0f }; +static Vec3f sCameraEye = { ROOM_CENTER_X + 150.0f, ROOM_CENTER_Y + 100.0f, ROOM_CENTER_Z + 0.0f }; +static Vec3f sCameraAtVel = { 0.0f, 0.0f, 0.0f }; +static Vec3f sCameraEyeVel = { 0.0f, 0.0f, 0.0f }; + +static Vec3f sCameraAtPoints[] = { + { ROOM_CENTER_X - 50.0f, ROOM_CENTER_Y + 300.0f, ROOM_CENTER_Z + 0.0f }, + { ROOM_CENTER_X + 150.0f, ROOM_CENTER_Y + 300.0f, ROOM_CENTER_Z + 100.0f }, + { ROOM_CENTER_X + 0.0f, ROOM_CENTER_Y + 600.0f, ROOM_CENTER_Z + 100.0f }, + { ROOM_CENTER_X + 50.0f, ROOM_CENTER_Y + 400.0f, ROOM_CENTER_Z + 200.0f }, + { ROOM_CENTER_X + 50.0f, ROOM_CENTER_Y + 200.0f, ROOM_CENTER_Z + 200.0f }, + { ROOM_CENTER_X - 50.0f, ROOM_CENTER_Y + 0.0f, ROOM_CENTER_Z + 200.0f }, + { ROOM_CENTER_X - 150.0f, ROOM_CENTER_Y + 0.0f, ROOM_CENTER_Z + 100.0f }, + { ROOM_CENTER_X - 60.0f, ROOM_CENTER_Y + 180.0f, ROOM_CENTER_Z + 730.0f }, +}; + +static Vec3f sCameraEyePoints[] = { + { ROOM_CENTER_X + 250.0f, ROOM_CENTER_Y + 800.0f, ROOM_CENTER_Z + 800.0f }, + { ROOM_CENTER_X - 150.0f, ROOM_CENTER_Y + 700.0f, ROOM_CENTER_Z + 1400.0f }, + { ROOM_CENTER_X + 250.0f, ROOM_CENTER_Y + 100.0f, ROOM_CENTER_Z + 750.0f }, + { ROOM_CENTER_X + 50.0f, ROOM_CENTER_Y + 200.0f, ROOM_CENTER_Z + 900.0f }, + { ROOM_CENTER_X + 50.0f, ROOM_CENTER_Y + 200.0f, ROOM_CENTER_Z + 900.0f }, + { ROOM_CENTER_X + 350.0f, ROOM_CENTER_Y + 400.0f, ROOM_CENTER_Z + 1200.0f }, + { ROOM_CENTER_X - 50.0f, ROOM_CENTER_Y + 200.0f, ROOM_CENTER_Z + 800.0f }, + { ROOM_CENTER_X - 50.0f, ROOM_CENTER_Y + 200.0f, ROOM_CENTER_Z + 800.0f }, +}; + +static Vec3f sZeroVec = { 0.0f, 0.0f, 0.0f }; +static u32 sBodyStatic = false; + +// Unreferenced. Maybe two zero vectors? +static u32 sUnkValues[] = { 0, 0, 0, 0, 0, 0 }; + +static Color_RGBA8 sBodyColor = { 255, 255, 255, 255 }; +static Color_RGBA8 sStaticColor = { 0, 0, 0, 255 }; +static s32 sHandState[] = { HAND_WAIT, HAND_WAIT }; -/* const ActorInit Boss_Sst_InitVars = { ACTOR_BOSS_SST, ACTORCAT_BOSS, @@ -18,604 +243,2982 @@ const ActorInit Boss_Sst_InitVars = { sizeof(BossSst), (ActorFunc)BossSst_Init, (ActorFunc)BossSst_Destroy, - (ActorFunc)BossSst_Update, - (ActorFunc)BossSst_Draw, -}; - -static ColliderJntSphElementInit D_80937630[11] = { - { - { - ELEMTYPE_UNK1, - { 0x20000000, 0x00, 0x30 }, - { 0xFFCFFFFF, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_ON, - OCELEM_ON, - }, - { 7, { { 1500, 0, 0 }, 70 }, 100 }, - }, - { - { - ELEMTYPE_UNK1, - { 0x20000000, 0x00, 0x30 }, - { 0xFFCFFFFF, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_ON, - OCELEM_ON, - }, - { 6, { { 0, 0, 0 }, 75 }, 100 }, - }, - { - { - ELEMTYPE_UNK1, - { 0x20000000, 0x00, 0x30 }, - { 0xFFCFFFFF, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_ON, - OCELEM_ON, - }, - { 4, { { 5000, 0, 0 }, 120 }, 100 }, - }, - { - { - ELEMTYPE_UNK1, - { 0x20000000, 0x00, 0x30 }, - { 0xFFCFFFFF, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_ON, - OCELEM_ON, - }, - { 3, { { -2500, 0, 0 }, 150 }, 100 }, - }, - { - { - ELEMTYPE_UNK1, - { 0x20000000, 0x00, 0x30 }, - { 0xFFCFFFFF, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_ON, - OCELEM_ON, - }, - { 43, { { 1500, 0, 0 }, 80 }, 100 }, - }, - { - { - ELEMTYPE_UNK1, - { 0x20000000, 0x00, 0x30 }, - { 0xFFCFFFFF, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_ON, - OCELEM_ON, - }, - { 43, { { 7500, 0, 0 }, 70 }, 100 }, - }, - { - { - ELEMTYPE_UNK1, - { 0x20000000, 0x00, 0x30 }, - { 0xFFCFFFFF, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_ON, - OCELEM_ON, - }, - { 44, { { 3000, 0, 0 }, 60 }, 100 }, - }, - { - { - ELEMTYPE_UNK1, - { 0x20000000, 0x00, 0x30 }, - { 0xFFCFFFFF, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_ON, - OCELEM_ON, - }, - { 40, { { 1500, 0, 0 }, 80 }, 100 }, - }, - { - { - ELEMTYPE_UNK1, - { 0x20000000, 0x00, 0x30 }, - { 0xFFCFFFFF, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_ON, - OCELEM_ON, - }, - { 40, { { 7500, 0, 0 }, 70 }, 100 }, - }, - { - { - ELEMTYPE_UNK1, - { 0x20000000, 0x00, 0x30 }, - { 0xFFCFFFFF, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_ON, - OCELEM_ON, - }, - { 41, { { 3000, 0, 0 }, 60 }, 100 }, - }, - { - { - ELEMTYPE_UNK1, - { 0x20000000, 0x00, 0x30 }, - { 0x00000080, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 8, { { 1500, 0, 0 }, 70 }, 100 }, - }, -}; - -static ColliderJntSphInit D_809377BC = { - { - COLTYPE_HARD, - AT_TYPE_ENEMY, - AC_ON | AC_HARD | AC_TYPE_PLAYER, - OC1_TYPE_ALL, - OC2_TYPE_1, - COLSHAPE_JNTSPH, - }, - 11, - D_80937630, -}; - -static ColliderCylinderInit D_809377CC = { - { - COLTYPE_HIT0, - AT_NONE, - AC_NONE | AC_TYPE_PLAYER, - OC1_NONE, - OC2_TYPE_1, - COLSHAPE_CYLINDER, - }, - { - ELEMTYPE_UNK0, - { 0x00000000, 0x00, 0x00 }, - { 0xFFCFFFFF, 0x00, 0x00 }, - TOUCH_NONE, - BUMP_ON, - OCELEM_NONE, - }, - { 85, 100, -50, { 0, 0, 0 } }, -}; - -static ColliderJntSphElementInit D_80937494[11] = { - { - { - ELEMTYPE_UNK1, - { 0x20000000, 0x00, 0x00 }, - { 0xFFCFFFFF, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_ON, - OCELEM_ON, - }, - { 2, { { 2000, -1500, 250 }, 65 }, 100 }, - }, - { - { - ELEMTYPE_UNK1, - { 0x20000000, 0x00, 0x00 }, - { 0xFFCFFFFF, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_ON, - OCELEM_ON, - }, - { 10, { { 0, 0, 0 }, 22 }, 100 }, - }, - { - { - ELEMTYPE_UNK1, - { 0x20000000, 0x00, 0x00 }, - { 0xFFCFFFFF, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_ON, - OCELEM_ON, - }, - { 11, { { 500, 0, 0 }, 22 }, 100 }, - }, - { - { - ELEMTYPE_UNK1, - { 0x20000000, 0x00, 0x00 }, - { 0xFFCFFFFF, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_ON, - OCELEM_ON, - }, - { 15, { { -250, -250, 0 }, 25 }, 100 }, - }, - { - { - ELEMTYPE_UNK1, - { 0x20000000, 0x00, 0x00 }, - { 0xFFCFFFFF, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_ON, - OCELEM_ON, - }, - { 16, { { 500, -250, 0 }, 25 }, 100 }, - }, - { - { - ELEMTYPE_UNK1, - { 0x20000000, 0x00, 0x00 }, - { 0xFFCFFFFF, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_ON, - OCELEM_ON, - }, - { 20, { { 250, -250, 0 }, 25 }, 100 }, - }, - { - { - ELEMTYPE_UNK1, - { 0x20000000, 0x00, 0x00 }, - { 0xFFCFFFFF, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_ON, - OCELEM_ON, - }, - { 21, { { 500, -250, 0 }, 25 }, 100 }, - }, - { - { - ELEMTYPE_UNK1, - { 0x20000000, 0x00, 0x00 }, - { 0xFFCFFFFF, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_ON, - OCELEM_ON, - }, - { 25, { { 0, 0, 0 }, 27 }, 100 }, - }, - { - { - ELEMTYPE_UNK1, - { 0x20000000, 0x00, 0x00 }, - { 0xFFCFFFFF, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_ON, - OCELEM_ON, - }, - { 26, { { 750, 0, 0 }, 26 }, 100 }, - }, - { - { - ELEMTYPE_UNK1, - { 0x20000000, 0x00, 0x00 }, - { 0xFFCFFFFF, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_ON, - OCELEM_ON, - }, - { 5, { { 750, -150, 0 }, 21 }, 100 }, - }, - { - { - ELEMTYPE_UNK1, - { 0x20000000, 0x00, 0x00 }, - { 0xFFCFFFFF, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_ON, - OCELEM_ON, - }, - { 6, { { 750, 0, 0 }, 20 }, 100 }, - }, -}; - -static ColliderJntSphInit D_80937620 = { - { - COLTYPE_HIT0, - AT_TYPE_ENEMY, - AC_ON | AC_TYPE_PLAYER, - OC1_TYPE_ALL, - OC2_TYPE_1, - COLSHAPE_JNTSPH, - }, - 11, - D_80937494, + (ActorFunc)BossSst_UpdateHand, + (ActorFunc)BossSst_DrawHand, }; -static ColliderCylinderInit D_809377F8 = { - { - COLTYPE_NONE, - AT_TYPE_ENEMY, - AC_NONE, - OC1_NONE, - OC2_TYPE_1, - COLSHAPE_CYLINDER, - }, - { - ELEMTYPE_UNK0, - { 0x20000000, 0x04, 0x10 }, - { 0x00000000, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NONE, - BUMP_NONE, - OCELEM_NONE, - }, - { 85, 1, 0, { 0, 0, 0 } }, +#include "z_boss_sst_colchk.c" + +static AnimationHeader* sHandIdleAnims[] = { &gBongoLeftHandIdleAnim, &gBongoRightHandIdleAnim }; +static AnimationHeader* sHandFlatPoses[] = { &gBongoLeftHandFlatPoseAnim, &gBongoRightHandFlatPoseAnim }; +static AnimationHeader* sHandOpenPoses[] = { &gBongoLeftHandOpenPoseAnim, &gBongoRightHandOpenPoseAnim }; +static AnimationHeader* sHandFistPoses[] = { &gBongoLeftHandFistPoseAnim, &gBongoRightHandFistPoseAnim }; +static AnimationHeader* sHandClenchAnims[] = { &gBongoLeftHandClenchAnim, &gBongoRightHandClenchAnim }; +static AnimationHeader* sHandDamagePoses[] = { &gBongoLeftHandDamagePoseAnim, &gBongoRightHandDamagePoseAnim }; +static AnimationHeader* sHandPushoffPoses[] = { &gBongoLeftHandPushoffPoseAnim, &gBongoRightHandPushoffPoseAnim }; +static AnimationHeader* sHandHangPoses[] = { &gBongoLeftHandHangPoseAnim, &gBongoRightHandHangPoseAnim }; + +static InitChainEntry sInitChain[] = { + ICHAIN_S8(naviEnemyId, 41, ICHAIN_CONTINUE), + ICHAIN_U8(targetMode, 5, ICHAIN_CONTINUE), + ICHAIN_VEC3F_DIV1000(scale, 20, ICHAIN_STOP), }; -*/ -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/BossSst_Init.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/BossSst_Destroy.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092CAA0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092CAD0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092CB0C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092CC58.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092DA6C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092DAB8.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092DB30.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092DB4C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092DCEC.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092DD50.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092DE48.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092DEA0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092DF40.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092DFFC.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092E25C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092E2E0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092E34C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092E3A0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092E3E8.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092E438.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092E470.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092E510.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092E790.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092E830.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092E930.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092EA00.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092EA50.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092EAE0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092EC74.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092ED9C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092EF28.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092F0BC.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092F30C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092F374.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092F3F0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092F434.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092F65C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092F6F0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092F790.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092F7DC.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092F894.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092F8F0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092FBE4.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092FC60.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092FDD0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092FE44.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092FF94.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8092FFF0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_809300E4.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80930158.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80930238.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80930284.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_809303C8.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8093043C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80930474.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8093051C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80930748.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_809307B4.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_809308A4.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80930934.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80930B18.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80930BC0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80930CE4.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80930D70.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80930F80.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80930FE8.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80931044.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_809310CC.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80931210.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80931300.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_809314F0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80931560.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80931788.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_809317F8.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_809318A0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80931928.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_809319D0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80931A5C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80931D04.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80931D5C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80931E70.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80931EC0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80931EF8.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80931F84.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_809322B4.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8093234C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_809324A4.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_809324F4.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8093265C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80932674.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80932808.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8093285C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_809329D4.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80932A80.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80932BDC.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80932C38.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80932D10.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80932DAC.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80932FA0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80932FF0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80933064.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_809330B4.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80933134.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80933170.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_809331E8.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80933210.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8093323C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80933290.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80933328.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_809333F4.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80933554.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80933608.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80933724.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80933748.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_809338DC.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80933978.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_809339F8.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80933B84.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80933C80.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80933CEC.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80933D2C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80933D54.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80933EE0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/BossSst_Update.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80934338.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_809345A4.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_809345F0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80934628.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/BossSst_Draw.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80934A44.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80935238.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_809352DC.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80935764.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80935890.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80935948.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80935A20.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80935CDC.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_80935F30.s") - -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_809360FC.s") -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Sst/func_8093639C.s") +void BossSst_Init(Actor* thisx, GlobalContext* globalCtx2) { + GlobalContext* globalCtx = globalCtx2; + BossSst* this = THIS; + + Actor_ProcessInitChain(&this->actor, sInitChain); + Collider_InitCylinder(globalCtx, &this->colliderCyl); + Collider_InitJntSph(globalCtx, &this->colliderJntSph); + CollisionCheck_SetInfo(&this->actor.colChkInfo, &sDamageTable, &sColChkInfoInit); + Flags_SetSwitch(globalCtx, 0x14); + if (this->actor.params == BONGO_HEAD) { + sFloor = (BgSstFloor*)Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_BG_SST_FLOOR, sRoomCenter.x, + sRoomCenter.y, sRoomCenter.z, 0, 0, 0, BONGOFLOOR_REST); + SkelAnime_InitFlex(globalCtx, &this->skelAnime, &gBongoHeadSkel, &gBongoHeadEyeOpenIdleAnim, this->jointTable, + this->morphTable, 45); + ActorShape_Init(&this->actor.shape, 70000.0f, ActorShadow_DrawCircle, 95.0f); + Collider_SetJntSph(globalCtx, &this->colliderJntSph, &this->actor, &sJntSphInitHead, this->colliderItems); + Collider_SetCylinder(globalCtx, &this->colliderCyl, &this->actor, &sCylinderInitHead); + sHead = this; + this->actor.world.pos.x = ROOM_CENTER_X + 50.0f; + this->actor.world.pos.y = ROOM_CENTER_Y + 0.0f; + this->actor.world.pos.z = ROOM_CENTER_Z - 650.0f; + this->actor.home.pos = this->actor.world.pos; + this->actor.shape.rot.y = 0; + if (Flags_GetClear(globalCtx, globalCtx->roomCtx.curRoom.num)) { + Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_DOOR_WARP1, ROOM_CENTER_X, ROOM_CENTER_Y, + ROOM_CENTER_Z + 400.0f, 0, 0, 0, -1); + Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_ITEM_B_HEART, ROOM_CENTER_X, ROOM_CENTER_Y, + ROOM_CENTER_Z - 200.0f, 0, 0, 0, 0); + Actor_Kill(&this->actor); + } else { + sHands[LEFT] = + (BossSst*)Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_BOSS_SST, this->actor.world.pos.x + 200.0f, + this->actor.world.pos.y, this->actor.world.pos.z + 400.0f, 0, + this->actor.shape.rot.y, 0, BONGO_LEFT_HAND); + sHands[RIGHT] = (BossSst*)Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_BOSS_SST, + this->actor.world.pos.x + (-200.0f), this->actor.world.pos.y, + this->actor.world.pos.z + 400.0f, 0, this->actor.shape.rot.y, 0, + BONGO_RIGHT_HAND); + sHands[LEFT]->actor.child = &sHands[RIGHT]->actor; + sHands[RIGHT]->actor.child = &sHands[LEFT]->actor; + + this->actor.flags &= ~1; + this->actor.update = BossSst_UpdateHead; + this->actor.draw = BossSst_DrawHead; + this->radius = -650.0f; + this->actor.targetArrowOffset = 4000.0f; + BossSst_HeadSetupLurk(this); + Actor_ChangeCategory(globalCtx, &globalCtx->actorCtx, &this->actor, ACTORCAT_BOSS); + } + } else { + Collider_SetJntSph(globalCtx, &this->colliderJntSph, &this->actor, &sJntSphInitHand, this->colliderItems); + Collider_SetCylinder(globalCtx, &this->colliderCyl, &this->actor, &sCylinderInitHand); + if (this->actor.params == BONGO_LEFT_HAND) { + SkelAnime_InitFlex(globalCtx, &this->skelAnime, &gBongoLeftHandSkel, &gBongoLeftHandIdleAnim, + this->jointTable, this->morphTable, 27); + this->vParity = -1; + this->colliderJntSph.elements[0].dim.modelSphere.center.z *= -1; + } else { + SkelAnime_InitFlex(globalCtx, &this->skelAnime, &gBongoRightHandSkel, &gBongoRightHandIdleAnim, + this->jointTable, this->morphTable, 27); + this->vParity = 1; + } + + ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 95.0f); + this->handZPosMod = -3500; + this->actor.targetArrowOffset = 5000.0f; + this->actor.flags &= ~1; + BossSst_HandSetupWait(this); + } +} + +void BossSst_Destroy(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + BossSst* this = THIS; + + Collider_DestroyJntSph(globalCtx, &this->colliderJntSph); + Collider_DestroyCylinder(globalCtx, &this->colliderCyl); + func_800F89E8(&this->center); +} + +void BossSst_HeadSetupLurk(BossSst* this) { + this->actor.draw = NULL; + sHands[LEFT]->actor.draw = NULL; + sHands[RIGHT]->actor.draw = NULL; + this->vVanish = false; + this->actionFunc = BossSst_HeadLurk; +} + +void BossSst_HeadLurk(BossSst* this, GlobalContext* globalCtx) { + if (this->actor.yDistToPlayer < 1000.0f) { + BossSst_HeadSetupIntro(this, globalCtx); + } +} + +void BossSst_HeadSetupIntro(BossSst* this, GlobalContext* globalCtx) { + Player* player = PLAYER; + + this->timer = 611; + this->ready = false; + player->actor.world.pos.x = sRoomCenter.x; + player->actor.world.pos.y = ROOM_CENTER_Y + 1000.0f; + player->actor.world.pos.z = sRoomCenter.z; + player->linearVelocity = player->actor.velocity.y = 0.0f; + player->actor.shape.rot.y = -0x8000; + player->targetYaw = -0x8000; + player->currentYaw = -0x8000; + player->fallStartHeight = 0; + player->stateFlags1 |= 0x20; + + func_80064520(globalCtx, &globalCtx->csCtx); + func_8002DF54(globalCtx, &this->actor, 8); + sCutsceneCamera = Gameplay_CreateSubCamera(globalCtx); + Gameplay_ChangeCameraStatus(globalCtx, MAIN_CAM, CAM_STAT_WAIT); + Gameplay_ChangeCameraStatus(globalCtx, sCutsceneCamera, CAM_STAT_ACTIVE); + Math_Vec3f_Copy(&sCameraAt, &player->actor.world.pos); + if (gSaveContext.eventChkInf[7] & 0x80) { + sCameraEye.z = ROOM_CENTER_Z - 100.0f; + } + + Gameplay_CameraSetAtEye(globalCtx, sCutsceneCamera, &sCameraAt, &sCameraEye); + Audio_SetBGM(0x100100FF); + this->actionFunc = BossSst_HeadIntro; +} + +void BossSst_HeadIntro(BossSst* this, GlobalContext* globalCtx) { + Player* player = PLAYER; + s32 tempo; + s32 introStateTimer; + s32 revealStateTimer; + + if (this->timer != 0) { + this->timer--; + } + + if (SkelAnime_Update(&this->skelAnime)) { + Animation_MorphToLoop(&this->skelAnime, &gBongoHeadEyeCloseIdleAnim, -3.0f); + } + + if (this->timer == 0) { + sHands[RIGHT]->actor.flags |= 1; + sHands[LEFT]->actor.flags |= 1; + player->stateFlags1 &= ~0x20; + func_80064534(globalCtx, &globalCtx->csCtx); + func_8002DF54(globalCtx, &this->actor, 7); + sCameraAt.y += 30.0f; + sCameraAt.z += 300.0f; + Gameplay_CameraSetAtEye(globalCtx, sCutsceneCamera, &sCameraAt, &sCameraEye); + Gameplay_CopyCamera(globalCtx, MAIN_CAM, sCutsceneCamera); + Gameplay_ChangeCameraStatus(globalCtx, sCutsceneCamera, CAM_STAT_WAIT); + Gameplay_ChangeCameraStatus(globalCtx, MAIN_CAM, CAM_STAT_ACTIVE); + Gameplay_ClearCamera(globalCtx, sCutsceneCamera); + gSaveContext.eventChkInf[7] |= 0x80; + BossSst_HeadSetupNeutral(this); + this->colliderJntSph.base.ocFlags1 |= OC1_ON; + sHands[LEFT]->colliderJntSph.base.ocFlags1 |= OC1_ON; + sHands[RIGHT]->colliderJntSph.base.ocFlags1 |= OC1_ON; + this->timer = 112; + } else if (this->timer >= 546) { + if (player->actor.world.pos.y > 100.0f) { + player->actor.world.pos.x = sRoomCenter.x; + player->actor.world.pos.z = sRoomCenter.z; + player->linearVelocity = 0; + player->actor.shape.rot.y = -0x8000; + player->targetYaw = -0x8000; + player->currentYaw = -0x8000; + } + + Math_Vec3f_Copy(&sCameraAt, &player->actor.world.pos); + if (player->actor.bgCheckFlags & 2) { + if (!this->ready) { + sFloor->dyna.actor.params = BONGOFLOOR_HIT; + this->ready = true; + func_800AA000(this->actor.xyzDistToPlayerSq, 0xFF, 0x14, 0x96); + Audio_PlayActorSound2(&sFloor->dyna.actor, NA_SE_EN_SHADEST_TAIKO_HIGH); + } else if (gSaveContext.eventChkInf[7] & 0x80) { + sHands[RIGHT]->actor.draw = BossSst_DrawHand; + sHands[LEFT]->actor.draw = BossSst_DrawHand; + this->actor.draw = BossSst_DrawHead; + this->timer = 178; + sCameraAt.x = ROOM_CENTER_X - 23.0f; + sCameraAt.y = ROOM_CENTER_Y + 0.0f; + sCameraAt.z = ROOM_CENTER_Z + 0.0f; + } else { + this->timer = 546; + } + } + } else if (this->timer >= 478) { + sCameraEye.x += 10.0f; + sCameraEye.y += 10.0f; + sCameraEye.z -= 10.0f; + } else if (this->timer >= 448) { + if (this->timer == 460) { + sHands[RIGHT]->actor.draw = BossSst_DrawHand; + sHands[LEFT]->actor.draw = BossSst_DrawHand; + this->actor.draw = BossSst_DrawHead; + player->actor.world.pos.x = sRoomCenter.x; + player->actor.world.pos.z = sRoomCenter.z; + BossSst_HandSetupDownbeat(sHands[RIGHT]); + } + if (this->timer > 460) { + sCameraEye.x -= 40.0f; + sCameraEye.y -= 40.0f; + sCameraEye.z += 20.0f; + } else if (this->timer == 460) { + sCameraAt.x = sHands[RIGHT]->actor.home.pos.x + 0.0f; + sCameraAt.y = sHands[RIGHT]->actor.home.pos.y - 20.0f; + sCameraAt.z = sHands[RIGHT]->actor.home.pos.z + 10.0f; + sCameraEye.x = sHands[RIGHT]->actor.home.pos.x + 150.0f; + sCameraEye.y = sHands[RIGHT]->actor.home.pos.y + 100.0f; + sCameraEye.z = sHands[RIGHT]->actor.home.pos.z + 80.0f; + } + } else { + if (this->timer >= 372) { + introStateTimer = this->timer - 372; + tempo = 6; + if (this->timer == 447) { + sCameraAt = player->actor.world.pos; + sCameraEye.x = ROOM_CENTER_X - 200.0f; + sCameraEye.y = ROOM_CENTER_Y + 160.0f; + sCameraEye.z = ROOM_CENTER_Z - 190.0f; + } else if (introStateTimer == 11) { + sCameraAt.x = sHands[RIGHT]->actor.home.pos.x + 30.0f; + sCameraAt.y = sHands[RIGHT]->actor.home.pos.y + 0.0f; + sCameraAt.z = sHands[RIGHT]->actor.home.pos.z + 20.0f; + sCameraEye.x = sHands[RIGHT]->actor.home.pos.x + 100.0f; + sCameraEye.y = sHands[RIGHT]->actor.home.pos.y + 10.0f; + sCameraEye.z = sHands[RIGHT]->actor.home.pos.z - 210.0f; + } else if (introStateTimer == 62) { + sCameraAt.x = sHands[LEFT]->actor.home.pos.x + 0.0f; + sCameraAt.y = sHands[LEFT]->actor.home.pos.y + 50.0f; + sCameraAt.z = sHands[LEFT]->actor.home.pos.z + 100.0f; + sCameraEye.x = sHands[LEFT]->actor.home.pos.x + 110.0f; + sCameraEye.y = sHands[LEFT]->actor.home.pos.y + 180.0f; + sCameraEye.z = sHands[LEFT]->actor.home.pos.z - 70.0f; + } + } else if (this->timer >= 304) { + introStateTimer = this->timer - 304; + tempo = 5; + if (introStateTimer == 11) { + sCameraAt.x = sHands[RIGHT]->actor.home.pos.x + 40.0f; + sCameraAt.y = sHands[RIGHT]->actor.home.pos.y - 90.0f; + sCameraAt.z = sHands[RIGHT]->actor.home.pos.z - 40.0f; + sCameraEye.x = sHands[RIGHT]->actor.home.pos.x - 20.0f; + sCameraEye.y = sHands[RIGHT]->actor.home.pos.y + 210.0f; + sCameraEye.z = sHands[RIGHT]->actor.home.pos.z + 170.0f; + } else if (this->timer == 368) { + sCameraAt.x = sHands[LEFT]->actor.home.pos.x - 20.0f; + sCameraAt.y = sHands[LEFT]->actor.home.pos.y + 0.0f; + sCameraAt.z = sHands[LEFT]->actor.home.pos.z + 0.0f; + sCameraEye.x = sHands[LEFT]->actor.home.pos.x - 70.0f; + sCameraEye.y = sHands[LEFT]->actor.home.pos.y + 170.0f; + sCameraEye.z = sHands[LEFT]->actor.home.pos.z + 150.0f; + } + } else if (this->timer >= 244) { + introStateTimer = this->timer - 244; + tempo = 4; + if (introStateTimer == 11) { + sCameraAt.x = sHands[RIGHT]->actor.home.pos.x + 30.0f; + sCameraAt.y = sHands[RIGHT]->actor.home.pos.y + 70.0f; + sCameraAt.z = sHands[RIGHT]->actor.home.pos.z + 40.0f; + sCameraEye.x = sHands[RIGHT]->actor.home.pos.x + 110.0f; + sCameraEye.y = sHands[RIGHT]->actor.home.pos.y - 140.0f; + sCameraEye.z = sHands[RIGHT]->actor.home.pos.z - 10.0f; + } else if (this->timer == 300) { + sCameraAt.x = sHands[LEFT]->actor.home.pos.x - 20.0f; + sCameraAt.y = sHands[LEFT]->actor.home.pos.y - 80.0f; + sCameraAt.z = sHands[LEFT]->actor.home.pos.z + 320.0f; + sCameraEye.x = sHands[LEFT]->actor.home.pos.x - 130.0f; + sCameraEye.y = sHands[LEFT]->actor.home.pos.y + 130.0f; + sCameraEye.z = sHands[LEFT]->actor.home.pos.z - 150.0f; + } + } else if (this->timer >= 192) { + introStateTimer = this->timer - 192; + tempo = 3; + if (this->timer == 240) { + sCameraAt.x = sHands[LEFT]->actor.home.pos.x - 190.0f; + sCameraAt.y = sHands[LEFT]->actor.home.pos.y - 110.0f; + sCameraAt.z = sHands[LEFT]->actor.home.pos.z + 40.0f; + sCameraEye.x = sHands[LEFT]->actor.home.pos.x + 120.0f; + sCameraEye.y = sHands[LEFT]->actor.home.pos.y + 130.0f; + sCameraEye.z = sHands[LEFT]->actor.home.pos.z + 50.0f; + } else if (introStateTimer == 12) { + sCameraAt.x = sRoomCenter.x + 50.0f; + sCameraAt.y = sRoomCenter.y - 90.0f; + sCameraAt.z = sRoomCenter.z - 200.0f; + sCameraEye.x = sRoomCenter.x + 50.0f; + sCameraEye.y = sRoomCenter.y + 350.0f; + sCameraEye.z = sRoomCenter.z + 150.0f; + } + } else if (this->timer >= 148) { + introStateTimer = this->timer - 148; + tempo = 2; + } else if (this->timer >= 112) { + introStateTimer = this->timer - 112; + tempo = 1; + } else { + introStateTimer = this->timer % 28; + tempo = 0; + } + if (this->timer <= 198) { + revealStateTimer = 198 - this->timer; + if ((gSaveContext.eventChkInf[7] & 0x80) && (revealStateTimer <= 44)) { + sCameraAt.x += 492.0f * 0.01f; + sCameraAt.y += 200.0f * 0.01f; + sCameraEye.x -= 80.0f * 0.01f; + sCameraEye.y -= 360.0f * 0.01f; + sCameraEye.z += 1000.0f * 0.01f; + } else if (this->timer <= 20) { + sCameraAt.y -= 700.0f * 0.01f; + sCameraAt.z += 900.0f * 0.01f; + sCameraEye.x += 650.0f * 0.01f; + sCameraEye.y += 400.0f * 0.01f; + sCameraEye.z += 1550.0f * 0.01f; + this->vVanish = true; + this->actor.flags |= 0x80; + } else if (revealStateTimer < 40) { + sCameraAt.x += 125.0f * 0.01f; + sCameraAt.y += 350.0f * 0.01f; + sCameraAt.z += 500.0f * 0.01f; + sCameraEye.x += 200.0f * 0.01f; + sCameraEye.y -= 850.0f * 0.01f; + } else if (revealStateTimer >= 45) { + if (revealStateTimer < 85) { + sCameraAt.x -= 250.0f * 0.01f; + sCameraAt.y += 425.0f * 0.01f; + sCameraAt.z -= 1200.0f * 0.01f; + sCameraEye.x -= 650.0f * 0.01f; + sCameraEye.y += 125.0f * 0.01f; + sCameraEye.z -= 350.0f * 0.01f; + } else if (revealStateTimer == 85) { + if (!(gSaveContext.eventChkInf[7] & 0x80)) { + TitleCard_InitBossName(globalCtx, &globalCtx->actorCtx.titleCtx, + SEGMENTED_TO_VIRTUAL(&gBongoTitleCardTex), 160, 180, 128, 40); + } + Audio_SetBGM(0x1B); + Animation_MorphToPlayOnce(&this->skelAnime, &gBongoHeadEyeCloseAnim, -5.0f); + BossSst_HeadSfx(this, NA_SE_EN_SHADEST_DISAPPEAR); + } + } + } + if (introStateTimer == 12) { + BossSst_HandSetupDownbeat(sHands[RIGHT]); + } + if ((introStateTimer != 5) && ((introStateTimer % ((tempo * 2) + 7)) == 5)) { + BossSst_HandSetupOffbeat(sHands[LEFT]); + } + } + + if (this->actionFunc != BossSst_HeadNeutral) { + Gameplay_CameraSetAtEye(globalCtx, sCutsceneCamera, &sCameraAt, &sCameraEye); + } +} + +void BossSst_HeadSetupWait(BossSst* this) { + if (this->skelAnime.animation != &gBongoHeadEyeCloseIdleAnim) { + Animation_MorphToLoop(&this->skelAnime, &gBongoHeadEyeCloseIdleAnim, -5.0f); + } + this->actionFunc = BossSst_HeadWait; +} + +void BossSst_HeadWait(BossSst* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + if ((HAND_STATE(sHands[LEFT]) == HAND_WAIT) && (HAND_STATE(sHands[RIGHT]) == HAND_WAIT)) { + BossSst_HeadSetupNeutral(this); + } +} + +void BossSst_HeadSetupNeutral(BossSst* this) { + this->timer = 127; + this->ready = false; + this->actionFunc = BossSst_HeadNeutral; +} + +void BossSst_HeadNeutral(BossSst* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + if (!this->ready && ((HAND_STATE(sHands[LEFT]) == HAND_BEAT) || (HAND_STATE(sHands[LEFT]) == HAND_WAIT)) && + ((HAND_STATE(sHands[RIGHT]) == HAND_BEAT) || (HAND_STATE(sHands[RIGHT]) == HAND_WAIT))) { + this->ready = true; + } + + if (this->ready) { + if (this->timer != 0) { + this->timer--; + } + } + + if (this->timer == 0) { + if ((PLAYER->actor.world.pos.y > -50.0f) && !(PLAYER->stateFlags1 & 0x6080)) { + sHands[Rand_ZeroOne() <= 0.5f]->ready = true; + BossSst_HeadSetupWait(this); + } else { + this->timer = 28; + } + } else { + Math_ApproachS(&this->actor.shape.rot.y, Actor_WorldYawTowardPoint(&PLAYER->actor, &sRoomCenter) + 0x8000, 4, + 0x400); + if ((this->timer == 28) || (this->timer == 84)) { + BossSst_HeadSfx(this, NA_SE_EN_SHADEST_PRAY); + } + } +} + +void BossSst_HeadSetupDamagedHand(BossSst* this, s32 bothHands) { + if (bothHands) { + Animation_MorphToPlayOnce(&this->skelAnime, &gBongoHeadEyeOpenAnim, -5.0f); + } else { + Animation_MorphToPlayOnce(&this->skelAnime, &gBongoHeadDamagedHandAnim, -5.0f); + } + this->actionFunc = BossSst_HeadDamagedHand; +} + +void BossSst_HeadDamagedHand(BossSst* this, GlobalContext* globalCtx) { + if (SkelAnime_Update(&this->skelAnime)) { + if ((HAND_STATE(sHands[LEFT]) == HAND_DAMAGED) && (HAND_STATE(sHands[RIGHT]) == HAND_DAMAGED)) { + BossSst_HeadSetupReadyCharge(this); + } else if ((HAND_STATE(sHands[LEFT]) == HAND_FROZEN) || (HAND_STATE(sHands[RIGHT]) == HAND_FROZEN)) { + BossSst_HeadSetupFrozenHand(this); + } else if (this->skelAnime.animation == &gBongoHeadEyeOpenAnim) { + BossSst_HeadSetupUnfreezeHand(this); + } else { + BossSst_HeadSetupWait(this); + } + } +} + +void BossSst_HeadSetupReadyCharge(BossSst* this) { + Animation_MorphToLoop(&this->skelAnime, &gBongoHeadEyeOpenIdleAnim, -5.0f); + this->actor.speedXZ = 0.0f; + this->colliderCyl.base.acFlags |= AC_ON; + this->actionFunc = BossSst_HeadReadyCharge; +} + +void BossSst_HeadReadyCharge(BossSst* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + if (sHands[LEFT]->ready && (sHands[LEFT]->actionFunc == BossSst_HandReadyCharge) && sHands[RIGHT]->ready && + (sHands[RIGHT]->actionFunc == BossSst_HandReadyCharge)) { + BossSst_HeadSetupCharge(this); + } else { + Math_SmoothStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 4, 0x800, 0x400); + } +} + +void BossSst_HeadSetupCharge(BossSst* this) { + Animation_Change(&this->skelAnime, &gBongoHeadChargeAnim, 0.5f, 0.0f, Animation_GetLastFrame(&gBongoHeadChargeAnim), + ANIMMODE_ONCE_INTERP, -5.0f); + BossSst_HandSetDamage(sHands[LEFT], 0x20); + BossSst_HandSetDamage(sHands[RIGHT], 0x20); + this->colliderJntSph.base.atFlags |= AT_ON; + this->actor.speedXZ = 3.0f; + this->radius = -650.0f; + this->ready = false; + this->actionFunc = BossSst_HeadCharge; +} + +void BossSst_HeadCharge(BossSst* this, GlobalContext* globalCtx) { + f32 chargeDist; + s32 animFinish = SkelAnime_Update(&this->skelAnime); + + if (!this->ready && Animation_OnFrame(&this->skelAnime, 6.0f)) { + this->ready = true; + this->actor.speedXZ = 0.25f; + this->skelAnime.playSpeed = 0.2f; + } + + this->actor.speedXZ *= 1.25f; + this->actor.speedXZ = CLAMP_MAX(this->actor.speedXZ, 45.0f); + + if (this->ready) { + if (Math_SmoothStepToF(&this->radius, 650.0f, 0.4f, this->actor.speedXZ, 1.0f) < 10.0f) { + this->radius = 650.0f; + BossSst_HeadSetupEndCharge(this); + } else { + chargeDist = (650.0f - this->radius) * 3.0f; + if (chargeDist > 180.0f) { + chargeDist = 180.0f; + } + + this->actor.world.pos.y = this->actor.home.pos.y - chargeDist; + } + + if (!animFinish) { + sHandOffsets[LEFT].z += 5.0f; + sHandOffsets[RIGHT].z += 5.0f; + } + } else { + Math_ApproachF(&this->radius, -700.0f, 0.4f, this->actor.speedXZ); + Math_StepToF(&this->actor.world.pos.y, this->actor.home.pos.y - 180.0f, 20.0f); + sHandOffsets[LEFT].y += 5.0f; + sHandOffsets[RIGHT].y += 5.0f; + } + + if (this->colliderJntSph.base.atFlags & AT_HIT) { + this->colliderJntSph.base.atFlags &= ~(AT_ON | AT_HIT); + sHands[LEFT]->colliderJntSph.base.atFlags &= ~(AT_ON | AT_HIT); + sHands[RIGHT]->colliderJntSph.base.atFlags &= ~(AT_ON | AT_HIT); + func_8002F71C(globalCtx, &this->actor, 10.0f, this->actor.shape.rot.y, 5.0f); + func_8002F7DC(&PLAYER->actor, NA_SE_PL_BODY_HIT); + } +} + +void BossSst_HeadSetupEndCharge(BossSst* this) { + Animation_MorphToLoop(&this->skelAnime, &gBongoHeadEyeCloseIdleAnim, -20.0f); + this->targetYaw = Actor_WorldYawTowardPoint(&this->actor, &sRoomCenter); + this->colliderJntSph.base.atFlags &= ~(AT_ON | AT_HIT); + this->colliderCyl.base.acFlags &= ~AC_ON; + this->radius *= -1.0f; + this->actionFunc = BossSst_HeadEndCharge; +} + +void BossSst_HeadEndCharge(BossSst* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + if (Math_SmoothStepToS(&this->actor.shape.rot.y, this->targetYaw, 4, 0x800, 0x100) == 0) { + BossSst_HandSetupRetreat(sHands[LEFT]); + BossSst_HandSetupRetreat(sHands[RIGHT]); + BossSst_HeadSetupNeutral(this); + } +} + +void BossSst_HeadSetupFrozenHand(BossSst* this) { + Animation_MorphToLoop(&this->skelAnime, &gBongoHeadEyeOpenIdleAnim, -5.0f); + this->ready = false; + this->colliderCyl.base.acFlags |= AC_ON; + this->actionFunc = BossSst_HeadFrozenHand; +} + +void BossSst_HeadFrozenHand(BossSst* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + if (this->ready) { + BossSst_HeadSetupUnfreezeHand(this); + } +} + +void BossSst_HeadSetupUnfreezeHand(BossSst* this) { + Animation_MorphToPlayOnce(&this->skelAnime, &gBongoHeadEyeCloseAnim, -5.0f); + this->colliderCyl.base.acFlags &= ~AC_ON; + this->actionFunc = BossSst_HeadUnfreezeHand; +} + +void BossSst_HeadUnfreezeHand(BossSst* this, GlobalContext* globalCtx) { + if (SkelAnime_Update(&this->skelAnime)) { + BossSst_HeadSetupWait(this); + } +} + +void BossSst_HeadSetupStunned(BossSst* this) { + Animation_MorphToPlayOnce(&this->skelAnime, &gBongoHeadKnockoutAnim, -5.0f); + Actor_SetColorFilter(&this->actor, 0, 0xFF, 0, Animation_GetLastFrame(&gBongoHeadKnockoutAnim)); + this->colliderJntSph.base.atFlags &= ~(AT_ON | AT_HIT); + this->colliderCyl.base.acFlags &= ~AC_ON; + this->vVanish = false; + this->actor.flags &= ~0x80; + BossSst_HeadSfx(this, NA_SE_EN_SHADEST_FREEZE); + this->actionFunc = BossSst_HeadStunned; +} + +void BossSst_HeadStunned(BossSst* this, GlobalContext* globalCtx) { + f32 bounce; + s32 animFinish; + f32 currentFrame; + + Math_StepToF(&sHandOffsets[LEFT].z, 600.0f, 20.0f); + Math_StepToF(&sHandOffsets[RIGHT].z, 600.0f, 20.0f); + Math_StepToF(&sHandOffsets[LEFT].x, 200.0f, 20.0f); + Math_StepToF(&sHandOffsets[RIGHT].x, -200.0f, 20.0f); + this->actor.velocity.y += this->actor.gravity; + animFinish = SkelAnime_Update(&this->skelAnime); + currentFrame = this->skelAnime.curFrame; + if (currentFrame <= 6.0f) { + bounce = (sinf((M_PI / 11) * currentFrame) * 100.0f) + (this->actor.home.pos.y - 180.0f); + if (this->actor.world.pos.y < bounce) { + this->actor.world.pos.y = bounce; + } + } else if (currentFrame <= 11.0f) { + this->actor.world.pos.y = (sinf((M_PI / 11) * currentFrame) * 170.0f) + (this->actor.home.pos.y - 250.0f); + } else { + this->actor.world.pos.y = + (sinf((currentFrame - 11.0f) * (M_PI / 5)) * 50.0f) + (this->actor.home.pos.y - 250.0f); + } + + if ((animFinish) || Animation_OnFrame(&this->skelAnime, 11.0f)) { + BossSst_HeadSfx(this, NA_SE_EN_SHADEST_LAND); + } + + if (this->radius < -500.0f) { + Math_SmoothStepToF(&this->radius, -500.0f, 1.0f, 50.0f, 5.0f); + } else { + Math_SmoothStepToF(&this->actor.speedXZ, 0.0f, 0.5f, 15.0f, 3.0f); + this->radius += this->actor.speedXZ; + } + + this->radius = CLAMP_MAX(this->radius, 400.0f); + + this->actor.world.pos.y += this->actor.velocity.y; + if (animFinish) { + BossSst_HeadSetupVulnerable(this); + } +} + +void BossSst_HeadSetupVulnerable(BossSst* this) { + Animation_MorphToLoop(&this->skelAnime, &gBongoHeadStunnedAnim, -5.0f); + this->colliderCyl.base.acFlags |= AC_ON; + this->colliderCyl.info.bumper.dmgFlags = 0x0FC00702; // Sword-type damage + this->actor.speedXZ = 0.0f; + this->colliderJntSph.elements[10].info.bumperFlags |= (BUMP_ON | BUMP_HOOKABLE); + this->colliderJntSph.elements[0].info.bumperFlags &= ~BUMP_ON; + if (this->actionFunc != BossSst_HeadDamage) { + this->timer = 50; + } + + this->actionFunc = BossSst_HeadVulnerable; +} + +void BossSst_HeadVulnerable(BossSst* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + Math_StepToF(&sHandOffsets[LEFT].z, 600.0f, 20.0f); + Math_StepToF(&sHandOffsets[RIGHT].z, 600.0f, 20.0f); + Math_StepToF(&sHandOffsets[LEFT].x, 200.0f, 20.0f); + Math_StepToF(&sHandOffsets[RIGHT].x, -200.0f, 20.0f); + if ((this->actor.flags & 0x2000) == 0x2000) { + this->timer += 2; + this->timer = CLAMP_MAX(this->timer, 50); + } else { + if (this->timer != 0) { + this->timer--; + } + + if (this->timer == 0) { + BossSst_HandSetupRecover(sHands[LEFT]); + BossSst_HandSetupRecover(sHands[RIGHT]); + BossSst_HeadSetupRecover(this); + } + } +} + +void BossSst_HeadSetupDamage(BossSst* this) { + Animation_MorphToPlayOnce(&this->skelAnime, &gBongoHeadDamageAnim, -3.0f); + Actor_SetColorFilter(&this->actor, 0x4000, 0xFF, 0, Animation_GetLastFrame(&gBongoHeadDamageAnim)); + Actor_SetColorFilter(&sHands[LEFT]->actor, 0x4000, 0xFF, 0, Animation_GetLastFrame(&gBongoHeadDamageAnim)); + Actor_SetColorFilter(&sHands[RIGHT]->actor, 0x4000, 0xFF, 0, Animation_GetLastFrame(&gBongoHeadDamageAnim)); + this->colliderCyl.base.acFlags &= ~AC_ON; + BossSst_HeadSfx(this, NA_SE_EN_SHADEST_DAMAGE); + this->actionFunc = BossSst_HeadDamage; +} + +void BossSst_HeadDamage(BossSst* this, GlobalContext* globalCtx) { + if (this->timer != 0) { + this->timer--; + } + + if (SkelAnime_Update(&this->skelAnime)) { + BossSst_HeadSetupVulnerable(this); + } +} + +void BossSst_HeadSetupRecover(BossSst* this) { + Animation_MorphToPlayOnce(&this->skelAnime, &gBongoHeadRecoverAnim, -5.0f); + this->colliderCyl.base.acFlags &= ~AC_ON; + this->colliderCyl.info.bumper.dmgFlags = 0xFFCFFFFF; + this->colliderJntSph.elements[10].info.bumperFlags &= ~(BUMP_ON | BUMP_HOOKABLE); + this->colliderJntSph.elements[0].info.bumperFlags |= BUMP_ON; + this->vVanish = true; + this->actor.speedXZ = 5.0f; + this->actionFunc = BossSst_HeadRecover; +} + +void BossSst_HeadRecover(BossSst* this, GlobalContext* globalCtx) { + s32 animFinish; + f32 currentFrame; + f32 diff; + + animFinish = SkelAnime_Update(&this->skelAnime); + currentFrame = this->skelAnime.curFrame; + if (currentFrame < 10.0f) { + this->actor.world.pos.y += 10.0f; + sHandOffsets[LEFT].y -= 10.0f; + sHandOffsets[RIGHT].y -= 10.0f; + Math_SmoothStepToF(&this->radius, -750.0f, 1.0f, this->actor.speedXZ, 2.0f); + } else { + this->actor.speedXZ *= 1.25f; + this->actor.speedXZ = CLAMP_MAX(this->actor.speedXZ, 50.0f); + diff = Math_SmoothStepToF(&this->radius, -650.0f, 1.0f, this->actor.speedXZ, 2.0f); + diff += Math_SmoothStepToF(&this->actor.world.pos.y, this->actor.home.pos.y, 0.5f, 30.0f, 3.0f); + } + if (animFinish && (diff < 10.0f)) { + this->actor.world.pos.y = this->actor.home.pos.y; + this->radius = -650.0f; + BossSst_HandSetupRetreat(sHands[LEFT]); + BossSst_HandSetupRetreat(sHands[RIGHT]); + BossSst_HeadSetupNeutral(this); + } +} + +void BossSst_SetCameraTargets(f32 cameraSpeedMod, s32 targetIndex) { + Vec3f* nextAt = &sCameraAtPoints[targetIndex]; + Vec3f* nextEye = &sCameraEyePoints[targetIndex]; + + if (targetIndex != 0) { + Math_Vec3f_Copy(&sCameraAt, &sCameraAtPoints[targetIndex - 1]); + Math_Vec3f_Copy(&sCameraEye, &sCameraEyePoints[targetIndex - 1]); + } + + sCameraAtVel.x = (nextAt->x - sCameraAt.x) * cameraSpeedMod; + sCameraAtVel.y = (nextAt->y - sCameraAt.y) * cameraSpeedMod; + sCameraAtVel.z = (nextAt->z - sCameraAt.z) * cameraSpeedMod; + + sCameraEyeVel.x = (nextEye->x - sCameraEye.x) * cameraSpeedMod; + sCameraEyeVel.y = (nextEye->y - sCameraEye.y) * cameraSpeedMod; + sCameraEyeVel.z = (nextEye->z - sCameraEye.z) * cameraSpeedMod; +} + +void BossSst_UpdateDeathCamera(BossSst* this, GlobalContext* globalCtx) { + Vec3f cameraAt; + Vec3f cameraEye; + f32 sn; + f32 cs; + + sCameraAt.x += sCameraAtVel.x; + sCameraAt.y += sCameraAtVel.y; + sCameraAt.z += sCameraAtVel.z; + sCameraEye.x += sCameraEyeVel.x; + sCameraEye.y += sCameraEyeVel.y; + sCameraEye.z += sCameraEyeVel.z; + + sn = Math_SinS(this->actor.shape.rot.y); + cs = Math_CosS(this->actor.shape.rot.y); + cameraAt.x = this->actor.world.pos.x + (sCameraAt.z * sn) + (sCameraAt.x * cs); + cameraAt.y = this->actor.home.pos.y - 140.0f + sCameraAt.y; + cameraAt.z = this->actor.world.pos.z + (sCameraAt.z * cs) - (sCameraAt.x * sn); + cameraEye.x = this->actor.world.pos.x + (sCameraEye.z * sn) + (sCameraEye.x * cs); + cameraEye.y = this->actor.home.pos.y - 140.0f + sCameraEye.y; + cameraEye.z = this->actor.world.pos.z + (sCameraEye.z * cs) - (sCameraEye.x * sn); + Gameplay_CameraSetAtEye(globalCtx, sCutsceneCamera, &cameraAt, &cameraEye); +} + +void BossSst_HeadSetupDeath(BossSst* this, GlobalContext* globalCtx) { + Player* player = PLAYER; + + Animation_MorphToLoop(&this->skelAnime, &gBongoHeadEyeOpenIdleAnim, -5.0f); + BossSst_HeadSfx(this, NA_SE_EN_SHADEST_DEAD); + Actor_SetColorFilter(&this->actor, 0x4000, 0xFF, 0, 60); + Actor_SetColorFilter(&sHands[LEFT]->actor, 0x4000, 0xFF, 0, 60); + Actor_SetColorFilter(&sHands[RIGHT]->actor, 0x4000, 0xFF, 0, 60); + this->timer = 60; + this->colliderCyl.base.acFlags &= ~AC_ON; + this->colliderJntSph.base.ocFlags1 &= ~OC1_ON; + sHands[LEFT]->colliderJntSph.base.ocFlags1 &= ~OC1_ON; + sHands[RIGHT]->colliderJntSph.base.ocFlags1 &= ~OC1_ON; + Audio_SetBGM(0x100100FF); + sCutsceneCamera = Gameplay_CreateSubCamera(globalCtx); + Gameplay_ChangeCameraStatus(globalCtx, MAIN_CAM, CAM_STAT_WAIT); + Gameplay_ChangeCameraStatus(globalCtx, sCutsceneCamera, CAM_STAT_ACTIVE); + Gameplay_CopyCamera(globalCtx, sCutsceneCamera, MAIN_CAM); + func_8002DF54(globalCtx, &player->actor, 8); + func_80064520(globalCtx, &globalCtx->csCtx); + Math_Vec3f_Copy(&sCameraEye, &ACTIVE_CAM->eye); + this->actionFunc = BossSst_HeadDeath; +} + +void BossSst_HeadDeath(BossSst* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + if (this->timer != 0) { + this->timer--; + } + + Math_StepToF(&this->actor.world.pos.y, this->actor.home.pos.y - 140.0f, 20.0f); + if (this->timer == 0) { + BossSst_HandSetupThrash(sHands[LEFT]); + BossSst_HandSetupThrash(sHands[RIGHT]); + BossSst_HeadSetupThrash(this); + } else if (this->timer > 48) { + Gameplay_CameraSetAtEye(globalCtx, sCutsceneCamera, &this->actor.focus.pos, &sCameraEye); + Math_StepToF(&this->radius, -350.0f, 10.0f); + } else if (this->timer == 48) { + Player* player = PLAYER; + + player->actor.world.pos.x = sRoomCenter.x + (400.0f * Math_SinS(this->actor.shape.rot.y)) + + (Math_CosS(this->actor.shape.rot.y) * -120.0f); + player->actor.world.pos.z = sRoomCenter.z + (400.0f * Math_CosS(this->actor.shape.rot.y)) - + (Math_SinS(this->actor.shape.rot.y) * -120.0f); + player->actor.shape.rot.y = Actor_WorldYawTowardPoint(&player->actor, &sRoomCenter); + func_8002DBD0(&this->actor, &sCameraEye, &globalCtx->cameraPtrs[globalCtx->activeCamera]->eye); + func_8002DBD0(&this->actor, &sCameraAt, &globalCtx->cameraPtrs[globalCtx->activeCamera]->at); + this->radius = -350.0f; + this->actor.world.pos.x = sRoomCenter.x - (Math_SinS(this->actor.shape.rot.y) * 350.0f); + this->actor.world.pos.z = sRoomCenter.z - (Math_CosS(this->actor.shape.rot.y) * 350.0f); + BossSst_SetCameraTargets(1.0 / 48, 0); + BossSst_UpdateDeathCamera(this, globalCtx); + } else { + BossSst_UpdateDeathCamera(this, globalCtx); + } +} + +void BossSst_HeadSetupThrash(BossSst* this) { + Animation_MorphToPlayOnce(&this->skelAnime, &gBongoHeadEyeOpenIdleAnim, -5.0f); + this->timer = 160; + this->targetYaw = this->actor.shape.rot.y; + BossSst_SetCameraTargets(1.0 / 80, 1); + this->actionFunc = BossSst_HeadThrash; +} + +void BossSst_HeadThrash(BossSst* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + if (this->timer != 0) { + this->timer--; + } + + if ((this->timer == 0) && (this->actor.shape.rot.y == this->targetYaw)) { + BossSst_HeadSetupDarken(this); + } else if (this->timer >= 80) { + BossSst_UpdateDeathCamera(this, globalCtx); + } +} + +void BossSst_HeadSetupDarken(BossSst* this) { + this->timer = 160; + BossSst_SetCameraTargets(1.0 / 80, 2); + this->actionFunc = BossSst_HeadDarken; +} + +void BossSst_HeadDarken(BossSst* this, GlobalContext* globalCtx) { + if (this->timer != 0) { + this->timer--; + } + if (1) {} + + if (this->timer >= 80) { + if (this->timer == 80) { + sBodyStatic = true; + } + BossSst_UpdateDeathCamera(this, globalCtx); + sBodyColor.r = sBodyColor.g = sBodyColor.b = (this->timer * 3) - 240; + if (this->timer == 80) { + BossSst_SetCameraTargets(1.0 / 80, 3); + } + } else { + sBodyColor.b = (80 - this->timer) / 1.0f; + sBodyColor.r = sBodyColor.g = sStaticColor.r = sStaticColor.g = sStaticColor.b = (80 - this->timer) / 8.0f; + BossSst_UpdateDeathCamera(this, globalCtx); + if (this->timer == 0) { + BossSst_HeadSetupFall(this); + } + } +} + +void BossSst_HeadSetupFall(BossSst* this) { + this->actor.speedXZ = 1.0f; + Math_Vec3f_Copy(&sCameraAt, &sCameraAtPoints[3]); + Math_Vec3f_Copy(&sCameraEye, &sCameraEyePoints[3]); + sCameraAtVel.x = 0.0f; + sCameraAtVel.z = 0.0f; + sCameraAtVel.y = -50.0f; + Math_Vec3f_Copy(&sCameraEyeVel, &sZeroVec); + this->actionFunc = BossSst_HeadFall; +} + +void BossSst_HeadFall(BossSst* this, GlobalContext* globalCtx) { + this->actor.speedXZ *= 1.5f; + if (Math_StepToF(&this->actor.world.pos.y, this->actor.home.pos.y - 230.0f, this->actor.speedXZ)) { + BossSst_HeadSetupMelt(this); + } + + if (sCameraAt.y > 200.0f) { + BossSst_UpdateDeathCamera(this, globalCtx); + } +} + +void BossSst_HeadSetupMelt(BossSst* this) { + BossSst_SpawnHeadShadow(this); + this->timer = 80; + BossSst_SetCameraTargets(1.0 / 60, 5); + this->actionFunc = BossSst_HeadMelt; +} + +void BossSst_HeadMelt(BossSst* this, GlobalContext* globalCtx) { + if (this->timer != 0) { + this->timer--; + } + + this->actor.scale.y -= 0.00025f; + this->actor.scale.x += 0.000075f; + this->actor.scale.z += 0.000075f; + this->actor.world.pos.y = this->actor.home.pos.y - 11500.0f * this->actor.scale.y; + if (this->timer == 0) { + BossSst_HeadSetupFinish(this); + } else if (this->timer >= 20.0f) { + BossSst_UpdateDeathCamera(this, globalCtx); + } +} + +void BossSst_HeadSetupFinish(BossSst* this) { + this->actor.draw = BossSst_DrawEffect; + this->timer = 40; + Audio_SetBGM(0x21); + BossSst_SetCameraTargets(1.0 / 40, 6); + this->actionFunc = BossSst_HeadFinish; +} + +void BossSst_HeadFinish(BossSst* this, GlobalContext* globalCtx) { + static Color_RGBA8 colorIndigo = { 80, 80, 150, 255 }; + static Color_RGBA8 colorDarkIndigo = { 40, 40, 80, 255 }; + static Color_RGBA8 colorUnused[2] = { + { 0, 0, 0, 255 }, + { 100, 100, 100, 0 }, + }; + Vec3f spawnPos; + s32 i; + + this->timer--; + if (this->effectMode == BONGO_NULL) { + if (this->timer < -170) { + BossSst_UpdateDeathCamera(this, globalCtx); + Gameplay_CopyCamera(globalCtx, MAIN_CAM, sCutsceneCamera); + Gameplay_ChangeCameraStatus(globalCtx, sCutsceneCamera, CAM_STAT_WAIT); + Gameplay_ChangeCameraStatus(globalCtx, MAIN_CAM, CAM_STAT_ACTIVE); + Gameplay_ClearCamera(globalCtx, sCutsceneCamera); + func_8002DF54(globalCtx, &PLAYER->actor, 7); + func_80064534(globalCtx, &globalCtx->csCtx); + Actor_Kill(&this->actor); + Actor_Kill(&sHands[LEFT]->actor); + Actor_Kill(&sHands[RIGHT]->actor); + Flags_SetClear(globalCtx, globalCtx->roomCtx.curRoom.num); + } + } else if (this->effects[0].alpha == 0) { + Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_DOOR_WARP1, ROOM_CENTER_X, ROOM_CENTER_Y, ROOM_CENTER_Z, 0, + 0, 0, -1); + Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_ITEM_B_HEART, + (Math_SinS(this->actor.shape.rot.y) * 200.0f) + ROOM_CENTER_X, ROOM_CENTER_Y, + Math_CosS(this->actor.shape.rot.y) * 200.0f + ROOM_CENTER_Z, 0, 0, 0, 0); + BossSst_SetCameraTargets(1.0f, 7); + this->effectMode = BONGO_NULL; + } else if (this->timer == 0) { + this->effects[0].status = 0; + this->effects[1].status = -1; + this->effects[2].status = -1; + } else if (this->timer > 0) { + this->effects[0].status += 5; + BossSst_UpdateDeathCamera(this, globalCtx); + } + + colorIndigo.a = this->effects[0].alpha; + colorDarkIndigo.a = this->effects[0].alpha; + + for (i = 0; i < 5; i++) { + spawnPos.x = sRoomCenter.x + 0.0f + Rand_CenteredFloat(800.0f); + spawnPos.y = sRoomCenter.y + (-28.0f) + (Rand_ZeroOne() * 5.0f); + spawnPos.z = sRoomCenter.z + 0.0f + Rand_CenteredFloat(800.0f); + EffectSsGSplash_Spawn(globalCtx, &spawnPos, &colorIndigo, &colorDarkIndigo, 0, 0x3E8); + } +} + +void BossSst_HandSetupWait(BossSst* this) { + HAND_STATE(this) = HAND_WAIT; + this->colliderJntSph.base.atFlags &= ~(AT_ON | AT_HIT); + Animation_MorphToLoop(&this->skelAnime, sHandIdleAnims[this->actor.params], 5.0f); + this->ready = false; + this->timer = 20; + this->actionFunc = BossSst_HandWait; +} + +void BossSst_HandWait(BossSst* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + Math_StepToF(&this->actor.world.pos.y, this->actor.floorHeight, 20.0f); + Math_StepToF(&this->actor.world.pos.x, this->actor.home.pos.x, 1.0f); + Math_StepToF(&this->actor.world.pos.z, this->actor.home.pos.z, 1.0f); + if (HAND_STATE(OTHER_HAND(this)) == HAND_DAMAGED) { + Player* player = PLAYER; + + if (this->timer != 0) { + this->timer--; + } + + if ((this->timer == 0) && (player->actor.world.pos.y > -50.0f) && !(player->stateFlags1 & 0x6080)) { + BossSst_HandSelectAttack(this); + } + } else if (sHead->actionFunc == BossSst_HeadNeutral) { + if ((this->actor.params == BONGO_RIGHT_HAND) && ((sHead->timer % 28) == 12)) { + BossSst_HandSetupDownbeat(this); + } else if ((this->actor.params == BONGO_LEFT_HAND) && ((sHead->timer % 7) == 5) && (sHead->timer < 112)) { + BossSst_HandSetupOffbeat(this); + } + } +} + +void BossSst_HandSetupDownbeat(BossSst* this) { + HAND_STATE(this) = HAND_BEAT; + Animation_MorphToPlayOnce(&this->skelAnime, sHandOpenPoses[this->actor.params], 5.0f); + this->actor.shape.rot.x = 0; + this->timer = 12; + this->actionFunc = BossSst_HandDownbeat; +} + +void BossSst_HandDownbeat(BossSst* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + if (HAND_STATE(OTHER_HAND(this)) == HAND_DAMAGED) { + BossSst_HandSetupWait(this); + } else { + if (this->timer != 0) { + this->timer--; + } + + if (this->timer >= 3) { + this->actor.shape.rot.x -= 0x100; + Math_StepToF(&this->actor.world.pos.y, ROOM_CENTER_Y + 180.0f, 20.0f); + } else { + this->actor.shape.rot.x += 0x300; + Math_StepToF(&this->actor.world.pos.y, ROOM_CENTER_Y + 0.0f, 60.0f); + } + + if (this->timer == 0) { + sFloor->dyna.actor.params = BONGOFLOOR_HIT; + if (sHead->actionFunc == BossSst_HeadWait) { + if (this->ready) { + BossSst_HandSelectAttack(this); + } else { + BossSst_HandSetupWait(this); + } + } else { + BossSst_HandSetupDownbeatEnd(this); + } + func_800AA000(this->actor.xyzDistToPlayerSq, 0xFF, 0x14, 0x96); + Audio_PlayActorSound2(&this->actor, NA_SE_EN_SHADEST_TAIKO_HIGH); + } + } +} + +void BossSst_HandSetupDownbeatEnd(BossSst* this) { + sFloor->dyna.actor.params = BONGOFLOOR_HIT; + Animation_PlayOnce(&this->skelAnime, sHandFlatPoses[this->actor.params]); + this->actionFunc = BossSst_HandDownbeatEnd; +} + +void BossSst_HandDownbeatEnd(BossSst* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + if (HAND_STATE(OTHER_HAND(this)) == HAND_DAMAGED) { + BossSst_HandSetupWait(this); + } else { + Math_SmoothStepToF(&this->actor.world.pos.y, ROOM_CENTER_Y + 40.0f, 0.5f, 20.0f, 3.0f); + Math_ScaledStepToS(&this->actor.shape.rot.x, -0x800, 0x100); + Math_StepToF(&this->actor.world.pos.x, this->actor.home.pos.x, 1.0f); + Math_StepToF(&this->actor.world.pos.z, this->actor.home.pos.z, 1.0f); + if ((sHead->actionFunc != BossSst_HeadIntro) && ((sHead->timer % 28) == 12)) { + BossSst_HandSetupDownbeat(this); + } + } +} + +void BossSst_HandSetupOffbeat(BossSst* this) { + HAND_STATE(this) = HAND_BEAT; + Animation_MorphToPlayOnce(&this->skelAnime, sHandOpenPoses[this->actor.params], 5.0f); + this->actor.shape.rot.x = 0; + this->timer = 5; + this->actionFunc = BossSst_HandOffbeat; +} + +void BossSst_HandOffbeat(BossSst* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + if (HAND_STATE(OTHER_HAND(this)) == HAND_DAMAGED) { + BossSst_HandSetupWait(this); + } else { + if (this->timer != 0) { + this->timer--; + } + + if (this->timer != 0) { + this->actor.shape.rot.x -= 0x140; + Math_StepToF(&this->actor.world.pos.y, ROOM_CENTER_Y + 60.0f, 15.0f); + } else { + this->actor.shape.rot.x += 0x500; + Math_StepToF(&this->actor.world.pos.y, ROOM_CENTER_Y + 0.0f, 60.0f); + } + + if (this->timer == 0) { + Audio_PlayActorSound2(&this->actor, NA_SE_EN_SHADEST_TAIKO_LOW); + BossSst_HandSetupOffbeatEnd(this); + } + } +} + +void BossSst_HandSetupOffbeatEnd(BossSst* this) { + Animation_PlayOnce(&this->skelAnime, sHandFlatPoses[this->actor.params]); + this->actionFunc = BossSst_HandOffbeatEnd; +} + +void BossSst_HandOffbeatEnd(BossSst* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + if (HAND_STATE(OTHER_HAND(this)) == HAND_DAMAGED) { + BossSst_HandSetupWait(this); + } else { + Math_SmoothStepToF(&this->actor.world.pos.y, ROOM_CENTER_Y + 40.0f, 0.5f, 20.0f, 3.0f); + Math_ScaledStepToS(&this->actor.shape.rot.x, -0x400, 0xA0); + Math_StepToF(&this->actor.world.pos.x, this->actor.home.pos.x, 1.0f); + Math_StepToF(&this->actor.world.pos.z, this->actor.home.pos.z, 1.0f); + if (sHead->actionFunc == BossSst_HeadWait) { + if (this->ready) { + BossSst_HandSelectAttack(this); + } else { + BossSst_HandSetupWait(this); + } + } else if ((sHead->actionFunc != BossSst_HeadIntro) && ((sHead->timer % 7) == 5) && + ((sHead->timer % 28) != 5)) { + BossSst_HandSetupOffbeat(this); + } + } +} + +void BossSst_HandSetupEndSlam(BossSst* this) { + HAND_STATE(this) = HAND_RETREAT; + this->colliderJntSph.base.atFlags &= ~(AT_ON | AT_HIT); + Animation_MorphToPlayOnce(&this->skelAnime, sHandPushoffPoses[this->actor.params], 6.0f); + this->actionFunc = BossSst_HandEndSlam; +} + +void BossSst_HandEndSlam(BossSst* this, GlobalContext* globalCtx) { + if (SkelAnime_Update(&this->skelAnime)) { + BossSst_HandSetupRetreat(this); + } +} + +void BossSst_HandSetupRetreat(BossSst* this) { + HAND_STATE(this) = HAND_RETREAT; + Animation_MorphToPlayOnce(&this->skelAnime, sHandHangPoses[this->actor.params], 10.0f); + this->colliderJntSph.base.atFlags &= ~(AT_ON | AT_HIT); + this->colliderJntSph.base.acFlags |= AC_ON; + this->actor.flags |= 1; + BossSst_HandSetInvulnerable(this, false); + this->timer = 0; + this->actionFunc = BossSst_HandRetreat; + this->actor.speedXZ = 3.0f; +} + +void BossSst_HandRetreat(BossSst* this, GlobalContext* globalCtx) { + f32 diff; + s32 inPosition; + + SkelAnime_Update(&this->skelAnime); + this->actor.speedXZ = this->actor.speedXZ * 1.2f; + this->actor.speedXZ = CLAMP_MAX(this->actor.speedXZ, 50.0f); + + diff = Math_SmoothStepToF(&this->actor.world.pos.x, this->actor.home.pos.x, 0.3f, this->actor.speedXZ, 1.0f); + diff += Math_SmoothStepToF(&this->actor.world.pos.z, this->actor.home.pos.z, 0.3f, this->actor.speedXZ, 1.0f); + if (this->timer != 0) { + if (this->timer != 0) { + this->timer--; + } + + this->actor.world.pos.y = (sinf((this->timer * M_PI) / 16.0f) * 250.0f) + this->actor.home.pos.y; + if (this->timer == 0) { + BossSst_HandSetupWait(this); + } else if (this->timer == 4) { + Animation_MorphToLoop(&this->skelAnime, sHandIdleAnims[this->actor.params], 4.0f); + } + } else { + inPosition = Math_ScaledStepToS(&this->actor.shape.rot.y, this->actor.home.rot.y, 0x200); + inPosition &= Math_ScaledStepToS(&this->actor.shape.rot.z, this->actor.home.rot.z, 0x200); + inPosition &= Math_ScaledStepToS(&this->handYRotMod, 0, 0x800); + func_8002F974(&this->actor, NA_SE_EN_SHADEST_HAND_FLY - SFX_FLAG); + if ((Math_SmoothStepToF(&this->actor.world.pos.y, ROOM_CENTER_Y + 250.0f, 0.5f, 70.0f, 5.0f) < 1.0f) && + inPosition && (diff < 10.0f)) { + this->timer = 8; + } + } +} + +void BossSst_HandSetupReadySlam(BossSst* this) { + HAND_STATE(this) = HAND_SLAM; + this->timer = 0; + Animation_MorphToPlayOnce(&this->skelAnime, sHandOpenPoses[this->actor.params], 10.0f); + this->actionFunc = BossSst_HandReadySlam; +} + +void BossSst_HandReadySlam(BossSst* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + if (this->timer != 0) { + if (this->timer != 0) { + this->timer--; + } + + if (this->timer == 0) { + BossSst_HandSetupSlam(this); + } + } else { + Player* player = PLAYER; + + if (Math_StepToF(&this->actor.world.pos.y, ROOM_CENTER_Y + 300.0f, 30.0f) && + (this->actor.xzDistToPlayer < 140.0f)) { + this->timer = 20; + } + Math_ScaledStepToS(&this->actor.shape.rot.x, -0x1000, 0x100); + Math_ApproachF(&this->actor.world.pos.x, player->actor.world.pos.x, 0.5f, 40.0f); + Math_ApproachF(&this->actor.world.pos.z, player->actor.world.pos.z, 0.5f, 40.0f); + func_8002F974(&this->actor, NA_SE_EN_SHADEST_HAND_FLY - SFX_FLAG); + } +} + +void BossSst_HandSetupSlam(BossSst* this) { + HAND_STATE(this) = HAND_SLAM; + this->actor.velocity.y = 1.0f; + Animation_MorphToPlayOnce(&this->skelAnime, sHandFlatPoses[this->actor.params], 10.0f); + BossSst_HandSetDamage(this, 0x20); + this->ready = false; + Audio_PlayActorSound2(&this->actor, NA_SE_EN_SHADEST_FLY_ATTACK); + this->actionFunc = BossSst_HandSlam; +} + +void BossSst_HandSlam(BossSst* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + Math_StepToS(&this->handZPosMod, -0xDAC, 0x1F4); + Math_ScaledStepToS(&this->actor.shape.rot.x, 0, 0x1000); + Math_ScaledStepToS(&this->handYRotMod, 0, 0x1000); + if (this->timer != 0) { + if (this->timer != 0) { + this->timer--; + } + + if (this->timer == 0) { + if (this->colliderJntSph.base.acFlags & AC_ON) { + BossSst_HandSetupEndSlam(this); + } else { + this->colliderJntSph.base.acFlags |= AC_ON; + BossSst_HandSetupWait(this); + } + } + } else { + if (this->ready) { + this->timer = 30; + this->colliderJntSph.base.atFlags &= ~(AT_ON | AT_HIT); + } else { + this->actor.velocity.y *= 1.5f; + if (Math_StepToF(&this->actor.world.pos.y, this->actor.floorHeight, this->actor.velocity.y)) { + this->ready = true; + Audio_PlayActorSound2(&this->actor, NA_SE_EN_SHADEST_TAIKO_LOW); + BossSst_SpawnShockwave(this); + this->colliderCyl.base.atFlags |= AT_ON; + Collider_UpdateCylinder(&this->actor, &this->colliderCyl); + this->colliderCyl.dim.radius = sCylinderInitHand.dim.radius; + } + } + + if (this->colliderJntSph.base.atFlags & AT_HIT) { + Player* player = PLAYER; + + player->actor.world.pos.x = (Math_SinS(this->actor.yawTowardsPlayer) * 100.0f) + this->actor.world.pos.x; + player->actor.world.pos.z = (Math_CosS(this->actor.yawTowardsPlayer) * 100.0f) + this->actor.world.pos.z; + + this->colliderJntSph.base.atFlags &= ~(AT_ON | AT_HIT); + func_8002F71C(globalCtx, &this->actor, 5.0f, this->actor.yawTowardsPlayer, 0.0f); + } + + Math_ScaledStepToS(&this->actor.shape.rot.x, 0, 0x200); + } +} + +void BossSst_HandSetupReadySweep(BossSst* this) { + HAND_STATE(this) = HAND_SWEEP; + Animation_MorphToPlayOnce(&this->skelAnime, sHandOpenPoses[this->actor.params], 10.0f); + this->radius = Actor_WorldDistXZToPoint(&this->actor, &sHead->actor.world.pos); + this->actor.world.rot.y = Actor_WorldYawTowardPoint(&sHead->actor, &this->actor.world.pos); + this->targetYaw = this->actor.home.rot.y + (this->vParity * 0x2000); + this->actionFunc = BossSst_HandReadySweep; +} + +void BossSst_HandReadySweep(BossSst* this, GlobalContext* globalCtx) { + s32 inPosition; + + SkelAnime_Update(&this->skelAnime); + inPosition = Math_StepToF(&this->actor.world.pos.y, ROOM_CENTER_Y + 50.0f, 4.0f); + inPosition &= Math_ScaledStepToS(&this->actor.shape.rot.y, this->targetYaw, 0x200); + inPosition &= Math_ScaledStepToS(&this->actor.world.rot.y, this->targetYaw, 0x400); + inPosition &= (Math_SmoothStepToF(&this->radius, sHead->actor.xzDistToPlayer, 0.5f, 60.0f, 1.0f) < 10.0f); + + this->actor.world.pos.x = (Math_SinS(this->actor.world.rot.y) * this->radius) + sHead->actor.world.pos.x; + this->actor.world.pos.z = (Math_CosS(this->actor.world.rot.y) * this->radius) + sHead->actor.world.pos.z; + if (inPosition) { + BossSst_HandSetupSweep(this); + } else { + func_8002F974(&this->actor, NA_SE_EN_SHADEST_HAND_FLY - SFX_FLAG); + } +} + +void BossSst_HandSetupSweep(BossSst* this) { + Animation_MorphToPlayOnce(&this->skelAnime, sHandFlatPoses[this->actor.params], 5.0f); + BossSst_HandSetDamage(this, 0x10); + this->targetYaw = this->actor.home.rot.y - (this->vParity * 0x2000); + this->handMaxSpeed = 0x300; + this->handAngSpeed = 0; + this->ready = false; + Audio_PlayActorSound2(&this->actor, NA_SE_EN_SHADEST_FLY_ATTACK); + this->actionFunc = BossSst_HandSweep; +} + +void BossSst_HandSweep(BossSst* this, GlobalContext* globalCtx) { + Player* player = PLAYER; + s16 newTargetYaw; + + SkelAnime_Update(&this->skelAnime); + this->handAngSpeed += 0x60; + this->handAngSpeed = CLAMP_MAX(this->handAngSpeed, this->handMaxSpeed); + + if (!Math_SmoothStepToS(&this->actor.shape.rot.y, this->targetYaw, 4, this->handAngSpeed, 0x10)) { + this->colliderJntSph.base.ocFlags1 &= ~OC1_NO_PUSH; + BossSst_HandSetupRetreat(this); + } else if (this->colliderJntSph.base.atFlags & AT_HIT) { + this->colliderJntSph.base.atFlags &= ~(AT_ON | AT_HIT); + this->ready = true; + func_8002F71C(globalCtx, &this->actor, 5.0f, this->actor.shape.rot.y - (this->vParity * 0x3800), 0.0f); + func_8002F7DC(&player->actor, NA_SE_PL_BODY_HIT); + newTargetYaw = this->actor.shape.rot.y - (this->vParity * 0x1400); + if (((s16)(newTargetYaw - this->targetYaw) * this->vParity) > 0) { + this->targetYaw = newTargetYaw; + } + } + + if (!this->ready && ((player->cylinder.dim.height > 40.0f) || (player->actor.world.pos.y > 1.0f))) { + this->colliderJntSph.base.atFlags |= AT_ON; + this->colliderJntSph.base.ocFlags1 &= ~OC1_NO_PUSH; + } else { + this->colliderJntSph.base.atFlags &= ~AT_ON; + this->colliderJntSph.base.ocFlags1 |= OC1_NO_PUSH; + } + + this->actor.world.pos.x = (Math_SinS(this->actor.shape.rot.y) * this->radius) + sHead->actor.world.pos.x; + this->actor.world.pos.z = (Math_CosS(this->actor.shape.rot.y) * this->radius) + sHead->actor.world.pos.z; +} + +void BossSst_HandSetupReadyPunch(BossSst* this) { + HAND_STATE(this) = HAND_PUNCH; + Animation_MorphToPlayOnce(&this->skelAnime, sHandPushoffPoses[this->actor.params], 10.0f); + this->actionFunc = BossSst_HandReadyPunch; +} + +void BossSst_HandReadyPunch(BossSst* this, GlobalContext* globalCtx) { + s32 inPosition = Math_ScaledStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 0x400); + + if (SkelAnime_Update(&this->skelAnime) && inPosition) { + BossSst_HandSetupPunch(this); + } +} + +void BossSst_HandSetupPunch(BossSst* this) { + this->actor.speedXZ = 0.5f; + Animation_MorphToPlayOnce(&this->skelAnime, sHandFistPoses[this->actor.params], 5.0f); + BossSst_HandSetInvulnerable(this, true); + this->targetRoll = this->vParity * 0x3F00; + BossSst_HandSetDamage(this, 0x10); + this->actionFunc = BossSst_HandPunch; +} + +void BossSst_HandPunch(BossSst* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + Math_StepToF(&this->actor.world.pos.y, ROOM_CENTER_Y + 80.0f, 20.0f); + if (Math_ScaledStepToS(&this->actor.shape.rot.z, this->targetRoll, 0x400)) { + this->targetRoll *= -1; + } + + this->actor.speedXZ *= 1.25f; + this->actor.speedXZ = CLAMP_MAX(this->actor.speedXZ, 50.0f); + + this->actor.world.pos.x += this->actor.speedXZ * Math_SinS(this->actor.shape.rot.y); + this->actor.world.pos.z += this->actor.speedXZ * Math_CosS(this->actor.shape.rot.y); + if (this->actor.bgCheckFlags & 8) { + BossSst_HandSetupRetreat(this); + } else if (this->colliderJntSph.base.atFlags & AT_HIT) { + func_8002F7DC(&PLAYER->actor, NA_SE_PL_BODY_HIT); + func_8002F71C(globalCtx, &this->actor, 10.0f, this->actor.shape.rot.y, 5.0f); + BossSst_HandSetupRetreat(this); + } + + func_8002F974(&this->actor, NA_SE_EN_SHADEST_HAND_FLY - SFX_FLAG); +} + +void BossSst_HandSetupReadyClap(BossSst* this) { + HAND_STATE(this) = HAND_CLAP; + if (HAND_STATE(OTHER_HAND(this)) != HAND_CLAP) { + BossSst_HandSetupReadyClap(OTHER_HAND(this)); + } + + Animation_MorphToPlayOnce(&this->skelAnime, sHandOpenPoses[this->actor.params], 10.0f); + this->radius = Actor_WorldDistXZToPoint(&this->actor, &sHead->actor.world.pos); + this->actor.world.rot.y = Actor_WorldYawTowardPoint(&sHead->actor, &this->actor.world.pos); + this->targetYaw = this->actor.home.rot.y - (this->vParity * 0x1800); + this->targetRoll = this->vParity * 0x4000; + this->timer = 0; + this->ready = false; + OTHER_HAND(this)->ready = false; + this->actionFunc = BossSst_HandReadyClap; +} + +void BossSst_HandReadyClap(BossSst* this, GlobalContext* globalCtx) { + if (this->timer != 0) { + if (this->timer != 0) { + this->timer--; + } + + if (this->timer == 0) { + BossSst_HandSetupClap(this); + BossSst_HandSetupClap(OTHER_HAND(this)); + OTHER_HAND(this)->radius = this->radius; + } + } else if (!this->ready) { + this->ready = SkelAnime_Update(&this->skelAnime); + this->ready &= Math_ScaledStepToS(&this->actor.shape.rot.x, 0, 0x600); + this->ready &= Math_ScaledStepToS(&this->actor.shape.rot.z, this->targetRoll, 0x600); + this->ready &= Math_ScaledStepToS(&this->actor.shape.rot.y, this->targetYaw, 0x200); + this->ready &= Math_ScaledStepToS(&this->actor.world.rot.y, this->targetYaw, 0x400); + this->ready &= Math_SmoothStepToF(&this->radius, sHead->actor.xzDistToPlayer, 0.5f, 50.0f, 1.0f) < 10.0f; + this->ready &= Math_SmoothStepToF(&this->actor.world.pos.y, ROOM_CENTER_Y + 95.0f, 0.5f, 30.0f, 1.0f) < 1.0f; + + this->actor.world.pos.x = Math_SinS(this->actor.world.rot.y) * this->radius + sHead->actor.world.pos.x; + this->actor.world.pos.z = Math_CosS(this->actor.world.rot.y) * this->radius + sHead->actor.world.pos.z; + } else if (OTHER_HAND(this)->ready) { + this->timer = 20; + } +} + +void BossSst_HandSetupClap(BossSst* this) { + Animation_MorphToPlayOnce(&this->skelAnime, sHandFlatPoses[this->actor.params], 3.0f); + this->timer = 0; + this->handMaxSpeed = 0x240; + this->handAngSpeed = 0; + this->ready = false; + BossSst_HandSetDamage(this, 0x20); + this->actionFunc = BossSst_HandClap; +} + +void BossSst_HandClap(BossSst* this, GlobalContext* globalCtx) { + static s32 dropFlag = false; + Player* player = PLAYER; + + SkelAnime_Update(&this->skelAnime); + if (this->timer != 0) { + if (this->timer != 0) { + this->timer--; + } + + if (this->timer == 0) { + if (dropFlag) { + Item_DropCollectible(globalCtx, &this->actor.world.pos, + (Rand_ZeroOne() < 0.5f) ? ITEM00_ARROWS_SMALL : ITEM00_MAGIC_SMALL); + dropFlag = false; + } + + BossSst_HandReleasePlayer(this, globalCtx, true); + BossSst_HandSetupEndClap(this); + } + } else { + if (this->colliderJntSph.base.atFlags & AT_HIT) { + this->colliderJntSph.base.atFlags &= ~(AT_ON | AT_HIT); + OTHER_HAND(this)->colliderJntSph.base.atFlags &= ~(AT_ON | AT_HIT); + BossSst_HandGrabPlayer(this, globalCtx); + } + + if (this->ready) { + this->timer = 30; + this->colliderJntSph.base.atFlags &= ~(AT_ON | AT_HIT); + if (!(player->stateFlags2 & 0x80)) { + dropFlag = true; + } + } else { + this->handAngSpeed += 0x40; + this->handAngSpeed = CLAMP_MAX(this->handAngSpeed, this->handMaxSpeed); + + if (Math_ScaledStepToS(&this->actor.shape.rot.y, this->actor.home.rot.y, this->handAngSpeed)) { + if (this->actor.params == BONGO_LEFT_HAND) { + Audio_PlayActorSound2(&this->actor, NA_SE_EN_SHADEST_CLAP); + } + this->ready = true; + } else { + func_8002F974(&this->actor, NA_SE_EN_SHADEST_HAND_FLY - SFX_FLAG); + } + + this->actor.world.pos.x = (Math_SinS(this->actor.shape.rot.y) * this->radius) + sHead->actor.world.pos.x; + this->actor.world.pos.z = (Math_CosS(this->actor.shape.rot.y) * this->radius) + sHead->actor.world.pos.z; + } + } + + if (player->actor.parent == &this->actor) { + player->unk_850 = 0; + player->actor.world.pos = this->actor.world.pos; + } +} + +void BossSst_HandSetupEndClap(BossSst* this) { + this->targetYaw = this->actor.home.rot.y - (this->vParity * 0x1000); + Animation_MorphToPlayOnce(&this->skelAnime, sHandOpenPoses[this->actor.params], 10.0f); + this->colliderJntSph.base.atFlags &= ~(AT_ON | AT_HIT); + this->actionFunc = BossSst_HandEndClap; +} + +void BossSst_HandEndClap(BossSst* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + Math_ScaledStepToS(&this->actor.shape.rot.z, 0, 0x200); + if (Math_ScaledStepToS(&this->actor.shape.rot.y, this->targetYaw, 0x100)) { + BossSst_HandSetupRetreat(this); + } + this->actor.world.pos.x = (Math_SinS(this->actor.shape.rot.y) * this->radius) + sHead->actor.world.pos.x; + this->actor.world.pos.z = (Math_CosS(this->actor.shape.rot.y) * this->radius) + sHead->actor.world.pos.z; +} + +void BossSst_HandSetupReadyGrab(BossSst* this) { + HAND_STATE(this) = HAND_GRAB; + Animation_MorphToPlayOnce(&this->skelAnime, sHandOpenPoses[this->actor.params], 10.0f); + this->targetYaw = this->vParity * -0x5000; + this->targetRoll = this->vParity * 0x4000; + this->actionFunc = BossSst_HandReadyGrab; +} + +void BossSst_HandReadyGrab(BossSst* this, GlobalContext* globalCtx) { + s32 inPosition; + + SkelAnime_Update(&this->skelAnime); + inPosition = Math_SmoothStepToS(&this->actor.shape.rot.z, this->targetRoll, 4, 0x800, 0x100) == 0; + inPosition &= Math_ScaledStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer + this->targetYaw, 0xA00); + Math_ApproachF(&this->actor.world.pos.y, ROOM_CENTER_Y + 95.0f, 0.5f, 20.0f); + if (inPosition) { + BossSst_HandSetupGrab(this); + } +} + +void BossSst_HandSetupGrab(BossSst* this) { + Animation_MorphToPlayOnce(&this->skelAnime, sHandFistPoses[this->actor.params], 5.0f); + this->actor.world.rot.y = this->actor.shape.rot.y + (this->vParity * 0x4000); + this->targetYaw = this->actor.world.rot.y; + this->timer = 30; + this->actor.speedXZ = 0.5f; + BossSst_HandSetDamage(this, 0x20); + this->actionFunc = BossSst_HandGrab; +} + +void BossSst_HandGrab(BossSst* this, GlobalContext* globalCtx) { + Player* player = PLAYER; + + if (this->timer != 0) { + this->timer--; + } + + this->actor.world.rot.y = ((1.0f - sinf(this->timer * (M_PI / 60.0f))) * (this->vParity * 0x2000)) + this->targetYaw; + this->actor.shape.rot.y = this->actor.world.rot.y - (this->vParity * 0x4000); + if (this->timer < 5) { + Math_SmoothStepToF(&this->actor.speedXZ, 0.0f, 0.5f, 25.0f, 5.0f); + if (SkelAnime_Update(&this->skelAnime)) { + this->colliderJntSph.base.atFlags &= ~(AT_ON | AT_HIT); + this->actor.speedXZ = 0.0f; + if (player->stateFlags2 & 0x80) { + if (Rand_ZeroOne() < 0.5f) { + BossSst_HandSetupCrush(this); + } else { + BossSst_HandSetupSwing(this); + } + } else { + Item_DropCollectible(globalCtx, &this->actor.world.pos, + (Rand_ZeroOne() < 0.5f) ? ITEM00_ARROWS_SMALL : ITEM00_MAGIC_SMALL); + BossSst_HandSetupRetreat(this); + } + } + } else { + this->actor.speedXZ *= 1.26f; + this->actor.speedXZ = CLAMP_MAX(this->actor.speedXZ, 70.0f); + func_8002F974(&this->actor, NA_SE_EN_SHADEST_HAND_FLY - SFX_FLAG); + } + + if (this->colliderJntSph.base.atFlags & AT_HIT) { + this->colliderJntSph.base.atFlags &= ~(AT_ON | AT_HIT); + Audio_PlayActorSound2(&this->actor, NA_SE_EN_SHADEST_CATCH); + BossSst_HandGrabPlayer(this, globalCtx); + this->timer = CLAMP_MAX(this->timer, 5); + } + + this->actor.world.pos.x += this->actor.speedXZ * Math_SinS(this->actor.world.rot.y); + this->actor.world.pos.z += this->actor.speedXZ * Math_CosS(this->actor.world.rot.y); + if (player->stateFlags2 & 0x80) { + player->unk_850 = 0; + player->actor.world.pos = this->actor.world.pos; + player->actor.shape.rot.y = this->actor.shape.rot.y; + } +} + +void BossSst_HandSetupCrush(BossSst* this) { + Animation_MorphToLoop(&this->skelAnime, sHandClenchAnims[this->actor.params], -10.0f); + this->timer = 20; + this->actionFunc = BossSst_HandCrush; +} + +void BossSst_HandCrush(BossSst* this, GlobalContext* globalCtx) { + Player* player = PLAYER; + + SkelAnime_Update(&this->skelAnime); + if (this->timer != 0) { + this->timer--; + } + + if (!(player->stateFlags2 & 0x80)) { + BossSst_HandReleasePlayer(this, globalCtx, true); + BossSst_HandSetupEndCrush(this); + } else { + player->actor.world.pos = this->actor.world.pos; + if (this->timer == 0) { + this->timer = 20; + if (LINK_IS_CHILD) { + func_8002F7DC(&player->actor, NA_SE_VO_LI_DAMAGE_S_KID); + } else { + func_8002F7DC(&player->actor, NA_SE_VO_LI_DAMAGE_S); + } + + globalCtx->damagePlayer(globalCtx, -8); + } + if (Animation_OnFrame(&this->skelAnime, 0.0f)) { + Audio_PlayActorSound2(&this->actor, NA_SE_EN_SHADEST_CATCH); + } + } +} + +void BossSst_HandSetupEndCrush(BossSst* this) { + Animation_MorphToPlayOnce(&this->skelAnime, sHandFlatPoses[this->actor.params], 10.0f); + this->actionFunc = BossSst_HandEndCrush; +} + +void BossSst_HandEndCrush(BossSst* this, GlobalContext* globalCtx) { + if (SkelAnime_Update(&this->skelAnime)) { + BossSst_HandSetupRetreat(this); + } +} + +void BossSst_HandSetupSwing(BossSst* this) { + this->amplitude = -0x4000; + this->timer = 1; + this->center.x = this->actor.world.pos.x - (Math_SinS(this->actor.shape.rot.y) * 200.0f); + this->center.y = this->actor.world.pos.y; + this->center.z = this->actor.world.pos.z - (Math_CosS(this->actor.shape.rot.y) * 200.0f); + this->actionFunc = BossSst_HandSwing; +} + +void BossSst_HandSwing(BossSst* this, GlobalContext* globalCtx) { + Player* player = PLAYER; + f32 offXZ; + + if (Math_ScaledStepToS(&this->actor.shape.rot.x, this->amplitude, this->timer * 0xE4 + 0x1C8)) { + if (this->amplitude != 0) { + this->amplitude = 0; + if (this->timer == 4) { + Animation_MorphToPlayOnce(&this->skelAnime, sHandFlatPoses[this->actor.params], 4.0f); + } + } else { + if (this->timer == 4) { + player->actor.shape.rot.x = 0; + player->actor.shape.rot.z = 0; + BossSst_HandSetupRetreat(this); + return; + } + this->amplitude = (this->timer == 3) ? -0x6000 : -0x4000; + this->timer++; + } + } + + this->actor.world.pos.y = (Math_CosS(this->actor.shape.rot.x + 0x4000) * 200.0f) + this->center.y; + offXZ = Math_SinS(this->actor.shape.rot.x + 0x4000) * 200.0f; + this->actor.world.pos.x = (Math_SinS(this->actor.shape.rot.y) * offXZ) + this->center.x; + this->actor.world.pos.z = (Math_CosS(this->actor.shape.rot.y) * offXZ) + this->center.z; + if (this->timer != 4) { + this->actor.shape.rot.z = (this->actor.shape.rot.x + 0x4000) * this->vParity; + } else { + Math_ScaledStepToS(&this->actor.shape.rot.z, 0, 0x800); + } + + if (player->stateFlags2 & 0x80) { + player->unk_850 = 0; + Math_Vec3f_Copy(&player->actor.world.pos, &this->actor.world.pos); + player->actor.shape.rot.x = this->actor.shape.rot.x; + player->actor.shape.rot.z = (this->vParity * -0x4000) + this->actor.shape.rot.z; + } else { + Math_ScaledStepToS(&player->actor.shape.rot.x, 0, 0x600); + Math_ScaledStepToS(&player->actor.shape.rot.z, 0, 0x600); + player->actor.world.pos.x += 20.0f * Math_SinS(this->actor.shape.rot.y); + player->actor.world.pos.z += 20.0f * Math_CosS(this->actor.shape.rot.y); + } + + if ((this->timer == 4) && (this->amplitude == 0) && SkelAnime_Update(&this->skelAnime) && + (player->stateFlags2 & 0x80)) { + BossSst_HandReleasePlayer(this, globalCtx, false); + player->actor.world.pos.x += 70.0f * Math_SinS(this->actor.shape.rot.y); + player->actor.world.pos.z += 70.0f * Math_CosS(this->actor.shape.rot.y); + func_8002F71C(globalCtx, &this->actor, 15.0f, this->actor.shape.rot.y, 2.0f); + func_8002F7DC(&player->actor, NA_SE_PL_BODY_HIT); + } + + func_8002F974(&this->actor, NA_SE_EN_SHADEST_HAND_FLY - SFX_FLAG); +} + +void BossSst_HandSetupReel(BossSst* this) { + HAND_STATE(this) = HAND_DAMAGED; + Animation_MorphToPlayOnce(&this->skelAnime, sHandFlatPoses[this->actor.params], 4.0f); + this->timer = 36; + Math_Vec3f_Copy(&this->center, &this->actor.world.pos); + Actor_SetColorFilter(&this->actor, 0, 0xFF, 0, 200); + this->actionFunc = BossSst_HandReel; +} + +void BossSst_HandReel(BossSst* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + if (this->timer != 0) { + this->timer--; + } + + if (!(this->timer % 4)) { + if (this->timer % 8) { + Animation_MorphToPlayOnce(&this->skelAnime, sHandFlatPoses[this->actor.params], 4.0f); + } else { + Animation_MorphToPlayOnce(&this->skelAnime, sHandFistPoses[this->actor.params], 6.0f); + } + } + + this->actor.colorFilterTimer = 200; + this->actor.world.pos.x += Rand_CenteredFloat(20.0f); + this->actor.world.pos.y += Rand_CenteredFloat(20.0f); + this->actor.world.pos.z += Rand_CenteredFloat(20.0f); + + if (this->actor.world.pos.y < (this->actor.floorHeight + 100.0f)) { + Math_StepToF(&this->actor.world.pos.y, this->actor.floorHeight + 100.0f, 20.0f); + } + + if (this->timer == 0) { + BossSst_HandSetupReadyShake(this); + } +} + +void BossSst_HandSetupReadyShake(BossSst* this) { + Animation_MorphToPlayOnce(&this->skelAnime, sHandDamagePoses[this->actor.params], 8.0f); + this->actionFunc = BossSst_HandReadyShake; +} + +void BossSst_HandReadyShake(BossSst* this, GlobalContext* globalCtx) { + f32 diff; + s32 inPosition; + + diff = Math_SmoothStepToF(&this->actor.world.pos.x, this->actor.home.pos.x, 0.5f, 25.0f, 1.0f); + diff += Math_SmoothStepToF(&this->actor.world.pos.z, this->actor.home.pos.z, 0.5f, 25.0f, 1.0f); + diff += Math_SmoothStepToF(&this->actor.world.pos.y, this->actor.home.pos.y + 200.0f, 0.2f, 30.0f, 1.0f); + inPosition = Math_ScaledStepToS(&this->actor.shape.rot.x, 0x4000, 0x400); + inPosition &= Math_ScaledStepToS(&this->actor.shape.rot.z, 0, 0x1000); + inPosition &= Math_ScaledStepToS(&this->actor.shape.rot.y, this->actor.home.rot.y, 0x800); + inPosition &= Math_StepToS(&this->handZPosMod, -0x5DC, 0x1F4); + inPosition &= Math_ScaledStepToS(&this->handYRotMod, this->vParity * -0x2000, 0x800); + this->actor.colorFilterTimer = 200; + if ((diff < 30.0f) && inPosition) { + BossSst_HandSetupShake(this); + } else { + func_8002F974(&this->actor, NA_SE_EN_SHADEST_HAND_FLY - SFX_FLAG); + } +} + +void BossSst_HandSetupShake(BossSst* this) { + this->timer = 200; + this->actionFunc = BossSst_HandShake; +} + +void BossSst_HandShake(BossSst* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + if (this->timer != 0) { + this->timer--; + } + + this->actor.shape.rot.x = 0x4000 + (sinf(this->timer * (M_PI / 5)) * 0x2000); + this->handYRotMod = (this->vParity * -0x2000) + (sinf(this->timer * (M_PI / 4)) * 0x2800); + + if (!(this->timer % 8)) { + Audio_PlayActorSound2(&this->actor, NA_SE_EN_SHADEST_SHAKEHAND); + } + + if (HAND_STATE(OTHER_HAND(this)) == HAND_DAMAGED) { + if ((OTHER_HAND(this)->actionFunc == BossSst_HandShake) || + (OTHER_HAND(this)->actionFunc == BossSst_HandReadyCharge)) { + BossSst_HandSetupReadyCharge(this); + } else if (this->timer == 0) { + this->timer = 80; + } + } else if (this->timer == 0) { + this->actor.flags |= 1; + BossSst_HandSetupSlam(this); + } +} + +void BossSst_HandSetupReadyCharge(BossSst* this) { + Animation_MorphToPlayOnce(&this->skelAnime, sHandFistPoses[this->actor.params], 10.0f); + this->ready = false; + this->actionFunc = BossSst_HandReadyCharge; +} + +void BossSst_HandReadyCharge(BossSst* this, GlobalContext* globalCtx) { + if (!this->ready) { + this->ready = SkelAnime_Update(&this->skelAnime); + this->ready &= Math_ScaledStepToS(&this->actor.shape.rot.x, 0, 0x800); + this->ready &= + Math_ScaledStepToS(&this->actor.shape.rot.y, this->actor.home.rot.y + (this->vParity * 0x1000), 0x800); + this->ready &= Math_ScaledStepToS(&this->handYRotMod, 0, 0x800); + this->ready &= Math_ScaledStepToS(&this->actor.shape.rot.z, this->vParity * 0x2800, 0x800); + this->ready &= Math_StepToS(&this->handZPosMod, -0xDAC, 0x1F4); + if (this->ready) { + this->actor.colorFilterTimer = 0; + } + } else if (this->colliderJntSph.base.atFlags & AT_HIT) { + this->colliderJntSph.base.atFlags &= ~(AT_ON | AT_HIT); + OTHER_HAND(this)->colliderJntSph.base.atFlags &= ~(AT_ON | AT_HIT); + sHead->colliderJntSph.base.atFlags &= ~(AT_ON | AT_HIT); + func_8002F71C(globalCtx, &this->actor, 10.0f, this->actor.shape.rot.y, 5.0f); + func_8002F7DC(&PLAYER->actor, NA_SE_PL_BODY_HIT); + } +} + +void BossSst_HandSetupStunned(BossSst* hand) { + Animation_MorphToPlayOnce(&hand->skelAnime, sHandIdleAnims[hand->actor.params], 10.0f); + if (hand->actionFunc != BossSst_HandDamage) { + hand->ready = false; + } + + hand->colliderJntSph.base.atFlags &= ~(AT_ON | AT_HIT); + hand->colliderJntSph.base.acFlags |= AC_ON; + BossSst_HandSetInvulnerable(hand, true); + Actor_SetColorFilter(&hand->actor, 0, 0xFF, 0, Animation_GetLastFrame(&gBongoHeadKnockoutAnim)); + hand->actionFunc = BossSst_HandStunned; +} + +void BossSst_HandStunned(BossSst* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + Math_ApproachF(&this->actor.world.pos.z, (Math_CosS(sHead->actor.shape.rot.y) * 200.0f) + this->actor.home.pos.z, + 0.5f, 25.0f); + Math_ApproachF(&this->actor.world.pos.x, (Math_SinS(sHead->actor.shape.rot.y) * 200.0f) + this->actor.home.pos.x, + 0.5f, 25.0f); + if (!this->ready) { + Math_ScaledStepToS(&this->handYRotMod, 0, 0x800); + Math_StepToS(&this->handZPosMod, -0xDAC, 0x1F4); + Math_ScaledStepToS(&this->actor.shape.rot.x, this->actor.home.rot.x, 0x800); + Math_ScaledStepToS(&this->actor.shape.rot.z, this->actor.home.rot.z, 0x800); + Math_ScaledStepToS(&this->actor.shape.rot.y, this->actor.home.rot.y, 0x800); + if (sHead->actionFunc == BossSst_HeadVulnerable) { + this->ready = true; + Animation_MorphToPlayOnce(&this->skelAnime, sHandDamagePoses[this->actor.params], 10.0f); + } + } else { + Math_StepToF(&this->actor.world.pos.y, this->actor.floorHeight, 30.0f); + } +} + +void BossSst_HandSetupDamage(BossSst* hand) { + hand->actor.shape.rot.x = 0; + Animation_MorphToPlayOnce(&hand->skelAnime, sHandOpenPoses[hand->actor.params], 3.0f); + hand->timer = 6; + hand->actionFunc = BossSst_HandDamage; +} + +void BossSst_HandDamage(BossSst* this, GlobalContext* globalCtx) { + if (this->timer != 0) { + this->timer--; + } + + SkelAnime_Update(&this->skelAnime); + if (this->timer >= 2) { + this->actor.shape.rot.x -= 0x200; + Math_StepToF(&this->actor.world.pos.y, this->actor.floorHeight + 200.0f, 50.0f); + } else { + this->actor.shape.rot.x += 0x400; + Math_StepToF(&this->actor.world.pos.y, this->actor.floorHeight, 100.0f); + } + + if (this->timer == 0) { + if (this->actor.floorHeight >= 0.0f) { + Audio_PlayActorSound2(&this->actor, NA_SE_EN_SHADEST_TAIKO_HIGH); + } + BossSst_HandSetupStunned(this); + } +} + +void BossSst_HandSetupThrash(BossSst* this) { + HAND_STATE(this) = HAND_DEATH; + Animation_MorphToPlayOnce(&this->skelAnime, sHandOpenPoses[this->actor.params], 2.0f); + this->actor.shape.rot.x = 0; + this->timer = 160; + if (this->actor.params == BONGO_LEFT_HAND) { + this->amplitude = -0x800; + } else { + this->amplitude = 0; + this->actor.shape.rot.x = -0x800; + } + + this->handAngSpeed = 0x180; + this->actionFunc = BossSst_HandThrash; +} + +void BossSst_HandThrash(BossSst* this, GlobalContext* globalCtx) { + if (this->timer != 0) { + this->timer--; + } + + SkelAnime_Update(&this->skelAnime); + Math_ApproachF(&this->actor.world.pos.z, (Math_CosS(sHead->actor.shape.rot.y) * 200.0f) + this->actor.home.pos.z, + 0.5f, 25.0f); + Math_ApproachF(&this->actor.world.pos.x, (Math_SinS(sHead->actor.shape.rot.y) * 200.0f) + this->actor.home.pos.x, + 0.5f, 25.0f); + if (Math_ScaledStepToS(&this->actor.shape.rot.x, this->amplitude, this->handAngSpeed)) { + if (this->amplitude != 0) { + this->amplitude = 0; + Animation_MorphToPlayOnce(&this->skelAnime, sHandFlatPoses[this->actor.params], 5.0f); + } else { + Audio_PlayActorSound2(&this->actor, NA_SE_EN_SHADEST_TAIKO_HIGH); + this->amplitude = -0x800; + Animation_MorphToPlayOnce(&this->skelAnime, sHandOpenPoses[this->actor.params], 5.0f); + } + + if (this->timer < 80.0f) { + this->handAngSpeed -= 0x40; + this->handAngSpeed = CLAMP_MIN(this->handAngSpeed, 0x40); + } + } + + this->actor.world.pos.y = + (((this->handAngSpeed / 256.0f) + 0.5f) * 150.0f) * (-1.0f / 0x800) * this->actor.shape.rot.x; + if (this->timer == 0) { + BossSst_HandSetupDarken(this); + } +} + +void BossSst_HandSetupDarken(BossSst* this) { + Animation_MorphToPlayOnce(&this->skelAnime, sHandFlatPoses[this->actor.params], 5.0f); + this->actionFunc = BossSst_HandDarken; +} + +void BossSst_HandDarken(BossSst* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + Math_ScaledStepToS(&this->actor.shape.rot.x, -0x800, this->handAngSpeed); + Math_StepToF(&this->actor.world.pos.y, ROOM_CENTER_Y + 90.0f, 5.0f); + if (sHead->actionFunc == BossSst_HeadFall) { + BossSst_HandSetupFall(this); + } +} + +void BossSst_HandSetupFall(BossSst* this) { + Animation_MorphToPlayOnce(&this->skelAnime, sHandFlatPoses[this->actor.params], 3.0f); + this->actionFunc = BossSst_HandFall; +} + +void BossSst_HandFall(BossSst* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + Math_ScaledStepToS(&this->actor.shape.rot.x, 0, 0x400); + this->actor.world.pos.y = sHead->actor.world.pos.y + 230.0f; + if (sHead->actionFunc == BossSst_HeadMelt) { + BossSst_HandSetupMelt(this); + } +} + +void BossSst_HandSetupMelt(BossSst* this) { + BossSst_SpawnHandShadow(this); + this->actor.shape.shadowDraw = NULL; + this->timer = 80; + this->actionFunc = BossSst_HandMelt; +} + +void BossSst_HandMelt(BossSst* this, GlobalContext* globalCtx) { + if (this->timer != 0) { + this->timer--; + } + + this->actor.scale.y -= 0.00025f; + this->actor.scale.x += 0.000025f; + this->actor.scale.z += 0.000025f; + this->actor.world.pos.y = ROOM_CENTER_Y + 0.0f; + if (this->timer == 0) { + BossSst_HandSetupFinish(this); + } +} + +void BossSst_HandSetupFinish(BossSst* this) { + this->actor.draw = BossSst_DrawEffect; + this->timer = 20; + this->effects[0].status = 0; + this->actionFunc = BossSst_HandFinish; +} + +void BossSst_HandFinish(BossSst* this, GlobalContext* globalCtx) { + if (this->timer != 0) { + this->timer--; + } + + if (this->timer == 0) { + this->effectMode = BONGO_NULL; + } +} + +void BossSst_HandSetupRecover(BossSst* this) { + Animation_MorphToPlayOnce(&this->skelAnime, sHandPushoffPoses[this->actor.params], 10.0f); + this->ready = false; + this->actionFunc = BossSst_HandRecover; +} + +void BossSst_HandRecover(BossSst* this, GlobalContext* globalCtx) { + Math_SmoothStepToF(&this->actor.world.pos.y, ROOM_CENTER_Y + 250.0f, 0.5f, 70.0f, 5.0f); + if (SkelAnime_Update(&this->skelAnime)) { + if (!this->ready) { + Animation_MorphToPlayOnce(&this->skelAnime, sHandHangPoses[this->actor.params], 10.0f); + this->ready = true; + } + } + func_8002F974(&this->actor, NA_SE_EN_SHADEST_HAND_FLY - SFX_FLAG); +} + +void BossSst_HandSetupFrozen(BossSst* this) { + s32 i; + + HAND_STATE(this) = HAND_FROZEN; + Math_Vec3f_Copy(&this->center, &this->actor.world.pos); + BossSst_HandSetupReadyBreakIce(OTHER_HAND(this)); + this->ready = false; + this->effectMode = BONGO_ICE; + this->timer = 35; + for (i = 0; i < 18; i++) { + this->effects[i].move = false; + } + + BossSst_SpawnIceCrystal(this, 0); + Actor_SetColorFilter(&this->actor, 0, 0xFF, 0, 0xA); + this->handAngSpeed = 0; + this->actionFunc = BossSst_HandFrozen; +} + +void BossSst_HandFrozen(BossSst* this, GlobalContext* globalCtx) { + if (this->timer != 0) { + this->timer--; + } + + if ((this->timer % 2) != 0) { + BossSst_SpawnIceCrystal(this, (this->timer >> 1) + 1); + } + + if (this->ready) { + BossSst_IceShatter(this); + BossSst_HandSetupRetreat(this); + sHead->ready = true; + } else { + this->actor.colorFilterTimer = 10; + if (this->handAngSpeed != 0) { + f32 offY = Math_SinS(OTHER_HAND(this)->actor.shape.rot.x) * 5.0f; + f32 offXZ = Math_CosS(OTHER_HAND(this)->actor.shape.rot.x) * 5.0f; + + if ((this->handAngSpeed % 2) != 0) { + offY *= -1.0f; + offXZ *= -1.0f; + } + + this->actor.world.pos.x = this->center.x + (Math_CosS(OTHER_HAND(this)->actor.shape.rot.y) * offXZ); + this->actor.world.pos.y = this->center.y + offY; + this->actor.world.pos.z = this->center.z + (Math_SinS(OTHER_HAND(this)->actor.shape.rot.y) * offXZ); + this->handAngSpeed--; + } + } +} + +void BossSst_HandSetupReadyBreakIce(BossSst* this) { + HAND_STATE(this) = HAND_BREAK_ICE; + Animation_MorphToPlayOnce(&this->skelAnime, sHandFistPoses[this->actor.params], 5.0f); + this->ready = false; + this->actor.colorFilterTimer = 0; + if (this->effectMode == BONGO_ICE) { + this->effectMode = BONGO_NULL; + } + + this->radius = Actor_WorldDistXZToPoint(&this->actor, &OTHER_HAND(this)->center); + this->targetYaw = Actor_WorldYawTowardPoint(&this->actor, &OTHER_HAND(this)->center); + BossSst_HandSetInvulnerable(this, true); + this->actionFunc = BossSst_HandReadyBreakIce; +} + +void BossSst_HandReadyBreakIce(BossSst* this, GlobalContext* globalCtx) { + s32 inPosition; + + inPosition = Math_ScaledStepToS(&this->actor.shape.rot.y, this->targetYaw, 0x400); + inPosition &= Math_ScaledStepToS(&this->actor.shape.rot.x, 0x1000, 0x400); + inPosition &= Math_ScaledStepToS(&this->actor.shape.rot.z, 0, 0x800); + inPosition &= Math_ScaledStepToS(&this->handYRotMod, 0, 0x400); + inPosition &= Math_StepToF(&this->actor.world.pos.y, OTHER_HAND(this)->center.y + 200.0f, 50.0f); + inPosition &= Math_StepToF(&this->radius, 400.0f, 60.0f); + this->actor.world.pos.x = OTHER_HAND(this)->center.x - (Math_SinS(this->targetYaw) * this->radius); + this->actor.world.pos.z = OTHER_HAND(this)->center.z - (Math_CosS(this->targetYaw) * this->radius); + if (SkelAnime_Update(&this->skelAnime) && inPosition) { + BossSst_HandSetupBreakIce(this); + } +} + +void BossSst_HandSetupBreakIce(BossSst* this) { + this->timer = 9; + this->actionFunc = BossSst_HandBreakIce; + this->actor.speedXZ = 0.5f; +} + +void BossSst_HandBreakIce(BossSst* this, GlobalContext* globalCtx) { + if ((this->timer % 2) != 0) { + this->actor.speedXZ *= 1.5f; + this->actor.speedXZ = CLAMP_MAX(this->actor.speedXZ, 60.0f); + + if (Math_StepToF(&this->radius, 100.0f, this->actor.speedXZ)) { + BossSst_SpawnIceShard(this); + if (this->timer != 0) { + this->timer--; + } + + if (this->timer != 0) { + Audio_PlayActorSound2(&this->actor, NA_SE_EV_ICE_BROKEN); + } + + OTHER_HAND(this)->handAngSpeed = 5; + } + } else { + this->actor.speedXZ *= 0.8f; + Math_StepToF(&this->radius, 500.0f, this->actor.speedXZ); + if (this->actor.speedXZ < 2.0f) { + if (this->timer != 0) { + this->timer--; + } + } + } + + this->actor.world.pos.x = OTHER_HAND(this)->center.x - (Math_SinS(this->targetYaw) * this->radius); + this->actor.world.pos.z = OTHER_HAND(this)->center.z - (Math_CosS(this->targetYaw) * this->radius); + this->actor.world.pos.y = OTHER_HAND(this)->center.y + (this->radius * 0.4f); + if (this->timer == 0) { + OTHER_HAND(this)->ready = true; + BossSst_HandSetupRetreat(this); + } + + func_8002F974(&this->actor, NA_SE_EN_SHADEST_HAND_FLY - SFX_FLAG); +} + +void BossSst_HandGrabPlayer(BossSst* this, GlobalContext* globalCtx) { + Player* player = PLAYER; + + if (globalCtx->grabPlayer(globalCtx, player)) { + player->actor.parent = &this->actor; + if (player->actor.colChkInfo.health > 0) { + this->colliderJntSph.base.ocFlags1 &= ~OC1_ON; + if (HAND_STATE(this) == HAND_CLAP) { + OTHER_HAND(this)->colliderJntSph.base.ocFlags1 &= ~OC1_ON; + } + } + } +} + +void BossSst_HandReleasePlayer(BossSst* this, GlobalContext* globalCtx, s32 dropPlayer) { + Player* player = PLAYER; + + if (player->actor.parent == &this->actor) { + player->actor.parent = NULL; + player->unk_850 = 100; + this->colliderJntSph.base.ocFlags1 |= OC1_ON; + OTHER_HAND(this)->colliderJntSph.base.ocFlags1 |= OC1_ON; + if (dropPlayer) { + func_8002F71C(globalCtx, &this->actor, 0.0f, this->actor.shape.rot.y, 0.0f); + } + } +} + +void BossSst_MoveAround(BossSst* this) { + BossSst* hand; + Vec3f* vec; + f32 sn; + f32 cs; + s32 i; + + sn = Math_SinS(this->actor.shape.rot.y); + cs = Math_CosS(this->actor.shape.rot.y); + if (this->actionFunc != BossSst_HeadEndCharge) { + this->actor.world.pos.x = sRoomCenter.x + (this->radius * sn); + this->actor.world.pos.z = sRoomCenter.z + (this->radius * cs); + } + + for (i = 0; i < 2; i++) { + hand = sHands[i]; + vec = &sHandOffsets[i]; + + hand->actor.world.pos.x = this->actor.world.pos.x + (vec->z * sn) + (vec->x * cs); + hand->actor.world.pos.y = this->actor.world.pos.y + vec->y; + hand->actor.world.pos.z = this->actor.world.pos.z + (vec->z * cs) - (vec->x * sn); + + hand->actor.home.pos.x = this->actor.world.pos.x + (400.0f * sn) + (-200.0f * hand->vParity * cs); + hand->actor.home.pos.y = this->actor.world.pos.y; + hand->actor.home.pos.z = this->actor.world.pos.z + (400.0f * cs) - (-200.0f * hand->vParity * sn); + + hand->actor.home.rot.y = this->actor.shape.rot.y; + hand->actor.shape.rot.y = sHandYawOffsets[i] + this->actor.shape.rot.y; + + if (hand->actor.world.pos.y < hand->actor.floorHeight) { + hand->actor.world.pos.y = hand->actor.floorHeight; + } + } +} + +void BossSst_HandSelectAttack(BossSst* this) { + f32 rand = Rand_ZeroOne() * 6.0f; + s32 randInt; + + if (HAND_STATE(OTHER_HAND(this)) == HAND_DAMAGED) { + rand *= 5.0f / 6; + if (rand > 4.0f) { + rand = 4.0f; + } + } + + randInt = rand; + if (randInt == 0) { + BossSst_HandSetupReadySlam(this); + } else if (randInt == 1) { + BossSst_HandSetupReadySweep(this); + } else if (randInt == 2) { + BossSst_HandSetupReadyPunch(this); + } else if (randInt == 5) { + BossSst_HandSetupReadyClap(this); + } else { // randInt == 3 || randInt == 4 + BossSst_HandSetupReadyGrab(this); + } +} + +void BossSst_HandSetDamage(BossSst* this, s32 damage) { + s32 i; + + this->colliderJntSph.base.atFlags |= AT_ON; + for (i = 0; i < 11; i++) { + this->colliderJntSph.elements[i].info.toucher.damage = damage; + } +} + +void BossSst_HandSetInvulnerable(BossSst* this, s32 isInv) { + this->colliderJntSph.base.acFlags &= ~AC_HIT; + if (isInv) { + this->colliderJntSph.base.colType = COLTYPE_HARD; + this->colliderJntSph.base.acFlags |= AC_HARD; + } else { + this->colliderJntSph.base.colType = COLTYPE_HIT0; + this->colliderJntSph.base.acFlags &= ~AC_HARD; + } +} + +void BossSst_HeadSfx(BossSst* this, u16 sfxId) { + func_80078914(&this->center, sfxId); +} + +void BossSst_HandCollisionCheck(BossSst* this, GlobalContext* globalCtx) { + if ((this->colliderJntSph.base.acFlags & AC_HIT) && (this->colliderJntSph.base.colType != COLTYPE_HARD)) { + s32 bothHands = true; + + this->colliderJntSph.base.acFlags &= ~AC_HIT; + if ((this->actor.colChkInfo.damageEffect != 0) || (this->actor.colChkInfo.damage != 0)) { + this->colliderJntSph.base.atFlags &= ~(AT_ON | AT_HIT); + this->colliderJntSph.base.acFlags &= ~AC_ON; + this->colliderJntSph.base.ocFlags1 &= ~OC1_NO_PUSH; + BossSst_HandReleasePlayer(this, globalCtx, true); + if (HAND_STATE(OTHER_HAND(this)) == HAND_CLAP) { + BossSst_HandReleasePlayer(OTHER_HAND(this), globalCtx, true); + BossSst_HandSetupRetreat(OTHER_HAND(this)); + } + + this->actor.flags &= ~1; + if (this->actor.colChkInfo.damageEffect == 3) { + BossSst_HandSetupFrozen(this); + } else { + BossSst_HandSetupReel(this); + if (HAND_STATE(OTHER_HAND(this)) != HAND_DAMAGED) { + bothHands = false; + } + } + + BossSst_HeadSetupDamagedHand(sHead, bothHands); + Item_DropCollectible(globalCtx, &this->actor.world.pos, + (Rand_ZeroOne() < 0.5f) ? ITEM00_ARROWS_SMALL : ITEM00_MAGIC_SMALL); + Audio_PlayActorSound2(&this->actor, NA_SE_EN_SHADEST_DAMAGE_HAND); + } + } +} + +void BossSst_HeadCollisionCheck(BossSst* this, GlobalContext* globalCtx) { + if (this->colliderCyl.base.acFlags & AC_HIT) { + this->colliderCyl.base.acFlags &= ~AC_HIT; + if ((this->actor.colChkInfo.damageEffect != 0) || (this->actor.colChkInfo.damage != 0)) { + if (this->actionFunc == BossSst_HeadVulnerable) { + if (Actor_ApplyDamage(&this->actor) == 0) { + func_80032C7C(globalCtx, &this->actor); + BossSst_HeadSetupDeath(this, globalCtx); + } else { + BossSst_HeadSetupDamage(this); + } + + BossSst_HandSetupDamage(sHands[LEFT]); + BossSst_HandSetupDamage(sHands[RIGHT]); + } else { + BossSst_HeadSetupStunned(this); + if (HAND_STATE(sHands[RIGHT]) == HAND_FROZEN) { + BossSst_IceShatter(sHands[RIGHT]); + } else if (HAND_STATE(sHands[LEFT]) == HAND_FROZEN) { + BossSst_IceShatter(sHands[LEFT]); + } + + BossSst_HandSetupStunned(sHands[RIGHT]); + BossSst_HandSetupStunned(sHands[LEFT]); + } + } + } +} + +void BossSst_UpdateHand(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + BossSst* this = THIS; + BossSstHandTrail* trail; + + if (this->colliderCyl.base.atFlags & AT_ON) { + if ((this->effects[0].move < 5) || + (this->actor.xzDistToPlayer < ((this->effects[2].scale * 0.01f) * sCylinderInitHand.dim.radius)) || + (this->colliderCyl.base.atFlags & AT_HIT)) { + this->colliderCyl.base.atFlags &= ~(AT_ON | AT_HIT); + } else { + this->colliderCyl.dim.radius = (this->effects[0].scale * 0.01f) * sCylinderInitHand.dim.radius; + } + } + + BossSst_HandCollisionCheck(this, globalCtx); + this->actionFunc(this, globalCtx); + Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 50.0f, 130.0f, 0.0f, 5); + Actor_SetFocus(&this->actor, 0.0f); + if (this->colliderJntSph.base.atFlags & AT_ON) { + CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->colliderJntSph.base); + } + + if ((sHead->actionFunc != BossSst_HeadLurk) && (sHead->actionFunc != BossSst_HeadIntro) && + (this->colliderJntSph.base.acFlags & AC_ON)) { + CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->colliderJntSph.base); + } + + if (this->colliderJntSph.base.ocFlags1 & OC1_ON) { + CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->colliderJntSph.base); + } + + if (this->colliderCyl.base.atFlags & AT_ON) { + CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->colliderCyl.base); + } + + if ((HAND_STATE(this) != HAND_DEATH) && (HAND_STATE(this) != HAND_WAIT) && (HAND_STATE(this) != HAND_BEAT) && + (HAND_STATE(this) != HAND_FROZEN)) { + this->trailCount++; + this->trailCount = CLAMP_MAX(this->trailCount, 7); + } else { + this->trailCount--; + this->trailCount = CLAMP_MIN(this->trailCount, 0); + } + + trail = &this->handTrails[this->trailIndex]; + Math_Vec3f_Copy(&trail->world.pos, &this->actor.world.pos); + trail->world.rot = this->actor.shape.rot; + trail->zPosMod = this->handZPosMod; + trail->yRotMod = this->handYRotMod; + + this->trailIndex = (this->trailIndex + 1) % 7; + BossSst_UpdateEffect(&this->actor, globalCtx); +} + +void BossSst_UpdateHead(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + BossSst* this = THIS; + + func_8002DBD0(&this->actor, &sHandOffsets[RIGHT], &sHands[RIGHT]->actor.world.pos); + func_8002DBD0(&this->actor, &sHandOffsets[LEFT], &sHands[LEFT]->actor.world.pos); + + sHandYawOffsets[LEFT] = sHands[LEFT]->actor.shape.rot.y - thisx->shape.rot.y; + sHandYawOffsets[RIGHT] = sHands[RIGHT]->actor.shape.rot.y - thisx->shape.rot.y; + + BossSst_HeadCollisionCheck(this, globalCtx); + this->actionFunc(this, globalCtx); + if (this->vVanish) { + if ((globalCtx->actorCtx.unk_03 == 0) || (thisx->colorFilterTimer != 0)) { + this->actor.flags &= ~0x80; + } else { + this->actor.flags |= 0x80; + } + } + + if (this->colliderJntSph.base.atFlags & AT_ON) { + CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->colliderJntSph.base); + } + + if ((this->actionFunc != BossSst_HeadLurk) && (this->actionFunc != BossSst_HeadIntro)) { + if (this->colliderCyl.base.acFlags & AC_ON) { + CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->colliderCyl.base); + } + CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->colliderJntSph.base); + } + + if (this->colliderJntSph.base.ocFlags1 & OC1_ON) { + CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->colliderJntSph.base); + } + + BossSst_MoveAround(this); + if ((!this->vVanish || ((this->actor.flags & 0x80) == 0x80)) && + ((this->actionFunc == BossSst_HeadReadyCharge) || (this->actionFunc == BossSst_HeadCharge) || + (this->actionFunc == BossSst_HeadFrozenHand) || (this->actionFunc == BossSst_HeadStunned) || + (this->actionFunc == BossSst_HeadVulnerable) || (this->actionFunc == BossSst_HeadDamage))) { + this->actor.flags |= 1; + } else { + this->actor.flags &= ~1; + } + + if (this->actionFunc == BossSst_HeadCharge) { + BossSst_HeadSfx(this, NA_SE_EN_SHADEST_MOVE - SFX_FLAG); + } + + BossSst_UpdateEffect(&this->actor, globalCtx); +} + +s32 BossSst_OverrideHandDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, + void* thisx) { + BossSst* this = THIS; + + if (limbIndex == 1) { + pos->z += this->handZPosMod; + rot->y += this->handYRotMod; + } + return false; +} + +void BossSst_PostHandDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) { + BossSst* this = THIS; + + Collider_UpdateSpheres(limbIndex, &this->colliderJntSph); +} + +s32 BossSst_OverrideHandTrailDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, + void* data, Gfx** gfx) { + BossSstHandTrail* trail = (BossSstHandTrail*)data; + + if (limbIndex == 1) { + pos->z += trail->zPosMod; + rot->y += trail->yRotMod; + } + return false; +} + +void BossSst_DrawHand(Actor* thisx, GlobalContext* globalCtx) { + BossSst* this = THIS; + + OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_sst.c", 6563); + + func_80093D18(globalCtx->state.gfxCtx); + + gDPSetPrimColor(POLY_OPA_DISP++, 0x00, 0x80, sBodyColor.r, sBodyColor.g, sBodyColor.b, 255); + + if (!sBodyStatic) { + gSPSegment(POLY_OPA_DISP++, 0x08, &D_80116280[2]); + } else { + gDPSetEnvColor(POLY_OPA_DISP++, sStaticColor.r, sStaticColor.g, sStaticColor.b, 0); + gSPSegment(POLY_OPA_DISP++, 0x08, sBodyStaticDList); + } + + SkelAnime_DrawFlexOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount, + BossSst_OverrideHandDraw, BossSst_PostHandDraw, this); + if (this->trailCount >= 2) { + BossSstHandTrail* trail; + BossSstHandTrail* trail2; + s32 i; + s32 idx; + s32 end; + s32 pad; + + func_80093D84(globalCtx->state.gfxCtx); + + end = this->trailCount >> 1; + idx = (this->trailIndex + 4) % 7; + trail = &this->handTrails[idx]; + trail2 = &this->handTrails[(idx + 2) % 7]; + + for (i = 0; i < end; i++) { + if (Math3D_Vec3fDistSq(&trail2->world.pos, &trail->world.pos) > 900.0f) { + func_800D1694(trail->world.pos.x, trail->world.pos.y, trail->world.pos.z, &trail->world.rot); + Matrix_Scale(0.02f, 0.02f, 0.02f, MTXMODE_APPLY); + + gSPSegment(POLY_XLU_DISP++, 0x08, sHandTrailDList); + gDPSetPrimColor(POLY_XLU_DISP++, 0x00, 0x00, ((3 - i) * 10) + 20, 0, ((3 - i) * 20) + 50, + ((3 - i) * 30) + 70); + + POLY_XLU_DISP = SkelAnime_DrawFlex(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, + this->skelAnime.dListCount, BossSst_OverrideHandTrailDraw, NULL, + trail, POLY_XLU_DISP); + } + idx = (idx + 5) % 7; + trail2 = trail; + trail = &this->handTrails[idx]; + } + } + + CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_sst.c", 6654); + + BossSst_DrawEffect(&this->actor, globalCtx); +} + +s32 BossSst_OverrideHeadDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, void* thisx, + Gfx** gfx) { + BossSst* this = THIS; + s32 shakeAmp; + s32 pad; + s32 timer12; + f32 shakeMod; + + if (((this->actor.flags & 0x80) != 0x80) && this->vVanish) { + *dList = NULL; + } else if (this->actionFunc == BossSst_HeadThrash) { // Animation modifications for death cutscene + shakeAmp = (this->timer / 10) + 1; + if ((limbIndex == 3) || (limbIndex == 39) || (limbIndex == 42)) { + + shakeMod = sinf(this->timer * (M_PI / 5)); + rot->x += ((0x500 * Rand_ZeroOne() + 0xA00) / 0x10) * shakeAmp * shakeMod; + + shakeMod = sinf((this->timer % 5) * (M_PI / 5)); + rot->z -= ((0x800 * Rand_ZeroOne() + 0x1000) / 0x10) * shakeAmp * shakeMod + 0x1000; + + if (limbIndex == 3) { + + shakeMod = sinf(this->timer * (M_PI / 5)); + rot->y += ((0x500 * Rand_ZeroOne() + 0xA00) / 0x10) * shakeAmp * shakeMod; + } + } else if ((limbIndex == 5) || (limbIndex == 6)) { + + shakeMod = sinf((this->timer % 5) * (M_PI / 5)); + rot->z -= ((0x280 * Rand_ZeroOne() + 0x500) / 0x10) * shakeAmp * shakeMod + 0x500; + + if (limbIndex == 5) { + + shakeMod = sinf(this->timer * (M_PI / 5)); + rot->x += ((0x500 * Rand_ZeroOne() + 0xA00) / 0x10) * shakeAmp * shakeMod; + + shakeMod = sinf(this->timer * (M_PI / 5)); + rot->y += ((0x500 * Rand_ZeroOne() + 0xA00) / 0x10) * shakeAmp * shakeMod; + } + } else if (limbIndex == 2) { + shakeMod = sinf(this->timer * (M_PI / 5)); + rot->x += ((0x200 * Rand_ZeroOne() + 0x400) / 0x10) * shakeAmp * shakeMod; + + shakeMod = sinf(this->timer * (M_PI / 5)); + rot->y += ((0x200 * Rand_ZeroOne() + 0x400) / 0x10) * shakeAmp * shakeMod; + + shakeMod = sinf((this->timer % 5) * (M_PI / 5)); + rot->z -= ((0x100 * Rand_ZeroOne() + 0x200) / 0x10) * shakeAmp * shakeMod + 0x200; + } + } else if (this->actionFunc == BossSst_HeadDeath) { + if (this->timer > 48) { + timer12 = this->timer - 36; + } else { + pad = ((this->timer > 6) ? 6 : this->timer); + timer12 = pad * 2; + } + + if ((limbIndex == 3) || (limbIndex == 39) || (limbIndex == 42)) { + rot->z -= 0x2000 * sinf(timer12 * (M_PI / 24)); + } else if ((limbIndex == 5) || (limbIndex == 6)) { + rot->z -= 0xA00 * sinf(timer12 * (M_PI / 24)); + } else if (limbIndex == 2) { + rot->z -= 0x400 * sinf(timer12 * (M_PI / 24)); + } + } else if ((this->actionFunc == BossSst_HeadDarken) || (this->actionFunc == BossSst_HeadFall) || + (this->actionFunc == BossSst_HeadMelt)) { + if ((limbIndex == 3) || (limbIndex == 39) || (limbIndex == 42)) { + rot->z -= 0x1000; + } else if ((limbIndex == 5) || (limbIndex == 6)) { + rot->z -= 0x500; + } else if (limbIndex == 2) { + rot->z -= 0x200; + } + } + return false; +} + +void BossSst_PostHeadDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx, Gfx** gfx) { + static Vec3f zeroVec = { 0.0f, 0.0f, 0.0f }; + static Vec3f headVec = { 1000.0f, 0.0f, 0.0f }; + BossSst* this = THIS; + Vec3f headPos; + + if (limbIndex == 8) { + Matrix_MultVec3f(&zeroVec, &this->actor.focus.pos); + Matrix_MultVec3f(&headVec, &headPos); + this->colliderCyl.dim.pos.x = headPos.x; + this->colliderCyl.dim.pos.y = headPos.y; + this->colliderCyl.dim.pos.z = headPos.z; + } + + Collider_UpdateSpheres(limbIndex, &this->colliderJntSph); +} + +void BossSst_DrawHead(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + BossSst* this = THIS; + + OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_sst.c", 6810); + + if ((this->actor.flags & 0x80) != 0x80) { + func_80093D18(globalCtx->state.gfxCtx); + gDPSetPrimColor(POLY_OPA_DISP++, 0x00, 0x80, sBodyColor.r, sBodyColor.g, sBodyColor.b, 255); + if (!sBodyStatic) { + gSPSegment(POLY_OPA_DISP++, 0x08, &D_80116280[2]); + } else { + gDPSetEnvColor(POLY_OPA_DISP++, sStaticColor.r, sStaticColor.g, sStaticColor.b, 0); + gSPSegment(POLY_OPA_DISP++, 0x08, sBodyStaticDList); + } + } else { + func_80093D84(globalCtx->state.gfxCtx); + gDPSetPrimColor(POLY_XLU_DISP++, 0x00, 0x80, 255, 255, 255, 255); + gSPSegment(POLY_XLU_DISP++, 0x08, &D_80116280[2]); + } + + if (this->actionFunc == BossSst_HeadThrash) { + f32 randPitch = Rand_ZeroOne() * (2 * M_PI); + f32 randYaw = Rand_ZeroOne() * (2 * M_PI); + + Matrix_RotateY(randYaw, MTXMODE_APPLY); + Matrix_RotateX(randPitch, MTXMODE_APPLY); + Matrix_Scale((this->timer * 0.000375f) + 1.0f, 1.0f - (this->timer * 0.00075f), + (this->timer * 0.000375f) + 1.0f, MTXMODE_APPLY); + Matrix_RotateX(-randPitch, MTXMODE_APPLY); + Matrix_RotateY(-randYaw, MTXMODE_APPLY); + } + + if ((this->actor.flags & 0x80) != 0x80) { + POLY_OPA_DISP = SkelAnime_DrawFlex(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, + this->skelAnime.dListCount, BossSst_OverrideHeadDraw, BossSst_PostHeadDraw, + this, POLY_OPA_DISP); + } else { + POLY_XLU_DISP = SkelAnime_DrawFlex(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, + this->skelAnime.dListCount, BossSst_OverrideHeadDraw, BossSst_PostHeadDraw, + this, POLY_XLU_DISP); + } + + if ((this->actionFunc == BossSst_HeadIntro) && (113 >= this->timer) && (this->timer > 20)) { + s32 yOffset; + Vec3f vanishMaskPos; + Vec3f vanishMaskOffset; + + func_80093D84(globalCtx->state.gfxCtx); + gDPSetPrimColor(POLY_XLU_DISP++, 0x00, 0x00, 0, 0, 18, 255); + + yOffset = 113 * 8 - this->timer * 8; + vanishMaskPos.x = ROOM_CENTER_X + 85.0f; + vanishMaskPos.y = ROOM_CENTER_Y - 250.0f + yOffset; + vanishMaskPos.z = ROOM_CENTER_Z + 190.0f; + if (vanishMaskPos.y > 450.0f) { + vanishMaskPos.y = 450.0f; + } + + Matrix_MultVec3fExt(&vanishMaskPos, &vanishMaskOffset, &globalCtx->mf_11DA0); + Matrix_Translate(this->actor.world.pos.x + vanishMaskOffset.x, this->actor.world.pos.y + vanishMaskOffset.y, + this->actor.world.pos.z + vanishMaskOffset.z, MTXMODE_NEW); + Matrix_Scale(1.0f, 1.0f, 1.0f, MTXMODE_APPLY); + + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_sst.c", 6934), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_XLU_DISP++, sIntroVanishDList); + } + + CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_sst.c", 6941); + + SkinMatrix_Vec3fMtxFMultXYZ(&globalCtx->mf_11D60, &this->actor.focus.pos, &this->center); + BossSst_DrawEffect(&this->actor, globalCtx); +} + +void BossSst_SpawnHeadShadow(BossSst* this) { + static Vec3f shadowOffset[] = { + { 0.0f, 0.0f, 340.0f }, + { -160.0f, 0.0f, 250.0f }, + { 160.0f, 0.0f, 250.0f }, + }; + s32 pad; + s32 i; + f32 sn; + f32 cs; + + this->effectMode = BONGO_SHADOW; + sn = Math_SinS(this->actor.shape.rot.y); + cs = Math_CosS(this->actor.shape.rot.y); + + for (i = 0; i < 3; i++) { + BossSstEffect* shadow = &this->effects[i]; + Vec3f* offset = &shadowOffset[i]; + + shadow->pos.x = this->actor.world.pos.x + (sn * offset->z) + (cs * offset->x); + shadow->pos.y = 0.0f; + shadow->pos.z = this->actor.world.pos.z + (cs * offset->z) - (sn * offset->x); + + shadow->scale = 1450; + shadow->alpha = 254; + shadow->status = 65; + } + + this->effects[3].status = -1; +} + +void BossSst_SpawnHandShadow(BossSst* this) { + this->effectMode = BONGO_SHADOW; + this->effects[0].pos.x = this->actor.world.pos.x + (Math_CosS(this->actor.shape.rot.y) * 30.0f * this->vParity); + this->effects[0].pos.z = this->actor.world.pos.z - (Math_SinS(this->actor.shape.rot.y) * 30.0f * this->vParity); + this->effects[0].pos.y = this->actor.world.pos.y; + this->effects[0].scale = 2300; + this->effects[0].alpha = 254; + this->effects[0].status = 5; + this->effects[1].status = -1; +} + +void BossSst_SpawnShockwave(BossSst* this) { + s32 i; + s32 scale = 120; + s32 alpha = 250; + + Audio_PlayActorSound2(&this->actor, NA_SE_EN_SHADEST_HAND_WAVE); + this->effectMode = BONGO_SHOCKWAVE; + + for (i = 0; i < 3; i++) { + BossSstEffect* shockwave = &this->effects[i]; + + Math_Vec3f_Copy(&shockwave->pos, &this->actor.world.pos); + shockwave->move = (i + 9) * 2; + shockwave->scale = scale; + shockwave->alpha = alpha / shockwave->move; + scale -= 50; + alpha -= 25; + } +} + +void BossSst_SpawnIceCrystal(BossSst* this, s32 index) { + BossSstEffect* ice = &this->effects[index]; + Sphere16* sphere; + + if (index < 11) { + sphere = &this->colliderJntSph.elements[index].dim.worldSphere; + + ice->pos.x = sphere->center.x; + ice->pos.y = sphere->center.y; + ice->pos.z = sphere->center.z; + if (index == 0) { + ice->pos.x -= 25.0f; + ice->pos.y -= 25.0f; + ice->pos.z -= 25.0f; + } + } else { + sphere = &this->colliderJntSph.elements[0].dim.worldSphere; + + ice->pos.x = ((((index - 11) & 1) ? 1 : -1) * 25.0f) + sphere->center.x; + ice->pos.y = ((((index - 11) & 2) ? 1 : -1) * 25.0f) + sphere->center.y; + ice->pos.z = ((((index - 11) & 4) ? 1 : -1) * 25.0f) + sphere->center.z; + } + + ice->pos.x -= this->actor.world.pos.x; + ice->pos.y -= this->actor.world.pos.y; + ice->pos.z -= this->actor.world.pos.z; + + ice->status = 0; + + ice->rot.x = Rand_ZeroOne() * 0x10000; + ice->rot.y = Rand_ZeroOne() * 0x10000; + ice->rot.z = Rand_ZeroOne() * 0x10000; + + ice->alpha = 120; + ice->move = true; + + ice->vel.x = (Rand_ZeroOne() * 0.06f + 0.12f) * ice->pos.x; + ice->vel.y = (Rand_ZeroOne() * 15.0f + 5.0f); + ice->vel.z = (Rand_ZeroOne() * 0.06f + 0.12f) * ice->pos.z; + ice->scale = 4000; + + if ((index % 2) == 0) { + Audio_PlayActorSound2(&this->actor, NA_SE_PL_FREEZE_S); + } +} + +void BossSst_SpawnIceShard(BossSst* this) { + s32 i; + Vec3f spawnPos; + f32 offXZ; + + this->effectMode = BONGO_ICE; + offXZ = Math_CosS(this->actor.shape.rot.x) * 50.0f; + spawnPos.x = Math_CosS(this->actor.shape.rot.y) * offXZ + this->actor.world.pos.x; + spawnPos.y = Math_SinS(this->actor.shape.rot.x) * 50.0f + this->actor.world.pos.y - 10.0f; + spawnPos.z = Math_SinS(this->actor.shape.rot.y) * offXZ + this->actor.world.pos.z; + + for (i = 0; i < 18; i++) { + BossSstEffect* ice = &this->effects[i]; + + Math_Vec3f_Copy(&ice->pos, &spawnPos); + ice->status = 1; + ice->rot.x = Rand_ZeroOne() * 0x10000; + ice->rot.y = Rand_ZeroOne() * 0x10000; + ice->rot.z = Rand_ZeroOne() * 0x10000; + + ice->alpha = 120; + ice->move = true; + + ice->vel.x = Rand_CenteredFloat(20.0f); + ice->vel.y = Rand_ZeroOne() * 10.0f + 3.0f; + ice->vel.z = Rand_CenteredFloat(20.0f); + + ice->scale = Rand_ZeroOne() * 200.0f + 400.0f; + } +} + +void BossSst_IceShatter(BossSst* this) { + s32 i; + + this->effects[0].status = 1; + Audio_PlayActorSound2(&this->actor, NA_SE_PL_ICE_BROKEN); + + for (i = 0; i < 18; i++) { + BossSstEffect* ice = &this->effects[i]; + + if (ice->move) { + ice->pos.x += this->actor.world.pos.x; + ice->pos.y += this->actor.world.pos.y; + ice->pos.z += this->actor.world.pos.z; + } + } +} + +void BossSst_UpdateEffect(Actor* thisx, GlobalContext* globalCtx) { + BossSst* this = THIS; + BossSstEffect* effect; + s32 i; + + if (this->effectMode != BONGO_NULL) { + if (this->effectMode == BONGO_ICE) { + if (this->effects[0].status) { + for (i = 0; i < 18; i++) { + effect = &this->effects[i]; + + if (effect->move) { + effect->pos.x += effect->vel.x; + effect->pos.y += effect->vel.y; + effect->pos.z += effect->vel.z; + effect->alpha -= 3; + effect->vel.y -= 1.0f; + effect->rot.x += 0xD00; + effect->rot.y += 0x1100; + effect->rot.z += 0x1500; + } + } + } + if (this->effects[0].alpha == 0) { + this->effectMode = BONGO_NULL; + } + } else if (this->effectMode == BONGO_SHOCKWAVE) { + for (i = 0; i < 3; i++) { + BossSstEffect* effect2 = &this->effects[i]; + s32 scale = effect2->move * 2; + + effect2->scale += CLAMP_MAX(scale, 20) + i; + if (effect2->move != 0) { + effect2->move--; + } + } + + if (this->effects[0].move == 0) { + this->effectMode = BONGO_NULL; + } + } else if (this->effectMode == BONGO_SHADOW) { + effect = &this->effects[0]; + + if (this->actor.params == BONGO_HEAD) { + SkinMatrix_Vec3fMtxFMultXYZ(&globalCtx->mf_11D60, &this->actor.focus.pos, &this->center); + BossSst_HeadSfx(this, NA_SE_EN_SHADEST_LAST - SFX_FLAG); + } + while (effect->status != -1) { + if (effect->status == 0) { + effect->alpha -= 2; + } else { + effect->scale += effect->status; + } + + effect->scale = CLAMP_MAX(effect->scale, 10000); + effect++; + } + } + } +} + +void BossSst_DrawEffect(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + BossSst* this = THIS; + s32 i; + BossSstEffect* effect; + + if (this->effectMode != BONGO_NULL) { + OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_sst.c", 7302); + + func_80093D84(globalCtx->state.gfxCtx); + if (this->effectMode == BONGO_ICE) { + gSPSegment(POLY_XLU_DISP++, 0x08, + Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, globalCtx->gameplayFrames % 256, 0x20, 0x10, 1, + 0, (globalCtx->gameplayFrames * 2) % 256, 0x40, 0x20)); + gDPSetEnvColor(POLY_XLU_DISP++, 0, 50, 100, this->effects[0].alpha); + gSPDisplayList(POLY_XLU_DISP++, gBongoIceCrystalDL); + + for (i = 0; i < 18; i++) { + effect = &this->effects[i]; + if (effect->move) { + func_8003435C(&effect->pos, globalCtx); + if (this->effects[0].status != 0) { + Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW); + } else { + Matrix_Translate(effect->pos.x + this->actor.world.pos.x, + effect->pos.y + this->actor.world.pos.y, + effect->pos.z + this->actor.world.pos.z, MTXMODE_NEW); + } + + Matrix_RotateRPY(effect->rot.x, effect->rot.y, effect->rot.z, MTXMODE_APPLY); + Matrix_Scale(effect->scale * 0.001f, effect->scale * 0.001f, effect->scale * 0.001f, MTXMODE_APPLY); + + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_sst.c", 7350), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_XLU_DISP++, gBongoIceShardDL); + } + } + } else if (this->effectMode == BONGO_SHOCKWAVE) { + f32 scaleY = 0.005f; + + gDPPipeSync(POLY_XLU_DISP++); + gSPSegment(POLY_XLU_DISP++, 0x08, + Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, globalCtx->gameplayFrames % 128, 0, 0x20, 0x40, 1, + 0, (globalCtx->gameplayFrames * -15) % 256, 0x20, 0x40)); + + for (i = 0; i < 3; i++, scaleY -= 0.001f) { + effect = &this->effects[i]; + + if (effect->move != 0) { + Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW); + Matrix_Scale(effect->scale * 0.001f, scaleY, effect->scale * 0.001f, MTXMODE_APPLY); + + gDPPipeSync(POLY_XLU_DISP++); + gDPSetPrimColor(POLY_XLU_DISP++, 0x80, 0x80, 30, 0, 30, effect->alpha * effect->move); + gDPSetEnvColor(POLY_XLU_DISP++, 30, 0, 30, 0); + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_sst.c", 7396), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_XLU_DISP++, gEffFireCircleDL); + } + } + } else if (this->effectMode == BONGO_SHADOW) { + gDPSetPrimColor(POLY_XLU_DISP++, 0x00, 0x80, 10, 10, 80, 0); + gDPSetEnvColor(POLY_XLU_DISP++, 10, 10, 10, this->effects[0].alpha); + + effect = &this->effects[0]; + while (effect->status != -1) { + Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW); + Matrix_Scale(effect->scale * 0.001f, 1.0f, effect->scale * 0.001f, MTXMODE_APPLY); + + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_sst.c", 7423), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_XLU_DISP++, sShadowDList); + effect++; + } + } + + CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_sst.c", 7433); + } +} diff --git a/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.h b/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.h index 7bd008564..f19caa3e3 100644 --- a/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.h +++ b/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.h @@ -6,11 +6,59 @@ struct BossSst; +typedef void (*BossSstActionFunc)(struct BossSst*, GlobalContext*); + + +typedef struct { + /* 0x0000 */ Vec3f pos; + /* 0x0010 */ Vec3f vel; + /* 0x0018 */ Vec3s rot; + /* 0x001E */ u16 scale; + /* 0x0020 */ s16 move; + /* 0x0022 */ s16 status; + /* 0x0024 */ u8 alpha; +} BossSstEffect; // size = 0x28 + +typedef struct { + /* 0x0000 */ PosRot world; + /* 0x0014 */ f32 zPosMod; + /* 0x0018 */ s16 yRotMod; +} BossSstHandTrail; // size = 0x1C + typedef struct BossSst { /* 0x0000 */ Actor actor; - /* 0x014C */ char unk_14C[0x94C]; + /* 0x014C */ SkelAnime skelAnime; + /* 0x0190 */ BossSstActionFunc actionFunc; + /* 0x0194 */ s8 actionVar; // head: flag for visible without lens; hand: 1 for right, -1 for left + /* 0x0195 */ s8 ready; + /* 0x0196 */ u8 effectMode; + /* 0x0198 */ s16 timer; + /* 0x019A */ s16 handAngSpeed; + /* 0x019C */ s16 handMaxSpeed; + /* 0x019E */ s16 handZPosMod; + /* 0x01A0 */ s16 handYRotMod; + /* 0x01A2 */ s16 amplitude; + /* 0x01A4 */ s16 targetYaw; + /* 0x01A6 */ s16 targetRoll; + /* 0x01A8 */ Vec3s jointTable[45]; + /* 0x02B6 */ Vec3s morphTable[45]; + /* 0x03C4 */ f32 radius; + /* 0x03C8 */ Vec3f center; + /* 0x03D4 */ ColliderJntSph colliderJntSph; + /* 0x03F4 */ ColliderJntSphElement colliderItems[11]; + /* 0x06B4 */ ColliderCylinder colliderCyl; + /* 0x0700 */ BossSstEffect effects[18]; + /* 0x09D0 */ s16 trailIndex; + /* 0x09D2 */ s16 trailCount; + /* 0x09D4 */ BossSstHandTrail handTrails[7]; } BossSst; // size = 0x0A98 +typedef enum { + /* -1 */ BONGO_HEAD = -1, + /* 0 */ BONGO_LEFT_HAND, + /* 1 */ BONGO_RIGHT_HAND +} BossSstType; + extern const ActorInit Boss_Sst_InitVars; #endif diff --git a/src/overlays/actors/ovl_Boss_Sst/z_boss_sst_colchk.c b/src/overlays/actors/ovl_Boss_Sst/z_boss_sst_colchk.c new file mode 100644 index 000000000..821d5f36a --- /dev/null +++ b/src/overlays/actors/ovl_Boss_Sst/z_boss_sst_colchk.c @@ -0,0 +1,352 @@ +#include "z_boss_sst.h" + +static ColliderJntSphElementInit sJntSphItemsInitHand[11] = { + { + { + ELEMTYPE_UNK1, + { 0x20000000, 0x00, 0x00 }, + { 0xFFCFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { 2, { { 2000, -1500, 250 }, 65 }, 100 }, + }, + { + { + ELEMTYPE_UNK1, + { 0x20000000, 0x00, 0x00 }, + { 0xFFCFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { 10, { { 0, 0, 0 }, 22 }, 100 }, + }, + { + { + ELEMTYPE_UNK1, + { 0x20000000, 0x00, 0x00 }, + { 0xFFCFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { 11, { { 500, 0, 0 }, 22 }, 100 }, + }, + { + { + ELEMTYPE_UNK1, + { 0x20000000, 0x00, 0x00 }, + { 0xFFCFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { 15, { { -250, -250, 0 }, 25 }, 100 }, + }, + { + { + ELEMTYPE_UNK1, + { 0x20000000, 0x00, 0x00 }, + { 0xFFCFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { 16, { { 500, -250, 0 }, 25 }, 100 }, + }, + { + { + ELEMTYPE_UNK1, + { 0x20000000, 0x00, 0x00 }, + { 0xFFCFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { 20, { { 250, -250, 0 }, 25 }, 100 }, + }, + { + { + ELEMTYPE_UNK1, + { 0x20000000, 0x00, 0x00 }, + { 0xFFCFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { 21, { { 500, -250, 0 }, 25 }, 100 }, + }, + { + { + ELEMTYPE_UNK1, + { 0x20000000, 0x00, 0x00 }, + { 0xFFCFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { 25, { { 0, 0, 0 }, 27 }, 100 }, + }, + { + { + ELEMTYPE_UNK1, + { 0x20000000, 0x00, 0x00 }, + { 0xFFCFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { 26, { { 750, 0, 0 }, 26 }, 100 }, + }, + { + { + ELEMTYPE_UNK1, + { 0x20000000, 0x00, 0x00 }, + { 0xFFCFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { 5, { { 750, -150, 0 }, 21 }, 100 }, + }, + { + { + ELEMTYPE_UNK1, + { 0x20000000, 0x00, 0x00 }, + { 0xFFCFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { 6, { { 750, 0, 0 }, 20 }, 100 }, + }, +}; + +static ColliderJntSphInit sJntSphInitHand = { + { + COLTYPE_HIT0, + AT_TYPE_ENEMY, + AC_ON | AC_TYPE_PLAYER, + OC1_TYPE_ALL, + OC2_TYPE_1, + COLSHAPE_JNTSPH, + }, + 11, + sJntSphItemsInitHand, +}; + +static ColliderJntSphElementInit sJntSphItemsInitHead[11] = { + { + { + ELEMTYPE_UNK1, + { 0x20000000, 0x00, 0x30 }, + { 0xFFCFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { 7, { { 1500, 0, 0 }, 70 }, 100 }, + }, + { + { + ELEMTYPE_UNK1, + { 0x20000000, 0x00, 0x30 }, + { 0xFFCFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { 6, { { 0, 0, 0 }, 75 }, 100 }, + }, + { + { + ELEMTYPE_UNK1, + { 0x20000000, 0x00, 0x30 }, + { 0xFFCFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { 4, { { 5000, 0, 0 }, 120 }, 100 }, + }, + { + { + ELEMTYPE_UNK1, + { 0x20000000, 0x00, 0x30 }, + { 0xFFCFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { 3, { { -2500, 0, 0 }, 150 }, 100 }, + }, + { + { + ELEMTYPE_UNK1, + { 0x20000000, 0x00, 0x30 }, + { 0xFFCFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { 43, { { 1500, 0, 0 }, 80 }, 100 }, + }, + { + { + ELEMTYPE_UNK1, + { 0x20000000, 0x00, 0x30 }, + { 0xFFCFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { 43, { { 7500, 0, 0 }, 70 }, 100 }, + }, + { + { + ELEMTYPE_UNK1, + { 0x20000000, 0x00, 0x30 }, + { 0xFFCFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { 44, { { 3000, 0, 0 }, 60 }, 100 }, + }, + { + { + ELEMTYPE_UNK1, + { 0x20000000, 0x00, 0x30 }, + { 0xFFCFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { 40, { { 1500, 0, 0 }, 80 }, 100 }, + }, + { + { + ELEMTYPE_UNK1, + { 0x20000000, 0x00, 0x30 }, + { 0xFFCFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { 40, { { 7500, 0, 0 }, 70 }, 100 }, + }, + { + { + ELEMTYPE_UNK1, + { 0x20000000, 0x00, 0x30 }, + { 0xFFCFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { 41, { { 3000, 0, 0 }, 60 }, 100 }, + }, + { + { + ELEMTYPE_UNK1, + { 0x20000000, 0x00, 0x30 }, + { 0x00000080, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 8, { { 1500, 0, 0 }, 70 }, 100 }, + }, +}; + +static ColliderJntSphInit sJntSphInitHead = { + { + COLTYPE_HARD, + AT_TYPE_ENEMY, + AC_ON | AC_HARD | AC_TYPE_PLAYER, + OC1_TYPE_ALL, + OC2_TYPE_1, + COLSHAPE_JNTSPH, + }, + 11, + sJntSphItemsInitHead, +}; + +static ColliderCylinderInit sCylinderInitHead = { + { + COLTYPE_HIT0, + AT_NONE, + AC_NONE | AC_TYPE_PLAYER, + OC1_NONE, + OC2_TYPE_1, + COLSHAPE_CYLINDER, + }, + { + ELEMTYPE_UNK0, + { 0x00000000, 0x00, 0x00 }, + { 0xFFCFFFFF, 0x00, 0x00 }, + TOUCH_NONE, + BUMP_ON, + OCELEM_NONE, + }, + { 85, 100, -50, { 0, 0, 0 } }, +}; + +static ColliderCylinderInit sCylinderInitHand = { + { + COLTYPE_NONE, + AT_TYPE_ENEMY, + AC_NONE, + OC1_NONE, + OC2_TYPE_1, + COLSHAPE_CYLINDER, + }, + { + ELEMTYPE_UNK0, + { 0x20000000, 0x04, 0x10 }, + { 0x00000000, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NONE, + BUMP_NONE, + OCELEM_NONE, + }, + { 85, 1, 0, { 0, 0, 0 } }, +}; + +static CollisionCheckInfoInit sColChkInfoInit = { 36, 100, 100, 200 }; + +static DamageTable sDamageTable = { + /* Deku nut */ DMG_ENTRY(0 , 0x0), + /* Deku stick */ DMG_ENTRY(2 , 0x0), + /* Slingshot */ DMG_ENTRY(1 , 0x0), + /* Explosive */ DMG_ENTRY(2 , 0x0), + /* Boomerang */ DMG_ENTRY(0 , 0x0), + /* Normal arrow */ DMG_ENTRY(2 , 0x0), + /* Hammer swing */ DMG_ENTRY(2 , 0x0), + /* Hookshot */ DMG_ENTRY(2 , 0x0), + /* Kokiri sword */ DMG_ENTRY(1 , 0x0), + /* Master sword */ DMG_ENTRY(2 , 0x0), + /* Giant's Knife */ DMG_ENTRY(4 , 0x0), + /* Fire arrow */ DMG_ENTRY(2 , 0x0), + /* Ice arrow */ DMG_ENTRY(4 , 0x3), + /* Light arrow */ DMG_ENTRY(2 , 0x0), + /* Unk arrow 1 */ DMG_ENTRY(4 , 0x0), + /* Unk arrow 2 */ DMG_ENTRY(2 , 0x0), + /* Unk arrow 3 */ DMG_ENTRY(2 , 0x0), + /* Fire magic */ DMG_ENTRY(0 , 0x0), + /* Ice magic */ DMG_ENTRY(4 , 0x3), + /* Light magic */ DMG_ENTRY(4 , 0x4), + /* Shield */ DMG_ENTRY(0 , 0x0), + /* Mirror Ray */ DMG_ENTRY(0 , 0x0), + /* Kokiri spin */ DMG_ENTRY(1 , 0x0), + /* Giant spin */ DMG_ENTRY(4 , 0x0), + /* Master spin */ DMG_ENTRY(2 , 0x0), + /* Kokiri jump */ DMG_ENTRY(2 , 0x0), + /* Giant jump */ DMG_ENTRY(8 , 0x0), + /* Master jump */ DMG_ENTRY(4 , 0x0), + /* Unknown 1 */ DMG_ENTRY(0 , 0x0), + /* Unblockable */ DMG_ENTRY(0 , 0x0), + /* Hammer jump */ DMG_ENTRY(4 , 0x0), + /* Unknown 2 */ DMG_ENTRY(0 , 0x0), +}; |
