diff --git a/BUILDING.md b/BUILDING.md index 7606032ba..f68794783 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -2,9 +2,27 @@ ## Windows -1. Requires Visual Studio 2022 Community Edition && `python3, cmake, git` (can be installed via chocolatey or manually) -2. Clone the Ship of Harkinian repository -3. Place one or more [compatible](#compatible-roms) roms in the `OTRExporter` directory with namings of your choice +Requires: + * At least 8GB of RAM (machines with 4GB have seen complier failures) + * Visual Studio 2022 Community Edition with the C++ feature set + * One of the Windows SDKs that comes with Visual Studio, for example the current Windows 10 version 10.0.19041.0 + * The `MSVC v142 - VS 2019 C++ build tools` component of Visual Studio + * Python 3 (can be installed manually or as part of Visual Studio) + * Git (can be installed manually or as part of Visual Studio) + * Cmake (can be installed via chocolatey or manually) + +During installation, check the "Desktop development with C++" feature set: + +![image](https://user-images.githubusercontent.com/30329717/183511274-d11aceea-7900-46ec-acb6-3f2cc110021a.png) +Doing so should also check one of the Windows SDKs by default. Then, in the installation details in the right-hand column, make sure you also check the v142 toolset. + +You can also find the v142 toolset by searching through the individual components tab: + +![image](https://user-images.githubusercontent.com/30329717/183521169-ead6a73b-a1bf-4e99-aab8-441746d8f08e.png) +While you're there, you can also install Python 3 and Git if needed. + +1. Clone the Ship of Harkinian repository +2. Place one or more [compatible](#compatible-roms) roms in the `OTRExporter` directory with namings of your choice _Note: Instructions assume using powershell_ ```powershell @@ -30,8 +48,10 @@ With the cmake build system you have two options for working on the project: #### Visual Studio To develop using Visual Studio you only need to use cmake to generate the solution file: ```powershell -# Generates Ship.sln at `build/x64` +# Generates Ship.sln at `build/x64` for Visual Studio 2022 & 'C:\Program Files\CMake\bin\cmake' -S . -B "build/x64" -G "Visual Studio 17 2022" -T v142 -A x64 +# or for Visual Studio 2019 +& 'C:\Program Files\CMake\bin\cmake' -S . -B "build/x64" -G "Visual Studio 16 2019" -T v142 -A x64 ``` #### Visual Studio Code or another editor @@ -53,7 +73,7 @@ cd "build/x64" ``` ## Linux -1. Requires `gcc >= 10, x11, curl, python3, sdl2 >= 2.0.22, libpng, glew >= 2.2, ninja, cmake, lld` +Requires `gcc >= 10, x11, curl, python3, sdl2 >= 2.0.22, libpng, glew >= 2.2, ninja, cmake, lld` **Important: For maximum performance make sure you have ninja build tools installed!** @@ -91,7 +111,7 @@ cpack -G External (creates appimage) ``` ## macOS -1. Requires Xcode (or xcode-tools) && `sdl2, libpng, glew, ninja, cmake` (can be installed via homebrew, macports, etc) +Requires Xcode (or xcode-tools) && `sdl2, libpng, glew, ninja, cmake` (can be installed via homebrew, macports, etc) **Important: For maximum performance make sure you have ninja build tools installed!** diff --git a/CMake/genscript.cmake b/CMake/genscript.cmake new file mode 100644 index 000000000..10089a4fd --- /dev/null +++ b/CMake/genscript.cmake @@ -0,0 +1,5 @@ +file(READ ${CMAKE_CURRENT_SOURCE_DIR}/extract_assets.py filedata) +string(REGEX REPLACE "zapd_exe = .*exec_cmd =" "zapd_exe = \"${program}\"\n exec_cmd =" filedata "${filedata}") +file(WRITE "${CMAKE_CURRENT_SOURCE_DIR}/extract_assets_cmake2.py" "${filedata}") +file(CHMOD "${CMAKE_CURRENT_SOURCE_DIR}/extract_assets_cmake2.py" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_WRITE GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) + diff --git a/CMakeLists.txt b/CMakeLists.txt index d6b44d786..ef21271f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,11 +45,16 @@ endif() ################################################################################ # Global configuration types ################################################################################ -set(CMAKE_CONFIGURATION_TYPES - "Debug" - "Release" - CACHE STRING "" FORCE -) +if (CMAKE_SYSTEM_NAME STREQUAL "NintendoSwitch") +set(CMAKE_C_FLAGS_DEBUG "-O3 -ffast-math") +set(CMAKE_CXX_FLAGS_DEBUG "-O3 -ffast-math") +set(CMAKE_C_FLAGS_RELEASE "-O3 -ffast-math -DNDEBUG") +set(CMAKE_CXX_FLAGS_RELEASE "-O3 -ffast-math -DNDEBUG") +else() +set(CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG") +set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG") +set(CMAKE_OBJCXX_FLAGS_RELEASE "-O2 -DNDEBUG") +endif() if(NOT CMAKE_BUILD_TYPE ) set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build." FORCE) @@ -129,25 +134,19 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") INSTALL(PROGRAMS "${CMAKE_SOURCE_DIR}/scripts/linux/appimage/soh.sh" DESTINATION . COMPONENT appimage) endif() -file(READ ${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter/extract_assets.py filedata) -string(REGEX REPLACE "../ZAPDTR/ZAPD.out" "${CMAKE_BINARY_DIR}/ZAPD/ZAPD.out" filedata "${filedata}") -string(REGEX REPLACE "x64" "..\\\\\\\\x64" filedata "${filedata}") -string(REGEX REPLACE "Release" "${CMAKE_BUILD_TYPE}" filedata "${filedata}") -file(WRITE "${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter/extract_assets_cmake2.py" "${filedata}") -file(CHMOD "${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter/extract_assets_cmake2.py" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_WRITE GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) - find_package(Python3 COMPONENTS Interpreter) add_custom_target( ExtractAssets + COMMAND ${CMAKE_COMMAND} -Dprogram=$ -P ${CMAKE_SOURCE_DIR}/CMake/genscript.cmake COMMAND ${CMAKE_COMMAND} -E rm -f oot.otr - COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter/extract_assets_cmake2.py + COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter/extract_assets_cmake2.py COMMAND ${CMAKE_COMMAND} -E copy oot.otr ${CMAKE_SOURCE_DIR} COMMAND ${CMAKE_COMMAND} -E copy oot.otr ${CMAKE_BINARY_DIR}/soh WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter COMMENT "Running asset extraction..." DEPENDS ZAPD - + BYPRODUCTS oot.otr ${CMAKE_SOURCE_DIR}/oot.otr ${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter/extract_assets_cmake2.py ) if(CMAKE_SYSTEM_NAME MATCHES "Linux") diff --git a/Jenkinsfile b/Jenkinsfile index a15b2ac12..80df7b0cc 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -8,12 +8,35 @@ pipeline { } stages { + stage('Generate Assets') { + options { + timeout(time: 10) + } + agent { + label "SoH-Mac-Builders" + } + steps { + checkout([ + $class: 'GitSCM', + branches: scm.branches, + doGenerateSubmoduleConfigurations: scm.doGenerateSubmoduleConfigurations, + extensions: scm.extensions, + userRemoteConfigs: scm.userRemoteConfigs + ]) + catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { + sh ''' + cp ../../ZELOOTD.z64 OTRExporter/baserom_non_mq.z64 + + cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release + cmake --build build-cmake --target ExtractAssets --config Release + ''' + stash includes: 'soh/assets/**/*', name: 'assets' + } + } + } stage('Build SoH') { parallel { stage ('Build Windows') { - options { - timeout(time: 20) - } environment { PLATFORM='x64' PYTHON='C:\\Users\\jenkins\\AppData\\Local\\Programs\\Python\\Python310\\python.exe' @@ -34,12 +57,9 @@ pipeline { ]) catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { - bat """ - - xcopy "..\\..\\ZELOOTD.z64" "OTRExporter\\" - + unstash 'assets' + bat """ "${env.CMAKE}" -S . -B "build\\${env.PLATFORM}" -G "Visual Studio 17 2022" -T ${env.TOOLSET} -A ${env.PLATFORM} -D Python_EXECUTABLE=${env.PYTHON} -D CMAKE_BUILD_TYPE:STRING=Release - "${env.CMAKE}" --build ".\\build\\${env.PLATFORM}" --target ExtractAssets --config Release "${env.CMAKE}" --build ".\\build\\${env.PLATFORM}" --config Release cd ".\\build\\${env.PLATFORM}" "${env.CPACK}" -G ZIP @@ -47,8 +67,8 @@ pipeline { move "_packages\\*.zip" "soh.zip" """ - archiveArtifacts artifacts: 'soh.zip', followSymlinks: false, onlyIfSuccessful: true } + archiveArtifacts artifacts: 'soh.zip', followSymlinks: false, onlyIfSuccessful: true } post { always { @@ -57,9 +77,6 @@ pipeline { } } stage ('Build Linux') { - options { - timeout(time: 20) - } agent { label "SoH-Linux-Builders" } @@ -72,9 +89,9 @@ pipeline { userRemoteConfigs: scm.userRemoteConfigs ]) catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { + unstash 'assets' sh ''' - - cp ../../ZELOOTD.z64 OTRExporter/baserom_non_mq.z64 + if docker ps -aq --filter "name=sohcont" | grep -q .; then docker rm -f sohcont; fi docker build . -t soh docker run --name sohcont -dit --rm -v $(pwd):/soh soh /bin/bash docker exec sohcont scripts/linux/appimage/build.sh @@ -86,11 +103,12 @@ pipeline { ''' } - sh 'sudo docker container stop sohcont' archiveArtifacts artifacts: 'soh-linux.7z', followSymlinks: false, onlyIfSuccessful: true } post { always { + sh 'sudo docker container stop sohcont' + sh 'docker images --quiet --filter=dangling=true | xargs --no-run-if-empty docker rmi' // Clean dangling docker images step([$class: 'WsCleanup']) // Clean workspace } } @@ -108,11 +126,9 @@ pipeline { userRemoteConfigs: scm.userRemoteConfigs ]) catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { + unstash 'assets' sh ''' - cp ../../ZELOOTD.z64 OTRExporter/baserom_non_mq.z64 - cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" - cmake --build build-cmake --target ExtractAssets -- cmake --build build-cmake --config Release -- (cd build-cmake && cpack) @@ -131,9 +147,6 @@ pipeline { } } stage ('Build Switch') { - options { - timeout(time: 20) - } agent { label "SoH-Linux-Builders" } @@ -146,12 +159,12 @@ pipeline { userRemoteConfigs: scm.userRemoteConfigs ]) catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { - sh ''' - - cp ../../ZELOOTD.z64 OTRExporter/baserom_non_mq.z64 + unstash 'assets' + sh ''' + if docker ps -aq --filter "name=sohswitchcont" | grep -q .; then docker rm -f sohswitchcont; fi docker build . -t sohswitch - docker run --name sohcont -dit --rm -v $(pwd):/soh sohswitch /bin/bash - docker exec sohcont scripts/switch/build.sh + docker run --name sohswitchcont -dit --rm -v $(pwd):/soh sohswitch /bin/bash + docker exec sohswitchcont scripts/switch/build.sh mv build-switch/soh/*.nro soh.nro mv README.md readme.txt @@ -160,11 +173,12 @@ pipeline { ''' } - sh 'sudo docker container stop sohcont' archiveArtifacts artifacts: 'soh-switch.7z', followSymlinks: false, onlyIfSuccessful: true } post { always { + sh 'sudo docker container stop sohswitchcont' + sh 'docker images --quiet --filter=dangling=true | xargs --no-run-if-empty docker rmi' // Clean dangling docker images step([$class: 'WsCleanup']) // Clean workspace } } diff --git a/ZAPDTR/ZAPD/ZResource.cpp b/ZAPDTR/ZAPD/ZResource.cpp index 89238d9a0..7536fa019 100644 --- a/ZAPDTR/ZAPD/ZResource.cpp +++ b/ZAPDTR/ZAPD/ZResource.cpp @@ -348,11 +348,14 @@ std::string ZResource::GetSourceOutputHeader([[maybe_unused]] const std::string& str += StringHelper::Sprintf("#define d%s \"__OTR__%s/%s\"", name.c_str(), outName.c_str(), nameStr.c_str()); if (nameSet && nameSet->find(name) == nameSet->end()) { + str += StringHelper::Sprintf(R"( #ifdef _WIN32 - str += StringHelper::Sprintf("\nstatic const __declspec(align(2)) char %s[] = d%s;", name.c_str(), name.c_str()); +static const __declspec(align(2)) char %s[] = d%s; #else - str += StringHelper::Sprintf("\nstatic const char %s[] __attribute__((aligned (2))) = d%s;", name.c_str(), name.c_str()); +static const char %s[] __attribute__((aligned (2))) = d%s; #endif + )", name.c_str(), name.c_str(), name.c_str(), name.c_str()); + if (nameSet) { nameSet->insert(name); } diff --git a/libultraship/libultraship/ControlDeck.cpp b/libultraship/libultraship/ControlDeck.cpp index 31eb90067..7437afeee 100644 --- a/libultraship/libultraship/ControlDeck.cpp +++ b/libultraship/libultraship/ControlDeck.cpp @@ -6,6 +6,7 @@ #include "KeyboardController.h" #include "SDLController.h" #include +#include "Cvar.h" namespace Ship { uint8_t* controllerBits; @@ -51,18 +52,31 @@ namespace Ship { *controllerBits |= (backend->Connected()) << slot; } - void ControlDeck::WriteToPad(OSContPad* pad) const { - for (size_t i = 0; i < virtualDevices.size(); i++) { - const std::shared_ptr backend = physicalDevices[virtualDevices[i]]; - if (backend->GetGuid() == "Auto") { - for (const auto& device : physicalDevices) { - device->Read(&pad[i], i); - } - continue; - } - backend->Read(&pad[i], i); - } - } + void ControlDeck::WriteToPad(OSContPad* pad) const { + + #ifdef __SWITCH__ + bool shouldBlockGameInput = CVar_GetS32("gOpenMenuBar", 0); + #else + bool shouldBlockGameInput = CVar_GetS32("gOpenMenuBar", 0) && CVar_GetS32("gControlNav", 0); + #endif + + for (size_t i = 0; i < virtualDevices.size(); i++) { + const std::shared_ptr backend = physicalDevices[virtualDevices[i]]; + if (backend->GetGuid() == "Auto") { + for (const auto& device : physicalDevices) { + if(shouldBlockGameInput && device->GetGuid() != "Keyboard") { + continue; + } + device->Read(&pad[i], i); + } + continue; + } + if(shouldBlockGameInput && backend->GetGuid() != "Keyboard") { + continue; + } + backend->Read(&pad[i], i); + } + } #define NESTED(key, ...) StringHelper::Sprintf("Controllers.%s.Slot_%d." key, device->GetGuid().c_str(), slot, __VA_ARGS__) diff --git a/libultraship/libultraship/ImGuiImpl.cpp b/libultraship/libultraship/ImGuiImpl.cpp index 79af829e3..52e48ed80 100644 --- a/libultraship/libultraship/ImGuiImpl.cpp +++ b/libultraship/libultraship/ImGuiImpl.cpp @@ -822,7 +822,12 @@ namespace SohImGui { GlobalCtx2::GetInstance()->GetWindow()->SetMenuBar(menu_bar); ShowCursor(menu_bar, Dialogues::dMenubar); GlobalCtx2::GetInstance()->GetWindow()->GetControlDeck()->SaveControllerSettings(); - if (CVar_GetS32("gControlNav", 0)) { + #ifdef __SWITCH__ + bool enableControllerNavigation = true; + #else + bool enableControllerNavigation = CVar_GetS32("gControlNav", 0); + #endif + if (enableControllerNavigation) { if (CVar_GetS32("gOpenMenuBar", 0)) { io->ConfigFlags |=ImGuiConfigFlags_NavEnableGamepad | ImGuiConfigFlags_NavEnableKeyboard; } else { @@ -892,9 +897,11 @@ namespace SohImGui { if (ImGui::BeginMenu("Controller")) { + + #ifndef __SWITCH__ EnhancementCheckbox("Use Controller Navigation", "gControlNav"); Tooltip("Allows controller navigation of the menu bar\nD-pad to move between items, A to select, and X to grab focus on the menu bar"); - + #endif EnhancementCheckbox("Controller Configuration", "gControllerConfigurationEnabled"); controller->Opened = CVar_GetS32("gControllerConfigurationEnabled", 0); @@ -1008,6 +1015,24 @@ namespace SohImGui { if (ImGui::BeginMenu("Enhancements")) { + + const char* enhancementPresets[4] = { "Default", "Vanilla Plus", "Enhanced", "Randomizer"}; + ImGui::Text("Enhancement Presets"); + SohImGui::EnhancementCombobox("gSelectEnhancementPresets", enhancementPresets, 4, 0); + Tooltip( + "Default - Set all enhancements to their default values. The true vanilla SoH experience.\n" + "\n" + "Vanilla Plus - Adds Quality of Life features that enhance your experience, but don't alter gameplay. Recommended for a first playthrough of OoT.\n" + "\n" + "Enhanced - The \"Vanilla Plus\" preset, but with more quality of life enhancements that might alter gameplay slightly. Recommended for returning players.\n" + "\n" + "Randomizer - The \"Enhanced\" preset, plus any other enhancements that are recommended for playing Randomizer." + ); + if (ImGui::Button("Apply Preset")) { + applyEnhancementPresets(); + } + ImGui::Separator(); + if (ImGui::BeginMenu("Gameplay")) { if (ImGui::BeginMenu("Time Savers")) @@ -1037,6 +1062,8 @@ namespace SohImGui { Tooltip("Skip the part where the Ocarina playback is called when you play a song"); EnhancementCheckbox("Prevent Dropped Ocarina Inputs", "gDpadNoDropOcarinaInput"); Tooltip("Prevent dropping inputs when playing the ocarina quickly"); + EnhancementCheckbox("Instant Boomerang Recall", "gFastBoomerang"); + Tooltip("Instantly return the boomerang to Link by pressing its item button while it's in the air"); EnhancementCheckbox("Instant Putaway", "gInstantPutaway"); Tooltip("Allow Link to put items away without having to wait around"); EnhancementCheckbox("Mask Select in Inventory", "gMaskSelect"); @@ -1347,7 +1374,7 @@ namespace SohImGui { { val = 20; } - + CVar_SetS32(fps_cvar, val); needs_save = true; } @@ -1748,6 +1775,319 @@ namespace SohImGui { } } + void applyEnhancementPresets(void) { + + switch (CVar_GetS32("gSelectEnhancementPresets", 0)) { + // Default + case 0: + applyEnhancementPresetDefault(); + break; + + // Vanilla Plus + case 1: + applyEnhancementPresetDefault(); + applyEnhancementPresetVanillaPlus(); + break; + + // Enhanced + case 2: + applyEnhancementPresetDefault(); + applyEnhancementPresetVanillaPlus(); + applyEnhancementPresetEnhanced(); + break; + + // Randomizer + case 3: + applyEnhancementPresetDefault(); + applyEnhancementPresetVanillaPlus(); + applyEnhancementPresetEnhanced(); + applyEnhancementPresetRandomizer(); + break; + } + } + + void applyEnhancementPresetDefault(void) { + // Text Speed (1 to 5) + CVar_SetS32("gTextSpeed", 1); + // King Zora Speed (1 to 5) + CVar_SetS32("gMweepSpeed", 1); + // Biggoron Forge Time (0 to 3) + CVar_SetS32("gForgeTime", 3); + // Vine/Ladder Climb speed (+0 to +12) + CVar_SetS32("gClimbSpeed", 0); + // Faster Block Push + CVar_SetS32("gFasterBlockPush", 0); + // No Forced Navi + CVar_SetS32("gNoForcedNavi", 0); + // No Skulltula Freeze + CVar_SetS32("gSkulltulaFreeze", 0); + // MM Bunny Hood + CVar_SetS32("gMMBunnyHood", 0); + // Fast Chests + CVar_SetS32("gFastChests", 0); + // Fast Drops + CVar_SetS32("gFastDrops", 0); + // Better Owl + CVar_SetS32("gBetterOwl", 0); + // Fast Ocarina Playback + CVar_SetS32("gFastOcarinaPlayback", 0); + // Prevent Dropped Ocarina Inputs + CVar_SetS32("gDpadNoDropOcarinaInput", 0); + // Instant Putaway + CVar_SetS32("gInstantPutaway", 0); + // Mask Select in Inventory + CVar_SetS32("gMaskSelect", 0); + + // Damage Multiplier (0 to 8) + CVar_SetS32("gDamageMul", 0); + // Fall Damage Multiplier (0 to 7) + CVar_SetS32("gFallDamageMul", 0); + // Void Damage Multiplier (0 to 6) + CVar_SetS32("gVoidDamageMul", 0); + // No Random Drops + CVar_SetS32("gNoRandomDrops", 0); + // No Heart Drops + CVar_SetS32("gNoHeartDrops", 0); + // Always Win Goron Pot + CVar_SetS32("gGoronPot", 0); + + // Change Red Potion Effect + CVar_SetS32("gRedPotionEffect", 0); + // Red Potion Health (1 to 100) + CVar_SetS32("gRedPotionHealth", 1); + // Red Potion Percent Restore + CVar_SetS32("gRedPercentRestore", 0); + // Change Green Potion Effect + CVar_SetS32("gGreenPotionEffect", 0); + // Green Potion Mana (1 to 100) + CVar_SetS32("gGreenPotionMana", 1); + // Green Potion Percent Restore + CVar_SetS32("gGreenPercentRestore", 0); + // Change Blue Potion Effects + CVar_SetS32("gBluePotionEffects", 0); + // Blue Potion Health (1 to 100) + CVar_SetS32("gBluePotionHealth", 1); + // Blue Potion Health Percent Restore + CVar_SetS32("gBlueHealthPercentRestore", 0); + // Blue Potion Mana (1 to 100) + CVar_SetS32("gBluePotionMana", 1); + // Blue Potion Mana Percent Restore + CVar_SetS32("gBlueManaPercentRestore", 0); + // Change Milk Effect + CVar_SetS32("gMilkEffect", 0); + // Milk Health (1 to 100) + CVar_SetS32("gMilkHealth", 1); + // Milk Percent Restore + CVar_SetS32("gMilkPercentRestore", 0); + // Separate Half Milk Effect + CVar_SetS32("gSeparateHalfMilkEffect", 0); + // Half Milk Health (1 to 100) + CVar_SetS32("gHalfMilkHealth", 0); + // Half Milk Percent Restore + CVar_SetS32("gHalfMilkPercentRestore", 0); + // Change Fairy Effect + CVar_SetS32("gFairyEffect", 0); + // Fairy (1 to 100) + CVar_SetS32("gFairyHealth", 1); + // Fairy Percent Restore + CVar_SetS32("gFairyPercentRestore", 0); + // Change Fairy Revive Effect + CVar_SetS32("gFairyReviveEffect", 0); + // Fairy Revival (1 to 100) + CVar_SetS32("gFairyReviveHealth", 1); + // Fairy Revive Percent Restore + CVar_SetS32("gFairyRevivePercentRestore", 0); + + // Instant Fishing + CVar_SetS32("gInstantFishing", 0); + // Guarantee Bite + CVar_SetS32("gGuaranteeFishingBite", 0); + // Child Minimum Weight (6 to 10) + CVar_SetS32("gChildMinimumWeightFish", 10); + // Adult Minimum Weight (8 to 13) + CVar_SetS32("gAdultMinimumWeightFish", 13); + + // Mute Low HP Alarm + CVar_SetS32("gLowHpAlarm", 0); + // Minimal UI + CVar_SetS32("gMinimalUI", 0); + // Disable Navi Call Audio + CVar_SetS32("gDisableNaviCallAudio", 0); + + // Visual Stone of Agony + CVar_SetS32("gVisualAgony", 0); + // Assignable Tunics and Boots + CVar_SetS32("gAssignableTunicsAndBoots", 0); + // Link's Cow in Both Time Periods + CVar_SetS32("gCowOfTime", 0); + // Enable visible guard vision + CVar_SetS32("gGuardVision", 0); + // Enable passage of time on file select + CVar_SetS32("gTimeFlowFileSelect", 0); + // Allow the cursor to be on any slot + CVar_SetS32("gPauseAnyCursor", 0); + // Count Golden Skulltulas + CVar_SetS32("gInjectSkulltulaCount", 0); + // Pull grave during the day + CVar_SetS32("gDayGravePull", 0); + + // Rotate link (0 to 2) + CVar_SetS32("gPauseLiveLinkRotation", 0); + // Pause link animation (0 to 16) + CVar_SetS32("gPauseLiveLink", 0); + // Frames to wait + CVar_SetS32("gMinFrameCount", 1); + + // N64 Mode + CVar_SetS32("gN64Mode", 0); + // Enable 3D Dropped items/projectiles + CVar_SetS32("gNewDrops", 0); + // Disable Black Bar Letterboxes + CVar_SetS32("gDisableBlackBars", 0); + // Dynamic Wallet Icon + CVar_SetS32("gDynamicWalletIcon", 0); + // Always show dungeon entrances + CVar_SetS32("gAlwaysShowDungeonMinimapIcon", 0); + + // Fix L&R Pause menu + CVar_SetS32("gUniformLR", 0); + // Fix L&Z Page switch in Pause menu + CVar_SetS32("gNGCKaleidoSwitcher", 0); + // Fix Dungeon entrances + CVar_SetS32("gFixDungeonMinimapIcon", 0); + // Fix Two Handed idle animations + CVar_SetS32("gTwoHandedIdle", 0); + // Fix the Gravedigging Tour Glitch + CVar_SetS32("gGravediggingTourFix", 0); + // Fix Deku Nut upgrade + CVar_SetS32("gDekuNutUpgradeFix", 0); + // Fix Navi text HUD position + CVar_SetS32("gNaviTextFix", 0); + // Fix Anubis fireballs + CVar_SetS32("gAnubisFix", 0); + // Fix Megaton Hammer crouch stab + CVar_SetS32("gCrouchStabHammerFix", 0); + // Fix all crouch stab + CVar_SetS32("gCrouchStabFix", 0); + + // Red Ganon blood + CVar_SetS32("gRedGanonBlood", 0); + // Fish while hovering + CVar_SetS32("gHoverFishing", 0); + // N64 Weird Frames + CVar_SetS32("gN64WeirdFrames", 0); + // Bombchus out of bounds + CVar_SetS32("gBombchusOOB", 0); + } + + void applyEnhancementPresetVanillaPlus(void) { + // Text Speed (1 to 5) + CVar_SetS32("gTextSpeed", 5); + // King Zora Speed (1 to 5) + CVar_SetS32("gMweepSpeed", 2); + // Faster Block Push + CVar_SetS32("gFasterBlockPush", 1); + // Better Owl + CVar_SetS32("gBetterOwl", 1); + // Prevent Dropped Ocarina Inputs + CVar_SetS32("gDpadNoDropOcarinaInput", 1); + + // Assignable Tunics and Boots + CVar_SetS32("gAssignableTunicsAndBoots", 1); + // Enable passage of time on file select + CVar_SetS32("gTimeFlowFileSelect", 1); + // Count Golden Skulltulas + CVar_SetS32("gInjectSkulltulaCount", 1); + + // Pause link animation (0 to 16) + CVar_SetS32("gPauseLiveLink", 1); + + // Dynamic Wallet Icon + CVar_SetS32("gDynamicWalletIcon", 1); + // Always show dungeon entrances + CVar_SetS32("gAlwaysShowDungeonMinimapIcon", 1); + + // Fix L&R Pause menu + CVar_SetS32("gUniformLR", 1); + // Fix Dungeon entrances + CVar_SetS32("gFixDungeonMinimapIcon", 1); + // Fix Two Handed idle animations + CVar_SetS32("gTwoHandedIdle", 1); + // Fix the Gravedigging Tour Glitch + CVar_SetS32("gGravediggingTourFix", 1); + // Fix Deku Nut upgrade + CVar_SetS32("gDekuNutUpgradeFix", 1); + + // Red Ganon blood + CVar_SetS32("gRedGanonBlood", 1); + // Fish while hovering + CVar_SetS32("gHoverFishing", 1); + // N64 Weird Frames + CVar_SetS32("gN64WeirdFrames", 1); + // Bombchus out of bounds + CVar_SetS32("gBombchusOOB", 1); + } + + void applyEnhancementPresetEnhanced(void) { + // King Zora Speed (1 to 5) + CVar_SetS32("gMweepSpeed", 5); + // Biggoron Forge Time (0 to 3) + CVar_SetS32("gForgeTime", 0); + // Vine/Ladder Climb speed (+0 to +12) + CVar_SetS32("gClimbSpeed", 1); + // No Forced Navi + CVar_SetS32("gNoForcedNavi", 1); + // No Skulltula Freeze + CVar_SetS32("gSkulltulaFreeze", 1); + // MM Bunny Hood + CVar_SetS32("gMMBunnyHood", 1); + // Fast Chests + CVar_SetS32("gFastChests", 1); + // Fast Drops + CVar_SetS32("gFastDrops", 1); + // Fast Ocarina Playback + CVar_SetS32("gFastOcarinaPlayback", 1); + // Instant Putaway + CVar_SetS32("gInstantPutaway", 1); + // Mask Select in Inventory + CVar_SetS32("gMaskSelect", 1); + + // Disable Navi Call Audio + CVar_SetS32("gDisableNaviCallAudio", 1); + + // Count Golden Skulltulas + CVar_SetS32("gInjectSkulltulaCount", 1); + + // Enable 3D Dropped items/projectiles + CVar_SetS32("gNewDrops", 1); + + // Fix Anubis fireballs + CVar_SetS32("gAnubisFix", 1); + } + + void applyEnhancementPresetRandomizer(void) { + // Instant Fishing + CVar_SetS32("gInstantFishing", 1); + // Guarantee Bite + CVar_SetS32("gGuaranteeFishingBite", 1); + // Child Minimum Weight (6 to 10) + CVar_SetS32("gChildMinimumWeightFish", 6); + // Adult Minimum Weight (8 to 13) + CVar_SetS32("gAdultMinimumWeightFish", 8); + + // Visual Stone of Agony + CVar_SetS32("gVisualAgony", 1); + // Allow the cursor to be on any slot + CVar_SetS32("gPauseAnyCursor", 1); + // Pull grave during the day + CVar_SetS32("gDayGravePull", 1); + + // Pause link animation (0 to 16) + CVar_SetS32("gPauseLiveLink", 16); + // Frames to wait + CVar_SetS32("gMinFrameCount", 200); + } + void Render() { ImGui::Render(); ImGuiRenderDrawData(ImGui::GetDrawData()); diff --git a/libultraship/libultraship/ImGuiImpl.h b/libultraship/libultraship/ImGuiImpl.h index 6913fce61..5358e2028 100644 --- a/libultraship/libultraship/ImGuiImpl.h +++ b/libultraship/libultraship/ImGuiImpl.h @@ -86,6 +86,12 @@ namespace SohImGui { void EnhancementColor(const char* text, const char* cvarName, ImVec4 ColorRGBA, ImVec4 default_colors, bool allow_rainbow = true, bool has_alpha=false, bool TitleSameLine=false); void EnhancementCombo(const std::string& name, const char* cvarName, const std::vector& items, int defaultValue = 0); + void applyEnhancementPresets(void); + void applyEnhancementPresetDefault(void); + void applyEnhancementPresetVanillaPlus(void); + void applyEnhancementPresetEnhanced(void); + void applyEnhancementPresetRandomizer(void); + void DrawMainMenuAndCalculateGameSize(void); void DrawFramebufferAndGameInput(void); diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp index 23cff4698..76573c084 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp +++ b/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp @@ -166,10 +166,12 @@ static void gfx_sdl_init(const char *game_name, bool start_in_fullscreen, uint32 #ifdef __SWITCH__ // For Switch we need to set the window width before creating the window Ship::Switch::GetDisplaySize(&window_width, &window_height); + width = window_width; + height = window_height; #endif wnd = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - window_width, window_height, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); + width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); #ifndef __SWITCH__ SDL_GL_GetDrawableSize(wnd, &window_width, &window_height); diff --git a/libultraship/libultraship/ResourceMgr.cpp b/libultraship/libultraship/ResourceMgr.cpp index bcc783993..4c517b39d 100644 --- a/libultraship/libultraship/ResourceMgr.cpp +++ b/libultraship/libultraship/ResourceMgr.cpp @@ -82,19 +82,14 @@ namespace Ship { break; } - //Lock.lock(); std::shared_ptr ToLoad = FileLoadQueue.front(); FileLoadQueue.pop(); - //Lock.unlock(); OTR->LoadFile(ToLoad->path, true, ToLoad); - //Lock.lock(); if (!ToLoad->bHasLoadError) FileCache[ToLoad->path] = ToLoad->bIsLoaded && !ToLoad->bHasLoadError ? ToLoad : nullptr; - //Lock.unlock(); - SPDLOG_DEBUG("Loaded File {} on ResourceMgr thread", ToLoad->path); ToLoad->FileLoadNotifier.notify_all(); @@ -117,10 +112,8 @@ namespace Ship { } std::shared_ptr ToLoad = nullptr; - //ResLock.lock(); ToLoad = ResourceLoadQueue.front(); ResourceLoadQueue.pop(); - //ResLock.unlock(); // Wait for the underlying File to complete loading { @@ -148,9 +141,6 @@ namespace Ship { SPDLOG_DEBUG("Loaded Resource {} on ResourceMgr thread", ToLoad->file->path); - // Disabled for now because it can cause random crashes - //FileCache[Res->File->path] = nullptr; - //FileCache.erase(FileCache.find(Res->File->path)); Res->file = nullptr; } else { @@ -159,9 +149,6 @@ namespace Ship { SPDLOG_ERROR("Resource load FAILED {} on ResourceMgr thread", ToLoad->file->path); } - - //ResLock.lock(); - //ResLock.unlock(); } } else diff --git a/libultraship/libultraship/Window.cpp b/libultraship/libultraship/Window.cpp index 0db33792e..f4f047428 100644 --- a/libultraship/libultraship/Window.cpp +++ b/libultraship/libultraship/Window.cpp @@ -19,7 +19,7 @@ #include #include #include "Console.h" -#include "Cvar.h" +#include "ImGuiImpl.h" #include @@ -67,10 +67,9 @@ extern "C" { pad->gyro_x = 0; pad->gyro_y = 0; - if (!CVar_GetS32("gOpenMenuBar", 0)) { - Ship::GlobalCtx2::GetInstance()->GetWindow()->GetControlDeck()->WriteToPad(pad); - } + if (SohImGui::controller->Opened) return; + Ship::GlobalCtx2::GetInstance()->GetWindow()->GetControlDeck()->WriteToPad(pad); Ship::ExecuteHooks(pad); } diff --git a/scripts/linux/appimage/build.sh b/scripts/linux/appimage/build.sh index bad6b00c5..86f46fb90 100755 --- a/scripts/linux/appimage/build.sh +++ b/scripts/linux/appimage/build.sh @@ -1,7 +1,6 @@ #!/bin/bash cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release -cmake --build build-cmake --target ExtractAssets -- cmake --build build-cmake --config Release -- (cd build-cmake && cpack -G External) diff --git a/scripts/switch/build.sh b/scripts/switch/build.sh index b5b137652..2a208dd43 100755 --- a/scripts/switch/build.sh +++ b/scripts/switch/build.sh @@ -1,7 +1,4 @@ #!/bin/bash -cmake --no-warn-unused-cli -H. -Bbuild-linux -GNinja -cmake --build build-linux --target ExtractAssets - cmake -H. -Bbuild-switch -GNinja -DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/Switch.cmake cmake --build build-switch --target soh_nro diff --git a/soh/CMakeLists.txt b/soh/CMakeLists.txt index 36b30e602..5342374f0 100644 --- a/soh/CMakeLists.txt +++ b/soh/CMakeLists.txt @@ -215,6 +215,13 @@ set(Header_Files__soh__Enhancements__randomizer__3drando ) source_group("Header Files\\soh\\Enhancements\\randomizer\\3drando" FILES ${Header_Files__soh__Enhancements__randomizer__3drando}) +set(Header_Files__soh__Enhancements__custom_message + "soh/Enhancements/custom-message/CustomMessageTypes.h" + "soh/Enhancements/custom-message/CustomMessageManager.h" +) + +source_group("Header Files\\soh\\Enhancements\\custom-message" FILES ${Header_Files__soh__Enhancements__custom_message}) + set(Source_Files__soh "soh/GbiWrap.cpp" "soh/OTRAudio.h" @@ -326,6 +333,12 @@ set(Source_Files__soh__Enhancements__randomizer__3drando__location_access ) source_group("Source Files\\soh\\Enhancements\\randomizer\\3drando\\location_access" FILES ${Source_Files__soh__Enhancements__randomizer__3drando__location_access}) +set(Source_Files__soh__Enhancements__custom_message + "soh/Enhancements/custom-message/CustomMessageManager.cpp" +) + +source_group("Source Files\\soh\\Enhancements\\custom-message" FILES ${Source_Files__soh__Enhancements__custom_message}) + set(Source_Files__src__boot "src/boot/assert.c" "src/boot/boot_main.c" @@ -1534,6 +1547,7 @@ set(ALL_FILES ${Header_Files__soh__Enhancements__debugger} ${Header_Files__soh__Enhancements__randomizer} ${Header_Files__soh__Enhancements__randomizer__3drando} + ${Header_Files__soh__Enhancements__custom_message} ${Source_Files__soh} ${Source_Files__soh__Enhancements} ${Source_Files__soh__Enhancements__cosmetics} @@ -1542,6 +1556,7 @@ set(ALL_FILES ${Source_Files__soh__Enhancements__randomizer__3drando} ${Source_Files__soh__Enhancements__randomizer__3drando__hint_list} ${Source_Files__soh__Enhancements__randomizer__3drando__location_access} + ${Source_Files__soh__Enhancements__custom_message} ${Source_Files__src__boot} ${Source_Files__src__buffers} ${Source_Files__src__code} @@ -1805,7 +1820,6 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang") $<$:-fpermissive> $<$:-Wno-deprecated-enum-enum-conversion> -pthread - -O3 -ffast-math ) target_link_options(${PROJECT_NAME} PRIVATE diff --git a/soh/include/z64effect.h b/soh/include/z64effect.h index 8dce5b6a3..861eb9070 100644 --- a/soh/include/z64effect.h +++ b/soh/include/z64effect.h @@ -25,7 +25,7 @@ typedef struct { /* 0x0C */ Vec3f position; /* 0x18 */ Vec3s unkVelocity; /* 0x1E */ Vec3s unkPosition; - /* 0x24 */ s32 epoch; + /* 0x24 */ u32 epoch; } EffectSparkElement; // size = 0x28 typedef struct { @@ -118,7 +118,7 @@ typedef struct { /* 0x10 */ f32 startX; /* 0x14 */ s16 yaw; /* 0x16 */ s16 pitch; - /* 0x18 */ s32 epoch; + /* 0x18 */ u32 epoch; } EffectShieldParticleElement; // size = 0x1C typedef struct { diff --git a/soh/include/z64player.h b/soh/include/z64player.h index 08c77a0ee..33ae4c6d9 100644 --- a/soh/include/z64player.h +++ b/soh/include/z64player.h @@ -638,6 +638,7 @@ typedef struct Player { /* 0x0A88 */ Vec3f unk_A88; // previous body part 0 position /* 0x0A89 */ bool pendingIceTrap; /* 0x0A95 */ PendingFlag pendingFlag; -} Player; // size = 0xAA1 + /* 0x0AA1 */ u8 boomerangQuickRecall; // Has the player pressed the boomerang button while it's in the air still? +} Player; // size = 0xAA2 #endif diff --git a/soh/soh/Enhancements/custom-message/CustomMessageManager.cpp b/soh/soh/Enhancements/custom-message/CustomMessageManager.cpp new file mode 100644 index 000000000..d7dd08991 --- /dev/null +++ b/soh/soh/Enhancements/custom-message/CustomMessageManager.cpp @@ -0,0 +1,150 @@ +#include "CustomMessageManager.h" +#include + +using namespace std::literals::string_literals; + +CustomMessageManager::CustomMessageManager() { + this->textBoxSpecialCharacters = { { "À", 0x80 }, { "î", 0x81 }, { "Â", 0x82 }, { "Ä", 0x83 }, { "Ç", 0x84 }, + { "È", 0x85 }, { "É", 0x86 }, { "Ê", 0x87 }, { "Ë", 0x88 }, { "Ï", 0x89 }, + { "Ô", 0x8A }, { "Ö", 0x8B }, { "Ù", 0x8C }, { "Û", 0x8D }, { "Ü", 0x8E }, + { "ß", 0x8F }, { "à", 0x90 }, { "á", 0x91 }, { "â", 0x92 }, { "ä", 0x93 }, + { "ç", 0x94 }, { "è", 0x95 }, { "é", 0x96 }, { "ê", 0x97 }, { "ë", 0x98 }, + { "ï", 0x99 }, { "ô", 0x9A }, { "ö", 0x9B }, { "ù", 0x9C }, { "û", 0x9D }, + { "ü", 0x9E } }; + this->colors = { { "w", QM_WHITE }, { "r", QM_RED }, { "g", QM_GREEN }, { "b", QM_BLUE }, + { "c", QM_LBLUE }, { "p", QM_PINK }, { "y", QM_YELLOW }, { "B", QM_BLACK } }; +} + +CustomMessageManager::~CustomMessageManager() { + this->textBoxSpecialCharacters.clear(); + this->colors.clear(); + this->messageTables.clear(); +} + +void CustomMessageManager::ReplaceSpecialCharacters(std::string& string) { + // add special characters + for (auto specialCharacterPair : this->textBoxSpecialCharacters) { + size_t start_pos = 0; + std::string textBoxSpecialCharacterString = ""s; + textBoxSpecialCharacterString += specialCharacterPair.second; + while ((start_pos = string.find(specialCharacterPair.first, 0)) != std::string::npos) { + string.replace(start_pos, specialCharacterPair.first.length(), textBoxSpecialCharacterString); + start_pos += textBoxSpecialCharacterString.length(); + } + } +} + +void CustomMessageManager::ReplaceColors(std::string& string) { + for (auto colorPair : colors) { + std::string textToReplace = "%"; + textToReplace += colorPair.first; + size_t start_pos = 0; + while ((start_pos = string.find(textToReplace)) != std::string::npos) { + string.replace(start_pos, textToReplace.length(), COLOR(colorPair.second)); + start_pos += textToReplace.length(); + } + } +} + +void CustomMessageManager::FormatCustomMessage(std::string& message, ItemID iid) { + message.insert(0, ITEM_OBTAINED(iid)); + size_t start_pos = 0; + std::replace(message.begin(), message.end(), '&', NEWLINE()[0]); + while ((start_pos = message.find('^', start_pos)) != std::string::npos) { + message.replace(start_pos, 1, WAIT_FOR_INPUT() + ITEM_OBTAINED(iid)); + start_pos += 3; + } + std::replace(message.begin(), message.end(), '@', PLAYER_NAME()[0]); + ReplaceSpecialCharacters(message); + ReplaceColors(message); + message += MESSAGE_END(); +} + +void CustomMessageManager::FormatCustomMessage(std::string& message) { + size_t start_pos = 0; + std::replace(message.begin(), message.end(), '&', NEWLINE()[0]); + std::replace(message.begin(), message.end(), '^', WAIT_FOR_INPUT()[0]); + std::replace(message.begin(), message.end(), '@', PLAYER_NAME()[0]); + ReplaceSpecialCharacters(message); + ReplaceColors(message); + message += MESSAGE_END(); +} + +bool CustomMessageManager::InsertCustomMessage(std::string tableID, uint16_t textID, CustomMessageEntry messages) { + auto foundMessageTable = messageTables.find(tableID); + if (foundMessageTable == messageTables.end()) { + return false; + } + auto& messageTable = foundMessageTable->second; + auto messageInsertResult = messageTable.emplace(textID, messages); + return messageInsertResult.second; +} + + + +bool CustomMessageManager::CreateGetItemMessage(std::string tableID, GetItemID giid, ItemID iid, CustomMessageEntry messageEntry) { + FormatCustomMessage(messageEntry.english, iid); + FormatCustomMessage(messageEntry.german, iid); + FormatCustomMessage(messageEntry.french, iid); + const uint16_t textID = giid; + return InsertCustomMessage(tableID, textID, messageEntry); +} + +bool CustomMessageManager::CreateMessage(std::string tableID, uint16_t textID, CustomMessageEntry messageEntry) { + FormatCustomMessage(messageEntry.english); + FormatCustomMessage(messageEntry.german); + FormatCustomMessage(messageEntry.french); + return InsertCustomMessage(tableID, textID, messageEntry); +} + +CustomMessageEntry CustomMessageManager::RetrieveMessage(std::string tableID, uint16_t textID) { + std::unordered_map::const_iterator foundMessageTable = messageTables.find(tableID); + if (foundMessageTable == messageTables.end()) { + return NULL_CUSTOM_MESSAGE; + } + CustomMessageTable messageTable = foundMessageTable->second; + std::unordered_map::const_iterator foundMessage = messageTable.find(textID); + if (foundMessage == messageTable.end()) { + return NULL_CUSTOM_MESSAGE; + } + CustomMessageEntry message = foundMessage->second; + return message; +} + +bool CustomMessageManager::ClearMessageTable(std::string tableID) { + auto foundMessageTable = messageTables.find(tableID); + if (foundMessageTable == messageTables.end()) { + return false; + } + auto& messageTable = foundMessageTable->second; + messageTable.clear(); +} + +bool CustomMessageManager::AddCustomMessageTable(std::string tableID) { + CustomMessageTable newMessageTable; + return messageTables.emplace(tableID, newMessageTable).second; +} + +std::string CustomMessageManager::MESSAGE_END() { + return "\x02"s; +} + +std::string CustomMessageManager::ITEM_OBTAINED(uint8_t x) { + return "\x13"s + char(x); +} + +std::string CustomMessageManager::NEWLINE() { + return "\x01"s; +} + +std::string CustomMessageManager::COLOR(uint8_t x) { + return "\x05"s + char(x); +} + +std::string CustomMessageManager::WAIT_FOR_INPUT() { + return "\x04"s; +} + +std::string CustomMessageManager::PLAYER_NAME() { + return "\x0F"s; +} diff --git a/soh/soh/Enhancements/custom-message/CustomMessageManager.h b/soh/soh/Enhancements/custom-message/CustomMessageManager.h new file mode 100644 index 000000000..0681073b8 --- /dev/null +++ b/soh/soh/Enhancements/custom-message/CustomMessageManager.h @@ -0,0 +1,133 @@ +#pragma once +#include +#include +#include "../../../include/z64item.h" + +#undef MESSAGE_END + +#define QM_WHITE 0x00 +#define QM_RED 0x41 +#define QM_GREEN 0x42 +#define QM_BLUE 0x43 +#define QM_LBLUE 0x44 +#define QM_PINK 0x45 +#define QM_YELLOW 0x46 +#define QM_BLACK 0x47 + +#ifndef MESSAGE_DATA_STATIC_H + +typedef enum { + /* 0 */ TEXTBOX_TYPE_BLACK, + /* 1 */ TEXTBOX_TYPE_WOODEN, + /* 2 */ TEXTBOX_TYPE_BLUE, + /* 3 */ TEXTBOX_TYPE_OCARINA, + /* 4 */ TEXTBOX_TYPE_NONE_BOTTOM, + /* 5 */ TEXTBOX_TYPE_NONE_NO_SHADOW, + /* 11 */ TEXTBOX_TYPE_CREDITS = 11 +} TextBoxType; + +typedef enum { + /* 0 */ TEXTBOX_BG_CROSS +} TextBoxBackground; + +typedef enum { + /* 0 */ TEXTBOX_POS_VARIABLE, + /* 1 */ TEXTBOX_POS_TOP, + /* 2 */ TEXTBOX_POS_MIDDLE, + /* 3 */ TEXTBOX_POS_BOTTOM +} TextBoxPosition; + +#endif + +typedef struct { + TextBoxType textBoxType; + TextBoxPosition textBoxPos; + std::string english; + std::string german; + std::string french; +} CustomMessageEntry; + +// Message Entry without the text type and position, useful for when +// you need an array of these to loop over for registration +// that will all have the same textbox type and position. +typedef struct { + std::string english; + std::string german; + std::string french; +} CustomMessageMinimal; + +#define NULL_CUSTOM_MESSAGE \ + { (TextBoxType)(-1), (TextBoxPosition)(-1), "", "", "" } + +typedef std::unordered_map CustomMessageTable; + +class CustomMessageManager { + private: + std::unordered_map textBoxSpecialCharacters; + std::unordered_map colors; + std::unordered_map messageTables; + + void ReplaceSpecialCharacters(std::string &string); + void ReplaceColors(std::string& string); + bool InsertCustomMessage(std::string tableID, uint16_t textID, CustomMessageEntry messages); + + std::string MESSAGE_END(); + std::string ITEM_OBTAINED(uint8_t x); + std::string NEWLINE(); + std::string COLOR(uint8_t x); + std::string WAIT_FOR_INPUT(); + std::string PLAYER_NAME(); + + public: + static CustomMessageManager* Instance; + + CustomMessageManager(); + ~CustomMessageManager(); + + /* + Formats the provided Custom Message Entry and inserts it into the table with the provided tableID, + with the provided giid (getItemID) as its key. This function also inserts the icon corresponding to + the provided iid (itemID) at the beginning of each page of the textbox. + */ + bool CreateGetItemMessage(std::string tableID, GetItemID giid, ItemID iid, CustomMessageEntry messages); + + /* + Formats the provided Custom Message Entry and inserts it into the table with the provided tableID, + with the provided textID as its key. + */ + bool CreateMessage(std::string tableID, uint16_t textID, CustomMessageEntry messages); + + /* + Retrieves a message from the table with id tableID with the provided textID. + Returns a NULL_CUSTOM_MESSAGE if the message or table does not exist. + */ + CustomMessageEntry RetrieveMessage(std::string tableID, uint16_t textID); + + /* + Empties out the message table identified by tableID. + Returns true if successful and false if not (for instance + if a table with the provided tableID does not exist). + */ + bool ClearMessageTable(std::string tableID); + + /* + Creates an empty CustomMessageTable accessible at the provided + tableID, returns true if creation was successful and false + if not. + */ + bool AddCustomMessageTable(std::string tableID); + + /* + Replaces special characters and certain symbols with control codes + & for newline, ^ for wait-for-input, and @ for the player name, + as well as % for colors (i.e. %r for red and %w for white). + */ + void FormatCustomMessage(std::string& message, ItemID iid); + + /* + Replaces special characters and certain symbols with control codes + & for newline, ^ for wait-for-input, and @ for the player name, + as well as % for colors (i.e. %r for red and %w for white). + */ + void FormatCustomMessage(std::string& message); +}; diff --git a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h new file mode 100644 index 000000000..d2f30f123 --- /dev/null +++ b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h @@ -0,0 +1,33 @@ +#pragma once + +typedef enum { + TEXT_GS_NO_FREEZE = 0xB4, + TEXT_GS_FREEZE = 0xB5, + TEXT_RANDOMIZER_CUSTOM_ITEM = 0xF8, + TEXT_SCRUB_POH = 0x10A2, + TEXT_SCRUB_STICK_UPGRADE = 0x10DC, + TEXT_SCRUB_NUT_UPGRADE = 0x10DD, + TEXT_RANDOMIZER_GOSSIP_STONE_HINTS = 0x2053, + TEXT_ALTAR_CHILD = 0x7040, + TEXT_ALTAR_ADULT = 0x7088, + TEXT_GANONDORF = 0x70CC, + TEXT_GANONDORF_NOHINT = 0x70CD +} TextIDs; + +#ifdef __cplusplus + +typedef struct { + GetItemID giid; + ItemID iid; + std::string english; + std::string german; + std::string french; +} GetItemMessage; + +#define GIMESSAGE(giid, iid, english, german, french) \ + { giid, iid, english, german, french } + +#define GIMESSAGE_UNTRANSLATED(giid, iid, message) \ + { giid, iid, message, message, message } + +#endif diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index d4b2874c6..fd85d10bc 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -14,13 +14,20 @@ #include "3drando/rando_main.hpp" #include #include "Lib/ImGui/imgui_internal.h" +#include +#include using json = nlohmann::json; +using namespace std::literals::string_literals; std::unordered_map gSeedTextures; u8 generated; +const std::string Randomizer::getItemMessageTableID = "Randomizer"; +const std::string Randomizer::hintMessageTableID = "RandomizerHints"; +const std::string Randomizer::scrubMessageTableID = "RandomizerScrubs"; + Randomizer::Randomizer() { Sprite bowSprite = { dgFairyBowIconTex, 32, 32, G_IM_FMT_RGBA, G_IM_SIZ_32b, 0 }; gSeedTextures[0] = bowSprite; @@ -1520,6 +1527,26 @@ void Randomizer::LoadHintLocations(const char* spoilerFileName) { ParseHintLocationsFile(spoilerFileName); } + CustomMessageManager::Instance->ClearMessageTable(Randomizer::hintMessageTableID); + CustomMessageManager::Instance->AddCustomMessageTable(Randomizer::hintMessageTableID); + + CustomMessageManager::Instance->CreateMessage( + Randomizer::hintMessageTableID, TEXT_ALTAR_CHILD, + { TEXTBOX_TYPE_BLUE, TEXTBOX_POS_BOTTOM, gSaveContext.childAltarText, + gSaveContext.childAltarText, gSaveContext.childAltarText }); + CustomMessageManager::Instance->CreateMessage( + Randomizer::hintMessageTableID, TEXT_ALTAR_ADULT, + { TEXTBOX_TYPE_BLUE, TEXTBOX_POS_BOTTOM, gSaveContext.adultAltarText, + gSaveContext.adultAltarText, gSaveContext.adultAltarText }); + CustomMessageManager::Instance->CreateMessage( + Randomizer::hintMessageTableID, TEXT_GANONDORF, + { TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM, gSaveContext.ganonHintText, + gSaveContext.ganonHintText, gSaveContext.ganonHintText }); + CustomMessageManager::Instance->CreateMessage( + Randomizer::hintMessageTableID, TEXT_GANONDORF_NOHINT, + { TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM, gSaveContext.ganonText, + gSaveContext.ganonText, gSaveContext.ganonText }); + this->childAltarText = gSaveContext.childAltarText; this->adultAltarText = gSaveContext.adultAltarText; this->ganonHintText = gSaveContext.ganonHintText; @@ -1528,6 +1555,8 @@ void Randomizer::LoadHintLocations(const char* spoilerFileName) { for (auto hintLocation : gSaveContext.hintLocations) { if(hintLocation.check == RC_LINKS_POCKET) break; this->hintLocations[hintLocation.check] = hintLocation.hintText; + CustomMessageManager::Instance->CreateMessage( + Randomizer::hintMessageTableID, hintLocation.check, { TEXTBOX_TYPE_BLUE, TEXTBOX_POS_BOTTOM, hintLocation.hintText, hintLocation.hintText, hintLocation.hintText }); } } @@ -1896,57 +1925,8 @@ std::string AltarIconString(char iconChar) { std::string FormatJsonHintText(std::string jsonHint) { std::string formattedHintMessage = jsonHint; - char newLine = 0x01; - char playerName = 0x0F; - char nextBox = 0x04; - std::replace(formattedHintMessage.begin(), formattedHintMessage.end(), '&', newLine); - std::replace(formattedHintMessage.begin(), formattedHintMessage.end(), '^', nextBox); - std::replace(formattedHintMessage.begin(), formattedHintMessage.end(), '@', playerName); - std::unordered_map textBoxSpecialCharacters = { - {"À", 0x80 }, - {"î", 0x81 }, - {"Â", 0x82 }, - {"Ä", 0x83 }, - {"Ç", 0x84 }, - {"È", 0x85 }, - {"É", 0x86 }, - {"Ê", 0x87 }, - {"Ë", 0x88 }, - {"Ï", 0x89 }, - {"Ô", 0x8A }, - {"Ö", 0x8B }, - {"Ù", 0x8C }, - {"Û", 0x8D }, - {"Ü", 0x8E }, - {"ß", 0x8F }, - {"à", 0x90 }, - {"á", 0x91 }, - {"â", 0x92 }, - {"ä", 0x93 }, - {"ç", 0x94 }, - {"è", 0x95 }, - {"é", 0x96 }, - {"ê", 0x97 }, - {"ë", 0x98 }, - {"ï", 0x99 }, - {"ô", 0x9A }, - {"ö", 0x9B }, - {"ù", 0x9C }, - {"û", 0x9D }, - {"ü", 0x9E } - }; - - // add special characters - for (auto specialCharacterPair : textBoxSpecialCharacters) { - size_t start_pos = 0; - std::string textBoxSpecialCharacterString = ""; - textBoxSpecialCharacterString += specialCharacterPair.second; - while((start_pos = formattedHintMessage.find(specialCharacterPair.first, start_pos)) != std::string::npos) { - formattedHintMessage.replace(start_pos, specialCharacterPair.first.length(), textBoxSpecialCharacterString); - start_pos += textBoxSpecialCharacterString.length(); - } - } + CustomMessageManager::Instance->FormatCustomMessage(formattedHintMessage); // add icons to altar text for (char iconChar : {'0', '1', '2', '3', '4', '5', '6', '7', '8', 'o', 'c', 'i', 'l', 'b', 'L', 'k'}) { @@ -2536,10 +2516,6 @@ std::string Randomizer::GetGanonHintText() const { return ganonHintText; } -std::string Randomizer::GetHintFromCheck(RandomizerCheck check) { - return this->hintLocations[check]; -} - u8 Randomizer::GetRandoSettingValue(RandomizerSettingKey randoSettingKey) { return this->randoSettings[randoSettingKey]; } @@ -3572,7 +3548,8 @@ void GenerateRandomizerImgui() { // if we skip child zelda, we start with zelda's letter, and malon starts // at the ranch, so we should *not* shuffle the weird egg - cvarSettings[RSK_SHUFFLE_WEIRD_EGG] = ((CVar_GetS32("gRandomizeSkipChildZelda", 0) == 0) && CVar_GetS32("gRandomizeShuffleWeirdEgg", 0)); + cvarSettings[RSK_SHUFFLE_WEIRD_EGG] = ((CVar_GetS32("gRandomizeSkipChildZelda", 0) == 0) && + CVar_GetS32("gRandomizeShuffleWeirdEgg", 0)); cvarSettings[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD] = CVar_GetS32("gRandomizeShuffleGerudoToken", 0); cvarSettings[RSK_SHUFFLE_FROG_SONG_RUPEES] = CVar_GetS32("gRandomizeShuffleFrogSongRupees", 0); @@ -3603,7 +3580,10 @@ void GenerateRandomizerImgui() { cvarSettings[RSK_CUCCO_COUNT] = CVar_GetS32("gRandomizeCuccosToReturn", 7); cvarSettings[RSK_BIG_POE_COUNT] = CVar_GetS32("gRandomizeBigPoeTargetCount", 10); - cvarSettings[RSK_SKIP_CHILD_STEALTH] = CVar_GetS32("gRandomizeSkipChildStealth", 0); + // If we skip child zelda, skip child stealth is pointless, so this needs to be reflected in the spoiler log + cvarSettings[RSK_SKIP_CHILD_STEALTH] = + !CVar_GetS32("gRandomizeSkipChildZelda", 0) && CVar_GetS32("gRandomizeSkipChildStealth", 0); + cvarSettings[RSK_SKIP_EPONA_RACE] = CVar_GetS32("gRandomizeSkipEponaRace", 0); cvarSettings[RSK_SKIP_TOWER_ESCAPE] = CVar_GetS32("gRandomizeSkipTowerEscape", 0); @@ -4561,8 +4541,64 @@ void DrawRandoEditor(bool& open) { ImGui::End(); } +void CreateGetItemMessages(std::vector messageEntries) { + CustomMessageManager* customMessageManager = CustomMessageManager::Instance; + customMessageManager->AddCustomMessageTable(Randomizer::getItemMessageTableID); + for (GetItemMessage messageEntry : messageEntries) { + customMessageManager->CreateGetItemMessage(Randomizer::getItemMessageTableID, messageEntry.giid, messageEntry.iid, + { TEXTBOX_TYPE_BLUE, TEXTBOX_POS_BOTTOM, + messageEntry.english, messageEntry.german, + messageEntry.french }); + } +} + +void CreateScrubMessages() { + CustomMessageManager* customMessageManager = CustomMessageManager::Instance; + customMessageManager->AddCustomMessageTable(Randomizer::scrubMessageTableID); + const std::vector prices = { 10, 40 }; + for (u8 price : prices) { + customMessageManager->CreateMessage(Randomizer::scrubMessageTableID, price, + { TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM, + "\x12\x38\x82\All right! You win! In return for&sparing me, I will sell you a&%gmysterious item%w!&%r" + + std::to_string(price) + " Rupees%w it is!\x07\x10\xA3", + // RANDTODO: Translate the below string to German. + "\x12\x38\x82\All right! You win! In return for&sparing me, I will sell you a&%gmysterious item%w!&%r" + + std::to_string(price) + " Rupees%w it is!\x07\x10\xA3", + "\x12\x38\x82J'abandonne! Tu veux bien m'acheter&un %gobjet mystérieux%w?&Ça fera %r" + + std::to_string(price) + " Rubis%w!\x07\x10\xA3" + }); + } +} + +void Randomizer::CreateCustomMessages() { + // RANDTODO: Translate into french and german and replace GIMESSAGE_UNTRANSLATED + // with GIMESSAGE(getItemID, itemID, english, german, french). + const std::vector getItemMessages = { + GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_BLUE_FIRE, ITEM_BLUE_FIRE, + "You got a %rBottle with Blue &Fire%w! Use it to melt Red Ice!"), + GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_BIG_POE, ITEM_BIG_POE, + "You got a %rBig Poe in a Bottle%w!&Sell it to the Ghost Shop!"), + GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_BLUE_POTION, ITEM_POTION_BLUE, + "You got a %rBottle of Blue Potion%w!&Drink it to replenish your&%ghealth%w and %bmagic%w!"), + GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_FISH, ITEM_FISH, + "You got a %rFish in a Bottle%w!&It looks fresh and delicious!&They say Jabu-Jabu loves them!"), + GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_BUGS, ITEM_BUG, + "You got a %rBug in a Bottle%w!&They love to burrow in&dirt holes!"), + GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_FAIRY, ITEM_FAIRY, "You got a %rFairy in a Bottle%w!&Use it wisely!"), + GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_RED_POTION, ITEM_POTION_RED, + "You got a %rBottle of Red Potion%w!&Drink it to replenish your&%ghealth%w!"), + GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_GREEN_POTION, ITEM_POTION_GREEN, + "You got a %rBottle of Green Potion%w!&Drink it to replenish your&%bmagic%w!"), + GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_POE, ITEM_POE, + "You got a %rPoe in a Bottle%w!&That creepy Ghost Shop might&be interested in this..."), + }; + CreateGetItemMessages(getItemMessages); + CreateScrubMessages(); +} + void InitRando() { SohImGui::AddWindow("Randomizer", "Randomizer Settings", DrawRandoEditor); + Randomizer::CreateCustomMessages(); } extern "C" { diff --git a/soh/soh/Enhancements/randomizer/randomizer.h b/soh/soh/Enhancements/randomizer/randomizer.h index f4101e8fd..1994cfdc4 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.h +++ b/soh/soh/Enhancements/randomizer/randomizer.h @@ -4,7 +4,8 @@ #include #include "../../../include/ultra64.h" #include "../../../include/z64item.h" -#include "soh/Enhancements/randomizer/randomizerTypes.h" +#include +#include class Randomizer { private: @@ -25,6 +26,10 @@ class Randomizer { Randomizer(); ~Randomizer(); + static const std::string getItemMessageTableID; + static const std::string hintMessageTableID; + static const std::string scrubMessageTableID; + static Sprite* GetSeedTexture(uint8_t index); s16 GetItemModelFromId(s16 itemId); s32 GetItemIDFromGetItemID(s32 getItemId); @@ -38,9 +43,9 @@ class Randomizer { std::string GetAdultAltarText() const; std::string GetGanonText() const; std::string GetGanonHintText() const; - std::string GetHintFromCheck(RandomizerCheck check); GetItemID GetRandomizedItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId); GetItemID GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum); + static void CreateCustomMessages(); }; #ifdef __cplusplus diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 48ecceb07..ba61805f0 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -32,7 +32,6 @@ #include "Enhancements/cosmetics/CosmeticsEditor.h" #include "Enhancements/debugconsole.h" #include "Enhancements/debugger/debugger.h" -#include "Enhancements/randomizer/randomizer.h" #include #include "Enhancements/n64_weird_frame_data.inc" #include "soh/frame_interpolation.h" @@ -40,6 +39,7 @@ #include "macros.h" #include #include "Hooks.h" +#include #ifdef __APPLE__ #include @@ -52,9 +52,12 @@ #endif #include +#include +#include OTRGlobals* OTRGlobals::Instance; SaveManager* SaveManager::Instance; +CustomMessageManager* CustomMessageManager::Instance; OTRGlobals::OTRGlobals() { context = Ship::GlobalCtx2::CreateInstance("Ship of Harkinian"); @@ -171,6 +174,7 @@ extern "C" void InitOTR() { #endif OTRGlobals::Instance = new OTRGlobals(); SaveManager::Instance = new SaveManager(); + CustomMessageManager::Instance = new CustomMessageManager(); auto t = OTRGlobals::Instance->context->GetResourceManager()->LoadFile("version"); if (!t->bHasLoadError) @@ -1431,99 +1435,39 @@ extern "C" RandomizerCheck Randomizer_GetCheckFromActor(s16 sceneNum, s16 actorI return OTRGlobals::Instance->gRandomizer->GetCheckFromActor(sceneNum, actorId, actorParams); } -extern "C" int CopyScrubMessage(u16 scrubTextId, char* buffer, const int maxBufferSize) { - std::string scrubText(""); - int language = CVar_GetS32("gLanguages", 0); +extern "C" CustomMessageEntry Randomizer_GetScrubMessage(u16 scrubTextId) { int price = 0; switch (scrubTextId) { - case 0x10A2: + case TEXT_SCRUB_POH: price = 10; break; - case 0x10DC: - case 0x10DD: + case TEXT_SCRUB_STICK_UPGRADE: + case TEXT_SCRUB_NUT_UPGRADE: price = 40; break; } - switch (language) { - case 0: default: - scrubText += 0x12; // add the sound - scrubText += 0x38; // sound id - scrubText += 0x82; // sound id - scrubText += "All right! You win! In return for"; - scrubText += 0x01; // newline - scrubText += "sparing me, I will sell you a"; - scrubText += 0x01; // newline - scrubText += 0x05; // change the color - scrubText += 0x42; // green - scrubText += "mysterious item"; - scrubText += 0x05; // change the color - scrubText += 0x40; // white - scrubText += "!"; - scrubText += 0x01; // newline - scrubText += 0x05; // change the color - scrubText += 0x41; // red - scrubText += std::to_string(price); - scrubText += price > 1 ? " Rupees" : " Rupee"; - scrubText += 0x05; // change the color - scrubText += 0x40; // white - scrubText += " it is!"; - scrubText += 0x07; // go to a new message - scrubText += 0x10; // message id - scrubText += 0xA3; // message id - break; - case 2: - scrubText += 0x12; // add the sound - scrubText += 0x38; // sound id - scrubText += 0x82; // sound id - scrubText += "J'abandonne! Tu veux bien m'acheter"; - scrubText += 0x01; // newline - scrubText += "un "; - scrubText += 0x05; // change the color - scrubText += 0x42; // green - scrubText += "objet myst\x96rieux"; - //scrubText += "; - scrubText += 0x05; // change the color - scrubText += 0x40; // white - scrubText += "?"; - scrubText += 0x01; // newline - scrubText += "\x84"; - scrubText += "a fera "; - scrubText += 0x05; // change the color - scrubText += 0x41; // red - scrubText += std::to_string(price) + " Rubis"; - scrubText += 0x05; // change the color - scrubText += 0x40; // white - scrubText += "!"; - scrubText += 0x07; // go to a new message - scrubText += 0x10; // message id - scrubText += 0xA3; // message id - break; - } - - return CopyStringToCharBuffer(scrubText, buffer, maxBufferSize); + return CustomMessageManager::Instance->RetrieveMessage(Randomizer::scrubMessageTableID, price); } -extern "C" int Randomizer_CopyAltarMessage(char* buffer, const int maxBufferSize) { - const std::string& altarText = (LINK_IS_ADULT) ? OTRGlobals::Instance->gRandomizer->GetAdultAltarText() - : OTRGlobals::Instance->gRandomizer->GetChildAltarText(); - return CopyStringToCharBuffer(altarText, buffer, maxBufferSize); +extern "C" CustomMessageEntry Randomizer_GetAltarMessage() { + return (LINK_IS_ADULT) + ? CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, TEXT_ALTAR_ADULT) + : CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, TEXT_ALTAR_CHILD); } -extern "C" int Randomizer_CopyGanonText(char* buffer, const int maxBufferSize) { - const std::string& ganonText = OTRGlobals::Instance->gRandomizer->GetGanonText(); - return CopyStringToCharBuffer(ganonText, buffer, maxBufferSize); +extern "C" CustomMessageEntry Randomizer_GetGanonText() { + return CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, TEXT_GANONDORF_NOHINT); } -extern "C" int Randomizer_CopyGanonHintText(char* buffer, const int maxBufferSize) { - const std::string& ganonText = OTRGlobals::Instance->gRandomizer->GetGanonHintText(); - return CopyStringToCharBuffer(ganonText, buffer, maxBufferSize); +extern "C" CustomMessageEntry Randomizer_GetGanonHintText() { + return CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, TEXT_GANONDORF); } -extern "C" int Randomizer_CopyHintFromCheck(RandomizerCheck check, char* buffer, const int maxBufferSize) { - // we don't want to make a copy of the std::string returned from GetHintFromCheck +extern "C" CustomMessageEntry Randomizer_GetHintFromCheck(RandomizerCheck check) { + // we don't want to make a copy of the std::string returned from GetHintFromCheck // so we're just going to let RVO take care of it - const std::string& hintText = OTRGlobals::Instance->gRandomizer->GetHintFromCheck(check); - return CopyStringToCharBuffer(hintText, buffer, maxBufferSize); + const CustomMessageEntry hintText = CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, check); + return hintText; } extern "C" s32 Randomizer_GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum) { @@ -1542,3 +1486,89 @@ extern "C" bool Randomizer_ObtainedFreestandingIceTrap(RandomizerCheck randomize extern "C" bool Randomizer_ItemIsIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId) { return gSaveContext.n64ddFlag && Randomizer_GetItemIdFromKnownCheck(randomizerCheck, ogId) == GI_ICE_TRAP; } + +extern "C" CustomMessageEntry Randomizer_GetCustomGetItemMessage(GetItemID giid, char* buffer, const int maxBufferSize) { + const CustomMessageEntry getItemText = CustomMessageManager::Instance->RetrieveMessage(Randomizer::getItemMessageTableID, giid); + return getItemText; +} + +extern "C" int CustomMessage_RetrieveIfExists(GlobalContext* globalCtx) { + MessageContext* msgCtx = &globalCtx->msgCtx; + uint16_t textId = msgCtx->textId; + Font* font = &msgCtx->font; + char* buffer = font->msgBuf; + const int maxBufferSize = sizeof(font->msgBuf); + CustomMessageEntry messageEntry; + if (gSaveContext.n64ddFlag) { + if (textId == TEXT_RANDOMIZER_CUSTOM_ITEM) { + messageEntry = + Randomizer_GetCustomGetItemMessage((GetItemID)GET_PLAYER(globalCtx)->getItemId, buffer, maxBufferSize); + } else if (textId == TEXT_RANDOMIZER_GOSSIP_STONE_HINTS && Randomizer_GetSettingValue(RSK_GOSSIP_STONE_HINTS) != 0 && + (Randomizer_GetSettingValue(RSK_GOSSIP_STONE_HINTS) == 1 || + (Randomizer_GetSettingValue(RSK_GOSSIP_STONE_HINTS) == 2 && + Player_GetMask(globalCtx) == PLAYER_MASK_TRUTH) || + (Randomizer_GetSettingValue(RSK_GOSSIP_STONE_HINTS) == 3 && CHECK_QUEST_ITEM(QUEST_STONE_OF_AGONY)))) { + + s16 actorParams = msgCtx->talkActor->params; + + // if we're in a generic grotto + if (globalCtx->sceneNum == 62 && actorParams == 14360) { + // look for the chest in the actorlist to determine + // which grotto we're in + int numOfActorLists = + sizeof(globalCtx->actorCtx.actorLists) / sizeof(globalCtx->actorCtx.actorLists[0]); + for (int i = 0; i < numOfActorLists; i++) { + if (globalCtx->actorCtx.actorLists[i].length) { + if (globalCtx->actorCtx.actorLists[i].head->id == 10) { + // set the params for the hint check to be negative chest params + actorParams = 0 - globalCtx->actorCtx.actorLists[i].head->params; + } + } + } + } + + RandomizerCheck hintCheck = + Randomizer_GetCheckFromActor(globalCtx->sceneNum, msgCtx->talkActor->id, actorParams); + + messageEntry = Randomizer_GetHintFromCheck(hintCheck); + } else if (textId == TEXT_ALTAR_CHILD || textId == TEXT_ALTAR_ADULT) { + // rando hints at altar + messageEntry = Randomizer_GetAltarMessage(); + } else if (textId == TEXT_GANONDORF) { + if (INV_CONTENT(ITEM_ARROW_LIGHT) == ITEM_ARROW_LIGHT) { + messageEntry = Randomizer_GetGanonText(); + } else { + messageEntry = Randomizer_GetGanonHintText(); + } + } else if (textId == TEXT_SCRUB_POH || textId == TEXT_SCRUB_STICK_UPGRADE || textId == TEXT_SCRUB_NUT_UPGRADE) { + messageEntry = Randomizer_GetScrubMessage(textId); + } + } + if (textId == TEXT_GS_NO_FREEZE || textId == TEXT_GS_FREEZE) { + if (CVar_GetS32("gInjectSkulltulaCount", 0) != 0) { + if (CVar_GetS32("gSkulltulaFreeze", 0) != 0) { + textId = TEXT_GS_NO_FREEZE; + } else { + textId = TEXT_GS_FREEZE; + } + messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId); + } + } + if (messageEntry.textBoxType != -1) { + font->charTexBuf[0] = (messageEntry.textBoxType << 4) | messageEntry.textBoxPos; + switch (gSaveContext.language) { + case LANGUAGE_FRA: + return msgCtx->msgLength = font->msgLength = + CopyStringToCharBuffer(messageEntry.french, buffer, maxBufferSize); + case LANGUAGE_GER: + return msgCtx->msgLength = font->msgLength = + CopyStringToCharBuffer(messageEntry.german, buffer, maxBufferSize); + + case LANGUAGE_ENG: + default: + return msgCtx->msgLength = font->msgLength = + CopyStringToCharBuffer(messageEntry.english, buffer, maxBufferSize); + } + } + return false; +} diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index fca7baea6..ae8f799b9 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -10,6 +10,8 @@ #include "Enhancements/savestates.h" #include "Enhancements/randomizer/randomizer.h" +const std::string customMessageTableID = "BaseGameOverrides"; + class OTRGlobals { public: @@ -91,10 +93,6 @@ Sprite* GetSeedTexture(uint8_t index); void Randomizer_LoadSettings(const char* spoilerFileName); u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey); RandomizerCheck Randomizer_GetCheckFromActor(s16 actorId, s16 actorParams, s16 sceneNum); -int Randomizer_CopyAltarMessage(char* buffer, const int maxBufferSize); -int Randomizer_CopyHintFromCheck(RandomizerCheck check, char* buffer, const int maxBufferSize); -int Randomizer_CopyGanonText(char* buffer, const int maxBufferSize); -int Randomizer_CopyGanonHintText(char* buffer, const int maxBufferSize); void Randomizer_LoadHintLocations(const char* spoilerFileName); void Randomizer_LoadItemLocations(const char* spoilerFileName, bool silent); s16 Randomizer_GetItemModelFromId(s16 itemId); @@ -103,6 +101,7 @@ s32 Randomizer_GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams, s32 Randomizer_GetItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId); bool Randomizer_ObtainedFreestandingIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId, Actor* actor); bool Randomizer_ItemIsIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId); +int CustomMessage_RetrieveIfExists(GlobalContext* globalCtx); #endif #endif diff --git a/soh/soh/z_message_OTR.cpp b/soh/soh/z_message_OTR.cpp index 8c1d26a75..c6be43964 100644 --- a/soh/soh/z_message_OTR.cpp +++ b/soh/soh/z_message_OTR.cpp @@ -1,11 +1,13 @@ #include "OTRGlobals.h" #include "ResourceMgr.h" #include "Scene.h" -#include "message_data_static.h" #include "Utils/StringHelper.h" #include "global.h" #include "vt.h" #include +#include +#include +#include extern "C" MessageTableEntry* sNesMessageEntryTablePtr; extern "C" MessageTableEntry* sGerMessageEntryTablePtr; @@ -92,4 +94,22 @@ extern "C" void OTRMessage_Init() sStaffMessageEntryTablePtr[i].segment = file2->messages[i].msg.c_str(); sStaffMessageEntryTablePtr[i].msgSize = file2->messages[i].msg.size(); } -} \ No newline at end of file + + CustomMessageManager::Instance->AddCustomMessageTable(customMessageTableID); + CustomMessageManager::Instance->CreateGetItemMessage( + customMessageTableID, (GetItemID)TEXT_GS_NO_FREEZE, ITEM_SKULL_TOKEN, + { + TEXTBOX_TYPE_BLUE, TEXTBOX_POS_BOTTOM, + "You got a %rGold Skulltula Token%w!&You've collected %r\x19%w tokens&in total!\x0E\x3C", + "Du erhälst ein %rGoldene&Skulltula-Symbol%w! Du hast&insgesamt %r\x19%w symbol gesammelt!\x0E\x3C", + "Vous obtenez un %rSymbole de&Skulltula d'or%w! Vous avez&collecté %r\x19\%w symboles en tout!\x0E\x3C" + } + ); + CustomMessageManager::Instance->CreateGetItemMessage( + customMessageTableID, (GetItemID)TEXT_GS_FREEZE, ITEM_SKULL_TOKEN, + { + TEXTBOX_TYPE_BLUE, TEXTBOX_POS_BOTTOM, + "You got a %rGold Skulltula Token%w!&You've collected %r\x19%w tokens&in total!", + "Du erhälst ein %rGoldene&Skulltula-Symbol%w! Du hast&insgesamt %r\x19%w symbol gesammelt!", + "Vous obtenez un %rSymbole de&Skulltula d'or%w! Vous avez&collecté %r\x19\%w symboles en tout!" }); +} diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index c788a6e38..45e84a050 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -3961,7 +3961,7 @@ void Actor_DrawDoorLock(GlobalContext* globalCtx, s32 frame, s32 type) { f32 chainsTranslateX; f32 chainsTranslateY; f32 rotZStep; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; entry = &sDoorLocksInfo[type]; diff --git a/soh/src/code/z_demo.c b/soh/src/code/z_demo.c index 885446271..a447f549c 100644 --- a/soh/src/code/z_demo.c +++ b/soh/src/code/z_demo.c @@ -492,9 +492,10 @@ void Cutscene_Command_Terminator(GlobalContext* globalCtx, CutsceneContext* csCt s32 temp = 0; // Automatically skip certain cutscenes when in rando - // cmd->base == 33: Zelda escaping with impa cutscene // cmd->base == 8: Traveling back/forward in time cutscene - bool randoCsSkip = (gSaveContext.n64ddFlag && (cmd->base == 33 || cmd->base == 8)); + // cmd->base == 24: Dropping a fish for Jabu Jabu + // cmd->base == 33: Zelda escaping with impa cutscene + bool randoCsSkip = (gSaveContext.n64ddFlag && (cmd->base == 8 || cmd->base == 24 || cmd->base == 33)); bool debugCsSkip = (CHECK_BTN_ALL(globalCtx->state.input[0].press.button, BTN_START) && (gSaveContext.fileNum != 0xFEDC) && CVar_GetS32("gDebugEnabled", 0)); @@ -2090,6 +2091,8 @@ void Cutscene_HandleConditionalTriggers(GlobalContext* globalCtx) { osSyncPrintf("\ngame_info.mode=[%d] restart_flag", ((void)0, gSaveContext.respawnFlag)); if ((gSaveContext.gameMode == 0) && (gSaveContext.respawnFlag <= 0) && (gSaveContext.cutsceneIndex < 0xFFF0)) { + const bool bShouldTowerRandoSkip = + (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SKIP_TOWER_ESCAPE)); if ((gSaveContext.entranceIndex == 0x01E1) && !Flags_GetEventChkInf(0xAC)) { if (!gSaveContext.n64ddFlag) { Flags_SetEventChkInf(0xAC); @@ -2118,14 +2121,15 @@ void Cutscene_HandleConditionalTriggers(GlobalContext* globalCtx) { gSaveContext.entranceIndex = 0x0053; gSaveContext.cutsceneIndex = 0xFFF8; } - } else if (!Flags_GetEventChkInf(0xC7) && - (gEntranceTable[((void)0, gSaveContext.entranceIndex)].scene == SCENE_GANON_DEMO)) { + } else if ((!Flags_GetEventChkInf(0xC7) && + gEntranceTable[((void)0, gSaveContext.entranceIndex)].scene == SCENE_GANON_DEMO) || + (bShouldTowerRandoSkip && + gEntranceTable[((void)0, gSaveContext.entranceIndex)].scene == SCENE_GANON_FINAL)) { Flags_SetEventChkInf(0xC7); gSaveContext.entranceIndex = 0x0517; - // If we are rando and tower escape skip is on, then set the flag to say we saw the towers fall // and exit. - if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SKIP_TOWER_ESCAPE)) { + if (bShouldTowerRandoSkip) { return; } gSaveContext.cutsceneIndex = 0xFFF0; diff --git a/soh/src/code/z_kankyo.c b/soh/src/code/z_kankyo.c index de8634f32..7fd9a7480 100644 --- a/soh/src/code/z_kankyo.c +++ b/soh/src/code/z_kankyo.c @@ -1459,7 +1459,7 @@ void Environment_DrawLensFlare(GlobalContext* globalCtx, EnvironmentContext* env LENS_FLARE_RING, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1, }; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(gfxCtx); @@ -1642,7 +1642,7 @@ void Environment_DrawRain(GlobalContext* globalCtx, View* view, GraphicsContext* Vec3f unused = { 0.0f, 0.0f, 0.0f }; Vec3f windDirection = { 0.0f, 0.0f, 0.0f }; Player* player = GET_PLAYER(globalCtx); - static s32 epoch = 0; + static u32 epoch = 0; epoch++; if (!(globalCtx->cameraPtrs[0]->unk_14C & 0x100) && (globalCtx->envCtx.unk_EE[2] == 0)) { @@ -1925,7 +1925,7 @@ void Environment_DrawLightning(GlobalContext* globalCtx, s32 unused) { s32 pad[2]; Vec3f unused1 = { 0.0f, 0.0f, 0.0f }; Vec3f unused2 = { 0.0f, 0.0f, 0.0f }; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(globalCtx->state.gfxCtx); diff --git a/soh/src/code/z_lifemeter.c b/soh/src/code/z_lifemeter.c index 400f0a275..071cc18a7 100644 --- a/soh/src/code/z_lifemeter.c +++ b/soh/src/code/z_lifemeter.c @@ -413,7 +413,7 @@ void HealthMeter_Draw(GlobalContext* globalCtx) { s32 curCombineModeSet = 0; u8* curBgImgLoaded = NULL; s32 ddHeartCountMinusOne = gSaveContext.inventory.defenseHearts - 1; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(gfxCtx); diff --git a/soh/src/code/z_message_PAL.c b/soh/src/code/z_message_PAL.c index 5c7bccac0..11c59db8b 100644 --- a/soh/src/code/z_message_PAL.c +++ b/soh/src/code/z_message_PAL.c @@ -1663,7 +1663,10 @@ void Message_OpenText(GlobalContext* globalCtx, u16 textId) { gSaveContext.eventInf[0] = gSaveContext.eventInf[1] = gSaveContext.eventInf[2] = gSaveContext.eventInf[3] = 0; } - if (sTextIsCredits) { + // RANDOTODO: Use this for ice trap messages + if (CustomMessage_RetrieveIfExists(globalCtx)) { + osSyncPrintf("Found custom message"); + } else if (sTextIsCredits) { Message_FindCreditsMessage(globalCtx, textId); msgCtx->msgLength = font->msgLength; char* src = (uintptr_t)font->msgOffset; @@ -1674,232 +1677,9 @@ void Message_OpenText(GlobalContext* globalCtx, u16 textId) { //font->msgLength, __FILE__, __LINE__); } else { Message_FindMessage(globalCtx, textId); - // if we're rando'd and talking to a gossip stone - if (gSaveContext.n64ddFlag && - textId == 0x2053 && - Randomizer_GetSettingValue(RSK_GOSSIP_STONE_HINTS) != 0 && - (Randomizer_GetSettingValue(RSK_GOSSIP_STONE_HINTS) == 1 || - (Randomizer_GetSettingValue(RSK_GOSSIP_STONE_HINTS) == 2 && - Player_GetMask(globalCtx) == PLAYER_MASK_TRUTH) || - (Randomizer_GetSettingValue(RSK_GOSSIP_STONE_HINTS) == 3 && - CHECK_QUEST_ITEM(QUEST_STONE_OF_AGONY)))) { - - s16 actorParams = msgCtx->talkActor->params; - - // if we're in a generic grotto - if (globalCtx->sceneNum == 62 && actorParams == 14360) { - // look for the chest in the actorlist to determine - // which grotto we're in - int numOfActorLists = sizeof(globalCtx->actorCtx.actorLists)/sizeof(globalCtx->actorCtx.actorLists[0]); - for(int i = 0; i < numOfActorLists; i++) { - if(globalCtx->actorCtx.actorLists[i].length) { - if(globalCtx->actorCtx.actorLists[i].head->id == 10) { - // set the params for the hint check to be negative chest params - actorParams = 0 - globalCtx->actorCtx.actorLists[i].head->params; - } - } - } - } - - RandomizerCheck hintCheck = Randomizer_GetCheckFromActor(globalCtx->sceneNum, msgCtx->talkActor->id, actorParams); - - // Pass the sizeof the message buffer so we don't hardcode any sizes and can rely on globals. - // If no hint can be found, this just returns 0 size and doesn't modify the buffer, so no worries. - msgCtx->msgLength = font->msgLength = Randomizer_CopyHintFromCheck(hintCheck, font->msgBuf, sizeof(font->msgBuf)); - } else if (gSaveContext.n64ddFlag && (textId == 0x7040 || textId == 0x7088)) { - // rando hints at altar - msgCtx->msgLength = font->msgLength = Randomizer_CopyAltarMessage(font->msgBuf, sizeof(font->msgBuf)); - } else if (textId == 0x00b4 && CVar_GetS32("gInjectSkulltulaCount", 0) != 0) { - switch (gSaveContext.language) { - case LANGUAGE_FRA: - strcpy(font->msgBuf, "\x08\x13\x71Vous obtenez un \x05\x41Symbole de\x01Skulltula d'or\x05\x40! " - "Vous avez\x01\collect\x96 " - "\x05\x41\x19\x05\x40 symboles en tout!\x02"); - break; - case LANGUAGE_GER: - strcpy(font->msgBuf, "\x08\x13\x71\Du erh\x93lst ein \x05\x41Goldene\x01Skulltula-Symbol\x05\x40\! " - "Du hast\x01insgesamt " - "\x05\x41\x19\x05\x40 symbol gesammelt!\x02"); - break; - case LANGUAGE_ENG: default: - strcpy(font->msgBuf, - "\x08\x13\x71You got a \x05\x41Gold Skulltula Token\x05\x40!\x01You've collected " - "\x05\x41\x19\x05\x40 tokens\x01in total!\x02"); - break; - } - msgCtx->msgLength = font->msgLength = strlen(font->msgBuf); - } else if (gSaveContext.n64ddFlag && (textId == 0x10A2 || textId == 0x10DC || textId == 0x10DD)) { - msgCtx->msgLength = font->msgLength = CopyScrubMessage(textId, font->msgBuf, sizeof(font->msgBuf)); - } else if (gSaveContext.n64ddFlag && textId == 0x70CC) { - if (INV_CONTENT(ITEM_ARROW_LIGHT) == ITEM_ARROW_LIGHT) { - msgCtx->msgLength = font->msgLength = Randomizer_CopyGanonText(font->msgBuf, sizeof(font->msgBuf)); - } else { - msgCtx->msgLength = font->msgLength = Randomizer_CopyGanonHintText(font->msgBuf, sizeof(font->msgBuf)); - } - } else if (gSaveContext.n64ddFlag && textId == 0x60 && GET_PLAYER(globalCtx)->getItemId >= GI_GERUDO_FORTRESS_SMALL_KEY && GET_PLAYER(globalCtx)->getItemId <= GI_GANONS_CASTLE_SMALL_KEY) { - char* keyMsg; - switch (gSaveContext.language) { - case LANGUAGE_ENG: default: - switch (GET_PLAYER(globalCtx)->getItemId) { - case GI_GERUDO_FORTRESS_SMALL_KEY: - keyMsg = "\x08You got a \x05\x46\Thieves Hideout\x01\Small Key\x05\x40!\x09\x02"; - break; - case GI_FOREST_TEMPLE_SMALL_KEY: - keyMsg = "\x08You got a \x05\x42\Forest Temple\x01\Small Key\x05\x40!\x09\x02"; - break; - case GI_FIRE_TEMPLE_SMALL_KEY: - keyMsg = "\x08You got a \x05\x41\Fire Temple\x01\Small Key\x05\x40!\x09\x02"; - break; - case GI_WATER_TEMPLE_SMALL_KEY: - keyMsg = "\x08You got a \x05\x43\Water Temple\x01\Small Key\x05\x40!\x09\x02"; - break; - case GI_SPIRIT_TEMPLE_SMALL_KEY: - keyMsg = "\x08You got a \x05\x46\Spirit Temple\x01\Small Key\x05\x40!\x09\x02"; - break; - case GI_SHADOW_TEMPLE_SMALL_KEY: - keyMsg = "\x08You got a \x05\x45\Shadow Temple\x01\Small Key\x05\x40!\x09\x02"; - break; - case GI_BOTTOM_OF_THE_WELL_SMALL_KEY: - keyMsg = "\x08You got a \x05\x45\Bottom of the Well\x01\Small Key\x05\x40!\x09\x02"; - break; - case GI_GERUDO_TRAINING_GROUNDS_SMALL_KEY: - keyMsg = "\x08You got a \x05\x46\Gerudo Training Grounds\x01\Small Key\x05\x40!\x09\x02"; - break; - case GI_GANONS_CASTLE_SMALL_KEY: - keyMsg = "\x08You got a \x05\x41\Ganon's Castle\x01\Small Key\x05\x40!\x09\x02"; - break; - } - strcpy(font->msgBuf, keyMsg); - break; - } - msgCtx->msgLength = font->msgLength = strlen(font->msgBuf); - } else if (gSaveContext.n64ddFlag && textId == 0xC7 && GET_PLAYER(globalCtx)->getItemId >= GI_FOREST_TEMPLE_BOSS_KEY && GET_PLAYER(globalCtx)->getItemId <= GI_GANONS_CASTLE_BOSS_KEY) { - char* keyMsg; - switch (gSaveContext.language) { - case LANGUAGE_ENG: default: - switch (GET_PLAYER(globalCtx)->getItemId) { - case GI_FOREST_TEMPLE_BOSS_KEY: - keyMsg = "\x08You got a \x05\x42\Forest Temple\x01\Boss Key\x05\x40!\x09\x02"; - break; - case GI_FIRE_TEMPLE_BOSS_KEY: - keyMsg = "\x08You got a \x05\x41\Fire Temple\x01\Boss Key\x05\x40!\x09\x02"; - break; - case GI_WATER_TEMPLE_BOSS_KEY: - keyMsg = "\x08You got a \x05\x43\Water Temple\x01\Boss Key\x05\x40!\x09\x02"; - break; - case GI_SPIRIT_TEMPLE_BOSS_KEY: - keyMsg = "\x08You got a \x05\x46\Spirit Temple\x01\Boss Key\x05\x40!\x09\x02"; - break; - case GI_SHADOW_TEMPLE_BOSS_KEY: - keyMsg = "\x08You got a \x05\x45\Shadow Temple\x01\Boss Key\x05\x40!\x09\x02"; - break; - case GI_GANONS_CASTLE_BOSS_KEY: - keyMsg = "\x08You got a \x05\x41\Ganon's Castle\x01\Boss Key\x05\x40!\x09\x02"; - break; - } - strcpy(font->msgBuf, keyMsg); - break; - } - msgCtx->msgLength = font->msgLength = strlen(font->msgBuf); - } else if (gSaveContext.n64ddFlag && textId == 0x66 && GET_PLAYER(globalCtx)->getItemId >= GI_DEKU_TREE_MAP && GET_PLAYER(globalCtx)->getItemId <= GI_ICE_CAVERN_MAP) { - char* keyMsg; - switch (gSaveContext.language) { - case LANGUAGE_ENG: default: - switch (GET_PLAYER(globalCtx)->getItemId) { - case GI_DEKU_TREE_MAP: - keyMsg = "\x08You got the \x05\x42\Deku Tree Map\x05\x40!\x09\x02"; - break; - case GI_DODONGOS_CAVERN_MAP: - keyMsg = "\x08You got the \x05\x41\Dodongo's Cavern Map\x05\x40!\x09\x02"; - break; - case GI_JABU_JABUS_BELLY_MAP: - keyMsg = "\x08You got the \x05\x43\Jabu Jabu's Belly Map\x05\x40!\x09\x02"; - break; - case GI_FOREST_TEMPLE_MAP: - keyMsg = "\x08You got the \x05\x42\Forest Temple Map\x05\x40!\x09\x02"; - break; - case GI_FIRE_TEMPLE_MAP: - keyMsg = "\x08You got the \x05\x41\Fire Temple Map\x05\x40!\x09\x02"; - break; - case GI_WATER_TEMPLE_MAP: - keyMsg = "\x08You got the \x05\x43\Water Temple Map\x05\x40!\x09\x02"; - break; - case GI_SPIRIT_TEMPLE_MAP: - keyMsg = "\x08You got the \x05\x46\Spirit Temple Map\x05\x40!\x09\x02"; - break; - case GI_SHADOW_TEMPLE_MAP: - keyMsg = "\x08You got the \x05\x45\Shadow Temple Map\x05\x40!\x09\x02"; - break; - case GI_BOTTOM_OF_THE_WELL_MAP: - keyMsg = "\x08You got the \x05\x45\Bottom of the Well Map\x05\x40!\x09\x02"; - break; - case GI_ICE_CAVERN_MAP: - keyMsg = "\x08You got the \x05\x43\Ice Cavern Map\x05\x40!\x09\x02"; - break; - } - strcpy(font->msgBuf, keyMsg); - break; - } - msgCtx->msgLength = font->msgLength = strlen(font->msgBuf); - } else if (gSaveContext.n64ddFlag && textId == 0x67 && GET_PLAYER(globalCtx)->getItemId >= GI_DEKU_TREE_COMPASS && GET_PLAYER(globalCtx)->getItemId <= GI_ICE_CAVERN_COMPASS) { - char* keyMsg; - switch (gSaveContext.language) { - case LANGUAGE_ENG: default: - switch (GET_PLAYER(globalCtx)->getItemId) { - case GI_DEKU_TREE_COMPASS: - keyMsg = "\x08You got the \x05\x42\Deku Tree Compass\x05\x40!\x09\x02"; - break; - case GI_DODONGOS_CAVERN_COMPASS: - keyMsg = "\x08You got the \x05\x41\Dodongo's Cavern Compass\x05\x40!\x09\x02"; - break; - case GI_JABU_JABUS_BELLY_COMPASS: - keyMsg = "\x08You got the \x05\x43\Jabu Jabu's Belly Compass\x05\x40!\x09\x02"; - break; - case GI_FOREST_TEMPLE_COMPASS: - keyMsg = "\x08You got the \x05\x42\Forest Temple Compass\x05\x40!\x09\x02"; - break; - case GI_FIRE_TEMPLE_COMPASS: - keyMsg = "\x08You got the \x05\x41\Fire Temple Compass\x05\x40!\x09\x02"; - break; - case GI_WATER_TEMPLE_COMPASS: - keyMsg = "\x08You got the \x05\x43\Water Temple Compass\x05\x40!\x09\x02"; - break; - case GI_SPIRIT_TEMPLE_COMPASS: - keyMsg = "\x08You got the \x05\x46\Spirit Temple Compass\x05\x40!\x09\x02"; - break; - case GI_SHADOW_TEMPLE_COMPASS: - keyMsg = "\x08You got the \x05\x45\Shadow Temple Compass\x05\x40!\x09\x02"; - break; - case GI_BOTTOM_OF_THE_WELL_COMPASS: - keyMsg = "\x08You got the \x05\x45\Bottom of the Well Compass\x05\x40!\x09\x02"; - break; - case GI_ICE_CAVERN_COMPASS: - keyMsg = "\x08You got the \x05\x43\Ice Cavern Compass\x05\x40!\x09\x02"; - break; - } - strcpy(font->msgBuf, keyMsg); - break; - } - msgCtx->msgLength = font->msgLength = strlen(font->msgBuf); - } else if (textId == 0xF8 && GET_PLAYER(globalCtx)->getItemId == GI_ICE_TRAP) { - switch (gSaveContext.language) { - case LANGUAGE_FRA: - strcpy(font->msgBuf, "\x08\x06\x50\x05\x43IDIOT\x0E\x20\x02"); - break; - case LANGUAGE_GER: - strcpy(font->msgBuf, "\x08\x06\x15 Du bist ein\x05\x43 DUMMKOPF\x05\x40!\x0E\x20\x02"); - break; - case LANGUAGE_ENG: - default: - strcpy(font->msgBuf, "\x08\x06\x30You are a\x05\x43 FOWL\x05\x40!\x0E\x20\x02"); - break; - } - msgCtx->msgLength = font->msgLength = strlen(font->msgBuf); - } else { - msgCtx->msgLength = font->msgLength; - char* src = (uintptr_t)font->msgOffset; - memcpy(font->msgBuf, src, font->msgLength); - } + msgCtx->msgLength = font->msgLength; + char* src = (uintptr_t)font->msgOffset; + memcpy(font->msgBuf, src, font->msgLength); } msgCtx->textBoxProperties = font->charTexBuf[0]; diff --git a/soh/src/code/z_play.c b/soh/src/code/z_play.c index 5c3b97da6..104b7f1e4 100644 --- a/soh/src/code/z_play.c +++ b/soh/src/code/z_play.c @@ -277,11 +277,15 @@ void Gameplay_Init(GameState* thisx) { u8 tempSetupIndex; s32 pad[2]; - if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SKIP_CHILD_STEALTH)) { + // Skip Child Stealth when option is enabled, Zelda's Letter isn't obtained and Impa's reward hasn't been received + // eventChkInf[4] & 1 = Got Zelda's Letter + // eventChkInf[5] & 0x200 = Got Impa's reward + // entranceIndex 0x7A, Castle Courtyard - Day from crawlspace + // entranceIndex 0x400, Zelda's Courtyard + if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SKIP_CHILD_STEALTH) && + !(gSaveContext.eventChkInf[4] & 1) && !(gSaveContext.eventChkInf[5] & 0x200)) { if (gSaveContext.entranceIndex == 0x7A) { gSaveContext.entranceIndex = 0x400; - } else if (gSaveContext.entranceIndex == 0x296) { - gSaveContext.entranceIndex = 0x23D; } } diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index 24dfd2b1e..c211d93ec 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -895,12 +895,12 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { gSaveContext.eventChkInf[1] |= (1 << 3); gSaveContext.eventChkInf[1] |= (1 << 4); + // Set "Got Zelda's Letter" flag. Also ensures Saria is back at SFM. TODO: Is this flag used for anything else? + gSaveContext.eventChkInf[4] |= 1; + // Got item from impa gSaveContext.eventChkInf[5] |= 0x200; - // make sure saria is at SFM - gSaveContext.eventChkInf[4] |= (1 << 0); - // set this at the end to ensure we always start with the letter // this is for the off chance we got the weird egg from impa (which should never happen) INV_CONTENT(ITEM_LETTER_ZELDA) = ITEM_LETTER_ZELDA; diff --git a/soh/src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.h b/soh/src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.h index 401eb8b22..c25205729 100644 --- a/soh/src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.h +++ b/soh/src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.h @@ -24,7 +24,7 @@ typedef struct { /* 0x36 */ f32 pitch; /* 0x36 */ f32 yaw; /* 0x40 */ f32 roll; - /* 0x44 */ s32 epoch; + /* 0x44 */ u32 epoch; } BgDyYoseizoParticle; // size = 0x48 typedef struct BgDyYoseizo { diff --git a/soh/src/overlays/actors/ovl_Bg_Jya_Megami/z_bg_jya_megami.h b/soh/src/overlays/actors/ovl_Bg_Jya_Megami/z_bg_jya_megami.h index 4198781b0..8ccac6a95 100644 --- a/soh/src/overlays/actors/ovl_Bg_Jya_Megami/z_bg_jya_megami.h +++ b/soh/src/overlays/actors/ovl_Bg_Jya_Megami/z_bg_jya_megami.h @@ -13,7 +13,7 @@ typedef struct { /* 0x0C */ Vec3f vel; /* 0x18 */ s16 rotVelX; /* 0x1A */ s16 rotVelY; - /* 0x1C */ s32 epoch; + /* 0x1C */ u32 epoch; } BgJyaMegamiPiece; // size = 0x20 typedef struct BgJyaMegami { diff --git a/soh/src/overlays/actors/ovl_Bg_Spot00_Hanebasi/z_bg_spot00_hanebasi.c b/soh/src/overlays/actors/ovl_Bg_Spot00_Hanebasi/z_bg_spot00_hanebasi.c index d74a39624..50b3e1fc4 100644 --- a/soh/src/overlays/actors/ovl_Bg_Spot00_Hanebasi/z_bg_spot00_hanebasi.c +++ b/soh/src/overlays/actors/ovl_Bg_Spot00_Hanebasi/z_bg_spot00_hanebasi.c @@ -261,7 +261,7 @@ void BgSpot00Hanebasi_DrawTorches(Actor* thisx, GlobalContext* globalCtx2) { GlobalContext* globalCtx = globalCtx2; f32 angle; s32 i; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(globalCtx->state.gfxCtx); diff --git a/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.h b/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.h index f920b44a6..ddc76960c 100644 --- a/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.h +++ b/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.h @@ -17,7 +17,7 @@ typedef struct { /* 0x26 */ Color_RGB8 color; /* 0x2A */ s16 alpha; /* 0x2C */ f32 unk_2C; - /* 0x30 */ s32 epoch; + /* 0x30 */ u32 epoch; } BossDodongoEffect; // Size = 0x34 typedef struct BossDodongo { 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 8afb08ba1..b1bfeb5de 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 @@ -1835,7 +1835,7 @@ void BossFd_DrawBody(GlobalContext* globalCtx, BossFd* this) { s16 i; f32 temp_float; Mtx* tempMat = Graph_Alloc(globalCtx->state.gfxCtx, 18 * sizeof(Mtx)); - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(globalCtx->state.gfxCtx); diff --git a/soh/src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2.h b/soh/src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2.h index 3bc77b0b7..7133b78a6 100644 --- a/soh/src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2.h +++ b/soh/src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2.h @@ -87,7 +87,7 @@ typedef struct BossFd2 { /* 0x1394 */ BossFd2Cam camData; /* 0x141C */ ColliderJntSph collider; /* 0x143C */ ColliderJntSphElement elements[9]; - /* 0x167C */ s32 epoch; + /* 0x167C */ u32 epoch; } BossFd2; // size = 0x1680 #endif 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 10e118c17..da84d0f5e 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 @@ -3356,7 +3356,7 @@ void BossGanon_DrawShock(BossGanon* this, GlobalContext* globalCtx) { s32 pad; GraphicsContext* gfxCtx = globalCtx->state.gfxCtx; s16 i; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(gfxCtx); @@ -3463,7 +3463,7 @@ void BossGanon_DrawBigMagicCharge(BossGanon* this, GlobalContext* globalCtx) { f32 yRot; GraphicsContext* gfxCtx = globalCtx->state.gfxCtx; s16 i; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(gfxCtx); @@ -4158,7 +4158,7 @@ void BossGanon_LightBall_Draw(Actor* thisx, GlobalContext* globalCtx) { s16 i; f32 alpha; s32 pad; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(globalCtx->state.gfxCtx); 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 ecc084be3..1f5455e24 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 @@ -2464,7 +2464,7 @@ void func_80904340(BossGanon2* this, GlobalContext* globalCtx) { f32 angle; f32 sin; f32 cos; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(globalCtx->state.gfxCtx); @@ -2637,7 +2637,7 @@ void BossGanon2_PostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dLis void func_80904D88(BossGanon2* this, GlobalContext* globalCtx) { s32 pad; s16 i; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(globalCtx->state.gfxCtx); @@ -2701,7 +2701,7 @@ void func_80904FC8(BossGanon2* this, GlobalContext* globalCtx) { void func_8090523C(BossGanon2* this, GlobalContext* globalCtx) { Player* player; f32 phi_f20; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(globalCtx->state.gfxCtx); @@ -2933,7 +2933,7 @@ void func_809060E8(GlobalContext* globalCtx) { BossGanon2Effect* effect; s16 i; BossGanon2Effect* effects; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; effects = effect = globalCtx->specialEffects; 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 b7756765a..ae326d696 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 @@ -2443,7 +2443,7 @@ void BossMo_DrawTentacle(BossMo* this, GlobalContext* globalCtx) { f32 phi_f20; f32 phi_f22; Vec3f sp110; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(globalCtx->state.gfxCtx); 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 1a1a93b07..31d1488a7 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 @@ -2706,7 +2706,7 @@ s32 BossSst_OverrideHandTrailDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** void BossSst_DrawHand(Actor* thisx, GlobalContext* globalCtx) { BossSst* this = (BossSst*)thisx; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(globalCtx->state.gfxCtx); diff --git a/soh/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.h b/soh/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.h index 32c12b7fd..ea287fb1b 100644 --- a/soh/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.h +++ b/soh/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.h @@ -17,7 +17,7 @@ typedef struct { /* 0x0020 */ s16 move; /* 0x0022 */ s16 status; /* 0x0024 */ u8 alpha; - /* 0x0028 */ s32 epoch; + /* 0x0028 */ u32 epoch; } BossSstEffect; // size = 0x2C typedef struct { 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 1252df4bf..533420b06 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 @@ -3329,7 +3329,7 @@ void func_80942180(BossTw* this, GlobalContext* globalCtx) { void func_809426F0(BossTw* this, GlobalContext* globalCtx) { s32 pad; s16 i; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(globalCtx->state.gfxCtx); @@ -4418,7 +4418,7 @@ void BossTw_BlastDraw(Actor* thisx, GlobalContext* globalCtx2) { f32 scaleFactor; s16 tailIdx; s16 i; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(globalCtx->state.gfxCtx); @@ -4492,7 +4492,7 @@ void BossTw_DrawDeathBall(Actor* thisx, GlobalContext* globalCtx2) { f32 scaleFactor; s16 tailIdx; s16 i; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(globalCtx->state.gfxCtx); diff --git a/soh/src/overlays/actors/ovl_Boss_Tw/z_boss_tw.h b/soh/src/overlays/actors/ovl_Boss_Tw/z_boss_tw.h index 1a4a31438..5560f58d7 100644 --- a/soh/src/overlays/actors/ovl_Boss_Tw/z_boss_tw.h +++ b/soh/src/overlays/actors/ovl_Boss_Tw/z_boss_tw.h @@ -43,7 +43,7 @@ typedef struct { /* 0x002E */ s16 work[EFF_WORK_MAX]; /* 0x0034 */ f32 workf[EFF_FWORK_MAX]; /* 0x0044 */ Actor* target; - s32 epoch; + u32 epoch; } BossTwEffect; typedef enum { 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 b4236ef25..c8134866a 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 @@ -4006,7 +4006,7 @@ void BossVa_DrawDoor(GlobalContext* globalCtx, s16 scale) { f32 yScale; f32 segAngle = 0.0f; s32 i; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(globalCtx->state.gfxCtx); diff --git a/soh/src/overlays/actors/ovl_Demo_6K/z_demo_6k.c b/soh/src/overlays/actors/ovl_Demo_6K/z_demo_6k.c index fd131a244..bd1bafc0a 100644 --- a/soh/src/overlays/actors/ovl_Demo_6K/z_demo_6k.c +++ b/soh/src/overlays/actors/ovl_Demo_6K/z_demo_6k.c @@ -564,7 +564,7 @@ void func_80967FFC(Actor* thisx, GlobalContext* globalCtx) { Demo6K* this = (Demo6K*)thisx; s32 pad; u16 timer1 = this->timer1; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(globalCtx->state.gfxCtx); @@ -695,7 +695,7 @@ void func_809688C4(Actor* thisx, GlobalContext* globalCtx2) { GlobalContext* globalCtx = globalCtx2; u32 frames = globalCtx->state.frames; s32 i; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; if ((i = (globalCtx->csCtx.state != CS_STATE_IDLE) && (globalCtx->csCtx.npcActions[1] != NULL)) && diff --git a/soh/src/overlays/actors/ovl_Demo_Kankyo/z_demo_kankyo.c b/soh/src/overlays/actors/ovl_Demo_Kankyo/z_demo_kankyo.c index 6ca6a025b..ca162f584 100644 --- a/soh/src/overlays/actors/ovl_Demo_Kankyo/z_demo_kankyo.c +++ b/soh/src/overlays/actors/ovl_Demo_Kankyo/z_demo_kankyo.c @@ -522,7 +522,7 @@ void DemoKankyo_DrawRain(Actor* thisx, GlobalContext* globalCtx) { f32 translateY; f32 translateZ; s16 j; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(globalCtx->state.gfxCtx); @@ -663,7 +663,7 @@ void DemoKankyo_DrawClouds(Actor* thisx, GlobalContext* globalCtx) { f32 dx; f32 dy; f32 dz; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(globalCtx->state.gfxCtx); @@ -784,7 +784,7 @@ void DemoKankyo_DrawWarpSparkles(Actor* thisx, GlobalContext* globalCtx) { f32 translateZ; PosRot posRot; u8 linkAge = gSaveContext.linkAge; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(globalCtx->state.gfxCtx); @@ -933,7 +933,7 @@ void DemoKankyo_DrawSparkles(Actor* thisx, GlobalContext* globalCtx) { f32 scale; s16 i; PosRot posRot; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(globalCtx->state.gfxCtx); diff --git a/soh/src/overlays/actors/ovl_Efc_Erupc/z_efc_erupc.h b/soh/src/overlays/actors/ovl_Efc_Erupc/z_efc_erupc.h index 6e7fa6693..596159815 100644 --- a/soh/src/overlays/actors/ovl_Efc_Erupc/z_efc_erupc.h +++ b/soh/src/overlays/actors/ovl_Efc_Erupc/z_efc_erupc.h @@ -19,7 +19,7 @@ typedef struct { /* 0x30 */ char unk_2C[4]; /* 0x34 */ f32 scale; /* 0x38 */ char unk_34[8]; - /* 0x3C */ s32 epoch; + /* 0x3C */ u32 epoch; } EfcErupcParticles; // size 0x40 #define EFC_ERUPC_NUM_PARTICLES 100 diff --git a/soh/src/overlays/actors/ovl_Eff_Dust/z_eff_dust.c b/soh/src/overlays/actors/ovl_Eff_Dust/z_eff_dust.c index e3af7ba4d..b9bd8e311 100644 --- a/soh/src/overlays/actors/ovl_Eff_Dust/z_eff_dust.c +++ b/soh/src/overlays/actors/ovl_Eff_Dust/z_eff_dust.c @@ -269,7 +269,7 @@ void EffDust_DrawFunc_8099E4F4(Actor* thisx, GlobalContext* globalCtx2) { f32* distanceTraveled; s32 i; f32 aux; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(gfxCtx); @@ -321,7 +321,7 @@ void EffDust_DrawFunc_8099E784(Actor* thisx, GlobalContext* globalCtx2) { s32 i; f32 aux; Player* player = GET_PLAYER(globalCtx); - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(gfxCtx); diff --git a/soh/src/overlays/actors/ovl_En_Anubice_Fire/z_en_anubice_fire.h b/soh/src/overlays/actors/ovl_En_Anubice_Fire/z_en_anubice_fire.h index 848bcdae9..aa6359c48 100644 --- a/soh/src/overlays/actors/ovl_En_Anubice_Fire/z_en_anubice_fire.h +++ b/soh/src/overlays/actors/ovl_En_Anubice_Fire/z_en_anubice_fire.h @@ -19,7 +19,7 @@ typedef struct EnAnubiceFire { /* 0x015E */ s16 unk_15E; /* 0x0178 */ Vec3f unk_160[6]; /* 0x01A8 */ ColliderCylinder cylinder; - /* 0x01F4 */ s32 epoch; + /* 0x01F4 */ u32 epoch; } EnAnubiceFire; // size = 0x01F8 #endif diff --git a/soh/src/overlays/actors/ovl_En_Ba/z_en_ba.h b/soh/src/overlays/actors/ovl_En_Ba/z_en_ba.h index a43c33e81..1996a09bc 100644 --- a/soh/src/overlays/actors/ovl_En_Ba/z_en_ba.h +++ b/soh/src/overlays/actors/ovl_En_Ba/z_en_ba.h @@ -32,7 +32,7 @@ typedef struct EnBa { /* 0x031C */ s16 unk31C; /* 0x0320 */ ColliderJntSph collider; /* 0x0340 */ ColliderJntSphElement colliderItems[2]; - /* 0x03C0 */ s32 epoch; + /* 0x03C0 */ u32 epoch; } EnBa; // size = 0x03C4 #endif diff --git a/soh/src/overlays/actors/ovl_En_Boom/z_en_boom.c b/soh/src/overlays/actors/ovl_En_Boom/z_en_boom.c index f041d55bd..e79d14109 100644 --- a/soh/src/overlays/actors/ovl_En_Boom/z_en_boom.c +++ b/soh/src/overlays/actors/ovl_En_Boom/z_en_boom.c @@ -167,12 +167,12 @@ void EnBoom_Fly(EnBoom* this, GlobalContext* globalCtx) { // Decrement the return timer and check if it's 0. If it is, check if Link can catch it and handle accordingly. // Otherwise handle grabbing and colliding. - if (DECR(this->returnTimer) == 0) { + if (DECR(this->returnTimer) == 0 || player->boomerangQuickRecall) { distFromLink = Math_Vec3f_DistXYZ(&this->actor.world.pos, &player->actor.focus.pos); this->moveTo = &player->actor; // If the boomerang is less than 40 units away from Link, he can catch it. - if (distFromLink < 40.0f) { + if (distFromLink < 40.0f || player->boomerangQuickRecall) { target = this->grabbed; if (target != NULL) { Math_Vec3f_Copy(&target->world.pos, &player->actor.world.pos); @@ -187,7 +187,8 @@ void EnBoom_Fly(EnBoom* this, GlobalContext* globalCtx) { } } // Set player flags and kill the boomerang beacause Link caught it. - player->stateFlags1 &= ~0x02000000; + player->stateFlags1 &= ~PLAYER_STATE1_25; + player->boomerangQuickRecall = false; Actor_Kill(&this->actor); } } else { diff --git a/soh/src/overlays/actors/ovl_En_Bx/z_en_bx.h b/soh/src/overlays/actors/ovl_En_Bx/z_en_bx.h index e842ce3a0..87f9370d6 100644 --- a/soh/src/overlays/actors/ovl_En_Bx/z_en_bx.h +++ b/soh/src/overlays/actors/ovl_En_Bx/z_en_bx.h @@ -16,7 +16,7 @@ typedef struct EnBx { /* 0x01B4 */ Vec3s unk_1B4[4]; /* 0x01CC */ ColliderCylinder collider; /* 0x0218 */ ColliderQuad colliderQuad; - /* 0x0298 */ s32 epoch; + /* 0x0298 */ u32 epoch; } EnBx; // size = 0x029C #endif diff --git a/soh/src/overlays/actors/ovl_En_Clear_Tag/z_en_clear_tag.h b/soh/src/overlays/actors/ovl_En_Clear_Tag/z_en_clear_tag.h index 4c9b92584..f6328ea8d 100644 --- a/soh/src/overlays/actors/ovl_En_Clear_Tag/z_en_clear_tag.h +++ b/soh/src/overlays/actors/ovl_En_Clear_Tag/z_en_clear_tag.h @@ -88,7 +88,7 @@ typedef struct EnClearTagEffect { /* 0x0058 */ f32 rotationX; /* 0x005C */ f32 floorHeight; /* 0x0060 */ Vec3f floorTangent; - /* 0x006C */ s32 epoch; + /* 0x006C */ u32 epoch; } EnClearTagEffect; // size = 0x70 #define CLEAR_TAG_EFFECT_MAX_COUNT 100 diff --git a/soh/src/overlays/actors/ovl_En_Encount2/z_en_encount2.h b/soh/src/overlays/actors/ovl_En_Encount2/z_en_encount2.h index b4c7db491..9e3aca0eb 100644 --- a/soh/src/overlays/actors/ovl_En_Encount2/z_en_encount2.h +++ b/soh/src/overlays/actors/ovl_En_Encount2/z_en_encount2.h @@ -14,7 +14,7 @@ typedef struct { /* 0x0010 */ u8 isAlive; /* 0x0014 */ Vec3f moveDirection; /* 0x0020 */ Vec3f rot; - /* 0x002C */ s32 epoch; + /* 0x002C */ u32 epoch; } EnEncount2Particle; // size = 0x30 typedef struct EnEncount2 { diff --git a/soh/src/overlays/actors/ovl_En_Fd/z_en_fd.h b/soh/src/overlays/actors/ovl_En_Fd/z_en_fd.h index 7dc990a7e..0ee372369 100644 --- a/soh/src/overlays/actors/ovl_En_Fd/z_en_fd.h +++ b/soh/src/overlays/actors/ovl_En_Fd/z_en_fd.h @@ -25,7 +25,7 @@ typedef struct { /* 0x0014 */ Vec3f pos; /* 0x0020 */ Vec3f velocity; /* 0x002C */ Vec3f accel; - s32 epoch; + u32 epoch; } EnFdEffect; // size = 0x38 typedef struct EnFd { diff --git a/soh/src/overlays/actors/ovl_En_Fw/z_en_fw.h b/soh/src/overlays/actors/ovl_En_Fw/z_en_fw.h index 0230a2c3d..79279a71f 100644 --- a/soh/src/overlays/actors/ovl_En_Fw/z_en_fw.h +++ b/soh/src/overlays/actors/ovl_En_Fw/z_en_fw.h @@ -19,7 +19,7 @@ typedef struct { /* 0x0014 */ Vec3f pos; /* 0x0020 */ Vec3f velocity; /* 0x002C */ Vec3f accel; - s32 epoch; + u32 epoch; } EnFwEffect; typedef struct EnFw { diff --git a/soh/src/overlays/actors/ovl_En_Fz/z_en_fz.h b/soh/src/overlays/actors/ovl_En_Fz/z_en_fz.h index 471a2fce2..7dab02bbc 100644 --- a/soh/src/overlays/actors/ovl_En_Fz/z_en_fz.h +++ b/soh/src/overlays/actors/ovl_En_Fz/z_en_fz.h @@ -21,7 +21,7 @@ typedef struct { /* 0x0030 */ f32 xyScale; // /* 0x0034 */ f32 xyScaleTarget; /* 0x0038 */ u8 isTimerMod8; // conditional, used to run CollisionCheck_SetAT - s32 epoch; + u32 epoch; } EnFzEffectSsIceSmoke; // size = 0x3C typedef struct EnFz { diff --git a/soh/src/overlays/actors/ovl_En_G_Switch/z_en_g_switch.h b/soh/src/overlays/actors/ovl_En_G_Switch/z_en_g_switch.h index 366a7d120..38b6de292 100644 --- a/soh/src/overlays/actors/ovl_En_G_Switch/z_en_g_switch.h +++ b/soh/src/overlays/actors/ovl_En_G_Switch/z_en_g_switch.h @@ -32,7 +32,7 @@ typedef struct { /* 0x12 */ u8 flag; /* 0x14 */ Vec3f velocity; /* 0x20 */ Vec3f rot; - s32 epoch; + u32 epoch; } EnGSwitchEffect; // size = 0x2C typedef struct EnGSwitch { diff --git a/soh/src/overlays/actors/ovl_En_Gb/z_en_gb.h b/soh/src/overlays/actors/ovl_En_Gb/z_en_gb.h index 48908d7e5..e72a33f14 100644 --- a/soh/src/overlays/actors/ovl_En_Gb/z_en_gb.h +++ b/soh/src/overlays/actors/ovl_En_Gb/z_en_gb.h @@ -27,7 +27,7 @@ typedef struct { /* 0x20 */ f32 unk_20; /* 0x24 */ f32 unk_24; /* 0x28 */ f32 unk_28; - s32 epoch; + u32 epoch; } EnGbCagedSoul; // size = 0x2C typedef struct EnGb { diff --git a/soh/src/overlays/actors/ovl_En_Go/z_en_go.h b/soh/src/overlays/actors/ovl_En_Go/z_en_go.h index 94bad5bab..e54d45bfc 100644 --- a/soh/src/overlays/actors/ovl_En_Go/z_en_go.h +++ b/soh/src/overlays/actors/ovl_En_Go/z_en_go.h @@ -34,7 +34,7 @@ typedef struct { /* 0x0014 */ Vec3f pos; /* 0x0020 */ Vec3f velocity; /* 0x002C */ Vec3f accel; - s32 epoch; + u32 epoch; } EnGoEffect; // size = 0x38 typedef struct EnGo { diff --git a/soh/src/overlays/actors/ovl_En_Heishi1/z_en_heishi1.c b/soh/src/overlays/actors/ovl_En_Heishi1/z_en_heishi1.c index d2d9fac4b..5a313a07f 100644 --- a/soh/src/overlays/actors/ovl_En_Heishi1/z_en_heishi1.c +++ b/soh/src/overlays/actors/ovl_En_Heishi1/z_en_heishi1.c @@ -112,14 +112,23 @@ void EnHeishi1_Init(Actor* thisx, GlobalContext* globalCtx) { } } + // eventChkInf[4] & 1 = Got Zelda's Letter + // eventChkInf[5] & 0x200 = Got item from impa + // eventChkInf[8] & 1 = Ocarina thrown in moat + bool metZelda = (gSaveContext.eventChkInf[4] & 1) && (gSaveContext.eventChkInf[5] & 0x200); + if (this->type != 5) { - if (((gSaveContext.dayTime < 0xB888) || IS_DAY) && (gSaveContext.n64ddFlag || !(gSaveContext.eventChkInf[8] & 1))) { + if ((gSaveContext.dayTime < 0xB888 || IS_DAY) && + ((!gSaveContext.n64ddFlag && !(gSaveContext.eventChkInf[8] & 1)) || + (gSaveContext.n64ddFlag && !metZelda))) { this->actionFunc = EnHeishi1_SetupWalk; } else { Actor_Kill(&this->actor); } } else { - if ((gSaveContext.dayTime >= 0xB889) || !IS_DAY || (!gSaveContext.n64ddFlag && (gSaveContext.eventChkInf[8] & 1))) { + if ((gSaveContext.dayTime >= 0xB889) || !IS_DAY || + (!gSaveContext.n64ddFlag && gSaveContext.eventChkInf[8] & 1) || + (gSaveContext.n64ddFlag && metZelda)) { this->actionFunc = EnHeishi1_SetupWaitNight; } else { Actor_Kill(&this->actor); diff --git a/soh/src/overlays/actors/ovl_En_Niw/z_en_niw.h b/soh/src/overlays/actors/ovl_En_Niw/z_en_niw.h index 78d52af33..5c481e5e6 100644 --- a/soh/src/overlays/actors/ovl_En_Niw/z_en_niw.h +++ b/soh/src/overlays/actors/ovl_En_Niw/z_en_niw.h @@ -18,7 +18,7 @@ typedef struct { /* 0x002C */ f32 scale; /* 0x0030 */ f32 unk_30; /* 0x0034 */ u8 timer; - s32 epoch; + u32 epoch; } EnNiwFeather; // size = 0x0038 typedef struct EnNiw { diff --git a/soh/src/overlays/actors/ovl_En_Nwc/z_en_nwc.h b/soh/src/overlays/actors/ovl_En_Nwc/z_en_nwc.h index fa57bb2f3..eb4d9fb1d 100644 --- a/soh/src/overlays/actors/ovl_En_Nwc/z_en_nwc.h +++ b/soh/src/overlays/actors/ovl_En_Nwc/z_en_nwc.h @@ -23,7 +23,7 @@ typedef struct EnNwcChick { /* 0x36 */ u16 height; /* 0x38 */ CollisionPoly* floorPoly; /* 0x44 */ char unk_3C[0x20]; - s32 epoch; + u32 epoch; } EnNwcChick; // size = 0x5C typedef struct EnNwc { diff --git a/soh/src/overlays/actors/ovl_En_Ny/z_en_ny.h b/soh/src/overlays/actors/ovl_En_Ny/z_en_ny.h index ebc358254..407a2d761 100644 --- a/soh/src/overlays/actors/ovl_En_Ny/z_en_ny.h +++ b/soh/src/overlays/actors/ovl_En_Ny/z_en_ny.h @@ -30,7 +30,7 @@ typedef struct EnNy { /* 0x01F0 */ f32 unk_1F0; /* 0x01F4 */ f32 unk_1F4; /* 0x01F8 */ Vec3f unk_1F8[16]; - s32 epoch; + u32 epoch; } EnNy; // size = 0x02B8 #endif diff --git a/soh/src/overlays/actors/ovl_En_Po_Sisters/z_en_po_sisters.h b/soh/src/overlays/actors/ovl_En_Po_Sisters/z_en_po_sisters.h index cc55a1dc9..0e9464738 100644 --- a/soh/src/overlays/actors/ovl_En_Po_Sisters/z_en_po_sisters.h +++ b/soh/src/overlays/actors/ovl_En_Po_Sisters/z_en_po_sisters.h @@ -29,7 +29,7 @@ typedef struct EnPoSisters { /* 0x029C */ LightInfo lightInfo; /* 0x02AC */ ColliderCylinder collider; /* 0x02F8 */ MtxF unk_2F8; - s32 epoch; + u32 epoch; } EnPoSisters; // size = 0x0338 #endif diff --git a/soh/src/overlays/actors/ovl_En_Ru1/z_en_ru1.c b/soh/src/overlays/actors/ovl_En_Ru1/z_en_ru1.c index 4b55990da..0abbb4cd3 100644 --- a/soh/src/overlays/actors/ovl_En_Ru1/z_en_ru1.c +++ b/soh/src/overlays/actors/ovl_En_Ru1/z_en_ru1.c @@ -760,6 +760,14 @@ void func_80AEC2C0(EnRu1* this, GlobalContext* globalCtx) { func_80AEC070(this, globalCtx, something); } +// Convenience function used so that Ruto always spawns in Jabu in rando, even after she's been kidnapped +// Equivalent to !(gSaveContext.infTable[20] & 0x20) in vanilla +bool shouldSpawnRuto() { + // gSaveContext.infTable[20] & 0x40 check is to prevent Ruto from spawning during the short period of time when + // she's on the Zora's Sapphire pedestal but hasn't been kidnapped yet (would result in multiple Rutos otherwise) + return !(gSaveContext.infTable[20] & 0x20) || (gSaveContext.n64ddFlag && (gSaveContext.infTable[20] & 0x40)); +} + void func_80AEC320(EnRu1* this, GlobalContext* globalCtx) { s8 actorRoom; @@ -767,8 +775,7 @@ void func_80AEC320(EnRu1* this, GlobalContext* globalCtx) { func_80AEB264(this, &gRutoChildWait2Anim, 0, 0, 0); this->action = 7; EnRu1_SetMouthIndex(this, 1); - } else if ((gSaveContext.infTable[20] & 0x80) && !(gSaveContext.infTable[20] & 1) && - !(gSaveContext.infTable[20] & 0x20)) { + } else if ((gSaveContext.infTable[20] & 0x80) && !(gSaveContext.infTable[20] & 1) && shouldSpawnRuto()) { if (!func_80AEB020(this, globalCtx)) { func_80AEB264(this, &gRutoChildWait2Anim, 0, 0, 0); actorRoom = this->actor.room; @@ -1172,7 +1179,7 @@ void func_80AED414(EnRu1* this, GlobalContext* globalCtx) { void func_80AED44C(EnRu1* this, GlobalContext* globalCtx) { s8 actorRoom; - if ((gSaveContext.infTable[20] & 2) && !(gSaveContext.infTable[20] & 0x20) && !(gSaveContext.infTable[20] & 1) && + if ((gSaveContext.infTable[20] & 2) && shouldSpawnRuto() && !(gSaveContext.infTable[20] & 1) && !(gSaveContext.infTable[20] & 0x80)) { if (!func_80AEB020(this, globalCtx)) { func_80AEB264(this, &gRutoChildWait2Anim, 0, 0, 0); @@ -2179,7 +2186,7 @@ void func_80AEFF40(EnRu1* this, GlobalContext* globalCtx) { void func_80AEFF94(EnRu1* this, GlobalContext* globalCtx) { s8 actorRoom; - if ((gSaveContext.infTable[20] & 2) && (gSaveContext.infTable[20] & 1) && !(gSaveContext.infTable[20] & 0x20) && + if ((gSaveContext.infTable[20] & 2) && (gSaveContext.infTable[20] & 1) && shouldSpawnRuto() && (!(func_80AEB020(this, globalCtx)))) { func_80AEB264(this, &gRutoChildWait2Anim, 0, 0, 0); actorRoom = this->actor.room; diff --git a/soh/src/overlays/actors/ovl_En_Syateki_Niw/z_en_syateki_niw.h b/soh/src/overlays/actors/ovl_En_Syateki_Niw/z_en_syateki_niw.h index dfa493817..aa9b5dde8 100644 --- a/soh/src/overlays/actors/ovl_En_Syateki_Niw/z_en_syateki_niw.h +++ b/soh/src/overlays/actors/ovl_En_Syateki_Niw/z_en_syateki_niw.h @@ -18,7 +18,7 @@ typedef struct { /* 0x2C */ f32 unk_2C; /* 0x30 */ f32 unk_30; /* 0x34 */ u8 unk_34; - s32 epoch; + u32 epoch; } EnSyatekiNiw_1; // size = 0x38 typedef struct EnSyatekiNiw { diff --git a/soh/src/overlays/actors/ovl_En_Ta/z_en_ta.c b/soh/src/overlays/actors/ovl_En_Ta/z_en_ta.c index dad7d25e5..85e47a7e7 100644 --- a/soh/src/overlays/actors/ovl_En_Ta/z_en_ta.c +++ b/soh/src/overlays/actors/ovl_En_Ta/z_en_ta.c @@ -460,10 +460,13 @@ void func_80B14AF4(EnTa* this, GlobalContext* globalCtx) { void func_80B14B6C(EnTa* this, GlobalContext* globalCtx) { if (Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_EVENT) { - OnePointCutscene_Init(globalCtx, 4175, -99, &this->actor, MAIN_CAM); + s16 csCamIdx = OnePointCutscene_Init(globalCtx, 4175, -99, &this->actor, MAIN_CAM); func_80B13AA0(this, func_80B14AF4, func_80B167C0); this->unk_2CC = 5; gSaveContext.eventChkInf[1] |= 0x10; + if (gSaveContext.n64ddFlag) { + OnePointCutscene_EndCutscene(globalCtx, csCamIdx); + } Animation_PlayOnce(&this->skelAnime, &gTalonRunTransitionAnim); this->currentAnimation = &gTalonRunAnim; } diff --git a/soh/src/overlays/actors/ovl_En_Tk/z_en_tk.h b/soh/src/overlays/actors/ovl_En_Tk/z_en_tk.h index 82fb6eef3..1dff6a252 100644 --- a/soh/src/overlays/actors/ovl_En_Tk/z_en_tk.h +++ b/soh/src/overlays/actors/ovl_En_Tk/z_en_tk.h @@ -17,7 +17,7 @@ typedef struct EnTkEff { /* 0x0014 */ Vec3f pos; /* 0x0020 */ Vec3f speed; /* 0x002C */ Vec3f accel; - s32 epoch; + u32 epoch; } EnTkEff; // size = 0x0038 struct EnTk; diff --git a/soh/src/overlays/actors/ovl_En_Viewer/z_en_viewer.h b/soh/src/overlays/actors/ovl_En_Viewer/z_en_viewer.h index d16613fcf..c6ca0eb80 100644 --- a/soh/src/overlays/actors/ovl_En_Viewer/z_en_viewer.h +++ b/soh/src/overlays/actors/ovl_En_Viewer/z_en_viewer.h @@ -56,7 +56,7 @@ typedef struct { /* 0x28 */ f32 scale; /* 0x2C */ f32 lerpFactor; /* 0x30 */ u8 state; - s32 epoch; + u32 epoch; } EnViewerFireEffect; // size = 0x34 typedef struct EnViewer { diff --git a/soh/src/overlays/actors/ovl_Fishing/z_fishing.c b/soh/src/overlays/actors/ovl_Fishing/z_fishing.c index 5f404c4ad..1cb3b53e9 100644 --- a/soh/src/overlays/actors/ovl_Fishing/z_fishing.c +++ b/soh/src/overlays/actors/ovl_Fishing/z_fishing.c @@ -90,7 +90,7 @@ typedef struct { /* 0x32 */ s16 timer; /* 0x34 */ u8 shouldDraw; /* 0x38 */ f32 drawDistance; - s32 epoch; + u32 epoch; } FishingProp; // size = 0x3C typedef enum { @@ -116,7 +116,7 @@ typedef struct { /* 0x40 */ s16 unk_40; /* 0x42 */ s16 unk_42; /* 0x44 */ u8 shouldDraw; - s32 epoch; + u32 epoch; } FishingGroupFish; // size = 0x48 #define LINE_SEG_COUNT 200 @@ -1766,7 +1766,7 @@ static f32 sSinkingLureSizes[] = { void Fishing_DrawSinkingLure(GlobalContext* globalCtx) { s16 i; f32 scale; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; OPEN_DISPS(globalCtx->state.gfxCtx); diff --git a/soh/src/overlays/actors/ovl_Mir_Ray/z_mir_ray.c b/soh/src/overlays/actors/ovl_Mir_Ray/z_mir_ray.c index c332590dd..9ea675b55 100644 --- a/soh/src/overlays/actors/ovl_Mir_Ray/z_mir_ray.c +++ b/soh/src/overlays/actors/ovl_Mir_Ray/z_mir_ray.c @@ -482,7 +482,7 @@ void MirRay_Draw(Actor* thisx, GlobalContext* globalCtx) { s32 i; MirRayShieldReflection reflection[6]; s32 temp; - static s32 epoch = 0; + static u32 epoch = 0; epoch++; this->reflectIntensity = 0.0f; diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index 8c5914cca..db5ad2dd1 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -20,6 +20,7 @@ #include "objects/gameplay_keep/gameplay_keep.h" #include "objects/object_link_child/object_link_child.h" #include "textures/icon_item_24_static/icon_item_24_static.h" +#include #define GET_ITEM(itemId, objectId, drawId, textId, field, chestAnim) \ { itemId, field, (chestAnim != CHEST_ANIM_SHORT ? 1 : -1) * (drawId + 1), textId, objectId } @@ -138,10 +139,10 @@ s32 func_808353D8(Player* this, GlobalContext* globalCtx); s32 func_80835588(Player* this, GlobalContext* globalCtx); s32 func_808356E8(Player* this, GlobalContext* globalCtx); s32 func_80835800(Player* this, GlobalContext* globalCtx); -s32 func_80835884(Player* this, GlobalContext* globalCtx); -s32 func_808358F0(Player* this, GlobalContext* globalCtx); -s32 func_808359FC(Player* this, GlobalContext* globalCtx); -s32 func_80835B60(Player* this, GlobalContext* globalCtx); +s32 func_80835884(Player* this, GlobalContext* globalCtx); // Start aiming boomerang +s32 func_808358F0(Player* this, GlobalContext* globalCtx); // Aim boomerang +s32 func_808359FC(Player* this, GlobalContext* globalCtx); // Throw boomerang +s32 func_80835B60(Player* this, GlobalContext* globalCtx); // Boomerang active s32 func_80835C08(Player* this, GlobalContext* globalCtx); void func_80835F44(GlobalContext* globalCtx, Player* this, s32 item); void func_80839F90(Player* this, GlobalContext* globalCtx); @@ -479,8 +480,8 @@ static s32 D_80853604 = 0; static s32 D_80853608 = 0; static s32 D_8085360C = 0; static s16 D_80853610 = 0; -static s32 D_80853614 = 0; -static s32 D_80853618 = 0; +static s32 D_80853614 = 0; // Held item button just pressed? +static s32 D_80853618 = 0; // Held item button currently down? static u16 D_8085361C[] = { NA_SE_VO_LI_SWEAT, @@ -645,15 +646,15 @@ GetItemEntry sGetItemTable[] = { GET_ITEM(ITEM_DOUBLE_MAGIC, OBJECT_GI_MAGICPOT, GID_MAGIC_LARGE, 0xE8, 0x80, CHEST_ANIM_LONG), GET_ITEM(ITEM_DOUBLE_DEFENSE, OBJECT_GI_HEARTS, GID_HEART_CONTAINER, 0xE9, 0x80, CHEST_ANIM_LONG), - GET_ITEM(ITEM_BOTTLE_WITH_RED_POTION, OBJECT_GI_LIQUID, GID_POTION_RED, 0x43, 0x80, CHEST_ANIM_LONG), - GET_ITEM(ITEM_BOTTLE_WITH_GREEN_POTION, OBJECT_GI_LIQUID, GID_POTION_GREEN, 0x44, 0x80, CHEST_ANIM_LONG), - GET_ITEM(ITEM_BOTTLE_WITH_BLUE_POTION, OBJECT_GI_LIQUID, GID_POTION_BLUE, 0x45, 0x80, CHEST_ANIM_LONG), - GET_ITEM(ITEM_BOTTLE_WITH_FAIRY, OBJECT_GI_BOTTLE, GID_BOTTLE, 0x46, 0x80, CHEST_ANIM_LONG), - GET_ITEM(ITEM_BOTTLE_WITH_FISH, OBJECT_GI_FISH, GID_FISH, 0x47, 0x80, CHEST_ANIM_LONG), - GET_ITEM(ITEM_BOTTLE_WITH_BLUE_FIRE, OBJECT_GI_FIRE, GID_BLUE_FIRE, 0x5D, 0x80, CHEST_ANIM_LONG), - GET_ITEM(ITEM_BOTTLE_WITH_BUGS, OBJECT_GI_INSECT, GID_BUG, 0x7A, 0x80, CHEST_ANIM_LONG), - GET_ITEM(ITEM_BOTTLE_WITH_POE, OBJECT_GI_GHOST, GID_POE, 0x97, 0x80, CHEST_ANIM_LONG), - GET_ITEM(ITEM_BOTTLE_WITH_BIG_POE, OBJECT_GI_GHOST, GID_BIG_POE, 0xF9, 0x80, CHEST_ANIM_LONG), + GET_ITEM(ITEM_BOTTLE_WITH_RED_POTION, OBJECT_GI_LIQUID, GID_POTION_RED, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG), + GET_ITEM(ITEM_BOTTLE_WITH_GREEN_POTION, OBJECT_GI_LIQUID, GID_POTION_GREEN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG), + GET_ITEM(ITEM_BOTTLE_WITH_BLUE_POTION, OBJECT_GI_LIQUID, GID_POTION_BLUE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG), + GET_ITEM(ITEM_BOTTLE_WITH_FAIRY, OBJECT_GI_BOTTLE, GID_BOTTLE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG), + GET_ITEM(ITEM_BOTTLE_WITH_FISH, OBJECT_GI_FISH, GID_FISH, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG), + GET_ITEM(ITEM_BOTTLE_WITH_BLUE_FIRE, OBJECT_GI_FIRE, GID_BLUE_FIRE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG), + GET_ITEM(ITEM_BOTTLE_WITH_BUGS, OBJECT_GI_INSECT, GID_BUG, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG), + GET_ITEM(ITEM_BOTTLE_WITH_POE, OBJECT_GI_GHOST, GID_POE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG), + GET_ITEM(ITEM_BOTTLE_WITH_BIG_POE, OBJECT_GI_GHOST, GID_BIG_POE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG), GET_ITEM(ITEM_GERUDO_FORTRESS_SMALL_KEY, OBJECT_GI_KEY, GID_KEY_SMALL, 0x60, 0x80, CHEST_ANIM_SHORT), GET_ITEM(ITEM_FOREST_TEMPLE_SMALL_KEY, OBJECT_GI_KEY, GID_KEY_SMALL, 0x60, 0x80, CHEST_ANIM_SHORT), @@ -986,6 +987,7 @@ static s8 sItemActionParams[] = { static u8 sMaskMemory; +// Used to map action params to update functions static s32(*D_80853EDC[])(Player* this, GlobalContext* globalCtx) = { func_8083485C, func_8083485C, func_8083485C, func_808349DC, func_808349DC, func_808349DC, func_8083485C, func_8083485C, func_8083501C, func_8083501C, func_8083501C, func_8083501C, func_8083501C, func_8083501C, @@ -2760,6 +2762,10 @@ s32 func_80835B60(Player* this, GlobalContext* globalCtx) { return 1; } + if (D_80853614 && CVar_GetS32("gFastBoomerang", 0)) { + this->boomerangQuickRecall = true; + } + return 0; } diff --git a/soh/src/overlays/effects/ovl_Effect_Ss_Bomb2/z_eff_ss_bomb2.h b/soh/src/overlays/effects/ovl_Effect_Ss_Bomb2/z_eff_ss_bomb2.h index 93dc28031..8fe9efc02 100644 --- a/soh/src/overlays/effects/ovl_Effect_Ss_Bomb2/z_eff_ss_bomb2.h +++ b/soh/src/overlays/effects/ovl_Effect_Ss_Bomb2/z_eff_ss_bomb2.h @@ -11,7 +11,7 @@ typedef struct { /* 0x24 */ s16 scale; /* 0x26 */ s16 scaleStep; /* 0x28 */ u8 drawMode; - /* 0x29 */ s32 epoch; + /* 0x29 */ u32 epoch; } EffectSsBomb2InitParams; // size = 0x30 #endif diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c index 8bb4cc431..675fc1191 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c @@ -12,12 +12,12 @@ static s16 sEquipMoveTimer = 10; bool gSelectingMask; static s16 sAmmoVtxOffset[] = { - 0, 2, 4, 6, 99, 99, 8, 99, 99, 10, 99, 99, 99, 99, 99, 99, 12, + 0, 2, 4, 6, 99, 99, 8, 99, 10, 99, 99, 99, 99, 99, 12, }; extern const char* _gAmmoDigit0Tex[]; -void KaleidoScope_DrawAmmoCount(PauseContext* pauseCtx, GraphicsContext* gfxCtx, s16 item) { +void KaleidoScope_DrawAmmoCount(PauseContext* pauseCtx, GraphicsContext* gfxCtx, s16 item, int slot) { s16 ammo; s16 i; @@ -51,7 +51,7 @@ void KaleidoScope_DrawAmmoCount(PauseContext* pauseCtx, GraphicsContext* gfxCtx, gDPPipeSync(POLY_KAL_DISP++); if (i != 0) { - gSPVertex(POLY_KAL_DISP++, &pauseCtx->itemVtx[(sAmmoVtxOffset[item] + 31) * 4], 4, 0); + gSPVertex(POLY_KAL_DISP++, &pauseCtx->itemVtx[(sAmmoVtxOffset[slot] + 31) * 4], 4, 0); gDPLoadTextureBlock(POLY_KAL_DISP++, ((u8*)_gAmmoDigit0Tex[i]), G_IM_FMT_IA, G_IM_SIZ_8b, 8, 8, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, @@ -60,7 +60,7 @@ void KaleidoScope_DrawAmmoCount(PauseContext* pauseCtx, GraphicsContext* gfxCtx, gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0); } - gSPVertex(POLY_KAL_DISP++, &pauseCtx->itemVtx[(sAmmoVtxOffset[item] + 32) * 4], 4, 0); + gSPVertex(POLY_KAL_DISP++, &pauseCtx->itemVtx[(sAmmoVtxOffset[slot] + 32) * 4], 4, 0); gDPLoadTextureBlock(POLY_KAL_DISP++, ((u8*)_gAmmoDigit0Tex[ammo]), G_IM_FMT_IA, G_IM_SIZ_8b, 8, 8, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, @@ -499,7 +499,7 @@ void KaleidoScope_DrawItemSelect(GlobalContext* globalCtx) { for (i = 0; i < 15; i++) { if ((gAmmoItems[i] != ITEM_NONE) && (gSaveContext.inventory.items[i] != ITEM_NONE)) { - KaleidoScope_DrawAmmoCount(pauseCtx, globalCtx->state.gfxCtx, gSaveContext.inventory.items[i]); + KaleidoScope_DrawAmmoCount(pauseCtx, globalCtx->state.gfxCtx, gSaveContext.inventory.items[i], i); } }