Shipwright/soh/src/overlays/actors/ovl_Boss_Ganon/z_boss_ganon.c

5076 lines
188 KiB
C
Raw Normal View History

#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 };
2022-05-12 13:28:24 -04:00
EnGanonMant* sBossGanonCape;
2022-05-12 13:28:24 -04:00
s32 sBossGanonSeed1;
s32 sBossGanonSeed3;
s32 sBossGanonSeed2;
2022-05-12 13:28:24 -04:00
BossGanon* sBossGanonGanondorf;
2022-05-12 13:28:24 -04:00
EnZl3* sBossGanonZelda;
2022-05-12 13:28:24 -04:00
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);
2022-05-12 13:28:24 -04:00
globalCtx->specialEffects = sBossGanonEffectBuf;
2022-05-12 13:28:24 -04:00
for (i = 0; i < ARRAY_COUNT(sBossGanonEffectBuf); i++) {
sBossGanonEffectBuf[i].type = GDF_EFF_NONE;
}
2022-05-12 13:28:24 -04:00
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);
}
2022-05-12 13:28:24 -04:00
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;
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);
2022-05-12 13:28:24 -04:00
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;
testing out item replacement (#416) * skip learning song of storms * don't set flag when getting goron tunic as child * Initiates prelude check when master sword unloads. Not quite how N64 rando does it but so far it's the only way I've found to make it trigger without also triggering the time travel again. * Stops Shadow Temple lore prompts from appearing in rando. * Skips cutscene of royal tomb explosion in rando. Explosion sound doesn't play correctly and I think the debris appears in the wrong place, but the functionality is here. * Improves visual of exploding gravestone. * Adds some comments explaining the rando differences * Skip ruto text box in jabu blue warp For rando * skip intro cutscene in dodongo's cavern * load spoiler files on boot, fix spoilerfile existing check when making new saves * name entry dropped spoiler logic * make sure to actually init the cvar * no chime on load * uncomment * Skip ganondrof cutscene Skip to scream part of the death animation, skipping the text boxes etc. For rando * Update z_boss_ganondrof.c * skip owl flight cutscenes in rando * Fixes skipped text so it only applies to shadow temple. Earlier fix inadvertently applied to some other text as well, changed logic so that only specified sceneNums and textIds can have this enabled, and text skipped by sceneNum can have the skip overriden by textId if needed. Currently there are no overrides so the textId section of the logic is commented out to avoid compilation errors. * Adds a default to the switch case statements that leaves the randoSkipText variable unchanged, just in case. * TEST: Text for item * Adding ganon flavor text * ADD: AMMO Count * format ganon text/hint text * Autoskip the tower cutscene if settings call for tower collapse. * ganon hint text logic * Improved prelude after time travel fix * swapped the sizes between ganon hint text and ganon text, as they were set to the wrong things. * this is all i did * not the cleanest code ever but it's working * ADD: GS Count * ADD: Wallter (crash for now) * TWEAK: Wallet check * FIX: Use DrawItem instread of DrawUpgrade... b-baka! * Fixes some vanilla bugs introduced by rando code. * Added cutscene skip for zelda escaping Using the debug cutscene skipping function. Also added a conditional so the bridge doesn't spawn closed when cutscene is ready to trigger * ADD: X Spacing + Placeholders for song * ADD: default case for items * TWEAK: Spacing * FIX: Light Arrow * ADD: Ammo Option * use groups instead * ADD: More spacing logic * songs and names * TWEAK: Color on wallet * colors * Added flags cutscene before nabooru fight * ADD: ChromaKey text * First attempt skip cs after nabooru defeat * Better implementation for specific rando cutscene skips * use pulseaudio defaults * spaces/tabs * move color push/pop to stop crash * make the colors work again * the real bottle fix * pulseaudio values tuned for n64 audio at 44.1khz * update tlength * remove one hardcoded samplerate * Cleaned up and fixed zelda escape skip The if statement is a freaking monster, but unless we want to skip more cutscenes in the same way later, this is the most compact way of doing it that I know of. * Revert one line to match original nothing functional * another hint line that breaks autonewline logic * don't autospawn epona if we don't have the song/ocarina * Trying to use iron knuckle death effects not working yet * Streamlined OoT cutscene skip for future additions Also cleaned up if statement in general * Made if statement more readable Also added clarity for what cutscene was skipped * Fixed typo in comment * Janky nabooru defeat cs skip * altar text formatting (gonna need help shortening some of the french ones) * more altar text formatting * english altar text formatting complete * make gtg blocking guard check for card not bridge * FIX: Typo! * FIX: Uppercases * FIX: Typo * TWEAK: Alter + some names * TWEAK: More caps! * ADD: Missing string TWEAK more uppercases and namefixe s * Hide nabooru death by covering her in flames * bandaid fix for death crash issue * Twinrova defeat cs skip Skips the animation and manually calls the function to show the "beam" around the sisters * fix crash * fix caps to match * fix great fairy reward mashing/shielding issue * TWEAK : Typo clé to Clé * TWEAK: Some Altar hints TWEAK: Some capitals * TWEAK: Unmatching text + some cap again * TWEAK: More tweaks * fix build * remove extra json.hpp, add hint * Update randomizer_item_tracker.cpp * TWEAK: Double Defense with RedParticles instead of white * make sure we don't optimize out the check to ensure a spoilerfile exists * vanilla ganon boss key hint formatting * TWEAK: FR- better way of the hero text * fix * and again * Initializes dungeonsDone items in gSaveContext to 0. * Replaces sizeof calculation with a NUM_DUNGEONS constant. * Fixes Saria's Gift on the LW Bridge from getting killed when holding shield. * More airtight fix for Saria's Gift on the Bridge. * Lifts one of the conditions in the if statement a little higher to prevent unnecessary lookups of getItemId. * Invalidate text box icon before drawing * Fixes the case where Saria's gift is an Ice Trap. We still get the Ice Trap once, but never again. This does mean you can now hold R while walking in to avoid the ice trap, but everything else seems to work fine. * Initial commit Might need changing when we change the settings in the future * Fixes Door of Time opening cutscene after warping with prelude. * Initial waterfall skip Very rudimentary way of doing things but it seems to work so :shrug: * inital rework * fixed default rotation for 2D sprites * fix tab/space issues * 3d drops rando merge fix again * Allows Impa to appear in the Lullaby check post drawbridge escape. * Changes Ganon's Trials Count setting to a checkbox The checkbox is whether or not to skip all of them. Leaving the box unchecked will mean doing all of them. Eventually this will be switched back to a slider once we implement the logic for which trials start out completed. * Sets all Ganon's Trials to incomplete in new saves. Fixes https://github.com/briaguya-ai/rando-issue-tracker/issues/131 * fix castle guards when oot throw cutscene has already played in rando * Properly removes the beams when trials are cleared. * Removes Question Mark from Skip Ganon's Trials UI. * Adds a todo comment about when to change back to slider. * make deku seeds check for bullet bag * Various tweaks TWEAK: Altar Text TWEAK: Hint names TWEAK: Replace more problematic œ to oe * upgrade ocarina on both child and adult equips * FIX: Jabu Item * update equipped hookshot/longshot when obtained as other age * add hint * don't give the bgs check without the claim check * Skips Darunia Cutscene in Fire Temple * Added a TODO note about not skipping the cutscene. There is a setting we will want to have eventually that will require this cutscene to not be skipped since it is used during a glitch. * remove todo * restore fast ocarina option in imgui that was lost in merge * Fixes grey screen issue + tooltip for 2 handed shield * update to use dg instead of g for textures in item tracker * TWEAK: Default color for cosmetic RAND button was not the corect one * fix texture crash, remove unused item tracker code * don't open mask shop until we get zelda's letter * Update README.md * Prevents "correct" chime under incorrect conditions. * Fixes typo in conditional and adds "bonk" sound effect. "Bonk" sound is NA_SE_SY_OCARINA_ERROR and it plays when conditions for the Door of Time have not been met after playing Song of Time. This is only possible in rando's "Intended" Door of Time option, in which the Ocarina of Time and all 3 spritual stones are required to open the door, instead of the vanilla requirements of just having the song of time. * remove modify dpad equips toggle, replace with checks for dpad menu * remove extra check * add ability to hold c-up to assign to dpad when dpad menuing is enabled * disable d-pad navigation on item menu when holding c-up to equip * dpad+c-up stuff for equipment menu * ADD: Checbox for songs colors * TWEAK: RandoColors for normal songs * kind of quick and dirty but it works * TWEAK: Clarity of the tooltip Co-authored-by: briaguya <briaguya@alice> Co-authored-by: Christopher Leggett <chris@leggett.dev> Co-authored-by: aMannus <mannusmenting@gmail.com> Co-authored-by: PurpleHato <linkvssangoku.jr@gmail.com> Co-authored-by: Dog <5172592+Dog@users.noreply.github.com> Co-authored-by: Vague Rant <vaguerant@users.noreply.github.com> Co-authored-by: Baoulettes <perlouzerie@hotmail.fr> Co-authored-by: Ada <60364512+GreatArgorath@users.noreply.github.com>
2022-07-11 20:11:07 -04:00
if (gSaveContext.eventChkInf[7] & 0x100 || gSaveContext.n64ddFlag) {
// 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;
2022-05-12 13:28:24 -04:00
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);
2022-05-12 13:28:24 -04:00
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);
2022-05-12 13:28:24 -04:00
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) {
2022-05-12 13:28:24 -04:00
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;
2022-05-12 13:28:24 -04:00
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) {
2022-05-12 13:28:24 -04:00
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);
testing out item replacement (#416) * skip learning song of storms * don't set flag when getting goron tunic as child * Initiates prelude check when master sword unloads. Not quite how N64 rando does it but so far it's the only way I've found to make it trigger without also triggering the time travel again. * Stops Shadow Temple lore prompts from appearing in rando. * Skips cutscene of royal tomb explosion in rando. Explosion sound doesn't play correctly and I think the debris appears in the wrong place, but the functionality is here. * Improves visual of exploding gravestone. * Adds some comments explaining the rando differences * Skip ruto text box in jabu blue warp For rando * skip intro cutscene in dodongo's cavern * load spoiler files on boot, fix spoilerfile existing check when making new saves * name entry dropped spoiler logic * make sure to actually init the cvar * no chime on load * uncomment * Skip ganondrof cutscene Skip to scream part of the death animation, skipping the text boxes etc. For rando * Update z_boss_ganondrof.c * skip owl flight cutscenes in rando * Fixes skipped text so it only applies to shadow temple. Earlier fix inadvertently applied to some other text as well, changed logic so that only specified sceneNums and textIds can have this enabled, and text skipped by sceneNum can have the skip overriden by textId if needed. Currently there are no overrides so the textId section of the logic is commented out to avoid compilation errors. * Adds a default to the switch case statements that leaves the randoSkipText variable unchanged, just in case. * TEST: Text for item * Adding ganon flavor text * ADD: AMMO Count * format ganon text/hint text * Autoskip the tower cutscene if settings call for tower collapse. * ganon hint text logic * Improved prelude after time travel fix * swapped the sizes between ganon hint text and ganon text, as they were set to the wrong things. * this is all i did * not the cleanest code ever but it's working * ADD: GS Count * ADD: Wallter (crash for now) * TWEAK: Wallet check * FIX: Use DrawItem instread of DrawUpgrade... b-baka! * Fixes some vanilla bugs introduced by rando code. * Added cutscene skip for zelda escaping Using the debug cutscene skipping function. Also added a conditional so the bridge doesn't spawn closed when cutscene is ready to trigger * ADD: X Spacing + Placeholders for song * ADD: default case for items * TWEAK: Spacing * FIX: Light Arrow * ADD: Ammo Option * use groups instead * ADD: More spacing logic * songs and names * TWEAK: Color on wallet * colors * Added flags cutscene before nabooru fight * ADD: ChromaKey text * First attempt skip cs after nabooru defeat * Better implementation for specific rando cutscene skips * use pulseaudio defaults * spaces/tabs * move color push/pop to stop crash * make the colors work again * the real bottle fix * pulseaudio values tuned for n64 audio at 44.1khz * update tlength * remove one hardcoded samplerate * Cleaned up and fixed zelda escape skip The if statement is a freaking monster, but unless we want to skip more cutscenes in the same way later, this is the most compact way of doing it that I know of. * Revert one line to match original nothing functional * another hint line that breaks autonewline logic * don't autospawn epona if we don't have the song/ocarina * Trying to use iron knuckle death effects not working yet * Streamlined OoT cutscene skip for future additions Also cleaned up if statement in general * Made if statement more readable Also added clarity for what cutscene was skipped * Fixed typo in comment * Janky nabooru defeat cs skip * altar text formatting (gonna need help shortening some of the french ones) * more altar text formatting * english altar text formatting complete * make gtg blocking guard check for card not bridge * FIX: Typo! * FIX: Uppercases * FIX: Typo * TWEAK: Alter + some names * TWEAK: More caps! * ADD: Missing string TWEAK more uppercases and namefixe s * Hide nabooru death by covering her in flames * bandaid fix for death crash issue * Twinrova defeat cs skip Skips the animation and manually calls the function to show the "beam" around the sisters * fix crash * fix caps to match * fix great fairy reward mashing/shielding issue * TWEAK : Typo clé to Clé * TWEAK: Some Altar hints TWEAK: Some capitals * TWEAK: Unmatching text + some cap again * TWEAK: More tweaks * fix build * remove extra json.hpp, add hint * Update randomizer_item_tracker.cpp * TWEAK: Double Defense with RedParticles instead of white * make sure we don't optimize out the check to ensure a spoilerfile exists * vanilla ganon boss key hint formatting * TWEAK: FR- better way of the hero text * fix * and again * Initializes dungeonsDone items in gSaveContext to 0. * Replaces sizeof calculation with a NUM_DUNGEONS constant. * Fixes Saria's Gift on the LW Bridge from getting killed when holding shield. * More airtight fix for Saria's Gift on the Bridge. * Lifts one of the conditions in the if statement a little higher to prevent unnecessary lookups of getItemId. * Invalidate text box icon before drawing * Fixes the case where Saria's gift is an Ice Trap. We still get the Ice Trap once, but never again. This does mean you can now hold R while walking in to avoid the ice trap, but everything else seems to work fine. * Initial commit Might need changing when we change the settings in the future * Fixes Door of Time opening cutscene after warping with prelude. * Initial waterfall skip Very rudimentary way of doing things but it seems to work so :shrug: * inital rework * fixed default rotation for 2D sprites * fix tab/space issues * 3d drops rando merge fix again * Allows Impa to appear in the Lullaby check post drawbridge escape. * Changes Ganon's Trials Count setting to a checkbox The checkbox is whether or not to skip all of them. Leaving the box unchecked will mean doing all of them. Eventually this will be switched back to a slider once we implement the logic for which trials start out completed. * Sets all Ganon's Trials to incomplete in new saves. Fixes https://github.com/briaguya-ai/rando-issue-tracker/issues/131 * fix castle guards when oot throw cutscene has already played in rando * Properly removes the beams when trials are cleared. * Removes Question Mark from Skip Ganon's Trials UI. * Adds a todo comment about when to change back to slider. * make deku seeds check for bullet bag * Various tweaks TWEAK: Altar Text TWEAK: Hint names TWEAK: Replace more problematic œ to oe * upgrade ocarina on both child and adult equips * FIX: Jabu Item * update equipped hookshot/longshot when obtained as other age * add hint * don't give the bgs check without the claim check * Skips Darunia Cutscene in Fire Temple * Added a TODO note about not skipping the cutscene. There is a setting we will want to have eventually that will require this cutscene to not be skipped since it is used during a glitch. * remove todo * restore fast ocarina option in imgui that was lost in merge * Fixes grey screen issue + tooltip for 2 handed shield * update to use dg instead of g for textures in item tracker * TWEAK: Default color for cosmetic RAND button was not the corect one * fix texture crash, remove unused item tracker code * don't open mask shop until we get zelda's letter * Update README.md * Prevents "correct" chime under incorrect conditions. * Fixes typo in conditional and adds "bonk" sound effect. "Bonk" sound is NA_SE_SY_OCARINA_ERROR and it plays when conditions for the Door of Time have not been met after playing Song of Time. This is only possible in rando's "Intended" Door of Time option, in which the Ocarina of Time and all 3 spritual stones are required to open the door, instead of the vanilla requirements of just having the song of time. * remove modify dpad equips toggle, replace with checks for dpad menu * remove extra check * add ability to hold c-up to assign to dpad when dpad menuing is enabled * disable d-pad navigation on item menu when holding c-up to equip * dpad+c-up stuff for equipment menu * ADD: Checbox for songs colors * TWEAK: RandoColors for normal songs * kind of quick and dirty but it works * TWEAK: Clarity of the tooltip Co-authored-by: briaguya <briaguya@alice> Co-authored-by: Christopher Leggett <chris@leggett.dev> Co-authored-by: aMannus <mannusmenting@gmail.com> Co-authored-by: PurpleHato <linkvssangoku.jr@gmail.com> Co-authored-by: Dog <5172592+Dog@users.noreply.github.com> Co-authored-by: Vague Rant <vaguerant@users.noreply.github.com> Co-authored-by: Baoulettes <perlouzerie@hotmail.fr> Co-authored-by: Ada <60364512+GreatArgorath@users.noreply.github.com>
2022-07-11 20:11:07 -04:00
if (!gSaveContext.n64ddFlag) {
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;
2022-05-12 13:28:24 -04:00
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);
2022-05-12 13:28:24 -04:00
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);
}
2022-05-12 13:28:24 -04:00
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) {
static Color_RGBA8 bloodPrimColor = { 0, 120, 0, 255 };
static Color_RGBA8 bloodEnvColor = { 0, 120, 0, 255 };
if(CVar_GetS32("gRedGanonBlood", 0)) {
bloodPrimColor.r = 120;
bloodPrimColor.g = 0;
bloodEnvColor.r = 120;
bloodEnvColor.g = 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;
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SKIP_TOWER_ESCAPE)) {
testing out item replacement (#416) * skip learning song of storms * don't set flag when getting goron tunic as child * Initiates prelude check when master sword unloads. Not quite how N64 rando does it but so far it's the only way I've found to make it trigger without also triggering the time travel again. * Stops Shadow Temple lore prompts from appearing in rando. * Skips cutscene of royal tomb explosion in rando. Explosion sound doesn't play correctly and I think the debris appears in the wrong place, but the functionality is here. * Improves visual of exploding gravestone. * Adds some comments explaining the rando differences * Skip ruto text box in jabu blue warp For rando * skip intro cutscene in dodongo's cavern * load spoiler files on boot, fix spoilerfile existing check when making new saves * name entry dropped spoiler logic * make sure to actually init the cvar * no chime on load * uncomment * Skip ganondrof cutscene Skip to scream part of the death animation, skipping the text boxes etc. For rando * Update z_boss_ganondrof.c * skip owl flight cutscenes in rando * Fixes skipped text so it only applies to shadow temple. Earlier fix inadvertently applied to some other text as well, changed logic so that only specified sceneNums and textIds can have this enabled, and text skipped by sceneNum can have the skip overriden by textId if needed. Currently there are no overrides so the textId section of the logic is commented out to avoid compilation errors. * Adds a default to the switch case statements that leaves the randoSkipText variable unchanged, just in case. * TEST: Text for item * Adding ganon flavor text * ADD: AMMO Count * format ganon text/hint text * Autoskip the tower cutscene if settings call for tower collapse. * ganon hint text logic * Improved prelude after time travel fix * swapped the sizes between ganon hint text and ganon text, as they were set to the wrong things. * this is all i did * not the cleanest code ever but it's working * ADD: GS Count * ADD: Wallter (crash for now) * TWEAK: Wallet check * FIX: Use DrawItem instread of DrawUpgrade... b-baka! * Fixes some vanilla bugs introduced by rando code. * Added cutscene skip for zelda escaping Using the debug cutscene skipping function. Also added a conditional so the bridge doesn't spawn closed when cutscene is ready to trigger * ADD: X Spacing + Placeholders for song * ADD: default case for items * TWEAK: Spacing * FIX: Light Arrow * ADD: Ammo Option * use groups instead * ADD: More spacing logic * songs and names * TWEAK: Color on wallet * colors * Added flags cutscene before nabooru fight * ADD: ChromaKey text * First attempt skip cs after nabooru defeat * Better implementation for specific rando cutscene skips * use pulseaudio defaults * spaces/tabs * move color push/pop to stop crash * make the colors work again * the real bottle fix * pulseaudio values tuned for n64 audio at 44.1khz * update tlength * remove one hardcoded samplerate * Cleaned up and fixed zelda escape skip The if statement is a freaking monster, but unless we want to skip more cutscenes in the same way later, this is the most compact way of doing it that I know of. * Revert one line to match original nothing functional * another hint line that breaks autonewline logic * don't autospawn epona if we don't have the song/ocarina * Trying to use iron knuckle death effects not working yet * Streamlined OoT cutscene skip for future additions Also cleaned up if statement in general * Made if statement more readable Also added clarity for what cutscene was skipped * Fixed typo in comment * Janky nabooru defeat cs skip * altar text formatting (gonna need help shortening some of the french ones) * more altar text formatting * english altar text formatting complete * make gtg blocking guard check for card not bridge * FIX: Typo! * FIX: Uppercases * FIX: Typo * TWEAK: Alter + some names * TWEAK: More caps! * ADD: Missing string TWEAK more uppercases and namefixe s * Hide nabooru death by covering her in flames * bandaid fix for death crash issue * Twinrova defeat cs skip Skips the animation and manually calls the function to show the "beam" around the sisters * fix crash * fix caps to match * fix great fairy reward mashing/shielding issue * TWEAK : Typo clé to Clé * TWEAK: Some Altar hints TWEAK: Some capitals * TWEAK: Unmatching text + some cap again * TWEAK: More tweaks * fix build * remove extra json.hpp, add hint * Update randomizer_item_tracker.cpp * TWEAK: Double Defense with RedParticles instead of white * make sure we don't optimize out the check to ensure a spoilerfile exists * vanilla ganon boss key hint formatting * TWEAK: FR- better way of the hero text * fix * and again * Initializes dungeonsDone items in gSaveContext to 0. * Replaces sizeof calculation with a NUM_DUNGEONS constant. * Fixes Saria's Gift on the LW Bridge from getting killed when holding shield. * More airtight fix for Saria's Gift on the Bridge. * Lifts one of the conditions in the if statement a little higher to prevent unnecessary lookups of getItemId. * Invalidate text box icon before drawing * Fixes the case where Saria's gift is an Ice Trap. We still get the Ice Trap once, but never again. This does mean you can now hold R while walking in to avoid the ice trap, but everything else seems to work fine. * Initial commit Might need changing when we change the settings in the future * Fixes Door of Time opening cutscene after warping with prelude. * Initial waterfall skip Very rudimentary way of doing things but it seems to work so :shrug: * inital rework * fixed default rotation for 2D sprites * fix tab/space issues * 3d drops rando merge fix again * Allows Impa to appear in the Lullaby check post drawbridge escape. * Changes Ganon's Trials Count setting to a checkbox The checkbox is whether or not to skip all of them. Leaving the box unchecked will mean doing all of them. Eventually this will be switched back to a slider once we implement the logic for which trials start out completed. * Sets all Ganon's Trials to incomplete in new saves. Fixes https://github.com/briaguya-ai/rando-issue-tracker/issues/131 * fix castle guards when oot throw cutscene has already played in rando * Properly removes the beams when trials are cleared. * Removes Question Mark from Skip Ganon's Trials UI. * Adds a todo comment about when to change back to slider. * make deku seeds check for bullet bag * Various tweaks TWEAK: Altar Text TWEAK: Hint names TWEAK: Replace more problematic œ to oe * upgrade ocarina on both child and adult equips * FIX: Jabu Item * update equipped hookshot/longshot when obtained as other age * add hint * don't give the bgs check without the claim check * Skips Darunia Cutscene in Fire Temple * Added a TODO note about not skipping the cutscene. There is a setting we will want to have eventually that will require this cutscene to not be skipped since it is used during a glitch. * remove todo * restore fast ocarina option in imgui that was lost in merge * Fixes grey screen issue + tooltip for 2 handed shield * update to use dg instead of g for textures in item tracker * TWEAK: Default color for cosmetic RAND button was not the corect one * fix texture crash, remove unused item tracker code * don't open mask shop until we get zelda's letter * Update README.md * Prevents "correct" chime under incorrect conditions. * Fixes typo in conditional and adds "bonk" sound effect. "Bonk" sound is NA_SE_SY_OCARINA_ERROR and it plays when conditions for the Door of Time have not been met after playing Song of Time. This is only possible in rando's "Intended" Door of Time option, in which the Ocarina of Time and all 3 spritual stones are required to open the door, instead of the vanilla requirements of just having the song of time. * remove modify dpad equips toggle, replace with checks for dpad menu * remove extra check * add ability to hold c-up to assign to dpad when dpad menuing is enabled * disable d-pad navigation on item menu when holding c-up to equip * dpad+c-up stuff for equipment menu * ADD: Checbox for songs colors * TWEAK: RandoColors for normal songs * kind of quick and dirty but it works * TWEAK: Clarity of the tooltip Co-authored-by: briaguya <briaguya@alice> Co-authored-by: Christopher Leggett <chris@leggett.dev> Co-authored-by: aMannus <mannusmenting@gmail.com> Co-authored-by: PurpleHato <linkvssangoku.jr@gmail.com> Co-authored-by: Dog <5172592+Dog@users.noreply.github.com> Co-authored-by: Vague Rant <vaguerant@users.noreply.github.com> Co-authored-by: Baoulettes <perlouzerie@hotmail.fr> Co-authored-by: Ada <60364512+GreatArgorath@users.noreply.github.com>
2022-07-11 20:11:07 -04:00
Flags_SetEventChkInf(0xC7);
globalCtx->nextEntranceIndex = 0x517;
}
else {
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;
2022-05-12 13:28:24 -04:00
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;
2022-05-12 13:28:24 -04:00
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;
2022-05-12 13:28:24 -04:00
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:
2022-05-12 13:28:24 -04:00
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;
2022-05-12 13:28:24 -04:00
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) {
2022-05-12 13:28:24 -04:00
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;
2022-05-12 13:28:24 -04:00
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) {
2022-05-12 13:28:24 -04:00
sBossGanonZelda->unk_3C8 = 8;
}
if (this->csTimer == 50) {
2022-05-12 13:28:24 -04:00
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;
2022-05-12 13:28:24 -04:00
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) {
2022-05-12 13:28:24 -04:00
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;
2022-05-12 13:28:24 -04:00
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) {
2022-05-12 13:28:24 -04:00
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;
2022-05-12 13:28:24 -04:00
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)) {
2022-05-12 13:28:24 -04:00
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);
2022-05-12 13:28:24 -04:00
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:
2022-05-12 13:28:24 -04:00
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);
2022-05-12 13:28:24 -04:00
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) {
2022-05-12 13:28:24 -04:00
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)) {
2022-05-12 13:28:24 -04:00
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;
2022-05-12 13:28:24 -04:00
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;
2022-05-12 13:28:24 -04:00
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);
2022-05-12 13:28:24 -04:00
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);
2022-05-12 13:28:24 -04:00
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;
2022-05-12 13:28:24 -04:00
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);
2022-05-12 13:28:24 -04:00
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);
2022-05-12 13:28:24 -04:00
sBossGanonCape->attachShouldersTimer = 15.0f;
Audio_PlayActorSound2(&this->actor, NA_SE_EV_GANON_MANTLE);
}
} else {
2022-05-12 13:28:24 -04:00
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;
2022-05-12 13:28:24 -04:00
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);
2022-05-12 13:28:24 -04:00
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);
2022-05-12 13:28:24 -04:00
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;
2022-05-12 13:28:24 -04:00
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:
2022-05-12 13:28:24 -04:00
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);
2022-05-12 13:28:24 -04:00
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);
2022-05-12 13:28:24 -04:00
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;
}
2022-05-12 13:28:24 -04:00
for (i = 0; i < ARRAY_COUNT(sBossGanonCape->strands); i++) {
for (j = 1; j < 12; j++) {
2022-05-12 13:28:24 -04:00
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;
2022-05-12 13:28:24 -04:00
sBossGanonCape->tearTimer = 1;
}
}
} else if (acHitInfo->toucher.dmgFlags & 0x1F8A4) {
Audio_PlayActorSound2(&this->actor, 0);
2022-05-12 13:28:24 -04:00
for (i = 0; i < ARRAY_COUNT(sBossGanonCape->strands); i++) {
for (j = 1; j < 12; j++) {
2022-05-12 13:28:24 -04:00
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;
2022-05-12 13:28:24 -04:00
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);
Matrix_MultVec3f(&D_808E4DB8, &this->unk_208);
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
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);
} 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) {
2022-05-12 13:28:24 -04:00
sBossGanonSeed1 = seedInit0;
sBossGanonSeed2 = seedInit1;
sBossGanonSeed3 = seedInit2;
}
f32 BossGanon_RandZeroOne(void) {
// Wichmann-Hill algorithm
f32 randFloat;
2022-05-12 13:28:24 -04:00
sBossGanonSeed1 = (sBossGanonSeed1 * 171) % 30269;
sBossGanonSeed2 = (sBossGanonSeed2 * 172) % 30307;
sBossGanonSeed3 = (sBossGanonSeed3 * 170) % 30323;
2022-05-12 13:28:24 -04:00
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;
static u32 epoch = 0;
epoch++;
OPEN_DISPS(gfxCtx);
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++) {
FrameInterpolation_RecordOpenChild("Ganondorf Shock 0", epoch + i * 25);
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),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gDorfSquareDL);
FrameInterpolation_RecordCloseChild();
}
} else {
for (i = 1; i < 15; i++) {
FrameInterpolation_RecordOpenChild("Ganondorf Shock 1", epoch + i * 25);
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),
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);
}
FrameInterpolation_RecordCloseChild();
}
}
}
CLOSE_DISPS(gfxCtx);
}
void BossGanon_DrawHandLightBall(BossGanon* this, GlobalContext* globalCtx) {
s32 pad;
GraphicsContext* gfxCtx = globalCtx->state.gfxCtx;
s32 alpha;
OPEN_DISPS(gfxCtx);
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),
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),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gDorfLightCoreDL);
}
CLOSE_DISPS(gfxCtx);
}
void BossGanon_DrawBigMagicCharge(BossGanon* this, GlobalContext* globalCtx) {
s32 pad;
f32 yRot;
GraphicsContext* gfxCtx = globalCtx->state.gfxCtx;
s16 i;
static u32 epoch = 0;
epoch++;
OPEN_DISPS(gfxCtx);
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),
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),
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),
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++) {
FrameInterpolation_RecordOpenChild("Ganondorf Big Magic", epoch + i * 25);
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),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gDorfLightRayTriDL);
Matrix_Pop();
FrameInterpolation_RecordCloseChild();
}
}
CLOSE_DISPS(gfxCtx);
}
void BossGanon_DrawTriforce(BossGanon* this, GlobalContext* globalCtx) {
s32 pad;
if (this->fwork[GDF_TRIFORCE_PRIM_A] > 0.0f) {
OPEN_DISPS(globalCtx->state.gfxCtx);
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) {
2022-05-12 13:28:24 -04:00
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),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(gDorfTriforceDL));
Matrix_Pop();
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
}
void BossGanon_DrawDarkVortex(BossGanon* this, GlobalContext* globalCtx) {
s32 pad;
if (this->fwork[GDF_VORTEX_ALPHA] > 0.0f) {
OPEN_DISPS(globalCtx->state.gfxCtx);
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),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(gDorfVortexDL));
Matrix_Pop();
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
}
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++) {
2022-05-12 13:28:24 -04:00
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;
2022-05-12 13:28:24 -04:00
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);
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),
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);
}
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);
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);
2022-05-12 13:28:24 -04:00
sBossGanonCape->actor.world.pos = this->actor.world.pos;
2022-05-12 13:28:24 -04:00
sBossGanonCape->rightForearmPos = this->unk_214;
sBossGanonCape->leftForearmPos = this->unk_220;
2022-05-12 13:28:24 -04:00
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);
}
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;
static u32 epoch = 0;
epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx);
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),
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++) {
FrameInterpolation_RecordOpenChild("Ganondorf Light Ball 0", epoch + i * 25);
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),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gDorfSquareDL);
Matrix_Pop();
FrameInterpolation_RecordCloseChild();
}
} 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),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gDorfSquareDL);
}
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
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 (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);
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),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gDorfSquareDL);
}
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
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) {
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);
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);
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),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gDorfLightBallMaterialDL);
gSPDisplayList(POLY_XLU_DISP++, gDorfSquareDL);
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
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;
2022-05-12 13:28:24 -04:00
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) {
2022-05-12 13:28:24 -04:00
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;
2022-05-12 13:28:24 -04:00
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;
2022-05-12 13:28:24 -04:00
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);
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),
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),
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),
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),
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);
2022-05-12 13:28:24 -04:00
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),
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),
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),
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),
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),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gDorfDotDL);
FrameInterpolation_RecordCloseChild();
}
}
CLOSE_DISPS(gfxCtx);
}
#include "overlays/ovl_Boss_Ganon/ovl_Boss_Ganon.h"
void BossGanon_Reset(void) {
2022-05-12 13:28:24 -04:00
sBossGanonSeed1 = 0;
sBossGanonSeed2 = 0;
sBossGanonSeed3 = 0;
sBossGanonGanondorf = NULL;
sBossGanonZelda = NULL;
sBossGanonCape = NULL;
memset(sBossGanonEffectBuf, 0, sizeof(sBossGanonEffectBuf));
}