Compare commits

...

36 Commits

Author SHA1 Message Date
Garrett Cox 60faf3f750 Bump version to MacReady Echo 8.0.4 (#3537) 2023-12-17 22:47:39 -06:00
Garrett Cox ef910a02f7 Remove use of static variable in en_box (#3536) 2023-12-17 21:47:02 -06:00
inspectredc f607afc754 Add player state dead check to Player_UseTunicBoots (#3530)
* Add player state dead check to Player_UseTunicBoots

* Update soh/src/overlays/actors/ovl_player_actor/z_player.c

---------

Co-authored-by: Garrett Cox <garrettjcox@gmail.com>
2023-12-17 21:46:35 -06:00
inspectredc 865bcc57a7 Fix Logical Error With Darunias Door Entrance (#3529) 2023-12-17 21:20:09 -06:00
Garrett Cox b5caf33a9b Initialize GameInteractor before SaveManager so it can correctly set up a hook (#3535) 2023-12-17 21:19:30 -06:00
Adam Bird f655ab592d Re-implement Pause menu Dungeon map texture effects (#3496)
* first pass implement dungeon maps

* wrap up map dungeon implementation

* add comments and enums, rename vars

* bump lus
2023-12-17 15:42:34 -05:00
briaguya e6fc34e4c2 bump lus to latest 1.x (#3528) 2023-12-17 13:36:38 -05:00
Adam Bird d370ca93fd [Tweak] Improve KD lava effect performance and stability (#3501)
* improve kd lava performance and stability

* enum typo

* account for rock tex size
2023-12-17 13:23:07 -05:00
Garrett Cox fcf2141266 Fix JSON parsing every frame on file select (#3513)
* Fix JSON parsing every frame on file select

* string (#73)

---------

Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com>
2023-12-16 21:40:09 -05:00
Adam Bird e2f1cebfb5 fix condition causing enemies to always be small (#3512) 2023-12-16 20:56:36 -05:00
Adam Bird 907b770676 more swordless fixes when time traveling (#3510) 2023-12-16 20:56:14 -05:00
Adam Bird ea49196bae retain gameplay stats window size (#3508) 2023-12-16 20:52:36 -05:00
Adam Bird f65b711376 fix led crash when set to health (#3507) 2023-12-16 20:52:07 -05:00
Adam Bird 269e9faa46 change adult shooting gallery reward and add message (#3506) 2023-12-16 20:51:44 -05:00
Malkierian 35301556d9 Added "Always show gold skulltula" to check tracker options. Toggleable without restart. (#3505)
Made "Hide right-side shop checks" toggleable without restart.
2023-12-16 20:51:25 -05:00
Adam Bird fb0f7169d7 fix jabu mq minimap mark points (#3494) 2023-12-16 20:50:32 -05:00
Adam Bird fbc397a131 Tweak skeleton limbs to use OTR path strings for loading DList and improve Alt toggling (#3479)
* set otr string paths for DList on skeleton limbs

* delay toggling alt assets cvar to end of frame
2023-12-04 07:33:14 -06:00
briaguya 818addfdda delta bump (#3465) 2023-11-29 01:32:15 -05:00
Malkierian f14c390364 [Vanilla Fix] Slow Down Darunia's Dance (#3438)
* Fix Darunia's dancing animation speed (static for now; needs toggle later).

* Moved previous code to toggleable fix in enhancements. Tweaked speed factors, partially successful.
2023-11-29 00:38:48 -05:00
Adam Bird dd5e72a023 limit entrance discovered saving to end of operation (#3459) 2023-11-29 00:29:25 -05:00
rozlette d523b104d8 Change declaration of Morpha tentacle verts to combine them all and avoid overlaps that result in dropped verts 2023-11-28 21:09:34 -08:00
Garrett Cox fdcd9a7508 Race Integrity QoL (#3445)
* Add gDisableChangingSettings

* Add support for dropping a config file to overwrite CVars
2023-11-28 23:42:37 -05:00
Malkierian c4f34624ba Flag tracker (#3447)
* Hook into flagset hooks for processing check tracking. Has some manual workarounds (some breaks still need to be found).
Remove areaChecks and looping functionality as redundant.

* Additional vanilla handling.

* Fix tracker not showing MQ checks in MQ non-rando.
Fix tracker marking non-MQ variants of dungeon checks (e.g. map chest, etc) when collecting in MQ.

* Set all areas to spoiled if not rando.

* Revert attempt to spoil in randomizer based on MQ dungeon count as I don't know how that works at the moment.

* Restore and update spoiling based on MQ dungeon settings (none, selection, or count of 12).
Fix Anju As Adult check.

* Remove Anchor-specific code :baguette:

* Use `ClearAreaTotals()` in `Teardown()` instead of the duplicate code there.

* Update to `ClearAreaChecksAndTotals()` with `vec.clear()` added.

* Fix type spoiling again. Now spoils on 0 MQ dungeons, not rando, if the option is enabled in check tracker settings, selection, or set number of 12.
Fix vanilla checks being marked collected in MQ dungeons.

* Fix 100 GS check.

* ACTUALLY fix 100 GS: change flag type to `RandomizerInf()` in `item_location.cpp`, add RC to RandoInf for it to the table. Also don't send GI for flag if father, falsely triggers ZR frogs minigame.

* Fix gravedigging tour tracking.

* Fix membership card check tracking.
Change scene and flag values to any existing enums.
Clarifying formatting for the checking loop vOrMQ conditions.

* Fix Gravedigging Tour tracking.
Simplify Always Win Gravedigging Tour and Fix Gravedigging Tour Glitch applications.
Modified all necessary paths to use vanilla GDT PoH collection flag instead of randomizer variant.

* Fix Kak Potion Shop being "seen" when entering as child.
2023-11-28 21:25:48 -05:00
Adam Bird 33fe8776bb Fix bugs dont despawn cheat to work with soil patches (#3457) 2023-11-29 02:02:45 +01:00
briaguya 02256fac66 bump LUS to 1.4.0 (#3461) 2023-11-29 01:37:54 +01:00
briaguya 621afc99f0 sort patch otrs (#3430) 2023-11-29 01:34:00 +01:00
inspectredc 9d215b6dce Separate Arrows Equip Dupe Fix (#3450)
* add gseparatearrow check for equip dupe fix

* update gseparatearrows tooltip
2023-11-28 22:13:00 +01:00
aMannus 420bdab328 Random Enemy Sizes fixes (#3452) 2023-11-28 14:30:36 -05:00
Adam Bird 717074ff86 Fix: Missing TextIDs for MQ PAL and change lava size (#3449)
* Fix text offset for MQ pal and add text ID asserts

* correct lava texture size
2023-11-28 20:11:03 +01:00
Malkierian 3ab16b70c2 Changed all checks for !gPlayState to !GameInteractor::IsSaveLoaded() in mods.cpp for all the cheats, and added the same full check to others that really didn't need to be running outside of a game (like infinite rupees, magic, health, etc), and clear any triggering CVars. (#3441)
Changed `RegisterSwitchAge()` to clear the CVar instead of setting it to 0.
2023-11-27 23:00:25 +01:00
Malkierian 3cf9d655a7 Disable Fix Vine Fall when Climb Everything is enabled (#3439)
* Disable Fix Vine Fall when Climb Everything is enabled.

* Remove option disabling.
2023-11-26 11:34:54 -05:00
inspectredc 95f27ace2e Fix kokiri sword unequipping when using switch age cheat/enhancements (#3415)
* test fix for ks unequip

* remove unnecessary brackets
2023-11-24 09:40:42 -05:00
Salt d50ad4779d Fix #3417 Symlinks to Directories in Mods Dir Aren't Traversed (#3418) 2023-11-24 09:40:30 -05:00
Adam Bird f2df029efa fix: skybox crash for mask shop (#3427) 2023-11-24 09:38:45 -05:00
Garrett Cox bdb201201e Fix audio cutoff issues (#3428) 2023-11-24 09:38:13 -05:00
Adam Bird f4e4545180 Re-implement King Dodongo's Lava texture effects (#3434)
* fix alt backgrounds not always loading

* include gfx lookup with the original unload

* Add hook for alt toggle

* handle cpu modified texture for kd lava

* malloc array instead of illegal initialize
2023-11-23 09:07:30 -05:00
64 changed files with 1133 additions and 383 deletions
+2 -2
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") set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version")
project(Ship VERSION 8.0.2 LANGUAGES C CXX) project(Ship VERSION 8.0.4 LANGUAGES C CXX)
set(PROJECT_BUILD_NAME "MacReady Charlie" CACHE STRING "") set(PROJECT_BUILD_NAME "MacReady Echo" CACHE STRING "")
set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "") set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "")
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT soh) set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT soh)
+1 -1
View File
@@ -79,7 +79,7 @@
<Vtx/> <Vtx/>
</Array> </Array>
<Array Name="gMorphaVtx_007BB8" Count="4" Offset="0x7BB8"> <Array Name="gMorphaVtx_006A18" Count="286" Offset="0x006A18">
<Vtx/> <Vtx/>
</Array> </Array>
@@ -1,6 +1,6 @@
<Root> <Root>
<File Name="ovl_Boss_Dodongo" BaseAddress="0x808C1190" RangeStart="0x6238" RangeEnd="0x9238"> <File Name="ovl_Boss_Dodongo" BaseAddress="0x808C1190" RangeStart="0x6238" RangeEnd="0x9238">
<Texture Name="sLavaFloorLavaTex" OutName="lava_floor_lava" Format="rgba16" Width="64" Height="64" Offset="0x6238"/> <Texture Name="sLavaFloorLavaTex" OutName="lava_floor_lava" Format="rgba16" Width="32" Height="64" Offset="0x6238"/>
<Texture Name="sLavaFloorRockTex" OutName="lava_floor_rock" Format="rgba16" Width="32" Height="64" Offset="0x8238"/> <Texture Name="sLavaFloorRockTex" OutName="lava_floor_rock" Format="rgba16" Width="32" Height="64" Offset="0x8238"/>
</File> </File>
</Root> </Root>
@@ -8,7 +8,7 @@
<!-- Morpha's Title Card --> <!-- Morpha's Title Card -->
<Texture Name="gMorphaTitleCardTex" Format="i8" Width="128" Height="120" Offset="0x1010"/> <Texture Name="gMorphaTitleCardTex" Format="i8" Width="128" Height="120" Offset="0x1010"/>
<Texture Name="gMorphaWaterTex" Format="rgba16" Width="32" Height="32" Offset="0x8870"/> <Texture Name="gMorphaWaterTex" Format="rgba16" Width="32" Height="32" Offset="0x8870"/>
<!-- DLists for Morpha's Core --> <!-- DLists for Morpha's Core -->
<DList Name="gMorphaCoreMembraneDL" Offset="0x6700"/> <DList Name="gMorphaCoreMembraneDL" Offset="0x6700"/>
<DList Name="gMorphaCoreNucleusDL" Offset="0x6838"/> <DList Name="gMorphaCoreNucleusDL" Offset="0x6838"/>
@@ -69,17 +69,17 @@
<!-- Unused content --> <!-- Unused content -->
<!-- This is the dlist for EnVbBall for some reason. --> <!-- This is the dlist for EnVbBall for some reason. -->
<DList Name="gMorphaDL_000550" Offset="0x550"/> <DList Name="gMorphaDL_000550" Offset="0x550"/>
<DList Name="gMorphaDL_000EC0" Offset="0xEC0"/> <DList Name="gMorphaDL_000EC0" Offset="0xEC0"/>
<DList Name="gMorphaDL_000EF8" Offset="0xEF8"/> <DList Name="gMorphaDL_000EF8" Offset="0xEF8"/>
<DList Name="gMorphaDL_007BF8" Offset="0x7BF8"/> <DList Name="gMorphaDL_007BF8" Offset="0x7BF8"/>
<Array Name="gMorphaVtx_006938" Count="14" Offset="0x6938"> <Array Name="gMorphaVtx_006938" Count="14" Offset="0x6938">
<Vtx/> <Vtx/>
</Array> </Array>
<Array Name="gMorphaVtx_007BB8" Count="4" Offset="0x7BB8"> <Array Name="gMorphaVtx_006A18" Count="286" Offset="0x006A18">
<Vtx/> <Vtx/>
</Array> </Array>
@@ -1,6 +1,6 @@
<Root> <Root>
<File Name="ovl_Boss_Dodongo" BaseAddress="0x808B7370" RangeStart="0x61E8" RangeEnd="0x9238"> <File Name="ovl_Boss_Dodongo" BaseAddress="0x808B7370" RangeStart="0x61E8" RangeEnd="0x91E8">
<Texture Name="sLavaFloorLavaTex" OutName="lava_floor_lava" Format="rgba16" Width="64" Height="64" Offset="0x61E8"/> <Texture Name="sLavaFloorLavaTex" OutName="lava_floor_lava" Format="rgba16" Width="32" Height="64" Offset="0x61E8"/>
<Texture Name="sLavaFloorRockTex" OutName="lava_floor_rock" Format="rgba16" Width="32" Height="64" Offset="0x81E8"/> <Texture Name="sLavaFloorRockTex" OutName="lava_floor_rock" Format="rgba16" Width="32" Height="64" Offset="0x81E8"/>
</File> </File>
</Root> </Root>
@@ -1,14 +1,14 @@
<Root> <Root>
<File Name="nes_message_data_static"> <File Name="nes_message_data_static">
<Text Name="nes_message_data_static" CodeOffset="0xF6910"/> <Text Name="nes_message_data_static" CodeOffset="0xF68F0"/>
</File> </File>
<File Name="ger_message_data_static"> <File Name="ger_message_data_static">
<Text Name="ger_message_data_static" CodeOffset="0xF6910" LangOffset="0xFAB38"/> <Text Name="ger_message_data_static" CodeOffset="0xF68F0" LangOffset="0xFAB18"/>
</File> </File>
<File Name="fra_message_data_static"> <File Name="fra_message_data_static">
<Text Name="fra_message_data_static" CodeOffset="0xF6910" LangOffset="0xFCC48"/> <Text Name="fra_message_data_static" CodeOffset="0xF68F0" LangOffset="0xFCC28"/>
</File> </File>
<File Name="staff_message_data_static"> <File Name="staff_message_data_static">
<Text Name="staff_message_data_static" CodeOffset="0xFED58"/> <Text Name="staff_message_data_static" CodeOffset="0xFED38"/>
</File> </File>
</Root> </Root>
@@ -8,7 +8,7 @@
<!-- Morpha's Title Card --> <!-- Morpha's Title Card -->
<Texture Name="gMorphaTitleCardTex" Format="i8" Width="128" Height="120" Offset="0x1010"/> <Texture Name="gMorphaTitleCardTex" Format="i8" Width="128" Height="120" Offset="0x1010"/>
<Texture Name="gMorphaWaterTex" Format="rgba16" Width="32" Height="32" Offset="0x8870"/> <Texture Name="gMorphaWaterTex" Format="rgba16" Width="32" Height="32" Offset="0x8870"/>
<!-- DLists for Morpha's Core --> <!-- DLists for Morpha's Core -->
<DList Name="gMorphaCoreMembraneDL" Offset="0x6700"/> <DList Name="gMorphaCoreMembraneDL" Offset="0x6700"/>
<DList Name="gMorphaCoreNucleusDL" Offset="0x6838"/> <DList Name="gMorphaCoreNucleusDL" Offset="0x6838"/>
@@ -69,17 +69,17 @@
<!-- Unused content --> <!-- Unused content -->
<!-- This is the dlist for EnVbBall for some reason. --> <!-- This is the dlist for EnVbBall for some reason. -->
<DList Name="gMorphaDL_000550" Offset="0x550"/> <DList Name="gMorphaDL_000550" Offset="0x550"/>
<DList Name="gMorphaDL_000EC0" Offset="0xEC0"/> <DList Name="gMorphaDL_000EC0" Offset="0xEC0"/>
<DList Name="gMorphaDL_000EF8" Offset="0xEF8"/> <DList Name="gMorphaDL_000EF8" Offset="0xEF8"/>
<DList Name="gMorphaDL_007BF8" Offset="0x7BF8"/> <DList Name="gMorphaDL_007BF8" Offset="0x7BF8"/>
<Array Name="gMorphaVtx_006938" Count="14" Offset="0x6938"> <Array Name="gMorphaVtx_006938" Count="14" Offset="0x6938">
<Vtx/> <Vtx/>
</Array> </Array>
<Array Name="gMorphaVtx_007BB8" Count="4" Offset="0x7BB8"> <Array Name="gMorphaVtx_006A18" Count="286" Offset="0x006A18">
<Vtx/> <Vtx/>
</Array> </Array>
@@ -1,6 +1,6 @@
<Root> <Root>
<File Name="ovl_Boss_Dodongo" BaseAddress="0x808C1210" RangeStart="0x6238" RangeEnd="0x9238"> <File Name="ovl_Boss_Dodongo" BaseAddress="0x808C1210" RangeStart="0x6238" RangeEnd="0x9238">
<Texture Name="sLavaFloorLavaTex" OutName="lava_floor_lava" Format="rgba16" Width="64" Height="64" Offset="0x6238"/> <Texture Name="sLavaFloorLavaTex" OutName="lava_floor_lava" Format="rgba16" Width="32" Height="64" Offset="0x6238"/>
<Texture Name="sLavaFloorRockTex" OutName="lava_floor_rock" Format="rgba16" Width="32" Height="64" Offset="0x8238"/> <Texture Name="sLavaFloorRockTex" OutName="lava_floor_rock" Format="rgba16" Width="32" Height="64" Offset="0x8238"/>
</File> </File>
</Root> </Root>
@@ -8,7 +8,7 @@
<!-- Morpha's Title Card --> <!-- Morpha's Title Card -->
<Texture Name="gMorphaTitleCardTex" Format="i8" Width="128" Height="120" Offset="0x1010"/> <Texture Name="gMorphaTitleCardTex" Format="i8" Width="128" Height="120" Offset="0x1010"/>
<Texture Name="gMorphaWaterTex" Format="rgba16" Width="32" Height="32" Offset="0x8870"/> <Texture Name="gMorphaWaterTex" Format="rgba16" Width="32" Height="32" Offset="0x8870"/>
<!-- DLists for Morpha's Core --> <!-- DLists for Morpha's Core -->
<DList Name="gMorphaCoreMembraneDL" Offset="0x6700"/> <DList Name="gMorphaCoreMembraneDL" Offset="0x6700"/>
<DList Name="gMorphaCoreNucleusDL" Offset="0x6838"/> <DList Name="gMorphaCoreNucleusDL" Offset="0x6838"/>
@@ -69,17 +69,17 @@
<!-- Unused content --> <!-- Unused content -->
<!-- This is the dlist for EnVbBall for some reason. --> <!-- This is the dlist for EnVbBall for some reason. -->
<DList Name="gMorphaDL_000550" Offset="0x550"/> <DList Name="gMorphaDL_000550" Offset="0x550"/>
<DList Name="gMorphaDL_000EC0" Offset="0xEC0"/> <DList Name="gMorphaDL_000EC0" Offset="0xEC0"/>
<DList Name="gMorphaDL_000EF8" Offset="0xEF8"/> <DList Name="gMorphaDL_000EF8" Offset="0xEF8"/>
<DList Name="gMorphaDL_007BF8" Offset="0x7BF8"/> <DList Name="gMorphaDL_007BF8" Offset="0x7BF8"/>
<Array Name="gMorphaVtx_006938" Count="14" Offset="0x6938"> <Array Name="gMorphaVtx_006938" Count="14" Offset="0x6938">
<Vtx/> <Vtx/>
</Array> </Array>
<Array Name="gMorphaVtx_007BB8" Count="4" Offset="0x7BB8"> <Array Name="gMorphaVtx_006A18" Count="286" Offset="0x006A18">
<Vtx/> <Vtx/>
</Array> </Array>
@@ -1,6 +1,6 @@
<Root> <Root>
<File Name="ovl_Boss_Dodongo" BaseAddress="0x808C1190" RangeStart="0x6238" RangeEnd="0x9238"> <File Name="ovl_Boss_Dodongo" BaseAddress="0x808C1190" RangeStart="0x61E8" RangeEnd="0x91E8">
<Texture Name="sLavaFloorLavaTex" OutName="lava_floor_lava" Format="rgba16" Width="64" Height="64" Offset="0x6238"/> <Texture Name="sLavaFloorLavaTex" OutName="lava_floor_lava" Format="rgba16" Width="32" Height="64" Offset="0x61E8"/>
<Texture Name="sLavaFloorRockTex" OutName="lava_floor_rock" Format="rgba16" Width="32" Height="64" Offset="0x8238"/> <Texture Name="sLavaFloorRockTex" OutName="lava_floor_rock" Format="rgba16" Width="32" Height="64" Offset="0x81E8"/>
</File> </File>
</Root> </Root>
@@ -8,7 +8,7 @@
<!-- Morpha's Title Card --> <!-- Morpha's Title Card -->
<Texture Name="gMorphaTitleCardTex" Format="i8" Width="128" Height="120" Offset="0x1010"/> <Texture Name="gMorphaTitleCardTex" Format="i8" Width="128" Height="120" Offset="0x1010"/>
<Texture Name="gMorphaWaterTex" Format="rgba16" Width="32" Height="32" Offset="0x8870"/> <Texture Name="gMorphaWaterTex" Format="rgba16" Width="32" Height="32" Offset="0x8870"/>
<!-- DLists for Morpha's Core --> <!-- DLists for Morpha's Core -->
<DList Name="gMorphaCoreMembraneDL" Offset="0x6700"/> <DList Name="gMorphaCoreMembraneDL" Offset="0x6700"/>
<DList Name="gMorphaCoreNucleusDL" Offset="0x6838"/> <DList Name="gMorphaCoreNucleusDL" Offset="0x6838"/>
@@ -69,17 +69,17 @@
<!-- Unused content --> <!-- Unused content -->
<!-- This is the dlist for EnVbBall for some reason. --> <!-- This is the dlist for EnVbBall for some reason. -->
<DList Name="gMorphaDL_000550" Offset="0x550"/> <DList Name="gMorphaDL_000550" Offset="0x550"/>
<DList Name="gMorphaDL_000EC0" Offset="0xEC0"/> <DList Name="gMorphaDL_000EC0" Offset="0xEC0"/>
<DList Name="gMorphaDL_000EF8" Offset="0xEF8"/> <DList Name="gMorphaDL_000EF8" Offset="0xEF8"/>
<DList Name="gMorphaDL_007BF8" Offset="0x7BF8"/> <DList Name="gMorphaDL_007BF8" Offset="0x7BF8"/>
<Array Name="gMorphaVtx_006938" Count="14" Offset="0x6938"> <Array Name="gMorphaVtx_006938" Count="14" Offset="0x6938">
<Vtx/> <Vtx/>
</Array> </Array>
<Array Name="gMorphaVtx_007BB8" Count="4" Offset="0x7BB8"> <Array Name="gMorphaVtx_006A18" Count="286" Offset="0x006A18">
<Vtx/> <Vtx/>
</Array> </Array>
@@ -1,6 +1,6 @@
<Root> <Root>
<File Name="ovl_Boss_Dodongo" BaseAddress="0x8089E470" RangeStart="0x61C8" RangeEnd="0x91C8"> <File Name="ovl_Boss_Dodongo" BaseAddress="0x8089E470" RangeStart="0x61C8" RangeEnd="0x91C8">
<Texture Name="sLavaFloorLavaTex" OutName="lava_floor_lava" Format="rgba16" Width="64" Height="64" Offset="0x61C8"/> <Texture Name="sLavaFloorLavaTex" OutName="lava_floor_lava" Format="rgba16" Width="32" Height="64" Offset="0x61C8"/>
<Texture Name="sLavaFloorRockTex" OutName="lava_floor_rock" Format="rgba16" Width="32" Height="64" Offset="0x81C8"/> <Texture Name="sLavaFloorRockTex" OutName="lava_floor_rock" Format="rgba16" Width="32" Height="64" Offset="0x81C8"/>
</File> </File>
</Root> </Root>
@@ -8,7 +8,7 @@
<!-- Morpha's Title Card --> <!-- Morpha's Title Card -->
<Texture Name="gMorphaTitleCardTex" Format="i8" Width="128" Height="120" Offset="0x1010"/> <Texture Name="gMorphaTitleCardTex" Format="i8" Width="128" Height="120" Offset="0x1010"/>
<Texture Name="gMorphaWaterTex" Format="rgba16" Width="32" Height="32" Offset="0x8870"/> <Texture Name="gMorphaWaterTex" Format="rgba16" Width="32" Height="32" Offset="0x8870"/>
<!-- DLists for Morpha's Core --> <!-- DLists for Morpha's Core -->
<DList Name="gMorphaCoreMembraneDL" Offset="0x6700"/> <DList Name="gMorphaCoreMembraneDL" Offset="0x6700"/>
<DList Name="gMorphaCoreNucleusDL" Offset="0x6838"/> <DList Name="gMorphaCoreNucleusDL" Offset="0x6838"/>
@@ -69,17 +69,17 @@
<!-- Unused content --> <!-- Unused content -->
<!-- This is the dlist for EnVbBall for some reason. --> <!-- This is the dlist for EnVbBall for some reason. -->
<DList Name="gMorphaDL_000550" Offset="0x550"/> <DList Name="gMorphaDL_000550" Offset="0x550"/>
<DList Name="gMorphaDL_000EC0" Offset="0xEC0"/> <DList Name="gMorphaDL_000EC0" Offset="0xEC0"/>
<DList Name="gMorphaDL_000EF8" Offset="0xEF8"/> <DList Name="gMorphaDL_000EF8" Offset="0xEF8"/>
<DList Name="gMorphaDL_007BF8" Offset="0x7BF8"/> <DList Name="gMorphaDL_007BF8" Offset="0x7BF8"/>
<Array Name="gMorphaVtx_006938" Count="14" Offset="0x6938"> <Array Name="gMorphaVtx_006938" Count="14" Offset="0x6938">
<Vtx/> <Vtx/>
</Array> </Array>
<Array Name="gMorphaVtx_007BB8" Count="4" Offset="0x7BB8"> <Array Name="gMorphaVtx_006A18" Count="286" Offset="0x006A18">
<Vtx/> <Vtx/>
</Array> </Array>
@@ -1,6 +1,6 @@
<Root> <Root>
<File Name="ovl_Boss_Dodongo" BaseAddress="0x808C1190" RangeStart="0x61C8" RangeEnd="0x91C8"> <File Name="ovl_Boss_Dodongo" BaseAddress="0x808C1190" RangeStart="0x61C8" RangeEnd="0x91C8">
<Texture Name="sLavaFloorLavaTex" OutName="lava_floor_lava" Format="rgba16" Width="64" Height="64" Offset="0x61C8"/> <Texture Name="sLavaFloorLavaTex" OutName="lava_floor_lava" Format="rgba16" Width="32" Height="64" Offset="0x61C8"/>
<Texture Name="sLavaFloorRockTex" OutName="lava_floor_rock" Format="rgba16" Width="32" Height="64" Offset="0x81C8"/> <Texture Name="sLavaFloorRockTex" OutName="lava_floor_rock" Format="rgba16" Width="32" Height="64" Offset="0x81C8"/>
</File> </File>
</Root> </Root>
@@ -312,6 +312,7 @@ namespace GameControlEditor {
DrawHelpIcon("Allows the cursor on the pause menu to be over any slot. Sometimes required in rando to select " DrawHelpIcon("Allows the cursor on the pause menu to be over any slot. Sometimes required in rando to select "
"certain items."); "certain items.");
UIWidgets::Spacer(0); UIWidgets::Spacer(0);
ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0));
UIWidgets::PaddedEnhancementCheckbox("Enable walk speed modifiers", "gEnableWalkModify", true, false); UIWidgets::PaddedEnhancementCheckbox("Enable walk speed modifiers", "gEnableWalkModify", true, false);
DrawHelpIcon("Hold the assigned button to change the maximum walking speed\nTo change the assigned button, go into the Ports tabs above"); DrawHelpIcon("Hold the assigned button to change the maximum walking speed\nTo change the assigned button, go into the Ports tabs above");
if (CVarGetInteger("gEnableWalkModify", 0)) { if (CVarGetInteger("gEnableWalkModify", 0)) {
@@ -323,6 +324,7 @@ namespace GameControlEditor {
UIWidgets::PaddedEnhancementSliderFloat("Modifier 2: %d %%", "##WalkMod2", "gWalkModifierTwo", 0.0f, 5.0f, "", 1.0f, true, true, false, true); UIWidgets::PaddedEnhancementSliderFloat("Modifier 2: %d %%", "##WalkMod2", "gWalkModifierTwo", 0.0f, 5.0f, "", 1.0f, true, true, false, true);
window->EndGroupPanelPublic(0); window->EndGroupPanelPublic(0);
} }
ImGui::EndDisabled();
UIWidgets::Spacer(0); UIWidgets::Spacer(0);
UIWidgets::PaddedEnhancementCheckbox("Answer Navi Prompt with L Button", "gNaviOnL"); UIWidgets::PaddedEnhancementCheckbox("Answer Navi Prompt with L Button", "gNaviOnL");
DrawHelpIcon("Speak to Navi with L but enter first-person camera with C-Up"); DrawHelpIcon("Speak to Navi with L but enter first-person camera with C-Up");
@@ -1485,6 +1485,7 @@ void Draw_Placements(){
} }
void DrawSillyTab() { void DrawSillyTab() {
ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0));
if (CVarGetInteger("gLetItSnow", 0)) { if (CVarGetInteger("gLetItSnow", 0)) {
if (UIWidgets::EnhancementCheckbox("Let It Snow", "gLetItSnow")) { if (UIWidgets::EnhancementCheckbox("Let It Snow", "gLetItSnow")) {
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
@@ -1569,6 +1570,7 @@ void DrawSillyTab() {
CVarClear("gCosmetics.Kak_Windmill_Speed.Changed"); CVarClear("gCosmetics.Kak_Windmill_Speed.Changed");
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
} }
ImGui::EndDisabled();
} }
// Copies the RGB values from one cosmetic option to another, multiplied by the passed in amount, this // Copies the RGB values from one cosmetic option to another, multiplied by the passed in amount, this
@@ -51,6 +51,7 @@ typedef enum {
TEXT_WARP_NOCTURNE_OF_SHADOW = 0x891, TEXT_WARP_NOCTURNE_OF_SHADOW = 0x891,
TEXT_WARP_PRELUDE_OF_LIGHT = 0x892, TEXT_WARP_PRELUDE_OF_LIGHT = 0x892,
TEXT_WARP_RANDOM_REPLACED_TEXT = 0x9200, TEXT_WARP_RANDOM_REPLACED_TEXT = 0x9200,
TEXT_SHOOTING_GALLERY_MAN_COME_BACK_WITH_BOW = 0x9210,
TEXT_LAKE_HYLIA_WATER_SWITCH_SIGN = 0x346, // 0x3yy for cuttable sign range TEXT_LAKE_HYLIA_WATER_SWITCH_SIGN = 0x346, // 0x3yy for cuttable sign range
TEXT_LAKE_HYLIA_WATER_SWITCH_NAVI = 0x1B3, // 0x1yy for Navi msg range TEXT_LAKE_HYLIA_WATER_SWITCH_NAVI = 0x1B3, // 0x1yy for Navi msg range
} TextIDs; } TextIDs;
+5
View File
@@ -1,3 +1,6 @@
#ifndef _ENHANCEMENT_TYPES_H_
#define _ENHANCEMENT_TYPES_H_
typedef enum { typedef enum {
WARP_MODE_OVERRIDE_OFF, WARP_MODE_OVERRIDE_OFF,
WARP_MODE_OVERRIDE_MQ_AS_VANILLA, WARP_MODE_OVERRIDE_MQ_AS_VANILLA,
@@ -74,3 +77,5 @@ typedef enum {
DEKU_STICK_UNBREAKABLE, DEKU_STICK_UNBREAKABLE,
DEKU_STICK_UNBREAKABLE_AND_ALWAYS_ON_FIRE, DEKU_STICK_UNBREAKABLE_AND_ALWAYS_ON_FIRE,
} DekuStickType; } DekuStickType;
#endif
@@ -94,6 +94,7 @@ void GameInteractor_SetTriforceHuntCreditsWarpActive(uint8_t state);
#include <vector> #include <vector>
#include <functional> #include <functional>
#include <string>
#define DEFINE_HOOK(name, type) \ #define DEFINE_HOOK(name, type) \
struct name { \ struct name { \
@@ -193,6 +194,9 @@ public:
DEFINE_HOOK(OnSetGameLanguage, void()); DEFINE_HOOK(OnSetGameLanguage, void());
DEFINE_HOOK(OnFileDropped, void(std::string filePath));
DEFINE_HOOK(OnAssetAltChange, void());
// Helpers // Helpers
static bool IsSaveLoaded(); static bool IsSaveLoaded();
static bool IsGameplayPaused(); static bool IsGameplayPaused();
@@ -181,3 +181,9 @@ void GameInteractor_ExecuteOnUpdateFileNameSelection(int16_t charCode) {
void GameInteractor_ExecuteOnSetGameLanguage() { void GameInteractor_ExecuteOnSetGameLanguage() {
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnSetGameLanguage>(); GameInteractor::Instance->ExecuteHooks<GameInteractor::OnSetGameLanguage>();
} }
// MARK: - System
void GameInteractor_RegisterOnAssetAltChange(void (*fn)(void)) {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnAssetAltChange>(fn);
}
@@ -56,6 +56,10 @@ void GameInteractor_ExecuteOnUpdateFileNameSelection(int16_t charCode);
// MARK: - Game // MARK: - Game
void GameInteractor_ExecuteOnSetGameLanguage(); void GameInteractor_ExecuteOnSetGameLanguage();
// MARK: - System
void GameInteractor_RegisterOnAssetAltChange(void (*fn)(void));
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
+1 -1
View File
@@ -618,7 +618,7 @@ void DrawGameplayStatsOptionsTab() {
} }
void GameplayStatsWindow::DrawElement() { void GameplayStatsWindow::DrawElement() {
ImGui::SetNextWindowSize(ImVec2(480, 550), ImGuiCond_Appearing); ImGui::SetNextWindowSize(ImVec2(480, 550), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("Gameplay Stats", &mIsVisible, ImGuiWindowFlags_NoFocusOnAppearing)) { if (!ImGui::Begin("Gameplay Stats", &mIsVisible, ImGuiWindowFlags_NoFocusOnAppearing)) {
ImGui::End(); ImGui::End();
return; return;
+28 -13
View File
@@ -47,6 +47,7 @@ void ReloadSceneTogglingLinkAge() {
void RegisterInfiniteMoney() { void RegisterInfiniteMoney() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() { GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
if (!GameInteractor::IsSaveLoaded()) return;
if (CVarGetInteger("gInfiniteMoney", 0) != 0) { if (CVarGetInteger("gInfiniteMoney", 0) != 0) {
if (gSaveContext.rupees < CUR_CAPACITY(UPG_WALLET)) { if (gSaveContext.rupees < CUR_CAPACITY(UPG_WALLET)) {
gSaveContext.rupees = CUR_CAPACITY(UPG_WALLET); gSaveContext.rupees = CUR_CAPACITY(UPG_WALLET);
@@ -57,6 +58,7 @@ void RegisterInfiniteMoney() {
void RegisterInfiniteHealth() { void RegisterInfiniteHealth() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() { GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
if (!GameInteractor::IsSaveLoaded()) return;
if (CVarGetInteger("gInfiniteHealth", 0) != 0) { if (CVarGetInteger("gInfiniteHealth", 0) != 0) {
if (gSaveContext.health < gSaveContext.healthCapacity) { if (gSaveContext.health < gSaveContext.healthCapacity) {
gSaveContext.health = gSaveContext.healthCapacity; gSaveContext.health = gSaveContext.healthCapacity;
@@ -67,6 +69,7 @@ void RegisterInfiniteHealth() {
void RegisterInfiniteAmmo() { void RegisterInfiniteAmmo() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() { GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
if (!GameInteractor::IsSaveLoaded()) return;
if (CVarGetInteger("gInfiniteAmmo", 0) != 0) { if (CVarGetInteger("gInfiniteAmmo", 0) != 0) {
// Deku Sticks // Deku Sticks
if (AMMO(ITEM_STICK) < CUR_CAPACITY(UPG_STICKS)) { if (AMMO(ITEM_STICK) < CUR_CAPACITY(UPG_STICKS)) {
@@ -103,6 +106,7 @@ void RegisterInfiniteAmmo() {
void RegisterInfiniteMagic() { void RegisterInfiniteMagic() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() { GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
if (!GameInteractor::IsSaveLoaded()) return;
if (CVarGetInteger("gInfiniteMagic", 0) != 0) { if (CVarGetInteger("gInfiniteMagic", 0) != 0) {
if (gSaveContext.isMagicAcquired && gSaveContext.magic != (gSaveContext.isDoubleMagicAcquired + 1) * 0x30) { if (gSaveContext.isMagicAcquired && gSaveContext.magic != (gSaveContext.isDoubleMagicAcquired + 1) * 0x30) {
gSaveContext.magic = (gSaveContext.isDoubleMagicAcquired + 1) * 0x30; gSaveContext.magic = (gSaveContext.isDoubleMagicAcquired + 1) * 0x30;
@@ -113,6 +117,7 @@ void RegisterInfiniteMagic() {
void RegisterInfiniteNayrusLove() { void RegisterInfiniteNayrusLove() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() { GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
if (!GameInteractor::IsSaveLoaded()) return;
if (CVarGetInteger("gInfiniteNayru", 0) != 0) { if (CVarGetInteger("gInfiniteNayru", 0) != 0) {
gSaveContext.nayrusLoveTimer = 0x44B; gSaveContext.nayrusLoveTimer = 0x44B;
} }
@@ -121,7 +126,7 @@ void RegisterInfiniteNayrusLove() {
void RegisterMoonJumpOnL() { void RegisterMoonJumpOnL() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() { GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
if (!gPlayState) return; if (!GameInteractor::IsSaveLoaded()) return;
if (CVarGetInteger("gMoonJumpOnL", 0) != 0) { if (CVarGetInteger("gMoonJumpOnL", 0) != 0) {
Player* player = GET_PLAYER(gPlayState); Player* player = GET_PLAYER(gPlayState);
@@ -136,7 +141,7 @@ void RegisterMoonJumpOnL() {
void RegisterInfiniteISG() { void RegisterInfiniteISG() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() { GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
if (!gPlayState) return; if (!GameInteractor::IsSaveLoaded()) return;
if (CVarGetInteger("gEzISG", 0) != 0) { if (CVarGetInteger("gEzISG", 0) != 0) {
Player* player = GET_PLAYER(gPlayState); Player* player = GET_PLAYER(gPlayState);
@@ -148,7 +153,7 @@ void RegisterInfiniteISG() {
//Permanent quick put away (QPA) glitched damage value //Permanent quick put away (QPA) glitched damage value
void RegisterEzQPA() { void RegisterEzQPA() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() { GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
if (!gPlayState) return; if (!GameInteractor::IsSaveLoaded()) return;
if (CVarGetInteger("gEzQPA", 0) != 0) { if (CVarGetInteger("gEzQPA", 0) != 0) {
Player* player = GET_PLAYER(gPlayState); Player* player = GET_PLAYER(gPlayState);
@@ -160,7 +165,7 @@ void RegisterEzQPA() {
void RegisterUnrestrictedItems() { void RegisterUnrestrictedItems() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() { GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
if (!gPlayState) return; if (!GameInteractor::IsSaveLoaded()) return;
if (CVarGetInteger("gNoRestrictItems", 0) != 0) { if (CVarGetInteger("gNoRestrictItems", 0) != 0) {
u8 sunsBackup = gPlayState->interfaceCtx.restrictions.sunsSong; u8 sunsBackup = gPlayState->interfaceCtx.restrictions.sunsSong;
@@ -188,14 +193,16 @@ void RegisterFreezeTime() {
/// Switches Link's age and respawns him at the last entrance he entered. /// Switches Link's age and respawns him at the last entrance he entered.
void RegisterSwitchAge() { void RegisterSwitchAge() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() { GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
if (!GameInteractor::IsSaveLoaded()) {
CVarClear("gSwitchAge");
return;
}
static bool warped = false; static bool warped = false;
static Vec3f playerPos; static Vec3f playerPos;
static int16_t playerYaw; static int16_t playerYaw;
static RoomContext* roomCtx; static RoomContext* roomCtx;
static s32 roomNum; static s32 roomNum;
if (!gPlayState) return;
if (CVarGetInteger("gSwitchAge", 0) && !warped) { if (CVarGetInteger("gSwitchAge", 0) && !warped) {
playerPos = GET_PLAYER(gPlayState)->actor.world.pos; playerPos = GET_PLAYER(gPlayState)->actor.world.pos;
playerYaw = GET_PLAYER(gPlayState)->actor.shape.rot.y; playerYaw = GET_PLAYER(gPlayState)->actor.shape.rot.y;
@@ -215,7 +222,7 @@ void RegisterSwitchAge() {
func_80097534(gPlayState, roomCtx); // load map for new room (unloading the previous room) func_80097534(gPlayState, roomCtx); // load map for new room (unloading the previous room)
} }
warped = false; warped = false;
CVarSetInteger("gSwitchAge", 0); CVarClear("gSwitchAge");
} }
}); });
} }
@@ -224,7 +231,8 @@ void RegisterSwitchAge() {
void RegisterOcarinaTimeTravel() { void RegisterOcarinaTimeTravel() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnOcarinaSongAction>([]() { GameInteractor::Instance->RegisterGameHook<GameInteractor::OnOcarinaSongAction>([]() {
if (!gPlayState) { if (!GameInteractor::IsSaveLoaded()) {
CVarClear("gTimeTravel");
return; return;
} }
@@ -1025,8 +1033,16 @@ void RegisterRandomizedEnemySizes() {
Player* player = GET_PLAYER(gPlayState); Player* player = GET_PLAYER(gPlayState);
Actor* actor = static_cast<Actor*>(refActor); Actor* actor = static_cast<Actor*>(refActor);
// Only apply to enemies and bosses. Exclude the wobbly platforms in Jabu because they need to act like platforms. // Exclude wobbly platforms in Jabu because they need to act like platforms.
if (!CVarGetInteger("gRandomizedEnemySizes", 0) || (actor->category != ACTORCAT_ENEMY && actor->category != ACTORCAT_BOSS) || actor->id == ACTOR_EN_BROB) { // Exclude Dead Hand hands and Bongo Bongo main body because they make the fights (near) impossible.
uint8_t excludedEnemy = actor->id == ACTOR_EN_BROB || actor->id == ACTOR_EN_DHA || (actor->id == ACTOR_BOSS_SST && actor->params == -1);
// Dodongo, Volvagia and Dead Hand are always smaller because they're impossible when bigger.
uint8_t smallOnlyEnemy = actor->id == ACTOR_BOSS_DODONGO || actor->id == ACTOR_BOSS_FD ||
actor->id == ACTOR_BOSS_FD2 || actor->id == ACTOR_EN_DH;
// Only apply to enemies and bosses.
if (!CVarGetInteger("gRandomizedEnemySizes", 0) || (actor->category != ACTORCAT_ENEMY && actor->category != ACTORCAT_BOSS) || excludedEnemy) {
return; return;
} }
@@ -1035,9 +1051,8 @@ void RegisterRandomizedEnemySizes() {
uint8_t bigActor = rand() % 2; uint8_t bigActor = rand() % 2;
// Big actor. Dodongo and Volvagia are always smaller because they're impossible when bigger. // Big actor
if (bigActor && actor->id != ACTOR_BOSS_DODONGO && actor->id != ACTOR_BOSS_FD && if (bigActor && !smallOnlyEnemy) {
actor->id != ACTOR_BOSS_FD2) {
randomNumber = rand() % 200; randomNumber = rand() % 200;
// Between 100% and 300% size. // Between 100% and 300% size.
randomScale = 1.0f + (randomNumber / 100); randomScale = 1.0f + (randomNumber / 100);
+51 -1
View File
@@ -217,6 +217,31 @@ const std::vector<const char*> enhancementsCvars = {
"gFixTexturesOOB", "gFixTexturesOOB",
"gIvanCoopModeEnabled", "gIvanCoopModeEnabled",
"gEnemySpawnsOverWaterboxes", "gEnemySpawnsOverWaterboxes",
"gTreeStickDrops",
"gShadowTag",
"gRandomizedEnemySizes",
"gRandomizedEnemies",
"gMirroredWorldMode",
"gMirroredWorld",
"gHyperEnemies",
"gHookshotableReticle",
"gHideBunnyHood",
"gFixVineFall",
"gFileSelectMoreInfo",
"gEnemyHealthBar",
"gBushDropFix",
"gAllDogsRichard",
"gAddTraps.enabled",
"gAddTraps.Ammo",
"gAddTraps.Bomb",
"gAddTraps.Burn",
"gAddTraps.Ice",
"gAddTraps.Kill",
"gAddTraps.Knock",
"gAddTraps.Shock",
"gAddTraps.Speed",
"gAddTraps.Tele",
"gAddTraps.Void",
}; };
const std::vector<const char*> cheatCvars = { const std::vector<const char*> cheatCvars = {
@@ -269,7 +294,23 @@ const std::vector<const char*> cheatCvars = {
"gNoRedeadFreeze", "gNoRedeadFreeze",
"gBombTimerMultiplier", "gBombTimerMultiplier",
"gNoFishDespawn", "gNoFishDespawn",
"gNoBugsDespawn" "gNoBugsDespawn",
"gWalkModifierDoesntChangeJump",
"gStatsEnabled",
"gSaveStatesEnabled",
"gSaveStatePromise",
"gRegEditEnabled",
"gPreset0",
"gPreset1",
"gDekuStickCheat",
"gDebugWarpScreenTranslation",
"gDebugSaveFileMode",
"gCosmetics.Link_BodyScale.Changed",
"gCosmetics.Link_BodyScale.Value",
"gCosmetics.Link_HeadScale.Changed",
"gCosmetics.Link_HeadScale.Value",
"gCosmetics.Link_SwordScale.Changed",
"gCosmetics.Link_SwordScale.Value",
}; };
const std::vector<const char*> randomizerCvars = { const std::vector<const char*> randomizerCvars = {
@@ -399,6 +440,15 @@ const std::vector<const char*> randomizerCvars = {
"gRandomizeGregHint", "gRandomizeGregHint",
"gRandoManualSeedEntry", "gRandoManualSeedEntry",
"gRandomizerSettingsEnabled", "gRandomizerSettingsEnabled",
"gRandomizeTriforceHuntTotalPieces",
"gRandomizeTriforceHuntRequiredPieces",
"gRandomizeTriforceHunt",
"gRandomizeShuffleMasterSword",
"gRandomizeSariaHint",
"gRandomizeRupeeNames",
"gRandomizeFrogsHint",
"gRandoRelevantNavi",
"gRandoQuestItemFanfares",
}; };
const std::vector<PresetEntry> vanillaPlusPresetEntries = { const std::vector<PresetEntry> vanillaPlusPresetEntries = {
@@ -24,11 +24,11 @@ void LocationTable_Init() {
//Lost Woods //Lost Woods
locationTable[LW_NEAR_SHORTCUTS_GROTTO_CHEST] = ItemLocation::Chest (RC_LW_NEAR_SHORTCUTS_GROTTO_CHEST, 0x3E, 0x14, "LW Near Shortcuts Grotto Chest", LW_NEAR_SHORTCUTS_GROTTO_CHEST, BLUE_RUPEE, {}, SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); locationTable[LW_NEAR_SHORTCUTS_GROTTO_CHEST] = ItemLocation::Chest (RC_LW_NEAR_SHORTCUTS_GROTTO_CHEST, 0x3E, 0x14, "LW Near Shortcuts Grotto Chest", LW_NEAR_SHORTCUTS_GROTTO_CHEST, BLUE_RUPEE, {}, SpoilerCollectionCheckGroup::GROUP_LOST_WOODS);
locationTable[LW_SKULL_KID] = ItemLocation::Base (RC_LW_SKULL_KID, 0x5B, "LW Skull Kid", LW_SKULL_KID, PIECE_OF_HEART, {}, SpoilerCollectionCheck::ItemGetInf(30), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); locationTable[LW_SKULL_KID] = ItemLocation::Base (RC_LW_SKULL_KID, 0x5B, "LW Skull Kid", LW_SKULL_KID, PIECE_OF_HEART, {}, SpoilerCollectionCheck::ItemGetInf(22), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS);
locationTable[LW_TRADE_COJIRO] = ItemLocation::Base (RC_LW_TRADE_COJIRO, 0x5B, "LW Trade Cojiro", LW_TRADE_COJIRO, ODD_MUSHROOM, {Category::cAdultTrade}, SpoilerCollectionCheck::RandomizerInf(), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); locationTable[LW_TRADE_COJIRO] = ItemLocation::Base (RC_LW_TRADE_COJIRO, 0x5B, "LW Trade Cojiro", LW_TRADE_COJIRO, ODD_MUSHROOM, {Category::cAdultTrade}, SpoilerCollectionCheck::RandomizerInf(), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS);
locationTable[LW_TRADE_ODD_POTION] = ItemLocation::Base (RC_LW_TRADE_ODD_POTION, 0x5B, "LW Trade Odd Potion", LW_TRADE_ODD_POTION, ODD_POTION, {Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(57), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); locationTable[LW_TRADE_ODD_POTION] = ItemLocation::Base (RC_LW_TRADE_ODD_POTION, 0x5B, "LW Trade Odd Potion", LW_TRADE_ODD_POTION, ODD_POTION, {Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(49), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS);
locationTable[LW_OCARINA_MEMORY_GAME] = ItemLocation::Base (RC_LW_OCARINA_MEMORY_GAME, 0x5B, "LW Ocarina Memory Game", LW_OCARINA_MEMORY_GAME, PIECE_OF_HEART, {}, SpoilerCollectionCheck::ItemGetInf(31), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); locationTable[LW_OCARINA_MEMORY_GAME] = ItemLocation::Base (RC_LW_OCARINA_MEMORY_GAME, 0x5B, "LW Ocarina Memory Game", LW_OCARINA_MEMORY_GAME, PIECE_OF_HEART, {}, SpoilerCollectionCheck::ItemGetInf(23), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS);
locationTable[LW_TARGET_IN_WOODS] = ItemLocation::Base (RC_LW_TARGET_IN_WOODS, 0x5B, "LW Target in Woods", LW_TARGET_IN_WOODS, PROGRESSIVE_SLINGSHOT, {}, SpoilerCollectionCheck::ItemGetInf(21), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); locationTable[LW_TARGET_IN_WOODS] = ItemLocation::Base (RC_LW_TARGET_IN_WOODS, 0x5B, "LW Target in Woods", LW_TARGET_IN_WOODS, PROGRESSIVE_SLINGSHOT, {}, SpoilerCollectionCheck::ItemGetInf(29), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS);
locationTable[LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT] = ItemLocation::Base (RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, 0x5B, "LW Deku Scrub Near Deku Theater Right",LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, BUY_DEKU_NUT_5, {Category::cDekuScrub}, SpoilerCollectionCheck::Scrub(), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); locationTable[LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT] = ItemLocation::Base (RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, 0x5B, "LW Deku Scrub Near Deku Theater Right",LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, BUY_DEKU_NUT_5, {Category::cDekuScrub}, SpoilerCollectionCheck::Scrub(), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS);
locationTable[LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT] = ItemLocation::Base (RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, 0x5B, "LW Deku Scrub Near Deku Theater Left", LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, BUY_DEKU_STICK_1, {Category::cDekuScrub}, SpoilerCollectionCheck::Scrub(), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); locationTable[LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT] = ItemLocation::Base (RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, 0x5B, "LW Deku Scrub Near Deku Theater Left", LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, BUY_DEKU_STICK_1, {Category::cDekuScrub}, SpoilerCollectionCheck::Scrub(), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS);
locationTable[LW_DEKU_SCRUB_NEAR_BRIDGE] = ItemLocation::Base (RC_LW_DEKU_SCRUB_NEAR_BRIDGE, 0x5B, "LW Deku Scrub Near Bridge", LW_DEKU_SCRUB_NEAR_BRIDGE, PROGRESSIVE_STICK_UPGRADE, {Category::cDekuScrub, Category::cDekuScrubUpgrades}, SpoilerCollectionCheck::Scrub(), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); locationTable[LW_DEKU_SCRUB_NEAR_BRIDGE] = ItemLocation::Base (RC_LW_DEKU_SCRUB_NEAR_BRIDGE, 0x5B, "LW Deku Scrub Near Bridge", LW_DEKU_SCRUB_NEAR_BRIDGE, PROGRESSIVE_STICK_UPGRADE, {Category::cDekuScrub, Category::cDekuScrubUpgrades}, SpoilerCollectionCheck::Scrub(), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS);
@@ -53,7 +53,7 @@ void LocationTable_Init() {
//Lake Hylia //Lake Hylia
locationTable[LH_CHILD_FISHING] = ItemLocation::Base (RC_LH_CHILD_FISHING, 0x49, "LH Child Fishing", LH_CHILD_FISHING, PIECE_OF_HEART, {}, SpoilerCollectionCheck::RandomizerInf(), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); locationTable[LH_CHILD_FISHING] = ItemLocation::Base (RC_LH_CHILD_FISHING, 0x49, "LH Child Fishing", LH_CHILD_FISHING, PIECE_OF_HEART, {}, SpoilerCollectionCheck::RandomizerInf(), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA);
locationTable[LH_ADULT_FISHING] = ItemLocation::Base (RC_LH_ADULT_FISHING, 0x49, "LH Adult Fishing", LH_ADULT_FISHING, PROGRESSIVE_SCALE, {}, SpoilerCollectionCheck::RandomizerInf(), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); locationTable[LH_ADULT_FISHING] = ItemLocation::Base (RC_LH_ADULT_FISHING, 0x49, "LH Adult Fishing", LH_ADULT_FISHING, PROGRESSIVE_SCALE, {}, SpoilerCollectionCheck::RandomizerInf(), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA);
locationTable[LH_LAB_DIVE] = ItemLocation::Base (RC_LH_LAB_DIVE, 0x38, "LH Lab Dive", LH_LAB_DIVE, PIECE_OF_HEART, {}, SpoilerCollectionCheck::ItemGetInf(24), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); locationTable[LH_LAB_DIVE] = ItemLocation::Base (RC_LH_LAB_DIVE, 0x38, "LH Lab Dive", LH_LAB_DIVE, PIECE_OF_HEART, {}, SpoilerCollectionCheck::ItemGetInf(16), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA);
locationTable[LH_TRADE_FROG] = ItemLocation::Base (RC_LH_TRADE_FROG, 0x38, "LH Lab Trade Eyeball Frog", LH_TRADE_FROG, EYEDROPS, {Category::cAdultTrade}, SpoilerCollectionCheck::RandomizerInf(), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); locationTable[LH_TRADE_FROG] = ItemLocation::Base (RC_LH_TRADE_FROG, 0x38, "LH Lab Trade Eyeball Frog", LH_TRADE_FROG, EYEDROPS, {Category::cAdultTrade}, SpoilerCollectionCheck::RandomizerInf(), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA);
locationTable[LH_UNDERWATER_ITEM] = ItemLocation::Base (RC_LH_UNDERWATER_ITEM, 0x57, "LH Underwater Item", LH_UNDERWATER_ITEM, RUTOS_LETTER, {}, SpoilerCollectionCheck::EventChkInf(0x31), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); locationTable[LH_UNDERWATER_ITEM] = ItemLocation::Base (RC_LH_UNDERWATER_ITEM, 0x57, "LH Underwater Item", LH_UNDERWATER_ITEM, RUTOS_LETTER, {}, SpoilerCollectionCheck::EventChkInf(0x31), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA);
locationTable[LH_SUN] = ItemLocation::Base (RC_LH_SUN, 0x57, "LH Sun", LH_SUN, FIRE_ARROWS, {}, SpoilerCollectionCheck::Chest(0x57, 0x1F), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); locationTable[LH_SUN] = ItemLocation::Base (RC_LH_SUN, 0x57, "LH Sun", LH_SUN, FIRE_ARROWS, {}, SpoilerCollectionCheck::Chest(0x57, 0x1F), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA);
@@ -73,7 +73,7 @@ void LocationTable_Init() {
//Gerudo Fortress //Gerudo Fortress
locationTable[GF_CHEST] = ItemLocation::Chest (RC_GF_CHEST, 0x5D, 0x00, "GF Chest", GF_CHEST, PIECE_OF_HEART, {}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); locationTable[GF_CHEST] = ItemLocation::Chest (RC_GF_CHEST, 0x5D, 0x00, "GF Chest", GF_CHEST, PIECE_OF_HEART, {}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY);
locationTable[GF_HBA_1000_POINTS] = ItemLocation::Base (RC_GF_HBA_1000_POINTS, 0x5D, "GF HBA 1000 Points", GF_HBA_1000_POINTS, PIECE_OF_HEART, {}, SpoilerCollectionCheck::InfTable(0x19, 0x08), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); locationTable[GF_HBA_1000_POINTS] = ItemLocation::Base (RC_GF_HBA_1000_POINTS, 0x5D, "GF HBA 1000 Points", GF_HBA_1000_POINTS, PIECE_OF_HEART, {}, SpoilerCollectionCheck::InfTable(0x19, 0x08), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY);
locationTable[GF_HBA_1500_POINTS] = ItemLocation::Base (RC_GF_HBA_1500_POINTS, 0x5D, "GF HBA 1500 Points", GF_HBA_1500_POINTS, PROGRESSIVE_BOW, {}, SpoilerCollectionCheck::ItemGetInf(7), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); locationTable[GF_HBA_1500_POINTS] = ItemLocation::Base (RC_GF_HBA_1500_POINTS, 0x5D, "GF HBA 1500 Points", GF_HBA_1500_POINTS, PROGRESSIVE_BOW, {}, SpoilerCollectionCheck::ItemGetInf(15), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY);
locationTable[GF_GERUDO_MEMBERSHIP_CARD] = ItemLocation::Base (RC_GF_GERUDO_MEMBERSHIP_CARD, 0x0C, "GF Gerudo Membership Card", GF_GERUDO_MEMBERSHIP_CARD, GERUDO_MEMBERSHIP_CARD, {}, SpoilerCollectionCheck::GerudoToken(), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); locationTable[GF_GERUDO_MEMBERSHIP_CARD] = ItemLocation::Base (RC_GF_GERUDO_MEMBERSHIP_CARD, 0x0C, "GF Gerudo Membership Card", GF_GERUDO_MEMBERSHIP_CARD, GERUDO_MEMBERSHIP_CARD, {}, SpoilerCollectionCheck::GerudoToken(), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY);
locationTable[GF_NORTH_F1_CARPENTER] = ItemLocation::Collectable(RC_GF_NORTH_F1_CARPENTER, 0x0C, 0x0C, "GF North F1 Carpenter", GF_NORTH_F1_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, {Category::cVanillaGFSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); locationTable[GF_NORTH_F1_CARPENTER] = ItemLocation::Collectable(RC_GF_NORTH_F1_CARPENTER, 0x0C, 0x0C, "GF North F1 Carpenter", GF_NORTH_F1_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, {Category::cVanillaGFSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY);
locationTable[GF_NORTH_F2_CARPENTER] = ItemLocation::Collectable(RC_GF_NORTH_F2_CARPENTER, 0x0C, 0x0A, "GF North F2 Carpenter", GF_NORTH_F2_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, {Category::cVanillaGFSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); locationTable[GF_NORTH_F2_CARPENTER] = ItemLocation::Collectable(RC_GF_NORTH_F2_CARPENTER, 0x0C, 0x0A, "GF North F2 Carpenter", GF_NORTH_F2_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, {Category::cVanillaGFSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY);
@@ -90,12 +90,12 @@ void LocationTable_Init() {
locationTable[COLOSSUS_DEKU_SCRUB_GROTTO_FRONT] = ItemLocation::GrottoScrub(RC_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, 0xFD, "Colossus Deku Scrub Grotto Front", COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, BUY_GREEN_POTION, {Category::cDekuScrub}, SpoilerCollectionCheck::Scrub(), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); locationTable[COLOSSUS_DEKU_SCRUB_GROTTO_FRONT] = ItemLocation::GrottoScrub(RC_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, 0xFD, "Colossus Deku Scrub Grotto Front", COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, BUY_GREEN_POTION, {Category::cDekuScrub}, SpoilerCollectionCheck::Scrub(), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY);
//Market //Market
locationTable[MARKET_TREASURE_CHEST_GAME_REWARD] = ItemLocation::Chest (RC_MARKET_TREASURE_CHEST_GAME_REWARD, 0x10, "MK Treasure Chest Game Reward", MARKET_TREASURE_CHEST_GAME_REWARD, TREASURE_GAME_HEART, {}, SpoilerCollectionCheck::ItemGetInf(19), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); locationTable[MARKET_TREASURE_CHEST_GAME_REWARD] = ItemLocation::Chest (RC_MARKET_TREASURE_CHEST_GAME_REWARD, 0x10, "MK Treasure Chest Game Reward", MARKET_TREASURE_CHEST_GAME_REWARD, TREASURE_GAME_HEART, {}, SpoilerCollectionCheck::ItemGetInf(27), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE);
locationTable[MARKET_BOMBCHU_BOWLING_FIRST_PRIZE] = ItemLocation::Base (RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, 0x4B, "MK Bombchu Bowling First Prize", MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, PROGRESSIVE_BOMB_BAG, {}, SpoilerCollectionCheck::ItemGetInf(25), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); locationTable[MARKET_BOMBCHU_BOWLING_FIRST_PRIZE] = ItemLocation::Base (RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, 0x4B, "MK Bombchu Bowling First Prize", MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, PROGRESSIVE_BOMB_BAG, {}, SpoilerCollectionCheck::ItemGetInf(17), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE);
locationTable[MARKET_BOMBCHU_BOWLING_SECOND_PRIZE] = ItemLocation::Base (RC_MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, 0x4B, "MK Bombchu Bowling Second Prize", MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, PIECE_OF_HEART, {}, SpoilerCollectionCheck::ItemGetInf(26), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); locationTable[MARKET_BOMBCHU_BOWLING_SECOND_PRIZE] = ItemLocation::Base (RC_MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, 0x4B, "MK Bombchu Bowling Second Prize", MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, PIECE_OF_HEART, {}, SpoilerCollectionCheck::ItemGetInf(18), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE);
locationTable[MARKET_BOMBCHU_BOWLING_BOMBCHUS] = ItemLocation::Base (RC_MARKET_BOMBCHU_BOWLING_BOMBCHUS, 0x4B, "MK Bombchu Bowling Bombchus", NONE, BOMBCHU_DROP, {}, SpoilerCollectionCheck::None(), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); locationTable[MARKET_BOMBCHU_BOWLING_BOMBCHUS] = ItemLocation::Base (RC_MARKET_BOMBCHU_BOWLING_BOMBCHUS, 0x4B, "MK Bombchu Bowling Bombchus", NONE, BOMBCHU_DROP, {}, SpoilerCollectionCheck::None(), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE);
locationTable[MARKET_LOST_DOG] = ItemLocation::Base (RC_MARKET_LOST_DOG, 0x35, "MK Lost Dog", MARKET_LOST_DOG, PIECE_OF_HEART, {}, SpoilerCollectionCheck::InfTable(0x19, 0x09), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); locationTable[MARKET_LOST_DOG] = ItemLocation::Base (RC_MARKET_LOST_DOG, 0x35, "MK Lost Dog", MARKET_LOST_DOG, PIECE_OF_HEART, {}, SpoilerCollectionCheck::InfTable(0x19, 0x09), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE);
locationTable[MARKET_SHOOTING_GALLERY_REWARD] = ItemLocation::Base (RC_MARKET_SHOOTING_GALLERY_REWARD, 0x42, "MK Shooting Gallery", MARKET_SHOOTING_GALLERY_REWARD, PROGRESSIVE_SLINGSHOT, {}, SpoilerCollectionCheck::ItemGetInf(5), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); locationTable[MARKET_SHOOTING_GALLERY_REWARD] = ItemLocation::Base (RC_MARKET_SHOOTING_GALLERY_REWARD, 0x42, "MK Shooting Gallery", MARKET_SHOOTING_GALLERY_REWARD, PROGRESSIVE_SLINGSHOT, {}, SpoilerCollectionCheck::ItemGetInf(13), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE);
locationTable[MARKET_10_BIG_POES] = ItemLocation::Base (RC_MARKET_10_BIG_POES, 0x4D, "MK 10 Big Poes", MARKET_10_BIG_POES, EMPTY_BOTTLE, {}, SpoilerCollectionCheck::RandomizerInf(), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); locationTable[MARKET_10_BIG_POES] = ItemLocation::Base (RC_MARKET_10_BIG_POES, 0x4D, "MK 10 Big Poes", MARKET_10_BIG_POES, EMPTY_BOTTLE, {}, SpoilerCollectionCheck::RandomizerInf(), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE);
locationTable[MARKET_TREASURE_CHEST_GAME_ITEM_1] = ItemLocation::Chest (RC_MARKET_TREASURE_CHEST_GAME_ITEM_1, 0x10, 0x01, "MK Chest Game First Room Chest", MARKET_TREASURE_CHEST_GAME_ITEM_1, TREASURE_GAME_SMALL_KEY, {Category::cChestMinigame}, SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); locationTable[MARKET_TREASURE_CHEST_GAME_ITEM_1] = ItemLocation::Chest (RC_MARKET_TREASURE_CHEST_GAME_ITEM_1, 0x10, 0x01, "MK Chest Game First Room Chest", MARKET_TREASURE_CHEST_GAME_ITEM_1, TREASURE_GAME_SMALL_KEY, {Category::cChestMinigame}, SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE);
locationTable[MARKET_TREASURE_CHEST_GAME_ITEM_2] = ItemLocation::Chest (RC_MARKET_TREASURE_CHEST_GAME_ITEM_2, 0x10, 0x03, "MK Chest Game Second Room Chest", MARKET_TREASURE_CHEST_GAME_ITEM_2, TREASURE_GAME_SMALL_KEY, {Category::cChestMinigame}, SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); locationTable[MARKET_TREASURE_CHEST_GAME_ITEM_2] = ItemLocation::Chest (RC_MARKET_TREASURE_CHEST_GAME_ITEM_2, 0x10, 0x03, "MK Chest Game Second Room Chest", MARKET_TREASURE_CHEST_GAME_ITEM_2, TREASURE_GAME_SMALL_KEY, {Category::cChestMinigame}, SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE);
@@ -115,14 +115,14 @@ void LocationTable_Init() {
locationTable[KAK_30_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (RC_KAK_30_GOLD_SKULLTULA_REWARD, 0x50, "Kak 30 Gold Skulltula Reward", KAK_30_GOLD_SKULLTULA_REWARD, PROGRESSIVE_WALLET, {}, SpoilerCollectionCheck::EventChkInf(0xDC), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_30_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (RC_KAK_30_GOLD_SKULLTULA_REWARD, 0x50, "Kak 30 Gold Skulltula Reward", KAK_30_GOLD_SKULLTULA_REWARD, PROGRESSIVE_WALLET, {}, SpoilerCollectionCheck::EventChkInf(0xDC), SpoilerCollectionCheckGroup::GROUP_KAKARIKO);
locationTable[KAK_40_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (RC_KAK_40_GOLD_SKULLTULA_REWARD, 0x50, "Kak 40 Gold Skulltula Reward", KAK_40_GOLD_SKULLTULA_REWARD, BOMBCHU_10, {}, SpoilerCollectionCheck::EventChkInf(0xDD), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_40_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (RC_KAK_40_GOLD_SKULLTULA_REWARD, 0x50, "Kak 40 Gold Skulltula Reward", KAK_40_GOLD_SKULLTULA_REWARD, BOMBCHU_10, {}, SpoilerCollectionCheck::EventChkInf(0xDD), SpoilerCollectionCheckGroup::GROUP_KAKARIKO);
locationTable[KAK_50_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (RC_KAK_50_GOLD_SKULLTULA_REWARD, 0x50, "Kak 50 Gold Skulltula Reward", KAK_50_GOLD_SKULLTULA_REWARD, PIECE_OF_HEART, {}, SpoilerCollectionCheck::EventChkInf(0xDE), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_50_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (RC_KAK_50_GOLD_SKULLTULA_REWARD, 0x50, "Kak 50 Gold Skulltula Reward", KAK_50_GOLD_SKULLTULA_REWARD, PIECE_OF_HEART, {}, SpoilerCollectionCheck::EventChkInf(0xDE), SpoilerCollectionCheckGroup::GROUP_KAKARIKO);
locationTable[KAK_100_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (RC_KAK_100_GOLD_SKULLTULA_REWARD, 0x50, "Kak 100 Gold Skulltula Reward", KAK_100_GOLD_SKULLTULA_REWARD, HUGE_RUPEE, {}, SpoilerCollectionCheck::EventChkInf(0xDF), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_100_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (RC_KAK_100_GOLD_SKULLTULA_REWARD, 0x50, "Kak 100 Gold Skulltula Reward", KAK_100_GOLD_SKULLTULA_REWARD, HUGE_RUPEE, {}, SpoilerCollectionCheck::RandomizerInf(), SpoilerCollectionCheckGroup::GROUP_KAKARIKO);
locationTable[KAK_MAN_ON_ROOF] = ItemLocation::Base (RC_KAK_MAN_ON_ROOF, 0x52, "Kak Man on Roof", KAK_MAN_ON_ROOF, PIECE_OF_HEART, {}, SpoilerCollectionCheck::ItemGetInf(29), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_MAN_ON_ROOF] = ItemLocation::Base (RC_KAK_MAN_ON_ROOF, 0x52, "Kak Man on Roof", KAK_MAN_ON_ROOF, PIECE_OF_HEART, {}, SpoilerCollectionCheck::ItemGetInf(21), SpoilerCollectionCheckGroup::GROUP_KAKARIKO);
locationTable[KAK_SHOOTING_GALLERY_REWARD] = ItemLocation::Base (RC_KAK_SHOOTING_GALLERY_REWARD, 0x42, "Kak Shooting Gallery Reward", KAK_SHOOTING_GALLERY_REWARD, PROGRESSIVE_BOW, {}, SpoilerCollectionCheck::Chest(0x42, 0x1F), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_SHOOTING_GALLERY_REWARD] = ItemLocation::Base (RC_KAK_SHOOTING_GALLERY_REWARD, 0x42, "Kak Shooting Gallery Reward", KAK_SHOOTING_GALLERY_REWARD, PROGRESSIVE_BOW, {}, SpoilerCollectionCheck::Chest(0x42, 0x1F), SpoilerCollectionCheckGroup::GROUP_KAKARIKO);
locationTable[KAK_TRADE_ODD_MUSHROOM] = ItemLocation::Base (RC_KAK_TRADE_ODD_MUSHROOM, 0x4E, "Kak Trade Odd Mushroom", KAK_TRADE_ODD_MUSHROOM, ODD_POTION, {Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(56), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_TRADE_ODD_MUSHROOM] = ItemLocation::Base (RC_KAK_TRADE_ODD_MUSHROOM, 0x4E, "Kak Trade Odd Mushroom", KAK_TRADE_ODD_MUSHROOM, ODD_POTION, {Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(48), SpoilerCollectionCheckGroup::GROUP_KAKARIKO);
locationTable[KAK_GRANNYS_SHOP] = ItemLocation::Base (RC_KAK_GRANNYS_SHOP, 0x4E, "Kak Granny's Shop", KAK_GRANNYS_SHOP, BLUE_POTION_REFILL, {Category::cMerchant}, SpoilerCollectionCheck::RandomizerInf(), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_GRANNYS_SHOP] = ItemLocation::Base (RC_KAK_GRANNYS_SHOP, 0x4E, "Kak Granny's Shop", KAK_GRANNYS_SHOP, BLUE_POTION_REFILL, {Category::cMerchant}, SpoilerCollectionCheck::RandomizerInf(), SpoilerCollectionCheckGroup::GROUP_KAKARIKO);
locationTable[KAK_ANJU_AS_ADULT] = ItemLocation::Base (RC_KAK_ANJU_AS_ADULT, 0x52, "Kak Anju as Adult", KAK_ANJU_AS_ADULT, CLAIM_CHECK, {}, SpoilerCollectionCheck::ItemGetInf(36), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_ANJU_AS_ADULT] = ItemLocation::Base (RC_KAK_ANJU_AS_ADULT, 0x52, "Kak Anju as Adult", KAK_ANJU_AS_ADULT, CLAIM_CHECK, {}, SpoilerCollectionCheck::ItemGetInf(44), SpoilerCollectionCheckGroup::GROUP_KAKARIKO);
locationTable[KAK_ANJU_AS_CHILD] = ItemLocation::Base (RC_KAK_ANJU_AS_CHILD, 0x52, "Kak Anju as Child", KAK_ANJU_AS_CHILD, EMPTY_BOTTLE, {}, SpoilerCollectionCheck::ItemGetInf(4), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_ANJU_AS_CHILD] = ItemLocation::Base (RC_KAK_ANJU_AS_CHILD, 0x52, "Kak Anju as Child", KAK_ANJU_AS_CHILD, EMPTY_BOTTLE, {}, SpoilerCollectionCheck::ItemGetInf(12), SpoilerCollectionCheckGroup::GROUP_KAKARIKO);
locationTable[KAK_TRADE_POCKET_CUCCO] = ItemLocation::Base (RC_KAK_TRADE_POCKET_CUCCO, 0x52, "Kak Trade Pocket Cucco", KAK_TRADE_POCKET_CUCCO, COJIRO, {Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(38), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_TRADE_POCKET_CUCCO] = ItemLocation::Base (RC_KAK_TRADE_POCKET_CUCCO, 0x52, "Kak Trade Pocket Cucco", KAK_TRADE_POCKET_CUCCO, COJIRO, {Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(46), SpoilerCollectionCheckGroup::GROUP_KAKARIKO);
locationTable[KAK_IMPAS_HOUSE_FREESTANDING_POH] = ItemLocation::Collectable(RC_KAK_IMPAS_HOUSE_FREESTANDING_POH, 0x37, 0x01, "Kak Impas House Freestanding PoH", KAK_IMPAS_HOUSE_FREESTANDING_POH, PIECE_OF_HEART, {}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_IMPAS_HOUSE_FREESTANDING_POH] = ItemLocation::Collectable(RC_KAK_IMPAS_HOUSE_FREESTANDING_POH, 0x37, 0x01, "Kak Impas House Freestanding PoH", KAK_IMPAS_HOUSE_FREESTANDING_POH, PIECE_OF_HEART, {}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO);
locationTable[KAK_WINDMILL_FREESTANDING_POH] = ItemLocation::Collectable(RC_KAK_WINDMILL_FREESTANDING_POH, 0x48, 0x01, "Kak Windmill Freestanding PoH", KAK_WINDMILL_FREESTANDING_POH, PIECE_OF_HEART, {}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_WINDMILL_FREESTANDING_POH] = ItemLocation::Collectable(RC_KAK_WINDMILL_FREESTANDING_POH, 0x48, 0x01, "Kak Windmill Freestanding PoH", KAK_WINDMILL_FREESTANDING_POH, PIECE_OF_HEART, {}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO);
@@ -133,7 +133,7 @@ void LocationTable_Init() {
locationTable[GRAVEYARD_HOOKSHOT_CHEST] = ItemLocation::Chest (RC_GRAVEYARD_HOOKSHOT_CHEST, 0x48, 0x00, "GY Hookshot Chest", GRAVEYARD_HOOKSHOT_CHEST, PROGRESSIVE_HOOKSHOT, {}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[GRAVEYARD_HOOKSHOT_CHEST] = ItemLocation::Chest (RC_GRAVEYARD_HOOKSHOT_CHEST, 0x48, 0x00, "GY Hookshot Chest", GRAVEYARD_HOOKSHOT_CHEST, PROGRESSIVE_HOOKSHOT, {}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO);
locationTable[GRAVEYARD_DAMPE_RACE_FREESTANDING_POH] = ItemLocation::Collectable(RC_GRAVEYARD_DAMPE_RACE_FREESTANDING_POH, 0x48, 0x07, "GY Dampe Race Freestanding PoH", GRAVEYARD_DAMPE_RACE_FREESTANDING_POH, PIECE_OF_HEART, {}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[GRAVEYARD_DAMPE_RACE_FREESTANDING_POH] = ItemLocation::Collectable(RC_GRAVEYARD_DAMPE_RACE_FREESTANDING_POH, 0x48, 0x07, "GY Dampe Race Freestanding PoH", GRAVEYARD_DAMPE_RACE_FREESTANDING_POH, PIECE_OF_HEART, {}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO);
locationTable[GRAVEYARD_FREESTANDING_POH] = ItemLocation::Collectable(RC_GRAVEYARD_FREESTANDING_POH, 0x53, 0x04, "GY Freestanding PoH", GRAVEYARD_FREESTANDING_POH, PIECE_OF_HEART, {}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[GRAVEYARD_FREESTANDING_POH] = ItemLocation::Collectable(RC_GRAVEYARD_FREESTANDING_POH, 0x53, 0x04, "GY Freestanding PoH", GRAVEYARD_FREESTANDING_POH, PIECE_OF_HEART, {}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO);
locationTable[GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR] = ItemLocation::Collectable(RC_GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, 0x53, "GY Dampe Gravedigging Tour", GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, PIECE_OF_HEART, {}, SpoilerCollectionCheck::Gravedigger(0x53, 0x1F), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR] = ItemLocation::Collectable(RC_GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, 0x53, "GY Dampe Gravedigging Tour", GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, PIECE_OF_HEART, {}, SpoilerCollectionCheck::Gravedigger(0x53, 0x19), SpoilerCollectionCheckGroup::GROUP_KAKARIKO);
//Death Mountain //Death Mountain
locationTable[DMT_CHEST] = ItemLocation::Chest (RC_DMT_CHEST, 0x60, 0x01, "DMT Chest", DMT_CHEST, PURPLE_RUPEE, {}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); locationTable[DMT_CHEST] = ItemLocation::Chest (RC_DMT_CHEST, 0x60, 0x01, "DMT Chest", DMT_CHEST, PURPLE_RUPEE, {}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN);
@@ -191,7 +191,7 @@ void LocationTable_Init() {
locationTable[ZF_BOTTOM_FREESTANDING_POH] = ItemLocation::Collectable(RC_ZF_BOTTOM_FREESTANDING_POH, 0x59, 0x14, "ZF Bottom Freestanding PoH", ZF_BOTTOM_FREESTANDING_POH, PIECE_OF_HEART, {}, SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); locationTable[ZF_BOTTOM_FREESTANDING_POH] = ItemLocation::Collectable(RC_ZF_BOTTOM_FREESTANDING_POH, 0x59, 0x14, "ZF Bottom Freestanding PoH", ZF_BOTTOM_FREESTANDING_POH, PIECE_OF_HEART, {}, SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN);
//Lon Lon Ranch //Lon Lon Ranch
locationTable[LLR_TALONS_CHICKENS] = ItemLocation::Base (RC_LLR_TALONS_CHICKENS, 0x4C, "LLR Talons Chickens", LLR_TALONS_CHICKENS, BOTTLE_WITH_MILK, {}, SpoilerCollectionCheck::ItemGetInf(10), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); locationTable[LLR_TALONS_CHICKENS] = ItemLocation::Base (RC_LLR_TALONS_CHICKENS, 0x4C, "LLR Talons Chickens", LLR_TALONS_CHICKENS, BOTTLE_WITH_MILK, {}, SpoilerCollectionCheck::ItemGetInf(2), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH);
locationTable[LLR_FREESTANDING_POH] = ItemLocation::Collectable(RC_LLR_FREESTANDING_POH, 0x4C, 0x01, "LLR Freestanding PoH", LLR_FREESTANDING_POH, PIECE_OF_HEART, {}, SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); locationTable[LLR_FREESTANDING_POH] = ItemLocation::Collectable(RC_LLR_FREESTANDING_POH, 0x4C, 0x01, "LLR Freestanding PoH", LLR_FREESTANDING_POH, PIECE_OF_HEART, {}, SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH);
locationTable[LLR_DEKU_SCRUB_GROTTO_LEFT] = ItemLocation::GrottoScrub(RC_LLR_DEKU_SCRUB_GROTTO_LEFT, 0xFC, "LLR Deku Scrub Grotto Left", LLR_DEKU_SCRUB_GROTTO_LEFT, BUY_DEKU_NUT_5, {Category::cDekuScrub}, SpoilerCollectionCheck::Scrub(), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); locationTable[LLR_DEKU_SCRUB_GROTTO_LEFT] = ItemLocation::GrottoScrub(RC_LLR_DEKU_SCRUB_GROTTO_LEFT, 0xFC, "LLR Deku Scrub Grotto Left", LLR_DEKU_SCRUB_GROTTO_LEFT, BUY_DEKU_NUT_5, {Category::cDekuScrub}, SpoilerCollectionCheck::Scrub(), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH);
locationTable[LLR_DEKU_SCRUB_GROTTO_RIGHT] = ItemLocation::GrottoScrub(RC_LLR_DEKU_SCRUB_GROTTO_RIGHT, 0xFC, "LLR Deku Scrub Grotto Right", LLR_DEKU_SCRUB_GROTTO_RIGHT, BUY_BOMBS_535, {Category::cDekuScrub}, SpoilerCollectionCheck::Scrub(), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); locationTable[LLR_DEKU_SCRUB_GROTTO_RIGHT] = ItemLocation::GrottoScrub(RC_LLR_DEKU_SCRUB_GROTTO_RIGHT, 0xFC, "LLR Deku Scrub Grotto Right", LLR_DEKU_SCRUB_GROTTO_RIGHT, BUY_BOMBS_535, {Category::cDekuScrub}, SpoilerCollectionCheck::Scrub(), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH);
@@ -104,7 +104,7 @@ void AreaTable_Init_DeathMountain() {
Entrance(DEATH_MOUNTAIN_TRAIL, {[]{return true;}}), Entrance(DEATH_MOUNTAIN_TRAIL, {[]{return true;}}),
Entrance(GC_WOODS_WARP, {[]{return GCWoodsWarpOpen;}}), Entrance(GC_WOODS_WARP, {[]{return GCWoodsWarpOpen;}}),
Entrance(GC_SHOP, {[]{return (IsAdult && StopGCRollingGoronAsAdult) || (IsChild && (CanBlastOrSmash || GoronBracelet || GoronCityChildFire || CanUse(BOW)));}}), Entrance(GC_SHOP, {[]{return (IsAdult && StopGCRollingGoronAsAdult) || (IsChild && (CanBlastOrSmash || GoronBracelet || GoronCityChildFire || CanUse(BOW)));}}),
Entrance(GC_DARUNIAS_CHAMBER, {[]{return (IsAdult && StopGCRollingGoronAsAdult) || GCDaruniasDoorOpenChild;}}), Entrance(GC_DARUNIAS_CHAMBER, {[]{return (IsAdult && StopGCRollingGoronAsAdult) || (IsChild && GCDaruniasDoorOpenChild);}}),
Entrance(GC_GROTTO_PLATFORM, {[]{return IsAdult && ((CanPlay(SongOfTime) && ((EffectiveHealth > 2) || CanUse(GORON_TUNIC) || CanUse(LONGSHOT) || CanUse(NAYRUS_LOVE))) || (EffectiveHealth > 1 && CanUse(GORON_TUNIC) && CanUse(HOOKSHOT)) || (CanUse(NAYRUS_LOVE) && CanUse(HOOKSHOT)) || (EffectiveHealth > 2 && CanUse(HOOKSHOT) && LogicGoronCityGrotto));}}), Entrance(GC_GROTTO_PLATFORM, {[]{return IsAdult && ((CanPlay(SongOfTime) && ((EffectiveHealth > 2) || CanUse(GORON_TUNIC) || CanUse(LONGSHOT) || CanUse(NAYRUS_LOVE))) || (EffectiveHealth > 1 && CanUse(GORON_TUNIC) && CanUse(HOOKSHOT)) || (CanUse(NAYRUS_LOVE) && CanUse(HOOKSHOT)) || (EffectiveHealth > 2 && CanUse(HOOKSHOT) && LogicGoronCityGrotto));}}),
}); });
@@ -1,5 +1,6 @@
#include "playthrough.hpp" #include "playthrough.hpp"
#include <libultraship/libultraship.h>
#include <boost_custom/container_hash/hash_32.hpp> #include <boost_custom/container_hash/hash_32.hpp>
#include "custom_messages.hpp" #include "custom_messages.hpp"
#include "fill.hpp" #include "fill.hpp"
@@ -8,6 +9,7 @@
#include "random.hpp" #include "random.hpp"
#include "spoiler_log.hpp" #include "spoiler_log.hpp"
#include "soh/Enhancements/randomizer/randomizerTypes.h" #include "soh/Enhancements/randomizer/randomizerTypes.h"
#include "variables.h"
namespace Playthrough { namespace Playthrough {
@@ -39,6 +41,10 @@ int Playthrough_Init(uint32_t seed, std::unordered_map<RandomizerSettingKey, uin
} }
} }
if (CVarGetInteger("gRandomizerDontGenerateSpoiler", 0)) {
settingsStr += (char*)gBuildVersion;
}
uint32_t finalHash = boost::hash_32<std::string>{}(std::to_string(Settings::seed) + settingsStr); uint32_t finalHash = boost::hash_32<std::string>{}(std::to_string(Settings::seed) + settingsStr);
Random_Init(finalHash); Random_Init(finalHash);
Settings::hash = std::to_string(finalHash); Settings::hash = std::to_string(finalHash);
+27 -26
View File
@@ -360,29 +360,12 @@ std::unordered_map<std::string, RandomizerSettingKey> SpoilerfileSettingNameToEn
{ "Shuffle Dungeon Quest:Ganon's Castle", RSK_MQ_GANONS_CASTLE }, { "Shuffle Dungeon Quest:Ganon's Castle", RSK_MQ_GANONS_CASTLE },
}; };
std::string sanitize(std::string stringValue) {
// Add backslashes.
for (auto i = stringValue.begin();;) {
auto const pos = std::find_if(i, stringValue.end(), [](char const c) { return '\\' == c || '\'' == c || '"' == c; });
if (pos == stringValue.end()) {
break;
}
i = std::next(stringValue.insert(pos, '\\'), 2);
}
// Removes others.
stringValue.erase(std::remove_if(stringValue.begin(), stringValue.end(), [](char const c) {
return '\n' == c || '\r' == c || '\0' == c || '\x1A' == c; }), stringValue.end());
return stringValue;
}
#pragma optimize("", off) #pragma optimize("", off)
#pragma GCC push_options #pragma GCC push_options
#pragma GCC optimize ("O0") #pragma GCC optimize ("O0")
bool Randomizer::SpoilerFileExists(const char* spoilerFileName) { bool Randomizer::SpoilerFileExists(const char* spoilerFileName) {
if (strcmp(spoilerFileName, "") != 0) { if (strcmp(spoilerFileName, "") != 0) {
std::ifstream spoilerFileStream(sanitize(spoilerFileName)); std::ifstream spoilerFileStream(SohUtils::Sanitize(spoilerFileName));
if (!spoilerFileStream) { if (!spoilerFileStream) {
return false; return false;
} else { } else {
@@ -496,6 +479,13 @@ void Randomizer::LoadHintLocations(const char* spoilerFileName) {
"Zu {{location}}?\x1B&%gOK&No%w\x02", "Zu {{location}}?\x1B&%gOK&No%w\x02",
"Se téléporter vers&{{location}}?\x1B&%gOK!&Non%w\x02")); "Se téléporter vers&{{location}}?\x1B&%gOK!&Non%w\x02"));
// Bow Shooting Gallery reminder
CustomMessageManager::Instance->CreateMessage(Randomizer::hintMessageTableID, TEXT_SHOOTING_GALLERY_MAN_COME_BACK_WITH_BOW,
CustomMessage("Come back when you have your own&bow and you'll get a %rdifferent prize%w!",
"Komm wieder sobald du deinen eigenen&Bogen hast, um einen %rspeziellen Preis%w zu&erhalten!",
"J'aurai %rune autre récompense%w pour toi&lorsque tu auras ton propre arc."));
// Lake Hylia water level system
CustomMessageManager::Instance->CreateMessage(Randomizer::hintMessageTableID, TEXT_LAKE_HYLIA_WATER_SWITCH_SIGN, CustomMessageManager::Instance->CreateMessage(Randomizer::hintMessageTableID, TEXT_LAKE_HYLIA_WATER_SWITCH_SIGN,
CustomMessage("Water level control system.&Keep away!", CustomMessage("Water level control system.&Keep away!",
"Wasserstand Kontrollsystem&Finger weg!", "Wasserstand Kontrollsystem&Finger weg!",
@@ -659,7 +649,7 @@ void Randomizer::LoadMasterQuestDungeons(const char* spoilerFileName) {
} }
void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) { void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) {
std::ifstream spoilerFileStream(sanitize(spoilerFileName)); std::ifstream spoilerFileStream(SohUtils::Sanitize(spoilerFileName));
if (!spoilerFileStream) if (!spoilerFileStream)
return; return;
@@ -1293,7 +1283,7 @@ std::string FormatJsonHintText(std::string jsonHint) {
} }
void Randomizer::ParseHintLocationsFile(const char* spoilerFileName) { void Randomizer::ParseHintLocationsFile(const char* spoilerFileName) {
std::ifstream spoilerFileStream(sanitize(spoilerFileName)); std::ifstream spoilerFileStream(SohUtils::Sanitize(spoilerFileName));
if (!spoilerFileStream) if (!spoilerFileStream)
return; return;
@@ -1394,7 +1384,7 @@ void Randomizer::ParseHintLocationsFile(const char* spoilerFileName) {
} }
void Randomizer::ParseRequiredTrialsFile(const char* spoilerFileName) { void Randomizer::ParseRequiredTrialsFile(const char* spoilerFileName) {
std::ifstream spoilerFileStream(sanitize(spoilerFileName)); std::ifstream spoilerFileStream(SohUtils::Sanitize(spoilerFileName));
if (!spoilerFileStream) { if (!spoilerFileStream) {
return; return;
} }
@@ -1415,7 +1405,7 @@ void Randomizer::ParseRequiredTrialsFile(const char* spoilerFileName) {
} }
void Randomizer::ParseMasterQuestDungeonsFile(const char* spoilerFileName) { void Randomizer::ParseMasterQuestDungeonsFile(const char* spoilerFileName) {
std::ifstream spoilerFileStream(sanitize(spoilerFileName)); std::ifstream spoilerFileStream(SohUtils::Sanitize(spoilerFileName));
if (!spoilerFileStream) { if (!spoilerFileStream) {
return; return;
} }
@@ -1495,7 +1485,7 @@ int16_t Randomizer::GetVanillaMerchantPrice(RandomizerCheck check) {
} }
void Randomizer::ParseItemLocationsFile(const char* spoilerFileName, bool silent) { void Randomizer::ParseItemLocationsFile(const char* spoilerFileName, bool silent) {
std::ifstream spoilerFileStream(sanitize(spoilerFileName)); std::ifstream spoilerFileStream(SohUtils::Sanitize(spoilerFileName));
if (!spoilerFileStream) if (!spoilerFileStream)
return; return;
@@ -1558,7 +1548,7 @@ void Randomizer::ParseItemLocationsFile(const char* spoilerFileName, bool silent
} }
void Randomizer::ParseEntranceDataFile(const char* spoilerFileName, bool silent) { void Randomizer::ParseEntranceDataFile(const char* spoilerFileName, bool silent) {
std::ifstream spoilerFileStream(sanitize(spoilerFileName)); std::ifstream spoilerFileStream(SohUtils::Sanitize(spoilerFileName));
if (!spoilerFileStream) { if (!spoilerFileStream) {
return; return;
} }
@@ -2547,6 +2537,7 @@ std::map<RandomizerCheck, RandomizerInf> rcToRandomizerInf = {
{ RC_LH_CHILD_FISHING, RAND_INF_CHILD_FISHING }, { RC_LH_CHILD_FISHING, RAND_INF_CHILD_FISHING },
{ RC_LH_ADULT_FISHING, RAND_INF_ADULT_FISHING }, { RC_LH_ADULT_FISHING, RAND_INF_ADULT_FISHING },
{ RC_MARKET_10_BIG_POES, RAND_INF_10_BIG_POES }, { RC_MARKET_10_BIG_POES, RAND_INF_10_BIG_POES },
{ RC_KAK_100_GOLD_SKULLTULA_REWARD, RAND_INF_KAK_100_GOLD_SKULLTULA_REWARD },
}; };
RandomizerCheckObject Randomizer::GetCheckObjectFromActor(s16 actorId, s16 sceneNum, s32 actorParams = 0x00) { RandomizerCheckObject Randomizer::GetCheckObjectFromActor(s16 actorId, s16 sceneNum, s32 actorParams = 0x00) {
@@ -3143,7 +3134,9 @@ void RandomizerSettingsWindow::DrawElement() {
UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f); UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f);
} }
ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0));
DrawPresetSelector(PRESET_TYPE_RANDOMIZER); DrawPresetSelector(PRESET_TYPE_RANDOMIZER);
ImGui::EndDisabled();
UIWidgets::Spacer(0); UIWidgets::Spacer(0);
UIWidgets::EnhancementCheckbox("Manual seed entry", "gRandoManualSeedEntry", false, ""); UIWidgets::EnhancementCheckbox("Manual seed entry", "gRandoManualSeedEntry", false, "");
@@ -3166,13 +3159,17 @@ void RandomizerSettingsWindow::DrawElement() {
} }
UIWidgets::Spacer(0); UIWidgets::Spacer(0);
ImGui::BeginDisabled(CVarGetInteger("gRandomizerDontGenerateSpoiler", 0) && gSaveContext.gameMode != GAMEMODE_FILE_SELECT);
if (ImGui::Button("Generate Randomizer")) { if (ImGui::Button("Generate Randomizer")) {
GenerateRandomizer(CVarGetInteger("gRandoManualSeedEntry", 0) ? seedString : ""); GenerateRandomizer(CVarGetInteger("gRandoManualSeedEntry", 0) ? seedString : "");
} }
ImGui::EndDisabled();
UIWidgets::Spacer(0); UIWidgets::Spacer(0);
std::string spoilerfilepath = CVarGetString("gSpoilerLog", ""); if (!CVarGetInteger("gRandomizerDontGenerateSpoiler", 0)) {
ImGui::Text("Spoiler File: %s", spoilerfilepath.c_str()); std::string spoilerfilepath = CVarGetString("gSpoilerLog", "");
ImGui::Text("Spoiler File: %s", spoilerfilepath.c_str());
}
// RANDOTODO settings presets // RANDOTODO settings presets
// std::string presetfilepath = CVarGetString("gLoadedPreset", ""); // std::string presetfilepath = CVarGetString("gLoadedPreset", "");
@@ -3180,6 +3177,8 @@ void RandomizerSettingsWindow::DrawElement() {
UIWidgets::PaddedSeparator(); UIWidgets::PaddedSeparator();
ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0));
ImGuiWindow* window = ImGui::GetCurrentWindow(); ImGuiWindow* window = ImGui::GetCurrentWindow();
static ImVec2 cellPadding(8.0f, 8.0f); static ImVec2 cellPadding(8.0f, 8.0f);
@@ -5224,6 +5223,8 @@ void RandomizerSettingsWindow::DrawElement() {
ImGui::EndTabBar(); ImGui::EndTabBar();
} }
ImGui::EndDisabled();
if (disableEditingRandoSettings) { if (disableEditingRandoSettings) {
UIWidgets::ReEnableComponent(""); UIWidgets::ReEnableComponent("");
@@ -39,7 +39,7 @@ std::map<RandomizerCheck, RandomizerCheckObject> rcObjects = {
RC_OBJECT(RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, RCVORMQ_BOTH, RCTYPE_SCRUB, RCAREA_LOST_WOODS, ACTOR_EN_DNS, SCENE_LOST_WOODS, 0x01, GI_STICKS_1, "Deku Scrub Near Deku Theater Left", "LW Deku Scrub Near Deku Theater Left", false), RC_OBJECT(RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, RCVORMQ_BOTH, RCTYPE_SCRUB, RCAREA_LOST_WOODS, ACTOR_EN_DNS, SCENE_LOST_WOODS, 0x01, GI_STICKS_1, "Deku Scrub Near Deku Theater Left", "LW Deku Scrub Near Deku Theater Left", false),
RC_OBJECT(RC_LW_DEKU_SCRUB_NEAR_BRIDGE, RCVORMQ_BOTH, RCTYPE_SCRUB, RCAREA_LOST_WOODS, ACTOR_EN_DNS, SCENE_LOST_WOODS, 0x09, GI_STICK_UPGRADE_20, "Deku Scrub Near Bridge", "LW Deku Scrub Near Bridge", true), RC_OBJECT(RC_LW_DEKU_SCRUB_NEAR_BRIDGE, RCVORMQ_BOTH, RCTYPE_SCRUB, RCAREA_LOST_WOODS, ACTOR_EN_DNS, SCENE_LOST_WOODS, 0x09, GI_STICK_UPGRADE_20, "Deku Scrub Near Bridge", "LW Deku Scrub Near Bridge", true),
RC_OBJECT(RC_LW_DEKU_SCRUB_GROTTO_REAR, RCVORMQ_BOTH, RCTYPE_SCRUB, RCAREA_LOST_WOODS, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x03,0xF5), GI_SEEDS_30, "Deku Scrub Grotto Rear", "LW Deku Scrub Grotto Rear", false), RC_OBJECT(RC_LW_DEKU_SCRUB_GROTTO_REAR, RCVORMQ_BOTH, RCTYPE_SCRUB, RCAREA_LOST_WOODS, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x03,0xF5), GI_SEEDS_30, "Deku Scrub Grotto Rear", "LW Deku Scrub Grotto Rear", false),
RC_OBJECT(RC_LW_DEKU_SCRUB_GROTTO_FRONT, RCVORMQ_BOTH, RCTYPE_SCRUB, RCAREA_LOST_WOODS, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x0A,0xF5), GI_NUT_UPGRADE_30, "Deku Scrub Grotto Front", "LW Deku Scrub Grotto Front", false), RC_OBJECT(RC_LW_DEKU_SCRUB_GROTTO_FRONT, RCVORMQ_BOTH, RCTYPE_SCRUB, RCAREA_LOST_WOODS, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x0A,0xF5), GI_NUT_UPGRADE_30, "Deku Scrub Grotto Front", "LW Deku Scrub Grotto Front", true),
RC_OBJECT(RC_DEKU_THEATER_SKULL_MASK, RCVORMQ_BOTH, RCTYPE_STANDARD, RCAREA_LOST_WOODS, ACTOR_ID_MAX, SCENE_GROTTOS, 0x00, GI_NONE, "Deku Theater Skull Mask", "Deku Theater Skull Mask", true), RC_OBJECT(RC_DEKU_THEATER_SKULL_MASK, RCVORMQ_BOTH, RCTYPE_STANDARD, RCAREA_LOST_WOODS, ACTOR_ID_MAX, SCENE_GROTTOS, 0x00, GI_NONE, "Deku Theater Skull Mask", "Deku Theater Skull Mask", true),
RC_OBJECT(RC_DEKU_THEATER_MASK_OF_TRUTH, RCVORMQ_BOTH, RCTYPE_STANDARD, RCAREA_LOST_WOODS, ACTOR_ID_MAX, SCENE_GROTTOS, 0x00, GI_NONE, "Deku Theater Mask of Truth", "Deku Theater Mask of Truth", true), RC_OBJECT(RC_DEKU_THEATER_MASK_OF_TRUTH, RCVORMQ_BOTH, RCTYPE_STANDARD, RCAREA_LOST_WOODS, ACTOR_ID_MAX, SCENE_GROTTOS, 0x00, GI_NONE, "Deku Theater Mask of Truth", "Deku Theater Mask of Truth", true),
RC_OBJECT(RC_LW_GS_BEAN_PATCH_NEAR_BRIDGE, RCVORMQ_BOTH, RCTYPE_SKULL_TOKEN, RCAREA_LOST_WOODS, ACTOR_EN_SI, SCENE_LOST_WOODS, 27905, GI_SKULL_TOKEN, "GS Bean Patch Near Bridge", "LW GS Bean Patch Near Bridge", true), RC_OBJECT(RC_LW_GS_BEAN_PATCH_NEAR_BRIDGE, RCVORMQ_BOTH, RCTYPE_SKULL_TOKEN, RCAREA_LOST_WOODS, ACTOR_EN_SI, SCENE_LOST_WOODS, 27905, GI_SKULL_TOKEN, "GS Bean Patch Near Bridge", "LW GS Bean Patch Near Bridge", true),
@@ -238,7 +238,7 @@ std::map<RandomizerCheck, RandomizerCheckObject> rcObjects = {
RC_OBJECT(RC_GRAVEYARD_HOOKSHOT_CHEST, RCVORMQ_BOTH, RCTYPE_STANDARD, RCAREA_GRAVEYARD, ACTOR_EN_BOX, SCENE_WINDMILL_AND_DAMPES_GRAVE, 4352, GI_HOOKSHOT, "Hookshot Chest", "GY Hookshot Chest", true), RC_OBJECT(RC_GRAVEYARD_HOOKSHOT_CHEST, RCVORMQ_BOTH, RCTYPE_STANDARD, RCAREA_GRAVEYARD, ACTOR_EN_BOX, SCENE_WINDMILL_AND_DAMPES_GRAVE, 4352, GI_HOOKSHOT, "Hookshot Chest", "GY Hookshot Chest", true),
RC_OBJECT(RC_GRAVEYARD_DAMPE_RACE_FREESTANDING_POH, RCVORMQ_BOTH, RCTYPE_STANDARD, RCAREA_GRAVEYARD, ACTOR_EN_ITEM00, SCENE_WINDMILL_AND_DAMPES_GRAVE, 1798, GI_HEART_PIECE, "Dampe Race Freestanding PoH", "GY Dampe Race Freestanding PoH", true), RC_OBJECT(RC_GRAVEYARD_DAMPE_RACE_FREESTANDING_POH, RCVORMQ_BOTH, RCTYPE_STANDARD, RCAREA_GRAVEYARD, ACTOR_EN_ITEM00, SCENE_WINDMILL_AND_DAMPES_GRAVE, 1798, GI_HEART_PIECE, "Dampe Race Freestanding PoH", "GY Dampe Race Freestanding PoH", true),
RC_OBJECT(RC_GRAVEYARD_FREESTANDING_POH, RCVORMQ_BOTH, RCTYPE_STANDARD, RCAREA_GRAVEYARD, ACTOR_EN_ITEM00, SCENE_GRAVEYARD, 1030, GI_HEART_PIECE, "Freestanding PoH", "GY Freestanding PoH", true), RC_OBJECT(RC_GRAVEYARD_FREESTANDING_POH, RCVORMQ_BOTH, RCTYPE_STANDARD, RCAREA_GRAVEYARD, ACTOR_EN_ITEM00, SCENE_GRAVEYARD, 1030, GI_HEART_PIECE, "Freestanding PoH", "GY Freestanding PoH", true),
RC_OBJECT(RC_GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, RCVORMQ_BOTH, RCTYPE_STANDARD, RCAREA_GRAVEYARD, ACTOR_EN_ITEM00, SCENE_GRAVEYARD, 7942, GI_HEART_PIECE, "Dampe Gravedigging Tour", "GY Dampe Gravedigging Tour", true), RC_OBJECT(RC_GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, RCVORMQ_BOTH, RCTYPE_STANDARD, RCAREA_GRAVEYARD, ACTOR_EN_ITEM00, SCENE_GRAVEYARD, 6406, GI_HEART_PIECE, "Dampe Gravedigging Tour", "GY Dampe Gravedigging Tour", true),
RC_OBJECT(RC_GRAVEYARD_GS_WALL, RCVORMQ_BOTH, RCTYPE_SKULL_TOKEN, RCAREA_GRAVEYARD, ACTOR_EN_SI, SCENE_GRAVEYARD, 20608, GI_SKULL_TOKEN, "GS Wall", "Graveyard GS Wall", true), RC_OBJECT(RC_GRAVEYARD_GS_WALL, RCVORMQ_BOTH, RCTYPE_SKULL_TOKEN, RCAREA_GRAVEYARD, ACTOR_EN_SI, SCENE_GRAVEYARD, 20608, GI_SKULL_TOKEN, "GS Wall", "Graveyard GS Wall", true),
RC_OBJECT(RC_GRAVEYARD_GS_BEAN_PATCH, RCVORMQ_BOTH, RCTYPE_SKULL_TOKEN, RCAREA_GRAVEYARD, ACTOR_EN_SI, SCENE_GRAVEYARD, 28673, GI_SKULL_TOKEN, "GS Bean Patch", "Graveyard GS Bean Patch", true), RC_OBJECT(RC_GRAVEYARD_GS_BEAN_PATCH, RCVORMQ_BOTH, RCTYPE_SKULL_TOKEN, RCAREA_GRAVEYARD, ACTOR_EN_SI, SCENE_GRAVEYARD, 28673, GI_SKULL_TOKEN, "GS Bean Patch", "Graveyard GS Bean Patch", true),
RC_OBJECT(RC_SONG_FROM_ROYAL_FAMILYS_TOMB, RCVORMQ_BOTH, RCTYPE_SONG_LOCATION, RCAREA_GRAVEYARD, ACTOR_ID_MAX, SCENE_ID_MAX, 0x00, GI_NONE, "Song from Composers Grave", "Song from Composers Grave", true), RC_OBJECT(RC_SONG_FROM_ROYAL_FAMILYS_TOMB, RCVORMQ_BOTH, RCTYPE_SONG_LOCATION, RCAREA_GRAVEYARD, ACTOR_ID_MAX, SCENE_ID_MAX, 0x00, GI_NONE, "Song from Composers Grave", "Song from Composers Grave", true),
@@ -73,20 +73,12 @@ bool showLinksPocket;
bool fortressFast; bool fortressFast;
bool fortressNormal; bool fortressNormal;
bool bypassRandoCheck = true;
// persistent during gameplay // persistent during gameplay
bool initialized; bool initialized;
bool doAreaScroll; bool doAreaScroll;
bool previousShowHidden = false; bool previousShowHidden = false;
bool hideShopRightChecks = true; bool hideShopRightChecks = true;
bool alwaysShowGS = false;
bool checkCollected = false;
int checkLoops = 0;
int checkCounter = 0;
u16 savedFrames = 0;
bool messageCloseCheck = false;
bool pendingSaleCheck = false;
bool transitionCheck = false;
std::map<uint32_t, RandomizerCheck> startingShopItem = { { SCENE_KOKIRI_SHOP, RC_KF_SHOP_ITEM_1 }, std::map<uint32_t, RandomizerCheck> startingShopItem = { { SCENE_KOKIRI_SHOP, RC_KF_SHOP_ITEM_1 },
{ SCENE_BAZAAR, RC_MARKET_BAZAAR_ITEM_1 }, { SCENE_BAZAAR, RC_MARKET_BAZAAR_ITEM_1 },
@@ -118,12 +110,9 @@ bool showVOrMQ;
s8 areaChecksGotten[32]; //| "Kokiri Forest (4/9)" s8 areaChecksGotten[32]; //| "Kokiri Forest (4/9)"
bool optCollapseAll; // A bool that will collapse all checks once bool optCollapseAll; // A bool that will collapse all checks once
bool optExpandAll; // A bool that will expand all checks once bool optExpandAll; // A bool that will expand all checks once
RandomizerCheck lastItemGetCheck = RC_UNKNOWN_CHECK;
RandomizerCheck lastLocationChecked = RC_UNKNOWN_CHECK; RandomizerCheck lastLocationChecked = RC_UNKNOWN_CHECK;
RandomizerCheckArea previousArea = RCAREA_INVALID; RandomizerCheckArea previousArea = RCAREA_INVALID;
RandomizerCheckArea currentArea = RCAREA_INVALID; RandomizerCheckArea currentArea = RCAREA_INVALID;
std::vector<RandomizerCheckArea> checkAreas;
std::vector<GetItemEntry> itemsReceived;
OSContPad* trackerButtonsPressed; OSContPad* trackerButtonsPressed;
void BeginFloatWindows(std::string UniqueName, bool& open, ImGuiWindowFlags flags = 0); void BeginFloatWindows(std::string UniqueName, bool& open, ImGuiWindowFlags flags = 0);
@@ -194,10 +183,6 @@ Color_RGBA8 Color_Saved_Extra = { 0, 185, 0, 255 }; // Green
std::vector<uint32_t> buttons = { BTN_A, BTN_B, BTN_CUP, BTN_CDOWN, BTN_CLEFT, BTN_CRIGHT, BTN_L, std::vector<uint32_t> buttons = { BTN_A, BTN_B, BTN_CUP, BTN_CDOWN, BTN_CLEFT, BTN_CRIGHT, BTN_L,
BTN_Z, BTN_R, BTN_START, BTN_DUP, BTN_DDOWN, BTN_DLEFT, BTN_DRIGHT }; BTN_Z, BTN_R, BTN_START, BTN_DUP, BTN_DDOWN, BTN_DLEFT, BTN_DRIGHT };
void SetLastItemGetRC(RandomizerCheck rc) {
lastItemGetCheck = rc;
}
void DefaultCheckData(RandomizerCheck rc) { void DefaultCheckData(RandomizerCheck rc) {
gSaveContext.checkTrackerData[rc].status = RCSHOW_UNCHECKED; gSaveContext.checkTrackerData[rc].status = RCSHOW_UNCHECKED;
gSaveContext.checkTrackerData[rc].skipped = 0; gSaveContext.checkTrackerData[rc].skipped = 0;
@@ -253,9 +238,6 @@ void SetCheckCollected(RandomizerCheck rc) {
} else { } else {
gSaveContext.checkTrackerData[rc].skipped = false; gSaveContext.checkTrackerData[rc].skipped = false;
} }
if (!checkAreas.empty()) {
checkAreas.erase(checkAreas.begin());
}
SaveManager::Instance->SaveSection(gSaveContext.fileNum, sectionId, true); SaveManager::Instance->SaveSection(gSaveContext.fileNum, sectionId, true);
doAreaScroll = true; doAreaScroll = true;
@@ -360,32 +342,18 @@ bool vector_contains_scene(std::vector<SceneID> vec, const int16_t scene) {
std::vector<SceneID> skipScenes = {SCENE_GANON_BOSS, SCENE_GANONS_TOWER_COLLAPSE_EXTERIOR, SCENE_GANON_BOSS, SCENE_INSIDE_GANONS_CASTLE_COLLAPSE, SCENE_GANONS_TOWER_COLLAPSE_INTERIOR}; std::vector<SceneID> skipScenes = {SCENE_GANON_BOSS, SCENE_GANONS_TOWER_COLLAPSE_EXTERIOR, SCENE_GANON_BOSS, SCENE_INSIDE_GANONS_CASTLE_COLLAPSE, SCENE_GANONS_TOWER_COLLAPSE_INTERIOR};
bool EvaluateCheck(RandomizerCheckObject rco) { void ClearAreaChecksAndTotals() {
if (HasItemBeenCollected(rco.rc) && gSaveContext.checkTrackerData[rco.rc].status != RCSHOW_COLLECTED && for (auto& [rcArea, vec] : checksByArea) {
gSaveContext.checkTrackerData[rco.rc].status != RCSHOW_SAVED) { vec.clear();
SetCheckCollected(rco.rc); areaChecksGotten[rcArea] = 0;
return true;
}
return false;
}
bool CheckByArea(RandomizerCheckArea area = RCAREA_INVALID) {
if (area == RCAREA_INVALID) {
area = checkAreas.front();
}
if (area != RCAREA_INVALID) {
auto areaChecks = checksByArea.find(area)->second;
if (checkCounter >= areaChecks.size()) {
checkCounter = 0;
checkLoops++;
}
auto rco = areaChecks.at(checkCounter);
return EvaluateCheck(rco);
} }
} }
void SetShopSeen(uint32_t sceneNum, bool prices) { void SetShopSeen(uint32_t sceneNum, bool prices) {
RandomizerCheck start = startingShopItem.find(sceneNum)->second; RandomizerCheck start = startingShopItem.find(sceneNum)->second;
if (sceneNum == SCENE_POTION_SHOP_KAKARIKO && !LINK_IS_ADULT) {
return;
}
if (GetCheckArea() == RCAREA_KAKARIKO_VILLAGE && sceneNum == SCENE_BAZAAR) { if (GetCheckArea() == RCAREA_KAKARIKO_VILLAGE && sceneNum == SCENE_BAZAAR) {
start = RC_KAK_BAZAAR_ITEM_1; start = RC_KAK_BAZAAR_ITEM_1;
} }
@@ -467,7 +435,6 @@ void CheckTrackerLoadGame(int32_t fileNum) {
} else { } else {
realRcObj = rcObj; realRcObj = rcObj;
} }
if (!IsVisibleInCheckTracker(realRcObj)) continue;
checksByArea.find(realRcObj.rcArea)->second.push_back(realRcObj); checksByArea.find(realRcObj.rcArea)->second.push_back(realRcObj);
if (rcTrackerData.status == RCSHOW_SAVED || rcTrackerData.skipped) { if (rcTrackerData.status == RCSHOW_SAVED || rcTrackerData.skipped) {
@@ -509,12 +476,6 @@ void CheckTrackerLoadGame(int32_t fileNum) {
UpdateInventoryChecks(); UpdateInventoryChecks();
} }
void CheckTrackerDialogClosed() {
if (messageCloseCheck) {
messageCloseCheck = false;
}
}
void CheckTrackerShopSlotChange(uint8_t cursorSlot, int16_t basePrice) { void CheckTrackerShopSlotChange(uint8_t cursorSlot, int16_t basePrice) {
if (gPlayState->sceneNum == SCENE_HAPPY_MASK_SHOP) { // Happy Mask Shop is not used in rando, so is not tracked if (gPlayState->sceneNum == SCENE_HAPPY_MASK_SHOP) { // Happy Mask Shop is not used in rando, so is not tracked
return; return;
@@ -536,10 +497,6 @@ void CheckTrackerTransition(uint32_t sceneNum) {
if (!GameInteractor::IsSaveLoaded()) { if (!GameInteractor::IsSaveLoaded()) {
return; return;
} }
gSaveContext;
if (transitionCheck) {
transitionCheck = false;
}
doAreaScroll = true; doAreaScroll = true;
previousArea = currentArea; previousArea = currentArea;
currentArea = GetCheckArea(); currentArea = GetCheckArea();
@@ -557,31 +514,19 @@ void CheckTrackerTransition(uint32_t sceneNum) {
} }
void CheckTrackerFrame() { void CheckTrackerFrame() {
if (IS_RANDO) {
hideShopRightChecks = CVarGetInteger("gCheckTrackerOptionHideRightShopChecks", 1);
alwaysShowGS = CVarGetInteger("gCheckTrackerOptionAlwaysShowGSLocs", 0);
}
if (!GameInteractor::IsSaveLoaded()) { if (!GameInteractor::IsSaveLoaded()) {
return; return;
} }
if (!checkAreas.empty() && !transitionCheck && !messageCloseCheck && !pendingSaleCheck) { // TODO: Move to OnAmmoChange hook once it gets added.
for (int i = 0; i < 10; i++) { if (gSaveContext.checkTrackerData[RC_ZR_MAGIC_BEAN_SALESMAN].status != RCSHOW_COLLECTED &&
if (CheckByArea()) { gSaveContext.checkTrackerData[RC_ZR_MAGIC_BEAN_SALESMAN].status != RCSHOW_SAVED) {
checkCounter = 0; if (BEANS_BOUGHT >= 10) {
break; SetCheckCollected(RC_ZR_MAGIC_BEAN_SALESMAN);
} else {
checkCounter++;
}
} }
if (checkLoops > 15) {
checkAreas.erase(checkAreas.begin());
checkLoops = 0;
}
}
if (savedFrames > 0 && !pendingSaleCheck && !messageCloseCheck) {
savedFrames--;
}
}
void CheckTrackerSaleEnd(GetItemEntry giEntry) {
if (pendingSaleCheck) {
pendingSaleCheck = false;
} }
} }
@@ -593,7 +538,7 @@ void CheckTrackerItemReceive(GetItemEntry giEntry) {
// Vanilla special item checks // Vanilla special item checks
if (!IS_RANDO) { if (!IS_RANDO) {
if (giEntry.itemId == ITEM_SHIELD_DEKU) { if (giEntry.itemId == ITEM_SHIELD_DEKU) {
SetCheckCollected(RC_KF_SHOP_ITEM_3); SetCheckCollected(RC_KF_SHOP_ITEM_1);
return; return;
}else if (giEntry.itemId == ITEM_KOKIRI_EMERALD) { }else if (giEntry.itemId == ITEM_KOKIRI_EMERALD) {
SetCheckCollected(RC_QUEEN_GOHMA); SetCheckCollected(RC_QUEEN_GOHMA);
@@ -622,16 +567,19 @@ void CheckTrackerItemReceive(GetItemEntry giEntry) {
} else if (giEntry.itemId == ITEM_MEDALLION_LIGHT) { } else if (giEntry.itemId == ITEM_MEDALLION_LIGHT) {
SetCheckCollected(RC_GIFT_FROM_SAGES); SetCheckCollected(RC_GIFT_FROM_SAGES);
return; return;
} else if (giEntry.itemId == ITEM_SONG_LULLABY) {
SetCheckCollected(RC_SONG_FROM_IMPA);
return;
} else if (giEntry.itemId == ITEM_SONG_EPONA) { } else if (giEntry.itemId == ITEM_SONG_EPONA) {
SetCheckCollected(RC_SONG_FROM_MALON); SetCheckCollected(RC_SONG_FROM_MALON);
return; return;
} else if (giEntry.itemId == ITEM_SONG_SARIA) { } else if (giEntry.itemId == ITEM_SONG_SARIA) {
SetCheckCollected(RC_SONG_FROM_SARIA); SetCheckCollected(RC_SONG_FROM_SARIA);
return; return;
} else if (giEntry.itemId == ITEM_SONG_SUN) { } else if (giEntry.itemId == ITEM_BEAN) {
SetCheckCollected(RC_ZR_MAGIC_BEAN_SALESMAN);
return;
} else if (giEntry.itemId == ITEM_BRACELET) {
SetCheckCollected(RC_GC_DARUNIAS_JOY);
return;
}/* else if (giEntry.itemId == ITEM_SONG_SUN) {
SetCheckCollected(RC_SONG_FROM_ROYAL_FAMILYS_TOMB); SetCheckCollected(RC_SONG_FROM_ROYAL_FAMILYS_TOMB);
return; return;
} else if (giEntry.itemId == ITEM_SONG_TIME) { } else if (giEntry.itemId == ITEM_SONG_TIME) {
@@ -658,42 +606,127 @@ void CheckTrackerItemReceive(GetItemEntry giEntry) {
} else if (giEntry.itemId == ITEM_SONG_PRELUDE) { } else if (giEntry.itemId == ITEM_SONG_PRELUDE) {
SetCheckCollected(RC_SHEIK_AT_TEMPLE); SetCheckCollected(RC_SHEIK_AT_TEMPLE);
return; return;
} else if (giEntry.itemId == ITEM_BRACELET) { }*/
SetCheckCollected(RC_GC_DARUNIAS_JOY); }
return; }
} else if (giEntry.itemId == ITEM_LETTER_ZELDA) {
SetCheckCollected(RC_HC_ZELDAS_LETTER); void CheckTrackerSceneFlagSet(int16_t sceneNum, int16_t flagType, int32_t flag) {
return; if (flagType != FLAG_SCENE_TREASURE && flagType != FLAG_SCENE_COLLECTIBLE) {
} else if (giEntry.itemId == ITEM_WEIRD_EGG) { return;
SetCheckCollected(RC_HC_MALON_EGG); }
return; if (sceneNum == SCENE_GRAVEYARD && flag == 0x19 && flagType == FLAG_SCENE_COLLECTIBLE) { // Gravedigging tour special case
} else if (giEntry.itemId == ITEM_BEAN) { SetCheckCollected(RC_GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR);
SetCheckCollected(RC_ZR_MAGIC_BEAN_SALESMAN); return;
}
for (auto [rc, rcObj] : RandomizerCheckObjects::GetAllRCObjects()) {
if (!IsVisibleInCheckTracker(rcObj)) {
continue;
}
SpoilerCollectionCheckType checkMatchType = flagType == FLAG_SCENE_TREASURE ? SpoilerCollectionCheckType::SPOILER_CHK_CHEST : SpoilerCollectionCheckType::SPOILER_CHK_COLLECTABLE;
SpoilerCollectionCheck scCheck = Location(rc)->GetCollectionCheck();
if (scCheck.scene == sceneNum && scCheck.flag == flag && scCheck.type == checkMatchType) {
SetCheckCollected(rc);
return; return;
} }
} }
auto checkArea = GetCheckArea(); }
if (gSaveContext.pendingSale != ITEM_NONE) {
pendingSaleCheck = true; void CheckTrackerFlagSet(int16_t flagType, int32_t flag) {
checkAreas.push_back(checkArea); SpoilerCollectionCheckType checkMatchType = SpoilerCollectionCheckType::SPOILER_CHK_NONE;
switch (flagType) {
case FLAG_GS_TOKEN:
checkMatchType = SpoilerCollectionCheckType::SPOILER_CHK_GOLD_SKULLTULA;
break;
case FLAG_EVENT_CHECK_INF:
if ((flag == EVENTCHKINF_CARPENTERS_FREE(0) || flag == EVENTCHKINF_CARPENTERS_FREE(1) ||
flag == EVENTCHKINF_CARPENTERS_FREE(2) || flag == EVENTCHKINF_CARPENTERS_FREE(3))
&& GET_EVENTCHKINF_CARPENTERS_FREE_ALL()) {
SetCheckCollected(RC_GF_GERUDO_MEMBERSHIP_CARD);
return;
}
checkMatchType = SpoilerCollectionCheckType::SPOILER_CHK_EVENT_CHK_INF;
break;
case FLAG_INF_TABLE:
if (flag == INFTABLE_190) {
SetCheckCollected(RC_GF_HBA_1000_POINTS);
return;
} else if (flag == INFTABLE_11E) {
SetCheckCollected(RC_GC_ROLLING_GORON_AS_CHILD);
return;
} else if (flag == INFTABLE_GORON_CITY_DOORS_UNLOCKED) {
SetCheckCollected(RC_GC_ROLLING_GORON_AS_ADULT);
return;
} else if (flag == INFTABLE_139) {
SetCheckCollected(RC_ZD_KING_ZORA_THAWED);
return;
} else if (flag == INFTABLE_191) {
SetCheckCollected(RC_MARKET_LOST_DOG);
return;
}
if (!IS_RANDO) {
if (flag == INFTABLE_192) {
SetCheckCollected(RC_LW_DEKU_SCRUB_NEAR_BRIDGE);
return;
} else if (flag == INFTABLE_193) {
SetCheckCollected(RC_LW_DEKU_SCRUB_GROTTO_FRONT);
return;
}
}
break;
case FLAG_ITEM_GET_INF:
if (!IS_RANDO) {
if (flag == ITEMGETINF_OBTAINED_STICK_UPGRADE_FROM_STAGE) {
SetCheckCollected(RC_DEKU_THEATER_SKULL_MASK);
return;
} else if (flag == ITEMGETINF_OBTAINED_NUT_UPGRADE_FROM_STAGE) {
SetCheckCollected(RC_DEKU_THEATER_MASK_OF_TRUTH);
return;
} else if (flag == ITEMGETINF_0B) {
SetCheckCollected(RC_HF_DEKU_SCRUB_GROTTO);
return;
}
}
checkMatchType = SpoilerCollectionCheckType::SPOILER_CHK_ITEM_GET_INF;
break;
case FLAG_RANDOMIZER_INF:
checkMatchType = SpoilerCollectionCheckType::SPOILER_CHK_RANDOMIZER_INF;
break;
}
if (checkMatchType == SpoilerCollectionCheckType::SPOILER_CHK_NONE) {
return; return;
} }
if (scene == SCENE_DESERT_COLOSSUS && (gSaveContext.entranceIndex == 485 || gSaveContext.entranceIndex == 489)) { for (auto [rc, rcObj] : RandomizerCheckObjects::GetAllRCObjects()) {
checkAreas.push_back(RCAREA_SPIRIT_TEMPLE); if ((!IS_RANDO && ((rcObj.vOrMQ == RCVORMQ_MQ && !IS_MASTER_QUEST) ||
return; (rcObj.vOrMQ == RCVORMQ_VANILLA && IS_MASTER_QUEST))) ||
} (IS_RANDO && ((OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(rcObj.sceneId) &&
if (GET_PLAYER(gPlayState) == nullptr) { rcObj.vOrMQ == RCVORMQ_VANILLA) ||
transitionCheck = true; !OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(rcObj.sceneId) &&
return; rcObj.vOrMQ == RCVORMQ_MQ))) {
} continue;
if (gPlayState->msgCtx.msgMode != MSGMODE_NONE) { }
checkAreas.push_back(checkArea); SpoilerCollectionCheck scCheck = Location(rc)->GetCollectionCheck();
messageCloseCheck = true; SpoilerCollectionCheckType scCheckType = scCheck.type;
return; if (checkMatchType == SpoilerCollectionCheckType::SPOILER_CHK_RANDOMIZER_INF &&
} (scCheckType == SpoilerCollectionCheckType::SPOILER_CHK_MERCHANT ||
if (IS_RANDO || (!IS_RANDO && giEntry.getItemCategory != ITEM_CATEGORY_JUNK)) { scCheckType == SpoilerCollectionCheckType::SPOILER_CHK_SHOP_ITEM ||
checkAreas.push_back(checkArea); scCheckType == SpoilerCollectionCheckType::SPOILER_CHK_COW ||
checkCollected = true; scCheckType == SpoilerCollectionCheckType::SPOILER_CHK_SCRUB ||
scCheckType == SpoilerCollectionCheckType::SPOILER_CHK_MASTER_SWORD ||
scCheckType == SpoilerCollectionCheckType::SPOILER_CHK_RANDOMIZER_INF)) {
if (flag == OTRGlobals::Instance->gRandomizer->GetRandomizerInfFromCheck(rc)) {
SetCheckCollected(rc);
return;
}
continue;
}
int16_t checkFlag = scCheck.flag;
if (checkMatchType == SpoilerCollectionCheckType::SPOILER_CHK_GOLD_SKULLTULA) {
checkFlag = rcObj.actorParams;
}
if (checkFlag == flag && scCheck.type == checkMatchType) {
SetCheckCollected(rc);
return;
}
} }
} }
@@ -711,7 +744,7 @@ void InitTrackerData(bool isDebug) {
void SaveTrackerData(SaveContext* saveContext, int sectionID, bool gameSave) { void SaveTrackerData(SaveContext* saveContext, int sectionID, bool gameSave) {
SaveManager::Instance->SaveArray("checks", ARRAY_COUNT(saveContext->checkTrackerData), [&](size_t i) { SaveManager::Instance->SaveArray("checks", ARRAY_COUNT(saveContext->checkTrackerData), [&](size_t i) {
if (saveContext->checkTrackerData[i].status == RCSHOW_COLLECTED) { if (saveContext->checkTrackerData[i].status == RCSHOW_COLLECTED) {
if (gameSave || savedFrames > 0) { if (gameSave) {
gSaveContext.checkTrackerData[i].status = saveContext->checkTrackerData[i].status = RCSHOW_SAVED; gSaveContext.checkTrackerData[i].status = saveContext->checkTrackerData[i].status = RCSHOW_SAVED;
UpdateAllOrdering(); UpdateAllOrdering();
UpdateInventoryChecks(); UpdateInventoryChecks();
@@ -730,9 +763,6 @@ void SaveTrackerData(SaveContext* saveContext, int sectionID, bool gameSave) {
void SaveFile(SaveContext* saveContext, int sectionID, bool fullSave) { void SaveFile(SaveContext* saveContext, int sectionID, bool fullSave) {
SaveTrackerData(saveContext, sectionID, fullSave); SaveTrackerData(saveContext, sectionID, fullSave);
if (fullSave) {
savedFrames = 40;
}
} }
void LoadFile() { void LoadFile() {
@@ -748,14 +778,9 @@ void LoadFile() {
void Teardown() { void Teardown() {
initialized = false; initialized = false;
for (auto& [rcArea, vec] : checksByArea) { ClearAreaChecksAndTotals();
vec.clear();
areaChecksGotten[rcArea] = 0;
}
checksByArea.clear(); checksByArea.clear();
areasSpoiled = 0; areasSpoiled = 0;
checkCollected = false;
checkLoops = 0;
lastLocationChecked = RC_UNKNOWN_CHECK; lastLocationChecked = RC_UNKNOWN_CHECK;
} }
@@ -925,7 +950,11 @@ void CheckTrackerWindow::DrawElement() {
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(extraColor.r / 255.0f, extraColor.g / 255.0f, ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(extraColor.r / 255.0f, extraColor.g / 255.0f,
extraColor.b / 255.0f, extraColor.a / 255.0f)); extraColor.b / 255.0f, extraColor.a / 255.0f));
isThisAreaSpoiled = areasSpoiled & areaMask || CVarGetInteger("gCheckTrackerOptionMQSpoilers", 0); isThisAreaSpoiled = areasSpoiled & areaMask || CVarGetInteger("gCheckTrackerOptionMQSpoilers", 0) || !IS_RANDO ||
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_NONE ||
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_SELECTION ||
(OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_SET_NUMBER &&
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_MQ_DUNGEON_COUNT) == 12);
if (isThisAreaSpoiled) { if (isThisAreaSpoiled) {
if (showVOrMQ && RandomizerCheckObjects::AreaIsDungeon(rcArea)) { if (showVOrMQ && RandomizerCheckObjects::AreaIsDungeon(rcArea)) {
@@ -1059,7 +1088,6 @@ void LoadSettings() {
showLinksPocket = IS_RANDO ? // don't show Link's Pocket if not randomizer, or if rando and pocket is disabled showLinksPocket = IS_RANDO ? // don't show Link's Pocket if not randomizer, or if rando and pocket is disabled
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_LINKS_POCKET) != RO_LINKS_POCKET_NOTHING OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_LINKS_POCKET) != RO_LINKS_POCKET_NOTHING
:false; :false;
hideShopRightChecks = IS_RANDO ? CVarGetInteger("gCheckTrackerOptionHideRightShopChecks", 1) : false;
if (IS_RANDO) { if (IS_RANDO) {
switch (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_TOKENS)) { switch (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_TOKENS)) {
@@ -1123,7 +1151,7 @@ bool IsVisibleInCheckTracker(RandomizerCheckObject rcObj) {
) && ) &&
(rcObj.rcType != RCTYPE_MERCHANT || showMerchants) && (rcObj.rcType != RCTYPE_MERCHANT || showMerchants) &&
(rcObj.rcType != RCTYPE_OCARINA || showOcarinas) && (rcObj.rcType != RCTYPE_OCARINA || showOcarinas) &&
(rcObj.rcType != RCTYPE_SKULL_TOKEN || (rcObj.rcType != RCTYPE_SKULL_TOKEN || alwaysShowGS ||
(showOverworldTokens && RandomizerCheckObjects::AreaIsOverworld(rcObj.rcArea)) || (showOverworldTokens && RandomizerCheckObjects::AreaIsOverworld(rcObj.rcArea)) ||
(showDungeonTokens && RandomizerCheckObjects::AreaIsDungeon(rcObj.rcArea)) (showDungeonTokens && RandomizerCheckObjects::AreaIsDungeon(rcObj.rcArea))
) && ) &&
@@ -1151,8 +1179,8 @@ bool IsVisibleInCheckTracker(RandomizerCheckObject rcObj) {
} }
else if (rcObj.vanillaCompletion) { else if (rcObj.vanillaCompletion) {
return (rcObj.vOrMQ == RCVORMQ_BOTH || return (rcObj.vOrMQ == RCVORMQ_BOTH ||
rcObj.vOrMQ == RCVORMQ_MQ && OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(rcObj.sceneId) || (rcObj.vOrMQ == RCVORMQ_MQ && IS_MASTER_QUEST) ||
rcObj.vOrMQ == RCVORMQ_VANILLA && !OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(rcObj.sceneId) || (rcObj.vOrMQ == RCVORMQ_VANILLA && !IS_MASTER_QUEST) ||
rcObj.rc == RC_GIFT_FROM_SAGES) && rcObj.rc != RC_LINKS_POCKET; rcObj.rc == RC_GIFT_FROM_SAGES) && rcObj.rc != RC_LINKS_POCKET;
} }
return false; return false;
@@ -1493,7 +1521,9 @@ void CheckTrackerSettingsWindow::DrawElement() {
UIWidgets::EnhancementCheckbox("Vanilla/MQ Dungeon Spoilers", "gCheckTrackerOptionMQSpoilers"); UIWidgets::EnhancementCheckbox("Vanilla/MQ Dungeon Spoilers", "gCheckTrackerOptionMQSpoilers");
UIWidgets::Tooltip("If enabled, Vanilla/MQ dungeons will show on the tracker immediately. Otherwise, Vanilla/MQ dungeon locations must be unlocked."); UIWidgets::Tooltip("If enabled, Vanilla/MQ dungeons will show on the tracker immediately. Otherwise, Vanilla/MQ dungeon locations must be unlocked.");
UIWidgets::EnhancementCheckbox("Hide right-side shop item checks", "gCheckTrackerOptionHideRightShopChecks", false, "", UIWidgets::CheckboxGraphics::Cross, true); UIWidgets::EnhancementCheckbox("Hide right-side shop item checks", "gCheckTrackerOptionHideRightShopChecks", false, "", UIWidgets::CheckboxGraphics::Cross, true);
UIWidgets::Tooltip("If enabled, will prevent the tracker from displaying slots 1-4 in all shops. Requires save reload."); UIWidgets::Tooltip("If enabled, will prevent the tracker from displaying slots 1-4 in all shops.");
UIWidgets::EnhancementCheckbox("Always show gold skulltulas", "gCheckTrackerOptionAlwaysShowGSLocs", false, "");
UIWidgets::Tooltip("If enabled, will show GS locations in the tracker regardless of tokensanity settings.");
ImGui::TableNextColumn(); ImGui::TableNextColumn();
@@ -1541,10 +1571,11 @@ void CheckTrackerWindow::InitElement() {
Teardown(); Teardown();
}); });
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnItemReceive>(CheckTrackerItemReceive); GameInteractor::Instance->RegisterGameHook<GameInteractor::OnItemReceive>(CheckTrackerItemReceive);
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSaleEnd>(CheckTrackerSaleEnd);
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>(CheckTrackerFrame); GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>(CheckTrackerFrame);
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnTransitionEnd>(CheckTrackerTransition); GameInteractor::Instance->RegisterGameHook<GameInteractor::OnTransitionEnd>(CheckTrackerTransition);
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnShopSlotChange>(CheckTrackerShopSlotChange); GameInteractor::Instance->RegisterGameHook<GameInteractor::OnShopSlotChange>(CheckTrackerShopSlotChange);
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneFlagSet>(CheckTrackerSceneFlagSet);
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnFlagSet>(CheckTrackerFlagSet);
LocationTable_Init(); LocationTable_Init();
} }
@@ -48,10 +48,7 @@ void Teardown();
void UpdateAllOrdering(); void UpdateAllOrdering();
bool IsVisibleInCheckTracker(RandomizerCheckObject rcObj); bool IsVisibleInCheckTracker(RandomizerCheckObject rcObj);
void InitTrackerData(bool isDebug); void InitTrackerData(bool isDebug);
void SetLastItemGetRC(RandomizerCheck rc);
RandomizerCheckArea GetCheckArea(); RandomizerCheckArea GetCheckArea();
void CheckTrackerDialogClosed();
void ToggleShopRightChecks();
void UpdateCheck(uint32_t, RandomizerCheckTrackerData); void UpdateCheck(uint32_t, RandomizerCheckTrackerData);
} // namespace CheckTracker } // namespace CheckTracker
@@ -76,7 +76,7 @@ static s16 newIceCavernEntrance = ICE_CAVERN_ENTRANCE;
static s8 hasCopiedEntranceTable = 0; static s8 hasCopiedEntranceTable = 0;
static s8 hasModifiedEntranceTable = 0; static s8 hasModifiedEntranceTable = 0;
void Entrance_SetEntranceDiscovered(u16 entranceIndex); void Entrance_SetEntranceDiscovered(u16 entranceIndex, u8 isReversedEntrance);
u8 Entrance_EntranceIsNull(EntranceOverride* entranceOverride) { u8 Entrance_EntranceIsNull(EntranceOverride* entranceOverride) {
return entranceOverride->index == 0 && entranceOverride->destination == 0 && entranceOverride->blueWarp == 0 return entranceOverride->index == 0 && entranceOverride->destination == 0 && entranceOverride->blueWarp == 0
@@ -276,13 +276,13 @@ s16 Entrance_OverrideNextIndex(s16 nextEntranceIndex) {
return nextEntranceIndex; return nextEntranceIndex;
} }
Entrance_SetEntranceDiscovered(nextEntranceIndex); Entrance_SetEntranceDiscovered(nextEntranceIndex, false);
EntranceTracker_SetLastEntranceOverride(nextEntranceIndex); EntranceTracker_SetLastEntranceOverride(nextEntranceIndex);
return Grotto_OverrideSpecialEntrance(Entrance_GetOverride(nextEntranceIndex)); return Grotto_OverrideSpecialEntrance(Entrance_GetOverride(nextEntranceIndex));
} }
s16 Entrance_OverrideDynamicExit(s16 dynamicExitIndex) { s16 Entrance_OverrideDynamicExit(s16 dynamicExitIndex) {
Entrance_SetEntranceDiscovered(dynamicExitList[dynamicExitIndex]); Entrance_SetEntranceDiscovered(dynamicExitList[dynamicExitIndex], false);
EntranceTracker_SetLastEntranceOverride(dynamicExitList[dynamicExitIndex]); EntranceTracker_SetLastEntranceOverride(dynamicExitList[dynamicExitIndex]);
return Grotto_OverrideSpecialEntrance(Entrance_GetOverride(dynamicExitList[dynamicExitIndex])); return Grotto_OverrideSpecialEntrance(Entrance_GetOverride(dynamicExitList[dynamicExitIndex]));
} }
@@ -784,7 +784,7 @@ u8 Entrance_GetIsEntranceDiscovered(u16 entranceIndex) {
return 0; return 0;
} }
void Entrance_SetEntranceDiscovered(u16 entranceIndex) { void Entrance_SetEntranceDiscovered(u16 entranceIndex, u8 isReversedEntrance) {
// Skip if already set to save time from setting the connected entrance or // Skip if already set to save time from setting the connected entrance or
// if this entrance is outside of the randomized entrance range (i.e. is a dynamic entrance) // if this entrance is outside of the randomized entrance range (i.e. is a dynamic entrance)
if (entranceIndex > MAX_ENTRANCE_RANDO_USED_INDEX || Entrance_GetIsEntranceDiscovered(entranceIndex)) { if (entranceIndex > MAX_ENTRANCE_RANDO_USED_INDEX || Entrance_GetIsEntranceDiscovered(entranceIndex)) {
@@ -796,14 +796,20 @@ void Entrance_SetEntranceDiscovered(u16 entranceIndex) {
if (idx < SAVEFILE_ENTRANCES_DISCOVERED_IDX_COUNT) { if (idx < SAVEFILE_ENTRANCES_DISCOVERED_IDX_COUNT) {
u32 entranceBit = 1 << (entranceIndex - (idx * bitsPerIndex)); u32 entranceBit = 1 << (entranceIndex - (idx * bitsPerIndex));
gSaveContext.sohStats.entrancesDiscovered[idx] |= entranceBit; gSaveContext.sohStats.entrancesDiscovered[idx] |= entranceBit;
// Set connected
for (size_t i = 0; i < ENTRANCE_OVERRIDES_MAX_COUNT; i++) { // Set reverse entrance when not decoupled
if (entranceIndex == gSaveContext.entranceOverrides[i].index) { if (!Randomizer_GetSettingValue(RSK_DECOUPLED_ENTRANCES) && !isReversedEntrance) {
Entrance_SetEntranceDiscovered(gSaveContext.entranceOverrides[i].overrideDestination); for (size_t i = 0; i < ENTRANCE_OVERRIDES_MAX_COUNT; i++) {
break; if (entranceIndex == gSaveContext.entranceOverrides[i].index) {
Entrance_SetEntranceDiscovered(gSaveContext.entranceOverrides[i].overrideDestination, true);
break;
}
} }
} }
} }
// Save entrancesDiscovered
Save_SaveSection(SECTION_ID_ENTRANCES); // Save entrancesDiscovered when it is not the reversed entrance
if (!isReversedEntrance) {
Save_SaveSection(SECTION_ID_ENTRANCES);
}
} }
@@ -63,7 +63,7 @@ void Entrance_OverrideSpawnScene(int32_t sceneNum, int32_t spawn);
int32_t Entrance_OverrideSpawnSceneRoom(int32_t sceneNum, int32_t spawn, int32_t room); int32_t Entrance_OverrideSpawnSceneRoom(int32_t sceneNum, int32_t spawn, int32_t room);
void Entrance_EnableFW(void); void Entrance_EnableFW(void);
uint8_t Entrance_GetIsEntranceDiscovered(uint16_t entranceIndex); uint8_t Entrance_GetIsEntranceDiscovered(uint16_t entranceIndex);
void Entrance_SetEntranceDiscovered(uint16_t entranceIndex); void Entrance_SetEntranceDiscovered(uint16_t entranceIndex, uint8_t isReversedEntrance);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
@@ -140,7 +140,7 @@ s16 Grotto_OverrideSpecialEntrance(s16 nextEntranceIndex) {
// If Link hits a grotto exit, load the entrance index from the grotto exit list // If Link hits a grotto exit, load the entrance index from the grotto exit list
// based on the current grotto ID // based on the current grotto ID
if (nextEntranceIndex == 0x7FFF) { if (nextEntranceIndex == 0x7FFF) {
Entrance_SetEntranceDiscovered(ENTRANCE_RANDO_GROTTO_EXIT_START + grottoId); Entrance_SetEntranceDiscovered(ENTRANCE_RANDO_GROTTO_EXIT_START + grottoId, false);
EntranceTracker_SetLastEntranceOverride(ENTRANCE_RANDO_GROTTO_EXIT_START + grottoId); EntranceTracker_SetLastEntranceOverride(ENTRANCE_RANDO_GROTTO_EXIT_START + grottoId);
nextEntranceIndex = grottoExitList[grottoId]; nextEntranceIndex = grottoExitList[grottoId];
} }
@@ -211,7 +211,7 @@ void Grotto_OverrideActorEntrance(Actor* thisx) {
if (grottoContent == grottoLoadTable[index].content && gPlayState->sceneNum == grottoLoadTable[index].scene) { if (grottoContent == grottoLoadTable[index].content && gPlayState->sceneNum == grottoLoadTable[index].scene) {
// Find the override for the matching index from the grotto Load List // Find the override for the matching index from the grotto Load List
Entrance_SetEntranceDiscovered(ENTRANCE_RANDO_GROTTO_LOAD_START + index); Entrance_SetEntranceDiscovered(ENTRANCE_RANDO_GROTTO_LOAD_START + index, false);
EntranceTracker_SetLastEntranceOverride(ENTRANCE_RANDO_GROTTO_LOAD_START + index); EntranceTracker_SetLastEntranceOverride(ENTRANCE_RANDO_GROTTO_LOAD_START + index);
index = grottoLoadList[index]; index = grottoLoadList[index];
+155 -13
View File
@@ -49,6 +49,9 @@
#include "Fonts.h" #include "Fonts.h"
#include <Utils/StringHelper.h> #include <Utils/StringHelper.h>
#include "Enhancements/custom-message/CustomMessageManager.h" #include "Enhancements/custom-message/CustomMessageManager.h"
#include "Enhancements/presets.h"
#include "util.h"
#include <boost_custom/container_hash/hash_32.hpp>
#if not defined (__SWITCH__) && not defined(__WIIU__) #if not defined (__SWITCH__) && not defined(__WIIU__)
#include "Extractor/Extract.h" #include "Extractor/Extract.h"
@@ -115,6 +118,8 @@ CrowdControl* CrowdControl::Instance;
#include "soh/config/ConfigUpdaters.h" #include "soh/config/ConfigUpdaters.h"
void SoH_ProcessDroppedFiles(std::string filePath);
OTRGlobals* OTRGlobals::Instance; OTRGlobals* OTRGlobals::Instance;
SaveManager* SaveManager::Instance; SaveManager* SaveManager::Instance;
CustomMessageManager* CustomMessageManager::Instance; CustomMessageManager* CustomMessageManager::Instance;
@@ -253,15 +258,26 @@ OTRGlobals::OTRGlobals() {
OTRFiles.push_back(sohOtrPath); OTRFiles.push_back(sohOtrPath);
} }
std::string patchesPath = LUS::Context::LocateFileAcrossAppDirs("mods", appShortName); std::string patchesPath = LUS::Context::LocateFileAcrossAppDirs("mods", appShortName);
std::vector<std::string> patchOTRs = {};
if (patchesPath.length() > 0 && std::filesystem::exists(patchesPath)) { if (patchesPath.length() > 0 && std::filesystem::exists(patchesPath)) {
if (std::filesystem::is_directory(patchesPath)) { if (std::filesystem::is_directory(patchesPath)) {
for (const auto& p : std::filesystem::recursive_directory_iterator(patchesPath)) { for (const auto& p : std::filesystem::recursive_directory_iterator(patchesPath, std::filesystem::directory_options::follow_directory_symlink)) {
if (StringHelper::IEquals(p.path().extension().string(), ".otr")) { if (StringHelper::IEquals(p.path().extension().string(), ".otr")) {
OTRFiles.push_back(p.path().generic_string()); patchOTRs.push_back(p.path().generic_string());
} }
} }
} }
} }
std::sort(patchOTRs.begin(), patchOTRs.end(), [](const std::string& a, const std::string& b) {
return std::lexicographical_compare(
a.begin(), a.end(),
b.begin(), b.end(),
[](char c1, char c2) {
return std::tolower(c1) < std::tolower(c2);
}
);
});
OTRFiles.insert(OTRFiles.end(), patchOTRs.begin(), patchOTRs.end());
std::unordered_set<uint32_t> ValidHashes = { std::unordered_set<uint32_t> ValidHashes = {
OOT_PAL_MQ, OOT_PAL_MQ,
OOT_NTSC_JP_MQ, OOT_NTSC_JP_MQ,
@@ -1021,9 +1037,9 @@ extern "C" void InitOTR() {
OTRGlobals::Instance = new OTRGlobals(); OTRGlobals::Instance = new OTRGlobals();
CustomMessageManager::Instance = new CustomMessageManager(); CustomMessageManager::Instance = new CustomMessageManager();
ItemTableManager::Instance = new ItemTableManager(); ItemTableManager::Instance = new ItemTableManager();
GameInteractor::Instance = new GameInteractor();
SaveManager::Instance = new SaveManager(); SaveManager::Instance = new SaveManager();
SohGui::SetupGuiElements(); SohGui::SetupGuiElements();
GameInteractor::Instance = new GameInteractor();
AudioCollection::Instance = new AudioCollection(); AudioCollection::Instance = new AudioCollection();
ActorDB::Instance = new ActorDB(); ActorDB::Instance = new ActorDB();
#ifdef __APPLE__ #ifdef __APPLE__
@@ -1043,6 +1059,11 @@ extern "C" void InitOTR() {
InitMods(); InitMods();
ActorDB::AddBuiltInCustomActors(); ActorDB::AddBuiltInCustomActors();
// #region SOH [Randomizer] TODO: Remove these and refactor spoiler file handling for randomizer
CVarClear("gRandomizerNewFileDropped");
CVarClear("gRandomizerDroppedFile");
// #endregion
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnFileDropped>(SoH_ProcessDroppedFiles);
time_t now = time(NULL); time_t now = time(NULL);
tm *tm_now = localtime(&now); tm *tm_now = localtime(&now);
@@ -1131,7 +1152,7 @@ extern "C" void Graph_ProcessFrame(void (*run_one_game_iter)(void)) {
OTRGlobals::Instance->context->GetWindow()->MainLoop(run_one_game_iter); OTRGlobals::Instance->context->GetWindow()->MainLoop(run_one_game_iter);
} }
extern bool ShouldClearTextureCacheAtEndOfFrame; extern bool ToggleAltAssetsAtEndOfFrame;
extern "C" void Graph_StartFrame() { extern "C" void Graph_StartFrame() {
#ifndef __WIIU__ #ifndef __WIIU__
@@ -1214,13 +1235,21 @@ extern "C" void Graph_StartFrame() {
} }
#endif #endif
case KbScancode::LUS_KB_TAB: { case KbScancode::LUS_KB_TAB: {
// Toggle HD Assets ToggleAltAssetsAtEndOfFrame = true;
CVarSetInteger("gAltAssets", !CVarGetInteger("gAltAssets", 0));
ShouldClearTextureCacheAtEndOfFrame = true;
break; break;
} }
} }
#endif #endif
if (CVarGetInteger("gNewFileDropped", 0)) {
std::string filePath = SohUtils::Sanitize(CVarGetString("gDroppedFile", ""));
if (!filePath.empty()) {
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnFileDropped>(filePath);
}
CVarClear("gNewFileDropped");
CVarClear("gDroppedFile");
}
OTRGlobals::Instance->context->GetWindow()->StartFrame(); OTRGlobals::Instance->context->GetWindow()->StartFrame();
} }
@@ -1286,10 +1315,14 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) {
} }
} }
if (ShouldClearTextureCacheAtEndOfFrame) { if (ToggleAltAssetsAtEndOfFrame) {
ToggleAltAssetsAtEndOfFrame = false;
// Actually update the CVar now before runing the alt asset update listeners
CVarSetInteger("gAltAssets", !CVarGetInteger("gAltAssets", 0));
gfx_texture_cache_clear(); gfx_texture_cache_clear();
LUS::SkeletonPatcher::UpdateSkeletons(); LUS::SkeletonPatcher::UpdateSkeletons();
ShouldClearTextureCacheAtEndOfFrame = false; GameInteractor::Instance->ExecuteHooks<GameInteractor::OnAssetAltChange>();
} }
// OTRTODO: FIGURE OUT END FRAME POINT // OTRTODO: FIGURE OUT END FRAME POINT
@@ -1415,6 +1448,14 @@ extern "C" void ResourceMgr_DirtyDirectory(const char* resName) {
LUS::Context::GetInstance()->GetResourceManager()->DirtyDirectory(resName); LUS::Context::GetInstance()->GetResourceManager()->DirtyDirectory(resName);
} }
extern "C" void ResourceMgr_UnloadResource(const char* resName) {
std::string path = resName;
if (path.substr(0, 7) == "__OTR__") {
path = path.substr(7);
}
auto res = LUS::Context::GetInstance()->GetResourceManager()->UnloadResource(path);
}
// OTRTODO: There is probably a more elegant way to go about this... // OTRTODO: There is probably a more elegant way to go about this...
// Kenix: This is definitely leaking memory when it's called. // Kenix: This is definitely leaking memory when it's called.
extern "C" char** ResourceMgr_ListFiles(const char* searchMask, int* resultSize) { extern "C" char** ResourceMgr_ListFiles(const char* searchMask, int* resultSize) {
@@ -1441,6 +1482,27 @@ extern "C" uint8_t ResourceMgr_FileExists(const char* filePath) {
return ExtensionCache.contains(path); return ExtensionCache.contains(path);
} }
extern "C" uint8_t ResourceMgr_FileAltExists(const char* filePath) {
std::string path = filePath;
if (path.substr(0, 7) == "__OTR__") {
path = path.substr(7);
}
if (path.substr(0, 4) != "alt/") {
path = "alt/" + path;
}
return ExtensionCache.contains(path);
}
// Unloads a resource if an alternate version exists when alt assets are enabled
// The resource is only removed from the internal cache to prevent it from used in the next resource lookup
extern "C" void ResourceMgr_UnloadOriginalWhenAltExists(const char* resName) {
if (CVarGetInteger("gAltAssets", 0) && ResourceMgr_FileAltExists((char*) resName)) {
ResourceMgr_UnloadResource((char*) resName);
}
}
extern "C" void ResourceMgr_LoadFile(const char* resName) { extern "C" void ResourceMgr_LoadFile(const char* resName) {
LUS::Context::GetInstance()->GetResourceManager()->LoadResource(resName); LUS::Context::GetInstance()->GetResourceManager()->LoadResource(resName);
} }
@@ -1480,6 +1542,11 @@ extern "C" char* ResourceMgr_LoadFileFromDisk(const char* filePath) {
return data; return data;
} }
extern "C" uint8_t ResourceMgr_TexIsRaw(const char* texPath) {
auto res = std::static_pointer_cast<LUS::Texture>(GetResourceByNameHandlingMQ(texPath));
return res->Flags & TEX_FLAG_LOAD_AS_RAW;
}
extern "C" uint8_t ResourceMgr_ResourceIsBackground(char* texPath) { extern "C" uint8_t ResourceMgr_ResourceIsBackground(char* texPath) {
auto res = GetResourceByNameHandlingMQ(texPath); auto res = GetResourceByNameHandlingMQ(texPath);
return res->GetInitData()->Type == LUS::ResourceType::SOH_Background; return res->GetInitData()->Type == LUS::ResourceType::SOH_Background;
@@ -1565,6 +1632,11 @@ extern "C" void ResourceMgr_PushCurrentDirectory(char* path)
extern "C" Gfx* ResourceMgr_LoadGfxByName(const char* path) extern "C" Gfx* ResourceMgr_LoadGfxByName(const char* path)
{ {
// When an alt resource exists for the DL, we need to unload the original asset
// to clear the cache so the alt asset will be loaded instead
// OTRTODO: If Alt loading over original cache is fixed, this line can most likely be removed
ResourceMgr_UnloadOriginalWhenAltExists(path);
auto res = std::static_pointer_cast<LUS::DisplayList>(GetResourceByNameHandlingMQ(path)); auto res = std::static_pointer_cast<LUS::DisplayList>(GetResourceByNameHandlingMQ(path));
return (Gfx*)&res->Instructions[0]; return (Gfx*)&res->Instructions[0];
} }
@@ -2045,10 +2117,10 @@ Color_RGB8 GetColorForControllerLED() {
if (source == LED_SOURCE_CUSTOM) { if (source == LED_SOURCE_CUSTOM) {
color = CVarGetColor24("gLedPort1Color", { 255, 255, 255 }); color = CVarGetColor24("gLedPort1Color", { 255, 255, 255 });
} }
if (criticalOverride || source == LED_SOURCE_HEALTH) { if (gPlayState && (criticalOverride || source == LED_SOURCE_HEALTH)) {
if (HealthMeter_IsCritical()) { if (HealthMeter_IsCritical()) {
color = { 0xFF, 0, 0 }; color = { 0xFF, 0, 0 };
} else if (source == LED_SOURCE_HEALTH) { } else if (gSaveContext.healthCapacity != 0 && source == LED_SOURCE_HEALTH) {
if (gSaveContext.health / gSaveContext.healthCapacity <= 0.4f) { if (gSaveContext.health / gSaveContext.healthCapacity <= 0.4f) {
color = { 0xFF, 0xFF, 0 }; color = { 0xFF, 0xFF, 0 };
} else { } else {
@@ -2434,6 +2506,8 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) {
messageEntry = OTRGlobals::Instance->gRandomizer->GetWarpSongMessage(textId, Randomizer_GetSettingValue(RSK_WARP_SONG_HINTS) == RO_GENERIC_OFF); messageEntry = OTRGlobals::Instance->gRandomizer->GetWarpSongMessage(textId, Randomizer_GetSettingValue(RSK_WARP_SONG_HINTS) == RO_GENERIC_OFF);
} else if (textId == TEXT_LAKE_HYLIA_WATER_SWITCH_NAVI || textId == TEXT_LAKE_HYLIA_WATER_SWITCH_SIGN) { } else if (textId == TEXT_LAKE_HYLIA_WATER_SWITCH_NAVI || textId == TEXT_LAKE_HYLIA_WATER_SWITCH_SIGN) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, textId); messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, textId);
} else if (textId == TEXT_SHOOTING_GALLERY_MAN_COME_BACK_WITH_BOW) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, TEXT_SHOOTING_GALLERY_MAN_COME_BACK_WITH_BOW);
} else if (textId == 0x3052 || (textId >= 0x3069 && textId <= 0x3070)) { //Fire Temple gorons } else if (textId == 0x3052 || (textId >= 0x3069 && textId <= 0x3070)) { //Fire Temple gorons
u16 choice = Random(0, NUM_GORON_MESSAGES); u16 choice = Random(0, NUM_GORON_MESSAGES);
messageEntry = OTRGlobals::Instance->gRandomizer->GetGoronMessage(choice); messageEntry = OTRGlobals::Instance->gRandomizer->GetGoronMessage(choice);
@@ -2523,6 +2597,74 @@ extern "C" void Gfx_RegisterBlendedTexture(const char* name, u8* mask, u8* repla
gfx_register_blended_texture(name, mask, replacement); gfx_register_blended_texture(name, mask, replacement);
} }
extern "C" void CheckTracker_OnMessageClose() { void SoH_ProcessDroppedFiles(std::string filePath) {
CheckTracker::CheckTrackerDialogClosed(); try {
std::ifstream configStream(filePath);
if (!configStream) {
return;
}
nlohmann::json configJson;
configStream >> configJson;
// #region SOH [Randomizer] TODO: Refactor spoiler file handling for randomizer
if (configJson.contains("version") && configJson.contains("finalSeed")) {
CVarSetString("gRandomizerDroppedFile", filePath.c_str());
CVarSetInteger("gRandomizerNewFileDropped", 1);
return;
}
// #endregion
if (!configJson.contains("CVars")) {
return;
}
clearCvars(enhancementsCvars);
clearCvars(cheatCvars);
clearCvars(randomizerCvars);
// Flatten everything under CVars into a single array
auto cvars = configJson["CVars"].flatten();
for (auto& [key, value] : cvars.items()) {
// Replace slashes with dots in key, and remove leading dot
std::string path = key;
std::replace(path.begin(), path.end(), '/', '.');
if (path[0] == '.') {
path.erase(0, 1);
}
if (value.is_string()) {
CVarSetString(path.c_str(), value.get<std::string>().c_str());
} else if (value.is_number_integer()) {
CVarSetInteger(path.c_str(), value.get<int>());
} else if (value.is_number_float()) {
CVarSetFloat(path.c_str(), value.get<float>());
}
}
auto gui = LUS::Context::GetInstance()->GetWindow()->GetGui();
gui->GetGuiWindow("Console")->Hide();
gui->GetGuiWindow("Actor Viewer")->Hide();
gui->GetGuiWindow("Collision Viewer")->Hide();
gui->GetGuiWindow("Save Editor")->Hide();
gui->GetGuiWindow("Display List Viewer")->Hide();
gui->GetGuiWindow("Stats")->Hide();
std::dynamic_pointer_cast<LUS::ConsoleWindow>(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Console"))->ClearBindings();
gui->SaveConsoleVariablesOnNextTick();
uint32_t finalHash = boost::hash_32<std::string>{}(configJson.dump());
gui->GetGameOverlay()->TextDrawNotification(30.0f, true, "Configuration Loaded. Hash: %d", finalHash);
} catch (std::exception& e) {
SPDLOG_ERROR("Failed to load config file: {}", e.what());
auto gui = LUS::Context::GetInstance()->GetWindow()->GetGui();
gui->GetGameOverlay()->TextDrawNotification(30.0f, true, "Failed to load config file");
return;
} catch (...) {
SPDLOG_ERROR("Failed to load config file");
auto gui = LUS::Context::GetInstance()->GetWindow()->GetGui();
gui->GetGameOverlay()->TextDrawNotification(30.0f, true, "Failed to load config file");
return;
}
} }
// #endregion
+4
View File
@@ -86,11 +86,15 @@ uint32_t ResourceMgr_GetGameVersion(int index);
uint32_t ResourceMgr_GetGamePlatform(int index); uint32_t ResourceMgr_GetGamePlatform(int index);
uint32_t ResourceMgr_GetGameRegion(int index); uint32_t ResourceMgr_GetGameRegion(int index);
void ResourceMgr_LoadDirectory(const char* resName); void ResourceMgr_LoadDirectory(const char* resName);
void ResourceMgr_UnloadResource(const char* resName);
char** ResourceMgr_ListFiles(const char* searchMask, int* resultSize); char** ResourceMgr_ListFiles(const char* searchMask, int* resultSize);
uint8_t ResourceMgr_FileExists(const char* resName); uint8_t ResourceMgr_FileExists(const char* resName);
uint8_t ResourceMgr_FileAltExists(const char* resName);
void ResourceMgr_UnloadOriginalWhenAltExists(const char* resName);
char* GetResourceDataByNameHandlingMQ(const char* path); char* GetResourceDataByNameHandlingMQ(const char* path);
void ResourceMgr_LoadFile(const char* resName); void ResourceMgr_LoadFile(const char* resName);
char* ResourceMgr_LoadFileFromDisk(const char* filePath); char* ResourceMgr_LoadFileFromDisk(const char* filePath);
uint8_t ResourceMgr_TexIsRaw(const char* texPath);
uint8_t ResourceMgr_ResourceIsBackground(char* texPath); uint8_t ResourceMgr_ResourceIsBackground(char* texPath);
char* ResourceMgr_LoadJPEG(char* data, size_t dataSize); char* ResourceMgr_LoadJPEG(char* data, size_t dataSize);
uint16_t ResourceMgr_LoadTexWidthByName(char* texPath); uint16_t ResourceMgr_LoadTexWidthByName(char* texPath);
+1 -1
View File
@@ -38,7 +38,7 @@
#include "Enhancements/game-interactor/GameInteractor.h" #include "Enhancements/game-interactor/GameInteractor.h"
#include "Enhancements/cosmetics/authenticGfxPatches.h" #include "Enhancements/cosmetics/authenticGfxPatches.h"
bool ShouldClearTextureCacheAtEndOfFrame = false; bool ToggleAltAssetsAtEndOfFrame = false;
bool isBetaQuestEnabled = false; bool isBetaQuestEnabled = false;
extern "C" { extern "C" {
+22 -4
View File
@@ -28,7 +28,7 @@
#include "Enhancements/randomizer/randomizer_item_tracker.h" #include "Enhancements/randomizer/randomizer_item_tracker.h"
#include "Enhancements/randomizer/randomizer_settings_window.h" #include "Enhancements/randomizer/randomizer_settings_window.h"
extern bool ShouldClearTextureCacheAtEndOfFrame; extern bool ToggleAltAssetsAtEndOfFrame;
extern bool isBetaQuestEnabled; extern bool isBetaQuestEnabled;
extern "C" PlayState* gPlayState; extern "C" PlayState* gPlayState;
@@ -492,6 +492,8 @@ extern std::shared_ptr<GameplayStatsWindow> mGameplayStatsWindow;
void DrawEnhancementsMenu() { void DrawEnhancementsMenu() {
if (ImGui::BeginMenu("Enhancements")) if (ImGui::BeginMenu("Enhancements"))
{ {
ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0));
DrawPresetSelector(PRESET_TYPE_ENHANCEMENTS); DrawPresetSelector(PRESET_TYPE_ENHANCEMENTS);
UIWidgets::PaddedSeparator(); UIWidgets::PaddedSeparator();
@@ -605,7 +607,7 @@ void DrawEnhancementsMenu() {
UIWidgets::PaddedEnhancementCheckbox("Nuts explode bombs", "gNutsExplodeBombs", true, false); UIWidgets::PaddedEnhancementCheckbox("Nuts explode bombs", "gNutsExplodeBombs", true, false);
UIWidgets::Tooltip("Makes nuts explode bombs, similar to how they interact with bombchus. This does not affect bombflowers."); UIWidgets::Tooltip("Makes nuts explode bombs, similar to how they interact with bombchus. This does not affect bombflowers.");
UIWidgets::PaddedEnhancementCheckbox("Equip Multiple Arrows at Once", "gSeparateArrows", true, false); UIWidgets::PaddedEnhancementCheckbox("Equip Multiple Arrows at Once", "gSeparateArrows", true, false);
UIWidgets::Tooltip("Allow the bow and magic arrows to be equipped at the same time on different slots"); UIWidgets::Tooltip("Allow the bow and magic arrows to be equipped at the same time on different slots. (Note this will disable the behaviour of the 'Equip Dupe' glitch)");
UIWidgets::PaddedEnhancementCheckbox("Bow as Child/Slingshot as Adult", "gBowSlingShotAmmoFix", true, false); UIWidgets::PaddedEnhancementCheckbox("Bow as Child/Slingshot as Adult", "gBowSlingShotAmmoFix", true, false);
UIWidgets::Tooltip("Allows child to use bow with arrows.\nAllows adult to use slingshot with seeds.\n\nRequires glitches or 'Timeless Equipment' cheat to equip."); UIWidgets::Tooltip("Allows child to use bow with arrows.\nAllows adult to use slingshot with seeds.\n\nRequires glitches or 'Timeless Equipment' cheat to equip.");
UIWidgets::PaddedEnhancementCheckbox("Better Farore's Wind", "gBetterFW", true, false); UIWidgets::PaddedEnhancementCheckbox("Better Farore's Wind", "gBetterFW", true, false);
@@ -906,7 +908,10 @@ void DrawEnhancementsMenu() {
{ {
if (ImGui::BeginMenu("Mods")) { if (ImGui::BeginMenu("Mods")) {
if (UIWidgets::PaddedEnhancementCheckbox("Use Alternate Assets", "gAltAssets", false, false)) { if (UIWidgets::PaddedEnhancementCheckbox("Use Alternate Assets", "gAltAssets", false, false)) {
ShouldClearTextureCacheAtEndOfFrame = true; // The checkbox will flip the alt asset CVar, but we instead want it to change at the end of the game frame
// We toggle it back while setting the flag to update the CVar later
CVarSetInteger("gAltAssets", !CVarGetInteger("gAltAssets", 0));
ToggleAltAssetsAtEndOfFrame = true;
} }
UIWidgets::Tooltip("Toggle between standard assets and alternate assets. Usually mods will indicate if this setting has to be used or not."); UIWidgets::Tooltip("Toggle between standard assets and alternate assets. Usually mods will indicate if this setting has to be used or not.");
UIWidgets::PaddedEnhancementCheckbox("Disable Bomb Billboarding", "gDisableBombBillboarding", true, false); UIWidgets::PaddedEnhancementCheckbox("Disable Bomb Billboarding", "gDisableBombBillboarding", true, false);
@@ -1063,6 +1068,9 @@ void DrawEnhancementsMenu() {
UIWidgets::Tooltip("Prevents immediately falling off climbable surfaces if climbing on the edges."); UIWidgets::Tooltip("Prevents immediately falling off climbable surfaces if climbing on the edges.");
UIWidgets::PaddedEnhancementCheckbox("Fix Link's eyes open while sleeping", "gFixEyesOpenWhileSleeping", true, false); UIWidgets::PaddedEnhancementCheckbox("Fix Link's eyes open while sleeping", "gFixEyesOpenWhileSleeping", true, false);
UIWidgets::Tooltip("Fixes Link's eyes being open in the opening cutscene when he is supposed to be sleeping."); UIWidgets::Tooltip("Fixes Link's eyes being open in the opening cutscene when he is supposed to be sleeping.");
UIWidgets::PaddedEnhancementCheckbox("Fix Darunia dancing too fast", "gEnhancements.FixDaruniaDanceSpeed",
true, false, false, "", UIWidgets::CheckboxGraphics::Cross, true);
UIWidgets::Tooltip("Fixes Darunia's dancing speed so he dances to the beat of Saria's Song, like in vanilla.");
ImGui::EndMenu(); ImGui::EndMenu();
} }
@@ -1198,6 +1206,8 @@ void DrawEnhancementsMenu() {
UIWidgets::PaddedSeparator(true, true, 2.0f, 2.0f); UIWidgets::PaddedSeparator(true, true, 2.0f, 2.0f);
ImGui::EndDisabled();
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 6.0f)); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 6.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0, 0)); ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0, 0));
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
@@ -1239,6 +1249,8 @@ void DrawEnhancementsMenu() {
void DrawCheatsMenu() { void DrawCheatsMenu() {
if (ImGui::BeginMenu("Cheats")) if (ImGui::BeginMenu("Cheats"))
{ {
ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0));
if (ImGui::BeginMenu("Infinite...")) { if (ImGui::BeginMenu("Infinite...")) {
UIWidgets::EnhancementCheckbox("Money", "gInfiniteMoney"); UIWidgets::EnhancementCheckbox("Money", "gInfiniteMoney");
UIWidgets::PaddedEnhancementCheckbox("Health", "gInfiniteHealth", true, false); UIWidgets::PaddedEnhancementCheckbox("Health", "gInfiniteHealth", true, false);
@@ -1393,6 +1405,8 @@ void DrawCheatsMenu() {
} }
UIWidgets::Tooltip("Clears the cutscene pointer to a value safe for wrong warps."); UIWidgets::Tooltip("Clears the cutscene pointer to a value safe for wrong warps.");
ImGui::EndDisabled();
ImGui::EndMenu(); ImGui::EndMenu();
} }
} }
@@ -1406,6 +1420,8 @@ extern std::shared_ptr<DLViewerWindow> mDLViewerWindow;
void DrawDeveloperToolsMenu() { void DrawDeveloperToolsMenu() {
if (ImGui::BeginMenu("Developer Tools")) { if (ImGui::BeginMenu("Developer Tools")) {
ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0));
UIWidgets::EnhancementCheckbox("OoT Debug Mode", "gDebugEnabled"); UIWidgets::EnhancementCheckbox("OoT Debug Mode", "gDebugEnabled");
UIWidgets::Tooltip("Enables Debug Mode, allowing you to select maps with L + R + Z, noclip with L + D-pad Right, and open the debug menu with L on the pause screen"); UIWidgets::Tooltip("Enables Debug Mode, allowing you to select maps with L + R + Z, noclip with L + D-pad Right, and open the debug menu with L on the pause screen");
if (CVarGetInteger("gDebugEnabled", 0)) { if (CVarGetInteger("gDebugEnabled", 0)) {
@@ -1478,6 +1494,8 @@ void DrawDeveloperToolsMenu() {
ImGui::PopStyleVar(3); ImGui::PopStyleVar(3);
ImGui::PopStyleColor(1); ImGui::PopStyleColor(1);
ImGui::EndDisabled();
ImGui::EndMenu(); ImGui::EndMenu();
} }
} }
@@ -1626,4 +1644,4 @@ void SohMenuBar::DrawElement() {
ImGui::EndMenuBar(); ImGui::EndMenuBar();
} }
} }
} // namespace SohGui } // namespace SohGui
@@ -132,15 +132,15 @@ void LUS::SkeletonLimbFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> r
skeletonLimb->limbData.lodLimb.sibling = skeletonLimb->siblingIndex; skeletonLimb->limbData.lodLimb.sibling = skeletonLimb->siblingIndex;
if (skeletonLimb->dListPtr != "") { if (skeletonLimb->dListPtr != "") {
auto dList = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(skeletonLimb->dListPtr.c_str()); skeletonLimb->dListPtr = "__OTR__" + skeletonLimb->dListPtr;
skeletonLimb->limbData.lodLimb.dLists[0] = (Gfx*)(dList ? dList->GetRawPointer() : nullptr); skeletonLimb->limbData.lodLimb.dLists[0] = (Gfx*)skeletonLimb->dListPtr.c_str();
} else { } else {
skeletonLimb->limbData.lodLimb.dLists[0] = nullptr; skeletonLimb->limbData.lodLimb.dLists[0] = nullptr;
} }
if (skeletonLimb->dList2Ptr != "") { if (skeletonLimb->dList2Ptr != "") {
auto dList = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(skeletonLimb->dList2Ptr.c_str()); skeletonLimb->dList2Ptr = "__OTR__" + skeletonLimb->dList2Ptr;
skeletonLimb->limbData.lodLimb.dLists[1] = (Gfx*)(dList ? dList->GetRawPointer() : nullptr); skeletonLimb->limbData.lodLimb.dLists[1] = (Gfx*)skeletonLimb->dList2Ptr.c_str();
} else { } else {
skeletonLimb->limbData.lodLimb.dLists[1] = nullptr; skeletonLimb->limbData.lodLimb.dLists[1] = nullptr;
} }
@@ -153,8 +153,8 @@ void LUS::SkeletonLimbFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> r
skeletonLimb->limbData.standardLimb.dList = nullptr; skeletonLimb->limbData.standardLimb.dList = nullptr;
if (!skeletonLimb->dListPtr.empty()) { if (!skeletonLimb->dListPtr.empty()) {
const auto dList = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(skeletonLimb->dListPtr.c_str()); skeletonLimb->dListPtr = "__OTR__" + skeletonLimb->dListPtr;
skeletonLimb->limbData.standardLimb.dList = (Gfx*)(dList ? dList->GetRawPointer() : nullptr); skeletonLimb->limbData.standardLimb.dList = (Gfx*)skeletonLimb->dListPtr.c_str();
} }
} else if (skeletonLimb->limbType == LUS::LimbType::Curve) { } else if (skeletonLimb->limbType == LUS::LimbType::Curve) {
skeletonLimb->limbData.skelCurveLimb.firstChildIdx = skeletonLimb->childIndex; skeletonLimb->limbData.skelCurveLimb.firstChildIdx = skeletonLimb->childIndex;
@@ -163,13 +163,13 @@ void LUS::SkeletonLimbFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> r
skeletonLimb->limbData.skelCurveLimb.dList[1] = nullptr; skeletonLimb->limbData.skelCurveLimb.dList[1] = nullptr;
if (!skeletonLimb->dListPtr.empty()) { if (!skeletonLimb->dListPtr.empty()) {
const auto dList = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(skeletonLimb->dListPtr.c_str()); skeletonLimb->dListPtr = "__OTR__" + skeletonLimb->dListPtr;
skeletonLimb->limbData.skelCurveLimb.dList[0] = (Gfx*)(dList ? dList->GetRawPointer() : nullptr); skeletonLimb->limbData.skelCurveLimb.dList[0] = (Gfx*)skeletonLimb->dListPtr.c_str();
} }
if (!skeletonLimb->dList2Ptr.empty()) { if (!skeletonLimb->dList2Ptr.empty()) {
const auto dList = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(skeletonLimb->dList2Ptr.c_str()); skeletonLimb->dList2Ptr = "__OTR__" + skeletonLimb->dList2Ptr;
skeletonLimb->limbData.skelCurveLimb.dList[1] = (Gfx*)(dList ? dList->GetRawPointer() : nullptr); skeletonLimb->limbData.skelCurveLimb.dList[1] = (Gfx*)skeletonLimb->dList2Ptr.c_str();
} }
} else if (skeletonLimb->limbType == LUS::LimbType::Skin) { } else if (skeletonLimb->limbType == LUS::LimbType::Skin) {
skeletonLimb->limbData.skinLimb.jointPos.x = skeletonLimb->transX; skeletonLimb->limbData.skinLimb.jointPos.x = skeletonLimb->transX;
@@ -189,14 +189,23 @@ void LUS::SkeletonLimbFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> r
} }
if (skeletonLimb->skinSegmentType == LUS::ZLimbSkinType::SkinType_DList) { if (skeletonLimb->skinSegmentType == LUS::ZLimbSkinType::SkinType_DList) {
auto res = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(skeletonLimb->skinDList.c_str()); if (skeletonLimb->skinDList != "") {
skeletonLimb->limbData.skinLimb.segment = res ? res->GetRawPointer() : nullptr; skeletonLimb->skinDList = "__OTR__" + skeletonLimb->skinDList;
skeletonLimb->limbData.skinLimb.segment = (Gfx*)skeletonLimb->skinDList.c_str();
} else {
skeletonLimb->limbData.skinLimb.segment = nullptr;
}
} else if (skeletonLimb->skinSegmentType == LUS::ZLimbSkinType::SkinType_4) { } else if (skeletonLimb->skinSegmentType == LUS::ZLimbSkinType::SkinType_4) {
skeletonLimb->skinAnimLimbData.totalVtxCount = skeletonLimb->skinVtxCnt; skeletonLimb->skinAnimLimbData.totalVtxCount = skeletonLimb->skinVtxCnt;
skeletonLimb->skinAnimLimbData.limbModifCount = skeletonLimb->skinLimbModifCount; skeletonLimb->skinAnimLimbData.limbModifCount = skeletonLimb->skinLimbModifCount;
skeletonLimb->skinAnimLimbData.limbModifications = skeletonLimb->skinLimbModifArray.data(); skeletonLimb->skinAnimLimbData.limbModifications = skeletonLimb->skinLimbModifArray.data();
auto res = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(skeletonLimb->skinDList2.c_str());
skeletonLimb->skinAnimLimbData.dlist = (Gfx*)(res ? res->GetRawPointer() : nullptr); if (skeletonLimb->skinDList2 != "") {
skeletonLimb->skinDList2 = "__OTR__" + skeletonLimb->skinDList2;
skeletonLimb->skinAnimLimbData.dlist = (Gfx*)skeletonLimb->skinDList2.c_str();
} else {
skeletonLimb->skinAnimLimbData.dlist = nullptr;
}
for (size_t i = 0; i < skeletonLimb->skinLimbModifArray.size(); i++) { for (size_t i = 0; i < skeletonLimb->skinLimbModifArray.size(); i++) {
skeletonLimb->skinAnimLimbData.limbModifications[i].vtxCount = skeletonLimb->skinLimbModifVertexArrays[i].size(); skeletonLimb->skinAnimLimbData.limbModifications[i].vtxCount = skeletonLimb->skinLimbModifVertexArrays[i].size();
@@ -254,8 +263,8 @@ void SkeletonLimbFactoryV0::ParseFileXML(tinyxml2::XMLElement* reader, std::shar
limbData.lodLimb.jointPos.z = skelLimb->transZ; limbData.lodLimb.jointPos.z = skelLimb->transZ;
if (skelLimb->dListPtr != "") { if (skelLimb->dListPtr != "") {
auto res = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess((const char*)skelLimb->dListPtr.c_str()); skelLimb->dListPtr = "__OTR__" + skelLimb->dListPtr;
limbData.lodLimb.dLists[0] = (Gfx*)(res ? res->GetRawPointer() : nullptr); limbData.lodLimb.dLists[0] = (Gfx*)skelLimb->dListPtr.c_str();
} else { } else {
limbData.lodLimb.dLists[0] = nullptr; limbData.lodLimb.dLists[0] = nullptr;
} }
+1 -1
View File
@@ -260,7 +260,7 @@ void Audio_osWritebackDCache(void* mem, s32 size)
s32 osAiSetFrequency(u32 freq) s32 osAiSetFrequency(u32 freq)
{ {
return 1;
} }
s32 osEPiStartDma(OSPiHandle* handle, OSIoMesg* mb, s32 direction) s32 osEPiStartDma(OSPiHandle* handle, OSIoMesg* mb, s32 direction)
+18
View File
@@ -2,6 +2,7 @@
#include <string.h> #include <string.h>
#include <vector> #include <vector>
#include <algorithm>
std::vector<std::string> sceneNames = { std::vector<std::string> sceneNames = {
"Inside the Deku Tree", "Inside the Deku Tree",
@@ -318,3 +319,20 @@ void SohUtils::CopyStringToCharArray(char* destination, std::string source, size
strncpy(destination, source.c_str(), size - 1); strncpy(destination, source.c_str(), size - 1);
destination[size - 1] = '\0'; destination[size - 1] = '\0';
} }
std::string SohUtils::Sanitize(std::string stringValue) {
// Add backslashes.
for (auto i = stringValue.begin();;) {
auto const pos = std::find_if(i, stringValue.end(), [](char const c) { return '\\' == c || '\'' == c || '"' == c; });
if (pos == stringValue.end()) {
break;
}
i = std::next(stringValue.insert(pos, '\\'), 2);
}
// Removes others.
stringValue.erase(std::remove_if(stringValue.begin(), stringValue.end(), [](char const c) {
return '\n' == c || '\r' == c || '\0' == c || '\x1A' == c; }), stringValue.end());
return stringValue;
}
+2
View File
@@ -12,4 +12,6 @@ namespace SohUtils {
// Copies a string and ensures the destination is null terminated if the source string is larger than size // Copies a string and ensures the destination is null terminated if the source string is larger than size
// Only up to size-1 characters are copied from the source string // Only up to size-1 characters are copied from the source string
void CopyStringToCharArray(char* destination, std::string source, size_t size); void CopyStringToCharArray(char* destination, std::string source, size_t size);
std::string Sanitize(std::string stringValue);
} // namespace SohUtils } // namespace SohUtils
+6
View File
@@ -72,6 +72,9 @@ MessageTableEntry* OTRMessage_LoadTable(const char* filePath, bool isNES) {
_message_0xFFFC_nes = (char*)file->messages[i].msg.c_str(); _message_0xFFFC_nes = (char*)file->messages[i].msg.c_str();
} }
// Assert that the first message starts at the first text ID
assert(table[0].textId == 0x0001);
return table; return table;
} }
@@ -104,6 +107,9 @@ extern "C" void OTRMessage_Init()
sStaffMessageEntryTablePtr[i].segment = file2->messages[i].msg.c_str(); sStaffMessageEntryTablePtr[i].segment = file2->messages[i].msg.c_str();
sStaffMessageEntryTablePtr[i].msgSize = file2->messages[i].msg.size(); sStaffMessageEntryTablePtr[i].msgSize = file2->messages[i].msg.size();
} }
// Assert staff credits start at the first credits ID
assert(sStaffMessageEntryTablePtr[0].textId == 0x0500);
} }
CustomMessageManager::Instance->AddCustomMessageTable(customMessageTableID); CustomMessageManager::Instance->AddCustomMessageTable(customMessageTableID);
+1 -1
View File
@@ -3384,7 +3384,7 @@ void Message_Update(PlayState* play) {
} }
sLastPlayedSong = 0xFF; sLastPlayedSong = 0xFF;
osSyncPrintf("OCARINA_MODE=%d chk_ocarina_no=%d\n", play->msgCtx.ocarinaMode, msgCtx->unk_E3F2); osSyncPrintf("OCARINA_MODE=%d chk_ocarina_no=%d\n", play->msgCtx.ocarinaMode, msgCtx->unk_E3F2);
CheckTracker_OnMessageClose(); // TODO: OnMessageClose hook
break; break;
case MSGMODE_PAUSED: case MSGMODE_PAUSED:
break; break;
+18 -4
View File
@@ -1521,18 +1521,25 @@ void Inventory_SwapAgeEquipment(void) {
} }
} }
// In Rando, when switching to adult for the second+ time, if a sword was not previously
// equiped in MS shuffle, then we need to set the swordless flag again
if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) &&
gSaveContext.equips.buttonItems[0] == ITEM_NONE) {
Flags_SetInfTable(INFTABLE_SWORDLESS);
}
gSaveContext.equips.equipment = gSaveContext.adultEquips.equipment; gSaveContext.equips.equipment = gSaveContext.adultEquips.equipment;
} }
} else { } else {
// When becoming child, set swordless flag if player doesn't have kokiri sword // When becoming child, set swordless flag if player doesn't have kokiri sword
// Only in rando to keep swordless link bugs in vanilla // Only in rando to keep swordless link bugs in vanilla
if (IS_RANDO && (EQUIP_INV_SWORD_KOKIRI << (EQUIP_TYPE_SWORD * 4) & gSaveContext.inventory.equipment) == 0) { if (IS_RANDO && CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_KOKIRI) == 0) {
Flags_SetInfTable(INFTABLE_SWORDLESS); Flags_SetInfTable(INFTABLE_SWORDLESS);
} }
// When using enhancements, set swordless flag if player doesn't have kokiri sword or hasn't equipped a sword yet. // When using enhancements, set swordless flag if player doesn't have kokiri sword or hasn't equipped a sword yet.
// Then set the child equips button items to item none to ensure kokiri sword is not equipped // Then set the child equips button items to item none to ensure kokiri sword is not equipped
if ((CVarGetInteger("gSwitchAge", 0) || CVarGetInteger("gSwitchTimeline", 0)) && ((EQUIP_INV_SWORD_KOKIRI << (EQUIP_TYPE_SWORD * 4) & gSaveContext.inventory.equipment) == 0 || Flags_GetInfTable(INFTABLE_SWORDLESS))) { if ((CVarGetInteger("gSwitchAge", 0) || CVarGetInteger("gSwitchTimeline", 0)) && (CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_KOKIRI) == 0 || Flags_GetInfTable(INFTABLE_SWORDLESS))) {
Flags_SetInfTable(INFTABLE_SWORDLESS); Flags_SetInfTable(INFTABLE_SWORDLESS);
gSaveContext.childEquips.buttonItems[0] = ITEM_NONE; gSaveContext.childEquips.buttonItems[0] = ITEM_NONE;
} }
@@ -1568,7 +1575,7 @@ void Inventory_SwapAgeEquipment(void) {
gSaveContext.equips.equipment = gSaveContext.childEquips.equipment; gSaveContext.equips.equipment = gSaveContext.childEquips.equipment;
gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4)); gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4));
// Equips kokiri sword in the inventory screen only if kokiri sword exists in inventory and a sword has been equipped already // Equips kokiri sword in the inventory screen only if kokiri sword exists in inventory and a sword has been equipped already
if (!((EQUIP_INV_SWORD_KOKIRI << (EQUIP_TYPE_SWORD * 4) & gSaveContext.inventory.equipment) == 0) && !Flags_GetInfTable(INFTABLE_SWORDLESS)) { if (!(CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_KOKIRI) == 0) && !Flags_GetInfTable(INFTABLE_SWORDLESS)) {
gSaveContext.equips.equipment |= EQUIP_VALUE_SWORD_KOKIRI << (EQUIP_TYPE_SWORD * 4); gSaveContext.equips.equipment |= EQUIP_VALUE_SWORD_KOKIRI << (EQUIP_TYPE_SWORD * 4);
} }
} else if (gSaveContext.childEquips.buttonItems[0] != ITEM_NONE) { } else if (gSaveContext.childEquips.buttonItems[0] != ITEM_NONE) {
@@ -1589,6 +1596,13 @@ void Inventory_SwapAgeEquipment(void) {
} }
} }
// In Rando, when switching to child from a swordless adult, and child Link previously had a
// sword equiped, then we need to unset the swordless flag to match
if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) &&
gSaveContext.equips.buttonItems[0] != ITEM_NONE) {
Flags_UnsetInfTable(INFTABLE_SWORDLESS);
}
gSaveContext.equips.equipment = gSaveContext.childEquips.equipment; gSaveContext.equips.equipment = gSaveContext.childEquips.equipment;
gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4)); gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4));
gSaveContext.equips.equipment |= EQUIP_VALUE_SWORD_KOKIRI << (EQUIP_TYPE_SWORD * 4); gSaveContext.equips.equipment |= EQUIP_VALUE_SWORD_KOKIRI << (EQUIP_TYPE_SWORD * 4);
@@ -1598,7 +1612,7 @@ void Inventory_SwapAgeEquipment(void) {
(only kokiri tunic/boots equipped, no sword, no C-button items, no D-Pad items). (only kokiri tunic/boots equipped, no sword, no C-button items, no D-Pad items).
When becoming child, set swordless flag if player doesn't have kokiri sword When becoming child, set swordless flag if player doesn't have kokiri sword
Only in rando to keep swordless link bugs in vanilla*/ Only in rando to keep swordless link bugs in vanilla*/
if (EQUIP_INV_SWORD_KOKIRI << (EQUIP_TYPE_SWORD * 4) & gSaveContext.inventory.equipment == 0) { if (CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_KOKIRI) == 0) {
Flags_SetInfTable(INFTABLE_SWORDLESS); Flags_SetInfTable(INFTABLE_SWORDLESS);
} }
+5
View File
@@ -277,6 +277,11 @@ void func_8009638C(Gfx** displayList, void* source, void* tlut, u16 width, u16 h
bg->b.imagePal = 0; bg->b.imagePal = 0;
bg->b.imageFlip = CVarGetInteger("gMirroredWorld", 0) ? G_BG_FLAG_FLIPS : 0; bg->b.imageFlip = CVarGetInteger("gMirroredWorld", 0) ? G_BG_FLAG_FLIPS : 0;
// When an alt resource exists for the background, we need to unload the original asset
// to clear the cache so the alt asset will be loaded instead
// OTRTODO: If Alt loading over original cache is fixed, this line can most likely be removed
ResourceMgr_UnloadOriginalWhenAltExists((char*) source);
if (ResourceMgr_ResourceIsBackground((char*) source)) { if (ResourceMgr_ResourceIsBackground((char*) source)) {
char* blob = (char*) ResourceGetDataByName((char *) source); char* blob = (char*) ResourceGetDataByName((char *) source);
swapAndConvertJPEG(blob); swapAndConvertJPEG(blob);
+6 -1
View File
@@ -417,7 +417,12 @@ void func_800AEFC8(SkyboxContext* skyboxCtx, s16 skyboxId) {
s32 j; s32 j;
s32 phi_s3 = 0; s32 phi_s3 = 0;
if (skyboxId == SKYBOX_BAZAAR || (skyboxId > SKYBOX_HOUSE_KAKARIKO && skyboxId <= SKYBOX_BOMBCHU_SHOP)) { //! @bug All shops only provide 2 faces for their sky box. Mask shop is missing from the condition
// meaning that the Mask shop will calculate 4 faces
// This effect is not noticed as the faces are behind the camera, but will cause a crash in SoH.
// SOH General: We have added the Mask shop to this check so only the 2 expected faces are calculated.
if (skyboxId == SKYBOX_BAZAAR || skyboxId == SKYBOX_HAPPY_MASK_SHOP ||
(skyboxId >= SKYBOX_KOKIRI_SHOP && skyboxId <= SKYBOX_BOMBCHU_SHOP)) {
for (j = 0, i = 0; i < 2; i++, j += 2) { for (j = 0, i = 0; i < 2; i++, j += 2) {
phi_s3 = func_800ADBB0(skyboxCtx, skyboxCtx->roomVtx, phi_s3, D_8012AEBC[i].unk_0, D_8012AEBC[i].unk_4, phi_s3 = func_800ADBB0(skyboxCtx, skyboxCtx->roomVtx, phi_s3, D_8012AEBC[i].unk_0, D_8012AEBC[i].unk_4,
D_8012AEBC[i].unk_8, D_8012AEBC[i].unk_C, D_8012AEBC[i].unk_10, i, j); D_8012AEBC[i].unk_8, D_8012AEBC[i].unk_C, D_8012AEBC[i].unk_10, i, j);
+8 -2
View File
@@ -59,8 +59,14 @@ void SkyboxDraw_Draw(SkyboxContext* skyboxCtx, GraphicsContext* gfxCtx, s16 skyb
gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[2]); gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[2]);
gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[3]); gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[3]);
if (skyboxId != SKYBOX_BAZAAR) { //! @bug All shops only provide 2 faces for their sky box. Mask shop is missing from the condition
if (skyboxId <= SKYBOX_HOUSE_KAKARIKO || skyboxId > SKYBOX_BOMBCHU_SHOP) { // meaning that the Mask shop will render the previously loaded sky box values, or uninitialized data.
// This effect is not noticed as the faces are behind the camera, but will cause a crash in SoH.
// SOH General: We have added the Mask shop to this check so only the 2 expected faces are rendered.
if (skyboxId != SKYBOX_BAZAAR && skyboxId != SKYBOX_HAPPY_MASK_SHOP) {
if (skyboxId < SKYBOX_KOKIRI_SHOP || skyboxId > SKYBOX_BOMBCHU_SHOP) {
// Skip remaining faces for most shop skyboxes
gDPPipeSync(POLY_OPA_DISP++); gDPPipeSync(POLY_OPA_DISP++);
gDPLoadTLUT_pal256(POLY_OPA_DISP++, skyboxCtx->palettes[2]); gDPLoadTLUT_pal256(POLY_OPA_DISP++, skyboxCtx->palettes[2]);
gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[4]); gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[4]);
@@ -5,9 +5,21 @@
#include "scenes/dungeons/ddan_boss/ddan_boss_room_1.h" #include "scenes/dungeons/ddan_boss/ddan_boss_room_1.h"
#include "soh/frame_interpolation.h" #include "soh/frame_interpolation.h"
#include "soh/Enhancements/boss-rush/BossRush.h" #include "soh/Enhancements/boss-rush/BossRush.h"
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include <stdlib.h> // malloc
#include <string.h> // memcpy
// OTRTODO: Replace usage of this method when we can clear the cache
// for a single texture without the need of a DL opcode in the render code
void gfx_texture_cache_clear();
#define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_HOSTILE | ACTOR_FLAG_UPDATE_WHILE_CULLED | ACTOR_FLAG_DRAW_WHILE_CULLED) #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_HOSTILE | ACTOR_FLAG_UPDATE_WHILE_CULLED | ACTOR_FLAG_DRAW_WHILE_CULLED)
#define LAVA_TEX_WIDTH 32
#define LAVA_TEX_HEIGHT 64
#define LAVA_TEX_SIZE 2048
void BossDodongo_Init(Actor* thisx, PlayState* play); void BossDodongo_Init(Actor* thisx, PlayState* play);
void BossDodongo_Destroy(Actor* thisx, PlayState* play); void BossDodongo_Destroy(Actor* thisx, PlayState* play);
void BossDodongo_Update(Actor* thisx, PlayState* play); void BossDodongo_Update(Actor* thisx, PlayState* play);
@@ -57,7 +69,14 @@ static u8 sMaskTex16x32[16 * 32] = { { 0 } };
static u8 sMaskTex32x16[32 * 16] = { { 0 } }; static u8 sMaskTex32x16[32 * 16] = { { 0 } };
static u8 sMaskTex8x8[8 * 8] = { { 0 } }; static u8 sMaskTex8x8[8 * 8] = { { 0 } };
static u8 sMaskTex8x32[8 * 32] = { { 0 } }; static u8 sMaskTex8x32[8 * 32] = { { 0 } };
static u8 sMaskTexLava[32 * 64] = { { 0 } }; static u8 sMaskTexLava[LAVA_TEX_WIDTH * LAVA_TEX_HEIGHT] = { { 0 } };
static u32* sLavaFloorModifiedTexRaw = NULL;
static u32* sLavaWavyTexRaw = NULL;
static u16 sLavaFloorModifiedTex[LAVA_TEX_SIZE];
static u16 sLavaWavyTex[LAVA_TEX_SIZE];
static u8 hasRegisteredBlendedHook = 0;
static InitChainEntry sInitChain[] = { static InitChainEntry sInitChain[] = {
ICHAIN_U8(targetMode, 5, ICHAIN_CONTINUE), ICHAIN_U8(targetMode, 5, ICHAIN_CONTINUE),
@@ -66,6 +85,89 @@ static InitChainEntry sInitChain[] = {
ICHAIN_F32(targetArrowOffset, 8200.0f, ICHAIN_STOP), ICHAIN_F32(targetArrowOffset, 8200.0f, ICHAIN_STOP),
}; };
void BossDodongo_RegisterBlendedLavaTextureUpdate() {
// Not in scene so there is nothing to do
if (gPlayState == NULL || gPlayState->sceneNum != SCENE_DODONGOS_CAVERN_BOSS) {
return;
}
// Free old textures
if (sLavaFloorModifiedTexRaw != NULL) {
free(sLavaFloorModifiedTexRaw);
sLavaFloorModifiedTexRaw = NULL;
}
if (sLavaWavyTexRaw != NULL) {
free(sLavaWavyTexRaw);
sLavaWavyTexRaw = NULL;
}
// Unload original textures to bypass cache result for lookups
ResourceMgr_UnloadOriginalWhenAltExists(sLavaFloorLavaTex);
ResourceMgr_UnloadOriginalWhenAltExists(sLavaFloorRockTex);
ResourceMgr_UnloadOriginalWhenAltExists(gDodongosCavernBossLavaFloorTex);
// When the texture is HD (raw) we need to work with u32 values for RGBA32
// Otherwise the original asset is u16 for RGBA16
if (ResourceMgr_TexIsRaw(gDodongosCavernBossLavaFloorTex)) {
u32* lavaTex = ResourceGetDataByName(sLavaFloorLavaTex);
size_t lavaSize = ResourceGetSizeByName(sLavaFloorLavaTex);
size_t floorSize = ResourceGetSizeByName(gDodongosCavernBossLavaFloorTex);
size_t rockSize = ResourceGetSizeByName(sLavaFloorRockTex);
// If the sizes don't match, then don't bother with the blended effect to avoid crashing
if (floorSize != lavaSize || floorSize != rockSize) {
uint8_t maskVal = !!Flags_GetClear(gPlayState, gPlayState->roomCtx.curRoom.num);
if (sMaskTexLava[0] != maskVal) {
for (int i = 0; i < ARRAY_COUNT(sMaskTexLava); i++) {
sMaskTexLava[i] = maskVal;
}
}
Gfx_RegisterBlendedTexture(gDodongosCavernBossLavaFloorTex, sMaskTexLava, NULL);
return;
}
sLavaFloorModifiedTexRaw = malloc(lavaSize);
sLavaWavyTexRaw = malloc(floorSize);
memcpy(sLavaFloorModifiedTexRaw, lavaTex, lavaSize);
// When KD is dead, just immediately copy the rock texture
if (Flags_GetClear(gPlayState, gPlayState->roomCtx.curRoom.num)) {
u32* rockTex = ResourceGetDataByName(sLavaFloorRockTex);
memcpy(sLavaFloorModifiedTexRaw, rockTex, rockSize);
}
memcpy(sLavaWavyTexRaw, sLavaFloorModifiedTexRaw, floorSize);
// Register the blended effect for the raw texture
Gfx_RegisterBlendedTexture(gDodongosCavernBossLavaFloorTex, sMaskTexLava, sLavaWavyTexRaw);
} else {
// When KD is dead, just immediately copy the rock texture
if (Flags_GetClear(gPlayState, gPlayState->roomCtx.curRoom.num)) {
u16* rockTex = ResourceGetDataByName(sLavaFloorRockTex);
memcpy(sLavaFloorModifiedTex, rockTex, sizeof(sLavaFloorModifiedTex));
} else {
u16* lavaTex = ResourceGetDataByName(sLavaFloorLavaTex);
memcpy(sLavaFloorModifiedTex, lavaTex, sizeof(sLavaFloorModifiedTex));
}
// Register the blended effect for the non-raw texture
memcpy(sLavaWavyTex, sLavaFloorModifiedTex, sizeof(sLavaWavyTex));
Gfx_RegisterBlendedTexture(gDodongosCavernBossLavaFloorTex, sMaskTexLava, sLavaWavyTex);
}
// Set all true for the lava as it will always replace the scene texture
if (sMaskTexLava[0] == 0) {
for (int i = 0; i < ARRAY_COUNT(sMaskTexLava); i++) {
sMaskTexLava[i] = 1;
}
}
gfx_texture_cache_clear();
}
void func_808C12C4(u8* arg1, s16 arg2) { void func_808C12C4(u8* arg1, s16 arg2) {
if (arg2[arg1] != 0) { if (arg2[arg1] != 0) {
sMaskTex8x16[arg2 / 2] = 1; sMaskTex8x16[arg2 / 2] = 1;
@@ -86,12 +188,53 @@ void func_808C12C4(u8* arg1, s16 arg2) {
} }
} }
void func_808C1554(void* arg0, void* floorTex, s32 arg2, f32 arg3) { // Same as func_808C1554 but works with u32 values for RGBA32 raw textures
arg0 = GetResourceDataByNameHandlingMQ(arg0); void func_808C1554_Raw(void* arg0, void* floorTex, s32 arg2, f32 arg3) {
floorTex = ResourceGetDataByName(floorTex); // Raw lava not registered, so abort the wave modification
if (sLavaWavyTexRaw == NULL || sLavaFloorModifiedTexRaw == NULL) {
return;
}
u16* temp_s3 = SEGMENTED_TO_VIRTUAL(arg0); u16 width = ResourceGetTexWidthByName(arg0);
u16* temp_s1 = SEGMENTED_TO_VIRTUAL(floorTex); s32 size = ResourceGetTexHeightByName(arg0) * width;
u32* temp_s3 = sLavaWavyTexRaw;
u32* temp_s1 = sLavaFloorModifiedTexRaw;
s32 i;
s32 i2;
u32* sp54 = malloc(size * sizeof(u32)); // Match the size for lava floor tex
s32 temp;
s32 temp2;
// Multiplier is used to try to scale the wavy effect to match the scale of the HD texture
// Applying sqrt(multiplier) to arg3 is to control how many pixels move left/right for the selected row
// Applying to arg2 and M_PI help to space out the wave effect
// It's not perfect but close enough
u16 multiplier = width / LAVA_TEX_WIDTH;
for (i = 0; i < size; i += width) {
temp = sinf((((i / width) + (s32)(((arg2 * multiplier) * 50.0f) / 100.0f)) & (width - 1)) * (M_PI / (16 * multiplier))) * (arg3 * sqrt(multiplier));
for (i2 = 0; i2 < width; i2++) {
sp54[i + ((temp + i2) & (width - 1))] = temp_s1[i + i2];
}
}
for (i = 0; i < width; i++) {
temp = sinf(((i + (s32)(((arg2 * multiplier) * 80.0f) / 100.0f)) & (width - 1)) * (M_PI / (16 * multiplier))) * (arg3 * sqrt(multiplier));
temp *= width;
for (i2 = 0; i2 < size; i2 += width) {
temp2 = (temp + i2) & (size - 1);
temp_s3[i + temp2] = sp54[i + i2];
}
}
free(sp54);
}
// Modified to support CPU modified texture with the resource system
// Used for the original non-raw asset working with u16 values
void func_808C1554(void* arg0, void* floorTex, s32 arg2, f32 arg3) {
u16* temp_s3 = sLavaWavyTex;
u16* temp_s1 = sLavaFloorModifiedTex;
s16 i; s16 i;
s16 i2; s16 i2;
u16 sp54[2048]; u16 sp54[2048];
@@ -187,27 +330,21 @@ void BossDodongo_Init(Actor* thisx, PlayState* play) {
Collider_SetJntSph(play, &this->collider, &this->actor, &sJntSphInit, this->items); Collider_SetJntSph(play, &this->collider, &this->actor, &sJntSphInit, this->items);
if (Flags_GetClear(play, play->roomCtx.curRoom.num)) { // KD is dead if (Flags_GetClear(play, play->roomCtx.curRoom.num)) { // KD is dead
u16* LavaFloorTex = ResourceGetDataByName(gDodongosCavernBossLavaFloorTex); // SOH [General]
u16* LavaFloorRockTex = ResourceGetDataByName(sLavaFloorRockTex); // Applying the "cooled off" lava rock CPU modified texture for re-visiting the scene
temp_s1_3 = SEGMENTED_TO_VIRTUAL(LavaFloorTex); // is now handled by BossDodongo_RegisterBlendedLavaTextureUpdate below
temp_s2 = SEGMENTED_TO_VIRTUAL(LavaFloorRockTex);
Actor_Kill(&this->actor); Actor_Kill(&this->actor);
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_DOOR_WARP1, -890.0f, -1523.76f, Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_DOOR_WARP1, -890.0f, -1523.76f,
-3304.0f, 0, 0, 0, WARP_DUNGEON_CHILD); -3304.0f, 0, 0, 0, WARP_DUNGEON_CHILD);
Actor_Spawn(&play->actorCtx, play, ACTOR_BG_BREAKWALL, -890.0f, -1523.76f, -3304.0f, 0, 0, 0, 0x6000, true); Actor_Spawn(&play->actorCtx, play, ACTOR_BG_BREAKWALL, -890.0f, -1523.76f, -3304.0f, 0, 0, 0, 0x6000, true);
Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_B_HEART, -690.0f, -1523.76f, -3304.0f, 0, 0, 0, 0, true); Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_B_HEART, -690.0f, -1523.76f, -3304.0f, 0, 0, 0, 0, true);
for (int i = 0; i < ARRAY_COUNT(sMaskTexLava); i++) {
sMaskTexLava[i] = 1;
}
} else {
for (int i = 0; i < ARRAY_COUNT(sMaskTexLava); i++) {
sMaskTexLava[i] = 0;
}
} }
this->actor.flags &= ~ACTOR_FLAG_TARGETABLE; this->actor.flags &= ~ACTOR_FLAG_TARGETABLE;
// #region SOH [General]
// Init mask values for all KD blended textures
for (int i = 0; i < ARRAY_COUNT(sMaskTex8x16); i++) { for (int i = 0; i < ARRAY_COUNT(sMaskTex8x16); i++) {
sMaskTex8x16[i] = 0; sMaskTex8x16[i] = 0;
} }
@@ -223,6 +360,8 @@ void BossDodongo_Init(Actor* thisx, PlayState* play) {
for (int i = 0; i < ARRAY_COUNT(sMaskTex32x16); i++) { for (int i = 0; i < ARRAY_COUNT(sMaskTex32x16); i++) {
sMaskTex32x16[i] = 0; sMaskTex32x16[i] = 0;
} }
// Register all blended textures
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_015890, sMaskTex8x16, NULL); Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_015890, sMaskTex8x16, NULL);
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_017210, sMaskTex8x32, NULL); Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_017210, sMaskTex8x32, NULL);
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_015D90, sMaskTex16x16, NULL); Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_015D90, sMaskTex16x16, NULL);
@@ -234,10 +373,14 @@ void BossDodongo_Init(Actor* thisx, PlayState* play) {
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_016990, sMaskTex32x16, NULL); Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_016990, sMaskTex32x16, NULL);
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_016E10, sMaskTex32x16, NULL); Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_016E10, sMaskTex32x16, NULL);
// OTRTODO: This is causing OOB memory reads with HD assets BossDodongo_RegisterBlendedLavaTextureUpdate();
// commenting this out means the lava will stay lava even after beating king d
// // Register alt listener to update the blended lava for the replacement texture based on alt path
// Gfx_RegisterBlendedTexture(gDodongosCavernBossLavaFloorTex, sMaskTexLava, sLavaFloorRockTex); if (!hasRegisteredBlendedHook) {
GameInteractor_RegisterOnAssetAltChange(BossDodongo_RegisterBlendedLavaTextureUpdate);
hasRegisteredBlendedHook = 1;
}
// #endregion
} }
void BossDodongo_Destroy(Actor* thisx, PlayState* play) { void BossDodongo_Destroy(Actor* thisx, PlayState* play) {
@@ -1014,21 +1157,72 @@ void BossDodongo_Update(Actor* thisx, PlayState* play2) {
} }
} }
// TODO The lave floor bubbles with an effect that modifies the texture. This needs to be recreated shader-side. // The lava bubbles with a wavy effect as a CPU modified texture
//func_808C1554(gDodongosCavernBossLavaFloorTex, sLavaFloorLavaTex, this->unk_19E, this->unk_224); // This has been done by maintaining copied/modified texture values in the actor code
// The "cooling off" effect for the lava is pre-applied to the lava texture before applying
// the wavy effect. Since this is two effects and closely related to the actor, I've opted
// to handle them here rather than as a shader effect.
//
// Apply the corresponding wavy effect based on the texture being raw or not
if (ResourceMgr_TexIsRaw(gDodongosCavernBossLavaFloorTex)) {
func_808C1554_Raw(gDodongosCavernBossLavaFloorTex, sLavaFloorLavaTex, this->unk_19E, this->unk_224);
} else {
func_808C1554(gDodongosCavernBossLavaFloorTex, sLavaFloorLavaTex, this->unk_19E, this->unk_224);
}
} }
// Apply the "cooling off" effect for the lava
if (this->unk_1C6 != 0) { if (this->unk_1C6 != 0) {
u16* ptr1 = ResourceGetDataByName(sLavaFloorLavaTex); // Similar to above, the cooling off effect is a CPU modified texture effect
u16* ptr2 = ResourceGetDataByName(sLavaFloorRockTex); // Apply corresponding to the texture being raw or not
s16 i2; if (ResourceMgr_TexIsRaw(sLavaFloorRockTex)) {
u32* ptr1 = sLavaFloorModifiedTexRaw;
u32* ptr2 = ResourceGetDataByName(sLavaFloorRockTex);
u16 width = ResourceGetTexWidthByName(sLavaFloorRockTex);
u16 height = ResourceGetTexHeightByName(sLavaFloorRockTex);
s16 i2;
for (i2 = 0; i2 < 20; i2++) { // Get the scale based on the original texture size
s16 new_var = this->unk_1C2 & 0x7FF; u16 widthScale = width / LAVA_TEX_WIDTH;
u16 heightScale = height / LAVA_TEX_HEIGHT;
u32 size = width * height;
sMaskTexLava[new_var] = 1; for (i2 = 0; i2 < 20; i2++) {
this->unk_1C2 += 37; s16 new_var = this->unk_1C2 & (LAVA_TEX_SIZE - 1);
// Raw lava must be registered, otherwise skip the effect for incompatible texture pack
// and instead set the mask to simulate the lava disappearing by turning black
if (sLavaFloorModifiedTexRaw != NULL) {
// Compute the index to a scaled position (scaling pseudo x,y as a 1D value)
s32 indexStart =
((new_var % LAVA_TEX_WIDTH) * widthScale) + ((new_var / LAVA_TEX_WIDTH) * width * heightScale);
// From the starting index, apply extra pixels right/down based on the scale
for (size_t j = 0; j < heightScale; j++) {
for (size_t i3 = 0; i3 < widthScale; i3++) {
s32 scaledIndex = (indexStart + i3 + (j * width)) & (size - 1);
ptr1[scaledIndex] = ptr2[scaledIndex];
}
}
} else {
sMaskTexLava[new_var] = 1;
}
this->unk_1C2 += 37;
}
} else {
u16* ptr1 = sLavaFloorModifiedTex;
u16* ptr2 = ResourceGetDataByName(sLavaFloorRockTex);
s16 i2;
for (i2 = 0; i2 < 20; i2++) {
s16 new_var = this->unk_1C2 & 0x7FF;
ptr1[new_var] = ptr2[new_var];
this->unk_1C2 += 37;
}
} }
Math_SmoothStepToF(&this->unk_224, 0.0f, 1.0f, 0.01f, 0.0f); Math_SmoothStepToF(&this->unk_224, 0.0f, 1.0f, 0.01f, 0.0f);
} }
@@ -1151,8 +1345,16 @@ void BossDodongo_Draw(Actor* thisx, PlayState* play) {
gSPInvalidateTexCache(POLY_OPA_DISP++, sMaskTex32x16); gSPInvalidateTexCache(POLY_OPA_DISP++, sMaskTex32x16);
} }
if (this->unk_1C6 != 0) { gSPInvalidateTexCache(POLY_OPA_DISP++, sMaskTexLava);
gSPInvalidateTexCache(POLY_OPA_DISP++, sMaskTexLava);
// Using WORK_DISP to invalidate these textures as they are used in drawing the scene textures which happens
// before actors are drawn. WORK_DISP comes before POLAY_OPA_DISP. It is probably not meant for this, but it
// at least works for now.
// Alternatively, having a way to invalidate just these pointers from the Update func should be sufficient.
if (sLavaFloorModifiedTexRaw != NULL) {
gSPInvalidateTexCache(WORK_DISP++, sLavaWavyTexRaw);
} else {
gSPInvalidateTexCache(WORK_DISP++, sLavaWavyTex);
} }
if ((this->unk_1C0 >= 2) && (this->unk_1C0 & 1)) { if ((this->unk_1C0 >= 2) && (this->unk_1C0 & 1)) {
@@ -75,7 +75,6 @@ static InitChainEntry sInitChain[] = {
}; };
static UNK_TYPE sUnused; static UNK_TYPE sUnused;
GetItemEntry sItem;
Gfx gSkullTreasureChestChestSideAndLidDL[116] = {0}; Gfx gSkullTreasureChestChestSideAndLidDL[116] = {0};
Gfx gGoldTreasureChestChestSideAndLidDL[116] = {0}; Gfx gGoldTreasureChestChestSideAndLidDL[116] = {0};
@@ -472,7 +471,7 @@ void EnBox_WaitOpen(EnBox* this, PlayState* play) {
func_8002DBD0(&this->dyna.actor, &sp4C, &player->actor.world.pos); func_8002DBD0(&this->dyna.actor, &sp4C, &player->actor.world.pos);
if (sp4C.z > -50.0f && sp4C.z < 0.0f && fabsf(sp4C.y) < 10.0f && fabsf(sp4C.x) < 20.0f && if (sp4C.z > -50.0f && sp4C.z < 0.0f && fabsf(sp4C.y) < 10.0f && fabsf(sp4C.x) < 20.0f &&
Player_IsFacingActor(&this->dyna.actor, 0x3000, play)) { Player_IsFacingActor(&this->dyna.actor, 0x3000, play)) {
sItem = Randomizer_GetItemFromActor(this->dyna.actor.id, play->sceneNum, this->dyna.actor.params, this->dyna.actor.params >> 5 & 0x7F); GetItemEntry sItem = Randomizer_GetItemFromActor(this->dyna.actor.id, play->sceneNum, this->dyna.actor.params, this->dyna.actor.params >> 5 & 0x7F);
GetItemEntry blueRupee = ItemTable_RetrieveEntry(MOD_NONE, GI_RUPEE_BLUE); GetItemEntry blueRupee = ItemTable_RetrieveEntry(MOD_NONE, GI_RUPEE_BLUE);
// RANDOTODO treasure chest game rando // RANDOTODO treasure chest game rando
@@ -628,7 +627,7 @@ void EnBox_Update(Actor* thisx, PlayState* play) {
} }
if (((!IS_RANDO && ((this->dyna.actor.params >> 5 & 0x7F) == 0x7C)) || if (((!IS_RANDO && ((this->dyna.actor.params >> 5 & 0x7F) == 0x7C)) ||
(IS_RANDO && ABS(sItem.getItemId) == RG_ICE_TRAP)) && (IS_RANDO && this->getItemEntry.getItemId == RG_ICE_TRAP)) &&
this->actionFunc == EnBox_Open && this->skelanime.curFrame > 45 && this->iceSmokeTimer < 100) { this->actionFunc == EnBox_Open && this->skelanime.curFrame > 45 && this->iceSmokeTimer < 100) {
if (!CVarGetInteger("gAddTraps.enabled", 0)) { if (!CVarGetInteger("gAddTraps.enabled", 0)) {
EnBox_SpawnIceSmoke(this, play); EnBox_SpawnIceSmoke(this, play);
+41 -3
View File
@@ -95,6 +95,26 @@ static AnimationInfo sAnimationInfo[] = {
{ &gDaruniaDancingEndAnim, 1.0f, 0.0f, -1.0f, ANIMMODE_ONCE, -6.0f }, { &gDaruniaDancingEndAnim, 1.0f, 0.0f, -1.0f, ANIMMODE_ONCE, -6.0f },
}; };
// #region SOH [Enhancement] Only animations too fast need to be slowed down, otherwise not touched
static AnimationInfo sAnimationInfoFix[] = {
{ NULL },
{ NULL },
{ NULL },
{ NULL },
{ NULL },
{ NULL },
{ NULL },
{ &gDaruniaDancingLoop1Anim, 0.78f, 0.0f, -1.0f, ANIMMODE_ONCE, -10.0f }, //
{ &gDaruniaDancingLoop1Anim, 0.77f, 0.0f, -1.0f, ANIMMODE_ONCE, 0.0f }, // hop
{ &gDaruniaDancingLoop2Anim, 0.78f, 0.0f, -1.0f, ANIMMODE_ONCE, 0.0f }, // from hop to spin
{ &gDaruniaDancingLoop3Anim, 0.77f, 0.0f, -1.0f, ANIMMODE_ONCE, 0.0f }, // spin
{ NULL },
{ NULL },
{ &gDaruniaDancingLoop4Anim, 0.78f, 0.0f, -1.0f, ANIMMODE_ONCE, 0.0f }, // from spin to hop
{ NULL },
};
// #endregion
void EnDu_SetupAction(EnDu* this, EnDuActionFunc actionFunc) { void EnDu_SetupAction(EnDu* this, EnDuActionFunc actionFunc) {
this->actionFunc = actionFunc; this->actionFunc = actionFunc;
} }
@@ -255,7 +275,13 @@ void func_809FE040(EnDu* this) {
if (this->unk_1E6 >= 8) { if (this->unk_1E6 >= 8) {
this->unk_1E6 = 0; this->unk_1E6 = 0;
} }
Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, animationIndices[this->unk_1E6]); // #region SOH[Enhancement]
if (CVarGetInteger("gEnhancements.FixDaruniaDanceSpeed", 1)) {
Animation_ChangeByInfo(&this->skelAnime, sAnimationInfoFix, animationIndices[this->unk_1E6]);
// #endregion
} else {
Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, animationIndices[this->unk_1E6]);
}
} }
} }
@@ -271,7 +297,13 @@ void func_809FE104(EnDu* this) {
if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) { if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) {
this->unk_1E6++; this->unk_1E6++;
if (this->unk_1E6 < 4) { if (this->unk_1E6 < 4) {
Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, animationIndices[this->unk_1E6]); // #region SOH[Enhancement]
if (CVarGetInteger("gEnhancements.FixDaruniaDanceSpeed", 1) && this->unk_1E6 <= 1) {
Animation_ChangeByInfo(&this->skelAnime, sAnimationInfoFix, animationIndices[this->unk_1E6]);
// #endregion
} else {
Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, animationIndices[this->unk_1E6]);
}
} }
} }
} }
@@ -465,7 +497,13 @@ void func_809FE890(EnDu* this, PlayState* play) {
} }
if (csAction->action == 7 || csAction->action == 8) { if (csAction->action == 7 || csAction->action == 8) {
this->unk_1E6 = 0; this->unk_1E6 = 0;
Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, ENDU_ANIM_7); // #region SOH[Enhancement]
if (CVarGetInteger("gEnhancements.FixDaruniaDanceSpeed", 1)) {
Animation_ChangeByInfo(&this->skelAnime, sAnimationInfoFix, ENDU_ANIM_7);
// #endregion
} else {
Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, ENDU_ANIM_7);
}
} }
this->unk_1EA = csAction->action; this->unk_1EA = csAction->action;
if (this->unk_1EA == 7) { if (this->unk_1EA == 7) {
@@ -211,6 +211,13 @@ void EnInsect_Init(Actor* thisx, PlayState* play2) {
func_80A7D39C(this); func_80A7D39C(this);
// For bugs that aren't linked to a soil patch, we remove the "short lived" flag to prevent them from despawning
// And exit early to not increment the "bugs dropped count"
if (CVarGetInteger("gNoBugsDespawn", 0) && this->soilActor == NULL) {
this->unk_314 &= ~4;
return;
}
D_80A7DEB8++; D_80A7DEB8++;
} else { } else {
rand = Rand_ZeroOne(); rand = Rand_ZeroOne();
@@ -394,9 +401,6 @@ void func_80A7CAD0(EnInsect* this, PlayState* play) {
} }
void func_80A7CBC8(EnInsect* this) { void func_80A7CBC8(EnInsect* this) {
if (CVarGetInteger("gNoBugsDespawn", 0) != 0) {
return;
}
this->unk_31A = 60; this->unk_31A = 60;
func_80A7BF58(this); func_80A7BF58(this);
this->skelAnime.playSpeed = 1.9f; this->skelAnime.playSpeed = 1.9f;
@@ -313,7 +313,9 @@ void EnSth_GiveReward(EnSth* this, PlayState* play) {
this->actor.parent = NULL; this->actor.parent = NULL;
EnSth_SetupAction(this, EnSth_RewardObtainedTalk); EnSth_SetupAction(this, EnSth_RewardObtainedTalk);
gSaveContext.eventChkInf[EVENTCHKINF_SKULLTULA_REWARD_INDEX] |= this->eventFlag; gSaveContext.eventChkInf[EVENTCHKINF_SKULLTULA_REWARD_INDEX] |= this->eventFlag;
GameInteractor_ExecuteOnFlagSet(FLAG_EVENT_CHECK_INF, (EVENTCHKINF_SKULLTULA_REWARD_INDEX << 4) + sEventFlagsShift[this->actor.params]); if (this->eventFlag != 0) {
GameInteractor_ExecuteOnFlagSet(FLAG_EVENT_CHECK_INF, (EVENTCHKINF_SKULLTULA_REWARD_INDEX << 4) + sEventFlagsShift[this->actor.params]);
}
} else { } else {
EnSth_GivePlayerItem(this, play); EnSth_GivePlayerItem(this, play);
} }
@@ -3,6 +3,7 @@
#include "overlays/actors/ovl_En_Syateki_Itm/z_en_syateki_itm.h" #include "overlays/actors/ovl_En_Syateki_Itm/z_en_syateki_itm.h"
#include "objects/object_ossan/object_ossan.h" #include "objects/object_ossan/object_ossan.h"
#include "soh/Enhancements/randomizer/randomizer_entrance.h" #include "soh/Enhancements/randomizer/randomizer_entrance.h"
#include "soh/Enhancements/custom-message/CustomMessageTypes.h"
#define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY | ACTOR_FLAG_UPDATE_WHILE_CULLED | ACTOR_FLAG_NO_LOCKON) #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY | ACTOR_FLAG_UPDATE_WHILE_CULLED | ACTOR_FLAG_NO_LOCKON)
@@ -371,7 +372,8 @@ void EnSyatekiMan_EndGame(EnSyatekiMan* this, PlayState* play) {
this->getItemId = GI_RUPEE_PURPLE; this->getItemId = GI_RUPEE_PURPLE;
} }
} else { } else {
if(IS_RANDO && !Flags_GetTreasure(play, 0x1F)) { // Only give the adult rando reward when the player has a quiver
if (IS_RANDO && !Flags_GetTreasure(play, 0x1F) && CUR_UPG_VALUE(UPG_QUIVER) > 0) {
this->getItemEntry = Randomizer_GetItemFromKnownCheck(RC_KAK_SHOOTING_GALLERY_REWARD, GI_QUIVER_50); this->getItemEntry = Randomizer_GetItemFromKnownCheck(RC_KAK_SHOOTING_GALLERY_REWARD, GI_QUIVER_50);
this->getItemId = this->getItemEntry.getItemId; this->getItemId = this->getItemEntry.getItemId;
Flags_SetTreasure(play, 0x1F); Flags_SetTreasure(play, 0x1F);
@@ -448,6 +450,9 @@ void EnSyatekiMan_FinishPrize(EnSyatekiMan* this, PlayState* play) {
Flags_SetItemGetInf(ITEMGETINF_0D); Flags_SetItemGetInf(ITEMGETINF_0D);
} else if ((this->getItemId == GI_QUIVER_40) || (this->getItemId == GI_QUIVER_50)) { } else if ((this->getItemId == GI_QUIVER_40) || (this->getItemId == GI_QUIVER_50)) {
Flags_SetItemGetInf(ITEMGETINF_0E); Flags_SetItemGetInf(ITEMGETINF_0E);
} else if (IS_RANDO && LINK_IS_ADULT && CUR_UPG_VALUE(UPG_QUIVER) == 0) {
// In Rando without a quiver, display a message reminding the player to come back with a bow
Message_StartTextbox(play, TEXT_SHOOTING_GALLERY_MAN_COME_BACK_WITH_BOW, NULL);
} }
this->gameResult = SYATEKI_RESULT_NONE; this->gameResult = SYATEKI_RESULT_NONE;
this->actor.parent = this->tempGallery; this->actor.parent = this->tempGallery;
+23 -31
View File
@@ -408,7 +408,7 @@ s32 EnTk_ChooseReward(EnTk* this) {
f32 luck; f32 luck;
s32 reward; s32 reward;
if ((IS_RANDO || CVarGetInteger("gDampeWin", 0)) && !Flags_GetCollectible(gPlayState, 0x1F) && this->heartPieceSpawned == 0) { if ((IS_RANDO || CVarGetInteger("gDampeWin", 0)) && !Flags_GetCollectible(gPlayState, COLLECTFLAG_GRAVEDIGGING_HEART_PIECE) && this->heartPieceSpawned == 0) {
return 3; return 3;
} }
@@ -624,10 +624,8 @@ void EnTk_Dig(EnTk* this, PlayState* play) {
this->currentReward = EnTk_ChooseReward(this); this->currentReward = EnTk_ChooseReward(this);
// merging in dampe tour fix seems messy, so i'm just wrapping this whole thing if (this->currentReward == 3) {
// in an n64dd check for now if (IS_RANDO || CVarGetInteger("gDampeWin", 0)) {
if (IS_RANDO || CVarGetInteger("gDampeWin", 0)) {
if (this->currentReward == 3) {
/* /*
* Upgrade the purple rupee reward to the heart piece if this * Upgrade the purple rupee reward to the heart piece if this
* is the first grand prize dig. * is the first grand prize dig.
@@ -635,37 +633,31 @@ void EnTk_Dig(EnTk* this, PlayState* play) {
if (!Flags_GetItemGetInf(ITEMGETINF_1C) && !(IS_RANDO || CVarGetInteger("gDampeWin", 0))) { if (!Flags_GetItemGetInf(ITEMGETINF_1C) && !(IS_RANDO || CVarGetInteger("gDampeWin", 0))) {
Flags_SetItemGetInf(ITEMGETINF_1C); Flags_SetItemGetInf(ITEMGETINF_1C);
this->currentReward = 4; this->currentReward = 4;
} else if ((IS_RANDO || CVarGetInteger("gDampeWin", 0)) && !Flags_GetCollectible(gPlayState, 0x1F) && this->heartPieceSpawned == 0) { } else if ((IS_RANDO || CVarGetInteger("gDampeWin", 0)) && !Flags_GetCollectible(gPlayState, COLLECTFLAG_GRAVEDIGGING_HEART_PIECE) && this->heartPieceSpawned == 0) {
this->currentReward = 4; this->currentReward = 4;
} }
} }
/*
if ((IS_RANDO || CVarGetInteger("gDampeWin", 0)) && this->currentReward == 4) { * Upgrade the purple rupee reward to the heart piece if this
Actor_Spawn(&play->actorCtx, play, ACTOR_EN_ITEM00, rewardPos.x, rewardPos.y, rewardPos.z, 0, * is the first grand prize dig.
0, 0, 0x1F06, true); */
this->heartPieceSpawned = 1; // If vanilla itemGetInf flag is not set, it's impossible for the new flag to be set, so return true.
} else { // Otherwise if the gGravediggingTourFix is enabled and the new flag hasn't been set, return true.
Item_DropCollectible(play, &rewardPos, rewardParams[this->currentReward]); // If true, spawn the heart piece and set the vanilla itemGetInf flag and new temp clear flag.
if (!heartPieceSpawned &&
(!(gSaveContext.itemGetInf[1] & ITEMGETINFFLAG_GRAVEDIGGING_HEART_PIECE) ||
CVarGetInteger("gGravediggingTourFix", 0) &&
!Flags_GetCollectible(play, COLLECTFLAG_GRAVEDIGGING_HEART_PIECE))) {
this->currentReward = 4;
gSaveContext.itemGetInf[1] |= ITEMGETINFFLAG_GRAVEDIGGING_HEART_PIECE;
heartPieceSpawned = true;
} }
}
if (IS_RANDO && this->currentReward == 4) {
Actor_Spawn(&play->actorCtx, play, ACTOR_EN_ITEM00, rewardPos.x, rewardPos.y, rewardPos.z, 0, 0, 0, 0x1906, true);
this->heartPieceSpawned = 1;
} else { } else {
if (this->currentReward == 3) {
/*
* Upgrade the purple rupee reward to the heart piece if this
* is the first grand prize dig.
*/
// If vanilla itemGetInf flag is not set, it's impossible for the new flag to be set, so return true.
// Otherwise if the gGravediggingTourFix is enabled and the new flag hasn't been set, return true.
// If true, spawn the heart piece and set the vanilla itemGetInf flag and new temp clear flag.
if (!heartPieceSpawned &&
(!(gSaveContext.itemGetInf[1] & ITEMGETINFFLAG_GRAVEDIGGING_HEART_PIECE) ||
CVarGetInteger("gGravediggingTourFix", 0) &&
!Flags_GetCollectible(play, COLLECTFLAG_GRAVEDIGGING_HEART_PIECE))) {
this->currentReward = 4;
gSaveContext.itemGetInf[1] |= ITEMGETINFFLAG_GRAVEDIGGING_HEART_PIECE;
heartPieceSpawned = true;
}
}
EnItem00* reward = Item_DropCollectible(play, &rewardPos, rewardParams[this->currentReward]); EnItem00* reward = Item_DropCollectible(play, &rewardPos, rewardParams[this->currentReward]);
if (this->currentReward == 4) { if (this->currentReward == 4) {
reward->collectibleFlag = COLLECTFLAG_GRAVEDIGGING_HEART_PIECE; reward->collectibleFlag = COLLECTFLAG_GRAVEDIGGING_HEART_PIECE;
@@ -10101,7 +10101,8 @@ void func_80847BA0(PlayState* play, Player* this) {
D_808535F0 = func_80041DB8(&play->colCtx, this->actor.wallPoly, this->actor.wallBgId); D_808535F0 = func_80041DB8(&play->colCtx, this->actor.wallPoly, this->actor.wallBgId);
if (CVarGetInteger("gFixVineFall", 0)) { // conflicts arise from these two being enabled at once, and with ClimbEverything on, FixVineFall is redundant anyway
if (CVarGetInteger("gFixVineFall", 0) && !CVarGetInteger("gClimbEverything", 0)) {
/* This fixes the "started climbing a wall and then immediately fell off" bug. /* This fixes the "started climbing a wall and then immediately fell off" bug.
* The main idea is if a climbing wall is detected, double-check that it will * The main idea is if a climbing wall is detected, double-check that it will
* still be valid once climbing begins by doing a second raycast with a small * still be valid once climbing begins by doing a second raycast with a small
@@ -10628,7 +10629,14 @@ void Player_UseTunicBoots(Player* this, PlayState* play) {
s32 i; s32 i;
s32 item; s32 item;
s32 actionParam; s32 actionParam;
if (!(this->stateFlags1 & PLAYER_STATE1_INPUT_DISABLED || this->stateFlags1 & PLAYER_STATE1_IN_ITEM_CS || this->stateFlags1 & PLAYER_STATE1_IN_CUTSCENE || this->stateFlags1 & PLAYER_STATE1_TEXT_ON_SCREEN || this->stateFlags2 & PLAYER_STATE2_OCARINA_PLAYING)) { if (!(
this->stateFlags1 & PLAYER_STATE1_INPUT_DISABLED ||
this->stateFlags1 & PLAYER_STATE1_IN_ITEM_CS ||
this->stateFlags1 & PLAYER_STATE1_IN_CUTSCENE ||
this->stateFlags1 & PLAYER_STATE1_TEXT_ON_SCREEN ||
this->stateFlags1 & PLAYER_STATE1_DEAD ||
this->stateFlags2 & PLAYER_STATE2_OCARINA_PLAYING
)) {
for (i = 0; i < ARRAY_COUNT(D_80854388); i++) { for (i = 0; i < ARRAY_COUNT(D_80854388); i++) {
if (CHECK_BTN_ALL(sControlInput->press.button, D_80854388[i])) { if (CHECK_BTN_ALL(sControlInput->press.button, D_80854388[i])) {
break; break;
@@ -1,6 +1,7 @@
#include "file_choose.h" #include "file_choose.h"
#include <string.h> #include <string.h>
#include <stdio.h>
#include "textures/title_static/title_static.h" #include "textures/title_static/title_static.h"
#include "textures/parameter_static/parameter_static.h" #include "textures/parameter_static/parameter_static.h"
@@ -1024,23 +1025,23 @@ void FileChoose_UpdateRandomizer() {
return; return;
} }
if (!SpoilerFileExists(CVarGetString("gSpoilerLog", ""))) { if (!SpoilerFileExists(CVarGetString("gSpoilerLog", "")) && !CVarGetInteger("gRandomizerDontGenerateSpoiler", 0)) {
CVarSetString("gSpoilerLog", ""); CVarSetString("gSpoilerLog", "");
fileSelectSpoilerFileLoaded = false; fileSelectSpoilerFileLoaded = false;
} }
if ((CVarGetInteger("gNewFileDropped", 0) != 0) || (CVarGetInteger("gNewSeedGenerated", 0) != 0) || if ((CVarGetInteger("gRandomizerNewFileDropped", 0) != 0) || (CVarGetInteger("gNewSeedGenerated", 0) != 0) ||
(!fileSelectSpoilerFileLoaded && SpoilerFileExists(CVarGetString("gSpoilerLog", "")))) { (!fileSelectSpoilerFileLoaded && SpoilerFileExists(CVarGetString("gSpoilerLog", "")))) {
if (CVarGetInteger("gNewFileDropped", 0) != 0) { if (CVarGetInteger("gRandomizerNewFileDropped", 0) != 0) {
CVarSetString("gSpoilerLog", CVarGetString("gDroppedFile", "None")); CVarSetString("gSpoilerLog", CVarGetString("gRandomizerDroppedFile", "None"));
} }
bool silent = true; bool silent = true;
if ((CVarGetInteger("gNewFileDropped", 0) != 0) || (CVarGetInteger("gNewSeedGenerated", 0) != 0)) { if ((CVarGetInteger("gRandomizerNewFileDropped", 0) != 0) || (CVarGetInteger("gNewSeedGenerated", 0) != 0)) {
silent = false; silent = false;
} }
CVarSetInteger("gNewSeedGenerated", 0); CVarSetInteger("gNewSeedGenerated", 0);
CVarSetInteger("gNewFileDropped", 0); CVarSetInteger("gRandomizerNewFileDropped", 0);
CVarSetString("gDroppedFile", ""); CVarSetString("gRandomizerDroppedFile", "");
fileSelectSpoilerFileLoaded = false; fileSelectSpoilerFileLoaded = false;
const char* fileLoc = CVarGetString("gSpoilerLog", ""); const char* fileLoc = CVarGetString("gSpoilerLog", "");
Randomizer_LoadSettings(fileLoc); Randomizer_LoadSettings(fileLoc);
@@ -1051,6 +1052,10 @@ void FileChoose_UpdateRandomizer() {
Randomizer_LoadMasterQuestDungeons(fileLoc); Randomizer_LoadMasterQuestDungeons(fileLoc);
Randomizer_LoadEntranceOverrides(fileLoc, silent); Randomizer_LoadEntranceOverrides(fileLoc, silent);
fileSelectSpoilerFileLoaded = true; fileSelectSpoilerFileLoaded = true;
if (SpoilerFileExists(CVarGetString("gSpoilerLog", "")) && CVarGetInteger("gRandomizerDontGenerateSpoiler", 0)) {
remove(fileLoc);
}
} }
} }
@@ -3686,4 +3691,7 @@ void FileChoose_Init(GameState* thisx) {
Font_LoadOrderedFont(&this->font); Font_LoadOrderedFont(&this->font);
Audio_QueueSeqCmd(0xF << 28 | SEQ_PLAYER_BGM_MAIN << 24 | 0xA); Audio_QueueSeqCmd(0xF << 28 | SEQ_PLAYER_BGM_MAIN << 24 | 0xA);
func_800F5E18(SEQ_PLAYER_BGM_MAIN, NA_BGM_FILE_SELECT, 0, 7, 1); func_800F5E18(SEQ_PLAYER_BGM_MAIN, NA_BGM_FILE_SELECT, 0, 7, 1);
// Originally this was only set when transitioning from the title screen, but gSkipLogoTitle skips that process so we're ensuring it's set here
gSaveContext.gameMode = GAMEMODE_FILE_SELECT;
} }
@@ -456,7 +456,6 @@ void FileChoose_DrawNameEntry(GameState* thisx) {
this->prevConfigMode = CM_MAIN_MENU; this->prevConfigMode = CM_MAIN_MENU;
this->configMode = CM_NAME_ENTRY_TO_MAIN; this->configMode = CM_NAME_ENTRY_TO_MAIN;
CVarSetInteger("gOnFileSelectNameEntry", 0); CVarSetInteger("gOnFileSelectNameEntry", 0);
CVarSetInteger("gNewFileDropped", 0);
this->nameBoxAlpha[this->buttonIndex] = this->nameAlpha[this->buttonIndex] = 200; this->nameBoxAlpha[this->buttonIndex] = this->nameAlpha[this->buttonIndex] = 200;
this->connectorAlpha[this->buttonIndex] = 255; this->connectorAlpha[this->buttonIndex] = 255;
func_800AA000(300.0f, 0xB4, 0x14, 0x64); func_800AA000(300.0f, 0xB4, 0x14, 0x64);
@@ -1054,8 +1054,9 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) {
//Fix for Equip Dupe //Fix for Equip Dupe
if (pauseCtx->equipTargetItem == ITEM_BOW) { if (pauseCtx->equipTargetItem == ITEM_BOW) {
if ((gSaveContext.equips.buttonItems[otherButtonIndex] >= ITEM_BOW_ARROW_FIRE) && if (gSaveContext.equips.buttonItems[otherButtonIndex] >= ITEM_BOW_ARROW_FIRE &&
(gSaveContext.equips.buttonItems[otherButtonIndex] <= ITEM_BOW_ARROW_LIGHT)) { gSaveContext.equips.buttonItems[otherButtonIndex] <= ITEM_BOW_ARROW_LIGHT &&
!CVarGetInteger("gSeparateArrows", 0)) {
gSaveContext.equips.buttonItems[otherButtonIndex] = gSaveContext.equips.buttonItems[targetButtonIndex]; gSaveContext.equips.buttonItems[otherButtonIndex] = gSaveContext.equips.buttonItems[targetButtonIndex];
gSaveContext.equips.cButtonSlots[otherSlotIndex] = gSaveContext.equips.cButtonSlots[pauseCtx->equipTargetCBtn]; gSaveContext.equips.cButtonSlots[otherSlotIndex] = gSaveContext.equips.cButtonSlots[pauseCtx->equipTargetCBtn];
Interface_LoadItemIcon2(play, otherButtonIndex); Interface_LoadItemIcon2(play, otherButtonIndex);
@@ -343,7 +343,7 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) {
// Offset the U value of each vertex to be in the mirror boundary for the map textures // Offset the U value of each vertex to be in the mirror boundary for the map textures
if (mirroredWorld) { if (mirroredWorld) {
for (size_t i = 0; i < 8; i++) { for (size_t i = 0; i < 8; i++) {
pauseCtx->mapPageVtx[60 + i].v.tc[0] += 48 << 5; pauseCtx->mapPageVtx[60 + i].v.tc[0] += MAP_48x85_TEX_WIDTH << 5;
} }
} }
@@ -353,8 +353,9 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) {
gSPInvalidateTexCache(POLY_KAL_DISP++, interfaceCtx->mapSegment[0]); gSPInvalidateTexCache(POLY_KAL_DISP++, interfaceCtx->mapSegment[0]);
gSPInvalidateTexCache(POLY_KAL_DISP++, interfaceCtx->mapSegment[1]); gSPInvalidateTexCache(POLY_KAL_DISP++, interfaceCtx->mapSegment[1]);
gDPLoadTextureBlock_4b(POLY_KAL_DISP++, interfaceCtx->mapSegmentName[0], G_IM_FMT_CI, 48, 85, 0, G_TX_WRAP | mirrorMode, gDPLoadTextureBlock_4b(POLY_KAL_DISP++, interfaceCtx->mapSegmentName[0], G_IM_FMT_CI, MAP_48x85_TEX_WIDTH,
G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); MAP_48x85_TEX_HEIGHT, 0, G_TX_WRAP | mirrorMode, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK,
G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);
// Swap vertices to render left half on the right and vice-versa // Swap vertices to render left half on the right and vice-versa
if (mirroredWorld) { if (mirroredWorld) {
@@ -363,9 +364,9 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) {
gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0); gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0);
} }
gDPLoadTextureBlock_4b(POLY_KAL_DISP++, interfaceCtx->mapSegmentName[1], G_IM_FMT_CI, 48, 85, 0, gDPLoadTextureBlock_4b(POLY_KAL_DISP++, interfaceCtx->mapSegmentName[1], G_IM_FMT_CI, MAP_48x85_TEX_WIDTH,
G_TX_WRAP | mirrorMode, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, MAP_48x85_TEX_HEIGHT, 0, G_TX_WRAP | mirrorMode, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK,
G_TX_NOLOD); G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);
if (mirroredWorld) { if (mirroredWorld) {
gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0); gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0);
@@ -13,6 +13,10 @@ extern u8 gItemAgeReqs[];
extern u8 gAreaGsFlags[]; extern u8 gAreaGsFlags[];
extern bool gSelectingMask; extern bool gSelectingMask;
#define MAP_48x85_TEX_WIDTH 48
#define MAP_48x85_TEX_HEIGHT 85
#define MAP_48x85_TEX_SIZE ((MAP_48x85_TEX_WIDTH * MAP_48x85_TEX_HEIGHT) / 2) // 48x85 CI4 texture
#define AGE_REQ_ADULT LINK_AGE_ADULT #define AGE_REQ_ADULT LINK_AGE_ADULT
#define AGE_REQ_CHILD LINK_AGE_CHILD #define AGE_REQ_CHILD LINK_AGE_CHILD
#define AGE_REQ_NONE 9 #define AGE_REQ_NONE 9
@@ -1205,6 +1205,8 @@ Gfx* KaleidoScope_DrawPageSections(Gfx* gfx, Vtx* vertices, void** textures) {
return gfx; return gfx;
} }
static uint8_t mapBlendMask[MAP_48x85_TEX_WIDTH * MAP_48x85_TEX_HEIGHT];
void KaleidoScope_DrawPages(PlayState* play, GraphicsContext* gfxCtx) { void KaleidoScope_DrawPages(PlayState* play, GraphicsContext* gfxCtx) {
static Color_RGB8 D_8082ACF4[12] = { static Color_RGB8 D_8082ACF4[12] = {
{ 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 255, 255, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 255, 255, 0 }, { 0, 0, 0 },
@@ -1373,6 +1375,10 @@ void KaleidoScope_DrawPages(PlayState* play, GraphicsContext* gfxCtx) {
} }
} }
// Need to invalidate the blend mask every frame. Ideally this would be done in KaleidoScope_DrawDungeonMap
// but the reference is not shared between files
gSPInvalidateTexCache(POLY_KAL_DISP++, mapBlendMask);
if (pauseCtx->pageIndex) { // pageIndex != PAUSE_ITEM if (pauseCtx->pageIndex) { // pageIndex != PAUSE_ITEM
gDPPipeSync(OVERLAY_DISP++); gDPPipeSync(OVERLAY_DISP++);
gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA, G_CC_MODULATEIA); gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA, G_CC_MODULATEIA);
@@ -3315,13 +3321,118 @@ void KaleidoScope_UpdateCursorSize(PauseContext* pauseCtx) {
pauseCtx->cursorVtx[14].v.ob[1] = pauseCtx->cursorVtx[15].v.ob[1] = pauseCtx->cursorVtx[12].v.ob[1] - 16; pauseCtx->cursorVtx[14].v.ob[1] = pauseCtx->cursorVtx[15].v.ob[1] = pauseCtx->cursorVtx[12].v.ob[1] - 16;
} }
// Modifed map texture buffers for registered blend effects and the room indicator color
static uint8_t mapLeftTexModified[MAP_48x85_TEX_SIZE];
static uint8_t mapRightTexModified[MAP_48x85_TEX_SIZE];
static uint8_t* mapLeftTexModifiedRaw = NULL;
static uint8_t* mapRightTexModifiedRaw = NULL;
// Load dungeon maps into the interface context
// SoH [General] - Modified to account for our resource system and HD textures
void KaleidoScope_LoadDungeonMap(PlayState* play) { void KaleidoScope_LoadDungeonMap(PlayState* play) {
InterfaceContext* interfaceCtx = &play->interfaceCtx; InterfaceContext* interfaceCtx = &play->interfaceCtx;
// Free old textures
if (mapLeftTexModifiedRaw != NULL) {
free(mapLeftTexModifiedRaw);
mapLeftTexModifiedRaw = NULL;
}
if (mapRightTexModifiedRaw != NULL) {
free(mapRightTexModifiedRaw);
mapRightTexModifiedRaw = NULL;
}
// Unload original textures to bypass cache result for lookups
ResourceMgr_UnloadOriginalWhenAltExists(sDungeonMapTexs[R_MAP_TEX_INDEX]);
ResourceMgr_UnloadOriginalWhenAltExists(sDungeonMapTexs[R_MAP_TEX_INDEX + 1]);
interfaceCtx->mapSegmentName[0] = sDungeonMapTexs[R_MAP_TEX_INDEX]; interfaceCtx->mapSegmentName[0] = sDungeonMapTexs[R_MAP_TEX_INDEX];
interfaceCtx->mapSegmentName[1] = sDungeonMapTexs[R_MAP_TEX_INDEX + 1]; interfaceCtx->mapSegmentName[1] = sDungeonMapTexs[R_MAP_TEX_INDEX + 1];
interfaceCtx->mapSegment[0] = ResourceGetDataByName(sDungeonMapTexs[R_MAP_TEX_INDEX]);
interfaceCtx->mapSegment[1] = ResourceGetDataByName(sDungeonMapTexs[R_MAP_TEX_INDEX + 1]); // When the texture is HD (raw) we need to copy a dynamic amount of data
// Otherwise the original asset has a static size
if (ResourceMgr_TexIsRaw(interfaceCtx->mapSegmentName[0])) {
u32 width = ResourceGetTexWidthByName(interfaceCtx->mapSegmentName[0]);
u32 height = ResourceGetTexHeightByName(interfaceCtx->mapSegmentName[0]);
size_t size = (width * height) / 2; // account for CI4 size
// Resource size being larger than the calculated CI size means it is most likely not a CI4 texture
// Abort early end undo the blended effect by clearing the mask to avoid crashing
if (size < ResourceGetTexSizeByName(interfaceCtx->mapSegmentName[0])) {
if (mapBlendMask[0] != 0) {
for (size_t i = 0; i < ARRAY_COUNT(mapBlendMask); i++) {
mapBlendMask[i] = 0;
}
}
interfaceCtx->mapSegment[0] = NULL;
interfaceCtx->mapSegment[1] = NULL;
Gfx_RegisterBlendedTexture(interfaceCtx->mapSegmentName[0], mapBlendMask, NULL);
Gfx_RegisterBlendedTexture(interfaceCtx->mapSegmentName[1], mapBlendMask, NULL);
return;
}
u8* map1TexRaw = ResourceGetDataByName(interfaceCtx->mapSegmentName[0]);
u8* map2TexRaw = ResourceGetDataByName(interfaceCtx->mapSegmentName[1]);
mapLeftTexModifiedRaw = malloc(size);
mapRightTexModifiedRaw = malloc(size);
memcpy(mapLeftTexModifiedRaw, map1TexRaw, size);
memcpy(mapRightTexModifiedRaw, map2TexRaw, size);
interfaceCtx->mapSegment[0] = mapLeftTexModifiedRaw;
interfaceCtx->mapSegment[1] = mapRightTexModifiedRaw;
} else {
u8* map1Tex = ResourceGetDataByName(interfaceCtx->mapSegmentName[0]);
u8* map2Tex = ResourceGetDataByName(interfaceCtx->mapSegmentName[1]);
memcpy(mapLeftTexModified, map1Tex, MAP_48x85_TEX_SIZE);
memcpy(mapRightTexModified, map2Tex, MAP_48x85_TEX_SIZE);
interfaceCtx->mapSegment[0] = mapLeftTexModified;
interfaceCtx->mapSegment[1] = mapRightTexModified;
}
// Mark and register the blend mask for the copied textures
if (mapBlendMask[0] != 1) {
for (size_t i = 0; i < ARRAY_COUNT(mapBlendMask); i++) {
mapBlendMask[i] = 1;
}
}
Gfx_RegisterBlendedTexture(interfaceCtx->mapSegmentName[0], mapBlendMask, interfaceCtx->mapSegment[0]);
Gfx_RegisterBlendedTexture(interfaceCtx->mapSegmentName[1], mapBlendMask, interfaceCtx->mapSegment[1]);
}
static uint8_t registeredDungeonMapTextureHook = false;
void KaleidoScope_RegisterUpdatedDungeonMapTexture() {
if (gPlayState == NULL) {
return;
}
PauseContext* pauseCtx = &gPlayState->pauseCtx;
// Kaleido is not open in a dungeon so there is nothing to do
if (R_PAUSE_MENU_MODE < 3 || pauseCtx->state < 4 || pauseCtx->state > 7 || !sInDungeonScene) {
return;
}
KaleidoScope_UpdateDungeonMap(gPlayState);
// KaleidoScope_UpdateDungeonMap will update the palette index for the current floor if the cursor is on the floor
// If the player toggles alt assets while the cursor is not in the floor level, then we handle the palette index here
if (gPlayState->sceneNum >= SCENE_DEKU_TREE && gPlayState->sceneNum <= SCENE_TREASURE_BOX_SHOP &&
(VREG(30) + 3) == pauseCtx->dungeonMapSlot && (VREG(30) + 3) != pauseCtx->cursorPoint[PAUSE_MAP]) {
InterfaceContext* interfaceCtx = &gPlayState->interfaceCtx;
int32_t size = ResourceGetTexSizeByName(interfaceCtx->mapSegmentName[0]);
KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[0], size, interfaceCtx->mapPaletteIndex, 14);
KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[1], size, interfaceCtx->mapPaletteIndex, 14);
}
} }
void KaleidoScope_UpdateDungeonMap(PlayState* play) { void KaleidoScope_UpdateDungeonMap(PlayState* play) {
@@ -3333,19 +3444,29 @@ void KaleidoScope_UpdateDungeonMap(PlayState* play) {
KaleidoScope_LoadDungeonMap(play); KaleidoScope_LoadDungeonMap(play);
Map_SetFloorPalettesData(play, pauseCtx->dungeonMapSlot - 3); Map_SetFloorPalettesData(play, pauseCtx->dungeonMapSlot - 3);
s32 size = MAP_48x85_TEX_SIZE;
if (ResourceMgr_TexIsRaw(interfaceCtx->mapSegmentName[0])) {
size = ResourceGetTexSizeByName(interfaceCtx->mapSegmentName[0]);
}
if ((play->sceneNum >= SCENE_DEKU_TREE) && (play->sceneNum <= SCENE_TREASURE_BOX_SHOP)) { if ((play->sceneNum >= SCENE_DEKU_TREE) && (play->sceneNum <= SCENE_TREASURE_BOX_SHOP)) {
if ((VREG(30) + 3) == pauseCtx->cursorPoint[PAUSE_MAP]) { if ((VREG(30) + 3) == pauseCtx->cursorPoint[PAUSE_MAP]) {
// HDTODO: Handle Runtime Modified Textures (HD) KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[0], size, interfaceCtx->mapPaletteIndex, 14);
KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[0], 2040, interfaceCtx->mapPaletteIndex, 14);
} }
} }
if ((play->sceneNum >= SCENE_DEKU_TREE) && (play->sceneNum <= SCENE_TREASURE_BOX_SHOP)) { if ((play->sceneNum >= SCENE_DEKU_TREE) && (play->sceneNum <= SCENE_TREASURE_BOX_SHOP)) {
if ((VREG(30) + 3) == pauseCtx->cursorPoint[PAUSE_MAP]) { if ((VREG(30) + 3) == pauseCtx->cursorPoint[PAUSE_MAP]) {
// HDTODO: Handle Runtime Modified Textures (HD) KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[1], size, interfaceCtx->mapPaletteIndex, 14);
KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[1], 2040, interfaceCtx->mapPaletteIndex, 14);
} }
} }
// Register alt listener to update the blended dungeon map textures on alt toggle
if (!registeredDungeonMapTextureHook) {
registeredDungeonMapTextureHook = true;
GameInteractor_RegisterOnAssetAltChange(KaleidoScope_RegisterUpdatedDungeonMapTexture);
}
} }
void KaleidoScope_Update(PlayState* play) void KaleidoScope_Update(PlayState* play)
@@ -1762,6 +1762,13 @@ static MapMarkData sMapMarkJabuJabuBellyMq[] = {
} }, } },
{ MAP_MARK_NONE, 0, { 0 } }, { MAP_MARK_NONE, 0, { 0 } },
}, },
// Jabu-Jabu's Belly minimap 16
// SoH [General] - This entry corresponds to Big Octorok's room and is missing in the MQ game
// N64 hardware does an OoB read and lands on MQ Forest Temple room 0
// To avoid UB with OoB for SoH, the correct entry is now added below
{
{ MAP_MARK_NONE, 0, { 0 } },
},
}; };
static MapMarkData sMapMarkForestTempleMq[] = { static MapMarkData sMapMarkForestTempleMq[] = {