diff --git a/CMake/Packaging-2.cmake b/CMake/Packaging-2.cmake index c6e501c73..3525ae1e4 100644 --- a/CMake/Packaging-2.cmake +++ b/CMake/Packaging-2.cmake @@ -1,6 +1,6 @@ set(CPACK_ARCHIVE_COMPONENT_INSTALL ON) set(CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY 0) -set(CPACK_COMPONENTS_ALL "ship" "appimage") +set(CPACK_COMPONENTS_ALL "ship" "extractor" "appimage") if (NOT CPACK_GENERATOR STREQUAL "External") list(REMOVE_ITEM CPACK_COMPONENTS_ALL "appimage") diff --git a/CMakeLists.txt b/CMakeLists.txt index 3091f8824..f7ad4089d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,8 +5,8 @@ set(CMAKE_CXX_STANDARD 20 CACHE STRING "The C++ standard to use") set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version") -project(Ship VERSION 7.1.0 LANGUAGES C CXX) -set(PROJECT_BUILD_NAME "Sulu Alfa" CACHE STRING "") +project(Ship VERSION 7.1.1 LANGUAGES C CXX) +set(PROJECT_BUILD_NAME "Sulu Bravo" CACHE STRING "") set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "") set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT soh) @@ -98,14 +98,14 @@ set_property(TARGET soh PROPERTY APPIMAGE_ICON_FILE "${CMAKE_BINARY_DIR}/sohIcon if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") install(PROGRAMS "${CMAKE_SOURCE_DIR}/scripts/linux/appimage/soh.sh" DESTINATION . COMPONENT appimage) -install(FILES "${CMAKE_SOURCE_DIR}/soh.otr" DESTINATION . COMPONENT appimage) -install(TARGETS ZAPD DESTINATION ./assets/extractor COMPONENT appimage) -install(DIRECTORY "${CMAKE_SOURCE_DIR}/soh/assets/extractor/" DESTINATION ./assets/extractor COMPONENT appimage) -install(DIRECTORY "${CMAKE_SOURCE_DIR}/soh/assets/xml/" DESTINATION ./assets/extractor/xmls COMPONENT appimage) -install(DIRECTORY "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/filelists/" DESTINATION ./assets/extractor/filelists COMPONENT appimage) -install(FILES "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/ActorList_OoTMqDbg.txt" DESTINATION ./assets/extractor/symbols COMPONENT appimage) -install(FILES "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/ObjectList_OoTMqDbg.txt" DESTINATION ./assets/extractor/symbols COMPONENT appimage) -install(FILES "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/SymbolMap_OoTMqDbg.txt" DESTINATION ./assets/extractor/symbols COMPONENT appimage) +install(FILES "${CMAKE_SOURCE_DIR}/soh.otr" DESTINATION . COMPONENT ship) +install(TARGETS ZAPD DESTINATION ./assets/extractor COMPONENT extractor) +install(DIRECTORY "${CMAKE_SOURCE_DIR}/soh/assets/extractor/" DESTINATION ./assets/extractor COMPONENT extractor) +install(DIRECTORY "${CMAKE_SOURCE_DIR}/soh/assets/xml/" DESTINATION ./assets/extractor/xmls COMPONENT extractor) +install(DIRECTORY "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/filelists/" DESTINATION ./assets/extractor/filelists COMPONENT extractor) +install(FILES "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/ActorList_OoTMqDbg.txt" DESTINATION ./assets/extractor/symbols COMPONENT extractor) +install(FILES "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/ObjectList_OoTMqDbg.txt" DESTINATION ./assets/extractor/symbols COMPONENT extractor) +install(FILES "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/SymbolMap_OoTMqDbg.txt" DESTINATION ./assets/extractor/symbols COMPONENT extractor) endif() find_package(Python3 COMPONENTS Interpreter) @@ -198,4 +198,4 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin") endif() set(CPACK_PROJECT_CONFIG_FILE ${CMAKE_SOURCE_DIR}/CMake/Packaging-2.cmake) -include(CMake/Packaging.cmake) +include(CMake/Packaging.cmake) \ No newline at end of file diff --git a/OTRExporter/assets/accessibility/texts/kaleidoscope_eng.json b/OTRExporter/assets/accessibility/texts/kaleidoscope_eng.json index c1c472591..10b016b32 100644 --- a/OTRExporter/assets/accessibility/texts/kaleidoscope_eng.json +++ b/OTRExporter/assets/accessibility/texts/kaleidoscope_eng.json @@ -1,24 +1,35 @@ { - "health": "health $0", - "magic": "magic $0", - "rupees": "rupees $0", - "0": "Deku Stick $0", - "1": "Deku Nut $0", - "2": "Bomb $0", - "3": "Fairy Bow $0", + "health": "Health - $0 Hearts", + "magic": "Magic - $0", + "rupees": "Rupees - $0", + "floor": "Floor $0", + "basement": "Basement $0", + "item_menu": "Select Item", + "map_menu": "Map - $0", + "quest_menu": "Quest Status", + "equip_menu": "Equipment", + "overworld": "Overworld", + "equipped": "$0 - Equipped", + "save_prompt": "Would you like to save?", + "game_saved": "Game saved", + "assigned_to": "Assigned to $0", + "0": "Deku Stick - $0", + "1": "Deku Nut - $0", + "2": "Bomb - $0", + "3": "Fairy Bow - $0", "4": "Fire Arrow", "5": "Din's Fire", - "6": "Fairy Slingshot $0", + "6": "Fairy Slingshot - $0", "7": "Fairy Ocarina", "8": "Ocarina of Time", - "9": "Bombchu $0", + "9": "Bombchu - $0", "10": "Hookshot", "11": "Longshot", "12": "Ice Arrow", "13": "Farore's Wind", "14": "Boomerang", "15": "Lens of Truth", - "16": "Magic Beans $0", + "16": "Magic Beans - $0", "17": "Megaton Hammer", "18": "Light Arrow", "19": "Nayru's Love", @@ -115,8 +126,8 @@ "110": "Zora Sapphire", "111": "Stone of Agony", "112": "Gerudo's Card", - "113": "Skulltula Token $0", - "114": "Heart Container $0", + "113": "Skulltula Token - $0", + "114": "Piece of Heart - $0", "115": "Piece of Heart", "116": "Boss Key", "117": "Compass", @@ -124,7 +135,7 @@ "119": "Small Key", "120": "MAGIC SMALL", "121": "MAGIC LARGE", - "122": "PIECE OF HEART 2", + "122": "Biggoron's Sword", "123": "INVALID 1", "124": "INVALID 2", "125": "INVALID 3", @@ -217,4 +228,4 @@ "311": "Lon Lon Ranch", "312": "Question Mark", "313": "Ganon's Castle" -} \ No newline at end of file +} diff --git a/OTRExporter/assets/accessibility/texts/kaleidoscope_fra.json b/OTRExporter/assets/accessibility/texts/kaleidoscope_fra.json index 58898d70d..820eb4cbc 100644 --- a/OTRExporter/assets/accessibility/texts/kaleidoscope_fra.json +++ b/OTRExporter/assets/accessibility/texts/kaleidoscope_fra.json @@ -1,24 +1,35 @@ { - "health": "vie $0", - "magic": "magie $0", - "rupees": "rubis $0", - "0": "Bâton Mojo $0", - "1": "Noix Mojo $0", - "2": "Bombes $0", - "3": "Arc des Fées $0", + "health": "Vie - $0 Coeurs", + "magic": "Magie - $0", + "rupees": "Rubis - $0", + "floor": "Étage $0", + "basement": "Sous-sol $0", + "item_menu": "Inventaire", + "map_menu": "Carte - $0", + "quest_menu": "Statut de la quête", + "equip_menu": "Equipment", + "overworld": "Surmonde", + "equipped": "$0 - Équipé", + "save_prompt": "Voulez-vous sauvegarder?", + "game_saved": "Jeu sauvegardé", + "assigned_to": "Assigné au $0", + "0": "Bâton Mojo - $0", + "1": "Noix Mojo - $0", + "2": "Bombes - $0", + "3": "Arc des Fées - $0", "4": "Flèche de Feu", "5": "Feu de Din", - "6": "Lance-Pierre des Fées $0", + "6": "Lance-Pierre des Fées - $0", "7": "Ocarina des Fées", "8": "Ocarina of Temps", - "9": "Missiles Teigneux $0", + "9": "Missiles Teigneux - $0", "10": "Grappin", "11": "Super Grappin", "12": "Flèche de Glace", "13": "Vent de Farore", "14": "Boomerang", "15": "Monocle de Vérité", - "16": "Haricot Magique $0", + "16": "Haricot Magique - $0", "17": "Masse des Titans", "18": "Flèche de Lumière", "19": "Amour de Nayru", @@ -115,8 +126,8 @@ "110": "Saphir Zora", "111": "Pierre de Souffrance", "112": "Carte Gerudo", - "113": "Skulltula d'or $0", - "114": "Coeur d'Énergie $0", + "113": "Skulltula d'or - $0", + "114": "Quart de Coeur - $0", "115": "Quart de Coeur", "116": "Clé d'or", "117": "Boussole", @@ -124,7 +135,7 @@ "119": "Petite Clé", "120": "PETITE BOUTEILLE DE MAGIE", "121": "GRANDE BOUTEILLE DE MAGIE", - "122": "QUART DE COEUR 2", + "122": "Épée de Biggoron", "123": "INVALIDE 1", "124": "INVALIDE 2", "125": "INVALIDE 3", @@ -217,4 +228,4 @@ "311": "Ranch Lon Lon", "312": "Point d'interrogation", "313": "Château de Ganon" -} \ No newline at end of file +} diff --git a/OTRExporter/assets/accessibility/texts/kaleidoscope_ger.json b/OTRExporter/assets/accessibility/texts/kaleidoscope_ger.json index 460b32877..630d933fc 100644 --- a/OTRExporter/assets/accessibility/texts/kaleidoscope_ger.json +++ b/OTRExporter/assets/accessibility/texts/kaleidoscope_ger.json @@ -1,24 +1,35 @@ { - "health": "Energie $0", - "magic": "Magie $0", - "rupees": "Rubine $0", - "0": "Deku-Stab $0", - "1": "Deku-Nuß $0", - "2": "Bombe $0", - "3": "Feen-Bogen $0", + "health": "Energie - $0 Herzen", + "magic": "Magie - $0", + "rupees": "Rubine - $0", + "floor": "Etage $0", + "basement": "Keller $0", + "item_menu": "Gegenstände", + "map_menu": "Karte - $0", + "quest_menu": "Quest Status", + "equip_menu": "Ausrüstung", + "overworld": "Überwelt", + "equipped": "$0 - Ausgerüstet", + "save_prompt": "Spielstand sichern?", + "game_saved": "Spielstand gesichert", + "assigned_to": "$0 zugeordnet", + "0": "Deku-Stab - $0", + "1": "Deku-Nuß - $0", + "2": "Bombe - $0", + "3": "Feen-Bogen - $0", "4": "Feuer-Pfeil", "5": "Dins Feuerinferno", - "6": "Feen-Schleuder $0", + "6": "Feen-Schleuder - $0", "7": "Feen-Okarina", "8": "Okarina der Zeit", - "9": "Krabbelmine $0", + "9": "Krabbelmine - $0", "10": "Fanghaken", "11": "Enterhaken", "12": "Eis-Pfeil", "13": "Farores Donnersturm", "14": "Bumerang", "15": "Auge der Wahrheit", - "16": "Wundererbsen $0", + "16": "Wundererbsen - $0", "17": "Stahlhammer", "18": "Licht-Pfeil", "19": "Nayrus Umarmung", @@ -115,8 +126,8 @@ "110": "Zora-Saphir", "111": "Stein des Wissens", "112": "Gerudo-Paß", - "113": "Skulltula-Symbol $0", - "114": "Herzcontainer $0", + "113": "Skulltula-Symbol - $0", + "114": "Herzteil - $0", "115": "Herzteil", "116": "Master-Schlüssel", "117": "Kompaß", @@ -124,7 +135,7 @@ "119": "Kleiner Schlüssel", "120": "MAGIE KLEIN", "121": "MAGIE GROß", - "122": "HERZTEIL 2", + "122": "Biggoron-Schwert", "123": "UNGÜLTIG 1", "124": "UNGÜLTIG 2", "125": "UNGÜLTIG 3", @@ -217,4 +228,4 @@ "311": "Lon Lon-Farm", "312": "Fragezeichen", "313": "Teufelsturm" -} \ No newline at end of file +} diff --git a/OTRExporter/assets/accessibility/texts/misc_eng.json b/OTRExporter/assets/accessibility/texts/misc_eng.json index db59f3deb..6bff3b328 100644 --- a/OTRExporter/assets/accessibility/texts/misc_eng.json +++ b/OTRExporter/assets/accessibility/texts/misc_eng.json @@ -14,5 +14,11 @@ "input_button_c_left": "C Left", "input_button_c_right": "C Right", "input_analog_stick": "the Analog Stick", - "input_d_pad": "the D-Pad" -} \ No newline at end of file + "input_d_pad": "the D-Pad", + "input_d_pad_up": "D-Pad Up", + "input_d_pad_down": "D-Pad Down", + "input_d_pad_left": "D-Pad Left", + "input_d_pad_right": "D-Pad Right", + "yes": "Yes", + "no": "No" +} diff --git a/OTRExporter/assets/accessibility/texts/misc_fra.json b/OTRExporter/assets/accessibility/texts/misc_fra.json index e37268b95..0d9073e50 100644 --- a/OTRExporter/assets/accessibility/texts/misc_fra.json +++ b/OTRExporter/assets/accessibility/texts/misc_fra.json @@ -14,5 +14,11 @@ "input_button_c_left": "C Gauche", "input_button_c_right": "C Droit", "input_analog_stick": "le Stick Analogique", - "input_d_pad": "D-Pad" -} \ No newline at end of file + "input_d_pad": "D-Pad", + "input_d_pad_up": "D-Pad Haut", + "input_d_pad_down": "D-Pad Bas", + "input_d_pad_left": "D-Pad Gauche", + "input_d_pad_right": "D-Pad Droit", + "yes": "Oui", + "no": "Non" +} diff --git a/OTRExporter/assets/accessibility/texts/misc_ger.json b/OTRExporter/assets/accessibility/texts/misc_ger.json index 23b887861..2e07143f0 100644 --- a/OTRExporter/assets/accessibility/texts/misc_ger.json +++ b/OTRExporter/assets/accessibility/texts/misc_ger.json @@ -14,5 +14,11 @@ "input_button_c_left": "C Links", "input_button_c_right": "C Rechts", "input_analog_stick": "den Analog-Stick", - "input_d_pad": "das Steuerkreuz" -} \ No newline at end of file + "input_d_pad": "das Steuerkreuz", + "input_d_pad_up": "Steuerkreuz Oben", + "input_d_pad_down": "Steuerkreuz Unten", + "input_d_pad_left": "Steuerkreuz Links", + "input_d_pad_right": "Steuerkreuz Rechts", + "yes": "Ja", + "no": "Nein" +} diff --git a/libultraship b/libultraship index af368413f..0a5781296 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit af368413f5c61557a7baf2a7a6ab35ba16a7affd +Subproject commit 0a57812968539176bbeaa76c61532d0d6dec4881 diff --git a/scripts/linux/appimage/soh.sh b/scripts/linux/appimage/soh.sh index 1afcbb9b7..e503680ac 100644 --- a/scripts/linux/appimage/soh.sh +++ b/scripts/linux/appimage/soh.sh @@ -69,6 +69,14 @@ while [[ (! -e "$SHIP_HOME"/oot.otr) || (! -e "$SHIP_HOME"/oot-mq.otr) ]]; do continue fi ;; + cfecfdc58d650e71a200c81f033de4e6d617a9f6) + if [[ ! -e "$SHIP_HOME"/oot-mq.otr ]]; then + ROM=GC_MQ_D + OTRNAME="oot-mq.otr" + else + continue + fi + ;; 517bd9714c73cb96c21e7c2ef640d7b55186102f) if [[ ! -e "$SHIP_HOME"/oot-mq.otr ]]; then ROM=GC_MQ_D diff --git a/soh/assets/xml/GC_NMQ_PAL_F/code/fbdemo_circle.xml b/soh/assets/xml/GC_NMQ_PAL_F/code/fbdemo_circle.xml index 5c598c8b4..a3b79fb17 100644 --- a/soh/assets/xml/GC_NMQ_PAL_F/code/fbdemo_circle.xml +++ b/soh/assets/xml/GC_NMQ_PAL_F/code/fbdemo_circle.xml @@ -1,14 +1,14 @@ - - - - - - + + + + + + - + diff --git a/soh/assets/xml/GC_NMQ_PAL_F/overlays/ovl_En_Ganon_Mant.xml b/soh/assets/xml/GC_NMQ_PAL_F/overlays/ovl_En_Ganon_Mant.xml index 900ec46ac..a5fc99347 100644 --- a/soh/assets/xml/GC_NMQ_PAL_F/overlays/ovl_En_Ganon_Mant.xml +++ b/soh/assets/xml/GC_NMQ_PAL_F/overlays/ovl_En_Ganon_Mant.xml @@ -1,21 +1,21 @@ - - + + - + - + - + - + - + - + diff --git a/soh/assets/xml/GC_NMQ_PAL_F/overlays/ovl_Oceff_Spot.xml b/soh/assets/xml/GC_NMQ_PAL_F/overlays/ovl_Oceff_Spot.xml index 9a53952f0..d16cca39b 100644 --- a/soh/assets/xml/GC_NMQ_PAL_F/overlays/ovl_Oceff_Spot.xml +++ b/soh/assets/xml/GC_NMQ_PAL_F/overlays/ovl_Oceff_Spot.xml @@ -1,10 +1,10 @@ - - - + + + - - + + diff --git a/soh/assets/xml/GC_NMQ_PAL_F/overlays/ovl_Oceff_Wipe3.xml b/soh/assets/xml/GC_NMQ_PAL_F/overlays/ovl_Oceff_Wipe3.xml index 11f278866..b1022da79 100644 --- a/soh/assets/xml/GC_NMQ_PAL_F/overlays/ovl_Oceff_Wipe3.xml +++ b/soh/assets/xml/GC_NMQ_PAL_F/overlays/ovl_Oceff_Wipe3.xml @@ -1,10 +1,10 @@ - - - + + + - - + + diff --git a/soh/assets/xml/N64_PAL_11/overlays/ovl_Bg_Ganon_Otyuka.xml b/soh/assets/xml/N64_PAL_11/overlays/ovl_Bg_Ganon_Otyuka.xml index 5bba7f35b..99d32f6e6 100644 --- a/soh/assets/xml/N64_PAL_11/overlays/ovl_Bg_Ganon_Otyuka.xml +++ b/soh/assets/xml/N64_PAL_11/overlays/ovl_Bg_Ganon_Otyuka.xml @@ -1,8 +1,8 @@ - - + + - + diff --git a/soh/assets/xml/N64_PAL_11/overlays/ovl_File_Choose.xml b/soh/assets/xml/N64_PAL_11/overlays/ovl_File_Choose.xml index 55c8779e4..de41882eb 100644 --- a/soh/assets/xml/N64_PAL_11/overlays/ovl_File_Choose.xml +++ b/soh/assets/xml/N64_PAL_11/overlays/ovl_File_Choose.xml @@ -3,18 +3,20 @@ - + + - + + + - + @@ -24,5 +26,6 @@ + diff --git a/soh/assets/xml/N64_PAL_11/overlays/ovl_Magic_Fire.xml b/soh/assets/xml/N64_PAL_11/overlays/ovl_Magic_Fire.xml index b5b7ba82d..0164ab203 100644 --- a/soh/assets/xml/N64_PAL_11/overlays/ovl_Magic_Fire.xml +++ b/soh/assets/xml/N64_PAL_11/overlays/ovl_Magic_Fire.xml @@ -1,10 +1,10 @@ - - - + + + - - + + diff --git a/soh/macosx/soh-macos.sh b/soh/macosx/soh-macos.sh index 41b406295..b77a5a9fa 100755 --- a/soh/macosx/soh-macos.sh +++ b/soh/macosx/soh-macos.sh @@ -44,10 +44,14 @@ if [ ! -e "$SHIP_HOME"/oot.otr ] || [ ! -e "$SHIP_HOME"/oot-mq.otr ]; then ROM_TYPE=0;; 0227d7c0074f2d0ac935631990da8ec5914597b4) ROM_TYPE=0;; + cfbb98d392e4a9d39da8285d10cbef3974c2f012) + ROM_TYPE=0;; 50bebedad9e0f10746a52b07239e47fa6c284d03) ROM_TYPE=1;; 079b855b943d6ad8bd1eb026c0ed169ecbdac7da) ROM_TYPE=1;; + cfecfdc58d650e71a200c81f033de4e6d617a9f6) + ROM_TYPE=1;; 517bd9714c73cb96c21e7c2ef640d7b55186102f) ROM_TYPE=1;; *) @@ -130,6 +134,9 @@ if [ ! -e "$SHIP_HOME"/oot.otr ] || [ ! -e "$SHIP_HOME"/oot-mq.otr ]; then 079b855b943d6ad8bd1eb026c0ed169ecbdac7da) ROM=GC_MQ_D OTRNAME="oot-mq.otr";; + cfecfdc58d650e71a200c81f033de4e6d617a9f6) + ROM=GC_MQ_D + OTRNAME="oot-mq.otr";; 517bd9714c73cb96c21e7c2ef640d7b55186102f) ROM=GC_MQ_D OTRNAME="oot-mq.otr";; diff --git a/soh/soh/Enhancements/audio/AudioEditor.cpp b/soh/soh/Enhancements/audio/AudioEditor.cpp index fd24503bb..970685fb5 100644 --- a/soh/soh/Enhancements/audio/AudioEditor.cpp +++ b/soh/soh/Enhancements/audio/AudioEditor.cpp @@ -207,6 +207,10 @@ void Draw_SfxTab(const std::string& tabId, SeqType type) { LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); UpdateCurrentBGM(defaultValue, type); } + + if (currentValue == value) { + ImGui::SetItemDefaultFocus(); + } } ImGui::EndCombo(); diff --git a/soh/soh/Enhancements/bootcommands.c b/soh/soh/Enhancements/bootcommands.c index 05a682101..385a544a6 100644 --- a/soh/soh/Enhancements/bootcommands.c +++ b/soh/soh/Enhancements/bootcommands.c @@ -26,6 +26,8 @@ void BootCommands_Init() CVarClear("gOnFileSelectNameEntry"); // Clear when soh is killed on the file name entry page CVarClear("gBetterDebugWarpScreenMQMode"); CVarClear("gBetterDebugWarpScreenMQModeScene"); + CVarClear("gCheatEasyPauseBufferLastInputs"); + CVarClear("gCheatEasyPauseBufferTimer"); #if defined(__SWITCH__) || defined(__WIIU__) CVarRegisterInteger("gControlNav", 1); // always enable controller nav on switch/wii u #endif diff --git a/soh/soh/Enhancements/debugger/colViewer.cpp b/soh/soh/Enhancements/debugger/colViewer.cpp index 7aa7ab40a..e46628305 100644 --- a/soh/soh/Enhancements/debugger/colViewer.cpp +++ b/soh/soh/Enhancements/debugger/colViewer.cpp @@ -693,11 +693,23 @@ extern "C" void DrawColViewer() { OPEN_DISPS(gPlayState->state.gfxCtx); + uint8_t mirroredWorld = CVarGetInteger("gMirroredWorld", 0); + // Col viewer needs inverted culling in mirror mode for both OPA and XLU buffers + if (mirroredWorld) { + gSPSetExtraGeometryMode(POLY_OPA_DISP++, G_EX_INVERT_CULLING); + gSPSetExtraGeometryMode(POLY_XLU_DISP++, G_EX_INVERT_CULLING); + } + opaDl.push_back(gsSPEndDisplayList()); gSPDisplayList(POLY_OPA_DISP++, opaDl.data()); xluDl.push_back(gsSPEndDisplayList()); gSPDisplayList(POLY_XLU_DISP++, xluDl.data()); + if (mirroredWorld) { + gSPClearExtraGeometryMode(POLY_OPA_DISP++, G_EX_INVERT_CULLING); + gSPClearExtraGeometryMode(POLY_XLU_DISP++, G_EX_INVERT_CULLING); + } + CLOSE_DISPS(gPlayState->state.gfxCtx); } diff --git a/soh/soh/Enhancements/randomizer/3drando/fill.cpp b/soh/soh/Enhancements/randomizer/3drando/fill.cpp index e50adcd52..8138339c8 100644 --- a/soh/soh/Enhancements/randomizer/3drando/fill.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/fill.cpp @@ -548,13 +548,13 @@ static void CalculateWotH() { static void FastFill(std::vector items, std::vector locations, bool endOnItemsEmpty = false) { //Loop until locations are empty, or also end if items are empty and the parameters specify to end then while (!locations.empty() && (!endOnItemsEmpty || !items.empty())) { - uint32_t loc = RandomElement(locations, true); - Location(loc)->SetAsHintable(); - PlaceItemInLocation(loc, RandomElement(items, true)); - if (items.empty() && !endOnItemsEmpty) { items.push_back(GetJunkItem()); } + + uint32_t loc = RandomElement(locations, true); + Location(loc)->SetAsHintable(); + PlaceItemInLocation(loc, RandomElement(items, true)); } } diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_overworld.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_overworld.cpp index 721776418..8b9f37f9e 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_overworld.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_overworld.cpp @@ -423,6 +423,11 @@ void HintTable_Init_Exclude_Overworld() { Text{"#Medigoron# sells", /*french*/"#Medigoron# vend", /*spanish*/"#Medigoron# vende"}, }); + hintTable[KAK_GRANNYS_SHOP] = HintText::Exclude({ + // obscure text + Text{"the #potion shop lady# sells", /*french*/"la #dame du magasin de potion# vend", /*spanish*/"la #señora de la tienda de pociones# vende" }, + }); + hintTable[KAK_IMPAS_HOUSE_FREESTANDING_POH] = HintText::Exclude({ //obscure text Text{"#imprisoned in a house# lies", /*french*/"#encagé dans une maison# gît", /*spanish*/"#en una casa entre rejas# yace"}, @@ -483,7 +488,7 @@ void HintTable_Init_Exclude_Overworld() { hintTable[GV_WATERFALL_FREESTANDING_POH] = HintText::Exclude({ //obscure text - Text{"behind a #desert waterfall# is", /*french*/"#derrière la cascade du désert# se cache", /*spanish*/"tras una #desierta cascada# yace"}, + Text{"behind a #valley waterfall# is", /*french*/"#derrière la cascade du désert# se cache", /*spanish*/"tras una #desierta cascada# yace"}, }); hintTable[GV_CRATE_FREESTANDING_POH] = HintText::Exclude({ diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp index c074ffbf2..9b9913c8c 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp @@ -206,8 +206,8 @@ void HintTable_Init_Item() { hintTable[STONE_OF_AGONY] = HintText::Item({ //obscure text - Text{"the shake shard", /*french*/"le fragment vibrant", /*spanish*/"el fragmento tintineante"}, - Text{"a blue alarm", /*french*/"une alerte bleue", /*spanish*/"una azul alarma"}, + Text{"the shake stone", /*french*/"le fragment vibrant", /*spanish*/"el fragmento tintineante"}, + Text{"a gray alarm", /*french*/"une alerte bleue", /*spanish*/"una azul alarma"}, }, { //ambiguous text Text{"a prize of the House of Skulltulas", /*french*/"un prix de la maison des Skulltulas", /*spanish*/"un obsequio de la Casa Skulltula"}, diff --git a/soh/soh/Enhancements/randomizer/3drando/item_list.cpp b/soh/soh/Enhancements/randomizer/3drando/item_list.cpp index 59d8518f3..dd7533b98 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item_list.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/item_list.cpp @@ -66,7 +66,7 @@ void ItemTable_Init() { // RandomizerGet //Progression Items itemTable[PROGRESSIVE_HOOKSHOT] = Item(RG_PROGRESSIVE_HOOKSHOT, Text{"Progressive Hookshot", "Grappin (prog.)", "Gancho progresivo"}, ITEMTYPE_ITEM, 0x80, true, &ProgressiveHookshot, PROGRESSIVE_HOOKSHOT); - itemTable[PROGRESSIVE_STRENGTH] = Item(RG_PROGRESSIVE_STRENGTH, Text{"Progressive Strength Upgrade", "Amélioration de Force (prog.)", "Fuerza progresiva"}, ITEMTYPE_ITEM, 0x81, true, &ProgressiveStrength, PROGRESSIVE_STRENGTH); + itemTable[PROGRESSIVE_STRENGTH] = Item(RG_PROGRESSIVE_STRENGTH, Text{"Strength Upgrade", "Amélioration de Force (prog.)", "Fuerza progresiva"}, ITEMTYPE_ITEM, 0x81, true, &ProgressiveStrength, PROGRESSIVE_STRENGTH); itemTable[PROGRESSIVE_BOMB_BAG] = Item(RG_PROGRESSIVE_BOMB_BAG, Text{"Progressive Bomb Bag", "Sac de Bombes (prog.)", "Saco de bombas progresivo"}, ITEMTYPE_ITEM, 0x82, true, &ProgressiveBombBag, PROGRESSIVE_BOMB_BAG); itemTable[PROGRESSIVE_BOW] = Item(RG_PROGRESSIVE_BOW, Text{"Progressive Bow", "Arc (prog.)", "Arco progresivo"}, ITEMTYPE_ITEM, 0x83, true, &ProgressiveBow, PROGRESSIVE_BOW); itemTable[PROGRESSIVE_SLINGSHOT] = Item(RG_PROGRESSIVE_SLINGSHOT, Text{"Progressive Slingshot", "Lance-Pierre (prog.)", "Resortera progresiva"}, ITEMTYPE_ITEM, 0x84, true, &ProgressiveBulletBag, PROGRESSIVE_SLINGSHOT); @@ -207,8 +207,8 @@ void ItemTable_Init() { // RandomizerGet itemTable[BLUE_POTION_REFILL] = Item(RG_BLUE_POTION_REFILL, Text{"Blue Potion Refill", "Recharge de Potion Bleue", "Recarga de poción azul"}, ITEMTYPE_REFILL, GI_POTION_BLUE, false, &noVariable, NONE); //Treasure Game - itemTable[TREASURE_GAME_HEART] = Item(RG_TREASURE_GAME_HEART, Text{"Piece of Heart (Treasure Chest Minigame)", "Quart de Coeur (Chasse-aux-Trésors)", "Pieza de corazón (Cofre del Tesoro)"}, ITEMTYPE_ITEM, GI_HEART_PIECE_WIN, true, &PieceOfHeart, TREASURE_GAME_HEART); - itemTable[TREASURE_GAME_GREEN_RUPEE] = Item(RG_TREASURE_GAME_GREEN_RUPEE, Text{"Green Rupee (Treasure Chest Minigame)", "Rubis Vert (Chasse-aux-Trésors)", "Rupia Verde (Cofre del Tesoro)"}, ITEMTYPE_ITEM, GI_RUPEE_GREEN_LOSE, false, &noVariable, TREASURE_GAME_GREEN_RUPEE); + itemTable[TREASURE_GAME_HEART] = Item(RG_TREASURE_GAME_HEART, Text{"Piece of Heart (WINNER)", "Quart de Coeur (Chasse-aux-Trésors)", "Pieza de corazón (Cofre del Tesoro)"}, ITEMTYPE_ITEM, GI_HEART_PIECE_WIN, true, &PieceOfHeart, TREASURE_GAME_HEART); + itemTable[TREASURE_GAME_GREEN_RUPEE] = Item(RG_TREASURE_GAME_GREEN_RUPEE, Text{"Green Rupee (LOSER)", "Rubis Vert (Chasse-aux-Trésors)", "Rupia Verde (Cofre del Tesoro)"}, ITEMTYPE_ITEM, GI_RUPEE_GREEN_LOSE, false, &noVariable, TREASURE_GAME_GREEN_RUPEE); //Shop Items price itemTable[BUY_DEKU_NUT_5] = Item(RG_BUY_DEKU_NUT_5, Text{"Buy Deku Nut (5)", "Acheter: Noix Mojo (5)", "Comprar nueces deku (5)"}, ITEMTYPE_SHOP, 0x00, true, &Nuts, DEKU_NUTS_5, 15); diff --git a/soh/soh/Enhancements/randomizer/3drando/item_location.cpp b/soh/soh/Enhancements/randomizer/3drando/item_location.cpp index bf0257064..7283635a3 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item_location.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/item_location.cpp @@ -120,7 +120,7 @@ void LocationTable_Init() { locationTable[KAK_MAN_ON_ROOF] = ItemLocation::Base (RC_KAK_MAN_ON_ROOF, 0x52, 0x3E, "Kak Man on Roof", KAK_MAN_ON_ROOF, PIECE_OF_HEART, {Category::cKakarikoVillage, Category::cKakariko,}, SpoilerCollectionCheck::ItemGetInf(29), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_SHOOTING_GALLERY_REWARD] = ItemLocation::Base (RC_KAK_SHOOTING_GALLERY_REWARD, 0x42, 0x30, "Kak Shooting Gallery Reward", KAK_SHOOTING_GALLERY_REWARD, PROGRESSIVE_BOW, {Category::cKakarikoVillage, Category::cKakariko, Category::cMinigame}, SpoilerCollectionCheck::Chest(0x42, 0x1F), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_TRADE_ODD_MUSHROOM] = ItemLocation::Base (RC_KAK_TRADE_ODD_MUSHROOM, 0x4E, 0x20, "Kak Trade Odd Mushroom", KAK_TRADE_ODD_MUSHROOM, ODD_POTION, {Category::cKakarikoVillage, Category::cKakariko, Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(56), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); - locationTable[KAK_GRANNYS_SHOP] = ItemLocation::Base (RC_KAK_GRANNYS_SHOP, 0x4E, 0x10, "Kak Granny's Shop", KAK_GRANNYS_SHOP, BLUE_POTION_REFILL, {Category::cKakarikoVillage, Category::cKakariko, Category::cMerchant}, SpoilerCollectionCheck::EventChkInf(0x32), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_GRANNYS_SHOP] = ItemLocation::Base (RC_KAK_GRANNYS_SHOP, 0x4E, 0x10, "Kak Granny's Shop", KAK_GRANNYS_SHOP, BLUE_POTION_REFILL, {Category::cKakarikoVillage, Category::cKakariko, Category::cMerchant}, SpoilerCollectionCheck::RandomizerInf(0x4E, 0x88), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_ANJU_AS_ADULT] = ItemLocation::Base (RC_KAK_ANJU_AS_ADULT, 0x52, 0x1D, "Kak Anju as Adult", KAK_ANJU_AS_ADULT, CLAIM_CHECK, {Category::cKakarikoVillage, Category::cKakariko,}, SpoilerCollectionCheck::ItemGetInf(36), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_ANJU_AS_CHILD] = ItemLocation::Base (RC_KAK_ANJU_AS_CHILD, 0x52, 0x0F, "Kak Anju as Child", KAK_ANJU_AS_CHILD, EMPTY_BOTTLE, {Category::cKakarikoVillage, Category::cKakariko, Category::cMinigame}, SpoilerCollectionCheck::ItemGetInf(4), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_TRADE_POCKET_CUCCO] = ItemLocation::Base (RC_KAK_TRADE_POCKET_CUCCO, 0x52, 0x0E, "Kak Trade Pocket Cucco", KAK_TRADE_POCKET_CUCCO, COJIRO, {Category::cKakarikoVillage, Category::cKakariko, Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(38), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); diff --git a/soh/soh/Enhancements/randomizer/3drando/shops.cpp b/soh/soh/Enhancements/randomizer/3drando/shops.cpp index 4049ee628..aa2e64a78 100644 --- a/soh/soh/Enhancements/randomizer/3drando/shops.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/shops.cpp @@ -14,7 +14,7 @@ using namespace Settings; std::vector NonShopItems = {}; -static std::array, 0xD5> trickNameTable; //Table of trick names for ice traps +static std::array, 0xD5> trickNameTable; //Table of trick names for ice traps bool initTrickNames = false; //Indicates if trick ice trap names have been initialized yet //Set vanilla shop item locations before potentially shuffling @@ -225,18 +225,19 @@ void InitTrickNames() { trickNameTable[GI_SWORD_KOKIRI] = { Text{"Korok Sword", "Épée Korok", "Espada Korok"}, Text{"Hero's Sword", "Épée du Héros", "Espada del héroe"}, - Text{"Razor Sword", "Lame Rasoir", "Espada de esmeril"}}; + Text{"Butter Knife","Couteau à Beurre","cuchillo de mantequilla"}}; /* trickNameTable[GI_SWORD_MASTER] = { Text{"Goddess Sword", "Épée de la déesse", "Espada Divina"}, Text{"Gilded Sword", "Excalibur", "Espada de los Sabios"}, Text{"Magical Sword", "Lame dorée", "Fay"}};*/ trickNameTable[GI_SWORD_KNIFE] = { - Text{"Big Goron's Sword", "Épée de Gros Goron", "Espada de Big Goron"}, - Text{"Fierce Deity's Sword", "Épée du Dieu Démon", "Espada de la Fiera Deidad"}, - Text{"Biggoron's Knife", "Lame de Grogoron", "Daga de Biggoron"}}; + Text{"Medigoron's Sword", "l'Épée de Medigoron", "La espada de Medigoron"}, + Text{"Razor Sword", "Lame Rasoir", "Espada de esmeril"}, + Text{"Royal Claymore", "Claymore Royale", "Royal Claymore"}}; trickNameTable[GI_SWORD_BGS] = { - Text{"Big Goron's Sword", "Épée de Biggoron", "Espada de Big Goron"}, - Text{"Fierce Deity's Sword", "Épée du dieu démon", "Espada de la Fiera Deidad"}, + Text{"Power Sword", "Épée de Puissance", "Espada de poder"}, + Text{"Fierce Deity Sword", "Épée du dieu démon", "Espada de la Fiera Deidad"}, + Text{"Tempered Sword", "Épée de Légende Nv.2", "Espada Maestra mejorada"}, Text{"Biggoron's Knife", "Lame de Grogoron", "Daga de Biggoron"}}; trickNameTable[GI_SHIELD_DEKU] = { Text{"Boko Shield", "Bouclier Boko", "Escudo Boko"}, @@ -251,19 +252,23 @@ void InitTrickNames() { Text{"Magical Shield", "Bouclier Magique", "Escudo arcano"}, Text{"Mirror of Twilight", "Miroir des Ombres", "Espejo del Crepúsculo"}}; trickNameTable[GI_TUNIC_GORON] = { - Text{"Gerudo Tunic", "Tunique Gerudo", "Sayo gerudo"}, - Text{"Magic Armor", "Armure Magique", "Túnica Goron"}, + Text{"Gerudo Top", "Tunique Gerudo", "Pechera gerudo"}, + Text{"Flamebreaker Armor", "Armure de Pierre", " Armadura ignífuga"}, Text{"Red Mail", "Habits Rouges", "Ropas rojas"}}; trickNameTable[GI_TUNIC_ZORA] = { Text{"Rito Tunic", "Tunique Rito", "Sayo rito"}, + Text{"Mermaid Suit", "Costume de sirène", "Costume de sirène"}, Text{"Zora Armor", "Armure Zora", "Túnica Zora"}, Text{"Blue Mail", "Habits Bleus", "Ropas azules"}}; trickNameTable[GI_BOOTS_IRON] = { Text{"Iron Hoofs", "Patins de Plomb", "Botas férreas"}, Text{"Snow Boots", "Bottes de Neige", "Botas de nieve"}, + Text{"Red Boots", "Bottes rouges", "Botas rojas"}, + Text{"Zora Greaves", "Bottes Zora", "Zora Greaves"}, Text{"Boots of Power", "Bottes de Puissance", "Botas de plomo"}}; trickNameTable[GI_BOOTS_HOVER] = { Text{"Hover Hoofs", "Patins des airs", "Botas flotadoras"}, + Text{"Golden Boots", "Bottes dorées", "Botas de Oro"}, Text{"Pegasus Boots", "Bottes pégase", "Botas de Pegaso"}, Text{"Boots of Speed", "Bottes de vitesse", "Botas del desierto"}}; trickNameTable[GI_WEIRD_EGG] = { @@ -271,65 +276,81 @@ void InitTrickNames() { Text{"Lon Lon Egg", "Oeuf Lon Lon", "Huevo Lon Lon"}, Text{"Zora Egg", "Oeuf Zora", "Huevo Zora"}}; trickNameTable[GI_LETTER_ZELDA] = { - Text{"Ruto's Letter", "Lettre de Ruto", "Carta de Ruto"}, + Text{"Ruto's Letter", "Lettre de Ruto", "Carta de Ruto"}, Text{"Royal Letter", "Lettre Eoyale", "Carta para Kafei"}, - Text{"Zelda's Business Card", "Carte d'affaires de Zelda", "Carta"}}; + Text{"Zelda's Business Card", "Carte d'affaires de Zelda", "Carta"}, + Text{"Letter to Kafei", "Lettre pour Kafei", "Carta para Kafei "}, + Text{"Goat's Letter", "Lettre de la Chèvre", "Carta de la Cabra"}, + Text{"Maggie's Letter", "Lettre de Maggy", "Carta de Dolores"}}; trickNameTable[GI_BOOMERANG] = { + Text{"Banana", "Banane", "Plátano"}, Text{"Prank Fetch Toy", "Inséparable Bâtonnet", "Bumerang"}, Text{"Gale Boomerang", "Boomerang Tornade", "Bumerán tornado"}, Text{"Magic Boomerang", "Boomerang Magique", "Bumerán mágico"}}; trickNameTable[GI_LENS] = { Text{"Sheikah-leidoscope", "Sheikah-léidoscope", "Monóculo de la Verdad"}, Text{"Sheikah Sensor", "Sonar Sheikah", "Sensor Sheikah"}, + Text{"Crystal of Vision", "Cristal de Vision", "Cristal de Visión"}, Text{"Magnifying Lens", "Loupe", "Lente Aumentadora"}}; trickNameTable[GI_HAMMER] = { Text{"Goron Gavel", "Masse Perforatrice", "Mazo Goron"}, Text{"Magic Hammer", "Marteau Magique", "Martillo mágico"}, Text{"Skull Hammer", "Maillet Ressort", "Martillo de hierro"}}; trickNameTable[GI_STONE_OF_AGONY] = { - Text{"Shard of Agahnim", "Fragment d'Agahnim", "Piedra de Agahnim"}, + Text{"Cave Charm", "Charme de grotte", "Amuleto de la cueva"}, + Text{"Stone of Agahnim", "Fragment d'Agahnim", "Piedra de Agahnim"}, Text{"Shard of Agony", "Fragment de Souffrance", "Piedra de la Agonía"}, Text{"Pirate's Charm", "Pierre de Pirate", "Amuleto Pirata"}}; trickNameTable[GI_DINS_FIRE] = { Text{"Eldin's Fire", "Feu d'Eldin", "Fuego de Eldin"}, Text{"Din's Blaze", "Flamme de Din", "Poder de Din"}, - Text{"Din's Pearl", "Perle de Din", "Orbe de Din"}}; + Text{"Magic Lantern", "Lanterne Magique", "Linterna mágica"}, + Text{"Ether Medallion", "Médaillon d'Éther", "Medallón de Tesoro"}, + Text{"Bombos Medallion", "Médaillon des Flammes", "Medallón del Temblor"}}; trickNameTable[GI_FARORES_WIND] = { Text{"Faron's Wind", "Vent de Firone", "Viento de Farone"}, Text{"Farore's Windfall", "Zéphyr de Farore", "Valor de Farore"}, - Text{"Farore's Pearl", "Perle de Farore", "Orbe de Farore"}}; + Text{"Tingle Air", "Tingle Air", "Tingle de aire"}, + Text{"Travel Medallion", "Amulette de téléportation", "Medallón Maligno"}, + Text{"Irene's Taxi", "Le taxi d'Aëline", "El taxi de Airín"}}; trickNameTable[GI_NAYRUS_LOVE] = { Text{"Lanayru's Love", "Amour de Lanelle", "Amor de Lanayru"}, Text{"Nayru's Passion", "Passion de Nayru", "Sabiduría de Nayru"}, - Text{"Nayru's Pearl", "Perle de Nayru", "Orbe de Nayru"}}; + Text{"Tingle Shield", "Bouclier Tingle", "Escudo de hormigueo"}, + Text{"Shield Spell", "Bouclier Magique", "Hechizo de Protección"}, + Text{"Magic Armor", "Armure Magique", "Armadura mágica"}}; trickNameTable[GI_ARROW_FIRE] = { - Text{"Soul Arrow", "Flèche des Esprits", "Flecha del Espíritu"}, + Text{"Fire Rod", "Baguette de feu", "Cetro de fuego"}, Text{"Bomb Arrow", "Flèche-Bombe", "Flecha bomba"}, - Text{"Fire Candy", "Bonbon deFfeu", "Cetro de fuego"}}; + Text{"Red Candle", "Bougie Rouge", "Vela roja"}}; trickNameTable[GI_ARROW_ICE] = { - Text{"Shadow Arrow", "Flèche d'Ombre", "Flecha de las Sombras"}, + Text{"Ice Rod", "Baguette des Glaces", "Cetro de Hielo"}, Text{"Ancient Arrow", "Flèche Archéonique", "Flecha ancestral"}, Text{"Ice Trap Arrow", "Flèche de Piège de Glace", "Cetro de hielo"}}; trickNameTable[GI_ARROW_LIGHT] = { Text{"Wind Arrow", "Flèche de Vent", "Flecha del Viento"}, + Text{"Wand of Gamelon", "Baguette de Gamelon", "Varita de Gamelón"}, Text{"Shock Arrow", "Flèches Électriques", "Flecha eléctrica"}, Text{"Silver Arrow", "Flèches d'Argent", "Flecha de plata"}}; trickNameTable[GI_GERUDO_CARD] = { Text{"Desert Title Deed", "Abonnement Gerudo", "Escritura del desierto"}, + Text{"Sickle Moon Flag", "Drapeau du croissant de lune", "Bandera de la Luna Creciente"}, + Text{"Complimentary ID", "Bon de félicitation", "Cupón especial"}, Text{"Gerudo's Card", "Carte Goron", "Tóken Gerudo"}, Text{"Gerudo's Membership Card", "Autographe de Nabooru", "Tarjeta Gerudo"}}; trickNameTable[0xC9] = { Text{"Funky Bean Pack", "Paquet de Fèves Magiques", "Lote de frijoles mágicos"}, + Text{"Grapple Berries", "Baies de grappin", "Bayas de garfio"}, Text{"Crenel Bean Pack", "Paquet de Haricots Gonggle", "Lote de alubias mágicas"}, - Text{"Mystic Bean Pack", "Paquet de Haricots Mystiques", "Lote de porotos mágicos"}}; + Text{"Mystical Seed Pack", "Pack de graines mystiques", "Paquete de semillas místicas"}}; trickNameTable[0xB8] = { Text{"Diamond Hearts", "Coeurs de Diamant", "Contenedor de diamante"}, Text{"Double Damage", "Double Souffrance", "Doble daño receptivo"}, Text{"Quadruple Defence", "Quadruple Défence", "Defensa cuádruple"}}; trickNameTable[GI_POCKET_EGG] = { - Text{"Poached Egg", "oeuf à la coque", "Huevo pasado"}, + Text{"Arpagos Egg", "Oeuf d'Arpagos", "Huevo de Arpagos"}, Text{"Lon Lon Egg", "oeuf Lon Lon", "Huevo Lon Lon"}, Text{"Zora Egg", "oeuf Zora", "Huevo del Pez Viento"}}; trickNameTable[GI_POCKET_CUCCO] = { @@ -338,113 +359,161 @@ void InitTrickNames() { Text{"Hatched Cucco", "Cocotte éclose", "Pollo de bolsillo"}}; trickNameTable[GI_COJIRO] = { Text{"Blucco", "Chair-Qui-Poule", "Cucazul"}, - Text{"Grog's Cucco", "Cocotte de Grog", "Cuco de Grog"}, - Text{"Corijo", "Cojiro", "Corijo"}}; + Text{"Piyoko", "Piyoko", "Piyoko"}, + Text{"Dark Cucco", "Cocotte Sombre", "Cucco oscuro"}, + Text{"Grog's Cucco", "Cocotte de Grog", "Cuco de Grog"}}; trickNameTable[GI_ODD_MUSHROOM] = { Text{"Magic Mushroom", "Champignon magique", "Champiñón mágico"}, Text{"Endura Shroom", "Champi Vigueur", "Champiñón del bosque"}, + Text{"Sleepy Toadstool", "Crapaud Fatigué", "Seta durmiente"}, Text{"Mushroom", "Champignon", "Seta"}}; trickNameTable[GI_ODD_POTION] = { Text{"Odd Medicine", "Élixir suspect", "Poción rara"}, Text{"Granny's Poultice", "Mixture de Granny", "Medicina de la abuela"}, - Text{"Mushroom Poultice", "Mixture de champignon", "Medicina de champiñones"}}; + Text{"Mushroom Poultice", "Mixture de champignon", "Medicina de champiñones"}, + Text{"Secret Medicine", "Médicament", "Pócima secreta"}, + Text{"Mushroom Spores", "Spores de Champignons", "Esporas de hongos"}, + Text{"Hanyu Spore", "Hanyu Spore", "Espora Hanyu"}}; trickNameTable[GI_SAW] = { Text{"Carpenter's Saw", "Scie du charpentier", "Sierra del carpintero"}, Text{"Poacher's Sword", "Hache du chasseur", "Espada del capataz"}, + Text{"Ancient Bladesaw", "Longue Épée Archéonique", "Mandoble ancestral"}, + Text{"Woodcutter's Axe", "Hache du Bûcheron", "Hacha de leñador"}, Text{"Grog's Saw", "Scie de Grog", "Sierra del Cazador Furtivo"}}; trickNameTable[GI_SWORD_BROKEN] = { Text{"Broken Biggoron's Sword", "Épée brisée de Grogoron", "Espada de Biggoron rota"}, Text{"Broken Giant's Knife", "Lame des Géants brisée", "Daga gigante rota"}, - Text{"Biggoron's Sword", "Épée de Biggoron", "Espada de Biggoron"}}; + Text{"Broken Noble Sword", "Épée noble brisée", "Espada noble rota"}, + Text{"Broken Picori Blade", "Épée Minish brisée", "Espada minish rota"}, + Text{"Decayed Master Sword", "Épée de légende pourrie", "Espada decadente de leyenda"}}; trickNameTable[GI_PRESCRIPTION] = { Text{"Biggoron's Prescription", "Ordonnance de Grogoron", "Receta de Biggoron"}, Text{"Eyedrop Prescription", "Ordonnance de gouttes", "Receta ocular"}, - Text{"Urgent Prescription", "Ordonnance urgente", "Prescripción"}}; + Text{"Urgent Prescription", "Ordonnance urgente", "Prescripción"}, + Text{"Swordsman's Scroll", "Précis d'escrime", "Esgrimidorium"}, + Text{"Portrait of Oren", "Portrait d'Orlène", "Retrato de Oren"}, + Text{"Letter to King Zora", "Lettre au roi Zora", "Carta al Rey Zora"}}; trickNameTable[GI_FROG] = { Text{"Don Gero", "Don Gero", "Don Gero"}, - Text{"Eyedrop Frog", "Grenouille-qui-louche", "Globo Ocular de Rana"}, - Text{"Frog", "Crapaud", "Rana"}}; + Text{"Hot-Footed Frog", "Grenouille à pieds chauds", "Rana de patas calientes"}, + Text{"Lost Swordsmith", "Forgeron perdu", "Espadachín perdido"}, + Text{"Eyedrop Frog", "Grenouille-qui-louche", "Globo Ocular de Rana"}}; trickNameTable[GI_EYEDROPS] = { Text{"Biggoron's Eyedrops", "Gouttes de Grogoron", "Gotas de Biggoron"}, Text{"Hyrule's Finest Eyedrops", "Eau du Lac Hylia", "Gotas oculares"}, + Text{"Moon's Tear", "Larme de Lune", "Lágrima de Luna"}, + Text{"Engine Grease", "Graisse moteur", "Grasa del motor"}, Text{"Zora Perfume", "Parfum Zora", "Perfume Zora"}}; trickNameTable[GI_CLAIM_CHECK] = { Text{"Clay Check", "Certificat Grogoron", "Comprobante de Reclamación"}, + Text{"Ancient Tablet", "Stèle ancienne", "Litografía arcana"}, Text{"Sheikah Slate", "Tablette Sheikah", "Piedra Sheikah"}, Text{"Cyclone Slate", "Ardoise des tornades", "Pizarra de los Torbellinos"}}; trickNameTable[GI_SKULL_TOKEN] = { Text{"Skulltula Token", "Bon de Skulltula dorée", "Símbolo de Skulltula"}, Text{"Golden Skulltula Spirit", "Pièce de Skulltula dorée", "Tóken de Skulltula Dorada"}, - Text{"Gold Walltula Token", "Jeton de Walltula dorée", "Skulltula dorada"}}; + Text{"Gold Walltula Token", "Jeton de Walltula dorée", "Skulltula dorada"}, + Text{"Maiamai", "Ti'gorneau", "Maimai"}, + Text{"Gratitude Crystal", "Cristal de gratitude", "Gema de gratitud"}, + Text{"Korok Seed", "Noix korogu", "Semilla de kolog"}}; trickNameTable[0x80] = { Text{"Progressive Grappling Hook", "Lance-chaîne (prog.)", "Garra progresiva"}, Text{"Progressive Clawshot", "Grappin-griffe (prog.)", "Zarpa progresiva"}, - Text{"Progressive Gripshot", "Grappince (prog.)", "Enganchador progresivo"}}; + Text{"Progressive Gripshot", "Grappince (prog.)", "Enganchador progresivo"}, + Text{"Progressive Rope", "Corde (prog.)", "Cuerda progresivo"}}; trickNameTable[0x81] = { - Text{"Progressive Glove", "Gant de puissance (prog.)", "Guanteletes progresivos"}, - Text{"Progressive Power Bracelet", "Bracelet de force (prog.)", "Brasaletes progresivos"}, - Text{"Progressive Magic Bracelet", "Bracelet magique (prog.)", "Manoplas progresivas"}}; + Text{"Power Glove", "Gant de Puissance (prog.)", "Guanteletes progresivos"}, + Text{"Power Bracelet", "Bracelet de Force (prog.)", "Brasaletes progresivos"}, + Text{"Magic Bracelet", "Bracelet Magique (prog.)", "Manoplas progresivas"}}; trickNameTable[0x82] = { Text{"Progressive Bomb Capacity", "Capacité de bombes (prog.)", "Mayor capacidad de bombas"}, Text{"Progressive Bomb Pack", "Paquet de bombes (prog.)", "Zurrón de bombas progresivo"}, - Text{"Progressive Bomb Box", "Boîte à bombes (prog.)", "Bolsa de bombas progresiva"}}; + Text{"Progressive Bomb Box", "Boîte à bombes (prog.)", "Bolsa de bombas progresiva"}, + Text{"Progressive Blast Mask", "Masque d'Explosion (prog.)", "Máscara explosiva progresiva"}, + Text{"Progressive Powder Kegs", "Baril de Poudre (prog.)", "Barril de polvo progresivo"}, + Text{"Progressive Remote Bombs", "Bombes à distance (prog.)", "Bombas remotas progresivas"}}; trickNameTable[0x83] = { Text{"Progressive Arrow Capacity", "Capacité de flèches (prog.)", "Mayor capacidad de flechas"}, Text{"Progressive Hero's Bow", "Arc du héros (prog.)", "Arco del héroe progresivo"}, - Text{"Progressive Arrow Holder", "Arbalète (prog.)", "Ballesta progresiva"}}; + Text{"Progressive Arrow Holder", "Arbalète (prog.)", "Ballesta progresiva"}, + Text{"Progressive Crossbow", "Arbalète (prog.)", "Ballesta progresiva"}, + Text{"Progressive Sacred Bow", "Arc sacré (prog)", "Arco Sagrado Progresivo"}, + Text{"Progressive Lynel Bow", "Arc de Lynel (prog.)", "Arco de centaleón Progresivo"}}; trickNameTable[0x84] = { Text{"Progressive Seed Capacity", "Capacité de graines (prog.)", "Mayor capacidad de semillas"}, + Text{"Progressive Catapult", "Catapulte (prog.)", "Catapulta progresiva"}, Text{"Progressive Scattershot", "Lance-Pierre rafale (prog.)", "Resortera múltiple progresiva"}, + Text{"Progressive Seed Launcher", "Lanceur de semences (prog.)", "Lanzador de semillas progresivo"}, Text{"Progressive Seed Satchel", "Sac de graines (prog.)", "Bolsa de semillas progresiva"}}; trickNameTable[0x85] = { Text{"Progressive Rupee Capacity", "Capacité de rubis (prog.)", "Mayor capacidad de rupias"}, Text{"Progressive Purse", "Sacoche (prog.)", "Cartera de rupias progresiva"}, - Text{"Progressive Rupee Bag", "Sac à rubis (prog.)", "Zurrón de rupias progresivo"}}; + Text{"Progressive Rupee Bag", "Sac à rubis (prog.)", "Zurrón de rupias progresivo"}, + Text{"Progressive Rupoor Capacity", "Capacité de Roupir (prog.)", "Capacidad progresiva Rupobre"}, + Text{"Progressive Spoils Bag", "Sac à Butin (prog.)", "Bolsa de trofeos progresiva"}, + Text{"Progressive Ruby Bag", "Capacité du sac Ruby (prog.)", "Bolso Ruby progresivo"}}; trickNameTable[0x86] = { + Text{"Progressive Flippers", "Palmes de Zora (prog.)", "Aletas de zora progresiva"}, + Text{"Progressive Dragon's Scale", "Écaille du dragon d'eau (prog.)", "Escama dragón acuático progresiva"}, Text{"Progressive Diving Ability", "Plongée (prog.)", "Buceo progresivo"}, Text{"Progressive Pearl", "Perle (prog.)", "Perla progresiva"}, Text{"Progressive Scute", "Bulle (prog.)", "Fragmento Zora progresivo"}}; trickNameTable[0x87] = { Text{"Progressive Nut Pack", "Paquet de noix (prog.)", "Mayor capacidad de semillas"}, + Text{"Progressive Bait Bag", "Sac à Appâts (prog.)", "Bolsa de cebo progresiva"}, + Text{"Progressive Pear Capacity", "Capacité de poire (prog.)", "Capacidad progresiva de pera"}, Text{"Progressive Nut Bag", "Sac de noix (prog.)", "Bolsa de nueces progresiva"}, Text{"Progressive Husk Capacity", "Capacité de noisettes (prog.)", "Mayor capacidad de castañas"}}; trickNameTable[0x88] = { - Text{"Progressive Stick Pack", "Paquet de bâtons Mojo (prog.)", "Mayor capacidad de bastones"}, Text{"Progressive Stick Bag", "Sac de bâtons (prog.)", "Mayor capacidad de ramas deku"}, + Text{"Progressive Stick Pack", "Paquet de bâtons Mojo (prog.)", "Mayor capacidad de bastones"}, + Text{"Progressive Branch Capacity", "Capacité de la succursale (prog.)", "Capacidad progresiva de la sucursal"}, Text{"Progressive Rod Capacity", "Capacité de tiges (prog.)", "Mayor capacidad de cetros deku"}}; trickNameTable[0x89] = { Text{"Progressive Bomblings", "Bombinsectes (prog.)", "Bombinsectos progresivos"}, + Text{"Progressive Sentrobe Bombs", "Bombe de Sphérodrone (prog.)", "Bomba de helicobot progresivo"}, + Text{"Progressive Bomb-ombs", "Bombe Soldat (prog.)", "Soldado bomba progresivo"}, Text{"Progressive Missiles", "Missiles (prog.)", "Misiles progresivos"}, Text{"Progressive Bombchu Bag", "Sac à Bombchu (prog.)", "Bombachus progresivos"}}; trickNameTable[0x8A] = { Text{"Progressive Stamina Meter", "Jauge d'endurance (prog.)", "Medidor de vigor progresivo"}, - Text{"Progressive Energy Meter", "Jauge d'énergie (prog.)", "Medidor de energía progresivo"}, + Text{"Progressive Energy Gauge", "Jauge d'énergie (prog.)", "Medidor de energía progresivo"}, Text{"Progressive Magic Powder", "Poudre magique (prog.)", "Medidor de carga progresivo"}}; trickNameTable[0x8B] = { Text{"Progressive Memento", "Souvenir (prog.)", "Silbato progresivo"}, + Text{"Progressive Whistle", "Siffler (prog.)", "Silbido progresivo"}, Text{"Progressive Flute", "Flûte (prog.)", "Flauta progresiva"}, Text{"Progressive Recorder", "Harmonica (prog.)", "Armónica progresiva"}}; trickNameTable[0xD4] = { Text{"Progressive Titan Blade", "Lame des Titans (prog.)", "Hoja del Titán progresiva"}, Text{"Progressive Goron Knife", "Lame Goron (prog.)", "Daga Goron progresiva"}, - Text{"Progressive Giant Sword", "Épée géante (prog.)", "Espada gigante progresiva"}}; + Text{"Progressive Giant Sword", "Épée géante (prog.)", "Espada gigante progresiva"}, + Text{"Progressive Darknut Sword", "Épée de Darknut (prog.)", "Espada Darknut progresiva"}, + Text{"Progressive Power Sword", "Épée de Puissance (prog.)", "Espada de poder progresiva"}, + Text{"Progressive Big Stabby", "Gros coup de poignard (prog.)", "Gran puñalada progresiva"}}; trickNameTable[0x0F] = { + Text{"Empty Canteen", "Cantine vide", "cantimplora vacía"}, + Text{"Vial of Winds", "Fiole de vents", "Vial de Vientos"}, + Text{"Tingle Bottle", "Flacon de Tingle", "Botella de Tingle"}, Text{"Magic Bottle", "Flacon magique", "Frasco feérico"}, Text{"Glass Bottle", "Flacon de verre", "Botella de cristal"}, Text{"Bottle with Water", "Flacon d'eau", "Botella Tingle"}}; trickNameTable[0x14] = { Text{"Bottle with Chateau Romani", "Flacon de cuvée Romani", "Botella de Reserva Romani"}, - Text{"Bottle with Fresh Milk", "Flacon de lait frais", "Botella de leche fresca"}, - Text{"Bottle with Mystery Milk", "Flacon de lait grand cru", "Botella de leche extra"}}; + Text{"Bottle with Premium Milk", "Flacon avec lait de qualité supérieure", "Biberón con leche Premium"}, + Text{"Bottle with Mystery Milk", "Flacon de lait grand cru", "Botella de leche extra"}, + Text{"Bottle with Fresh Milk", "Flacon de lait frais", "Botella de leche fresca"},}; trickNameTable[0x8C] = { Text{"Bottle with Red Chu Jelly", "Flacon de gelée Chuchu rouge", "Jugo de Chuchu Rojo"}, + Text{"Bottle with Hibiscus Potion", "Flacon de potion de Hibiscus", "Botella de poción de Hibisco"}, Text{"Bottle with Medicine of Life", "Flacon d'élixir rouge", "Botella de medicina de la vida"}, Text{"Bottle with Heart Potion", "Flacon de potion de soin", "Botella de poción de salud"}}; trickNameTable[0x8D] = { Text{"Bottle with Green Chu Jelly", "Flacon de gelée Chuchu verte", "Jugo de Chuchu Verde"}, + Text{"Bottle with Lamp Oil", "Flacon de Huile à lanterne", "Botella de Aceite de candil "}, Text{"Bottle with Medicine of Magic", "Flacon d'élixir vert", "Botella de medicina mágica"}, Text{"Bottle with Stamina Potion", "Flacon d'Endurol", "Botella de elixir vigorizante"}}; trickNameTable[0x8E] = { @@ -453,22 +522,28 @@ void InitTrickNames() { Text{"Bottle with Air Potion", "Flacon de potion d'oxygène", "Botella de oxígeno"}}; trickNameTable[0x8F] = { Text{"Bottle with Forest Firefly", "Flacon avec une luciole", "Luciérnaga del bosque"}, - Text{"Bottle with Faerie", "Flacon de poudre féérique", "Gran Hada embotellada"}, + Text{"Bottle with Deku Princess", "Flacon avec Deku Princess", "Botella con Deku Princess"}, Text{"Bottle with Stray Fairy", "Flacon avec une fée perdue", "Hada perdida en una botella"}}; trickNameTable[0x90] = { Text{"Bottle with Small Jabu-Jabu", "Flacon avec mini Jabu-Jabu", "Lord Chapu-Chapu embotellado"}, + Text{"Bottle with Reekfish", "Flacon avec Reekfish", "Reekfish embotellada"}, Text{"Bottle with Hyrule Bass", "Flacon avec perche d'Hyrule", "Locha de Hyrule embotellada"}, Text{"Bottle with Hyrule Loach", "Flacon avec loche d'Hyrule", "Perca de Términa embotellada"}}; trickNameTable[0x91] = { Text{"Bottle with Will-O-Wisp", "Flacon avec feu follet", "Botella de llama azul"}, Text{"Bottle with Ancient Flame", "Flacon de flamme ancienne", "Botella de fuego ancestral"}, + Text{"Bottle with a Blue Candle", "Flacon avec une bougie bleue", "Botella con una vela azul"}, + Text{"Bottle with Red Ice", "Flacon de Glace Rouge", "Botella de Hielo rojo"}, Text{"Bottle with Nayru's Flame", "Flacon de flamme de Nayru", "Botella de llamas de Nayru"}}; trickNameTable[0x92] = { Text{"Bottle with Baby Tektites", "Flacon de bébé Araknon", "Tektites en una botella"}, + Text{"Bottle with A Beetle", "Flacon avec un scarabée", "Botella con un escarabajo"}, Text{"Bottle with Lanayru Ants", "Flacon de fourmis de Lanelle", "Celestarabajo embotellado"}, - Text{"Bottle with Insects", "Flacon de bibittes", "Saltabosques embotellados"}}; + Text{"Bottle with Insects", "Flacon de bibittes", "Saltabosques embotellados"}, + Text{"Bottle with a Golden Bee", "Flacon avec une abeille dorée", "Botella con una abeja dorada"}}; trickNameTable[0x94] = { Text{"Bottle with Ghini", "Flacon avec Ghini", "Ghini en una botella"}, + Text{"Bottle with Reapling", "Flacon avec Âme Damnée", "Reapling en una botella"}, Text{"Bottle with Imp Poe", "Flacon avec Spectre", "Espectro en una botella"}, Text{"Bottle with Anti-Fairy", "Flacon avec Tetdoss", "Whisp en una botella"}}; @@ -484,121 +559,146 @@ void InitTrickNames() { trickNameTable[0xC1] = { Text{"Ballad of the Goddess", "Chant de la déesse", "Cántico de la Diosa"}, Text{"Song of Healing", "Chant de l'apaisement", "Canción de curación"}, - Text{"Bolero of Fire", "Boléro du feu", "Bolero del fuego"}}; + Text{"Song of the Hero", "Chant du héros", "Canción del héroe"}}; trickNameTable[0xC2] = { - Text{"Earth God's Lyric", "Hymne du dieu de la terre", "Melodía del Espíritu de la Tierra"}, + Text{"Song of Birds","Chant des oiseaux","Cantar del ave"}, Text{"Song of Soaring", "Chant de l'envol", "Canción del viento"}, - Text{"Requiem of Spirit", "Requiem des esprits", "Réquiem del espíritu"}}; + Text{"Song of Horse", "Chant du cheval", "Chant du cheval"}}; trickNameTable[0xC3] = { - Text{"Wind God's Aria", "Hymne du dieu du vent", "Melodía del Espíritu del Viento"}, - Text{"Wind's Requiem", "Mélodie du vent", "Melodía del Viento"}, - Text{"Minuet of Forest", "Menuet de la forêt", "Minueto del bosque"}}; + Text{"Mido's Song", "La chanson de Mido", "La canción de Mido"}, + Text{"Kass' Theme", "Le thème de Kass", "El tema de Kass"}, + Text{"Tune of Echoes", "Chant des Échos ", "Melodía del Eco "}}; trickNameTable[0xC4] = { Text{"Song of Passing", "Mambo de Manbo", "Melodía del transcurrir"}, Text{"Command Melody", "Air du marionnettiste", "Cara al Sol"}, - Text{"Prelude of Light", "Prélude de la lumière", "Preludio de la luz"}}; + Text{"Moon's Song", "La chanson de Moon", "La canción de la luna"}}; trickNameTable[0xC5] = { Text{"Song of Double Time", "Chant accéléré", "Canción del doble tiempo"}, Text{"Inverted Song of Time", "Chant du temps inversé", "Canción del tiempo invertida"}, - Text{"Serenade of Water", "Sérénade de l'eau", "Serenata del agua"}}; + Text{"Tune of Ages", "Chant du Temps", "Melodía del Tiempo"}}; trickNameTable[0xC6] = { Text{"Ballad of Gales", "Requiem de la tornade", "Melodía del Tornado"}, Text{"Frog's Song of Soul", "Rap des grenouilles", "Canción del alma de la rana"}, - Text{"Nocturne of Shadow", "Nocturne de l'ombre", "Nocturno de la sombra"}}; + Text{"Wind's Requiem", "Mélodie du vent", "Melodía del Viento"}}; trickNameTable[0xBB] = { Text{"Saria's Karaoke", "Karaoké de Saria", "Dueto del bosque"}, Text{"Sonata of Awakening", "Sonate de l'éveil", "Sonata del despertar"}, - Text{"Saria's Song", "Chant de Saria", "Canción de Saria"}}; + Text{"Wind God's Aria", "Hymne du dieu du vent", "Melodía del Espíritu del Viento"}}; trickNameTable[0xBC] = { Text{"Darunia's Tango", "Tango de Darunia", "Coro del fuego"}, - Text{"Goron Lullaby", "Berceuse des Gorons", "Nana goron"}, - Text{"Zelda's Lullaby", "Berceuse de Zelda", "Nana de Zelda"}}; + Text{"Tune of Currents", "Chants des Flux", "Melodía de las Corrientes"}, + Text{"Goron Lullaby", "Berceuse des Gorons", "Nana goron"}}; trickNameTable[0xBD] = { Text{"Ruto's Blues", "Blues de Ruto", "Sonata del agua"}, Text{"New Wave Bossa Nova", "Bossa-nova des flots", "Bossanova de las olas"}, - Text{"Song of Time", "Chant du temps", "Canción del tiempo"}}; + Text{"Manbo's Mambo", "Mambo de Manbo", "Mambo de Manbo"}}; trickNameTable[0xBE] = { Text{"Nabooru's Reggae", "Reggae de Nabooru", "Reggae del espíritu"}, Text{"Elegy of Emptiness", "Hymne du vide", "Elegía al vacío"}, - Text{"Epona's Song", "Chant d'Épona", "Canción de Epona"}}; + Text{"Earth God's Lyric", "Hymne du dieu de la terre", "Melodía del Espíritu de la Tierra"}}; trickNameTable[0xBF] = { Text{"Impa's Death Metal", "Death métal d'Impa", "Diurno de la sombra"}, Text{"Oath to Order", "Ode de l'appel", "Oda al orden"}, - Text{"Song of Storms", "Chant des tempêtes", "Canción de la tormenta"}}; + Text{"Song of Discovery", "Chant des secrets", "Canto revelador"}}; trickNameTable[0xC0] = { Text{"Rauru's Sing-Along", "Chansonnette de Rauru", "Predulio de luz"}, Text{"Ballad of the Wind Fish", "Ballade sur Poisson-Rêve", "Balada del Piez Viento"}, - Text{"Sun's Song", "Chant du soleil", "Canción del Sol"}}; + Text{"Song of Light", "Chant de la lumière", "Sonidos de la luz"}}; trickNameTable[0xCB] = { Text{"Pendant of Courage", "Pendentif du courage", "Colgante del valor"}, + Text{"Farore's Pearl", "Perle de Farore", "Orbe de Farore"}, + Text{"Aquanine", "Smaragdine", "Yerbánida"}, Text{"Farore's Emerald", "Émeraude de Farore", "Esmeralda de Farore"}, Text{"Kokiri's Peridot", "Péridot Kokiri", "Ágata de los Kokiri"}}; trickNameTable[0xCC] = { Text{"Pendant of Power", "Pendentif de la force", "Colgante del poder"}, + Text{"Din's Pearl", "Perle de Din", "Orbe de Din"}, + Text{"Crimsonine", "Alzanine", "Bermellina"}, Text{"Din's Ruby", "Rubis de Din", "Rubí de Din"}, Text{"Goron's Garnet", "Grenat Goron", "Topacio de los Goron"}}; trickNameTable[0xCD] = { Text{"Pendant of Wisdom", "Pendentif de la sagesse", "Colgante de la sabiduría"}, + Text{"Nayru's Pearl", "Perle de Nayru", "Orbe de Nayru"}, + Text{"Azurine", "Aquanine", "Azurina"}, Text{"Nayru's Sapphire", "Saphir de Nayru", "Zafiro de Nayru"}, Text{"Zora's Aquamarine", "Aquamarine Zora", "Lapislázuli de los Zora"}}; trickNameTable[0xCE] = { Text{"Wind Medallion", "Médaillon du vent", "Medallón del Viento"}, + Text{"Wind Element", "Elément Vent", "Elemento de aire"}, Text{"Saria's Medallion", "Médaillon de Saria", "Medallón de Saria"}, + Text{"Sign of Air", "Glyphe de l'air", "Glifo de aire"}, Text{"Medallion of Forest", "Médaillon du Temple de la Forêt", "Medalla del Bosque"}}; trickNameTable[0xCF] = { - Text{"Bombos Medallion", "Médaillon des flammes", "Medallón del Temblor"}, + Text{"Fire Element", "Elément Feu", "Elemento de fuego"}, Text{"Darunia's Medallion", "Médaillon de Darunia", "Medallón de Darunia"}, + Text{"Sign of Fire", "Glyphe de feu", "Glifo de fuego"}, Text{"Medallion of Fire", "Médaillon du Temple du Feu", "Medalla del Fuego"}}; trickNameTable[0xD0] = { + Text{"Water Element", "Elément Eau", "Elemento de agua"}, Text{"Ice Medallion", "Médaillon de glace", "Medallón Helado"}, Text{"Ruto's Medallion", "Médaillon de Ruto", "Medallón de Ruto"}, + Text{"Sign of Water", "Glyphe de l'eau", "Glifo de agua"}, Text{"Medallion of Water", "Médaillon du Temple de l'Eau", "Medalla del Agua"}}; trickNameTable[0xD1] = { - Text{"Quake Medallion", "Médaillon des secousses", "Medallón Llamarada"}, + Text{"Earth Element", "Elément Terre", "Elemento de tierra"}, Text{"Nabooru's Medallion", "Médaillon de Nabooru", "Medallón de Nabooru"}, + Text{"Sign of Earth", "Glyphe de la Terre", "Glifo de la tierra"}, Text{"Medallion of Spirit", "Médaillon du Temple de l'Esprit", "Medalla del Espíritu"}}; trickNameTable[0xD2] = { - Text{"Travel Medallion", "Amulette de téléportation", "Medallón Maligno"}, + Text{"Fused Shadow", "Cristal d'ombre", "Sombra Fundida"}, Text{"Impa's Medallion", "Médaillon d'Impa", "Medallón de Impa"}, + Text{"Sign of Illusion", "Glyphe de l'illusion", "Glifo de ilusión"}, Text{"Medallion of Shadow", "Médaillon du Temple de l'Ombre", "Medalla de la Sombra"}}; trickNameTable[0xD3] = { - Text{"Ether Medallion", "Médaillon d'éther", "Medallón de Tesoro"}, + Text{"Compass of Light", "Boussole de lumière", "Brújula de Luz"}, Text{"Rauru's Medallion", "Médaillon de Rauru", "Medallón de Rauru"}, + Text{"Sign of Destiny", "Glyphe du destin", "Glifo del destino"}, Text{"Medallion of Light", "Médaillon du temple de lumière", "Medalla de la Luz"}}; trickNameTable[GI_HEART] = { Text{"Love", "Bisou", "Te amo"}, - Text{"Heart Container", "Réceptacle de coeur", "Contenedor de corazón"}, - Text{"Piece of Heart", "Quart de coeur", "Pieza de corazón"}}; + Text{"Life", "Vie", "vida"}, + Text{"HP", "VP", "VP"}}; trickNameTable[GI_RUPEE_GREEN] = { - Text{"Green Rupy", "Rupee vert", "Rubia verde"}, + Text{"False Greg", "Faux Greg", "Falso Greg"}, + Text{"One Ruby", "Un rubis", "Un rubí"}, + Text{"Rupoor (1)", "Roupir (1)", "Rupobre (1)"}, Text{"One Rupee", "Un rubis", "Guaraní hyliano"}, Text{"Rupee (1)", "Rubis (1)", "Peso hyliano"}}; trickNameTable[GI_RUPEE_BLUE] = { - Text{"Blue Rupy", "Rupee bleu", "Rubia azul"}, + Text{"Blupee", "Bleubi", "Azupia"}, + Text{"Five Rubies", "Cinq Rubys", "Cinco rubíes"}, Text{"Five Rupees", "Cinq rubis", "Bolívar hyliano"}, - Text{"Rupee (5)", "Rubis (5)", "Peso hyliano"}}; + Text{"Rupee (5)", "Rubis (5)", "Peso hyliano"}, + Text{"Rupoor (5)", "Roupir (5)", "Rupobre (5)"}}; trickNameTable[GI_RUPEE_RED] = { - Text{"Red Rupy", "Rupee rouge", "Rubia roja"}, + Text{"Big 20", "Grand 20", "Los 20 grandes"}, + Text{"Twenty Rubies", "vingt rubis", "Veinte rubíes"}, + Text{"Rupoor (20)", "Roupir (20)", "Rupobre (20)"}, Text{"Twenty Rupees", "Vingt rubis", "Colon hyliano"}, Text{"Rupee (20)", "Rubis (20)", "Peso hyliano"}}; trickNameTable[GI_RUPEE_PURPLE] = { - Text{"Purple Rupy", "Rupee pourpre", "Rubia morada"}, + Text{"Purpee", "pourbi", "morupiua"}, + Text{"Fifty Rubies", "cinquante rubis", "Cincuenta rubíes"}, + Text{"Rupoor (50)", "Roupir (50)", "Rupobre (50)"}, Text{"Fifty Rupees", "Cinquante rubis", "Balboa hyliano"}, Text{"Rupee (50)", "Rubis (50)", "Peso hyliano"}}; trickNameTable[GI_RUPEE_GOLD] = { - Text{"Huge Rupy", "Énorme Rupee", "Rubia gigante"}, + Text{"Hugo", "Or Rubi", "Oro Rubi"}, + Text{"Two Hundred Rubies", "deux cents rubis", "Doscientos rubíes"}, + Text{"Diamond", "Diamant", "Diamante"}, + Text{"Huge Ruby", "Énorme rubis", "Rubi gigante"}, Text{"Two Hundred Rupees", "Deux cent rubis", "Euro hyliano"}, Text{"Rupee (200)", "Rubis (200)", "Dólar hyliano"}}; trickNameTable[GI_HEART_PIECE] = { - Text{"Piece of Health", "Quart d'énergie", "Pieza de amor"}, - Text{"Recovery Heart", "Coeur d'énergie", "Corazón"}, - Text{"Heart Container", "Réceptacle de coeur", "Contenedor de corazón"}}; + Text{"Pizza Heart", "Fromage de cœur", "Pieza de Chorizo"}, + Text{"Little Bit Of Love", "Un peu d'amour", "Un poco de amor"}, + Text{"Rare Peach Stone", "Pierre de pêche rare", "Pierre de pêche rare"}}; trickNameTable[GI_HEART_CONTAINER_2] = { - Text{"Health Container", "Réceptacle d'énergie", "Contenedor de amor"}, - Text{"Recovery Heart", "Quart de coeur", "Corazón"}, - Text{"Piece of Heart", "Coeur d'énergie", "Pieza de corazón"}}; + Text{"Crystal Heart", "Cœur de cristal", "Corazón de cristal"}, + Text{"Life Heart", "Cœur de vie", "Vida Corazón"}, + Text{"Lots of Love", "Beaucoup d'amour", "Mucho amor"}}; /* //Names for individual upgrades, in case progressive names are replaced diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index dc4f41ae0..cb87bc115 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -402,6 +402,15 @@ static void WriteSettings(const bool printAll = false) { // 3drando doesn't have a "skip child zelda" setting, manually add it to the spoilerfile jsonData["settings"]["Skip Child Zelda"] = Settings::skipChildZelda; + // 3drando uses an MQ dungeon count of 13 to mean random, manually add that to the spoilerfile as a bool + if (Settings::MQDungeonCount.GetSelectedOptionIndex() == 0) { + jsonData["settings"]["World Settings:MQ Dungeons"] = "None"; + } else if (Settings::MQDungeonCount.GetSelectedOptionIndex() == 13) { + jsonData["settings"]["World Settings:MQ Dungeons"] = "Random Number"; + } else { + jsonData["settings"]["World Settings:MQ Dungeons"] = "Set Number"; + } + // spoilerLog.RootElement()->InsertEndChild(parentNode); // for (const uint32_t key : allLocations) { @@ -757,9 +766,9 @@ static void WriteHints(int language) { std::string textStr = AutoFormatHintTextString(unformattedHintTextString); jsonData["hints"][location->GetName()]["hint"] = textStr; jsonData["hints"][location->GetName()]["type"] = hintTypeNames.find(hintType)->second; - if (hintType == HINT_TYPE_ITEM || hintType == HINT_TYPE_NAMED_ITEM) { + if (hintType == HINT_TYPE_ITEM || hintType == HINT_TYPE_NAMED_ITEM || hintType == HINT_TYPE_WOTH) { jsonData["hints"][location->GetName()]["item"] = hintedLocation->GetPlacedItemName().GetEnglish(); - if (hintType != HINT_TYPE_NAMED_ITEM) { + if (hintType != HINT_TYPE_NAMED_ITEM || hintType == HINT_TYPE_WOTH) { jsonData["hints"][location->GetName()]["location"] = hintedLocation->GetName(); } } diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 03caa6b2d..4423ac7f0 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -348,6 +348,7 @@ std::unordered_map SpoilerfileSettingNameToEn { "Timesaver Settings:Complete Mask Quest", RSK_COMPLETE_MASK_QUEST }, { "Timesaver Settings:Skip Scarecrow's Song", RSK_SKIP_SCARECROWS_SONG }, { "Timesaver Settings:Enable Glitch-Useful Cutscenes", RSK_ENABLE_GLITCH_CUTSCENES }, + { "World Settings:MQ Dungeons", RSK_RANDOM_MQ_DUNGEONS }, { "World Settings:MQ Dungeon Count", RSK_MQ_DUNGEON_COUNT } }; @@ -1032,6 +1033,15 @@ void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) { gSaveContext.randoSettings[index].value = RO_GANON_BOSS_KEY_KAK_TOKENS; } break; + case RSK_RANDOM_MQ_DUNGEONS: + if (it.value() == "None") { + gSaveContext.randoSettings[index].value = RO_MQ_DUNGEONS_NONE; + } else if (it.value() == "Random Number") { + gSaveContext.randoSettings[index].value = RO_MQ_DUNGEONS_RANDOM_NUMBER; + } else if (it.value() == "Set Number") { + gSaveContext.randoSettings[index].value = RO_MQ_DUNGEONS_SET_NUMBER; + } + break; case RSK_SKIP_CHILD_ZELDA: gSaveContext.randoSettings[index].value = it.value(); break; @@ -3814,7 +3824,10 @@ void RandomizerSettingsWindow::DrawElement() { "A Giant's Knife and a pack of Bombchus will be added to the item pool, and " "one of the bottles will contain a Blue Potion.\n\n" "On (no hints) - Salesmen will be included but won't tell you what you'll get.\n" - "On (with hints) - Salesmen will be included and you'll know what you're buying." + "On (with hints) - Salesmen will be included and you'll know what you're buying.\n" + "\n" + "Granny's item will only be offered after you have traded in the Odd Mushroom when Shuffle Adult Trade is on. " + "Otherwise when off, you will need to have found the Claim Check to buy her item (simulating the trade quest is complete)." ); UIWidgets::EnhancementCombobox("gRandomizeShuffleMerchants", randoShuffleMerchants, RO_SHUFFLE_MERCHANTS_OFF); @@ -5260,7 +5273,10 @@ CustomMessage Randomizer::GetMapGetItemMessageWithHint(GetItemEntry itemEntry) { break; } - if (this->masterQuestDungeons.empty() || this->masterQuestDungeons.size() >= 12) { + if (this->randoSettings[RSK_RANDOM_MQ_DUNGEONS] == RO_MQ_DUNGEONS_NONE || + (this->randoSettings[RSK_RANDOM_MQ_DUNGEONS] == RO_MQ_DUNGEONS_SET_NUMBER && + this->randoSettings[RSK_MQ_DUNGEON_COUNT] == 12) + ) { messageEntry.Replace("{{typeHint}}", ""); } else if (ResourceMgr_IsSceneMasterQuest(sceneNum)) { messageEntry.Replace("{{typeHint}}", mapGetItemHints[0][1], mapGetItemHints[1][1], mapGetItemHints[2][1]); diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp index 6998c6bb5..d1e5514be 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp @@ -567,10 +567,10 @@ void InitializeChecks() { areasSpoiled |= (1 << rcObj.rcArea); } - showVOrMQ = (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_MQ_DUNGEON_COUNT) > 0); - //Bug: the above will spoil that everything is vanilla if the random count rolled 0. - // Should use the below instead, but the setting isn't currently saved to the savefile - //showVOrMQ = (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) != RO_GENERIC_OFF); + showVOrMQ = (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_RANDOM_NUMBER || + (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_SET_NUMBER && + OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_MQ_DUNGEON_COUNT) < 12) + ); UpdateChecks(); UpdateInventoryChecks(); diff --git a/soh/soh/Enhancements/tts/tts.cpp b/soh/soh/Enhancements/tts/tts.cpp index ab2bbf9d8..128ab4b1e 100644 --- a/soh/soh/Enhancements/tts/tts.cpp +++ b/soh/soh/Enhancements/tts/tts.cpp @@ -13,6 +13,7 @@ #include "soh/Enhancements/boss-rush/BossRush.h" extern "C" { +extern MapData* gMapData; extern SaveContext gSaveContext; extern PlayState* gPlayState; } @@ -191,28 +192,109 @@ void RegisterOnInterfaceUpdateHook() { void RegisterOnKaleidoscopeUpdateHook() { GameInteractor::Instance->RegisterGameHook([](int16_t inDungeonScene) { if (!CVarGetInteger("gA11yTTS", 0)) return; - - static uint16_t prevCursorIndex = 0; + + static int16_t prevCursorIndex = 0; static uint16_t prevCursorSpecialPos = 0; static uint16_t prevCursorPoint[5] = { 0 }; - + static int16_t prevPromptChoice = -1; + static int16_t prevSubState = -1; + static int16_t prevState = -1; + PauseContext* pauseCtx = &gPlayState->pauseCtx; Input* input = &gPlayState->state.input[0]; - - if (pauseCtx->state != 6) { - //reset cursor index to so it is announced when pause is reopened - prevCursorIndex = -1; + + // Save game prompt + if (pauseCtx->state == 7) { + if (pauseCtx->unk_1EC == 1) { + // prompt + if (prevPromptChoice != pauseCtx->promptChoice) { + auto prompt = GetParameritizedText(pauseCtx->promptChoice == 0 ? "yes" : "no", TEXT_BANK_MISC, nullptr); + if (prevPromptChoice == -1) { + auto translation = GetParameritizedText("save_prompt", TEXT_BANK_KALEIDO, nullptr); + SpeechSynthesizer::Instance->Speak((translation + " - " + prompt).c_str(), GetLanguageCode()); + } else { + SpeechSynthesizer::Instance->Speak(prompt.c_str(), GetLanguageCode()); + } + + prevPromptChoice = pauseCtx->promptChoice; + } + } else if (pauseCtx->unk_1EC == 4 && prevSubState != 4) { + // Saved + auto translation = GetParameritizedText("game_saved", TEXT_BANK_KALEIDO, nullptr); + SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode()); + } + prevSubState = pauseCtx->unk_1EC; + prevState = pauseCtx->state; return; } - + + // Announce page when + // Kaleido pages are rotating and page halfway rotated + // Or Kaleido was just opened + if ((pauseCtx->unk_1E4 == 1 && pauseCtx->unk_1EA == 32) || (pauseCtx->state == 4 && prevState != 4)) { + uint16_t modeNextPageMap[] = { + PAUSE_MAP, PAUSE_EQUIP, PAUSE_QUEST, PAUSE_ITEM, PAUSE_EQUIP, PAUSE_MAP, PAUSE_ITEM, PAUSE_QUEST, + }; + uint16_t nextPage = modeNextPageMap[pauseCtx->mode]; + + switch (nextPage) { + case PAUSE_ITEM: { + auto translation = GetParameritizedText("item_menu", TEXT_BANK_KALEIDO, nullptr); + SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode()); + break; + } + case PAUSE_MAP: { + std::string map; + if (inDungeonScene) { + std::string key = std::to_string(gSaveContext.mapIndex); + map = GetParameritizedText(key, TEXT_BANK_SCENES, nullptr); + } else { + map = GetParameritizedText("overworld", TEXT_BANK_KALEIDO, nullptr); + } + auto translation = GetParameritizedText("map_menu", TEXT_BANK_KALEIDO, map.c_str()); + SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode()); + break; + } + case PAUSE_QUEST: { + auto translation = GetParameritizedText("quest_menu", TEXT_BANK_KALEIDO, nullptr); + SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode()); + break; + } + case PAUSE_EQUIP: { + auto translation = GetParameritizedText("equip_menu", TEXT_BANK_KALEIDO, nullptr); + SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode()); + break; + } + } + prevState = pauseCtx->state; + return; + } + + prevState = pauseCtx->state; + + if (pauseCtx->state != 6) { + // Reset cursor index and values so it is announced when pause is reopened + prevCursorIndex = -1; + prevPromptChoice = -1; + prevSubState = -1; + return; + } + if ((pauseCtx->debugState != 1) && (pauseCtx->debugState != 2)) { char arg[8]; if (CHECK_BTN_ALL(input->press.button, BTN_DUP)) { - snprintf(arg, sizeof(arg), "%d", gSaveContext.health); + // Normalize hearts to fractional count similar to z_lifemeter + int curHeartFraction = gSaveContext.health % 16; + int fullHearts = gSaveContext.health / 16; + float fraction = ceilf((float)curHeartFraction / 5) * 0.25; + float health = (float)fullHearts + fraction; + snprintf(arg, sizeof(arg), "%g", health); auto translation = GetParameritizedText("health", TEXT_BANK_KALEIDO, arg); SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode()); - } else if (CHECK_BTN_ALL(input->press.button, BTN_DLEFT)) { - snprintf(arg, sizeof(arg), "%d", gSaveContext.magic); + } else if (CHECK_BTN_ALL(input->press.button, BTN_DLEFT) && gSaveContext.magicCapacity != 0) { + // Normalize magic to percentage + float magicLevel = ((float)gSaveContext.magic / gSaveContext.magicCapacity) * 100; + snprintf(arg, sizeof(arg), "%.0f%%", magicLevel); auto translation = GetParameritizedText("magic", TEXT_BANK_KALEIDO, arg); SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode()); } else if (CHECK_BTN_ALL(input->press.button, BTN_DDOWN)) { @@ -236,6 +318,17 @@ void RegisterOnKaleidoscopeUpdateHook() { if (pauseCtx->cursorSpecialPos > 0) { return; } + + std::string buttonNames[] = { + "input_button_c_left", + "input_button_c_down", + "input_button_c_right", + "input_d_pad_up", + "input_d_pad_down", + "input_d_pad_left", + "input_d_pad_right", + }; + int8_t assignedTo = -1; switch (pauseCtx->pageIndex) { case PAUSE_ITEM: @@ -248,36 +341,71 @@ void RegisterOnKaleidoscopeUpdateHook() { case ITEM_BOMBCHU: case ITEM_SLINGSHOT: case ITEM_BOW: - snprintf(arg, sizeof(arg), "%d", AMMO(pauseCtx->cursorItem[PAUSE_ITEM])); - break; case ITEM_BEAN: - snprintf(arg, sizeof(arg), "%d", 0); + snprintf(arg, sizeof(arg), "%d", AMMO(pauseCtx->cursorItem[PAUSE_ITEM])); break; default: arg[0] = '\0'; } - - if (pauseCtx->cursorItem[PAUSE_ITEM] == 999) { + + if (pauseCtx->cursorItem[PAUSE_ITEM] == PAUSE_ITEM_NONE || + pauseCtx->cursorItem[PAUSE_ITEM] == ITEM_NONE) { + prevCursorIndex = -1; return; } - + std::string key = std::to_string(pauseCtx->cursorItem[PAUSE_ITEM]); - auto translation = GetParameritizedText(key, TEXT_BANK_KALEIDO, arg); - SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode()); + std::string itemTranslation = GetParameritizedText(key, TEXT_BANK_KALEIDO, arg); + + // Check if item is assigned to a button + for (size_t i = 0; i < ARRAY_COUNT(gSaveContext.equips.cButtonSlots); i++) { + if (gSaveContext.equips.buttonItems[i + 1] == pauseCtx->cursorItem[PAUSE_ITEM]) { + assignedTo = i; + break; + } + } + + if (assignedTo != -1) { + auto button = GetParameritizedText(buttonNames[assignedTo], TEXT_BANK_MISC, nullptr); + auto translation = GetParameritizedText("assigned_to", TEXT_BANK_KALEIDO, button.c_str()); + SpeechSynthesizer::Instance->Speak((itemTranslation + " - " + translation).c_str(), GetLanguageCode()); + } else { + SpeechSynthesizer::Instance->Speak(itemTranslation.c_str(), GetLanguageCode()); + } break; } case PAUSE_MAP: if (inDungeonScene) { + // Dungeon map items if (pauseCtx->cursorItem[PAUSE_MAP] != PAUSE_ITEM_NONE) { std::string key = std::to_string(pauseCtx->cursorItem[PAUSE_MAP]); auto translation = GetParameritizedText(key, TEXT_BANK_KALEIDO, nullptr); SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode()); + } else { + // Dungeon map floor numbers + char arg[8]; + int cursorPoint = pauseCtx->cursorPoint[PAUSE_MAP]; + + // Cursor is on a dungeon floor position + if (cursorPoint >= 3 && cursorPoint < 11) { + int floorID = gMapData->floorID[gPlayState->interfaceCtx.unk_25A][pauseCtx->dungeonMapSlot - 3]; + // Normalize so F1 == 0, and negative numbers are basement levels + int normalizedFloor = (floorID * -1) + 8; + if (normalizedFloor >= 0) { + snprintf(arg, sizeof(arg), "%d", normalizedFloor + 1); + auto translation = GetParameritizedText("floor", TEXT_BANK_KALEIDO, arg); + SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode()); + } else { + snprintf(arg, sizeof(arg), "%d", normalizedFloor * -1); + auto translation = GetParameritizedText("basement", TEXT_BANK_KALEIDO, arg); + SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode()); + } + } } } else { std::string key = std::to_string(0x0100 + pauseCtx->cursorPoint[PAUSE_WORLD_MAP]); auto translation = GetParameritizedText(key, TEXT_BANK_KALEIDO, nullptr); SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode()); - SPDLOG_INFO("Item: {}", key); } break; case PAUSE_QUEST: @@ -288,16 +416,17 @@ void RegisterOnKaleidoscopeUpdateHook() { snprintf(arg, sizeof(arg), "%d", gSaveContext.inventory.gsTokens); break; case ITEM_HEART_CONTAINER: - snprintf(arg, sizeof(arg), "%d", ((gSaveContext.inventory.questItems & 0xF) & 0xF) >> 0x1C); + snprintf(arg, sizeof(arg), "%d", (gSaveContext.inventory.questItems & 0xF0000000) >> 0x1C); break; default: arg[0] = '\0'; } - - if (pauseCtx->cursorItem[PAUSE_QUEST] == 999) { + + if (pauseCtx->cursorItem[PAUSE_QUEST] == PAUSE_ITEM_NONE) { + prevCursorIndex = -1; return; } - + std::string key = std::to_string(pauseCtx->cursorItem[PAUSE_QUEST]); auto translation = GetParameritizedText(key, TEXT_BANK_KALEIDO, arg); SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode()); @@ -305,15 +434,51 @@ void RegisterOnKaleidoscopeUpdateHook() { } case PAUSE_EQUIP: { + if (pauseCtx->namedItem == PAUSE_ITEM_NONE) { + prevCursorIndex = -1; + return; + } + std::string key = std::to_string(pauseCtx->cursorItem[PAUSE_EQUIP]); - auto translation = GetParameritizedText(key, TEXT_BANK_KALEIDO, nullptr); - SpeechSynthesizer::Instance->Speak(translation.c_str(), GetLanguageCode()); + auto itemTranslation = GetParameritizedText(key, TEXT_BANK_KALEIDO, nullptr); + uint8_t checkEquipItem = pauseCtx->namedItem; + + // BGS from kaleido reports as ITEM_HEART_PIECE_2 (122) + // remap BGS and broken knife to be the BGS item for the current equip check + if (checkEquipItem == ITEM_HEART_PIECE_2 || checkEquipItem == ITEM_SWORD_KNIFE) { + checkEquipItem = ITEM_SWORD_BGS; + } + + // Check if equipment item is currently equipped or assigned to a button + if (checkEquipItem >= ITEM_SWORD_KOKIRI && checkEquipItem <= ITEM_BOOTS_HOVER) { + uint8_t checkEquipType = (checkEquipItem - ITEM_SWORD_KOKIRI) / 3; + uint8_t checkEquipValue = ((checkEquipItem - ITEM_SWORD_KOKIRI) % 3) + 1; + + if (CUR_EQUIP_VALUE(checkEquipType) == checkEquipValue) { + itemTranslation = GetParameritizedText("equipped", TEXT_BANK_KALEIDO, itemTranslation.c_str()); + } + + for (size_t i = 0; i < ARRAY_COUNT(gSaveContext.equips.cButtonSlots); i++) { + if (gSaveContext.equips.buttonItems[i + 1] == checkEquipItem) { + assignedTo = i; + break; + } + } + } + + if (assignedTo != -1) { + auto button = GetParameritizedText(buttonNames[assignedTo], TEXT_BANK_MISC, nullptr); + auto translation = GetParameritizedText("assigned_to", TEXT_BANK_KALEIDO, button.c_str()); + SpeechSynthesizer::Instance->Speak((itemTranslation + " - " + translation).c_str(), GetLanguageCode()); + } else { + SpeechSynthesizer::Instance->Speak(itemTranslation.c_str(), GetLanguageCode()); + } break; } default: break; } - + prevCursorIndex = cursorIndex; memcpy(prevCursorPoint, pauseCtx->cursorPoint, sizeof(prevCursorPoint)); }); diff --git a/soh/soh/Extractor/Extract.cpp b/soh/soh/Extractor/Extract.cpp index 143a86380..b5eff7bae 100644 --- a/soh/soh/Extractor/Extract.cpp +++ b/soh/soh/Extractor/Extract.cpp @@ -44,6 +44,8 @@ #include #include #include +#include +#include extern "C" uint32_t CRC32C(unsigned char* data, size_t dataSize); extern "C" void RomToBigEndian(void* rom, size_t romSize); @@ -496,14 +498,50 @@ const char* Extractor::GetZapdVerStr() const { } } +std::string Extractor::Mkdtemp() { + std::string temp_dir = std::filesystem::temp_directory_path().string(); + + // create 6 random alphanumeric characters + static const char charset[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<> dist(0, sizeof(charset) - 1); + + char randchr[7]; + for (int i = 0; i < 6; i++) { + randchr[i] = charset[dist(gen)]; + } + randchr[6] = '\0'; + + std::string tmppath = temp_dir + "/extractor-" + randchr; + std::filesystem::create_directory(tmppath); + return tmppath; +} + extern "C" int zapd_main(int argc, char** argv); -bool Extractor::CallZapd() { +bool Extractor::CallZapd(std::string installPath, std::string exportdir) { constexpr int argc = 16; char xmlPath[1024]; char confPath[1024]; std::array argv; const char* version = GetZapdVerStr(); + const char* otrFile = IsMasterQuest() ? "oot-mq.otr" : "oot.otr"; + + std::string romPath = std::filesystem::absolute(mCurrentRomPath).string(); + installPath = std::filesystem::absolute(installPath).string(); + exportdir = std::filesystem::absolute(exportdir).string(); + // Work this out in the temporary folder + std::string tempdir = Mkdtemp(); + std::string curdir = std::filesystem::current_path().string(); +#ifdef _WIN32 + std::filesystem::copy(installPath + "/assets", tempdir + "/assets", + std::filesystem::copy_options::recursive | std::filesystem::copy_options::update_existing); +#else + std::filesystem::create_symlink(installPath + "/assets", tempdir + "/assets"); +#endif + + std::filesystem::current_path(tempdir); snprintf(xmlPath, 1024, "assets/extractor/xmls/%s", version); snprintf(confPath, 1024, "assets/extractor/Config_%s.xml", version); @@ -513,7 +551,7 @@ bool Extractor::CallZapd() { argv[2] = "-i"; argv[3] = xmlPath; argv[4] = "-b"; - argv[5] = mCurrentRomPath.c_str(); + argv[5] = romPath.c_str(); argv[6] = "-fl"; argv[7] = "assets/extractor/filelists"; argv[8] = "-gsf"; @@ -523,7 +561,7 @@ bool Extractor::CallZapd() { argv[12] = "-se"; argv[13] = "OTR"; argv[14] = "--otrfile"; - argv[15] = IsMasterQuest() ? "oot-mq.otr" : "oot.otr"; + argv[15] = otrFile; #ifdef _WIN32 // Grab a handle to the command window. @@ -541,6 +579,12 @@ bool Extractor::CallZapd() { ShowWindow(cmdWindow, SW_HIDE); #endif + std::filesystem::copy(otrFile, exportdir + "/" + otrFile, std::filesystem::copy_options::overwrite_existing); + + // Go back to where this game was executed from + std::filesystem::current_path(curdir); + std::filesystem::remove_all(tempdir); + return 0; } diff --git a/soh/soh/Extractor/Extract.h b/soh/soh/Extractor/Extract.h index e4eb2e5bb..6c9b4a078 100644 --- a/soh/soh/Extractor/Extract.h +++ b/soh/soh/Extractor/Extract.h @@ -57,7 +57,8 @@ class Extractor { bool IsMasterQuest() const; bool Run(RomSearchMode searchMode = RomSearchMode::Both); - bool CallZapd(); + bool CallZapd(std::string installPath, std::string exportdir); const char* GetZapdStr(); + std::string Mkdtemp(); }; #endif diff --git a/soh/soh/Extractor/FastCrc32C.c b/soh/soh/Extractor/FastCrc32C.c index 5ec097193..d88b04beb 100644 --- a/soh/soh/Extractor/FastCrc32C.c +++ b/soh/soh/Extractor/FastCrc32C.c @@ -1,14 +1,28 @@ #include #include +// Force the compiler to assume we have support for the CRC32 intrinsic. We will check for our selves later. +// Clang will define both __llvm__ and __GNUC__ but GCC will only define __GNUC__. So we need to check for __llvm__ first. +#if ((defined(__llvm__) && (defined(__x86_64__) || defined(__i386__)))) +#pragma clang attribute push(__attribute__((target("crc32"))), apply_to = function) +#elif ((defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)))) +// GCC Only lets you enable all of sse4.2 so we will for just this file and reset it at the end. +#pragma GCC push_options +#pragma GCC target("sse4.2") +#endif + +// Include headers for the CRC32 intrinsic and cpuid instruction on windows. No need to do any other checks because it assumes the target will support CRC32 #ifdef _WIN32 #include -#elif ((defined(__GNUC__) && defined(__x86_64__) || defined(__i386__)) && defined(__SSE4_2__)) +#include +// Same as above but these platforms use slightly different headers +#elif ((defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)))) #include +#include #elif defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) // Nothing cause its a compiler builtin #else -#define USE_CRC_TABLE +#define NO_CRC_INTRIN #endif #if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) @@ -16,14 +30,13 @@ #define INTRIN_CRC32_32(crc, value) __asm__("crc32cw %w[c], %w[c], %w[v]" : [c] "+r"(crc) : [v] "r"(value)) #define INTRIN_CRC32_16(crc, value) __asm__("crc32ch %w[c], %w[c], %w[v]" : [c] "+r"(crc) : [v] "r"(value)) #define INTRIN_CRC32_8(crc, value) __asm__("crc32cb %w[c], %w[c], %w[v]" : [c] "+r"(crc) : [v] "r"(value)) -#elif defined(__SSE4_2__) || defined(_MSC_VER) +#elif defined(__GNUC__) || defined(_MSC_VER) #define INTRIN_CRC32_64(crc, data) crc = _mm_crc32_u64(crc, data) #define INTRIN_CRC32_32(crc, data) crc = _mm_crc32_u32(crc, data) #define INTRIN_CRC32_16(crc, data) crc = _mm_crc32_u16(crc, data) #define INTRIN_CRC32_8(crc, data) crc = _mm_crc32_u8(crc, data) #endif -#ifdef USE_CRC_TABLE static const uint32_t crc32Table[256] = { 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL, 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L, 0x105EC76FL, 0xE235446CL, @@ -55,17 +68,13 @@ static const uint32_t crc32Table[256] = { 0xE03E9C81L, 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL, 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L }; -#endif +// On platforms that we know will never support a crc32 instruction (such as the WiiU) we will skip compiling this function in. +#ifndef NO_CRC_INTRIN -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef USE_CRC_TABLE -uint32_t CRC32C(unsigned char* data, size_t dataSize) { +static uint32_t CRC32IntrinImpl(unsigned char* data, size_t dataSize) { uint32_t ret = 0xFFFFFFFF; int64_t sizeSigned = dataSize; - +// Only 64bit platforms support doing a CRC32 operation on a 64bit value #if defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__) while ((sizeSigned -= sizeof(uint64_t)) >= 0) { INTRIN_CRC32_64(ret, *(uint64_t*)data); @@ -77,6 +86,7 @@ uint32_t CRC32C(unsigned char* data, size_t dataSize) { data += sizeof(uint32_t); } +// On 32 bit we can only do 32bit operations #elif defined(_M_IX86) || defined(__i386__) while ((sizeSigned -= sizeof(uint32_t)) >= 0) { INTRIN_CRC32_32(ret, *(uint32_t*)data); @@ -94,17 +104,41 @@ uint32_t CRC32C(unsigned char* data, size_t dataSize) { return ~ret; } -#else -uint32_t CRC32C(const void* buf, size_t size) { - const uint8_t* p = buf; +#endif + +static uint32_t CRC32TableImpl(unsigned char* data, size_t dataSize) { + const uint8_t* p = data; uint32_t crc = 0xFFFFFFFF; - while (size--) + while (dataSize--) crc = crc32Table[(crc ^ *p++) & 0xff] ^ (crc >> 8); return ~crc; } + +uint32_t CRC32C(unsigned char* data, size_t dataSize) { +#ifndef NO_CRC_INTRIN + // Test to make sure the CPU supports the CRC32 intrinsic + unsigned int cpuidData[4]; +#ifdef _WIN32 + __cpuid(cpuidData, 1); +#elif __APPLE__ || (defined(__aarch64__) && defined(__ARM_FEATURE_CRC32)) +// Every Mac that supports SoH should support this instruction. Also check for ARM64 at the same time + return CRC32IntrinImpl(data, dataSize); +#else + __get_cpuid(1, &cpuidData[0], &cpuidData[1], &cpuidData[2], &cpuidData[3]); #endif -#ifdef __cplusplus + + if (cpuidData[2] & (1 << 20)) { // bit_SSE4_2 + return CRC32IntrinImpl(data, dataSize); + } +#endif // NO_CRC_INTRIN + return CRC32TableImpl(data, dataSize); } + +#if ((defined(__llvm__) && (defined(__x86_64__) || defined(__i386__)))) +#pragma clang attribute pop +#elif ((defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)))) +#pragma GCC pop_options +#else #endif diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 6c9663ed7..e05468684 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -208,11 +208,11 @@ const char* constCameraStrings[] = { OTRGlobals::OTRGlobals() { std::vector OTRFiles; - std::string mqPath = LUS::Context::GetPathRelativeToAppDirectory("oot-mq.otr"); + std::string mqPath = LUS::Context::LocateFileAcrossAppDirs("oot-mq.otr", appShortName); if (std::filesystem::exists(mqPath)) { OTRFiles.push_back(mqPath); } - std::string ootPath = LUS::Context::GetPathRelativeToAppDirectory("oot.otr"); + std::string ootPath = LUS::Context::LocateFileAcrossAppDirs("oot.otr", appShortName); if (std::filesystem::exists(ootPath)) { OTRFiles.push_back(ootPath); } @@ -220,7 +220,7 @@ OTRGlobals::OTRGlobals() { if (std::filesystem::exists(sohOtrPath)) { OTRFiles.push_back(sohOtrPath); } - std::string patchesPath = LUS::Context::GetPathRelativeToAppDirectory("mods"); + std::string patchesPath = LUS::Context::LocateFileAcrossAppDirs("mods", appShortName); if (patchesPath.length() > 0 && std::filesystem::exists(patchesPath)) { if (std::filesystem::is_directory(patchesPath)) { for (const auto& p : std::filesystem::recursive_directory_iterator(patchesPath)) { @@ -248,7 +248,7 @@ OTRGlobals::OTRGlobals() { OOT_PAL_GC_DBG2 }; // tell LUS to reserve 3 SoH specific threads (Game, Audio, Save) - context = LUS::Context::CreateInstance("Ship of Harkinian", "soh", "shipofharkinian.json", OTRFiles, {}, 3); + context = LUS::Context::CreateInstance("Ship of Harkinian", appShortName, "shipofharkinian.json", OTRFiles, {}, 3); context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Animation, "Animation", std::make_shared()); context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_PlayerAnimation, "PlayerAnimation", std::make_shared()); @@ -717,8 +717,16 @@ extern "C" void OTRExtScanner() { extern "C" void InitOTR() { #if not defined (__SWITCH__) && not defined(__WIIU__) - if (!std::filesystem::exists(LUS::Context::GetPathRelativeToAppDirectory("oot-mq.otr")) && - !std::filesystem::exists(LUS::Context::GetPathRelativeToAppDirectory("oot.otr"))){ + if (!std::filesystem::exists(LUS::Context::LocateFileAcrossAppDirs("oot-mq.otr", appShortName)) && + !std::filesystem::exists(LUS::Context::LocateFileAcrossAppDirs("oot.otr", appShortName))){ + + std::string installPath = LUS::Context::GetAppBundlePath(); + if (!std::filesystem::exists(installPath + "/assets/extractor")) { + Extractor::ShowErrorBox("Extractor assets not found", + "No OTR files found. Missing assets/extractor folder needed to generate OTR file. Exiting..."); + exit(1); + } + bool generatedOtrIsMQ = false; if (Extractor::ShowYesNoBox("No OTR Files", "No OTR files found. Generate one now?") == IDYES) { Extractor extract; @@ -726,7 +734,7 @@ extern "C" void InitOTR() { Extractor::ShowErrorBox("Error", "An error occured, no OTR file was generated. Exiting..."); exit(1); } - extract.CallZapd(); + extract.CallZapd(installPath, LUS::Context::GetAppDirectoryPath(appShortName)); generatedOtrIsMQ = extract.IsMasterQuest(); } else { exit(1); @@ -736,7 +744,7 @@ extern "C" void InitOTR() { if (!extract.Run(generatedOtrIsMQ ? RomSearchMode::Vanilla : RomSearchMode::MQ)) { Extractor::ShowErrorBox("Error", "An error occured, an OTR file may have been generated by a different step. Continuing..."); } else { - extract.CallZapd(); + extract.CallZapd(installPath, LUS::Context::GetAppDirectoryPath(appShortName)); } } } @@ -1030,6 +1038,52 @@ extern "C" uint32_t ResourceMgr_GetGameVersion(int index) { return LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->GetGameVersions()[index]; } +extern "C" uint32_t ResourceMgr_GetGamePlatform(int index) { + uint32_t version = LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->GetGameVersions()[index]; + + switch (version) { + case OOT_NTSC_US_10: + case OOT_NTSC_US_11: + case OOT_NTSC_US_12: + case OOT_PAL_10: + case OOT_PAL_11: + return GAME_PLATFORM_N64; + case OOT_NTSC_JP_GC: + case OOT_NTSC_US_GC: + case OOT_PAL_GC: + case OOT_NTSC_JP_MQ: + case OOT_NTSC_US_MQ: + case OOT_PAL_MQ: + case OOT_PAL_GC_DBG1: + case OOT_PAL_GC_DBG2: + case OOT_PAL_GC_MQ_DBG: + return GAME_PLATFORM_GC; + } +} + +extern "C" uint32_t ResourceMgr_GetGameRegion(int index) { + uint32_t version = LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->GetGameVersions()[index]; + + switch (version) { + case OOT_NTSC_US_10: + case OOT_NTSC_US_11: + case OOT_NTSC_US_12: + case OOT_NTSC_JP_GC: + case OOT_NTSC_US_GC: + case OOT_NTSC_JP_MQ: + case OOT_NTSC_US_MQ: + return GAME_REGION_NTSC; + case OOT_PAL_10: + case OOT_PAL_11: + case OOT_PAL_GC: + case OOT_PAL_MQ: + case OOT_PAL_GC_DBG1: + case OOT_PAL_GC_DBG2: + case OOT_PAL_GC_MQ_DBG: + return GAME_REGION_PAL; + } +} + uint32_t IsSceneMasterQuest(s16 sceneNum) { uint32_t value = 0; uint8_t mqMode = CVarGetInteger("gBetterDebugWarpScreenMQMode", WARP_MODE_OVERRIDE_OFF); diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index bef92f306..29d4a3f84 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -6,6 +6,12 @@ #include "SaveManager.h" #include +#define GAME_REGION_NTSC 0 +#define GAME_REGION_PAL 1 + +#define GAME_PLATFORM_N64 0 +#define GAME_PLATFORM_GC 1 + #ifdef __cplusplus #include #include "Enhancements/savestates.h" @@ -13,6 +19,7 @@ #include const std::string customMessageTableID = "BaseGameOverrides"; +const std::string appShortName = "soh"; class OTRGlobals { @@ -61,6 +68,8 @@ uint32_t ResourceMgr_GameHasMasterQuest(); uint32_t ResourceMgr_GameHasOriginal(); uint32_t ResourceMgr_GetNumGameVersions(); uint32_t ResourceMgr_GetGameVersion(int index); +uint32_t ResourceMgr_GetGamePlatform(int index); +uint32_t ResourceMgr_GetGameRegion(int index); void ResourceMgr_LoadDirectory(const char* resName); char** ResourceMgr_ListFiles(const char* searchMask, int* resultSize); uint8_t ResourceMgr_FileExists(const char* resName); diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index 9330feec4..68f64c3a2 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -249,16 +249,16 @@ void DrawSettingsMenu() { if (ImGui::BeginMenu("Graphics")) { #ifndef __APPLE__ - UIWidgets::EnhancementSliderFloat("Internal Resolution: %d %%", "##IMul", "gInternalResolution", 0.5f, 2.0f, "", 1.0f, true); + if (UIWidgets::EnhancementSliderFloat("Internal Resolution: %d %%", "##IMul", "gInternalResolution", 0.5f, 2.0f, "", 1.0f, true)) { + LUS::Context::GetInstance()->GetWindow()->SetResolutionMultiplier(CVarGetFloat("gInternalResolution", 1)); + }; UIWidgets::Tooltip("Multiplies your output resolution by the value inputted, as a more intensive but effective form of anti-aliasing"); - // OTRTODO: fix this - // LUS::SetResolutionMultiplier(CVarGetFloat("gInternalResolution", 1)); #endif #ifndef __WIIU__ - UIWidgets::PaddedEnhancementSliderInt("MSAA: %d", "##IMSAA", "gMSAAValue", 1, 8, "", 1, true, true, false); + if (UIWidgets::PaddedEnhancementSliderInt("MSAA: %d", "##IMSAA", "gMSAAValue", 1, 8, "", 1, true, true, false)) { + LUS::Context::GetInstance()->GetWindow()->SetMsaaLevel(CVarGetInteger("gMSAAValue", 1)); + }; UIWidgets::Tooltip("Activates multi-sample anti-aliasing when above 1x up to 8x for 8 samples for every pixel"); - // OTRTODO: fix this - // LUS::SetMSAALevel(CVarGetInteger("gMSAAValue", 1)); #endif { // FPS Slider @@ -1009,6 +1009,9 @@ void DrawEnhancementsMenu() { ApplyAuthenticGfxPatches(); } UIWidgets::Tooltip("Fixes authentic out of bounds texture reads, instead loading textures with the correct size"); + UIWidgets::PaddedEnhancementCheckbox("Fix Poacher's Saw Softlock", "gFixSawSoftlock", true, false, CVarGetInteger("gSkipText", 0), + "This is disabled because it is forced on when Skip Text is enabled.", UIWidgets::CheckboxGraphics::Checkmark); + UIWidgets::Tooltip("Prevents the Poacher's Saw softlock from mashing through the text, or with Skip Text enabled."); ImGui::EndMenu(); } diff --git a/soh/src/code/padmgr.c b/soh/src/code/padmgr.c index abfa029e1..4735a259c 100644 --- a/soh/src/code/padmgr.c +++ b/soh/src/code/padmgr.c @@ -284,6 +284,13 @@ void PadMgr_ProcessInputs(PadMgr* padMgr) { Fault_AddHungupAndCrash(__FILE__, __LINE__); } + // When 3 frames are left on easy pause buffer, re-apply the last held inputs to the prev inputs + // to compute the pressed difference. This makes it so previously held inputs are continued as "held", + // but new inputs when unpausing are "pressed" out of the pause menu. + if (CVarGetInteger("gCheatEasyPauseBufferTimer", 0) == 3) { + input->prev.button = CVarGetInteger("gCheatEasyPauseBufferLastInputs", 0); + } + buttonDiff = input->prev.button ^ input->cur.button; input->press.button |= (u16)(buttonDiff & input->cur.button); input->rel.button |= (u16)(buttonDiff & input->prev.button); @@ -295,12 +302,6 @@ void PadMgr_ProcessInputs(PadMgr* padMgr) { uint8_t rumble = (padMgr->rumbleEnable[0] > 0); OTRControllerCallback(rumble); - if (CVarGetInteger("gPauseBufferBlockInputFrame", 0)) { - ControllerBlockGameInput(PAUSE_BUFFER_INPUT_BLOCK_ID); - } else { - ControllerUnblockGameInput(PAUSE_BUFFER_INPUT_BLOCK_ID); - } - PadMgr_UnlockPadData(padMgr); } diff --git a/soh/src/code/z_camera.c b/soh/src/code/z_camera.c index e0d827107..325eca828 100644 --- a/soh/src/code/z_camera.c +++ b/soh/src/code/z_camera.c @@ -1678,12 +1678,13 @@ s32 Camera_Normal1(Camera* camera) { Camera_ClampDist(camera, eyeAdjustment.r, norm1->distMin, norm1->distMax, anim->unk_28); if (anim->startSwingTimer <= 0) { + // idle camera re-center if (CVarGetInteger("gA11yDisableIdleCam", 0)) return; eyeAdjustment.pitch = atEyeNextGeo.pitch; eyeAdjustment.yaw = Camera_LERPCeilS(anim->swingYawTarget, atEyeNextGeo.yaw, 1.0f / camera->yawUpdateRateInv, 0xA); } else if (anim->swing.unk_18 != 0) { - if (CVarGetInteger("gA11yDisableIdleCam", 0)) return; + // camera adjustments when obstructed/pushed by scene geometry eyeAdjustment.yaw = Camera_LERPCeilS(anim->swing.unk_16, atEyeNextGeo.yaw, 1.0f / camera->yawUpdateRateInv, 0xA); eyeAdjustment.pitch = @@ -1708,19 +1709,19 @@ s32 Camera_Normal1(Camera* camera) { if ((camera->status == CAM_STAT_ACTIVE) && (!(norm1->interfaceFlags & 0x10))) { anim->swingYawTarget = BINANG_ROT180(camera->playerPosRot.rot.y); if (!CVarGetInteger("gFixCameraSwing", 0)) { - if (anim->startSwingTimer > 0) { - func_80046E20(camera, &eyeAdjustment, norm1->distMin, norm1->unk_0C, &sp98, &anim->swing); - } else { - sp88 = *eyeNext; - anim->swing.swingUpdateRate = camera->yawUpdateRateInv = norm1->unk_0C * 2.0f; - if (Camera_BGCheck(camera, at, &sp88)) { - anim->swingYawTarget = atEyeNextGeo.yaw; - anim->startSwingTimer = -1; + if (anim->startSwingTimer > 0) { + func_80046E20(camera, &eyeAdjustment, norm1->distMin, norm1->unk_0C, &sp98, &anim->swing); } else { - *eye = *eyeNext; + sp88 = *eyeNext; + anim->swing.swingUpdateRate = camera->yawUpdateRateInv = norm1->unk_0C * 2.0f; + if (Camera_BGCheck(camera, at, &sp88)) { + anim->swingYawTarget = atEyeNextGeo.yaw; + anim->startSwingTimer = -1; + } else { + *eye = *eyeNext; + } + anim->swing.unk_18 = 0; } - anim->swing.unk_18 = 0; - } } else { if (anim->startSwingTimer <= 0) { anim->swing.swingUpdateRate = camera->yawUpdateRateInv = norm1->unk_0C * 2.0f; diff --git a/soh/src/code/z_kaleido_setup.c b/soh/src/code/z_kaleido_setup.c index 94cb91d49..a335c2460 100644 --- a/soh/src/code/z_kaleido_setup.c +++ b/soh/src/code/z_kaleido_setup.c @@ -18,15 +18,24 @@ void KaleidoSetup_Update(PlayState* play) { play->shootingGalleryStatus <= 1 && gSaveContext.magicState != 8 && gSaveContext.magicState != 9 && (play->sceneNum != SCENE_BOWLING || !Flags_GetSwitch(play, 0x38))) { - if (CVarGetInteger("gCheatEasyPauseBufferFrameAdvance", 0) == 2 && !CHECK_BTN_ALL(input->press.button, BTN_START)) { - CVarSetInteger("gCheatEasyPauseBufferFrameAdvance", 0); + u8 easyPauseBufferEnabled = CVarGetInteger("gCheatEasyPauseBufferEnabled", 0); + u8 easyPauseBufferTimer = CVarGetInteger("gCheatEasyPauseBufferTimer", 0); + + // If start is not seen as pressed on the 2nd to last frame then we should end the easy frame advance flow + if (easyPauseBufferEnabled && easyPauseBufferTimer == 2 && + !CHECK_BTN_ALL(input->press.button, BTN_START)) { + CVarSetInteger("gCheatEasyPauseBufferTimer", 0); } if (CHECK_BTN_ALL(input->cur.button, BTN_L) && CHECK_BTN_ALL(input->press.button, BTN_CUP)) { if (BREG(0)) { pauseCtx->debugState = 3; } - } else if ((CHECK_BTN_ALL(input->press.button, BTN_START) && !CVarGetInteger("gCheatEasyPauseBufferFrameAdvance", 0)) || CVarGetInteger("gCheatEasyPauseBufferFrameAdvance", 0) == 1) { + } else if ((CHECK_BTN_ALL(input->press.button, BTN_START) && (!easyPauseBufferEnabled || !easyPauseBufferTimer)) || + (easyPauseBufferEnabled && easyPauseBufferTimer == 1)) { // Force Kaleido open when easy pause buffer reaches 0 + // Remember last held buttons for pause buffer cheat (minus start so easy frame advance works) + CVarSetInteger("gCheatEasyPauseBufferLastInputs", input->cur.button & ~(BTN_START)); + gSaveContext.unk_13EE = gSaveContext.unk_13EA; if (CHECK_BTN_ALL(input->cur.button, BTN_L)) diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index a124ff5ce..9ac51adab 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -6442,26 +6442,24 @@ void Interface_Update(PlayState* play) { gSaveContext.rupees--; Audio_PlaySoundGeneral(NA_SE_SY_RUPY_COUNT, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); } - if (gSaveContext.rupeeAccumulator == 0) { - if (gSaveContext.pendingSale != ITEM_NONE) { - u16 tempSaleItem = gSaveContext.pendingSale; - u16 tempSaleMod = gSaveContext.pendingSaleMod; - gSaveContext.pendingSale = ITEM_NONE; - gSaveContext.pendingSaleMod = MOD_NONE; - if (tempSaleMod == MOD_NONE) { - s16 giid = GetGIID(tempSaleItem); - if (giid == -1) { - tempSaleMod = MOD_RANDOMIZER; - } else { - tempSaleItem = giid; - } - } - GameInteractor_ExecuteOnSaleEndHooks(ItemTable_RetrieveEntry(tempSaleMod, tempSaleItem)); - } - } } else { gSaveContext.rupeeAccumulator = 0; } + if (gSaveContext.rupeeAccumulator == 0 && gSaveContext.pendingSale != ITEM_NONE) { + u16 tempSaleItem = gSaveContext.pendingSale; + u16 tempSaleMod = gSaveContext.pendingSaleMod; + gSaveContext.pendingSale = ITEM_NONE; + gSaveContext.pendingSaleMod = MOD_NONE; + if (tempSaleMod == MOD_NONE) { + s16 giid = GetGIID(tempSaleItem); + if (giid == -1) { + tempSaleMod = MOD_RANDOMIZER; + } else { + tempSaleItem = giid; + } + } + GameInteractor_ExecuteOnSaleEndHooks(ItemTable_RetrieveEntry(tempSaleMod, tempSaleItem)); + } } switch (interfaceCtx->unk_1EC) { diff --git a/soh/src/code/z_play.c b/soh/src/code/z_play.c index 352ae03cd..dc5b890ec 100644 --- a/soh/src/code/z_play.c +++ b/soh/src/code/z_play.c @@ -1761,12 +1761,11 @@ time_t Play_GetRealTime() { void Play_Main(GameState* thisx) { PlayState* play = (PlayState*)thisx; - if (CVarGetInteger("gCheatEasyPauseBufferFrameAdvance", 0)) { - CVarSetInteger("gCheatEasyPauseBufferFrameAdvance", CVarGetInteger("gCheatEasyPauseBufferFrameAdvance", 0) - 1); - } - if (CVarGetInteger("gPauseBufferBlockInputFrame", 0)) { - CVarSetInteger("gPauseBufferBlockInputFrame", CVarGetInteger("gPauseBufferBlockInputFrame", 0) - 1); + // Decrease the easy pause buffer timer every frame + if (CVarGetInteger("gCheatEasyPauseBufferTimer", 0) > 0) { + CVarSetInteger("gCheatEasyPauseBufferTimer", CVarGetInteger("gCheatEasyPauseBufferTimer", 0) - 1); } + if (play->envCtx.unk_EE[2] == 0 && CVarGetInteger("gLetItSnow", 0)) { play->envCtx.unk_EE[3] = 64; Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_OBJECT_KANKYO, 0, 0, 0, 0, 0, 0, 3, 0); diff --git a/soh/src/overlays/actors/ovl_En_Ds/z_en_ds.c b/soh/src/overlays/actors/ovl_En_Ds/z_en_ds.c index f5733a3f8..21891b219 100644 --- a/soh/src/overlays/actors/ovl_En_Ds/z_en_ds.c +++ b/soh/src/overlays/actors/ovl_En_Ds/z_en_ds.c @@ -174,11 +174,20 @@ void EnDs_OfferOddPotion(EnDs* this, PlayState* play) { } } +u8 EnDs_RandoCanGetGrannyItem() { + return gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MERCHANTS) != RO_SHUFFLE_MERCHANTS_OFF && + !Flags_GetRandomizerInf(RAND_INF_MERCHANTS_GRANNYS_SHOP) && + // Traded odd mushroom when adult trade is on + ((Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE) && Flags_GetItemGetInf(ITEMGETINF_30)) || + // Found claim check when adult trade is off + (!Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE) && + INV_CONTENT(ITEM_CLAIM_CHECK) == ITEM_CLAIM_CHECK)); +} + s32 EnDs_CheckRupeesAndBottle() { if (gSaveContext.rupees < 100) { return 0; - } else if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MERCHANTS) != RO_SHUFFLE_MERCHANTS_OFF && - !Flags_GetRandomizerInf(RAND_INF_MERCHANTS_GRANNYS_SHOP)) { + } else if (EnDs_RandoCanGetGrannyItem()) { // Allow buying the rando item regardless of having a bottle return 2; } else if (Inventory_HasEmptyBottle() == 0) { return 1; @@ -189,18 +198,14 @@ s32 EnDs_CheckRupeesAndBottle() { void EnDs_GiveBluePotion(EnDs* this, PlayState* play) { if (Actor_HasParent(&this->actor, play)) { - if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MERCHANTS) != RO_SHUFFLE_MERCHANTS_OFF && - (Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE) || INV_CONTENT(ITEM_CLAIM_CHECK) == ITEM_CLAIM_CHECK) && - !Flags_GetRandomizerInf(RAND_INF_MERCHANTS_GRANNYS_SHOP)) { + if (EnDs_RandoCanGetGrannyItem()) { Flags_SetRandomizerInf(RAND_INF_MERCHANTS_GRANNYS_SHOP); } this->actor.parent = NULL; this->actionFunc = EnDs_Talk; } else { - if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MERCHANTS) != RO_SHUFFLE_MERCHANTS_OFF && - (Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE) || INV_CONTENT(ITEM_CLAIM_CHECK) == ITEM_CLAIM_CHECK) && - !Flags_GetRandomizerInf(RAND_INF_MERCHANTS_GRANNYS_SHOP)) { + if (EnDs_RandoCanGetGrannyItem()) { GetItemEntry entry = Randomizer_GetItemFromKnownCheck(RC_KAK_GRANNYS_SHOP, GI_POTION_BLUE); GiveItemEntryFromActor(&this->actor, play, entry, 10000.0f, 50.0f); } else { @@ -226,9 +231,7 @@ void EnDs_OfferBluePotion(EnDs* this, PlayState* play) { this->actor.flags &= ~ACTOR_FLAG_WILL_TALK; GetItemEntry itemEntry; - if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MERCHANTS) != RO_SHUFFLE_MERCHANTS_OFF && - (Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE) || INV_CONTENT(ITEM_CLAIM_CHECK) == ITEM_CLAIM_CHECK) && - !Flags_GetRandomizerInf(RAND_INF_MERCHANTS_GRANNYS_SHOP)) { + if (EnDs_RandoCanGetGrannyItem()) { itemEntry = Randomizer_GetItemFromKnownCheck(RC_KAK_GRANNYS_SHOP, GI_POTION_BLUE); GiveItemEntryFromActor(&this->actor, play, itemEntry, 10000.0f, 50.0f); } else { @@ -258,8 +261,10 @@ void EnDs_Wait(EnDs* this, PlayState* play) { Audio_PlaySoundGeneral(NA_SE_SY_TRE_BOX_APPEAR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); player->actor.textId = 0x504A; this->actionFunc = EnDs_OfferOddPotion; - } else if ((gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE) == RO_GENERIC_OFF) || - Flags_GetItemGetInf(ITEMGETINF_30)) { + } else if ( + // Always offer blue potion when adult trade is off + (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE) == RO_GENERIC_OFF) || + Flags_GetItemGetInf(ITEMGETINF_30)) { // Traded odd mushroom player->actor.textId = 0x500C; this->actionFunc = EnDs_OfferBluePotion; } else { diff --git a/soh/src/overlays/actors/ovl_En_Heishi4/z_en_heishi4.c b/soh/src/overlays/actors/ovl_En_Heishi4/z_en_heishi4.c index c0986aa7f..863288634 100644 --- a/soh/src/overlays/actors/ovl_En_Heishi4/z_en_heishi4.c +++ b/soh/src/overlays/actors/ovl_En_Heishi4/z_en_heishi4.c @@ -334,7 +334,12 @@ void func_80A56B40(EnHeishi4* this, PlayState* play) { return; } if (this->type == HEISHI4_AT_MARKET_NIGHT) { - if (CVarGetInteger("gMarketSneak", 0)) { + Player* player = GET_PLAYER(play); + // Only allow sneaking when not wearing a mask as that triggers different dialogue. MM Bunny hood disables + // these interactions, so bunny hood is fine in that case. + if (CVarGetInteger("gMarketSneak", 0) && + (player->currentMask == PLAYER_MASK_NONE || + (player->currentMask == PLAYER_MASK_BUNNY && CVarGetInteger("gMMBunnyHood", 0)))) { this->actionFunc = EnHeishi4_MarketSneak; } else { this->actionFunc = func_80A56614; diff --git a/soh/src/overlays/actors/ovl_En_Js/z_en_js.c b/soh/src/overlays/actors/ovl_En_Js/z_en_js.c index 9b558f3fc..30ed425f4 100644 --- a/soh/src/overlays/actors/ovl_En_Js/z_en_js.c +++ b/soh/src/overlays/actors/ovl_En_Js/z_en_js.c @@ -136,7 +136,7 @@ void func_80A89160(EnJs* this, PlayState* play) { GetItemEntry itemEntry = Randomizer_GetItemFromKnownCheck(RC_WASTELAND_BOMBCHU_SALESMAN, GI_BOMBCHUS_10); gSaveContext.pendingSale = itemEntry.itemId; gSaveContext.pendingSaleMod = itemEntry.modIndex; - GiveItemEntryFromActor(&this->actor, play, itemEntry, 90.0f, 10.0f); + GiveItemEntryFromActor(&this->actor, play, itemEntry, 10000.0f, 50.0f); Flags_SetRandomizerInf(RAND_INF_MERCHANTS_CARPET_SALESMAN); } else { GetItemEntry itemEntry = ItemTable_Retrieve(GI_BOMBCHUS_10); diff --git a/soh/src/overlays/actors/ovl_En_Niw_Lady/z_en_niw_lady.c b/soh/src/overlays/actors/ovl_En_Niw_Lady/z_en_niw_lady.c index 34b19aa60..b009212d9 100644 --- a/soh/src/overlays/actors/ovl_En_Niw_Lady/z_en_niw_lady.c +++ b/soh/src/overlays/actors/ovl_En_Niw_Lady/z_en_niw_lady.c @@ -401,8 +401,8 @@ void func_80ABA9B8(EnNiwLady* this, PlayState* play) { if (!gSaveContext.n64ddFlag) { func_8002F434(&this->actor, play, GI_POCKET_EGG, 200.0f, 100.0f); } else { - // TODO: get-item-rework Adult trade sequence this->getItemEntry = Randomizer_GetItemFromKnownCheck(RC_KAK_ANJU_AS_ADULT, GI_POCKET_EGG); + GiveItemEntryFromActor(&this->actor, play, this->getItemEntry, 200.0f, 100.0f); Flags_SetItemGetInf(ITEMGETINF_2C); } @@ -436,9 +436,9 @@ void func_80ABAB08(EnNiwLady* this, PlayState* play) { if (!gSaveContext.n64ddFlag) { func_8002F434(&this->actor, play, GI_COJIRO, 200.0f, 100.0f); } else { - // TODO: get-item-rework Adult trade sequence this->getItemEntry = Randomizer_GetItemFromKnownCheck(RC_KAK_TRADE_POCKET_CUCCO, GI_COJIRO); Randomizer_ConsumeAdultTradeItem(play, ITEM_POCKET_CUCCO); + GiveItemEntryFromActor(&this->actor, play, this->getItemEntry, 200.0f, 100.0f); Flags_SetItemGetInf(ITEMGETINF_2E); } this->actionFunc = func_80ABAC00; @@ -462,21 +462,17 @@ void func_80ABAC00(EnNiwLady* this, PlayState* play) { if (Actor_HasParent(&this->actor, play)) { this->actionFunc = func_80ABAC84; } else { + if (gSaveContext.n64ddFlag) { + getItemId = this->getItemEntry.getItemId; + GiveItemEntryFromActor(&this->actor, play, this->getItemEntry, 200.0f, 100.0f); + return; + } + getItemId = this->getItemId; if (LINK_IS_ADULT) { - if (!gSaveContext.n64ddFlag) { - getItemId = !Flags_GetItemGetInf(ITEMGETINF_2C) ? GI_POCKET_EGG : GI_COJIRO; - } else { - // TODO: get-item-rework Adult trade sequence - getItemId = this->getItemEntry.getItemId; - GiveItemEntryFromActor(&this->actor, play, this->getItemEntry, 200.0f, 100.0f); - // Skip setting item flags because that was done earlier - this->actionFunc = func_80ABA778; - } - } - if (this->getItemEntry.getItemId == GI_NONE) { - func_8002F434(&this->actor, play, getItemId, 200.0f, 100.0f); + getItemId = !Flags_GetItemGetInf(ITEMGETINF_2C) ? GI_POCKET_EGG : GI_COJIRO; } + func_8002F434(&this->actor, play, getItemId, 200.0f, 100.0f); } } @@ -486,10 +482,13 @@ void func_80ABAC84(EnNiwLady* this, PlayState* play) { } osSyncPrintf(VT_FGCOL(GREEN) "☆☆☆☆☆ 正常終了 ☆☆☆☆☆ \n" VT_RST); if (LINK_IS_ADULT) { - if (!Flags_GetItemGetInf(ITEMGETINF_2C)) { - Flags_SetItemGetInf(ITEMGETINF_2C); - } else { - Flags_SetItemGetInf(ITEMGETINF_2E); + // Flags for randomizer gives are set in the original message prompt choice handling + if (!gSaveContext.n64ddFlag) { + if (!Flags_GetItemGetInf(ITEMGETINF_2C)) { + Flags_SetItemGetInf(ITEMGETINF_2C); + } else { + Flags_SetItemGetInf(ITEMGETINF_2E); + } } this->actionFunc = func_80ABA778; } else { diff --git a/soh/src/overlays/actors/ovl_En_Torch2/z_en_torch2.c b/soh/src/overlays/actors/ovl_En_Torch2/z_en_torch2.c index d7bd610a2..120a924ff 100644 --- a/soh/src/overlays/actors/ovl_En_Torch2/z_en_torch2.c +++ b/soh/src/overlays/actors/ovl_En_Torch2/z_en_torch2.c @@ -591,6 +591,10 @@ void EnTorch2_Update(Actor* thisx, PlayState* play2) { input->prev.button = input->cur.button & (u16) ~(BTN_A | BTN_B); PadUtils_UpdateRelXY(input); + if (CVarGetInteger("gMirroredWorld", 0)) { + input->rel.stick_x *= -1; + } + input->press.stick_x += (s8)(input->cur.stick_x - input->prev.stick_x); input->press.stick_y += (s8)(input->cur.stick_y - input->prev.stick_y); diff --git a/soh/src/overlays/actors/ovl_En_Toryo/z_en_toryo.c b/soh/src/overlays/actors/ovl_En_Toryo/z_en_toryo.c index 1b266f9eb..627d28c17 100644 --- a/soh/src/overlays/actors/ovl_En_Toryo/z_en_toryo.c +++ b/soh/src/overlays/actors/ovl_En_Toryo/z_en_toryo.c @@ -291,7 +291,10 @@ void func_80B20768(EnToryo* this, PlayState* play) { s16 sp32; s16 sp30; - if (this->unk_1E4 == 3) { + // Animation Count should be no more than 1 to guarantee putaway is complete after giving the saw + // As this is vanilla behavior, it only applies with the Fix toggle or Skip Text enabled. + bool checkAnim = (CVarGetInteger("gFixSawSoftlock", 0) != 0 || CVarGetInteger("gSkipText", 0) != 0) ? play->animationCtx.animationCount <= 1 : true; + if (this->unk_1E4 == 3 && checkAnim) { Actor_ProcessTalkRequest(&this->actor, play); Message_ContinueTextbox(play, this->actor.textId); this->unk_1E4 = 1; diff --git a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c index d334b6dd2..f36b5d669 100644 --- a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c +++ b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c @@ -353,7 +353,11 @@ void FileChoose_UpdateRandomizer() { func_800F5E18(SEQ_PLAYER_BGM_MAIN, NA_BGM_HORSE, 0, 7, 1); return; } else if (CVarGetInteger("gRandoGenerating", 0) == 0 && generating) { - Audio_PlayFanfare(NA_BGM_HORSE_GOAL); + if (SpoilerFileExists(CVarGetString("gSpoilerLog", ""))) { + Audio_PlayFanfare(NA_BGM_HORSE_GOAL); + } else { + func_80078884(NA_SE_SY_OCARINA_ERROR); + } func_800F5E18(SEQ_PLAYER_BGM_MAIN, NA_BGM_FILE_SELECT, 0, 7, 1); generating = 0; return; diff --git a/soh/src/overlays/gamestates/ovl_file_choose/z_file_nameset_PAL.c b/soh/src/overlays/gamestates/ovl_file_choose/z_file_nameset_PAL.c index dba736f8e..44cb67987 100644 --- a/soh/src/overlays/gamestates/ovl_file_choose/z_file_nameset_PAL.c +++ b/soh/src/overlays/gamestates/ovl_file_choose/z_file_nameset_PAL.c @@ -911,7 +911,13 @@ void FileChoose_DrawOptionsImpl(GameState* thisx) { } } - if (gSaveContext.language == LANGUAGE_GER) { + uint8_t versionIndex = ResourceMgr_GameHasMasterQuest() && ResourceMgr_GameHasOriginal(); + uint8_t isPalN64 = ResourceMgr_GetGameRegion(versionIndex) == GAME_REGION_PAL && + ResourceMgr_GetGamePlatform(versionIndex) == GAME_PLATFORM_N64; + uint8_t isPalGC = ResourceMgr_GetGameRegion(versionIndex) == GAME_REGION_PAL && + ResourceMgr_GetGamePlatform(versionIndex) == GAME_PLATFORM_GC; + + if (gSaveContext.language == LANGUAGE_GER && isPalGC) { gSPVertex(POLY_OPA_DISP++, D_80811E30, 32, 0); } else { gSPVertex(POLY_OPA_DISP++, D_80811D30, 32, 0); @@ -928,13 +934,24 @@ void FileChoose_DrawOptionsImpl(GameState* thisx) { G_IM_SIZ_8b, gOptionsMenuHeaders[i].width[gSaveContext.language], gOptionsMenuHeaders[i].height, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - gSP1Quadrangle(POLY_OPA_DISP++, vtx, vtx + 2, vtx + 3, vtx + 1, 0); + + if (i == 2 && gSaveContext.language == LANGUAGE_GER && isPalN64) { + // Pal N64 German vertex for Z target header are offset by 12 vertices + gSP1Quadrangle(POLY_OPA_DISP++, vtx + 12, vtx + 2 + 12, vtx + 3 + 12, vtx + 1 + 12, 0); + } else { + gSP1Quadrangle(POLY_OPA_DISP++, vtx, vtx + 2, vtx + 3, vtx + 1, 0); + } } - if (gSaveContext.language == LANGUAGE_GER) { + if (gSaveContext.language == LANGUAGE_GER && isPalGC) { gSPVertex(POLY_OPA_DISP++, D_80812130, 32, 0); } else { - gSPVertex(POLY_OPA_DISP++, D_80811F30, 32, 0); + // PAL N64 has extra german vertices combined in the regular array instead of a dedicated array + if (isPalN64) { + gSPVertex(POLY_OPA_DISP++, D_80811F30, 40, 0); + } else { + gSPVertex(POLY_OPA_DISP++, D_80811F30, 32, 0); + } } for (i = 0, vtx = 0; i < 4; i++, vtx += 4) { @@ -981,7 +998,17 @@ void FileChoose_DrawOptionsImpl(GameState* thisx) { G_IM_SIZ_8b, gOptionsMenuSettings[i].width[gSaveContext.language], gOptionsMenuSettings[i].height, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - gSP1Quadrangle(POLY_OPA_DISP++, vtx, vtx + 2, vtx + 3, vtx + 1, 0); + // Pal N64 German vertices for z target options are offset an by 8 + if (gSaveContext.language == LANGUAGE_GER && isPalN64) { + gSP1Quadrangle(POLY_OPA_DISP++, vtx + 8, vtx + 2 + 8, vtx + 3 + 8, vtx + 1 + 8, 0); + } else { + gSP1Quadrangle(POLY_OPA_DISP++, vtx, vtx + 2, vtx + 3, vtx + 1, 0); + } + } + + // Pal N64 needs to skip over the extra german vertices to get to brightness vertices + if (isPalN64) { + vtx += 8; } gDPPipeSync(POLY_OPA_DISP++); diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c index 4b8a80f9e..fecf4627a 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c @@ -3653,10 +3653,8 @@ void KaleidoScope_Update(PlayState* play) if (CHECK_BTN_ALL(input->press.button, BTN_START) || (CHECK_BTN_ALL(input->press.button, BTN_B) && gSaveContext.isBossRush)) { if (CVarGetInteger("gCheatEasyPauseBufferEnabled", 0) || CVarGetInteger("gCheatEasyInputBufferingEnabled", 0)) { - CVarSetInteger("gPauseBufferBlockInputFrame", 9); - } - if (CVarGetInteger("gCheatEasyPauseBufferEnabled", 0)) { - CVarSetInteger("gCheatEasyPauseBufferFrameAdvance", 13); + // Easy pause buffer is 13 frames, 12 for kaledio to end, and one more to advance a single frame + CVarSetInteger("gCheatEasyPauseBufferTimer", 13); } Interface_SetDoAction(play, DO_ACTION_NONE); pauseCtx->state = 0x12;