Merge pull request #3121 from Archez/mergeSuluBravo

Merge Sulu Bravo -> develop
This commit is contained in:
Adam Bird 2023-08-14 22:01:36 -04:00 committed by GitHub
commit 74d6678543
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 925 additions and 345 deletions

View File

@ -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")

View File

@ -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)

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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"
"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"
}

View File

@ -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"
"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"
}

View File

@ -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"
"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"
}

@ -1 +1 @@
Subproject commit af368413f5c61557a7baf2a7a6ab35ba16a7affd
Subproject commit 0a57812968539176bbeaa76c61532d0d6dec4881

View File

@ -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

View File

@ -1,14 +1,14 @@
<Root>
<File Name="code" OutName="z_fbdemo_circle" RangeStart="0xE90E0" RangeEnd="0x12CBB0">
<Texture Name="sTransCircleNormalTex" Format="i8" Width="16" Height="64" Offset="0xE90E0"/>
<Texture Name="sTransCircleWaveTex" Format="i8" Width="16" Height="64" Offset="0xE94E0"/>
<Texture Name="sTransCircleRippleTex" Format="i8" Width="16" Height="64" Offset="0xE98E0"/>
<Texture Name="sTransCircleStarburstTex" Format="i8" Width="16" Height="64" Offset="0xE9CE0"/>
<Array Name="sCircleWipeVtx" Count="34" Offset="0xEA0E0">
<File Name="code" OutName="z_fbdemo_circle" RangeStart="0xE90C8" RangeEnd="0x106F10">
<Texture Name="sTransCircleNormalTex" Format="i8" Width="16" Height="64" Offset="0xE90C8"/>
<Texture Name="sTransCircleWaveTex" Format="i8" Width="16" Height="64" Offset="0xE94C8"/>
<Texture Name="sTransCircleRippleTex" Format="i8" Width="16" Height="64" Offset="0xE98C8"/>
<Texture Name="sTransCircleStarburstTex" Format="i8" Width="16" Height="64" Offset="0xE9CC8"/>
<Array Name="sCircleWipeVtx" Count="34" Offset="0xEA0C8">
<Vtx/>
</Array>
<!-- ZAPD isn't finding symbols correctly, instead finding them much later in `code`-->
<!--<DList Name="sCircleWipeDL" Offset="0x10FF68"/>-->
<DList Name="sCircleDList" Offset="0xEA2E0"/>
<DList Name="sCircleDList" Offset="0xEA2C8"/>
</File>
</Root>

View File

@ -1,21 +1,21 @@
<Root>
<File Name="ovl_En_Ganon_Mant" BaseAddress="0x80A23D60" RangeStart="0x1218" RangeEnd="0x4118">
<Texture Name="gMantTex" OutName="mant" Format="rgba16" Width="32" Height="64" Offset="0x1218"/>
<File Name="ovl_En_Ganon_Mant" BaseAddress="0x80A0BCC0" RangeStart="0x11F8" RangeEnd="0x40F8">
<Texture Name="gMantTex" OutName="mant" Format="rgba16" Width="32" Height="64" Offset="0x11F8"/>
<Texture Name="gMantUnusedTex" OutName="mant_unused" Format="rgba16" Width="32" Height="32" Offset="0x2218"/>
<Texture Name="gMantUnusedTex" OutName="mant_unused" Format="rgba16" Width="32" Height="32" Offset="0x21F8"/>
<Array Name="gMant1Vtx" Count="144" Offset="0x2A18">
<Array Name="gMant1Vtx" Count="144" Offset="0x29F8">
<Vtx/>
</Array>
<DList Name="gMantMaterialDL" Offset="0x3318"/>
<DList Name="gMantMaterialDL" Offset="0x32F8"/>
<!-- ! @bug gMantUnusedTex is 32x32 not 32x64, however this dlist is unused -->
<DList Name="gMantUnusedMaterialDL" Offset="0x3370"/>
<DList Name="gMantUnusedMaterialDL" Offset="0x3350"/>
<DList Name="gMantDL" Offset="0x33C8"/>
<DList Name="gMantDL" Offset="0x33A8"/>
<Array Name="gMant2Vtx" Count="144" Offset="0x3818">
<Array Name="gMant2Vtx" Count="144" Offset="0x37F8">
<Vtx/>
</Array>
</File>

View File

@ -1,10 +1,10 @@
<Root>
<File Name="ovl_Oceff_Spot" BaseAddress="0x80BA6070" RangeStart="0x7F0" RangeEnd="0xEC8">
<Texture Name="sTex" OutName="sun_song_effect" Format="i8" Width="32" Height="32" Offset="0x7F0"/>
<Array Name="sCylinderVtx" Count="27" Offset="0xBF0">
<File Name="ovl_Oceff_Spot" BaseAddress="0x80B7CDC0" RangeStart="0x780" RangeEnd="0xE58">
<Texture Name="sTex" OutName="sun_song_effect" Format="i8" Width="32" Height="32" Offset="0x780"/>
<Array Name="sCylinderVtx" Count="27" Offset="0xB80">
<Vtx/>
</Array>
<DList Name="sCylinderMaterialDL" Offset="0xDA0"/>
<DList Name="sCylinderModelDL" Offset="0xE38"/>
<DList Name="sCylinderMaterialDL" Offset="0xD30"/>
<DList Name="sCylinderModelDL" Offset="0xDC8"/>
</File>
</Root>

View File

@ -1,10 +1,10 @@
<Root>
<File Name="ovl_Oceff_Wipe3" BaseAddress="0x80BAB3F0" RangeStart="0x480" RangeEnd="0x16C8">
<Texture Name="sTex" OutName="saria_song_effect" Format="i8" Width="64" Height="64" Offset="0x480"/>
<Array Name="sFrustumVtx" Count="22" Offset="0x1480">
<File Name="ovl_Oceff_Wipe3" BaseAddress="0x80B81D90" RangeStart="0x430" RangeEnd="0x1678">
<Texture Name="sTex" OutName="saria_song_effect" Format="i8" Width="64" Height="64" Offset="0x430"/>
<Array Name="sFrustumVtx" Count="22" Offset="0x1430">
<Vtx/>
</Array>
<DList Name="sMaterialDL" Offset="0x15E0"/>
<DList Name="sFrustumDL" Offset="0x1668"/>
<DList Name="sMaterialDL" Offset="0x1590"/>
<DList Name="sFrustumDL" Offset="0x1618"/>
</File>
</Root>

View File

@ -1,8 +1,8 @@
<Root>
<File Name="ovl_Bg_Ganon_Otyuka" BaseAddress="0x80A54D80" RangeStart="0x1100" RangeEnd="0x259C">
<Texture Name="sPlatformTex" OutName="platform_tex" Format="rgba16" Width="32" Height="32" Offset="0x1100"/>
<File Name="ovl_Bg_Ganon_Otyuka" BaseAddress="0x80A54D80" RangeStart="0x1110" RangeEnd="0x24EC">
<Texture Name="sPlatformTex" OutName="platform_tex" Format="rgba16" Width="32" Height="32" Offset="0x1110"/>
<Array Name="sPlatformTopVtx" Count="4" Offset="0x1908">
<Array Name="sPlatformTopVtx" Count="4" Offset="0x1918">
<Vtx/>
</Array>
<DList Name="sPlatformMaterialDL" Offset="0x1958"/>

View File

@ -3,18 +3,20 @@
<Array Name="D_80811BB0" Count="24" Offset="0xF120" Static="Off">
<Vtx/>
</Array>
<Array Name="D_80811D30" Count="16" Offset="0xF2A0" Static="Off">
<!-- German vertices are combined into one array -->
<Array Name="D_80811D30" Count="24" Offset="0xF2A0" Static="Off">
<Vtx/>
</Array>
<Array Name="D_80811E30" Count="16" Offset="0xF3A0" Static="Off">
<!-- <Array Name="D_80811E30" Count="16" Offset="0xF3A0" Static="Off">
<Vtx/>
</Array> -->
<!-- German vertices are combined into one array -->
<Array Name="D_80811F30" Count="40" Offset="0xF420" Static="Off">
<Vtx/>
</Array>
<Array Name="D_80811F30" Count="32" Offset="0xF4A0" Static="Off">
<!-- <Array Name="D_80812130" Count="32" Offset="0xF6A0" Static="Off">
<Vtx/>
</Array>
<Array Name="D_80812130" Count="32" Offset="0xF6A0" Static="Off">
<Vtx/>
</Array>
</Array> -->
<Array Name="gOptionsDividerTopVtx" Count="4" Offset="0xF8A0" Static="Off">
<Vtx/>
</Array>
@ -24,5 +26,6 @@
<Array Name="gOptionsDividerBottomVtx" Count="4" Offset="0xF920" Static="Off">
<Vtx/>
</Array>
<!-- OTRTODO: Vertices for Choose Language header, options, and divider -->
</File>
</Root>

View File

@ -1,10 +1,10 @@
<Root>
<File Name="ovl_Magic_Fire" BaseAddress="0x8095E690" RangeStart="0x600" RangeEnd="0x21E0">
<Texture Name="sTex" OutName="dins_fire" Format="i8" Width="64" Height="64" Offset="0xB50"/>
<Array Name="sSphereVtx" Count="76" Offset="0x1B50">
<File Name="ovl_Magic_Fire" BaseAddress="0x8095E690" RangeStart="0xB20" RangeEnd="0x2170">
<Texture Name="sTex" OutName="dins_fire" Format="i8" Width="64" Height="64" Offset="0xB20"/>
<Array Name="sSphereVtx" Count="76" Offset="0x1B20">
<Vtx/>
</Array>
<DList Name="sMaterialDL" Offset="0x2010"/>
<DList Name="sModelDL" Offset="0x2038"/>
<DList Name="sMaterialDL" Offset="0x1FE0"/>
<DList Name="sModelDL" Offset="0x2008"/>
</File>
</Root>

View File

@ -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";;

View File

@ -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();

View File

@ -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

View File

@ -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);
}

View File

@ -548,13 +548,13 @@ static void CalculateWotH() {
static void FastFill(std::vector<uint32_t> items, std::vector<uint32_t> 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));
}
}

View File

@ -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({

View File

@ -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"},

View File

@ -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);

View File

@ -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);

View File

@ -14,7 +14,7 @@ using namespace Settings;
std::vector<ItemAndPrice> NonShopItems = {};
static std::array<std::array<Text, 3>, 0xD5> trickNameTable; //Table of trick names for ice traps
static std::array<std::vector<Text>, 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] = {
@ -273,63 +278,79 @@ void InitTrickNames() {
trickNameTable[GI_LETTER_ZELDA] = {
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

View File

@ -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();
}
}

View File

@ -348,6 +348,7 @@ std::unordered_map<std::string, RandomizerSettingKey> 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]);

View File

@ -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();

View File

@ -13,6 +13,7 @@
#include "soh/Enhancements/boss-rush/BossRush.h"
extern "C" {
extern MapData* gMapData;
extern SaveContext gSaveContext;
extern PlayState* gPlayState;
}
@ -192,27 +193,108 @@ void RegisterOnKaleidoscopeUpdateHook() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnKaleidoscopeUpdate>([](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];
// 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 to so it is announced when pause is reopened
// 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)) {
@ -237,6 +319,17 @@ void RegisterOnKaleidoscopeUpdateHook() {
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,13 +416,14 @@ 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;
}
@ -305,9 +434,45 @@ 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:

View File

@ -44,6 +44,8 @@
#include <fstream>
#include <filesystem>
#include <unordered_map>
#include <random>
#include <string>
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<const char*, argc> 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;
}

View File

@ -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

View File

@ -1,14 +1,28 @@
#include <stdint.h>
#include <stddef.h>
// 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 <immintrin.h>
#elif ((defined(__GNUC__) && defined(__x86_64__) || defined(__i386__)) && defined(__SSE4_2__))
#include <intrin.h>
// Same as above but these platforms use slightly different headers
#elif ((defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__))))
#include <nmmintrin.h>
#include <cpuid.h>
#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

View File

@ -208,11 +208,11 @@ const char* constCameraStrings[] = {
OTRGlobals::OTRGlobals() {
std::vector<std::string> 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<LUS::AnimationFactory>());
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_PlayerAnimation, "PlayerAnimation", std::make_shared<LUS::PlayerAnimationFactory>());
@ -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);

View File

@ -6,6 +6,12 @@
#include "SaveManager.h"
#include <soh/Enhancements/item-tables/ItemTableTypes.h>
#define GAME_REGION_NTSC 0
#define GAME_REGION_PAL 1
#define GAME_PLATFORM_N64 0
#define GAME_PLATFORM_GC 1
#ifdef __cplusplus
#include <Context.h>
#include "Enhancements/savestates.h"
@ -13,6 +19,7 @@
#include <vector>
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);

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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 =

View File

@ -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))

View File

@ -6442,8 +6442,10 @@ 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) {
} else {
gSaveContext.rupeeAccumulator = 0;
}
if (gSaveContext.rupeeAccumulator == 0 && gSaveContext.pendingSale != ITEM_NONE) {
u16 tempSaleItem = gSaveContext.pendingSale;
u16 tempSaleMod = gSaveContext.pendingSaleMod;
gSaveContext.pendingSale = ITEM_NONE;
@ -6459,10 +6461,6 @@ void Interface_Update(PlayState* play) {
GameInteractor_ExecuteOnSaleEndHooks(ItemTable_RetrieveEntry(tempSaleMod, tempSaleItem));
}
}
} else {
gSaveContext.rupeeAccumulator = 0;
}
}
switch (interfaceCtx->unk_1EC) {
case 1:

View File

@ -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);

View File

@ -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 {

View File

@ -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;

View File

@ -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);

View File

@ -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,22 +462,18 @@ void func_80ABAC00(EnNiwLady* this, PlayState* play) {
if (Actor_HasParent(&this->actor, play)) {
this->actionFunc = func_80ABAC84;
} else {
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
if (gSaveContext.n64ddFlag) {
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;
return;
}
getItemId = this->getItemId;
if (LINK_IS_ADULT) {
getItemId = !Flags_GetItemGetInf(ITEMGETINF_2C) ? GI_POCKET_EGG : GI_COJIRO;
}
if (this->getItemEntry.getItemId == GI_NONE) {
func_8002F434(&this->actor, play, getItemId, 200.0f, 100.0f);
}
}
}
void func_80ABAC84(EnNiwLady* this, PlayState* play) {
@ -486,11 +482,14 @@ void func_80ABAC84(EnNiwLady* this, PlayState* play) {
}
osSyncPrintf(VT_FGCOL(GREEN) "☆☆☆☆☆ 正常終了 ☆☆☆☆☆ \n" VT_RST);
if (LINK_IS_ADULT) {
// 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 {
Flags_SetItemGetInf(ITEMGETINF_0C);

View File

@ -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);

View File

@ -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;

View File

@ -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) {
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;

View File

@ -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,14 +934,25 @@ 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);
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 {
// 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) {
gDPPipeSync(POLY_OPA_DISP++);
@ -981,8 +998,18 @@ 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);
// 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++);

View File

@ -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;