mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2024-08-13 17:03:47 -04:00
45e5e5ca72
* Experimental 60 fps * Fix compile error * Fix compile error * Fix compile error
5053 lines
189 KiB
C
5053 lines
189 KiB
C
#include "z_boss_ganon.h"
|
|
#include "overlays/ovl_Boss_Ganon/ovl_Boss_Ganon.h"
|
|
#include "overlays/actors/ovl_En_Ganon_Mant/z_en_ganon_mant.h"
|
|
#include "overlays/actors/ovl_En_Zl3/z_en_zl3.h"
|
|
#include "overlays/actors/ovl_Bg_Ganon_Otyuka/z_bg_ganon_otyuka.h"
|
|
#include "overlays/actors/ovl_En_Bom/z_en_bom.h"
|
|
#include "assets/objects/object_ganon/object_ganon.h"
|
|
#include "assets/objects/object_ganon_anime1/object_ganon_anime1.h"
|
|
#include "assets/objects/object_ganon_anime2/object_ganon_anime2.h"
|
|
#include "assets/scenes/dungeons/ganon_boss/ganon_boss_scene.h"
|
|
|
|
#include "soh/frame_interpolation.h"
|
|
|
|
#include <string.h>
|
|
|
|
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_2 | ACTOR_FLAG_4 | ACTOR_FLAG_5)
|
|
|
|
void BossGanon_Init(Actor* thisx, GlobalContext* globalCtx);
|
|
void BossGanon_Destroy(Actor* thisx, GlobalContext* globalCtx);
|
|
void BossGanon_Update(Actor* thisx, GlobalContext* globalCtx);
|
|
void BossGanon_Draw(Actor* thisx, GlobalContext* globalCtx);
|
|
void func_808E1EB4(Actor* thisx, GlobalContext* globalCtx); // update
|
|
void func_808E2544(Actor* thisx, GlobalContext* globalCtx); // update
|
|
void BossGanon_LightBall_Update(Actor* thisx, GlobalContext* globalCtx);
|
|
void func_808E229C(Actor* thisx, GlobalContext* globalCtx); // draw
|
|
void func_808E324C(Actor* thisx, GlobalContext* globalCtx); // draw
|
|
void BossGanon_LightBall_Draw(Actor* thisx, GlobalContext* globalCtx);
|
|
void BossGanon_Reset(void);
|
|
|
|
|
|
void BossGanon_SetupIntroCutscene(BossGanon* this, GlobalContext* globalCtx);
|
|
void BossGanon_SetupTowerCutscene(BossGanon* this, GlobalContext* globalCtx);
|
|
void BossGanon_IntroCutscene(BossGanon* this, GlobalContext* globalCtx);
|
|
void BossGanon_DeathAndTowerCutscene(BossGanon* this, GlobalContext* globalCtx);
|
|
void BossGanon_Wait(BossGanon* this, GlobalContext* globalCtx);
|
|
void BossGanon_ChargeLightBall(BossGanon* this, GlobalContext* globalCtx);
|
|
void BossGanon_PlayTennis(BossGanon* this, GlobalContext* globalCtx);
|
|
void BossGanon_PoundFloor(BossGanon* this, GlobalContext* globalCtx);
|
|
void BossGanon_ChargeBigMagic(BossGanon* this, GlobalContext* globalCtx);
|
|
void BossGanon_Block(BossGanon* this, GlobalContext* globalCtx);
|
|
void BossGanon_HitByLightBall(BossGanon* this, GlobalContext* globalCtx);
|
|
void BossGanon_Vulnerable(BossGanon* this, GlobalContext* globalCtx);
|
|
void BossGanon_Damaged(BossGanon* this, GlobalContext* globalCtx);
|
|
|
|
void BossGanon_SetupWait(BossGanon* this, GlobalContext* globalCtx);
|
|
void BossGanon_SetupChargeLightBall(BossGanon* this, GlobalContext* globalCtx);
|
|
void BossGanon_SetupPlayTennis(BossGanon* this, GlobalContext* globalCtx);
|
|
|
|
void BossGanon_DrawEffects(GlobalContext* globalCtx);
|
|
void BossGanon_UpdateEffects(GlobalContext* globalCtx);
|
|
|
|
s32 BossGanon_CheckFallingPlatforms(BossGanon* this, GlobalContext* globalCtx, Vec3f* checkPos);
|
|
|
|
const ActorInit Boss_Ganon_InitVars = {
|
|
ACTOR_BOSS_GANON,
|
|
ACTORCAT_BOSS,
|
|
FLAGS,
|
|
OBJECT_GANON,
|
|
sizeof(BossGanon),
|
|
(ActorFunc)BossGanon_Init,
|
|
(ActorFunc)BossGanon_Destroy,
|
|
(ActorFunc)BossGanon_Update,
|
|
(ActorFunc)BossGanon_Draw,
|
|
(ActorResetFunc)BossGanon_Reset,
|
|
};
|
|
|
|
static ColliderCylinderInit sDorfCylinderInit = {
|
|
{
|
|
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,
|
|
},
|
|
{ 20, 80, -50, { 0, 0, 0 } },
|
|
};
|
|
|
|
static ColliderCylinderInit sLightBallCylinderInit = {
|
|
{
|
|
COLTYPE_NONE,
|
|
AT_ON | AT_TYPE_ENEMY,
|
|
AC_ON | AC_TYPE_PLAYER,
|
|
OC1_ON | OC1_TYPE_ALL,
|
|
OC2_TYPE_1,
|
|
COLSHAPE_CYLINDER,
|
|
},
|
|
{
|
|
ELEMTYPE_UNK6,
|
|
{ 0x00100700, 0x00, 0x08 },
|
|
{ 0x0D900740, 0x00, 0x00 },
|
|
TOUCH_ON | TOUCH_SFX_NORMAL,
|
|
BUMP_ON,
|
|
OCELEM_ON,
|
|
},
|
|
{ 20, 30, -15, { 0, 0, 0 } },
|
|
};
|
|
|
|
static u8 D_808E4C58[] = { 0, 12, 10, 12, 14, 16, 12, 14, 16, 12, 14, 16, 12, 14, 16, 10, 16, 14 };
|
|
static Vec3f sZeroVec = { 0.0f, 0.0f, 0.0f };
|
|
|
|
EnGanonMant* sBossGanonCape;
|
|
|
|
s32 sBossGanonSeed1;
|
|
s32 sBossGanonSeed3;
|
|
s32 sBossGanonSeed2;
|
|
|
|
BossGanon* sBossGanonGanondorf;
|
|
|
|
EnZl3* sBossGanonZelda;
|
|
|
|
GanondorfEffect sBossGanonEffectBuf[200];
|
|
|
|
void BossGanonEff_SpawnWindowShard(GlobalContext* globalCtx, Vec3f* pos, Vec3f* velocity, f32 scale) {
|
|
static Color_RGB8 shardColors[] = { { 255, 175, 85 }, { 155, 205, 155 }, { 155, 125, 55 } };
|
|
s16 i;
|
|
GanondorfEffect* eff = globalCtx->specialEffects;
|
|
Color_RGB8* color;
|
|
|
|
for (i = 0; i < 200; i++, eff++) {
|
|
if (eff->type == GDF_EFF_NONE) {
|
|
eff->type = GDF_EFF_WINDOW_SHARD;
|
|
eff->pos = *pos;
|
|
eff->velocity = *velocity;
|
|
eff->accel = sZeroVec;
|
|
eff->scale = scale;
|
|
eff->accel.y = -1.5f;
|
|
eff->unk_44 = Rand_ZeroFloat(6.28f);
|
|
eff->unk_48 = Rand_ZeroFloat(6.28f);
|
|
color = &shardColors[(s16)Rand_ZeroFloat(2.99f)];
|
|
eff->color.r = color->r;
|
|
eff->color.g = color->g;
|
|
eff->color.b = color->b;
|
|
eff->timer = (s16)Rand_ZeroFloat(20.0f);
|
|
eff->epoch++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossGanonEff_SpawnSparkle(GlobalContext* globalCtx, Vec3f* pos, Vec3f* velocity, Vec3f* accel, f32 scale,
|
|
s16 arg6) {
|
|
s16 i;
|
|
GanondorfEffect* eff = globalCtx->specialEffects;
|
|
|
|
for (i = 0; i < 150; i++, eff++) {
|
|
if (eff->type == GDF_EFF_NONE) {
|
|
eff->type = GDF_EFF_SPARKLE;
|
|
eff->pos = *pos;
|
|
eff->velocity = *velocity;
|
|
eff->accel = *accel;
|
|
eff->scale = scale / 1000.0f;
|
|
eff->unk_2E = (s16)Rand_ZeroFloat(100.0f) + 0xC8;
|
|
eff->unk_30 = arg6;
|
|
eff->timer = (s16)Rand_ZeroFloat(10.0f);
|
|
eff->epoch++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossGanonEff_SpawnLightRay(GlobalContext* globalCtx, Vec3f* pos, Vec3f* velocity, Vec3f* accel, f32 scale,
|
|
f32 arg5, s16 arg6) {
|
|
s16 i;
|
|
GanondorfEffect* eff = globalCtx->specialEffects;
|
|
|
|
for (i = 0; i < 150; i++, eff++) {
|
|
if (eff->type == GDF_EFF_NONE) {
|
|
eff->type = GDF_EFF_LIGHT_RAY;
|
|
eff->pos = *pos;
|
|
eff->velocity = *velocity;
|
|
eff->accel = *accel;
|
|
eff->scale = scale / 1000.0f;
|
|
eff->unk_38 = 1.0f;
|
|
eff->unk_40 = arg5;
|
|
eff->unk_2E = (s16)Rand_ZeroFloat(100.0f) + 0xC8;
|
|
eff->unk_30 = arg6;
|
|
eff->timer = (s16)Rand_ZeroFloat(10.0f);
|
|
eff->unk_48 = Math_Atan2F(eff->velocity.z, eff->velocity.x);
|
|
eff->unk_44 = -Math_Atan2F(sqrtf(SQXZ(eff->velocity)), eff->velocity.y);
|
|
eff->epoch++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossGanonEff_SpawnShock(GlobalContext* globalCtx, f32 scale, s16 shockType) {
|
|
s16 i;
|
|
GanondorfEffect* eff = globalCtx->specialEffects;
|
|
|
|
for (i = 0; i < 75; i++, eff++) {
|
|
if (eff->type == GDF_EFF_NONE) {
|
|
eff->type = GDF_EFF_SHOCK;
|
|
eff->pos = sZeroVec;
|
|
eff->pos.y = -2000.0f;
|
|
eff->velocity = sZeroVec;
|
|
eff->accel = sZeroVec;
|
|
eff->scale = scale / 1000.0f;
|
|
eff->unk_2E = shockType;
|
|
eff->timer = 0;
|
|
eff->epoch++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossGanonEff_SpawnLightning(GlobalContext* globalCtx, f32 scale, f32 arg2, f32 arg3) {
|
|
s16 i;
|
|
GanondorfEffect* eff = globalCtx->specialEffects;
|
|
|
|
for (i = 0; i < 150; i++, eff++) {
|
|
if (eff->type == GDF_EFF_NONE) {
|
|
eff->type = GDF_EFF_LIGHTNING;
|
|
eff->velocity = sZeroVec;
|
|
eff->accel = sZeroVec;
|
|
eff->unk_2E = 0;
|
|
eff->scale = scale;
|
|
eff->unk_48 = arg2;
|
|
eff->unk_3C = arg3;
|
|
eff->timer = 0;
|
|
eff->epoch++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossGanonEff_SpawnDustDark(GlobalContext* globalCtx, Vec3f* pos, f32 scale, f32 arg3) {
|
|
s16 i;
|
|
GanondorfEffect* eff = globalCtx->specialEffects;
|
|
|
|
for (i = 0; i < 150; i++, eff++) {
|
|
if (eff->type == GDF_EFF_NONE) {
|
|
eff->type = GDF_EFF_IMPACT_DUST_DARK;
|
|
eff->pos = *pos;
|
|
eff->velocity = sZeroVec;
|
|
eff->accel = sZeroVec;
|
|
eff->scale = scale;
|
|
eff->unk_40 = 1.0f;
|
|
eff->unk_38 = arg3;
|
|
eff->unk_30 = (s16)Rand_ZeroFloat(100.0f);
|
|
eff->unk_2E = eff->timer = eff->alpha = 0;
|
|
eff->epoch++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossGanonEff_SpawnDustLight(GlobalContext* globalCtx, Vec3f* pos, f32 scale, f32 arg3, s16 bufIndex) {
|
|
GanondorfEffect* effArr = globalCtx->specialEffects;
|
|
|
|
effArr[bufIndex].type = GDF_EFF_IMPACT_DUST_LIGHT;
|
|
effArr[bufIndex].pos = *pos;
|
|
effArr[bufIndex].velocity = sZeroVec;
|
|
effArr[bufIndex].accel = sZeroVec;
|
|
effArr[bufIndex].unk_40 = 1.0f;
|
|
effArr[bufIndex].scale = scale;
|
|
effArr[bufIndex].unk_38 = arg3;
|
|
effArr[bufIndex].unk_30 = Rand_ZeroFloat(100.0f);
|
|
effArr[bufIndex].unk_2E = effArr[bufIndex].timer = effArr[bufIndex].alpha = 0;
|
|
effArr[bufIndex].epoch++;
|
|
}
|
|
|
|
void BossGanonEff_SpawnShockwave(GlobalContext* globalCtx, Vec3f* pos, f32 scale, f32 arg3) {
|
|
s16 i;
|
|
GanondorfEffect* eff = globalCtx->specialEffects;
|
|
|
|
for (i = 0; i < 150; i++, eff++) {
|
|
if (eff->type == GDF_EFF_NONE) {
|
|
eff->type = GDF_EFF_SHOCKWAVE;
|
|
eff->pos = *pos;
|
|
eff->velocity = sZeroVec;
|
|
eff->accel = sZeroVec;
|
|
eff->alpha = 255;
|
|
eff->unk_40 = 0.6f;
|
|
eff->scale = scale;
|
|
eff->unk_38 = arg3;
|
|
eff->unk_30 = (s16)Rand_ZeroFloat(100.0f);
|
|
eff->unk_2E = eff->timer = 0;
|
|
eff->epoch++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossGanonEff_SpawnBlackDot(GlobalContext* globalCtx, Vec3f* pos, f32 scale) {
|
|
s16 i;
|
|
GanondorfEffect* eff = globalCtx->specialEffects;
|
|
|
|
for (i = 0; i < 150; i++, eff++) {
|
|
if (eff->type == GDF_EFF_NONE) {
|
|
eff->type = GDF_EFF_BLACK_DOT;
|
|
eff->pos = *pos;
|
|
eff->velocity = sZeroVec;
|
|
eff->accel = sZeroVec;
|
|
eff->unk_38 = 0.0f;
|
|
eff->scale = scale / 1000.0f;
|
|
eff->timer = 0;
|
|
eff->alpha = 0;
|
|
eff->unk_2E = 0;
|
|
eff->epoch++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossGanon_SetColliderPos(Vec3f* pos, ColliderCylinder* collider) {
|
|
collider->dim.pos.x = pos->x;
|
|
collider->dim.pos.y = pos->y;
|
|
collider->dim.pos.z = pos->z;
|
|
}
|
|
|
|
void BossGanon_SetAnimationObject(BossGanon* this, GlobalContext* globalCtx, s32 objectId) {
|
|
this->animBankIndex = Object_GetIndex(&globalCtx->objectCtx, objectId);
|
|
gSegments[6] = VIRTUAL_TO_PHYSICAL(globalCtx->objectCtx.status[this->animBankIndex].segment);
|
|
}
|
|
|
|
static InitChainEntry sInitChain[] = {
|
|
ICHAIN_U8(targetMode, 5, ICHAIN_CONTINUE),
|
|
ICHAIN_S8(naviEnemyId, 0x3D, ICHAIN_CONTINUE),
|
|
ICHAIN_F32_DIV1000(gravity, 0, ICHAIN_CONTINUE),
|
|
ICHAIN_F32(targetArrowOffset, 0, ICHAIN_STOP),
|
|
};
|
|
|
|
void BossGanon_Init(Actor* thisx, GlobalContext* globalCtx2) {
|
|
s16 i;
|
|
GlobalContext* globalCtx = globalCtx2;
|
|
BossGanon* this = (BossGanon*)thisx;
|
|
s32 cond;
|
|
f32 xDistFromPlayer;
|
|
f32 yDistFromPlayer;
|
|
f32 zDistFromPlayer;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
|
|
if (thisx->params < 0x64) {
|
|
Flags_SetSwitch(globalCtx, 0x14);
|
|
globalCtx->specialEffects = sBossGanonEffectBuf;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(sBossGanonEffectBuf); i++) {
|
|
sBossGanonEffectBuf[i].type = GDF_EFF_NONE;
|
|
}
|
|
|
|
sBossGanonGanondorf = this;
|
|
thisx->colChkInfo.health = 40;
|
|
Actor_ProcessInitChain(thisx, sInitChain);
|
|
ActorShape_Init(&thisx->shape, 0, NULL, 0);
|
|
Actor_SetScale(thisx, 0.01f);
|
|
SkelAnime_InitFlex(globalCtx, &this->skelAnime, &gDorfSkel, NULL, NULL, NULL, 0);
|
|
Collider_InitCylinder(globalCtx, &this->collider);
|
|
Collider_SetCylinder(globalCtx, &this->collider, thisx, &sDorfCylinderInit);
|
|
|
|
if (thisx->params != 1) {
|
|
BossGanon_SetupIntroCutscene(this, globalCtx);
|
|
this->organAlpha = 255;
|
|
} else {
|
|
cond = Flags_GetSwitch(globalCtx, 0x37) &&
|
|
((globalCtx->sceneNum == SCENE_GANON_DEMO) || (globalCtx->sceneNum == SCENE_GANON_FINAL) ||
|
|
(globalCtx->sceneNum == SCENE_GANON_SONOGO) || (globalCtx->sceneNum == SCENE_GANONTIKA_SONOGO));
|
|
|
|
if (!cond) {
|
|
BossGanon_SetupTowerCutscene(this, globalCtx);
|
|
} else {
|
|
Actor_Kill(thisx);
|
|
return;
|
|
}
|
|
|
|
BossGanon_SetupTowerCutscene(this, globalCtx);
|
|
}
|
|
|
|
sBossGanonCape = (EnGanonMant*)Actor_SpawnAsChild(&globalCtx->actorCtx, thisx, globalCtx, ACTOR_EN_GANON_MANT, 0.0f,
|
|
0.0f, 0.0f, 0, 0, 0, 1);
|
|
Actor_ChangeCategory(globalCtx, &globalCtx->actorCtx, thisx, ACTORCAT_BOSS);
|
|
} else {
|
|
thisx->flags &= ~ACTOR_FLAG_0;
|
|
this->fwork[GDF_FWORK_1] = 255.0f;
|
|
|
|
if (thisx->params >= 0xC8) {
|
|
if (thisx->params == 0x12C) {
|
|
thisx->update = BossGanon_LightBall_Update;
|
|
thisx->draw = BossGanon_LightBall_Draw;
|
|
this->unk_1A8 = 2;
|
|
} else if (thisx->params == 0x190) {
|
|
thisx->update = BossGanon_LightBall_Update;
|
|
thisx->draw = BossGanon_LightBall_Draw;
|
|
this->unk_1A8 = 1;
|
|
} else if (thisx->params >= 0x104) {
|
|
// big magic light ball thrown
|
|
thisx->update = func_808E2544;
|
|
thisx->draw = func_808E324C;
|
|
this->unk_1C2 = 10;
|
|
this->unk_1A2 = 520 + (-thisx->params * 2);
|
|
|
|
for (i = 0; i < 15; i++) {
|
|
this->unk_2EC[i] = thisx->world.pos;
|
|
}
|
|
|
|
this->timers[1] = 3;
|
|
Collider_InitCylinder(globalCtx, &this->collider);
|
|
Collider_SetCylinder(globalCtx, &this->collider, thisx, &sLightBallCylinderInit);
|
|
} else if (thisx->params >= 0xFA) {
|
|
// big magic light ball charge
|
|
thisx->update = func_808E2544;
|
|
thisx->draw = func_808E324C;
|
|
this->unk_1A2 = Rand_ZeroFloat(10000.0f);
|
|
|
|
for (i = 0; i < 15; i++) {
|
|
this->unk_2EC[i] = thisx->world.pos;
|
|
}
|
|
|
|
this->fwork[GDF_FWORK_1] = 0;
|
|
} else {
|
|
thisx->update = func_808E1EB4;
|
|
thisx->draw = func_808E229C;
|
|
if (1) {}
|
|
thisx->speedXZ = 11.0f;
|
|
|
|
if (thisx->params == 0xC8) {
|
|
this->timers[0] = 7;
|
|
} else {
|
|
this->timers[0] = (s16)Rand_ZeroFloat(3.0f) + 3;
|
|
}
|
|
|
|
for (i = 0; i < 15; i++) {
|
|
this->unk_2EC[i].y = 5000.0f;
|
|
}
|
|
}
|
|
} else {
|
|
// light ball (anything from 0x64 - 0xC7)
|
|
thisx->update = BossGanon_LightBall_Update;
|
|
thisx->draw = BossGanon_LightBall_Draw;
|
|
thisx->speedXZ = 12.0f;
|
|
|
|
xDistFromPlayer = player->actor.world.pos.x - thisx->world.pos.x;
|
|
yDistFromPlayer = (player->actor.world.pos.y + 30.0f) - thisx->world.pos.y;
|
|
zDistFromPlayer = player->actor.world.pos.z - thisx->world.pos.z;
|
|
|
|
thisx->world.rot.y = Math_Atan2S(zDistFromPlayer, xDistFromPlayer);
|
|
thisx->world.rot.x = Math_Atan2S(sqrtf(SQ(xDistFromPlayer) + SQ(zDistFromPlayer)), yDistFromPlayer);
|
|
|
|
if (Rand_ZeroOne() < 0) {
|
|
thisx->world.rot.y += (s16)Rand_CenteredFloat(5000.0f);
|
|
thisx->world.rot.x += (s16)Rand_CenteredFloat(5000.0f);
|
|
}
|
|
|
|
this->timers[1] = 3;
|
|
Collider_InitCylinder(globalCtx, &this->collider);
|
|
Collider_SetCylinder(globalCtx, &this->collider, thisx, &sLightBallCylinderInit);
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossGanon_Destroy(Actor* thisx, GlobalContext* globalCtx) {
|
|
BossGanon* this = (BossGanon*)thisx;
|
|
|
|
if ((this->actor.params < 0xC8) || (this->actor.params >= 0x104)) {
|
|
Collider_DestroyCylinder(globalCtx, &this->collider);
|
|
}
|
|
|
|
if (this->actor.params < 0x64) {
|
|
SkelAnime_Free(&this->skelAnime, globalCtx);
|
|
}
|
|
}
|
|
|
|
void BossGanon_SetupIntroCutscene(BossGanon* this, GlobalContext* globalCtx) {
|
|
s32 pad;
|
|
s32 animBankIndex = Object_GetIndex(&globalCtx->objectCtx, OBJECT_GANON_ANIME2);
|
|
|
|
if (animBankIndex < 0) {
|
|
Actor_Kill(&this->actor);
|
|
return;
|
|
}
|
|
|
|
if (Object_IsLoaded(&globalCtx->objectCtx, animBankIndex)) {
|
|
this->actionFunc = BossGanon_IntroCutscene;
|
|
this->unk_198 = 1;
|
|
this->animBankIndex = animBankIndex;
|
|
gSegments[6] = VIRTUAL_TO_PHYSICAL(globalCtx->objectCtx.status[animBankIndex].segment);
|
|
Animation_MorphToLoop(&this->skelAnime, &object_ganon_anime2_Anim_005FFC, 0.0f);
|
|
} else {
|
|
this->actionFunc = BossGanon_SetupIntroCutscene;
|
|
}
|
|
}
|
|
|
|
typedef struct {
|
|
/* 0x00 */ Vec3s eye;
|
|
/* 0x06 */ Vec3s at;
|
|
} CutsceneCameraPosition; // size = 0x12
|
|
|
|
static CutsceneCameraPosition sIntroCsCameraPositions[] = {
|
|
{ { 0, 40, 0 }, { 0, 50, 430 } },
|
|
{ { -20, 30, 400 }, { 10, 55, 440 } },
|
|
{ { 0, 60, 300 }, { 0, 273, -150 } },
|
|
{ { 0, 180, -260 }, { 0, 155, -300 } },
|
|
{ { -30, 60, 440 }, { 20, 25, 390 } },
|
|
{ { -50, 140, -360 }, { 50, 92, -390 } },
|
|
{ { -10, 264, -121 }, { 5, 266, -160 } },
|
|
{ { -13, 200, -310 }, { 0, 125, -410 } },
|
|
{ { 0, 40, -50 }, { 0, 35, 230 } },
|
|
{ { 0, 140, -250 }, { 0, 115, -570 } },
|
|
{ { -410, 150, -130 }, { 50, 155, -170 } },
|
|
{ { 0, 130, -230 }, { 0, 125, -2000 } },
|
|
{ { -2, 147, -293 }, { -200, 345, -2000 } },
|
|
};
|
|
|
|
void BossGanon_SetIntroCsCamera(BossGanon* this, u8 camPosIndex) {
|
|
CutsceneCameraPosition* camPos = &sIntroCsCameraPositions[camPosIndex];
|
|
|
|
this->csCamEye.x = camPos->eye.x;
|
|
this->csCamEye.y = camPos->eye.y;
|
|
this->csCamEye.z = camPos->eye.z;
|
|
|
|
this->csCamAt.x = camPos->at.x;
|
|
this->csCamAt.y = camPos->at.y;
|
|
this->csCamAt.z = camPos->at.z;
|
|
}
|
|
|
|
void BossGanon_IntroCutscene(BossGanon* this, GlobalContext* globalCtx) {
|
|
u8 moveCam = false;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
s32 pad;
|
|
f32 sin;
|
|
f32 cos;
|
|
Camera* mainCam;
|
|
|
|
gSegments[6] = VIRTUAL_TO_PHYSICAL(globalCtx->objectCtx.status[this->animBankIndex].segment);
|
|
|
|
sBossGanonCape->backPush = -2.0f;
|
|
sBossGanonCape->backSwayMagnitude = 0.25f;
|
|
sBossGanonCape->sideSwayMagnitude = -1.0f;
|
|
sBossGanonCape->minDist = 0.0f;
|
|
|
|
this->csTimer++;
|
|
|
|
SkelAnime_Update(&this->skelAnime);
|
|
|
|
switch (this->csState) {
|
|
case 0:
|
|
player->actor.world.pos.x = 0.0f;
|
|
player->actor.world.pos.y = 0.0f;
|
|
player->actor.world.pos.z = 430.0f;
|
|
|
|
this->actor.world.pos.x = 0.0f;
|
|
this->actor.world.pos.y = 112.0f;
|
|
this->actor.world.pos.z = -333.0f;
|
|
|
|
this->actor.shape.yOffset = -7000.0f;
|
|
this->actor.shape.rot.y = 0;
|
|
|
|
func_80064520(globalCtx, &globalCtx->csCtx);
|
|
func_8002DF54(globalCtx, &this->actor, 8);
|
|
this->csCamIndex = Gameplay_CreateSubCamera(globalCtx);
|
|
Gameplay_ChangeCameraStatus(globalCtx, MAIN_CAM, CAM_STAT_WAIT);
|
|
Gameplay_ChangeCameraStatus(globalCtx, this->csCamIndex, CAM_STAT_ACTIVE);
|
|
this->csCamFov = 60.0f;
|
|
|
|
if (gSaveContext.eventChkInf[7] & 0x100) {
|
|
// watched cutscene already, skip most of it
|
|
this->csState = 17;
|
|
this->csTimer = 0;
|
|
player->actor.world.pos.z = 20.0f;
|
|
this->useOpenHand = false;
|
|
Animation_MorphToLoop(&this->skelAnime, &object_ganon_anime2_Anim_0089F8, -5.0f);
|
|
this->fwork[GDF_FWORK_1] = 1000.0f;
|
|
BossGanon_SetIntroCsCamera(this, 11);
|
|
this->unk_198 = 2;
|
|
this->timers[2] = 110;
|
|
gSaveContext.healthAccumulator = 0x140;
|
|
Audio_QueueSeqCmd(NA_BGM_STOP);
|
|
} else {
|
|
this->useOpenHand = true;
|
|
BossGanon_SetIntroCsCamera(this, 0);
|
|
this->csState = 1;
|
|
sBossGanonZelda = (EnZl3*)Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_EN_ZL3, 0.0f,
|
|
220.0f, -150.0f, 0, 0, 0, 0x2000);
|
|
}
|
|
|
|
Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_EN_GANON_ORGAN, 0.0f, 0.0f, 0.0f, 0,
|
|
0, 0, 1);
|
|
sBossGanonCape->minY = 57.0f;
|
|
// fallthrough
|
|
case 1:
|
|
this->envLightMode = 3;
|
|
if (this->csTimer == 70) {
|
|
this->csState = 2;
|
|
this->csTimer = 0;
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
BossGanon_SetIntroCsCamera(this, 1);
|
|
|
|
if (this->csTimer == 10) {
|
|
func_8002DF54(globalCtx, &this->actor, 5);
|
|
}
|
|
|
|
if (this->csTimer == 13) {
|
|
func_8002F7DC(&player->actor, player->ageProperties->unk_92 + NA_SE_VO_LI_SURPRISE);
|
|
}
|
|
|
|
if (this->csTimer != 35) {
|
|
break;
|
|
}
|
|
|
|
this->csState = 3;
|
|
this->csTimer = 0;
|
|
|
|
this->csCamEye.x = 0.0f;
|
|
this->csCamEye.y = 60.0f;
|
|
this->csCamEye.z = 300.0f;
|
|
|
|
this->csCamAt.x = 0.0f;
|
|
this->unk_704 = 1.2566371f;
|
|
// fallthrough
|
|
case 3:
|
|
this->envLightMode = 0;
|
|
globalCtx->envCtx.unk_D8 = 0.0f;
|
|
this->csCamAt.y = (sinf(this->unk_704) * 300.0f) + this->csCamEye.y;
|
|
this->csCamAt.z = (cosf(this->unk_704) * -300.0f) + this->csCamEye.z;
|
|
Math_ApproachF(&this->unk_704, 0.25f, 0.05f, this->csCamAtMaxStep.y);
|
|
Math_ApproachF(&this->csCamAtMaxStep.y, 0.01f, 1.0f, 0.0001f);
|
|
|
|
if (this->csTimer != 200) {
|
|
break;
|
|
}
|
|
|
|
func_8002DF54(globalCtx, &this->actor, 8);
|
|
this->csState = 4;
|
|
BossGanon_SetIntroCsCamera(this, 2);
|
|
this->csTimer = 0;
|
|
// fallthrough
|
|
case 4:
|
|
if ((this->csTimer == 0) || (this->csTimer == 10) || (this->csTimer == 20)) {
|
|
this->csCamEye.y += 68.0f;
|
|
this->csCamEye.z -= 142.0f;
|
|
}
|
|
|
|
if (this->csTimer >= 20) {
|
|
this->envLightMode = 4;
|
|
} else {
|
|
this->envLightMode = 35;
|
|
}
|
|
|
|
if (this->csTimer == 60) {
|
|
BossGanon_SetIntroCsCamera(this, 1);
|
|
this->csState = 5;
|
|
this->csTimer = 0;
|
|
}
|
|
break;
|
|
|
|
case 5:
|
|
this->envLightMode = 5;
|
|
|
|
if (this->csTimer < 50) {
|
|
globalCtx->envCtx.unk_D8 = 1.0f;
|
|
}
|
|
|
|
if (this->csTimer == 10) {
|
|
func_8002DF54(globalCtx, &this->actor, 0x4B);
|
|
}
|
|
|
|
if (this->csTimer == 70) {
|
|
BossGanon_SetIntroCsCamera(this, 3);
|
|
this->csState = 6;
|
|
this->csTimer = 0;
|
|
this->envLightMode = 3;
|
|
}
|
|
break;
|
|
|
|
case 6:
|
|
this->envLightMode = 3;
|
|
|
|
if (this->csTimer != 30) {
|
|
break;
|
|
}
|
|
|
|
this->csState = 7;
|
|
this->csTimer = 0;
|
|
BossGanon_SetIntroCsCamera(this, 4);
|
|
this->triforceType = GDF_TRIFORCE_PLAYER;
|
|
this->fwork[GDF_TRIFORCE_SCALE] = 10.0f;
|
|
this->fwork[GDF_TRIFORCE_PRIM_A] = 0.0f;
|
|
this->fwork[GDF_TRIFORCE_PRIM_B] = 255.0f;
|
|
this->fwork[GDF_TRIFORCE_ENV_G] = 100.0f;
|
|
func_80078884(NA_SE_EV_TRIFORCE_MARK);
|
|
globalCtx->envCtx.unk_D8 = 0.0f;
|
|
// fallthrough
|
|
case 7:
|
|
this->envLightMode = 6;
|
|
// fade in links triforce
|
|
Math_ApproachF(&this->fwork[GDF_TRIFORCE_PRIM_A], 255.0f, 1.0f, 10.0f);
|
|
Math_ApproachF(&this->fwork[GDF_TRIFORCE_SCALE], 0.4f, 1.0f, 0.3f);
|
|
Math_ApproachF(&this->fwork[GDF_TRIFORCE_PRIM_B], 170.0f, 1.0f, 2.55f);
|
|
Math_ApproachF(&this->fwork[GDF_TRIFORCE_ENV_G], 200.0f, 1.0f, 3.0f);
|
|
|
|
if (this->csTimer >= 30) {
|
|
this->envLightMode = 65;
|
|
}
|
|
|
|
if (this->csTimer == 30) {
|
|
globalCtx->envCtx.unk_D8 = 1.0f;
|
|
}
|
|
|
|
BossGanon_SetIntroCsCamera(this, 4);
|
|
this->csCamEye.x += 5.0f;
|
|
this->csCamEye.z += -10.0f;
|
|
this->csCamAt.x += 18.0f;
|
|
|
|
if (this->csTimer == 60) {
|
|
this->csState = 8;
|
|
this->csTimer = 0;
|
|
}
|
|
break;
|
|
|
|
case 8:
|
|
this->envLightMode = 3;
|
|
BossGanon_SetIntroCsCamera(this, 5);
|
|
|
|
if (this->csTimer != 30) {
|
|
break;
|
|
}
|
|
|
|
this->csState = 9;
|
|
this->csTimer = 0;
|
|
func_8002DF54(globalCtx, &this->actor, 8);
|
|
sBossGanonZelda->unk_3C8 = 0;
|
|
this->triforceType = GDF_TRIFORCE_ZELDA;
|
|
this->fwork[GDF_TRIFORCE_SCALE] = 10.0f;
|
|
this->fwork[GDF_TRIFORCE_PRIM_A] = 0.0f;
|
|
this->fwork[GDF_TRIFORCE_PRIM_B] = 255.0f;
|
|
this->fwork[GDF_TRIFORCE_ENV_G] = 100.0f;
|
|
func_80078884(NA_SE_EV_TRIFORCE_MARK);
|
|
globalCtx->envCtx.unk_D8 = 0.0f;
|
|
// fallthrough
|
|
case 9:
|
|
this->envLightMode = 7;
|
|
BossGanon_SetIntroCsCamera(this, 6);
|
|
// fade in zeldas triforce
|
|
Math_ApproachF(&this->fwork[GDF_TRIFORCE_PRIM_A], 255.0f, 1.0f, 10.0f);
|
|
Math_ApproachF(&this->fwork[GDF_TRIFORCE_SCALE], 0.4f, 1.0f, 0.3f);
|
|
Math_ApproachF(&this->fwork[GDF_TRIFORCE_PRIM_B], 170.0f, 1.0f, 2.55f);
|
|
Math_ApproachF(&this->fwork[GDF_TRIFORCE_ENV_G], 200.0f, 1.0f, 3.0f);
|
|
|
|
if (this->csTimer == 30) {
|
|
sBossGanonZelda->unk_3C8 = 1;
|
|
}
|
|
|
|
if (this->csTimer >= 32) {
|
|
this->envLightMode = 75;
|
|
}
|
|
|
|
if (this->csTimer == 32) {
|
|
globalCtx->envCtx.unk_D8 = 1.0f;
|
|
}
|
|
|
|
if (this->csTimer == 50) {
|
|
this->csState = 10;
|
|
this->csTimer = 0;
|
|
}
|
|
break;
|
|
|
|
case 10: // top view of playing the organ
|
|
this->envLightMode = 3;
|
|
BossGanon_SetIntroCsCamera(this, 7);
|
|
|
|
if (this->csTimer == 40) {
|
|
this->csState = 11;
|
|
this->csTimer = 0;
|
|
this->fwork[GDF_TRIFORCE_PRIM_A] = 0.0f;
|
|
}
|
|
break;
|
|
|
|
case 11: // link is healed
|
|
this->envLightMode = 3;
|
|
BossGanon_SetIntroCsCamera(this, 8);
|
|
player->actor.world.pos.z = 20.0f;
|
|
|
|
if (this->csTimer == 20) {
|
|
func_8002DF54(globalCtx, &this->actor, 0x17);
|
|
Interface_ChangeAlpha(11); // show hearts only
|
|
}
|
|
|
|
if (this->csTimer == 25) {
|
|
gSaveContext.healthAccumulator = 0x140;
|
|
}
|
|
|
|
if (this->csTimer == 100) {
|
|
Interface_ChangeAlpha(1);
|
|
}
|
|
|
|
if (this->csTimer == 120) {
|
|
this->csState = 12;
|
|
this->csTimer = 0;
|
|
}
|
|
break;
|
|
|
|
case 12: // first dialogue, ganondorf facing away from link
|
|
this->envLightMode = 3;
|
|
BossGanon_SetIntroCsCamera(this, 9);
|
|
|
|
if (this->csTimer == 30) {
|
|
Audio_QueueSeqCmd(0x100100FF);
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&object_ganon_anime2_Anim_004F64);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_ganon_anime2_Anim_004F64, -5.0f);
|
|
}
|
|
|
|
if ((this->csTimer > 30) && Animation_OnFrame(&this->skelAnime, this->fwork[GDF_FWORK_1])) {
|
|
Animation_MorphToLoop(&this->skelAnime, &object_ganon_anime2_Anim_006AF4, 0.0f);
|
|
this->fwork[GDF_FWORK_1] = 1000.0f;
|
|
}
|
|
|
|
if (this->csTimer == 80) {
|
|
Message_StartTextbox(globalCtx, 0x70C8, NULL);
|
|
}
|
|
|
|
if ((this->csTimer > 180) && (Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_NONE)) {
|
|
this->csState = 15;
|
|
this->csTimer = 0;
|
|
this->useOpenHand = false;
|
|
}
|
|
break;
|
|
|
|
case 15: // side view of all 3 of them
|
|
this->envLightMode = 0;
|
|
globalCtx->envCtx.unk_D8 = 0.0f;
|
|
BossGanon_SetIntroCsCamera(this, 10);
|
|
|
|
if (this->csTimer == 30) {
|
|
Message_StartTextbox(globalCtx, 0x70C9, NULL);
|
|
}
|
|
|
|
if ((this->csTimer > 100) && (Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_NONE)) {
|
|
this->csState = 16;
|
|
this->csTimer = 0;
|
|
BossGanon_SetIntroCsCamera(this, 11);
|
|
this->unk_198 = 2;
|
|
sBossGanonZelda->unk_3C8 = 2;
|
|
this->timers[2] = 110;
|
|
this->envLightMode = 3;
|
|
}
|
|
break;
|
|
|
|
case 16:
|
|
this->envLightMode = 3;
|
|
|
|
if (this->csTimer <= 20) {
|
|
if (this->csTimer == 20) {
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_ganon_anime2_Anim_004304, -5.0f);
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&object_ganon_anime2_Anim_004304);
|
|
}
|
|
} else if (Animation_OnFrame(&this->skelAnime, this->fwork[GDF_FWORK_1])) {
|
|
Message_StartTextbox(globalCtx, 0x70CA, NULL);
|
|
Animation_MorphToLoop(&this->skelAnime, &object_ganon_anime2_Anim_0089F8, -5.0f);
|
|
this->fwork[GDF_FWORK_1] = 1000.0f;
|
|
}
|
|
|
|
if ((this->csTimer > 100) && (Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_NONE)) {
|
|
this->csState = 17;
|
|
this->csTimer = 0;
|
|
}
|
|
break;
|
|
|
|
case 17: // turns around
|
|
this->envLightMode = 3;
|
|
|
|
if (this->csTimer == 20) {
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_ganon_anime2_Anim_001F58, -5.0f);
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&object_ganon_anime2_Anim_001F58);
|
|
}
|
|
|
|
if (this->csTimer > 10) {
|
|
if (this->csTimer == 62) {
|
|
sBossGanonCape->attachRightArmTimer = 20.0f;
|
|
}
|
|
|
|
if (this->csTimer == 57) {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EV_GANON_MANTLE);
|
|
}
|
|
|
|
Math_ApproachF(&this->csCamFov, 110.0f, 0.1f, this->csCamMaxStepScale * 2.0f);
|
|
Math_ApproachF(&this->csCamEye.z, -290.0f, 0.1f, this->csCamMaxStepScale * 2.4f);
|
|
Math_ApproachF(&this->csCamMaxStepScale, 0.75f, 1.0f, 0.05f);
|
|
|
|
if (this->csTimer == 70) {
|
|
this->csState = 18;
|
|
this->csTimer = 0;
|
|
this->csCamFov = 60.0f;
|
|
BossGanon_SetIntroCsCamera(this, 12);
|
|
Message_StartTextbox(globalCtx, 0x70CB, NULL);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 18: // last dialog before triforce
|
|
this->envLightMode = 3;
|
|
BossGanon_SetIntroCsCamera(this, 12);
|
|
this->csCamEye.y += -6.0f;
|
|
this->csCamEye.z += 6.0f;
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->fwork[GDF_FWORK_1] - 5.0f)) {
|
|
Animation_MorphToLoop(&this->skelAnime, &object_ganon_anime2_Anim_003018, -5.0f);
|
|
this->fwork[GDF_FWORK_1] = 1000.0f;
|
|
}
|
|
|
|
if ((this->csTimer <= 50) || (Message_GetState(&globalCtx->msgCtx) != TEXT_STATE_NONE)) {
|
|
break;
|
|
}
|
|
|
|
this->csState = 19;
|
|
this->csTimer = 0;
|
|
Message_StartTextbox(globalCtx, 0x70CC, NULL);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_ganon_anime2_Anim_007268, -5.0f);
|
|
this->triforceType = GDF_TRIFORCE_DORF;
|
|
this->fwork[GDF_TRIFORCE_SCALE] = 10.0f;
|
|
this->fwork[GDF_TRIFORCE_PRIM_A] = 0.0f;
|
|
this->fwork[GDF_TRIFORCE_PRIM_B] = 255.0f;
|
|
this->fwork[GDF_TRIFORCE_ENV_G] = 100.0f;
|
|
globalCtx->envCtx.unk_D8 = 0.0f;
|
|
// fallthrough
|
|
case 19: // show triforce
|
|
this->envLightMode = 8;
|
|
|
|
if (this->csTimer >= 60) {
|
|
this->envLightMode = 9;
|
|
|
|
if (this->csTimer == 60) {
|
|
globalCtx->envCtx.unk_D8 = 1.0f;
|
|
}
|
|
}
|
|
|
|
BossGanon_SetIntroCsCamera(this, 12);
|
|
this->csCamEye.y += -6.0f;
|
|
this->csCamEye.z += 6.0f;
|
|
|
|
if (this->csTimer >= 30) {
|
|
if (this->csTimer == 30) {
|
|
func_80078884(NA_SE_EV_TRIFORCE_MARK);
|
|
}
|
|
|
|
// fade in ganondorf's triforce
|
|
Math_ApproachF(&this->fwork[GDF_TRIFORCE_PRIM_A], 255.0f, 1.0f, 10.0f);
|
|
Math_ApproachF(&this->fwork[GDF_TRIFORCE_SCALE], 0.6f, 1.0f, 0.3f);
|
|
Math_ApproachF(&this->fwork[GDF_TRIFORCE_PRIM_B], 170.0f, 1.0f, 2.55f);
|
|
Math_ApproachF(&this->fwork[GDF_TRIFORCE_ENV_G], 200.0f, 1.0f, 3.0f);
|
|
}
|
|
|
|
if (this->csTimer == 17) {
|
|
Animation_MorphToLoop(&this->skelAnime, &object_ganon_anime2_Anim_007A64, -5.0f);
|
|
}
|
|
|
|
if ((this->csTimer > 80) && (Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_NONE)) {
|
|
this->csState = 20;
|
|
this->csTimer = 0;
|
|
|
|
this->csCamTargetEye.x = this->csCamEye.x - 50.0f;
|
|
this->csCamTargetEye.y = this->csCamEye.y - 100.0f;
|
|
this->csCamTargetEye.z = this->csCamEye.z + 400.0f;
|
|
|
|
this->csCamEyeMaxStep.x = 50.0f;
|
|
this->csCamEyeMaxStep.y = 100.0f;
|
|
this->csCamEyeMaxStep.z = 400.0f;
|
|
|
|
this->csCamAtMaxStep.x = 400.0f;
|
|
this->csCamMaxStepScale = 0.0f;
|
|
|
|
this->csCamTargetAt.x = this->csCamAt.x + 400.0f;
|
|
this->csCamTargetAt.y = this->csCamAt.y;
|
|
this->csCamTargetAt.z = this->csCamAt.z;
|
|
|
|
this->csCamMovementScale = 0.2f;
|
|
|
|
this->fwork[GDF_VORTEX_ALPHA] = 0.0f;
|
|
this->fwork[GDF_VORTEX_SCALE] = 0.1f;
|
|
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_DARKWAVE);
|
|
}
|
|
break;
|
|
|
|
case 20: // zoom cam out
|
|
this->envLightMode = 10;
|
|
moveCam = true;
|
|
Math_ApproachF(&this->csCamMaxStepScale, 0.15f, 1.0f, 0.015f);
|
|
|
|
if (this->csTimer <= 40) {
|
|
Math_ApproachF(&this->fwork[GDF_VORTEX_ALPHA], 255.0f, 1.0f, 6.5f);
|
|
Math_ApproachF(&this->fwork[GDF_VORTEX_SCALE], 0.2f, 1.0f, 0.025f);
|
|
}
|
|
|
|
if (this->csTimer > 20) {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_DARKWAVE_M - SFX_FLAG);
|
|
}
|
|
|
|
if (this->csTimer > 20) {
|
|
BossGanonEff_SpawnShock(globalCtx, 700.0f, GDF_SHOCK_PLAYER_PURPLE);
|
|
BossGanonEff_SpawnShock(globalCtx, 700.0f, GDF_SHOCK_PLAYER_PURPLE);
|
|
}
|
|
|
|
if (this->csTimer == 30) {
|
|
func_8002DF54(globalCtx, &this->actor, 0x4A);
|
|
}
|
|
|
|
if (this->csTimer <= 50) {
|
|
break;
|
|
}
|
|
|
|
this->csState = 21;
|
|
this->csTimer = 0;
|
|
this->fwork[GDF_TRIFORCE_PRIM_A] = 0.0f;
|
|
this->fwork[GDF_VORTEX_SCALE] = 0.16f;
|
|
goto skip_sound_and_fx;
|
|
|
|
case 21: // purple vortex
|
|
this->envLightMode = 11;
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_DARKWAVE_M - SFX_FLAG);
|
|
BossGanonEff_SpawnShock(globalCtx, 700.0f, GDF_SHOCK_PLAYER_PURPLE);
|
|
BossGanonEff_SpawnShock(globalCtx, 700.0f, GDF_SHOCK_PLAYER_PURPLE);
|
|
|
|
skip_sound_and_fx:
|
|
this->csCamEye.x = -30.0f;
|
|
this->csCamEye.y = 37.0f;
|
|
this->csCamEye.z = -30.0f;
|
|
|
|
this->csCamAt.x = -10.0f;
|
|
this->csCamAt.y = 45.0f;
|
|
this->csCamAt.z = 0.0f;
|
|
|
|
if (this->csTimer == 13) {
|
|
Message_StartTextbox(globalCtx, 0x70CD, NULL);
|
|
}
|
|
|
|
if ((this->csTimer <= 120) || (Message_GetState(&globalCtx->msgCtx) != TEXT_STATE_NONE)) {
|
|
break;
|
|
}
|
|
|
|
this->csState = 22;
|
|
this->csTimer = 0;
|
|
this->timers[2] = 30;
|
|
this->organAlpha = 254;
|
|
this->csCamAt.x = this->unk_1FC.x - 10.0f;
|
|
this->csCamAt.y = this->unk_1FC.y + 30.0f;
|
|
this->csCamAt.z = this->unk_1FC.z;
|
|
this->fwork[GDF_VORTEX_ALPHA] = 255.0f;
|
|
this->fwork[GDF_VORTEX_SCALE] = 0.2f;
|
|
// fallthrough
|
|
case 22: // start floating, show title card, start fight
|
|
if (this->csTimer > 30) {
|
|
this->envLightMode = 0;
|
|
} else {
|
|
this->envLightMode = 12;
|
|
}
|
|
|
|
Math_ApproachZeroF(&this->fwork[GDF_VORTEX_ALPHA], 1.0f, 10.0f);
|
|
|
|
this->csCamEye.x = -30.0f;
|
|
this->csCamEye.y = 137.0f;
|
|
this->csCamEye.z = -110.0f;
|
|
|
|
Math_ApproachF(&this->csCamAt.y, this->unk_1FC.y + 30.0f, 0.1f, 20.0f);
|
|
Math_ApproachF(&this->csCamAt.x, this->unk_1FC.x - 10.0f, 0.1f, 5.0f);
|
|
|
|
if (this->csTimer == 20) {
|
|
BossGanon_SetAnimationObject(this, globalCtx, OBJECT_GANON_ANIME1);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &gDorfGetUp3Anim, 0.0f);
|
|
SkelAnime_Update(&this->skelAnime);
|
|
this->actor.shape.yOffset = 0.0f;
|
|
sBossGanonCape->attachShouldersTimer = 18.0f;
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EV_GANON_MANTLE);
|
|
this->unk_198 = 0;
|
|
Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_GANONDORF_BOSS);
|
|
}
|
|
|
|
if (this->csTimer == 50) {
|
|
gSegments[6] = VIRTUAL_TO_PHYSICAL(
|
|
globalCtx->objectCtx.status[Object_GetIndex(&globalCtx->objectCtx, OBJECT_GANON)].segment);
|
|
|
|
if (!(gSaveContext.eventChkInf[7] & 0x100)) {
|
|
TitleCard_InitBossName(globalCtx, &globalCtx->actorCtx.titleCtx,
|
|
SEGMENTED_TO_VIRTUAL(gDorfTitleCardTex), 160, 180, 128, 40, false);
|
|
}
|
|
|
|
gSaveContext.eventChkInf[7] |= 0x100;
|
|
}
|
|
|
|
if (this->csTimer >= 20) {
|
|
this->legSwayEnabled = true;
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_FLOAT - SFX_FLAG);
|
|
|
|
Math_ApproachF(&this->actor.world.pos.y, 228.0f, 0.05f, 2.0f);
|
|
Math_ApproachF(&this->actor.world.pos.z, -230.0f, 0.05f, 4.0f);
|
|
|
|
sBossGanonCape->backPush = -3.0f;
|
|
sBossGanonCape->backSwayMagnitude = 0.25f;
|
|
sBossGanonCape->sideSwayMagnitude = -3.0f;
|
|
|
|
sin = Math_SinS(this->csTimer * 1500);
|
|
this->actor.velocity.y = this->fwork[GDF_FWORK_0] * sin * 0.04f;
|
|
this->actor.world.pos.y += this->actor.velocity.y;
|
|
|
|
cos = Math_CosS(this->csTimer * 1800);
|
|
this->actor.world.pos.x = this->fwork[GDF_FWORK_0] * cos * 0.5f;
|
|
this->actor.velocity.x = this->actor.world.pos.x - this->actor.prevPos.x;
|
|
|
|
Math_ApproachF(&this->fwork[GDF_FWORK_0], 50.0f, 1.0f, 1.0f);
|
|
}
|
|
|
|
if (this->csTimer > 30) {
|
|
this->organAlpha -= 5;
|
|
|
|
if (this->organAlpha < 0) {
|
|
this->organAlpha = 0;
|
|
}
|
|
}
|
|
|
|
if (this->csTimer == 120) {
|
|
mainCam = Gameplay_GetCamera(globalCtx, MAIN_CAM);
|
|
mainCam->eye = this->csCamEye;
|
|
mainCam->eyeNext = this->csCamEye;
|
|
mainCam->at = this->csCamAt;
|
|
func_800C08AC(globalCtx, this->csCamIndex, 0);
|
|
this->csState = this->csCamIndex = 0;
|
|
func_80064534(globalCtx, &globalCtx->csCtx);
|
|
func_8002DF54(globalCtx, &this->actor, 7);
|
|
BossGanon_SetupWait(this, globalCtx);
|
|
}
|
|
|
|
if (sBossGanonZelda != NULL) {
|
|
sBossGanonZelda->actor.world.pos.x = 0.0f;
|
|
sBossGanonZelda->actor.world.pos.y = 350.0f;
|
|
sBossGanonZelda->actor.world.pos.z = 0.0f;
|
|
}
|
|
}
|
|
|
|
if (this->csCamIndex != 0) {
|
|
if (moveCam) {
|
|
Math_ApproachF(&this->csCamEye.x, this->csCamTargetEye.x, this->csCamMovementScale,
|
|
this->csCamEyeMaxStep.x * this->csCamMaxStepScale);
|
|
Math_ApproachF(&this->csCamEye.y, this->csCamTargetEye.y, this->csCamMovementScale,
|
|
this->csCamEyeMaxStep.y * this->csCamMaxStepScale);
|
|
Math_ApproachF(&this->csCamEye.z, this->csCamTargetEye.z, this->csCamMovementScale,
|
|
this->csCamEyeMaxStep.z * this->csCamMaxStepScale);
|
|
|
|
Math_ApproachF(&this->csCamAt.x, this->csCamTargetAt.x, this->csCamMovementScale,
|
|
this->csCamAtMaxStep.x * this->csCamMaxStepScale);
|
|
Math_ApproachF(&this->csCamAt.y, this->csCamTargetAt.y, this->csCamMovementScale,
|
|
this->csCamAtMaxStep.y * this->csCamMaxStepScale);
|
|
Math_ApproachF(&this->csCamAt.z, this->csCamTargetAt.z, this->csCamMovementScale,
|
|
this->csCamAtMaxStep.z * this->csCamMaxStepScale);
|
|
}
|
|
|
|
Gameplay_CameraSetAtEye(globalCtx, this->csCamIndex, &this->csCamAt, &this->csCamEye);
|
|
Gameplay_CameraSetFov(globalCtx, this->csCamIndex, this->csCamFov);
|
|
}
|
|
}
|
|
|
|
void BossGanon_SetupDeathCutscene(BossGanon* this, GlobalContext* globalCtx) {
|
|
s32 pad;
|
|
s32 animBankIndex = Object_GetIndex(&globalCtx->objectCtx, OBJECT_GANON_ANIME2);
|
|
|
|
if (Object_IsLoaded(&globalCtx->objectCtx, animBankIndex)) {
|
|
this->actionFunc = BossGanon_DeathAndTowerCutscene;
|
|
this->csTimer = this->csState = 0;
|
|
this->unk_198 = 1;
|
|
this->animBankIndex = animBankIndex;
|
|
gSegments[6] = VIRTUAL_TO_PHYSICAL(globalCtx->objectCtx.status[animBankIndex].segment);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_ganon_anime2_Anim_00EA00, 0.0f);
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&object_ganon_anime2_Anim_00EA00);
|
|
this->unk_508 = 0.0f;
|
|
}
|
|
}
|
|
|
|
void BossGanon_SetupTowerCutscene(BossGanon* this, GlobalContext* globalCtx) {
|
|
s32 pad;
|
|
s32 animBankIndex = Object_GetIndex(&globalCtx->objectCtx, OBJECT_GANON_ANIME2);
|
|
|
|
if (Object_IsLoaded(&globalCtx->objectCtx, animBankIndex)) {
|
|
this->animBankIndex = animBankIndex;
|
|
gSegments[6] = VIRTUAL_TO_PHYSICAL(globalCtx->objectCtx.status[animBankIndex].segment);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_ganon_anime2_Anim_00EA00, 0.0f);
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&object_ganon_anime2_Anim_00EA00);
|
|
this->actionFunc = BossGanon_DeathAndTowerCutscene;
|
|
this->csTimer = 0;
|
|
this->csState = 100;
|
|
this->unk_198 = 1;
|
|
gSaveContext.magic = gSaveContext.unk_13F4;
|
|
gSaveContext.health = gSaveContext.healthCapacity;
|
|
} else {
|
|
this->actionFunc = BossGanon_SetupTowerCutscene;
|
|
}
|
|
}
|
|
|
|
void BossGanon_ShatterWindows(u8 windowShatterState) {
|
|
s16 i;
|
|
u8* tex1 = ResourceMgr_LoadTexByName(SEGMENTED_TO_VIRTUAL(ganon_boss_sceneTex_006C18));
|
|
u8* tex2 = ResourceMgr_LoadTexByName(SEGMENTED_TO_VIRTUAL(ganon_boss_sceneTex_007418));
|
|
|
|
for (i = 0; i < 2048; i++) {
|
|
if ((tex1[i] != 0) && (Rand_ZeroOne() < 0.03f)) {
|
|
if ((((u8*)gDorfWindowShatterTemplateTex)[i] == 0) || (windowShatterState == GDF_WINDOW_SHATTER_FULL)) {
|
|
tex1[i] = tex2[i] = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossGanon_DeathAndTowerCutscene(BossGanon* this, GlobalContext* globalCtx) {
|
|
const bool originalBlood = CVar_GetS32("gOriginalBlood", 1);
|
|
|
|
static Color_RGBA8 bloodPrimColor = { 120, 0, 0, 255 };
|
|
static Color_RGBA8 bloodEnvColor = { 120, 0, 0, 255 };
|
|
|
|
if(!originalBlood) {
|
|
bloodPrimColor.r = 0;
|
|
bloodPrimColor.g = 120;
|
|
bloodPrimColor.b = 0;
|
|
|
|
bloodEnvColor.r = 0;
|
|
bloodEnvColor.g = 120;
|
|
bloodEnvColor.b = 0;
|
|
}
|
|
|
|
s16 i;
|
|
u8 moveCam = false;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
s16 pad;
|
|
Vec3f sp98;
|
|
Vec3f sp8C;
|
|
Vec3f sp80;
|
|
Vec3f sp74;
|
|
Camera* mainCam;
|
|
Vec3f sp64;
|
|
|
|
gSegments[6] = VIRTUAL_TO_PHYSICAL(globalCtx->objectCtx.status[this->animBankIndex].segment);
|
|
|
|
this->csTimer++;
|
|
SkelAnime_Update(&this->skelAnime);
|
|
|
|
switch (this->csState) {
|
|
case 0:
|
|
func_80064520(globalCtx, &globalCtx->csCtx);
|
|
func_8002DF54(globalCtx, &this->actor, 8);
|
|
this->csCamIndex = Gameplay_CreateSubCamera(globalCtx);
|
|
Gameplay_ChangeCameraStatus(globalCtx, MAIN_CAM, CAM_STAT_WAIT);
|
|
Gameplay_ChangeCameraStatus(globalCtx, this->csCamIndex, CAM_STAT_ACTIVE);
|
|
|
|
this->actor.world.pos.x = 0.0f;
|
|
this->actor.world.pos.y = 70.0f;
|
|
this->actor.world.pos.z = -80.0f;
|
|
|
|
this->actor.shape.yOffset = -7000.0f;
|
|
|
|
this->actor.shape.rot.y = 0;
|
|
this->csState = 1;
|
|
this->csTimer = 0;
|
|
this->useOpenHand = true;
|
|
// fallthrough
|
|
case 1:
|
|
player->actor.shape.rot.y = -0x8000;
|
|
|
|
player->actor.world.pos.x = -10.0f;
|
|
player->actor.world.pos.y = 0.0f;
|
|
player->actor.world.pos.z = 115.0f;
|
|
|
|
this->envLightMode = 13;
|
|
|
|
if (this->csTimer < 30) {
|
|
globalCtx->envCtx.unk_D8 = 0.0f;
|
|
}
|
|
|
|
if (this->csTimer >= 2) {
|
|
globalCtx->envCtx.fillScreen = false;
|
|
}
|
|
|
|
this->csCamEye.x = -50.0f;
|
|
this->csCamEye.z = -50.0f;
|
|
this->csCamEye.y = 50.0f;
|
|
|
|
this->csCamAt.x = this->unk_1FC.x;
|
|
this->csCamAt.y = this->unk_1FC.y + 30.0f;
|
|
this->csCamAt.z = this->unk_1FC.z;
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->fwork[GDF_FWORK_1])) {
|
|
Animation_MorphToLoop(&this->skelAnime, &object_ganon_anime2_Anim_00F19C, 0.0f);
|
|
this->csState = 2;
|
|
this->csTimer = 0;
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
this->csCamEye.x = -100.0f;
|
|
this->csCamEye.y = 20.0f;
|
|
this->csCamEye.z = -130.0f;
|
|
|
|
this->envLightMode = 13;
|
|
|
|
this->csCamAt.x = this->unk_1FC.x;
|
|
this->csCamAt.y = this->unk_1FC.y;
|
|
this->csCamAt.z = this->unk_1FC.z + 40.0f;
|
|
|
|
if (this->csTimer >= 30) {
|
|
this->csState = 3;
|
|
this->csTimer = 0;
|
|
Message_StartTextbox(globalCtx, 0x70CE, NULL);
|
|
this->fwork[GDF_FWORK_1] = 1000.0f;
|
|
}
|
|
|
|
if ((this->unk_1A2 % 32) == 0) {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_BREATH);
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
this->envLightMode = 14;
|
|
|
|
if ((this->fwork[GDF_FWORK_1] > 100.0f) && ((this->unk_1A2 % 32) == 0)) {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_BREATH);
|
|
}
|
|
|
|
this->csCamEye.x = 7.0f;
|
|
this->csCamEye.y = 52.0f;
|
|
this->csCamEye.z = -15.0f;
|
|
|
|
this->csCamAt.x = this->unk_1FC.x - 5.0f;
|
|
this->csCamAt.y = this->unk_1FC.y + 30.0f - 10.0f;
|
|
this->csCamAt.z = this->unk_1FC.z;
|
|
|
|
if ((this->fwork[GDF_FWORK_1] > 100.0f) && (this->csTimer > 100) &&
|
|
(Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_NONE)) {
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_ganon_anime2_Anim_00B668, 0.0f);
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&object_ganon_anime2_Anim_00B668);
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_TOKETU);
|
|
} else {
|
|
if (Animation_OnFrame(&this->skelAnime, this->fwork[GDF_FWORK_1] - 16.0f)) {
|
|
for (i = 0; i < 40; i++) {
|
|
sp98.x = Rand_CenteredFloat(5.0f);
|
|
sp98.y = Rand_CenteredFloat(1.5f) + 1.0f;
|
|
sp98.z = Rand_ZeroFloat(5.0f) + 2.0f;
|
|
|
|
sp8C.x = 0.0f;
|
|
sp8C.y = -1.0f;
|
|
sp8C.z = 0.0f;
|
|
|
|
sp80.x = this->unk_208.x;
|
|
sp80.y = this->unk_208.y - 10.0f;
|
|
sp80.z = this->unk_208.z;
|
|
|
|
func_8002836C(globalCtx, &sp80, &sp98, &sp8C, &bloodPrimColor, &bloodEnvColor,
|
|
(s16)Rand_ZeroFloat(50.0f) + 50, 0, 17);
|
|
}
|
|
}
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->fwork[GDF_FWORK_1])) {
|
|
Animation_MorphToLoop(&this->skelAnime, &object_ganon_anime2_Anim_00BE38, 0.0f);
|
|
this->csState = 4;
|
|
this->csTimer = 0;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
this->envLightMode = 14;
|
|
|
|
if (this->csTimer == 30) {
|
|
Message_StartTextbox(globalCtx, 0x70CF, NULL);
|
|
this->csState = 5;
|
|
this->csTimer = 0;
|
|
}
|
|
break;
|
|
|
|
case 5:
|
|
this->envLightMode = 14;
|
|
|
|
if ((this->csTimer > 70) && (Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_NONE)) {
|
|
this->csState = 6;
|
|
this->csTimer = 0;
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_ganon_anime2_Anim_010298, 0.0f);
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&object_ganon_anime2_Anim_010298);
|
|
|
|
this->csCamMovementScale = 0.05f;
|
|
this->csCamMaxStepScale = 0.0f;
|
|
|
|
this->csCamTargetEye.x = 7.0f;
|
|
this->csCamTargetEye.y = 12.0f;
|
|
this->csCamTargetEye.z = 70.0f;
|
|
|
|
this->csCamTargetAt.x = this->unk_1FC.x - 5.0f;
|
|
this->csCamTargetAt.y = (this->unk_1FC.y + 30.0f) - 10.0f;
|
|
this->csCamTargetAt.z = this->unk_1FC.z;
|
|
|
|
this->csCamEyeMaxStep.x = fabsf(this->csCamEye.x - this->csCamTargetEye.x);
|
|
this->csCamEyeMaxStep.y = fabsf(this->csCamEye.y - this->csCamTargetEye.y);
|
|
this->csCamEyeMaxStep.z = fabsf(this->csCamEye.z - this->csCamTargetEye.z);
|
|
|
|
this->csCamAtMaxStep.x = fabsf(this->csCamAt.x - this->csCamTargetAt.x);
|
|
this->csCamAtMaxStep.y = fabsf(this->csCamAt.y - this->csCamTargetAt.y);
|
|
this->csCamAtMaxStep.z = fabsf(this->csCamAt.z - this->csCamTargetAt.z);
|
|
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_CASBREAK);
|
|
}
|
|
break;
|
|
|
|
case 6:
|
|
this->envLightMode = 14;
|
|
moveCam = true;
|
|
Math_ApproachF(&this->csCamMaxStepScale, 0.2f, 1.0f, 0.01f);
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->fwork[GDF_FWORK_1])) {
|
|
Animation_MorphToLoop(&this->skelAnime, &object_ganon_anime2_Anim_010514, 0.0f);
|
|
this->csState = 7;
|
|
this->csTimer = 0;
|
|
this->unk_2E8 = 0;
|
|
this->envLightMode = 15;
|
|
this->unk_508 = 0.0f;
|
|
this->fwork[GDF_FWORK_1] = 1000.0f;
|
|
globalCtx->envCtx.unk_D8 = 0.0f;
|
|
}
|
|
break;
|
|
|
|
case 7:
|
|
if (this->csTimer < 10) {
|
|
globalCtx->envCtx.unk_D8 = 0.0f;
|
|
}
|
|
|
|
if (this->csTimer == 30) {
|
|
this->csState = 8;
|
|
this->csTimer = 0;
|
|
this->unk_70C = 0.0f;
|
|
}
|
|
goto skip_cam_and_quake;
|
|
|
|
case 8:
|
|
this->csCamEye.x = -60.0f;
|
|
this->csCamEye.y = 80.0f;
|
|
this->csCamEye.z = -130.0f;
|
|
|
|
this->csCamAt.x = 0.0f;
|
|
this->csCamAt.y = 0.0f;
|
|
this->csCamAt.z = 70.0f;
|
|
|
|
this->unk_70C = Math_SinS(this->csTimer * 0x6300) * 0.2f;
|
|
|
|
func_80078884(NA_SE_EV_EARTHQUAKE - SFX_FLAG);
|
|
|
|
skip_cam_and_quake:
|
|
this->envLightMode = 15;
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_BODY_SPARK - SFX_FLAG);
|
|
|
|
for (i = 1; i < 15; i++) {
|
|
this->unk_4E4[i] = 0xA;
|
|
}
|
|
|
|
this->unk_2E6 = 20000;
|
|
Math_ApproachF(&this->unk_508, 5.0f, 0.05f, 0.1f);
|
|
|
|
if (this->csTimer == 30) {
|
|
this->csState = 9;
|
|
this->csTimer = 0;
|
|
|
|
this->csCamEye.x = -30.0f;
|
|
this->csCamEye.y = 40.0f;
|
|
this->csCamEye.z = 60.0f;
|
|
|
|
this->csCamAt.x = 492.0f;
|
|
this->csCamAt.y = 43.0f;
|
|
this->csCamAt.z = 580.0f;
|
|
|
|
this->csCamMaxStepScale = 0.0f;
|
|
this->unk_710 = 10.0f;
|
|
}
|
|
break;
|
|
|
|
case 9:
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_BODY_SPARK - SFX_FLAG);
|
|
|
|
if (this->csTimer == 2) {
|
|
func_8002DF54(globalCtx, &this->actor, 0x39);
|
|
}
|
|
|
|
if (this->csTimer > 50) {
|
|
Math_ApproachZeroF(&this->unk_710, 1.0f, 0.2f);
|
|
Math_ApproachF(&this->csCamEye.x, 270.0f, 0.05f, this->csCamMaxStepScale * 30.0f);
|
|
Math_ApproachF(&this->csCamEye.z, 260.0f, 0.05f, this->csCamMaxStepScale * 20.0f);
|
|
Math_ApproachF(&this->csCamAt.y, 103.0f, 0.05f, this->csCamMaxStepScale * 6.0f);
|
|
Math_ApproachF(&this->csCamAt.z, 280.0f, 0.05f, this->csCamMaxStepScale * 20.0f);
|
|
Math_ApproachF(&this->csCamMaxStepScale, 1.0f, 1.0f, 0.01f);
|
|
}
|
|
|
|
this->unk_70C = Math_SinS(this->csTimer * 0x6300) * this->unk_710;
|
|
func_80078884(NA_SE_EV_EARTHQUAKE - SFX_FLAG);
|
|
|
|
if (this->csTimer < 100) {
|
|
this->windowShatterState = GDF_WINDOW_SHATTER_PARTIAL;
|
|
this->envLightMode = 15;
|
|
} else {
|
|
this->envLightMode = 16;
|
|
this->windowShatterState = GDF_WINDOW_SHATTER_FULL;
|
|
}
|
|
|
|
if (this->csTimer >= 130) {
|
|
Math_ApproachF(&this->whiteFillAlpha, 255.0f, 1.0f, 5.0f);
|
|
}
|
|
|
|
if (this->csTimer == 180) {
|
|
globalCtx->sceneLoadFlag = 0x14;
|
|
globalCtx->nextEntranceIndex = 0x43F;
|
|
globalCtx->fadeTransition = 5;
|
|
}
|
|
break;
|
|
|
|
case 100:
|
|
func_80064520(globalCtx, &globalCtx->csCtx);
|
|
func_8002DF54(globalCtx, &this->actor, 8);
|
|
this->csCamIndex = Gameplay_CreateSubCamera(globalCtx);
|
|
Gameplay_ChangeCameraStatus(globalCtx, MAIN_CAM, CAM_STAT_WAIT);
|
|
Gameplay_ChangeCameraStatus(globalCtx, this->csCamIndex, CAM_STAT_ACTIVE);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_ganon_anime2_Anim_00ADDC, 0.0f);
|
|
this->fwork[1] = Animation_GetLastFrame(&object_ganon_anime2_Anim_00EA00);
|
|
this->csState = 101;
|
|
this->skelAnime.playSpeed = 0.0f;
|
|
sBossGanonZelda = (EnZl3*)Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_EN_ZL3, 0.0f,
|
|
6000.0f, 0.0f, 0, 0, 0, 0x2000);
|
|
|
|
player->actor.world.pos.x = -472.0f;
|
|
player->actor.world.pos.y = 4102.0f;
|
|
player->actor.world.pos.z = -130.0f;
|
|
|
|
player->actor.shape.rot.y = -0x8000;
|
|
|
|
this->actor.world.pos.x = -472.0f;
|
|
this->actor.world.pos.y = 4172.0f;
|
|
this->actor.world.pos.z = -400.0f;
|
|
|
|
this->actor.shape.yOffset = -7000.0f;
|
|
this->actor.shape.rot.y = 0;
|
|
|
|
this->csCamEye.x = this->csCamAt.x = -472.0f;
|
|
this->csCamEye.y = this->csCamAt.y = 4152.0f;
|
|
this->csCamEye.z = -160.0f;
|
|
|
|
this->csCamAt.z = -100.0f;
|
|
|
|
sBossGanonCape->backPush = -2.0f;
|
|
sBossGanonCape->backSwayMagnitude = 0.25f;
|
|
sBossGanonCape->sideSwayMagnitude = -1.0f;
|
|
sBossGanonCape->minDist = 0.0f;
|
|
sBossGanonCape->minY = 4104.0f;
|
|
sBossGanonCape->tearTimer = 20;
|
|
|
|
this->whiteFillAlpha = 255.0f;
|
|
globalCtx->envCtx.unk_D8 = 1.0f;
|
|
// fallthrough
|
|
case 101:
|
|
player->actor.world.pos.y = 4102.0f;
|
|
Math_ApproachZeroF(&this->whiteFillAlpha, 1.0f, 5.0f);
|
|
|
|
if (this->csTimer > 40) {
|
|
Math_ApproachF(&this->csCamEye.z, -520.0f, 0.1f, this->csCamMaxStepScale);
|
|
Math_ApproachF(&this->csCamMaxStepScale, 5.0f, 1.0f, 0.1f);
|
|
|
|
if (this->csTimer == 150) {
|
|
this->skelAnime.playSpeed = 1.0f;
|
|
}
|
|
|
|
if (this->csTimer == 160) {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_PL_BOUND_NOWEAPON);
|
|
}
|
|
|
|
if (this->csTimer == 187) {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_PL_BODY_HIT);
|
|
}
|
|
|
|
if (this->csTimer == 180) {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EV_GANON_MANTLE);
|
|
}
|
|
|
|
if (this->csTimer == 190) {
|
|
sp74 = this->actor.world.pos;
|
|
sp74.y = 4102.0f;
|
|
BossGanonEff_SpawnDustDark(globalCtx, &sp74, 0.2f, 0.7f);
|
|
}
|
|
|
|
if (this->csTimer == 230) {
|
|
this->csState = 102;
|
|
this->csTimer = 0;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 102:
|
|
player->actor.world.pos.y = 4102.0f;
|
|
|
|
this->csCamEye.x = -442.0f;
|
|
this->csCamEye.y = 4152.0f;
|
|
this->csCamEye.z = -135.0f;
|
|
|
|
this->csCamAt.x = -472.0f;
|
|
this->csCamAt.y = 4152.0f;
|
|
this->csCamAt.z = -135.0f;
|
|
|
|
if (this->csTimer == 5) {
|
|
func_8002DF54(globalCtx, &this->actor, 0x4C);
|
|
}
|
|
|
|
if (this->csTimer == 70) {
|
|
func_8002DF54(globalCtx, &this->actor, 0x4D);
|
|
}
|
|
|
|
if (this->csTimer == 90) {
|
|
this->csState = 103;
|
|
this->csTimer = 0;
|
|
sBossGanonZelda->actor.world.pos.x = -472.0f;
|
|
sBossGanonZelda->actor.world.pos.y = 4352.0f;
|
|
sBossGanonZelda->actor.world.pos.z = -200.0f;
|
|
sBossGanonZelda->unk_3C8 = 3;
|
|
}
|
|
break;
|
|
|
|
case 103:
|
|
Audio_PlayActorSound2(&sBossGanonZelda->actor, NA_SE_EV_DOWN_TO_GROUND - SFX_FLAG);
|
|
Math_ApproachF(&sBossGanonZelda->actor.world.pos.y, 4102.0f, 0.05f, 1.5f);
|
|
|
|
this->csCamEye.x = -242.0f;
|
|
this->csCamEye.y = 4122.0f;
|
|
this->csCamEye.z = -190.0f;
|
|
|
|
this->csCamAt.x = sBossGanonZelda->actor.world.pos.x;
|
|
this->csCamAt.y = sBossGanonZelda->actor.world.pos.y + 40.0f + 5.0f;
|
|
this->csCamAt.z = sBossGanonZelda->actor.world.pos.z;
|
|
|
|
if (this->csTimer == 200) {
|
|
sBossGanonZelda->actor.world.pos.y = 4102.0f;
|
|
this->csState = 104;
|
|
this->csTimer = 0;
|
|
} else {
|
|
break;
|
|
}
|
|
// fallthrough
|
|
case 104:
|
|
this->csCamEye.x = -432.0f;
|
|
this->csCamEye.y = 4147.0f;
|
|
this->csCamEye.z = -200.0f;
|
|
|
|
this->csCamAt.x = sBossGanonZelda->actor.world.pos.x;
|
|
this->csCamAt.y = sBossGanonZelda->actor.world.pos.y + 40.0f + 5.0f;
|
|
this->csCamAt.z = sBossGanonZelda->actor.world.pos.z;
|
|
|
|
if (this->csTimer >= 10) {
|
|
Math_ApproachZeroF(&globalCtx->envCtx.unk_D8, 1.0f, 0.05f);
|
|
}
|
|
|
|
if (this->csTimer == 10) {
|
|
sBossGanonZelda->unk_3C8 = 8;
|
|
}
|
|
|
|
if (this->csTimer == 50) {
|
|
sBossGanonZelda->unk_3C8 = 4;
|
|
}
|
|
|
|
if (this->csTimer == 100) {
|
|
this->csState = 105;
|
|
this->csTimer = 0;
|
|
}
|
|
break;
|
|
|
|
case 105:
|
|
this->csCamEye.x = -450.0f;
|
|
this->csCamEye.y = 4154.0f;
|
|
this->csCamEye.z = -182.0f;
|
|
|
|
this->csCamAt.x = sBossGanonZelda->actor.world.pos.x - 5.0f;
|
|
this->csCamAt.y = sBossGanonZelda->actor.world.pos.y + 40.0f + 5.0f;
|
|
this->csCamAt.z = sBossGanonZelda->actor.world.pos.z - 25.0f;
|
|
|
|
if (this->csTimer == 10) {
|
|
Message_StartTextbox(globalCtx, 0x70D0, NULL);
|
|
}
|
|
|
|
if ((this->csTimer > 100) && (Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_NONE)) {
|
|
this->csState = 1055;
|
|
this->csTimer = 0;
|
|
}
|
|
break;
|
|
|
|
case 1055:
|
|
this->unk_70C = Math_SinS(this->csTimer * 0x6300) * 0.3f;
|
|
func_80078884(NA_SE_EV_EARTHQUAKE - SFX_FLAG);
|
|
|
|
if (this->csTimer == 20) {
|
|
sBossGanonZelda->unk_3C8 = 5;
|
|
func_8002DF54(globalCtx, &this->actor, 0x39);
|
|
}
|
|
|
|
if (this->csTimer == 40) {
|
|
this->csState = 1056;
|
|
this->csTimer = 0;
|
|
}
|
|
break;
|
|
|
|
case 1056:
|
|
this->unk_70C = Math_SinS(this->csTimer * 0x6300) * 0.3f;
|
|
func_80078884(NA_SE_EV_EARTHQUAKE - SFX_FLAG);
|
|
|
|
this->csCamEye.x = -503.0f;
|
|
this->csCamEye.y = 4128.0f;
|
|
this->csCamEye.z = -162.0f;
|
|
|
|
this->csCamAt.x = -416.0f;
|
|
this->csCamAt.y = 4181.0f;
|
|
this->csCamAt.z = -75.0f;
|
|
|
|
if (this->csTimer > 40) {
|
|
this->csState = 1057;
|
|
this->csTimer = 0;
|
|
}
|
|
break;
|
|
|
|
case 1057:
|
|
this->unk_70C = Math_SinS(this->csTimer * 0x6300) * (50.0f * this->csCamMovementScale);
|
|
func_80078884(NA_SE_EV_EARTHQUAKE - SFX_FLAG);
|
|
|
|
Math_ApproachF(&this->csCamEye.x, -1200.0f, 0.1f, this->csCamMovementScale * 697.0f);
|
|
Math_ApproachF(&this->csCamEye.y, 4241.0f, 0.1f, this->csCamMovementScale * 113.0f);
|
|
Math_ApproachF(&this->csCamEye.z, -1048.0f, 0.1f, this->csCamMovementScale * 886.0f);
|
|
|
|
Math_ApproachF(&this->csCamMovementScale, 0.05f, 1.0f, 0.001f);
|
|
|
|
if (this->csTimer > 80) {
|
|
this->csState = 106;
|
|
this->csTimer = 60;
|
|
}
|
|
break;
|
|
|
|
case 106:
|
|
this->csCamEye.x = -450.0f;
|
|
this->csCamEye.y = 4154.0f;
|
|
this->csCamEye.z = -182.0f;
|
|
|
|
this->csCamAt.x = sBossGanonZelda->actor.world.pos.x - 5.0f;
|
|
this->csCamAt.y = sBossGanonZelda->actor.world.pos.y + 40.0f + 5.0f;
|
|
this->csCamAt.z = sBossGanonZelda->actor.world.pos.z - 25.0f;
|
|
|
|
this->unk_70C = Math_SinS(this->csTimer * 0x6300) * 0.3f;
|
|
func_80078884(NA_SE_EV_EARTHQUAKE - SFX_FLAG);
|
|
|
|
if (this->csTimer == 70) {
|
|
sBossGanonZelda->unk_3C8 = 6;
|
|
}
|
|
|
|
if (this->csTimer == 90) {
|
|
Message_StartTextbox(globalCtx, 0x70D1, NULL);
|
|
}
|
|
|
|
if ((this->csTimer > 150) && (Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_NONE)) {
|
|
this->csState = 107;
|
|
this->csTimer = 0;
|
|
Message_StartTextbox(globalCtx, 0x70D2, NULL);
|
|
func_8002DF54(globalCtx, &this->actor, 0x39);
|
|
}
|
|
break;
|
|
|
|
case 107:
|
|
this->unk_70C = Math_SinS(this->csTimer * 0x6300) * 0.8f;
|
|
func_80078884(NA_SE_EV_EARTHQUAKE - SFX_FLAG);
|
|
|
|
this->csCamEye.x = -380.0f;
|
|
this->csCamEye.y = 4154.0f;
|
|
this->csCamEye.z = -242.0f;
|
|
|
|
this->csCamAt.x = (sBossGanonZelda->actor.world.pos.x - 5.0f) - 30.0f;
|
|
this->csCamAt.y = (sBossGanonZelda->actor.world.pos.y + 40.0f + 5.0f) - 20.0f;
|
|
this->csCamAt.z = (sBossGanonZelda->actor.world.pos.z - 25.0f) + 80.0f;
|
|
|
|
if ((this->csTimer > 50) && (Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_NONE)) {
|
|
sBossGanonZelda->unk_3C8 = 7;
|
|
this->csState = 108;
|
|
this->csTimer = 0;
|
|
}
|
|
break;
|
|
|
|
case 108:
|
|
this->unk_70C = Math_SinS(this->csTimer * 0x6300) * 0.8f;
|
|
func_80078884(NA_SE_EV_EARTHQUAKE - SFX_FLAG);
|
|
|
|
this->csCamAt.x = (sBossGanonZelda->actor.world.pos.x - 5.0f) - 30.0f;
|
|
this->csCamAt.y = (sBossGanonZelda->actor.world.pos.y + 40.0f + 5.0f) - 20.0f;
|
|
this->csCamAt.z = (sBossGanonZelda->actor.world.pos.z - 25.0f) + 80.0f;
|
|
|
|
if (this->csTimer > 50) {
|
|
mainCam = Gameplay_GetCamera(globalCtx, MAIN_CAM);
|
|
|
|
mainCam->eye = this->csCamEye;
|
|
mainCam->eyeNext = this->csCamEye;
|
|
mainCam->at = this->csCamAt;
|
|
|
|
func_800C08AC(globalCtx, this->csCamIndex, 0);
|
|
this->csState = 109;
|
|
this->csCamIndex = 0;
|
|
func_80064534(globalCtx, &globalCtx->csCtx);
|
|
func_8002DF54(globalCtx, &this->actor, 7);
|
|
Flags_SetSwitch(globalCtx, 0x37);
|
|
}
|
|
break;
|
|
|
|
case 109:
|
|
func_80078884(NA_SE_EV_EARTHQUAKE - SFX_FLAG);
|
|
break;
|
|
}
|
|
|
|
if (this->csState >= 100) {
|
|
this->envLightMode = 20;
|
|
}
|
|
|
|
if (this->csCamIndex != 0) {
|
|
if (moveCam) {
|
|
Math_ApproachF(&this->csCamEye.x, this->csCamTargetEye.x, this->csCamMovementScale,
|
|
this->csCamEyeMaxStep.x * this->csCamMaxStepScale);
|
|
Math_ApproachF(&this->csCamEye.y, this->csCamTargetEye.y, this->csCamMovementScale,
|
|
this->csCamEyeMaxStep.y * this->csCamMaxStepScale);
|
|
Math_ApproachF(&this->csCamEye.z, this->csCamTargetEye.z, this->csCamMovementScale,
|
|
this->csCamEyeMaxStep.z * this->csCamMaxStepScale);
|
|
Math_ApproachF(&this->csCamAt.x, this->csCamTargetAt.x, this->csCamMovementScale,
|
|
this->csCamAtMaxStep.x * this->csCamMaxStepScale);
|
|
Math_ApproachF(&this->csCamAt.y, this->csCamTargetAt.y, this->csCamMovementScale,
|
|
this->csCamAtMaxStep.y * this->csCamMaxStepScale);
|
|
Math_ApproachF(&this->csCamAt.z, this->csCamTargetAt.z, this->csCamMovementScale,
|
|
this->csCamAtMaxStep.z * this->csCamMaxStepScale);
|
|
}
|
|
|
|
sp64 = this->csCamAt;
|
|
sp64.y += this->unk_70C;
|
|
Gameplay_CameraSetAtEye(globalCtx, this->csCamIndex, &sp64, &this->csCamEye);
|
|
}
|
|
}
|
|
|
|
void BossGanon_SetupPoundFloor(BossGanon* this, GlobalContext* globalCtx) {
|
|
this->unk_1C2 = 0;
|
|
this->timers[0] = 40;
|
|
this->actionFunc = BossGanon_PoundFloor;
|
|
this->actor.velocity.x = 0.0f;
|
|
this->actor.velocity.y = 0.0f;
|
|
this->fwork[GDF_CENTER_POS] = 100.0f;
|
|
}
|
|
|
|
void BossGanon_PoundFloor(BossGanon* this, GlobalContext* globalCtx) {
|
|
s16 i;
|
|
f32 heightTarget;
|
|
f32 targetPosX;
|
|
f32 targetPosZ;
|
|
Vec3f sp6C;
|
|
Vec3f sp60;
|
|
Vec3f sp54;
|
|
Vec3f sp48;
|
|
|
|
SkelAnime_Update(&this->skelAnime);
|
|
|
|
switch (this->unk_1C2) {
|
|
case 0:
|
|
targetPosX = Math_SinS(this->unk_1A2 * 1280);
|
|
targetPosX = targetPosX * this->fwork[GDF_CENTER_POS];
|
|
targetPosZ = Math_CosS(this->unk_1A2 * 1792);
|
|
targetPosZ = targetPosZ * this->fwork[GDF_CENTER_POS];
|
|
|
|
Math_ApproachF(&this->actor.world.pos.x, targetPosX, 0.05f, this->fwork[GDF_FWORK_0]);
|
|
Math_ApproachF(&this->actor.world.pos.z, targetPosZ, 0.05f, this->fwork[GDF_FWORK_0]);
|
|
Math_ApproachF(&this->fwork[GDF_CENTER_POS], 0.0f, 1, 1.5f);
|
|
|
|
if (this->timers[0] == 5) {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_HIT_GND);
|
|
}
|
|
|
|
if (this->timers[0] < 14) {
|
|
heightTarget = 250.0f;
|
|
this->unk_258 += (Rand_ZeroFloat(M_PI / 2) + (M_PI / 2));
|
|
Math_ApproachF(&this->handLightBallScale, 7.0f, 0.5f, 1.0f);
|
|
this->envLightMode = 1;
|
|
} else {
|
|
heightTarget = 200.0f;
|
|
}
|
|
|
|
Math_ApproachF(&this->actor.world.pos.y, heightTarget, 0.1f, this->actor.velocity.y);
|
|
Math_ApproachF(&this->actor.velocity.y, 20.0f, 1.0f, 1.0f);
|
|
|
|
if (this->timers[0] == 14) {
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfPoundAnim);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &gDorfPoundAnim, 0.0f);
|
|
this->actor.velocity.y = 0.0f;
|
|
}
|
|
|
|
if (this->timers[0] == 0) {
|
|
this->unk_1C2 = 1;
|
|
this->actor.velocity.y = 0.0f;
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
sBossGanonCape->gravity = -1.0f;
|
|
this->envLightMode = 1;
|
|
Math_ApproachF(&this->actor.velocity.y, -50.0f, 1.0f, 10.0f);
|
|
this->actor.world.pos.y += this->actor.velocity.y;
|
|
|
|
if (this->actor.world.pos.y < 60.0f) {
|
|
this->actor.world.pos.y = 60.0f;
|
|
this->unk_1C2 = 2;
|
|
this->timers[0] = 10;
|
|
func_80033E88(&this->actor, globalCtx, 0xA, 0x14); // rumble
|
|
this->unk_19C = 35;
|
|
this->unk_19E = 0;
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_HIT_GND_IMP);
|
|
this->handLightBallScale = 0.0f;
|
|
sp60 = this->unk_260;
|
|
sp60.y = 0.0f;
|
|
|
|
for (i = 0; i < 80; i++) {
|
|
sp6C.x = Rand_CenteredFloat(25.0f);
|
|
sp6C.y = Rand_ZeroFloat(17.0f);
|
|
sp6C.z = Rand_CenteredFloat(25.0f);
|
|
BossGanonEff_SpawnLightRay(globalCtx, &sp60, &sp6C, &sZeroVec, Rand_ZeroFloat(300.0f) + 500.0f,
|
|
13.0f, 0x1E);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
this->envLightMode = 1;
|
|
|
|
if (this->timers[0] == 0) {
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfPoundEndAnim);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &gDorfPoundEndAnim, 0.0f);
|
|
this->unk_1C2 = 3;
|
|
this->unk_19F = 1;
|
|
this->actor.velocity.y = 0.0f;
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
Math_ApproachF(&this->actor.world.pos.y, 150.0f, 0.1f, this->actor.velocity.y);
|
|
Math_ApproachF(&this->actor.velocity.y, 20.0f, 1.0f, 1.0f);
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->fwork[GDF_FWORK_1])) {
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfGetUp3Anim);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &gDorfGetUp3Anim, 0.0f);
|
|
SkelAnime_Update(&this->skelAnime);
|
|
sBossGanonCape->attachShouldersTimer = 18.0f;
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EV_GANON_MANTLE);
|
|
this->unk_1C2 = 4;
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
Math_ApproachF(&this->actor.world.pos.y, 150.0f, 0.1f, this->actor.velocity.y);
|
|
Math_ApproachF(&this->actor.velocity.y, 20.0f, 1.0f, 1.0f);
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->fwork[GDF_FWORK_1])) {
|
|
BossGanon_SetupWait(this, globalCtx);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if ((this->unk_19C == 35) || (this->unk_19C == 30) || (this->unk_19C == 25)) {
|
|
sp54 = this->actor.world.pos;
|
|
sp54.y = 0.0f;
|
|
BossGanonEff_SpawnDustLight(globalCtx, &sp54, 0, 3.0f, this->unk_19C - 25);
|
|
}
|
|
|
|
if (this->unk_19C == 35) {
|
|
sp48 = this->actor.world.pos;
|
|
sp48.y = 0.0f;
|
|
BossGanonEff_SpawnShockwave(globalCtx, &sp48, 0, 3.0f);
|
|
}
|
|
}
|
|
|
|
void BossGanon_SetupChargeBigMagic(BossGanon* this, GlobalContext* globalCtx) {
|
|
this->unk_1C2 = 0;
|
|
this->timers[0] = 30;
|
|
this->actor.velocity.x = 0.0f;
|
|
this->actor.velocity.y = 0.0f;
|
|
this->fwork[GDF_CENTER_POS] = 100.0f;
|
|
this->unk_1AA = Rand_ZeroFloat(20000.0f);
|
|
this->unk_1AC = 0;
|
|
this->actionFunc = BossGanon_ChargeBigMagic;
|
|
}
|
|
|
|
void BossGanon_ChargeBigMagic(BossGanon* this, GlobalContext* globalCtx) {
|
|
s32 pad;
|
|
f32 targetPosX;
|
|
f32 targetPosZ;
|
|
Vec3f sp80;
|
|
Vec3f sp74;
|
|
Vec3f sp68;
|
|
s16 i;
|
|
|
|
SkelAnime_Update(&this->skelAnime);
|
|
|
|
targetPosX = Math_SinS(this->unk_1A2 * 1280);
|
|
targetPosX = targetPosX * this->fwork[GDF_CENTER_POS];
|
|
|
|
targetPosZ = Math_CosS(this->unk_1A2 * 1792);
|
|
targetPosZ = targetPosZ * this->fwork[GDF_CENTER_POS];
|
|
|
|
Math_ApproachF(&this->actor.world.pos.x, targetPosX, 0.05f, this->fwork[GDF_FWORK_0]);
|
|
Math_ApproachF(&this->actor.world.pos.z, targetPosZ, 0.05, this->fwork[GDF_FWORK_0]);
|
|
|
|
Math_ApproachF(&this->fwork[GDF_CENTER_POS], 0.0f, 1.0f, 1.5f);
|
|
Math_ApproachF(&this->actor.world.pos.y, 200.0f, 0.05f, this->actor.velocity.y);
|
|
Math_ApproachF(&this->actor.velocity.y, 20.0f, 1.0f, 1.0f);
|
|
|
|
switch (this->unk_1C2) {
|
|
case 0:
|
|
if (this->timers[0] == 0) {
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfBigMagicChargeStartAnim);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &gDorfBigMagicChargeStartAnim, 0.0f);
|
|
this->unk_1C2 = 1;
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
if (Animation_OnFrame(&this->skelAnime, this->fwork[GDF_FWORK_1])) {
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfBigMagicChargeHoldAnim);
|
|
Animation_MorphToLoop(&this->skelAnime, &gDorfBigMagicChargeHoldAnim, 0.0f);
|
|
this->unk_1C2 = 2;
|
|
this->timers[0] = 100;
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
this->envLightMode = 2;
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_CHARGE_MASIC - SFX_FLAG);
|
|
this->unk_278.x = this->unk_2EC[0].x;
|
|
this->unk_278.y = this->unk_2EC[0].y + 50.0f + 30.0f;
|
|
this->unk_278.z = this->unk_2EC[0].z;
|
|
|
|
Math_ApproachF(&this->unk_284, 0.25f, 0.1f, 0.006f);
|
|
Math_ApproachF(&this->unk_288, 255.0f, 1.0f, 255.0f);
|
|
Math_ApproachF(&this->unk_28C, 0.25f, 0.1f, 0.006f);
|
|
|
|
if ((this->timers[0] > 20) && (this->timers[0] < 60)) {
|
|
Math_ApproachF(&this->unk_290, 255.0f, 1.0f, 15.0f);
|
|
}
|
|
|
|
if (this->timers[0] == 0) {
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfBigMagicWindupAnim);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &gDorfBigMagicWindupAnim, 0.0f);
|
|
this->unk_1C2 = 3;
|
|
this->timers[0] = 6;
|
|
this->timers[1] = 15;
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_DARKWAVE);
|
|
break;
|
|
}
|
|
|
|
Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 5, 0x3E8);
|
|
|
|
if (this->timers[0] < -4) {
|
|
for (i = 0; i < ARRAY_COUNT(this->unk_294); i++) {
|
|
Math_ApproachF(&this->unk_294[i], 0.0f, 1.0f, 40.0f);
|
|
}
|
|
} else if ((this->timers[0] >= 7) && (this->timers[0] < 26)) {
|
|
if (this->unk_1AC < ARRAY_COUNT(this->unk_294)) {
|
|
this->unk_1AC++;
|
|
}
|
|
|
|
for (i = 0; i < this->unk_1AC; i++) {
|
|
Math_ApproachF(&this->unk_294[i], 200.0f, 1.0f, 40.0f);
|
|
}
|
|
}
|
|
|
|
if (this->timers[0] <= 30) {
|
|
Math_ApproachF(&this->unk_284, 0.4f, 0.5f, 0.017f);
|
|
this->unk_28C = this->unk_284;
|
|
}
|
|
|
|
if (this->timers[0] <= 30) {
|
|
Math_ApproachF(&this->unk_2D0, 45.0f, 0.1f, 10.0f);
|
|
this->lensFlareTimer = 1;
|
|
this->lensFlareMode = 2;
|
|
gCustomLensFlarePos = this->unk_278;
|
|
}
|
|
|
|
if (this->timers[0] == 47) {
|
|
this->unk_274 = 1;
|
|
}
|
|
|
|
if (this->timers[0] == 46) {
|
|
this->unk_274 = 2;
|
|
}
|
|
|
|
if (this->timers[0] == 45) {
|
|
this->unk_274 = 3;
|
|
}
|
|
|
|
if (this->timers[0] == 44) {
|
|
this->unk_274 = 4;
|
|
}
|
|
|
|
if (this->timers[0] == 43) {
|
|
this->unk_274 = 5;
|
|
}
|
|
|
|
if (this->timers[0] == 42) {
|
|
this->unk_274 = 6;
|
|
}
|
|
|
|
if (this->timers[0] > 30) {
|
|
sp74.x = 0.0f;
|
|
sp74.y = Rand_ZeroFloat(10.0f) + 150.0f;
|
|
sp74.z = 0.0f;
|
|
|
|
Matrix_RotateY(BINANG_TO_RAD(this->actor.yawTowardsPlayer), MTXMODE_NEW);
|
|
Matrix_RotateZ(Rand_ZeroFloat(65536.0f), MTXMODE_APPLY);
|
|
Matrix_MultVec3f(&sp74, &sp68);
|
|
|
|
sp80.x = this->unk_278.x + sp68.x;
|
|
sp80.y = this->unk_278.y + sp68.y;
|
|
sp80.z = this->unk_278.z + sp68.z;
|
|
|
|
BossGanonEff_SpawnBlackDot(globalCtx, &sp80, 20.0f);
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
this->envLightMode = 2;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(this->unk_294); i++) {
|
|
Math_ApproachF(&this->unk_294[i], 0.0f, 1.0f, 40.0f);
|
|
}
|
|
|
|
if (this->timers[0] == 1) {
|
|
sBossGanonCape->attachLeftArmTimer = 15.0f;
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EV_GANON_MANTLE);
|
|
}
|
|
|
|
if (this->timers[0] == 0) {
|
|
Math_ApproachZeroF(&this->unk_284, 1.0f, 0.08f);
|
|
this->unk_28C = this->unk_284;
|
|
Math_ApproachZeroF(&this->unk_2D0, 1.0f, 10.0f);
|
|
Math_ApproachF(&this->unk_278.x, this->unk_1FC.x, 0.5f, 30.0f);
|
|
Math_ApproachF(&this->unk_278.y, this->unk_1FC.y, 0.5f, 30.0f);
|
|
Math_ApproachF(&this->unk_278.z, this->unk_1FC.z, 0.5f, 30.0f);
|
|
}
|
|
|
|
if (this->timers[1] == 0) {
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfBigMagicThrowAnim);
|
|
Animation_MorphToLoop(&this->skelAnime, &gDorfBigMagicThrowAnim, 0.0f);
|
|
this->unk_1C2 = 4;
|
|
this->unk_288 = 0.0f;
|
|
this->unk_290 = 0.0f;
|
|
this->unk_284 = 0.0f;
|
|
this->unk_28C = 0.0f;
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
this->envLightMode = 2;
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, 5.0f)) {
|
|
for (i = 0; i < 5; i++) {
|
|
Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_BOSS_GANON, this->unk_1FC.x,
|
|
this->unk_1FC.y, this->unk_1FC.z, 0, this->actor.yawTowardsPlayer, 0, 0x104 + i);
|
|
}
|
|
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_BIGMASIC);
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_THROW_BIG);
|
|
}
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, 3.0f)) {
|
|
sBossGanonCape->attachShouldersTimer = 26.0f;
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EV_GANON_MANTLE);
|
|
}
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->fwork[GDF_FWORK_1])) {
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfBigMagicThrowEndAnim);
|
|
Animation_MorphToLoop(&this->skelAnime, &gDorfBigMagicThrowEndAnim, 0.0f);
|
|
this->unk_1C2 = 5;
|
|
}
|
|
break;
|
|
|
|
case 5:
|
|
this->envLightMode = 2;
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->fwork[GDF_FWORK_1])) {
|
|
BossGanon_SetupWait(this, globalCtx);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void BossGanon_SetupWait(BossGanon* this, GlobalContext* globalCtx) {
|
|
BossGanon_SetAnimationObject(this, globalCtx, OBJECT_GANON_ANIME1);
|
|
Animation_MorphToLoop(&this->skelAnime, &gDorfFloatAnim, -10.0f);
|
|
this->actionFunc = BossGanon_Wait;
|
|
this->fwork[GDF_FWORK_0] = 0.0f;
|
|
this->timers[0] = (s16)Rand_ZeroFloat(64.0f) + 30;
|
|
this->unk_1C2 = 0;
|
|
sBossGanonCape->minY = 2.0f;
|
|
}
|
|
|
|
void BossGanon_Wait(BossGanon* this, GlobalContext* globalCtx) {
|
|
f32 sin;
|
|
s32 pad;
|
|
f32 cos;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
|
|
this->legSwayEnabled = true;
|
|
|
|
sBossGanonCape->backPush = -3.0f;
|
|
sBossGanonCape->backSwayMagnitude = 0.25f;
|
|
sBossGanonCape->sideSwayMagnitude = -3.0f;
|
|
sBossGanonCape->minDist = 20.0f;
|
|
|
|
SkelAnime_Update(&this->skelAnime);
|
|
|
|
if ((this->unk_1C2 == 0) && !(player->actor.world.pos.y < 0.0f)) {
|
|
if (!(player->stateFlags1 & 0x2000) && (fabsf(player->actor.world.pos.x) < 110.0f) &&
|
|
(fabsf(player->actor.world.pos.z) < 110.0f)) {
|
|
BossGanon_SetupPoundFloor(this, globalCtx);
|
|
} else if ((this->timers[0] == 0) && !(player->stateFlags1 & 0x2000)) {
|
|
this->timers[0] = (s16)Rand_ZeroFloat(30.0f) + 30;
|
|
|
|
if ((s8)this->actor.colChkInfo.health >= 20) {
|
|
BossGanon_SetupChargeLightBall(this, globalCtx);
|
|
} else if (Rand_ZeroOne() >= 0.5f) {
|
|
if ((Rand_ZeroOne() >= 0.5f) || (this->actor.xzDistToPlayer > 350.0f)) {
|
|
BossGanon_SetupChargeBigMagic(this, globalCtx);
|
|
} else {
|
|
BossGanon_SetupPoundFloor(this, globalCtx);
|
|
}
|
|
} else {
|
|
BossGanon_SetupChargeLightBall(this, globalCtx);
|
|
}
|
|
}
|
|
}
|
|
|
|
sin = Math_SinS(this->unk_1A2 * 1280) * 100.0f;
|
|
cos = Math_CosS(this->unk_1A2 * 1792) * 100.0f;
|
|
|
|
Math_ApproachF(&this->actor.world.pos.x, sin, 0.05f, this->fwork[GDF_FWORK_0]);
|
|
Math_ApproachF(&this->actor.world.pos.y, 150.0f, 0.05f, this->fwork[GDF_FWORK_0] * 0.2f);
|
|
Math_ApproachF(&this->actor.world.pos.z, cos, 0.05f, this->fwork[GDF_FWORK_0]);
|
|
Math_ApproachF(&this->fwork[GDF_FWORK_0], 50.0f, 1.0f, 0.5f);
|
|
|
|
this->actor.velocity.x = this->actor.world.pos.x - this->actor.prevPos.x;
|
|
this->actor.velocity.z = this->actor.world.pos.z - this->actor.prevPos.z;
|
|
|
|
sin = Math_SinS(this->unk_1A2 * 1500);
|
|
this->actor.velocity.y = this->fwork[GDF_FWORK_0] * sin * 0.04f;
|
|
this->actor.world.pos.y += this->actor.velocity.y;
|
|
|
|
Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 5, 0xBB8);
|
|
func_80078914(&this->actor.projectedPos, NA_SE_EN_FANTOM_FLOAT - SFX_FLAG);
|
|
}
|
|
|
|
void BossGanon_SetupChargeLightBall(BossGanon* this, GlobalContext* globalCtx) {
|
|
BossGanon_SetAnimationObject(this, globalCtx, OBJECT_GANON_ANIME1);
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfChargeLightBallAnim);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &gDorfChargeLightBallAnim, -3.0f);
|
|
this->actionFunc = BossGanon_ChargeLightBall;
|
|
this->timers[0] = 25;
|
|
}
|
|
|
|
void BossGanon_ChargeLightBall(BossGanon* this, GlobalContext* globalCtx) {
|
|
SkelAnime_Update(&this->skelAnime);
|
|
|
|
sBossGanonCape->backPush = -3.0f;
|
|
sBossGanonCape->backSwayMagnitude = 1.25f;
|
|
sBossGanonCape->sideSwayMagnitude = -2.0f;
|
|
sBossGanonCape->minDist = 10.0f;
|
|
|
|
if (this->timers[0] < 17) {
|
|
this->envLightMode = 1;
|
|
}
|
|
|
|
if (this->timers[0] == 17) {
|
|
this->unk_26C = 10;
|
|
this->unk_270 = Rand_ZeroFloat(M_PI);
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_SPARK);
|
|
}
|
|
|
|
if (this->timers[0] < 10) {
|
|
this->unk_258 += (Rand_ZeroFloat(M_PI / 2) + (M_PI / 2));
|
|
Math_ApproachF(&this->handLightBallScale, 10.0f, 0.5f, 1.25f);
|
|
|
|
if (this->timers[0] == 0) {
|
|
BossGanon_SetupPlayTennis(this, globalCtx);
|
|
}
|
|
}
|
|
|
|
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.velocity.y = Math_SinS(this->unk_1A2 * 1500) * 2.0f;
|
|
this->actor.world.pos.y += this->actor.velocity.y;
|
|
}
|
|
|
|
void BossGanon_SetupPlayTennis(BossGanon* this, GlobalContext* globalCtx) {
|
|
BossGanon_SetAnimationObject(this, globalCtx, OBJECT_GANON_ANIME1);
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfThrowAnim);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &gDorfThrowAnim, 0.0f);
|
|
this->actionFunc = BossGanon_PlayTennis;
|
|
}
|
|
|
|
void BossGanon_PlayTennis(BossGanon* this, GlobalContext* globalCtx) {
|
|
static AnimationHeader* volleyAnims[] = { &gDorfVolleyLeftAnim, &gDorfVolleyRightAnim };
|
|
static s16 capeRightArmDurations[] = { 26, 20 };
|
|
s16 rand;
|
|
|
|
SkelAnime_Update(&this->skelAnime);
|
|
Math_ApproachZeroF(&this->handLightBallScale, 1.0f, 0.2f);
|
|
|
|
switch (this->unk_1C2) {
|
|
case 0:
|
|
this->envLightMode = 1;
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->fwork[GDF_FWORK_1])) {
|
|
this->unk_1C2 = 1;
|
|
Animation_MorphToLoop(&this->skelAnime, &gDorfFloatAnim, 0.0f);
|
|
}
|
|
|
|
if (this->skelAnime.curFrame <= 12.0f) {
|
|
this->lensFlareTimer = 2;
|
|
this->lensFlareMode = 2;
|
|
gCustomLensFlarePos = this->unk_260;
|
|
}
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, 12.0f)) {
|
|
this->handLightBallScale = 0.0f;
|
|
}
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, 11.0f)) {
|
|
this->unk_25C = 1;
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_THROW);
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_THROW_MASIC);
|
|
Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_BOSS_GANON, this->unk_260.x,
|
|
this->unk_260.y, this->unk_260.z, 0, 0, 0, 0x64);
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
if (this->startVolley) {
|
|
rand = Rand_ZeroOne() * 1.99f;
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(volleyAnims[rand]);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, volleyAnims[rand], 0.0f);
|
|
sBossGanonCape->attachRightArmTimer = capeRightArmDurations[rand];
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EV_GANON_MANTLE);
|
|
this->startVolley = false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
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_SmoothStepToF(&this->actor.velocity.x, 0.0f, 1.0f, 0.5f, 0.0f);
|
|
Math_SmoothStepToF(&this->actor.velocity.z, 0.0f, 1.0f, 0.5f, 0.0f);
|
|
|
|
this->actor.velocity.y = Math_SinS(this->unk_1A2 * 1500) * 2.0f;
|
|
this->actor.world.pos.y += this->actor.velocity.y;
|
|
}
|
|
|
|
void BossGanon_SetupBlock(BossGanon* this, GlobalContext* globalCtx) {
|
|
if ((this->actionFunc != BossGanon_Block) || (this->unk_1C2 != 0)) {
|
|
BossGanon_SetAnimationObject(this, globalCtx, OBJECT_GANON_ANIME1);
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfBlockAnim);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &gDorfBlockAnim, 0.0f);
|
|
this->actionFunc = BossGanon_Block;
|
|
}
|
|
|
|
this->unk_1C2 = 0;
|
|
sBossGanonCape->attachLeftArmTimer = this->timers[0] = 10;
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EV_GANON_MANTLE);
|
|
this->handLightBallScale = 0.0f;
|
|
}
|
|
|
|
void BossGanon_Block(BossGanon* this, GlobalContext* globalCtx) {
|
|
this->collider.base.colType = 9;
|
|
SkelAnime_Update(&this->skelAnime);
|
|
sBossGanonCape->backPush = -9.0f;
|
|
sBossGanonCape->backSwayMagnitude = 0.25f;
|
|
sBossGanonCape->sideSwayMagnitude = -2.0f;
|
|
sBossGanonCape->minDist = 13.0f;
|
|
|
|
if (this->unk_1C2 == 0) {
|
|
if (this->timers[0] == 0) {
|
|
this->unk_1C2 = 1;
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &gDorfBlockReleaseAnim, 0.0f);
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfBlockReleaseAnim);
|
|
SkelAnime_Update(&this->skelAnime);
|
|
sBossGanonCape->attachShouldersTimer = 15.0f;
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EV_GANON_MANTLE);
|
|
}
|
|
} else {
|
|
sBossGanonCape->sideSwayMagnitude = -13.0f;
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->fwork[GDF_FWORK_1])) {
|
|
BossGanon_SetupWait(this, globalCtx);
|
|
}
|
|
}
|
|
|
|
this->actor.world.pos.x += this->actor.velocity.x;
|
|
this->actor.world.pos.y += this->actor.velocity.y;
|
|
this->actor.world.pos.z += this->actor.velocity.z;
|
|
|
|
Math_ApproachZeroF(&this->actor.velocity.x, 1.0f, 0.5f);
|
|
Math_ApproachZeroF(&this->actor.velocity.y, 1.0f, 0.5f);
|
|
Math_ApproachZeroF(&this->actor.velocity.z, 1.0f, 0.5f);
|
|
}
|
|
|
|
void BossGanon_SetupHitByLightBall(BossGanon* this, GlobalContext* globalCtx) {
|
|
s16 i;
|
|
|
|
BossGanon_SetAnimationObject(this, globalCtx, OBJECT_GANON_ANIME1);
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfBigMagicHitAnim);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &gDorfBigMagicHitAnim, 0);
|
|
this->timers[0] = 70;
|
|
sBossGanonCape->attachRightArmTimer = sBossGanonCape->attachLeftArmTimer = 0;
|
|
|
|
for (i = 1; i < 15; i++) {
|
|
this->unk_4E4[i] = D_808E4C58[i];
|
|
}
|
|
|
|
this->unk_2E6 = 80;
|
|
this->unk_2E8 = 0;
|
|
this->actionFunc = BossGanon_HitByLightBall;
|
|
this->actor.velocity.x = this->actor.velocity.z = 0.0f;
|
|
this->unk_1C2 = 0;
|
|
this->unk_1A6 = 15;
|
|
this->unk_508 = 6.0f;
|
|
}
|
|
|
|
void BossGanon_HitByLightBall(BossGanon* this, GlobalContext* globalCtx) {
|
|
s16 i;
|
|
Vec3f sp50;
|
|
|
|
SkelAnime_Update(&this->skelAnime);
|
|
|
|
if (this->unk_1C2 == 0) {
|
|
BossGanonEff_SpawnShock(globalCtx, 1500.0f, GDF_SHOCK_DORF_YELLOW);
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->fwork[GDF_FWORK_1])) {
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfLightArrowWaitAnim);
|
|
Animation_MorphToLoop(&this->skelAnime, &gDorfLightArrowWaitAnim, 0.0f);
|
|
this->unk_1C2 = 1;
|
|
}
|
|
} else if (this->unk_1C2 == 1) {
|
|
BossGanonEff_SpawnShock(globalCtx, 1000.0f, GDF_SHOCK_DORF_YELLOW);
|
|
|
|
if (this->timers[0] == 0) {
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfGetUp3Anim);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &gDorfGetUp3Anim, 0.0f);
|
|
this->unk_1C2 = 2;
|
|
SkelAnime_Update(&this->skelAnime);
|
|
sBossGanonCape->attachShouldersTimer = 18.0f;
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EV_GANON_MANTLE);
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_RESTORE);
|
|
this->timers[2] = 130;
|
|
}
|
|
} else {
|
|
if (Animation_OnFrame(&this->skelAnime, 7.0f)) {
|
|
for (i = 0; i < 100; i++) {
|
|
sp50.x = Rand_CenteredFloat(25.0f);
|
|
sp50.y = Rand_CenteredFloat(25.0f);
|
|
sp50.z = Rand_CenteredFloat(25.0f);
|
|
|
|
BossGanonEff_SpawnSparkle(globalCtx, &this->unk_1FC, &sp50, &sZeroVec, Rand_ZeroFloat(200.0f) + 500.0f,
|
|
0x14);
|
|
}
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_PL_WALK_WATER2);
|
|
}
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->fwork[GDF_FWORK_1])) {
|
|
BossGanon_SetupWait(this, globalCtx);
|
|
}
|
|
}
|
|
|
|
this->actor.velocity.y = Math_SinS(this->unk_1A2 * 1500) * 2.0f;
|
|
this->actor.world.pos.y += this->actor.velocity.y;
|
|
}
|
|
|
|
void BossGanon_SetupVulnerable(BossGanon* this, GlobalContext* globalCtx) {
|
|
s16 i;
|
|
|
|
if (this->actionFunc != BossGanon_Vulnerable) {
|
|
BossGanon_SetAnimationObject(this, globalCtx, OBJECT_GANON_ANIME1);
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfLightArrowHitAnim);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &gDorfLightArrowHitAnim, 0.0f);
|
|
sBossGanonCape->attachRightArmTimer = sBossGanonCape->attachLeftArmTimer = 0;
|
|
this->actionFunc = BossGanon_Vulnerable;
|
|
|
|
this->actor.velocity.x = 0.0f;
|
|
this->actor.velocity.y = 0.0f;
|
|
this->actor.velocity.z = 0.0f;
|
|
|
|
this->unk_1C2 = 0;
|
|
sBossGanonCape->backPush = -4.0f;
|
|
sBossGanonCape->backSwayMagnitude = 0.75f;
|
|
sBossGanonCape->sideSwayMagnitude = -3.0f;
|
|
sBossGanonCape->minDist = 20.0f;
|
|
|
|
for (i = 0; i < 10; i++) {
|
|
Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_BOSS_GANON, this->unk_1FC.x,
|
|
this->unk_1FC.y, this->unk_1FC.z, Rand_CenteredFloat(0x8000),
|
|
(s16)Rand_CenteredFloat(0x8000) + this->actor.yawTowardsPlayer, 0, 0xC8 + i);
|
|
}
|
|
|
|
this->unk_1A4 = 0;
|
|
this->unk_288 = 0.0f;
|
|
this->unk_290 = 0.0f;
|
|
this->unk_284 = 0.0f;
|
|
this->unk_28C = 0.0f;
|
|
}
|
|
}
|
|
|
|
void BossGanon_Vulnerable(BossGanon* this, GlobalContext* globalCtx) {
|
|
s16 i;
|
|
Vec3f sp40;
|
|
|
|
if (this->timers[3] == 0) {
|
|
this->actor.flags |= ACTOR_FLAG_0;
|
|
}
|
|
|
|
SkelAnime_Update(&this->skelAnime);
|
|
|
|
this->envLightMode = 1;
|
|
this->actor.world.pos.y += this->actor.velocity.y;
|
|
|
|
if (this->unk_1A4 < 0x28) {
|
|
Math_ApproachF(&this->unk_508, 4.0f, 0.1f, 0.1f);
|
|
}
|
|
|
|
if ((this->unk_1A4 >= 0x28) && (this->unk_1A4 < 0x37)) {
|
|
Math_ApproachF(&this->unk_508, 0.0f, 1.0f, 0.5f);
|
|
}
|
|
|
|
if (this->unk_1A4 >= 0x37) {
|
|
Math_ApproachF(&this->unk_508, 5.0f, 0.1f, 0.15f);
|
|
this->shockGlow = true;
|
|
}
|
|
|
|
switch (this->unk_1C2) {
|
|
case 0:
|
|
if (Animation_OnFrame(&this->skelAnime, this->fwork[GDF_FWORK_1])) {
|
|
this->unk_1C2 = 1;
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfLightEnergyHitAnim);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &gDorfLightEnergyHitAnim, 0.0f);
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
if (Animation_OnFrame(&this->skelAnime, this->fwork[GDF_FWORK_1])) {
|
|
this->unk_1C2 = 2;
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfKneelVulnerableAnim);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &gDorfKneelVulnerableAnim, 0.0f);
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
sBossGanonCape->minDist = 0.0f;
|
|
this->actor.velocity.y = this->actor.velocity.y - 0.5f;
|
|
|
|
if (this->actor.world.pos.y < 40.0f) {
|
|
this->actor.world.pos.y = 40.0f;
|
|
this->actor.velocity.y = 0.0f;
|
|
this->unk_1C2 = 3;
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfLandAnim);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &gDorfLandAnim, 0.0f);
|
|
this->timers[0] = 70;
|
|
this->actor.flags |= ACTOR_FLAG_10;
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
if (this->timers[0] == 68) {
|
|
this->unk_19F = 1;
|
|
}
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->fwork[GDF_FWORK_1])) {
|
|
this->unk_1C2 = 4;
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfVulnerableAnim);
|
|
Animation_MorphToLoop(&this->skelAnime, &gDorfVulnerableAnim, 0.0f);
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
if (Animation_OnFrame(&this->skelAnime, 5.0f)) {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_DOWN);
|
|
}
|
|
|
|
if (this->timers[0] == 0) {
|
|
this->unk_1C2 = 5;
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfGetUp1Anim);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &gDorfGetUp1Anim, 0.0f);
|
|
this->unk_2D4 = 80;
|
|
|
|
for (i = 1; i < 15; i++) {
|
|
this->unk_4E4[i] = Rand_ZeroFloat(10.0f);
|
|
}
|
|
|
|
this->unk_2E6 = 80;
|
|
this->unk_2E8 = 0;
|
|
this->actor.flags &= ~ACTOR_FLAG_10;
|
|
}
|
|
break;
|
|
|
|
case 5:
|
|
BossGanonEff_SpawnShock(globalCtx, 1000.0f, GDF_SHOCK_DORF_YELLOW);
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->fwork[GDF_FWORK_1])) {
|
|
this->unk_1C2 = 6;
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfGetUp2Anim);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &gDorfGetUp2Anim, 0.0f);
|
|
sBossGanonCape->minDist = 20.0f;
|
|
this->unk_19F = 1;
|
|
}
|
|
break;
|
|
|
|
case 6:
|
|
this->envLightMode = 0;
|
|
Math_ApproachF(&this->actor.world.pos.y, 200.0f, 0.1f, 1000.0f);
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->fwork[GDF_FWORK_1])) {
|
|
this->unk_1C2 = 7;
|
|
}
|
|
break;
|
|
|
|
case 7:
|
|
this->envLightMode = 0;
|
|
Math_ApproachF(&this->actor.world.pos.y, 150.0f, 0.05f, 30.0f);
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfGetUp3Anim);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &gDorfGetUp3Anim, 0.0f);
|
|
this->unk_1C2 = 8;
|
|
SkelAnime_Update(&this->skelAnime);
|
|
sBossGanonCape->attachShouldersTimer = 18.0f;
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EV_GANON_MANTLE);
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_RESTORE);
|
|
break;
|
|
|
|
case 8:
|
|
this->envLightMode = 0;
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, 7.0f)) {
|
|
for (i = 0; i < 100; i++) {
|
|
sp40.x = Rand_CenteredFloat(25.0f);
|
|
sp40.y = Rand_CenteredFloat(25.0f);
|
|
sp40.z = Rand_CenteredFloat(25.0f);
|
|
BossGanonEff_SpawnSparkle(globalCtx, &this->unk_1FC, &sp40, &sZeroVec,
|
|
Rand_ZeroFloat(200.0f) + 500.0f, 0x14);
|
|
}
|
|
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_PL_WALK_WATER2);
|
|
this->timers[3] = 50;
|
|
}
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->fwork[GDF_FWORK_1])) {
|
|
BossGanon_SetupWait(this, globalCtx);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void BossGanon_SetupDamaged(BossGanon* this, GlobalContext* globalCtx) {
|
|
BossGanon_SetAnimationObject(this, globalCtx, OBJECT_GANON_ANIME1);
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfDamageAnim);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &gDorfDamageAnim, 0.0f);
|
|
this->actionFunc = BossGanon_Damaged;
|
|
}
|
|
|
|
void BossGanon_Damaged(BossGanon* this, GlobalContext* globalCtx) {
|
|
this->actor.flags |= ACTOR_FLAG_0;
|
|
|
|
SkelAnime_Update(&this->skelAnime);
|
|
|
|
if (this->unk_1A4 >= 0x37) {
|
|
Math_ApproachF(&this->unk_508, 5.0f, 0.1f, 0.15f);
|
|
this->shockGlow = true;
|
|
}
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->fwork[GDF_FWORK_1])) {
|
|
this->actionFunc = BossGanon_Vulnerable;
|
|
this->unk_1C2 = 4;
|
|
this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfVulnerableAnim);
|
|
Animation_MorphToLoop(&this->skelAnime, &gDorfVulnerableAnim, 0.0f);
|
|
}
|
|
}
|
|
|
|
void BossGanon_UpdateDamage(BossGanon* this, GlobalContext* globalCtx) {
|
|
s16 i;
|
|
s16 j;
|
|
ColliderInfo* acHitInfo;
|
|
|
|
if (this->collider.base.acFlags & 2) {
|
|
this->unk_2D4 = 2;
|
|
this->collider.base.acFlags &= ~2;
|
|
acHitInfo = this->collider.info.acHitInfo;
|
|
|
|
if ((this->actionFunc == BossGanon_HitByLightBall) || (this->actionFunc == BossGanon_ChargeBigMagic)) {
|
|
if (acHitInfo->toucher.dmgFlags & 0x2000) {
|
|
BossGanon_SetupVulnerable(this, globalCtx);
|
|
this->timers[2] = 0;
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_DAMAGE1);
|
|
this->unk_1A6 = 15;
|
|
}
|
|
} else if ((this->actionFunc == BossGanon_Vulnerable) && (this->unk_1C2 >= 3)) {
|
|
if (!(acHitInfo->toucher.dmgFlags & 0x80)) {
|
|
u8 hitWithSword = false;
|
|
u8 damage;
|
|
Vec3f sp50;
|
|
u32 flags;
|
|
|
|
for (i = 0; i < 30; i++) {
|
|
sp50.x = Rand_CenteredFloat(20.0f);
|
|
sp50.y = Rand_CenteredFloat(20.0f);
|
|
sp50.z = Rand_CenteredFloat(20.0f);
|
|
BossGanonEff_SpawnSparkle(globalCtx, &this->unk_1FC, &sp50, &sZeroVec,
|
|
Rand_ZeroFloat(200.0f) + 500.0f, 0x1E);
|
|
}
|
|
|
|
damage = flags = CollisionCheck_GetSwordDamage(acHitInfo->toucher.dmgFlags);
|
|
|
|
if (flags == 0) {
|
|
damage = 2;
|
|
} else {
|
|
hitWithSword = true;
|
|
}
|
|
|
|
if (((s8)this->actor.colChkInfo.health >= 3) || hitWithSword) {
|
|
this->actor.colChkInfo.health -= damage;
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_COUNT(sBossGanonCape->strands); i++) {
|
|
for (j = 1; j < 12; j++) {
|
|
sBossGanonCape->strands[i].velocities[j].x = Rand_CenteredFloat(15.0f);
|
|
sBossGanonCape->strands[i].velocities[j].z = Rand_CenteredFloat(15.0f);
|
|
}
|
|
}
|
|
|
|
if ((s8)this->actor.colChkInfo.health <= 0) {
|
|
BossGanon_SetupDeathCutscene(this, globalCtx);
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_DEAD);
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_DD_THUNDER);
|
|
func_80078914(&sZeroVec, NA_SE_EN_LAST_DAMAGE);
|
|
Audio_QueueSeqCmd(0x100100FF);
|
|
this->screenFlashTimer = 4;
|
|
} else {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_DAMAGE2);
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_CUTBODY);
|
|
BossGanon_SetupDamaged(this, globalCtx);
|
|
this->unk_1A6 = 15;
|
|
sBossGanonCape->tearTimer = 1;
|
|
}
|
|
}
|
|
} else if (acHitInfo->toucher.dmgFlags & 0x1F8A4) {
|
|
Audio_PlayActorSound2(&this->actor, 0);
|
|
|
|
for (i = 0; i < ARRAY_COUNT(sBossGanonCape->strands); i++) {
|
|
for (j = 1; j < 12; j++) {
|
|
sBossGanonCape->strands[i].velocities[j].x = Rand_CenteredFloat(15.0f);
|
|
sBossGanonCape->strands[i].velocities[j].z = Rand_CenteredFloat(15.0f);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static f32 D_808E4D44[] = {
|
|
1.0f, 3.0f, 0.0f, 7.0f, 13.0f, 4.0f, 6.0f, 11.0f, 5.0f, 2.0f, 8.0f, 14.0f, 10.0f, 12.0f, 9.0f,
|
|
};
|
|
|
|
void BossGanon_Update(Actor* thisx, GlobalContext* globalCtx2) {
|
|
BossGanon* this = (BossGanon*)thisx;
|
|
GlobalContext* globalCtx = globalCtx2;
|
|
f32 legRotX;
|
|
f32 legRotY;
|
|
f32 legRotZ;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
s16 i;
|
|
f32 sin;
|
|
f32 cos;
|
|
Vec3f shardPos;
|
|
Vec3f shardVel;
|
|
Vec3f spE8;
|
|
s16 i2;
|
|
s16 j;
|
|
Vec3f spD8;
|
|
Vec3f platformCheckPos;
|
|
Actor* explosive;
|
|
Vec3f spBC;
|
|
Vec3f spB0;
|
|
Vec3f platCheckPosBomb;
|
|
Actor* prop;
|
|
BgGanonOtyuka* platform;
|
|
f32 targetLensFlareScale;
|
|
f32 xOffset;
|
|
f32 zOffset;
|
|
|
|
if ((this->actionFunc != BossGanon_IntroCutscene) && (this->actionFunc != BossGanon_DeathAndTowerCutscene)) {
|
|
BossGanon_SetAnimationObject(this, globalCtx, OBJECT_GANON_ANIME1);
|
|
} else {
|
|
gSegments[6] = VIRTUAL_TO_PHYSICAL(globalCtx->objectCtx.status[this->animBankIndex].segment);
|
|
}
|
|
|
|
if (this->windowShatterState != GDF_WINDOW_SHATTER_OFF) {
|
|
BossGanon_ShatterWindows(this->windowShatterState);
|
|
shardVel.y = 0.0f;
|
|
|
|
for (i = 0; i < 10; i++) {
|
|
shardPos.y = Rand_ZeroFloat(240.0f) + 20.0f;
|
|
|
|
if (Rand_ZeroOne() < 0.5f) {
|
|
shardPos.x = 463;
|
|
shardPos.z = Rand_ZeroFloat(463.0f);
|
|
|
|
shardVel.x = Rand_ZeroFloat(2.0f);
|
|
shardVel.z = Rand_ZeroFloat(1.0f);
|
|
} else {
|
|
shardPos.z = 463;
|
|
shardPos.x = Rand_ZeroFloat(463.0f);
|
|
|
|
shardVel.z = Rand_ZeroFloat(2.0f);
|
|
shardVel.x = Rand_ZeroFloat(1.0f);
|
|
}
|
|
|
|
BossGanonEff_SpawnWindowShard(globalCtx, &shardPos, &shardVel, Rand_ZeroFloat(0.075f) + 0.08f);
|
|
}
|
|
}
|
|
|
|
this->collider.base.colType = 3;
|
|
sBossGanonCape->gravity = -3.0f;
|
|
this->shockGlow = false;
|
|
this->actor.flags &= ~ACTOR_FLAG_0;
|
|
this->unk_1A2++;
|
|
this->unk_1A4++;
|
|
|
|
// block players attack if hes shooting something
|
|
if ((this->actionFunc == BossGanon_Wait) || (this->actionFunc == BossGanon_Block)) {
|
|
if (player->unk_A73 != 0) {
|
|
BossGanon_SetupBlock(this, globalCtx);
|
|
}
|
|
}
|
|
|
|
this->actionFunc(this, globalCtx);
|
|
|
|
for (i = 0; i < ARRAY_COUNT(this->timers); i++) {
|
|
if (this->timers[i] != 0) {
|
|
this->timers[i]--;
|
|
}
|
|
}
|
|
|
|
if (this->unk_1A6 != 0) {
|
|
this->unk_1A6--;
|
|
}
|
|
|
|
if (this->unk_2D4 != 0) {
|
|
this->unk_2D4--;
|
|
}
|
|
|
|
if (this->unk_2E8 != 0) {
|
|
this->unk_2E8--;
|
|
}
|
|
|
|
if (this->unk_2E6 != 0) {
|
|
this->unk_2E6--;
|
|
}
|
|
|
|
if (this->unk_19C != 0) {
|
|
this->unk_19C--;
|
|
}
|
|
|
|
if (this->csState == 0) {
|
|
BossGanon_UpdateDamage(this, globalCtx);
|
|
BossGanon_SetColliderPos(&this->unk_1FC, &this->collider);
|
|
CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider.base);
|
|
|
|
if (this->unk_2D4 == 0) {
|
|
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->collider.base);
|
|
|
|
if ((this->actionFunc != BossGanon_HitByLightBall) && (this->actionFunc != BossGanon_Vulnerable) &&
|
|
(this->actionFunc != BossGanon_Damaged)) {
|
|
CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->collider.base);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (this->legSwayEnabled) {
|
|
sin = Math_SinS(-this->actor.shape.rot.y);
|
|
cos = Math_CosS(-this->actor.shape.rot.y);
|
|
|
|
legRotX = ((this->actor.velocity.z * sin) + (cos * this->actor.velocity.x)) * 300.0f;
|
|
legRotY = ((-sin * this->actor.velocity.x) + (cos * this->actor.velocity.z)) * 300.0f;
|
|
legRotZ = (Math_SinS(this->unk_1A2 * 2268) * -500.0f) - 500.0f;
|
|
} else {
|
|
legRotY = legRotX = legRotZ = 0.0f;
|
|
}
|
|
|
|
this->legSwayEnabled = false;
|
|
|
|
Math_SmoothStepToF(&this->legRot.x, legRotX, 1.0f, 600.0f, 0.0f);
|
|
Math_SmoothStepToF(&this->legRot.y, legRotY, 1.0f, 600.0f, 0.0f);
|
|
Math_SmoothStepToF(&this->legRot.z, legRotZ, 1.0f, 100.0f, 0.0f);
|
|
|
|
if (this->timers[2] == 1) {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_LAUGH);
|
|
}
|
|
|
|
if (this->timers[2] == 100) {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_FANTOM_ST_LAUGH);
|
|
this->timers[2] = 0;
|
|
}
|
|
|
|
if ((this->unk_2E6 != 0) || (this->unk_2E8 != 0)) {
|
|
for (i = 1; i < ARRAY_COUNT(this->unk_49C); i++) {
|
|
if (this->unk_4E4[i] != 0) {
|
|
this->unk_4E4[i]--;
|
|
Math_ApproachF(&this->unk_49C[i], this->unk_508, 1.0f, 2.0f);
|
|
} else {
|
|
Math_ApproachZeroF(&this->unk_49C[i], 1.0f, 0.2f);
|
|
}
|
|
}
|
|
|
|
// player hit, spawn shock and play sound
|
|
if (this->unk_2E8 != 0) {
|
|
func_80078914(&player->actor.projectedPos, NA_SE_PL_SPARK - SFX_FLAG);
|
|
BossGanonEff_SpawnShock(globalCtx, 700.0f, GDF_SHOCK_PLAYER_YELLOW);
|
|
}
|
|
}
|
|
|
|
if (this->unk_19F != 0) {
|
|
this->unk_19F = 0;
|
|
spE8 = this->actor.world.pos;
|
|
spE8.y = 0.0f;
|
|
BossGanonEff_SpawnDustDark(globalCtx, &spE8, 0.2, 0.7f);
|
|
BossGanonEff_SpawnDustDark(globalCtx, &spE8, 0.3f, 0.8f);
|
|
}
|
|
|
|
if (this->unk_26C != 0) {
|
|
this->unk_26C--;
|
|
|
|
if (this->unk_26C == 0) {
|
|
BossGanonEff_SpawnLightning(globalCtx, 1.0f, 0.0f, 0.0f);
|
|
}
|
|
|
|
BossGanonEff_SpawnLightning(globalCtx, 1.0f, D_808E4D44[this->unk_26C] * (M_PI / 5) + this->unk_270,
|
|
Rand_CenteredFloat(M_PI / 5) + (M_PI / 2));
|
|
}
|
|
|
|
// see if light ball hit and should knock platform down?
|
|
if ((this->unk_19C != 0) && (this->unk_19E < 4)) {
|
|
if ((this->unk_19A == 0) && (this->unk_19C == 20)) {
|
|
this->unk_19A = 1;
|
|
platformCheckPos.x = -180.0f;
|
|
platformCheckPos.y = 0.0f;
|
|
|
|
for (i2 = 0; i2 < 4; i2++) {
|
|
for (j = 0, platformCheckPos.z = -180.0f; j < 4; j++) {
|
|
BossGanon_CheckFallingPlatforms(this, globalCtx, &platformCheckPos);
|
|
platformCheckPos.z += 120.0f;
|
|
}
|
|
|
|
platformCheckPos.x += 120.0f;
|
|
}
|
|
} else if (this->unk_19C < 30) {
|
|
spD8.x = 0.0f;
|
|
spD8.y = 0.0f;
|
|
spD8.z = 15.0f * (30.0f - this->unk_19C);
|
|
|
|
Matrix_RotateY(Rand_ZeroFloat(6.2831855f), MTXMODE_NEW);
|
|
Matrix_MultVec3f(&spD8, &platformCheckPos);
|
|
|
|
this->unk_19E += BossGanon_CheckFallingPlatforms(this, globalCtx, &platformCheckPos);
|
|
}
|
|
}
|
|
|
|
// see if a bomb exploded near a group of platforms and if they should fall
|
|
explosive = globalCtx->actorCtx.actorLists[ACTORCAT_EXPLOSIVE].head;
|
|
|
|
while (explosive != NULL) {
|
|
if (explosive->params != BOMB_EXPLOSION) {
|
|
explosive = explosive->next;
|
|
} else {
|
|
for (i = 0; i < 8; i++) {
|
|
spBC.x = 0.0f;
|
|
spBC.y = 0.0f;
|
|
spBC.z = 60.0f;
|
|
|
|
Matrix_RotateY(i * (M_PI / 4), MTXMODE_NEW);
|
|
Matrix_MultVec3f(&spBC, &spB0);
|
|
|
|
platCheckPosBomb.x = explosive->world.pos.x + spB0.x;
|
|
platCheckPosBomb.y = explosive->world.pos.y;
|
|
platCheckPosBomb.z = explosive->world.pos.z + spB0.z;
|
|
|
|
BossGanon_CheckFallingPlatforms(this, globalCtx, &platCheckPosBomb);
|
|
}
|
|
|
|
explosive = explosive->next;
|
|
}
|
|
}
|
|
|
|
BossGanon_UpdateEffects(globalCtx);
|
|
|
|
prop = globalCtx->actorCtx.actorLists[ACTORCAT_PROP].head;
|
|
|
|
// if a platform is lit up, change the room lighting
|
|
while (prop != NULL) {
|
|
if (prop->id != ACTOR_BG_GANON_OTYUKA) {
|
|
prop = prop->next;
|
|
} else {
|
|
platform = (BgGanonOtyuka*)prop;
|
|
|
|
if (platform->flashState != 0) {
|
|
this->envLightMode = 1;
|
|
break;
|
|
}
|
|
|
|
prop = prop->next;
|
|
}
|
|
}
|
|
|
|
globalCtx->envCtx.unk_BF = 0;
|
|
globalCtx->envCtx.unk_BE = 0;
|
|
globalCtx->envCtx.unk_DC = 2;
|
|
|
|
switch (this->envLightMode) {
|
|
case -1:
|
|
break;
|
|
case 0:
|
|
Math_ApproachF(&globalCtx->envCtx.unk_D8, 0.0f, 1.0f, 0.02f);
|
|
break;
|
|
case 1:
|
|
globalCtx->envCtx.unk_BD = 1;
|
|
Math_ApproachF(&globalCtx->envCtx.unk_D8, 1.0f, 1.0f, 0.1f);
|
|
break;
|
|
case 2:
|
|
globalCtx->envCtx.unk_BD = 1;
|
|
Math_ApproachF(&globalCtx->envCtx.unk_D8, 1.0f, 1.0f, 0.02f);
|
|
break;
|
|
case 3:
|
|
globalCtx->envCtx.unk_BD = 3;
|
|
globalCtx->envCtx.unk_D8 = 1.0f;
|
|
break;
|
|
case 35:
|
|
globalCtx->envCtx.unk_BD = 0;
|
|
globalCtx->envCtx.unk_D8 = 1.0f;
|
|
break;
|
|
case 4:
|
|
globalCtx->envCtx.unk_BD = 4;
|
|
globalCtx->envCtx.unk_D8 = 1.0f;
|
|
break;
|
|
case 5:
|
|
globalCtx->envCtx.unk_BE = 5;
|
|
globalCtx->envCtx.unk_BD = 3;
|
|
Math_ApproachZeroF(&globalCtx->envCtx.unk_D8, 1.0f, 0.075f);
|
|
break;
|
|
case 6:
|
|
globalCtx->envCtx.unk_BE = 5;
|
|
globalCtx->envCtx.unk_D8 = 0.0f;
|
|
break;
|
|
case 65:
|
|
globalCtx->envCtx.unk_BE = 3;
|
|
globalCtx->envCtx.unk_BD = 6;
|
|
Math_ApproachZeroF(&globalCtx->envCtx.unk_D8, 1.0f, 0.05f);
|
|
break;
|
|
case 7:
|
|
globalCtx->envCtx.unk_BE = 7;
|
|
globalCtx->envCtx.unk_D8 = 0.0f;
|
|
break;
|
|
case 75:
|
|
globalCtx->envCtx.unk_BE = 4;
|
|
globalCtx->envCtx.unk_BD = 8;
|
|
Math_ApproachZeroF(&globalCtx->envCtx.unk_D8, 1.0f, 0.05f);
|
|
break;
|
|
case 8:
|
|
globalCtx->envCtx.unk_BE = 3;
|
|
globalCtx->envCtx.unk_BD = 9;
|
|
Math_ApproachF(&globalCtx->envCtx.unk_D8, 1.0f, 1.0f, 0.05f);
|
|
break;
|
|
case 9:
|
|
globalCtx->envCtx.unk_BE = 3;
|
|
globalCtx->envCtx.unk_BD = 0xA;
|
|
Math_ApproachZeroF(&globalCtx->envCtx.unk_D8, 1.0f, 0.05f);
|
|
break;
|
|
case 10:
|
|
globalCtx->envCtx.unk_BE = 3;
|
|
globalCtx->envCtx.unk_BD = 0xB;
|
|
Math_ApproachF(&globalCtx->envCtx.unk_D8, 1.0f, 1.0f, 0.05f);
|
|
this->unk_1A4 = 0;
|
|
break;
|
|
case 11:
|
|
globalCtx->envCtx.unk_BE = 0xC;
|
|
globalCtx->envCtx.unk_BD = 0xB;
|
|
Math_ApproachF(&globalCtx->envCtx.unk_D8, (Math_CosS(this->unk_1A4 * 0x1800) * 0.5f) + 0.5f, 1.0f, 1.0f);
|
|
break;
|
|
case 12:
|
|
globalCtx->envCtx.unk_BE = 0xC;
|
|
globalCtx->envCtx.unk_BD = 3;
|
|
Math_ApproachF(&globalCtx->envCtx.unk_D8, 1.0f, 1.0f, 0.05f);
|
|
break;
|
|
case 13:
|
|
globalCtx->envCtx.unk_BD = 0xD;
|
|
Math_ApproachF(&globalCtx->envCtx.unk_D8, 1.0f, 1.0f, 0.025f);
|
|
break;
|
|
case 14:
|
|
globalCtx->envCtx.unk_BD = 0xE;
|
|
globalCtx->envCtx.unk_D8 = 1.0f;
|
|
break;
|
|
case 15:
|
|
globalCtx->envCtx.unk_BE = 0xE;
|
|
globalCtx->envCtx.unk_BD = 0xF;
|
|
Math_ApproachF(&globalCtx->envCtx.unk_D8, 1.0f, 1.0f, 0.01f);
|
|
break;
|
|
case 16:
|
|
globalCtx->envCtx.unk_BE = 0x10;
|
|
globalCtx->envCtx.unk_BD = 0xF;
|
|
Math_ApproachZeroF(&globalCtx->envCtx.unk_D8, 1.0f, 0.05f);
|
|
break;
|
|
case 20:
|
|
globalCtx->envCtx.unk_BE = 2;
|
|
globalCtx->envCtx.unk_BD = 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
this->envLightMode = 0;
|
|
|
|
if (this->whiteFillAlpha != 0) {
|
|
globalCtx->envCtx.screenFillColor[3] = (s8)(u8)this->whiteFillAlpha;
|
|
globalCtx->envCtx.screenFillColor[0] = globalCtx->envCtx.screenFillColor[1] =
|
|
globalCtx->envCtx.screenFillColor[2] = 255;
|
|
globalCtx->envCtx.fillScreen = true;
|
|
} else if (this->screenFlashTimer != 0) {
|
|
globalCtx->envCtx.fillScreen = true;
|
|
globalCtx->envCtx.screenFillColor[0] = globalCtx->envCtx.screenFillColor[1] =
|
|
globalCtx->envCtx.screenFillColor[2] = 255;
|
|
|
|
globalCtx->envCtx.screenFillColor[3] = ((this->screenFlashTimer % 2) != 0) ? 100 : 0;
|
|
|
|
this->screenFlashTimer--;
|
|
} else {
|
|
globalCtx->envCtx.fillScreen = globalCtx->envCtx.screenFillColor[3] = 0;
|
|
}
|
|
|
|
if (this->lensFlareTimer != 0) {
|
|
this->lensFlareTimer--;
|
|
|
|
if (this->lensFlareMode == 1) {
|
|
targetLensFlareScale = 40.0f;
|
|
} else if (this->lensFlareMode == 4) {
|
|
targetLensFlareScale = 25.0f;
|
|
} else {
|
|
targetLensFlareScale = 10.0f;
|
|
}
|
|
|
|
Math_ApproachF(&this->lensFlareScale, targetLensFlareScale, 0.3f, 10.0f);
|
|
} else {
|
|
Math_ApproachZeroF(&this->lensFlareScale, 1.0f, 5.0f);
|
|
|
|
if (this->lensFlareScale == 0.0f) {
|
|
this->lensFlareMode = 0;
|
|
}
|
|
}
|
|
|
|
if (this->lensFlareMode != 0) {
|
|
gCustomLensFlareOn = true;
|
|
|
|
if (this->lensFlareMode == 1) {
|
|
gCustomLensFlarePos = this->actor.world.pos;
|
|
}
|
|
|
|
gLensFlareScale = this->lensFlareScale;
|
|
gLensFlareColorIntensity = 10.0f;
|
|
gLensFlareScreenFillAlpha = 0;
|
|
} else {
|
|
gCustomLensFlareOn = false;
|
|
}
|
|
|
|
if (this->unk_274 != 0) {
|
|
i = this->unk_274 - 1;
|
|
|
|
this->unk_278.x = this->unk_2EC[0].x;
|
|
this->unk_278.y = this->unk_2EC[0].y + 50.0f + 30.0f;
|
|
this->unk_278.z = this->unk_2EC[0].z;
|
|
|
|
xOffset = (sinf(i * 1.2566371f) * 600.0f);
|
|
zOffset = (cosf(i * 1.2566371f) * 600.0f);
|
|
|
|
// 5 or 6 light balls that go into the charge. not the same as the ones that he throws
|
|
Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_BOSS_GANON, this->unk_1FC.x + xOffset,
|
|
this->unk_1FC.y, this->unk_1FC.z + zOffset, 0, (s16)(i * 13107.2f) + 0x6000, 0, 0xFA + i);
|
|
this->unk_274 = 0;
|
|
}
|
|
}
|
|
|
|
s32 BossGanon_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot,
|
|
void* thisx) {
|
|
BossGanon* this = (BossGanon*)thisx;
|
|
|
|
switch (limbIndex) {
|
|
case 10:
|
|
if (this->useOpenHand) {
|
|
*dList = gDorfOpenHandDL;
|
|
}
|
|
break;
|
|
|
|
case 20:
|
|
rot->y += this->legRot.x + this->legRot.z;
|
|
rot->z += this->legRot.y;
|
|
break;
|
|
|
|
case 21:
|
|
if (this->legRot.y > 0.0f) {
|
|
rot->z += this->legRot.y;
|
|
}
|
|
break;
|
|
|
|
case 22:
|
|
rot->y += this->legRot.x + this->legRot.z;
|
|
rot->z += this->legRot.y;
|
|
break;
|
|
|
|
case 23:
|
|
rot->y += this->legRot.x - this->legRot.z;
|
|
rot->z += this->legRot.y;
|
|
break;
|
|
|
|
case 24:
|
|
if (this->legRot.y > 0.0f) {
|
|
rot->z += this->legRot.y;
|
|
}
|
|
break;
|
|
|
|
case 25:
|
|
rot->y += this->legRot.x - this->legRot.z;
|
|
rot->z += this->legRot.y;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void BossGanon_PostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) {
|
|
static s8 bodyPartLimbMap[] = {
|
|
-1, -1, 1, -1, 3, 4, 5, -1, 6, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, 2, 12, 13, 14, 9, 10, 11, -1, -1, -1, -1,
|
|
};
|
|
static Vec3f D_808E4DA0 = { -500.0f, 200.0f, -300.0f };
|
|
static Vec3f D_808E4DAC = { -500.0f, 200.0f, 300.0f };
|
|
static Vec3f D_808E4DB8 = { 0.0f, 0.0f, 0.0f };
|
|
static Vec3f D_808E4DC4 = { 0.0f, 0.0f, 0.0f };
|
|
static Vec3f D_808E4DD0 = { 0.0f, 0.0f, 0.0f };
|
|
static Vec3f D_808E4DDC = { 1300.0f, 0.0f, 0.0f };
|
|
static Vec3f D_808E4DE8 = { 600.0f, 420.0f, 100.0f };
|
|
s8 bodyPart;
|
|
BossGanon* this = (BossGanon*)thisx;
|
|
|
|
bodyPart = bodyPartLimbMap[limbIndex];
|
|
if (bodyPart >= 0) {
|
|
Matrix_MultVec3f(&D_808E4DB8, &this->unk_2EC[bodyPart]);
|
|
}
|
|
|
|
if (limbIndex == 2) {
|
|
Matrix_MultVec3f(&D_808E4DB8, &this->unk_1FC);
|
|
} else if (limbIndex == 19) {
|
|
Matrix_MultVec3f(&D_808E4DB8, &this->actor.focus.pos);
|
|
} else if (limbIndex == 11) {
|
|
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_ganon.c", 7191);
|
|
|
|
Matrix_MultVec3f(&D_808E4DB8, &this->unk_208);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_ganon.c", 7196),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_ganon_DL_00BE90));
|
|
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_ganon.c", 7198);
|
|
} else if (limbIndex == 6) {
|
|
Matrix_MultVec3f(&D_808E4DC4, &this->unk_238);
|
|
} else if (limbIndex == 10) {
|
|
Matrix_MultVec3f(&D_808E4DD0, &this->unk_22C);
|
|
|
|
if (this->unk_25C == 0) {
|
|
Matrix_MultVec3f(&D_808E4DDC, &this->unk_260);
|
|
}
|
|
|
|
this->unk_25C = 0;
|
|
|
|
if (this->triforceType == GDF_TRIFORCE_DORF) {
|
|
Matrix_MultVec3f(&D_808E4DE8, &this->triforcePos);
|
|
}
|
|
} else if (limbIndex == 4) {
|
|
Vec3f sp28 = D_808E4DA0;
|
|
|
|
if (this->unk_198 == 1) {
|
|
sp28.x += -300.0f;
|
|
sp28.y += -300.0f;
|
|
sp28.z += 700.0f;
|
|
} else if (this->unk_198 == 2) {
|
|
sp28.x += -300.0f;
|
|
sp28.z += 700.0f;
|
|
}
|
|
|
|
Matrix_MultVec3f(&sp28, &this->unk_220);
|
|
} else if (limbIndex == 8) {
|
|
Vec3f sp1C = D_808E4DAC;
|
|
|
|
if (this->unk_198 == 1) {
|
|
sp1C.x += -300.0f;
|
|
sp1C.y += -300.0f;
|
|
sp1C.z += -700.0f;
|
|
} else if (this->unk_198 == 2) {
|
|
sp1C.x += -300.0f;
|
|
sp1C.y += 100.0f;
|
|
sp1C.z += -700.0f;
|
|
}
|
|
|
|
Matrix_MultVec3f(&sp1C, &this->unk_214);
|
|
}
|
|
}
|
|
|
|
void BossGanon_InitRand(s32 seedInit0, s32 seedInit1, s32 seedInit2) {
|
|
sBossGanonSeed1 = seedInit0;
|
|
sBossGanonSeed2 = seedInit1;
|
|
sBossGanonSeed3 = seedInit2;
|
|
}
|
|
|
|
f32 BossGanon_RandZeroOne(void) {
|
|
// Wichmann-Hill algorithm
|
|
f32 randFloat;
|
|
|
|
sBossGanonSeed1 = (sBossGanonSeed1 * 171) % 30269;
|
|
sBossGanonSeed2 = (sBossGanonSeed2 * 172) % 30307;
|
|
sBossGanonSeed3 = (sBossGanonSeed3 * 170) % 30323;
|
|
|
|
randFloat = (sBossGanonSeed1 / 30269.0f) + (sBossGanonSeed2 / 30307.0f) + (sBossGanonSeed3 / 30323.0f);
|
|
|
|
while (randFloat >= 1.0f) {
|
|
randFloat -= 1.0f;
|
|
}
|
|
|
|
return fabsf(randFloat);
|
|
}
|
|
|
|
void BossGanon_DrawShock(BossGanon* this, GlobalContext* globalCtx) {
|
|
s32 pad;
|
|
GraphicsContext* gfxCtx = globalCtx->state.gfxCtx;
|
|
s16 i;
|
|
|
|
OPEN_DISPS(gfxCtx, "../z_boss_ganon.c", 7350);
|
|
|
|
if ((this->unk_2E8 != 0) || (this->unk_2E6 != 0)) {
|
|
func_80093D84(globalCtx->state.gfxCtx);
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, 255);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 0, 0);
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfLightBallMaterialDL);
|
|
|
|
if (this->unk_2E8 != 0) {
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
|
|
for (i = 0; i < ARRAY_COUNT(player->bodyPartsPos); i++) {
|
|
Matrix_Translate(player->bodyPartsPos[i].x, player->bodyPartsPos[i].y, player->bodyPartsPos[i].z,
|
|
MTXMODE_NEW);
|
|
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
|
|
Matrix_Scale(this->unk_49C[i], this->unk_49C[i], this->unk_49C[i], MTXMODE_APPLY);
|
|
Matrix_RotateZ(Rand_CenteredFloat(M_PI), MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 7384),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfSquareDL);
|
|
}
|
|
} else {
|
|
for (i = 1; i < 15; i++) {
|
|
Matrix_Translate(this->unk_2EC[i].x, this->unk_2EC[i].y, this->unk_2EC[i].z, MTXMODE_NEW);
|
|
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
|
|
Matrix_Scale(this->unk_49C[i], this->unk_49C[i], this->unk_49C[i], MTXMODE_APPLY);
|
|
|
|
if (!this->shockGlow) {
|
|
Matrix_RotateZ(Rand_CenteredFloat(M_PI), MTXMODE_APPLY);
|
|
}
|
|
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 7401),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
|
|
if (this->shockGlow) {
|
|
gSPSegment(POLY_XLU_DISP++, 0x08,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, 0, 32, 64, 1, 0,
|
|
(this->unk_1A2 + i) * -15, 32, 64));
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 200, 255, 170, 255);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 0, 128);
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfShockGlowDL);
|
|
} else {
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfSquareDL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CLOSE_DISPS(gfxCtx, "../z_boss_ganon.c", 7465);
|
|
}
|
|
|
|
void BossGanon_DrawHandLightBall(BossGanon* this, GlobalContext* globalCtx) {
|
|
s32 pad;
|
|
GraphicsContext* gfxCtx = globalCtx->state.gfxCtx;
|
|
s32 alpha;
|
|
|
|
OPEN_DISPS(gfxCtx, "../z_boss_ganon.c", 7476);
|
|
|
|
if (this->handLightBallScale > 0.0f) {
|
|
func_80093D84(globalCtx->state.gfxCtx);
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, 255);
|
|
|
|
if ((this->unk_1A2 % 2) != 0) {
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 0, 0);
|
|
} else {
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 100, 255, 0, 0);
|
|
}
|
|
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfLightBallMaterialDL);
|
|
|
|
Matrix_Translate(this->unk_260.x, this->unk_260.y, this->unk_260.z, MTXMODE_NEW);
|
|
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
|
|
Matrix_Scale(this->handLightBallScale, this->handLightBallScale, this->handLightBallScale, MTXMODE_APPLY);
|
|
Matrix_RotateZ(this->unk_258, 1);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 7510),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfSquareDL);
|
|
|
|
alpha = ((this->unk_1A2 % 2) != 0) ? 100 : 80;
|
|
gDPPipeSync(POLY_XLU_DISP++);
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 155, alpha);
|
|
Matrix_Translate(this->unk_260.x, 0.0f, this->unk_260.z, MTXMODE_NEW);
|
|
Matrix_Scale(this->handLightBallScale * 0.75f, 1.0f, this->handLightBallScale * 0.75f, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_ganon.c", 7531),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfLightCoreDL);
|
|
|
|
CLOSE_DISPS(gfxCtx, "../z_boss_ganon.c", 7534);
|
|
}
|
|
}
|
|
|
|
void BossGanon_DrawBigMagicCharge(BossGanon* this, GlobalContext* globalCtx) {
|
|
s32 pad;
|
|
f32 yRot;
|
|
GraphicsContext* gfxCtx = globalCtx->state.gfxCtx;
|
|
s16 i;
|
|
|
|
OPEN_DISPS(gfxCtx, "../z_boss_ganon.c", 7548);
|
|
|
|
if (this->unk_284 > 0.0f) {
|
|
func_80093D84(globalCtx->state.gfxCtx);
|
|
|
|
// light flecks
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 170, (s8)this->unk_290);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 200, 255, 0, 128);
|
|
gSPSegment(POLY_XLU_DISP++, 0x08,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, this->unk_1A2 * -2, 0, 0x40, 0x40, 1, 0,
|
|
this->unk_1A2 * 0xA, 0x40, 0x40));
|
|
Matrix_Translate(this->unk_278.x, this->unk_278.y, this->unk_278.z, MTXMODE_NEW);
|
|
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
|
|
Matrix_Scale(this->unk_28C, this->unk_28C, this->unk_28C, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 7588),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfLightFlecksDL);
|
|
|
|
// background circle texture
|
|
Matrix_Translate(this->unk_278.x, this->unk_278.y, this->unk_278.z, MTXMODE_NEW);
|
|
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
|
|
Matrix_Scale(this->unk_284, this->unk_284, this->unk_284, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 7601),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 0, 100, (s8)this->unk_288);
|
|
gSPSegment(
|
|
POLY_XLU_DISP++, 0x09,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, 0, 0x20, 0x20, 1, 0, this->unk_1A2 * -4, 0x20, 0x20));
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfBigMagicBGCircleDL);
|
|
|
|
// yellow background dot
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 150, 170, 0, (s8)this->unk_288);
|
|
gSPSegment(POLY_XLU_DISP++, 0x0A,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, 0, 0x20, 0x20, 1, this->unk_1A2 * 2,
|
|
this->unk_1A2 * -0x14, 0x40, 0x40));
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfDotDL);
|
|
|
|
// light ball material
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, 255);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 100, 0);
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfLightBallMaterialDL);
|
|
|
|
// light ball geometry
|
|
Matrix_Translate(this->unk_278.x, this->unk_278.y, this->unk_278.z, MTXMODE_NEW);
|
|
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
|
|
Matrix_Scale(this->unk_2D0, this->unk_2D0, this->unk_2D0, MTXMODE_APPLY);
|
|
Matrix_RotateZ((this->unk_1A2 * 10.0f) / 1000.0f, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 7673),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfSquareDL);
|
|
|
|
BossGanon_InitRand(this->unk_1AA + 1, 0x71AC, 0x263A);
|
|
Matrix_Translate(this->unk_278.x, this->unk_278.y, this->unk_278.z, MTXMODE_NEW);
|
|
Matrix_RotateY((this->unk_1A2 * 10.0f) / 1000.0f, MTXMODE_APPLY);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 200, 255, 0, 0);
|
|
|
|
yRot = BINANG_TO_RAD(this->actor.yawTowardsPlayer);
|
|
|
|
for (i = 0; i < this->unk_1AC; i++) {
|
|
f32 xzRot = (BossGanon_RandZeroOne() - 0.5f) * M_PI * 1.5f;
|
|
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, (s8)this->unk_294[i]);
|
|
Matrix_Push();
|
|
Matrix_RotateY(xzRot + yRot, MTXMODE_APPLY);
|
|
Matrix_RotateX((BossGanon_RandZeroOne() - 0.5f) * M_PI, MTXMODE_APPLY);
|
|
Matrix_RotateZ(xzRot, MTXMODE_APPLY);
|
|
Matrix_Translate(0.0f, 0.0f, 50.0f, MTXMODE_APPLY);
|
|
Matrix_Scale(4.0f, 4.0f, 1.0f, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 7713),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfLightRayTriDL);
|
|
|
|
Matrix_Pop();
|
|
}
|
|
|
|
CLOSE_DISPS(gfxCtx, "../z_boss_ganon.c", 7721);
|
|
}
|
|
}
|
|
|
|
void BossGanon_DrawTriforce(BossGanon* this, GlobalContext* globalCtx) {
|
|
s32 pad;
|
|
|
|
if (this->fwork[GDF_TRIFORCE_PRIM_A] > 0.0f) {
|
|
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_ganon.c", 7732);
|
|
|
|
Matrix_Push();
|
|
|
|
gDPPipeSync(POLY_XLU_DISP++);
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, (u8)this->fwork[GDF_TRIFORCE_PRIM_B],
|
|
(s8)this->fwork[GDF_TRIFORCE_PRIM_A]);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, (u8)this->fwork[GDF_TRIFORCE_ENV_G], 0, 128);
|
|
|
|
if (this->triforceType == GDF_TRIFORCE_PLAYER) {
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
|
|
this->triforcePos = player->bodyPartsPos[12];
|
|
|
|
this->triforcePos.x += -0.6f;
|
|
this->triforcePos.y += 3.0f;
|
|
this->triforcePos.z += -2.0f;
|
|
} else if (this->triforceType == GDF_TRIFORCE_ZELDA) {
|
|
this->triforcePos = sBossGanonZelda->unk_31C;
|
|
|
|
this->triforcePos.y += 1.8f;
|
|
this->triforcePos.z += 4.0f;
|
|
}
|
|
|
|
Matrix_Translate(this->triforcePos.x, this->triforcePos.y, this->triforcePos.z, MTXMODE_NEW);
|
|
|
|
if (this->triforceType == GDF_TRIFORCE_PLAYER) {
|
|
Matrix_RotateX(-1.4f, MTXMODE_APPLY);
|
|
Matrix_RotateZ(4.0f, MTXMODE_APPLY);
|
|
} else if (this->triforceType == GDF_TRIFORCE_ZELDA) {
|
|
Matrix_RotateY(1.5f, 1);
|
|
Matrix_RotateX(1.1f, 1);
|
|
Matrix_RotateZ(-0.99999994f, MTXMODE_APPLY);
|
|
} else {
|
|
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
|
|
}
|
|
|
|
Matrix_Scale(this->fwork[GDF_TRIFORCE_SCALE], this->fwork[GDF_TRIFORCE_SCALE], 1.0f, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_ganon.c", 7779),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(gDorfTriforceDL));
|
|
|
|
Matrix_Pop();
|
|
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_ganon.c", 7782);
|
|
}
|
|
}
|
|
|
|
void BossGanon_DrawDarkVortex(BossGanon* this, GlobalContext* globalCtx) {
|
|
s32 pad;
|
|
|
|
if (this->fwork[GDF_VORTEX_ALPHA] > 0.0f) {
|
|
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_ganon.c", 7792);
|
|
|
|
Matrix_Push();
|
|
gDPPipeSync(POLY_XLU_DISP++);
|
|
gSPSegment(POLY_XLU_DISP++, 0x08,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, this->unk_1A2 * -8, 0, 0x20, 0x40, 1,
|
|
this->unk_1A2 * -4, this->unk_1A2 * -8, 0x20, 0x20));
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 100, 0, 200, (s8)this->fwork[GDF_VORTEX_ALPHA]);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 130, 0, 0, 128);
|
|
|
|
if (this->csState != 21) {
|
|
Matrix_Translate(0.0f, 105.0f, -400.0f, MTXMODE_NEW);
|
|
Matrix_RotateX(M_PI / 2, MTXMODE_APPLY);
|
|
} else {
|
|
Matrix_Translate(-50.0f, 50.0f, -150.0f, MTXMODE_NEW);
|
|
Matrix_RotateY(M_PI / 10, MTXMODE_APPLY);
|
|
Matrix_RotateX(M_PI / 2, MTXMODE_APPLY);
|
|
}
|
|
|
|
Matrix_Scale(this->fwork[GDF_VORTEX_SCALE], this->fwork[GDF_VORTEX_SCALE], this->fwork[GDF_VORTEX_SCALE],
|
|
MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_ganon.c", 7841),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(gDorfVortexDL));
|
|
|
|
Matrix_Pop();
|
|
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_ganon.c", 7844);
|
|
}
|
|
}
|
|
|
|
void func_808E0254(BossGanon* this, u8* tex, f32 arg2) {
|
|
static s16 D_808E4DF4[] = { 1, 2, 3, 3, 2, 1 };
|
|
static s16 D_808E4E00[] = { 2, 3, 4, 4, 4, 3, 2 };
|
|
static s16 D_808E4E10[] = { 2, 3, 4, 4, 4, 4, 3, 2 };
|
|
static s16 D_808E4E20[] = { 2, 4, 5, 5, 6, 6, 6, 6, 5, 5, 4, 2 };
|
|
static s16 D_808E4E38[] = { 1, -1, 1, 1, 3, 4, 1, 6, 7, 2, 9, 10, 2, 12, 13 };
|
|
static u8 D_808E4E58[] = { 3, 2, 2, 1, 3, 3, 1, 3, 3, 1, 0, 3, 1, 0, 3 };
|
|
s16 baseX;
|
|
s16 index;
|
|
s16 i;
|
|
s16 baseY;
|
|
s16 x;
|
|
s16 addY;
|
|
f32 lerpX;
|
|
s16 y;
|
|
f32 lerpY;
|
|
f32 lerpZ;
|
|
Vec3f sp68;
|
|
Vec3f sp5C;
|
|
|
|
for (i = 0; i < 15; i++) {
|
|
if (arg2 == 0.0f || (y = D_808E4E38[i]) >= 0) {
|
|
if (arg2 > 0.0f) {
|
|
lerpX = this->unk_2EC[i].x + (this->unk_2EC[y].x - this->unk_2EC[i].x) * arg2;
|
|
lerpY = this->unk_2EC[i].y + (this->unk_2EC[y].y - this->unk_2EC[i].y) * arg2;
|
|
lerpZ = this->unk_2EC[i].z + (this->unk_2EC[y].z - this->unk_2EC[i].z) * arg2;
|
|
|
|
sp68.x = lerpX - this->actor.world.pos.x;
|
|
sp68.y = lerpY - this->actor.world.pos.y + 76 + 30 + 30;
|
|
sp68.z = lerpZ - this->actor.world.pos.z;
|
|
} else {
|
|
|
|
sp68.x = this->unk_2EC[i].x - this->actor.world.pos.x;
|
|
sp68.y = this->unk_2EC[i].y - this->actor.world.pos.y + 76 + 30 + 30;
|
|
sp68.z = this->unk_2EC[i].z - this->actor.world.pos.z;
|
|
}
|
|
Matrix_MultVec3f(&sp68, &sp5C);
|
|
|
|
sp5C.x *= 0.4f;
|
|
sp5C.y *= 0.4f;
|
|
|
|
baseX = (s16)(sp5C.x + 32.0f);
|
|
baseY = (s16)sp5C.y * 64;
|
|
|
|
if (D_808E4E58[i] == 2) {
|
|
for (y = 0, addY = -0x180; y < 12; y++, addY += 0x40) {
|
|
for (x = -D_808E4E20[y]; x < D_808E4E20[y]; x++) {
|
|
index = baseX + x + baseY + addY;
|
|
if ((index >= 0) && (index < 0x1000)) {
|
|
tex[index] = 255;
|
|
}
|
|
}
|
|
}
|
|
} else if (D_808E4E58[i] == 1) {
|
|
for (y = 0, addY = -0x100; y < 8; y++, addY += 0x40) {
|
|
for (x = -D_808E4E10[y]; x < D_808E4E10[y]; x++) {
|
|
index = baseX + x + baseY + addY;
|
|
if ((index >= 0) && (index < 0x1000)) {
|
|
tex[index] = 255;
|
|
}
|
|
}
|
|
}
|
|
} else if (D_808E4E58[i] == 0) {
|
|
for (y = 0, addY = -0xC0; y < 7; y++, addY += 0x40) {
|
|
for (x = -D_808E4E00[y]; x < D_808E4E00[y] - 1; x++) {
|
|
index = baseX + x + baseY + addY;
|
|
if ((index >= 0) && (index < 0x1000)) {
|
|
tex[index] = 255;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
for (y = 0, addY = -0x80; y < 6; y++, addY += 0x40) {
|
|
for (x = -D_808E4DF4[y]; x < D_808E4DF4[y] - 1; x++) {
|
|
index = baseX + x + baseY + addY;
|
|
if ((index >= 0) && (index < 0x1000)) {
|
|
tex[index] = 255;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossGanon_GenShadowTexture(u8* tex, BossGanon* this, GlobalContext* globalCtx) {
|
|
s16 addY;
|
|
s16 baseX;
|
|
s16 baseY;
|
|
s16 i;
|
|
s16 j;
|
|
s16 y;
|
|
s16 x;
|
|
s16 index;
|
|
Vec3f sp7C;
|
|
Vec3f sp70;
|
|
s32* ptr = (s32*)tex;
|
|
|
|
for (i = 0; i < 64 * 64 / 4; i++, ptr++) {
|
|
*ptr = 0;
|
|
}
|
|
|
|
Matrix_RotateX(1.0f, MTXMODE_NEW);
|
|
|
|
for (i = 0; i <= 5; i++) {
|
|
func_808E0254(this, tex, i / 5.0f);
|
|
}
|
|
|
|
for (i = 0; i < 12; i++) {
|
|
for (j = 0; j < 12; j++) {
|
|
sp7C.x = sBossGanonCape->strands[i].joints[j].x - this->actor.world.pos.x;
|
|
sp7C.y = sBossGanonCape->strands[i].joints[j].y - this->actor.world.pos.y + 76.0f + 100.0f + 30.0f;
|
|
sp7C.z = sBossGanonCape->strands[i].joints[j].z - this->actor.world.pos.z;
|
|
|
|
Matrix_MultVec3f(&sp7C, &sp70);
|
|
|
|
sp70.x = sp70.x * 0.28f;
|
|
sp70.y = sp70.y * 0.28f;
|
|
|
|
baseX = (s32)(sp70.x + 32.0f);
|
|
baseY = (s16)sp70.y * 0x40;
|
|
|
|
if (!sBossGanonCape->strands[i].torn[j]) {
|
|
for (y = -1, addY = -0x40; y <= 1; y++, addY += 0x40) {
|
|
for (x = -3; x <= 3; x++) {
|
|
index = baseX + x + baseY + addY;
|
|
if (0 <= index && index < 0x1000) {
|
|
tex[index] = 255;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
for (y = -1, addY = -0x40; y <= 1; y++, addY += 0x40) {
|
|
for (x = -1; x <= 1; x++) {
|
|
index = baseX + x + baseY + addY;
|
|
if (0 <= index && index < 0x1000) {
|
|
tex[index] = 255;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossGanon_DrawShadowTexture(void* tex, BossGanon* this, GlobalContext* globalCtx) {
|
|
s32 pad;
|
|
f32 zOffset;
|
|
GraphicsContext* gfxCtx = globalCtx->state.gfxCtx;
|
|
|
|
OPEN_DISPS(gfxCtx, "../z_boss_ganon.c", 8372);
|
|
|
|
func_80093D18(globalCtx->state.gfxCtx);
|
|
gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 0, 0, 0, 50);
|
|
gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 0);
|
|
|
|
if (this->csState < 100) {
|
|
zOffset = (((((this->actor.world.pos.y - 10) + 70.0f) * -5.0f) / 10.0f) + 10.0f);
|
|
Matrix_Translate(this->actor.world.pos.x, 0.0f, this->actor.world.pos.z + zOffset, MTXMODE_NEW);
|
|
} else {
|
|
Matrix_Translate(this->actor.world.pos.x, 4102.0f, this->actor.world.pos.z - 20.0f, MTXMODE_NEW);
|
|
}
|
|
|
|
Matrix_Scale(0.95000005f, 1.0f, 0.95000005f, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_ganon.c", 8396),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_OPA_DISP++, gDorfShadowSetupDL);
|
|
gDPLoadTextureBlock(POLY_OPA_DISP++, tex, G_IM_FMT_I, G_IM_SIZ_8b, 64, 64, 0, G_TX_NOMIRROR | G_TX_CLAMP,
|
|
G_TX_NOMIRROR | G_TX_CLAMP, 6, 6, G_TX_NOLOD, G_TX_NOLOD);
|
|
gSPDisplayList(POLY_OPA_DISP++, gDorfShadowModelDL);
|
|
|
|
CLOSE_DISPS(gfxCtx, "../z_boss_ganon.c", 8426);
|
|
}
|
|
|
|
void BossGanon_Draw(Actor* thisx, GlobalContext* globalCtx) {
|
|
s32 i;
|
|
BossGanon* this = (BossGanon*)thisx;
|
|
void* shadowTex;
|
|
|
|
shadowTex = Graph_Alloc(globalCtx->state.gfxCtx, 64 * 64);
|
|
|
|
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_ganon.c", 9138);
|
|
|
|
func_80093D18(globalCtx->state.gfxCtx);
|
|
func_80093D84(globalCtx->state.gfxCtx);
|
|
|
|
if ((this->unk_1A6 & 2) != 0) {
|
|
POLY_OPA_DISP = Gfx_SetFog(POLY_OPA_DISP, 255, 50, 0, 0, 900, 1099);
|
|
}
|
|
|
|
gSPSegment(POLY_XLU_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(gDorfEyeTex));
|
|
|
|
SkelAnime_DrawFlexOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount,
|
|
BossGanon_OverrideLimbDraw, BossGanon_PostLimbDraw, &this->actor);
|
|
|
|
this->unk_2EC[0].x = this->unk_2EC[1].x;
|
|
this->unk_2EC[0].y = this->unk_2EC[1].y + 30.0f;
|
|
this->unk_2EC[0].z = this->unk_2EC[1].z;
|
|
|
|
POLY_OPA_DISP = Gameplay_SetFog(globalCtx, POLY_OPA_DISP);
|
|
|
|
BossGanon_DrawEffects(globalCtx);
|
|
|
|
sBossGanonCape->actor.world.pos = this->actor.world.pos;
|
|
|
|
sBossGanonCape->rightForearmPos = this->unk_214;
|
|
sBossGanonCape->leftForearmPos = this->unk_220;
|
|
|
|
sBossGanonCape->rightShoulderPos = this->unk_22C;
|
|
sBossGanonCape->leftShoulderPos = this->unk_238;
|
|
|
|
BossGanon_DrawShock(this, globalCtx);
|
|
BossGanon_DrawHandLightBall(this, globalCtx);
|
|
BossGanon_DrawBigMagicCharge(this, globalCtx);
|
|
BossGanon_DrawTriforce(this, globalCtx);
|
|
BossGanon_DrawDarkVortex(this, globalCtx);
|
|
|
|
BossGanon_GenShadowTexture(shadowTex, this, globalCtx);
|
|
BossGanon_DrawShadowTexture(shadowTex, this, globalCtx);
|
|
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_ganon.c", 9393);
|
|
}
|
|
|
|
s32 BossGanon_CheckFallingPlatforms(BossGanon* this, GlobalContext* globalCtx, Vec3f* checkPos) {
|
|
Actor* prop = globalCtx->actorCtx.actorLists[ACTORCAT_PROP].head;
|
|
|
|
while (prop != NULL) {
|
|
if (((BossGanon*)prop == this) || (prop->id != ACTOR_BG_GANON_OTYUKA)) {
|
|
prop = prop->next;
|
|
} else {
|
|
BgGanonOtyuka* platform = (BgGanonOtyuka*)prop;
|
|
f32 xDiff = platform->dyna.actor.world.pos.x - checkPos->x;
|
|
f32 yDiff = platform->dyna.actor.world.pos.y - checkPos->y;
|
|
f32 zDiff = platform->dyna.actor.world.pos.z - checkPos->z;
|
|
|
|
if ((fabsf(xDiff) < 60.0f) && (yDiff < 20.0f) && (yDiff > -20.0f) && (fabsf(zDiff) < 60.0f)) {
|
|
platform->isFalling = true;
|
|
platform->visibleSides = OTYUKA_SIDE_ALL;
|
|
|
|
return 1;
|
|
} else {
|
|
prop = prop->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void BossGanon_LightBall_Update(Actor* thisx, GlobalContext* globalCtx2) {
|
|
u8 hitWithBottle;
|
|
s16 i;
|
|
s16 spBA = 0;
|
|
Vec3f spAC;
|
|
Vec3f spA0;
|
|
Vec3f sp94;
|
|
BossGanon* this = (BossGanon*)thisx;
|
|
GlobalContext* globalCtx = globalCtx2;
|
|
f32 xDistFromLink;
|
|
f32 yDistFromLink;
|
|
f32 zDistFromLink;
|
|
f32 minReflectDist;
|
|
f32 xDistFromGanondorf;
|
|
f32 yDistFromGanondorf;
|
|
f32 zDistFromGanondorf;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
s32 pad;
|
|
BossGanon* ganondorf = (BossGanon*)this->actor.parent;
|
|
s32 pad1;
|
|
|
|
this->unk_1A2++;
|
|
ganondorf->envLightMode = 1;
|
|
|
|
if (this->unk_1A8 != 0) {
|
|
if (this->unk_1A8 == 2) {
|
|
Math_ApproachZeroF(&this->fwork[GDF_FWORK_1], 1.0f, 10.0f);
|
|
Math_ApproachF(&this->actor.scale.x, 30.0f, 0.5f, 100.0f);
|
|
} else {
|
|
this->actor.shape.rot.y += 0x1000;
|
|
ganondorf->lensFlareTimer = 1;
|
|
gCustomLensFlarePos = this->actor.world.pos;
|
|
Math_ApproachZeroF(&this->fwork[GDF_FWORK_1], 1.0f, 30.0f);
|
|
Math_ApproachF(&this->actor.scale.x, 20.0f, 0.5f, 100.0f);
|
|
this->fwork[GDF_FWORK_0] += ((M_PI / 2) + Rand_ZeroFloat(M_PI / 4));
|
|
}
|
|
|
|
Actor_SetScale(&this->actor, this->actor.scale.x);
|
|
|
|
if (this->fwork[GDF_FWORK_1] == 0.0f) {
|
|
Actor_Kill(&this->actor);
|
|
}
|
|
} else {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_FIRE - SFX_FLAG);
|
|
|
|
if ((this->unk_1A2 % 2) != 0) {
|
|
Actor_SetScale(&this->actor, 6.0f);
|
|
} else {
|
|
Actor_SetScale(&this->actor, 5.25f);
|
|
}
|
|
|
|
this->actor.shape.rot.z += (s16)(Rand_ZeroOne() * 20000.0f) + 0x4000;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(this->timers); i++) {
|
|
if (this->timers[i] != 0) {
|
|
this->timers[i]--;
|
|
}
|
|
}
|
|
|
|
xDistFromGanondorf = ganondorf->unk_1FC.x - this->actor.world.pos.x;
|
|
yDistFromGanondorf = ganondorf->unk_1FC.y - this->actor.world.pos.y;
|
|
zDistFromGanondorf = ganondorf->unk_1FC.z - this->actor.world.pos.z;
|
|
|
|
xDistFromLink = player->actor.world.pos.x - this->actor.world.pos.x;
|
|
yDistFromLink = (player->actor.world.pos.y + 40.0f) - this->actor.world.pos.y;
|
|
zDistFromLink = player->actor.world.pos.z - this->actor.world.pos.z;
|
|
|
|
func_8002D908(&this->actor);
|
|
func_8002D7EC(&this->actor);
|
|
|
|
switch (this->unk_1C2) {
|
|
case 0:
|
|
if ((player->stateFlags1 & 2) &&
|
|
(ABS((s16)(player->actor.shape.rot.y - (s16)(ganondorf->actor.yawTowardsPlayer + 0x8000))) <
|
|
0x2000) &&
|
|
(sqrtf(SQ(xDistFromLink) + SQ(yDistFromLink) + SQ(zDistFromLink)) <= 25.0f)) {
|
|
hitWithBottle = true;
|
|
} else {
|
|
hitWithBottle = false;
|
|
}
|
|
|
|
if ((this->collider.base.acFlags & 2) || hitWithBottle) {
|
|
ColliderInfo* acHitInfo = this->collider.info.acHitInfo;
|
|
|
|
this->collider.base.acFlags &= ~2;
|
|
|
|
if ((hitWithBottle == false) && (acHitInfo->toucher.dmgFlags & 0x100000)) {
|
|
spBA = 2;
|
|
Audio_PlaySoundGeneral(NA_SE_IT_SHIELD_REFLECT_MG, &player->actor.projectedPos, 4, &D_801333E0,
|
|
&D_801333E0, &D_801333E8);
|
|
func_800AA000(this->actor.xyzDistToPlayerSq, 0xFF, 0x14, 0x96);
|
|
} else {
|
|
spBA = 1;
|
|
this->actor.world.rot.y = Math_Atan2S(zDistFromGanondorf, xDistFromGanondorf);
|
|
this->actor.world.rot.x =
|
|
Math_Atan2S(sqrtf(SQ(xDistFromGanondorf) + SQ(zDistFromGanondorf)), yDistFromGanondorf);
|
|
this->unk_1A4++;
|
|
this->timers[1] = 2;
|
|
Audio_PlaySoundGeneral(NA_SE_IT_SWORD_REFLECT_MG, &player->actor.projectedPos, 4, &D_801333E0,
|
|
&D_801333E0, &D_801333E8);
|
|
func_800AA000(this->actor.xyzDistToPlayerSq, 0xB4, 0x14, 0x64);
|
|
|
|
if (hitWithBottle == false) {
|
|
// if ganondorf is 250 units away from link, at least 3 volleys are required
|
|
if ((ganondorf->actor.xyzDistToPlayerSq > 62500.0f) && (this->unk_1A4 < 3)) {
|
|
this->unk_1C2 = 1;
|
|
} else if (Rand_ZeroOne() < 0.7f) {
|
|
this->unk_1C2 = 1;
|
|
} else {
|
|
this->unk_1C2 = 3;
|
|
}
|
|
|
|
// if a spin attack is used
|
|
if (player->swordAnimation >= 0x18) {
|
|
this->actor.speedXZ = 20.0f;
|
|
}
|
|
break;
|
|
} else {
|
|
if (Rand_ZeroOne() < 0.9f) {
|
|
this->unk_1C2 = 1;
|
|
} else {
|
|
this->unk_1C2 = 3;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (sqrtf(SQ(xDistFromLink) + SQ(yDistFromLink) + SQ(zDistFromLink)) <= 25.0f) {
|
|
spBA = 5;
|
|
func_8002F6D4(globalCtx, &this->actor, 3.0f, this->actor.world.rot.y, 0.0f, 0x30);
|
|
SoundSource_PlaySfxAtFixedWorldPos(globalCtx, &this->actor.world.pos, 40,
|
|
NA_SE_EN_GANON_HIT_THUNDER);
|
|
ganondorf->timers[2] = 20;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(ganondorf->unk_4E4); i++) {
|
|
ganondorf->unk_4E4[i] = D_808E4C58[i];
|
|
}
|
|
|
|
ganondorf->unk_2E6 = 0;
|
|
ganondorf->unk_2E8 = 60;
|
|
ganondorf->unk_508 = 4.0f;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
if ((ganondorf->actionFunc == BossGanon_PlayTennis) && (ganondorf->unk_1C2 == 1)) {
|
|
minReflectDist = (this->actor.speedXZ >= 19.0f) ? 250.0f : 170.0f;
|
|
|
|
if (sqrtf(SQ(xDistFromGanondorf) + SQ(yDistFromGanondorf) + SQ(zDistFromGanondorf)) <
|
|
minReflectDist) {
|
|
ganondorf->startVolley = true;
|
|
this->timers[0] = 8;
|
|
this->unk_1C2 = 2;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
if (this->timers[0] == 1) {
|
|
spBA = 1;
|
|
this->actor.world.rot.y = Math_Atan2S(zDistFromLink, xDistFromLink);
|
|
this->actor.world.rot.x = Math_Atan2S(sqrtf(SQ(xDistFromLink) + SQ(zDistFromLink)), yDistFromLink);
|
|
this->timers[1] = 2;
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_IT_SWORD_REFLECT_MG);
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_AT_RETURN);
|
|
this->unk_1C2 = 0;
|
|
break;
|
|
}
|
|
// fallthrough
|
|
case 4:
|
|
if (sqrtf(SQ(xDistFromGanondorf) + SQ(yDistFromGanondorf) + SQ(zDistFromGanondorf)) < 30.0f) {
|
|
spBA = 3;
|
|
SoundSource_PlaySfxAtFixedWorldPos(globalCtx, &this->actor.world.pos, 40, NA_SE_EN_GANON_DAMAGE1);
|
|
SoundSource_PlaySfxAtFixedWorldPos(globalCtx, &this->actor.world.pos, 40,
|
|
NA_SE_EN_GANON_HIT_THUNDER);
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
if (sqrtf(SQ(xDistFromGanondorf) + SQ(yDistFromGanondorf) + SQ(zDistFromGanondorf)) < 100.0f) {
|
|
ganondorf->startVolley = true;
|
|
this->unk_1C2 = 4;
|
|
}
|
|
break;
|
|
}
|
|
|
|
Collider_UpdateCylinder(&this->actor, &this->collider);
|
|
|
|
if (this->timers[1] == 0) {
|
|
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->collider.base);
|
|
}
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
spA0.x = spA0.z = 0.0f;
|
|
spA0.y = 0.2f;
|
|
|
|
spAC.x = spAC.y = spAC.z = 0.0f;
|
|
|
|
sp94.x = Rand_CenteredFloat(30.0f) + this->actor.world.pos.x;
|
|
sp94.y = Rand_CenteredFloat(30.0f) + this->actor.world.pos.y;
|
|
sp94.z = Rand_CenteredFloat(30.0f) + this->actor.world.pos.z;
|
|
|
|
BossGanonEff_SpawnSparkle(globalCtx, &sp94, &spAC, &spA0, Rand_ZeroFloat(500.0f) + 700.0f, 0x1E);
|
|
}
|
|
|
|
if (this->actor.world.pos.y < 10.0f) {
|
|
Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 0.0f, 20.0f, 20.0f, 4);
|
|
}
|
|
|
|
if ((fabsf(this->actor.world.pos.x) > 465.0f) || (this->actor.world.pos.y > 500.0f) ||
|
|
(fabsf(this->actor.world.pos.z) > 465.0f)) {
|
|
spBA = 4;
|
|
}
|
|
|
|
if ((spBA != 0) || (this->actor.bgCheckFlags & 1)) {
|
|
f32 sp58;
|
|
f32 sp54;
|
|
f32 phi_f20;
|
|
s16 sp4E;
|
|
|
|
if (spBA == 1) {
|
|
sp58 = Rand_ZeroFloat(100.0f) + 300.0f;
|
|
sp54 = 10.0f;
|
|
phi_f20 = 25.0f;
|
|
sp4E = 40;
|
|
} else {
|
|
sp58 = Rand_ZeroFloat(200.0f) + 500.0f;
|
|
sp54 = 15.0f;
|
|
phi_f20 = 30.0f;
|
|
sp4E = 70;
|
|
SoundSource_PlaySfxAtFixedWorldPos(globalCtx, &this->actor.world.pos, 80, NA_SE_EN_GANON_HIT_THUNDER);
|
|
}
|
|
|
|
for (i = 0; i < sp4E; i++) {
|
|
if (spBA != 0) {
|
|
spAC.x = Rand_CenteredFloat(phi_f20);
|
|
spAC.y = Rand_CenteredFloat(phi_f20);
|
|
spAC.z = Rand_CenteredFloat(phi_f20);
|
|
} else {
|
|
spAC.x = Rand_CenteredFloat(phi_f20);
|
|
spAC.y = Rand_ZeroFloat(25.0f);
|
|
spAC.z = Rand_CenteredFloat(phi_f20);
|
|
}
|
|
|
|
BossGanonEff_SpawnLightRay(globalCtx, &this->actor.world.pos, &spAC, &sZeroVec, sp58, sp54, 0x1E);
|
|
}
|
|
|
|
if (spBA != 1) {
|
|
this->unk_1A8 = 1;
|
|
|
|
if (spBA == 0) {
|
|
BossGanon_CheckFallingPlatforms(this, globalCtx, &this->actor.world.pos);
|
|
}
|
|
|
|
if (spBA == 3) {
|
|
BossGanon_SetupHitByLightBall(ganondorf, globalCtx);
|
|
} else if (ganondorf->actionFunc == BossGanon_PlayTennis) {
|
|
BossGanon_SetupWait(ganondorf, globalCtx);
|
|
|
|
if (spBA == 5) {
|
|
ganondorf->timers[0] = 125;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossGanon_LightBall_Draw(Actor* thisx, GlobalContext* globalCtx) {
|
|
BossGanon* this = (BossGanon*)thisx;
|
|
s16 i;
|
|
f32 alpha;
|
|
s32 pad;
|
|
|
|
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_ganon.c", 9849);
|
|
|
|
func_80093D84(globalCtx->state.gfxCtx);
|
|
|
|
alpha = ((this->unk_1A2 % 2) != 0) ? this->fwork[GDF_FWORK_1] * 0.4f : this->fwork[GDF_FWORK_1] * 0.35f;
|
|
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 155, (s8)alpha);
|
|
Matrix_Push();
|
|
Matrix_Translate(this->actor.world.pos.x, this->actor.floorHeight, this->actor.world.pos.z, MTXMODE_NEW);
|
|
Matrix_Scale(this->actor.scale.x * 0.75f, 1.0f, this->actor.scale.z * 0.75f, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_ganon.c", 9875),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfLightCoreDL);
|
|
|
|
Matrix_Pop();
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfLightBallMaterialDL);
|
|
|
|
gDPPipeSync(POLY_XLU_DISP++);
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, (s8)this->fwork[GDF_FWORK_1]);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 0, 0);
|
|
|
|
if (this->unk_1A8 == 1) {
|
|
for (i = 0; i < 8; i++) {
|
|
Matrix_Push();
|
|
Matrix_RotateY(i * (M_PI / 8), MTXMODE_APPLY);
|
|
Matrix_RotateZ(this->fwork[GDF_FWORK_0], MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_ganon.c", 9899),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfSquareDL);
|
|
Matrix_Pop();
|
|
}
|
|
} else if (this->unk_1A8 == 0) {
|
|
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
|
|
Matrix_RotateZ((this->actor.shape.rot.z / 32768.0f) * 3.1416f, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_ganon.c", 9907),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfSquareDL);
|
|
}
|
|
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_ganon.c", 9911);
|
|
}
|
|
|
|
void func_808E1EB4(Actor* thisx, GlobalContext* globalCtx2) {
|
|
s16 i;
|
|
BossGanon* this = (BossGanon*)thisx;
|
|
GlobalContext* globalCtx = globalCtx2;
|
|
BossGanon* dorf = (BossGanon*)this->actor.parent;
|
|
f32 xDiff;
|
|
f32 yDiff;
|
|
f32 zDiff;
|
|
f32 xzDist;
|
|
s16 xRotTarget;
|
|
s16 yRotTarget;
|
|
Vec3f vel;
|
|
Vec3f accel;
|
|
|
|
this->unk_1A2++;
|
|
dorf->envLightMode = 1;
|
|
Actor_SetScale(&this->actor, 6.0f);
|
|
this->actor.shape.rot.z += ((s16)(Rand_ZeroOne() * 20000.0f) + 0x4000);
|
|
|
|
for (i = 0; i < ARRAY_COUNT(this->timers); i++) {
|
|
if (this->timers[i] != 0) {
|
|
this->timers[i]--;
|
|
}
|
|
}
|
|
|
|
func_8002D908(&this->actor);
|
|
func_8002D7EC(&this->actor);
|
|
|
|
this->unk_1A6++;
|
|
|
|
if (this->unk_1A6 >= 15) {
|
|
this->unk_1A6 = 0;
|
|
}
|
|
|
|
this->unk_2EC[this->unk_1A6] = this->actor.world.pos;
|
|
|
|
if (this->unk_1C2 == 0) {
|
|
if (1) {}
|
|
if (this->timers[0] == 0) {
|
|
this->unk_1C2 = 1;
|
|
}
|
|
} else if (this->unk_1C2 == 1) {
|
|
xDiff = dorf->unk_1FC.x - this->actor.world.pos.x;
|
|
yDiff = dorf->unk_1FC.y - this->actor.world.pos.y;
|
|
zDiff = dorf->unk_1FC.z - this->actor.world.pos.z;
|
|
|
|
yRotTarget = RADF_TO_BINANG(Math_FAtan2F(xDiff, zDiff));
|
|
xzDist = sqrtf(SQ(xDiff) + SQ(zDiff));
|
|
xRotTarget = RADF_TO_BINANG(Math_FAtan2F(yDiff, xzDist));
|
|
|
|
Math_ApproachS(&this->actor.world.rot.x, xRotTarget, 1, 0x1000);
|
|
Math_ApproachS(&this->actor.world.rot.y, yRotTarget, 1, 0x1000);
|
|
|
|
if (sqrtf(SQ(xDiff) + SQ(zDiff) + SQ(yDiff)) < 40.0f) {
|
|
this->unk_1C2 = 2;
|
|
this->timers[0] = 30;
|
|
this->actor.speedXZ = 0.0f;
|
|
|
|
if (this->actor.params == 0xC8) {
|
|
func_80078884(NA_SE_EN_GANON_DAMAGE2);
|
|
func_80078884(NA_SE_EN_GANON_DD_THUNDER);
|
|
|
|
for (i = 0; i < 150; i++) {
|
|
|
|
vel.x = Rand_CenteredFloat(25.0f);
|
|
vel.y = Rand_CenteredFloat(25.0f);
|
|
vel.z = Rand_CenteredFloat(25.0f);
|
|
|
|
accel.x = vel.x * -0.03f;
|
|
accel.y = vel.y * -0.03f;
|
|
accel.z = vel.z * -0.03f;
|
|
|
|
BossGanonEff_SpawnLightRay(globalCtx, &dorf->unk_1FC, &vel, &accel,
|
|
Rand_ZeroFloat(500.0f) + 1000.0f, 15.0f, 0x14);
|
|
}
|
|
|
|
for (i = 1; i < 15; i++) {
|
|
dorf->unk_4E4[i] = 1000;
|
|
}
|
|
|
|
dorf->unk_2E6 = 1000;
|
|
dorf->unk_2E8 = 0;
|
|
dorf->screenFlashTimer = 4;
|
|
dorf->lensFlareTimer = 10;
|
|
dorf->lensFlareMode = 1;
|
|
dorf->unk_508 = 10.0f;
|
|
|
|
Actor_SpawnAsChild(&globalCtx->actorCtx, &dorf->actor, globalCtx, ACTOR_BOSS_GANON, dorf->unk_1FC.x,
|
|
dorf->unk_1FC.y, dorf->unk_1FC.z, 0, 0, 0, 0x12C);
|
|
}
|
|
|
|
this->actor.world.pos.y = 5000.0f;
|
|
}
|
|
} else if (this->timers[0] == 0) {
|
|
Actor_Kill(&this->actor);
|
|
}
|
|
}
|
|
|
|
void func_808E229C(Actor* thisx, GlobalContext* globalCtx2) {
|
|
BossGanon* this = (BossGanon*)thisx;
|
|
GlobalContext* globalCtx = globalCtx2;
|
|
s16 i;
|
|
s32 temp;
|
|
|
|
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_ganon.c", 10081);
|
|
func_80093D84(globalCtx->state.gfxCtx);
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, 255);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 0, 0);
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfLightBallMaterialDL);
|
|
|
|
for (i = 9; i >= 0; i--) {
|
|
temp = (s16)(((this->unk_1A6 - i) + 0xF) % 15);
|
|
Matrix_Translate(this->unk_2EC[temp].x, this->unk_2EC[temp].y, this->unk_2EC[temp].z, MTXMODE_NEW);
|
|
Matrix_Scale(this->actor.scale.x * (1.0f - (i * 0.07000001f)), this->actor.scale.y * (1.0f - (i * 0.07000001f)),
|
|
this->actor.scale.z * (1.0f - (i * 0.07000001f)), MTXMODE_APPLY);
|
|
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
|
|
Matrix_RotateZ(((2.0f * (i * M_PI)) / 10.0f) + BINANG_TO_RAD(this->actor.shape.rot.z), MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_ganon.c", 10109),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfSquareDL);
|
|
}
|
|
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_ganon.c", 10113);
|
|
}
|
|
|
|
void func_808E2544(Actor* thisx, GlobalContext* globalCtx) {
|
|
u8 numEffects = 0;
|
|
s16 xRot;
|
|
f32 xDiff;
|
|
f32 yDiff;
|
|
f32 zDiff;
|
|
f32 xzDist;
|
|
f32 new_var;
|
|
f32 sp84;
|
|
s16 i;
|
|
s16 sp80;
|
|
BossGanon* this = (BossGanon*)thisx;
|
|
BossGanon* dorf = (BossGanon*)this->actor.parent;
|
|
s32 pad;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
ColliderInfo* acHitInfo;
|
|
Vec3f sp60;
|
|
|
|
this->unk_1A2++;
|
|
Actor_SetScale(&this->actor, 0.01f);
|
|
|
|
for (i = 0; i < ARRAY_COUNT(this->timers); i++) {
|
|
if (this->timers[i] != 0) {
|
|
this->timers[i]--;
|
|
}
|
|
}
|
|
|
|
func_8002D908(&this->actor);
|
|
func_8002D7EC(&this->actor);
|
|
|
|
this->unk_1A6++;
|
|
|
|
if (this->unk_1A6 >= 15) {
|
|
this->unk_1A6 = 0;
|
|
}
|
|
|
|
this->unk_2EC[this->unk_1A6] = this->actor.world.pos;
|
|
this->unk_3C4[this->unk_1A6].x = BINANG_TO_RAD(this->actor.world.rot.x);
|
|
this->unk_3C4[this->unk_1A6].y = BINANG_TO_RAD(this->actor.world.rot.y);
|
|
|
|
switch (this->unk_1C2) {
|
|
if (1) {}
|
|
case 0:
|
|
this->actor.speedXZ = 40.0f;
|
|
Math_ApproachF(&this->fwork[1], 255.0f, 1.0f, 40.0f);
|
|
xDiff = dorf->unk_278.x - this->actor.world.pos.x;
|
|
yDiff = dorf->unk_278.y - this->actor.world.pos.y;
|
|
zDiff = dorf->unk_278.z - this->actor.world.pos.z;
|
|
sp80 = RADF_TO_BINANG(Math_FAtan2F(xDiff, zDiff));
|
|
xzDist = sqrtf(SQ(xDiff) + SQ(zDiff));
|
|
|
|
xRot = RADF_TO_BINANG(Math_FAtan2F(yDiff, xzDist));
|
|
sp84 = (xzDist * 700.0f) / 10.0f;
|
|
if (sp84 > 6144.0f) {
|
|
sp84 = 6144.0f;
|
|
}
|
|
|
|
xRot += (Math_CosS(this->unk_1A2 * 0x2200) * sp84);
|
|
this->actor.world.rot.x = xRot;
|
|
Math_ApproachS(&this->actor.shape.rot.y, sp80, 1, this->csCamMaxStepScale);
|
|
Math_ApproachF(&this->csCamMaxStepScale, 4096.0f, 1.0f, 256.0f);
|
|
this->actor.world.rot.y = (Math_SinS(this->unk_1A2 * 0x1A00) * sp84) + this->actor.shape.rot.y;
|
|
|
|
if (sqrtf(SQ(xDiff) + SQ(zDiff) + SQ(yDiff)) < 45.0f) {
|
|
this->unk_1C2 = 1;
|
|
this->actor.speedXZ = 0.0f;
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
Math_ApproachZeroF(&this->fwork[1], 1.0f, 40.0f);
|
|
|
|
if (this->fwork[1] == 0.0f) {
|
|
Actor_Kill(&this->actor);
|
|
}
|
|
break;
|
|
|
|
case 10:
|
|
this->unk_1C2 = 0xB;
|
|
this->timers[0] = 14;
|
|
|
|
this->collider.dim.radius = 15;
|
|
this->collider.dim.height = 20;
|
|
this->collider.dim.yShift = -10;
|
|
|
|
this->actor.speedXZ = 20.0f;
|
|
this->fwork[1] = 255.0f;
|
|
this->unk_1F0 = player->actor.world.pos;
|
|
new_var = this->unk_1F0.x - this->actor.world.pos.x;
|
|
this->actor.shape.rot.y = RADF_TO_BINANG(Math_FAtan2F(new_var, this->unk_1F0.z - this->actor.world.pos.z)) +
|
|
(this->actor.params << 0xD) - 0x20C000;
|
|
// fallthrough
|
|
case 11:
|
|
if (this->timers[0] != 0) {
|
|
this->unk_1F0 = player->actor.world.pos;
|
|
xDiff = this->unk_1F0.x - this->actor.world.pos.x;
|
|
yDiff = (this->unk_1F0.y + 30.0f) - this->actor.world.pos.y;
|
|
zDiff = this->unk_1F0.z - this->actor.world.pos.z;
|
|
|
|
sp80 = RADF_TO_BINANG(Math_FAtan2F(xDiff, zDiff));
|
|
this->actor.shape.rot.x = RADF_TO_BINANG(Math_FAtan2F(yDiff, sqrtf(SQ(xDiff) + SQ(zDiff))));
|
|
Math_ApproachS(&this->actor.shape.rot.y, sp80, 1, this->csCamMaxStepScale);
|
|
Math_ApproachF(&this->csCamMaxStepScale, 4096.0f, 1.0f, 256.0f);
|
|
}
|
|
|
|
sp84 = (sqrtf(this->actor.xyzDistToPlayerSq) * 200.0f) / 10.0f;
|
|
if (sp84 > 13824.0f) {
|
|
sp84 = 13824.0f;
|
|
}
|
|
|
|
this->actor.world.rot.x = (Math_CosS(this->unk_1A2 * 0x3400) * sp84 * 0.1f) + this->actor.shape.rot.x;
|
|
this->actor.world.rot.y = (Math_SinS(this->unk_1A2 * 0x1A00) * sp84) + this->actor.shape.rot.y;
|
|
|
|
if ((player->swordState != 0) && (player->swordAnimation >= 0x18) && (this->actor.xzDistToPlayer < 80.0f)) {
|
|
this->unk_1C2 = 0xC;
|
|
this->actor.speedXZ = -30.0f;
|
|
func_8002D908(&this->actor);
|
|
func_8002D7EC(&this->actor);
|
|
this->unk_1F0 = dorf->unk_1FC;
|
|
numEffects = 10;
|
|
break;
|
|
}
|
|
|
|
if (this->collider.base.acFlags & 2) {
|
|
acHitInfo = this->collider.info.acHitInfo;
|
|
|
|
this->collider.base.acFlags &= ~2;
|
|
|
|
if (!(acHitInfo->toucher.dmgFlags & 0x100000) || Player_HasMirrorShieldEquipped(globalCtx)) {
|
|
func_800AA000(this->actor.xyzDistToPlayerSq, 0xB4, 0x14, 0x64);
|
|
this->unk_1C2 = 0xC;
|
|
this->actor.speedXZ = -30.0f;
|
|
|
|
func_8002D908(&this->actor);
|
|
func_8002D7EC(&this->actor);
|
|
|
|
this->unk_1F0.x = Rand_CenteredFloat(700.0f) + dorf->unk_1FC.x;
|
|
this->unk_1F0.y = Rand_CenteredFloat(200.0f) + dorf->unk_1FC.y;
|
|
this->unk_1F0.z = Rand_CenteredFloat(700.0f) + dorf->unk_1FC.z;
|
|
|
|
this->unk_1F0.x = this->unk_1F0.x + ((this->unk_1F0.x - this->actor.world.pos.x) * 100.0f);
|
|
this->unk_1F0.y = this->unk_1F0.y + ((this->unk_1F0.y - this->actor.world.pos.y) * 100.0f);
|
|
this->unk_1F0.z = this->unk_1F0.z + ((this->unk_1F0.z - this->actor.world.pos.z) * 100.0f);
|
|
|
|
numEffects = 10;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Collider_UpdateCylinder(&this->actor, &this->collider);
|
|
|
|
if (this->timers[1] == 0) {
|
|
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->collider.base);
|
|
}
|
|
|
|
xDiff = player->actor.world.pos.x - this->actor.world.pos.x;
|
|
yDiff = (player->actor.world.pos.y + 30.0f) - this->actor.world.pos.y;
|
|
zDiff = player->actor.world.pos.z - this->actor.world.pos.z;
|
|
|
|
if (sqrtf(SQ(xDiff) + SQ(zDiff) + SQ(yDiff)) < 30.0f) {
|
|
this->unk_1C2 = 1;
|
|
this->actor.speedXZ = 0.0f;
|
|
|
|
if (dorf->timers[2] == 0) {
|
|
func_8002F6D4(globalCtx, &this->actor, 3.0f, this->actor.world.rot.y, 0.0f, 0x50);
|
|
SoundSource_PlaySfxAtFixedWorldPos(globalCtx, &this->actor.world.pos, 40,
|
|
NA_SE_EN_GANON_HIT_THUNDER);
|
|
dorf->timers[2] = 20;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(this->unk_4E4); i++) {
|
|
dorf->unk_4E4[i] = D_808E4C58[i];
|
|
}
|
|
|
|
dorf->unk_2E6 = 0;
|
|
dorf->unk_2E8 = 60;
|
|
dorf->unk_508 = 4.0f;
|
|
numEffects = 40;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 12:
|
|
this->actor.speedXZ = 20.0f;
|
|
|
|
xDiff = this->unk_1F0.x - this->actor.world.pos.x;
|
|
yDiff = this->unk_1F0.y - this->actor.world.pos.y;
|
|
zDiff = this->unk_1F0.z - this->actor.world.pos.z;
|
|
|
|
sp80 = RADF_TO_BINANG(Math_FAtan2F(xDiff, zDiff));
|
|
xzDist = sqrtf(SQ(xDiff) + SQ(zDiff));
|
|
xRot = RADF_TO_BINANG(Math_FAtan2F(yDiff, xzDist));
|
|
sp84 = (xzDist * 700.0f) / 10.0f;
|
|
|
|
if (sp84 > 6144.0f) {
|
|
sp84 = 6144.0f;
|
|
}
|
|
|
|
sp80 += Math_SinS(this->unk_1A2 * 0x2200) * sp84;
|
|
|
|
xRot += Math_CosS(this->unk_1A2 * 0x1800) * sp84;
|
|
|
|
this->actor.world.rot.x = xRot;
|
|
this->actor.world.rot.y = sp80;
|
|
|
|
xDiff = dorf->unk_1FC.x - this->actor.world.pos.x;
|
|
yDiff = dorf->unk_1FC.y - this->actor.world.pos.y;
|
|
zDiff = dorf->unk_1FC.z - this->actor.world.pos.z;
|
|
|
|
if (sqrtf(SQ(xDiff) + SQ(zDiff) + SQ(yDiff)) < 45.0f) {
|
|
BossGanon_SetupHitByLightBall(dorf, globalCtx);
|
|
this->timers[0] = 150;
|
|
numEffects = 40;
|
|
this->unk_1C2 = 1;
|
|
this->actor.speedXZ = 0.0f;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (this->unk_1C2 >= 0xB) {
|
|
xzDist = (this->unk_1C2 == 0xC) ? -65.0f : 0.0f;
|
|
|
|
if ((fabsf(this->actor.world.pos.x) > (465.0f + xzDist)) ||
|
|
(fabsf(this->actor.world.pos.z) > (465.0f + xzDist)) || ((this->actor.world.pos.y < 0.0f)) ||
|
|
(this->actor.world.pos.y > 450.0f)) {
|
|
this->unk_1C2 = 1;
|
|
this->actor.speedXZ = 0.0f;
|
|
numEffects = 10;
|
|
BossGanon_CheckFallingPlatforms(this, globalCtx, &this->actor.world.pos);
|
|
Actor_SpawnAsChild(&globalCtx->actorCtx, &dorf->actor, globalCtx, ACTOR_BOSS_GANON, this->actor.world.pos.x,
|
|
this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, 0, 0x190);
|
|
}
|
|
}
|
|
|
|
if (numEffects) {
|
|
SoundSource_PlaySfxAtFixedWorldPos(globalCtx, &this->actor.world.pos, 80, NA_SE_EN_FANTOM_THUNDER);
|
|
|
|
for (i = 0; i < numEffects; i++) {
|
|
sp60.x = Rand_CenteredFloat(30.0f);
|
|
sp60.y = Rand_CenteredFloat(30.0f);
|
|
sp60.z = Rand_CenteredFloat(30.0);
|
|
|
|
BossGanonEff_SpawnLightRay(globalCtx, &this->actor.world.pos, &sp60, &sZeroVec,
|
|
Rand_ZeroFloat(200.0f) + 500.0f, 15.0f, 0x1E);
|
|
}
|
|
}
|
|
}
|
|
|
|
static Gfx* sBigMagicLightStreakDLists[] = {
|
|
gDorfLightStreak12DL, gDorfLightStreak11DL, gDorfLightStreak10DL, gDorfLightStreak9DL,
|
|
gDorfLightStreak8DL, gDorfLightStreak7DL, gDorfLightStreak6DL, gDorfLightStreak5DL,
|
|
gDorfLightStreak4DL, gDorfLightStreak3DL, gDorfLightStreak2DL, gDorfLightStreak1DL,
|
|
};
|
|
|
|
void func_808E324C(Actor* thisx, GlobalContext* globalCtx) {
|
|
BossGanon* this = (BossGanon*)thisx;
|
|
Mtx* mtx;
|
|
s16 i;
|
|
s32 temp;
|
|
|
|
mtx = Graph_Alloc(globalCtx->state.gfxCtx, 12 * sizeof(Mtx));
|
|
|
|
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_ganon.c", 10489);
|
|
|
|
func_80093D84(globalCtx->state.gfxCtx);
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, 255, 255, 255, (s8)this->fwork[GDF_FWORK_1]);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 150, 255, 0, 128);
|
|
gSPSegment(POLY_XLU_DISP++, 0x0D, mtx);
|
|
|
|
for (i = 0; i < 12; i++) {
|
|
temp = (s16)(((this->unk_1A6 - i) + 0xF) % 15);
|
|
Matrix_Translate(this->unk_2EC[temp].x, this->unk_2EC[temp].y, this->unk_2EC[temp].z, MTXMODE_NEW);
|
|
Matrix_RotateY(this->unk_3C4[temp].y, MTXMODE_APPLY);
|
|
Matrix_RotateX(-this->unk_3C4[temp].x, MTXMODE_APPLY);
|
|
Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY);
|
|
Matrix_RotateY(M_PI / 2, MTXMODE_APPLY);
|
|
Matrix_ToMtx(mtx, "../z_boss_ganon.c", 10520);
|
|
gSPMatrix(POLY_XLU_DISP++, mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, sBigMagicLightStreakDLists[i]);
|
|
mtx++;
|
|
};
|
|
|
|
Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, MTXMODE_NEW);
|
|
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
|
|
Matrix_Scale(10.0f, 10.0f, 10.0f, MTXMODE_APPLY);
|
|
Matrix_RotateZ(Rand_CenteredFloat(M_PI), MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_ganon.c", 10534),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfLightBallMaterialDL);
|
|
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfSquareDL);
|
|
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_ganon.c", 10541);
|
|
}
|
|
|
|
void BossGanon_UpdateEffects(GlobalContext* globalCtx) {
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
GanondorfEffect* eff = globalCtx->specialEffects;
|
|
s16 i;
|
|
s32 pad;
|
|
f32 xDiff;
|
|
f32 yDiff;
|
|
f32 zDiff;
|
|
f32 yRot;
|
|
f32 xRot;
|
|
Vec3f spA0;
|
|
s16 bodyPart;
|
|
f32 distToPlayer;
|
|
s32 pad2;
|
|
s32 pad3;
|
|
|
|
spA0.x = 0.0f;
|
|
spA0.y = 0.0f;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(sBossGanonEffectBuf); i++, eff++) {
|
|
if (eff->type != GDF_EFF_NONE) {
|
|
eff->pos.x += eff->velocity.x;
|
|
eff->pos.y += eff->velocity.y;
|
|
eff->pos.z += eff->velocity.z;
|
|
|
|
eff->timer++;
|
|
|
|
eff->velocity.x += eff->accel.x;
|
|
eff->velocity.y += eff->accel.y;
|
|
eff->velocity.z += eff->accel.z;
|
|
|
|
if (eff->type == GDF_EFF_WINDOW_SHARD) {
|
|
eff->unk_44 += 0.3f;
|
|
eff->unk_48 += 0.5f;
|
|
|
|
if (eff->pos.y < 0.0f) {
|
|
eff->type = GDF_EFF_NONE;
|
|
}
|
|
} else if (eff->type == GDF_EFF_SPARKLE) {
|
|
eff->unk_3C += Rand_ZeroFloat(M_PI / 2) + M_PI / 2;
|
|
eff->unk_2E -= eff->unk_30;
|
|
|
|
if (eff->unk_2E <= 0) {
|
|
eff->unk_2E = 0;
|
|
eff->type = GDF_EFF_NONE;
|
|
}
|
|
|
|
eff->alpha = eff->unk_2E;
|
|
|
|
if (eff->alpha > 255) {
|
|
eff->alpha = 255;
|
|
}
|
|
} else if (eff->type == GDF_EFF_BLACK_DOT) {
|
|
xDiff = sBossGanonGanondorf->unk_278.x - eff->pos.x;
|
|
yDiff = sBossGanonGanondorf->unk_278.y - eff->pos.y;
|
|
zDiff = sBossGanonGanondorf->unk_278.z - eff->pos.z;
|
|
|
|
yRot = Math_FAtan2F(xDiff, zDiff);
|
|
|
|
xRot = -Math_FAtan2F(yDiff, sqrtf(SQ(xDiff) + SQ(zDiff)));
|
|
spA0.z = eff->unk_38;
|
|
Matrix_RotateY(yRot, MTXMODE_NEW);
|
|
Matrix_RotateX(xRot, MTXMODE_APPLY);
|
|
Matrix_MultVec3f(&spA0, &eff->velocity);
|
|
Math_ApproachF(&eff->unk_38, 10.0f, 1.0f, 0.5f);
|
|
|
|
eff->alpha += 10;
|
|
|
|
if (eff->alpha > 255) {
|
|
eff->alpha = 255;
|
|
}
|
|
|
|
if ((sqrtf(SQ(xDiff) + SQ(yDiff) + SQ(zDiff)) < 20.0f) || (eff->timer > 70)) {
|
|
eff->type = GDF_EFF_NONE;
|
|
}
|
|
} else if (eff->type == GDF_EFF_LIGHT_RAY) {
|
|
eff->unk_3C += Rand_ZeroFloat(M_PI / 2) + M_PI / 2;
|
|
eff->unk_2E -= eff->unk_30;
|
|
|
|
if (eff->unk_2E <= 0) {
|
|
eff->unk_2E = 0;
|
|
eff->type = GDF_EFF_NONE;
|
|
}
|
|
|
|
eff->alpha = eff->unk_2E;
|
|
|
|
if (eff->alpha > 255) {
|
|
eff->alpha = 255;
|
|
}
|
|
|
|
Math_ApproachF(&eff->unk_38, eff->unk_40, 1.0f, (eff->unk_40 / 15.0f) * 4.0f);
|
|
} else if (eff->type == GDF_EFF_SHOCK) {
|
|
if (eff->unk_2E == GDF_SHOCK_DORF_YELLOW) {
|
|
bodyPart = (s16)Rand_ZeroFloat(13.9f) + 1;
|
|
|
|
eff->pos.x = sBossGanonGanondorf->unk_2EC[bodyPart].x + Rand_CenteredFloat(20.0f);
|
|
eff->pos.y = sBossGanonGanondorf->unk_2EC[bodyPart].y + Rand_CenteredFloat(20.0f);
|
|
eff->pos.z = sBossGanonGanondorf->unk_2EC[bodyPart].z + Rand_CenteredFloat(20.0f);
|
|
} else {
|
|
bodyPart = (s16)Rand_ZeroFloat(17.9f);
|
|
|
|
eff->pos.x = player->bodyPartsPos[bodyPart].x + Rand_CenteredFloat(10.0f);
|
|
eff->pos.y = player->bodyPartsPos[bodyPart].y + Rand_CenteredFloat(15.0f);
|
|
eff->pos.z = player->bodyPartsPos[bodyPart].z + Rand_CenteredFloat(10.0f);
|
|
}
|
|
|
|
eff->unk_3C += (Rand_ZeroFloat(M_PI / 2) + M_PI / 2);
|
|
|
|
if (eff->timer > 20) {
|
|
eff->type = GDF_EFF_NONE;
|
|
}
|
|
} else if (eff->type == GDF_EFF_LIGHTNING) {
|
|
if (eff->unk_3C == 0.0f) {
|
|
eff->unk_44 = BINANG_TO_RAD(Camera_GetInputDirYaw(Gameplay_GetCamera(globalCtx, MAIN_CAM)));
|
|
} else {
|
|
eff->unk_44 = M_PI / 2;
|
|
}
|
|
|
|
if (eff->timer > 12) {
|
|
eff->type = GDF_EFF_NONE;
|
|
}
|
|
} else if (eff->type == GDF_EFF_IMPACT_DUST_DARK) {
|
|
eff->unk_30++; // unused
|
|
|
|
if (eff->unk_2E == 0) {
|
|
eff->alpha += 26;
|
|
|
|
if (eff->alpha > 255) {
|
|
eff->alpha = 255;
|
|
eff->unk_2E = 1;
|
|
}
|
|
} else if (eff->unk_2E == 1) {
|
|
eff->unk_2E = 2;
|
|
} else if (eff->unk_2E == 2) {
|
|
eff->alpha -= 26;
|
|
|
|
if (eff->alpha < 0) {
|
|
eff->alpha = 0;
|
|
eff->type = GDF_EFF_NONE;
|
|
}
|
|
}
|
|
|
|
Math_ApproachF(&eff->scale, eff->unk_38, 1.0f, 0.01f);
|
|
Math_ApproachF(&eff->unk_40, 4.0f, 1.0f, 0.15f);
|
|
} else if (eff->type == GDF_EFF_IMPACT_DUST_LIGHT) {
|
|
if (i == 0) {
|
|
func_80078884(NA_SE_EN_GANON_WAVE_GND - SFX_FLAG);
|
|
}
|
|
|
|
eff->unk_30++; // unused
|
|
|
|
if (eff->unk_2E == 0) {
|
|
eff->alpha += 100;
|
|
|
|
if (eff->alpha > 255) {
|
|
eff->alpha = 255;
|
|
eff->unk_2E = 1;
|
|
}
|
|
} else if (eff->unk_2E == 1) {
|
|
if (eff->timer >= 20) {
|
|
eff->unk_2E = 2;
|
|
}
|
|
} else if (eff->unk_2E == 2) {
|
|
eff->alpha -= 30;
|
|
|
|
if (eff->alpha < 0) {
|
|
eff->alpha = 0;
|
|
eff->type = GDF_EFF_NONE;
|
|
}
|
|
}
|
|
|
|
Math_ApproachF(&eff->scale, eff->unk_38, 1.0f, 0.1f);
|
|
Math_ApproachF(&eff->unk_40, 1.0f, 1.0f, 0.15f);
|
|
} else if (eff->type == GDF_EFF_SHOCKWAVE) {
|
|
eff->unk_30++; // unused
|
|
eff->alpha -= 30;
|
|
|
|
if (eff->alpha < 0) {
|
|
eff->alpha = 0;
|
|
eff->type = GDF_EFF_NONE;
|
|
}
|
|
|
|
Math_ApproachF(&eff->scale, eff->unk_38, 1.0f, 0.13f);
|
|
|
|
if ((eff->timer < 150) && (fabsf(player->actor.world.pos.y) < 5.0f)) {
|
|
distToPlayer =
|
|
sqrtf(SQ(eff->pos.x - player->actor.world.pos.x) + SQ(eff->pos.z - player->actor.world.pos.z));
|
|
|
|
if (((eff->scale * 150.0f) < distToPlayer) && (distToPlayer < (eff->scale * 300.0f))) {
|
|
eff->timer = 150;
|
|
func_8002F6D4(globalCtx, &sBossGanonGanondorf->actor, 7.0f, sBossGanonGanondorf->actor.yawTowardsPlayer, 0.0f,
|
|
0x20);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void* sLightningTextures[] = {
|
|
gDorfLightning1Tex, gDorfLightning1Tex, gDorfLightning2Tex, gDorfLightning3Tex, gDorfLightning4Tex,
|
|
gDorfLightning5Tex, gDorfLightning6Tex, gDorfLightning7Tex, gDorfLightning8Tex, gDorfLightning9Tex,
|
|
gDorfLightning10Tex, gDorfLightning11Tex, gDorfLightning12Tex,
|
|
};
|
|
|
|
static u8 sLightningPrimColors[] = {
|
|
0, 0, 0, 255, 255, 255, 231, 250, 231, 208, 245, 208, 185, 240, 185, 162, 235, 162, 139, 230,
|
|
139, 115, 225, 115, 92, 220, 92, 69, 215, 69, 46, 210, 46, 23, 205, 23, 0, 200, 0,
|
|
};
|
|
|
|
static u8 sLightningEnvColors[] = {
|
|
0, 0, 0, 255, 255, 0, 240, 231, 23, 226, 208, 46, 212, 185, 69, 198, 162, 92,
|
|
184, 139, 115, 170, 115, 139, 156, 92, 162, 142, 69, 185, 128, 46, 208, 114, 23, 231,
|
|
100, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
};
|
|
|
|
void BossGanon_DrawEffects(GlobalContext* globalCtx) {
|
|
u8 flag = 0;
|
|
s16 i;
|
|
s32 pad;
|
|
GraphicsContext* gfxCtx = globalCtx->state.gfxCtx;
|
|
GanondorfEffect* eff = globalCtx->specialEffects;
|
|
GanondorfEffect* effFirst = eff;
|
|
|
|
OPEN_DISPS(gfxCtx, "../z_boss_ganon.c", 10865);
|
|
func_80093D84(globalCtx->state.gfxCtx);
|
|
|
|
for (i = 0; i < 200; i++, eff++) {
|
|
if (eff->type == GDF_EFF_WINDOW_SHARD) {
|
|
FrameInterpolation_RecordOpenChild(eff, eff->epoch);
|
|
gDPPipeSync(POLY_OPA_DISP++);
|
|
if (flag == 0) {
|
|
gSPDisplayList(POLY_OPA_DISP++, gDorfWindowShardMaterialDL);
|
|
flag++;
|
|
}
|
|
if ((eff->timer & 7) != 0) {
|
|
gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, eff->color.r, eff->color.g, eff->color.b, 255);
|
|
} else {
|
|
gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, 255);
|
|
}
|
|
Matrix_Translate(eff->pos.x, eff->pos.y, eff->pos.z, MTXMODE_NEW);
|
|
Matrix_Scale(eff->scale, eff->scale, eff->scale, MTXMODE_APPLY);
|
|
Matrix_RotateY(eff->unk_48, MTXMODE_APPLY);
|
|
Matrix_RotateX(eff->unk_44, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 10898),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_OPA_DISP++, gDorfWindowShardModelDL);
|
|
FrameInterpolation_RecordCloseChild();
|
|
}
|
|
}
|
|
|
|
eff = effFirst;
|
|
flag = 0;
|
|
|
|
for (i = 0; i < 150; i++, eff++) {
|
|
if (eff->type == GDF_EFF_SPARKLE) {
|
|
FrameInterpolation_RecordOpenChild(eff, eff->epoch);
|
|
gDPPipeSync(POLY_XLU_DISP++);
|
|
if (flag == 0) {
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 0, 0);
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfLightBallMaterialDL);
|
|
flag++;
|
|
}
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, eff->alpha);
|
|
Matrix_Translate(eff->pos.x, eff->pos.y, eff->pos.z, MTXMODE_NEW);
|
|
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
|
|
Matrix_Scale(eff->scale, eff->scale, 1.0f, MTXMODE_APPLY);
|
|
Matrix_RotateZ(eff->unk_3C, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 10932),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfSquareDL);
|
|
FrameInterpolation_RecordCloseChild();
|
|
}
|
|
}
|
|
|
|
eff = effFirst;
|
|
flag = 0;
|
|
|
|
for (i = 0; i < 150; i++, eff++) {
|
|
if (eff->type == GDF_EFF_LIGHT_RAY) {
|
|
FrameInterpolation_RecordOpenChild(eff, eff->epoch);
|
|
gDPPipeSync(POLY_XLU_DISP++);
|
|
if (flag == 0) {
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 0, 0);
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfLightBallMaterialDL);
|
|
flag++;
|
|
}
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, eff->alpha);
|
|
Matrix_Translate(eff->pos.x, eff->pos.y, eff->pos.z, MTXMODE_NEW);
|
|
Matrix_RotateY(eff->unk_48, MTXMODE_APPLY);
|
|
Matrix_RotateX(eff->unk_44, MTXMODE_APPLY);
|
|
Matrix_RotateZ(eff->unk_3C, MTXMODE_APPLY);
|
|
Matrix_Scale(eff->scale, eff->scale, eff->unk_38 * eff->scale, MTXMODE_APPLY);
|
|
Matrix_RotateX(M_PI / 2, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 10971),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfSquareDL);
|
|
FrameInterpolation_RecordCloseChild();
|
|
}
|
|
}
|
|
|
|
eff = effFirst;
|
|
flag = 0;
|
|
|
|
for (i = 0; i < 150; i++, eff++) {
|
|
if (eff->type == GDF_EFF_SHOCK) {
|
|
FrameInterpolation_RecordOpenChild(eff, eff->epoch);
|
|
if (flag == 0) {
|
|
gDPPipeSync(POLY_XLU_DISP++);
|
|
if (eff->unk_2E == GDF_SHOCK_PLAYER_PURPLE) {
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 100, 0, 200, 255);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 130, 0, 0, 0);
|
|
} else { // GDF_SHOCK_DORF_YELLOW or GDF_SHOCK_PLAYER_YELLOW
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, 255);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 0, 0);
|
|
}
|
|
flag++;
|
|
}
|
|
Matrix_Translate(eff->pos.x, eff->pos.y, eff->pos.z, MTXMODE_NEW);
|
|
Matrix_Scale(eff->scale, eff->scale, 1.0f, MTXMODE_APPLY);
|
|
Matrix_RotateX(eff->unk_3C * 1.3f, MTXMODE_APPLY);
|
|
Matrix_RotateZ(eff->unk_3C, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 11023),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfShockDL);
|
|
FrameInterpolation_RecordCloseChild();
|
|
}
|
|
}
|
|
|
|
eff = effFirst;
|
|
|
|
for (i = 0; i < 150; i++, eff++) {
|
|
if (eff->type == GDF_EFF_LIGHTNING) {
|
|
FrameInterpolation_RecordOpenChild(eff, eff->epoch);
|
|
gDPPipeSync(POLY_XLU_DISP++);
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, sLightningPrimColors[(eff->timer * 3) + 0],
|
|
sLightningPrimColors[(eff->timer * 3) + 1], sLightningPrimColors[(eff->timer * 3) + 2],
|
|
255);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, sLightningEnvColors[(eff->timer * 3) + 0],
|
|
sLightningEnvColors[(eff->timer * 3) + 1], sLightningEnvColors[(eff->timer * 3) + 2], 0);
|
|
Matrix_Translate(sBossGanonGanondorf->unk_260.x, sBossGanonGanondorf->unk_260.y, sBossGanonGanondorf->unk_260.z, MTXMODE_NEW);
|
|
Matrix_RotateY(eff->unk_48, MTXMODE_APPLY);
|
|
Matrix_RotateZ(eff->unk_3C, MTXMODE_APPLY);
|
|
Matrix_Scale(eff->scale, eff->scale, eff->scale, MTXMODE_APPLY);
|
|
Matrix_RotateY(eff->unk_44, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 11074),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPSegment(POLY_XLU_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(sLightningTextures[eff->timer]));
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfLightningDL);
|
|
FrameInterpolation_RecordCloseChild();
|
|
}
|
|
}
|
|
|
|
eff = effFirst;
|
|
|
|
for (i = 0; i < 150; i++, eff++) {
|
|
if (eff->type == GDF_EFF_IMPACT_DUST_DARK) {
|
|
FrameInterpolation_RecordOpenChild(eff, eff->epoch);
|
|
gDPPipeSync(POLY_XLU_DISP++);
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 0, 0, 0, eff->alpha);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 100, 70, 0, 128);
|
|
gSPSegment(POLY_XLU_DISP++, 0x08,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, eff->timer * 4, 0, 32, 64, 1, eff->timer * 2,
|
|
eff->timer * -20, 32, 32));
|
|
Matrix_Translate(eff->pos.x, eff->pos.y, eff->pos.z, MTXMODE_NEW);
|
|
Matrix_Scale(eff->scale, eff->unk_40 * eff->scale, eff->scale, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 11121),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfImpactDarkDL);
|
|
FrameInterpolation_RecordCloseChild();
|
|
}
|
|
}
|
|
|
|
eff = effFirst;
|
|
|
|
for (i = 0; i < 150; i++, eff++) {
|
|
if (eff->type == GDF_EFF_IMPACT_DUST_LIGHT) {
|
|
FrameInterpolation_RecordOpenChild(eff, eff->epoch);
|
|
gDPPipeSync(POLY_XLU_DISP++);
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, eff->alpha);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 200, 100, 0, 128);
|
|
gSPSegment(POLY_XLU_DISP++, 0x08,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, eff->timer * 4, 0, 32, 64, 1, eff->timer * 2,
|
|
eff->timer * -20, 32, 32));
|
|
Matrix_Translate(eff->pos.x, eff->pos.y, eff->pos.z, MTXMODE_NEW);
|
|
Matrix_Scale(eff->scale, eff->unk_40 * eff->scale, eff->scale, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 11165),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfImpactLightDL);
|
|
FrameInterpolation_RecordCloseChild();
|
|
}
|
|
}
|
|
|
|
eff = effFirst;
|
|
|
|
for (i = 0; i < 150; i++, eff++) {
|
|
if (eff->type == GDF_EFF_SHOCKWAVE) {
|
|
FrameInterpolation_RecordOpenChild(eff, eff->epoch);
|
|
gDPPipeSync(POLY_XLU_DISP++);
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 170, eff->alpha);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 150, 255, 0, 128);
|
|
gSPSegment(POLY_XLU_DISP++, 0x08,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, (eff->timer * 100), 0, 64, 32, 1,
|
|
(eff->timer * 100), 0, 64, 32));
|
|
Matrix_Translate(eff->pos.x, eff->pos.y, eff->pos.z, MTXMODE_NEW);
|
|
Matrix_Scale((eff->scale * 200.0f) / 1500.0f, (eff->unk_40 * 200.0f) / 1500.0f,
|
|
(eff->scale * 200.0f) / 1500.0f, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 11209),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfShockwaveDL);
|
|
FrameInterpolation_RecordCloseChild();
|
|
}
|
|
}
|
|
|
|
eff = effFirst;
|
|
|
|
for (i = 0; i < 150; i++, eff++) {
|
|
if (eff->type == GDF_EFF_BLACK_DOT) {
|
|
FrameInterpolation_RecordOpenChild(eff, eff->epoch);
|
|
gDPPipeSync(POLY_XLU_DISP++);
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 150, 170, 0, eff->alpha);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, 128);
|
|
gSPSegment(POLY_XLU_DISP++, 0x0A,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, 0, 32, 32, 1, eff->timer * 2, eff->timer * -20,
|
|
64, 64));
|
|
Matrix_Translate(eff->pos.x, eff->pos.y, eff->pos.z, MTXMODE_NEW);
|
|
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
|
|
Matrix_Scale(eff->scale, eff->scale, 1.0f, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 11250),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, gDorfDotDL);
|
|
FrameInterpolation_RecordCloseChild();
|
|
}
|
|
}
|
|
|
|
CLOSE_DISPS(gfxCtx, "../z_boss_ganon.c", 11255);
|
|
}
|
|
|
|
#include "overlays/ovl_Boss_Ganon/ovl_Boss_Ganon.h"
|
|
|
|
void BossGanon_Reset(void) {
|
|
sBossGanonSeed1 = 0;
|
|
sBossGanonSeed2 = 0;
|
|
sBossGanonSeed3 = 0;
|
|
sBossGanonGanondorf = NULL;
|
|
sBossGanonZelda = NULL;
|
|
sBossGanonCape = NULL;
|
|
memset(sBossGanonEffectBuf, 0, sizeof(sBossGanonEffectBuf));
|
|
} |