Shipwright/soh/src/overlays/actors/ovl_Boss_Va/z_boss_va.c

4062 lines
159 KiB
C

/*
* File: z_boss_va.c
* Overlay: ovl_Boss_Va
* Description: Barinade
*/
#include "z_boss_va.h"
#include <string.h>
#include "objects/object_bv/object_bv.h"
#include "overlays/actors/ovl_En_Boom/z_en_boom.h"
#include "objects/gameplay_keep/gameplay_keep.h"
#include "soh/frame_interpolation.h"
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_2 | ACTOR_FLAG_4 | ACTOR_FLAG_5)
#define GET_BODY(this) ((BossVa*)(this)->actor.parent)
#define vaGorePulse offset.x
#define vaGorePulseRate offset.y
#define vaBariUnused headRot
#define vaCamRotMod headRot.x
#define vaBodySpinRate headRot.y
#define PHASE_2 3
#define PHASE_3 9
#define PHASE_4 15
#define PHASE_DEATH 18
typedef struct BossVaEffect {
/* 0x00 */ Vec3f pos;
/* 0x0C */ Vec3f velocity;
/* 0x18 */ Vec3f accel;
/* 0x24 */ u8 type;
/* 0x26 */ u16 timer;
/* 0x28 */ s16 mode;
/* 0x2A */ Vec3s rot;
/* 0x30 */ s16 primColor[4];
/* 0x38 */ s16 envColor[4];
/* 0x40 */ f32 scale;
/* 0x44 */ f32 scaleMod;
/* 0x48 */ Vec3f offset;
/* 0x54 */ struct BossVa* parent;
u32 epoch;
} BossVaEffect; // size = 0x58
typedef enum {
/* 0 */ VA_NONE,
/* 1 */ VA_LARGE_SPARK,
/* 2 */ VA_BLAST_SPARK,
/* 3 */ VA_SMALL_SPARK,
/* 4 */ VA_SPARK_BALL,
/* 5 */ VA_ZAP_CHARGE,
/* 6 */ VA_BLOOD,
/* 7 */ VA_TUMOR,
/* 8 */ VA_GORE
} BossVaEffectType;
typedef enum {
/* 1 */ SPARK_TETHER = 1,
/* 2 */ SPARK_BARI,
/* 3 */ SPARK_BLAST,
/* 4 */ SPARK_UNUSED,
/* 5 */ SPARK_BODY,
/* 6 */ SPARK_LINK
} BossVaSparkMode;
typedef enum {
/* 0 */ BLOOD_DROPLET,
/* 1 */ BLOOD_SPLATTER,
/* 2 */ BLOOD_SPOT
} BossVaBloodMode;
typedef enum {
/* 0 */ TUMOR_UNUSED,
/* 1 */ TUMOR_BODY,
/* 2 */ TUMOR_ARM
} BossVaTumorMode;
typedef enum {
/* 0 */ GORE_PERMANENT,
/* 1 */ GORE_FLOOR,
/* 2 */ GORE_FADING
} BossVaGoreMode;
typedef enum {
/* -5 */ INTRO_UNUSED_START = -5,
/* -4 */ INTRO_START,
/* -3 */ INTRO_LOOK_DOOR,
/* -2 */ INTRO_CLOSE_DOOR,
/* -1 */ INTRO_DOOR_SHUT,
/* 0 */ INTRO_CRACKLE,
/* 1 */ INTRO_SPAWN_BARI,
/* 2 */ INTRO_LOOK_BARI,
/* 3 */ INTRO_REVERSE_CAMERA,
/* 4 */ INTRO_SUPPORT_CAMERA,
/* 5 */ INTRO_BODY_SOUND,
/* 6 */ INTRO_LOOK_SUPPORT,
/* 7 */ INTRO_UNUSED_CALL_BARI,
/* 8 */ INTRO_CALL_BARI,
/* 9 */ INTRO_ATTACH_BARI,
/* 10 */ INTRO_TITLE,
/* 11 */ INTRO_BRIGHTEN,
/* 12 */ INTRO_FINISH,
/* 13 */ BOSSVA_BATTLE,
/* 14 */ DEATH_START,
/* 15 */ DEATH_BODY_TUMORS,
/* 16 */ DEATH_ZAPPER_1,
/* 17 */ DEATH_ZAPPER_2,
/* 18 */ DEATH_ZAPPER_3,
/* 19 */ DEATH_SHELL_BURST,
/* 20 */ DEATH_CORE_TUMORS,
/* 21 */ DEATH_CORE_DEAD,
/* 22 */ DEATH_CORE_BURST,
/* 23 */ DEATH_MUSIC,
/* 24 */ DEATH_FINISH
} BossVaCutscene;
void BossVa_Init(Actor* thisx, GlobalContext* globalCtx);
void BossVa_Destroy(Actor* thisx, GlobalContext* globalCtx);
void BossVa_Update(Actor* thisx, GlobalContext* globalCtx);
void BossVa_Draw(Actor* thisx, GlobalContext* globalCtx);
void BossVa_Reset(void);
void BossVa_UpdateEffects(GlobalContext* globalCtx);
void BossVa_DrawEffects(BossVaEffect* effect, GlobalContext* globalCtx);
void BossVa_DrawDoor(GlobalContext* globalCtx, s16 scale);
void BossVa_SetupIntro(BossVa* this);
void BossVa_SetupBodyPhase1(BossVa* this);
void BossVa_SetupBodyPhase2(BossVa* this, GlobalContext* globalCtx);
void BossVa_SetupBodyPhase3(BossVa* this);
void BossVa_SetupBodyPhase4(BossVa* this, GlobalContext* globalCtx);
void BossVa_SetupBodyDeath(BossVa* this, GlobalContext* globalCtx);
void BossVa_SetupSupportIntro(BossVa* this, GlobalContext* globalCtx);
void BossVa_SetupSupportAttached(BossVa* this, GlobalContext* globalCtx);
void BossVa_SetupSupportCut(BossVa* this, GlobalContext* globalCtx);
void BossVa_SetupZapperIntro(BossVa* this, GlobalContext* globalCtx);
void BossVa_SetupZapperAttack(BossVa* this, GlobalContext* globalCtx);
void BossVa_SetupZapperEnraged(BossVa* this, GlobalContext* globalCtx);
void BossVa_SetupZapperDamaged(BossVa* this, GlobalContext* globalCtx);
void BossVa_SetupZapperHold(BossVa* this, GlobalContext* globalCtx);
void BossVa_SetupStump(BossVa* this, GlobalContext* globalCtx);
void BossVa_SetupDoor(BossVa* this, GlobalContext* globalCtx);
void BossVa_SetupBariIntro(BossVa* this, GlobalContext* globalCtx);
void BossVa_SetupBariPhase2Attack(BossVa* this, GlobalContext* globalCtx);
void BossVa_SetupBariPhase3Attack(BossVa* this, GlobalContext* globalCtx);
void BossVa_SetupBariPhase3Stunned(BossVa* this, GlobalContext* globalCtx);
void BossVa_SetupBariDeath(BossVa* this);
void BossVa_BodyIntro(BossVa* this, GlobalContext* globalCtx);
void BossVa_BodyPhase1(BossVa* this, GlobalContext* globalCtx);
void BossVa_BodyPhase2(BossVa* this, GlobalContext* globalCtx);
void BossVa_BodyPhase3(BossVa* this, GlobalContext* globalCtx);
void BossVa_BodyPhase4(BossVa* this, GlobalContext* globalCtx);
void BossVa_BodyDeath(BossVa* this, GlobalContext* globalCtx);
void BossVa_SupportIntro(BossVa* this, GlobalContext* globalCtx);
void BossVa_SupportAttached(BossVa* this, GlobalContext* globalCtx);
void BossVa_SupportCut(BossVa* this, GlobalContext* globalCtx);
void BossVa_ZapperIntro(BossVa* this, GlobalContext* globalCtx);
void BossVa_ZapperAttack(BossVa* this, GlobalContext* globalCtx);
void BossVa_ZapperEnraged(BossVa* this, GlobalContext* globalCtx);
void BossVa_ZapperDamaged(BossVa* this, GlobalContext* globalCtx);
void BossVa_ZapperHold(BossVa* this, GlobalContext* globalCtx);
void BossVa_ZapperDeath(BossVa* this, GlobalContext* globalCtx);
void BossVa_Stump(BossVa* this, GlobalContext* globalCtx);
void BossVa_Door(BossVa* this, GlobalContext* globalCtx);
void BossVa_BariIntro(BossVa* this, GlobalContext* globalCtx);
void BossVa_BariPhase3Attack(BossVa* this, GlobalContext* globalCtx);
void BossVa_BariPhase2Attack(BossVa* this, GlobalContext* globalCtx);
void BossVa_BariPhase3Stunned(BossVa* this, GlobalContext* globalCtx);
void BossVa_BariDeath(BossVa* this, GlobalContext* globalCtx);
void BossVa_SpawnBloodSplatter(GlobalContext* globalCtx, BossVaEffect* effect, Vec3f* pos, s16 yaw, s16 scale);
void BossVa_SpawnGore(GlobalContext* globalCtx, BossVaEffect* effect, Vec3f* pos, s16 yaw, s16 scale);
void BossVa_SpawnSpark(GlobalContext* globalCtx, BossVaEffect* effect, BossVa* this, Vec3f* offset, s16 scale, u8 mode);
void BossVa_SpawnZapperCharge(GlobalContext* globalCtx, BossVaEffect* effect, BossVa* this, Vec3f* pos, Vec3s* rot,
s16 scale, u8 mode);
void BossVa_SpawnTumor(GlobalContext* globalCtx, BossVaEffect* effect, BossVa* this, Vec3f* offset, s16 scale, u8 mode);
void BossVa_SpawnSparkBall(GlobalContext* globalCtx, BossVaEffect* effect, BossVa* this, Vec3f* offset, s16 scale,
u8 mode);
void BossVa_SpawnBloodDroplets(GlobalContext* globalCtx, BossVaEffect* effect, Vec3f* pos, s16 scale, s16 phase,
s16 yaw);
void BossVa_Tumor(GlobalContext* globalCtx, BossVa* this, s32 count, s16 scale, f32 xzSpread, f32 ySpread, u8 mode,
f32 range, u8 fixed);
const ActorInit Boss_Va_InitVars = {
ACTOR_BOSS_VA,
ACTORCAT_BOSS,
FLAGS,
OBJECT_BV,
sizeof(BossVa),
(ActorFunc)BossVa_Init,
(ActorFunc)BossVa_Destroy,
(ActorFunc)BossVa_Update,
(ActorFunc)BossVa_Draw,
(ActorResetFunc)BossVa_Reset,
};
static ColliderCylinderInit sCylinderInit = {
{
COLTYPE_NONE,
AT_ON | AT_TYPE_ENEMY,
AC_ON | AC_TYPE_PLAYER,
OC1_ON | OC1_TYPE_ALL,
OC2_TYPE_2,
COLSHAPE_CYLINDER,
},
{
ELEMTYPE_UNK0,
{ 0xFFCFFFEF, 0x03, 0x08 },
{ 0x00000010, 0x00, 0x00 },
TOUCH_ON | TOUCH_SFX_NORMAL,
BUMP_ON,
OCELEM_ON,
},
{ 85, 120, 0, { 0, 0, 0 } },
};
static ColliderJntSphElementInit sJntSphElementsInitSupport[1] = {
{
{
ELEMTYPE_UNK0,
{ 0x00000000, 0x00, 0x00 },
{ 0x00000010, 0x00, 0x00 },
TOUCH_NONE,
BUMP_ON,
OCELEM_NONE,
},
{ 0, { { 0, 0, 0 }, 25 }, 100 },
},
};
static ColliderJntSphInit sJntSphInitSupport = {
{
COLTYPE_HIT6,
AT_NONE,
AC_ON | AC_TYPE_PLAYER,
OC1_NONE,
OC2_TYPE_1,
COLSHAPE_JNTSPH,
},
ARRAY_COUNT(sJntSphElementsInitSupport),
sJntSphElementsInitSupport,
};
static ColliderJntSphElementInit sJntSphElementsInitBari[1] = {
{
{
ELEMTYPE_UNK0,
{ 0xFFCFFFFF, 0x03, 0x04 },
{ 0xFFCFFFFF, 0x00, 0x00 },
TOUCH_ON | TOUCH_SFX_NORMAL,
BUMP_ON,
OCELEM_NONE,
},
{ 0, { { 0, 0, 0 }, 30 }, 100 },
},
};
static ColliderJntSphInit sJntSphInitBari = {
{
COLTYPE_NONE,
AT_ON | AT_TYPE_ENEMY,
AC_ON | AC_TYPE_PLAYER,
OC1_NONE,
OC2_TYPE_1,
COLSHAPE_JNTSPH,
},
ARRAY_COUNT(sJntSphElementsInitBari),
sJntSphElementsInitBari,
};
static ColliderQuadInit sQuadInit = {
{
COLTYPE_METAL,
AT_ON | AT_TYPE_ENEMY,
AC_ON | AC_TYPE_PLAYER,
OC1_NONE,
OC2_NONE,
COLSHAPE_QUAD,
},
{
ELEMTYPE_UNK0,
{ 0x20000000, 0x03, 0x04 },
{ 0x00000010, 0x00, 0x00 },
TOUCH_ON | TOUCH_SFX_NORMAL | TOUCH_UNK7,
BUMP_ON,
OCELEM_NONE,
},
{ { { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } } },
};
static Vec3f sInitPosOffsets[] = {
{ 0.0f, 175.35f, 0.0f }, // Support 1
{ 0.0f, 175.35f, 0.0f }, // Support 2
{ 0.0f, 175.35f, 0.0f }, // Support 3
{ 120.0f, 103.425f, -67.0f }, // Zapper 1
{ 0.0f, 103.425f, 140.0f }, // Zapper 2
{ -120.0f, 103.425f, -70.0f }, // Zapper 3
{ -2.0f, 16.0f, 50.0f }, // Upper Bari 1
{ 48.0f, 16.0f, 15.0f }, // Upper Bari 2
{ 25.0f, 16.0f, -36.0f }, // Upper Bari 3
{ -29.0f, 16.0f, -36.0f }, // Upper Bari 4
{ -63.0f, 16.0f, 22.0f }, // Upper Bari 5
{ 0.0f, -10.0f, -64.0f }, // Lower Bari 1
{ 63.0f, -10.0f, -22.0f }, // Lower Bari 2
{ 35.0f, -10.0f, 46.0f }, // Lower Bari 3
{ -36.0f, -10.0f, 46.0f }, // Lower Bari 4
{ -49.0f, -10.0f, -17.0f }, // Lower Bari 5
{ 0.0f, 160.0f, 370.0f }, // Upper Bari 1 CS
{ 65.0f, 35.0f, 370.0f }, // Upper Bari 2 CS
{ 80.0f, 70.0f, -130.0f }, // Upper Bari 3 CS
{ -160.0f, 100.0f, -130.0f }, // Upper Bari 4 CS
{ -150.0f, 130.0f, 0.0f }, // Upper Bari 5 CS
{ 230.0f, 0.0f, 0.0f }, // Lower Bari 1 CS
{ 60.0f, 140.0f, 0.0f }, // Lower Bari 2 CS
{ 0.0f, 40.0f, 270.0f }, // Lower Bari 3 CS
{ -100.0f, 10.0f, 200.0f }, // Lower Bari 4 CS
{ -90.0f, 70.0f, -310.0f }, // Lower Bari 5 CS
};
static Vec3s sInitRot[] = {
{ 0x1FFE, 0x0000, 0x0000 }, { 0x1FFE, 0x5550, 0x0000 }, { 0x1FFE, 0xAAB0, 0x0000 }, { 0xD558, 0x5550, 0x0000 },
{ 0xD558, 0x0000, 0x0000 }, { 0xD558, 0xAAB0, 0x0000 }, { 0x2AA8, 0xFCCC, 0x0000 }, { 0x2AA8, 0x3330, 0x0000 },
{ 0x2AA8, 0x6660, 0x0000 }, { 0x2AA8, 0x99A0, 0x0000 }, { 0x2AA8, 0xCCD0, 0x0000 }, { 0x4C98, 0x81D0, 0x0000 },
{ 0x4C98, 0x4F70, 0x0000 }, { 0x4C98, 0x1758, 0x0000 }, { 0x4C98, 0xE8A8, 0x0000 }, { 0x4C98, 0xB648, 0x0000 },
};
static Vec3f sWarpPos[] = {
{ 10.0f, 0.0f, 30.0f },
{ 260.0f, 0.0f, -470.0f },
{ -240.0f, 0.0f, -470.0f },
};
static DamageTable sDamageTable[] = {
/* Deku nut */ DMG_ENTRY(0, 0x1),
/* Deku stick */ DMG_ENTRY(2, 0x0),
/* Slingshot */ DMG_ENTRY(1, 0x0),
/* Explosive */ DMG_ENTRY(2, 0x0),
/* Boomerang */ DMG_ENTRY(0, 0x1),
/* Normal arrow */ DMG_ENTRY(2, 0x0),
/* Hammer swing */ DMG_ENTRY(2, 0x0),
/* Hookshot */ DMG_ENTRY(0, 0x1),
/* Kokiri sword */ DMG_ENTRY(1, 0x0),
/* Master sword */ DMG_ENTRY(2, 0x0),
/* Giant's Knife */ DMG_ENTRY(4, 0x0),
/* Fire arrow */ DMG_ENTRY(2, 0x0),
/* Ice arrow */ DMG_ENTRY(2, 0x0),
/* Light arrow */ DMG_ENTRY(2, 0x0),
/* Unk arrow 1 */ DMG_ENTRY(2, 0x0),
/* Unk arrow 2 */ DMG_ENTRY(2, 0x0),
/* Unk arrow 3 */ DMG_ENTRY(2, 0x0),
/* Fire magic */ DMG_ENTRY(0, 0xE),
/* Ice magic */ DMG_ENTRY(0, 0x6),
/* Light magic */ DMG_ENTRY(0, 0xD),
/* Shield */ DMG_ENTRY(0, 0x0),
/* Mirror Ray */ DMG_ENTRY(0, 0x0),
/* Kokiri spin */ DMG_ENTRY(1, 0x0),
/* Giant spin */ DMG_ENTRY(4, 0x0),
/* Master spin */ DMG_ENTRY(2, 0x0),
/* Kokiri jump */ DMG_ENTRY(2, 0x0),
/* Giant jump */ DMG_ENTRY(8, 0x0),
/* Master jump */ DMG_ENTRY(4, 0x0),
/* Unknown 1 */ DMG_ENTRY(0, 0x0),
/* Unblockable */ DMG_ENTRY(0, 0x0),
/* Hammer jump */ DMG_ENTRY(4, 0x0),
/* Unknown 2 */ DMG_ENTRY(0, 0x0),
};
static Vec3f sZeroVec = { 0.0f, 0.0f, 0.0f };
static u8 sKillBari = 0;
static u8 sBodyBari[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static s16 sCsCamera = 0;
static BossVaEffect sVaEffects[400];
static u8 sBodyState;
static u8 sFightPhase;
static s8 sCsState;
static Vec3f sCameraEye;
static Vec3f sCameraAt;
static Vec3f sCameraNextEye;
static Vec3f sCameraNextAt;
static Vec3f sCameraEyeMaxVel;
static Vec3f sCameraAtMaxVel;
static s16 sDoorState;
static u8 sPhase3StopMoving;
static Vec3s sZapperRot;
static u16 sPhase2Timer;
static s8 sPhase4HP;
void BossVa_SetupAction(BossVa* this, BossVaActionFunc func) {
this->actionFunc = func;
}
void BossVa_AttachToBody(BossVa* this) {
BossVa* vaBody = GET_BODY(this);
Matrix_Translate(vaBody->actor.world.pos.x, vaBody->actor.world.pos.y, vaBody->actor.world.pos.z, MTXMODE_NEW);
Matrix_RotateZYX(vaBody->actor.shape.rot.x, 0, vaBody->actor.shape.rot.z, MTXMODE_APPLY);
Matrix_MultVec3f(&sInitPosOffsets[this->actor.params], &this->actor.world.pos);
switch (this->actor.params) {
case BOSSVA_SUPPORT_1:
case BOSSVA_SUPPORT_2:
case BOSSVA_SUPPORT_3:
if (!this->onCeiling) {
this->actor.shape.rot.x = sInitRot[this->actor.params].x + vaBody->actor.shape.rot.x;
this->actor.shape.rot.y = sInitRot[this->actor.params].y;
this->actor.shape.rot.z = sInitRot[this->actor.params].z + vaBody->actor.shape.rot.z;
}
break;
case BOSSVA_ZAPPER_1:
case BOSSVA_ZAPPER_2:
case BOSSVA_ZAPPER_3:
this->actor.shape.rot.y = sInitRot[this->actor.params].y;
this->actor.shape.rot.x = (sInitRot[this->actor.params].x +
(s16)(Math_CosS(sInitRot[this->actor.params].y) * vaBody->actor.shape.rot.x)) -
(s16)(Math_SinS(sInitRot[this->actor.params].y) * vaBody->actor.shape.rot.z);
this->actor.shape.rot.z = (s16)(Math_CosS(sInitRot[this->actor.params].y) * vaBody->actor.shape.rot.z) +
(sInitRot[this->actor.params].z +
(s16)(Math_SinS(sInitRot[this->actor.params].y) * vaBody->actor.shape.rot.x));
break;
}
this->actor.world.rot = this->actor.shape.rot;
this->actor.shape.yOffset = GET_BODY(this)->actor.shape.yOffset;
}
void BossVa_BloodDroplets(GlobalContext* globalCtx, Vec3f* pos, s16 phase, s16 yaw) {
s32 i;
Vec3f spawnPos;
for (i = 2; i > 0; i--) {
spawnPos.x = Rand_CenteredFloat(10.0f) + pos->x;
spawnPos.y = pos->y - (Rand_ZeroOne() * 15.0f);
spawnPos.z = Rand_CenteredFloat(10.0f) + pos->z;
BossVa_SpawnBloodDroplets(globalCtx, sVaEffects, &spawnPos, 65, phase, yaw);
}
}
void BossVa_BloodSplatter(GlobalContext* globalCtx, BossVaEffect* src, s16 yaw, s16 scale, s32 count) {
s32 i;
Vec3f pos;
for (i = count; i > 0; i--) {
pos.x = Rand_CenteredFloat(10.0f) + src->pos.x;
pos.y = src->pos.y - (Rand_ZeroOne() * 15.0f);
pos.z = Rand_CenteredFloat(10.0f) + src->pos.z;
BossVa_SpawnBloodSplatter(globalCtx, sVaEffects, &pos, (s16)Rand_CenteredFloat(0x6590) + yaw, scale);
}
}
void BossVa_Gore(GlobalContext* globalCtx, BossVaEffect* src, s16 yaw, s16 scale) {
s32 i;
Vec3f pos;
for (i = (sCsState <= DEATH_SHELL_BURST) ? 2 : 1; i > 0; i--) {
pos.x = Rand_CenteredFloat(10.0f) + src->pos.x;
pos.y = Rand_CenteredFloat(10.0f) + src->pos.y;
pos.z = Rand_CenteredFloat(10.0f) + src->pos.z;
BossVa_SpawnGore(globalCtx, sVaEffects, &pos, (s16)Rand_CenteredFloat(0x6590) + yaw, scale);
}
}
void BossVa_Spark(GlobalContext* globalCtx, BossVa* this, s32 count, s16 scale, f32 xzSpread, f32 ySpread, u8 mode,
f32 range, u8 fixed) {
s32 i;
s16 index;
Vec3f offset;
for (i = count; i > 0; i--) {
if (!fixed) {
index = Rand_ZeroOne() * (range - 0.6f);
} else {
index = range - 0.6f;
}
offset.x = Rand_CenteredFloat(xzSpread) + this->effectPos[index].x - this->actor.world.pos.x;
offset.y = Rand_CenteredFloat(ySpread) + this->effectPos[index].y - this->actor.world.pos.y;
offset.z = Rand_CenteredFloat(xzSpread) + this->effectPos[index].z - this->actor.world.pos.z;
BossVa_SpawnSpark(globalCtx, sVaEffects, this, &offset, scale, mode);
}
}
void BossVa_Tumor(GlobalContext* globalCtx, BossVa* this, s32 count, s16 scale, f32 xzSpread, f32 ySpread, u8 mode,
f32 range, u8 fixed) {
s16 index;
s32 i;
Vec3f offset;
for (i = count; i > 0; i--) {
if (!fixed) {
index = Rand_ZeroOne() * (range - 0.6f);
} else {
index = range - 0.6f;
}
offset.x = Rand_CenteredFloat(xzSpread) + this->effectPos[index].x - this->actor.world.pos.x;
offset.y = Rand_CenteredFloat(ySpread) + this->effectPos[index].y - this->actor.world.pos.y;
offset.z = Rand_CenteredFloat(xzSpread) + this->effectPos[index].z - this->actor.world.pos.z;
BossVa_SpawnTumor(globalCtx, sVaEffects, this, &offset, scale, mode);
}
}
void BossVa_SetSparkEnv(GlobalContext* globalCtx) {
globalCtx->envCtx.adjAmbientColor[0] = 0xA;
globalCtx->envCtx.adjAmbientColor[1] = 0xA;
globalCtx->envCtx.adjAmbientColor[2] = 0xA;
globalCtx->envCtx.adjLight1Color[0] = 0x73;
globalCtx->envCtx.adjLight1Color[1] = 0x41;
globalCtx->envCtx.adjLight1Color[2] = 0x64;
globalCtx->envCtx.adjFogColor[0] = 0x78;
globalCtx->envCtx.adjFogColor[1] = 0x78;
globalCtx->envCtx.adjFogColor[2] = 0x46;
}
void BossVa_SetDeathEnv(GlobalContext* globalCtx) {
globalCtx->envCtx.adjFogColor[0] = 0xDC;
globalCtx->envCtx.adjFogColor[1] = 0xDC;
globalCtx->envCtx.adjFogColor[2] = 0x96;
globalCtx->envCtx.adjFogNear = -0x3E8;
globalCtx->envCtx.adjFogFar = -0x384;
globalCtx->envCtx.adjAmbientColor[0] = 0xC8;
globalCtx->envCtx.adjAmbientColor[1] = 0xC8;
globalCtx->envCtx.adjAmbientColor[2] = 0xC8;
globalCtx->envCtx.adjLight1Color[0] = 0xD7;
globalCtx->envCtx.adjLight1Color[1] = 0xA5;
globalCtx->envCtx.adjLight1Color[2] = 0xC8;
globalCtx->envCtx.screenFillColor[0] = 0xDC;
globalCtx->envCtx.screenFillColor[1] = 0xDC;
globalCtx->envCtx.screenFillColor[2] = 0x96;
globalCtx->envCtx.screenFillColor[3] = 0x64;
}
EnBoom* BossVa_FindBoomerang(GlobalContext* globalCtx) {
Actor* actorIt = globalCtx->actorCtx.actorLists[ACTORCAT_MISC].head;
while (actorIt != NULL) {
if (actorIt->id != ACTOR_EN_BOOM) {
actorIt = actorIt->next;
continue;
}
return (EnBoom*)actorIt;
}
return NULL;
}
void BossVa_KillBari(BossVa* this, GlobalContext* globalCtx) {
s32 i;
s16 scale;
Vec3f pos;
Vec3f velocity = { 0.0f, 0.0f, 0.0f };
Vec3f accel = { 0.0f, 0.0f, 0.0f };
for (i = 7; i >= 0; i--) {
pos.x = Rand_CenteredFloat(60.0f) + this->actor.world.pos.x;
pos.y =
Rand_CenteredFloat(50.0f) + (this->actor.world.pos.y + (this->actor.shape.yOffset * this->actor.scale.y));
pos.z = Rand_CenteredFloat(60.0f) + this->actor.world.pos.z;
velocity.y = Rand_ZeroOne() + 1.0f;
scale = Rand_S16Offset(80, 100);
if (Rand_ZeroOne() < 0.7f) {
EffectSsDtBubble_SpawnColorProfile(globalCtx, &pos, &velocity, &accel, scale, 25, 2, 1);
} else {
EffectSsDtBubble_SpawnColorProfile(globalCtx, &pos, &velocity, &accel, scale, 25, 0, 1);
}
}
sFightPhase++;
BossVa_SetupBariDeath(this);
}
void BossVa_Init(Actor* thisx, GlobalContext* globalCtx2) {
GlobalContext* globalCtx = globalCtx2;
BossVa* this = (BossVa*)thisx;
s32 i;
s16 warpId;
Actor_SetScale(&this->actor, 0.1f);
this->actor.targetMode = 5;
this->actor.colChkInfo.mass = MASS_IMMOVABLE;
switch (this->actor.params) {
case BOSSVA_BODY:
//sFightPhase = 0;
//sBodyState = 1;
SkelAnime_Init(globalCtx, &this->skelAnime, &gBarinadeBodySkel, &gBarinadeBodyAnim, NULL, NULL, 0);
this->actor.flags |= ACTOR_FLAG_24;
break;
case BOSSVA_SUPPORT_1:
case BOSSVA_SUPPORT_2:
case BOSSVA_SUPPORT_3:
SkelAnime_InitFlex(globalCtx, &this->skelAnime, &gBarinadeSupportSkel, &gBarinadeSupportAttachedAnim, NULL,
NULL, 0);
break;
case BOSSVA_ZAPPER_1:
case BOSSVA_ZAPPER_2:
case BOSSVA_ZAPPER_3:
SkelAnime_InitFlex(globalCtx, &this->skelAnime, &gBarinadeZapperSkel, &gBarinadeZapperIdleAnim, NULL, NULL,
0);
break;
case BOSSVA_STUMP_1:
case BOSSVA_STUMP_2:
case BOSSVA_STUMP_3:
SkelAnime_InitFlex(globalCtx, &this->skelAnime, &gBarinadeStumpSkel, &gBarinadeStumpAnim, NULL, NULL, 0);
break;
default:
this->actor.flags |= ACTOR_FLAG_24;
SkelAnime_Init(globalCtx, &this->skelAnime, &gBarinadeBariSkel, &gBarinadeBariAnim, NULL, NULL, 0);
this->actor.shape.yOffset = 400.0f;
break;
case BOSSVA_DOOR:
break;
}
this->actor.focus.pos = this->actor.world.pos;
this->onCeiling = false;
this->actor.naviEnemyId = 0x14;
switch (this->actor.params) {
case BOSSVA_BODY:
Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_BOSS_VA, 0.0f, 80.0f, 400.0f, 0, 0,
0, BOSSVA_DOOR);
if (Flags_GetClear(globalCtx, globalCtx->roomCtx.curRoom.num)) {
warpId = ACTOR_EN_RU1;
if (gSaveContext.eventChkInf[3] & 0x80) {
warpId = ACTOR_DOOR_WARP1;
}
Actor_Spawn(&globalCtx->actorCtx, globalCtx, warpId, this->actor.world.pos.x, this->actor.world.pos.y,
this->actor.world.pos.z, 0, 0, 0,
0); //! params could be WARP_DUNGEON_CHILD however this can also spawn Ru1
Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_ITEM_B_HEART, this->actor.world.pos.x + 160.0f,
this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, 0, 0);
sDoorState = 100;
Actor_Kill(&this->actor);
} else {
this->actor.colChkInfo.damageTable = sDamageTable;
sPhase2Timer = 0xFFFF;
if (gSaveContext.eventChkInf[7] & 0x40) {
sCsState = INTRO_CALL_BARI;
sDoorState = 100;
func_8002DF54(globalCtx, &this->actor, 1);
globalCtx->envCtx.screenFillColor[0] = 0xDC;
globalCtx->envCtx.screenFillColor[1] = 0xDC;
globalCtx->envCtx.screenFillColor[2] = 0xBE;
globalCtx->envCtx.screenFillColor[3] = 0xD2;
func_80064520(globalCtx, &globalCtx->csCtx);
sCsCamera = Gameplay_CreateSubCamera(globalCtx);
Gameplay_ChangeCameraStatus(globalCtx, MAIN_CAM, CAM_STAT_WAIT);
Gameplay_ChangeCameraStatus(globalCtx, sCsCamera, CAM_STAT_ACTIVE);
sCameraNextEye.x = sCameraEye.x = 140.0f;
sCameraNextEye.y = sCameraEye.y = 205.0f;
sCameraNextEye.z = sCameraEye.z = -20.0f;
sCameraNextAt.x = sCameraAt.x = 10.0f;
sCameraNextAt.y = sCameraAt.y = 50.0f;
sCameraNextAt.z = sCameraAt.z = -220.0f;
Gameplay_CameraSetAtEye(globalCtx, sCsCamera, &sCameraAt, &sCameraEye);
this->timer = 20;
for (i = BOSSVA_BARI_LOWER_5; i >= BOSSVA_BARI_UPPER_1; i--) {
Actor_SpawnAsChild(
&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_BOSS_VA,
sInitPosOffsets[i].x + this->actor.world.pos.x,
sInitPosOffsets[i].y + this->actor.world.pos.y,
sInitPosOffsets[i].z + this->actor.world.pos.z, sInitRot[i].x + this->actor.world.rot.x,
sInitRot[i].y + this->actor.world.rot.y, sInitRot[i].z + this->actor.world.rot.z, i);
}
sCameraAtMaxVel = sCameraEyeMaxVel = sZeroVec;
} else {
sCsState = INTRO_START;
sDoorState = 5;
}
this->zapHeadPos.x = 1.0f;
Collider_InitCylinder(globalCtx, &this->colliderBody);
Collider_SetCylinder(globalCtx, &this->colliderBody, &this->actor, &sCylinderInit);
for (i = BOSSVA_ZAPPER_3; i >= BOSSVA_SUPPORT_1; i--) {
Actor_SpawnAsChild(
&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_BOSS_VA,
sInitPosOffsets[i].x + this->actor.world.pos.x, sInitPosOffsets[i].y + this->actor.world.pos.y,
sInitPosOffsets[i].z + this->actor.world.pos.z, sInitRot[i].x + this->actor.world.rot.x,
sInitRot[i].y + this->actor.world.rot.y, sInitRot[i].z + this->actor.world.rot.z, i);
}
memset((u8*)sVaEffects, 0, ARRAY_COUNT(sVaEffects) * sizeof(BossVaEffect));
if (sCsState < BOSSVA_BATTLE) {
BossVa_SetupIntro(this);
} else {
BossVa_SetupBodyPhase1(this);
}
}
break;
case BOSSVA_SUPPORT_1:
case BOSSVA_SUPPORT_2:
case BOSSVA_SUPPORT_3:
Collider_InitJntSph(globalCtx, &this->colliderSph);
Collider_SetJntSph(globalCtx, &this->colliderSph, &this->actor, &sJntSphInitSupport, this->elements);
if (sCsState < BOSSVA_BATTLE) {
BossVa_SetupSupportIntro(this, globalCtx);
} else {
BossVa_SetupSupportAttached(this, globalCtx);
}
this->onCeiling++;
break;
case BOSSVA_ZAPPER_1:
case BOSSVA_ZAPPER_2:
case BOSSVA_ZAPPER_3:
Collider_InitQuad(globalCtx, &this->colliderLightning);
Collider_SetQuad(globalCtx, &this->colliderLightning, &this->actor, &sQuadInit);
if (sCsState < BOSSVA_BATTLE) {
BossVa_SetupZapperIntro(this, globalCtx);
} else {
BossVa_SetupZapperAttack(this, globalCtx);
}
break;
case BOSSVA_STUMP_1:
case BOSSVA_STUMP_2:
case BOSSVA_STUMP_3:
BossVa_SetupStump(this, globalCtx);
break;
case BOSSVA_DOOR:
BossVa_SetupDoor(this, globalCtx);
break;
default:
Collider_InitJntSph(globalCtx, &this->colliderSph);
Collider_SetJntSph(globalCtx, &this->colliderSph, &this->actor, &sJntSphInitBari, this->elements);
Collider_InitQuad(globalCtx, &this->colliderLightning);
Collider_SetQuad(globalCtx, &this->colliderLightning, &this->actor, &sQuadInit);
this->unk_1D8.x = 1.0f;
this->unk_1D8.y = 1.0f;
if (sCsState < BOSSVA_BATTLE) {
BossVa_SetupBariIntro(this, globalCtx);
} else if (sFightPhase >= PHASE_3) {
BossVa_SetupBariPhase3Attack(this, globalCtx);
} else {
BossVa_SetupBariPhase2Attack(this, globalCtx);
}
break;
}
}
void BossVa_Destroy(Actor* thisx, GlobalContext* globalCtx) {
BossVa* this = (BossVa*)thisx;
SkelAnime_Free(&this->skelAnime, globalCtx);
Collider_DestroyJntSph(globalCtx, &this->colliderSph);
Collider_DestroyCylinder(globalCtx, &this->colliderBody);
}
void BossVa_SetupIntro(BossVa* this) {
f32 lastFrame = Animation_GetLastFrame(&gBarinadeBodyAnim);
Animation_Change(&this->skelAnime, &gBarinadeBodyAnim, 1.0f, lastFrame, lastFrame, ANIMMODE_ONCE, 0.0f);
this->actor.shape.yOffset = -450.0f;
this->actor.flags &= ~ACTOR_FLAG_0;
BossVa_SetupAction(this, BossVa_BodyIntro);
}
void BossVa_BodyIntro(BossVa* this, GlobalContext* globalCtx) {
s32 i;
Player* player = GET_PLAYER(globalCtx);
this->unk_1AC += 0xC31;
this->unk_1A0 = (Math_CosS(this->unk_1AC) * 0.1f) + 1.0f;
this->unk_1A4 = (Math_SinS(this->unk_1AC) * 0.05f) + 1.0f;
switch (sCsState) {
case INTRO_UNUSED_START:
this->timer--;
if (this->timer == 0) {
sCsState = INTRO_CLOSE_DOOR;
this->timer = 10;
}
break;
case INTRO_START:
globalCtx->envCtx.screenFillColor[0] = 0xDC;
globalCtx->envCtx.screenFillColor[1] = 0xDC;
globalCtx->envCtx.screenFillColor[2] = 0xBE;
globalCtx->envCtx.screenFillColor[3] = 0xD2;
func_8002DF54(globalCtx, &this->actor, 8);
player->actor.world.rot.y = player->actor.shape.rot.y = 0x7FFF;
sCsState++;
break;
case INTRO_LOOK_DOOR:
func_80064520(globalCtx, &globalCtx->csCtx);
if (sCsCamera == SUBCAM_FREE) {
sCsCamera = Gameplay_CreateSubCamera(globalCtx);
}
Gameplay_ChangeCameraStatus(globalCtx, MAIN_CAM, CAM_STAT_WAIT);
Gameplay_ChangeCameraStatus(globalCtx, sCsCamera, CAM_STAT_ACTIVE);
sCameraNextEye.x = sCameraEye.x = 13.0f;
sCameraNextEye.y = sCameraEye.y = 124.0f;
sCameraNextEye.z = sCameraEye.z = 167.0f;
sCameraNextAt.x = sCameraAt.x = player->actor.world.pos.x;
sCameraNextAt.y = sCameraAt.y = player->actor.world.pos.y;
sCameraNextAt.z = sCameraAt.z = player->actor.world.pos.z;
sCameraAtMaxVel = sCameraEyeMaxVel = sZeroVec;
this->timer = 10;
sCsState++;
break;
case INTRO_CLOSE_DOOR:
this->timer--;
if (this->timer == 0) {
func_8002DF54(globalCtx, &this->actor, 2);
sCsState++;
this->timer = 30;
}
break;
case INTRO_DOOR_SHUT:
this->timer--;
if (this->timer == 0) {
sCsState++;
}
if (Rand_ZeroOne() < 0.1f) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_BL_SPARK - SFX_FLAG);
}
break;
case INTRO_CRACKLE:
func_8002DF54(globalCtx, &this->actor, 1);
sCsState++;
break;
case INTRO_SPAWN_BARI:
func_80064520(globalCtx, &globalCtx->csCtx);
if (sCsCamera == SUBCAM_FREE) {
sCsCamera = Gameplay_CreateSubCamera(globalCtx);
}
Gameplay_ChangeCameraStatus(globalCtx, MAIN_CAM, CAM_STAT_WAIT);
Gameplay_ChangeCameraStatus(globalCtx, sCsCamera, CAM_STAT_ACTIVE);
sCameraNextEye.x = sCameraEye.x = 13.0f;
sCameraNextEye.y = sCameraEye.y = 124.0f;
sCameraNextEye.z = sCameraEye.z = 167.0f;
sCameraNextAt.x = sCameraAt.x = player->actor.world.pos.x;
sCameraNextAt.y = sCameraAt.y = player->actor.world.pos.y;
sCameraNextAt.z = sCameraAt.z = player->actor.world.pos.z;
sCameraAtMaxVel = sCameraEyeMaxVel = sZeroVec;
for (i = BOSSVA_BARI_LOWER_5; i >= BOSSVA_BARI_UPPER_1; i--) {
Actor_SpawnAsChild(
&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_BOSS_VA,
sInitPosOffsets[i].x + this->actor.world.pos.x, sInitPosOffsets[i].y + this->actor.world.pos.y,
sInitPosOffsets[i].z + this->actor.world.pos.z, sInitRot[i].x + this->actor.world.rot.x,
sInitRot[i].y + this->actor.world.rot.y, sInitRot[i].z + this->actor.world.rot.z, i);
}
this->timer = 90;
sCsState++;
break;
case INTRO_REVERSE_CAMERA:
sCameraNextEye.x = -92.0f;
sCameraNextEye.y = 22.0f;
sCameraNextEye.z = 360.0f;
sCameraNextAt.x = 63.0f;
sCameraNextAt.y = 104.0f;
sCameraNextAt.z = 248.0f;
Math_SmoothStepToF(&sCameraEyeMaxVel.x, 7.0f, 0.3f, 0.7f, 0.05f);
sCameraEyeMaxVel.z = sCameraEyeMaxVel.x;
sCameraEyeMaxVel.y = sCameraEyeMaxVel.z;
sCameraAtMaxVel = sCameraEyeMaxVel;
this->timer--;
if (this->timer == 0) {
sCsState++;
this->timer = 60;
}
break;
case INTRO_SUPPORT_CAMERA:
sCameraNextEye.x = sCameraEye.x = 140.0f;
sCameraNextEye.y = sCameraEye.y = 205.0f;
sCameraNextEye.z = sCameraEye.z = -20.0f;
sCameraNextAt.x = sCameraAt.x = 10.0f;
sCameraNextAt.y = sCameraAt.y = 247.0f;
sCameraNextAt.z = sCameraAt.z = -220.0f;
sCsState++;
this->timer = 1;
break;
case INTRO_BODY_SOUND:
sCameraNextAt.x = 10.0f;
sCameraNextAt.y = 247.0f;
sCameraNextAt.z = -220.0f;
Math_SmoothStepToF(&sCameraEyeMaxVel.x, 7.0f, 0.3f, 0.7f, 0.05f);
sCameraEyeMaxVel.z = sCameraEyeMaxVel.x;
sCameraEyeMaxVel.y = sCameraEyeMaxVel.z;
sCameraAtMaxVel = sCameraEyeMaxVel;
this->timer--;
if (this->timer == 0) {
sCsState++;
this->timer = 40;
}
break;
case INTRO_LOOK_SUPPORT:
this->timer--;
if (this->timer == 0) {
sCameraNextAt.x = 10.0f;
sCameraNextAt.y = 50.0f;
sCameraNextAt.z = -220.0f;
sCameraAtMaxVel = sCameraEyeMaxVel = sZeroVec;
sCsState++;
sCsState++;
this->timer = 20;
}
break;
case INTRO_CALL_BARI:
Math_SmoothStepToF(&sCameraEyeMaxVel.x, 14.0f, 0.3f, 1.0f, 0.25f);
sCameraEyeMaxVel.y = sCameraEyeMaxVel.x * 0.7f;
sCameraEyeMaxVel.z = sCameraEyeMaxVel.x;
sCameraAtMaxVel = sCameraEyeMaxVel;
sCameraAtMaxVel.z = sCameraAtMaxVel.z * 1.75f;
this->timer--;
if (this->timer == 0) {
sCsState++;
this->timer = 7500;
this->unk_1F2 = 0;
}
break;
case INTRO_ATTACH_BARI:
for (i = 10; i >= 1; i--) {
if (sBodyBari[i - 1]) {
if (sBodyBari[i - 1] == 1) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_STICK);
BossVa_SetSparkEnv(globalCtx);
if (this->onCeiling == 0) {
this->onCeiling = 2; // Not used by body
}
} else if (sBodyBari[i - 1] == 2) {
BossVa_Spark(globalCtx, this, 6, 140, 50.0f, 30.0f, SPARK_BARI, i, true);
}
if (sBodyBari[i - 1] <= 2) {
sBodyBari[i - 1]++;
}
}
}
Math_SmoothStepToS(&this->unk_1F2, 0x280, 1, 0x32, 0);
Math_SmoothStepToF(&sCameraEyeMaxVel.x, 14.0f, 0.3f, 1.0f, 0.25f);
sCameraEyeMaxVel.z = sCameraEyeMaxVel.x;
sCameraAtMaxVel = sCameraEyeMaxVel;
if (this->timer >= 45000) {
globalCtx->envCtx.unk_BF = 1;
func_8002DF54(globalCtx, &this->actor, 8);
} else if (this->timer >= 35000) {
Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_BOSS);
}
this->timer += this->unk_1F2;
if (this->timer >= 65536) {
sCameraEyeMaxVel.y = sCameraAtMaxVel.y = 9.8f;
sCsState++;
sCameraNextEye.x = 10.0f;
sCameraNextEye.z = 0.0f;
sCameraNextAt.x = 10.0f;
sCameraNextAt.y = 140.0f;
sCameraNextAt.z = -200.0f;
if (!(gSaveContext.eventChkInf[7] & 0x40)) {
TitleCard_InitBossName(globalCtx, &globalCtx->actorCtx.titleCtx,
SEGMENTED_TO_VIRTUAL(gBarinadeTitleCardTex), 160, 180, 128, 40, true);
}
if (Rand_ZeroOne() < 0.1f) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_BL_SPARK - SFX_FLAG);
}
this->timer = 40;
} else {
sCameraEyeMaxVel.y = 1.6f;
sCameraNextEye.y = 5.0f;
sCameraNextEye.x = Math_SinS(this->timer) * 200.0f;
sCameraNextEye.z = (Math_CosS(this->timer) * 200.0f) + -200.0f;
}
break;
case INTRO_TITLE:
BossVa_Spark(globalCtx, this, 3, 140, 50.0f, 30.0f, SPARK_BARI, 10.0f, false);
this->timer--;
if (this->timer == 0) {
sCsState++;
this->timer = 45;
}
break;
case INTRO_BRIGHTEN:
BossVa_Spark(globalCtx, this, 3, 140, 50.0f, 30.0f, SPARK_BARI, 10.0f, false);
this->timer--;
if (this->timer == 0) {
sCsState++;
this->timer = 11;
}
break;
case INTRO_FINISH:
this->timer--;
if (this->timer == 0) {
Gameplay_ClearCamera(globalCtx, sCsCamera);
sCsCamera = 0;
func_80064534(globalCtx, &globalCtx->csCtx);
Gameplay_ChangeCameraStatus(globalCtx, MAIN_CAM, CAM_STAT_ACTIVE);
func_8002DF54(globalCtx, &this->actor, 7);
sCsState++;
gSaveContext.eventChkInf[7] |= 0x40;
player->actor.shape.rot.y = player->actor.world.rot.y = this->actor.yawTowardsPlayer + 0x8000;
}
break;
case BOSSVA_BATTLE:
BossVa_SetupBodyPhase1(this);
break;
}
if (sCsState >= INTRO_BODY_SOUND) {
func_800F436C(&this->actor.projectedPos, NA_SE_EN_BALINADE_LEVEL - SFX_FLAG, 1.0f);
if ((sCsState >= INTRO_CALL_BARI) && ((globalCtx->gameplayFrames % 4) == 0)) {
BossVa_Spark(globalCtx, this, 1, 100, 50.0f, 10.0f, SPARK_BODY, 10.0f, false);
}
}
this->unk_1B0 += 0xCE4;
this->bodyGlow = (s16)(Math_SinS(this->unk_1B0) * 50.0f) + 150;
if ((sCsCamera != 0) && (sCsState <= INTRO_TITLE)) {
Math_SmoothStepToF(&sCameraEye.x, sCameraNextEye.x, 0.3f, sCameraEyeMaxVel.x, 0.075f);
Math_SmoothStepToF(&sCameraEye.y, sCameraNextEye.y, 0.3f, sCameraEyeMaxVel.y, 0.075f);
Math_SmoothStepToF(&sCameraEye.z, sCameraNextEye.z, 0.3f, sCameraEyeMaxVel.z, 0.075f);
Math_SmoothStepToF(&sCameraAt.x, sCameraNextAt.x, 0.3f, sCameraAtMaxVel.x, 0.075f);
Math_SmoothStepToF(&sCameraAt.y, sCameraNextAt.y, 0.3f, sCameraAtMaxVel.y, 0.075f);
Math_SmoothStepToF(&sCameraAt.z, sCameraNextAt.z, 0.3f, sCameraAtMaxVel.z, 0.075f);
Gameplay_CameraSetAtEye(globalCtx, sCsCamera, &sCameraAt, &sCameraEye);
}
}
void BossVa_SetupBodyPhase1(BossVa* this) {
f32 lastFrame = Animation_GetLastFrame(&gBarinadeBodyAnim);
Animation_Change(&this->skelAnime, &gBarinadeBodyAnim, 1.0f, lastFrame, lastFrame, ANIMMODE_ONCE, 0.0f);
this->actor.shape.yOffset = -450.0f;
this->actor.flags &= ~ACTOR_FLAG_0;
this->timer = 25;
sBodyState = 0x80;
BossVa_SetupAction(this, BossVa_BodyPhase1);
}
void BossVa_BodyPhase1(BossVa* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
this->unk_1B0 += 0xCE4;
this->bodyGlow = (s16)(Math_SinS(this->unk_1B0) * 50.0f) + 150;
if (this->timer != 0) {
this->timer--;
if (this->timer == 0) {
sBodyState &= (u8)~0x80;
}
}
if (this->colliderBody.base.atFlags & AT_HIT) {
this->colliderBody.base.atFlags &= ~AT_HIT;
if (this->colliderBody.base.at == &player->actor) {
func_8002F71C(globalCtx, &this->actor, 8.0f, this->actor.yawTowardsPlayer, 8.0f);
}
}
if (sBodyState & 0x7F) {
this->skelAnime.curFrame = 0.0f;
Actor_SetColorFilter(&this->actor, 0, 255, 0, 12);
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_DAMAGE);
}
if (SkelAnime_Update(&this->skelAnime) && (sFightPhase >= PHASE_2)) {
BossVa_SetupBodyPhase2(this, globalCtx);
}
Math_SmoothStepToS(&this->actor.shape.rot.x, this->actor.world.rot.x, 1, 0xC8, 0);
Math_SmoothStepToS(&this->actor.shape.rot.z, this->actor.world.rot.z, 1, 0xC8, 0);
this->unk_1AC += 0xC31;
this->unk_1A0 = (Math_CosS(this->unk_1AC) * 0.1f) + 1.0f;
this->unk_1A4 = (Math_SinS(this->unk_1AC) * 0.05f) + 1.0f;
if ((globalCtx->gameplayFrames % 4) == 0) {
BossVa_Spark(globalCtx, this, 1, 100, 50.0f, 10.0f, SPARK_BARI, 10.0f, false);
}
if (Rand_ZeroOne() < 0.1f) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_BL_SPARK - SFX_FLAG);
}
Collider_UpdateCylinder(&this->actor, &this->colliderBody);
CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->colliderBody.base);
CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->colliderBody.base);
func_800F436C(&this->actor.projectedPos, NA_SE_EN_BALINADE_LEVEL - SFX_FLAG, 1.0f);
}
void BossVa_SetupBodyPhase2(BossVa* this, GlobalContext* globalCtx) {
s32 i;
sFightPhase++;
for (i = BOSSVA_BARI_UPPER_5; i >= BOSSVA_BARI_UPPER_1; i--) {
Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_BOSS_VA,
sInitPosOffsets[i].x + this->actor.world.pos.x,
sInitPosOffsets[i].y + this->actor.world.pos.y,
sInitPosOffsets[i].z + this->actor.world.pos.z, sInitRot[i].x + this->actor.world.rot.x,
sInitRot[i].y + this->actor.world.rot.y, sInitRot[i].z + this->actor.world.rot.z, i);
}
this->invincibilityTimer = 0;
this->actor.flags |= ACTOR_FLAG_0;
BossVa_SetupAction(this, BossVa_BodyPhase2);
}
void BossVa_BodyPhase2(BossVa* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
Vec3f sp48;
if (this->actor.colorFilterTimer == 0) {
sPhase2Timer++;
if ((this->invincibilityTimer != 0) && (this->actor.colorFilterParams & 0x4000)) {
Actor_SetColorFilter(&this->actor, 0, 255, 0, 160);
this->actor.colorFilterTimer = this->invincibilityTimer;
} else {
this->colliderBody.info.bumper.dmgFlags = 0x10;
}
}
if (this->colliderBody.base.acFlags & AC_HIT) {
this->colliderBody.base.acFlags &= ~AC_HIT;
if (this->colliderBody.base.ac->id == ACTOR_EN_BOOM) {
sPhase2Timer &= 0xFE00;
Actor_SetColorFilter(&this->actor, 0, 255, 0, 160);
this->colliderBody.info.bumper.dmgFlags = 0xFC00712;
} else {
sKillBari++;
if ((this->actor.colorFilterTimer != 0) && !(this->actor.colorFilterParams & 0x4000)) {
this->invincibilityTimer = this->actor.colorFilterTimer - 5;
if (this->invincibilityTimer > 160) {
this->invincibilityTimer = 0;
}
}
Actor_SetColorFilter(&this->actor, 0x4000, 255, 0, 12);
}
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_FAINT);
}
if (this->colliderBody.base.atFlags & AT_HIT) {
this->colliderBody.base.atFlags &= ~AT_HIT;
sPhase2Timer = (sPhase2Timer + 0x18) & 0xFFF0;
if (this->colliderBody.base.at == &player->actor) {
func_8002F71C(globalCtx, &this->actor, 8.0f, this->actor.yawTowardsPlayer, 8.0f);
Audio_PlayActorSound2(&player->actor, NA_SE_PL_BODY_HIT);
}
}
if ((sPhase2Timer > 10) && !(sPhase2Timer & 7) && (this->actor.speedXZ == 1.0f)) {
sp48 = this->actor.world.pos;
sp48.y += 310.0f + (this->actor.shape.yOffset * this->actor.scale.y);
sp48.x += -10.0f;
sp48.z += 220.0f;
BossVa_SpawnSparkBall(globalCtx, sVaEffects, this, &sp48, 4, 0);
}
if (Rand_ZeroOne() < 0.1f) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_BL_SPARK - SFX_FLAG);
}
Math_SmoothStepToS(&this->actor.shape.rot.x, this->actor.world.rot.x, 1, 0xC8, 0);
Math_SmoothStepToS(&this->actor.shape.rot.z, this->actor.world.rot.z, 1, 0xC8, 0);
Math_SmoothStepToF(&this->actor.shape.yOffset, -1000.0f, 1.0f, 20.0f, 0.0f);
if (!(sPhase2Timer & 0x100)) {
this->actor.flags |= ACTOR_FLAG_0;
this->actor.speedXZ = 1.0f;
} else {
this->actor.flags &= ~ACTOR_FLAG_0;
this->actor.speedXZ = 0.0f;
}
if (SkelAnime_Update(&this->skelAnime) && (sFightPhase >= PHASE_3)) {
BossVa_SetupBodyPhase3(this);
}
this->unk_1AC += 0xC31;
this->unk_1A0 = (Math_CosS(this->unk_1AC) * 0.1f) + 1.0f;
this->unk_1A4 = (Math_SinS(this->unk_1AC) * 0.05f) + 1.0f;
if ((globalCtx->gameplayFrames % 4) == 0) {
BossVa_Spark(globalCtx, this, 1, 100, 50.0f, 10.0f, SPARK_BODY, 10.0f, false);
}
this->actor.focus.pos = this->actor.world.pos;
this->actor.focus.pos.y += 45.0f;
Collider_UpdateCylinder(&this->actor, &this->colliderBody);
CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->colliderBody.base);
if (this->actor.colorFilterTimer == 0) {
CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->colliderBody.base);
}
if ((this->actor.colorFilterTimer == 0) || !(this->actor.colorFilterParams & 0x4000)) {
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->colliderBody.base);
}
func_800F436C(&this->actor.projectedPos, NA_SE_EN_BALINADE_LEVEL - SFX_FLAG,
(this->vaBodySpinRate * 0.00025f) + 1.0f);
}
void BossVa_SetupBodyPhase3(BossVa* this) {
this->colliderBody.info.bumper.dmgFlags = 0x10;
this->actor.speedXZ = 0.0f;
sPhase3StopMoving = false;
BossVa_SetupAction(this, BossVa_BodyPhase3);
}
void BossVa_BodyPhase3(BossVa* this, GlobalContext* globalCtx) {
s32 pad;
Player* player = GET_PLAYER(globalCtx);
s32 i;
s16 sp62;
sp62 = Math_Vec3f_Yaw(&this->actor.world.pos, &this->actor.home.pos);
this->unk_1B0 += 0xCE4;
this->bodyGlow = (s16)(Math_SinS(this->unk_1B0) * 50.0f) + 150;
if (this->colliderBody.base.atFlags & AT_HIT) {
this->colliderBody.base.atFlags &= ~AT_HIT;
if (this->colliderBody.base.at == &player->actor) {
func_8002F71C(globalCtx, &this->actor, 8.0f, this->actor.yawTowardsPlayer, 8.0f);
this->actor.world.rot.y += (s16)Rand_CenteredFloat(0x2EE0) + 0x8000;
Audio_PlayActorSound2(&player->actor, NA_SE_PL_BODY_HIT);
}
}
if (this->colliderBody.base.acFlags & AC_HIT) {
this->skelAnime.curFrame = 0.0f;
Actor_SetColorFilter(&this->actor, 0, 255, 0, 12);
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_FAINT);
sBodyState = 1;
this->timer = 131;
this->actor.flags &= ~ACTOR_FLAG_0;
} else {
sBodyState = 0;
if (this->timer == 0) {
if (Math_SmoothStepToS(&this->vaBodySpinRate, 0xFA0, 1, 0x12C, 0) == 0) {
if (this->actor.speedXZ == 0.0f) {
this->actor.world.rot.y = this->actor.yawTowardsPlayer;
}
Math_SmoothStepToF(&this->actor.speedXZ, 3.0f, 1.0f, 0.15f, 0.0f);
}
this->actor.flags |= ACTOR_FLAG_0;
} else {
this->timer--;
if (this->timer < 35) {
sBodyState = 0x80;
}
Math_SmoothStepToS(&this->vaBodySpinRate, 0, 1, 0x12C, 0);
Math_SmoothStepToF(&this->actor.speedXZ, 0.0f, 1.0f, 0.2f, 0.0f);
Math_SmoothStepToF(&this->actor.shape.yOffset, -1420.0f, 1.0f, 30.0f, 0.0f);
}
}
if (Math_Vec3f_DistXZ(&this->actor.world.pos, &this->actor.home.pos) >= 400.0f) {
Math_SmoothStepToS(&this->actor.world.rot.y, sp62, 1, 0x3E8, 0);
} else if (player->invincibilityTimer != 0) {
Math_SmoothStepToS(&this->actor.world.rot.y, this->actor.yawTowardsPlayer + 0x8000, 1, 0x12C, 0);
} else if ((globalCtx->gameplayFrames & 0x80) == 0) {
Math_SmoothStepToS(&this->actor.world.rot.y, this->actor.yawTowardsPlayer, 1, 0x12C, 0);
} else {
Math_SmoothStepToS(&this->actor.world.rot.y, sp62, 1, 0x258, 0);
}
if (sPhase3StopMoving) {
this->actor.speedXZ = 0.0f;
}
Actor_MoveForward(&this->actor);
if (SkelAnime_Update(&this->skelAnime) && (sFightPhase >= PHASE_4)) {
BossVa_SetupBodyPhase4(this, globalCtx);
}
this->actor.shape.rot.y += this->vaBodySpinRate;
if (sFightPhase == PHASE_3) {
Math_SmoothStepToF(&this->actor.shape.yOffset, -450.0f, 1.0f, 15.0f, 0.0f);
} else {
Math_SmoothStepToF(&this->actor.shape.yOffset, -810.0f, 1.0f, 15.0f, 0.0f);
}
if ((this->actor.shape.yOffset >= -500.0f) && (sFightPhase == PHASE_3)) {
for (i = BOSSVA_BARI_LOWER_5; i >= BOSSVA_BARI_LOWER_1; i--) {
Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_BOSS_VA,
sInitPosOffsets[i].x + this->actor.world.pos.x,
sInitPosOffsets[i].y + this->actor.world.pos.y,
sInitPosOffsets[i].z + this->actor.world.pos.z, sInitRot[i].x + this->actor.world.rot.x,
sInitRot[i].y + this->actor.world.rot.y, sInitRot[i].z + this->actor.world.rot.z, i);
}
sFightPhase++;
}
this->unk_1AC += 0xC31;
this->unk_1A0 = (Math_CosS(this->unk_1AC) * 0.1f) + 1.0f;
this->unk_1A4 = (Math_SinS(this->unk_1AC) * 0.05f) + 1.0f;
if ((globalCtx->gameplayFrames % 4) == 0) {
BossVa_Spark(globalCtx, this, 1, 0x64, 50.0f, 10.0f, SPARK_BODY, 10.0f, false);
}
this->actor.focus.pos = this->actor.world.pos;
this->actor.focus.pos.y += 20.0f;
if (Rand_ZeroOne() < 0.1f) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_BL_SPARK - SFX_FLAG);
}
Collider_UpdateCylinder(&this->actor, &this->colliderBody);
CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->colliderBody.base);
CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->colliderBody.base);
if (this->timer == 0) {
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->colliderBody.base);
}
func_800F436C(&this->actor.projectedPos, NA_SE_EN_BALINADE_LEVEL - SFX_FLAG,
(this->vaBodySpinRate * 0.00025f) + 1.0f);
}
void BossVa_SetupBodyPhase4(BossVa* this, GlobalContext* globalCtx) {
this->unk_1AC = 0;
this->actor.flags |= ACTOR_FLAG_0;
this->vaBodySpinRate = this->unk_1AC;
this->actor.world.rot.y = this->actor.yawTowardsPlayer;
this->timer2 = (s16)(Rand_ZeroOne() * 150.0f) + 300;
sBodyState = 1;
sPhase4HP = 4;
if (this->actor.shape.yOffset != 0.0f) {
this->timer = -30;
}
this->colliderBody.dim.radius = 55;
BossVa_SetupAction(this, BossVa_BodyPhase4);
}
void BossVa_BodyPhase4(BossVa* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
f32 tmpf1;
EnBoom* boomerang;
this->unk_1B0 = (this->unk_1B0 + (s16)((sFightPhase - PHASE_4 + 1) * 1000.0f)) + 0xCE4;
this->bodyGlow = (s16)(Math_SinS(this->unk_1B0) * 50.0f) + 150;
if (this->colliderBody.base.atFlags & AT_HIT) {
this->colliderBody.base.atFlags &= ~AT_HIT;
if (this->colliderBody.base.at == &player->actor) {
func_8002F71C(globalCtx, &this->actor, 8.0f, this->actor.yawTowardsPlayer, 8.0f);
this->actor.world.rot.y += (s16)Rand_CenteredFloat(0x2EE0) + 0x8000;
Audio_PlayActorSound2(&player->actor, NA_SE_PL_BODY_HIT);
}
}
if (Rand_ZeroOne() < 0.1f) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_BL_SPARK - SFX_FLAG);
}
if (this->colliderBody.base.acFlags & AC_HIT) {
this->colliderBody.base.acFlags &= ~AC_HIT;
this->skelAnime.curFrame = 0.0f;
if (this->timer >= 0) {
if (this->invincibilityTimer == 0) {
this->invincibilityTimer = 8;
if (this->actor.colChkInfo.damageEffect != 1) {
this->actor.world.rot.y = this->actor.yawTowardsPlayer;
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_DAMAGE);
Actor_SetColorFilter(&this->actor, 0x4000, 255, 0, 12);
sPhase4HP -= this->actor.colChkInfo.damage;
if (sPhase4HP <= 0) {
this->timer = 0;
sFightPhase++;
sPhase4HP += 3;
if (sFightPhase >= PHASE_DEATH) {
BossVa_SetupBodyDeath(this, globalCtx);
Enemy_StartFinishingBlow(globalCtx, &this->actor);
return;
}
this->actor.speedXZ = -10.0f;
this->timer = -170 - (s16)(Rand_ZeroOne() * 150.0f);
}
} else {
this->timer = (s16)Rand_CenteredFloat(40.0f) + 160;
this->vaBodySpinRate = 0;
this->actor.speedXZ = 0.0f;
Actor_SetColorFilter(&this->actor, 0, 125, 0, 255);
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_FAINT);
}
}
} else if (this->colliderBody.base.ac->id == ACTOR_EN_BOOM) {
boomerang = (EnBoom*)this->colliderBody.base.ac;
boomerang->returnTimer = 0;
boomerang->moveTo = &player->actor;
boomerang->actor.world.rot.y = boomerang->actor.yawTowardsPlayer;
Audio_PlayActorSound2(&this->actor, NA_SE_IT_SHIELD_REFLECT_SW);
}
} else if ((this->timer2 == 0) && (this->actor.shape.yOffset == 0.0f)) {
this->timer = -220 - (s16)(Rand_ZeroOne() * 200.0f);
} else if (this->timer2 != 0) {
this->timer2--;
}
SkelAnime_Update(&this->skelAnime);
if (this->timer == 0) {
Math_SmoothStepToF(&this->actor.shape.yOffset, 0.0f, 1.0f, ((sFightPhase - PHASE_4 + 1) * 5.0f) + 10.0f, 0.0f);
if (Math_SmoothStepToS(&this->vaBodySpinRate, (s16)((sFightPhase - PHASE_4 + 1) * 500.0f) + 0xFA0, 1, 0x12C,
0) == 0) {
if (this->actor.speedXZ == 0.0f) {
this->actor.colorFilterTimer = 0;
this->actor.world.rot.y = this->actor.yawTowardsPlayer;
this->timer2 = (s16)(Rand_ZeroOne() * 150.0f) + 300;
}
Math_SmoothStepToF(&this->actor.speedXZ, ((sFightPhase - PHASE_4 + 1) * 1.5f) + 4.0f, 1.0f, 0.25f, 0.0f);
}
this->colliderBody.info.bumper.dmgFlags = 0x10;
} else {
Math_SmoothStepToS(&this->vaBodySpinRate, 0, 1, 0x96, 0);
if (this->timer > 0) {
if ((player->stateFlags1 & 0x4000000) && (this->timer > 35)) {
this->timer = 35;
}
Math_SmoothStepToF(&this->actor.shape.yOffset, -480.0f, 1.0f, 30.0f, 0.0f);
this->colliderBody.info.bumper.dmgFlags = 0xFC00712;
this->timer--;
} else {
if ((player->stateFlags1 & 0x4000000) && (this->timer < -60)) {
this->timer = -59;
}
if ((globalCtx->gameplayFrames % 4) == 0) {
BossVa_Spark(globalCtx, this, 2, 0x64, 220.0f, 5.0f, SPARK_BODY, 12.0f, true);
}
if (this->timer < -30) {
if (this->actor.speedXZ > 0.0f) {
Math_SmoothStepToF(&this->actor.speedXZ, 0.0f, 1.0f, 0.5f, 0.0f);
}
Math_SmoothStepToF(&this->actor.shape.yOffset, -1400.0f, 1.0f, 60.0f, 0.0f);
} else {
if (this->actor.speedXZ == 0.0f) {
this->actor.world.rot.y = this->actor.yawTowardsPlayer + 0x8000;
this->timer2 = (s16)(Rand_ZeroOne() * 150.0f) + 330;
}
Math_SmoothStepToS(&this->vaBodySpinRate, 0xFA0, 1, 0x1F4, 0);
tmpf1 = sFightPhase - PHASE_4 + 1;
Math_SmoothStepToF(&this->actor.speedXZ, (tmpf1 + tmpf1) + 4.0f, 1.0f, 0.25f, 0.0f);
Math_SmoothStepToF(&this->actor.shape.yOffset, 0.0f, 1.0f, 20.0f, 0.0f);
}
this->timer++;
}
}
this->actor.shape.rot.y += this->vaBodySpinRate;
if (this->actor.speedXZ < 0.0f) {
Math_SmoothStepToF(&this->actor.speedXZ, 0.0f, 1.0f, 0.5f, 0.0f);
}
this->unk_1AC += 0xC31;
this->unk_1A0 = (Math_CosS(this->unk_1AC) * 0.1f) + 1.0f;
this->unk_1A4 = (Math_SinS(this->unk_1AC) * 0.05f) + 1.0f;
if (this->actor.bgCheckFlags & 8) {
this->actor.bgCheckFlags &= ~8;
this->actor.world.rot.y = (s16)Rand_CenteredFloat(30 * (0x10000 / 360)) + this->actor.wallYaw;
}
if (sFightPhase <= PHASE_4) {
if (Math_Vec3f_DistXZ(&this->actor.world.pos, &this->actor.home.pos) >= 400.0f) {
Math_SmoothStepToS(&this->actor.world.rot.y, Math_Vec3f_Yaw(&this->actor.world.pos, &this->actor.home.pos),
1, 0x5DC, 0);
} else if (player->invincibilityTimer != 0) {
Math_SmoothStepToS(&this->actor.world.rot.y, this->actor.yawTowardsPlayer + 0x8000, 1, 0x12C, 0);
} else if ((globalCtx->gameplayFrames & 0x80) == 0) {
Math_SmoothStepToS(&this->actor.world.rot.y, this->actor.yawTowardsPlayer, 1,
(s16)((sFightPhase - PHASE_4 + 1) * 100.0f) + 0x64, 0);
}
}
Actor_MoveForward(&this->actor);
this->actor.focus.pos = this->actor.world.pos;
this->actor.focus.pos.y += 60.0f;
if (((globalCtx->gameplayFrames % 2) == 0) && (this->timer == 0)) {
BossVa_Spark(globalCtx, this, 2, 125, 40.0f, 10.0f, SPARK_BODY, 10.0f, false);
BossVa_Spark(globalCtx, this, 1, 100, 15.0f, 10.0f, SPARK_BARI, 11.0f, true);
}
Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 30.0f, 70.0f, 0.0f, 1);
Collider_UpdateCylinder(&this->actor, &this->colliderBody);
CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->colliderBody.base);
if (this->invincibilityTimer == 0) {
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->colliderBody.base);
}
if ((this->vaBodySpinRate > 0x3E8) || (this->actor.shape.yOffset < -1200.0f)) {
CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->colliderBody.base);
}
func_800F436C(&this->actor.projectedPos, NA_SE_EN_BALINADE_LEVEL - SFX_FLAG,
(this->vaBodySpinRate * 0.00025f) + 1.0f);
if (this->invincibilityTimer != 0) {
this->invincibilityTimer--;
sBodyState = (sBodyState & 0x80) | 2;
} else {
sBodyState = (sBodyState & 0x80) | 1;
}
}
void BossVa_SetupBodyDeath(BossVa* this, GlobalContext* globalCtx) {
func_800F436C(&this->actor.projectedPos, NA_SE_EN_BALINADE_LEVEL - SFX_FLAG, 1.0f);
this->actor.flags &= ~(ACTOR_FLAG_0 | ACTOR_FLAG_2);
Audio_QueueSeqCmd(0x1 << 28 | SEQ_PLAYER_BGM_MAIN << 24 | 0x100FF);
this->vaCamRotMod = 0xC31;
sCsState = DEATH_START;
this->actor.speedXZ = 0.0f;
this->unk_1A8 = 0.0f;
Flags_SetClear(globalCtx, globalCtx->roomCtx.curRoom.num);
BossVa_SetupAction(this, BossVa_BodyDeath);
}
void BossVa_BodyDeath(BossVa* this, GlobalContext* globalCtx) {
s32 i;
Camera* camera = Gameplay_GetCamera(globalCtx, 0);
s32 sp7C;
Player* player = GET_PLAYER(globalCtx);
s16 tmp16;
switch (sCsState) {
case DEATH_START:
func_8002DF54(globalCtx, &this->actor, 1);
func_80064520(globalCtx, &globalCtx->csCtx);
sCsCamera = Gameplay_CreateSubCamera(globalCtx);
Gameplay_ChangeCameraStatus(globalCtx, MAIN_CAM, CAM_STAT_WAIT);
Gameplay_ChangeCameraStatus(globalCtx, sCsCamera, CAM_STAT_ACTIVE);
sCameraNextAt.x = this->actor.world.pos.x;
sCameraNextAt.y = this->actor.world.pos.y;
sCameraNextAt.z = this->actor.world.pos.z;
sCameraAt = camera->at;
sCameraNextEye = sCameraEye = camera->eye;
sCameraNextEye.y = 40.0f;
sCameraNextAt.y = 140.0f;
sCameraAtMaxVel = sCameraEyeMaxVel = sZeroVec;
this->unk_1AC = Math_Vec3f_Yaw(&sCameraEye, &sCameraNextAt) - 0x100;
this->unk_1B0 = 15;
globalCtx->envCtx.screenFillColor[0] = globalCtx->envCtx.screenFillColor[1] =
globalCtx->envCtx.screenFillColor[2] = 0xFF;
globalCtx->envCtx.screenFillColor[3] = 0;
globalCtx->envCtx.fillScreen = true;
sCsState++;
case DEATH_BODY_TUMORS:
this->unk_1AC += 0x100;
sCameraNextEye.x = (Math_SinS(this->unk_1AC) * (160.0f + this->unk_1A8)) + sCameraNextAt.x;
sCameraNextEye.z = (Math_CosS(this->unk_1AC) * (160.0f + this->unk_1A8)) + sCameraNextAt.z;
Math_SmoothStepToF(&sCameraEyeMaxVel.x, 16.0f, 0.4f, 1.5f, 0.5f);
sCameraEyeMaxVel.z = sCameraEyeMaxVel.x;
sCameraEyeMaxVel.y = sCameraEyeMaxVel.x * 0.5f;
sCameraAtMaxVel = sCameraEyeMaxVel;
tmp16 = Rand_CenteredFloat(0.5f) + ((sCameraEyeMaxVel.x * 0.5f) + 0.6f);
if (((globalCtx->gameplayFrames % 4) == 0) && (this->unk_1B0 != 0)) {
for (i = 6; i > 1; i--) {
BossVa_Tumor(globalCtx, this, 1, tmp16, 0.0f, 0.0f, TUMOR_BODY, i, true);
}
BossVa_Tumor(globalCtx, this, 1, tmp16, 0.0f, 0.0f, TUMOR_BODY, 11.0f, true);
this->unk_1B0--;
}
if (this->unk_1B0 == 0) {
sCsState++;
sCameraAtMaxVel = sCameraEyeMaxVel = sZeroVec;
}
break;
case DEATH_CORE_DEAD:
this->unk_1AC += 0x1862;
this->unk_1A0 = (Math_CosS(this->unk_1AC) * 0.12f) + 1.0f;
this->unk_1A4 = (Math_SinS(this->unk_1AC) * 0.075f) + 1.0f;
if (!this->isDead) {
this->burst++;
this->isDead++;
this->timer = 30;
sCsState++;
EffectSsDeadSound_SpawnStationary(globalCtx, &this->actor.projectedPos, NA_SE_EN_BALINADE_DEAD, 1, 1,
0x28);
this->onCeiling = 2; // Not used by body
BossVa_SetDeathEnv(globalCtx);
func_8002DF54(globalCtx, &this->actor, 8);
}
break;
case DEATH_CORE_BURST:
if (this->timer == 13) {
Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_BOSS_CLEAR);
}
this->timer--;
if (this->timer == 0) {
sCameraNextAt.x = this->actor.world.pos.x;
sCameraNextAt.y = this->actor.world.pos.y + 30.0f;
sCameraNextAt.z = this->actor.world.pos.z;
sCameraNextEye.x = (Math_SinS(player->actor.shape.rot.y) * -130.0f) + player->actor.world.pos.x;
sCameraNextEye.z = (Math_CosS(player->actor.shape.rot.y) * -130.0f) + player->actor.world.pos.z;
sCameraNextEye.y = player->actor.world.pos.y + 55.0f;
sCameraAtMaxVel = sCameraEyeMaxVel = sZeroVec;
sCsState++;
this->timer = 133;
}
break;
case DEATH_MUSIC:
Math_SmoothStepToF(&sCameraEyeMaxVel.x, 1.5f, 0.3f, 0.05f, 0.015f);
sCameraEyeMaxVel.z = sCameraEyeMaxVel.x;
sCameraEyeMaxVel.y = sCameraEyeMaxVel.z;
sCameraAtMaxVel = sCameraEyeMaxVel;
this->timer--;
if (this->timer == 0) {
Gameplay_ClearCamera(globalCtx, sCsCamera);
sCsCamera = 0;
func_80064534(globalCtx, &globalCtx->csCtx);
Gameplay_ChangeCameraStatus(globalCtx, MAIN_CAM, CAM_STAT_ACTIVE);
camera->eyeNext = camera->eye = sCameraEye;
camera->at = sCameraAt;
func_8002DF54(globalCtx, &this->actor, 7);
sCsState++;
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);
for (i = 2, sp7C = 2; i > 0; i--) {
if (Math_Vec3f_DistXYZ(&sWarpPos[i], &player->actor.world.pos) <
Math_Vec3f_DistXYZ(&sWarpPos[i - 1], &player->actor.world.pos)) {
sp7C = i - 1;
}
}
Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_RU1, sWarpPos[sp7C].x, sWarpPos[sp7C].y,
sWarpPos[sp7C].z, 0, 0, 0, 0);
}
case DEATH_FINISH:
Rand_CenteredFloat(0.5f);
globalCtx->envCtx.fillScreen = false;
break;
}
if (sCsCamera != 0) {
Math_SmoothStepToF(&sCameraEye.x, sCameraNextEye.x, 0.3f, sCameraEyeMaxVel.x, 0.15f);
Math_SmoothStepToF(&sCameraEye.y, sCameraNextEye.y, 0.3f, sCameraEyeMaxVel.y, 0.15f);
Math_SmoothStepToF(&sCameraEye.z, sCameraNextEye.z, 0.3f, sCameraEyeMaxVel.z, 0.15f);
Math_SmoothStepToF(&sCameraAt.x, sCameraNextAt.x, 0.3f, sCameraAtMaxVel.x, 0.15f);
Math_SmoothStepToF(&sCameraAt.y, sCameraNextAt.y, 0.3f, sCameraAtMaxVel.y, 0.15f);
Math_SmoothStepToF(&sCameraAt.z, sCameraNextAt.z, 0.3f, sCameraAtMaxVel.z, 0.15f);
Gameplay_CameraSetAtEye(globalCtx, sCsCamera, &sCameraAt, &sCameraEye);
}
SkelAnime_Update(&this->skelAnime);
Math_SmoothStepToF(&this->actor.shape.yOffset, -480.0f, 1.0f, 30.0f, 0.0f);
Math_SmoothStepToS(&this->vaBodySpinRate, 0, 1, 0xC8, 0);
Math_SmoothStepToS(&this->vaCamRotMod, 0, 1, 0xC8, 0);
Math_SmoothStepToS(&this->bodyGlow, 200, 1, 10, 0);
if (globalCtx->envCtx.screenFillColor[3] != 0) {
globalCtx->envCtx.screenFillColor[3] -= 50;
}
Math_SmoothStepToF(&this->actor.speedXZ, 0.0f, 1.0f, 0.5f, 0.0f);
this->actor.shape.rot.y += this->vaBodySpinRate;
this->unk_1AC += this->vaCamRotMod;
this->unk_1A0 = (Math_CosS(this->unk_1AC) * 0.1f) + 1.0f;
this->unk_1A4 = (Math_SinS(this->unk_1AC) * 0.05f) + 1.0f;
}
void BossVa_SetupSupportIntro(BossVa* this, GlobalContext* globalCtx) {
Animation_Change(&this->skelAnime, &gBarinadeSupportAttachedAnim, 0.0f, 0.0f,
Animation_GetLastFrame(&gBarinadeSupportAttachedAnim), ANIMMODE_LOOP_INTERP, 0.0f);
this->timer = 0;
BossVa_SetupAction(this, BossVa_SupportIntro);
}
void BossVa_SupportIntro(BossVa* this, GlobalContext* globalCtx) {
BossVa_AttachToBody(this);
if (sCsState == BOSSVA_BATTLE) {
BossVa_SetupSupportAttached(this, globalCtx);
} else if (sCsState >= INTRO_REVERSE_CAMERA) {
this->timer++;
if ((this->timer % 2) == 0) {
BossVa_Spark(globalCtx, this, 2, 90, 5.0f, 0.0f, SPARK_BODY, ((this->timer & 0x20) >> 5) + 1, true);
}
SkelAnime_Update(&this->skelAnime);
Math_SmoothStepToF(&this->skelAnime.playSpeed, 1.0f, 1.0f, 0.05f, 0.0f);
if (Rand_ZeroOne() < 0.1f) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_BL_SPARK - SFX_FLAG);
}
}
}
void BossVa_SetupSupportAttached(BossVa* this, GlobalContext* globalCtx) {
Animation_Change(&this->skelAnime, &gBarinadeSupportAttachedAnim, 1.0f, 0.0f,
Animation_GetLastFrame(&gBarinadeSupportAttachedAnim), ANIMMODE_LOOP, 0.0f);
this->timer = this->actor.params * 10;
BossVa_SetupAction(this, BossVa_SupportAttached);
}
void BossVa_SupportAttached(BossVa* this, GlobalContext* globalCtx) {
this->timer++;
if (sBodyState & 0x7F) {
Actor_SetColorFilter(&this->actor, 0, 255, 0, 12);
if (Rand_ZeroOne() > 0.5f) {
Animation_Change(&this->skelAnime, &gBarinadeSupportDamage1Anim, 1.0f, 0.0f,
Animation_GetLastFrame(&gBarinadeSupportDamage1Anim), ANIMMODE_ONCE, 0.0f);
} else {
Animation_Change(&this->skelAnime, &gBarinadeSupportDamage2Anim, 1.0f, 0.0f,
Animation_GetLastFrame(&gBarinadeSupportDamage2Anim), ANIMMODE_ONCE, 0.0f);
}
}
if (SkelAnime_Update(&this->skelAnime)) {
Animation_Change(&this->skelAnime, &gBarinadeSupportAttachedAnim, 1.0f, 0.0f,
Animation_GetLastFrame(&gBarinadeSupportAttachedAnim), ANIMMODE_LOOP, 0.0f);
}
BossVa_AttachToBody(this);
if (Rand_ZeroOne() < 0.1f) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_BL_SPARK - SFX_FLAG);
}
if (this->colliderSph.base.acFlags & AC_HIT) {
BossVa_SetupSupportCut(this, globalCtx);
} else {
if (this->actor.colorFilterTimer == 0) {
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->colliderSph.base);
}
if ((this->timer % 2) == 0) {
BossVa_Spark(globalCtx, this, 1, 100, 5.0f, 0.0f, SPARK_BODY, ((this->timer & 0x20) >> 5) + 1, true);
}
}
}
void BossVa_SetupSupportCut(BossVa* this, GlobalContext* globalCtx) {
s32 stumpParams = this->actor.params + BOSSVA_STUMP_1;
sBodyState++;
sFightPhase++;
Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_BOSS_VA, this->armTip.x, this->armTip.y + 20.0f, this->armTip.z,
0, this->actor.shape.rot.y, 0, stumpParams);
Camera_AddQuake(&globalCtx->mainCamera, 2, 11, 8);
this->burst = false;
this->timer2 = 0;
BossVa_SetupAction(this, BossVa_SupportCut);
}
void BossVa_SupportCut(BossVa* this, GlobalContext* globalCtx) {
BossVa* vaBody = GET_BODY(this);
f32 lastFrame;
BossVa_AttachToBody(this);
if (this->onCeiling) {
lastFrame = Animation_GetLastFrame(&gBarinadeSupportCutAnim);
this->onCeiling = false;
this->timer = (s32)(Rand_ZeroOne() * 10.0f) + 5;
SkelAnime_Free(&this->skelAnime, globalCtx);
SkelAnime_InitFlex(globalCtx, &this->skelAnime, &gBarinadeCutSupportSkel, &gBarinadeSupportCutAnim, NULL, NULL,
0);
Animation_Change(&this->skelAnime, &gBarinadeSupportCutAnim, 1.0f, 0.0f, lastFrame, ANIMMODE_ONCE, 0.0f);
sBodyState = 0;
GET_BODY(this)->actor.shape.yOffset -= 60.0f;
switch (this->actor.params) {
case BOSSVA_SUPPORT_1:
GET_BODY(this)->actor.world.rot.x += 0x4B0;
break;
case BOSSVA_SUPPORT_2:
GET_BODY(this)->actor.world.rot.x -= 0x258;
GET_BODY(this)->actor.world.rot.z -= 0x4E2;
break;
case BOSSVA_SUPPORT_3:
GET_BODY(this)->actor.world.rot.x -= 0x258;
GET_BODY(this)->actor.world.rot.z += 0x4E2;
break;
}
}
Math_SmoothStepToS(&this->headRot.x, vaBody->vaBodySpinRate * -3, 1, 0x4B0, 0);
if (SkelAnime_Update(&this->skelAnime)) {
lastFrame = Animation_GetLastFrame(&gBarinadeSupportDetachedAnim);
Animation_Change(&this->skelAnime, &gBarinadeSupportDetachedAnim, 1.0f, 0.0f, lastFrame, ANIMMODE_LOOP_INTERP,
0.0f);
this->actor.flags &= ~ACTOR_FLAG_0;
}
if ((this->timer == 0) && (sCsState < DEATH_START)) {
this->timer = (s32)(Rand_ZeroOne() * 10.0f) + 10;
BossVa_BloodDroplets(globalCtx, &this->armTip, this->headRot.x, this->actor.shape.rot.y);
}
if (sCsState >= DEATH_START) {
Math_SmoothStepToF(&this->skelAnime.playSpeed, 0.0f, 0.3f, 0.25f, 0.125f);
}
switch (sCsState) {
case DEATH_SHELL_BURST:
sCameraEye = sCameraNextEye;
sCameraAt = sCameraNextAt;
Math_SmoothStepToF(&sCameraEye.x, sCameraNextAt.x, 1.0f, 10.0f, 0.0f);
Math_SmoothStepToF(&sCameraEye.z, sCameraNextAt.z, 1.0f, 10.0f, 0.0f);
sCameraEye.y += 20.0f;
sCsState++;
case DEATH_CORE_TUMORS:
case DEATH_CORE_DEAD:
case DEATH_CORE_BURST:
if (!this->burst) {
if ((globalCtx->gameplayFrames % 2) != 0) {
BossVa_Tumor(globalCtx, this, 1, (s16)Rand_CenteredFloat(5.0f) + 6, 7.0f, 5.0f, TUMOR_ARM,
(this->timer2 >> 3) + 1, true);
}
this->timer2++;
if (this->timer2 >= 32) {
this->burst++;
this->isDead = true;
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_BREAK2);
if (this->actor.params == BOSSVA_SUPPORT_3) {
sCsState++;
}
}
} else {
this->timer2--;
if (this->timer2 == 0) {
Actor_Kill(&this->actor);
}
}
break;
}
this->timer--;
}
void BossVa_SetupStump(BossVa* this, GlobalContext* globalCtx) {
Animation_Change(&this->skelAnime, &gBarinadeStumpAnim, 1.0f, 0.0f, Animation_GetLastFrame(&gBarinadeStumpAnim),
ANIMMODE_ONCE, 0.0f);
this->actor.flags &= ~ACTOR_FLAG_0;
BossVa_SetupAction(this, BossVa_Stump);
}
void BossVa_Stump(BossVa* this, GlobalContext* globalCtx) {
if (SkelAnime_Update(&this->skelAnime) && (Rand_ZeroOne() < 0.3f)) {
this->skelAnime.curFrame -= Rand_ZeroOne() * 3.0f;
}
if (sCsState >= DEATH_START) {
Actor_Kill(&this->actor);
}
}
void BossVa_SetupZapperIntro(BossVa* this, GlobalContext* globalCtx) {
f32 lastFrame = Animation_GetLastFrame(&gBarinadeZapperIdleAnim);
Animation_Change(&this->skelAnime, &gBarinadeZapperIdleAnim, 1.0f, lastFrame - 1.0f, lastFrame,
ANIMMODE_LOOP_INTERP, -6.0f);
this->actor.flags &= ~ACTOR_FLAG_0;
BossVa_SetupAction(this, BossVa_ZapperIntro);
}
void BossVa_ZapperIntro(BossVa* this, GlobalContext* globalCtx) {
BossVa_AttachToBody(this);
switch (sCsState) {
case INTRO_TITLE:
case INTRO_BRIGHTEN:
case INTRO_FINISH:
SkelAnime_Update(&this->skelAnime);
break;
case BOSSVA_BATTLE:
BossVa_SetupZapperAttack(this, globalCtx);
break;
}
Math_SmoothStepToS(&this->unk_1F2, this->actor.shape.rot.y - this->actor.shape.rot.x, 1, 0x2EE, 0);
Math_SmoothStepToS(&this->unk_1F0, this->skelAnime.jointTable[7].z, 1, 0x2EE, 0);
}
void BossVa_SetupZapperAttack(BossVa* this, GlobalContext* globalCtx) {
f32 lastFrame = Animation_GetLastFrame(&gBarinadeZapperIdleAnim);
Animation_Change(&this->skelAnime, &gBarinadeZapperIdleAnim, 1.0f, lastFrame - 1.0f, lastFrame,
ANIMMODE_LOOP_INTERP, -6.0f);
this->actor.flags &= ~ACTOR_FLAG_0;
BossVa_SetupAction(this, BossVa_ZapperAttack);
}
void BossVa_ZapperAttack(BossVa* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
EnBoom* boomerang;
Actor* boomTarget;
s16 yaw;
s16 sp98;
s16 sp96;
s16 sp94;
s16 tmp17;
s16 sp90 = 0x1F4;
s16 sp8E;
u32 sp88;
Vec3f sp7C;
s32 pad3;
f32 sp74;
s32 i;
s16 sp6E;
s16 sp6C;
f32 sp68;
f32 sp64;
f32 sp60;
f32 sp5C;
s16 sp5A;
s16 sp58;
s16 sp56;
s16 sp54;
f32 sp50;
boomerang = BossVa_FindBoomerang(globalCtx);
if ((boomerang == NULL) || (boomerang->moveTo == NULL) || (boomerang->moveTo == &player->actor)) {
sp7C = player->actor.world.pos;
sp7C.y += 10.0f;
sp8E = 0x3E80;
} else {
sp74 = R_UPDATE_RATE * 0.5f;
sp8E = 0x4650;
boomTarget = boomerang->moveTo;
sp7C = boomerang->actor.world.pos;
sp6C = boomerang->actor.world.rot.y;
sp56 = boomerang->actor.world.rot.x;
for (i = boomerang->returnTimer; i >= 3; i--) {
sp6E = Math_Vec3f_Yaw(&sp7C, &boomTarget->focus.pos);
sp5A = sp6C - sp6E;
sp58 = Math_Vec3f_Pitch(&sp7C, &boomTarget->focus.pos);
sp54 = sp56 - sp58;
sp50 = (200.0f - Math_Vec3f_DistXYZ(&sp7C, &boomTarget->focus.pos)) * 0.005f;
if (sp50 < 0.12f) {
sp50 = 0.12f;
}
if (sp5A < 0) {
sp5A = -sp5A;
}
if (sp54 < 0) {
sp54 = -sp54;
}
Math_ScaledStepToS(&sp6C, sp6E, sp5A * sp50);
Math_ScaledStepToS(&sp56, sp58, sp54 * sp50);
sp68 = -Math_SinS(sp56) * 12.0f;
sp5C = Math_CosS(sp56) * 12.0f;
sp64 = Math_SinS(sp6C) * sp5C;
sp60 = Math_CosS(sp6C);
sp7C.x += sp64 * sp74;
sp7C.y += sp68 * sp74;
sp7C.z += sp60 * sp5C * sp74;
}
sp90 = 0x3E80;
}
SkelAnime_Update(&this->skelAnime);
BossVa_AttachToBody(this);
if (sFightPhase >= PHASE_4) {
BossVa_SetupZapperEnraged(this, globalCtx);
return;
}
if (sBodyState & 0x7F) {
BossVa_SetupZapperDamaged(this, globalCtx);
return;
}
if ((sFightPhase < PHASE_4) && (GET_BODY(this)->actor.speedXZ != 0.0f)) {
BossVa_SetupZapperHold(this, globalCtx);
return;
}
sp98 = Math_Vec3f_Yaw(&sp7C, &this->armTip);
tmp17 = sp98 - this->actor.shape.rot.y;
if ((sp8E >= ABS(tmp17) || this->burst) && !(sBodyState & 0x80) && !(player->stateFlags1 & 0x04000000)) {
if (!this->burst) {
sp94 = sp98 - this->actor.shape.rot.y;
if (ABS(sp94) > 0x1770) {
sp94 = (sp94 > 0) ? 0x1770 : -0x1770;
}
tmp17 = Math_SmoothStepToS(&this->unk_1E6, sp94, 1, 0x6D6, 0);
sp88 = ABS(tmp17);
sp94 = sp98 - sp94;
if (ABS(sp94) > 0x1770) {
sp94 = (sp94 > 0) ? 0x1770 : -0x1770;
}
tmp17 = Math_SmoothStepToS(&this->unk_1EC, sp94, 1, 0x6D6, 0);
sp88 += ABS(tmp17);
yaw = Math_Vec3f_Yaw(&this->zapHeadPos, &sp7C);
tmp17 = Math_SmoothStepToS(&this->unk_1F2, yaw - 0x4000, 1, 0x9C4, 0);
sp88 += ABS(tmp17);
sp96 = this->actor.shape.rot.x + this->skelAnime.jointTable[1].z + this->skelAnime.jointTable[2].z +
this->skelAnime.jointTable[3].z + this->skelAnime.jointTable[4].z + this->skelAnime.jointTable[5].z;
yaw = Math_Vec3f_Pitch(&sp7C, &this->zapNeckPos);
tmp17 = Math_SmoothStepToS(&this->unk_1EA, yaw - sp96, 1, 0xFA0, 0);
sp88 += ABS(tmp17);
yaw = Math_Vec3f_Pitch(&this->zapHeadPos, &sp7C);
tmp17 = Math_SmoothStepToS(&this->unk_1F0, -yaw, 1, 0xFA0, 0);
sp88 += ABS(tmp17);
this->skelAnime.playSpeed = 0.0f;
if (Math_SmoothStepToF(&this->skelAnime.curFrame, 0.0f, 1.0f, 2.0f, 0.0f) == 0.0f) {
if (sp88 < sp90) {
this->timer2 = 0;
this->burst++;
this->unk_1D8 = sp7C;
}
if (Rand_ZeroOne() < 0.1f) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_BL_SPARK - SFX_FLAG);
}
}
}
} else {
if (this->burst || (this->timer2 < 0)) {
if (this->colliderLightning.base.atFlags & AT_HIT) {
if (this->timer2 > 0) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_HIT_RINK);
BossVa_SetSparkEnv(globalCtx);
this->timer2 = -1;
GET_BODY(this)->onCeiling = 6; // not used by body
}
} else if (this->timer2 > 0) {
this->timer2 = 0;
}
if ((this->timer2 < 0) && (player->stateFlags1 & 0x4000000)) {
BossVa_Spark(globalCtx, this, 1, 30, 0.0f, 0.0f, SPARK_LINK, 0.0f, true);
}
}
Math_SmoothStepToS(&this->unk_1E6, 0, 1, 0x6D6, 0);
Math_SmoothStepToS(&this->unk_1EC, 0, 1, 0x6D6, 0);
Math_SmoothStepToS(&this->unk_1EA, 0, 1, 0x6D6, 0);
Math_SmoothStepToS(&this->unk_1F2, this->actor.shape.rot.y - this->actor.shape.rot.x, 1, 0x6D6, 0);
Math_SmoothStepToS(&this->unk_1F0, this->skelAnime.jointTable[7].z, 1, 0x6D6, 0);
Math_SmoothStepToF(&this->skelAnime.playSpeed, 1.0f, 1.0f, 0.05f, 0.0f);
this->burst = false;
}
if (this->burst && (this->burst != 2)) { // burst can never be 2
if (this->timer2 >= 32) {
if (this->timer2 == 32) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_THUNDER);
}
BossVa_Spark(globalCtx, this, 2, 110, 15.0f, 15.0f, SPARK_BLAST, 5.0f, true);
BossVa_Spark(globalCtx, this, 2, 110, 15.0f, 15.0f, SPARK_BLAST, 6.0f, true);
BossVa_Spark(globalCtx, this, 2, 110, 15.0f, 15.0f, SPARK_BLAST, 7.0f, true);
CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->colliderLightning.base);
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->colliderLightning.base);
} else {
BossVa_Spark(globalCtx, this, 2, 50, 15.0f, 0.0f, SPARK_BODY, (this->timer2 >> 3) + 1, true);
if (this->timer2 == 30) {
BossVa_SetSparkEnv(globalCtx);
}
if (this->timer2 == 20) {
Vec3f sp44 = this->zapHeadPos;
BossVa_SpawnZapperCharge(globalCtx, sVaEffects, this, &sp44, &this->headRot, 100, 0);
}
}
this->timer2++;
if (this->timer2 >= 40) {
this->burst = false;
}
}
}
void BossVa_SetupZapperDamaged(BossVa* this, GlobalContext* globalCtx) {
if (Rand_ZeroOne() > 0.5f) {
Animation_Change(&this->skelAnime, &gBarinadeZapperDamage1Anim, 0.5f, 0.0f,
Animation_GetLastFrame(&gBarinadeZapperDamage1Anim), ANIMMODE_ONCE_INTERP, 4.0f);
} else {
Animation_Change(&this->skelAnime, &gBarinadeZapperDamage2Anim, 0.5f, 0.0f,
Animation_GetLastFrame(&gBarinadeZapperDamage2Anim), ANIMMODE_ONCE_INTERP, 4.0f);
}
Actor_SetColorFilter(&this->actor, 0, 255, 0, 12);
this->burst = false;
BossVa_SetupAction(this, BossVa_ZapperDamaged);
}
void BossVa_ZapperDamaged(BossVa* this, GlobalContext* globalCtx) {
BossVa_AttachToBody(this);
Math_SmoothStepToS(&this->unk_1E6, 0, 1, 0xFA0, 0);
Math_SmoothStepToS(&this->unk_1E4, 0, 1, 0xFA0, 0);
Math_SmoothStepToS(&this->unk_1EC, 0, 1, 0xFA0, 0);
Math_SmoothStepToS(&this->unk_1EA, 0, 1, 0xFA0, 0);
Math_SmoothStepToS(&this->unk_1F2, this->actor.shape.rot.y - this->actor.shape.rot.x, 1, 0x2EE, 0);
Math_SmoothStepToS(&this->unk_1F0, this->skelAnime.jointTable[7].z, 1, 0x2EE, 0);
if (SkelAnime_Update(&this->skelAnime)) {
if (sFightPhase >= PHASE_4) {
BossVa_SetupZapperEnraged(this, globalCtx);
} else {
BossVa_SetupZapperAttack(this, globalCtx);
}
}
}
void BossVa_SetupZapperDeath(BossVa* this, GlobalContext* globalCtx) {
f32 lastFrame = Animation_GetLastFrame(&gBarinadeZapperIdleAnim);
Animation_Change(&this->skelAnime, &gBarinadeZapperIdleAnim, Rand_ZeroOne() + 0.25f, Rand_ZeroOne() * 3.0f,
lastFrame, ANIMMODE_LOOP_INTERP, -6.0f);
this->burst = false;
this->timer2 = (this->actor.params * -6) + 18;
this->unk_1B0 = 0;
BossVa_SetupAction(this, BossVa_ZapperDeath);
}
void BossVa_ZapperDeath(BossVa* this, GlobalContext* globalCtx) {
f32 sp3C = 55.0f;
f32 tmpf1;
f32 tmpf2;
BossVa_AttachToBody(this);
if (((globalCtx->gameplayFrames % 32) == 0) && (sCsState <= DEATH_BODY_TUMORS)) {
this->unk_1E8 = Rand_CenteredFloat(0x4000);
this->unk_1EE = Rand_CenteredFloat(0x4000);
this->unk_1F4 = (s16)Rand_CenteredFloat(0x4000) + this->actor.shape.rot.y - this->actor.shape.rot.x;
} else {
Math_SmoothStepToF(&this->skelAnime.playSpeed, 0.0f, 1.0f, 0.025f, 0.0f);
}
SkelAnime_Update(&this->skelAnime);
Math_SmoothStepToS(&this->unk_1E6, this->unk_1E8, 1, (s16)Rand_CenteredFloat(500.0f) + 0x1F4, 0);
Math_SmoothStepToS(&this->unk_1E4, 0, 1, 0x1F4, 0);
Math_SmoothStepToS(&this->unk_1EC, this->unk_1EE, 1, (s16)Rand_CenteredFloat(500.0f) + 0x1F4, 0);
Math_SmoothStepToS(&this->unk_1EA, 0, 1, 0x1F4, 0);
Math_SmoothStepToS(&this->unk_1F2, this->unk_1F4, 1, (s16)Rand_CenteredFloat(500.0f) + 0x1F4, 0);
switch (sCsState) {
case DEATH_ZAPPER_2:
sp3C = -55.0f;
case DEATH_ZAPPER_1:
case DEATH_ZAPPER_3:
if (!this->burst) {
if (((this->actor.params == BOSSVA_ZAPPER_1) && (this->timer2 < 16)) ||
((this->actor.params == BOSSVA_ZAPPER_2) && (this->timer2 < 24)) ||
(this->actor.params == BOSSVA_ZAPPER_3)) {
if ((this->timer2 % 2) == 0 && (this->timer2 >= 0)) {
if (this->timer2 < 8) {
BossVa_Tumor(globalCtx, this, 1, (s16)Rand_CenteredFloat(5.0f) + 0xD, 0.0f, 0.0f, TUMOR_ARM,
0.6f, true);
} else {
BossVa_Tumor(globalCtx, this, 1, (s16)Rand_CenteredFloat(5.0f) + 6, 0.0f, 7.0f, TUMOR_ARM,
(this->timer2 >> 3) + 1, true);
}
BossVa_Spark(globalCtx, this, 2, 50, 15.0f, 0.0f, SPARK_BODY, (this->timer2 >> 3) + 1, true);
}
this->timer2++;
if (this->timer2 >= 32) {
this->burst++;
this->isDead = true;
BossVa_SetDeathEnv(globalCtx);
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_BREAK2);
}
} else {
this->burst++;
this->isDead = true;
this->timer2 = 32;
sCsState++;
}
if ((this->actor.params - BOSSVA_ZAPPER_1 + DEATH_ZAPPER_1) == sCsState) {
sCameraAt.x = this->zapNeckPos.x;
sCameraEye.y = sCameraAt.y = this->zapNeckPos.y;
sCameraAt.z = this->zapNeckPos.z;
sCameraEye.x = (Math_CosS(-(this->actor.shape.rot.y + this->unk_1B0)) * sp3C) + this->zapNeckPos.x;
sCameraEye.z = (Math_SinS(-(this->actor.shape.rot.y + this->unk_1B0)) * sp3C) + this->zapNeckPos.z;
this->unk_1B0 += 0x15E;
}
} else {
this->timer2--;
if (this->timer2 == 0) {
if (this->actor.params == BOSSVA_ZAPPER_3) {
sCsState++;
}
Actor_Kill(&this->actor);
}
}
break;
}
}
void BossVa_SetupZapperEnraged(BossVa* this, GlobalContext* globalCtx) {
f32 lastFrame = Animation_GetLastFrame(&gBarinadeZapperIdleAnim);
Animation_Change(&this->skelAnime, &gBarinadeZapperIdleAnim, 1.0f, lastFrame - 1.0f, lastFrame,
ANIMMODE_LOOP_INTERP, -6.0f);
this->burst = false;
BossVa_SetupAction(this, BossVa_ZapperEnraged);
}
void BossVa_ZapperEnraged(BossVa* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
s32 pad;
s16 tmp16;
s16 sp6C;
s16 sp6A;
s16 sp68;
s16 yaw;
u32 sp60;
Vec3f sp54 = player->actor.world.pos;
sp54.y += 10.0f;
SkelAnime_Update(&this->skelAnime);
BossVa_AttachToBody(this);
if (sFightPhase >= PHASE_DEATH) {
BossVa_SetupZapperDeath(this, globalCtx);
return;
}
if (sBodyState & 0x7E) {
BossVa_SetupZapperDamaged(this, globalCtx);
return;
}
sp54.y += 25.0;
sp6C = Math_Vec3f_Yaw(&sp54, &this->armTip);
tmp16 = sp6C - this->actor.shape.rot.y;
if ((ABS(tmp16) <= 0x4650 || this->burst) && !(sBodyState & 0x80) && !(player->stateFlags1 & 0x04000000)) {
if (!this->burst) {
sp68 = sp6C - this->actor.shape.rot.y;
if (ABS(sp68) > 0x1770) {
sp68 = (sp68 > 0) ? 0x1770 : -0x1770;
}
tmp16 = Math_SmoothStepToS(&this->unk_1E6, sp68, 1, 0xDAC, 0);
sp60 = ABS(tmp16);
sp68 = sp6C - sp68;
if (ABS(sp68) > 0x1770) {
sp68 = sp68 > 0 ? 0x1770 : -0x1770;
}
tmp16 = Math_SmoothStepToS(&this->unk_1EC, sp68, 1, 0xDAC, 0);
sp60 += ABS(tmp16);
yaw = Math_Vec3f_Yaw(&this->zapHeadPos, &sp54);
tmp16 = Math_SmoothStepToS(&this->unk_1F2, yaw - 0x4000, 1, 0xEA6, 0);
sp60 += ABS(tmp16);
sp6A = this->actor.shape.rot.x + this->skelAnime.jointTable[1].x + this->skelAnime.jointTable[2].x +
this->skelAnime.jointTable[3].x + this->skelAnime.jointTable[4].x + this->skelAnime.jointTable[5].x;
yaw = Math_Vec3f_Pitch(&sp54, &this->zapNeckPos);
tmp16 = Math_SmoothStepToS(&this->unk_1EA, yaw - sp6A, 1, 0x1B58, 0);
sp60 += ABS(tmp16);
yaw = Math_Vec3f_Pitch(&this->zapHeadPos, &sp54);
tmp16 = Math_SmoothStepToS(&this->unk_1F0, -yaw, 1, 0x1B58, 0);
sp60 += ABS(tmp16);
this->skelAnime.playSpeed = 0.0f;
if ((Math_SmoothStepToF(&this->skelAnime.curFrame, 0.0f, 1.0f, 3.0f, 0.0f) == 0.0f) && (sp60 < 0x258)) {
this->timer2 = 0;
this->burst++;
this->unk_1D8 = sp54;
if (Rand_ZeroOne() < 0.1f) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_BL_SPARK - SFX_FLAG);
}
}
}
} else {
if (this->burst || (this->timer2 < 0)) {
if (this->colliderLightning.base.atFlags & AT_HIT) {
if (this->timer2 > 0) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_HIT_RINK);
BossVa_SetSparkEnv(globalCtx);
this->timer2 = -1;
GET_BODY(this)->onCeiling = 6; // not used by body
}
} else if (this->timer2 > 0) {
this->timer2 = 0;
}
if ((this->timer2 < 0) && (player->stateFlags1 & 0x4000000)) {
BossVa_Spark(globalCtx, this, 1, 30, 0.0f, 0, SPARK_LINK, 0.0f, true);
}
}
Math_SmoothStepToS(&this->unk_1E6, 0, 1, 0xEA6, 0);
Math_SmoothStepToS(&this->unk_1EC, 0, 1, 0xEA6, 0);
Math_SmoothStepToS(&this->unk_1EA, 0, 1, 0xEA6, 0);
Math_SmoothStepToS(&this->unk_1F2, this->actor.shape.rot.y - this->actor.shape.rot.x, 1, 0xEA6, 0);
Math_SmoothStepToS(&this->unk_1F0, this->skelAnime.jointTable[7].z, 1, 0xEA6, 0);
Math_SmoothStepToF(&this->skelAnime.playSpeed, 1.0f, 1.0f, 0.05f, 0.0f);
this->burst = false;
}
if (this->burst && (this->burst != 2)) { // burst can never be 2
if (this->timer2 >= 16) {
if (this->timer2 == 18) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_THUNDER);
}
BossVa_Spark(globalCtx, this, 2, 110, 15.0f, 15.0f, SPARK_BLAST, 5.0f, true);
BossVa_Spark(globalCtx, this, 2, 110, 15.0f, 15.0f, SPARK_BLAST, 6.0f, true);
BossVa_Spark(globalCtx, this, 2, 110, 15.0f, 15.0f, SPARK_BLAST, 7.0f, true);
CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->colliderLightning.base);
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->colliderLightning.base);
} else {
BossVa_Spark(globalCtx, this, 2, 50, 15.0f, 0.0f, SPARK_BODY, (this->timer2 >> 1) + 1, true);
if (this->timer2 == 14) {
BossVa_SetSparkEnv(globalCtx);
}
if (this->timer2 == 4) {
Vec3f sp48 = this->zapHeadPos;
BossVa_SpawnZapperCharge(globalCtx, sVaEffects, this, &sp48, &this->headRot, 100, 0);
}
}
this->timer2++;
if (this->timer2 >= 24) {
this->burst = false;
}
}
}
void BossVa_SetupZapperHold(BossVa* this, GlobalContext* globalCtx) {
Animation_Change(&this->skelAnime, &gBarinadeZapperDamage2Anim, 0.0f, 0.0f,
Animation_GetLastFrame(&gBarinadeZapperDamage2Anim), ANIMMODE_ONCE_INTERP, -6.0f);
this->burst = false;
BossVa_SetupAction(this, BossVa_ZapperHold);
}
void BossVa_ZapperHold(BossVa* this, GlobalContext* globalCtx) {
SkelAnime_Update(&this->skelAnime);
BossVa_AttachToBody(this);
Math_SmoothStepToS(&this->unk_1E6, 0, 1, 0x1770, 0);
Math_SmoothStepToS(&this->unk_1E4, 0, 1, 0x1770, 0);
Math_SmoothStepToS(&this->unk_1EC, 0, 1, 0x1770, 0);
Math_SmoothStepToS(&this->unk_1EA, 0, 1, 0x1770, 0);
Math_SmoothStepToS(&this->unk_1F2, this->actor.shape.rot.y - 0x4000, 1, 0x2710, 0);
Math_SmoothStepToS(&this->unk_1F0, this->skelAnime.jointTable[7].z - 0x1388, 1, 0x1770, 0);
if (GET_BODY(this)->actor.speedXZ == 0.0f) {
BossVa_SetupZapperAttack(this, globalCtx);
}
}
void BossVa_SetupBariIntro(BossVa* this, GlobalContext* globalCtx) {
Animation_Change(&this->skelAnime, &gBarinadeBariAnim, 1.0f, 0.0f, Animation_GetLastFrame(&gBarinadeBariAnim),
ANIMMODE_LOOP, 0.0f);
this->unk_1A0 = 60.0f;
this->unk_1A4 = Rand_ZeroOne() * 360.0f;
this->timer2 = 64;
this->unk_1F0 = 120;
this->unk_1A8 = 0.0f;
this->actor.world.pos.x = sInitPosOffsets[this->actor.params + 10].x + this->actor.home.pos.x;
this->actor.world.pos.y = sInitPosOffsets[this->actor.params + 10].y + this->actor.home.pos.y;
this->actor.world.pos.z = sInitPosOffsets[this->actor.params + 10].z + this->actor.home.pos.z;
this->timer = 45;
this->actor.flags &= ~ACTOR_FLAG_0;
BossVa_SetupAction(this, BossVa_BariIntro);
}
void BossVa_BariIntro(BossVa* this, GlobalContext* globalCtx) {
Vec3f sp54 = this->actor.home.pos;
f32 sp50 = 40.0f;
s16 sp4E;
s16 tmp;
if (this->actor.home.pos.y >= 0.0f) {
sp54.y += 25.0f;
}
this->unk_1A4 += Rand_ZeroOne() * 0.25f;
switch (sCsState) {
case INTRO_LOOK_BARI:
if (this->actor.params == BOSSVA_BARI_UPPER_1) {
func_8002DF54(globalCtx, &this->actor, 1);
if (Math_SmoothStepToF(&this->actor.world.pos.y, 60.0f, 0.3f, 1.0f, 0.15f) == 0.0f) {
this->timer--;
if (this->timer == 0) {
sCsState++;
}
}
}
this->actor.shape.rot.x = 0;
break;
case INTRO_REVERSE_CAMERA:
case INTRO_SUPPORT_CAMERA:
case INTRO_BODY_SOUND:
case INTRO_LOOK_SUPPORT:
if (this->actor.params != BOSSVA_BARI_UPPER_1) {
Math_SmoothStepToF(&this->actor.world.pos.y,
sInitPosOffsets[this->actor.params + 10].y + this->actor.home.pos.y, 0.3f, 1.0f,
0.15f);
this->actor.world.pos.x += (Math_SinF(this->unk_1A4 * 0.25f) * 0.5f);
} else {
Math_SmoothStepToF(&this->actor.world.pos.y, 60.0f, 0.3f, 1.0f, 0.15f);
}
this->actor.world.pos.y += Math_SinF(this->unk_1A4) * (2.0f - Math_SinF(this->unk_1A4));
break;
case INTRO_CALL_BARI:
case INTRO_ATTACH_BARI:
if ((this->timer2 > 15) && (this->timer < 0)) {
Math_SmoothStepToF(&this->actor.world.pos.x, sp54.x, 1.0f, 6.5f, 0.0f);
Math_SmoothStepToF(&this->actor.world.pos.y, sp54.y, 1.0f, 6.5f, 0.0f);
Math_SmoothStepToF(&this->actor.world.pos.z, sp54.z, 1.0f, 6.5f, 0.0f);
sp50 = Math_Vec3f_DistXYZ(&sp54, &this->actor.world.pos);
if (sp50 <= 60.0f) {
tmp = Math_SmoothStepToS(&this->actor.shape.rot.x, this->actor.home.rot.x, 1, 0x7D0, 0);
sp4E = ABS(tmp);
tmp = Math_SmoothStepToS(&this->actor.shape.rot.y, this->actor.home.rot.y, 1, 0x7D0, 0);
sp4E += ABS(tmp);
if ((sp50 == 0.0f) && (sp4E == 0)) {
if (!this->isDead) {
if (this->actor.params >= BOSSVA_BARI_LOWER_1) {
if (this->actor.params == BOSSVA_BARI_LOWER_1) {
sBodyBari[0]++;
} else {
sBodyBari[this->actor.params - BOSSVA_BARI_UPPER_1]++;
}
} else {
sBodyBari[this->actor.params - BOSSVA_BARI_UPPER_1 + 1]++;
}
this->timer = -30;
this->isDead++;
} else {
this->timer++;
if (this->timer == 0) {
Actor_Kill(&this->actor);
}
}
return;
}
}
}
case INTRO_UNUSED_CALL_BARI:
this->timer--;
if (this->timer == 0) {
this->timer2 = 0;
} else {
func_80035844(&GET_BODY(this)->actor.world.pos, &this->actor.world.pos, &this->actor.world.rot, false);
this->unk_1A0 = Math_Vec3f_DistXYZ(&GET_BODY(this)->actor.world.pos, &this->actor.world.pos);
if (sp50 > 30.0f) {
BossVa_Spark(globalCtx, this, 1, 80, 15.0f, 0.0f, SPARK_BARI, 1.0f, true);
}
}
break;
case BOSSVA_BATTLE:
this->timer++;
if (this->timer == 0) {
Actor_Kill(&this->actor);
}
return;
case INTRO_TITLE:
case INTRO_BRIGHTEN:
case INTRO_FINISH:
break;
}
if (((globalCtx->gameplayFrames % 4) == 0) && (sCsState < INTRO_ATTACH_BARI)) {
BossVa_Spark(globalCtx, this, 1, 70, 25.0f, 20.0f, SPARK_BARI, 2.0f, true);
}
if (Rand_ZeroOne() < 0.1f) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_BL_SPARK - SFX_FLAG);
}
}
void BossVa_SetupBariPhase3Attack(BossVa* this, GlobalContext* globalCtx) {
Animation_Change(&this->skelAnime, &gBarinadeBariAnim, 1.0f, 0.0f, Animation_GetLastFrame(&gBarinadeBariAnim),
ANIMMODE_LOOP, 0.0f);
this->timer2 = 0x80;
this->unk_1F0 = 0x78;
this->unk_1A0 = 60.0f;
this->unk_1A8 = 0.0f;
this->actor.flags &= ~ACTOR_FLAG_0;
BossVa_SetupAction(this, BossVa_BariPhase3Attack);
}
void BossVa_BariPhase3Attack(BossVa* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
EnBoom* boomerang;
Vec3f sp54 = GET_BODY(this)->unk_1D8;
s16 sp52;
s32 pad;
this->unk_1A4 += Rand_ZeroOne() * 0.5f;
sp52 = this->timer2 & 0x1FF;
if ((globalCtx->gameplayFrames % 128) == 0) {
this->vaBariUnused.x = (s16)(Rand_ZeroOne() * 100.0f) + 100;
}
Math_SmoothStepToS(&this->vaBariUnused.z, this->vaBariUnused.x, 1, 0x1E, 0);
this->vaBariUnused.y += this->vaBariUnused.z;
if ((this->colliderLightning.base.atFlags & AT_HIT) || (this->colliderSph.base.atFlags & AT_HIT)) {
if ((this->colliderLightning.base.at == &player->actor) || (this->colliderSph.base.at == &player->actor)) {
func_8002F71C(globalCtx, &this->actor, 8.0f, GET_BODY(this)->actor.yawTowardsPlayer, 8.0f);
Audio_PlayActorSound2(&player->actor, NA_SE_PL_BODY_HIT);
this->colliderSph.base.at = NULL;
this->colliderLightning.base.at = NULL;
}
this->colliderLightning.base.atFlags &= ~AT_HIT;
this->colliderSph.base.atFlags &= ~AT_HIT;
}
if (this->colliderSph.base.acFlags & AC_HIT) {
this->colliderSph.base.acFlags &= ~AC_HIT;
if ((this->colliderSph.base.ac->id == ACTOR_EN_BOOM) && (sp52 >= 128)) {
boomerang = (EnBoom*)this->colliderSph.base.ac;
boomerang->returnTimer = 0;
boomerang->moveTo = &player->actor;
boomerang->actor.world.rot.y = boomerang->actor.yawTowardsPlayer;
Audio_PlayActorSound2(&this->actor, NA_SE_IT_SHIELD_REFLECT_SW);
}
}
this->actor.world.pos.x = (Math_SinS(this->actor.world.rot.y) * this->unk_1A0) + sp54.x;
this->actor.world.pos.z = (Math_CosS(this->actor.world.rot.y) * this->unk_1A0) + sp54.z;
Math_SmoothStepToF(&this->actor.world.pos.y, 4.0f, 1.0f, 2.0f, 0.0f);
this->actor.world.pos.y += 2.0f * Math_SinF(this->unk_1A4);
this->actor.world.rot.x = Math_Vec3f_Pitch(&sp54, &this->actor.world.pos);
Math_SmoothStepToF(&this->unk_1A0, 160.0f, 1.0f, 2.0f, 0.0f);
Math_SmoothStepToS(&this->actor.shape.rot.x, 0, 1, 0x5DC, 0);
if (!(this->timer2 & 0x200)) {
this->unk_1AC = 0xBB8;
} else {
this->unk_1AC = -0xBB8;
}
if (sp52 >= 128) {
BossVa_Spark(globalCtx, this, 1, 75, 15.0f, 7.0f, SPARK_TETHER, 1.0f, true);
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->colliderSph.base);
sPhase3StopMoving = false;
} else {
sPhase3StopMoving = true;
}
CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->colliderLightning.base);
CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->colliderSph.base);
if ((globalCtx->gameplayFrames % 4) == 0) {
Math_SmoothStepToS(&this->unk_1F0, 0x78, 1, 0xA, 0);
}
if (Rand_ZeroOne() < 0.1f) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_BL_SPARK - SFX_FLAG);
}
this->actor.world.rot.y += this->unk_1AC;
if (sBodyState & 0x7F) {
BossVa_SetupBariPhase3Stunned(this, globalCtx);
}
}
void BossVa_SetupBariPhase2Attack(BossVa* this, GlobalContext* globalCtx) {
Animation_Change(&this->skelAnime, &gBarinadeBariAnim, 1.0f, 0.0f, Animation_GetLastFrame(&gBarinadeBariAnim),
ANIMMODE_LOOP, 0.0f);
this->timer2 = 0x40;
this->unk_1F0 = 0x78;
this->unk_1A0 = 60.0f;
this->unk_1A8 = 0.0f;
this->actor.flags &= ~ACTOR_FLAG_0;
BossVa_SetupAction(this, BossVa_BariPhase2Attack);
}
void BossVa_BariPhase2Attack(BossVa* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
EnBoom* boomerang;
Vec3f sp54 = GET_BODY(this)->unk_1D8;
s16 sp52;
s16 sp50;
f32 sp4C;
s32 pad;
this->unk_1A4 += Rand_ZeroOne() * 0.5f;
sp52 = this->timer2 & 0x1FF;
if ((globalCtx->gameplayFrames % 128) == 0) {
this->vaBariUnused.x = (s16)(Rand_ZeroOne() * 100.0f) + 100;
}
sp50 = (sFightPhase * 70) - 280;
Math_SmoothStepToS(&this->vaBariUnused.z, this->vaBariUnused.x, 1, 0x1E, 0);
this->vaBariUnused.y += this->vaBariUnused.z;
if (sKillBari != 0) {
sKillBari--;
BossVa_KillBari(this, globalCtx);
return;
}
if ((this->colliderLightning.base.atFlags & AT_HIT) || (this->colliderSph.base.atFlags & AT_HIT)) {
if ((this->colliderLightning.base.at == &player->actor) || (this->colliderSph.base.at == &player->actor)) {
func_8002F71C(globalCtx, &this->actor, 8.0f, GET_BODY(this)->actor.yawTowardsPlayer, 8.0f);
Audio_PlayActorSound2(&player->actor, NA_SE_PL_BODY_HIT);
this->colliderSph.base.at = NULL;
this->colliderLightning.base.at = NULL;
}
this->colliderLightning.base.atFlags &= ~AT_HIT;
this->colliderSph.base.atFlags &= ~AT_HIT;
}
Math_SmoothStepToF(&this->actor.world.pos.y, 4.0f, 1.0f, 2.0f, 0.0f);
this->actor.world.rot.x = Math_Vec3f_Pitch(&sp54, &this->actor.world.pos);
if ((globalCtx->gameplayFrames % 8) == 0) {
Math_SmoothStepToS(&this->unk_1F0, 0x28, 1, 0xA, 0);
BossVa_Spark(globalCtx, this, 1, this->unk_1F0, 25.0f, 20.0f, 2, 2.0f, true);
}
if (!(sPhase2Timer & 0x100) && (GET_BODY(this)->actor.colorFilterTimer == 0)) {
sp4C = 200.0f;
BossVa_Spark(globalCtx, this, 1, 125, 15.0f, 7.0f, SPARK_TETHER, 1.0f, true);
this->actor.flags &= ~ACTOR_FLAG_0;
if (this->actor.params & 1) {
sp4C = -200.0f;
}
Math_SmoothStepToF(&this->unk_1A0, (Math_SinS(sPhase2Timer * 0x190) * sp4C) + 320.0f, 1.0f, 10.0f, 0.0f);
Math_SmoothStepToS(&this->unk_1AC, sp50 + 0x1F4, 1, 0x3C, 0);
this->actor.world.pos.y += 2.0f * Math_SinF(this->unk_1A4);
if (this->colliderSph.base.acFlags & AC_HIT) {
this->colliderSph.base.acFlags &= ~AC_HIT;
if ((this->colliderSph.base.ac->id == ACTOR_EN_BOOM) && (sp52 >= 64)) {
boomerang = (EnBoom*)this->colliderSph.base.ac;
boomerang->returnTimer = 0;
boomerang->moveTo = &player->actor;
boomerang->actor.world.rot.y = boomerang->actor.yawTowardsPlayer;
Audio_PlayActorSound2(&this->actor, NA_SE_IT_SHIELD_REFLECT_SW);
}
}
CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->colliderLightning.base);
CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->colliderSph.base);
} else {
this->actor.flags |= ACTOR_FLAG_0;
Math_SmoothStepToS(&this->unk_1AC, sp50 + 150, 1, 0x3C, 0);
if (GET_BODY(this)->actor.colorFilterTimer == 0) {
Math_SmoothStepToF(&this->unk_1A0, 180.0f, 1.0f, 1.5f, 0.0f);
} else {
this->unk_1AC = 0;
if (this->actor.colorFilterTimer == 0) {
Actor_SetColorFilter(&this->actor, 0, 255, 0x2000, GET_BODY(this)->actor.colorFilterTimer);
}
}
this->actor.world.pos.y += Math_SinF(this->unk_1A4) * 4.0f;
if (this->colliderSph.base.acFlags & AC_HIT) {
BossVa_KillBari(this, globalCtx);
}
}
Math_SmoothStepToS(&this->actor.shape.rot.x, 0, 1, 0x5DC, 0);
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->colliderSph.base);
if ((globalCtx->gameplayFrames % 4) == 0) {
Math_SmoothStepToS(&this->unk_1F0, 0x78, 1, 0xA, 0);
}
if (Rand_ZeroOne() < 0.1f) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_BL_SPARK - SFX_FLAG);
}
if (GET_BODY(this)->actor.colorFilterTimer == 0) {
if (!(this->timer2 & 0x400)) {
this->actor.world.rot.y += this->unk_1AC;
} else {
this->actor.world.rot.y -= this->unk_1AC;
}
this->actor.world.pos.x = (Math_SinS(this->actor.world.rot.y) * this->unk_1A0) + sp54.x;
this->actor.world.pos.z = (Math_CosS(this->actor.world.rot.y) * this->unk_1A0) + sp54.z;
}
}
void BossVa_SetupBariPhase3Stunned(BossVa* this, GlobalContext* globalCtx) {
this->actor.flags |= ACTOR_FLAG_0;
this->timer = GET_BODY(this)->timer;
Actor_SetColorFilter(&this->actor, 0, 255, 0x2000, this->timer);
BossVa_SetupAction(this, BossVa_BariPhase3Stunned);
}
void BossVa_BariPhase3Stunned(BossVa* this, GlobalContext* globalCtx) {
s32 sp44_pad;
Vec3f sp40 = GET_BODY(this)->unk_1D8;
this->actor.world.rot.x = Math_Vec3f_Pitch(&GET_BODY(this)->actor.world.pos, &this->actor.world.pos);
if (this->colliderSph.base.acFlags & AC_HIT) {
BossVa_KillBari(this, globalCtx);
return;
}
this->unk_1A4 += Rand_ZeroOne() * 0.5f;
Math_SmoothStepToF(&this->actor.world.pos.y, 4.0f, 1.0f, 2.0f, 0.0f);
this->actor.world.pos.y += Math_SinF(this->unk_1A4) * 3.0f;
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->colliderSph.base);
if ((globalCtx->gameplayFrames % 4) == 0) {
Math_SmoothStepToS(&this->unk_1F0, 0x28, 1, 0xA, 0);
BossVa_Spark(globalCtx, this, 1, this->unk_1F0, 25.0f, 20.0f, SPARK_BARI, 2.0f, true);
}
this->timer--;
this->actor.world.rot.x = Math_Vec3f_Pitch(&sp40, &this->actor.world.pos);
if (this->timer <= 0) {
if (this->timer == 0) {
this->timer2 = 0;
} else {
BossVa_Spark(globalCtx, this, 1, 85, 15.0f, 0.0f, SPARK_TETHER, 1.0f, true);
if (this->timer2 >= 0x10) {
this->actor.flags &= ~ACTOR_FLAG_0;
this->timer2 = 0x80;
BossVa_SetupAction(this, BossVa_BariPhase3Attack);
}
}
}
}
void BossVa_SetupBariDeath(BossVa* this) {
this->actor.flags &= ~ACTOR_FLAG_0;
this->timer = 30;
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BALINADE_BL_DEAD);
this->isDead++;
BossVa_SetupAction(this, BossVa_BariDeath);
}
void BossVa_BariDeath(BossVa* this, GlobalContext* globalCtx) {
this->timer--;
if (this->timer == 0) {
Actor_Kill(&this->actor);
}
}
void BossVa_SetupDoor(BossVa* this, GlobalContext* globalCtx) {
if (sCsState >= INTRO_SPAWN_BARI) {
sDoorState = 100;
}
this->actor.flags &= ~ACTOR_FLAG_0;
BossVa_SetupAction(this, BossVa_Door);
}
void BossVa_Door(BossVa* this, GlobalContext* globalCtx) {
if (sDoorState == 29) {
Audio_PlayActorSound2(&this->actor, NA_SE_EV_BUYODOOR_CLOSE);
}
if (sCsState <= INTRO_DOOR_SHUT) {
if (sDoorState < 100) {
sDoorState += 8;
} else {
sDoorState = 100;
}
}
}
void BossVa_Update(Actor* thisx, GlobalContext* globalCtx2) {
GlobalContext* globalCtx = globalCtx2;
BossVa* this = (BossVa*)thisx;
EnBoom* boomerang;
s32 i;
this->actionFunc(this, globalCtx);
switch (this->actor.params) {
case BOSSVA_BODY:
if (this->colliderBody.base.acFlags & AC_HIT) {
this->colliderBody.base.acFlags &= ~AC_HIT;
if (this->colliderBody.base.ac->id == ACTOR_EN_BOOM) {
boomerang = (EnBoom*)this->colliderBody.base.ac;
boomerang->returnTimer = 0;
}
}
BossVa_UpdateEffects(globalCtx);
for (i = 2; i >= 0; i--) {
if ((globalCtx->envCtx.adjAmbientColor[i] - 1) > 0) {
globalCtx->envCtx.adjAmbientColor[i] -= 1;
} else {
globalCtx->envCtx.adjAmbientColor[i] = 0;
}
if ((globalCtx->envCtx.adjLight1Color[i] - 10) > 0) {
globalCtx->envCtx.adjLight1Color[i] -= 10;
} else {
globalCtx->envCtx.adjLight1Color[i] = 0;
}
if ((globalCtx->envCtx.adjFogColor[i] - 10) > 0) {
globalCtx->envCtx.adjFogColor[i] -= 10;
} else {
globalCtx->envCtx.adjFogColor[i] = 0;
}
}
if (this->onCeiling > 0) {
this->onCeiling--; // not used by body
}
break;
default:
this->timer2++;
this->actor.focus.pos = this->actor.world.pos;
this->actor.focus.pos.y += 45.0f;
this->unk_1D8.y = (Math_CosS(this->timer2 * 0xFA4) * 0.24f) + 0.76f;
this->unk_1D8.x = (Math_SinS(this->timer2 * 0xFA4) * 0.2f) + 1.0f;
break;
case BOSSVA_SUPPORT_1:
case BOSSVA_SUPPORT_2:
case BOSSVA_SUPPORT_3:
case BOSSVA_ZAPPER_1:
case BOSSVA_ZAPPER_2:
case BOSSVA_ZAPPER_3:
case BOSSVA_DOOR:
break;
}
}
s32 BossVa_BodyOverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot,
void* thisx) {
BossVa* this = (BossVa*)thisx;
s32 pad;
OPEN_DISPS(globalCtx->state.gfxCtx);
if (limbIndex == 20) {
gDPPipeSync(POLY_OPA_DISP++);
gSPSegment(POLY_OPA_DISP++, 0x08,
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, 0, 8, 16, 1, 0,
(globalCtx->gameplayFrames * -2) % 64, 16, 16));
gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, this->bodyGlow);
Matrix_RotateX(-M_PI / 2, MTXMODE_APPLY);
} else if ((limbIndex >= 10) && (limbIndex < 20)) {
rot->x -= 0x4000;
*dList = NULL;
} else if (limbIndex == 6) {
Matrix_Scale(this->unk_1A4, this->unk_1A4, this->unk_1A4, MTXMODE_APPLY);
} else if (limbIndex == 61) {
Matrix_Scale(this->unk_1A0, this->unk_1A0, this->unk_1A0, MTXMODE_APPLY);
} else if (limbIndex == 7) {
rot->x -= 0xCCC;
}
CLOSE_DISPS(globalCtx->state.gfxCtx);
return false;
}
void BossVa_BodyPostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) {
BossVa* this = (BossVa*)thisx;
Vec3f sp78 = { 0.0f, 0.0f, 0.0f };
s32 pad;
OPEN_DISPS(globalCtx->state.gfxCtx);
if (limbIndex == 6) {
if (sFightPhase < PHASE_3) {
sp78.x = -1000.0f;
} else {
sp78.x = 200.0f;
}
Matrix_MultVec3f(&sp78, &this->unk_1D8);
} else if ((limbIndex >= 10) && (limbIndex < 20) && (sBodyBari[limbIndex - 10] != 0)) {
if (((limbIndex >= 16) || (limbIndex == 10)) && (sFightPhase <= PHASE_3)) {
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_008BB8);
} else if ((limbIndex >= 11) && (sFightPhase <= PHASE_2)) {
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_008BB8);
}
if (sCsState >= DEATH_START) {
sp78.x = Rand_CenteredFloat(530.0f);
sp78.y = Rand_CenteredFloat(530.0f);
sp78.z = -60.0f;
}
Matrix_MultVec3f(&sp78, &this->effectPos[limbIndex - 10]);
} else if (limbIndex == 25) {
gSPSegment(POLY_XLU_DISP++, 0x09,
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, (globalCtx->gameplayFrames * 10) % 128, 16, 32, 1, 0,
(globalCtx->gameplayFrames * 5) % 128, 16, 32));
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_008D70);
} else if ((*dList != NULL) && (limbIndex >= 29) && (limbIndex < 56)) {
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, *dList);
} else if ((limbIndex == 24) && (sCsState < DEATH_START)) {
sp78.x = (this->actor.shape.yOffset + 450.0f) + -140.0f;
Matrix_MultVec3f(&sp78, &this->unk_280);
sp78.x = 200.0f;
Matrix_MultVec3f(&sp78, &this->unk_274);
}
if ((limbIndex == 7) && (sCsState >= DEATH_START)) {
sp78.x = Rand_CenteredFloat(320.0f) + -250.0f;
sp78.y = Rand_CenteredFloat(320.0f);
sp78.z = Rand_CenteredFloat(320.0f);
if (sp78.y < 0.0f) {
sp78.y -= 150.0f;
} else {
sp78.y += 150.0f;
}
if (sp78.z < 0.0f) {
sp78.z -= 150.0f;
} else {
sp78.z += 150.0f;
}
Matrix_MultVec3f(&sp78, &this->unk_274);
}
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
s32 BossVa_SupportOverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot,
void* thisx) {
BossVa* this = (BossVa*)thisx;
if (!this->onCeiling && (limbIndex == 4)) {
rot->z += this->headRot.x;
}
return false;
}
void BossVa_SupportPostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) {
BossVa* this = (BossVa*)thisx;
Vec3f sp20 = { 0.0f, 0.0f, 0.0f };
s32 pad;
if (this->onCeiling) {
switch (limbIndex) {
case 4:
Matrix_MultVec3f(&sZeroVec, &this->actor.focus.pos);
Collider_UpdateSpheres(0, &this->colliderSph);
break;
case 7:
Matrix_MultVec3f(&sZeroVec, &this->armTip);
sp20.x = ((this->timer & 0x1F) >> 1) * -40.0f;
sp20.y = ((this->timer & 0x1F) >> 1) * -7.0f;
Matrix_MultVec3f(&sp20, &this->effectPos[0]);
break;
case 9:
sp20.x = ((this->timer & 0x1F) >> 1) * -60.0f;
sp20.y = ((this->timer & 0x1F) >> 1) * -45.0f;
Matrix_MultVec3f(&sp20, &this->effectPos[1]);
break;
}
} else {
switch (limbIndex) {
case 5:
Matrix_MultVec3f(&sZeroVec, &this->armTip);
break;
case 8:
sp20.x = (this->timer2 & 7) * 90.0f;
Matrix_MultVec3f(&sp20, &this->effectPos[2]);
break;
case 9:
sp20.x = (this->timer2 & 7) * 50.0f;
Matrix_MultVec3f(&sp20, &this->effectPos[1]);
break;
case 10:
sp20.x = (this->timer2 & 7) * 46.0f;
Matrix_MultVec3f(&sp20, &this->effectPos[0]);
break;
}
}
}
s32 BossVa_ZapperOverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot,
void* thisx) {
BossVa* this = (BossVa*)thisx;
MtxF zapperMtx;
switch (limbIndex) {
case 4:
rot->y += this->unk_1E6;
rot->z += this->unk_1E4;
break;
case 5:
rot->y += this->unk_1EC;
rot->z += this->unk_1EA;
break;
case 7:
Matrix_Translate(pos->x, pos->y, pos->z, MTXMODE_APPLY);
Matrix_Get(&zapperMtx);
Matrix_MtxFToZYXRotS(&zapperMtx, &sZapperRot, false);
Matrix_RotateX(-sZapperRot.x * (M_PI / 0x8000), MTXMODE_APPLY);
Matrix_RotateY(-sZapperRot.y * (M_PI / 0x8000), MTXMODE_APPLY);
Matrix_RotateZ(-sZapperRot.z * (M_PI / 0x8000), MTXMODE_APPLY);
Matrix_RotateY(this->unk_1F2 * (M_PI / 0x8000), MTXMODE_APPLY);
Matrix_RotateZ(this->unk_1F0 * (M_PI / 0x8000), MTXMODE_APPLY);
pos->x = pos->y = pos->z = 0.0f;
rot->x = rot->y = rot->z = 0;
break;
}
return false;
}
void BossVa_ZapperPostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) {
BossVa* this = (BossVa*)thisx;
Vec3f sp70 = { 0.0f, 0.0f, 0.0f };
Vec3f sp64 = { 15.0f, 0.0f, 0.0f };
Vec3f sp58 = { -15.0f, 0.0f, 0.0f };
Vec3f sp4C = { 15.0f, 0.0f, 0.0f };
Vec3f sp40 = { -15.0f, 0.0f, 0.0f };
s16 sp3E;
s16 sp3C;
switch (limbIndex) {
case 3:
sp70.x = (this->timer2 & 7) * 30.0f;
Matrix_MultVec3f(&sp70, &this->effectPos[0]);
break;
case 4:
Matrix_MultVec3f(&sZeroVec, &this->armTip);
sp70.x = (this->timer2 & 7) * 30.0f;
Matrix_MultVec3f(&sp70, &this->effectPos[1]);
break;
case 5:
Matrix_MultVec3f(&sZeroVec, &this->zapNeckPos);
sp70.x = (this->timer2 & 7) * 46.0f;
Matrix_MultVec3f(&sp70, &this->effectPos[2]);
break;
case 7:
Matrix_MultVec3f(&sZeroVec, &this->zapHeadPos);
sp70.x = (this->timer2 & 7) * 46.0f;
Matrix_MultVec3f(&sp70, &this->effectPos[3]);
sp70.x = 20.0f;
Matrix_MultVec3f(&sp70, &this->effectPos[9]);
func_80035844(&this->effectPos[9], &this->unk_1D8, &this->headRot, false);
sp3E = this->headRot.x;
sp3C = this->headRot.y;
Matrix_Push();
Matrix_Translate(this->effectPos[9].x, this->effectPos[9].y, this->effectPos[9].z, MTXMODE_NEW);
Matrix_RotateZYX(sp3E, sp3C, 0, MTXMODE_APPLY);
sp70.x = 0.0f;
if (sFightPhase >= PHASE_4) {
sp70.z = ((this->timer2 - 16) & 7) * 120.0f;
} else {
sp70.z = ((this->timer2 - 32) & 0xF) * 80.0f;
}
sp4C.z = sp40.z = sp70.z += 40.0f;
sp70.z += 50.0f;
Matrix_MultVec3f(&sp70, &this->effectPos[4]);
if (sFightPhase >= PHASE_4) {
sp70.z -= 33.0f;
if (sp70.z < 0.0f) {
sp70.z = 0.0f;
}
Matrix_MultVec3f(&sp70, &this->effectPos[6]);
sp70.z -= 33.0f;
if (sp70.z < 0.0f) {
sp70.z = 0.0f;
}
} else {
sp70.z -= 22.0f;
if (sp70.z < 0.0f) {
sp70.z = 0.0f;
}
Matrix_MultVec3f(&sp70, &this->effectPos[6]);
sp70.z -= 22.0f;
if (sp70.z < 0.0f) {
sp70.z = 0.0f;
}
}
Matrix_MultVec3f(&sp70, &this->effectPos[5]);
Matrix_MultVec3f(&sp64, &this->colliderLightning.dim.quad[1]);
Matrix_MultVec3f(&sp58, &this->colliderLightning.dim.quad[0]);
Matrix_MultVec3f(&sp4C, &this->colliderLightning.dim.quad[3]);
Matrix_MultVec3f(&sp40, &this->colliderLightning.dim.quad[2]);
Collider_SetQuadVertices(&this->colliderLightning, &this->colliderLightning.dim.quad[0],
&this->colliderLightning.dim.quad[1], &this->colliderLightning.dim.quad[2],
&this->colliderLightning.dim.quad[3]);
Matrix_Pop();
break;
}
}
s32 BossVa_BariOverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot,
void* thisx) {
BossVa* this = (BossVa*)thisx;
switch (limbIndex) {
case 2:
*dList = NULL;
break;
case 3:
Matrix_Scale(this->unk_1D8.x, 1.0f, this->unk_1D8.x, MTXMODE_APPLY);
break;
case 4:
Matrix_Scale(1.0f, this->unk_1D8.y, 1.0f, MTXMODE_APPLY);
break;
}
return false;
}
void BossVa_BariPostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) {
BossVa* this = (BossVa*)thisx;
OPEN_DISPS(globalCtx->state.gfxCtx);
if (limbIndex == 2) {
gSPSegment(POLY_XLU_DISP++, 0x0A,
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, (globalCtx->gameplayFrames * 10) % 32, 16, 32, 1, 0,
(globalCtx->gameplayFrames * -5) % 32, 16, 32));
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_000FA0);
} else if ((limbIndex == 3) || (limbIndex == 4)) {
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, *dList);
}
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
void BossVa_Draw(Actor* thisx, GlobalContext* globalCtx) {
s16* paramsPtr; // This stack slot is almost certainly actually globalCtx2, but can't make it match
BossVa* this = (BossVa*)thisx;
Vec3f spBC;
Vec3f spB0 = { 0.0f, 45.0f, 0.0f };
Vec3f spA4 = { 0.4f, 0.4f, 0.4f };
Vec3f sp98 = { 15.0f, 40.0f, 0.0f };
Vec3f sp8C = { -15.0f, 40.0f, 0.0f };
Vec3f sp80 = { 15.0f, 40.0f, 0.0f };
Vec3f sp74 = { -15.0f, 40.0f, 0.0f };
Color_RGBA8 unused = { 250, 250, 230, 200 };
OPEN_DISPS(globalCtx->state.gfxCtx);
func_80093D18(globalCtx->state.gfxCtx);
paramsPtr = &this->actor.params;
func_80093D84(globalCtx->state.gfxCtx);
switch (this->actor.params) {
case BOSSVA_BODY:
if (globalCtx->envCtx.adjFogNear != 0) {
globalCtx->envCtx.adjFogNear += 0x15E;
if (globalCtx->envCtx.adjFogNear > 0) {
globalCtx->envCtx.adjFogNear = 0;
}
}
if (globalCtx->envCtx.adjFogFar != 0) {
globalCtx->envCtx.adjFogFar += 0x15E;
if (globalCtx->envCtx.adjFogFar > 0) {
globalCtx->envCtx.adjFogFar = 0;
}
}
if (!this->isDead) {
gSPSegment(POLY_OPA_DISP++, 0x08,
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, 0, 8, 16, 1, 0,
(globalCtx->gameplayFrames * -10) % 16, 16, 16));
gSPSegment(POLY_OPA_DISP++, 0x09,
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, (globalCtx->gameplayFrames * -10) % 32, 16,
0x20, 1, 0, (globalCtx->gameplayFrames * -5) % 32, 16, 32));
SkelAnime_DrawOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable,
BossVa_BodyOverrideLimbDraw, BossVa_BodyPostLimbDraw, this);
}
break;
case BOSSVA_SUPPORT_1:
case BOSSVA_SUPPORT_2:
case BOSSVA_SUPPORT_3:
if (!this->isDead) {
SkelAnime_DrawFlexOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable,
this->skelAnime.dListCount, BossVa_SupportOverrideLimbDraw,
BossVa_SupportPostLimbDraw, this);
}
break;
case BOSSVA_ZAPPER_1:
case BOSSVA_ZAPPER_2:
case BOSSVA_ZAPPER_3:
if (!this->isDead) {
SkelAnime_DrawFlexOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable,
this->skelAnime.dListCount, BossVa_ZapperOverrideLimbDraw,
BossVa_ZapperPostLimbDraw, this);
}
break;
case BOSSVA_STUMP_1:
case BOSSVA_STUMP_2:
case BOSSVA_STUMP_3:
SkelAnime_DrawFlexOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable,
this->skelAnime.dListCount, NULL, NULL, NULL);
break;
default:
if (!this->isDead) {
SkelAnime_DrawOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable,
BossVa_BariOverrideLimbDraw, BossVa_BariPostLimbDraw, this);
Collider_UpdateSpheres(0, &this->colliderSph);
if (sCsState < BOSSVA_BATTLE) {
spBC = GET_BODY(this)->actor.world.pos;
} else {
spBC = GET_BODY(this)->unk_1D8;
}
Matrix_MultVec3f(&sZeroVec, &this->effectPos[1]);
Matrix_Push();
Matrix_Translate(spBC.x, spBC.y, spBC.z, MTXMODE_NEW);
Matrix_RotateZYX(this->actor.world.rot.x, this->actor.world.rot.y, 0, MTXMODE_APPLY);
sp80.z = sp74.z = this->unk_1A0;
spB0.z = (this->timer2 & 0xF) * (this->unk_1A0 * 0.0625f);
Matrix_MultVec3f(&spB0, &this->effectPos[0]);
Matrix_MultVec3f(&sp98, &this->colliderLightning.dim.quad[1]);
Matrix_MultVec3f(&sp8C, &this->colliderLightning.dim.quad[0]);
Matrix_MultVec3f(&sp80, &this->colliderLightning.dim.quad[3]);
Matrix_MultVec3f(&sp74, &this->colliderLightning.dim.quad[2]);
Collider_SetQuadVertices(&this->colliderLightning, &this->colliderLightning.dim.quad[0],
&this->colliderLightning.dim.quad[1], &this->colliderLightning.dim.quad[2],
&this->colliderLightning.dim.quad[3]);
Matrix_Pop();
spBC = this->actor.world.pos;
spBC.y += 9.0f;
if (this->actor.colorFilterTimer != 0) {
func_80026A6C(globalCtx);
}
func_80033C30(&spBC, &spA4, 0xFF, globalCtx);
if (this->actor.colorFilterTimer != 0) {
Color_RGBA8 blue = { 0, 0, 255, 255 };
func_80026860(globalCtx, &blue, this->actor.colorFilterTimer, this->actor.colorFilterParams & 0xFF);
}
}
break;
case BOSSVA_DOOR:
break;
}
if (*paramsPtr == BOSSVA_BODY) {
BossVa_DrawEffects(sVaEffects, globalCtx);
} else if (*paramsPtr == BOSSVA_DOOR) {
BossVa_DrawDoor(globalCtx, sDoorState);
}
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
static s32 sUnkValue = 0x009B0000; // Unreferenced? Possibly a color
void BossVa_UpdateEffects(GlobalContext* globalCtx) {
BossVaEffect* effect = sVaEffects;
Player* player = GET_PLAYER(globalCtx);
s16 spB6;
s16 i;
f32 floorY;
s32 padAC;
s16 pitch;
s16 yaw;
BossVa* refActor2;
BossVa* refActor;
Vec3f sp94;
CollisionPoly* sp90;
f32 pad8C;
Vec3f sp80;
CollisionPoly* sp7C;
f32 pad78;
f32 pad74;
for (i = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) {
if (effect->type != VA_NONE) {
effect->timer--;
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 == VA_LARGE_SPARK) || (effect->type == VA_SMALL_SPARK)) {
refActor = effect->parent;
effect->rot.z += (s16)(Rand_ZeroOne() * 0x4E20) + 0x2000;
effect->rot.y += (s16)(Rand_ZeroOne() * 0x2710) + 0x2000;
if ((effect->mode == SPARK_TETHER) || (effect->mode == SPARK_UNUSED)) {
pitch = effect->rot.x - Math_Vec3f_Pitch(&refActor->actor.world.pos, &GET_BODY(refActor)->unk_1D8);
pad8C = Math_SinS(refActor->actor.world.rot.y);
effect->pos.x = refActor->actor.world.pos.x - (effect->offset.x * pad8C);
pad74 = Math_CosS(refActor->actor.world.rot.y);
effect->pos.z = refActor->actor.world.pos.z - (effect->offset.x * pad74);
pad78 = Math_CosS(-pitch);
effect->pos.y = (effect->offset.y * pad78) + refActor->actor.world.pos.y;
} else if ((effect->mode == SPARK_BARI) || (effect->mode == SPARK_BODY)) {
effect->pos.x = effect->offset.x + refActor->actor.world.pos.x;
effect->pos.y = effect->offset.y + refActor->actor.world.pos.y;
effect->pos.z = effect->offset.z + refActor->actor.world.pos.z;
} else {
spB6 = Rand_ZeroFloat(ARRAY_COUNT(player->bodyPartsPos) - 0.1f);
effect->pos.x = player->bodyPartsPos[spB6].x + Rand_CenteredFloat(10.0f);
effect->pos.y = player->bodyPartsPos[spB6].y + Rand_CenteredFloat(15.0f);
effect->pos.z = player->bodyPartsPos[spB6].z + Rand_CenteredFloat(10.0f);
}
if (effect->timer < 100) {
effect->primColor[3] -= 50;
if (effect->primColor[3] < 0) {
effect->primColor[3] = 0;
effect->timer = 0;
effect->type = VA_NONE;
}
}
}
if (effect->type == VA_BLAST_SPARK) {
effect->rot.z += (s16)(Rand_ZeroOne() * 0x4E20) + 0x4000;
if (effect->timer < 100) {
effect->primColor[3] -= 50;
if (effect->primColor[3] < 0) {
effect->primColor[3] = 0;
effect->timer = 0;
effect->type = VA_NONE;
}
}
}
if (effect->type == VA_SPARK_BALL) {
refActor2 = effect->parent;
effect->rot.z += (s16)(Rand_ZeroOne() * 0x2710) + 0x24A8;
effect->pos.x = effect->offset.x + refActor2->actor.world.pos.x;
effect->pos.y =
refActor2->actor.world.pos.y + 310.0f + (refActor2->actor.shape.yOffset * refActor2->actor.scale.y);
effect->pos.z = effect->offset.z + refActor2->actor.world.pos.z;
effect->mode = (effect->mode + 1) & 7;
if (effect->timer < 100) {
effect->primColor[3] -= 50;
if (effect->primColor[3] < 0) {
effect->primColor[3] = 0;
effect->timer = 0;
effect->type = VA_NONE;
}
}
}
if (effect->type == VA_ZAP_CHARGE) {
effect->mode = (effect->mode + 1) & 7;
effect->primColor[3] -= 20;
if (effect->primColor[3] <= 0) {
effect->primColor[3] = 0;
effect->timer = 0;
effect->type = VA_NONE;
}
}
if (effect->type == VA_BLOOD) {
if (effect->mode < BLOOD_SPOT) {
sp94 = effect->pos;
sp94.y -= effect->velocity.y + 4.0f;
floorY = BgCheck_EntityRaycastFloor1(&globalCtx->colCtx, &sp90, &sp94);
if ((sp90 != NULL) && (effect->pos.y <= floorY)) {
effect->mode = BLOOD_SPOT;
effect->pos.y = floorY + 1.0f;
if (sCsState <= DEATH_SHELL_BURST) {
effect->timer = 80;
} else {
effect->timer = 60000;
}
effect->accel = effect->velocity = sZeroVec;
}
if (!effect->timer) {
effect->type = VA_NONE;
}
} else {
if (effect->timer < 20) {
effect->envColor[3] = effect->timer * 5;
effect->primColor[3] = effect->timer * 10;
} else if (effect->timer > 50000) {
effect->timer++;
}
}
if (!effect->timer) {
effect->type = VA_NONE;
}
}
if (effect->type == VA_GORE) {
if (effect->mode == GORE_PERMANENT) {
sp80 = effect->pos;
sp80.y -= effect->velocity.y + 4.0f;
effect->rot.x += 0x1770;
floorY = BgCheck_EntityRaycastFloor1(&globalCtx->colCtx, &sp7C, &sp80);
if ((sp7C != NULL) && (effect->pos.y <= floorY)) {
effect->mode = GORE_FLOOR;
effect->timer = 30;
effect->pos.y = floorY + 1.0f;
effect->accel = effect->velocity = sZeroVec;
effect->rot.x = -0x4000;
}
if (!effect->timer) {
effect->type = VA_NONE;
}
} else if (effect->mode == GORE_FADING) {
if (effect->timer == 0) {
effect->type = VA_NONE;
}
} else {
Math_SmoothStepToF(&effect->scaleMod, 0.075f, 1.0f, 0.005f, 0.0f);
Math_SmoothStepToF(&effect->vaGorePulseRate, 0.0f, 0.6f, 0.005f, 0.0013f);
if ((globalCtx->gameplayFrames % 4) == 0) {
Math_SmoothStepToS(&effect->primColor[0], 95, 1, 1, 0);
}
}
effect->vaGorePulse += effect->vaGorePulseRate;
}
if (effect->type == VA_TUMOR) {
refActor = effect->parent;
effect->rot.z += 0x157C;
effect->envColor[3] = (s16)(Math_SinS(effect->rot.z) * 50.0f) + 80;
Math_SmoothStepToF(&effect->scale, effect->scaleMod, 1.0f, 0.01f, 0.005f);
effect->pos.x = effect->offset.x + refActor->actor.world.pos.x;
effect->pos.y = effect->offset.y + refActor->actor.world.pos.y;
effect->pos.z = effect->offset.z + refActor->actor.world.pos.z;
switch (effect->mode) {
case TUMOR_UNUSED:
if (effect->timer == 0) {
yaw = Math_Vec3f_Yaw(&refActor->actor.world.pos, &effect->pos);
effect->type = VA_NONE;
BossVa_BloodSplatter(globalCtx, effect, yaw, effect->scale * 4500.0f, 1);
BossVa_Gore(globalCtx, effect, yaw, effect->scale * 1.2f);
}
break;
case TUMOR_BODY:
case TUMOR_ARM:
if (refActor->burst) {
effect->type = VA_NONE;
yaw = Math_Vec3f_Yaw(&refActor->actor.world.pos, &effect->pos);
BossVa_BloodSplatter(globalCtx, effect, yaw, effect->scale * 4500.0f, 1);
BossVa_Gore(globalCtx, effect, yaw, effect->scale * 1.2f);
}
break;
}
}
}
}
}
void BossVa_DrawEffects(BossVaEffect* effect, GlobalContext* globalCtx) {
static void* sSparkBallTex[] = {
gBarinadeSparkBall1Tex, gBarinadeSparkBall2Tex, gBarinadeSparkBall3Tex, gBarinadeSparkBall4Tex,
gBarinadeSparkBall5Tex, gBarinadeSparkBall6Tex, gBarinadeSparkBall7Tex, gBarinadeSparkBall8Tex,
};
s16 i;
GraphicsContext* gfxCtx = globalCtx->state.gfxCtx;
u8 flag = 0;
BossVaEffect* effectHead = effect;
Camera* camera = Gameplay_GetCamera(globalCtx, sCsCamera);
OPEN_DISPS(gfxCtx);
for (i = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) {
if (effect->type == VA_LARGE_SPARK) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
func_80093D84(globalCtx->state.gfxCtx);
gDPSetEnvColor(POLY_XLU_DISP++, 130, 130, 30, 0);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_0156A0);
flag++;
}
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 230, 230, 230, effect->primColor[3]);
Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW);
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
Matrix_RotateZ((effect->rot.z / (f32)0x8000) * 3.1416f, MTXMODE_APPLY);
Matrix_Scale(effect->scale * 0.0185f, effect->scale * 0.0185f, 1.0f, MTXMODE_APPLY);
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_015710);
FrameInterpolation_RecordCloseChild();
}
}
effect = effectHead;
for (i = 0, flag = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) {
if (effect->type == VA_SPARK_BALL) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
func_80093D84(globalCtx->state.gfxCtx);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_011738);
flag++;
}
Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW);
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
Matrix_Scale(effect->scale, effect->scale, effect->scale, MTXMODE_APPLY);
Matrix_RotateZ((effect->rot.z / (f32)0x8000) * 3.1416f, MTXMODE_APPLY);
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gDPPipeSync(POLY_XLU_DISP++);
gSPSegment(POLY_XLU_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(sSparkBallTex[effect->mode]));
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, effect->primColor[0], effect->primColor[1], effect->primColor[2],
effect->primColor[3]);
gDPPipeSync(POLY_XLU_DISP++);
gDPSetEnvColor(POLY_XLU_DISP++, effect->envColor[0], effect->envColor[1], effect->envColor[2],
effect->envColor[3]);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_011768);
FrameInterpolation_RecordCloseChild();
}
}
effect = effectHead;
for (i = 0, flag = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) {
if (effect->type == VA_BLOOD) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
func_80093D84(globalCtx->state.gfxCtx);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_009430);
gSPSegment(POLY_XLU_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(gEffBubble1Tex));
flag++;
}
gDPPipeSync(POLY_XLU_DISP++);
gDPSetEnvColor(POLY_XLU_DISP++, 0, 100, 0, effect->envColor[3]);
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 0, 150, 0, effect->primColor[3]);
Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW);
if (effect->mode == BLOOD_SPOT) {
Matrix_RotateX(M_PI / 2, MTXMODE_APPLY);
} else {
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
}
Matrix_Scale(effect->scale, effect->scale, 1.0f, MTXMODE_APPLY);
gDPPipeSync(POLY_XLU_DISP++);
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_009468);
FrameInterpolation_RecordCloseChild();
}
}
effect = effectHead;
for (i = 0, flag = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) {
if (effect->type == VA_TUMOR) {
BossVa* parent = effect->parent;
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
func_80093D18(globalCtx->state.gfxCtx);
gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, effect->envColor[3]);
gSPDisplayList(POLY_OPA_DISP++, gBarinadeDL_0128B8);
flag++;
}
if ((effect->mode != TUMOR_BODY) || ((Math_Vec3f_DistXZ(&camera->eye, &effect->pos) -
Math_Vec3f_DistXZ(&camera->eye, &parent->actor.world.pos)) < 10.0f)) {
Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW);
Matrix_Scale(effect->scale, effect->scale, effect->scale, MTXMODE_APPLY);
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, gBarinadeDL_012948);
}
FrameInterpolation_RecordCloseChild();
}
}
effect = effectHead;
for (i = 0, flag = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) {
if (effect->type == VA_GORE) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
func_80093D18(globalCtx->state.gfxCtx);
gSPDisplayList(POLY_OPA_DISP++, gBarinadeDL_012BA0);
flag++;
}
gDPPipeSync(POLY_OPA_DISP++);
gDPSetEnvColor(POLY_OPA_DISP++, 255, 255, 255, effect->primColor[3]);
gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, effect->primColor[0], effect->primColor[1], effect->primColor[2],
effect->primColor[3]);
Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW);
Matrix_RotateZYX(effect->rot.x, effect->rot.y, 0, MTXMODE_APPLY);
Matrix_Scale(effect->scale, effect->scale, effect->scale, MTXMODE_APPLY);
Matrix_RotateX(effect->offset.x * 0.115f, MTXMODE_APPLY);
Matrix_RotateY(effect->offset.x * 0.13f, MTXMODE_APPLY);
Matrix_RotateZ(effect->offset.x * 0.1f, MTXMODE_APPLY);
Matrix_Scale(1.0f - effect->scaleMod, effect->scaleMod + 1.0f, 1.0f - effect->scaleMod, MTXMODE_APPLY);
Matrix_RotateZ(-(effect->offset.x * 0.1f), MTXMODE_APPLY);
Matrix_RotateY(-(effect->offset.x * 0.13f), MTXMODE_APPLY);
Matrix_RotateX(-(effect->offset.x * 0.115f), MTXMODE_APPLY);
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, gBarinadeDL_012C50);
FrameInterpolation_RecordCloseChild();
}
}
effect = effectHead;
for (i = 0, flag = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) {
if (effect->type == VA_ZAP_CHARGE) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
func_80093D84(globalCtx->state.gfxCtx);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_0135B0);
flag++;
}
gDPPipeSync(POLY_XLU_DISP++);
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 50, effect->primColor[3]);
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, effect->primColor[3]);
Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW);
Matrix_RotateZYX(effect->rot.x, effect->rot.y, 0, MTXMODE_APPLY);
Matrix_Scale(effect->scale, effect->scale, effect->scale, MTXMODE_APPLY);
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_013638);
FrameInterpolation_RecordCloseChild();
}
}
effect = effectHead;
for (i = 0, flag = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) {
if (effect->type == VA_BLAST_SPARK) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
func_80093C14(globalCtx->state.gfxCtx);
gDPSetEnvColor(POLY_XLU_DISP++, 130, 130, 30, 0);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_0156A0);
flag++;
}
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 230, 230, 230, effect->primColor[3]);
Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW);
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
Matrix_RotateZ((effect->rot.z / (f32)0x8000) * 3.1416f, MTXMODE_APPLY);
Matrix_Scale(effect->scale * 0.02f, effect->scale * 0.02f, 1.0f, MTXMODE_APPLY);
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_015710);
FrameInterpolation_RecordCloseChild();
}
}
effect = effectHead;
for (i = 0, flag = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) {
if (effect->type == VA_SMALL_SPARK) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
func_80093D84(globalCtx->state.gfxCtx);
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 100, 0);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_008F08);
flag++;
}
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, effect->primColor[3]);
Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW);
Matrix_RotateZ((effect->rot.z / (f32)0x8000) * 3.1416f, MTXMODE_APPLY);
Matrix_RotateY((effect->rot.y / (f32)0x8000) * 3.1416f, MTXMODE_APPLY);
Matrix_Scale(effect->scale, effect->scale, 1.0f, MTXMODE_APPLY);
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_008F70);
FrameInterpolation_RecordCloseChild();
}
}
CLOSE_DISPS(gfxCtx);
}
void BossVa_SpawnSpark(GlobalContext* globalCtx, BossVaEffect* effect, BossVa* this, Vec3f* offset, s16 scale,
u8 mode) {
Player* player = GET_PLAYER(globalCtx);
s16 index;
Vec3f pos = { 0.0f, -1000.0f, 0.0f };
Vec3f tempVec;
s16 i;
for (i = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) {
if (effect->type == VA_NONE) {
effect->type = VA_LARGE_SPARK;
effect->parent = this;
effect->pos = pos;
effect->timer = (s16)(Rand_ZeroOne() * 10.0f) + 111;
effect->velocity = effect->accel = sZeroVec;
effect->mode = mode;
effect->epoch++;
switch (mode) {
case SPARK_UNUSED:
effect->type = VA_SMALL_SPARK;
case SPARK_TETHER:
tempVec = *offset;
tempVec.x += this->actor.world.pos.x;
tempVec.z += this->actor.world.pos.z;
effect->offset.x = Math_Vec3f_DistXZ(&this->actor.world.pos, &tempVec);
effect->rot.x = Math_Vec3f_Pitch(&this->actor.world.pos, &GET_BODY(this)->unk_1D8);
break;
case SPARK_BODY:
effect->type = VA_SMALL_SPARK;
case SPARK_BARI:
effect->offset.x = offset->x;
effect->offset.z = offset->z;
break;
case SPARK_BLAST:
effect->type = VA_BLAST_SPARK;
effect->pos.x = offset->x + this->actor.world.pos.x;
effect->pos.y = offset->y + this->actor.world.pos.y;
effect->pos.z = offset->z + this->actor.world.pos.z;
effect->timer = 111;
break;
case SPARK_LINK:
effect->type = VA_SMALL_SPARK;
index = Rand_ZeroFloat(ARRAY_COUNT(player->bodyPartsPos) - 0.1f);
effect->pos.x = player->bodyPartsPos[index].x + Rand_CenteredFloat(10.0f);
effect->pos.y = player->bodyPartsPos[index].y + Rand_CenteredFloat(15.0f);
effect->pos.z = player->bodyPartsPos[index].z + Rand_CenteredFloat(10.0f);
break;
}
effect->offset.y = offset->y;
effect->scale = (Rand_ZeroFloat(scale) + scale) * 0.01f;
effect->primColor[3] = 255;
break;
}
}
}
void BossVa_SpawnSparkBall(GlobalContext* globalCtx, BossVaEffect* effect, BossVa* this, Vec3f* offset, s16 scale,
u8 mode) {
Vec3f pos = { 0.0f, -1000.0f, 0.0f };
s16 i;
for (i = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) {
if (effect->type == VA_NONE) {
effect->type = VA_SPARK_BALL;
effect->parent = this;
effect->pos = pos;
effect->velocity = effect->accel = sZeroVec;
effect->mode = 0;
effect->offset.x = offset->x;
effect->offset.z = offset->z;
effect->offset.y = offset->y;
effect->timer = (s16)(Rand_ZeroOne() * 10.0f) + 111;
effect->primColor[0] = effect->primColor[1] = effect->primColor[2] = effect->primColor[3] = 230;
effect->envColor[0] = 0;
effect->envColor[1] = 100;
effect->envColor[2] = 220;
effect->envColor[3] = 160;
effect->scale = (Rand_ZeroFloat(scale) + scale) * 0.01f;
return;
}
}
}
void BossVa_SpawnBloodDroplets(GlobalContext* globalCtx, BossVaEffect* effect, Vec3f* pos, s16 scale, s16 phase,
s16 yaw) {
s32 i;
Vec3f accel = { 0.0f, 0.0f, 0.0f };
Vec3f velocity = { 0.0f, 0.0f, 0.0f };
f32 xzVel;
for (i = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) {
if (effect->type == VA_NONE) {
effect->type = VA_BLOOD;
effect->pos = *pos;
effect->mode = BLOOD_DROPLET;
xzVel = Math_SinS(phase) * 6.0f;
velocity.x = Rand_CenteredFloat(1.0f) + (-Math_SinS(yaw) * xzVel);
velocity.z = Rand_CenteredFloat(1.0f) + (-Math_CosS(yaw) * xzVel);
effect->velocity = velocity;
accel.y = Rand_CenteredFloat(0.3f) - 1.0f;
effect->accel = accel;
effect->timer = 20;
effect->envColor[3] = 100;
effect->primColor[3] = 200;
effect->scale = (Rand_ZeroFloat(scale) + scale) * 0.01f;
break;
}
}
}
void BossVa_SpawnBloodSplatter(GlobalContext* globalCtx, BossVaEffect* effect, Vec3f* pos, s16 yaw, s16 scale) {
s32 i;
f32 xzVel;
Vec3f accel = { 0.0f, 0.0f, 0.0f };
Vec3f velocity;
for (i = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) {
if (effect->type == VA_NONE) {
effect->type = VA_BLOOD;
effect->pos = *pos;
effect->mode = BLOOD_SPLATTER;
xzVel = Rand_ZeroOne() * 7.0f;
velocity.x = Math_SinS(yaw) * xzVel;
velocity.y = Rand_CenteredFloat(4.0f) + 4.0f;
velocity.z = Math_CosS(yaw) * xzVel;
effect->velocity = velocity;
accel.y = Rand_CenteredFloat(0.3f) - 1.0f;
effect->accel = accel;
if (sCsState <= DEATH_SHELL_BURST) {
effect->timer = 20;
} else {
effect->timer = 60;
}
effect->envColor[3] = 100;
effect->primColor[3] = 200;
effect->scale = scale * 0.01f;
break;
}
}
}
void BossVa_SpawnTumor(GlobalContext* globalCtx, BossVaEffect* effect, BossVa* this, Vec3f* offset, s16 scale,
u8 mode) {
Vec3f pos = { 0.0f, -1000.0f, 0.0f };
s16 i;
for (i = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) {
if (effect->type == VA_NONE) {
effect->type = VA_TUMOR;
effect->parent = this;
effect->pos = pos;
effect->velocity = effect->accel = sZeroVec;
effect->mode = mode;
effect->rot.z = 0;
effect->offset.x = offset->x;
effect->offset.z = offset->z;
effect->offset.y = offset->y;
effect->timer = (s16)(Rand_ZeroOne() * 10.0f) + 10;
effect->envColor[3] = 100;
effect->scaleMod = scale * 0.01f;
effect->scale = 0.0f;
if (((i % 4) == 0) || (mode == 2)) {
Audio_PlaySoundGeneral(NA_SE_EN_BALINADE_BREAK, &effect->pos, 4, &D_801333E0, &D_801333E0, &D_801333E8);
}
break;
}
}
}
void BossVa_SpawnGore(GlobalContext* globalCtx, BossVaEffect* effect, Vec3f* pos, s16 yaw, s16 scale) {
s32 i;
f32 xzVel;
Vec3f accel = { 0.0f, 0.0f, 0.0f };
Vec3f velocity;
for (i = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) {
if (effect->type == VA_NONE) {
effect->type = VA_GORE;
effect->pos = *pos;
effect->scaleMod = 0.0f;
xzVel = (Rand_ZeroOne() * 4.0f) + 4.0f;
velocity.x = Math_SinS(yaw) * xzVel;
velocity.y = Rand_CenteredFloat(8.0f);
velocity.z = Math_CosS(yaw) * xzVel;
effect->velocity = velocity;
accel.y = Rand_CenteredFloat(0.3f) - 1.0f;
effect->accel = accel;
effect->timer = 20;
if (sCsState <= DEATH_SHELL_BURST) {
effect->mode = GORE_FADING;
} else {
effect->mode = GORE_PERMANENT;
}
effect->primColor[3] = effect->envColor[0] = effect->envColor[1] = effect->envColor[2] =
effect->envColor[3] = 255;
effect->primColor[0] = 155;
effect->primColor[1] = effect->primColor[2] = 55;
effect->rot.x = Rand_CenteredFloat(0x10000);
effect->rot.y = Rand_CenteredFloat(0x10000);
effect->scale = (Rand_ZeroFloat(scale) + scale) * 0.01f;
effect->vaGorePulseRate = (Rand_ZeroOne() * 0.25f) + 0.9f;
break;
}
}
}
void BossVa_SpawnZapperCharge(GlobalContext* globalCtx, BossVaEffect* effect, BossVa* this, Vec3f* pos, Vec3s* rot,
s16 scale, u8 mode) {
Vec3f unused = { 0.0f, -1000.0f, 0.0f };
s16 i;
for (i = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) {
if (effect->type == VA_NONE) {
effect->type = VA_ZAP_CHARGE;
effect->parent = this;
effect->pos = *pos;
effect->velocity = effect->accel = sZeroVec;
effect->mode = mode;
effect->rot.x = rot->x + 0x4000;
effect->rot.y = rot->y;
effect->timer = (s16)(Rand_ZeroOne() * 10.0f) + 10;
effect->primColor[3] = 240;
effect->scale = scale * 0.01f;
break;
}
}
}
void BossVa_DrawDoor(GlobalContext* globalCtx, s16 scale) {
static Gfx* doorPieceDispList[] = {
gBarinadeDoorPiece1DL, gBarinadeDoorPiece2DL, gBarinadeDoorPiece3DL, gBarinadeDoorPiece4DL,
gBarinadeDoorPiece5DL, gBarinadeDoorPiece6DL, gBarinadeDoorPiece7DL, gBarinadeDoorPiece8DL,
};
static s16 doorPieceLength[] = { 836, 900, 836, 1016, 800, 1016, 836, 900 };
MtxF doorMtx;
f32 yScale;
f32 segAngle = 0.0f;
s32 i;
OPEN_DISPS(globalCtx->state.gfxCtx);
Matrix_Translate(0.0f, 80.0f, 400.0f, MTXMODE_NEW);
Matrix_RotateY(M_PI, MTXMODE_APPLY);
yScale = (scale * 0.01f) * 0.1f;
Matrix_Scale(0.1f, yScale, 0.1f, MTXMODE_APPLY);
if (yScale != 0.0f) {
yScale = 0.1f / yScale;
} else {
yScale = 0.0f;
}
Matrix_Get(&doorMtx);
for (i = 0; i < 8; i++, segAngle -= M_PI / 4) {
FrameInterpolation_RecordOpenChild("Barinade Door", i);
Matrix_Put(&doorMtx);
Matrix_RotateZ(segAngle, MTXMODE_APPLY);
Matrix_Translate(0.0f, doorPieceLength[i] * yScale, 0.0f, MTXMODE_APPLY);
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, doorPieceDispList[i]);
FrameInterpolation_RecordCloseChild();
}
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
void BossVa_Reset(void) {
sKillBari = 0;
sCsCamera = 0;
memset(sVaEffects, 0, sizeof(sVaEffects));
sBodyState = 0;
sFightPhase = 0;
sCsState = 0;
sDoorState = 0;
sPhase3StopMoving = 0;
sZapperRot.x = 0;
sZapperRot.y = 0;
sZapperRot.z = 0;
sPhase2Timer = 0;
sPhase4HP = 0;
for (u8 i = 0; i < ARRAY_SIZE(sBodyBari); i++) {
sBodyBari[i] = 0;
}
}