/* * File: z_boss_va.c * Overlay: ovl_Boss_Va * Description: Barinade */ #include "z_boss_va.h" #include #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; } }