From 8a14fea94c07332bcf61a135076d930073e1d2da Mon Sep 17 00:00:00 2001 From: briaguya <70942617+briaguya-ai@users.noreply.github.com> Date: Thu, 8 Feb 2024 20:28:02 -0500 Subject: [PATCH 1/3] support LUS archivemanager refactor (#3912) --- OTRExporter | 2 +- libultraship | 2 +- soh/soh/Enhancements/debugger/dlViewer.cpp | 4 +- soh/soh/Enhancements/tts/tts.cpp | 16 +++--- soh/soh/OTRGlobals.cpp | 59 +++++++++++----------- soh/soh/SohMenuBar.cpp | 3 +- soh/soh/resource/importer/SceneFactory.cpp | 2 +- soh/soh/z_message_OTR.cpp | 2 +- 8 files changed, 44 insertions(+), 46 deletions(-) diff --git a/OTRExporter b/OTRExporter index 44adc47b4..d8f3c4dd4 160000 --- a/OTRExporter +++ b/OTRExporter @@ -1 +1 @@ -Subproject commit 44adc47b4da529e72d968b14cab94aefd8260f22 +Subproject commit d8f3c4dd4a46fb46c4f69cd387afadfa711606e9 diff --git a/libultraship b/libultraship index 0833afad6..825bd1275 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit 0833afad66e96d2ec4bbc410186d7247dc243ee2 +Subproject commit 825bd1275bc26a8532f07a887db5141cd635df13 diff --git a/soh/soh/Enhancements/debugger/dlViewer.cpp b/soh/soh/Enhancements/debugger/dlViewer.cpp index 9ed250615..da44a908a 100644 --- a/soh/soh/Enhancements/debugger/dlViewer.cpp +++ b/soh/soh/Enhancements/debugger/dlViewer.cpp @@ -66,7 +66,7 @@ std::map cmdMap = { }; void PerformDisplayListSearch() { - auto result = LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->ListFiles("*" + std::string(searchString) + "*DL*"); + auto result = LUS::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->ListFiles("*" + std::string(searchString) + "*DL*"); std::regex dlSearch(".*((DL)|(DL_.*))$"); @@ -134,7 +134,7 @@ void DLViewerWindow::DrawElement() { try { auto res = std::static_pointer_cast(LUS::Context::GetInstance()->GetResourceManager()->LoadResource(activeDisplayList)); - if (res->GetInitData()->Type != LUS::ResourceType::DisplayList) { + if (res->GetInitData()->Type != static_cast(LUS::ResourceType::DisplayList)) { ImGui::Text("Resource type is not a Display List. Please choose another."); ImGui::End(); return; diff --git a/soh/soh/Enhancements/tts/tts.cpp b/soh/soh/Enhancements/tts/tts.cpp index 0b46cd18f..1ed6eafa5 100644 --- a/soh/soh/Enhancements/tts/tts.cpp +++ b/soh/soh/Enhancements/tts/tts.cpp @@ -1037,24 +1037,24 @@ void InitTTSBank() { break; } - auto sceneFile = LUS::Context::GetInstance()->GetResourceManager()->LoadFile("accessibility/texts/scenes" + languageSuffix); + auto sceneFile = LUS::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->LoadFileRaw("accessibility/texts/scenes" + languageSuffix); if (sceneFile != nullptr) { - sceneMap = nlohmann::json::parse(sceneFile->Buffer, nullptr, true, true); + sceneMap = nlohmann::json::parse(*sceneFile->Buffer.get(), nullptr, true, true); } - auto miscFile = LUS::Context::GetInstance()->GetResourceManager()->LoadFile("accessibility/texts/misc" + languageSuffix); + auto miscFile = LUS::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->LoadFileRaw("accessibility/texts/misc" + languageSuffix); if (miscFile != nullptr) { - miscMap = nlohmann::json::parse(miscFile->Buffer, nullptr, true, true); + miscMap = nlohmann::json::parse(*miscFile->Buffer.get(), nullptr, true, true); } - auto kaleidoFile = LUS::Context::GetInstance()->GetResourceManager()->LoadFile("accessibility/texts/kaleidoscope" + languageSuffix); + auto kaleidoFile = LUS::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->LoadFileRaw("accessibility/texts/kaleidoscope" + languageSuffix); if (kaleidoFile != nullptr) { - kaleidoMap = nlohmann::json::parse(kaleidoFile->Buffer, nullptr, true, true); + kaleidoMap = nlohmann::json::parse(*kaleidoFile->Buffer.get(), nullptr, true, true); } - auto fileChooseFile = LUS::Context::GetInstance()->GetResourceManager()->LoadFile("accessibility/texts/filechoose" + languageSuffix); + auto fileChooseFile = LUS::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->LoadFileRaw("accessibility/texts/filechoose" + languageSuffix); if (fileChooseFile != nullptr) { - fileChooseMap = nlohmann::json::parse(fileChooseFile->Buffer, nullptr, true, true); + fileChooseMap = nlohmann::json::parse(*fileChooseFile->Buffer.get(), nullptr, true, true); } } diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 283d35e53..62a8bdd3d 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -319,19 +319,19 @@ OTRGlobals::OTRGlobals() { SPDLOG_INFO("Starting Ship of Harkinian version {}", (char*)gBuildVersion); - context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Animation, "Animation", std::make_shared()); - context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_PlayerAnimation, "PlayerAnimation", std::make_shared()); - context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Room, "Room", std::make_shared()); // Is room scene? maybe? - context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_CollisionHeader, "CollisionHeader", std::make_shared()); - context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Skeleton, "Skeleton", std::make_shared()); - context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_SkeletonLimb, "SkeletonLimb", std::make_shared()); - context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Path, "Path", std::make_shared()); - context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Cutscene, "Cutscene", std::make_shared()); - context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Text, "Text", std::make_shared()); - context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_AudioSample, "AudioSample", std::make_shared()); - context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_AudioSoundFont, "AudioSoundFont", std::make_shared()); - context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_AudioSequence, "AudioSequence", std::make_shared()); - context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Background, "Background", std::make_shared()); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(static_cast(LUS::ResourceType::SOH_Animation), std::make_shared()); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(static_cast(LUS::ResourceType::SOH_PlayerAnimation), std::make_shared()); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(static_cast(LUS::ResourceType::SOH_Room), std::make_shared()); // Is room scene? maybe? + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(static_cast(LUS::ResourceType::SOH_CollisionHeader), std::make_shared()); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(static_cast(LUS::ResourceType::SOH_Skeleton), std::make_shared()); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(static_cast(LUS::ResourceType::SOH_SkeletonLimb), std::make_shared()); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(static_cast(LUS::ResourceType::SOH_Path), std::make_shared()); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(static_cast(LUS::ResourceType::SOH_Cutscene), std::make_shared()); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(static_cast(LUS::ResourceType::SOH_Text), std::make_shared()); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(static_cast(LUS::ResourceType::SOH_AudioSample), std::make_shared()); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(static_cast(LUS::ResourceType::SOH_AudioSoundFont), std::make_shared()); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(static_cast(LUS::ResourceType::SOH_AudioSequence), std::make_shared()); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(static_cast(LUS::ResourceType::SOH_Background), std::make_shared()); gSaveStateMgr = std::make_shared(); gRandomizer = std::make_shared(); @@ -354,7 +354,7 @@ OTRGlobals::OTRGlobals() { cameraStrings[i] = dup; } - auto versions = context->GetResourceManager()->GetArchive()->GetGameVersions(); + auto versions = context->GetResourceManager()->GetArchiveManager()->GetGameVersions(); for (uint32_t version : versions) { if (!ValidHashes.contains(version)) { @@ -836,7 +836,7 @@ extern "C" RandomizerGet RetrieveRandomizerGetFromItemID(ItemID itemID) { } extern "C" void OTRExtScanner() { - auto lst = *LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->ListFiles("*").get(); + auto lst = *LUS::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->ListFiles().get(); for (auto& rPath : lst) { std::vector raw = StringHelper::Split(rPath, "."); @@ -859,11 +859,11 @@ OTRVersion ReadPortVersionFromOTR(std::string otrPath) { OTRVersion version = {}; // Use a temporary archive instance to load the otr and read the version file - auto archive = std::make_shared(otrPath, "", std::unordered_set(), false); - if (archive->IsMainMPQValid()) { - auto t = archive->LoadFile("portVersion", false); + auto archive = LUS::OtrArchive(otrPath); + if (archive.LoadRaw()) { + auto t = archive.LoadFileRaw("portVersion"); if (t != nullptr && t->IsLoaded) { - auto stream = std::make_shared(t->Buffer.data(), t->Buffer.size()); + auto stream = std::make_shared(t->Buffer->data(), t->Buffer->size()); auto reader = std::make_shared(stream); LUS::Endianness endianness = (LUS::Endianness)reader->ReadUByte(); reader->SetEndianness(endianness); @@ -871,10 +871,9 @@ OTRVersion ReadPortVersionFromOTR(std::string otrPath) { version.minor = reader->ReadUInt16(); version.patch = reader->ReadUInt16(); } + archive.UnloadRaw(); } - archive = nullptr; - return version; } @@ -1412,15 +1411,15 @@ extern "C" uint16_t OTRGetPixelDepth(float x, float y) { } extern "C" uint32_t ResourceMgr_GetNumGameVersions() { - return LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->GetGameVersions().size(); + return LUS::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->GetGameVersions().size(); } extern "C" uint32_t ResourceMgr_GetGameVersion(int index) { - return LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->GetGameVersions()[index]; + return LUS::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->GetGameVersions()[index]; } extern "C" uint32_t ResourceMgr_GetGamePlatform(int index) { - uint32_t version = LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->GetGameVersions()[index]; + uint32_t version = LUS::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->GetGameVersions()[index]; switch (version) { case OOT_NTSC_US_10: @@ -1443,7 +1442,7 @@ extern "C" uint32_t ResourceMgr_GetGamePlatform(int index) { } extern "C" uint32_t ResourceMgr_GetGameRegion(int index) { - uint32_t version = LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->GetGameVersions()[index]; + uint32_t version = LUS::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->GetGameVersions()[index]; switch (version) { case OOT_NTSC_US_10: @@ -1529,7 +1528,7 @@ extern "C" void ResourceMgr_UnloadResource(const char* resName) { // OTRTODO: There is probably a more elegant way to go about this... // Kenix: This is definitely leaking memory when it's called. extern "C" char** ResourceMgr_ListFiles(const char* searchMask, int* resultSize) { - auto lst = LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->ListFiles(searchMask); + auto lst = LUS::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->ListFiles(searchMask); char** result = (char**)malloc(lst->size() * sizeof(char*)); for (size_t i = 0; i < lst->size(); i++) { @@ -1619,7 +1618,7 @@ extern "C" uint8_t ResourceMgr_TexIsRaw(const char* texPath) { extern "C" uint8_t ResourceMgr_ResourceIsBackground(char* texPath) { auto res = GetResourceByNameHandlingMQ(texPath); - return res->GetInitData()->Type == LUS::ResourceType::SOH_Background; + return res->GetInitData()->Type == static_cast(LUS::ResourceType::SOH_Background); } extern "C" char* ResourceMgr_LoadJPEG(char* data, size_t dataSize) @@ -1667,9 +1666,9 @@ extern "C" uint16_t ResourceMgr_LoadTexHeightByName(char* texPath); extern "C" char* ResourceMgr_LoadTexOrDListByName(const char* filePath) { auto res = GetResourceByNameHandlingMQ(filePath); - if (res->GetInitData()->Type == LUS::ResourceType::DisplayList) + if (res->GetInitData()->Type == static_cast(LUS::ResourceType::DisplayList)) return (char*)&((std::static_pointer_cast(res))->Instructions[0]); - else if (res->GetInitData()->Type == LUS::ResourceType::Array) + else if (res->GetInitData()->Type == static_cast(LUS::ResourceType::Array)) return (char*)(std::static_pointer_cast(res))->Vertices.data(); else { return (char*)GetResourceDataByNameHandlingMQ(filePath); @@ -1679,7 +1678,7 @@ extern "C" char* ResourceMgr_LoadTexOrDListByName(const char* filePath) { extern "C" char* ResourceMgr_LoadIfDListByName(const char* filePath) { auto res = GetResourceByNameHandlingMQ(filePath); - if (res->GetInitData()->Type == LUS::ResourceType::DisplayList) + if (res->GetInitData()->Type == static_cast(LUS::ResourceType::DisplayList)) return (char*)&((std::static_pointer_cast(res))->Instructions[0]); return nullptr; diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index f59e3a343..f8dc26ad4 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -201,8 +201,7 @@ void DrawSettingsMenu() { static std::unordered_map audioBackendNames = { { LUS::AudioBackend::WASAPI, "Windows Audio Session API" }, - { LUS::AudioBackend::PULSE, "PulseAudio" }, - { LUS::AudioBackend::SDL, "SDL" }, + { LUS::AudioBackend::SDL, "SDL" } }; ImGui::Text("Audio API (Needs reload)"); diff --git a/soh/soh/resource/importer/SceneFactory.cpp b/soh/soh/resource/importer/SceneFactory.cpp index 01066ffc1..b71f78a2c 100644 --- a/soh/soh/resource/importer/SceneFactory.cpp +++ b/soh/soh/resource/importer/SceneFactory.cpp @@ -109,7 +109,7 @@ std::shared_ptr SceneFactoryV0::ParseSceneCommand(std::shared_ptr if (commandFactory != nullptr) { auto initData = std::make_shared(); initData->Id = scene->GetInitData()->Id; - initData->Type = ResourceType::SOH_SceneCommand; + initData->Type = static_cast(ResourceType::SOH_SceneCommand); initData->Path = scene->GetInitData()->Path + "/SceneCommand" + std::to_string(index); initData->ResourceVersion = scene->GetInitData()->ResourceVersion; result = std::static_pointer_cast(commandFactory->ReadResource(initData, reader)); diff --git a/soh/soh/z_message_OTR.cpp b/soh/soh/z_message_OTR.cpp index a4255d08a..ce594879a 100644 --- a/soh/soh/z_message_OTR.cpp +++ b/soh/soh/z_message_OTR.cpp @@ -23,7 +23,7 @@ static void SetMessageEntry(MessageTableEntry& entry, const LUS::MessageEntry& m } static void OTRMessage_LoadCustom(const std::string& folderPath, MessageTableEntry*& table, size_t tableSize) { - auto lst = *LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->ListFiles(folderPath).get(); + auto lst = *LUS::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->ListFiles(folderPath).get(); for (auto& tPath : lst) { auto file = std::static_pointer_cast(LUS::Context::GetInstance()->GetResourceManager()->LoadResource(tPath)); From c1eb0a897019993f16b9f0603b51b136a1ea7bcc Mon Sep 17 00:00:00 2001 From: Archez Date: Tue, 13 Feb 2024 20:55:33 -0500 Subject: [PATCH 2/3] Bump latest LUS and Fix ship menu bar icon (#3935) * fix ship menu bar icon * update cmake in wiiu/switch * different cmake install * wrong arch --- .github/workflows/generate-builds.yml | 6 ++++++ libultraship | 2 +- soh/soh/SohMenuBar.cpp | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/generate-builds.yml b/.github/workflows/generate-builds.yml index 6f7134282..582022dbd 100644 --- a/.github/workflows/generate-builds.yml +++ b/.github/workflows/generate-builds.yml @@ -221,6 +221,9 @@ jobs: run: | sudo apt-get update sudo apt-get install -y ninja-build + sudo apt-get remove -y cmake + wget https://github.com/Kitware/CMake/releases/download/v3.28.3/cmake-3.28.3-linux-x86_64.sh -O /tmp/cmake.sh + sudo sh /tmp/cmake.sh --prefix=/usr/local/ --exclude-subdir - name: Fix dubious ownership error if: ${{ vars.LINUX_RUNNER }} run: git config --global --add safe.directory '*' @@ -264,6 +267,9 @@ jobs: run: | sudo apt-get update sudo apt-get install -y ninja-build + sudo apt-get remove -y cmake + wget https://github.com/Kitware/CMake/releases/download/v3.28.3/cmake-3.28.3-linux-x86_64.sh -O /tmp/cmake.sh + sudo sh /tmp/cmake.sh --prefix=/usr/local/ --exclude-subdir - uses: actions/checkout@v3 with: submodules: true diff --git a/libultraship b/libultraship index 825bd1275..d5a39635a 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit 825bd1275bc26a8532f07a887db5141cd635df13 +Subproject commit d5a39635a118f814613c0fdd1601f80c809a742d diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index f8dc26ad4..858c12da7 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -111,11 +111,11 @@ namespace SohGui { void DrawMenuBarIcon() { static bool gameIconLoaded = false; if (!gameIconLoaded) { - LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTexture("Game_Icon", "textures/icons/gIcon.png"); + LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Game_Icon", "textures/icons/gIcon.png"); gameIconLoaded = true; } - if (LUS::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("Game_Icon")) { + if (LUS::Context::GetInstance()->GetWindow()->GetGui()->HasTextureByName("Game_Icon")) { #ifdef __SWITCH__ ImVec2 iconSize = ImVec2(20.0f, 20.0f); float posScale = 1.0f; From 3187564f5b4120e159f5e506b4a3db88716b56aa Mon Sep 17 00:00:00 2001 From: mckinlee Date: Thu, 15 Feb 2024 20:13:54 -0500 Subject: [PATCH 3/3] Pause Warp Enhancement (#3223) * Pause Warp Enhancement This commit introduces the PauseWarp mod, a feature that allows players to warp to different locations in the game directly from the pause menu. - Add PauseWarpState structure to manage flags and cooldowns for the pause warp feature. - Implement IsStateValid function for state validation. - Implement ResetStateFlags function to reset all state flags to default values. - Add InitiateWarp function to handle the initiation of warp sequences. - Implement HandleWarpConfirmation function to confirm and execute warp actions. - Implement HandleCooldowns function to manage various cooldown timers. - Add PauseWarp_Main function as the main logic, called every frame to handle pause warp functionality. - Map warp song messages to in-game text messages. * Warp Song Check -Now if you do not have a warp song you won't be able to select the empty slot and still teleport. * Added Audio Fanfares and Changed stateFlag1 to PLAYER_STATE1_IN_CUTSCENE -When selecting a warp song the audio for the applicable warp song will now play for a extra vanilla feel. -Changed the stateFlag1 because previously it just disabled input allowing enemies to harm you. Now that won't happen because the game is put into a cutscene state. * Feedback Update -A new hook was created 'OnPauseMenu' so now PauseWarp_Main is only called when the pause menu is open -Moved pauswarp.c to the Enhancements folder -Removed from graph.c PR Change: Changing to the main branch instead of sulu * Feedback Update #2 -Introduced new function 'PauseWarp_Idle' now that 'PauseWarp_Main' is no longer called every frame -Added C wrapper to access 'GameInteractor::IsSaveLoaded' and scrapped the 'IsStateValid' function -Added 'PauseWarp_Idle' to the the 'RegisterPauseWarp' function -Refactored the code some * Linux Compile Issue -Added a missing header that was causing a compile issue for linux -Hopefully, it won't crash * Minor Bug Fix -Now link won't get soft locked when warping to the same location twice * Update libultraship * Revert "Update libultraship" This reverts commit 746fc234795c06261a4fb69484f4656676f1eaaa. * Bug Fix -Added more checks to ensure vanilla behavior when a Ocarina is not in the players inventory. * WIP * Done unless I'm missing headers * now we done * clean up, these arn't needed anymore * Rename OnPauseMenu to OnKaleidoUpdate --- soh/include/functions.h | 4 + .../game-interactor/GameInteractor.h | 1 + .../game-interactor/GameInteractor_Hooks.cpp | 6 ++ .../game-interactor/GameInteractor_Hooks.h | 3 + soh/soh/Enhancements/mods.cpp | 18 ++++ soh/soh/Enhancements/pausewarp.c | 92 +++++++++++++++++++ soh/soh/SohMenuBar.cpp | 2 + soh/src/code/z_kaleido_scope_call.c | 3 + 8 files changed, 129 insertions(+) create mode 100644 soh/soh/Enhancements/pausewarp.c diff --git a/soh/include/functions.h b/soh/include/functions.h index 3898ea63d..2c4fe9b15 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -2467,6 +2467,10 @@ void Message_DrawText(PlayState* play, Gfx** gfxP); void Interface_CreateQuadVertexGroup(Vtx* vtxList, s32 xStart, s32 yStart, s32 width, s32 height, u8 flippedH); void Interface_RandoRestoreSwordless(void); +//Pause Warp +void PauseWarp_HandleSelection(); +void PauseWarp_Execute(); + // #endregion #ifdef __cplusplus diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor.h b/soh/soh/Enhancements/game-interactor/GameInteractor.h index be27e74a2..3e70da37a 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor.h @@ -221,6 +221,7 @@ public: DEFINE_HOOK(OnFileDropped, void(std::string filePath)); DEFINE_HOOK(OnAssetAltChange, void()); + DEFINE_HOOK(OnKaleidoUpdate, void()); // Helpers static bool IsSaveLoaded(); diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp index 4bd5354a6..911c47a71 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp @@ -187,3 +187,9 @@ void GameInteractor_ExecuteOnSetGameLanguage() { void GameInteractor_RegisterOnAssetAltChange(void (*fn)(void)) { GameInteractor::Instance->RegisterGameHook(fn); } + +//MARK: Pause Menu + +void GameInteractor_ExecuteOnKaleidoUpdate() { + GameInteractor::Instance->ExecuteHooks(); +} diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h index 7b7b226fa..5c86cb39b 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h @@ -60,6 +60,9 @@ void GameInteractor_ExecuteOnSetGameLanguage(); // MARK: - System void GameInteractor_RegisterOnAssetAltChange(void (*fn)(void)); +//Mark: - Pause Menu +void GameInteractor_ExecuteOnKaleidoUpdate(); + #ifdef __cplusplus } #endif diff --git a/soh/soh/Enhancements/mods.cpp b/soh/soh/Enhancements/mods.cpp index f829d767f..8b65cdcbe 100644 --- a/soh/soh/Enhancements/mods.cpp +++ b/soh/soh/Enhancements/mods.cpp @@ -1304,6 +1304,23 @@ void RegisterToTMedallions() { }); } +void RegisterPauseMenuHooks() { + static bool pauseWarpHooksRegistered = false; + GameInteractor::Instance->RegisterGameHook([&]() { + if (!GameInteractor::IsSaveLoaded() || !CVarGetInteger("gPauseWarp", 0)) { + pauseWarpHooksRegistered = false; + return; + } + if (!pauseWarpHooksRegistered) { + GameInteractor::Instance->RegisterGameHook([]() {PauseWarp_HandleSelection();}); + GameInteractor::Instance->RegisterGameHook([]() { + PauseWarp_Execute(); + }); + pauseWarpHooksRegistered = true; + } + }); +} + void InitMods() { RegisterTTS(); RegisterInfiniteMoney(); @@ -1340,4 +1357,5 @@ void InitMods() { NameTag_RegisterHooks(); RegisterPatchHandHandler(); RegisterHurtContainerModeHandler(); + RegisterPauseMenuHooks(); } diff --git a/soh/soh/Enhancements/pausewarp.c b/soh/soh/Enhancements/pausewarp.c new file mode 100644 index 000000000..e0fd97e24 --- /dev/null +++ b/soh/soh/Enhancements/pausewarp.c @@ -0,0 +1,92 @@ +#include "custom-message/CustomMessageTypes.h" +#include "global.h" +#include "z64.h" +#include "game-interactor/GameInteractor.h" + +static const int songMessageMap[] = { + TEXT_WARP_MINUET_OF_FOREST, + TEXT_WARP_BOLERO_OF_FIRE, + TEXT_WARP_SERENADE_OF_WATER, + TEXT_WARP_REQUIEM_OF_SPIRIT, + TEXT_WARP_NOCTURNE_OF_SHADOW, + TEXT_WARP_PRELUDE_OF_LIGHT +}; + +static const int ocarinaSongMap[] = { + OCARINA_SONG_MINUET, + OCARINA_SONG_BOLERO, + OCARINA_SONG_SERENADE, + OCARINA_SONG_REQUIEM, + OCARINA_SONG_NOCTURNE, + OCARINA_SONG_PRELUDE +}; + +static const int entranceIndexMap[] = { + ENTR_SACRED_FOREST_MEADOW_2, // Minuet + ENTR_DEATH_MOUNTAIN_CRATER_4, // Bolero + ENTR_LAKE_HYLIA_8, // Serenade + ENTR_DESERT_COLOSSUS_5, // Requiem + ENTR_GRAVEYARD_7, // Nocturne + ENTR_TEMPLE_OF_TIME_7 // Prelude +}; + +static const int songAudioMap[] = { + NA_BGM_OCA_MINUET, + NA_BGM_OCA_BOLERO, + NA_BGM_OCA_SERENADE, + NA_BGM_OCA_REQUIEM, + NA_BGM_OCA_NOCTURNE, + NA_BGM_OCA_LIGHT +}; + +static bool isWarpActive = false; + +void PauseWarp_Execute() { + if (!isWarpActive || gPlayState->msgCtx.msgMode != MSGMODE_NONE) { + return; + } + isWarpActive = false; + GET_PLAYER(gPlayState)->stateFlags1 &= ~PLAYER_STATE1_IN_CUTSCENE; + if (gPlayState->msgCtx.choiceIndex != 0) { + return; + } + if (IS_RANDO) { + Entrance_SetWarpSongEntrance(); + return; + } + gPlayState->transitionTrigger = TRANS_TRIGGER_START; + gPlayState->transitionType = TRANS_TYPE_FADE_WHITE_FAST; + for (int i = 0; i < ARRAY_COUNT(ocarinaSongMap); i++) { + if (gPlayState->msgCtx.lastPlayedSong == ocarinaSongMap[i]) { + gPlayState->nextEntranceIndex = entranceIndexMap[i]; + return; + } + } + gPlayState->transitionTrigger = TRANS_TRIGGER_OFF; +} + +void ActivateWarp(PauseContext* pauseCtx, int song) { + Audio_OcaSetInstrument(0); + Interface_SetDoAction(gPlayState, DO_ACTION_NONE); + pauseCtx->state = 0x12; + WREG(2) = -6240; + func_800F64E0(0); + pauseCtx->unk_1E4 = 0; + int idx = song - QUEST_SONG_MINUET; + gPlayState->msgCtx.lastPlayedSong = ocarinaSongMap[idx]; + Audio_SetSoundBanksMute(0x20); + Audio_PlayFanfare(songAudioMap[idx]); + Message_StartTextbox(gPlayState, songMessageMap[idx], NULL); + GET_PLAYER(gPlayState)->stateFlags1 |= PLAYER_STATE1_IN_CUTSCENE; + isWarpActive = true; +} + +void PauseWarp_HandleSelection() { + if (gSaveContext.inventory.items[SLOT_OCARINA] != ITEM_NONE) { + int aButtonPressed = CHECK_BTN_ALL(gPlayState->state.input->press.button, BTN_A); + int song = gPlayState->pauseCtx.cursorPoint[PAUSE_QUEST]; + if (aButtonPressed && CHECK_QUEST_ITEM(song) && song >= QUEST_SONG_MINUET && song <= QUEST_SONG_PRELUDE) { + ActivateWarp(&gPlayState->pauseCtx, song); + } + } +} diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index 858c12da7..c2a300877 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -644,6 +644,8 @@ void DrawEnhancementsMenu() { "- Obtained the Master Sword\n" "- Not within range of Time Block\n" "- Not within range of Ocarina playing spots"); + UIWidgets::PaddedEnhancementCheckbox("Pause Warp", "gPauseWarp", true, false); + UIWidgets::Tooltip("Selection of warp song in pause menu initiates warp. Disables song playback."); ImGui::EndTable(); ImGui::EndMenu(); diff --git a/soh/src/code/z_kaleido_scope_call.c b/soh/src/code/z_kaleido_scope_call.c index dd7e3fdd9..82922acd0 100644 --- a/soh/src/code/z_kaleido_scope_call.c +++ b/soh/src/code/z_kaleido_scope_call.c @@ -1,5 +1,6 @@ #include "global.h" #include "vt.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" void (*sKaleidoScopeUpdateFunc)(PlayState* play); void (*sKaleidoScopeDrawFunc)(PlayState* play); @@ -56,6 +57,8 @@ void KaleidoScopeCall_Update(PlayState* play) { KaleidoMgrOverlay* kaleidoScopeOvl = &gKaleidoMgrOverlayTable[KALEIDO_OVL_KALEIDO_SCOPE]; PauseContext* pauseCtx = &play->pauseCtx; + GameInteractor_ExecuteOnKaleidoUpdate(); + if (!gSaveContext.sohStats.gameComplete && (!IS_BOSS_RUSH || !gSaveContext.isBossRushPaused)) { gSaveContext.sohStats.pauseTimer++;