summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorpetrie911 <69443847+petrie911@users.noreply.github.com>2021-04-17 12:12:46 -0500
committerGitHub <noreply@github.com>2021-04-17 19:12:46 +0200
commit7b2b88d552fad0f6603effd3c59a69b7a455e5de (patch)
treeec8677590e03704f04f5b690c1126bee15305be0 /src
parent7306d13897d682c7fd29bd17af9e102933afc599 (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.c2
-rw-r--r--src/code/z_skin_awb.c3
-rw-r--r--src/overlays/actors/ovl_Bg_Vb_Sima/z_bg_vb_sima.c142
-rw-r--r--src/overlays/actors/ovl_Bg_Vb_Sima/z_bg_vb_sima.h12
-rw-r--r--src/overlays/actors/ovl_Boss_Fd/z_boss_fd.c2183
-rw-r--r--src/overlays/actors/ovl_Boss_Fd/z_boss_fd.h173
-rw-r--r--src/overlays/actors/ovl_Boss_Fd/z_boss_fd_colchk.c226
-rw-r--r--src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2.c1306
-rw-r--r--src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2.h80
-rw-r--r--src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2_colchk.c116
-rw-r--r--src/overlays/actors/ovl_En_Anubice_Fire/z_en_anubice_fire.c4
-rw-r--r--src/overlays/actors/ovl_En_Vb_Ball/z_en_vb_ball.c286
-rw-r--r--src/overlays/actors/ovl_En_Vb_Ball/z_en_vb_ball.h10
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(&centerManeMod, &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;