Shipwright/soh/src/overlays/actors/ovl_Boss_Ganondrof/z_boss_ganondrof.c

1517 lines
62 KiB
C

/*
* File: z_boss_ganondrof.c
* Overlay: ovl_Boss_Ganondrof
* Description: Phantom Ganon
*/
#include "z_boss_ganondrof.h"
#include "objects/object_gnd/object_gnd.h"
#include "overlays/actors/ovl_En_fHG/z_en_fhg.h"
#include "overlays/actors/ovl_En_Fhg_Fire/z_en_fhg_fire.h"
#include "overlays/effects/ovl_Effect_Ss_Fhg_Flash/z_eff_ss_fhg_flash.h"
#include "overlays/effects/ovl_Effect_Ss_Hahen/z_eff_ss_hahen.h"
#include "overlays/actors/ovl_Door_Warp1/z_door_warp1.h"
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_2 | ACTOR_FLAG_4 | ACTOR_FLAG_5)
typedef enum {
/* 0 */ NOT_DEAD,
/* 1 */ DEATH_START,
/* 2 */ DEATH_THROES,
/* 3 */ DEATH_WARP,
/* 4 */ DEATH_SCREAM,
/* 5 */ DEATH_DISINTEGRATE,
/* 6 */ DEATH_FINISH
} BossGanondrofDeathState;
typedef enum {
/* 0 */ THROW_NORMAL,
/* 1 */ THROW_SLOW
} BossGanondrofThrowAction;
typedef enum {
/* 0 */ STUNNED_FALL,
/* 1 */ STUNNED_GROUND
} BossGanondrofStunnedAction;
typedef enum {
/* 0 */ CHARGE_WINDUP,
/* 1 */ CHARGE_START,
/* 2 */ CHARGE_ATTACK,
/* 3 */ CHARGE_FINISH
} BossGanondrofChargeAction;
typedef enum {
/* 0 */ DEATH_SPASM,
/* 1 */ DEATH_LIMP,
/* 2 */ DEATH_HUNCHED
} BossGanondrofDeathAction;
void BossGanondrof_Init(Actor* thisx, PlayState* play);
void BossGanondrof_Destroy(Actor* thisx, PlayState* play);
void BossGanondrof_Update(Actor* thisx, PlayState* play);
void BossGanondrof_Draw(Actor* thisx, PlayState* play);
void BossGanondrof_SetupIntro(BossGanondrof* this, PlayState* play);
void BossGanondrof_Intro(BossGanondrof* this, PlayState* play);
void BossGanondrof_SetupPaintings(BossGanondrof* this);
void BossGanondrof_Paintings(BossGanondrof* this, PlayState* play);
void BossGanondrof_SetupNeutral(BossGanondrof* this, f32 arg1);
void BossGanondrof_Neutral(BossGanondrof* this, PlayState* play);
void BossGanondrof_SetupThrow(BossGanondrof* this, PlayState* play);
void BossGanondrof_Throw(BossGanondrof* this, PlayState* play);
void BossGanondrof_SetupBlock(BossGanondrof* this, PlayState* play);
void BossGanondrof_Block(BossGanondrof* this, PlayState* play);
void BossGanondrof_SetupReturn(BossGanondrof* this, PlayState* play);
void BossGanondrof_Return(BossGanondrof* this, PlayState* play);
void BossGanondrof_SetupCharge(BossGanondrof* this, PlayState* play);
void BossGanondrof_Charge(BossGanondrof* this, PlayState* play);
void BossGanondrof_Stunned(BossGanondrof* this, PlayState* play);
void BossGanondrof_Death(BossGanondrof* this, PlayState* play);
const ActorInit Boss_Ganondrof_InitVars = {
ACTOR_BOSS_GANONDROF,
ACTORCAT_BOSS,
FLAGS,
OBJECT_GND,
sizeof(BossGanondrof),
(ActorFunc)BossGanondrof_Init,
(ActorFunc)BossGanondrof_Destroy,
(ActorFunc)BossGanondrof_Update,
(ActorFunc)BossGanondrof_Draw,
NULL,
};
static ColliderCylinderInit sCylinderInitBody = {
{
COLTYPE_HIT3,
AT_ON | AT_TYPE_ENEMY,
AC_ON | AC_TYPE_PLAYER,
OC1_ON | OC1_TYPE_ALL,
OC2_TYPE_1,
COLSHAPE_CYLINDER,
},
{
ELEMTYPE_UNK0,
{ 0xFFCFFFFF, 0x00, 0x10 },
{ 0xFFCFFFFE, 0x00, 0x00 },
TOUCH_ON | TOUCH_SFX_NORMAL,
BUMP_ON | BUMP_HOOKABLE,
OCELEM_ON,
},
{ 30, 90, -50, { 0, 0, 0 } },
};
static ColliderCylinderInit sCylinderInitSpear = {
{
COLTYPE_HIT3,
AT_ON | AT_TYPE_ENEMY,
AC_ON | AC_TYPE_PLAYER,
OC1_ON | OC1_TYPE_ALL,
OC2_TYPE_1,
COLSHAPE_CYLINDER,
},
{
ELEMTYPE_UNK0,
{ 0xFFCFFFFF, 0x00, 0x30 },
{ 0xFFCFFFFF, 0x00, 0x00 },
TOUCH_ON | TOUCH_SFX_NORMAL,
BUMP_ON,
OCELEM_ON,
},
{ 20, 30, -20, { 0, 0, 0 } },
};
// clang-format off
static u8 sDecayMaskHigh[16 * 16] = {
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,
1,0,1,1,0,0,0,0,1,1,1,1,1,1,0,1,
1,0,1,1,1,0,0,0,0,1,1,1,1,1,0,1,
1,0,0,1,1,1,1,0,0,0,1,1,1,0,0,1,
1,0,0,1,1,1,1,1,0,0,0,1,1,0,0,1,
1,0,1,1,1,1,0,0,0,0,0,1,0,0,0,1,
1,1,1,1,1,1,1,1,0,0,0,0,1,1,0,1,
1,0,1,1,1,1,1,0,0,0,0,1,1,1,0,1,
1,0,0,1,1,1,0,0,0,1,1,1,1,1,0,1,
1,0,0,0,0,0,0,0,0,0,1,1,1,1,0,1,
1,0,0,0,1,1,0,0,0,1,1,1,1,1,1,1,
1,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,
1,0,1,1,1,1,1,0,0,1,1,1,1,1,0,1,
1,1,1,1,1,1,1,0,0,1,1,1,0,0,0,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
};
static u8 sDecayMaskLow[16 * 16] = {
1,1,1,0,1,0,0,1,0,0,1,1,1,1,1,1,
0,0,0,0,0,0,0,0,1,1,1,0,0,1,1,0,
1,0,1,1,0,0,0,0,0,1,1,0,0,1,0,0,
1,0,0,1,1,0,0,0,0,0,1,1,1,0,0,0,
0,0,0,1,1,1,0,0,0,0,0,1,1,0,0,1,
0,0,0,1,0,0,1,0,0,0,0,0,1,0,0,1,
1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,
1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,1,
0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,
0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,
1,0,0,0,0,1,0,0,0,0,0,1,1,1,0,0,
1,0,0,0,0,1,0,0,0,0,1,0,1,1,0,0,
0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,
1,0,0,0,1,0,1,0,0,0,1,1,0,0,0,1,
1,0,0,1,1,1,0,0,0,1,1,1,0,0,0,1,
};
static u8 sDecayMaskTotal[16 * 16] = {
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
};
// clang-format on
static u8 sDecayTex[16 * 16] = { { 0 } };
// These are Phantom Ganon's body textures, but I don't know which is which.
static void* sLimbTex_rgba16_8x8[] = {
gPhantomGanonLimbTex_00A800, gPhantomGanonLimbTex_00AE80, gPhantomGanonLimbTex_00AF00,
gPhantomGanonLimbTex_00C180, gPhantomGanonLimbTex_00C400,
};
static void* sLimbTex_rgba16_16x8[] = {
gPhantomGanonLimbTex_00B980, gPhantomGanonLimbTex_00C480, gPhantomGanonLimbTex_00BC80,
gPhantomGanonLimbTex_00BD80, gPhantomGanonLimbTex_00C080,
};
static void* sLimbTex_rgba16_16x16[] = {
gPhantomGanonLimbTex_00C200, gPhantomGanonLimbTex_00A000, gPhantomGanonLimbTex_00A200,
gPhantomGanonLimbTex_00A400, gPhantomGanonLimbTex_00A600, gPhantomGanonLimbTex_00A880,
gPhantomGanonLimbTex_00B780, gPhantomGanonLimbTex_00BA80, gPhantomGanonLimbTex_00BE80,
};
static void* sLimbTex_rgba16_16x32[] = { gPhantomGanonLimbTex_00AA80, gPhantomGanonLimbTex_00AF80 };
static void* sMouthTex_ci8_16x16[] = { gPhantomGanonMouthTex, gPhantomGanonSmileTex };
static InitChainEntry sInitChain[] = {
ICHAIN_U8(targetMode, 5, ICHAIN_CONTINUE),
ICHAIN_S8(naviEnemyId, 0x2B, ICHAIN_CONTINUE),
ICHAIN_F32_DIV1000(gravity, 0, ICHAIN_CONTINUE),
ICHAIN_F32(targetArrowOffset, 0, ICHAIN_STOP),
};
static Vec3f sAudioVec = { 0.0f, 0.0f, 50.0f };
void BossGanondrof_ClearPixels(u8* mask, s16 index) {
if (mask[index]) {
sDecayTex[index] = 1;
}
}
void BossGanondrof_SetColliderPos(Vec3f* pos, ColliderCylinder* collider) {
collider->dim.pos.x = pos->x;
collider->dim.pos.y = pos->y;
collider->dim.pos.z = pos->z;
}
void BossGanondrof_Init(Actor* thisx, PlayState* play) {
s32 pad;
BossGanondrof* this = (BossGanondrof*)thisx;
Actor_ProcessInitChain(&this->actor, sInitChain);
ActorShape_Init(&this->actor.shape, 0.0f, NULL, 0.0f);
Actor_SetScale(&this->actor, 0.01f);
SkelAnime_Init(play, &this->skelAnime, &gPhantomGanonSkel, &gPhantomGanonRideAnim, NULL, NULL, 0);
if (this->actor.params < GND_FAKE_BOSS) {
this->actor.params = GND_REAL_BOSS;
this->actor.colChkInfo.health = 30;
this->lightNode = LightContext_InsertLight(play, &play->lightCtx, &this->lightInfo);
Lights_PointNoGlowSetInfo(&this->lightInfo, this->actor.world.pos.x, this->actor.world.pos.y,
this->actor.world.pos.z, 255, 255, 255, 255);
BossGanondrof_SetupIntro(this, play);
} else {
BossGanondrof_SetupPaintings(this);
}
Collider_InitCylinder(play, &this->colliderBody);
Collider_InitCylinder(play, &this->colliderSpear);
Collider_SetCylinder(play, &this->colliderBody, &this->actor, &sCylinderInitBody);
Collider_SetCylinder(play, &this->colliderSpear, &this->actor, &sCylinderInitSpear);
this->actor.flags &= ~ACTOR_FLAG_0;
if (Flags_GetClear(play, play->roomCtx.curRoom.num)) {
Actor_Kill(&this->actor);
Actor_Spawn(&play->actorCtx, play, ACTOR_DOOR_WARP1, GND_BOSSROOM_CENTER_X, GND_BOSSROOM_CENTER_Y,
GND_BOSSROOM_CENTER_Z, 0, 0, 0, WARP_DUNGEON_ADULT, true);
Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_B_HEART, 200.0f + GND_BOSSROOM_CENTER_X,
GND_BOSSROOM_CENTER_Y, GND_BOSSROOM_CENTER_Z, 0, 0, 0, 0, true);
} else {
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_EN_FHG, this->actor.world.pos.x,
this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, 0, this->actor.params);
}
for (int i = 0; i < ARRAY_COUNT(sDecayTex); i++) {
sDecayTex[i] = 0;
}
for (int i = 0; i < 5; i++) {
Gfx_RegisterBlendedTexture(sLimbTex_rgba16_8x8[i], sDecayTex, NULL);
Gfx_RegisterBlendedTexture(sLimbTex_rgba16_16x8[i], sDecayTex, NULL);
}
for (int i = 0; i < ARRAY_COUNT(sLimbTex_rgba16_16x16); i++) {
Gfx_RegisterBlendedTexture(sLimbTex_rgba16_16x16[i], sDecayTex, NULL);
}
for (int i = 0; i < ARRAY_COUNT(sLimbTex_rgba16_16x32); i++) {
Gfx_RegisterBlendedTexture(sLimbTex_rgba16_16x32[i], sDecayTex, NULL);
}
Gfx_RegisterBlendedTexture(gPhantomGanonLimbTex_00B380, sDecayTex, NULL);
Gfx_RegisterBlendedTexture(gPhantomGanonEyeTex, sDecayTex, NULL);
for (int i = 0; i < ARRAY_COUNT(sMouthTex_ci8_16x16); i++) {
Gfx_RegisterBlendedTexture(sMouthTex_ci8_16x16[i], sDecayTex, NULL);
}
}
void BossGanondrof_Destroy(Actor* thisx, PlayState* play) {
s32 pad;
BossGanondrof* this = (BossGanondrof*)thisx;
osSyncPrintf("DT1\n");
SkelAnime_Free(&this->skelAnime, play);
Collider_DestroyCylinder(play, &this->colliderBody);
Collider_DestroyCylinder(play, &this->colliderSpear);
if (this->actor.params == GND_REAL_BOSS) {
LightContext_RemoveLight(play, &play->lightCtx, this->lightNode);
}
osSyncPrintf("DT2\n");
}
void BossGanondrof_SetupIntro(BossGanondrof* this, PlayState* play) {
Animation_PlayLoop(&this->skelAnime, &gPhantomGanonRidePoseAnim);
this->actionFunc = BossGanondrof_Intro;
this->work[GND_MASK_OFF] = true;
}
void BossGanondrof_Intro(BossGanondrof* this, PlayState* play) {
s16 i;
s32 pad;
EnfHG* horse = (EnfHG*)this->actor.child;
SkelAnime_Update(&this->skelAnime);
this->actor.world.pos = horse->actor.world.pos;
this->actor.shape.rot.y = this->actor.world.rot.y = horse->actor.world.rot.y;
osSyncPrintf("SW %d------------------------------------------------\n", horse->bossGndSignal);
if ((this->timers[1] != 0) && (this->timers[1] < 25)) {
Vec3f pos;
Vec3f vel = { 0.0f, 0.0f, 0.0f };
Vec3f accel = { 0.0f, 0.0f, 0.0f };
pos.x = this->bodyPartsPos[14].x + Rand_CenteredFloat(10.0f);
pos.y = this->bodyPartsPos[14].y + Rand_ZeroFloat(-5.0f);
pos.z = this->bodyPartsPos[14].z + Rand_CenteredFloat(10.0f) + 5.0f;
accel.y = 0.03f;
EffectSsKFire_Spawn(play, &pos, &vel, &accel, (s16)Rand_ZeroFloat(10.0f) + 5, 0);
}
if (this->timers[1] == 20) {
this->work[GND_MASK_OFF] = false;
}
if (this->timers[1] == 30) {
func_80078914(&sAudioVec, NA_SE_EN_FANTOM_TRANSFORM);
}
if (horse->bossGndSignal == FHG_LIGHTNING) {
Animation_Change(&this->skelAnime, &gPhantomGanonMaskOnAnim, 0.5f, 0.0f,
Animation_GetLastFrame(&gPhantomGanonMaskOnAnim), ANIMMODE_ONCE_INTERP, 0.0f);
this->timers[1] = 40;
}
if (horse->bossGndSignal == FHG_REAR) {
Animation_MorphToPlayOnce(&this->skelAnime, &gPhantomGanonHorseRearingAnim, -3.0f);
}
if (horse->bossGndSignal == FHG_RIDE) {
Animation_MorphToLoop(&this->skelAnime, &gPhantomGanonRidePoseAnim, -13.0f);
}
if (horse->bossGndSignal == FHG_SPUR) {
EnfHG* horseTemp;
Animation_MorphToPlayOnce(&this->skelAnime, &gPhantomGanonRideSpearRaiseAnim, -7.0f);
horseTemp = (EnfHG*)this->actor.child;
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_EN_FHG_FIRE, this->spearTip.x,
this->spearTip.y, this->spearTip.z, 50, FHGFIRE_LIGHT_GREEN, 0, FHGFIRE_SPEAR_LIGHT);
this->actor.child = &horseTemp->actor;
}
if (horse->bossGndSignal == FHG_FINISH) {
Animation_MorphToPlayOnce(&this->skelAnime, &gPhantomGanonRideSpearResetAnim, -5.0f);
}
switch (this->work[GND_EYE_STATE]) {
case GND_EYESTATE_FADE:
this->fwork[GND_EYE_ALPHA] += 40.0f;
if (this->fwork[GND_EYE_ALPHA] >= 255.0f) {
this->fwork[GND_EYE_ALPHA] = 255.0f;
}
break;
case GND_EYESTATE_BRIGHTEN:
this->fwork[GND_EYE_BRIGHTNESS] += 20.0f;
if (this->fwork[GND_EYE_BRIGHTNESS] > 255.0f) {
this->fwork[GND_EYE_BRIGHTNESS] = 255.0f;
}
break;
}
this->armRotY = Math_SinS(this->work[GND_VARIANCE_TIMER] * 0x6E8) * 0;
this->armRotZ = Math_CosS(this->work[GND_VARIANCE_TIMER] * 0x8DC) * 300.0f;
for (i = 0; i < 30; i++) {
this->rideRotY[i] = Math_SinS(this->work[GND_VARIANCE_TIMER] * ((i * 50) + 0x7B0)) * 100.0f;
this->rideRotZ[i] = Math_CosS(this->work[GND_VARIANCE_TIMER] * ((i * 50) + 0x8DC)) * 100.0f;
}
if (horse->bossGndSignal == FHG_START_FIGHT) {
BossGanondrof_SetupPaintings(this);
for (i = 0; i < 30; i++) {
this->rideRotY[i] = this->rideRotZ[i] = 0.0f;
}
}
horse->bossGndSignal = FHG_NO_SIGNAL;
}
void BossGanondrof_SetupPaintings(BossGanondrof* this) {
Animation_MorphToLoop(&this->skelAnime, &gPhantomGanonRideAnim, -5.0f);
this->actionFunc = BossGanondrof_Paintings;
}
void BossGanondrof_Paintings(BossGanondrof* this, PlayState* play) {
EnfHG* horse = (EnfHG*)this->actor.child;
osSyncPrintf("RUN 1\n");
SkelAnime_Update(&this->skelAnime);
osSyncPrintf("RUN 2\n");
if (horse->bossGndSignal == FHG_RAISE_SPEAR) {
EnfHG* horseTemp;
Animation_MorphToPlayOnce(&this->skelAnime, &gPhantomGanonRideSpearRaiseAnim, -2.0f);
this->actor.flags |= ACTOR_FLAG_0;
horseTemp = (EnfHG*)this->actor.child;
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_EN_FHG_FIRE, this->spearTip.x,
this->spearTip.y, this->spearTip.z, 30, FHGFIRE_LIGHT_GREEN, 0, FHGFIRE_SPEAR_LIGHT);
this->actor.child = &horseTemp->actor;
} else if (horse->bossGndSignal == FHG_LIGHTNING) {
Animation_MorphToPlayOnce(&this->skelAnime, &gPhantomGanonRideSpearStrikeAnim, -2.0f);
} else if (horse->bossGndSignal == FHG_RESET) {
Animation_MorphToPlayOnce(&this->skelAnime, &gPhantomGanonRideSpearResetAnim, -2.0f);
} else if (horse->bossGndSignal == FHG_RIDE) {
Animation_MorphToLoop(&this->skelAnime, &gPhantomGanonRideAnim, -2.0f);
this->actor.flags &= ~ACTOR_FLAG_0;
}
osSyncPrintf("RUN 3\n");
this->actor.world.pos = horse->actor.world.pos;
this->actor.world.pos.y = horse->actor.world.pos.y;
this->actor.shape.rot.y = this->actor.world.rot.y = horse->actor.world.rot.y;
if (this->flyMode != GND_FLY_PAINTING) {
BossGanondrof_SetupNeutral(this, -20.0f);
this->timers[0] = 100;
this->colliderBody.dim.radius = 20;
this->colliderBody.dim.height = 60;
this->colliderBody.dim.yShift = -33;
Audio_PlayActorSound2(&this->actor, NA_SE_EN_FANTOM_LAUGH);
this->actor.naviEnemyId = 0x1A;
} else {
horse->bossGndSignal = FHG_NO_SIGNAL;
this->actor.scale.x = horse->actor.scale.x / 1.15f;
this->actor.scale.y = horse->actor.scale.y / 1.15f;
this->actor.scale.z = horse->actor.scale.z / 1.15f;
osSyncPrintf("RUN 4\n");
}
}
void BossGanondrof_SetupNeutral(BossGanondrof* this, f32 arg1) {
Animation_MorphToLoop(&this->skelAnime, &gPhantomGanonNeutralAnim, arg1);
this->actionFunc = BossGanondrof_Neutral;
this->actor.flags |= ACTOR_FLAG_0;
this->fwork[GND_FLOAT_SPEED] = 0.0f;
this->timers[0] = (s16)(Rand_ZeroOne() * 64.0f) + 30;
}
void BossGanondrof_Neutral(BossGanondrof* this, PlayState* play) {
f32 targetX;
f32 targetY;
f32 targetZ;
Player* player = GET_PLAYER(play);
Actor* playerx = &player->actor;
Actor* thisx = &this->actor;
f32 rand01;
s16 i;
SkelAnime_Update(&this->skelAnime);
switch (this->flyMode) {
case GND_FLY_NEUTRAL:
if (this->timers[0] == 0) {
this->timers[0] = (s16)(Rand_ZeroOne() * 64.0f) + 30;
rand01 = Rand_ZeroOne();
if (thisx->colChkInfo.health < 5) {
if (rand01 < 0.25f) {
BossGanondrof_SetupThrow(this, play);
} else if (rand01 >= 0.8f) {
this->flyMode = GND_FLY_CHARGE;
this->timers[0] = 60;
this->fwork[GND_FLOAT_SPEED] = 0.0f;
Audio_PlayActorSound2(thisx, NA_SE_EN_FANTOM_LAUGH);
} else {
this->flyMode = GND_FLY_VOLLEY;
this->timers[0] = 60;
this->fwork[GND_FLOAT_SPEED] = 0.0f;
Audio_PlayActorSound2(thisx, NA_SE_EN_FANTOM_LAUGH);
}
} else if ((rand01 < 0.5f) || (this->work[GND_THROW_COUNT] < 5)) {
BossGanondrof_SetupThrow(this, play);
} else {
this->flyMode = GND_FLY_VOLLEY;
this->timers[0] = 60;
this->fwork[GND_FLOAT_SPEED] = 0.0f;
Audio_PlayActorSound2(thisx, NA_SE_EN_FANTOM_LAUGH);
}
}
if (this->timers[1] != 0) {
targetX = GND_BOSSROOM_CENTER_X;
targetZ = GND_BOSSROOM_CENTER_Z;
} else {
targetX = playerx->world.pos.x + (180.0f * Math_SinS(playerx->shape.rot.y));
targetZ = playerx->world.pos.z + (180.0f * Math_CosS(playerx->shape.rot.y));
if (sqrtf(SQ(targetX - GND_BOSSROOM_CENTER_X) + SQ(targetZ - GND_BOSSROOM_CENTER_Z)) > 280.0f) {
this->timers[1] = 50;
this->fwork[GND_FLOAT_SPEED] = 0.0f;
}
}
targetY = playerx->world.pos.y + 100.0f + 0.0f;
targetX += Math_SinS(this->work[GND_VARIANCE_TIMER] * 0x500) * 100.0f;
targetZ += Math_CosS(this->work[GND_VARIANCE_TIMER] * 0x700) * 100.0f;
break;
case GND_FLY_VOLLEY:
targetX = GND_BOSSROOM_CENTER_X - 14.0f;
targetZ = GND_BOSSROOM_CENTER_Z + 265.0f;
targetY = playerx->world.pos.y + 100.0f + 100.0f;
targetX += Math_SinS(this->work[GND_VARIANCE_TIMER] * 0x500) * 100.0f;
targetZ += Math_CosS(this->work[GND_VARIANCE_TIMER] * 0x700) * 100.0f;
if (this->timers[0] == 0) {
this->flyMode = GND_FLY_RETURN;
this->returnSuccess = false;
BossGanondrof_SetupThrow(this, play);
this->timers[0] = 80;
}
break;
case GND_FLY_RETURN:
targetX = GND_BOSSROOM_CENTER_X - 14.0f;
targetZ = GND_BOSSROOM_CENTER_Z + 265.0f;
targetY = playerx->world.pos.y + 100.0f + 100.0f;
targetX += Math_SinS(this->work[GND_VARIANCE_TIMER] * 0x500) * 50.0f;
targetZ += Math_CosS(this->work[GND_VARIANCE_TIMER] * 0x700) * 50.0f;
if (this->returnSuccess) {
this->returnSuccess = false;
BossGanondrof_SetupReturn(this, play);
this->timers[0] = 80;
}
if (this->timers[0] == 0) {
this->flyMode = GND_FLY_NEUTRAL;
}
break;
case GND_FLY_CHARGE:
targetX = GND_BOSSROOM_CENTER_X - 14.0f;
targetZ = GND_BOSSROOM_CENTER_Z + 215.0f;
targetY = playerx->world.pos.y + 100.0f + 50.0f;
targetX += Math_SinS(this->work[GND_VARIANCE_TIMER] * 0x500) * 100.0f;
targetZ += Math_CosS(this->work[GND_VARIANCE_TIMER] * 0x700) * 100.0f;
if (this->timers[0] == 0) {
BossGanondrof_SetupCharge(this, play);
}
break;
}
Math_ApproachF(&thisx->world.pos.x, targetX, 0.05f, this->fwork[GND_FLOAT_SPEED]);
if (this->timers[2] != 0) {
Math_ApproachF(&thisx->world.pos.y, targetY + 100.0f, 0.1f, 50.0f);
} else {
Math_ApproachF(&thisx->world.pos.y, targetY, 0.05f, 10.0f);
}
Math_ApproachF(&thisx->world.pos.z, targetZ, 0.05f, this->fwork[GND_FLOAT_SPEED]);
Math_ApproachF(&this->fwork[GND_FLOAT_SPEED], 50.0f, 1.0f, 0.5f);
thisx->velocity.x = thisx->world.pos.x - thisx->prevPos.x;
thisx->velocity.z = thisx->world.pos.z - thisx->prevPos.z;
thisx->world.pos.y += 2.0f * Math_SinS(this->work[GND_VARIANCE_TIMER] * 1500);
Math_ApproachS(&thisx->shape.rot.y, thisx->yawTowardsPlayer, 5, 0xBB8);
if ((this->work[GND_VARIANCE_TIMER] & 1) == 0) {
Vec3f pos;
Vec3f vel = { 0.0f, 0.0f, 0.0f };
Vec3f accel = { 0.0f, 0.0f, 0.0f };
for (i = 0; i < 3; i++) {
pos.x = Rand_CenteredFloat(20.0f) + this->spearTip.x;
pos.y = Rand_CenteredFloat(20.0f) + this->spearTip.y;
pos.z = Rand_CenteredFloat(20.0f) + this->spearTip.z;
accel.y = -0.08f;
EffectSsFhgFlash_SpawnLightBall(play, &pos, &vel, &accel, (s16)(Rand_ZeroOne() * 80.0f) + 150,
FHGFLASH_LIGHTBALL_GREEN);
}
}
if (player->unk_A73 != 0) {
BossGanondrof_SetupBlock(this, play);
}
Audio_PlayActorSound2(thisx, NA_SE_EN_FANTOM_FLOAT - SFX_FLAG);
}
void BossGanondrof_SetupThrow(BossGanondrof* this, PlayState* play) {
EnfHG* horseTemp;
s16 lightTime;
this->fwork[GND_END_FRAME] = Animation_GetLastFrame(&gPhantomGanonThrowAnim);
Animation_MorphToPlayOnce(&this->skelAnime, &gPhantomGanonThrowAnim, -5.0f);
this->actionFunc = BossGanondrof_Throw;
if ((Rand_ZeroOne() <= 0.1f) && (this->work[GND_THROW_COUNT] >= 10) && (this->flyMode == GND_FLY_NEUTRAL)) {
this->work[GND_ACTION_STATE] = THROW_SLOW;
this->work[GND_THROW_FRAME] = 1000;
lightTime = 32;
} else {
this->work[GND_ACTION_STATE] = THROW_NORMAL;
this->work[GND_THROW_FRAME] = 25;
lightTime = 25;
}
horseTemp = (EnfHG*)this->actor.child;
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_EN_FHG_FIRE, this->spearTip.x,
this->spearTip.y, this->spearTip.z, lightTime, FHGFIRE_LIGHT_GREEN, 0, FHGFIRE_SPEAR_LIGHT);
this->actor.child = &horseTemp->actor;
this->work[GND_THROW_COUNT]++;
Audio_PlayActorSound2(&this->actor, NA_SE_EN_FANTOM_STICK);
}
void BossGanondrof_Throw(BossGanondrof* this, PlayState* play) {
SkelAnime_Update(&this->skelAnime);
osSyncPrintf("this->fwork[GND_END_FRAME] = %d\n", (s16)this->fwork[GND_END_FRAME]);
osSyncPrintf("this->work[GND_SHOT_FRAME] = %d\n", this->work[GND_THROW_FRAME]);
if (Animation_OnFrame(&this->skelAnime, this->fwork[GND_END_FRAME])) {
BossGanondrof_SetupNeutral(this, -6.0f);
}
if ((this->work[GND_ACTION_STATE] != THROW_NORMAL) && Animation_OnFrame(&this->skelAnime, 21.0f)) {
this->fwork[GND_END_FRAME] = Animation_GetLastFrame(&gPhantomGanonThrowEndAnim);
Animation_MorphToPlayOnce(&this->skelAnime, &gPhantomGanonThrowEndAnim, 0.0f);
this->work[GND_THROW_FRAME] = 10;
}
if (Animation_OnFrame(&this->skelAnime, this->work[GND_THROW_FRAME])) {
if (this->flyMode <= GND_FLY_NEUTRAL) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_FANTOM_MASIC2);
} else {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_FANTOM_MASIC1);
}
Audio_PlayActorSound2(&this->actor, NA_SE_EN_FANTOM_VOICE);
}
if (Animation_OnFrame(&this->skelAnime, this->work[GND_THROW_FRAME])) {
EnfHG* horseTemp = (EnfHG*)this->actor.child;
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_EN_FHG_FIRE, this->spearTip.x,
this->spearTip.y, this->spearTip.z, this->work[GND_ACTION_STATE], 0, 0, FHGFIRE_ENERGY_BALL);
this->actor.child = &horseTemp->actor;
}
Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 5, 0x7D0);
this->actor.world.pos.x += this->actor.velocity.x;
this->actor.world.pos.z += this->actor.velocity.z;
Math_ApproachZeroF(&this->actor.velocity.x, 1.0f, 0.5f);
Math_ApproachZeroF(&this->actor.velocity.z, 1.0f, 0.5f);
this->actor.world.pos.y += 2.0f * Math_SinS(this->work[GND_VARIANCE_TIMER] * 1500);
}
void BossGanondrof_SetupReturn(BossGanondrof* this, PlayState* play) {
static AnimationHeader* returnAnim[] = { &gPhantomGanonReturn1Anim, &gPhantomGanonReturn2Anim };
s16 rand = Rand_ZeroOne() * 1.99f;
this->fwork[GND_END_FRAME] = Animation_GetLastFrame(returnAnim[rand]);
Animation_MorphToPlayOnce(&this->skelAnime, returnAnim[rand], 0.0f);
this->actionFunc = BossGanondrof_Return;
}
void BossGanondrof_Return(BossGanondrof* this, PlayState* play) {
SkelAnime_Update(&this->skelAnime);
if (Animation_OnFrame(&this->skelAnime, 5.0f)) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_FANTOM_VOICE);
osSyncPrintf("VOISE 2 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
osSyncPrintf("VOISE 2 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
}
if (Animation_OnFrame(&this->skelAnime, this->fwork[GND_END_FRAME])) {
BossGanondrof_SetupNeutral(this, 0.0f);
}
this->actor.world.pos.x += this->actor.velocity.x;
this->actor.world.pos.z += this->actor.velocity.z;
Math_ApproachZeroF(&this->actor.velocity.x, 1.0f, 0.5f);
Math_ApproachZeroF(&this->actor.velocity.z, 1.0f, 0.5f);
this->actor.world.pos.y += 2.0f * Math_SinS(this->work[GND_VARIANCE_TIMER] * 1500);
if (this->returnSuccess) {
this->returnSuccess = false;
BossGanondrof_SetupReturn(this, play);
this->timers[0] = 80;
}
}
void BossGanondrof_SetupStunned(BossGanondrof* this, PlayState* play) {
if (this->actionFunc != BossGanondrof_Stunned) {
this->fwork[GND_END_FRAME] = Animation_GetLastFrame(&gPhantomGanonAirDamageAnim);
Animation_MorphToLoop(&this->skelAnime, &gPhantomGanonAirDamageAnim, 0.0f);
this->timers[0] = 50;
this->shockTimer = 60;
} else {
this->fwork[GND_END_FRAME] = Animation_GetLastFrame(&gPhantomGanonGroundDamageAnim);
Animation_MorphToLoop(&this->skelAnime, &gPhantomGanonGroundDamageAnim, 0.0f);
}
this->actionFunc = BossGanondrof_Stunned;
this->work[GND_ACTION_STATE] = STUNNED_FALL;
this->actor.velocity.x = 0.0f;
this->actor.velocity.z = 0.0f;
}
void BossGanondrof_Stunned(BossGanondrof* this, PlayState* play) {
osSyncPrintf("DAMAGE .................................\n");
SkelAnime_Update(&this->skelAnime);
this->actor.gravity = -0.2f;
if (this->actor.world.pos.y <= 5.0f) {
if (this->work[GND_ACTION_STATE] == STUNNED_FALL) {
this->fwork[GND_END_FRAME] = Animation_GetLastFrame(&gPhantomGanonStunnedAnim);
Animation_MorphToLoop(&this->skelAnime, &gPhantomGanonStunnedAnim, -10.0f);
this->work[GND_ACTION_STATE] = STUNNED_GROUND;
}
this->actor.velocity.y = 0.0f;
this->actor.gravity = 0.0f;
if (Animation_OnFrame(&this->skelAnime, this->fwork[GND_END_FRAME])) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_FANTOM_DAMAGE2);
}
this->actor.flags |= ACTOR_FLAG_10;
}
osSyncPrintf("TIME0 %d ********************************************\n", this->timers[0]);
if (this->timers[0] == 0) {
BossGanondrof_SetupNeutral(this, -5.0f);
this->timers[0] = 30;
this->timers[2] = 30;
this->flyMode = GND_FLY_NEUTRAL;
this->actor.velocity.y = 0.0f;
this->actor.gravity = 0.0f;
}
Actor_MoveForward(&this->actor);
}
void BossGanondrof_SetupBlock(BossGanondrof* this, PlayState* play) {
this->fwork[GND_END_FRAME] = Animation_GetLastFrame(&gPhantomGanonBlockAnim);
Animation_MorphToLoop(&this->skelAnime, &gPhantomGanonBlockAnim, -3.0f);
this->actionFunc = BossGanondrof_Block;
this->timers[0] = 10;
Audio_PlayActorSound2(&this->actor, NA_SE_EN_FANTOM_STICK);
}
void BossGanondrof_Block(BossGanondrof* this, PlayState* play) {
this->colliderBody.base.colType = COLTYPE_METAL;
SkelAnime_Update(&this->skelAnime);
this->actor.world.pos.x += this->actor.velocity.x;
this->actor.world.pos.z += this->actor.velocity.z;
Math_ApproachZeroF(&this->actor.velocity.x, 1.0f, 0.5f);
Math_ApproachZeroF(&this->actor.velocity.z, 1.0f, 0.5f);
this->actor.world.pos.y += 2.0f * Math_SinS(this->work[GND_VARIANCE_TIMER] * 1500);
if (this->timers[0] == 0) {
BossGanondrof_SetupNeutral(this, -5.0f);
this->timers[0] = 10;
this->flyMode = GND_FLY_NEUTRAL;
}
}
void BossGanondrof_SetupCharge(BossGanondrof* this, PlayState* play) {
this->fwork[GND_END_FRAME] = Animation_GetLastFrame(&gPhantomGanonChargeWindupAnim);
Animation_MorphToLoop(&this->skelAnime, &gPhantomGanonChargeWindupAnim, -3.0f);
this->actionFunc = BossGanondrof_Charge;
this->timers[0] = 20;
this->work[GND_ACTION_STATE] = CHARGE_WINDUP;
}
void BossGanondrof_Charge(BossGanondrof* this, PlayState* play) {
Player* player = GET_PLAYER(play);
Actor* playerx = &player->actor;
Actor* thisx = &this->actor;
f32 dxCenter = thisx->world.pos.x - GND_BOSSROOM_CENTER_X;
f32 dzCenter = thisx->world.pos.z - GND_BOSSROOM_CENTER_Z;
this->colliderBody.base.colType = COLTYPE_METAL;
SkelAnime_Update(&this->skelAnime);
switch (this->work[GND_ACTION_STATE]) {
case CHARGE_WINDUP:
if (this->timers[0] == 218) {
Audio_PlayActorSound2(thisx, NA_SE_EN_FANTOM_STICK);
}
if (this->timers[0] == 19) {
Audio_PlayActorSound2(thisx, NA_SE_EN_FANTOM_ATTACK);
}
thisx->world.pos.x += thisx->velocity.x;
thisx->world.pos.z += thisx->velocity.z;
Math_ApproachZeroF(&thisx->velocity.x, 1.0f, 0.5f);
Math_ApproachZeroF(&thisx->velocity.z, 1.0f, 0.5f);
if (this->timers[0] == 0) {
this->work[GND_ACTION_STATE] = CHARGE_START;
this->timers[0] = 10;
thisx->speedXZ = 0.0f;
this->fwork[GND_END_FRAME] = Animation_GetLastFrame(&gPhantomGanonChargeStartAnim);
Animation_MorphToPlayOnce(&this->skelAnime, &gPhantomGanonChargeStartAnim, 0.0f);
}
Math_ApproachS(&thisx->shape.rot.y, thisx->yawTowardsPlayer, 5, 0x7D0);
break;
case CHARGE_START:
if (Animation_OnFrame(&this->skelAnime, this->fwork[GND_END_FRAME])) {
this->fwork[GND_END_FRAME] = Animation_GetLastFrame(&gPhantomGanonChargeAnim);
Animation_MorphToLoop(&this->skelAnime, &gPhantomGanonChargeAnim, 0.0f);
this->work[GND_ACTION_STATE] = CHARGE_ATTACK;
}
case CHARGE_ATTACK:
if (this->timers[0] != 0) {
Vec3f vecToLink;
Math_ApproachS(&thisx->shape.rot.y, thisx->yawTowardsPlayer, 5, 0x7D0);
vecToLink.x = playerx->world.pos.x - thisx->world.pos.x;
vecToLink.y = playerx->world.pos.y + 40.0f - thisx->world.pos.y;
vecToLink.z = playerx->world.pos.z - thisx->world.pos.z;
thisx->world.rot.y = thisx->shape.rot.y;
thisx->world.rot.x =
Math_FAtan2F(vecToLink.y, sqrtf(SQ(vecToLink.x) + SQ(vecToLink.z))) * (0x8000 / M_PI);
}
func_8002D908(thisx);
func_8002D7EC(thisx);
Math_ApproachF(&thisx->speedXZ, 10.0f, 1.0f, 0.5f);
if ((sqrtf(SQ(dxCenter) + SQ(dzCenter)) > 280.0f) || (thisx->xyzDistToPlayerSq < SQ(100.0f))) {
this->work[GND_ACTION_STATE] = CHARGE_FINISH;
this->timers[0] = 20;
}
break;
case CHARGE_FINISH:
thisx->gravity = 0.2f;
Actor_MoveForward(thisx);
osSyncPrintf("YP %f @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n", thisx->world.pos.y);
if (thisx->world.pos.y < 5.0f) {
thisx->world.pos.y = 5.0f;
thisx->velocity.y = 0.0f;
}
if (sqrtf(SQ(dxCenter) + SQ(dzCenter)) > 280.0f) {
Math_ApproachZeroF(&thisx->speedXZ, 1.0f, 2.0f);
this->timers[0] = 0;
}
if (this->timers[0] == 0) {
Math_ApproachZeroF(&thisx->speedXZ, 1.0f, 2.0f);
Math_ApproachZeroF(&thisx->velocity.y, 1.0f, 2.0f);
Math_ApproachS(&thisx->shape.rot.y, thisx->yawTowardsPlayer, 5, 0x7D0);
if ((thisx->speedXZ <= 0.5f) && (fabsf(thisx->velocity.y) <= 0.1f)) {
BossGanondrof_SetupNeutral(this, -10.0f);
this->timers[0] = 30;
this->flyMode = GND_FLY_NEUTRAL;
}
}
break;
}
if (thisx->world.pos.y > (GND_BOSSROOM_CENTER_Y + 83.0f)) {
thisx->world.pos.y += 2.0f * Math_SinS(this->work[GND_VARIANCE_TIMER] * 1500);
}
{
s16 i;
Vec3f pos;
Vec3f vel = { 0.0f, 0.0f, 0.0f };
Vec3f accel = { 0.0f, 0.0f, 0.0f };
Vec3f baseOffset = { 0.0f, 50.0f, 0.0f };
Vec3f offset;
baseOffset.y = 10.0f;
for (i = 0; i < 10; i++) {
Matrix_Push();
Matrix_RotateY((thisx->shape.rot.y / (f32)0x8000) * M_PI, MTXMODE_NEW);
Matrix_RotateX((thisx->shape.rot.x / (f32)0x8000) * M_PI, MTXMODE_APPLY);
Matrix_RotateZ((this->work[GND_PARTICLE_ANGLE] / (f32)0x8000) * M_PI, MTXMODE_APPLY);
Matrix_MultVec3f(&baseOffset, &offset);
Matrix_Pop();
pos.x = this->spearTip.x + offset.x;
pos.y = this->spearTip.y + offset.y;
pos.z = this->spearTip.z + offset.z;
vel.x = (offset.x * 500.0f) / 1000.0f;
vel.y = (offset.y * 500.0f) / 1000.0f;
vel.z = (offset.z * 500.0f) / 1000.0f;
accel.x = (offset.x * -50.0f) / 1000.0f;
accel.y = (offset.y * -50.0f) / 1000.0f;
accel.z = (offset.z * -50.0f) / 1000.0f;
EffectSsFhgFlash_SpawnLightBall(play, &pos, &vel, &accel, 150, i % 7);
this->work[GND_PARTICLE_ANGLE] += 0x1A5C;
}
}
if (!(this->work[GND_VARIANCE_TIMER] & 7)) {
EnfHG* horse = (EnfHG*)thisx->child;
Actor_SpawnAsChild(&play->actorCtx, thisx, play, ACTOR_EN_FHG_FIRE, this->spearTip.x,
this->spearTip.y, this->spearTip.z, 8, FHGFIRE_LIGHT_BLUE, 0, FHGFIRE_SPEAR_LIGHT);
thisx->child = &horse->actor;
}
}
void BossGanondrof_SetupDeath(BossGanondrof* this, PlayState* play) {
Animation_PlayOnce(&this->skelAnime, &gPhantomGanonDeathBlowAnim);
this->fwork[GND_END_FRAME] = Animation_GetLastFrame(&gPhantomGanonDeathBlowAnim);
this->actionFunc = BossGanondrof_Death;
Audio_QueueSeqCmd(0x1 << 28 | SEQ_PLAYER_BGM_MAIN << 24 | 0x100FF);
Audio_PlayActorSound2(&this->actor, NA_SE_EN_FANTOM_DEAD);
this->deathState = DEATH_START;
this->actor.flags &= ~ACTOR_FLAG_0;
this->work[GND_VARIANCE_TIMER] = 0;
this->shockTimer = 50;
}
void BossGanondrof_Death(BossGanondrof* this, PlayState* play) {
u8 holdCamera = false;
u8 bodyDecayLevel = 0;
f32 camX;
f32 camZ;
f32 pad;
Player* player = GET_PLAYER(play);
Camera* camera = Play_GetCamera(play, 0);
osSyncPrintf("PYP %f\n", player->actor.floorHeight);
SkelAnime_Update(&this->skelAnime);
this->work[GND_DEATH_SFX_TIMER]++;
if (((60 < this->work[GND_DEATH_SFX_TIMER]) && (this->work[GND_DEATH_SFX_TIMER] < 500)) ||
((501 < this->work[GND_DEATH_SFX_TIMER]) && (this->work[GND_DEATH_SFX_TIMER] < 620))) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GOMA_LAST - SFX_FLAG);
}
switch (this->deathState) {
case DEATH_START:
func_80064520(play, &play->csCtx);
func_8002DF54(play, &this->actor, 1);
this->deathCamera = Play_CreateSubCamera(play);
Play_ChangeCameraStatus(play, MAIN_CAM, CAM_STAT_WAIT);
osSyncPrintf("7\n");
Play_ChangeCameraStatus(play, this->deathCamera, CAM_STAT_ACTIVE);
osSyncPrintf("8\n");
this->deathState = DEATH_THROES;
player->actor.speedXZ = 0.0f;
this->timers[0] = 50;
this->cameraEye = camera->eye;
this->cameraAt = camera->at;
this->cameraNextEye.x = this->targetPos.x;
this->cameraNextEye.y = GND_BOSSROOM_CENTER_Y + 83.0f;
this->cameraNextEye.z = (this->targetPos.z + 100.0f) + 50;
this->cameraNextAt.x = this->targetPos.x;
this->cameraNextAt.y = this->targetPos.y - 10.0f;
this->cameraNextAt.z = this->targetPos.z;
this->cameraEyeVel.x = fabsf(camera->eye.x - this->cameraNextEye.x);
this->cameraEyeVel.y = fabsf(camera->eye.y - this->cameraNextEye.y);
this->cameraEyeVel.z = fabsf(camera->eye.z - this->cameraNextEye.z);
this->cameraAtVel.x = fabsf(camera->at.x - this->cameraNextAt.x);
this->cameraAtVel.y = fabsf(camera->at.y - this->cameraNextAt.y);
this->cameraAtVel.z = fabsf(camera->at.z - this->cameraNextAt.z);
this->cameraAccel = 0.02f;
this->cameraEyeMaxVel.x = this->cameraEyeMaxVel.y = this->cameraEyeMaxVel.z = 0.05f;
this->work[GND_ACTION_STATE] = DEATH_SPASM;
this->timers[0] = 150;
this->cameraAtMaxVel.x = 0.2f;
this->cameraAtMaxVel.y = 0.2f;
this->cameraAtMaxVel.z = 0.2f;
case DEATH_THROES:
switch (this->work[GND_ACTION_STATE]) {
case DEATH_SPASM:
if (Animation_OnFrame(&this->skelAnime, this->fwork[GND_END_FRAME]) && !gSaveContext.n64ddFlag) {
this->fwork[GND_END_FRAME] = Animation_GetLastFrame(&gPhantomGanonAirDamageAnim);
Animation_Change(&this->skelAnime, &gPhantomGanonAirDamageAnim, 0.5f, 0.0f,
this->fwork[GND_END_FRAME], ANIMMODE_ONCE_INTERP, 0.0f);
this->work[GND_ACTION_STATE] = DEATH_LIMP;
} else if (gSaveContext.n64ddFlag) {
// Skip to death scream animation and move ganondrof to middle
this->deathState = DEATH_SCREAM;
this->timers[0] = 50;
Animation_MorphToLoop(&this->skelAnime, &gPhantomGanonScreamAnim, -10.0f);
this->actor.world.pos.x = GND_BOSSROOM_CENTER_X;
this->actor.world.pos.y = GND_BOSSROOM_CENTER_Y + 83.0f;
this->actor.world.pos.z = GND_BOSSROOM_CENTER_Z;
this->actor.shape.rot.y = 0;
this->work[GND_BODY_DECAY_INDEX] = 0;
Audio_PlayActorSound2(&this->actor, NA_SE_EN_FANTOM_LAST);
// Move Player out of the center of the room
player->actor.world.pos.x = GND_BOSSROOM_CENTER_X - 200.0f;
player->actor.world.pos.z = GND_BOSSROOM_CENTER_Z;
}
break;
case DEATH_LIMP:
if (Animation_OnFrame(&this->skelAnime, this->fwork[GND_END_FRAME])) {
this->fwork[GND_END_FRAME] = Animation_GetLastFrame(&gPhantomGanonLimpAnim);
Animation_MorphToLoop(&this->skelAnime, &gPhantomGanonLimpAnim, -20.0f);
this->work[GND_ACTION_STATE] = DEATH_HUNCHED;
}
case DEATH_HUNCHED:
bodyDecayLevel = 1;
break;
}
if (gSaveContext.n64ddFlag) {
break;
}
Math_ApproachS(&this->actor.shape.rot.y, this->work[GND_VARIANCE_TIMER] * -100, 5, 0xBB8);
Math_ApproachF(&this->cameraNextEye.z, this->targetPos.z + 60.0f, 0.02f, 0.5f);
Math_ApproachF(&this->actor.world.pos.y, GND_BOSSROOM_CENTER_Y + 133.0f, 0.05f, 100.0f);
this->actor.world.pos.y += Math_SinS(this->work[GND_VARIANCE_TIMER] * 1500);
this->cameraNextAt.x = this->targetPos.x;
this->cameraNextAt.y = this->targetPos.y - 10.0f;
this->cameraNextAt.z = this->targetPos.z;
if (this->timers[0] == 0) {
this->deathState = DEATH_WARP;
this->timers[0] = 350;
this->timers[1] = 50;
this->fwork[GND_CAMERA_ZOOM] = 300.0f;
this->cameraNextEye.y = GND_BOSSROOM_CENTER_Y + 233.0f;
player->actor.world.pos.x = GND_BOSSROOM_CENTER_X - 200.0f;
player->actor.world.pos.z = GND_BOSSROOM_CENTER_Z;
holdCamera = true;
bodyDecayLevel = 1;
}
break;
case DEATH_WARP:
if (this->timers[1] == 1) {
EnfHG* horseTemp = (EnfHG*)this->actor.child;
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_EN_FHG_FIRE,
GND_BOSSROOM_CENTER_X, GND_BOSSROOM_CENTER_Y + 3.0f, GND_BOSSROOM_CENTER_Z, 0x4000,
0, 0, FHGFIRE_WARP_DEATH);
this->actor.child = &horseTemp->actor;
Message_StartTextbox(play, 0x108E, NULL);
}
this->actor.shape.rot.y -= 0xC8;
this->actor.world.pos.y += Math_SinS(this->work[GND_VARIANCE_TIMER] * 1500);
this->fwork[GND_CAMERA_ANGLE] += 0x78;
camX = Math_SinS(this->fwork[GND_CAMERA_ANGLE]) * this->fwork[GND_CAMERA_ZOOM];
camZ = Math_CosS(this->fwork[GND_CAMERA_ANGLE]) * this->fwork[GND_CAMERA_ZOOM];
this->cameraEye.x = GND_BOSSROOM_CENTER_X + camX;
this->cameraEye.y = this->cameraNextEye.y;
this->cameraEye.z = GND_BOSSROOM_CENTER_Z + camZ;
this->cameraAt.x = GND_BOSSROOM_CENTER_X;
this->cameraAt.y = GND_BOSSROOM_CENTER_Y + 23.0f;
this->cameraAt.z = GND_BOSSROOM_CENTER_Z;
Math_ApproachF(&this->cameraNextEye.y, GND_BOSSROOM_CENTER_Y + 33.0f, 0.05f, 0.5f);
Math_ApproachF(&this->fwork[GND_CAMERA_ZOOM], 170.0f, 0.05f, 1.0f);
Math_ApproachF(&this->actor.world.pos.x, GND_BOSSROOM_CENTER_X, 0.05f, 1.5f);
Math_ApproachF(&this->actor.world.pos.y, GND_BOSSROOM_CENTER_Y + 83.0f, 0.05f, 1.0f);
Math_ApproachF(&this->actor.world.pos.z, GND_BOSSROOM_CENTER_Z, 0.05f, 1.5f);
if (this->timers[0] == 0) {
this->deathState = DEATH_SCREAM;
this->timers[0] = 50;
Animation_MorphToLoop(&this->skelAnime, &gPhantomGanonScreamAnim, -10.0f);
this->actor.world.pos.x = GND_BOSSROOM_CENTER_X;
this->actor.world.pos.y = GND_BOSSROOM_CENTER_Y + 83.0f;
this->actor.world.pos.z = GND_BOSSROOM_CENTER_Z;
this->actor.shape.rot.y = 0;
this->work[GND_BODY_DECAY_INDEX] = 0;
Audio_PlayActorSound2(&this->actor, NA_SE_EN_FANTOM_LAST);
}
holdCamera = true;
bodyDecayLevel = 1;
break;
case DEATH_SCREAM:
holdCamera = true;
bodyDecayLevel = 2;
this->actor.world.pos.y = GND_BOSSROOM_CENTER_Y + 83.0f;
this->cameraEye.x = GND_BOSSROOM_CENTER_X;
this->cameraEye.y = GND_BOSSROOM_CENTER_Y + 83.0f;
this->cameraEye.z = GND_BOSSROOM_CENTER_Z + 50.0f;
this->cameraAt.x = GND_BOSSROOM_CENTER_X;
this->cameraAt.y = GND_BOSSROOM_CENTER_Y + 103.0f;
this->cameraAt.z = GND_BOSSROOM_CENTER_Z;
if (this->timers[0] == 0) {
this->deathState = DEATH_DISINTEGRATE;
Animation_MorphToPlayOnce(&this->skelAnime, &gPhantomGanonLastPoseAnim, -10.0f);
this->work[GND_BODY_DECAY_INDEX] = 0;
this->timers[0] = 40;
}
break;
case DEATH_DISINTEGRATE:
holdCamera = true;
bodyDecayLevel = 3;
Math_ApproachZeroF(&this->cameraEye.y, 0.05f, 1.0f); // approaches GND_BOSSROOM_CENTER_Y + 33.0f
Math_ApproachF(&this->cameraEye.z, GND_BOSSROOM_CENTER_Z + 170.0f, 0.05f, 2.0f);
Math_ApproachF(&this->cameraAt.y, GND_BOSSROOM_CENTER_Y + 53.0f, 0.05f, 1.0f);
if (this->timers[0] == 0) {
this->timers[0] = 250;
this->deathState = DEATH_FINISH;
}
break;
case DEATH_FINISH:
holdCamera = true;
bodyDecayLevel = 10;
if (this->timers[0] == 150) {
Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_BOSS_CLEAR);
Actor_Spawn(&play->actorCtx, play, ACTOR_DOOR_WARP1, GND_BOSSROOM_CENTER_X,
GND_BOSSROOM_CENTER_Y, GND_BOSSROOM_CENTER_Z, 0, 0, 0, WARP_DUNGEON_ADULT, true);
}
Math_ApproachZeroF(&this->cameraEye.y, 0.05f, 1.0f); // GND_BOSSROOM_CENTER_Y + 33.0f
Math_ApproachF(&this->cameraEye.z, GND_BOSSROOM_CENTER_Z + 170.0f, 0.05f, 2.0f);
Math_ApproachF(&this->cameraAt.y, GND_BOSSROOM_CENTER_Y + 53.0f, 0.05f, 1.0f);
if (this->timers[0] == 0) {
EnfHG* horse = (EnfHG*)this->actor.child;
camera->eye = this->cameraEye;
camera->eyeNext = this->cameraEye;
camera->at = this->cameraAt;
func_800C08AC(play, this->deathCamera, 0);
this->deathCamera = 0;
func_80064534(play, &play->csCtx);
func_8002DF54(play, &this->actor, 7);
Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_B_HEART, GND_BOSSROOM_CENTER_X,
GND_BOSSROOM_CENTER_Y, GND_BOSSROOM_CENTER_Z + 200.0f, 0, 0, 0, 0, true);
this->actor.child = &horse->actor;
this->killActor = true;
horse->killActor = true;
Flags_SetClear(play, play->roomCtx.curRoom.num);
Flags_SetSwitch(play, 0x22);
}
break;
}
if (bodyDecayLevel) {
Vec3f pos;
Vec3f vel = { 0.0f, 0.0f, 0.0f };
Vec3f accelKFire = { 0.0f, 0.0f, 0.0f };
Vec3f accelHahen = { 0.0f, -0.5f, 0.0f };
s16 limbDecayIndex;
s16 i;
vel.x = this->actor.world.pos.x - this->actor.prevPos.x;
vel.z = this->actor.world.pos.z - this->actor.prevPos.z;
if (bodyDecayLevel < 10) {
if (this->work[GND_DEATH_ENV_TIMER] == 0) {
if (play->envCtx.unk_BF == 0) {
play->envCtx.unk_BF = 3;
this->work[GND_DEATH_ENV_TIMER] = (s16)Rand_ZeroFloat(5.0f) + 4.0f;
play->envCtx.unk_D6 = 0x28;
} else {
play->envCtx.unk_BF = 0;
this->work[GND_DEATH_ENV_TIMER] = (s16)Rand_ZeroFloat(2.0f) + 2.0f;
play->envCtx.unk_D6 = 0x14;
}
} else {
this->work[GND_DEATH_ENV_TIMER]--;
}
for (i = 0; i <= 0; i++) {
limbDecayIndex = this->work[GND_LIMB_DECAY_INDEX];
this->work[GND_LIMB_DECAY_INDEX]++;
this->work[GND_LIMB_DECAY_INDEX] %= 25;
pos.x = this->bodyPartsPos[limbDecayIndex].x + Rand_CenteredFloat(5.0f);
pos.y = this->bodyPartsPos[limbDecayIndex].y + Rand_CenteredFloat(5.0f);
pos.z = this->bodyPartsPos[limbDecayIndex].z + Rand_CenteredFloat(5.0f);
accelKFire.y = 0.0f;
if (bodyDecayLevel == 3) {
accelKFire.y = -0.2f;
accelKFire.x = (GND_BOSSROOM_CENTER_X - pos.x) * 0.002f;
accelKFire.z = (GND_BOSSROOM_CENTER_Z - pos.z) * 0.002f;
accelHahen.x = (GND_BOSSROOM_CENTER_X - pos.x) * 0.001f;
accelHahen.y = -1.0f;
accelHahen.z = (GND_BOSSROOM_CENTER_Z - pos.z) * 0.001f;
}
EffectSsKFire_Spawn(play, &pos, &vel, &accelKFire, (s16)Rand_ZeroFloat(20.0f) + 15,
bodyDecayLevel);
if ((Rand_ZeroOne() < 0.5f) || (bodyDecayLevel == 3)) {
EffectSsHahen_Spawn(play, &pos, &vel, &accelHahen, 0, (s16)Rand_ZeroFloat(4.0f) + 7,
HAHEN_OBJECT_DEFAULT, 10, NULL);
}
}
} else {
play->envCtx.unk_BF = 0;
play->envCtx.unk_D6 = 0x14;
}
this->work[GND_BODY_DECAY_FLAG] = true;
for (i = 0; i < 5; i++) {
if (bodyDecayLevel == 1) {
BossGanondrof_ClearPixels(sDecayMaskLow, this->work[GND_BODY_DECAY_INDEX]);
} else if (bodyDecayLevel == 2) {
BossGanondrof_ClearPixels(sDecayMaskHigh, this->work[GND_BODY_DECAY_INDEX]);
} else {
BossGanondrof_ClearPixels(sDecayMaskTotal, this->work[GND_BODY_DECAY_INDEX]);
}
if (this->work[GND_BODY_DECAY_INDEX] < 0xFF) {
this->work[GND_BODY_DECAY_INDEX]++;
}
}
}
if (this->deathCamera != 0) {
if (!holdCamera) {
Math_ApproachF(&this->cameraEye.x, this->cameraNextEye.x, this->cameraEyeMaxVel.x,
this->cameraEyeVel.x * this->cameraSpeedMod);
Math_ApproachF(&this->cameraEye.y, this->cameraNextEye.y, this->cameraEyeMaxVel.y,
this->cameraEyeVel.y * this->cameraSpeedMod);
Math_ApproachF(&this->cameraEye.z, this->cameraNextEye.z, this->cameraEyeMaxVel.z,
this->cameraEyeVel.z * this->cameraSpeedMod);
Math_ApproachF(&this->cameraAt.x, this->cameraNextAt.x, this->cameraAtMaxVel.x,
this->cameraAtVel.x * this->cameraSpeedMod);
Math_ApproachF(&this->cameraAt.y, this->cameraNextAt.y, this->cameraAtMaxVel.y,
this->cameraAtVel.y * this->cameraSpeedMod);
Math_ApproachF(&this->cameraAt.z, this->cameraNextAt.z, this->cameraAtMaxVel.z,
this->cameraAtVel.z * this->cameraSpeedMod);
Math_ApproachF(&this->cameraSpeedMod, 1.0f, 1.0f, this->cameraAccel);
}
Play_CameraSetAtEye(play, this->deathCamera, &this->cameraAt, &this->cameraEye);
}
}
void BossGanondrof_CollisionCheck(BossGanondrof* this, PlayState* play) {
s32 acHit;
EnfHG* horse = (EnfHG*)this->actor.child;
ColliderInfo* hurtbox;
if (this->work[GND_INVINC_TIMER] != 0) {
this->work[GND_INVINC_TIMER]--;
this->returnCount = 0;
this->colliderBody.base.acFlags &= ~AC_HIT;
} else {
acHit = this->colliderBody.base.acFlags & AC_HIT;
if ((acHit && ((s8)this->actor.colChkInfo.health > 0)) || (this->returnCount != 0)) {
if (acHit) {
this->colliderBody.base.acFlags &= ~AC_HIT;
hurtbox = this->colliderBody.info.acHitInfo;
}
if (this->flyMode != GND_FLY_PAINTING) {
if (acHit && (this->actionFunc != BossGanondrof_Stunned) && (hurtbox->toucher.dmgFlags & 0x0001F8A4)) {
Audio_PlayActorSound2(&this->actor, NA_SE_PL_WALK_GROUND - SFX_FLAG);
osSyncPrintf("hit != 0 \n");
} else if (this->actionFunc != BossGanondrof_Charge) {
if (this->returnCount == 0) {
u8 dmg;
u8 canKill = false;
s32 dmgFlags = hurtbox->toucher.dmgFlags;
if (dmgFlags & 0x80) {
return;
}
dmg = CollisionCheck_GetSwordDamage(dmgFlags, play);
(dmg == 0) ? (dmg = 2) : (canKill = true);
if (((s8)this->actor.colChkInfo.health > 2) || canKill) {
this->actor.colChkInfo.health -= dmg;
}
if ((s8)this->actor.colChkInfo.health <= 0) {
BossGanondrof_SetupDeath(this, play);
Enemy_StartFinishingBlow(play, &this->actor);
gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_PHANTOM_GANON] = GAMEPLAYSTAT_TOTAL_TIME;
return;
}
}
BossGanondrof_SetupStunned(this, play);
if (this->returnCount >= 2) {
this->timers[0] = 120;
}
this->work[GND_INVINC_TIMER] = 10;
horse->hitTimer = 20;
Audio_PlayActorSound2(&this->actor, NA_SE_EN_FANTOM_DAMAGE);
} else {
Audio_PlayActorSound2(&this->actor, NA_SE_PL_WALK_GROUND - SFX_FLAG);
}
} else if (acHit && (hurtbox->toucher.dmgFlags & 0x0001F8A4)) {
this->work[GND_INVINC_TIMER] = 10;
this->actor.colChkInfo.health -= 2;
horse->hitTimer = 20;
Audio_PlayActorSound2(&this->actor, NA_SE_EN_FANTOM_DAMAGE);
}
this->returnCount = 0;
}
}
}
void BossGanondrof_Update(Actor* thisx, PlayState* play) {
f32 cs;
f32 sn;
f32 legRotTargetY;
f32 legRotTargetZ;
f32 legSplitTarget;
s32 pad2;
s16 i;
s32 pad;
BossGanondrof* this = (BossGanondrof*)thisx;
EnfHG* horse;
osSyncPrintf("MOVE START %d\n", this->actor.params);
this->actor.flags &= ~ACTOR_FLAG_10;
this->colliderBody.base.colType = COLTYPE_HIT3;
if (this->killActor) {
Actor_Kill(&this->actor);
return;
}
this->work[GND_VARIANCE_TIMER]++;
horse = (EnfHG*)this->actor.child;
osSyncPrintf("MOVE START EEEEEEEEEEEEEEEEEEEEEE%d\n", this->actor.params);
this->actionFunc(this, play);
for (i = 0; i < ARRAY_COUNT(this->timers); i++) {
if (this->timers[i]) {
this->timers[i]--;
}
}
if (this->work[GND_UNKTIMER_1]) {
this->work[GND_UNKTIMER_1]--;
}
if (this->work[GND_UNKTIMER_2]) {
this->work[GND_UNKTIMER_2]--;
}
if (this->actionFunc != BossGanondrof_Death) {
BossGanondrof_CollisionCheck(this, play);
}
osSyncPrintf("MOVE END\n");
BossGanondrof_SetColliderPos(&this->targetPos, &this->colliderBody);
BossGanondrof_SetColliderPos(&this->spearTip, &this->colliderSpear);
if ((this->flyMode == GND_FLY_PAINTING) && !horse->bossGndInPainting) {
CollisionCheck_SetAC(play, &play->colChkCtx, &this->colliderBody.base);
}
if ((this->actionFunc == BossGanondrof_Stunned) && (this->timers[0] > 1)) {
CollisionCheck_SetAC(play, &play->colChkCtx, &this->colliderBody.base);
CollisionCheck_SetOC(play, &play->colChkCtx, &this->colliderBody.base);
} else if (this->actionFunc == BossGanondrof_Block) {
CollisionCheck_SetAC(play, &play->colChkCtx, &this->colliderBody.base);
} else if (this->actionFunc == BossGanondrof_Charge) {
CollisionCheck_SetAC(play, &play->colChkCtx, &this->colliderBody.base);
CollisionCheck_SetAT(play, &play->colChkCtx, &this->colliderBody.base);
CollisionCheck_SetAT(play, &play->colChkCtx, &this->colliderSpear.base);
}
this->actor.focus.pos = this->targetPos;
sn = Math_SinS(-this->actor.shape.rot.y);
cs = Math_CosS(-this->actor.shape.rot.y);
legRotTargetY = ((sn * this->actor.velocity.z) + (cs * this->actor.velocity.x)) * 300.0f;
legRotTargetZ = ((-sn * this->actor.velocity.x) + (cs * this->actor.velocity.z)) * 300.0f;
Math_ApproachF(&this->legRotY, legRotTargetY, 1.0f, 600.0f);
Math_ApproachF(&this->legRotZ, legRotTargetZ, 1.0f, 600.0f);
if ((this->flyMode != GND_FLY_PAINTING) && (this->actionFunc != BossGanondrof_Stunned) &&
(this->deathState == NOT_DEAD)) {
legSplitTarget = (Math_SinS(this->work[GND_VARIANCE_TIMER] * 0x8DC) * -500.0f) - 500.0f;
} else {
legSplitTarget = 0.0f;
}
Math_ApproachF(&this->legSplitY, legSplitTarget, 1.0f, 100.0f);
if (this->shockTimer != 0) {
s16 j;
this->shockTimer--;
osSyncPrintf("F 1\n");
for (j = 0; j < 7; j++) {
osSyncPrintf("F 15\n");
EffectSsFhgFlash_SpawnShock(play, &this->actor, &this->actor.world.pos, 45, FHGFLASH_SHOCK_PG);
}
osSyncPrintf("F 2\n");
}
if (this->actor.params == GND_REAL_BOSS) {
Lights_PointNoGlowSetInfo(&this->lightInfo, this->spearTip.x, this->spearTip.y, this->spearTip.z, 255, 255, 255,
200);
}
}
s32 BossGanondrof_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot,
void* thisx) {
BossGanondrof* this = (BossGanondrof*)thisx;
switch (limbIndex) {
case 15:
if ((this->actionFunc == BossGanondrof_Intro) && this->work[GND_MASK_OFF]) {
*dList = gPhantomGanonFaceDL;
}
rot->y += this->rideRotY[limbIndex];
rot->z += this->rideRotZ[limbIndex];
break;
case 19:
rot->y += this->legRotY + this->legSplitY;
rot->z += this->legRotZ;
break;
case 20:
rot->y += this->legRotY + this->legSplitY;
rot->z += this->legRotZ;
break;
case 21:
rot->y += this->legRotY + this->legSplitY;
rot->z += this->legRotZ;
break;
case 23:
rot->y += this->legRotY - this->legSplitY;
rot->z += this->legRotZ;
break;
case 24:
rot->y += this->legRotY - this->legSplitY;
rot->z += this->legRotZ;
break;
case 25:
rot->y += this->legRotY - this->legSplitY;
rot->z += this->legRotZ;
break;
case 5:
case 6:
case 7:
rot->y += this->armRotY;
rot->z += this->armRotZ;
break;
case 8:
case 9:
case 10:
rot->y += this->armRotY;
rot->z += this->armRotZ;
break;
case 13:
if (this->deathState != NOT_DEAD) {
*dList = NULL;
}
default:
rot->y += this->rideRotY[limbIndex];
rot->z += this->rideRotZ[limbIndex];
break;
}
return 0;
}
void BossGanondrof_PostLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) {
static Vec3f zeroVec = { 0.0f, 0.0f, 0.0f };
static Vec3f spearVec = { 0.0f, 0.0f, 6000.0f };
BossGanondrof* this = (BossGanondrof*)thisx;
if (limbIndex == 14) {
Matrix_MultVec3f(&zeroVec, &this->targetPos);
} else if (limbIndex == 13) {
Matrix_MultVec3f(&spearVec, &this->spearTip);
}
if (((this->flyMode != GND_FLY_PAINTING) || (this->actionFunc == BossGanondrof_Intro)) && (limbIndex <= 25)) {
Matrix_MultVec3f(&zeroVec, &this->bodyPartsPos[limbIndex - 1]);
}
}
Gfx* BossGanondrof_GetClearPixelDList(GraphicsContext* gfxCtx) {
Gfx* dList = (Gfx*)Graph_Alloc(gfxCtx, sizeof(Gfx) * 4);
Gfx* dListHead = dList;
gDPPipeSync(dListHead++);
gDPSetRenderMode(dListHead++, G_RM_FOG_SHADE_A, G_RM_AA_ZB_TEX_EDGE2);
gSPClearGeometryMode(dListHead++, G_CULL_BACK);
gSPEndDisplayList(dListHead++);
return dList;
}
Gfx* BossGanondrof_GetNullDList(GraphicsContext* gfxCtx) {
Gfx* dList = (Gfx*)Graph_Alloc(gfxCtx, sizeof(Gfx) * 1);
Gfx* dListHead = dList;
gSPEndDisplayList(dListHead++);
return dList;
}
void BossGanondrof_Draw(Actor* thisx, PlayState* play) {
s32 pad;
BossGanondrof* this = (BossGanondrof*)thisx;
EnfHG* horse;
OPEN_DISPS(play->state.gfxCtx);
if (this->work[GND_BODY_DECAY_FLAG]) {
gSPInvalidateTexCache(POLY_OPA_DISP++, sDecayTex);
}
osSyncPrintf("MOVE P = %x\n", this->actor.update);
osSyncPrintf("STOP TIMER = %d ==============\n", this->actor.freezeTimer);
horse = (EnfHG*)this->actor.child;
if (this->flyMode == GND_FLY_PAINTING) {
Matrix_RotateY((horse->turnRot * 3.1416f) / (f32)0x8000, MTXMODE_APPLY);
}
osSyncPrintf("YP %f\n", this->actor.world.pos.y);
Gfx_SetupDL_25Opa(play->state.gfxCtx);
if (this->work[GND_INVINC_TIMER] & 4) {
POLY_OPA_DISP = Gfx_SetFog(POLY_OPA_DISP, 255, 50, 0, 0, 900, 1099);
} else {
POLY_OPA_DISP = Gfx_SetFog(POLY_OPA_DISP, (u32)horse->warpColorFilterR, (u32)horse->warpColorFilterG,
(u32)horse->warpColorFilterB, 0, (s32)horse->warpColorFilterUnk1 + 995,
(s32)horse->warpColorFilterUnk2 + 1000);
}
osSyncPrintf("DRAW 11\n");
osSyncPrintf("EYE_COL %d\n", (s16)this->fwork[GND_EYE_BRIGHTNESS]);
gDPSetEnvColor(POLY_OPA_DISP++, (s16)this->fwork[GND_EYE_BRIGHTNESS], (s16)this->fwork[GND_EYE_BRIGHTNESS],
(s16)this->fwork[GND_EYE_BRIGHTNESS], (s16)this->fwork[GND_EYE_ALPHA]);
if (this->work[GND_BODY_DECAY_FLAG]) {
gSPSegment(POLY_OPA_DISP++, 0x08, BossGanondrof_GetClearPixelDList(play->state.gfxCtx));
} else {
gSPSegment(POLY_OPA_DISP++, 0x08, BossGanondrof_GetNullDList(play->state.gfxCtx));
}
SkelAnime_DrawOpa(play, this->skelAnime.skeleton, this->skelAnime.jointTable, BossGanondrof_OverrideLimbDraw,
BossGanondrof_PostLimbDraw, this);
osSyncPrintf("DRAW 22\n");
POLY_OPA_DISP = Play_SetFog(play, POLY_OPA_DISP);
CLOSE_DISPS(play->state.gfxCtx);
osSyncPrintf("DRAW END %d\n", this->actor.params);
}