Document the function that handles the Giant's Mask cutscene in Boss02 (#1345)

* Document the function that handles the Giant's Mask cutscene in Boss02

* Remove newline between fallthrough and next case
This commit is contained in:
Tom Overton 2023-08-03 20:06:36 -07:00 committed by GitHub
parent 5625603b56
commit 27ccadc77e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 264 additions and 191 deletions

View File

@ -31,12 +31,42 @@ void Boss02_Static_Update(Actor* thisx, PlayState* play);
void Boss02_Static_Draw(Actor* thisx, PlayState* play); void Boss02_Static_Draw(Actor* thisx, PlayState* play);
void Boss02_UpdateEffects(PlayState* play); void Boss02_UpdateEffects(PlayState* play);
void Boss02_DrawEffects(PlayState* play); void Boss02_DrawEffects(PlayState* play);
void func_809DD934(Boss02* this, PlayState* play); void Boss02_HandleGiantsMaskCutscene(Boss02* this, PlayState* play);
void func_809DEAC4(Boss02* this, PlayState* play); void func_809DEAC4(Boss02* this, PlayState* play);
u8 D_809E0420; typedef enum {
u8 D_809E0421; /* 0 */ GIANTS_MASK_CS_STATE_WAITING_FOR_MASK, // Starts the cutscene when the player puts on/takes off the mask.
/* 1 */ GIANTS_MASK_CS_STATE_MASK_ON, // Controls the cutscene where the player puts the mask on.
/* 2 */ GIANTS_MASK_CS_STATE_MASK_ON_SKIPPED, // Moves to the "done" state when the mask-on cutscene is skipped.
/* 10 */ GIANTS_MASK_CS_STATE_MASK_OFF = 10, // Controls the cutscene where the player takes the mask off.
/* 11 */ GIANTS_MASK_CS_STATE_MASK_OFF_SKIPPED, // Moves to the "done" state when the mask-off cutscene is skipped.
/* 20 */ GIANTS_MASK_CS_STATE_DONE = 20 // Stops the cutscene and resets the player's scale back to normal.
} GiantsMaskCsState;
typedef enum {
/* 0 */ GIANTS_MASK_CS_FLASH_STATE_NOT_STARTED, // Does nothing at all.
/* 1 */ GIANTS_MASK_CS_FLASH_STATE_STARTED, // Plays the "mask flash" SFX and initializes a white FillScreen.
/* 2 */ GIANTS_MASK_CS_FLASH_STATE_INCREASE_ALPHA, // Increases the alpha for the FillScreen on every frame.
/* 3 */ GIANTS_MASK_CS_FLASH_STATE_DECREASE_ALPHA // Decreases the alpha for the FillScreen on every frame.
} GiantsMaskCsFlashState;
/**
* If set to true, the player can skip the cutscene of putting on the Giant's Mask
* by pressing A, B, or any C-button. If false, they must watch it in full.
*/
u8 sCanSkipMaskOnCs;
/**
* If set to true, the player can skip the cutscene of taking off the Giant's Mask
* by pressing A, B, or any C-button. If false, they must watch it in full.
*/
u8 sCanSkipMaskOffCs;
/**
* True when the player is giant-sized (i.e. wearing the Giant's Mask), false when the player is normal-sized.
*/
u8 sIsInGiantMode; u8 sIsInGiantMode;
Boss02* sRedTwinmold; Boss02* sRedTwinmold;
Boss02* sBlueTwinmold; Boss02* sBlueTwinmold;
Boss02* sTwinmoldStatic; Boss02* sTwinmoldStatic;
@ -468,7 +498,7 @@ Vec3f D_809DFA2C[] = {
{ -800.0f, -1000.0f, 0.0f }, { -800.0f, -1000.0f, 0.0f }, { -800.0f, -1000.0f, 0.0f }, { -800.0f, -1000.0f, 0.0f }, { -800.0f, -1000.0f, 0.0f }, { -800.0f, -1000.0f, 0.0f },
}; };
void func_809DA1D0(PlayState* play, u8 red, u8 green, u8 blue, u8 alpha) { void Boss02_FillScreen(PlayState* play, u8 red, u8 green, u8 blue, u8 alpha) {
R_PLAY_FILL_SCREEN_ON = true; R_PLAY_FILL_SCREEN_ON = true;
R_PLAY_FILL_SCREEN_R = red; R_PLAY_FILL_SCREEN_R = red;
R_PLAY_FILL_SCREEN_G = green; R_PLAY_FILL_SCREEN_G = green;
@ -476,11 +506,11 @@ void func_809DA1D0(PlayState* play, u8 red, u8 green, u8 blue, u8 alpha) {
R_PLAY_FILL_SCREEN_ALPHA = alpha; R_PLAY_FILL_SCREEN_ALPHA = alpha;
} }
void func_809DA22C(PlayState* play, u8 alpha) { void Boss02_SetFillScreenAlpha(PlayState* play, u8 alpha) {
R_PLAY_FILL_SCREEN_ALPHA = alpha; R_PLAY_FILL_SCREEN_ALPHA = alpha;
} }
void func_809DA24C(PlayState* play) { void Boss02_StopFillScreen(PlayState* play) {
R_PLAY_FILL_SCREEN_ON = false; R_PLAY_FILL_SCREEN_ON = false;
} }
@ -572,7 +602,7 @@ void Boss02_Init(Actor* thisx, PlayState* play) {
this->actor.update = Boss02_Static_Update; this->actor.update = Boss02_Static_Update;
this->actor.draw = Boss02_Static_Draw; this->actor.draw = Boss02_Static_Draw;
this->actor.flags &= ~ACTOR_FLAG_1; this->actor.flags &= ~ACTOR_FLAG_1;
this->unk_1D70 = 0.00999999977648f; this->playerScale = 0.01f;
if ((KREG(64) != 0) || CHECK_EVENTINF(EVENTINF_55) || (sBlueWarp != NULL)) { if ((KREG(64) != 0) || CHECK_EVENTINF(EVENTINF_55) || (sBlueWarp != NULL)) {
this->unk_1D20 = 0; this->unk_1D20 = 0;
sMusicStartTimer = KREG(15) + 20; sMusicStartTimer = KREG(15) + 20;
@ -1181,7 +1211,7 @@ void Boss02_Twinmold_Update(Actor* thisx, PlayState* play) {
Actor_SetScale(&this->actor, 0.060000001f); Actor_SetScale(&this->actor, 0.060000001f);
} }
if (sTwinmoldStatic->unk_1D18 == 0) { if (sTwinmoldStatic->giantsMaskCsState == GIANTS_MASK_CS_STATE_WAITING_FOR_MASK) {
for (i = 0; i < ARRAY_COUNT(this->unk_0146); i++) { for (i = 0; i < ARRAY_COUNT(this->unk_0146); i++) {
if (this->unk_0146[i] != 0) { if (this->unk_0146[i] != 0) {
this->unk_0146[i]--; this->unk_0146[i]--;
@ -1294,17 +1324,17 @@ void Boss02_Static_Update(Actor* thisx, PlayState* play) {
play->envCtx.sandstormState = 0xD; play->envCtx.sandstormState = 0xD;
if (sBlueWarp != NULL) { if (sBlueWarp != NULL) {
this->unk_1D74 = KREG(23) + -15.0f; this->fogNear = KREG(23) + -15.0f;
D_801F4E30 = 0; D_801F4E30 = 0;
play->envCtx.lightSettingOverride = 1; play->envCtx.lightSettingOverride = 1;
play->skyboxId = SKYBOX_NORMAL_SKY; play->skyboxId = SKYBOX_NORMAL_SKY;
} else if (!sIsInGiantMode) { } else if (!sIsInGiantMode) {
this->unk_1D74 = 0.0f; this->fogNear = 0.0f;
D_801F4E30 = this->unk_1D7C; D_801F4E30 = this->unk_1D7C;
play->envCtx.lightSettingOverride = 0; play->envCtx.lightSettingOverride = 0;
play->skyboxId = SKYBOX_2; play->skyboxId = SKYBOX_2;
} else { } else {
this->unk_1D74 = KREG(23) + -15.0f; this->fogNear = KREG(23) + -15.0f;
D_801F4E30 = ((KREG(24) * 0.1f) + 1.0f) * this->unk_1D7C; D_801F4E30 = ((KREG(24) * 0.1f) + 1.0f) * this->unk_1D7C;
play->envCtx.lightSettingOverride = 1; play->envCtx.lightSettingOverride = 1;
play->skyboxId = SKYBOX_NORMAL_SKY; play->skyboxId = SKYBOX_NORMAL_SKY;
@ -1327,7 +1357,7 @@ void Boss02_Static_Update(Actor* thisx, PlayState* play) {
Boss02_UpdateEffects(play); Boss02_UpdateEffects(play);
func_809DEAC4(this, play); func_809DEAC4(this, play);
func_809DD934(this, play); Boss02_HandleGiantsMaskCutscene(this, play);
} }
Gfx* D_809DFA9C[] = { Gfx* D_809DFA9C[] = {
@ -1630,158 +1660,181 @@ void Boss02_DrawEffects(PlayState* play) {
CLOSE_DISPS(play->state.gfxCtx); CLOSE_DISPS(play->state.gfxCtx);
} }
void func_809DD934(Boss02* this, PlayState* play) { /**
* This function is primarily responsible for handling the cutscene where the player puts on
* or takes off the Giant's Mask. It does some manual camera control, adjusts the player's
* scale, switches between the "Normal" and "Giant" variations of the arena, and creates a
* "flash" when the cutscene ends by filling the screen with white. In addition, this function
* is responsible for updating the EnvironmentContext's fogNear variable, which it does even
* when the Giant's Mask cutscene is not playing.
*/
void Boss02_HandleGiantsMaskCutscene(Boss02* this, PlayState* play) {
Player* player = GET_PLAYER(play); Player* player = GET_PLAYER(play);
s16 i; s16 i;
Actor* temp_a0_5; Actor* actorIter;
Vec3f sp58; Vec3f subCamEyeOffset;
u8 sp57 = 0; u8 switchArena = false;
f32 phi_f0_2; f32 scale;
s16 alpha; s16 alpha;
this->unk_1D14++; this->giantsMaskCsTimer++;
switch (this->unk_1D18) { switch (this->giantsMaskCsState) {
case 0: case GIANTS_MASK_CS_STATE_WAITING_FOR_MASK:
if (player->stateFlags1 & PLAYER_STATE1_100) { if (player->stateFlags1 & PLAYER_STATE1_100) {
Cutscene_StartManual(play, &play->csCtx); Cutscene_StartManual(play, &play->csCtx);
this->subCamId = Play_CreateSubCamera(play); this->subCamId = Play_CreateSubCamera(play);
Play_ChangeCameraStatus(play, CAM_ID_MAIN, CAM_STATUS_WAIT); Play_ChangeCameraStatus(play, CAM_ID_MAIN, CAM_STATUS_WAIT);
Play_ChangeCameraStatus(play, this->subCamId, CAM_STATUS_ACTIVE); Play_ChangeCameraStatus(play, this->subCamId, CAM_STATUS_ACTIVE);
Play_EnableMotionBlur(150); Play_EnableMotionBlur(150);
this->unk_1D14 = 0; this->giantsMaskCsTimer = 0;
this->subCamAtVel = 0.0f; this->subCamAtVel = 0.0f;
this->unk_1D58 = 0.0f; this->subCamUpRotZScale = 0.0f;
if (!sIsInGiantMode) { if (!sIsInGiantMode) {
this->unk_1D18 = 1; this->giantsMaskCsState = GIANTS_MASK_CS_STATE_MASK_ON;
this->unk_1D68 = 10.0f; this->subCamEyeOffsetY = 10.0f;
this->unk_1D64 = 60.0f; this->subCamDistZFromPlayer = 60.0f;
this->unk_1D6C = 23.0f; this->subCamAtOffsetY = 23.0f;
this->unk_1D70 = 0.01f; this->playerScale = 0.01f;
this->unk_1D74 = 0.0f; this->fogNear = 0.0f;
goto label1; goto maskOn; // Jumps to this label to prevent the player from skipping the cutscene immediately.
} else { } else {
this->unk_1D18 = 10; this->giantsMaskCsState = GIANTS_MASK_CS_STATE_MASK_OFF;
this->unk_1D68 = 10.0f; this->subCamEyeOffsetY = 10.0f;
this->unk_1D64 = 200.0f; this->subCamDistZFromPlayer = 200.0f;
this->unk_1D6C = 273.0f; this->subCamAtOffsetY = 273.0f;
this->unk_1D70 = 0.1f; this->playerScale = 0.1f;
this->unk_1D74 = -100.0f; this->fogNear = -100.0f;
sp57 = 1; switchArena = true;
goto label2; goto maskOff; // Jumps to this label to prevent the player from skipping the cutscene immediately.
} }
} }
break; break;
case 1: case GIANTS_MASK_CS_STATE_MASK_ON:
if ((this->unk_1D14 < 80) && (D_809E0420 != 0) && if ((this->giantsMaskCsTimer < 80) && sCanSkipMaskOnCs &&
CHECK_BTN_ANY(CONTROLLER1(&play->state)->press.button, CHECK_BTN_ANY(CONTROLLER1(&play->state)->press.button,
BTN_A | BTN_B | BTN_CUP | BTN_CDOWN | BTN_CLEFT | BTN_CRIGHT)) { BTN_A | BTN_B | BTN_CUP | BTN_CDOWN | BTN_CLEFT | BTN_CRIGHT)) {
this->unk_1D18++; this->giantsMaskCsState++;
this->unk_1D78 = 1; this->giantsMaskCsFlashState = GIANTS_MASK_CS_FLASH_STATE_STARTED;
this->unk_1D14 = 0; this->giantsMaskCsTimer = 0;
break;
}
maskOn:
if (this->giantsMaskCsTimer >= 50) {
if (this->giantsMaskCsTimer == (u32)(BREG(43) + 60)) {
Audio_PlaySfx(NA_SE_PL_TRANSFORM_GIANT);
}
// Makes the camera quickly move away from the player and look upwards as the player
// increases in size. Also decreases the fogNear from 0.0f to -100.0f.
Math_ApproachF(&this->subCamDistZFromPlayer, 200.0f, 0.1f, this->subCamAtVel * 640.0f);
Math_ApproachF(&this->subCamAtOffsetY, 273.0f, 0.1f, this->subCamAtVel * 150.0f);
Math_ApproachF(&this->playerScale, 0.1f, 0.2f, this->subCamAtVel * 0.1f);
Math_ApproachF(&this->fogNear, -100.0f, 1.0f, this->subCamAtVel * 100.0f);
Math_ApproachF(&this->subCamAtVel, 1.0f, 1.0f, 0.001f);
} else { } else {
label1: // Makes the camera slowly approach the player.
if (this->unk_1D14 >= 50) { Math_ApproachF(&this->subCamDistZFromPlayer, 30.0f, 0.1f, 1.0f);
if (this->unk_1D14 == (u32)(BREG(43) + 60)) { }
Audio_PlaySfx(NA_SE_PL_TRANSFORM_GIANT);
}
Math_ApproachF(&this->unk_1D64, 200.0f, 0.1f, this->subCamAtVel * 640.0f);
Math_ApproachF(&this->unk_1D6C, 273.0f, 0.1f, this->subCamAtVel * 150.0f);
Math_ApproachF(&this->unk_1D70, 0.1f, 0.2f, this->subCamAtVel * 0.1f);
Math_ApproachF(&this->unk_1D74, -100.0f, 1.0f, this->subCamAtVel * 100.0f);
Math_ApproachF(&this->subCamAtVel, 1.0f, 1.0f, 0.001f);
} else {
Math_ApproachF(&this->unk_1D64, 30.0f, 0.1f, 1.0f);
}
if (this->unk_1D14 > 50) { // Makes the camera roll side-to-side at the start of the cutscene, and stops
Math_ApproachZeroF(&this->unk_1D58, 1.0f, 0.06f); // the camera from rolling after 51 frames have passed.
} else { if (this->giantsMaskCsTimer > 50) {
Math_ApproachF(&this->unk_1D58, 0.4f, 1.0f, 0.02f); Math_ApproachZeroF(&this->subCamUpRotZScale, 1.0f, 0.06f);
} } else {
Math_ApproachF(&this->subCamUpRotZScale, 0.4f, 1.0f, 0.02f);
}
if (this->unk_1D14 == 107) { if (this->giantsMaskCsTimer == 107) {
this->unk_1D78 = 1; this->giantsMaskCsFlashState = GIANTS_MASK_CS_FLASH_STATE_STARTED;
} }
if (this->unk_1D14 < 121) { if (this->giantsMaskCsTimer > 120) {
break; switchArena = true;
} sCanSkipMaskOnCs = true;
goto done;
sp57 = 1;
D_809E0420 = 1;
goto block_38;
} }
break; break;
case 2: case GIANTS_MASK_CS_STATE_MASK_ON_SKIPPED:
if (this->unk_1D14 < 8) { if (this->giantsMaskCsTimer >= 8) {
break; switchArena = true;
goto done;
} }
sp57 = 1; break;
goto block_38;
case 10: case GIANTS_MASK_CS_STATE_MASK_OFF:
if ((this->unk_1D14 < 30) && (D_809E0421 != 0) && if ((this->giantsMaskCsTimer < 30) && sCanSkipMaskOffCs &&
CHECK_BTN_ANY(CONTROLLER1(&play->state)->press.button, CHECK_BTN_ANY(CONTROLLER1(&play->state)->press.button,
BTN_A | BTN_B | BTN_CUP | BTN_CDOWN | BTN_CLEFT | BTN_CRIGHT)) { BTN_A | BTN_B | BTN_CUP | BTN_CDOWN | BTN_CLEFT | BTN_CRIGHT)) {
this->unk_1D18++; this->giantsMaskCsState++;
this->unk_1D78 = 1; this->giantsMaskCsFlashState = GIANTS_MASK_CS_FLASH_STATE_STARTED;
this->unk_1D14 = 0; this->giantsMaskCsTimer = 0;
break; break;
} }
label2: maskOff:
if (this->unk_1D14 != 0) { if (this->giantsMaskCsTimer != 0) {
if (this->unk_1D14 == (u32)(BREG(44) + 10)) { if (this->giantsMaskCsTimer == (u32)(BREG(44) + 10)) {
Audio_PlaySfx(NA_SE_PL_TRANSFORM_NORAML); Audio_PlaySfx(NA_SE_PL_TRANSFORM_NORAML);
} }
Math_ApproachF(&this->unk_1D64, 60.0f, 0.1f, this->subCamAtVel * 640.0f);
Math_ApproachF(&this->unk_1D6C, 23.0f, 0.1f, this->subCamAtVel * 150.0f); // Makes the camera move slowly towards the player and look downwards as the player
Math_ApproachF(&this->unk_1D70, 0.01f, 0.1f, 0.003f); // decreases in size. Also increases the fogNear from -100.0f to 0.0f.
Math_ApproachF(&this->unk_1D74, 0.0f, 1.0f, this->subCamAtVel * 100.0f); Math_ApproachF(&this->subCamDistZFromPlayer, 60.0f, 0.1f, this->subCamAtVel * 640.0f);
Math_ApproachF(&this->subCamAtOffsetY, 23.0f, 0.1f, this->subCamAtVel * 150.0f);
Math_ApproachF(&this->playerScale, 0.01f, 0.1f, 0.003f);
Math_ApproachF(&this->fogNear, 0.0f, 1.0f, this->subCamAtVel * 100.0f);
Math_ApproachF(&this->subCamAtVel, 2.0f, 1.0f, 0.01f); Math_ApproachF(&this->subCamAtVel, 2.0f, 1.0f, 0.01f);
} }
if (this->unk_1D14 == 42) { if (this->giantsMaskCsTimer == 42) {
this->unk_1D78 = 1; this->giantsMaskCsFlashState = GIANTS_MASK_CS_FLASH_STATE_STARTED;
} }
if (this->unk_1D14 > 50) { if (this->giantsMaskCsTimer > 50) {
D_809E0421 = 1; sCanSkipMaskOffCs = true;
goto block_38; goto done;
} }
break; break;
case 11: case GIANTS_MASK_CS_STATE_MASK_OFF_SKIPPED:
if (this->unk_1D14 < 8) { if (this->giantsMaskCsTimer >= 8) {
break; goto done;
} }
break;
block_38: done:
case 20: case GIANTS_MASK_CS_STATE_DONE:
this->unk_1D18 = 0; // Ends the cutscene and restores the player's scale to its "original" value of 0.1f.
// This might seem strange in the case where the player has put on the Giant's Mask,
// since they seem so large after the cutscene ends. However, the player is still
// their normal size; the arena and everything in it has shrunk instead.
this->giantsMaskCsState = GIANTS_MASK_CS_STATE_WAITING_FOR_MASK;
func_80169AFC(play, this->subCamId, 0); func_80169AFC(play, this->subCamId, 0);
this->subCamId = SUB_CAM_ID_DONE; this->subCamId = SUB_CAM_ID_DONE;
Cutscene_StopManual(play, &play->csCtx); Cutscene_StopManual(play, &play->csCtx);
this->actor.flags |= ACTOR_FLAG_1; this->actor.flags |= ACTOR_FLAG_1;
player->stateFlags1 &= ~PLAYER_STATE1_100; player->stateFlags1 &= ~PLAYER_STATE1_100;
this->unk_1D70 = 0.01f; this->playerScale = 0.01f;
Play_DisableMotionBlur(); Play_DisableMotionBlur();
break; break;
} }
if (player->transformation == PLAYER_FORM_FIERCE_DEITY) { if (player->transformation == PLAYER_FORM_FIERCE_DEITY) {
Actor_SetScale(&player->actor, this->unk_1D70 * 1.5f); Actor_SetScale(&player->actor, this->playerScale * 1.5f);
} else { } else {
Actor_SetScale(&player->actor, this->unk_1D70); Actor_SetScale(&player->actor, this->playerScale);
} }
play->envCtx.lightSettings.fogNear = this->unk_1D74; play->envCtx.lightSettings.fogNear = this->fogNear;
if (sp57) { // Switches from the "normal" variation of the arena to the "giant" variation (or vice versa)
sIsInGiantMode = 1 - sIsInGiantMode; // at the appropriate point in the Giant's Mask cutscene.
if (switchArena) {
sIsInGiantMode = true - sIsInGiantMode;
if (!sIsInGiantMode) { if (!sIsInGiantMode) {
sGiantModeScaleFactor = 1.0f; sGiantModeScaleFactor = 1.0f;
} else { } else {
@ -1789,7 +1842,12 @@ void func_809DD934(Boss02* this, PlayState* play) {
} }
this->giantModeScaleFactor = sGiantModeScaleFactor; this->giantModeScaleFactor = sGiantModeScaleFactor;
if (!sIsInGiantMode) { if (!sIsInGiantMode) {
// In this case, the player is switching from the "giant" arena to the "normal" arena.
// The "giant" arena sits 3150 units above the "normal" arena, so this moves the player,
// Twinmold, and the blue warp down and scales their world coordinates upwards to be
// appropriate for the larger arena.
if (sBlueWarp != NULL) { if (sBlueWarp != NULL) {
sBlueWarp->unk_203 = 0; sBlueWarp->unk_203 = 0;
sBlueWarp->unk_204 = 1.0f; sBlueWarp->unk_204 = 1.0f;
@ -1802,6 +1860,10 @@ void func_809DD934(Boss02* this, PlayState* play) {
player->fallStartHeight = player->actor.world.pos.y; player->fallStartHeight = player->actor.world.pos.y;
player->actor.world.pos.z *= 10.0f; player->actor.world.pos.z *= 10.0f;
// If the blue warp exists, and if the player is within 60 units of its center after switching
// to the "normal" arena, this code will move the player to a fixed point next to the blue warp.
// This prevents the player from instantly activating the blue warp after switching arenas, and
// it relies on the blue warp's XZ-coordinates being (0, 0) as they are in Twinmold's boss room.
if ((sBlueWarp != NULL) && ((SQ(player->actor.world.pos.z) + SQ(player->actor.world.pos.x)) < SQ(60.0f))) { if ((sBlueWarp != NULL) && ((SQ(player->actor.world.pos.z) + SQ(player->actor.world.pos.x)) < SQ(60.0f))) {
player->actor.world.pos.z = 60.0f; player->actor.world.pos.z = 60.0f;
player->actor.world.pos.x = 60.0f; player->actor.world.pos.x = 60.0f;
@ -1862,7 +1924,11 @@ void func_809DD934(Boss02* this, PlayState* play) {
sBlueTwinmold->unk_0188.y *= 10.0f; sBlueTwinmold->unk_0188.y *= 10.0f;
} else { } else {
if (sBlueWarp != 0) { // In this case, the player is switching from the "normal" arena to the "giant" arena.
// The "giant" arena sits 3150 units above the "normal" arena, so this moves the player,
// Twinmold, and the blue warp up and scales their world coordinates downwards to be
// appropriate for the smaller arena.
if (sBlueWarp != NULL) {
sBlueWarp->unk_203 = 1; sBlueWarp->unk_203 = 1;
sBlueWarp->unk_204 = 0.1f; sBlueWarp->unk_204 = 0.1f;
sBlueWarp->dyna.actor.world.pos.y = 3155.0f; sBlueWarp->dyna.actor.world.pos.y = 3155.0f;
@ -1932,113 +1998,120 @@ void func_809DD934(Boss02* this, PlayState* play) {
player->actor.home.pos = player->actor.world.pos; player->actor.home.pos = player->actor.world.pos;
player->actor.prevPos = player->actor.world.pos; player->actor.prevPos = player->actor.world.pos;
temp_a0_5 = play->actorCtx.actorLists[ACTORCAT_BG].first; // Kills the existing instance of Twinmold's arena and spawns a new instance with the appropriate
while (temp_a0_5 != NULL) { // scale and at the appropriate height.
if (temp_a0_5->id == ACTOR_BG_INIBS_MOVEBG) { actorIter = play->actorCtx.actorLists[ACTORCAT_BG].first;
Actor_Kill(temp_a0_5); while (actorIter != NULL) {
if (actorIter->id == ACTOR_BG_INIBS_MOVEBG) {
Actor_Kill(actorIter);
break; break;
} }
temp_a0_5 = temp_a0_5->next;
actorIter = actorIter->next;
} }
{ {
f32 tmp = sIsInGiantMode ? 3150.0f : 0.0f; f32 arenaPosY = sIsInGiantMode ? 3150.0f : 0.0f;
Actor_Spawn(&play->actorCtx, play, ACTOR_BG_INIBS_MOVEBG, 0, tmp, 0, 0, 0, 0, sIsInGiantMode); Actor_Spawn(&play->actorCtx, play, ACTOR_BG_INIBS_MOVEBG, 0, arenaPosY, 0, 0, 0, 0, sIsInGiantMode);
} }
temp_a0_5 = play->actorCtx.actorLists[ACTORCAT_BOSS].first; // Moves the props in Twinmold's arena and the Heart Container 3150 units up or down
while (temp_a0_5 != NULL) { // so they're in the appropriate arena and scales them accordingly.
if ((temp_a0_5->id == ACTOR_EN_TANRON5) || (temp_a0_5->id == ACTOR_ITEM_B_HEART)) { actorIter = play->actorCtx.actorLists[ACTORCAT_BOSS].first;
while (actorIter != NULL) {
if ((actorIter->id == ACTOR_EN_TANRON5) || (actorIter->id == ACTOR_ITEM_B_HEART)) {
if (!sIsInGiantMode) { if (!sIsInGiantMode) {
temp_a0_5->world.pos.y -= 3150.0f; actorIter->world.pos.y -= 3150.0f;
temp_a0_5->world.pos.y *= 10.0f; actorIter->world.pos.y *= 10.0f;
temp_a0_5->floorHeight -= 3150.0f; actorIter->floorHeight -= 3150.0f;
temp_a0_5->floorHeight *= 10.0f; actorIter->floorHeight *= 10.0f;
phi_f0_2 = 10.0f; scale = 10.0f;
} else { } else {
temp_a0_5->world.pos.y *= 0.1f; actorIter->world.pos.y *= 0.1f;
temp_a0_5->world.pos.y += 3150.0f; actorIter->world.pos.y += 3150.0f;
temp_a0_5->floorHeight *= 0.1f; actorIter->floorHeight *= 0.1f;
temp_a0_5->floorHeight += 3150.0f; actorIter->floorHeight += 3150.0f;
phi_f0_2 = 0.1f; scale = 0.1f;
} }
temp_a0_5->world.pos.x *= phi_f0_2; actorIter->world.pos.x *= scale;
temp_a0_5->world.pos.z *= phi_f0_2; actorIter->world.pos.z *= scale;
temp_a0_5->speed *= phi_f0_2; actorIter->speed *= scale;
temp_a0_5->velocity.x *= phi_f0_2; actorIter->velocity.x *= scale;
temp_a0_5->velocity.y *= phi_f0_2; actorIter->velocity.y *= scale;
temp_a0_5->velocity.z *= phi_f0_2; actorIter->velocity.z *= scale;
temp_a0_5->gravity *= phi_f0_2; actorIter->gravity *= scale;
temp_a0_5->terminalVelocity *= phi_f0_2; actorIter->terminalVelocity *= scale;
temp_a0_5->scale.x *= phi_f0_2; actorIter->scale.x *= scale;
temp_a0_5->scale.y *= phi_f0_2; actorIter->scale.y *= scale;
temp_a0_5->scale.z *= phi_f0_2; actorIter->scale.z *= scale;
if (temp_a0_5->id == ACTOR_ITEM_B_HEART) { if (actorIter->id == ACTOR_ITEM_B_HEART) {
((ItemBHeart*)temp_a0_5)->baseScale *= phi_f0_2; ((ItemBHeart*)actorIter)->baseScale *= scale;
} }
} }
temp_a0_5 = temp_a0_5->next;
actorIter = actorIter->next;
} }
} }
switch (this->unk_1D78) { switch (this->giantsMaskCsFlashState) {
case 0: case GIANTS_MASK_CS_FLASH_STATE_NOT_STARTED:
break; break;
case 1: case GIANTS_MASK_CS_FLASH_STATE_STARTED:
this->unk_1D7A = 0; this->giantsMaskCsFlashAlpha = 0;
func_809DA1D0(play, 255, 255, 255, 0); Boss02_FillScreen(play, 255, 255, 255, 0);
this->unk_1D78 = 2; this->giantsMaskCsFlashState = GIANTS_MASK_CS_FLASH_STATE_INCREASE_ALPHA;
Audio_PlaySfx(NA_SE_SY_TRANSFORM_MASK_FLASH); Audio_PlaySfx(NA_SE_SY_TRANSFORM_MASK_FLASH);
// fallthrough
case 2: case GIANTS_MASK_CS_FLASH_STATE_INCREASE_ALPHA:
this->unk_1D7A += 40; this->giantsMaskCsFlashAlpha += 40;
if (this->unk_1D7A >= 400) { if (this->giantsMaskCsFlashAlpha >= 400) {
this->unk_1D78 = 3; this->giantsMaskCsFlashState = GIANTS_MASK_CS_FLASH_STATE_DECREASE_ALPHA;
} }
alpha = this->unk_1D7A;
alpha = this->giantsMaskCsFlashAlpha;
alpha = CLAMP_MAX(alpha, 255); alpha = CLAMP_MAX(alpha, 255);
func_809DA22C(play, alpha); Boss02_SetFillScreenAlpha(play, alpha);
break; break;
case 3: case GIANTS_MASK_CS_FLASH_STATE_DECREASE_ALPHA:
this->unk_1D7A -= 40; this->giantsMaskCsFlashAlpha -= 40;
if (this->unk_1D7A <= 0) { if (this->giantsMaskCsFlashAlpha <= 0) {
this->unk_1D7A = 0; this->giantsMaskCsFlashAlpha = 0;
this->unk_1D78 = 0; this->giantsMaskCsFlashState = GIANTS_MASK_CS_FLASH_STATE_NOT_STARTED;
func_809DA24C(play); Boss02_StopFillScreen(play);
} else { } else {
alpha = this->unk_1D7A; alpha = this->giantsMaskCsFlashAlpha;
alpha = CLAMP_MAX(alpha, 255); alpha = CLAMP_MAX(alpha, 255);
func_809DA22C(play, alpha); Boss02_SetFillScreenAlpha(play, alpha);
} }
break; break;
} }
if ((this->unk_1D18 != 0) && (this->subCamId != SUB_CAM_ID_DONE)) { if ((this->giantsMaskCsState != GIANTS_MASK_CS_STATE_WAITING_FOR_MASK) && (this->subCamId != SUB_CAM_ID_DONE)) {
Matrix_RotateYS(player->actor.shape.rot.y, MTXMODE_NEW); Matrix_RotateYS(player->actor.shape.rot.y, MTXMODE_NEW);
Matrix_MultVecZ(this->unk_1D64, &sp58); Matrix_MultVecZ(this->subCamDistZFromPlayer, &subCamEyeOffset);
this->subCamEye.x = player->actor.world.pos.x + sp58.x; this->subCamEye.x = player->actor.world.pos.x + subCamEyeOffset.x;
this->subCamEye.y = player->actor.world.pos.y + sp58.y + this->unk_1D68; this->subCamEye.y = player->actor.world.pos.y + subCamEyeOffset.y + this->subCamEyeOffsetY;
this->subCamEye.z = player->actor.world.pos.z + sp58.z; this->subCamEye.z = player->actor.world.pos.z + subCamEyeOffset.z;
this->subCamAt.x = player->actor.world.pos.x; this->subCamAt.x = player->actor.world.pos.x;
this->subCamAt.y = player->actor.world.pos.y + this->unk_1D6C; this->subCamAt.y = player->actor.world.pos.y + this->subCamAtOffsetY;
this->subCamAt.z = player->actor.world.pos.z; this->subCamAt.z = player->actor.world.pos.z;
this->unk_1D54 = Math_SinS(this->unk_1D14 * 1512) * this->unk_1D58; this->subCamUpRotZ = Math_SinS(this->giantsMaskCsTimer * 1512) * this->subCamUpRotZScale;
Matrix_RotateZF(this->unk_1D54, MTXMODE_APPLY); Matrix_RotateZF(this->subCamUpRotZ, MTXMODE_APPLY);
Matrix_MultVecY(1.0f, &this->subCamUp); Matrix_MultVecY(1.0f, &this->subCamUp);
Play_SetCameraAtEyeUp(play, this->subCamId, &this->subCamAt, &this->subCamEye, &this->subCamUp); Play_SetCameraAtEyeUp(play, this->subCamId, &this->subCamAt, &this->subCamEye, &this->subCamUp);
ShrinkWindow_Letterbox_SetSizeTarget(27); ShrinkWindow_Letterbox_SetSizeTarget(27);
@ -2049,7 +2122,7 @@ void func_809DEAC4(Boss02* this, PlayState* play) {
Player* player = GET_PLAYER(play); Player* player = GET_PLAYER(play);
Boss02* sp68; Boss02* sp68;
Vec3f subCamEye; Vec3f subCamEye;
f32 sp58 = 0.0f; f32 subCamEyeOffset = 0.0f;
this->unk_1D1C++; this->unk_1D1C++;
if (this->unk_0194 == 0) { if (this->unk_0194 == 0) {
@ -2089,7 +2162,7 @@ void func_809DEAC4(Boss02* this, PlayState* play) {
Rumble_Override(0.0f, 50, 200, 1); Rumble_Override(0.0f, 50, 200, 1);
} }
this->unk_0150 += 0x4000; this->unk_0150 += 0x4000;
sp58 = (Math_SinS(this->unk_0150) * (BREG(19) + 5)) * 0.1f; subCamEyeOffset = (Math_SinS(this->unk_0150) * (BREG(19) + 5)) * 0.1f;
Matrix_RotateZF(Math_SinS(this->unk_1D1C * 0x3000) * ((KREG(28) * 0.001f) + 0.017f), MTXMODE_NEW); Matrix_RotateZF(Math_SinS(this->unk_1D1C * 0x3000) * ((KREG(28) * 0.001f) + 0.017f), MTXMODE_NEW);
Matrix_MultVecY(1.0f, &this->subCamUp); Matrix_MultVecY(1.0f, &this->subCamUp);
Audio_PlaySfx_2(NA_SE_EV_EARTHQUAKE_LAST - SFX_FLAG); Audio_PlaySfx_2(NA_SE_EV_EARTHQUAKE_LAST - SFX_FLAG);
@ -2208,8 +2281,8 @@ void func_809DEAC4(Boss02* this, PlayState* play) {
case 103: case 103:
this->unk_0150 += 0x4000; this->unk_0150 += 0x4000;
sp58 = Math_SinS(this->unk_0150); subCamEyeOffset = Math_SinS(this->unk_0150);
sp58 = (sp58 * this->unk_0146[0]) * 1.5f; subCamEyeOffset = (subCamEyeOffset * this->unk_0146[0]) * 1.5f;
if (this->unk_1D1C == 30) { if (this->unk_1D1C == 30) {
func_80169AFC(play, this->subCamId, 0); func_80169AFC(play, this->subCamId, 0);
this->subCamId = SUB_CAM_ID_DONE; this->subCamId = SUB_CAM_ID_DONE;
@ -2248,7 +2321,7 @@ void func_809DEAC4(Boss02* this, PlayState* play) {
if ((this->unk_1D20 != 0) && (this->subCamId != SUB_CAM_ID_DONE)) { if ((this->unk_1D20 != 0) && (this->subCamId != SUB_CAM_ID_DONE)) {
subCamEye = this->subCamEye; subCamEye = this->subCamEye;
subCamEye.y += sp58 * sGiantModeScaleFactor; subCamEye.y += subCamEyeOffset * sGiantModeScaleFactor;
Play_SetCameraAtEyeUp(play, this->subCamId, &this->subCamAt, &subCamEye, &this->subCamUp); Play_SetCameraAtEyeUp(play, this->subCamId, &this->subCamAt, &subCamEye, &this->subCamUp);
this->subCamUp.z = this->subCamUp.x = 0.0f; this->subCamUp.z = this->subCamUp.x = 0.0f;
this->subCamUp.y = 1.0f; this->subCamUp.y = 1.0f;

View File

@ -87,8 +87,8 @@ typedef struct Boss02 {
/* 0x1C28 */ ColliderJntSph colliderSphere2; /* 0x1C28 */ ColliderJntSph colliderSphere2;
/* 0x1C48 */ ColliderJntSphElement colliderSphere2Elements[2]; /* 0x1C48 */ ColliderJntSphElement colliderSphere2Elements[2];
/* 0x1CC8 */ ColliderCylinder colliderCylinder; /* 0x1CC8 */ ColliderCylinder colliderCylinder;
/* 0x1D14 */ u32 unk_1D14; /* 0x1D14 */ u32 giantsMaskCsTimer;
/* 0x1D18 */ s16 unk_1D18; /* 0x1D18 */ s16 giantsMaskCsState;
/* 0x1D1A */ s16 unk_1D1A; /* 0x1D1A */ s16 unk_1D1A;
/* 0x1D1C */ u32 unk_1D1C; /* 0x1D1C */ u32 unk_1D1C;
/* 0x1D20 */ s16 unk_1D20; /* 0x1D20 */ s16 unk_1D20;
@ -97,17 +97,17 @@ typedef struct Boss02 {
/* 0x1D30 */ Vec3f subCamAt; /* 0x1D30 */ Vec3f subCamAt;
/* 0x1D3C */ Vec3f subCamUp; /* 0x1D3C */ Vec3f subCamUp;
/* 0x1D48 */ Vec3f subCamAtNext; /* 0x1D48 */ Vec3f subCamAtNext;
/* 0x1D54 */ f32 unk_1D54; /* 0x1D54 */ f32 subCamUpRotZ;
/* 0x1D58 */ f32 unk_1D58; /* 0x1D58 */ f32 subCamUpRotZScale;
/* 0x1D5C */ f32 subCamAtVel; /* 0x1D5C */ f32 subCamAtVel;
/* 0x1D60 */ UNK_TYPE1 unk1D60[0x4]; /* 0x1D60 */ UNK_TYPE1 unk1D60[0x4];
/* 0x1D64 */ f32 unk_1D64; /* 0x1D64 */ f32 subCamDistZFromPlayer;
/* 0x1D68 */ f32 unk_1D68; /* 0x1D68 */ f32 subCamEyeOffsetY;
/* 0x1D6C */ f32 unk_1D6C; /* 0x1D6C */ f32 subCamAtOffsetY;
/* 0x1D70 */ f32 unk_1D70; /* 0x1D70 */ f32 playerScale;
/* 0x1D74 */ f32 unk_1D74; /* 0x1D74 */ f32 fogNear;
/* 0x1D78 */ u8 unk_1D78; /* 0x1D78 */ u8 giantsMaskCsFlashState;
/* 0x1D7A */ s16 unk_1D7A; /* 0x1D7A */ s16 giantsMaskCsFlashAlpha;
/* 0x1D7C */ s16 unk_1D7C; /* 0x1D7C */ s16 unk_1D7C;
/* 0x1D7E */ s16 unk_1D7E; /* 0x1D7E */ s16 unk_1D7E;
} Boss02; // size = 0x1D80 } Boss02; // size = 0x1D80

View File

@ -9292,9 +9292,9 @@
0x809D6C98:("func_809D6C98",), 0x809D6C98:("func_809D6C98",),
0x809D6E7C:("func_809D6E7C",), 0x809D6E7C:("func_809D6E7C",),
0x809D73D4:("func_809D73D4",), 0x809D73D4:("func_809D73D4",),
0x809DA1D0:("func_809DA1D0",), 0x809DA1D0:("Boss02_FillScreen",),
0x809DA22C:("func_809DA22C",), 0x809DA22C:("Boss02_SetFillScreenAlpha",),
0x809DA24C:("func_809DA24C",), 0x809DA24C:("Boss02_StopFillScreen",),
0x809DA264:("Boss02_SpawnEffectSand",), 0x809DA264:("Boss02_SpawnEffectSand",),
0x809DA344:("Boss02_SpawnEffectFragment",), 0x809DA344:("Boss02_SpawnEffectFragment",),
0x809DA460:("Boss02_SpawnEffectFlash",), 0x809DA460:("Boss02_SpawnEffectFlash",),
@ -9313,7 +9313,7 @@
0x809DD0A8:("Boss02_Static_Draw",), 0x809DD0A8:("Boss02_Static_Draw",),
0x809DD0CC:("Boss02_UpdateEffects",), 0x809DD0CC:("Boss02_UpdateEffects",),
0x809DD2F8:("Boss02_DrawEffects",), 0x809DD2F8:("Boss02_DrawEffects",),
0x809DD934:("func_809DD934",), 0x809DD934:("Boss02_HandleGiantsMaskCutscene",),
0x809DEAC4:("func_809DEAC4",), 0x809DEAC4:("func_809DEAC4",),
0x809E2760:("Boss03_PlayUnderwaterSfx",), 0x809E2760:("Boss03_PlayUnderwaterSfx",),
0x809E2788:("Boss03_SpawnEffectWetSpot",), 0x809E2788:("Boss03_SpawnEffectWetSpot",),

View File

@ -10109,9 +10109,9 @@
0x809DFD34:("D_809DFD34","f32","",0x4), 0x809DFD34:("D_809DFD34","f32","",0x4),
0x809DFD38:("D_809DFD38","f32","",0x4), 0x809DFD38:("D_809DFD38","f32","",0x4),
0x809DFD3C:("D_809DFD3C","f32","",0x4), 0x809DFD3C:("D_809DFD3C","f32","",0x4),
0x809E0420:("D_809E0420","UNK_TYPE1","",0x1), 0x809E0420:("sCanSkipMaskOnCs","UNK_TYPE1","",0x1),
0x809E0421:("D_809E0421","UNK_TYPE1","",0x1), 0x809E0421:("sCanSkipMaskOffCs","UNK_TYPE1","",0x1),
0x809E0422:("D_809E0422","UNK_TYPE1","",0x1), 0x809E0422:("sIsInGiantMode","UNK_TYPE1","",0x1),
0x809E0424:("sRedTwinmold","UNK_TYPE4","",0x4), 0x809E0424:("sRedTwinmold","UNK_TYPE4","",0x4),
0x809E0428:("sBlueTwinmold","UNK_TYPE4","",0x4), 0x809E0428:("sBlueTwinmold","UNK_TYPE4","",0x4),
0x809E042C:("sTwinmoldStatic","UNK_TYPE4","",0x4), 0x809E042C:("sTwinmoldStatic","UNK_TYPE4","",0x4),