diff options
| author | petrie911 <69443847+petrie911@users.noreply.github.com> | 2021-04-17 12:12:46 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-04-17 19:12:46 +0200 |
| commit | 7b2b88d552fad0f6603effd3c59a69b7a455e5de (patch) | |
| tree | ec8677590e03704f04f5b690c1126bee15305be0 /src | |
| parent | 7306d13897d682c7fd29bd17af9e102933afc599 (diff) | |
Volvagia (ovl_Boss_Fd) and related actors (#352)
* Darkmeiro decompilation
Bg_Gnd_Darkmeiro decompiled, matched, and documented.
* Lots of functions matched. Some big ones are close.
* Five left unmatched, one close.
* Merged data and decompiled the giant function into something readable. Its branch structure has yet to be matched.
* Three unmatched, one essentially matched, the rest matched.
* More fixes.
* Documented more of the structure and cleaned up a bit.
* BossFd2, BgVbSima, and EnVbBall matched and documented
* Also removed unneeded .s files
* And need to name EnVbBall's functions
* give this a shot
* fix conflict
* one more try
* removing darkmeiro changes
* and again
* now OK from make clean
* minor cleanup
* One more matching function for BossFd
* which means it doesn't need its .s
* splitting
* splitting
* splitting
* forgot some .s
* fancy new names
* fancy new names
* trying again
* sneaky .s files
* sound effects and some hex to decimal conversions
* Sound effects and static variable cleanup
* format.sh and clean up static variables
* sfx and formatting
* ZAP and cleanup
* small cleanup
* cleanup and ZAP
* ZAP
* looking at the giant function again
* looking at the giant function again
* Only the big function left.
* Those .s files aren't mine, officer
* float literals might be fixed. regalloc still a nightmare
* almost done with the big function
* should make now
* not much of a change
* all functions match. rodata somehow doesn't.
* forgot some things
* lots of cleanup
* and a little more
* small error
* large cleanup. Also BossFd has function names and inlined variable declarations
* still more cleanup
* the quest for 0.1f continues
* forgot to put NON_MATCHING back in
* Data structures fully documented. Still more cleanup.
* DECR now works with BossFd2
* should match now
* cleanup
* small cleanup
* cleanup and names
* tiny thing
* particles and headers and stuff
* now with more enums
* merge
* test
* end test
* update
* cleanup
* object 2
* object 1
* doc object_fd2
* git subrepo pull --force tools/ZAPD
subrepo:
subdir: "tools/ZAPD"
merged: "6f874af4a"
upstream:
origin: "https://github.com/zeldaret/ZAPD.git"
branch: "master"
commit: "6f874af4a"
git-subrepo:
version: "0.4.3"
origin: "https://github.com/ingydotnet/git-subrepo.git"
commit: "2f68596"
* formatting
* .s
* merge actor
* vertex arrays
* a little more
* formatting
* merge opd
* fixed damage check
* cleanup
* fixes
* effect struct
* review
Co-authored-by: petrie911 <pmontag@DESKTOP-LG8A167.localdomain>
Co-authored-by: fig02 <fig02srl@gmail.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/code/z_actor.c | 2 | ||||
| -rw-r--r-- | src/code/z_skin_awb.c | 3 | ||||
| -rw-r--r-- | src/overlays/actors/ovl_Bg_Vb_Sima/z_bg_vb_sima.c | 142 | ||||
| -rw-r--r-- | src/overlays/actors/ovl_Bg_Vb_Sima/z_bg_vb_sima.h | 12 | ||||
| -rw-r--r-- | src/overlays/actors/ovl_Boss_Fd/z_boss_fd.c | 2183 | ||||
| -rw-r--r-- | src/overlays/actors/ovl_Boss_Fd/z_boss_fd.h | 173 | ||||
| -rw-r--r-- | src/overlays/actors/ovl_Boss_Fd/z_boss_fd_colchk.c | 226 | ||||
| -rw-r--r-- | src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2.c | 1306 | ||||
| -rw-r--r-- | src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2.h | 80 | ||||
| -rw-r--r-- | src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2_colchk.c | 116 | ||||
| -rw-r--r-- | src/overlays/actors/ovl_En_Anubice_Fire/z_en_anubice_fire.c | 4 | ||||
| -rw-r--r-- | src/overlays/actors/ovl_En_Vb_Ball/z_en_vb_ball.c | 286 | ||||
| -rw-r--r-- | src/overlays/actors/ovl_En_Vb_Ball/z_en_vb_ball.h | 10 |
13 files changed, 4124 insertions, 419 deletions
diff --git a/src/code/z_actor.c b/src/code/z_actor.c index 98ecdc4d2..9a0e62319 100644 --- a/src/code/z_actor.c +++ b/src/code/z_actor.c @@ -847,7 +847,7 @@ void Actor_Destroy(Actor* actor, GlobalContext* globalCtx) { } } -void func_8002D7EC(Actor* actor) { +s16 func_8002D7EC(Actor* actor) { f32 speedRate = R_UPDATE_RATE * 0.5f; actor->world.pos.x += (actor->velocity.x * speedRate) + actor->colChkInfo.displacement.x; diff --git a/src/code/z_skin_awb.c b/src/code/z_skin_awb.c index 4b0b34eec..121556b8b 100644 --- a/src/code/z_skin_awb.c +++ b/src/code/z_skin_awb.c @@ -72,8 +72,9 @@ void func_800A663C(GlobalContext* globalCtx, PSkinAwb* skin, SkeletonHeader* ske } void func_800A6888(GlobalContext* globalCtx, PSkinAwb* arg1) { - s32 i; if (arg1->avbTbl != NULL) { + s32 i; + for (i = 0; i < arg1->avbCount; i++) { if (arg1->avbTbl[i].buf[0] != 0) { ZeldaArena_FreeDebug(arg1->avbTbl[i].buf[0], "../z_skin_awb.c", 276); diff --git a/src/overlays/actors/ovl_Bg_Vb_Sima/z_bg_vb_sima.c b/src/overlays/actors/ovl_Bg_Vb_Sima/z_bg_vb_sima.c index 22bf754a2..bff752460 100644 --- a/src/overlays/actors/ovl_Bg_Vb_Sima/z_bg_vb_sima.c +++ b/src/overlays/actors/ovl_Bg_Vb_Sima/z_bg_vb_sima.c @@ -1,4 +1,12 @@ +/* + * File: z_bg_vb_sima.c + * Overlay: ovl_Bg_Vb_Sima + * Description: Volvagia's platform + */ + #include "z_bg_vb_sima.h" +#include "objects/object_fd/object_fd.h" +#include "overlays/actors/ovl_Boss_Fd/z_boss_fd.h" #define FLAGS 0x00000000 @@ -9,7 +17,6 @@ void BgVbSima_Destroy(Actor* thisx, GlobalContext* globalCtx); void BgVbSima_Update(Actor* thisx, GlobalContext* globalCtx); void BgVbSima_Draw(Actor* thisx, GlobalContext* globalCtx); -/* const ActorInit Bg_Vb_Sima_InitVars = { ACTOR_BG_VB_SIMA, ACTORCAT_BG, @@ -21,13 +28,134 @@ const ActorInit Bg_Vb_Sima_InitVars = { (ActorFunc)BgVbSima_Update, (ActorFunc)BgVbSima_Draw, }; -*/ -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Bg_Vb_Sima/BgVbSima_Init.s") -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Bg_Vb_Sima/BgVbSima_Destroy.s") +static InitChainEntry sInitChain[] = { + ICHAIN_VEC3F_DIV1000(scale, 100, ICHAIN_STOP), +}; + +void BgVbSima_Init(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + BgVbSima* this = THIS; + CollisionHeader* colHeader = NULL; + + Actor_ProcessInitChain(&this->dyna.actor, sInitChain); + DynaPolyActor_Init(&this->dyna, DPM_PLAYER); + CollisionHeader_GetVirtual(&gVolvagiaPlatformCol, &colHeader); + this->dyna.bgId = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->dyna.actor, colHeader); +} + +void BgVbSima_Destroy(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + BgVbSima* this = THIS; + + DynaPoly_DeleteBgActor(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId); +} + +void BgVbSima_SpawnEmber(BossFdEffect* effect, Vec3f* position, Vec3f* velocity, Vec3f* acceleration, f32 scale) { + s16 i; + + for (i = 0; i < 180; i++, effect++) { + if (effect->type == BFD_FX_NONE) { + effect->type = BFD_FX_EMBER; + effect->pos = *position; + effect->velocity = *velocity; + effect->accel = *acceleration; + effect->scale = scale / 1000.0f; + effect->alpha = 255; + effect->timer1 = (s16)Rand_ZeroFloat(10.0f); + break; + } + } +} + +void BgVbSima_Update(Actor* thisx, GlobalContext* globalCtx) { + static Color_RGBA8 colorYellow = { 255, 255, 0, 255 }; + static Color_RGBA8 colorRed = { 255, 10, 0, 255 }; + s32 pad; + BgVbSima* this = THIS; + BossFd* bossFd = (BossFd*)this->dyna.actor.parent; + f32 minus1 = -1.0f; + + this->shakeTimer++; + if (!Flags_GetClear(globalCtx, globalCtx->roomCtx.curRoom.num)) { + s32 signal = bossFd->platformSignal; + + if (signal == VBSIMA_COLLAPSE) { + Math_SmoothStepToF(&this->dyna.actor.world.pos.y, -1000.0f, 1.0f, 1.5f, 0.0f); + this->dyna.actor.world.pos.z += 2.0f * Math_CosS(this->shakeTimer * 0x8000); + this->dyna.actor.shape.rot.x = (s16)Math_SinS(this->shakeTimer * 0x7000) * 0x37; + this->dyna.actor.shape.rot.z = (s16)Math_SinS(this->shakeTimer * 0x5000) * 0x37; + Audio_PlaySoundGeneral(NA_SE_EV_BLOCKSINK - SFX_FLAG, &this->dyna.actor.projectedPos, 4, &D_801333E0, + &D_801333E0, &D_801333E8); + } else if (signal == VBSIMA_KILL) { + Actor_Kill(&this->dyna.actor); + } + if (bossFd->platformSignal != VBSIMA_STAND) { + s16 i2; + s16 i1; + Vec3f splashVel; + Vec3f splashAcc; + Vec3f splashPos; + Vec3f emberPos; + Vec3f emberVel; + Vec3f emberAcc; + f32 edgeX; + f32 edgeZ; + + for (i1 = 0; i1 < 10; i1++) { + if (Rand_ZeroOne() < 0.33f) { + edgeX = -80.0f; + edgeZ = Rand_CenteredFloat(160.0f); + } else { + edgeZ = 80.0f; + if (Rand_ZeroOne() < 0.5f) { + // minus1 = -1.0f; // Not a fake match; the game really does this. + edgeZ = 80.0f * minus1; + } + edgeX = Rand_CenteredFloat(160.0f); + } + + splashVel.x = edgeX * 0.05f; + splashVel.y = Rand_ZeroFloat(3.0f) + 3.0f; + splashVel.z = edgeZ * 0.05f; + + splashAcc.y = -0.3f; + splashAcc.x = splashVel.x; + splashAcc.z = splashVel.z; + + splashPos.x = this->dyna.actor.world.pos.x + edgeX; + splashPos.y = -80.0f; + splashPos.z = this->dyna.actor.world.pos.z + edgeZ; + + func_8002836C(globalCtx, &splashPos, &splashVel, &splashAcc, &colorYellow, &colorRed, + (s16)Rand_ZeroFloat(100.0f) + 500, 10, 20); + + for (i2 = 0; i2 < 3; i2++) { + emberVel.x = splashVel.x; + emberVel.y = Rand_ZeroFloat(5.0f); + emberVel.z = splashVel.z; + + emberAcc.y = 0.4f; + emberAcc.x = Rand_CenteredFloat(0.5f); + emberAcc.z = Rand_CenteredFloat(0.5f); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Bg_Vb_Sima/func_808BDDF8.s") + emberPos.x = Rand_CenteredFloat(60.0f) + splashPos.x; + emberPos.y = Rand_ZeroFloat(40.0f) + splashPos.y; + emberPos.z = Rand_CenteredFloat(60.0f) + splashPos.z; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Bg_Vb_Sima/BgVbSima_Update.s") + BgVbSima_SpawnEmber(bossFd->effects, &emberPos, &emberVel, &emberAcc, + (s16)Rand_ZeroFloat(2.0f) + 8); + } + } + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Bg_Vb_Sima/BgVbSima_Draw.s") +void BgVbSima_Draw(Actor* thisx, GlobalContext* globalCtx) { + OPEN_DISPS(globalCtx->state.gfxCtx, "../z_bg_vb_sima.c", 285); + func_80093D18(globalCtx->state.gfxCtx); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_bg_vb_sima.c", 291), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, gVolvagiaPlatformDL); + CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_bg_vb_sima.c", 296); +} diff --git a/src/overlays/actors/ovl_Bg_Vb_Sima/z_bg_vb_sima.h b/src/overlays/actors/ovl_Bg_Vb_Sima/z_bg_vb_sima.h index 3c296fa37..34aa6856e 100644 --- a/src/overlays/actors/ovl_Bg_Vb_Sima/z_bg_vb_sima.h +++ b/src/overlays/actors/ovl_Bg_Vb_Sima/z_bg_vb_sima.h @@ -6,9 +6,17 @@ struct BgVbSima; +typedef enum { + /* 0 */ VBSIMA_STAND, + /* 1 */ VBSIMA_COLLAPSE, + /* 2 */ VBSIMA_KILL +} BgVbSimaSignal; + typedef struct BgVbSima { - /* 0x0000 */ Actor actor; - /* 0x014C */ char unk_14C[0x30]; + /* 0x0000 */ DynaPolyActor dyna; + /* 0x0164 */ char unk_164[0x10]; + /* 0x0174 */ s16 shakeTimer; + /* 0x0176 */ char unk_176[6]; } BgVbSima; // size = 0x017C extern const ActorInit Bg_Vb_Sima_InitVars; diff --git a/src/overlays/actors/ovl_Boss_Fd/z_boss_fd.c b/src/overlays/actors/ovl_Boss_Fd/z_boss_fd.c index d57ea1bb5..ccb2c09df 100644 --- a/src/overlays/actors/ovl_Boss_Fd/z_boss_fd.c +++ b/src/overlays/actors/ovl_Boss_Fd/z_boss_fd.c @@ -1,16 +1,50 @@ +/* + * File: z_boss_fd.c + * Overlay: ovl_Boss_Fd + * Description: Volvagia, flying form + */ + #include "z_boss_fd.h" +#include "objects/object_fd/object_fd.h" +#include "overlays/actors/ovl_En_Vb_Ball/z_en_vb_ball.h" +#include "overlays/actors/ovl_Bg_Vb_Sima/z_bg_vb_sima.h" +#include "overlays/actors/ovl_Boss_Fd2/z_boss_fd2.h" #include "objects/gameplay_keep/gameplay_keep.h" #define FLAGS 0x00000035 #define THIS ((BossFd*)thisx) +typedef enum { + /* 0 */ INTRO_FLY_EMERGE, + /* 1 */ INTRO_FLY_HOLE, + /* 2 */ INTRO_FLY_CAMERA, + /* 3 */ INTRO_FLY_RETRAT +} BossFdIntroFlyState; + +typedef enum { + /* 0 */ MANE_CENTER, + /* 1 */ MANE_RIGHT, + /* 2 */ MANE_LEFT +} BossFdManeIndex; + +typedef enum { + /* 0 */ EYE_OPEN, + /* 1 */ EYE_HALF, + /* 2 */ EYE_CLOSED +} BossFdEyeState; + void BossFd_Init(Actor* thisx, GlobalContext* globalCtx); void BossFd_Destroy(Actor* thisx, GlobalContext* globalCtx); void BossFd_Update(Actor* thisx, GlobalContext* globalCtx); void BossFd_Draw(Actor* thisx, GlobalContext* globalCtx); -/* +void BossFd_SetupFly(BossFd* this, GlobalContext* globalCtx); +void BossFd_Fly(BossFd* this, GlobalContext* globalCtx); +void BossFd_Wait(BossFd* this, GlobalContext* globalCtx); +void BossFd_UpdateEffects(BossFd* this, GlobalContext* globalCtx); +void BossFd_DrawBody(GlobalContext* globalCtx, BossFd* this); + const ActorInit Boss_Fd_InitVars = { ACTOR_BOSS_FD, ACTORCAT_BOSS, @@ -23,275 +57,1930 @@ const ActorInit Boss_Fd_InitVars = { (ActorFunc)BossFd_Draw, }; -static ColliderJntSphElementInit D_808D1660[19] = { - { - { - ELEMTYPE_UNK3, - { 0xFFCFFFFF, 0x00, 0x10 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_ON, - OCELEM_ON, - }, - { 0, { { 0, 0, 0 }, 20 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x10 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 1, { { 0, 0, 0 }, 20 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x10 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 2, { { 0, 0, 0 }, 20 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x10 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 3, { { 0, 0, 0 }, 20 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x10 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 4, { { 0, 0, 0 }, 20 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x10 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 5, { { 0, 0, 0 }, 20 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x10 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 6, { { 0, 0, 0 }, 20 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x10 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 7, { { 0, 0, 0 }, 20 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x10 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 8, { { 0, 0, 0 }, 20 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x10 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 9, { { 0, 0, 0 }, 20 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x10 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 10, { { 0, 0, 0 }, 20 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x10 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 11, { { 0, 0, 0 }, 20 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x10 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 12, { { 0, 0, 0 }, 20 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x10 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 13, { { 0, 0, 0 }, 20 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x10 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 14, { { 0, 0, 0 }, 18 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x10 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 15, { { 0, 0, 0 }, 16 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x10 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 16, { { 0, 0, 0 }, 14 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x10 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 17, { { 0, 0, 0 }, 12 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x10 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 18, { { 0, 0, 0 }, 10 }, 100 }, - }, +#include "z_boss_fd_colchk.c" + +static InitChainEntry sInitChain[] = { + ICHAIN_U8(targetMode, 5, ICHAIN_CONTINUE), + ICHAIN_S8(naviEnemyId, 33, ICHAIN_CONTINUE), + ICHAIN_F32_DIV1000(gravity, 0, ICHAIN_CONTINUE), + ICHAIN_F32(targetArrowOffset, 0, ICHAIN_STOP), }; -static ColliderJntSphInit D_808D190C = { - { - COLTYPE_METAL, - AT_ON | AT_TYPE_ENEMY, - AC_ON | AC_TYPE_PLAYER, - OC1_ON | OC1_TYPE_PLAYER, - OC2_TYPE_1, - COLSHAPE_JNTSPH, - }, - 19, - D_808D1660, +void BossFd_SpawnEmber(BossFdEffect* effect, Vec3f* position, Vec3f* velocity, Vec3f* acceleration, f32 scale) { + s16 i; + + for (i = 0; i < 150; i++, effect++) { + if (effect->type == BFD_FX_NONE) { + effect->type = BFD_FX_EMBER; + effect->pos = *position; + effect->velocity = *velocity; + effect->accel = *acceleration; + effect->scale = scale / 1000.0f; + effect->alpha = 255; + effect->timer1 = (s16)Rand_ZeroFloat(10.0f); + break; + } + } +} + +void BossFd_SpawnDebris(BossFdEffect* effect, Vec3f* position, Vec3f* velocity, Vec3f* acceleration, f32 scale) { + s16 i; + + for (i = 0; i < 150; i++, effect++) { + if (effect->type == BFD_FX_NONE) { + effect->type = BFD_FX_DEBRIS; + effect->pos = *position; + effect->velocity = *velocity; + effect->accel = *acceleration; + effect->scale = scale / 1000.0f; + effect->vFdFxRotX = Rand_ZeroFloat(100.0f); + effect->vFdFxRotY = Rand_ZeroFloat(100.0f); + break; + } + } +} + +void BossFd_SpawnDust(BossFdEffect* effect, Vec3f* position, Vec3f* velocity, Vec3f* acceleration, f32 scale) { + s16 i; + + for (i = 0; i < 150; i++, effect++) { + if (effect->type == BFD_FX_NONE) { + effect->type = BFD_FX_DUST; + effect->pos = *position; + effect->velocity = *velocity; + effect->accel = *acceleration; + effect->timer2 = 0; + effect->scale = scale / 400.0f; + break; + } + } +} + +void BossFd_SpawnFireBreath(BossFdEffect* effect, Vec3f* position, Vec3f* velocity, Vec3f* acceleration, f32 scale, + s16 alpha, s16 kbAngle) { + s16 i; + + for (i = 0; i < 180; i++, effect++) { + if (effect->type == BFD_FX_NONE) { + effect->type = BFD_FX_FIRE_BREATH; + effect->timer1 = 0; + effect->pos = *position; + effect->velocity = *velocity; + effect->accel = *acceleration; + effect->pos.x -= effect->velocity.x; + effect->pos.y -= effect->velocity.y; + effect->pos.z -= effect->velocity.z; + effect->vFdFxScaleMod = 0.0f; + effect->alpha = alpha; + effect->vFdFxYStop = Rand_ZeroFloat(10.0f); + effect->timer2 = 0; + effect->scale = scale / 400.0f; + effect->kbAngle = kbAngle; + break; + } + } +} + +void BossFd_SetCameraSpeed(BossFd* this, f32 speedMod) { + this->camData.eyeVel.x = fabsf(this->camData.eye.x - this->camData.nextEye.x) * speedMod; + this->camData.eyeVel.y = fabsf(this->camData.eye.y - this->camData.nextEye.y) * speedMod; + this->camData.eyeVel.z = fabsf(this->camData.eye.z - this->camData.nextEye.z) * speedMod; + this->camData.atVel.x = fabsf(this->camData.at.x - this->camData.nextAt.x) * speedMod; + this->camData.atVel.y = fabsf(this->camData.at.y - this->camData.nextAt.y) * speedMod; + this->camData.atVel.z = fabsf(this->camData.at.z - this->camData.nextAt.z) * speedMod; +} + +void BossFd_UpdateCamera(BossFd* this, GlobalContext* globalCtx) { + if (this->introCamera != SUBCAM_FREE) { + Math_ApproachF(&this->camData.eye.x, this->camData.nextEye.x, this->camData.eyeMaxVel.x, + this->camData.eyeVel.x * this->camData.speedMod); + Math_ApproachF(&this->camData.eye.y, this->camData.nextEye.y, this->camData.eyeMaxVel.y, + this->camData.eyeVel.y * this->camData.speedMod); + Math_ApproachF(&this->camData.eye.z, this->camData.nextEye.z, this->camData.eyeMaxVel.z, + this->camData.eyeVel.z * this->camData.speedMod); + Math_ApproachF(&this->camData.at.x, this->camData.nextAt.x, this->camData.atMaxVel.x, + this->camData.atVel.x * this->camData.speedMod); + Math_ApproachF(&this->camData.at.y, this->camData.nextAt.y, this->camData.atMaxVel.y, + this->camData.atVel.y * this->camData.speedMod); + Math_ApproachF(&this->camData.at.z, this->camData.nextAt.z, this->camData.atMaxVel.z, + this->camData.atVel.z * this->camData.speedMod); + Math_ApproachF(&this->camData.speedMod, 1.0f, 1.0f, this->camData.accel); + this->camData.at.y += this->camData.yMod; + Gameplay_CameraSetAtEye(globalCtx, this->introCamera, &this->camData.at, &this->camData.eye); + Math_ApproachZeroF(&this->camData.yMod, 1.0f, 0.1f); + } +} + +void BossFd_Init(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + BossFd* this = THIS; + s16 i; + + Flags_SetSwitch(globalCtx, 0x14); + Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_BG_VB_SIMA, 680.0f, -100.0f, 0.0f, 0, 0, 0, + 100); + Actor_ProcessInitChain(&this->actor, sInitChain); + ActorShape_Init(&this->actor.shape, 0.0f, NULL, 0.0f); + Actor_SetScale(&this->actor, 0.05f); + SkelAnime_Init(globalCtx, &this->skelAnimeHead, &gVolvagiaHeadSkel, &gVolvagiaHeadEmergeAnim, NULL, NULL, 0); + SkelAnime_Init(globalCtx, &this->skelAnimeRightArm, &gVolvagiaRightArmSkel, &gVolvagiaRightArmEmergeAnim, NULL, + NULL, 0); + SkelAnime_Init(globalCtx, &this->skelAnimeLeftArm, &gVolvagiaLeftArmSkel, &gVolvagiaLeftArmEmergeAnim, NULL, NULL, + 0); + this->introState = BFD_CS_WAIT; + if (this->introState == BFD_CS_NONE) { + Audio_SetBGM(0x6B); + } + + this->actor.world.pos.x = this->actor.world.pos.z = 0.0f; + this->actor.world.pos.y = -200.0f; + Collider_InitJntSph(globalCtx, &this->collider); + Collider_SetJntSph(globalCtx, &this->collider, &this->actor, &sJntSphInit, this->elements); + + for (i = 0; i < 100; i++) { + this->bodySegsPos[i].x = this->actor.world.pos.x; + this->bodySegsPos[i].y = this->actor.world.pos.y; + this->bodySegsPos[i].z = this->actor.world.pos.z; + if (i < 30) { + this->centerMane.pos[i].x = this->actor.world.pos.x; + this->centerMane.pos[i].y = this->actor.world.pos.y; + this->centerMane.pos[i].z = this->actor.world.pos.z; + } + } + + this->actor.colChkInfo.health = 24; + this->skinSegments = 18; + if (this->introState == BFD_CS_NONE) { + this->actionFunc = BossFd_Wait; + } else { + BossFd_SetupFly(this, globalCtx); + } + + if (Flags_GetClear(globalCtx, globalCtx->roomCtx.curRoom.num)) { + Actor_Kill(&this->actor); + Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_DOOR_WARP1, 0.0f, 100.0f, 0.0f, 0, 0, 0, + -1); + Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_ITEM_B_HEART, 0.0f, 100.0f, 200.0f, 0, 0, 0, 0); + } else { + Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_BOSS_FD2, this->actor.world.pos.x, + this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, 0, this->introState); + } +} + +void BossFd_Destroy(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + BossFd* this = THIS; + + SkelAnime_Free(&this->skelAnimeHead, globalCtx); + SkelAnime_Free(&this->skelAnimeRightArm, globalCtx); + SkelAnime_Free(&this->skelAnimeLeftArm, globalCtx); + Collider_DestroyJntSph(globalCtx, &this->collider); +} + +s32 BossFd_IsFacingLink(BossFd* this) { + return ABS((s16)(this->actor.yawTowardsPlayer - this->actor.world.rot.y)) < 0x2000; +} + +void BossFd_SetupFly(BossFd* this, GlobalContext* globalCtx) { + Animation_PlayOnce(&this->skelAnimeHead, &gVolvagiaHeadEmergeAnim); + Animation_PlayOnce(&this->skelAnimeRightArm, &gVolvagiaRightArmEmergeAnim); + Animation_PlayOnce(&this->skelAnimeLeftArm, &gVolvagiaLeftArmEmergeAnim); + this->actionFunc = BossFd_Fly; + this->fwork[BFD_TURN_RATE_MAX] = 1000.0f; +} + +static Vec3f sHoleLocations[] = { + { 0.0f, 90.0f, -243.0f }, { 0.0f, 90.0f, 0.0f }, { 0.0f, 90.0f, 243.0f }, + { -243.0f, 90.0f, -243.0f }, { -243.0f, 90.0f, 0.0f }, { -243.0f, 90.0f, 243.0f }, + { 243.0f, 90.0f, -243.0f }, { 243.0f, 90.0f, 0.0f }, { 243.0f, 90.0f, 243.0f }, }; -*/ -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/func_808CADC0.s") -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/func_808CAE8C.s") +static Vec3f sCeilingTargets[] = { + { 0.0f, 900.0f, -243.0f }, { 243.0, 900.0f, -100.0f }, { 243.0f, 900.0f, 100.0f }, + { 0.0f, 900.0f, 243.0f }, { -243.0f, 900.0f, 100.0f }, { -243.0, 900.0f, -100.0f }, +}; + +#ifdef NON_MATCHING +// Somehow doesn't use rodata value D_808D1EB4 = 0.1f. It would occur after the 85.56f float +// literal in case 6 of the boss intro switch statement but before the next switch statement. +// All instructions match. +void BossFd_Fly(BossFd* this, GlobalContext* globalCtx) { + u8 sp1CF = false; + u8 temp_rand; + s16 i1; + s16 i2; + s16 i3; + f32 dx; + f32 dy; + f32 dz; + Player* player = PLAYER; + f32 angleToTarget; + f32 pitchToTarget; + Vec3f* holePosition1; + f32 temp_y; + f32 temp_x; + f32 temp_z; + s32 pad19C; + + SkelAnime_Update(&this->skelAnimeHead); + SkelAnime_Update(&this->skelAnimeRightArm); + SkelAnime_Update(&this->skelAnimeLeftArm); + dx = this->targetPosition.x - this->actor.world.pos.x; + dy = this->targetPosition.y - this->actor.world.pos.y; + dz = this->targetPosition.z - this->actor.world.pos.z; + dx += Math_SinS((2096.0f + this->fwork[BFD_FLY_WOBBLE_RATE]) * this->work[BFD_MOVE_TIMER]) * + this->fwork[BFD_FLY_WOBBLE_AMP]; + dy += Math_SinS((1096.0f + this->fwork[BFD_FLY_WOBBLE_RATE]) * this->work[BFD_MOVE_TIMER]) * + this->fwork[BFD_FLY_WOBBLE_AMP]; + dz += Math_SinS((1796.0f + this->fwork[BFD_FLY_WOBBLE_RATE]) * this->work[BFD_MOVE_TIMER]) * + this->fwork[BFD_FLY_WOBBLE_AMP]; + angleToTarget = (s16)(Math_FAtan2F(dx, dz) * (0x8000 / M_PI)); + pitchToTarget = (s16)(Math_FAtan2F(dy, sqrtf(SQ(dx) + SQ(dz))) * (0x8000 / M_PI)); + + osSyncPrintf("MODE %d\n", this->work[BFD_ACTION_STATE]); + + Math_ApproachF(&this->fwork[BFD_BODY_PULSE], 0.1f, 1.0f, 0.02); + + // Boss Intro Cutscene + + if (this->introState != BFD_CS_NONE) { + Player* player2 = PLAYER; + Camera* mainCam = Gameplay_GetCamera(globalCtx, MAIN_CAM); + + switch (this->introState) { + case BFD_CS_WAIT: + this->fogMode = 3; + this->targetPosition.x = 0.0f; + this->targetPosition.y = -110.0f; + this->targetPosition.z = 0.0; + this->fwork[BFD_TURN_RATE_MAX] = 10000.0f; + this->work[BFD_ACTION_STATE] = BOSSFD_WAIT_INTRO; + if ((fabsf(player2->actor.world.pos.z) < 80.0f) && + (fabsf(player2->actor.world.pos.x - 340.0f) < 60.0f)) { + + this->introState = BFD_CS_START; + func_80064520(globalCtx, &globalCtx->csCtx); + func_8002DF54(globalCtx, &this->actor, 8); + this->introCamera = Gameplay_CreateSubCamera(globalCtx); + Gameplay_ChangeCameraStatus(globalCtx, MAIN_CAM, CAM_STAT_WAIT); + Gameplay_ChangeCameraStatus(globalCtx, this->introCamera, CAM_STAT_ACTIVE); + player2->actor.world.pos.x = 380.0f; + player2->actor.world.pos.y = 100.0f; + player2->actor.world.pos.z = 0.0f; + player2->actor.shape.rot.y = player2->actor.world.rot.y = -0x4000; + player2->actor.speedXZ = 0.0f; + this->camData.eye.x = player2->actor.world.pos.x - 70.0f; + this->camData.eye.y = player2->actor.world.pos.y + 40.0f; + this->camData.eye.z = player2->actor.world.pos.z + 70.0f; + this->camData.at.x = player2->actor.world.pos.x; + this->camData.at.y = player2->actor.world.pos.y + 30.0f; + this->camData.at.z = player2->actor.world.pos.z; + this->camData.nextEye.x = player2->actor.world.pos.x - 50.0f + 18.0f; + this->camData.nextEye.y = player2->actor.world.pos.y + 40; + this->camData.nextEye.z = player2->actor.world.pos.z + 50.0f - 18.0f; + this->camData.nextAt.x = player2->actor.world.pos.x; + this->camData.nextAt.y = player2->actor.world.pos.y + 50.0f; + this->camData.nextAt.z = player2->actor.world.pos.z; + BossFd_SetCameraSpeed(this, 1.0f); + this->camData.atMaxVel.x = this->camData.atMaxVel.y = this->camData.atMaxVel.z = 0.05f; + this->camData.eyeMaxVel.x = this->camData.eyeMaxVel.y = this->camData.eyeMaxVel.z = 0.05f; + this->timers[0] = 0; + this->camData.speedMod = 0.0f; + this->camData.accel = 0.0f; + if (gSaveContext.eventChkInf[7] & 8) { + this->introState = BFD_CS_EMERGE; + this->camData.nextEye.x = player2->actor.world.pos.x + 100.0f + 300.0f - 600.0f; + this->camData.nextEye.y = player2->actor.world.pos.y + 100.0f - 50.0f; + this->camData.nextEye.z = player2->actor.world.pos.z + 200.0f - 150.0f; + this->camData.nextAt.x = 0.0f; + this->camData.nextAt.y = 120.0f; + this->camData.nextAt.z = 0.0f; + BossFd_SetCameraSpeed(this, 0.5f); + this->camData.eyeMaxVel.x = this->camData.eyeMaxVel.y = this->camData.eyeMaxVel.z = 0.1f; + this->camData.atMaxVel.x = this->camData.atMaxVel.y = this->camData.atMaxVel.z = 0.1f; + this->camData.accel = 0.005f; + this->timers[0] = 0; + this->holeIndex = 1; + this->targetPosition.x = sHoleLocations[this->holeIndex].x; + this->targetPosition.y = sHoleLocations[this->holeIndex].y - 200.0f; + this->targetPosition.z = sHoleLocations[this->holeIndex].z; + this->timers[0] = 50; + this->work[BFD_ACTION_STATE] = BOSSFD_EMERGE; + this->actor.world.rot.x = 0x4000; + this->work[BFD_MOVE_TIMER] = 0; + this->timers[3] = 250; + this->timers[2] = 470; + this->fwork[BFD_FLY_SPEED] = 5.0f; + } + } + break; + case BFD_CS_START: + if (this->timers[0] == 0) { + this->camData.accel = 0.0010000002f; + this->timers[0] = 100; + this->introState = BFD_CS_LOOK_LINK; + } + case BFD_CS_LOOK_LINK: + player2->actor.world.pos.x = 380.0f; + player2->actor.world.pos.y = 100.0f; + player2->actor.world.pos.z = 0.0f; + player2->actor.speedXZ = 0.0f; + player2->actor.shape.rot.y = player2->actor.world.rot.y = -0x4000; + if (this->timers[0] == 50) { + this->fogMode = 1; + } + if (this->timers[0] < 50) { + Audio_PlaySoundGeneral(NA_SE_EN_DODO_K_ROLL - SFX_FLAG, &this->actor.projectedPos, 4, &D_801333E0, + &D_801333E0, &D_801333E8); + this->camData.yMod = Math_CosS(this->work[BFD_MOVE_TIMER] * 0x8000) * this->camData.shake; + Math_ApproachF(&this->camData.shake, 2.0f, 1.0f, 0.8 * 0.01f); + } + if (this->timers[0] == 40) { + func_8002DF54(globalCtx, &this->actor, 0x13); + } + if (this->timers[0] == 0) { + this->introState = BFD_CS_LOOK_GROUND; + this->camData.nextAt.y = player2->actor.world.pos.y + 10.0f; + this->camData.atMaxVel.y = 0.2f; + this->camData.speedMod = 0.0f; + this->camData.accel = 0.02f; + this->timers[0] = 70; + this->work[BFD_MOVE_TIMER] = 0; + } + break; + case BFD_CS_LOOK_GROUND: + this->camData.yMod = Math_CosS(this->work[BFD_MOVE_TIMER] * 0x8000) * this->camData.shake; + Math_ApproachF(&this->camData.shake, 2.0f, 1.0f, 0.8 * 0.01f); + Audio_PlaySoundGeneral(NA_SE_EN_DODO_K_ROLL - SFX_FLAG, &this->actor.projectedPos, 4, &D_801333E0, + &D_801333E0, &D_801333E8); + if (this->timers[0] == 0) { + this->introState = BFD_CS_COLLAPSE; + this->camData.nextEye.x = player2->actor.world.pos.x + 100.0f + 300.0f; + this->camData.nextEye.y = player2->actor.world.pos.y + 100.0f; + this->camData.nextEye.z = player2->actor.world.pos.z + 200.0f; + this->camData.nextAt.x = player2->actor.world.pos.x; + this->camData.nextAt.y = player2->actor.world.pos.y - 150.0f; + this->camData.nextAt.z = player2->actor.world.pos.z - 50.0f; + BossFd_SetCameraSpeed(this, 0.1f); + this->timers[0] = 170; + this->camData.speedMod = 0.0f; + this->camData.accel = 0.0f; + func_8002DF54(globalCtx, &this->actor, 0x14); + } + break; + case BFD_CS_COLLAPSE: + this->camData.accel = 0.005f; + this->camData.yMod = Math_CosS(this->work[BFD_MOVE_TIMER] * 0x8000) * this->camData.shake; + Math_ApproachF(&this->camData.shake, 2.0f, 1.0f, 0.8 * 0.01f); + Audio_PlaySoundGeneral(NA_SE_EN_DODO_K_ROLL - SFX_FLAG, &this->actor.projectedPos, 4, &D_801333E0, + &D_801333E0, &D_801333E8); + if (this->timers[0] == 100) { + this->platformSignal = VBSIMA_COLLAPSE; + } + if (this->timers[0] == 0) { + this->introState = BFD_CS_EMERGE; + this->camData.speedMod = 0.0f; + this->camData.nextEye.x = player2->actor.world.pos.x + 100.0f + 300.0f - 600.0f; + this->camData.nextEye.y = player2->actor.world.pos.y + 100.0f - 50.0f; + this->camData.nextEye.z = player2->actor.world.pos.z + 200.0f - 150.0f; + this->camData.nextAt.x = 0.0f; + this->camData.nextAt.y = 120.0f; + this->camData.nextAt.z = 0.0f; + BossFd_SetCameraSpeed(this, 0.5f); + this->camData.atMaxVel.x = this->camData.atMaxVel.y = this->camData.atMaxVel.z = 0.1f; + this->camData.eyeMaxVel.x = this->camData.eyeMaxVel.y = this->camData.eyeMaxVel.z = 0.1f; + this->camData.accel = 0.005f; + this->timers[0] = 0; + this->holeIndex = 1; + this->targetPosition.x = sHoleLocations[this->holeIndex].x; + this->targetPosition.y = sHoleLocations[this->holeIndex].y - 200.0f; + this->targetPosition.z = sHoleLocations[this->holeIndex].z; + this->timers[0] = 50; + this->work[BFD_ACTION_STATE] = BOSSFD_EMERGE; + this->actor.world.rot.x = 0x4000; + this->work[BFD_MOVE_TIMER] = 0; + this->timers[3] = 250; + this->timers[2] = 470; + this->fwork[BFD_FLY_SPEED] = 5.0f; + } + break; + case BFD_CS_EMERGE: + osSyncPrintf("WAY_SPD X = %f\n", this->camData.atVel.x); + osSyncPrintf("WAY_SPD Y = %f\n", this->camData.atVel.y); + osSyncPrintf("WAY_SPD Z = %f\n", this->camData.atVel.z); + if ((this->timers[3] > 190) && !(gSaveContext.eventChkInf[7] & 8)) { + Audio_PlaySoundGeneral(NA_SE_EN_DODO_K_ROLL - SFX_FLAG, &this->actor.projectedPos, 4, &D_801333E0, + &D_801333E0, &D_801333E8); + } + if (this->timers[3] == 190) { + this->camData.atMaxVel.x = this->camData.atMaxVel.y = this->camData.atMaxVel.z = 0.05f; + this->platformSignal = VBSIMA_KILL; + func_8002DF54(globalCtx, &this->actor, 1); + } + if (this->actor.world.pos.y > 120.0f) { + this->camData.nextAt = this->actor.world.pos; + this->camData.atVel.x = 190.0f; + this->camData.atVel.y = 85.56f; + this->camData.atVel.z = 25.0f; + } else { + Math_ApproachF(&this->camData.shake, 2.0f, 1.0f, 0.1 * 0.08f); + this->camData.yMod = Math_CosS(this->work[BFD_MOVE_TIMER] * 0x8000) * this->camData.shake; + } + if (this->timers[3] == 160) { + Audio_SetBGM(0x6B); + } + if ((this->timers[3] == 130) && !(gSaveContext.eventChkInf[7] & 8)) { + TitleCard_InitBossName(globalCtx, &globalCtx->actorCtx.titleCtx, + SEGMENTED_TO_VIRTUAL(&gVolvagiaBossTitleCardTex), 0xA0, 0xB4, 0x80, 0x28); + } + if (this->timers[3] <= 100) { + this->camData.eyeVel.x = this->camData.eyeVel.y = this->camData.eyeVel.z = 2.0f; + this->camData.nextEye.x = player2->actor.world.pos.x + 50.0f; + this->camData.nextEye.y = player2->actor.world.pos.y + 50.0f; + this->camData.nextEye.z = player2->actor.world.pos.z + 50.0f; + } + if (this->work[BFD_ACTION_STATE] == BOSSFD_FLY_HOLE) { + switch (this->introFlyState) { + case INTRO_FLY_EMERGE: + this->timers[5] = 100; + this->introFlyState = INTRO_FLY_HOLE; + case INTRO_FLY_HOLE: + if (this->timers[5] == 0) { + this->introFlyState = INTRO_FLY_CAMERA; + this->timers[5] = 75; + } + break; + case INTRO_FLY_CAMERA: + this->targetPosition = this->camData.eye; + if (this->timers[5] == 0) { + this->timers[0] = 0; + this->holeIndex = 7; + this->targetPosition.x = sHoleLocations[this->holeIndex].x; + this->targetPosition.y = sHoleLocations[this->holeIndex].y + 200.0f + 50.0f; + this->targetPosition.z = sHoleLocations[this->holeIndex].z; + this->introFlyState = INTRO_FLY_RETRAT; + } + if (this->timers[5] == 30) { + this->work[BFD_ROAR_TIMER] = 40; + this->fireBreathTimer = 20; + } + case INTRO_FLY_RETRAT: + break; + } + } + osSyncPrintf("this->timer[2] = %d\n", this->timers[2]); + osSyncPrintf("this->timer[5] = %d\n", this->timers[5]); + if (this->timers[2] == 0) { + mainCam->eye = this->camData.eye; + mainCam->eyeNext = this->camData.eye; + mainCam->at = this->camData.at; + func_800C08AC(globalCtx, this->introCamera, 0); + this->introState = this->introFlyState = this->introCamera = BFD_CS_NONE; + func_80064534(globalCtx, &globalCtx->csCtx); + func_8002DF54(globalCtx, &this->actor, 7); + this->actionFunc = BossFd_Wait; + this->handoffSignal = FD2_SIGNAL_GROUND; + gSaveContext.eventChkInf[7] |= 8; + } + break; + } + BossFd_UpdateCamera(this, globalCtx); + } else { + this->fwork[BFD_FLY_SPEED] = 5.0f; + } + + // Attacks and Death Cutscene + + switch (this->work[BFD_ACTION_STATE]) { + case BOSSFD_FLY_MAIN: + sp1CF = true; + if (this->timers[0] == 0) { + if (this->actor.colChkInfo.health == 0) { + this->work[BFD_ACTION_STATE] = BOSSFD_DEATH_START; + this->timers[0] = 0; + this->timers[1] = 100; + } else { + if (this->introState != BFD_CS_NONE) { + this->holeIndex = 6; + } else { + do { + temp_rand = Rand_ZeroFloat(8.9f); + } while (temp_rand == this->holeIndex); + this->holeIndex = temp_rand; + } + this->targetPosition.x = sHoleLocations[this->holeIndex].x; + this->targetPosition.y = sHoleLocations[this->holeIndex].y + 200.0f + 50.0f; + this->targetPosition.z = sHoleLocations[this->holeIndex].z; + this->fwork[BFD_TURN_RATE] = 0.0f; + this->fwork[BFD_TURN_RATE_MAX] = 1000.0f; + if (this->introState != BFD_CS_NONE) { + this->timers[0] = 10050; + } else { + this->timers[0] = 20; + } + this->fwork[BFD_FLY_WOBBLE_AMP] = 100.0f; + this->work[BFD_ACTION_STATE] = BOSSFD_FLY_HOLE; + + if (this->work[BFD_START_ATTACK]) { + this->work[BFD_START_ATTACK] = false; + this->work[BFD_FLY_COUNT]++; + if (this->work[BFD_FLY_COUNT] & 1) { + this->work[BFD_ACTION_STATE] = BOSSFD_FLY_CHASE; + this->timers[0] = 300; + this->fwork[BFD_TURN_RATE_MAX] = 900.0f; + this->fwork[BFD_TARGET_Y_OFFSET] = 300.0f; + this->work[BFD_UNK_234] = this->work[BFD_UNK_236] = 0; + } else { + this->work[BFD_ACTION_STATE] = BOSSFD_FLY_CEILING; + } + } + } + } + break; + case BOSSFD_FLY_HOLE: + if ((this->timers[0] == 0) && (sqrtf(SQ(dx) + SQ(dy) + SQ(dz)) < 100.0f)) { + this->work[BFD_ACTION_STATE] = BOSSFD_BURROW; + this->targetPosition.y = sHoleLocations[this->holeIndex].y - 70.0f; + this->fwork[BFD_TURN_RATE_MAX] = 10000.0f; + this->fwork[BFD_FLY_WOBBLE_AMP] = 0.0f; + this->timers[0] = 150; + this->work[BFD_ROAR_TIMER] = 40; + this->holePosition.x = this->targetPosition.x; + this->holePosition.z = this->targetPosition.z; + } + break; + case BOSSFD_BURROW: + sp1CF = true; + if (this->timers[0] == 0) { + this->actionFunc = BossFd_Wait; + this->handoffSignal = FD2_SIGNAL_GROUND; + } + break; + case BOSSFD_EMERGE: + if ((this->timers[0] == 0) && (sqrtf(SQ(dx) + SQ(dy) + SQ(dz)) < 100.0f)) { + this->actor.world.pos = this->targetPosition; + this->work[BFD_ACTION_STATE] = BOSSFD_FLY_MAIN; + this->actor.world.rot.x = 0x4000; + this->targetPosition.y = sHoleLocations[this->holeIndex].y + 200.0f; + this->timers[4] = 80; + this->fwork[BFD_TURN_RATE_MAX] = 1000.0f; + this->fwork[BFD_FLY_WOBBLE_AMP] = 0.0f; + this->holePosition.x = this->targetPosition.x; + this->holePosition.z = this->targetPosition.z; + + func_80033E1C(globalCtx, 1, 0x50, 0x5000); + if (this->introState != BFD_CS_NONE) { + this->timers[0] = 50; + } else { + this->timers[0] = 50; + } + } + break; + case BOSSFD_FLY_CEILING: + this->fwork[BFD_FLY_SPEED] = 8; + this->targetPosition.x = 0.0f; + this->targetPosition.y = 700.0f; + this->targetPosition.z = -300.0f; + this->fwork[BFD_FLY_WOBBLE_AMP] = 200.0f; + this->fwork[BFD_TURN_RATE_MAX] = 3000.0f; + if (this->actor.world.pos.y > 700.0f) { + this->work[BFD_ACTION_STATE] = BOSSFD_DROP_ROCKS; + this->timers[0] = 25; + this->timers[2] = 150; + this->work[BFD_CEILING_TARGET] = 0; + } + break; + case BOSSFD_DROP_ROCKS: + this->fwork[BFD_FLY_SPEED] = 8; + this->fwork[BFD_FLY_WOBBLE_AMP] = 200.0f; + this->fwork[BFD_TURN_RATE_MAX] = 10000.0f; + this->targetPosition.x = sCeilingTargets[this->work[BFD_CEILING_TARGET]].x; + this->targetPosition.y = sCeilingTargets[this->work[BFD_CEILING_TARGET]].y + 900.0f; + this->targetPosition.z = sCeilingTargets[this->work[BFD_CEILING_TARGET]].z; + if (this->timers[0] == 0) { + this->timers[0] = 25; + this->work[BFD_CEILING_TARGET]++; + if (this->work[BFD_CEILING_TARGET] >= 6) { + this->work[BFD_CEILING_TARGET] = 0; + } + } + Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 50.0f, 50.0f, 100.0f, 2); + if (this->timers[1] == 0) { + osSyncPrintf("BGCHECKKKKKKKKKKKKKKKKKKKKKKK\n"); + if (this->actor.bgCheckFlags & 0x10) { + this->fwork[BFD_CEILING_BOUNCE] = -18384.0f; + this->timers[1] = 10; + Audio_PlaySoundGeneral(NA_SE_EV_EXPLOSION, &this->actor.projectedPos, 4, &D_801333E0, &D_801333E0, + &D_801333E8); + func_80033E1C(globalCtx, 3, 0xA, 0x7530); + this->work[BFD_ROCK_TIMER] = 300; + } + } else { + pitchToTarget = this->fwork[BFD_CEILING_BOUNCE]; + Math_ApproachZeroF(&this->fwork[BFD_CEILING_BOUNCE], 1.0f, 1000.0f); + } + if (this->timers[2] == 0) { + this->work[BFD_ACTION_STATE] = BOSSFD_FLY_MAIN; + this->timers[0] = 0; + this->work[BFD_START_ATTACK] = false; + } + break; + case BOSSFD_FLY_CHASE: + this->actor.flags |= 0x1000000; + temp_y = Math_SinS(this->work[BFD_MOVE_TIMER] * 2396.0f) * 30.0f + this->fwork[BFD_TARGET_Y_OFFSET]; + this->targetPosition.x = player->actor.world.pos.x; + this->targetPosition.y = player->actor.world.pos.y + temp_y + 30.0f; + this->targetPosition.z = player->actor.world.pos.z; + this->fwork[BFD_FLY_WOBBLE_AMP] = 0.0f; + if (((this->timers[0] % 64) == 0) && (this->timers[0] < 450)) { + this->work[BFD_ROAR_TIMER] = 40; + if (BossFd_IsFacingLink(this)) { + this->fireBreathTimer = 20; + } + } + if ((this->work[BFD_DAMAGE_FLASH_TIMER] != 0) || (this->timers[0] == 0) || + (player->actor.world.pos.y < 70.0f)) { + this->work[BFD_ACTION_STATE] = BOSSFD_FLY_MAIN; + this->timers[0] = 0; + this->work[BFD_START_ATTACK] = false; + } else { + Math_ApproachF(&this->fwork[BFD_TARGET_Y_OFFSET], 50.0, 1.0f, 2.0f); + } + break; + case BOSSFD_DEATH_START: + if (sqrtf(SQ(dx) + SQ(dz)) < 50.0f) { + this->timers[0] = 0; + } + if (this->timers[0] == 0) { + this->timers[0] = (s16)Rand_ZeroFloat(10.0f) + 10; + do { + this->targetPosition.x = Rand_CenteredFloat(200.0f); + this->targetPosition.y = 390.0f; + this->targetPosition.z = Rand_CenteredFloat(200.0f); + temp_x = this->targetPosition.x - this->actor.world.pos.x; + temp_z = this->targetPosition.z - this->actor.world.pos.z; + } while (!(sqrtf(SQ(temp_x) + SQ(temp_z)) > 100.0f)); + } + this->fwork[BFD_FLY_WOBBLE_AMP] = 200.0f; + this->fwork[BFD_FLY_WOBBLE_RATE] = 1000.0f; + this->fwork[BFD_TURN_RATE_MAX] = 10000.0f; + Math_ApproachF(&this->fwork[BFD_BODY_PULSE], 0.3f, 1.0f, 0.05f); + if (this->timers[1] == 0) { + this->work[BFD_ACTION_STATE] = BOSSFD_SKIN_BURN; + this->timers[0] = 30; + } + break; + case BOSSFD_SKIN_BURN: + this->targetPosition.x = 0.0f; + this->targetPosition.y = 390.0f; + this->targetPosition.z = 0.0f; + this->fwork[BFD_FLY_WOBBLE_AMP] = 200.0f; + this->fwork[BFD_FLY_WOBBLE_RATE] = 1000.0f; + this->fwork[BFD_TURN_RATE_MAX] = 2000.0f; + Math_ApproachF(&this->fwork[BFD_BODY_PULSE], 0.3f, 1.0f, 0.05f); + if ((this->timers[0] == 0) && ((this->work[BFD_MOVE_TIMER] % 4) == 0)) { + if (this->skinSegments != 0) { + this->skinSegments--; + if (this->skinSegments == 0) { + Audio_SetBGM(0x21); + } + } else { + this->work[BFD_ACTION_STATE] = BOSSFD_BONES_FALL; + this->timers[0] = 30; + } + } + if ((this->work[BFD_MOVE_TIMER] % 32) == 0) { + this->work[BFD_ROAR_TIMER] = 40; + } + + if (this->skinSegments != 0) { + Vec3f sp188; + Vec3f sp17C = { 0.0f, 0.0f, 0.0f }; + Vec3f sp170; + Vec3f sp164 = { 0.0f, 0.03f, 0.0f }; + Vec3f sp158; + f32 pad154; + s16 temp_rand2; + s16 sp150; + + if (this->fogMode == 0) { + globalCtx->envCtx.unk_D8 = 0; + } + this->fogMode = 0xA; + + sp150 = 1; + if (this->work[BFD_MOVE_TIMER] & 0x1C) { + Audio_PlaySoundGeneral(NA_SE_EN_VALVAISA_BURN - SFX_FLAG, &this->actor.projectedPos, 4, &D_801333E0, + &D_801333E0, &D_801333E8); + } + for (i1 = 0; i1 < sp150; i1++) { + if (sp150) { // Needed for matching + temp_rand2 = Rand_ZeroFloat(99.9f); + + sp188.x = this->bodySegsPos[temp_rand2].x; + sp188.y = this->bodySegsPos[temp_rand2].y - 10.0f; + sp188.z = this->bodySegsPos[temp_rand2].z; + + sp164.y = 0.03f; + + EffectSsKFire_Spawn(globalCtx, &sp188, &sp17C, &sp164, (s16)Rand_ZeroFloat(20.0f) + 40, 0x64); + + for (i2 = 0; i2 < 15; i2++) { + sp170.x = Rand_CenteredFloat(20.0f); + sp170.y = Rand_CenteredFloat(20.0f); + sp170.z = Rand_CenteredFloat(20.0f); + + sp158.y = 0.4f; + sp158.x = Rand_CenteredFloat(0.5f); + sp158.z = Rand_CenteredFloat(0.5f); + + BossFd_SpawnEmber(this->effects, &sp188, &sp170, &sp158, (s16)Rand_ZeroFloat(3.0f) + 8); + } + } + } + } + break; + case BOSSFD_BONES_FALL: + this->work[BFD_STOP_FLAG] = true; + this->fogMode = 3; + if (this->timers[0] < 18) { + this->bodyFallApart[this->timers[0]] = 1; + } + if (this->timers[0] == 0) { + this->work[BFD_ACTION_STATE] = BOSSFD_SKULL_PAUSE; + this->timers[0] = 15; + this->work[BFD_CEILING_TARGET] = 0; + player->actor.world.pos.y = 90.0f; + player->actor.world.pos.x = 40.0f; + player->actor.world.pos.z = 150.0f; + } + break; + case BOSSFD_SKULL_PAUSE: + if (this->timers[0] == 0) { + this->work[BFD_ACTION_STATE] = BOSSFD_SKULL_FALL; + this->timers[0] = 20; + this->work[BFD_STOP_FLAG] = false; + } + break; + case BOSSFD_SKULL_FALL: + this->fwork[BFD_TURN_RATE] = this->fwork[BFD_TURN_RATE_MAX] = this->actor.speedXZ = + this->fwork[BFD_FLY_SPEED] = 0; + + if (this->timers[0] == 1) { + this->actor.world.pos.x = 0; + this->actor.world.pos.y = 900.0f; + this->actor.world.pos.z = 150.0f; + this->actor.world.rot.x = this->actor.world.rot.y = 0; + this->actor.shape.rot.z = 0x1200; + this->actor.velocity.x = 0; + this->actor.velocity.z = 0; + } + if (this->timers[0] == 0) { + if (this->actor.world.pos.y <= 110.0f) { + this->actor.world.pos.y = 110.0f; + this->actor.velocity.y = 0; + if (this->work[BFD_CEILING_TARGET] == 0) { + this->work[BFD_CEILING_TARGET]++; + this->timers[1] = 60; + this->work[BFD_CAM_SHAKE_TIMER] = 20; + Audio_PlaySoundGeneral(NA_SE_EN_VALVAISA_LAND2, &this->actor.projectedPos, 4, &D_801333E0, + &D_801333E0, &D_801333E8); + func_8002DF54(globalCtx, &this->actor, 5); + for (i1 = 0; i1 < 15; i1++) { + Vec3f sp144 = { 0.0f, 0.0f, 0.0f }; + Vec3f sp138 = { 0.0f, 0.0f, 0.0f }; + Vec3f sp12C; + + sp144.x = Rand_CenteredFloat(8.0f); + sp144.y = Rand_ZeroFloat(1.0f); + sp144.z = Rand_CenteredFloat(8.0f); + + sp138.y = 0.3f; + + sp12C.x = Rand_CenteredFloat(10.0f) + this->actor.world.pos.x; + sp12C.y = Rand_CenteredFloat(10.0f) + this->actor.world.pos.y; + sp12C.z = Rand_CenteredFloat(10.0f) + this->actor.world.pos.z; + BossFd_SpawnDust(this->effects, &sp12C, &sp144, &sp138, Rand_ZeroFloat(100.0f) + 300); + } + } + } else { + this->actor.velocity.y -= 1.0f; + } + } else { + this->actor.velocity.y = 0; + } + if (this->timers[1] == 1) { + this->work[BFD_ACTION_STATE] = BOSSFD_SKULL_BURN; + this->timers[0] = 70; + } + break; + case BOSSFD_SKULL_BURN: + this->actor.velocity.y = 0.0f; + this->actor.world.pos.y = 110.0f; + this->fwork[BFD_TURN_RATE] = this->fwork[BFD_TURN_RATE_MAX] = this->actor.speedXZ = + this->fwork[BFD_FLY_SPEED] = 0.0f; + + if ((50 > this->timers[0]) && (this->timers[0] > 0)) { + Vec3f sp120; + Vec3f sp114 = { 0.0f, 0.0f, 0.0f }; + Vec3f sp108 = { 0.0f, 0.03f, 0.0f }; + + Audio_PlaySoundGeneral(NA_SE_EN_GOMA_LAST - SFX_FLAG, &this->actor.projectedPos, 4, &D_801333E0, + &D_801333E0, &D_801333E8); + + sp120.x = Rand_CenteredFloat(40.0f) + this->actor.world.pos.x; + sp120.y = (Rand_CenteredFloat(10.0f) + this->actor.world.pos.y) - 10.0f; + sp120.z = (Rand_CenteredFloat(40.0f) + this->actor.world.pos.z) + 5.0f; + + sp108.y = 0.03f; + + EffectSsKFire_Spawn(globalCtx, &sp120, &sp114, &sp108, (s16)Rand_ZeroFloat(15.0f) + 30, 0); + } + if (this->timers[0] < 20) { + Math_ApproachZeroF(&this->actor.scale.x, 1.0f, 0.0025f); + Actor_SetScale(&this->actor, this->actor.scale.x); + } + if (this->timers[0] == 0) { + this->actionFunc = BossFd_Wait; + this->actor.world.pos.y -= 1000.0f; + } + if (this->timers[0] == 7) { + Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_ITEM_B_HEART, this->actor.world.pos.x, + this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, 0, 0); + } + break; + case BOSSFD_WAIT_INTRO: + break; + } + + // Update body segments and mane + + if (!this->work[BFD_STOP_FLAG]) { + s16 i4; + Vec3f spE0[3]; + Vec3f spBC[3]; + f32 phi_f20; + f32 padB4; + f32 padB0; + f32 padAC; + + Math_ApproachS(&this->actor.world.rot.y, angleToTarget, 0xA, this->fwork[BFD_TURN_RATE]); + + if (((this->work[BFD_ACTION_STATE] == BOSSFD_FLY_CHASE) || + (this->work[BFD_ACTION_STATE] == BOSSFD_FLY_UNUSED)) && + (this->actor.world.pos.y < 110.0f) && (pitchToTarget < 0)) { + pitchToTarget = 0; + Math_ApproachF(&this->actor.world.pos.y, 110.0f, 1.0f, 5.0f); + } + + Math_ApproachS(&this->actor.world.rot.x, pitchToTarget, 0xA, this->fwork[BFD_TURN_RATE]); + Math_ApproachF(&this->fwork[BFD_TURN_RATE], this->fwork[BFD_TURN_RATE_MAX], 1.0f, 20000.0f); + Math_ApproachF(&this->actor.speedXZ, this->fwork[BFD_FLY_SPEED], 1.0f, 0.1f); + if (this->work[BFD_ACTION_STATE] < BOSSFD_SKULL_FALL) { + func_8002D908(&this->actor); + } + func_8002D7EC(&this->actor); + + this->work[BFD_LEAD_BODY_SEG]++; + if (this->work[BFD_LEAD_BODY_SEG] >= 100) { + this->work[BFD_LEAD_BODY_SEG] = 0; + } + i4 = this->work[BFD_LEAD_BODY_SEG]; + this->bodySegsPos[i4].x = this->actor.world.pos.x; + this->bodySegsPos[i4].y = this->actor.world.pos.y; + this->bodySegsPos[i4].z = this->actor.world.pos.z; + this->bodySegsRot[i4].x = (this->actor.world.rot.x / (f32)0x8000) * M_PI; + this->bodySegsRot[i4].y = (this->actor.world.rot.y / (f32)0x8000) * M_PI; + this->bodySegsRot[i4].z = (this->actor.world.rot.z / (f32)0x8000) * M_PI; + + this->work[BFD_LEAD_MANE_SEG]++; + if (this->work[BFD_LEAD_MANE_SEG] >= 30) { + this->work[BFD_LEAD_MANE_SEG] = 0; + } + i4 = this->work[BFD_LEAD_MANE_SEG]; + this->centerMane.scale[i4] = (Math_SinS(this->work[BFD_MOVE_TIMER] * 5596.0f) * 0.3f) + 1.0f; + this->rightMane.scale[i4] = (Math_SinS(this->work[BFD_MOVE_TIMER] * 5496.0f) * 0.3f) + 1.0f; + this->leftMane.scale[i4] = (Math_CosS(this->work[BFD_MOVE_TIMER] * 5696.0f) * 0.3f) + 1.0f; + this->centerMane.pos[i4] = this->centerMane.head; + this->fireManeRot[i4].x = (this->actor.world.rot.x / (f32)0x8000) * M_PI; + this->fireManeRot[i4].y = (this->actor.world.rot.y / (f32)0x8000) * M_PI; + this->fireManeRot[i4].z = (this->actor.world.rot.z / (f32)0x8000) * M_PI; + this->rightMane.pos[i4] = this->rightMane.head; + this->leftMane.pos[i4] = this->leftMane.head; + + if ((0x3000 > this->actor.world.rot.x) && (this->actor.world.rot.x > -0x3000)) { + Math_ApproachF(&this->flattenMane, 1.0f, 1.0f, 0.05f); + } else { + Math_ApproachF(&this->flattenMane, 0.5f, 1.0f, 0.05f); + } + + if (this->work[BFD_ACTION_STATE] < BOSSFD_SKULL_FALL) { + if ((this->actor.prevPos.y < 90.0f) && (90.0f <= this->actor.world.pos.y)) { + this->timers[4] = 80; + func_80033E1C(globalCtx, 1, 80, 0x5000); + this->work[BFD_ROAR_TIMER] = 40; + this->work[BFD_MANE_EMBERS_TIMER] = 30; + this->work[BFD_SPLASH_TIMER] = 10; + } + if ((this->actor.prevPos.y > 90.0f) && (90.0f >= this->actor.world.pos.y)) { + this->timers[4] = 80; + func_80033E1C(globalCtx, 1, 80, 0x5000); + this->work[BFD_MANE_EMBERS_TIMER] = 30; + this->work[BFD_SPLASH_TIMER] = 10; + } + } + + if (!sp1CF) { + spE0[0].x = spE0[0].y = Math_SinS(this->work[BFD_MOVE_TIMER] * 1500.0f) * 3000.0f; + spE0[1].x = Math_SinS(this->work[BFD_MOVE_TIMER] * 2000.0f) * 4000.0f; + spE0[1].y = Math_SinS(this->work[BFD_MOVE_TIMER] * 2200.0f) * 4000.0f; + spE0[2].x = Math_SinS(this->work[BFD_MOVE_TIMER] * 1700.0f) * 2000.0f; + spE0[2].y = Math_SinS(this->work[BFD_MOVE_TIMER] * 1900.0f) * 2000.0f; + spBC[0].x = spBC[0].y = Math_SinS(this->work[BFD_MOVE_TIMER] * 1500.0f) * -3000.0f; + spBC[1].x = Math_SinS(this->work[BFD_MOVE_TIMER] * 2200.0f) * -4000.0f; + spBC[1].y = Math_SinS(this->work[BFD_MOVE_TIMER] * 2000.0f) * -4000.0f; + spBC[2].x = Math_SinS(this->work[BFD_MOVE_TIMER] * 1900.0f) * -2000.0f; + spBC[2].y = Math_SinS(this->work[BFD_MOVE_TIMER] * 1700.0f) * -2000.0f; + + for (i3 = 0; i3 < 3; i3++) { + Math_ApproachF(&this->rightArmRot[i3].x, spE0[i3].x, 1.0f, 1000.0f); + Math_ApproachF(&this->rightArmRot[i3].y, spE0[i3].y, 1.0f, 1000.0f); + Math_ApproachF(&this->leftArmRot[i3].x, spBC[i3].x, 1.0f, 1000.0f); + Math_ApproachF(&this->leftArmRot[i3].y, spBC[i3].y, 1.0f, 1000.0f); + } + } else { + for (i2 = 0; i2 < 3; i2++) { + phi_f20 = 0.0f; + Math_ApproachZeroF(&this->rightArmRot[i2].y, 0.1f, 100.0f); + Math_ApproachZeroF(&this->leftArmRot[i2].y, 0.1f, 100.0f); + if (i2 == 0) { + phi_f20 = -3000.0f; + } + Math_ApproachF(&this->rightArmRot[i2].x, phi_f20, 0.1f, 100.0f); + Math_ApproachF(&this->leftArmRot[i2].x, -phi_f20, 0.1f, 100.0f); + } + } + } +} +#else +static Vec3f D_808D19E0 = { 0.0f, 0.0f, 0.0f }; +static Vec3f D_808D19EC = { 0.0f, 0.03f, 0.0f }; + +static Vec3f D_808D19F8 = { 0.0f, 0.0f, 0.0f }; +static Vec3f D_808D1A04 = { 0.0f, 0.0f, 0.0f }; + +static Vec3f D_808D1A10 = { 0.0f, 0.0f, 0.0f }; +static Vec3f D_808D1A1C = { 0.0f, 0.03f, 0.0f }; +#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/BossFd_Fly.s") +#endif + +void BossFd_Wait(BossFd* this, GlobalContext* globalCtx) { + if (this->handoffSignal == FD2_SIGNAL_FLY) { // Set by BossFd2 + u8 temp_rand; + + this->handoffSignal = FD2_SIGNAL_NONE; + BossFd_SetupFly(this, globalCtx); + do { + temp_rand = Rand_ZeroFloat(8.9f); + } while (temp_rand == this->holeIndex); + this->holeIndex = temp_rand; + if (1) {} // Needed for matching + this->targetPosition.x = sHoleLocations[this->holeIndex].x; + this->targetPosition.y = sHoleLocations[this->holeIndex].y - 200.0f; + this->targetPosition.z = sHoleLocations[this->holeIndex].z; + this->actor.world.pos = this->targetPosition; + + this->timers[0] = 10; + this->work[BFD_ACTION_STATE] = BOSSFD_EMERGE; + this->work[BFD_START_ATTACK] = true; + } + if (this->handoffSignal == FD2_SIGNAL_DEATH) { + this->handoffSignal = FD2_SIGNAL_NONE; + BossFd_SetupFly(this, globalCtx); + this->holeIndex = 1; + this->targetPosition.x = sHoleLocations[1].x; + this->targetPosition.y = sHoleLocations[1].y - 200.0f; + this->targetPosition.z = sHoleLocations[1].z; + this->actor.world.pos = this->targetPosition; + this->timers[0] = 10; + this->work[BFD_ACTION_STATE] = BOSSFD_EMERGE; + } +} + +static Vec3f sFireAudioVec = { 0.0f, 0.0f, 50.0f }; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/func_808CAF5C.s") +void BossFd_Effects(BossFd* this, GlobalContext* globalCtx) { + static Color_RGBA8 colorYellow = { 255, 255, 0, 255 }; + static Color_RGBA8 colorRed = { 255, 10, 0, 255 }; + s16 breathOpacity = 0; + f32 jawAngle; + f32 jawSpeed; + f32 emberRate; + f32 emberSpeed; + s16 eyeStates[] = { EYE_OPEN, EYE_HALF, EYE_CLOSED, EYE_CLOSED, EYE_HALF }; + f32 temp_x; + f32 temp_z; + s16 i; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/func_808CAFF4.s") + if (1) {} // Needed for match -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/func_808CB100.s") + if (this->fogMode == 0) { + globalCtx->envCtx.unk_BF = 0; + globalCtx->envCtx.unk_D8 = 0.5f + 0.5f * Math_SinS(this->work[BFD_VAR_TIMER] * 0x500); + globalCtx->envCtx.unk_DC = 2; + globalCtx->envCtx.unk_BD = 1; + globalCtx->envCtx.unk_BE = 0; + } else if (this->fogMode == 3) { + globalCtx->envCtx.unk_BF = 0; + globalCtx->envCtx.unk_DC = 2; + globalCtx->envCtx.unk_BD = 2; + globalCtx->envCtx.unk_BE = 0; + Math_ApproachF(&globalCtx->envCtx.unk_D8, 1.0f, 1.0f, 0.05f); + } else if (this->fogMode == 2) { + this->fogMode--; + globalCtx->envCtx.unk_BF = 0; + Math_ApproachF(&globalCtx->envCtx.unk_D8, 0.55f + 0.05f * Math_SinS(this->work[BFD_VAR_TIMER] * 0x3E00), 1.0f, + 0.15f); + globalCtx->envCtx.unk_DC = 2; + globalCtx->envCtx.unk_BD = 3; + globalCtx->envCtx.unk_BE = 0; + } else if (this->fogMode == 10) { + this->fogMode = 1; + globalCtx->envCtx.unk_BF = 0; + Math_ApproachF(&globalCtx->envCtx.unk_D8, 0.21f + 0.07f * Math_SinS(this->work[BFD_VAR_TIMER] * 0xC00), 1.0f, + 0.05f); + globalCtx->envCtx.unk_DC = 2; + globalCtx->envCtx.unk_BD = 3; + globalCtx->envCtx.unk_BE = 0; + } else if (this->fogMode == 1) { + Math_ApproachF(&globalCtx->envCtx.unk_D8, 0.0f, 1.0f, 0.03f); + if (globalCtx->envCtx.unk_D8 <= 0.01f) { + this->fogMode = 0; + } + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/func_808CB198.s") + if (this->work[BFD_MANE_EMBERS_TIMER] != 0) { + this->work[BFD_MANE_EMBERS_TIMER]--; + emberSpeed = emberRate = 20.0f; + } else { + emberRate = 3.0f; + emberSpeed = 5.0f; + } + Math_ApproachF(&this->fwork[BFD_MANE_EMBER_RATE], emberRate, 1.0f, 0.1f); + Math_ApproachF(&this->fwork[BFD_MANE_EMBER_SPEED], emberSpeed, 1.0f, 0.5f); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/BossFd_Init.s") + if (((this->work[BFD_VAR_TIMER] % 8) == 0) && (Rand_ZeroOne() < 0.3f)) { + this->work[BFD_BLINK_TIMER] = 4; + } + this->eyeState = eyeStates[this->work[BFD_BLINK_TIMER]]; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/BossFd_Destroy.s") + if (this->work[BFD_BLINK_TIMER] != 0) { + this->work[BFD_BLINK_TIMER]--; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/func_808CB67C.s") + if (this->work[BFD_ROAR_TIMER] != 0) { + if (this->work[BFD_ROAR_TIMER] == 37) { + Audio_PlaySoundGeneral(NA_SE_EN_VALVAISA_ROAR, &this->actor.projectedPos, 4, &D_801333E0, &D_801333E0, + &D_801333E8); + } + jawAngle = 6000.0f; + jawSpeed = 1300.0f; + } else { + jawAngle = (this->work[BFD_VAR_TIMER] & 0x10) ? 0.0f : 1000.0f; + jawSpeed = 500.0f; + } + Math_ApproachF(&this->jawOpening, jawAngle, 0.3f, jawSpeed); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/func_808CB6A8.s") + if (this->work[BFD_ROAR_TIMER] != 0) { + this->work[BFD_ROAR_TIMER]--; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/func_808CB718.s") + if (this->timers[4] != 0) { + Vec3f spawnVel1; + Vec3f spawnAccel1; + Vec3f spawnPos1; + s32 pad; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/func_808CDE30.s") + Audio_PlaySoundGeneral(NA_SE_EN_VALVAISA_APPEAR - SFX_FLAG, &this->actor.projectedPos, 4, &D_801333E0, + &D_801333E0, &D_801333E8); + if (this->work[BFD_SPLASH_TIMER] != 0) { + this->work[BFD_SPLASH_TIMER]--; + if ((this->actor.colChkInfo.health == 0) || + ((this->introState == BFD_CS_EMERGE) && (this->actor.world.rot.x > 0x3000))) { + if ((u8)this->fogMode == 0) { + globalCtx->envCtx.unk_D8 = 0.0f; + } + this->fogMode = 2; + } + for (i = 0; i < 5; i++) { + spawnVel1.x = Rand_CenteredFloat(20.0f); + spawnVel1.y = Rand_ZeroFloat(5.0f) + 4.0f; + spawnVel1.z = Rand_CenteredFloat(20.0f); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/func_808CE01C.s") + spawnAccel1.x = spawnAccel1.z = 0.0f; + spawnAccel1.y = -0.3f; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/func_808CEC34.s") + temp_x = (spawnVel1.x * 20) / 10.0f; + temp_z = (spawnVel1.z * 20) / 10.0f; + spawnPos1.x = temp_x + this->holePosition.x; + spawnPos1.y = 100.0f; + spawnPos1.z = temp_z + this->holePosition.z; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/BossFd_Update.s") + func_8002836C(globalCtx, &spawnPos1, &spawnVel1, &spawnAccel1, &colorYellow, &colorRed, + (s16)Rand_ZeroFloat(150.0f) + 800, 10, (s16)Rand_ZeroFloat(5.0f) + 17); + } + } else { + for (i = 0; i < 2; i++) { + spawnVel1.x = Rand_CenteredFloat(10.0f); + spawnVel1.y = Rand_ZeroFloat(3.0f) + 3.0f; + spawnVel1.z = Rand_CenteredFloat(10.0f); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/func_808CF448.s") + spawnAccel1.x = spawnAccel1.z = 0.0f; + spawnAccel1.y = -0.3f; + temp_x = (spawnVel1.x * 50) / 10.0f; + temp_z = (spawnVel1.z * 50) / 10.0f; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/func_808CF898.s") + spawnPos1.x = temp_x + this->holePosition.x; + spawnPos1.y = 100.0f; + spawnPos1.z = temp_z + this->holePosition.z; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/BossFd_Draw.s") + func_8002836C(globalCtx, &spawnPos1, &spawnVel1, &spawnAccel1, &colorYellow, &colorRed, 500, 10, 20); + } + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/func_808D00A4.s") + for (i = 0; i < 8; i++) { + spawnVel1.x = Rand_CenteredFloat(20.0f); + spawnVel1.y = Rand_ZeroFloat(10.0f); + spawnVel1.z = Rand_CenteredFloat(20.0f); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/func_808D01C0.s") + spawnAccel1.y = 0.4f; + spawnAccel1.x = Rand_CenteredFloat(0.5f); + spawnAccel1.z = Rand_CenteredFloat(0.5f); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/func_808D02DC.s") + spawnPos1.x = Rand_CenteredFloat(60.0) + this->holePosition.x; + spawnPos1.y = Rand_ZeroFloat(40.0f) + 100.0f; + spawnPos1.z = Rand_CenteredFloat(60.0) + this->holePosition.z; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/func_808D07A4.s") + BossFd_SpawnEmber(this->effects, &spawnPos1, &spawnVel1, &spawnAccel1, (s16)Rand_ZeroFloat(1.5f) + 6); + } + } + + if ((this->fireBreathTimer != 0) && (this->fireBreathTimer < 17)) { + breathOpacity = (this->fireBreathTimer >= 6) ? 255 : this->fireBreathTimer * 50; + } + if (breathOpacity != 0) { + f32 spawnAngleX; + f32 spawnAngleY; + Vec3f spawnSpeed2 = { 0.0f, 0.0f, 0.0f }; + Vec3f spawnVel2; + Vec3f spawnAccel2 = { 0.0f, 0.0f, 0.0f }; + Vec3f spawnPos2; + + this->fogMode = 2; + spawnSpeed2.z = 30.0f; + + Audio_PlaySoundGeneral(NA_SE_EN_VALVAISA_FIRE - SFX_FLAG, &sFireAudioVec, 4, &D_801333E0, &D_801333E0, + &D_801333E8); + spawnPos2 = this->headPos; + + spawnAngleY = (this->actor.world.rot.y / (f32)0x8000) * M_PI; + spawnAngleX = (((-this->actor.world.rot.x) / (f32)0x8000) * M_PI) + 0.3f; + Matrix_RotateY(spawnAngleY, MTXMODE_NEW); + Matrix_RotateX(spawnAngleX, MTXMODE_APPLY); + Matrix_MultVec3f(&spawnSpeed2, &spawnVel2); + + BossFd_SpawnFireBreath(this->effects, &spawnPos2, &spawnVel2, &spawnAccel2, + 50.0f * Math_SinS(this->work[BFD_VAR_TIMER] * 0x2000) + 300.0f, breathOpacity, + this->actor.world.rot.y); + + spawnPos2.x += spawnVel2.x * 0.5f; + spawnPos2.y += spawnVel2.y * 0.5f; + spawnPos2.z += spawnVel2.z * 0.5f; + + BossFd_SpawnFireBreath(this->effects, &spawnPos2, &spawnVel2, &spawnAccel2, + 50.0f * Math_SinS(this->work[BFD_VAR_TIMER] * 0x2000) + 300.0f, breathOpacity, + this->actor.world.rot.y); + spawnSpeed2.x = 0.0f; + spawnSpeed2.y = 17.0f; + spawnSpeed2.z = 0.0f; + + for (i = 0; i < 6; i++) { + spawnAngleY = Rand_ZeroFloat(2.0f * M_PI); + spawnAngleX = Rand_ZeroFloat(2.0f * M_PI); + Matrix_RotateY(spawnAngleY, MTXMODE_NEW); + Matrix_RotateX(spawnAngleX, MTXMODE_APPLY); + Matrix_MultVec3f(&spawnSpeed2, &spawnVel2); + + spawnAccel2.x = (spawnVel2.x * -10) / 100; + spawnAccel2.y = (spawnVel2.y * -10) / 100; + spawnAccel2.z = (spawnVel2.z * -10) / 100; + + BossFd_SpawnEmber(this->effects, &this->headPos, &spawnVel2, &spawnAccel2, (s16)Rand_ZeroFloat(2.0f) + 8); + } + } + + if ((this->actor.world.pos.y < 90.0f) || (700.0f < this->actor.world.pos.y) || (this->actionFunc == BossFd_Wait)) { + this->actor.flags &= ~1; + } else { + this->actor.flags |= 1; + } +} + +void BossFd_CollisionCheck(BossFd* this, GlobalContext* globalCtx) { + ColliderJntSphElement* headCollider = &this->collider.elements[0]; + ColliderInfo* hurtbox; + + if (headCollider->info.bumperFlags & BUMP_HIT) { + headCollider->info.bumperFlags &= ~BUMP_HIT; + hurtbox = headCollider->info.acHitInfo; + this->actor.colChkInfo.health -= 2; + if (hurtbox->toucher.dmgFlags & 0x1000) { + this->actor.colChkInfo.health -= 2; + } + if ((s8)this->actor.colChkInfo.health <= 2) { + this->actor.colChkInfo.health = 2; + } + this->work[BFD_DAMAGE_FLASH_TIMER] = 10; + this->work[BFD_INVINC_TIMER] = 20; + Audio_PlaySoundGeneral(NA_SE_EN_VALVAISA_DAMAGE1, &this->actor.projectedPos, 4, &D_801333E0, &D_801333E0, + &D_801333E8); + } +} + +void BossFd_Update(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + BossFd* this = THIS; + f32 headGlow; + f32 rManeGlow; + f32 lManeGlow; + s16 i; + + osSyncPrintf("FD MOVE START \n"); + this->work[BFD_VAR_TIMER]++; + this->work[BFD_MOVE_TIMER]++; + this->actionFunc(this, globalCtx); + + for (i = 0; i < ARRAY_COUNT(this->timers); i++) { + if (this->timers[i] != 0) { + this->timers[i]--; + } + } + if (this->fireBreathTimer != 0) { + this->fireBreathTimer--; + } + if (this->work[BFD_DAMAGE_FLASH_TIMER] != 0) { + this->work[BFD_DAMAGE_FLASH_TIMER]--; + } + if (this->work[BFD_INVINC_TIMER] != 0) { + this->work[BFD_INVINC_TIMER]--; + } + if (this->work[BFD_ACTION_STATE] < BOSSFD_DEATH_START) { + if (this->work[BFD_INVINC_TIMER] == 0) { + BossFd_CollisionCheck(this, globalCtx); + } + CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->collider.base); + CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->collider.base); + } + + BossFd_Effects(this, globalCtx); + this->fwork[BFD_TEX1_SCROLL_X] += 4.0f; + this->fwork[BFD_TEX1_SCROLL_Y] = 120.0f; + this->fwork[BFD_TEX2_SCROLL_X] += 3.0f; + this->fwork[BFD_TEX2_SCROLL_Y] -= 2.0f; + + Math_ApproachF(&this->fwork[BFD_BODY_TEX2_ALPHA], (this->work[BFD_VAR_TIMER] & 0x10) ? 30.0f : 158.0f, 1.0f, 8.0f); + if (this->skinSegments == 0) { + this->fwork[BFD_HEAD_TEX2_ALPHA] = this->fwork[BFD_BODY_TEX2_ALPHA]; + } else { + headGlow = (this->work[BFD_VAR_TIMER] & 4) ? 0.0f : 255.0f; + Math_ApproachF(&this->fwork[BFD_HEAD_TEX2_ALPHA], headGlow, 1.0f, 64.0f); + } + + headGlow = (this->work[BFD_VAR_TIMER] & 8) ? 128.0f : 255.0f; + rManeGlow = ((this->work[BFD_VAR_TIMER] + 3) & 8) ? 128.0f : 255.0f; + lManeGlow = ((this->work[BFD_VAR_TIMER] + 6) & 8) ? 128.0f : 255.0f; + + Math_ApproachF(&this->fwork[BFD_MANE_COLOR_CENTER], headGlow, 1.0f, 16.0f); + Math_ApproachF(&this->fwork[BFD_MANE_COLOR_RIGHT], rManeGlow, 1.0f, 16.0f); + Math_ApproachF(&this->fwork[BFD_MANE_COLOR_LEFT], lManeGlow, 1.0f, 16.0f); + + if (this->work[BFD_ROCK_TIMER] != 0) { + this->work[BFD_ROCK_TIMER]--; + if ((this->work[BFD_ROCK_TIMER] % 16) == 0) { + EnVbBall* bossFdRock = (EnVbBall*)Actor_SpawnAsChild( + &globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_EN_VB_BALL, this->actor.world.pos.x, 1000.0f, + this->actor.world.pos.z, 0, 0, (s16)Rand_ZeroFloat(50.0f) + 130, 100); + + if (bossFdRock != NULL) { + for (i = 0; i < 10; i++) { + Vec3f debrisVel = { 0.0f, 0.0f, 0.0f }; + Vec3f debrisAccel = { 0.0f, -1.0f, 0.0f }; + Vec3f debrisPos; + + debrisPos.x = Rand_CenteredFloat(300.0f) + bossFdRock->actor.world.pos.x; + debrisPos.y = Rand_CenteredFloat(300.0f) + bossFdRock->actor.world.pos.y; + debrisPos.z = Rand_CenteredFloat(300.0f) + bossFdRock->actor.world.pos.z; + + BossFd_SpawnDebris(this->effects, &debrisPos, &debrisVel, &debrisAccel, + (s16)Rand_ZeroFloat(15.0f) + 20); + } + } + } + } + + if (1) { // Needed for matching, and also to define new variables + Vec3f emberVel = { 0.0f, 0.0f, 0.0f }; + Vec3f emberAccel = { 0.0f, 0.0f, 0.0f }; + Vec3f emberPos; + s16 temp_rand; + + for (i = 0; i < 6; i++) { + emberAccel.y = 0.4f; + emberAccel.x = Rand_CenteredFloat(0.5f); + emberAccel.z = Rand_CenteredFloat(0.5f); + + temp_rand = Rand_ZeroFloat(8.9f); + + emberPos.x = sHoleLocations[temp_rand].x + Rand_CenteredFloat(60.0f); + emberPos.y = (sHoleLocations[temp_rand].y + 10.0f) + Rand_ZeroFloat(40.0f); + emberPos.z = sHoleLocations[temp_rand].z + Rand_CenteredFloat(60.0f); + + BossFd_SpawnEmber(this->effects, &emberPos, &emberVel, &emberAccel, (s16)Rand_ZeroFloat(2.0f) + 6); + } + + if (this->skinSegments != 0) { + for (i = 0; i < (s16)this->fwork[BFD_MANE_EMBER_RATE]; i++) { + temp_rand = Rand_ZeroFloat(29.9f); + emberPos.y = this->centerMane.pos[temp_rand].y + Rand_CenteredFloat(20.0f); + + if (emberPos.y >= 90.0f) { + emberPos.x = this->centerMane.pos[temp_rand].x + Rand_CenteredFloat(20.0f); + emberPos.z = this->centerMane.pos[temp_rand].z + Rand_CenteredFloat(20.0f); + + emberVel.x = Rand_CenteredFloat(this->fwork[BFD_MANE_EMBER_SPEED]); + emberVel.y = Rand_CenteredFloat(this->fwork[BFD_MANE_EMBER_SPEED]); + emberVel.z = Rand_CenteredFloat(this->fwork[BFD_MANE_EMBER_SPEED]); + + emberAccel.y = 0.4f; + emberAccel.x = Rand_CenteredFloat(0.5f); + emberAccel.z = Rand_CenteredFloat(0.5f); + + BossFd_SpawnEmber(this->effects, &emberPos, &emberVel, &emberAccel, (s16)Rand_ZeroFloat(2.0f) + 8); + } + } + } + } + osSyncPrintf("FD MOVE END 1\n"); + BossFd_UpdateEffects(this, globalCtx); + osSyncPrintf("FD MOVE END 2\n"); +} + +void BossFd_UpdateEffects(BossFd* this, GlobalContext* globalCtx) { + BossFdEffect* effect = this->effects; + Player* player = PLAYER; + Color_RGB8 colors[4] = { { 255, 128, 0 }, { 255, 0, 0 }, { 255, 255, 0 }, { 255, 0, 0 } }; + Vec3f diff; + s16 i1; + s16 i2; + + for (i1 = 0; i1 < 180; i1++, effect++) { + if (effect->type != BFD_FX_NONE) { + effect->timer1++; + + effect->pos.x += effect->velocity.x; + effect->pos.y += effect->velocity.y; + effect->pos.z += effect->velocity.z; + + effect->velocity.x += effect->accel.x; + effect->velocity.y += effect->accel.y; + effect->velocity.z += effect->accel.z; + if (effect->type == BFD_FX_EMBER) { + s16 cInd = effect->timer1 % 4; + + effect->color.r = colors[cInd].r; + effect->color.g = colors[cInd].g; + effect->color.b = colors[cInd].b; + effect->alpha -= 20; + if (effect->alpha <= 0) { + effect->alpha = 0; + effect->type = 0; + } + } else if ((effect->type == BFD_FX_DEBRIS) || (effect->type == BFD_FX_SKULL_PIECE)) { + effect->vFdFxRotX += 0.55f; + effect->vFdFxRotY += 0.1f; + if (effect->pos.y <= 100.0f) { + effect->type = 0; + } + } else if (effect->type == BFD_FX_DUST) { + if (effect->timer2 >= 8) { + effect->timer2 = 8; + effect->type = 0; + } else if (((effect->timer1 % 2) != 0) || (Rand_ZeroOne() < 0.3f)) { + effect->timer2++; + } + } else if (effect->type == BFD_FX_FIRE_BREATH) { + diff.x = player->actor.world.pos.x - effect->pos.x; + diff.y = player->actor.world.pos.y + 30.0f - effect->pos.y; + diff.z = player->actor.world.pos.z - effect->pos.z; + if ((this->timers[3] == 0) && (sqrtf(SQ(diff.x) + SQ(diff.y) + SQ(diff.z)) < 20.0f)) { + this->timers[3] = 50; + func_8002F6D4(globalCtx, NULL, 5.0f, effect->kbAngle, 0.0f, 0x30); + if (player->isBurning == false) { + for (i2 = 0; i2 < ARRAY_COUNT(player->flameTimers); i2++) { + player->flameTimers[i2] = Rand_S16Offset(0, 200); + } + player->isBurning = true; + } + } + if (effect->timer2 == 0) { + if (effect->scale < 2.5f) { + effect->scale += effect->vFdFxScaleMod; + effect->vFdFxScaleMod += 0.08f; + } + if ((effect->pos.y <= (effect->vFdFxYStop + 130.0f)) || (effect->timer1 >= 10)) { + effect->accel.y = 5.0f; + effect->timer2++; + effect->velocity.y = 0.0f; + effect->accel.x = (effect->velocity.x * -25.0f) / 100.0f; + effect->accel.z = (effect->velocity.z * -25.0f) / 100.0f; + } + } else { + if (effect->scale < 2.5f) { + Math_ApproachF(&effect->scale, 2.5f, 0.5f, 0.5f); + } + effect->timer2++; + if (effect->timer2 >= 9) { + effect->type = 0; + } + } + } + } + } +} + +void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) { + static u64* dustTex[] = { + gDust1Tex, gDust1Tex, gDust2Tex, gDust3Tex, gDust4Tex, gDust5Tex, gDust6Tex, gDust7Tex, gDust8Tex, + }; + u8 flag = false; + GraphicsContext* gfxCtx = globalCtx->state.gfxCtx; + s16 i; + BossFdEffect* firstEffect = effect; + + OPEN_DISPS(gfxCtx, "../z_boss_fd.c", 4023); + + for (i = 0; i < 180; i++, effect++) { + if (effect->type == BFD_FX_EMBER) { + if (!flag) { + func_80093D84(globalCtx->state.gfxCtx); + gSPDisplayList(POLY_XLU_DISP++, gVolvagiaEmberSetupDL); + flag++; + } + + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, effect->color.r, effect->color.g, effect->color.b, effect->alpha); + Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW); + func_800D1FD4(&globalCtx->mf_11DA0); + Matrix_Scale(effect->scale, effect->scale, 1.0f, MTXMODE_APPLY); + + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_fd.c", 4046), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_XLU_DISP++, gVolvagiaEmberVtxDL); + } + } + + effect = firstEffect; + flag = false; + for (i = 0; i < 180; i++, effect++) { + if (effect->type == BFD_FX_DEBRIS) { + if (!flag) { + func_80093D18(globalCtx->state.gfxCtx); + gSPDisplayList(POLY_OPA_DISP++, gVolvagiaDebrisSetupDL); + flag++; + } + + Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW); + Matrix_RotateY(effect->vFdFxRotY, MTXMODE_APPLY); + Matrix_RotateX(effect->vFdFxRotX, MTXMODE_APPLY); + Matrix_Scale(effect->scale, effect->scale, 1.0f, MTXMODE_APPLY); + + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_fd.c", 4068), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, gVolvagiaDebrisVtxDL); + } + } + + effect = firstEffect; + flag = false; + for (i = 0; i < 180; i++, effect++) { + if (effect->type == BFD_FX_DUST) { + if (!flag) { + POLY_XLU_DISP = Gfx_CallSetupDL(POLY_XLU_DISP, 0); + gSPDisplayList(POLY_XLU_DISP++, gVolvagiaDustSetupDL); + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 90, 30, 0, 255); + gDPSetEnvColor(POLY_XLU_DISP++, 90, 30, 0, 0); + flag++; + } + + Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW); + Matrix_Scale(effect->scale, effect->scale, effect->scale, MTXMODE_APPLY); + func_800D1FD4(&globalCtx->mf_11DA0); + + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_fd.c", 4104), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPSegment(POLY_XLU_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(dustTex[effect->timer2])); + gSPDisplayList(POLY_XLU_DISP++, gVolvagiaDustVtxDL); + } + } + + effect = firstEffect; + flag = false; + for (i = 0; i < 180; i++, effect++) { + if (effect->type == BFD_FX_FIRE_BREATH) { + if (!flag) { + POLY_XLU_DISP = Gfx_CallSetupDL(POLY_XLU_DISP, 0); + gSPDisplayList(POLY_XLU_DISP++, gVolvagiaDustSetupDL); + gDPSetEnvColor(POLY_XLU_DISP++, 255, 10, 0, 255); + flag++; + } + + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 0, effect->alpha); + Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW); + Matrix_Scale(effect->scale, effect->scale, effect->scale, MTXMODE_APPLY); + func_800D1FD4(&globalCtx->mf_11DA0); + + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_fd.c", 4154), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPSegment(POLY_XLU_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(dustTex[effect->timer2])); + gSPDisplayList(POLY_XLU_DISP++, gVolvagiaDustVtxDL); + } + } + + effect = firstEffect; + flag = false; + for (i = 0; i < 180; i++, effect++) { + if (effect->type == BFD_FX_SKULL_PIECE) { + if (!flag) { + func_80093D84(globalCtx->state.gfxCtx); + gSPDisplayList(POLY_XLU_DISP++, gVolvagiaSkullPieceSetupDL); + flag++; + } + + Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW); + Matrix_RotateY(effect->vFdFxRotY, MTXMODE_APPLY); + Matrix_RotateX(effect->vFdFxRotX, MTXMODE_APPLY); + Matrix_Scale(effect->scale, effect->scale, 1.0f, MTXMODE_APPLY); + + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_fd.c", 4192), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_XLU_DISP++, gVolvagiaSkullPieceVtxDL); + } + } + + CLOSE_DISPS(gfxCtx, "../z_boss_fd.c", 4198); +} + +void BossFd_Draw(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + BossFd* this = THIS; + + osSyncPrintf("FD DRAW START\n"); + if (this->actionFunc != BossFd_Wait) { + OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_fd.c", 4217); + func_80093D18(globalCtx->state.gfxCtx); + if (this->work[BFD_DAMAGE_FLASH_TIMER] & 2) { + POLY_OPA_DISP = Gfx_SetFog(POLY_OPA_DISP, 255, 255, 255, 0, 900, 1099); + } + + BossFd_DrawBody(globalCtx, this); + POLY_OPA_DISP = func_800BC8A0(globalCtx, POLY_OPA_DISP); + CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_fd.c", 4243); + } + + osSyncPrintf("FD DRAW END\n"); + BossFd_DrawEffects(this->effects, globalCtx); + osSyncPrintf("FD DRAW END2\n"); +} + +s32 BossFd_OverrideRightArmDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, + void* thisx) { + BossFd* this = THIS; + + switch (limbIndex) { + case 1: + rot->y += 4000.0f + this->rightArmRot[0].x; + break; + case 2: + rot->y += this->rightArmRot[1].x; + rot->z += this->rightArmRot[1].y; + break; + case 3: + rot->y += this->rightArmRot[2].x; + rot->z += this->rightArmRot[2].y; + break; + } + if (this->skinSegments < limbIndex) { + *dList = NULL; + } + return false; +} + +s32 BossFd_OverrideLeftArmDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, + void* thisx) { + BossFd* this = THIS; + + switch (limbIndex) { + case 1: + rot->y += -4000.0f + this->leftArmRot[0].x; + break; + case 2: + rot->y += this->leftArmRot[1].x; + rot->z += this->leftArmRot[1].y; + break; + case 3: + rot->y += this->leftArmRot[2].x; + rot->z += this->leftArmRot[2].y; + break; + } + if (this->skinSegments < limbIndex) { + *dList = NULL; + } + return false; +} + +static s16 sBodyIndex[] = { 0, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40, 35, 30, 25, 20, 15, 10, 5 }; +static s16 sManeIndex[] = { 0, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10 }; // Unused + +void BossFd_DrawMane(GlobalContext* globalCtx, BossFd* this, Vec3f* manePos, Vec3f* maneRot, f32* maneScale, u8 mode) { + f32 sp140[] = { 0.0f, 10.0f, 17.0f, 20.0f, 19.5f, 18.0f, 17.0f, 15.0f, 15.0f, 15.0f }; + f32 sp118[] = { 0.0f, 10.0f, 17.0f, 20.0f, 21.0f, 21.0f, 21.0f, 21.0f, 21.0f, 21.0f }; + f32 spF0[] = { 0.4636457f, 0.33661291f, 0.14879614f, 0.04995025f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; + // arctan of {0.5, 0.35, 0.15, 0.05, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} + f32 spC8[] = { -0.4636457f, -0.33661291f, -0.14879614f, 0.024927188f, 0.07478157f, + 0.04995025f, 0.09961288f, 0.0f, 0.0f, 0.0f }; + // arctan of {-0.5, -0.35, -0.15, 0.025, 0.075, 0.05, 0.1, 0.0, 0.0} + s16 maneIndex; + s16 i; + s16 maneLength; + Vec3f spB4; + Vec3f spA8; + f32 phi_f20; + f32 phi_f22; + + OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_fd.c", 4419); + + maneLength = this->skinSegments; + maneLength = CLAMP_MAX(maneLength, 10); + + for (i = 0; i < maneLength; i++) { + maneIndex = (this->work[BFD_LEAD_MANE_SEG] - (i * 2) + 30) % 30; + + if (mode == 0) { + spB4.x = spB4.z = 0.0f; + spB4.y = ((sp140[i] * 0.1f) * 10.0f) * this->flattenMane; + phi_f20 = 0.0f; + phi_f22 = spC8[i] * this->flattenMane; + } else if (mode == 1) { + phi_f22 = (spC8[i] * this->flattenMane) * 0.7f; + phi_f20 = spF0[i] * this->flattenMane; + + spB4.y = (sp140[i] * this->flattenMane) * 0.7f; + spB4.x = -sp118[i] * this->flattenMane; + spB4.z = 0.0f; + } else { + phi_f22 = (spC8[i] * this->flattenMane) * 0.7f; + phi_f20 = -spF0[i] * this->flattenMane; + + spB4.y = (sp140[i] * this->flattenMane) * 0.7f; + spB4.x = sp118[i] * this->flattenMane; + spB4.z = 0.0f; + } + + Matrix_RotateY((maneRot + maneIndex)->y, MTXMODE_NEW); + Matrix_RotateX(-(maneRot + maneIndex)->x, MTXMODE_APPLY); + + Matrix_MultVec3f(&spB4, &spA8); + + Matrix_Translate((manePos + maneIndex)->x + spA8.x, (manePos + maneIndex)->y + spA8.y, + (manePos + maneIndex)->z + spA8.z, MTXMODE_NEW); + Matrix_RotateY((maneRot + maneIndex)->y + phi_f20, MTXMODE_APPLY); + Matrix_RotateX(-((maneRot + maneIndex)->x + phi_f22), MTXMODE_APPLY); + Matrix_Scale(maneScale[maneIndex] * (0.01f - (i * 0.0008f)), maneScale[maneIndex] * (0.01f - (i * 0.0008f)), + 0.01f, 1); + Matrix_RotateX(-M_PI / 2.0f, MTXMODE_APPLY); + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_fd.c", 4480), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_XLU_DISP++, gVolvagiaManeVtxDL); + } + + CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_fd.c", 4483); +} + +s32 BossFd_OverrideHeadDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, void* thisx) { + BossFd* this = THIS; + + switch (limbIndex) { + case 5: + case 6: + rot->z -= this->jawOpening * 0.1f; + break; + case 2: + rot->z += this->jawOpening; + break; + } + if ((this->faceExposed == true) && (limbIndex == 5)) { + *dList = gVolvagiaBrokenFaceDL; + } + if (this->skinSegments == 0) { + if (limbIndex == 6) { + *dList = gVolvagiaSkullDL; + } else if (limbIndex == 2) { + *dList = gVolvagiaJawboneDL; + } else { + *dList = NULL; + } + } + return false; +} + +void BossFd_PostHeadDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) { + static Vec3f targetMod = { 4500.0f, 0.0f, 0.0f }; + static Vec3f headMod = { 4000.0f, 0.0f, 0.0f }; + BossFd* this = THIS; + + if (limbIndex == 5) { + Matrix_MultVec3f(&targetMod, &this->actor.focus.pos); + Matrix_MultVec3f(&headMod, &this->headPos); + } +} + +static u64* sEyeTextures[] = { gVolvagiaEyeOpenTex, gVolvagiaEyeHalfTex, gVolvagiaEyeClosedTex }; + +static Gfx* sBodyDLists[] = { + gVolvagiaBodySeg1DL, gVolvagiaBodySeg2DL, gVolvagiaBodySeg3DL, gVolvagiaBodySeg4DL, gVolvagiaBodySeg5DL, + gVolvagiaBodySeg6DL, gVolvagiaBodySeg7DL, gVolvagiaBodySeg8DL, gVolvagiaBodySeg9DL, gVolvagiaBodySeg10DL, + gVolvagiaBodySeg11DL, gVolvagiaBodySeg12DL, gVolvagiaBodySeg13DL, gVolvagiaBodySeg14DL, gVolvagiaBodySeg15DL, + gVolvagiaBodySeg16DL, gVolvagiaBodySeg17DL, gVolvagiaBodySeg18DL, +}; + +void BossFd_DrawBody(GlobalContext* globalCtx, BossFd* this) { + s16 segIndex; + s16 i; + f32 temp_float; + Mtx* tempMat = Graph_Alloc(globalCtx->state.gfxCtx, 18 * sizeof(Mtx)); + + OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_fd.c", 4589); + if (this->skinSegments != 0) { + gSPSegment(POLY_OPA_DISP++, 0x09, SEGMENTED_TO_VIRTUAL(sEyeTextures[this->eyeState])); + } + gSPSegment(POLY_OPA_DISP++, 0x08, + Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, (s16)this->fwork[BFD_TEX1_SCROLL_X], + (s16)this->fwork[BFD_TEX1_SCROLL_Y], 0x20, 0x20, 1, (s16)this->fwork[BFD_TEX2_SCROLL_X], + (s16)this->fwork[BFD_TEX2_SCROLL_Y], 0x20, 0x20)); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, 255); + gDPSetEnvColor(POLY_OPA_DISP++, 255, 255, 255, (s8)this->fwork[BFD_BODY_TEX2_ALPHA]); + + osSyncPrintf("LH\n"); + Matrix_Push(); + segIndex = (this->work[BFD_LEAD_BODY_SEG] + sBodyIndex[2]) % 100; + Matrix_Translate(this->bodySegsPos[segIndex].x, this->bodySegsPos[segIndex].y, this->bodySegsPos[segIndex].z, + MTXMODE_NEW); + Matrix_RotateY(this->bodySegsRot[segIndex].y, MTXMODE_APPLY); + Matrix_RotateX(-this->bodySegsRot[segIndex].x, MTXMODE_APPLY); + Matrix_Translate(-13.0f, -5.0f, 13.0f, MTXMODE_APPLY); + Matrix_Scale(this->actor.scale.x * 0.1f, this->actor.scale.y * 0.1f, this->actor.scale.z * 0.1f, MTXMODE_APPLY); + SkelAnime_DrawOpa(globalCtx, this->skelAnimeRightArm.skeleton, this->skelAnimeRightArm.jointTable, + BossFd_OverrideRightArmDraw, NULL, this); + Matrix_Pop(); + osSyncPrintf("RH\n"); + Matrix_Push(); + segIndex = (this->work[BFD_LEAD_BODY_SEG] + sBodyIndex[2]) % 100; + Matrix_Translate(this->bodySegsPos[segIndex].x, this->bodySegsPos[segIndex].y, this->bodySegsPos[segIndex].z, + MTXMODE_NEW); + Matrix_RotateY(this->bodySegsRot[segIndex].y, MTXMODE_APPLY); + Matrix_RotateX(-this->bodySegsRot[segIndex].x, MTXMODE_APPLY); + Matrix_Translate(13.0f, -5.0f, 13.0f, MTXMODE_APPLY); + Matrix_Scale(this->actor.scale.x * 0.1f, this->actor.scale.y * 0.1f, this->actor.scale.z * 0.1f, MTXMODE_APPLY); + SkelAnime_DrawOpa(globalCtx, this->skelAnimeLeftArm.skeleton, this->skelAnimeLeftArm.jointTable, + BossFd_OverrideLeftArmDraw, NULL, this); + Matrix_Pop(); + osSyncPrintf("BD\n"); + gSPSegment(POLY_OPA_DISP++, 0x0D, tempMat); + + Matrix_Push(); + for (i = 0; i < 18; i++, tempMat++) { + segIndex = (this->work[BFD_LEAD_BODY_SEG] + sBodyIndex[i + 1]) % 100; + Matrix_Translate(this->bodySegsPos[segIndex].x, this->bodySegsPos[segIndex].y, this->bodySegsPos[segIndex].z, + MTXMODE_NEW); + Matrix_RotateY(this->bodySegsRot[segIndex].y, MTXMODE_APPLY); + Matrix_RotateX(-this->bodySegsRot[segIndex].x, MTXMODE_APPLY); + Matrix_Translate(0.0f, 0.0f, 35.0f, 1); + Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY); + if (i < this->skinSegments) { + Matrix_Scale(1.0f + (Math_SinS((this->work[BFD_LEAD_BODY_SEG] * 5000.0f) + (i * 7000.0f)) * + this->fwork[BFD_BODY_PULSE]), + 1.0f + (Math_SinS((this->work[BFD_LEAD_BODY_SEG] * 5000.0f) + (i * 7000.0f)) * + this->fwork[BFD_BODY_PULSE]), + 1.0f, MTXMODE_APPLY); + Matrix_RotateY(M_PI / 2.0f, MTXMODE_APPLY); + Matrix_ToMtx(tempMat, "../z_boss_fd.c", 4719); + gSPMatrix(POLY_OPA_DISP++, tempMat, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, sBodyDLists[i]); + } else { + MtxF spFC; + Vec3f spF0 = { 0.0f, 0.0f, 0.0f }; + Vec3f spE4; + Vec3s spDC; + f32 padD8; + + if (this->bodyFallApart[i] < 2) { + f32 spD4 = 0.1f; + + temp_float = 0.1f; + Matrix_Translate(0.0f, 0.0f, -1100.0f, MTXMODE_APPLY); + Matrix_RotateY(-M_PI, MTXMODE_APPLY); + if (i >= 14) { + f32 sp84 = 1.0f - ((i - 14) * 0.2f); + + Matrix_Scale(sp84, sp84, 1.0f, 1); + spD4 = 0.1f * sp84; + temp_float = 0.1f * sp84; + } + Matrix_Scale(0.1f, 0.1f, 0.1f, MTXMODE_APPLY); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_fd.c", 4768), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, gVolvagiaRibsDL); + + if (this->bodyFallApart[i] == 1) { + EnVbBall* bones; + + this->bodyFallApart[i] = 2; + Matrix_MultVec3f(&spF0, &spE4); + Matrix_Get(&spFC); + func_800D20CC(&spFC, &spDC, 0); + bones = + (EnVbBall*)Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_EN_VB_BALL, + spE4.x, spE4.y, spE4.z, spDC.x, spDC.y, spDC.z, i + 200); + + bones->actor.scale.x = this->actor.scale.x * temp_float; + bones->actor.scale.y = this->actor.scale.y * spD4; + bones->actor.scale.z = this->actor.scale.z * 0.1f; + } + } + } + if (i > 0) { + Collider_UpdateSpheres(i + 1, &this->collider); + } + } + Matrix_Pop(); + osSyncPrintf("BH\n"); + + gDPPipeSync(POLY_OPA_DISP++); + gDPSetEnvColor(POLY_OPA_DISP++, 255, 255, 255, (s8)this->fwork[BFD_HEAD_TEX2_ALPHA]); + Matrix_Push(); + temp_float = + (this->work[BFD_ACTION_STATE] >= BOSSFD_SKULL_FALL) ? -20.0f : -10.0f - ((this->actor.speedXZ - 5.0f) * 10.0f); + segIndex = (this->work[BFD_LEAD_BODY_SEG] + sBodyIndex[0]) % 100; + Matrix_Translate(this->bodySegsPos[segIndex].x, this->bodySegsPos[segIndex].y, this->bodySegsPos[segIndex].z, + MTXMODE_NEW); + Matrix_RotateY(this->bodySegsRot[segIndex].y, MTXMODE_APPLY); + Matrix_RotateX(-this->bodySegsRot[segIndex].x, MTXMODE_APPLY); + Matrix_RotateZ((this->actor.shape.rot.z / (f32)0x8000) * M_PI, MTXMODE_APPLY); + Matrix_Translate(0.0f, 0.0f, temp_float, MTXMODE_APPLY); + Matrix_Push(); + Matrix_Translate(0.0f, 0.0f, 25.0f, MTXMODE_APPLY); + osSyncPrintf("BHC\n"); + Collider_UpdateSpheres(0, &this->collider); + Matrix_Pop(); + osSyncPrintf("BHCE\n"); + Matrix_Scale(this->actor.scale.x * 0.1f, this->actor.scale.y * 0.1f, this->actor.scale.z * 0.1f, MTXMODE_APPLY); + SkelAnime_DrawOpa(globalCtx, this->skelAnimeHead.skeleton, this->skelAnimeHead.jointTable, BossFd_OverrideHeadDraw, + BossFd_PostHeadDraw, &this->actor); + osSyncPrintf("SK\n"); + { + Vec3f spB0 = { 0.0f, 1700.0f, 7000.0f }; + Vec3f spA4 = { -1000.0f, 700.0f, 7000.0f }; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/func_808D08A4.s") + func_80093D84(globalCtx->state.gfxCtx); + gSPDisplayList(POLY_XLU_DISP++, gVolvagiaManeSetupDL); + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, this->fwork[BFD_MANE_COLOR_CENTER], 0, 255); + Matrix_Push(); + Matrix_MultVec3f(&spB0, &this->centerMane.head); + BossFd_DrawMane(globalCtx, this, this->centerMane.pos, this->fireManeRot, this->centerMane.scale, MANE_CENTER); + Matrix_Pop(); + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, this->fwork[BFD_MANE_COLOR_RIGHT], 0, 255); + Matrix_Push(); + Matrix_MultVec3f(&spA4, &this->rightMane.head); + BossFd_DrawMane(globalCtx, this, this->rightMane.pos, this->fireManeRot, this->rightMane.scale, MANE_RIGHT); + Matrix_Pop(); + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, this->fwork[BFD_MANE_COLOR_LEFT], 0, 255); + Matrix_Push(); + spA4.x *= -1.0f; + Matrix_MultVec3f(&spA4, &this->leftMane.head); + BossFd_DrawMane(globalCtx, this, this->leftMane.pos, this->fireManeRot, this->leftMane.scale, MANE_LEFT); + Matrix_Pop(); + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd/func_808D08F8.s") + Matrix_Pop(); + osSyncPrintf("END\n"); + CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_fd.c", 4987); +} diff --git a/src/overlays/actors/ovl_Boss_Fd/z_boss_fd.h b/src/overlays/actors/ovl_Boss_Fd/z_boss_fd.h index ea3351936..eafc002d5 100644 --- a/src/overlays/actors/ovl_Boss_Fd/z_boss_fd.h +++ b/src/overlays/actors/ovl_Boss_Fd/z_boss_fd.h @@ -6,9 +6,180 @@ struct BossFd; +typedef void (*BossFdActionFunc)(struct BossFd*, GlobalContext*); + +typedef enum { + /* -1 */ BOSSFD_WAIT_INTRO = -1, + /* 0 */ BOSSFD_FLY_MAIN, + /* 1 */ BOSSFD_FLY_HOLE, + /* 2 */ BOSSFD_BURROW, + /* 3 */ BOSSFD_EMERGE, + /* 50 */ BOSSFD_FLY_CEILING = 50, + /* 51 */ BOSSFD_DROP_ROCKS, + /* 100 */ BOSSFD_FLY_CHASE = 100, + /* 101 */ BOSSFD_FLY_UNUSED, + /* 200 */ BOSSFD_DEATH_START = 200, + /* 201 */ BOSSFD_SKIN_BURN, + /* 202 */ BOSSFD_BONES_FALL, + /* 203 */ BOSSFD_SKULL_PAUSE, + /* 204 */ BOSSFD_SKULL_FALL, + /* 205 */ BOSSFD_SKULL_BURN +} BossFdActionState; + +typedef enum { + /* 0 */ BFD_CS_NONE, + /* 1 */ BFD_CS_WAIT, + /* 2 */ BFD_CS_START, + /* 3 */ BFD_CS_LOOK_LINK, + /* 4 */ BFD_CS_LOOK_GROUND, + /* 5 */ BFD_CS_COLLAPSE, + /* 6 */ BFD_CS_EMERGE +} BossFdCutsceneState; + +typedef struct { + /* 0x00 */ Vec3f pos; + /* 0x0C */ Vec3f velocity; + /* 0x18 */ Vec3f accel; + /* 0x24 */ u8 type; + /* 0x25 */ u8 timer1; + /* 0x26 */ Color_RGB8 color; + /* 0x2A */ s16 alpha; + /* 0x2C */ s16 timer2; + /* 0x2E */ s16 kbAngle; + /* 0x30 */ f32 scale; + /* 0x34 */ f32 bFdFxFloat1; + /* 0x38 */ f32 bFdFxFloat2; +} BossFdEffect; // size = 0x3C + +#define BOSSFD_EFFECT_COUNT 180 + +#define vFdFxRotX bFdFxFloat1 +#define vFdFxScaleMod bFdFxFloat1 +#define vFdFxRotY bFdFxFloat2 +#define vFdFxYStop bFdFxFloat2 + +typedef enum { + /* 0 */ BFD_FX_NONE, + /* 1 */ BFD_FX_EMBER, + /* 2 */ BFD_FX_DEBRIS, + /* 3 */ BFD_FX_DUST, + /* 4 */ BFD_FX_FIRE_BREATH, + /* 5 */ BFD_FX_SKULL_PIECE +} BossFdEffectType; + +typedef struct { + /* 0x000 */ Vec3f pos[30]; + /* 0x168 */ f32 scale[30]; + /* 0x1E0 */ Vec3f head; +} BossFdMane; // size = 0x1EC + +typedef struct { + /* 0x00 */ Vec3f eye; + /* 0x0C */ Vec3f at; + /* 0x18 */ Vec3f pad[2]; + /* 0x30 */ Vec3f eyeVel; + /* 0x3C */ Vec3f atVel; + /* 0x48 */ Vec3f nextEye; + /* 0x54 */ Vec3f eyeMaxVel; + /* 0x60 */ Vec3f nextAt; + /* 0x6C */ Vec3f atMaxVel; + /* 0x78 */ f32 speedMod; + /* 0x7C */ f32 accel; + /* 0x80 */ f32 yMod; + /* 0x84 */ f32 shake; +} BossFdCam; // size = 0x88 + +typedef enum { + /* 0 */ BFD_ACTION_STATE, + /* 1 */ BFD_MOVE_TIMER, + /* 2 */ BFD_VAR_TIMER, + /* 3 */ BFD_LEAD_BODY_SEG, + /* 4 */ BFD_LEAD_MANE_SEG, + /* 5 */ BFD_BLINK_TIMER, + /* 6 */ BFD_ROAR_TIMER, + /* 7 */ BFD_DAMAGE_FLASH_TIMER, + /* 8 */ BFD_START_ATTACK, + /* 9 */ BFD_UNK_234, + /* 10 */ BFD_UNK_236, + /* 11 */ BFD_MANE_EMBERS_TIMER, + /* 12 */ BFD_ROCK_TIMER, + /* 13 */ BFD_CEILING_TARGET, + /* 14 */ BFD_INVINC_TIMER, + /* 15 */ BFD_SPLASH_TIMER, + /* 16 */ BFD_CAM_SHAKE_TIMER, + /* 17 */ BFD_STOP_FLAG, + /* 18 */ BFD_FLY_COUNT, + /* 19 */ BFD_SHORT_COUNT +} BossFdS16Var; + +typedef enum { + /* 0 */ BFD_TEX1_SCROLL_X, + /* 1 */ BFD_TEX1_SCROLL_Y, + /* 2 */ BFD_TEX2_SCROLL_X, + /* 3 */ BFD_TEX2_SCROLL_Y, + /* 4 */ BFD_UNUSED_F4, + /* 5 */ BFD_UNUSED_F5, + /* 6 */ BFD_UNUSED_F6, + /* 7 */ BFD_BODY_TEX2_ALPHA, + /* 8 */ BFD_HEAD_TEX2_ALPHA, + /* 9 */ BFD_TARGET_Y_OFFSET, + /* 10 */ BFD_CEILING_BOUNCE, + /* 11 */ BFD_BODY_PULSE, + /* 12 */ BFD_MANE_COLOR_CENTER, + /* 13 */ BFD_MANE_COLOR_RIGHT, + /* 14 */ BFD_MANE_COLOR_LEFT, + /* 15 */ BFD_MANE_EMBER_SPEED, + /* 16 */ BFD_MANE_EMBER_RATE, + /* 17 */ BFD_UNUSED_F17, + /* 18 */ BFD_UNUSED_F18, + /* 19 */ BFD_UNUSED_F19, + /* 20 */ BFD_FLY_SPEED, + /* 21 */ BFD_TURN_RATE, + /* 22 */ BFD_TURN_RATE_MAX, + /* 23 */ BFD_FLY_WOBBLE_AMP, + /* 24 */ BFD_FLY_WOBBLE_RATE, + /* 25 */ BFD_UNUSED_F25, + /* 26 */ BFD_FLOAT_COUNT +} BossFdF32Var; + typedef struct BossFd { /* 0x0000 */ Actor actor; - /* 0x014C */ char unk_14C[0x4254]; + /* 0x014C */ SkelAnime skelAnimeHead; + /* 0x0190 */ SkelAnime skelAnimeRightArm; + /* 0x01D4 */ SkelAnime skelAnimeLeftArm; + /* 0x0218 */ BossFdActionFunc actionFunc; + /* 0x021C */ s16 fireBreathTimer; + /* 0x021E */ s16 skinSegments; + /* 0x0220 */ u8 fogMode; + /* 0x0222 */ s16 work[BFD_SHORT_COUNT]; + /* 0x0248 */ s16 timers[6]; + /* 0x0254 */ f32 fwork[BFD_FLOAT_COUNT]; + /* 0x02BC */ Vec3f targetPosition; + /* 0x02C8 */ Vec3f holePosition; + /* 0x02D4 */ u8 holeIndex; + /* 0x02D5 */ u8 eyeState; + /* 0x02D6 */ u8 platformSignal; + /* 0x02D7 */ u8 faceExposed; + /* 0x02D8 */ u8 handoffSignal; + /* 0x02DC */ Vec3f bodySegsRot[100]; + /* 0x078C */ Vec3f bodySegsPos[100]; + /* 0x0C3C */ Vec3f rightArmRot[4]; + /* 0x0C6C */ Vec3f leftArmRot[4]; + /* 0x0C9C */ Vec3f fireManeRot[30]; + /* 0x0E04 */ BossFdMane centerMane; + /* 0x0FF0 */ BossFdMane rightMane; + /* 0x11DC */ BossFdMane leftMane; + /* 0x13C8 */ f32 flattenMane; + /* 0x13CC */ f32 jawOpening; + /* 0x13D0 */ s16 bodyFallApart[18]; + /* 0x13F4 */ Vec3f headPos; + /* 0x1400 */ s16 introFlyState; + /* 0x1402 */ s16 introState; + /* 0x1404 */ s16 introCamera; + /* 0x1408 */ BossFdCam camData; + /* 0x1490 */ ColliderJntSph collider; + /* 0x14B0 */ ColliderJntSphElement elements[19]; + /* 0x1970 */ BossFdEffect effects[180]; } BossFd; // size = 0x43A0 extern const ActorInit Boss_Fd_InitVars; diff --git a/src/overlays/actors/ovl_Boss_Fd/z_boss_fd_colchk.c b/src/overlays/actors/ovl_Boss_Fd/z_boss_fd_colchk.c new file mode 100644 index 000000000..c7b6a8b80 --- /dev/null +++ b/src/overlays/actors/ovl_Boss_Fd/z_boss_fd_colchk.c @@ -0,0 +1,226 @@ +#include "global.h" + +static ColliderJntSphElementInit sJntSphItemsInit[19] = { + { + { + ELEMTYPE_UNK3, + { 0xFFCFFFFF, 0x00, 0x10 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { 0, { { 0, 0, 0 }, 20 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x10 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 1, { { 0, 0, 0 }, 20 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x10 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 2, { { 0, 0, 0 }, 20 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x10 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 3, { { 0, 0, 0 }, 20 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x10 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 4, { { 0, 0, 0 }, 20 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x10 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 5, { { 0, 0, 0 }, 20 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x10 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 6, { { 0, 0, 0 }, 20 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x10 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 7, { { 0, 0, 0 }, 20 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x10 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 8, { { 0, 0, 0 }, 20 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x10 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 9, { { 0, 0, 0 }, 20 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x10 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 10, { { 0, 0, 0 }, 20 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x10 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 11, { { 0, 0, 0 }, 20 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x10 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 12, { { 0, 0, 0 }, 20 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x10 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 13, { { 0, 0, 0 }, 20 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x10 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 14, { { 0, 0, 0 }, 18 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x10 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 15, { { 0, 0, 0 }, 16 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x10 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 16, { { 0, 0, 0 }, 14 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x10 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 17, { { 0, 0, 0 }, 12 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x10 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 18, { { 0, 0, 0 }, 10 }, 100 }, + }, +}; + +static ColliderJntSphInit sJntSphInit = { + { + COLTYPE_METAL, + AT_ON | AT_TYPE_ENEMY, + AC_ON | AC_TYPE_PLAYER, + OC1_ON | OC1_TYPE_PLAYER, + OC2_TYPE_1, + COLSHAPE_JNTSPH, + }, + 19, + sJntSphItemsInit, +}; diff --git a/src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2.c b/src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2.c index fa31868e0..95ff3a7d4 100644 --- a/src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2.c +++ b/src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2.c @@ -1,15 +1,52 @@ +/* + * File: z_boss_fd2.c + * Overlay: ovl_Boss_Fd2 + * Description: Volvagia, hole form + */ + #include "z_boss_fd2.h" +#include "objects/object_fd2/object_fd2.h" +#include "overlays/actors/ovl_Boss_Fd/z_boss_fd.h" +#include "vt.h" #define FLAGS 0x00000035 #define THIS ((BossFd2*)thisx) +typedef enum { + /* 0 */ DEATH_START, + /* 1 */ DEATH_RETREAT, + /* 2 */ DEATH_HANDOFF, + /* 3 */ DEATH_FD_BODY, + /* 4 */ DEATH_FD_SKULL, + /* 5 */ DEATH_FINISH +} BossFd2CutsceneState; + +typedef enum { + /* 0 */ EYE_OPEN, + /* 1 */ EYE_HALF, + /* 2 */ EYE_CLOSED +} BossFd2EyeState; + void BossFd2_Init(Actor* thisx, GlobalContext* globalCtx); void BossFd2_Destroy(Actor* thisx, GlobalContext* globalCtx); void BossFd2_Update(Actor* thisx, GlobalContext* globalCtx); void BossFd2_Draw(Actor* thisx, GlobalContext* globalCtx); -/* +void BossFd2_SetupEmerge(BossFd2* this, GlobalContext* globalCtx); +void BossFd2_Emerge(BossFd2* this, GlobalContext* globalCtx); +void BossFd2_SetupIdle(BossFd2* this, GlobalContext* globalCtx); +void BossFd2_Idle(BossFd2* this, GlobalContext* globalCtx); +void BossFd2_Burrow(BossFd2* this, GlobalContext* globalCtx); +void BossFd2_SetupBreatheFire(BossFd2* this, GlobalContext* globalCtx); +void BossFd2_BreatheFire(BossFd2* this, GlobalContext* globalCtx); +void BossFd2_SetupClawSwipe(BossFd2* this, GlobalContext* globalCtx); +void BossFd2_ClawSwipe(BossFd2* this, GlobalContext* globalCtx); +void BossFd2_Vulnerable(BossFd2* this, GlobalContext* globalCtx); +void BossFd2_Damaged(BossFd2* this, GlobalContext* globalCtx); +void BossFd2_Death(BossFd2* this, GlobalContext* globalCtx); +void BossFd2_Wait(BossFd2* this, GlobalContext* globalCtx); + const ActorInit Boss_Fd2_InitVars = { ACTOR_BOSS_FD2, ACTORCAT_BOSS, @@ -22,183 +59,1160 @@ const ActorInit Boss_Fd2_InitVars = { (ActorFunc)BossFd2_Draw, }; -static ColliderJntSphElementInit D_808D5FD0[9] = { - { - { - ELEMTYPE_UNK3, - { 0xFFCFFFFF, 0x00, 0x20 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_NONE, - BUMP_ON | BUMP_HOOKABLE, - OCELEM_ON, - }, - { 35, { { 6000, 0, 0 }, 21 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x20 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 18, { { 4000, 0, 0 }, 13 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x20 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 19, { { 3000, 0, 0 }, 13 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x20 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 20, { { 4000, 0, 0 }, 15 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x20 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 24, { { 4000, 0, 0 }, 13 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x20 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 25, { { 3000, 0, 0 }, 13 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x20 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 26, { { 3500, 1500, 0 }, 15 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x20 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 17, { { 0, 0, 0 }, 26 }, 100 }, - }, - { - { - ELEMTYPE_UNK2, - { 0xFFCFFFFF, 0x00, 0x20 }, - { 0xFFCDFFFE, 0x00, 0x00 }, - TOUCH_ON | TOUCH_SFX_NORMAL, - BUMP_NONE, - OCELEM_ON, - }, - { 30, { { 0, 0, 0 }, 17 }, 100 }, - }, +#include "z_boss_fd2_colchk.c" + +static Vec3f sHoleLocations[] = { + { 0.0f, 90.0f, -243.0f }, { 0.0f, 90.0f, 0.0f }, { 0.0f, 90.0f, 243.0f }, + { -243.0f, 90.0f, -243.0f }, { -243.0f, 90.0f, 0.0f }, { -243.0f, 90.0f, 243.0f }, + { 243.0f, 90.0f, -243.0f }, { 243.0f, 90.0f, 0.0f }, { 243.0f, 90.0f, 243.0f }, }; -static ColliderJntSphInit D_808D6114 = { - { - COLTYPE_METAL, - AT_ON | AT_TYPE_ENEMY, - AC_ON | AC_TYPE_PLAYER, - OC1_ON | OC1_TYPE_PLAYER, - OC2_TYPE_1, - COLSHAPE_JNTSPH, - }, - 9, - D_808D5FD0, +static InitChainEntry sInitChain[] = { + ICHAIN_U8(targetMode, 5, ICHAIN_CONTINUE), + ICHAIN_S8(naviEnemyId, 33, ICHAIN_CONTINUE), + ICHAIN_F32_DIV1000(gravity, 0, ICHAIN_CONTINUE), + ICHAIN_F32(targetArrowOffset, 0, ICHAIN_STOP), }; -*/ -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D2670.s") -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D2748.s") +void BossFd2_SpawnDebris(GlobalContext* globalCtx, BossFdEffect* effect, Vec3f* position, Vec3f* velocity, + Vec3f* acceleration, f32 scale) { + s16 i; + + for (i = 0; i < 180; i++, effect++) { + if (effect->type == BFD_FX_NONE) { + effect->type = BFD_FX_DEBRIS; + effect->pos = *position; + effect->velocity = *velocity; + effect->accel = *acceleration; + effect->scale = scale / 1000.0f; + effect->vFdFxRotX = Rand_ZeroFloat(100.0f); + effect->vFdFxRotY = Rand_ZeroFloat(100.0f); + break; + } + } +} + +void BossFd2_SpawnFireBreath(GlobalContext* globalCtx, BossFdEffect* effect, Vec3f* position, Vec3f* velocity, + Vec3f* acceleration, f32 scale, s16 alpha, s16 kbAngle) { + s16 i; + + for (i = 0; i < 180; i++, effect++) { + if (effect->type == BFD_FX_NONE) { + effect->type = BFD_FX_FIRE_BREATH; + effect->timer1 = 0; + effect->pos = *position; + effect->velocity = *velocity; + effect->accel = *acceleration; + effect->pos.x -= effect->velocity.x; + effect->pos.y -= effect->velocity.y; + effect->pos.z -= effect->velocity.z; + effect->vFdFxScaleMod = 0.0f; + effect->alpha = alpha; + effect->vFdFxYStop = Rand_ZeroFloat(10.0f); + effect->timer2 = 0; + effect->scale = scale / 400.0f; + effect->kbAngle = kbAngle; + break; + } + } +} + +void BossFd2_SpawnEmber(GlobalContext* globalCtx, BossFdEffect* effect, Vec3f* position, Vec3f* velocity, + Vec3f* acceleration, f32 scale) { + s16 i; + + for (i = 0; i < 180; i++, effect++) { + if (effect->type == 0) { + effect->type = BFD_FX_EMBER; + effect->pos = *position; + effect->velocity = *velocity; + effect->accel = *acceleration; + effect->scale = scale / 1000.0f; + effect->alpha = 255; + effect->timer1 = (s16)Rand_ZeroFloat(10.0f); + break; + } + } +} + +void BossFd2_SpawnSkullPiece(GlobalContext* globalCtx, BossFdEffect* effect, Vec3f* position, Vec3f* velocity, + Vec3f* acceleration, f32 scale) { + s16 i; + + for (i = 0; i < 180; i++, effect++) { + if (effect->type == BFD_FX_NONE) { + effect->type = BFD_FX_SKULL_PIECE; + effect->pos = *position; + effect->velocity = *velocity; + effect->accel = *acceleration; + effect->scale = scale / 1000.0f; + effect->vFdFxRotX = Rand_ZeroFloat(100.0f); + effect->vFdFxRotY = Rand_ZeroFloat(100.0f); + break; + } + } +} + +void BossFd2_SpawnDust(BossFdEffect* effect, Vec3f* position, Vec3f* velocity, Vec3f* acceleration, f32 scale) { + s16 i; + + for (i = 0; i < 180; i++, effect++) { + if (effect->type == BFD_FX_NONE) { + effect->type = BFD_FX_DUST; + effect->pos = *position; + effect->velocity = *velocity; + effect->accel = *acceleration; + effect->timer2 = 0; + effect->scale = scale / 400.0f; + break; + } + } +} + +void BossFd2_Init(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + BossFd2* this = THIS; + + Actor_ProcessInitChain(&this->actor, sInitChain); + Actor_SetScale(&this->actor, 0.0069999993f); + this->actor.world.pos.y = -850.0f; + ActorShape_Init(&this->actor.shape, -580.0f / this->actor.scale.y, NULL, 0.0f); + SkelAnime_InitFlex(globalCtx, &this->skelAnime, &gHoleVolvagiaSkel, &gHoleVolvagiaIdleAnim, NULL, NULL, 0); + if (this->actor.params == BFD_CS_NONE) { + BossFd2_SetupEmerge(this, globalCtx); + } else { + this->actionFunc = BossFd2_Wait; + } + Collider_InitJntSph(globalCtx, &this->collider); + Collider_SetJntSph(globalCtx, &this->collider, &this->actor, &sJntSphInit, this->elements); +} + +void BossFd2_Destroy(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + BossFd2* this = THIS; + + SkelAnime_Free(&this->skelAnime, globalCtx); + Collider_DestroyJntSph(globalCtx, &this->collider); +} + +void BossFd2_SetupEmerge(BossFd2* this, GlobalContext* globalCtx) { + BossFd* bossFd = (BossFd*)this->actor.parent; + s16 temp_rand; + s8 health; + + osSyncPrintf("UP INIT 1\n"); + Animation_PlayOnce(&this->skelAnime, &gHoleVolvagiaEmergeAnim); + this->actionFunc = BossFd2_Emerge; + this->skelAnime.playSpeed = 0.0f; + temp_rand = Rand_ZeroFloat(8.9f); + this->actor.world.pos.x = sHoleLocations[temp_rand].x; + this->actor.world.pos.z = sHoleLocations[temp_rand].z; + this->work[FD2_ACTION_STATE] = 0; + osSyncPrintf("UP INIT 2\n"); + this->timers[0] = 10; + if (bossFd != NULL) { + health = bossFd->actor.colChkInfo.health; + if (health >= 18) { + this->work[FD2_FAKEOUT_COUNT] = 0; + } else if (health >= 12) { + this->work[FD2_FAKEOUT_COUNT] = 1; + } else if (health >= 6) { + this->work[FD2_FAKEOUT_COUNT] = 2; + } else { + this->work[FD2_FAKEOUT_COUNT] = 3; + } + } +} + +void BossFd2_Emerge(BossFd2* this, GlobalContext* globalCtx) { + s8 health; + BossFd* bossFd = (BossFd*)this->actor.parent; + Player* player = PLAYER; + s16 i; + s16 holeTime; + + osSyncPrintf("UP 1 mode %d\n", this->work[FD2_ACTION_STATE]); + SkelAnime_Update(&this->skelAnime); + osSyncPrintf("UP 1.5 \n"); + switch (this->work[FD2_ACTION_STATE]) { + case 0: + osSyncPrintf("UP time %d \n", this->timers[0]); + osSyncPrintf("PL time %x \n", player); + osSyncPrintf("MT time %x \n", bossFd); + if ((this->timers[0] == 0) && (player->actor.world.pos.y > 70.0f)) { + osSyncPrintf("UP 1.6 \n"); + bossFd->faceExposed = 0; + bossFd->holePosition.x = this->actor.world.pos.x; + bossFd->holePosition.z = this->actor.world.pos.z; + func_80033E1C(globalCtx, 1, 0x32, 0x5000); + this->work[FD2_ACTION_STATE] = 1; + this->work[FD2_HOLE_COUNTER]++; + this->actor.world.pos.y = -200.0f; + health = bossFd->actor.colChkInfo.health; + if (health == 24) { + holeTime = 30; + } else if (health >= 18) { + holeTime = 25; + } else if (health >= 12) { + holeTime = 20; + } else if (health >= 6) { + holeTime = 10; + } else { + holeTime = 5; + } + this->timers[0] = holeTime; + bossFd->timers[4] = this->timers[0] + 10; + osSyncPrintf("UP 1.7 \n"); + } + break; + case 1: + if (this->timers[0] == 0) { + if (this->work[FD2_FAKEOUT_COUNT] != 0) { + this->work[FD2_FAKEOUT_COUNT]--; + i = Rand_ZeroFloat(8.9f); + this->actor.world.pos.x = sHoleLocations[i].x; + this->actor.world.pos.z = sHoleLocations[i].z; + this->work[FD2_ACTION_STATE] = 0; + this->timers[0] = 10; + } else { + this->skelAnime.playSpeed = 1.0f; + this->fwork[FD2_END_FRAME] = Animation_GetLastFrame(&gHoleVolvagiaEmergeAnim); + this->work[FD2_ACTION_STATE] = 2; + Audio_PlayActorSound2(&this->actor, NA_SE_EN_VALVAISA_ROAR); + this->actor.shape.rot.y = this->actor.yawTowardsPlayer; + this->timers[0] = 15; + this->actor.world.pos.y = 150.0f; + for (i = 0; i < 10; i++) { + this->rightMane.pos[i].x += Rand_CenteredFloat(100.0f); + this->rightMane.pos[i].z += Rand_CenteredFloat(100.0f); + this->leftMane.pos[i].x += Rand_CenteredFloat(100.0f); + this->leftMane.pos[i].z += Rand_CenteredFloat(100.0f); + } + bossFd->work[BFD_SPLASH_TIMER] = 5; + } + } + break; + case 2: + Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 3, 0x7D0); + if ((this->timers[0] == 1) && (this->actor.xzDistToPlayer < 120.0f)) { + func_8002F6D4(globalCtx, &this->actor, 3.0f, this->actor.yawTowardsPlayer, 2.0f, 0x20); + Audio_PlayActorSound2(&player->actor, NA_SE_PL_BODY_HIT); + } + if (Animation_OnFrame(&this->skelAnime, this->fwork[FD2_END_FRAME])) { + BossFd2_SetupIdle(this, globalCtx); + } + break; + } + osSyncPrintf("UP 2\n"); +} + +void BossFd2_SetupIdle(BossFd2* this, GlobalContext* globalCtx) { + BossFd* bossFd = (BossFd*)this->actor.parent; + s8 health; + s16 idleTime; + + osSyncPrintf("UP INIT 1\n"); + Animation_PlayLoop(&this->skelAnime, &gHoleVolvagiaTurnAnim); + this->actionFunc = BossFd2_Idle; + health = bossFd->actor.colChkInfo.health; + if (health == 24) { + idleTime = 50; + } else if (health >= 18) { + idleTime = 40; + } else if (health >= 12) { + idleTime = 40; + } else if (health >= 6) { + idleTime = 30; + } else { + idleTime = 20; + } + this->timers[0] = idleTime; +} + +void BossFd2_Idle(BossFd2* this, GlobalContext* globalCtx) { + s16 prevToLink; + + SkelAnime_Update(&this->skelAnime); + prevToLink = this->work[FD2_TURN_TO_LINK]; + this->work[FD2_TURN_TO_LINK] = + Math_SmoothStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 3, 0x7D0, 0); + osSyncPrintf("SW1 = %d\n", prevToLink); + osSyncPrintf("SW2 = %d\n", this->work[FD2_TURN_TO_LINK]); + if ((fabsf(prevToLink) <= 1000.0f) && (1000.0f < fabsf(this->work[FD2_TURN_TO_LINK]))) { + Animation_MorphToLoop(&this->skelAnime, &gHoleVolvagiaTurnAnim, -5.0f); + } + if ((1000.0f < fabsf(prevToLink)) && (fabsf(this->work[FD2_TURN_TO_LINK]) <= 1000.0f)) { + Animation_MorphToLoop(&this->skelAnime, &gHoleVolvagiaIdleAnim, -5.0f); + } + if (this->timers[0] == 0) { + if (this->actor.xzDistToPlayer < 200.0f) { + BossFd2_SetupClawSwipe(this, globalCtx); + } else { + BossFd2_SetupBreatheFire(this, globalCtx); + } + } +} + +void BossFd2_SetupBurrow(BossFd2* this, GlobalContext* globalCtx) { + BossFd* bossFd = (BossFd*)this->actor.parent; + + Animation_MorphToPlayOnce(&this->skelAnime, &gHoleVolvagiaBurrowAnim, -5.0f); + this->actionFunc = BossFd2_Burrow; + this->fwork[FD2_END_FRAME] = Animation_GetLastFrame(&gHoleVolvagiaBurrowAnim); + bossFd->timers[4] = 30; + this->work[FD2_ACTION_STATE] = 0; +} + +void BossFd2_Burrow(BossFd2* this, GlobalContext* globalCtx) { + BossFd* bossFd = (BossFd*)this->actor.parent; + + if (this->work[FD2_ACTION_STATE] == 0) { + SkelAnime_Update(&this->skelAnime); + if (Animation_OnFrame(&this->skelAnime, this->fwork[FD2_END_FRAME])) { + this->work[FD2_ACTION_STATE] = 1; + this->timers[0] = 25; + } + } else { + Math_ApproachF(&this->actor.world.pos.y, -100.0f, 1.0f, 10.0f); + if (this->timers[0] == 0) { + if ((this->work[FD2_HOLE_COUNTER] >= 3) && ((s8)bossFd->actor.colChkInfo.health < 24)) { + this->work[FD2_HOLE_COUNTER] = 0; + this->actionFunc = BossFd2_Wait; + bossFd->handoffSignal = FD2_SIGNAL_FLY; + } else { + BossFd2_SetupEmerge(this, globalCtx); + } + } + } +} + +void BossFd2_SetupBreatheFire(BossFd2* this, GlobalContext* globalCtx) { + Animation_MorphToPlayOnce(&this->skelAnime, &gHoleVolvagiaBreatheFireAnim, -5.0f); + this->actionFunc = BossFd2_BreatheFire; + this->fwork[FD2_END_FRAME] = Animation_GetLastFrame(&gHoleVolvagiaBreatheFireAnim); + this->work[FD2_ACTION_STATE] = 0; +} + +static Vec3f sUnkVec = { 0.0f, 0.0f, 50.0f }; // Unused? BossFd uses a similar array for its fire breath sfx. + +void BossFd2_BreatheFire(BossFd2* this, GlobalContext* globalCtx) { + s16 i; + Vec3f toLink; + s16 angleX; + s16 angleY; + s16 breathOpacity = 0; + BossFd* bossFd = (BossFd*)this->actor.parent; + Player* player = PLAYER; + f32 tempX; + f32 tempY; + + SkelAnime_Update(&this->skelAnime); + if (Animation_OnFrame(&this->skelAnime, this->fwork[FD2_END_FRAME])) { + BossFd2_SetupBurrow(this, globalCtx); + } + if ((25.0f <= this->skelAnime.curFrame) && (this->skelAnime.curFrame < 70.0f)) { + if (this->skelAnime.curFrame == 25.0f) { + globalCtx->envCtx.unk_D8 = 0.0f; + } + Audio_PlayActorSound2(&this->actor, NA_SE_EN_VALVAISA_FIRE - SFX_FLAG); + if (this->skelAnime.curFrame > 50) { + breathOpacity = (70.0f - this->skelAnime.curFrame) * 12.0f; + } else { + breathOpacity = 255; + } + toLink.x = player->actor.world.pos.x - this->headPos.x; + toLink.y = player->actor.world.pos.y - this->headPos.y; + toLink.z = player->actor.world.pos.z - this->headPos.z; + angleY = Math_Atan2S(toLink.z, toLink.x); + angleX = -Math_Atan2S(sqrtf(SQ(toLink.x) + SQ(toLink.z)), toLink.y); + angleY -= this->actor.shape.rot.y; + if (angleY > 0x1F40) { + angleY = 0x1F40; + } + if (angleY < -0x1F40) { + angleY = -0x1F40; + } + angleX += (-0x1B58); + if (angleX > 0x3E8) { + angleX = 0x3E8; + } + if (angleX < -0xFA0) { + angleX = -0xFA0; + } + Math_ApproachS(&this->headRot.y, angleY, 5, 0x7D0); + Math_ApproachS(&this->headRot.x, angleX, 5, 0x7D0); + } else { + Math_ApproachS(&this->headRot.y, 0, 5, 0x7D0); + Math_ApproachS(&this->headRot.x, 0, 5, 0x7D0); + } + if (breathOpacity != 0) { + f32 breathScale; + Vec3f spawnSpeed = { 0.0f, 0.0f, 0.0f }; + Vec3f spawnVel; + Vec3f spawnAccel = { 0.0f, 0.0f, 0.0f }; + Vec3f spawnPos; + + bossFd->fogMode = 2; + spawnSpeed.z = 30.0f; + spawnPos = this->headPos; + + tempY = ((this->actor.shape.rot.y + this->headRot.y) / (f32)0x8000) * M_PI; + tempX = ((this->headRot.x / (f32)0x8000) * M_PI) + 1.0f / 2; + Matrix_RotateY(tempY, MTXMODE_NEW); + Matrix_RotateX(tempX, MTXMODE_APPLY); + Matrix_MultVec3f(&spawnSpeed, &spawnVel); + + breathScale = 300.0f + 50.0f * Math_SinS(this->work[FD2_VAR_TIMER] * 0x2000); + BossFd2_SpawnFireBreath(globalCtx, bossFd->effects, &spawnPos, &spawnVel, &spawnAccel, breathScale, + breathOpacity, this->actor.shape.rot.y + this->headRot.y); + + spawnPos.x += spawnVel.x * 0.5f; + spawnPos.y += spawnVel.y * 0.5f; + spawnPos.z += spawnVel.z * 0.5f; + + breathScale = 300.0f + 50.0f * Math_SinS(this->work[FD2_VAR_TIMER] * 0x2000); + BossFd2_SpawnFireBreath(globalCtx, bossFd->effects, &spawnPos, &spawnVel, &spawnAccel, breathScale, + breathOpacity, this->actor.shape.rot.y + this->headRot.y); + + spawnSpeed.x = 0.0f; + spawnSpeed.y = 17.0f; + spawnSpeed.z = 0.0f; + + for (i = 0; i < 6; i++) { + tempY = Rand_ZeroFloat(2.0f * M_PI); + tempX = Rand_ZeroFloat(2.0f * M_PI); + Matrix_RotateY(tempY, MTXMODE_NEW); + Matrix_RotateX(tempX, MTXMODE_APPLY); + Matrix_MultVec3f(&spawnSpeed, &spawnVel); + + spawnAccel.x = (spawnVel.x * -10.0f) / 100.0f; + spawnAccel.y = (spawnVel.y * -10.0f) / 100.0f; + spawnAccel.z = (spawnVel.z * -10.0f) / 100.0f; + + BossFd2_SpawnEmber(globalCtx, bossFd->effects, &this->headPos, &spawnVel, &spawnAccel, + (s16)Rand_ZeroFloat(2.0f) + 8); + } + } +} + +void BossFd2_SetupClawSwipe(BossFd2* this, GlobalContext* globalCtx) { + Animation_MorphToPlayOnce(&this->skelAnime, &gHoleVolvagiaClawSwipeAnim, -5.0f); + this->actionFunc = BossFd2_ClawSwipe; + this->fwork[FD2_END_FRAME] = Animation_GetLastFrame(&gHoleVolvagiaClawSwipeAnim); +} + +void BossFd2_ClawSwipe(BossFd2* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + if (Animation_OnFrame(&this->skelAnime, 5.0f)) { + Audio_PlayActorSound2(&this->actor, NA_SE_EN_VALVAISA_ROAR); + Audio_PlayActorSound2(&this->actor, NA_SE_EN_VALVAISA_SW_NAIL); + } + if (Animation_OnFrame(&this->skelAnime, this->fwork[FD2_END_FRAME])) { + BossFd2_SetupBurrow(this, globalCtx); + } +} + +void BossFd2_SetupVulnerable(BossFd2* this, GlobalContext* globalCtx) { + Animation_PlayOnce(&this->skelAnime, &gHoleVolvagiaKnockoutAnim); + this->fwork[FD2_END_FRAME] = Animation_GetLastFrame(&gHoleVolvagiaKnockoutAnim); + this->actionFunc = BossFd2_Vulnerable; + this->work[FD2_ACTION_STATE] = 0; +} + +void BossFd2_Vulnerable(BossFd2* this, GlobalContext* globalCtx) { + BossFd* bossFd = (BossFd*)this->actor.parent; + s16 i; + + this->disableAT = true; + this->actor.flags |= 0x400; + SkelAnime_Update(&this->skelAnime); + switch (this->work[FD2_ACTION_STATE]) { + case 0: + if (Animation_OnFrame(&this->skelAnime, 13.0f)) { + Audio_PlayActorSound2(&this->actor, NA_SE_EN_VALVAISA_MAHI2); + } + if (Animation_OnFrame(&this->skelAnime, this->fwork[FD2_END_FRAME] - 3.0f)) { + for (i = 0; i < 25; i++) { + Vec3f spawnVel; + Vec3f spawnAccel = { 0.0f, 0.0f, 0.0f }; + Vec3f spawnPos; + + spawnVel.x = Rand_CenteredFloat(8.0f); + spawnVel.y = Rand_ZeroFloat(1.0f); + spawnVel.z = Rand_CenteredFloat(8.0f); + + spawnAccel.y = 0.5f; + + spawnPos.x = Rand_CenteredFloat(10.0f) + this->actor.focus.pos.x; + spawnPos.y = Rand_CenteredFloat(10.0f) + this->actor.focus.pos.y; + spawnPos.z = Rand_CenteredFloat(10.0f) + this->actor.focus.pos.z; + + BossFd2_SpawnDust(bossFd->effects, &spawnPos, &spawnVel, &spawnAccel, + Rand_ZeroFloat(100.0f) + 300.0f); + } + Audio_PlayActorSound2(&this->actor, NA_SE_EN_VALVAISA_LAND); + } + if (Animation_OnFrame(&this->skelAnime, this->fwork[FD2_END_FRAME])) { + Animation_MorphToLoop(&this->skelAnime, &gHoleVolvagiaVulnerableAnim, -5.0f); + this->work[FD2_ACTION_STATE] = 1; + this->timers[0] = 60; + } + break; + case 1: + if ((this->work[FD2_VAR_TIMER] & 0xF) == 0xF) { + Audio_PlayActorSound2(&this->actor, NA_SE_EN_VALVAISA_KNOCKOUT); + } + if (this->timers[0] == 0) { + BossFd2_SetupBurrow(this, globalCtx); + } + break; + } +} + +void BossFd2_SetupDamaged(BossFd2* this, GlobalContext* globalCtx) { + Animation_PlayOnce(&this->skelAnime, &gHoleVolvagiaHitAnim); + this->fwork[FD2_END_FRAME] = Animation_GetLastFrame(&gHoleVolvagiaHitAnim); + this->actionFunc = BossFd2_Damaged; + this->work[FD2_ACTION_STATE] = 0; +} + +void BossFd2_Damaged(BossFd2* this, GlobalContext* globalCtx) { + BossFd* bossFd = (BossFd*)this->actor.parent; + + SkelAnime_Update(&this->skelAnime); + this->disableAT = true; + if (this->work[FD2_ACTION_STATE] == 0) { + if (Animation_OnFrame(&this->skelAnime, this->fwork[FD2_END_FRAME])) { + Animation_PlayOnce(&this->skelAnime, &gHoleVolvagiaDamagedAnim); + this->fwork[FD2_END_FRAME] = Animation_GetLastFrame(&gHoleVolvagiaDamagedAnim); + this->work[FD2_ACTION_STATE] = 1; + } + } else if (this->work[FD2_ACTION_STATE] == 1) { + if (Animation_OnFrame(&this->skelAnime, 6.0f)) { + Audio_PlayActorSound2(&this->actor, NA_SE_EN_VALVAISA_DAMAGE2); + } + if (Animation_OnFrame(&this->skelAnime, 20.0f)) { + bossFd->timers[4] = 30; + } + if (Animation_OnFrame(&this->skelAnime, this->fwork[FD2_END_FRAME])) { + this->work[FD2_ACTION_STATE] = 2; + this->timers[0] = 25; + } + } else { + Math_ApproachF(&this->actor.world.pos.y, -100.0f, 1.0f, 10.0f); + if (this->timers[0] == 0) { + this->actionFunc = BossFd2_Wait; + bossFd->handoffSignal = FD2_SIGNAL_FLY; + } + } +} + +void BossFd2_SetupDeath(BossFd2* this, GlobalContext* globalCtx) { + this->fwork[FD2_END_FRAME] = Animation_GetLastFrame(&gHoleVolvagiaDamagedAnim); + Animation_Change(&this->skelAnime, &gHoleVolvagiaDamagedAnim, 1.0f, 0.0f, this->fwork[FD2_END_FRAME], + ANIMMODE_ONCE_INTERP, -3.0f); + this->actionFunc = BossFd2_Death; + this->actor.flags &= ~1; + this->deathState = DEATH_START; +} + +void BossFd2_UpdateCamera(BossFd2* this, GlobalContext* globalCtx) { + if (this->deathCamera != SUBCAM_FREE) { + Math_ApproachF(&this->camData.eye.x, this->camData.nextEye.x, this->camData.eyeMaxVel.x, + this->camData.eyeVel.x * this->camData.speedMod); + Math_ApproachF(&this->camData.eye.y, this->camData.nextEye.y, this->camData.eyeMaxVel.y, + this->camData.eyeVel.y * this->camData.speedMod); + Math_ApproachF(&this->camData.eye.z, this->camData.nextEye.z, this->camData.eyeMaxVel.z, + this->camData.eyeVel.z * this->camData.speedMod); + Math_ApproachF(&this->camData.at.x, this->camData.nextAt.x, this->camData.atMaxVel.x, + this->camData.atVel.x * this->camData.speedMod); + Math_ApproachF(&this->camData.at.y, this->camData.nextAt.y, this->camData.atMaxVel.y, + this->camData.atVel.y * this->camData.speedMod); + Math_ApproachF(&this->camData.at.z, this->camData.nextAt.z, this->camData.atMaxVel.z, + this->camData.atVel.z * this->camData.speedMod); + Math_ApproachF(&this->camData.speedMod, 1.0f, 1.0f, this->camData.accel); + this->camData.at.y += this->camData.yMod; + Gameplay_CameraSetAtEye(globalCtx, this->deathCamera, &this->camData.at, &this->camData.eye); + Math_ApproachF(&this->camData.yMod, 0.0f, 1.0f, 0.1f); + } +} + +void BossFd2_Death(BossFd2* this, GlobalContext* globalCtx) { + f32 retreatSpeed; + Vec3f sp70; + Vec3f sp64; + BossFd* bossFd = (BossFd*)this->actor.parent; + Camera* mainCam = Gameplay_GetCamera(globalCtx, MAIN_CAM); + f32 pad3; + f32 pad2; + f32 pad1; + f32 cameraShake; + SkelAnime* skelAnime = &this->skelAnime; + + SkelAnime_Update(skelAnime); + switch (this->deathState) { + case DEATH_START: + this->deathState = DEATH_RETREAT; + func_80064520(globalCtx, &globalCtx->csCtx); + func_8002DF54(globalCtx, &this->actor, 1); + this->deathCamera = Gameplay_CreateSubCamera(globalCtx); + Gameplay_ChangeCameraStatus(globalCtx, MAIN_CAM, CAM_STAT_WAIT); + Gameplay_ChangeCameraStatus(globalCtx, this->deathCamera, CAM_STAT_ACTIVE); + this->camData.eye = mainCam->eye; + this->camData.at = mainCam->at; + this->camData.eyeVel.x = 100.0f; + this->camData.eyeVel.y = 100.0f; + this->camData.eyeVel.z = 100.0f; + this->camData.atVel.x = 100.0f; + this->camData.atVel.y = 100.0f; + this->camData.atVel.z = 100.0f; + this->camData.accel = 0.02f; + this->timers[0] = 0; + this->work[FD2_HOLE_COUNTER] = 0; + this->camData.eyeMaxVel.x = 0.1f; + this->camData.eyeMaxVel.y = 0.1f; + this->camData.eyeMaxVel.z = 0.1f; + this->camData.atMaxVel.x = 0.1f; + this->camData.atMaxVel.y = 0.1f; + this->camData.atMaxVel.z = 0.1f; + case DEATH_RETREAT: + this->work[FD2_HOLE_COUNTER]++; + if (this->work[FD2_HOLE_COUNTER] < 15) { + retreatSpeed = 1.0f; + } else if (this->work[FD2_HOLE_COUNTER] < 20) { + retreatSpeed = 0.5f; + } else { + retreatSpeed = 0.25f; + } + if ((this->work[FD2_HOLE_COUNTER] == 1) || (this->work[FD2_HOLE_COUNTER] == 40)) { + this->work[FD2_SCREAM_TIMER] = 20; + if (this->work[FD2_HOLE_COUNTER] == 40) { + func_800F8D04(NA_SE_EN_VALVAISA_DEAD); + } + + Audio_PlayActorSound2(&this->actor, NA_SE_EN_VALVAISA_DAMAGE2); + } + Math_ApproachF(&this->skelAnime.playSpeed, retreatSpeed, 1.0f, 1.0f); + Matrix_RotateY(((this->actor.yawTowardsPlayer / (f32)0x8000) * M_PI) + 0.2f, MTXMODE_NEW); + sp70.x = 0.0f; + sp70.y = 0.0f; + sp70.z = 250.0f; + Matrix_MultVec3f(&sp70, &sp64); + this->camData.nextEye.x = this->actor.world.pos.x + sp64.x; + this->camData.nextEye.y = 140.0f; + this->camData.nextEye.z = this->actor.world.pos.z + sp64.z; + if (this->actor.focus.pos.y >= 90.0f) { + this->camData.nextAt.y = this->actor.focus.pos.y; + this->camData.nextAt.x = this->actor.focus.pos.x; + this->camData.nextAt.z = this->actor.focus.pos.z; + } + if (this->timers[0] == 0) { + if (Animation_OnFrame(skelAnime, 20.0f)) { + bossFd->timers[4] = 60; + } + if (this->work[FD2_HOLE_COUNTER] >= 100) { + this->deathState = DEATH_HANDOFF; + this->timers[0] = 50; + } + } else if (Animation_OnFrame(skelAnime, 15.0f)) { + Animation_MorphToPlayOnce(skelAnime, &gHoleVolvagiaDamagedAnim, -10.0f); + } + break; + case DEATH_HANDOFF: + if (this->timers[0] == 0) { + this->actor.draw = NULL; + this->deathState = DEATH_FD_BODY; + bossFd->handoffSignal = FD2_SIGNAL_DEATH; + this->work[FD2_ACTION_STATE] = 0; + this->camData.speedMod = 0.0f; + } else { + Math_ApproachF(&this->actor.world.pos.y, -100.0f, 1.0f, 5.0f); + } + break; + case DEATH_FD_BODY: + if (bossFd->actor.world.pos.y < 80.0f) { + if (bossFd->actor.world.rot.x > 0x3000) { + this->camData.nextAt = bossFd->actor.world.pos; + this->camData.nextAt.y = 80.0f; + this->camData.nextEye.x = bossFd->actor.world.pos.x; + this->camData.nextEye.y = 150.0f; + this->camData.nextEye.z = bossFd->actor.world.pos.z + 300.0f; + } + } else { + this->camData.nextAt = bossFd->actor.world.pos; + this->camData.nextEye.x = this->actor.world.pos.x; + Math_ApproachF(&this->camData.nextEye.y, 200.0f, 1.0f, 2.0f); + Math_ApproachF(&this->camData.nextEye.z, bossFd->actor.world.pos.z + 200.0f, 1.0f, 3.0f); + if (this->work[FD2_ACTION_STATE] == 0) { + this->work[FD2_ACTION_STATE]++; + this->camData.speedMod = 0.0f; + this->camData.accel = 0.02f; + func_8002DF54(globalCtx, &bossFd->actor, 1); + } + } + if ((bossFd->work[BFD_ACTION_STATE] == BOSSFD_BONES_FALL) && (bossFd->timers[0] == 5)) { + this->deathState = DEATH_FD_SKULL; + this->camData.speedMod = 0.0f; + this->camData.accel = 0.02f; + this->camData.nextEye.y = 150.0f; + this->camData.nextEye.z = bossFd->actor.world.pos.z + 300.0f; + } + break; + case DEATH_FD_SKULL: + Math_ApproachF(&this->camData.nextAt.y, 100.0, 1.0f, 100.0f); + this->camData.nextAt.x = 0.0f; + this->camData.nextAt.z = 0.0f; + this->camData.nextEye.x = 0.0f; + this->camData.nextEye.y = 140.0f; + Math_ApproachF(&this->camData.nextEye.z, 220.0f, 0.5f, 1.15f); + if (bossFd->work[BFD_CAM_SHAKE_TIMER] != 0) { + bossFd->work[BFD_CAM_SHAKE_TIMER]--; + cameraShake = bossFd->work[BFD_CAM_SHAKE_TIMER] / 0.5f; + if (cameraShake >= 20.0f) { + cameraShake = 20.0f; + } + this->camData.yMod = (bossFd->work[BFD_CAM_SHAKE_TIMER] & 1) ? cameraShake : -cameraShake; + } + if (bossFd->work[BFD_ACTION_STATE] == BOSSFD_SKULL_BURN) { + this->deathState = DEATH_FINISH; + mainCam->eye = this->camData.eye; + mainCam->eyeNext = this->camData.eye; + mainCam->at = this->camData.at; + func_800C08AC(globalCtx, this->deathCamera, 0); + this->deathCamera = 0; + func_80064534(globalCtx, &globalCtx->csCtx); + func_8002DF54(globalCtx, &this->actor, 7); + Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_DOOR_WARP1, 0.0f, 100.0f, 0.0f, + 0, 0, 0, -1); + Flags_SetClear(globalCtx, globalCtx->roomCtx.curRoom.num); + } + break; + case DEATH_FINISH: + break; + } + BossFd2_UpdateCamera(this, globalCtx); +} + +void BossFd2_Wait(BossFd2* this, GlobalContext* globalCtx) { + BossFd* bossFd = (BossFd*)this->actor.parent; + + if (bossFd->handoffSignal == FD2_SIGNAL_GROUND) { + bossFd->handoffSignal = FD2_SIGNAL_NONE; + BossFd2_SetupEmerge(this, globalCtx); + this->timers[0] = 20; + this->work[FD2_HOLE_COUNTER] = 0; + } +} + +void BossFd2_CollisionCheck(BossFd2* this, GlobalContext* globalCtx) { + s16 i; + ColliderInfo* hurtbox; + BossFd* bossFd = (BossFd*)this->actor.parent; + + if (this->actionFunc == BossFd2_ClawSwipe) { + Player* player = PLAYER; + + for (i = 0; i < ARRAY_COUNT(this->elements); i++) { + if (this->collider.elements[i].info.toucherFlags & TOUCH_HIT) { + this->collider.elements[i].info.toucherFlags &= ~TOUCH_HIT; + Audio_PlayActorSound2(&player->actor, NA_SE_PL_BODY_HIT); + } + } + } + if (!bossFd->faceExposed) { + this->collider.elements[0].info.elemType = ELEMTYPE_UNK2; + this->collider.base.colType = COLTYPE_METAL; + } else { + this->collider.elements[0].info.elemType = ELEMTYPE_UNK3; + this->collider.base.colType = COLTYPE_HIT3; + } + + if (this->collider.elements[0].info.bumperFlags & BUMP_HIT) { + this->collider.elements[0].info.bumperFlags &= ~BUMP_HIT; + + hurtbox = this->collider.elements[0].info.acHitInfo; + if (!bossFd->faceExposed) { + if (hurtbox->toucher.dmgFlags & 0x40000040) { + bossFd->actor.colChkInfo.health -= 2; + if ((s8)bossFd->actor.colChkInfo.health <= 2) { + bossFd->actor.colChkInfo.health = 1; + } + bossFd->faceExposed = true; + BossFd2_SetupVulnerable(this, globalCtx); + this->work[FD2_INVINC_TIMER] = 30; + this->work[FD2_DAMAGE_FLASH_TIMER] = 5; + Audio_PlayActorSound2(&this->actor, NA_SE_EN_VALVAISA_MAHI1); + for (i = 0; i < 30; i++) { + Vec3f debrisVel = { 0.0f, 0.0f, 0.0f }; + Vec3f debrisAccel = { 0.0f, -1.0f, 0.0f }; + Vec3f debrisPos; + + debrisVel.x = Rand_CenteredFloat(10.0f); + debrisVel.y = Rand_ZeroFloat(5.0f) + 8.0f; + debrisVel.z = Rand_CenteredFloat(10.0f); + + debrisPos.x = this->actor.focus.pos.x; + debrisPos.y = this->actor.focus.pos.y; + debrisPos.z = this->actor.focus.pos.z; + + BossFd2_SpawnDebris(globalCtx, bossFd->effects, &debrisPos, &debrisVel, &debrisAccel, + (s16)Rand_ZeroFloat(10.0) + 10); + } + } + } else { + u8 canKill = false; + u8 damage; + + if ((damage = CollisionCheck_GetSwordDamage(hurtbox->toucher.dmgFlags)) == 0) { + damage = (hurtbox->toucher.dmgFlags & 0x00001000) ? 4 : 2; + } else { + canKill = true; + } + if (hurtbox->toucher.dmgFlags & 0x80) { + damage = 0; + } + if (((s8)bossFd->actor.colChkInfo.health > 2) || canKill) { + bossFd->actor.colChkInfo.health -= damage; + osSyncPrintf(VT_FGCOL(GREEN)); + osSyncPrintf("damage %d\n", damage); + } + osSyncPrintf(VT_RST); + osSyncPrintf("hp %d\n", bossFd->actor.colChkInfo.health); + + if ((s8)bossFd->actor.colChkInfo.health <= 0) { + bossFd->actor.colChkInfo.health = 0; + BossFd2_SetupDeath(this, globalCtx); + this->work[FD2_DAMAGE_FLASH_TIMER] = 10; + this->work[FD2_INVINC_TIMER] = 30000; + Audio_SetBGM(0x100100FF); + Audio_PlayActorSound2(&this->actor, NA_SE_EN_VALVAISA_DEAD); + func_80032C7C(globalCtx, &this->actor); + } else if (damage) { + BossFd2_SetupDamaged(this, globalCtx); + this->work[FD2_DAMAGE_FLASH_TIMER] = 10; + this->work[FD2_INVINC_TIMER] = 100; + Audio_PlayActorSound2(&this->actor, NA_SE_EN_VALVAISA_DAMAGE1); + } + if (damage) { + for (i = 0; i < 30; i++) { + Vec3f pieceVel = { 0.0f, 0.0f, 0.0f }; + Vec3f pieceAccel = { 0.0f, -1.0f, 0.0f }; + Vec3f piecePos; + + pieceVel.x = Rand_CenteredFloat(6.0f); + pieceVel.y = Rand_ZeroFloat(4.0f) + 6.0f; + pieceVel.z = Rand_CenteredFloat(6.0f); + + piecePos.x = this->actor.focus.pos.x; + piecePos.y = this->actor.focus.pos.y; + piecePos.z = this->actor.focus.pos.z; + + BossFd2_SpawnSkullPiece(globalCtx, bossFd->effects, &piecePos, &pieceVel, &pieceAccel, + (s16)Rand_ZeroFloat(6.0f) + 10); + } + } + } + } +} + +void BossFd2_UpdateFace(BossFd2* this, GlobalContext* globalCtx) { + f32 maxOpen; + f32 openRate; + s16 eyeStates[5] = { EYE_OPEN, EYE_HALF, EYE_CLOSED, EYE_CLOSED, EYE_HALF }; + + if (((this->work[FD2_VAR_TIMER] % 8) == 0) && (Rand_ZeroOne() < 0.3f)) { + this->work[FD2_BLINK_TIMER] = 4; + } + if ((this->actionFunc == BossFd2_Vulnerable) || (this->actionFunc == BossFd2_Damaged)) { + if (this->work[FD2_VAR_TIMER] & 0x10) { + this->eyeState = EYE_HALF; + } else { + this->eyeState = EYE_CLOSED; + } + } else { + this->eyeState = eyeStates[this->work[FD2_BLINK_TIMER]]; + } + + if (this->work[FD2_BLINK_TIMER] != 0) { + this->work[FD2_BLINK_TIMER]--; + } + + if (this->work[FD2_SCREAM_TIMER] != 0) { + maxOpen = 6000.0f; + openRate = 1300.0f; + } else { + maxOpen = (this->work[FD2_VAR_TIMER] & 0x10) ? 1000.0f : 0.0f; + openRate = 700.0f; + } + Math_ApproachF(&this->jawOpening, maxOpen, 0.3f, openRate); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D285C.s") + if (this->work[FD2_SCREAM_TIMER] != 0) { + this->work[FD2_SCREAM_TIMER]--; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D2930.s") +void BossFd2_Update(Actor* thisx, GlobalContext* globalCtx) { + GlobalContext* globalCtx2 = globalCtx; + BossFd2* this = THIS; + s16 i; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D2A08.s") + osSyncPrintf("FD2 move start \n"); + this->disableAT = false; + this->actor.flags &= ~0x400; + this->work[FD2_VAR_TIMER]++; + this->work[FD2_UNK_TIMER]++; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/BossFd2_Init.s") + this->actionFunc(this, globalCtx2); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/BossFd2_Destroy.s") + for (i = 0; i < ARRAY_COUNT(this->timers); i++) { + if (this->timers[i] != 0) { + this->timers[i]--; + } + } + if (this->work[FD2_DAMAGE_FLASH_TIMER] != 0) { + this->work[FD2_DAMAGE_FLASH_TIMER]--; + } + if (this->work[FD2_INVINC_TIMER] != 0) { + this->work[FD2_INVINC_TIMER]--; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D2BD0.s") + if (this->deathState == DEATH_START) { + if (this->work[FD2_INVINC_TIMER] == 0) { + BossFd2_CollisionCheck(this, globalCtx2); + } + CollisionCheck_SetAC(globalCtx2, &globalCtx2->colChkCtx, &this->collider.base); + CollisionCheck_SetOC(globalCtx2, &globalCtx2->colChkCtx, &this->collider.base); + if (!this->disableAT) { + CollisionCheck_SetAT(globalCtx2, &globalCtx2->colChkCtx, &this->collider.base); + } + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D2CE0.s") + BossFd2_UpdateFace(this, globalCtx2); + this->fwork[FD2_TEX1_SCROLL_X] += 4.0f; + this->fwork[FD2_TEX1_SCROLL_Y] = 120.0f; + this->fwork[FD2_TEX2_SCROLL_X] += 3.0f; + this->fwork[FD2_TEX2_SCROLL_Y] -= 2.0f; + if (this->actor.focus.pos.y < 90.0f) { + this->actor.flags &= ~1; + } else { + this->actor.flags |= 1; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D308C.s") +s32 BossFd2_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, + void* thisx) { + BossFd2* this = THIS; + BossFd* bossFd = (BossFd*)this->actor.parent; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D3140.s") + if (limbIndex == 31) { + rot->y -= (f32)this->headRot.y; + rot->z += (f32)this->headRot.x; + } + switch (limbIndex) { + case 35: + case 36: + rot->z -= this->jawOpening * 0.1f; + break; + case 32: + rot->z += this->jawOpening; + break; + } + if ((bossFd->faceExposed == 1) && (limbIndex == 35)) { + *dList = gHoleVolvagiaBrokenFaceDL; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D32B4.s") + if ((limbIndex == 32) || (limbIndex == 35) || (limbIndex == 36)) { + OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_fd2.c", 2165); + gDPPipeSync(POLY_OPA_DISP++); + gDPSetEnvColor(POLY_OPA_DISP++, 255, 255, 255, (s8)bossFd->fwork[BFD_HEAD_TEX2_ALPHA]); + CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_fd2.c", 2172); + } else { + OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_fd2.c", 2174); + gDPPipeSync(POLY_OPA_DISP++); + gDPSetEnvColor(POLY_OPA_DISP++, 255, 255, 255, (s8)bossFd->fwork[BFD_BODY_TEX2_ALPHA]); + CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_fd2.c", 2181); + } + if ((0 < limbIndex) && (limbIndex < 16)) { + *dList = NULL; + } + return false; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D3330.s") +void BossFd2_PostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) { + static Vec3f targetMod = { 4500.0f, 0.0f, 0.0f }; + static Vec3f headMod = { 4000.0f, 0.0f, 0.0f }; + static Vec3f centerManeMod = { 4000.0f, -2900.0, 2000.0f }; + static Vec3f rightManeMod = { 4000.0f, -1600.0, 0.0f }; + static Vec3f leftManeMod = { 4000.0f, -1600.0, -2000.0f }; + BossFd2* this = THIS; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D3400.s") + if (limbIndex == 35) { + Matrix_MultVec3f(&targetMod, &this->actor.focus.pos); + Matrix_MultVec3f(&headMod, &this->headPos); + Matrix_MultVec3f(¢erManeMod, &this->centerMane.head); + Matrix_MultVec3f(&rightManeMod, &this->rightMane.head); + Matrix_MultVec3f(&leftManeMod, &this->leftMane.head); + } + Collider_UpdateSpheres(limbIndex, &this->collider); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D3464.s") +void BossFd2_UpdateMane(BossFd2* this, GlobalContext* globalCtx, Vec3f* head, Vec3f* pos, Vec3f* rot, Vec3f* pull, + f32* scale) { + f32 sp138[10] = { 0.0f, 100.0f, 50.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; + f32 sp110[10] = { 0.0f, 5.0f, -10.0f, 500.0f, 500.0f, 500.0f, 500.0f, 500.0f, 500.0f, 500.0f }; + f32 spE8[10] = { 0.4f, 0.6f, 0.8f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; + s16 i; + Vec3f temp_vec; + f32 temp_f2; + f32 phi_f0; + f32 temp_angleX; + f32 temp_angleY; + Vec3f spBC; + Vec3f spB0; + f32 xyScale; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D39A8.s") + OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_fd2.c", 2389); + Matrix_Push(); + gDPPipeSync(POLY_OPA_DISP++); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D3A08.s") + for (i = 0; i < 10; i++) { + if (i == 0) { + (pos + i)->x = head->x; + (pos + i)->y = head->y; + (pos + i)->z = head->z; + } else { + Math_ApproachF(&(pull + i)->x, 0.0f, 1.0f, 1.0f); + Math_ApproachF(&(pull + i)->y, 0.0f, 1.0f, 1.0f); + Math_ApproachF(&(pull + i)->z, 0.0f, 1.0f, 1.0f); + } + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D3A80.s") + for (i = 1; i < 10; i++) { + temp_vec.x = (pos + i)->x + (pull + i)->x - (pos + i - 1)->x; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D3AE0.s") + phi_f0 = (pos + i)->y + (pull + i)->y - 2.0f + sp138[i]; + temp_f2 = (pos + i - 1)->y + sp110[i]; + if (phi_f0 > temp_f2) { + phi_f0 = temp_f2; + } + if ((head->y >= -910.0f) && (phi_f0 < 110.0f)) { + phi_f0 = 110.0f; + } + temp_vec.y = phi_f0 - (pos + i - 1)->y; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D3D38.s") + temp_vec.z = (pos + i)->z + (pull + i)->z - (pos + i - 1)->z; + temp_angleY = Math_Atan2F(temp_vec.z, temp_vec.x); + temp_angleX = -Math_Atan2F(sqrtf(SQ(temp_vec.x) + SQ(temp_vec.z)), temp_vec.y); + (rot + i - 1)->y = temp_angleY; + (rot + i - 1)->x = temp_angleX; + spBC.x = 0.0f; + spBC.y = 0.0f; + spBC.z = spE8[i] * 25.0f; + Matrix_RotateY(temp_angleY, MTXMODE_NEW); + Matrix_RotateX(temp_angleX, MTXMODE_APPLY); + Matrix_MultVec3f(&spBC, &spB0); + temp_vec.x = (pos + i)->x; + temp_vec.y = (pos + i)->y; + temp_vec.z = (pos + i)->z; + (pos + i)->x = (pos + i - 1)->x + spB0.x; + (pos + i)->y = (pos + i - 1)->y + spB0.y; + (pos + i)->z = (pos + i - 1)->z + spB0.z; + (pull + i)->x = (((pos + i)->x - temp_vec.x) * 88.0f) / 100.0f; + (pull + i)->y = (((pos + i)->y - temp_vec.y) * 88.0f) / 100.0f; + (pull + i)->z = (((pos + i)->z - temp_vec.z) * 88.0f) / 100.0f; + if ((pull + i)->x > 30.0f) { + (pull + i)->x = 30.0f; + } + if ((pull + i)->x < -30.0f) { + (pull + i)->x = -30.0f; + } + if ((pull + i)->y > 30.0f) { + (pull + i)->y = 30.0f; + } + if ((pull + i)->y < -30.0f) { + (pull + i)->y = -30.0f; + } + if ((pull + i)->z > 30.0f) { + (pull + i)->z = 30.0f; + } + if ((pull + i)->z < -30.0f) { + (pull + i)->z = -30.0f; + } + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D3D98.s") + for (i = 0; i < 9; i++) { + Matrix_Translate((pos + i)->x, (pos + i)->y, (pos + i)->z, MTXMODE_NEW); + Matrix_RotateY((rot + i)->y, MTXMODE_APPLY); + Matrix_RotateX((rot + i)->x, MTXMODE_APPLY); + xyScale = (0.01f - (i * 0.0009f)) * spE8[i] * scale[i]; + Matrix_Scale(xyScale, xyScale, 0.01f * spE8[i], MTXMODE_APPLY); + Matrix_RotateX(M_PI / 2.0f, MTXMODE_APPLY); + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_fd2.c", 2498), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_XLU_DISP++, gHoleVolvagiaManeVtxDL); + } + Matrix_Pop(); + CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_fd2.c", 2503); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D3EC8.s") +void BossFd2_DrawMane(BossFd2* this, GlobalContext* globalCtx) { + s32 pad; + BossFd* bossFd = (BossFd*)this->actor.parent; + s16 i; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D3F58.s") + OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_fd2.c", 2515); + if (1) {} + for (i = 0; i < 10; i++) { + this->centerMane.scale[i] = 1.5f + 0.3f * Math_SinS(5596.0f * this->work[FD2_VAR_TIMER] + i * 0x3200); + this->rightMane.scale[i] = 1.5f + 0.3f * Math_SinS(5496.0f * this->work[FD2_VAR_TIMER] + i * 0x3200); + this->leftMane.scale[i] = 1.5f + 0.3f * Math_CosS(5696.0f * this->work[FD2_VAR_TIMER] + i * 0x3200); + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D40C8.s") + func_80093D84(globalCtx->state.gfxCtx); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D4748.s") + gSPDisplayList(POLY_XLU_DISP++, gHoleVolvagiaManeSetupDL); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D4790.s") + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, bossFd->fwork[BFD_MANE_COLOR_CENTER], 0, 255); + BossFd2_UpdateMane(this, globalCtx, &this->centerMane.head, this->centerMane.pos, this->centerMane.rot, + this->centerMane.pull, this->centerMane.scale); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D4C68.s") + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, bossFd->fwork[BFD_MANE_COLOR_RIGHT], 0, 255); + BossFd2_UpdateMane(this, globalCtx, &this->rightMane.head, this->rightMane.pos, this->rightMane.rot, + this->rightMane.pull, this->rightMane.scale); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/BossFd2_Update.s") + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, bossFd->fwork[BFD_MANE_COLOR_LEFT], 0, 255); + BossFd2_UpdateMane(this, globalCtx, &this->leftMane.head, this->leftMane.pos, this->leftMane.rot, + this->leftMane.pull, this->leftMane.scale); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D4F94.s") + CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_fd2.c", 2601); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D5228.s") +void BossFd2_Draw(Actor* thisx, GlobalContext* globalCtx) { + static u64* eyeTextures[] = { gHoleVolvagiaEyeOpenTex, gHoleVolvagiaEyeHalfTex, gHoleVolvagiaEyeClosedTex }; + s32 pad; + BossFd2* this = THIS; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D52CC.s") + OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_fd2.c", 2617); + osSyncPrintf("FD2 draw start \n"); + if (this->actionFunc != BossFd2_Wait) { + func_80093D18(globalCtx->state.gfxCtx); + if (this->work[FD2_DAMAGE_FLASH_TIMER] & 2) { + POLY_OPA_DISP = Gfx_SetFog(POLY_OPA_DISP, 255, 255, 255, 0, 900, 1099); + } + gSPSegment(POLY_OPA_DISP++, 0x09, SEGMENTED_TO_VIRTUAL(eyeTextures[this->eyeState])); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/func_808D58E0.s") + gSPSegment(POLY_OPA_DISP++, 0x08, + Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, (s16)this->fwork[FD2_TEX1_SCROLL_X], + (s16)this->fwork[FD2_TEX1_SCROLL_Y], 0x20, 0x20, 1, + (s16)this->fwork[FD2_TEX2_SCROLL_X], (s16)this->fwork[FD2_TEX2_SCROLL_Y], 0x20, + 0x20)); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, 255); + gDPSetEnvColor(POLY_OPA_DISP++, 255, 255, 255, 128); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Boss_Fd2/BossFd2_Draw.s") + SkelAnime_DrawFlexOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, + this->skelAnime.dListCount, BossFd2_OverrideLimbDraw, BossFd2_PostLimbDraw, &this->actor); + BossFd2_DrawMane(this, globalCtx); + POLY_OPA_DISP = func_800BC8A0(globalCtx, POLY_OPA_DISP); + } + CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_fd2.c", 2688); +} diff --git a/src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2.h b/src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2.h index ef0f6f401..129f1b48d 100644 --- a/src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2.h +++ b/src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2.h @@ -6,9 +6,87 @@ struct BossFd2; +typedef void (*BossFd2ActionFunc)(struct BossFd2*, GlobalContext*); + +typedef enum { + /* 0 */ FD2_SIGNAL_NONE, + /* 1 */ FD2_SIGNAL_FLY, + /* 2 */ FD2_SIGNAL_DEATH, + /* 100 */ FD2_SIGNAL_GROUND = 100 +} BossFd2Signal; + +typedef struct { + /* 0x000 */ Vec3f rot[10]; + /* 0x078 */ Vec3f pos[10]; + /* 0x0F0 */ Vec3f pull[10]; + /* 0x168 */ f32 scale[10]; + /* 0x190 */ Vec3f head; +} BossFd2Mane; // size = 0x19C + +typedef struct { + /* 0x00 */ Vec3f eye; + /* 0x0C */ Vec3f at; + /* 0x18 */ Vec3f pad[2]; + /* 0x30 */ Vec3f eyeVel; + /* 0x3C */ Vec3f atVel; + /* 0x48 */ Vec3f nextEye; + /* 0x54 */ Vec3f eyeMaxVel; + /* 0x60 */ Vec3f nextAt; + /* 0x6C */ Vec3f atMaxVel; + /* 0x78 */ f32 speedMod; + /* 0x7C */ f32 accel; + /* 0x80 */ f32 yMod; + /* 0x84 */ f32 shake; +} BossFd2Cam; // size = 0x88 + +typedef enum { + /* 0 */ FD2_TURN_TO_LINK, + /* 1 */ FD2_ACTION_STATE, + /* 2 */ FD2_UNK_TIMER, + /* 3 */ FD2_VAR_TIMER, + /* 4 */ FD2_UNUSED_4, + /* 5 */ FD2_UNUSED_5, + /* 6 */ FD2_BLINK_TIMER, + /* 7 */ FD2_SCREAM_TIMER, + /* 8 */ FD2_DAMAGE_FLASH_TIMER, + /* 9 */ FD2_HOLE_COUNTER, + /* 10 */ FD2_INVINC_TIMER, + /* 11 */ FD2_FAKEOUT_COUNT, + /* 19 */ FD2_SHORT_COUNT = 19 +} BossFd2S16Var; + +typedef enum { + /* 0 */ FD2_TEX1_SCROLL_X, + /* 1 */ FD2_TEX1_SCROLL_Y, + /* 2 */ FD2_TEX2_SCROLL_X, + /* 3 */ FD2_TEX2_SCROLL_Y, + /* 10 */ FD2_END_FRAME = 10, + /* 18 */ FD2_FLOAT_COUNT = 18 +} BossFd2F32Var; + typedef struct BossFd2 { /* 0x0000 */ Actor actor; - /* 0x014C */ char unk_14C[0x1530]; + /* 0x014C */ SkelAnime skelAnime; + /* 0x0190 */ BossFd2ActionFunc actionFunc; + /* 0x0194 */ u8 disableAT; + /* 0x0196 */ s16 work[FD2_SHORT_COUNT]; + /* 0x01BC */ s16 timers[5]; + /* 0x01C8 */ f32 fwork[FD2_FLOAT_COUNT]; + /* 0x0210 */ Vec3f headPos; + /* 0x021C */ Vec3s headRot; + /* 0x0222 */ char unk_222; + /* 0x0223 */ u8 eyeState; + /* 0x0224 */ char unk_224[0xC90]; // despite its size, seems to be unused. + /* 0x0EB4 */ BossFd2Mane centerMane; + /* 0x1050 */ BossFd2Mane rightMane; + /* 0x11EC */ BossFd2Mane leftMane; + /* 0x1388 */ char unk_1388[4]; + /* 0x138C */ f32 jawOpening; + /* 0x1390 */ s16 deathState; + /* 0x1392 */ s16 deathCamera; + /* 0x1394 */ BossFd2Cam camData; + /* 0x141C */ ColliderJntSph collider; + /* 0x143C */ ColliderJntSphElement elements[9]; } BossFd2; // size = 0x167C extern const ActorInit Boss_Fd2_InitVars; diff --git a/src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2_colchk.c b/src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2_colchk.c new file mode 100644 index 000000000..f888dc486 --- /dev/null +++ b/src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2_colchk.c @@ -0,0 +1,116 @@ +#include "global.h" + +static ColliderJntSphElementInit sJntSphElementsInit[9] = { + { + { + ELEMTYPE_UNK3, + { 0xFFCFFFFF, 0x00, 0x20 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_NONE, + BUMP_ON | BUMP_HOOKABLE, + OCELEM_ON, + }, + { 35, { { 6000, 0, 0 }, 21 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x20 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 18, { { 4000, 0, 0 }, 13 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x20 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 19, { { 3000, 0, 0 }, 13 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x20 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 20, { { 4000, 0, 0 }, 15 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x20 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 24, { { 4000, 0, 0 }, 13 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x20 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 25, { { 3000, 0, 0 }, 13 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x20 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 26, { { 3500, 1500, 0 }, 15 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x20 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 17, { { 0, 0, 0 }, 26 }, 100 }, + }, + { + { + ELEMTYPE_UNK2, + { 0xFFCFFFFF, 0x00, 0x20 }, + { 0xFFCDFFFE, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 30, { { 0, 0, 0 }, 17 }, 100 }, + }, +}; + +static ColliderJntSphInit sJntSphInit = { + { + COLTYPE_METAL, + AT_ON | AT_TYPE_ENEMY, + AC_ON | AC_TYPE_PLAYER, + OC1_ON | OC1_TYPE_PLAYER, + OC2_TYPE_1, + COLSHAPE_JNTSPH, + }, + 9, + sJntSphElementsInit, +}; diff --git a/src/overlays/actors/ovl_En_Anubice_Fire/z_en_anubice_fire.c b/src/overlays/actors/ovl_En_Anubice_Fire/z_en_anubice_fire.c index 24ce81547..2b86bfd9c 100644 --- a/src/overlays/actors/ovl_En_Anubice_Fire/z_en_anubice_fire.c +++ b/src/overlays/actors/ovl_En_Anubice_Fire/z_en_anubice_fire.c @@ -181,7 +181,9 @@ void EnAnubiceFire_Update(Actor* thisx, GlobalContext* globalCtx) { func_8002D7EC(&this->actor); this->unk_160[0] = this->actor.world.pos; - for (i = 4; i >= 0; --i) { + if (1) {} + + for (i = 4; i >= 0; i--) { this->unk_160[i + 1] = this->unk_160[i]; } diff --git a/src/overlays/actors/ovl_En_Vb_Ball/z_en_vb_ball.c b/src/overlays/actors/ovl_En_Vb_Ball/z_en_vb_ball.c index d39556df8..2abc8d858 100644 --- a/src/overlays/actors/ovl_En_Vb_Ball/z_en_vb_ball.c +++ b/src/overlays/actors/ovl_En_Vb_Ball/z_en_vb_ball.c @@ -1,10 +1,13 @@ /* * File: z_en_vb_ball.c * Overlay: ovl_En_Vb_Ball - * Description: Volvagia's Rocks + * Description: Volvagia's rocks and bones */ #include "z_en_vb_ball.h" +#include "objects/object_fd/object_fd.h" +#include "objects/gameplay_keep/gameplay_keep.h" +#include "overlays/actors/ovl_Boss_Fd/z_boss_fd.h" #define FLAGS 0x00000030 @@ -15,7 +18,6 @@ void EnVbBall_Destroy(Actor* thisx, GlobalContext* globalCtx); void EnVbBall_Update(Actor* thisx, GlobalContext* globalCtx); void EnVbBall_Draw(Actor* thisx, GlobalContext* globalCtx); -/* const ActorInit En_Vb_Ball_InitVars = { 0, ACTORCAT_BOSS, @@ -28,7 +30,7 @@ const ActorInit En_Vb_Ball_InitVars = { (ActorFunc)EnVbBall_Draw, }; -static ColliderCylinderInit D_80B2A000 = { +static ColliderCylinderInit sCylinderInit = { { COLTYPE_NONE, AT_ON | AT_TYPE_ENEMY, @@ -47,17 +49,279 @@ static ColliderCylinderInit D_80B2A000 = { }, { 20, 30, 10, { 0, 0, 0 } }, }; -*/ -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Vb_Ball/EnVbBall_Init.s") -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Vb_Ball/EnVbBall_Destroy.s") +void EnVbBall_Init(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + EnVbBall* this = THIS; + s32 pad2; + f32 angle; + + if (this->actor.params >= 200) { // Volvagia's bones + this->yRotVel = Rand_CenteredFloat(0x300); + this->xRotVel = Rand_CenteredFloat(0x300); + angle = Math_FAtan2F(this->actor.world.pos.x, this->actor.world.pos.z); + this->actor.velocity.y = Rand_ZeroFloat(3.0f); + this->actor.velocity.x = 2.0f * sinf(angle); + this->actor.velocity.z = 2.0f * cosf(angle); + this->actor.gravity = -0.8f; + } else { // Volvagia's rocks + Collider_InitCylinder(globalCtx, &this->collider); + Collider_SetCylinder(globalCtx, &this->collider, &this->actor, &sCylinderInit); + Actor_SetScale(&this->actor, this->actor.world.rot.z / 10000.0f); + this->collider.dim.radius = this->actor.scale.y * 3000.0f; + this->collider.dim.height = this->actor.scale.y * 5000.0f; + this->collider.dim.yShift = this->actor.scale.y * -2500.0f; + this->xRotVel = Rand_CenteredFloat(0x2000); + this->yRotVel = Rand_CenteredFloat(0x2000); + this->shadowSize = this->actor.scale.y * 68.0f; + } +} + +void EnVbBall_Destroy(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + EnVbBall* this = THIS; + + if (this->actor.params < 200) { + Collider_DestroyCylinder(globalCtx, &this->collider); + } +} + +void EnVbBall_SpawnDebris(GlobalContext* globalCtx, BossFdEffect* effect, Vec3f* position, Vec3f* velocity, + Vec3f* acceleration, f32 scale) { + s16 i; + + for (i = 0; i < 180; i++, effect++) { + if (effect->type == BFD_FX_NONE) { + effect->type = BFD_FX_DEBRIS; + effect->pos = *position; + effect->velocity = *velocity; + effect->accel = *acceleration; + effect->scale = scale / 1000.0f; + effect->vFdFxRotX = Rand_ZeroFloat(100.0f); + effect->vFdFxRotY = Rand_ZeroFloat(100.0f); + break; + } + } +} + +void EnVbBall_SpawnDust(GlobalContext* globalCtx, BossFdEffect* effect, Vec3f* position, Vec3f* velocity, + Vec3f* acceleration, f32 scale) { + s16 i; + + for (i = 0; i < 180; i++, effect++) { + if (effect->type == BFD_FX_NONE) { + effect->type = BFD_FX_DUST; + effect->pos = *position; + effect->velocity = *velocity; + effect->accel = *acceleration; + effect->timer2 = 0; + effect->scale = scale / 400.0f; + break; + } + } +} + +void EnVbBall_UpdateBones(EnVbBall* this, GlobalContext* globalCtx) { + BossFd* bossFd = (BossFd*)this->actor.parent; + f32 pad2; + f32 pad1; + f32 angle; + s16 i; + + Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 50.0f, 50.0f, 100.0f, 4); + if ((this->actor.bgCheckFlags & 1) && (this->actor.velocity.y <= 0.0f)) { + this->xRotVel = Rand_CenteredFloat((f32)0x4000); + this->yRotVel = Rand_CenteredFloat((f32)0x4000); + angle = Math_FAtan2F(this->actor.world.pos.x, this->actor.world.pos.z); + this->actor.velocity.x = sinf(angle) * 10.0f; + this->actor.velocity.z = cosf(angle) * 10.0f; + this->actor.velocity.y *= -0.5f; + if (this->actor.params & 1) { + Audio_PlaySoundGeneral(NA_SE_EN_VALVAISA_LAND, &this->actor.projectedPos, 4, &D_801333E0, &D_801333E0, + &D_801333E8); + } + for (i = 0; i < 10; i++) { + Vec3f dustVel = { 0.0f, 0.0f, 0.0f }; + Vec3f dustAcc = { 0.0f, 0.0f, 0.0f }; + Vec3f dustPos; + + dustVel.x = Rand_CenteredFloat(8.0f); + dustVel.y = Rand_ZeroFloat(1.0f); + dustVel.z = Rand_CenteredFloat(8.0f); + + dustAcc.y = 0.3f; + + dustPos.x = Rand_CenteredFloat(20.0f) + this->actor.world.pos.x; + dustPos.y = this->actor.floorHeight + 10.0f; + dustPos.z = Rand_CenteredFloat(20.0f) + this->actor.world.pos.z; + + EnVbBall_SpawnDust(globalCtx, bossFd->effects, &dustPos, &dustVel, &dustAcc, + Rand_ZeroFloat(80.0f) + 200.0f); + } + } + if (this->actor.world.pos.y < 50.0f) { + Actor_Kill(&this->actor); + } +} + +void EnVbBall_Update(Actor* thisx, GlobalContext* globalCtx) { + GlobalContext* globalCtx2 = globalCtx; + EnVbBall* this = THIS; + BossFd* bossFd = (BossFd*)this->actor.parent; + f32 radius; + f32 pad2; + s16 spawnNum; + s16 i; + + this->unkTimer2++; + if (this->unkTimer1 != 0) { + this->unkTimer1--; + } + this->actor.shape.rot.x += (s16)this->xRotVel; + this->actor.shape.rot.y += (s16)this->yRotVel; + this->actor.velocity.y += -1.0f; + this->actor.gravity = -1.0f; + func_8002D7EC(&this->actor); + if (this->actor.params >= 200) { + EnVbBall_UpdateBones(this, globalCtx2); + } else { + Math_ApproachF(&this->shadowOpacity, 175.0f, 1.0f, 40.0f); + radius = this->actor.scale.y * 1700.0f; + this->actor.world.pos.y -= radius; + Actor_UpdateBgCheckInfo(globalCtx2, &this->actor, 50.0f, 50.0f, 100.0f, 4); + this->actor.world.pos.y += radius; + if ((this->actor.bgCheckFlags & 1) && (this->actor.velocity.y <= 0.0f)) { + if ((this->actor.params == 100) || (this->actor.params == 101)) { + Actor_Kill(&this->actor); + if (this->actor.params == 100) { + func_80033E88(&this->actor, globalCtx2, 5, 0xA); + } + if (this->actor.params == 100) { + spawnNum = 2; + } else { + spawnNum = 2; + } + for (i = 0; i < spawnNum; i++) { + Vec3f spawnOffset; + EnVbBall* newActor; + f32 xRotVel; + + if (this->actor.params == 100) { + spawnOffset.x = Rand_CenteredFloat(13.0f); + spawnOffset.y = Rand_ZeroFloat(5.0f) + 6.0f; + spawnOffset.z = Rand_CenteredFloat(13); + } else { + spawnOffset.x = Rand_CenteredFloat(10.0f); + spawnOffset.y = Rand_ZeroFloat(3.0f) + 4.0f; + spawnOffset.z = Rand_CenteredFloat(10.0f); + } + newActor = (EnVbBall*)Actor_SpawnAsChild(&globalCtx2->actorCtx, &this->actor, globalCtx2, + ACTOR_EN_VB_BALL, this->actor.world.pos.x + spawnOffset.x, + this->actor.world.pos.y + spawnOffset.y, + this->actor.world.pos.z + spawnOffset.z, 0, 0, + this->actor.world.rot.z * 0.5f, this->actor.params + 1); + if (newActor != NULL) { + if ((i == 0) && (this->actor.params == 100)) { + Audio_PlaySoundGeneral(NA_SE_EN_VALVAISA_ROCK, &newActor->actor.projectedPos, 4, + &D_801333E0, &D_801333E0, &D_801333E8); + } + newActor->actor.parent = this->actor.parent; + newActor->actor.velocity = spawnOffset; + newActor->yRotVel = 0.0f; + xRotVel = sqrtf(SQ(spawnOffset.x) + SQ(spawnOffset.z)); + newActor->xRotVel = 0x1000 / 10.0f * xRotVel; + newActor->actor.shape.rot.y = Math_FAtan2F(spawnOffset.x, spawnOffset.z) * ((f32)0x8000 / M_PI); + newActor->shadowOpacity = 200.0f; + } + } + for (i = 0; i < 15; i++) { + Vec3f debrisVel1 = { 0.0f, 0.0f, 0.0f }; + Vec3f debrisAcc1 = { 0.0f, -1.0f, 0.0f }; + Vec3f debrisPos1; + + debrisVel1.x = Rand_CenteredFloat(25.0f); + debrisVel1.y = Rand_ZeroFloat(5.0f) + 8; + debrisVel1.z = Rand_CenteredFloat(25.0f); + + debrisPos1.x = Rand_CenteredFloat(10.0f) + this->actor.world.pos.x; + debrisPos1.y = Rand_CenteredFloat(10.0f) + this->actor.world.pos.y; + debrisPos1.z = Rand_CenteredFloat(10.0f) + this->actor.world.pos.z; + + EnVbBall_SpawnDebris(globalCtx2, bossFd->effects, &debrisPos1, &debrisVel1, &debrisAcc1, + (s16)Rand_ZeroFloat(12.0f) + 15); + } + for (i = 0; i < 10; i++) { + Vec3f dustVel = { 0.0f, 0.0f, 0.0f }; + Vec3f dustAcc = { 0.0f, 0.0f, 0.0f }; + Vec3f dustPos; + + dustVel.x = Rand_CenteredFloat(8.0f); + dustVel.y = Rand_ZeroFloat(1.0f); + dustVel.z = Rand_CenteredFloat(8.0f); + + dustAcc.y = 1.0f / 2; + + dustPos.x = Rand_CenteredFloat(30.0f) + this->actor.world.pos.x; + dustPos.y = Rand_CenteredFloat(30.0f) + this->actor.world.pos.y; + dustPos.z = Rand_CenteredFloat(30.0f) + this->actor.world.pos.z; + + EnVbBall_SpawnDust(globalCtx2, bossFd->effects, &dustPos, &dustVel, &dustAcc, + Rand_ZeroFloat(100.0f) + 350.0f); + } + } else { + for (i = 0; i < 5; i++) { + Vec3f debrisVel2 = { 0.0f, 0.0f, 0.0f }; + Vec3f debrisAcc2 = { 0.0f, -1.0f, 0.0f }; + Vec3f debrisPos2; + + debrisVel2.x = Rand_CenteredFloat(10.0f); + debrisVel2.y = Rand_ZeroFloat(3.0f) + 3.0f; + debrisVel2.z = Rand_CenteredFloat(10.0f); + + debrisPos2.x = Rand_CenteredFloat(5.0f) + this->actor.world.pos.x; + debrisPos2.y = Rand_CenteredFloat(5.0f) + this->actor.world.pos.y; + debrisPos2.z = Rand_CenteredFloat(5.0f) + this->actor.world.pos.z; + + EnVbBall_SpawnDebris(globalCtx2, bossFd->effects, &debrisPos2, &debrisVel2, &debrisAcc2, + (s16)Rand_ZeroFloat(12.0f) + 15); + } + Actor_Kill(&this->actor); + } + } + if (this->collider.base.atFlags & AT_HIT) { + Player* player = PLAYER; + + this->collider.base.atFlags &= ~AT_HIT; + Audio_PlayActorSound2(&player->actor, NA_SE_PL_BODY_HIT); + } + Collider_UpdateCylinder(&this->actor, &this->collider); + CollisionCheck_SetAT(globalCtx2, &globalCtx2->colChkCtx, &this->collider.base); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Vb_Ball/func_80B29158.s") +void EnVbBall_Draw(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + EnVbBall* this = THIS; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Vb_Ball/func_80B29230.s") + OPEN_DISPS(globalCtx->state.gfxCtx, "../z_en_vb_ball.c", 604); + if (1) {} // needed for match + func_80093D18(globalCtx->state.gfxCtx); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_en_vb_ball.c", 607), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Vb_Ball/func_80B292D0.s") + if (this->actor.params >= 200) { + gSPDisplayList(POLY_OPA_DISP++, SEGMENTED_TO_VIRTUAL(gVolvagiaRibsDL)); + } else { + gSPDisplayList(POLY_OPA_DISP++, SEGMENTED_TO_VIRTUAL(gVolvagiaRockDL)); + func_80094044(globalCtx->state.gfxCtx); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Vb_Ball/EnVbBall_Update.s") + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 0, 0, 0, (s8)this->shadowOpacity); + Matrix_Translate(this->actor.world.pos.x, 100.0f, this->actor.world.pos.z, MTXMODE_NEW); + Matrix_Scale(this->shadowSize, 1.0f, this->shadowSize, MTXMODE_APPLY); + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_en_vb_ball.c", 626), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(gCircleShadowDL)); + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Vb_Ball/EnVbBall_Draw.s") + CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_en_vb_ball.c", 632); +} diff --git a/src/overlays/actors/ovl_En_Vb_Ball/z_en_vb_ball.h b/src/overlays/actors/ovl_En_Vb_Ball/z_en_vb_ball.h index 11a60c04e..3ccca500f 100644 --- a/src/overlays/actors/ovl_En_Vb_Ball/z_en_vb_ball.h +++ b/src/overlays/actors/ovl_En_Vb_Ball/z_en_vb_ball.h @@ -8,7 +8,15 @@ struct EnVbBall; typedef struct EnVbBall { /* 0x0000 */ Actor actor; - /* 0x014C */ char unk_14C[0x68]; + /* 0x014C */ char unk_14C[4]; + /* 0x0150 */ s16 unkTimer1; // These count up and down, but nothing uses them. + /* 0x0152 */ s16 unkTimer2; + /* 0x0154 */ char unk_154[4]; + /* 0x0158 */ f32 xRotVel; + /* 0x015C */ f32 yRotVel; + /* 0x0160 */ f32 shadowSize; + /* 0x0164 */ f32 shadowOpacity; + /* 0x0168 */ ColliderCylinder collider; } EnVbBall; // size = 0x01B4 extern const ActorInit En_Vb_Ball_InitVars; |
