diff --git a/README.md b/README.md index 65a6b90e0..1cbe0cd3f 100644 --- a/README.md +++ b/README.md @@ -7,14 +7,21 @@ The Ship does not include assets and as such requires a prior copy of the game t ## Quick Start 1) Download The Ship of Harkinian from Discord. -2) Requires an `oot debug` rom (not Master Quest). +2) Requires a supported copy of the game (See supported games below). +3) Use the OTRGui to generate an `oot.otr` archive file. +4) Launch `soh.exe` + +### Supported Games +Ocarina of Time Debug (not Master Quest) ``` Build team: `zelda@srd022j` Build date: `03-02-21 00:49:18` (year-month-day) sha1: cee6bc3c2a634b41728f2af8da54d9bf8cc14099 ``` -3) Use the OTRGui to generate an `oot.otr` archive file. -4) Launch `soh.exe` +Ocarina of Time Pal Gamecube +``` +sha1: d0c95b2cb3c6682a171db267932af7af8cf5fa82 +``` Congratulations, you are now sailing with the Ship of Harkinian! Have fun! @@ -51,7 +58,7 @@ Official Discord: https://discord.com/invite/BtBmd55HVH ## Building The Ship of Harkinian -Refer to the [building instructions](https://github.com/HarbourMasters/Shipwright/BUILDING.md) to compile SoH. +Refer to the [building instructions](BUILDING.md) to compile SoH. ## Troubleshooting The Exporter - Affirm that you have an `/assets` folder filled with XMLs in the same directory as OTRGui.exe diff --git a/libultraship/libultraship/GameSettings.cpp b/libultraship/libultraship/GameSettings.cpp index 62de92f37..afae642eb 100644 --- a/libultraship/libultraship/GameSettings.cpp +++ b/libultraship/libultraship/GameSettings.cpp @@ -32,7 +32,7 @@ namespace Game { const std::string EnhancementSection = ENHANCEMENTS_SECTION; const std::string CosmeticsSection = COSMETICS_SECTION; const std::string CheatSection = CHEATS_SECTION; - + const std::string LanguagesSection = LANGUAGES_SECTION; void UpdateAudio() { Audio_SetGameVolume(SEQ_BGM_MAIN, CVar_GetFloat("gMainMusicVolume", 1)); diff --git a/libultraship/libultraship/GameSettings.h b/libultraship/libultraship/GameSettings.h index 947689cd5..0cfa38faa 100644 --- a/libultraship/libultraship/GameSettings.h +++ b/libultraship/libultraship/GameSettings.h @@ -34,6 +34,7 @@ enum SeqPlayers { #define ENHANCEMENTS_SECTION "ENHANCEMENT SETTINGS" #define COSMETICS_SECTION "COSMETIC SETTINGS" #define CHEATS_SECTION "CHEATS SETTINGS" +#define LANGUAGES_SECTION "LANGUAGES SETTINGS" namespace Game { extern SoHConfigType Settings; diff --git a/libultraship/libultraship/Lib/Fast3D/U64/PR/ultra64/gbi.h b/libultraship/libultraship/Lib/Fast3D/U64/PR/ultra64/gbi.h index 8af624e8f..dedc97939 100644 --- a/libultraship/libultraship/Lib/Fast3D/U64/PR/ultra64/gbi.h +++ b/libultraship/libultraship/Lib/Fast3D/U64/PR/ultra64/gbi.h @@ -4575,6 +4575,20 @@ _DW({ \ _g2->words.w1 = (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)); \ } +# define gsSPWideTextureRectangle(xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \ +{{ \ + (_SHIFTL(G_TEXRECT_WIDE, 24, 8) | _SHIFTL((xh), 0, 24)), \ + _SHIFTL((yh), 0, 24), \ +}}, \ +{{ \ + (_SHIFTL((tile), 24, 3) | _SHIFTL((xl), 0, 24)), \ + _SHIFTL((yl), 0, 24), \ +}}, \ +{{ \ + _SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16), \ + _SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16) \ +}} + /* like gSPTextureRectangle but accepts negative position arguments */ #define gSPScisTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \ _DW({ \ diff --git a/libultraship/libultraship/SohImGuiImpl.cpp b/libultraship/libultraship/SohImGuiImpl.cpp index f174cbf20..af9252927 100644 --- a/libultraship/libultraship/SohImGuiImpl.cpp +++ b/libultraship/libultraship/SohImGuiImpl.cpp @@ -56,6 +56,7 @@ namespace SohImGui { Console* console = new Console; bool p_open = false; bool needs_save = false; + int SelectedLanguage = CVar_GetS32("gLanguages", 0); //Default Language to 0=English 1=German 2=French int SelectedHUD = CVar_GetS32("gHudColors", 1); //Default colors to Gamecube. float hearts_colors[3] = {0,0,0}; float hearts_dd_colors[3] = {0,0,0}; @@ -384,6 +385,24 @@ namespace SohImGui { } } + void EnhancementRadioButton(std::string text, std::string cvarName, int id) { + /*Usage : + EnhancementRadioButton("My Visible Name","gMyCVarName", MyID); + First arg is the visible name of the Radio button + Second is the cvar name where MyID will be saved. + Note: the CVar name should be the same to each Buddies. + Example : + EnhancementRadioButton("English", "gLanguages", 0); + EnhancementRadioButton("German", "gLanguages", 1); + EnhancementRadioButton("French", "gLanguages", 2); + */ + int val = CVar_GetS32(cvarName.c_str(), 0); + if (ImGui::RadioButton(text.c_str(), id==val)) { + CVar_SetS32(cvarName.c_str(), (int)id); + needs_save = true; + } + } + void EnhancementCheckbox(std::string text, std::string cvarName) { bool val = (bool)CVar_GetS32(cvarName.c_str(), 0); @@ -576,6 +595,7 @@ namespace SohImGui { ImGui::Separator(); EnhancementSliderInt("Text Speed: %dx", "##TEXTSPEED", "gTextSpeed", 1, 5, ""); + EnhancementSliderInt("King Zora Speed: %dx", "##WEEPSPEED", "gMweepSpeed", 1, 5, ""); EnhancementCheckbox("Skip Text", "gSkipText"); EnhancementCheckbox("Minimal UI", "gMinimalUI"); @@ -591,7 +611,13 @@ namespace SohImGui { EnhancementCheckbox("Disable LOD", "gDisableLOD"); EnhancementCheckbox("Enable 3D Dropped items", "gNewDrops"); EnhancementCheckbox("Dynamic Wallet Icon", "gDynamicWalletIcon"); - + EnhancementCheckbox("Always show dungeon entrances", "gAlwaysShowDungeonMinimapIcon"); + + if (ImGui::BeginMenu("Fixes")) { + EnhancementCheckbox("Fix L&R Pause menu", "gUniformLR"); + EnhancementCheckbox("Fix Dungeon entrances", "gFixDungeonMinimapIcon"); + ImGui::EndMenu(); + } ImGui::EndMenu(); } @@ -634,7 +660,40 @@ namespace SohImGui { EnhancementCheckbox("Unrestricted Items", "gNoRestrictItems"); EnhancementCheckbox("Freeze Time", "gFreezeTime"); + + if (ImGui::Checkbox("Climb Everything", &Game::Settings.cheats.climb_everything)) { + CVar_SetS32("gClimbEverything", Game::Settings.cheats.climb_everything); + needs_save = true; + } + + if (ImGui::Checkbox("Moon Jump on L", &Game::Settings.cheats.moon_jump_on_l)) { + CVar_SetS32("gMoonJumpOnL", Game::Settings.cheats.moon_jump_on_l); + needs_save = true; + } + + if (ImGui::Checkbox("Super Tunic", &Game::Settings.cheats.super_tunic)) { + CVar_SetS32("gSuperTunic", Game::Settings.cheats.super_tunic); + needs_save = true; + } + + if (ImGui::Checkbox("Easy ISG", &Game::Settings.cheats.ez_isg)) { + CVar_SetS32("gEzISG", Game::Settings.cheats.ez_isg); + needs_save = true; + } + + if (ImGui::Checkbox("Unrestricted Items", &Game::Settings.cheats.no_restrict_item)) { + CVar_SetS32("gNoRestrictItem", Game::Settings.cheats.no_restrict_item); + needs_save = true; + } + + if (ImGui::Checkbox("Freeze Time", &Game::Settings.cheats.freeze_time)) { + CVar_SetS32("gFreezeTime", Game::Settings.cheats.freeze_time); + needs_save = true; + } + + ImGui::EndMenu(); + } if (CVar_GetS32("gHudColors", 1) ==0) { @@ -715,6 +774,20 @@ namespace SohImGui { ImGui::PopStyleColor(); } + if (CVar_GetS32("gLanguages", 0) == 0) { + SelectedLanguage = 0; + } else if (CVar_GetS32("gLanguages", 0) == 1) { + SelectedLanguage = 1; + } else if (CVar_GetS32("gLanguages", 0) == 2) { + SelectedLanguage = 2; + } + if (ImGui::BeginMenu("Languages")) { + EnhancementRadioButton("English", "gLanguages", 0); + EnhancementRadioButton("German", "gLanguages", 1); + EnhancementRadioButton("French", "gLanguages", 2); + ImGui::EndMenu(); + } + for (const auto& category : windowCategories) { if (ImGui::BeginMenu(category.first.c_str())) { for (const std::string& name : category.second) { diff --git a/libultraship/libultraship/SohImGuiImpl.h b/libultraship/libultraship/SohImGuiImpl.h index 2e7aa773c..64e804570 100644 --- a/libultraship/libultraship/SohImGuiImpl.h +++ b/libultraship/libultraship/SohImGuiImpl.h @@ -63,6 +63,7 @@ namespace SohImGui { void EnhancementColorEdit3(std::string text, std::string cvarName, float ColorRGB[3]); int ClampFloatToInt(float value, int min, int max); + void EnhancementRadioButton(std::string text, std::string cvarName, int value); void EnhancementCheckbox(std::string text, std::string cvarName); void EnhancementSliderInt(std::string text, std::string id, std::string cvarName, int min, int max, std::string format); void EnhancementSliderFloat(std::string text, std::string id, std::string cvarName, float min, float max, std::string format, float defaultValue); diff --git a/soh/include/functions.h b/soh/include/functions.h index 01901d5d0..7d368edb6 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -381,7 +381,7 @@ void Flags_UnsetTempClear(GlobalContext* globalCtx, s32 flag); s32 Flags_GetCollectible(GlobalContext* globalCtx, s32 flag); void Flags_SetCollectible(GlobalContext* globalCtx, s32 flag); void TitleCard_InitBossName(GlobalContext* globalCtx, TitleCardContext* titleCtx, void* texture, s16 x, s16 y, u8 width, - u8 height); + u8 height, s16 hastranslation); void TitleCard_InitPlaceName(GlobalContext* globalCtx, TitleCardContext* titleCtx, void* texture, s32 x, s32 y, s32 width, s32 height, s32 delay); s32 func_8002D53C(GlobalContext* globalCtx, TitleCardContext* titleCtx); diff --git a/soh/include/z64.h b/soh/include/z64.h index f0dfba52d..103c8650f 100644 --- a/soh/include/z64.h +++ b/soh/include/z64.h @@ -251,6 +251,8 @@ typedef struct { /* 0x0B */ u8 delayTimer; // how long the title card waits to appear /* 0x0C */ s16 alpha; /* 0x0E */ s16 intensity; + /* ---- */ s16 isBossCard; //To detect if that a Boss name title card. + /* ---- */ s16 hasTranslation; // to detect if the current title card has translation (used for bosses only) } TitleCardContext; // size = 0x10 typedef struct { diff --git a/soh/soh/Enhancements/bootcommands.c b/soh/soh/Enhancements/bootcommands.c index 71404d20c..7411c751e 100644 --- a/soh/soh/Enhancements/bootcommands.c +++ b/soh/soh/Enhancements/bootcommands.c @@ -30,6 +30,7 @@ void BootCommands_Init() CVar_RegisterS32("gNewDrops", 0); CVar_RegisterS32("gVisualAgony", 0); CVar_RegisterS32("gHudColors", 1); //0 N64 colors/1 Gamecube colors/2 Custom colors + CVar_RegisterS32("gLanguages", 0); //0 = English / 1 = German / 2 = French } //void BootCommands_ParseBootArgs(char* str) diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index d2bc941cf..aad82be29 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -289,6 +289,13 @@ extern "C" Gfx* ResourceMgr_LoadGfxByName(const char* path) return (Gfx*)&res->instructions[0]; } +extern "C" Gfx* ResourceMgr_PatchGfxByName(const char* path, int size) { + auto res = std::static_pointer_cast( + OTRGlobals::Instance->context->GetResourceManager()->LoadResource(path)); + res->instructions.resize(res->instructions.size() + size); + return (Gfx*)&res->instructions[0]; +} + extern "C" char* ResourceMgr_LoadArrayByName(const char* path) { auto res = std::static_pointer_cast(OTRGlobals::Instance->context->GetResourceManager()->LoadResource(path)); diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index 7ce08649a..339613b25 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -38,6 +38,7 @@ char* ResourceMgr_LoadPlayerAnimByName(const char* animPath); char* ResourceMgr_GetNameByCRC(uint64_t crc, char* alloc); Gfx* ResourceMgr_LoadGfxByCRC(uint64_t crc); Gfx* ResourceMgr_LoadGfxByName(const char* path); +Gfx* ResourceMgr_PatchGfxByName(const char* path, int size); Vtx* ResourceMgr_LoadVtxByCRC(uint64_t crc); Vtx* ResourceMgr_LoadVtxByName(const char* path); CollisionHeader* ResourceMgr_LoadColByName(const char* path); diff --git a/soh/src/code/game.c b/soh/src/code/game.c index b69537fd8..a411523ec 100644 --- a/soh/src/code/game.c +++ b/soh/src/code/game.c @@ -421,8 +421,12 @@ void GameState_Update(GameState* gameState) { int32_t prevTime = CVar_GetS32("gPrevTime", gSaveContext.dayTime); gSaveContext.dayTime = prevTime; + } else { + CVar_SetS32("gPrevTime", -1); } - + + //since our CVar is same value and properly default to 0 there is not problems doing this in single line. + gSaveContext.language = CVar_GetS32("gLanguages", 0); gameState->frames++; } diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index a11184dde..052582f0f 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -758,12 +758,14 @@ void func_8002CDE4(GlobalContext* globalCtx, TitleCardContext* titleCtx) { } void TitleCard_InitBossName(GlobalContext* globalCtx, TitleCardContext* titleCtx, void* texture, s16 x, s16 y, u8 width, - u8 height) { + u8 height, s16 hasTranslation) { if (ResourceMgr_OTRSigCheck(texture)) texture = ResourceMgr_LoadTexByName(texture); titleCtx->texture = texture; + titleCtx->isBossCard = true; + titleCtx->hasTranslation = hasTranslation; titleCtx->x = x; titleCtx->y = y; titleCtx->width = width; @@ -957,7 +959,7 @@ void TitleCard_InitPlaceName(GlobalContext* globalCtx, TitleCardContext* titleCt default: titleCtx->texture = NULL; return; - + } char newName[512]; @@ -981,6 +983,8 @@ void TitleCard_InitPlaceName(GlobalContext* globalCtx, TitleCardContext* titleCt titleCtx->texture = ResourceMgr_LoadTexByName(texture); //titleCtx->texture = texture; + titleCtx->isBossCard = false; + titleCtx->hasTranslation = false; titleCtx->x = x; titleCtx->y = y; titleCtx->width = width; @@ -1009,6 +1013,9 @@ void TitleCard_Draw(GlobalContext* globalCtx, TitleCardContext* titleCtx) { s32 doubleWidth; s32 titleY; s32 titleSecondY; + s32 textureLanguageOffset; + s32 shiftTopY; + s32 shiftBottomY; if (titleCtx->alpha != 0) { width = titleCtx->width; @@ -1022,31 +1029,48 @@ void TitleCard_Draw(GlobalContext* globalCtx, TitleCardContext* titleCtx) { height = (width * height > 0x1000) ? 0x1000 / width : height; titleSecondY = titleY + (height * 4); + textureLanguageOffset = 0x0; + shiftTopY = 0x0; + shiftBottomY = 0x1000; + + //if this card is bosses cards, has translation and that is not using English language. + if (titleCtx->isBossCard == 1 && titleCtx->hasTranslation == 1 && gSaveContext.language != LANGUAGE_ENG) { + if (gSaveContext.language == LANGUAGE_GER) { + textureLanguageOffset = (width * height * gSaveContext.language); + shiftTopY = 0x400; + shiftBottomY = 0x1400; + } else if (gSaveContext.language == LANGUAGE_FRA) { + textureLanguageOffset = (width * height * gSaveContext.language); + shiftTopY = 0x800; + shiftBottomY = 0x1800; + } + } + // WORLD_OVERLAY_DISP Goes over POLY_XLU_DISP but under POLY_KAL_DISP WORLD_OVERLAY_DISP = func_80093808(WORLD_OVERLAY_DISP); gDPSetPrimColor(WORLD_OVERLAY_DISP++, 0, 0, (u8)titleCtx->intensity, (u8)titleCtx->intensity, (u8)titleCtx->intensity, (u8)titleCtx->alpha); - gDPLoadTextureBlock(WORLD_OVERLAY_DISP++, (uintptr_t)titleCtx->texture, G_IM_FMT_IA, + gDPLoadTextureBlock(WORLD_OVERLAY_DISP++, (uintptr_t)titleCtx->texture + textureLanguageOffset + shiftBottomY, G_IM_FMT_IA, G_IM_SIZ_8b, width, height, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - - gSPTextureRectangle(WORLD_OVERLAY_DISP++, titleX, titleY, ((doubleWidth * 2) + titleX) - 4, titleY + (height * 4) - 1, + //Removing the -1 there remove the gap between top and bottom textures. + gSPTextureRectangle(WORLD_OVERLAY_DISP++, titleX, titleY, ((doubleWidth * 2) + titleX) - 4, titleY + (height * 4), G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); height = titleCtx->height - height; // If texture is bigger than 0x1000, display the rest if (height > 0) { - gDPLoadTextureBlock(WORLD_OVERLAY_DISP++, (uintptr_t)titleCtx->texture + 0x1000, + gDPLoadTextureBlock(WORLD_OVERLAY_DISP++, (uintptr_t)titleCtx->texture + textureLanguageOffset + shiftBottomY, G_IM_FMT_IA, G_IM_SIZ_8b, width, height, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - + //Removing the -1 there remove the gap between top and bottom textures. gSPTextureRectangle(WORLD_OVERLAY_DISP++, titleX, titleSecondY, ((doubleWidth * 2) + titleX) - 4, - titleSecondY + (height * 4) - 1, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); + titleSecondY + (height * 4), G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); } CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_actor.c", 2880); @@ -1122,7 +1146,7 @@ void Actor_Init(Actor* actor, GlobalContext* globalCtx) { CollisionCheck_InitInfo(&actor->colChkInfo); actor->floorBgId = BGCHECK_SCENE; ActorShape_Init(&actor->shape, 0.0f, NULL, 0.0f); - //if (Object_IsLoaded(&globalCtx->objectCtx, actor->objBankIndex)) + //if (Object_IsLoaded(&globalCtx->objectCtx, actor->objBankIndex)) { //Actor_SetObjectDependency(globalCtx, actor); actor->init(actor, globalCtx); @@ -2358,7 +2382,7 @@ void Actor_UpdateAll(GlobalContext* globalCtx, ActorContext* actorCtx) { actor->sfx = 0; if (actor->init != NULL) { - if (Object_IsLoaded(&globalCtx->objectCtx, actor->objBankIndex)) + if (Object_IsLoaded(&globalCtx->objectCtx, actor->objBankIndex)) { Actor_SetObjectDependency(globalCtx, actor); actor->init(actor, globalCtx); @@ -2547,10 +2571,16 @@ void func_80030FA8(GraphicsContext* gfxCtx) { gDPLoadTextureBlock(POLY_XLU_DISP++, gLensOfTruthMaskTex, G_IM_FMT_I, G_IM_SIZ_8b, 64, 64, 0, G_TX_MIRROR | G_TX_CLAMP, G_TX_MIRROR | G_TX_CLAMP, 6, 6, G_TX_NOLOD, G_TX_NOLOD); - gDPSetTileSize(POLY_XLU_DISP++, G_TX_RENDERTILE, 384, 224, 892, 732); - gSPTextureRectangle(POLY_XLU_DISP++, 0, 0, 1280, 960, G_TX_RENDERTILE, 2240, 1600, 576, 597); - gDPPipeSync(POLY_XLU_DISP++); + s32 x = OTRGetRectDimensionFromLeftEdge(0) << 2; + s32 w = OTRGetRectDimensionFromRightEdge(SCREEN_WIDTH) << 2; + float ratio = OTRGetAspectRatio(); + + gDPSetTileSize(POLY_XLU_DISP++, G_TX_RENDERTILE, 384, 224, 892, 732); + // TODO: Do correct math to fix it + gSPWideTextureRectangle(POLY_XLU_DISP++, x, 0, x + abs(x), 960, G_TX_RENDERTILE, 0, 0, 0, 0); + gSPWideTextureRectangle(POLY_XLU_DISP++, 0, 0, w, 960, G_TX_RENDERTILE, 2240, 1600, 576, 597); + gDPPipeSync(POLY_XLU_DISP++); CLOSE_DISPS(gfxCtx, "../z_actor.c", 6183); } @@ -2894,7 +2924,7 @@ void Actor_FreeOverlay(ActorOverlay* actorOverlay) { osSyncPrintf(VT_FGCOL(CYAN)); if (actorOverlay->numLoaded == 0) { - + if (actorOverlay->initInfo->reset != NULL) { actorOverlay->initInfo->reset(); } @@ -3020,7 +3050,7 @@ Actor* Actor_Spawn(ActorContext* actorCtx, GlobalContext* globalCtx, s16 actorId if (objBankIndex < 0 && !gMapLoading) objBankIndex = 0; - + if ((objBankIndex < 0) || ((actorInit->category == ACTORCAT_ENEMY) && Flags_GetClear(globalCtx, globalCtx->roomCtx.curRoom.num))) { // "No data bank!! (profilep->bank=%d)" diff --git a/soh/src/code/z_fbdemo_circle.c b/soh/src/code/z_fbdemo_circle.c index b19948737..a6a46a0e4 100644 --- a/soh/src/code/z_fbdemo_circle.c +++ b/soh/src/code/z_fbdemo_circle.c @@ -145,8 +145,6 @@ void TransitionCircle_Draw(void* thisx, Gfx** gfxP) { modelView = this->modelView[this->frame]; - this->color.rgba = 0xFFFFFFFF; - this->frame ^= 1; gDPPipeSync(gfx++); texScroll = Gfx_BranchTexScroll(&gfx, this->texX, this->texY, 0x10, 0x40); diff --git a/soh/src/code/z_kankyo.c b/soh/src/code/z_kankyo.c index f3ac083ab..9f7518374 100644 --- a/soh/src/code/z_kankyo.c +++ b/soh/src/code/z_kankyo.c @@ -743,7 +743,7 @@ void Environment_UpdateSkybox(GlobalContext* globalCtx, u8 skyboxId, Environment if (envCtx->skyboxDmaState == SKYBOX_DMA_FILE2_DONE) { envCtx->skyboxDmaState = SKYBOX_DMA_PAL2_START; - if ((newSkybox2Index & 1) ^ ((newSkybox2Index & 4) >> 2)) + if ((newSkybox2Index & 1) ^ ((newSkybox2Index & 4) >> 2)) { SkyboxTableEntry entryA = sSkyboxTable[newSkybox2Index]; LoadSkyboxPalette(skyboxCtx, 0, entryA.palettes[0], 16, 8); @@ -753,7 +753,7 @@ void Environment_UpdateSkybox(GlobalContext* globalCtx, u8 skyboxId, Environment DmaMgr_SendRequest2(&envCtx->dmaRequest, (uintptr_t)skyboxCtx->palettes, gSkyboxFiles[newSkybox2Index].palette.vromStart, size, 0, &envCtx->loadQueue, NULL, "../z_kankyo.c", 1342);*/ - } else + } else { SkyboxTableEntry entryA = sSkyboxTable[newSkybox2Index]; LoadSkyboxPalette(skyboxCtx, 1, entryA.palettes[0], 16, 8); @@ -769,12 +769,12 @@ void Environment_UpdateSkybox(GlobalContext* globalCtx, u8 skyboxId, Environment } if ((envCtx->skyboxDmaState == SKYBOX_DMA_FILE1_START) || (envCtx->skyboxDmaState == SKYBOX_DMA_FILE2_START)) { - //if (osRecvMesg(&envCtx->loadQueue, 0, OS_MESG_NOBLOCK) == 0) + //if (osRecvMesg(&envCtx->loadQueue, 0, OS_MESG_NOBLOCK) == 0) { envCtx->skyboxDmaState++; } } else if (envCtx->skyboxDmaState >= SKYBOX_DMA_FILE1_DONE) { - //if (osRecvMesg(&envCtx->loadQueue, 0, OS_MESG_NOBLOCK) == 0) + //if (osRecvMesg(&envCtx->loadQueue, 0, OS_MESG_NOBLOCK) == 0) { envCtx->skyboxDmaState = SKYBOX_DMA_INACTIVE; } @@ -2275,6 +2275,29 @@ Color_RGB8 sSandstormEnvColors[] = { { 50, 40, 0 }, }; +Gfx* gFieldSandstormDL_Custom = NULL; + +void Environment_PatchSandstorm(GlobalContext* globalCtx) { + if (gFieldSandstormDL_Custom) return; + + gFieldSandstormDL_Custom = ResourceMgr_PatchGfxByName(gFieldSandstormDL, -3); + + const Gfx gFSPatchDL[2] = { gsSPEndDisplayList() }; + bool patched = false; + Gfx* cmd = gFieldSandstormDL_Custom; + int id = 0; + + while (!patched) { + const uint32_t opcode = cmd->words.w0 >> 24; + if (opcode == G_TEXRECT) { + gFieldSandstormDL_Custom[id] = gFSPatchDL[0]; + patched = true; + } + ++cmd; + id++; + } +} + void Environment_DrawSandstorm(GlobalContext* globalCtx, u8 sandstormState) { s32 primA1; s32 envA1; @@ -2288,6 +2311,8 @@ void Environment_DrawSandstorm(GlobalContext* globalCtx, u8 sandstormState) { u16 sp94; u16 sp92; + Environment_PatchSandstorm(globalCtx); + switch (sandstormState) { case 3: if ((globalCtx->sceneNum == SCENE_SPOT13) && (globalCtx->roomCtx.curRoom.num == 0)) { @@ -2394,8 +2419,11 @@ void Environment_DrawSandstorm(GlobalContext* globalCtx, u8 sandstormState) { Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, (u32)sp96 % 0x1000, 0, 0x200, 0x20, 1, (u32)sp94 % 0x1000, 0xFFF - ((u32)sp92 % 0x1000), 0x100, 0x40)); gDPSetTextureLUT(POLY_XLU_DISP++, G_TT_NONE); - gSPDisplayList(POLY_XLU_DISP++, gFieldSandstormDL); + gSPDisplayList(POLY_XLU_DISP++, gFieldSandstormDL_Custom); + gSPWideTextureRectangle(POLY_XLU_DISP++, OTRGetRectDimensionFromLeftEdge(0) << 2, 0, + OTRGetRectDimensionFromRightEdge(SCREEN_WIDTH) << 2, 0x03C0, G_TX_RENDERTILE, 0, 0, 0x008C, + -0x008C); CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_kankyo.c", 4068); D_8015FDB0 += (s32)sp98; diff --git a/soh/src/code/z_map_exp.c b/soh/src/code/z_map_exp.c index aa01bcaf4..45ba8a00a 100644 --- a/soh/src/code/z_map_exp.c +++ b/soh/src/code/z_map_exp.c @@ -775,17 +775,16 @@ void Minimap_Draw(GlobalContext* globalCtx) { IconSize, IconSize, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); gSPWideTextureRectangle(OVERLAY_DISP++, TopLeftX, TopLeftY, TopLeftW, TopLeftH, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); - } + } } - - if ((globalCtx->sceneNum == SCENE_SPOT08) && (gSaveContext.infTable[26] & gBitFlags[9])) { + if ((globalCtx->sceneNum == SCENE_SPOT08) && (gSaveContext.infTable[26] & gBitFlags[9])) { gDPLoadTextureBlock(OVERLAY_DISP++, gMapDungeonEntranceIconTex, G_IM_FMT_RGBA, G_IM_SIZ_16b, 8, 8, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - const s16 entranceX = OTRGetRectDimensionFromRightEdge(270); + const s16 entranceX = OTRGetRectDimensionFromRightEdge(270); - gSPWideTextureRectangle(OVERLAY_DISP++, entranceX << 2, 154 << 2, (entranceX + 32) << 2, (154 + 8) << 2, + gSPWideTextureRectangle(OVERLAY_DISP++, entranceX << 2, 154 << 2, (entranceX + 32) << 2, (154 + 8) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); } diff --git a/soh/src/code/z_room.c b/soh/src/code/z_room.c index 93aab731f..5212799a6 100644 --- a/soh/src/code/z_room.c +++ b/soh/src/code/z_room.c @@ -126,7 +126,7 @@ void func_80095D04(GlobalContext* globalCtx, Room* room, u32 flags) { sp90.y = polygonDlist->pos.y; sp90.z = polygonDlist->pos.z; SkinMatrix_Vec3fMtxFMultXYZW(&globalCtx->viewProjectionMtxF, &sp90, &sp84, &sp80); - if (-(f32)polygonDlist->unk_06 < sp84.z) + if (-(f32)polygonDlist->unk_06 < sp84.z) { temp_f2 = sp84.z - polygonDlist->unk_06; if (temp_f2 < globalCtx->lightCtx.fogFar) { @@ -171,7 +171,7 @@ void func_80095D04(GlobalContext* globalCtx, Room* room, u32 flags) { Gfx* temp2; polygonDlist = spB4->unk_00; - if (iREG(86) != 0) + if (iREG(86) != 0) { temp = sp78; for (phi_v1 = 0; phi_v1 < polygon2->num; phi_v1++, temp++) { @@ -180,7 +180,7 @@ void func_80095D04(GlobalContext* globalCtx, Room* room, u32 flags) { } } - if (((iREG(86) == 1) && (iREG(89) >= sp9C)) || ((iREG(86) == 2) && (iREG(89) == sp9C))) + if (((iREG(86) == 1) && (iREG(89) >= sp9C)) || ((iREG(86) == 2) && (iREG(89) == sp9C))) { if (flags & 1) { temp2 = polygonDlist->opa; @@ -224,7 +224,7 @@ void func_80095D04(GlobalContext* globalCtx, Room* room, u32 flags) { s32 func_80096238(void* data) { OSTime time; - if (*(u32*)data == JPEG_MARKER) + if (*(u32*)data == JPEG_MARKER) { char* decodedJpeg = ResourceMgr_LoadJPEG(data, 320 * 240 * 2); //char* decodedJpeg = ResourceMgr_LoadJPEG(data, 480 * 240 * 2); @@ -235,8 +235,8 @@ s32 func_80096238(void* data) { osSyncPrintf("ワークバッファアドレス(Zバッファ)%08x\n", gZBuffer); time = osGetTime(); - - //if (!Jpeg_Decode(data, gZBuffer, gGfxSPTaskOutputBuffer, sizeof(gGfxSPTaskOutputBuffer))) + + //if (!Jpeg_Decode(data, gZBuffer, gGfxSPTaskOutputBuffer, sizeof(gGfxSPTaskOutputBuffer))) if (1) { memcpy(data, decodedJpeg, 320 * 240 * 2); @@ -294,14 +294,17 @@ void func_8009638C(Gfx** displayList, void* source, void* tlut, u16 width, u16 h bg->b.frameW = width * 4; bg->b.frameH = height * 4; guS2DInitBg(bg); - - gDPSetOtherMode(displayListHead++, mode0 | G_TL_TILE | G_TD_CLAMP | G_TP_NONE | G_CYC_COPY | G_PM_NPRIMITIVE, + + gDPSetOtherMode(displayListHead++, mode0 | G_TL_TILE | G_TD_CLAMP | G_TP_NONE | G_CYC_FILL | G_PM_NPRIMITIVE, G_AC_THRESHOLD | G_ZS_PIXEL | G_RM_NOOP | G_RM_NOOP2); gDPSetFillColor(displayListHead++, GPACK_RGBA5551(0, 0, 0, 1) << 16 | GPACK_RGBA5551(0, 0, 0, 1)); gDPFillWideRectangle(displayListHead++, OTRGetRectDimensionFromLeftEdge(0), 0, OTRGetRectDimensionFromRightEdge(SCREEN_WIDTH), SCREEN_HEIGHT); + gDPSetOtherMode(displayListHead++, mode0 | G_TL_TILE | G_TD_CLAMP | G_TP_NONE | G_CYC_COPY | G_PM_NPRIMITIVE, + G_AC_THRESHOLD | G_ZS_PIXEL | G_RM_NOOP | G_RM_NOOP2); + gDPLoadMultiTile(displayListHead++, bg->b.imagePtr, 0, G_TX_RENDERTILE, G_IM_FMT_RGBA, G_IM_SIZ_16b, 320, 0, 0, 0, 0 + 31, 0 + 31, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, diff --git a/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c b/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c index 3b130b229..fa4d06b05 100644 --- a/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c +++ b/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c @@ -418,7 +418,7 @@ void BossDodongo_IntroCutscene(BossDodongo* this, GlobalContext* globalCtx) { if (this->unk_198 == 0x5A) { if (!(gSaveContext.eventChkInf[7] & 2)) { TitleCard_InitBossName(globalCtx, &globalCtx->actorCtx.titleCtx, - SEGMENTED_TO_VIRTUAL(gKingDodongoTitleCardTex), 0xA0, 0xB4, 0x80, 0x28); + SEGMENTED_TO_VIRTUAL(gKingDodongoTitleCardTex), 160, 180, 128, 40, true); } Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_FIRE_BOSS); } diff --git a/soh/src/overlays/actors/ovl_Boss_Fd/z_boss_fd.c b/soh/src/overlays/actors/ovl_Boss_Fd/z_boss_fd.c index 6553b3c11..649774346 100644 --- a/soh/src/overlays/actors/ovl_Boss_Fd/z_boss_fd.c +++ b/soh/src/overlays/actors/ovl_Boss_Fd/z_boss_fd.c @@ -493,7 +493,7 @@ void BossFd_Fly(BossFd* this, GlobalContext* globalCtx) { } if ((this->timers[3] == 130) && !(gSaveContext.eventChkInf[7] & 8)) { TitleCard_InitBossName(globalCtx, &globalCtx->actorCtx.titleCtx, - SEGMENTED_TO_VIRTUAL(gVolvagiaBossTitleCardTex), 0xA0, 0xB4, 0x80, 0x28); + SEGMENTED_TO_VIRTUAL(gVolvagiaBossTitleCardTex), 160, 180, 128, 40, true); } if (this->timers[3] <= 100) { this->camData.eyeVel.x = this->camData.eyeVel.y = this->camData.eyeVel.z = 2.0f; diff --git a/soh/src/overlays/actors/ovl_Boss_Ganon/z_boss_ganon.c b/soh/src/overlays/actors/ovl_Boss_Ganon/z_boss_ganon.c index c5c19f864..e4a5afc65 100644 --- a/soh/src/overlays/actors/ovl_Boss_Ganon/z_boss_ganon.c +++ b/soh/src/overlays/actors/ovl_Boss_Ganon/z_boss_ganon.c @@ -1088,7 +1088,7 @@ void BossGanon_IntroCutscene(BossGanon* this, GlobalContext* globalCtx) { if (!(gSaveContext.eventChkInf[7] & 0x100)) { TitleCard_InitBossName(globalCtx, &globalCtx->actorCtx.titleCtx, - SEGMENTED_TO_VIRTUAL(gDorfTitleCardTex), 160, 180, 128, 40); + SEGMENTED_TO_VIRTUAL(gDorfTitleCardTex), 160, 180, 128, 40, false); } gSaveContext.eventChkInf[7] |= 0x100; @@ -5044,4 +5044,4 @@ static EnGanonMant* sCape; memset(sEffectBuf, 0, sizeof(sEffectBuf)); -} \ No newline at end of file +} diff --git a/soh/src/overlays/actors/ovl_Boss_Ganon2/z_boss_ganon2.c b/soh/src/overlays/actors/ovl_Boss_Ganon2/z_boss_ganon2.c index 74da86927..21fd1a149 100644 --- a/soh/src/overlays/actors/ovl_Boss_Ganon2/z_boss_ganon2.c +++ b/soh/src/overlays/actors/ovl_Boss_Ganon2/z_boss_ganon2.c @@ -671,7 +671,8 @@ void func_808FD5F4(BossGanon2* this, GlobalContext* globalCtx) { if (this->unk_398 == 80) { BossGanon2_SetObjectSegment(this, globalCtx, OBJECT_GANON2, false); TitleCard_InitBossName(globalCtx, &globalCtx->actorCtx.titleCtx, - SEGMENTED_TO_VIRTUAL(object_ganon2_Tex_021A90), 160, 180, 128, 40); + SEGMENTED_TO_VIRTUAL(object_ganon2_Tex_021A90), 160, 180, 128, 40, true); + //It has translation but they are all the same. they all say "GANON" only } this->unk_3A4.x = ((this->actor.world.pos.x + 500.0f) - 350.0f) + 100.0f; this->unk_3A4.y = this->actor.world.pos.y; @@ -3087,4 +3088,4 @@ void BossGanon2_Reset(void) { memset(D_809105D8, 0, sizeof(D_809105D8)); memset(D_80910608, 0, sizeof(D_80910608)); memset(sParticles, 0, sizeof(sParticles)); -} \ No newline at end of file +} diff --git a/soh/src/overlays/actors/ovl_Boss_Goma/z_boss_goma.c b/soh/src/overlays/actors/ovl_Boss_Goma/z_boss_goma.c index ad8e4537d..d84cf4a74 100644 --- a/soh/src/overlays/actors/ovl_Boss_Goma/z_boss_goma.c +++ b/soh/src/overlays/actors/ovl_Boss_Goma/z_boss_goma.c @@ -926,7 +926,7 @@ void BossGoma_Encounter(BossGoma* this, GlobalContext* globalCtx) { if (!(gSaveContext.eventChkInf[7] & 1)) { TitleCard_InitBossName(globalCtx, &globalCtx->actorCtx.titleCtx, - SEGMENTED_TO_VIRTUAL(gGohmaTitleCardTex), 0xA0, 0xB4, 0x80, 0x28); + SEGMENTED_TO_VIRTUAL(gGohmaTitleCardTex), 160, 180, 128, 40, true); } Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_BOSS); diff --git a/soh/src/overlays/actors/ovl_Boss_Mo/z_boss_mo.c b/soh/src/overlays/actors/ovl_Boss_Mo/z_boss_mo.c index 7bcfd7c50..c6d8a8032 100644 --- a/soh/src/overlays/actors/ovl_Boss_Mo/z_boss_mo.c +++ b/soh/src/overlays/actors/ovl_Boss_Mo/z_boss_mo.c @@ -1423,7 +1423,7 @@ void BossMo_IntroCs(BossMo* this, GlobalContext* globalCtx) { } if (this->timers[2] == 130) { TitleCard_InitBossName(globalCtx, &globalCtx->actorCtx.titleCtx, - SEGMENTED_TO_VIRTUAL(gMorphaTitleCardTex), 0xA0, 0xB4, 0x80, 0x28); + SEGMENTED_TO_VIRTUAL(gMorphaTitleCardTex), 160, 180, 128, 40, true); gSaveContext.eventChkInf[7] |= 0x10; } break; @@ -3591,4 +3591,4 @@ void BossMo_Reset(void) { sSeed1 = 0; sSeed2 = 0; sSeed3 = 0; -} \ No newline at end of file +} diff --git a/soh/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.c b/soh/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.c index 6fae3778b..eeae20698 100644 --- a/soh/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.c +++ b/soh/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.c @@ -598,7 +598,7 @@ void BossSst_HeadIntro(BossSst* this, GlobalContext* globalCtx) { } else if (revealStateTimer == 85) { if (!(gSaveContext.eventChkInf[7] & 0x80)) { TitleCard_InitBossName(globalCtx, &globalCtx->actorCtx.titleCtx, - SEGMENTED_TO_VIRTUAL(gBongoTitleCardTex), 160, 180, 128, 40); + SEGMENTED_TO_VIRTUAL(gBongoTitleCardTex), 160, 180, 128, 40, true); } Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_BOSS); Animation_MorphToPlayOnce(&this->skelAnime, &gBongoHeadEyeCloseAnim, -5.0f); @@ -3245,4 +3245,4 @@ void BossSst_Reset(void) { sCutsceneCamera= 0; sBodyStatic = false; -} \ No newline at end of file +} diff --git a/soh/src/overlays/actors/ovl_Boss_Tw/z_boss_tw.c b/soh/src/overlays/actors/ovl_Boss_Tw/z_boss_tw.c index 38e4996db..6b31635b9 100644 --- a/soh/src/overlays/actors/ovl_Boss_Tw/z_boss_tw.c +++ b/soh/src/overlays/actors/ovl_Boss_Tw/z_boss_tw.c @@ -2220,7 +2220,7 @@ void BossTw_TwinrovaIntroCS(BossTw* this, GlobalContext* globalCtx) { globalCtx->envCtx.unk_BE = 1; globalCtx->envCtx.unk_BD = 1; globalCtx->envCtx.unk_D8 = 0.0f; - TitleCard_InitBossName(globalCtx, &globalCtx->actorCtx.titleCtx, SEGMENTED_TO_VIRTUAL(gTwinrovaTitleCardTex), 160, 180, 128, 40); // OTRTODO + TitleCard_InitBossName(globalCtx, &globalCtx->actorCtx.titleCtx, SEGMENTED_TO_VIRTUAL(gTwinrovaTitleCardTex), 160, 180, 128, 40, true); gSaveContext.eventChkInf[7] |= 0x20; Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_BOSS); } @@ -5469,4 +5469,4 @@ void BossTw_TwinrovaLaugh(BossTw* this, GlobalContext* globalCtx) { void BossTw_Reset(void) { sTwInitalized = false; memset(sTwEffects, 0, sizeof(sTwEffects)); -} \ No newline at end of file +} diff --git a/soh/src/overlays/actors/ovl_Boss_Va/z_boss_va.c b/soh/src/overlays/actors/ovl_Boss_Va/z_boss_va.c index 071baa106..c5b60a327 100644 --- a/soh/src/overlays/actors/ovl_Boss_Va/z_boss_va.c +++ b/soh/src/overlays/actors/ovl_Boss_Va/z_boss_va.c @@ -979,7 +979,7 @@ void BossVa_BodyIntro(BossVa* this, GlobalContext* globalCtx) { if (!(gSaveContext.eventChkInf[7] & 0x40)) { TitleCard_InitBossName(globalCtx, &globalCtx->actorCtx.titleCtx, - SEGMENTED_TO_VIRTUAL(gBarinadeTitleCardTex), 0xA0, 0xB4, 0x80, 0x28); + SEGMENTED_TO_VIRTUAL(gBarinadeTitleCardTex), 160, 180, 128, 40, true); } if (Rand_ZeroOne() < 0.1f) { @@ -4028,4 +4028,4 @@ void BossVa_Reset(void) { sZapperRot.z = 0; sPhase2Timer = 0; sPhase4HP = 0; -} \ No newline at end of file +} diff --git a/soh/src/overlays/actors/ovl_En_Kz/z_en_kz.c b/soh/src/overlays/actors/ovl_En_Kz/z_en_kz.c index 1161ba5e3..502f2c056 100644 --- a/soh/src/overlays/actors/ovl_En_Kz/z_en_kz.c +++ b/soh/src/overlays/actors/ovl_En_Kz/z_en_kz.c @@ -287,7 +287,7 @@ s32 EnKz_FollowPath(EnKz* this, GlobalContext* globalCtx) { pathDiffZ = pointPos->z - this->actor.world.pos.z; Math_SmoothStepToS(&this->actor.world.rot.y, (Math_FAtan2F(pathDiffX, pathDiffZ) * (0x8000 / M_PI)), 0xA, 0x3E8, 1); - if ((SQ(pathDiffX) + SQ(pathDiffZ)) < 10.0f) { + if ((SQ(pathDiffX) + SQ(pathDiffZ)) < 10.0f * CVar_GetS32("gMweepSpeed", 1)) { this->waypoint++; if (this->waypoint >= path->count) { this->waypoint = 0; @@ -378,7 +378,7 @@ void EnKz_SetupMweep(EnKz* this, GlobalContext* globalCtx) { initPos.z += 260.0f; Gameplay_CameraSetAtEye(globalCtx, this->cutsceneCamera, &pos, &initPos); func_8002DF54(globalCtx, &this->actor, 8); - this->actor.speedXZ = 0.1f; + this->actor.speedXZ = 0.1f * CVar_GetS32("gMweepSpeed", 1); this->actionFunc = EnKz_Mweep; } diff --git a/soh/src/overlays/actors/ovl_En_fHG/z_en_fhg.c b/soh/src/overlays/actors/ovl_En_fHG/z_en_fhg.c index ce1029165..82f37b801 100644 --- a/soh/src/overlays/actors/ovl_En_fHG/z_en_fhg.c +++ b/soh/src/overlays/actors/ovl_En_fHG/z_en_fhg.c @@ -332,7 +332,7 @@ void EnfHG_Intro(EnfHG* this, GlobalContext* globalCtx) { Math_ApproachF(&this->cameraSpeedMod, 1.0f, 1.0f, 0.05f); if (this->timers[0] == 75) { TitleCard_InitBossName(globalCtx, &globalCtx->actorCtx.titleCtx, - SEGMENTED_TO_VIRTUAL(gPhantomGanonTitleCardTex), 160, 180, 128, 40); + SEGMENTED_TO_VIRTUAL(gPhantomGanonTitleCardTex), 160, 180, 128, 40, true); } if (this->timers[0] == 0) { this->cutsceneState = INTRO_RETREAT;