diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0633ab80a..fccae7f36 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,8 +5,8 @@ set(CMAKE_CXX_STANDARD 20 CACHE STRING "The C++ standard to use")
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version")
-project(Ship VERSION 8.0.0 LANGUAGES C CXX)
-set(PROJECT_BUILD_NAME "MacReady Alfa" CACHE STRING "")
+project(Ship VERSION 8.0.1 LANGUAGES C CXX)
+set(PROJECT_BUILD_NAME "MacReady Bravo" CACHE STRING "")
set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "")
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT soh)
diff --git a/OTRExporter b/OTRExporter
index 0d8f5570a..04b85b95f 160000
--- a/OTRExporter
+++ b/OTRExporter
@@ -1 +1 @@
-Subproject commit 0d8f5570a8e57f302ec6633d65615ee21ab39454
+Subproject commit 04b85b95fab07a394b62dcd28a502a3040f08e0c
diff --git a/libultraship b/libultraship
index c75ff3653..9509806ae 160000
--- a/libultraship
+++ b/libultraship
@@ -1 +1 @@
-Subproject commit c75ff3653f699cb1a8c017b10e4b3986259d8cf0
+Subproject commit 9509806ae3ca6e35882fb976de70c5bde471b8f5
diff --git a/soh/assets/custom/objects/object_kakariko_decor/CuccoBedding_32 b/soh/assets/custom/objects/object_kakariko_decor/CuccoBedding_32
new file mode 100644
index 000000000..68187fbf5
Binary files /dev/null and b/soh/assets/custom/objects/object_kakariko_decor/CuccoBedding_32 differ
diff --git a/soh/assets/custom/objects/object_kakariko_decor/SnowBlanket_32 b/soh/assets/custom/objects/object_kakariko_decor/SnowBlanket_32
new file mode 100644
index 000000000..733b30757
Binary files /dev/null and b/soh/assets/custom/objects/object_kakariko_decor/SnowBlanket_32 differ
diff --git a/soh/assets/custom/objects/object_kakariko_decor/SnowDissolve_32 b/soh/assets/custom/objects/object_kakariko_decor/SnowDissolve_32
new file mode 100644
index 000000000..e7c7aa142
Binary files /dev/null and b/soh/assets/custom/objects/object_kakariko_decor/SnowDissolve_32 differ
diff --git a/soh/assets/custom/objects/object_kakariko_decor/String_BYBY_32 b/soh/assets/custom/objects/object_kakariko_decor/String_BYBY_32
new file mode 100644
index 000000000..62efcb10a
Binary files /dev/null and b/soh/assets/custom/objects/object_kakariko_decor/String_BYBY_32 differ
diff --git a/soh/assets/custom/objects/object_kakariko_decor/UsagiLeaf_8 b/soh/assets/custom/objects/object_kakariko_decor/UsagiLeaf_8
new file mode 100644
index 000000000..fc4d3ff5b
Binary files /dev/null and b/soh/assets/custom/objects/object_kakariko_decor/UsagiLeaf_8 differ
diff --git a/soh/assets/custom/objects/object_kakariko_decor/YukiUsagi_16 b/soh/assets/custom/objects/object_kakariko_decor/YukiUsagi_16
new file mode 100644
index 000000000..2034627ff
Binary files /dev/null and b/soh/assets/custom/objects/object_kakariko_decor/YukiUsagi_16 differ
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gFrontGateDecorDL_vtx_0 b/soh/assets/custom/objects/object_kakariko_decor/gFrontGateDecorDL_vtx_0
deleted file mode 100644
index 3b2a2a21c..000000000
--- a/soh/assets/custom/objects/object_kakariko_decor/gFrontGateDecorDL_vtx_0
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gFrontGateDecorDL_vtx_1 b/soh/assets/custom/objects/object_kakariko_decor/gFrontGateDecorDL_vtx_1
deleted file mode 100644
index a5aeeaa53..000000000
--- a/soh/assets/custom/objects/object_kakariko_decor/gFrontGateDecorDL_vtx_1
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gFrontGateDecorDL_vtx_cull b/soh/assets/custom/objects/object_kakariko_decor/gFrontGateDecorDL_vtx_cull
deleted file mode 100644
index 6e79464b2..000000000
--- a/soh/assets/custom/objects/object_kakariko_decor/gFrontGateDecorDL_vtx_cull
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gFrontGateDecorDL b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoAdultDecorDL
similarity index 53%
rename from soh/assets/custom/objects/object_kakariko_decor/gFrontGateDecorDL
rename to soh/assets/custom/objects/object_kakariko_decor/gKakarikoAdultDecorDL
index 5b0d3694f..13d9447f7 100644
--- a/soh/assets/custom/objects/object_kakariko_decor/gFrontGateDecorDL
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoAdultDecorDL
@@ -1,11 +1,11 @@
-
+
-
-
-
-
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoAdultDecorDL_tri_0 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoAdultDecorDL_tri_0
new file mode 100644
index 000000000..1263127aa
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoAdultDecorDL_tri_0
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gFrontGateDecorDL_tri_0 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoAdultDecorDL_tri_1
similarity index 64%
rename from soh/assets/custom/objects/object_kakariko_decor/gFrontGateDecorDL_tri_0
rename to soh/assets/custom/objects/object_kakariko_decor/gKakarikoAdultDecorDL_tri_1
index bce87b152..2aff9496e 100644
--- a/soh/assets/custom/objects/object_kakariko_decor/gFrontGateDecorDL_tri_0
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoAdultDecorDL_tri_1
@@ -1,10 +1,9 @@
-
+
-
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoAdultDecorDL_vtx_0 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoAdultDecorDL_vtx_0
new file mode 100644
index 000000000..9f3683fed
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoAdultDecorDL_vtx_0
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoAdultDecorDL_vtx_1 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoAdultDecorDL_vtx_1
new file mode 100644
index 000000000..e438e71cf
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoAdultDecorDL_vtx_1
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoAdultDecorDL_vtx_cull b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoAdultDecorDL_vtx_cull
new file mode 100644
index 000000000..c3ecddb8a
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoAdultDecorDL_vtx_cull
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoChildDecorDL b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoChildDecorDL
new file mode 100644
index 000000000..a3972ce7a
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoChildDecorDL
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoChildDecorDL_tri_0 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoChildDecorDL_tri_0
new file mode 100644
index 000000000..eb7e92fdf
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoChildDecorDL_tri_0
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoChildDecorDL_tri_1 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoChildDecorDL_tri_1
new file mode 100644
index 000000000..77468a738
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoChildDecorDL_tri_1
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoChildDecorDL_tri_2 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoChildDecorDL_tri_2
new file mode 100644
index 000000000..97634bb7b
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoChildDecorDL_tri_2
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoChildDecorDL_vtx_0 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoChildDecorDL_vtx_0
new file mode 100644
index 000000000..24e3e3d6e
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoChildDecorDL_vtx_0
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoChildDecorDL_vtx_1 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoChildDecorDL_vtx_1
new file mode 100644
index 000000000..0b12310ec
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoChildDecorDL_vtx_1
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoChildDecorDL_vtx_2 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoChildDecorDL_vtx_2
new file mode 100644
index 000000000..f2a81069d
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoChildDecorDL_vtx_2
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoChildDecorDL_vtx_cull b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoChildDecorDL_vtx_cull
new file mode 100644
index 000000000..b2e233783
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoChildDecorDL_vtx_cull
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL
new file mode 100644
index 000000000..f0363d242
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_tri_0 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_tri_0
new file mode 100644
index 000000000..5ee2633e5
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_tri_0
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_tri_1 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_tri_1
new file mode 100644
index 000000000..2b52e5ef3
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_tri_1
@@ -0,0 +1,221 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_tri_2 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_tri_2
new file mode 100644
index 000000000..d6f5dbafe
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_tri_2
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gFrontGateDecorDL_tri_1 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_tri_3
similarity index 59%
rename from soh/assets/custom/objects/object_kakariko_decor/gFrontGateDecorDL_tri_1
rename to soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_tri_3
index ac9146850..f66ba5914 100644
--- a/soh/assets/custom/objects/object_kakariko_decor/gFrontGateDecorDL_tri_1
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_tri_3
@@ -1,5 +1,5 @@
-
+
@@ -8,12 +8,18 @@
-
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_tri_4 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_tri_4
new file mode 100644
index 000000000..e0d376897
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_tri_4
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_tri_5 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_tri_5
new file mode 100644
index 000000000..ca52719c9
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_tri_5
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_tri_6 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_tri_6
new file mode 100644
index 000000000..75be056f5
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_tri_6
@@ -0,0 +1,330 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_tri_7 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_tri_7
new file mode 100644
index 000000000..eeedcf1ee
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_tri_7
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_0 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_0
new file mode 100644
index 000000000..c0a07802c
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_0
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_1 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_1
new file mode 100644
index 000000000..c7615dd3b
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_1
@@ -0,0 +1,770 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_2 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_2
new file mode 100644
index 000000000..3ff9d2e43
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_2
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_3 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_3
new file mode 100644
index 000000000..b0e49797a
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_3
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_4 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_4
new file mode 100644
index 000000000..043452939
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_4
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_5 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_5
new file mode 100644
index 000000000..46c6ac9a1
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_5
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_6 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_6
new file mode 100644
index 000000000..0e5970505
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_6
@@ -0,0 +1,497 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_7 b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_7
new file mode 100644
index 000000000..1929d460e
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_7
@@ -0,0 +1,230 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_cull b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_cull
new file mode 100644
index 000000000..a183da293
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/gKakarikoDecorDL_vtx_cull
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/mat_gFrontGateDecorDL_f3dlite_StringGRGR b/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoAdultDecorDL_f3dlite_StringGRGR
similarity index 100%
rename from soh/assets/custom/objects/object_kakariko_decor/mat_gFrontGateDecorDL_f3dlite_StringGRGR
rename to soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoAdultDecorDL_f3dlite_StringGRGR
diff --git a/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoAdultDecorDL_f3dlite_snowlayer b/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoAdultDecorDL_f3dlite_snowlayer
new file mode 100644
index 000000000..5456b3893
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoAdultDecorDL_f3dlite_snowlayer
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/mat_gFrontGateDecorDL_f3dlite_SnowBuildup b/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoChildDecorDL_f3dlite_SnowBuildup
similarity index 100%
rename from soh/assets/custom/objects/object_kakariko_decor/mat_gFrontGateDecorDL_f3dlite_SnowBuildup
rename to soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoChildDecorDL_f3dlite_SnowBuildup
diff --git a/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoChildDecorDL_f3dlite_UsagiLeaf b/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoChildDecorDL_f3dlite_UsagiLeaf
new file mode 100644
index 000000000..be29498ef
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoChildDecorDL_f3dlite_UsagiLeaf
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoChildDecorDL_f3dlite_YukiUsagiBody b/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoChildDecorDL_f3dlite_YukiUsagiBody
new file mode 100644
index 000000000..3a2d2c889
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoChildDecorDL_f3dlite_YukiUsagiBody
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoDecorDL_f3dlite_CuccoBedding b/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoDecorDL_f3dlite_CuccoBedding
new file mode 100644
index 000000000..520258210
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoDecorDL_f3dlite_CuccoBedding
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoDecorDL_f3dlite_SnowBuildup b/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoDecorDL_f3dlite_SnowBuildup
new file mode 100644
index 000000000..a79cca54f
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoDecorDL_f3dlite_SnowBuildup
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoDecorDL_f3dlite_StringBYBY b/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoDecorDL_f3dlite_StringBYBY
new file mode 100644
index 000000000..5c85eb88f
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoDecorDL_f3dlite_StringBYBY
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoDecorDL_f3dlite_StringGRGR b/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoDecorDL_f3dlite_StringGRGR
new file mode 100644
index 000000000..b8478fa90
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoDecorDL_f3dlite_StringGRGR
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoDecorDL_f3dlite_UsagiLeaf b/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoDecorDL_f3dlite_UsagiLeaf
new file mode 100644
index 000000000..be29498ef
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoDecorDL_f3dlite_UsagiLeaf
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoDecorDL_f3dlite_YukiUsagiBody b/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoDecorDL_f3dlite_YukiUsagiBody
new file mode 100644
index 000000000..3a2d2c889
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoDecorDL_f3dlite_YukiUsagiBody
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoDecorDL_f3dlite_snowdissolve b/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoDecorDL_f3dlite_snowdissolve
new file mode 100644
index 000000000..e86142f29
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoDecorDL_f3dlite_snowdissolve
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoDecorDL_f3dlite_snowlayer b/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoDecorDL_f3dlite_snowlayer
new file mode 100644
index 000000000..5456b3893
--- /dev/null
+++ b/soh/assets/custom/objects/object_kakariko_decor/mat_gKakarikoDecorDL_f3dlite_snowlayer
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/soh_assets.h b/soh/assets/soh_assets.h
index 95a3ec1b3..c3233d79f 100644
--- a/soh/assets/soh_assets.h
+++ b/soh/assets/soh_assets.h
@@ -95,8 +95,14 @@ static const ALIGN_ASSET(2) char gXmasDecor100DL[] = dgXmasDecor100DL;
#define dgXmasStarDL "__OTR__objects/object_xmas_tree/gXmasStarDL"
static const ALIGN_ASSET(2) char gXmasStarDL[] = dgXmasStarDL;
-#define dgFrontGateDecorDL "__OTR__objects/object_kakariko_decor/gFrontGateDecorDL"
-static const ALIGN_ASSET(2) char gFrontGateDecorDL[] = dgFrontGateDecorDL;
+#define dgKakarikoDecorDL "__OTR__objects/object_kakariko_decor/gKakarikoDecorDL"
+static const ALIGN_ASSET(2) char gKakarikoDecorDL[] = dgKakarikoDecorDL;
+
+#define dgKakarikoChildDecorDL "__OTR__objects/object_kakariko_decor/gKakarikoChildDecorDL"
+static const ALIGN_ASSET(2) char gKakarikoChildDecorDL[] = dgKakarikoChildDecorDL;
+
+#define dgKakarikoAdultDecorDL "__OTR__objects/object_kakariko_decor/gKakarikoAdultDecorDL"
+static const ALIGN_ASSET(2) char gKakarikoAdultDecorDL[] = dgKakarikoAdultDecorDL;
// overlays
#define dgOptionsDividerChangeLangVtx "__OTR__overlays/ovl_file_choose/gOptionsDividerChangeLangVtx"
diff --git a/soh/soh/ActorDB.cpp b/soh/soh/ActorDB.cpp
index fe7d87a25..3f515d19a 100644
--- a/soh/soh/ActorDB.cpp
+++ b/soh/soh/ActorDB.cpp
@@ -439,7 +439,7 @@ static std::unordered_map actorDescriptions = {
{ ACTOR_EN_DAIKU_KAKARIKO, "Carpenters (Kakariko)" },
{ ACTOR_BG_BOWL_WALL, "Bombchu Bowling Alley Wall" },
{ ACTOR_EN_WALL_TUBO, "Bombchu Bowling Alley Bullseyes" },
- { ACTOR_EN_PO_DESERT, "Poe Guide (Desert Wasteland)" },
+ { ACTOR_EN_PO_DESERT, "Poe Guide (Haunted Wasteland)" },
{ ACTOR_EN_CROW, "Guay" },
{ ACTOR_DOOR_KILLER, "Fake Door" },
{ ACTOR_BG_SPOT11_OASIS, "Oasis (Desert Colossus)" },
@@ -609,7 +609,7 @@ static ActorDBInit EnChristmasTreeInit = {
"En_ChristmasTree",
"Christmas Tree",
ACTORCAT_PROP,
- (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY),
+ (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY | ACTOR_FLAG_UPDATE_WHILE_CULLED | ACTOR_FLAG_DRAW_WHILE_CULLED),
OBJECT_GAMEPLAY_KEEP,
sizeof(EnChristmasTree),
(ActorFunc)EnChristmasTree_Init,
diff --git a/soh/soh/Enhancements/audio/AudioCollection.cpp b/soh/soh/Enhancements/audio/AudioCollection.cpp
index a5499bd4f..9da742f91 100644
--- a/soh/soh/Enhancements/audio/AudioCollection.cpp
+++ b/soh/soh/Enhancements/audio/AudioCollection.cpp
@@ -400,8 +400,9 @@ void AudioCollection::InitializeShufflePool() {
if (shufflePoolInitialized) return;
for (auto& [seqId, seqInfo] : sequenceMap) {
+ if (!seqInfo.canBeUsedAsReplacement) continue;
const std::string cvarKey = "gAudioEditor.Excluded." + seqInfo.sfxKey;
- if (CVarGetInteger(cvarKey.c_str(), 0) && !seqInfo.canBeUsedAsReplacement) {
+ if (CVarGetInteger(cvarKey.c_str(), 0)) {
excludedSequences.insert(&seqInfo);
} else {
includedSequences.insert(&seqInfo);
diff --git a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp
index 8c2707453..9c56ac32b 100644
--- a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp
+++ b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp
@@ -1767,6 +1767,10 @@ void CosmeticsEditorWindow::DrawElement() {
ImGui::SameLine();
UIWidgets::EnhancementCombobox("gCosmetics.DefaultColorScheme", colorSchemes, COLORSCHEME_N64);
UIWidgets::EnhancementCheckbox("Advanced Mode", "gCosmetics.AdvancedMode");
+ UIWidgets::InsertHelpHoverText(
+ "Some cosmetic options may not apply if you have any mods that provide custom models for the cosmetic option.\n\n"
+ "For example, if you have custom Link model, then the Link's Hair color option will most likely not apply."
+ );
if (CVarGetInteger("gCosmetics.AdvancedMode", 0)) {
if (ImGui::Button("Lock All Advanced", ImVec2(ImGui::GetContentRegionAvail().x / 2, 30.0f))) {
for (auto& [id, cosmeticOption] : cosmeticOptions) {
diff --git a/soh/soh/Enhancements/debugconsole.cpp b/soh/soh/Enhancements/debugconsole.cpp
index 3e61505b2..88a23718e 100644
--- a/soh/soh/Enhancements/debugconsole.cpp
+++ b/soh/soh/Enhancements/debugconsole.cpp
@@ -207,6 +207,7 @@ static bool ResetHandler(std::shared_ptr Console, std::vectorgameplayFrames = 0;
SET_NEXT_GAMESTATE(&gPlayState->state, TitleSetup_Init, GameState);
gPlayState->state.running = false;
GameInteractor::Instance->ExecuteHooks(gSaveContext.fileNum);
diff --git a/soh/soh/Enhancements/mods.cpp b/soh/soh/Enhancements/mods.cpp
index 6234fbab6..338cbfc40 100644
--- a/soh/soh/Enhancements/mods.cpp
+++ b/soh/soh/Enhancements/mods.cpp
@@ -35,8 +35,6 @@ extern PlayState* gPlayState;
extern void Overlay_DisplayText(float duration, const char* text);
uint32_t ResourceMgr_IsSceneMasterQuest(s16 sceneNum);
}
-bool performDelayedSave = false;
-bool performSave = false;
// TODO: When there's more uses of something like this, create a new GI::RawAction?
void ReloadSceneTogglingLinkAge() {
@@ -258,14 +256,12 @@ void RegisterOcarinaTimeTravel() {
void AutoSave(GetItemEntry itemEntry) {
u8 item = itemEntry.itemId;
+ bool performSave = false;
// Don't autosave immediately after buying items from shops to prevent getting them for free!
// Don't autosave in the Chamber of Sages since resuming from that map breaks the game
// Don't autosave during the Ganon fight when picking up the Master Sword
- // Don't autosave in the fishing pond to prevent getting rod on B outside of the pond
- // Don't autosave in the bombchu bowling alley to prevent having chus on B outside of the minigame
- // Don't autosave in grottos since resuming from grottos breaks the game.
if ((CVarGetInteger("gAutosave", AUTOSAVE_OFF) != AUTOSAVE_OFF) && (gPlayState != NULL) && (gSaveContext.pendingSale == ITEM_NONE) &&
- (gPlayState->gameplayFrames > 60 && gSaveContext.cutsceneIndex < 0xFFF0) && (gPlayState->sceneNum != SCENE_GANON_BOSS)) {
+ (gPlayState->gameplayFrames > 60 && gSaveContext.cutsceneIndex < 0xFFF0) && (gPlayState->sceneNum != SCENE_GANON_BOSS) && (gPlayState->sceneNum != SCENE_CHAMBER_OF_THE_SAGES)) {
if (((CVarGetInteger("gAutosave", AUTOSAVE_OFF) == AUTOSAVE_LOCATION_AND_ALL_ITEMS) || (CVarGetInteger("gAutosave", AUTOSAVE_OFF) == AUTOSAVE_ALL_ITEMS)) && (item != ITEM_NONE)) {
// Autosave for all items
performSave = true;
@@ -326,25 +322,9 @@ void AutoSave(GetItemEntry itemEntry) {
CVarGetInteger("gAutosave", AUTOSAVE_OFF) == AUTOSAVE_LOCATION) {
performSave = true;
}
- if (gPlayState->sceneNum == SCENE_FAIRYS_FOUNTAIN || gPlayState->sceneNum == SCENE_GROTTOS ||
- gPlayState->sceneNum == SCENE_CHAMBER_OF_THE_SAGES || gPlayState->sceneNum == SCENE_FISHING_POND ||
- gPlayState->sceneNum == SCENE_BOMBCHU_BOWLING_ALLEY) {
- if (CVarGetInteger("gAutosave", AUTOSAVE_OFF) == AUTOSAVE_LOCATION_AND_MAJOR_ITEMS ||
- CVarGetInteger("gAutosave", AUTOSAVE_OFF) == AUTOSAVE_LOCATION_AND_ALL_ITEMS ||
- CVarGetInteger("gAutosave", AUTOSAVE_OFF) == AUTOSAVE_LOCATION) {
- performSave = false;
- return;
- }
- if (performSave) {
- performSave = false;
- performDelayedSave = true;
- }
- return;
- }
- if (performSave || performDelayedSave) {
+ if (performSave) {
Play_PerformSave(gPlayState);
performSave = false;
- performDelayedSave = false;
}
}
}
@@ -675,7 +655,9 @@ void RegisterGrantGanonsBossKey() {
Player* player = GET_PLAYER(gPlayState);
// Triforce Hunt needs the check if the player isn't being teleported to the credits scene.
if (!GameInteractor::IsGameplayPaused() && Flags_GetRandomizerInf(RAND_INF_GRANT_GANONS_BOSSKEY) &&
- gPlayState->sceneLoadFlag != 0x14 && (1 << 0 & gSaveContext.inventory.dungeonItems[SCENE_GANONS_TOWER]) == 0) {
+ gPlayState->sceneLoadFlag != 0x14 &&
+ (1 << 0 & gSaveContext.inventory.dungeonItems[SCENE_GANONS_TOWER]) == 0 && player->stateFlags1 !=
+ PLAYER_STATE1_INPUT_DISABLED) {
GetItemEntry getItemEntry =
ItemTableManager::Instance->RetrieveItemEntry(MOD_RANDOMIZER, RG_GANONS_CASTLE_BOSS_KEY);
GiveItemEntryWithoutActor(gPlayState, getItemEntry);
diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp
index 9a3669582..d7f99edfb 100644
--- a/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp
+++ b/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp
@@ -783,7 +783,7 @@ std::map rcAreaNames = {
{ RCAREA_LAKE_HYLIA, "Lake Hylia"},
{ RCAREA_GERUDO_VALLEY, "Gerudo Valley"},
{ RCAREA_GERUDO_FORTRESS, "Gerudo Fortress"},
- { RCAREA_WASTELAND, "Desert Wasteland"},
+ { RCAREA_WASTELAND, "Haunted Wasteland"},
{ RCAREA_DESERT_COLOSSUS, "Desert Colossus"},
{ RCAREA_MARKET, "Hyrule Market"},
{ RCAREA_HYRULE_CASTLE, "Hyrule Castle"},
diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp
index 5f7790dd0..6123c1a27 100644
--- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp
+++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp
@@ -452,6 +452,63 @@ bool HasItemBeenCollected(RandomizerCheck rc) {
return false;
}
+void CheckTrackerLoadGame(int32_t fileNum) {
+ LoadSettings();
+ TrySetAreas();
+ for (auto [rc, rcObj] : RandomizerCheckObjects::GetAllRCObjects()) {
+ RandomizerCheckTrackerData rcTrackerData = gSaveContext.checkTrackerData[rc];
+ if (rc == RC_UNKNOWN_CHECK || rc == RC_MAX || rc == RC_LINKS_POCKET ||
+ !RandomizerCheckObjects::GetAllRCObjects().contains(rc))
+ continue;
+
+ RandomizerCheckObject realRcObj;
+ if (rc == RC_GIFT_FROM_SAGES && !IS_RANDO) {
+ realRcObj = RCO_RAORU;
+ } else {
+ realRcObj = rcObj;
+ }
+ if (!IsVisibleInCheckTracker(realRcObj)) continue;
+
+ checksByArea.find(realRcObj.rcArea)->second.push_back(realRcObj);
+ if (rcTrackerData.status == RCSHOW_SAVED || rcTrackerData.skipped) {
+ areaChecksGotten[realRcObj.rcArea]++;
+ }
+
+ if (areaChecksGotten[realRcObj.rcArea] != 0 || RandomizerCheckObjects::AreaIsOverworld(realRcObj.rcArea)) {
+ areasSpoiled |= (1 << realRcObj.rcArea);
+ }
+ }
+ if (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_LINKS_POCKET) != RO_LINKS_POCKET_NOTHING && IS_RANDO) {
+ s8 startingAge = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_STARTING_AGE);
+ RandomizerCheckArea startingArea;
+ switch (startingAge) {
+ case RO_AGE_CHILD:
+ startingArea = RCAREA_KOKIRI_FOREST;
+ break;
+ case RO_AGE_ADULT:
+ startingArea = RCAREA_MARKET;
+ break;
+ default:
+ startingArea = RCAREA_KOKIRI_FOREST;
+ break;
+ }
+ RandomizerCheckObject linksPocket = { RC_LINKS_POCKET, RCVORMQ_BOTH, RCTYPE_LINKS_POCKET, startingArea, ACTOR_ID_MAX, SCENE_ID_MAX, 0x00, GI_NONE, false, "Link's Pocket", "Link's Pocket" };
+
+ checksByArea.find(startingArea)->second.push_back(linksPocket);
+ areaChecksGotten[startingArea]++;
+ }
+
+ showVOrMQ = (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_RANDOM_NUMBER ||
+ (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_SET_NUMBER &&
+ OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_MQ_DUNGEON_COUNT) < 12));
+ LinksPocket();
+ SongFromImpa();
+ GiftFromSages();
+ initialized = true;
+ UpdateAllOrdering();
+ UpdateInventoryChecks();
+}
+
void CheckTrackerDialogClosed() {
if (messageCloseCheck) {
messageCloseCheck = false;
@@ -679,9 +736,6 @@ void SaveFile(SaveContext* saveContext, int sectionID, bool fullSave) {
}
void LoadFile() {
- Teardown();
- LoadSettings();
- TrySetAreas();
SaveManager::Instance->LoadArray("checks", RC_MAX, [](size_t i) {
SaveManager::Instance->LoadStruct("", [&]() {
SaveManager::Instance->LoadData("status", gSaveContext.checkTrackerData[i].status);
@@ -689,58 +743,7 @@ void LoadFile() {
SaveManager::Instance->LoadData("price", gSaveContext.checkTrackerData[i].price);
SaveManager::Instance->LoadData("hintItem", gSaveContext.checkTrackerData[i].hintItem);
});
- RandomizerCheckTrackerData entry = gSaveContext.checkTrackerData[i];
- RandomizerCheck rc = static_cast(i);
- if (rc == RC_UNKNOWN_CHECK || rc == RC_MAX ||
- !RandomizerCheckObjects::GetAllRCObjects().contains(rc))
- return;
-
- RandomizerCheckObject entry2;
- if (rc == RC_GIFT_FROM_SAGES && !IS_RANDO) {
- entry2 = RCO_RAORU;
- } else {
- entry2 = RandomizerCheckObjects::GetAllRCObjects().find(rc)->second;
- }
- if (!IsVisibleInCheckTracker(entry2)) return;
-
- checksByArea.find(entry2.rcArea)->second.push_back(entry2);
- if (entry.status == RCSHOW_SAVED || entry.skipped) {
- areaChecksGotten[entry2.rcArea]++;
- }
-
- if (areaChecksGotten[entry2.rcArea] != 0 || RandomizerCheckObjects::AreaIsOverworld(entry2.rcArea)) {
- areasSpoiled |= (1 << entry2.rcArea);
- }
});
- if (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_LINKS_POCKET) != RO_LINKS_POCKET_NOTHING && IS_RANDO) {
- s8 startingAge = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_STARTING_AGE);
- RandomizerCheckArea startingArea;
- switch (startingAge) {
- case RO_AGE_CHILD:
- startingArea = RCAREA_KOKIRI_FOREST;
- break;
- case RO_AGE_ADULT:
- startingArea = RCAREA_MARKET;
- break;
- default:
- startingArea = RCAREA_KOKIRI_FOREST;
- break;
- }
- RandomizerCheckObject linksPocket = { RC_LINKS_POCKET, RCVORMQ_BOTH, RCTYPE_LINKS_POCKET, startingArea, ACTOR_ID_MAX, SCENE_ID_MAX, 0x00, GI_NONE, false, "Link's Pocket", "Link's Pocket" };
-
- checksByArea.find(startingArea)->second.push_back(linksPocket);
- areaChecksGotten[startingArea]++;
- }
-
- showVOrMQ = (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_RANDOM_NUMBER ||
- (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_SET_NUMBER &&
- OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_MQ_DUNGEON_COUNT) < 12));
- LinksPocket();
- SongFromImpa();
- GiftFromSages();
- initialized = true;
- UpdateAllOrdering();
- UpdateInventoryChecks();
}
void Teardown() {
@@ -1533,6 +1536,7 @@ void CheckTrackerWindow::InitElement() {
SaveManager::Instance->AddInitFunction(InitTrackerData);
sectionId = SaveManager::Instance->AddSaveFunction("trackerData", 1, SaveFile, true, -1);
SaveManager::Instance->AddLoadFunction("trackerData", 1, LoadFile);
+ GameInteractor::Instance->RegisterGameHook(CheckTrackerLoadGame);
GameInteractor::Instance->RegisterGameHook([](uint32_t fileNum) {
Teardown();
});
diff --git a/soh/soh/Enhancements/randomizer/randomizer_tricks.cpp b/soh/soh/Enhancements/randomizer/randomizer_tricks.cpp
index 398077f6e..8a397f840 100644
--- a/soh/soh/Enhancements/randomizer/randomizer_tricks.cpp
+++ b/soh/soh/Enhancements/randomizer/randomizer_tricks.cpp
@@ -219,7 +219,7 @@ std::unordered_map rtAreaNames = {
{ RTAREA_LAKE_HYLIA, "Lake Hylia"},
{ RTAREA_GERUDO_VALLEY, "Gerudo Valley"},
{ RTAREA_GERUDO_FORTRESS, "Gerudo Fortress"},
- { RTAREA_WASTELAND, "Desert Wasteland"},
+ { RTAREA_WASTELAND, "Haunted Wasteland"},
{ RTAREA_DESERT_COLOSSUS, "Desert Colossus"},
{ RTAREA_MARKET, "Hyrule Market"},
{ RTAREA_HYRULE_CASTLE, "Hyrule Castle"},
diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp
index 0cb48bd69..c3bebe952 100644
--- a/soh/soh/OTRGlobals.cpp
+++ b/soh/soh/OTRGlobals.cpp
@@ -1566,6 +1566,11 @@ extern "C" Gfx* ResourceMgr_LoadGfxByName(const char* path)
return (Gfx*)&res->Instructions[0];
}
+extern "C" uint8_t ResourceMgr_FileIsCustomByName(const char* path) {
+ auto res = std::static_pointer_cast(GetResourceByNameHandlingMQ(path));
+ return res->GetInitData()->IsCustom;
+}
+
typedef struct {
int index;
Gfx instruction;
@@ -1597,6 +1602,11 @@ extern "C" void ResourceMgr_PatchGfxByName(const char* path, const char* patchNa
// index /= 2;
// }
+ // Do not patch custom assets as they most likely do not have the same instructions as authentic assets
+ if (res->GetInitData()->IsCustom) {
+ return;
+ }
+
Gfx* gfx = (Gfx*)&res->Instructions[index];
if (!originalGfx.contains(path) || !originalGfx[path].contains(patchName)) {
@@ -1613,6 +1623,11 @@ extern "C" void ResourceMgr_PatchGfxCopyCommandByName(const char* path, const ch
auto res = std::static_pointer_cast(
LUS::Context::GetInstance()->GetResourceManager()->LoadResource(path));
+ // Do not patch custom assets as they most likely do not have the same instructions as authentic assets
+ if (res->GetInitData()->IsCustom) {
+ return;
+ }
+
Gfx* destinationGfx = (Gfx*)&res->Instructions[destinationIndex];
Gfx sourceGfx = res->Instructions[sourceIndex];
diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h
index 82659dbc4..e00cfecd5 100644
--- a/soh/soh/OTRGlobals.h
+++ b/soh/soh/OTRGlobals.h
@@ -101,6 +101,7 @@ AnimationHeaderCommon* ResourceMgr_LoadAnimByName(const char* path);
char* ResourceMgr_GetNameByCRC(uint64_t crc, char* alloc);
Gfx* ResourceMgr_LoadGfxByCRC(uint64_t crc);
Gfx* ResourceMgr_LoadGfxByName(const char* path);
+uint8_t ResourceMgr_FileIsCustomByName(const char* path);
void ResourceMgr_PatchGfxByName(const char* path, const char* patchName, int index, Gfx instruction);
void ResourceMgr_UnpatchGfxByName(const char* path, const char* patchName);
char* ResourceMgr_LoadArrayByNameAsVec3s(const char* path);
diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp
index 14ab736dc..e61cf9223 100644
--- a/soh/soh/SaveManager.cpp
+++ b/soh/soh/SaveManager.cpp
@@ -47,6 +47,11 @@ std::filesystem::path SaveManager::GetFileName(int fileNum) {
return sSavePath / ("file" + std::to_string(fileNum + 1) + ".sav");
}
+std::filesystem::path SaveManager::GetFileTempName(int fileNum) {
+ const std::filesystem::path sSavePath(LUS::Context::GetPathRelativeToAppDirectory("Save"));
+ return sSavePath / ("file" + std::to_string(fileNum + 1) + ".temp");
+}
+
SaveManager::SaveManager() {
coreSectionIDsByName["base"] = SECTION_ID_BASE;
coreSectionIDsByName["randomizer"] = SECTION_ID_RANDOMIZER;
@@ -65,6 +70,10 @@ SaveManager::SaveManager() {
AddInitFunction(InitFileImpl);
+ GameInteractor::Instance->RegisterGameHook([this](uint32_t fileNum) { ThreadPoolWait(); });
+
+ smThreadPool = std::make_shared(1);
+
for (SaveFileMetaInfo& info : fileMetaInfo) {
info.valid = false;
info.deaths = 0;
@@ -357,12 +366,14 @@ void SaveManager::SaveRandomizer(SaveContext* saveContext, int sectionID, bool f
});
}
+// Init() here is an extension of InitSram, and thus not truly an initializer for SaveManager itself. don't put any class initialization stuff here
void SaveManager::Init() {
+ // Wait on saves that snuck through the Wait in OnExitGame
+ ThreadPoolWait();
const std::filesystem::path sSavePath(LUS::Context::GetPathRelativeToAppDirectory("Save"));
const std::filesystem::path sGlobalPath = sSavePath / std::string("global.sav");
auto sOldSavePath = LUS::Context::GetPathRelativeToAppDirectory("oot_save.sav");
auto sOldBackupSavePath = LUS::Context::GetPathRelativeToAppDirectory("oot_save.bak");
- GameInteractor::Instance->RegisterGameHook([this](uint32_t fileNum) { ThreadPoolWait(); });
// If the save directory does not exist, create it
if (!std::filesystem::exists(sSavePath)) {
@@ -403,7 +414,6 @@ void SaveManager::Init() {
} else {
CreateDefaultGlobal();
}
- smThreadPool = std::make_shared(1);
// Load files to initialize metadata
for (int fileNum = 0; fileNum < MaxFiles; fileNum++) {
@@ -869,6 +879,32 @@ void SaveManager::InitFileMaxed() {
gSaveContext.sceneFlags[5].swch = 0x40000000;
}
+#if defined(__WIIU__) || defined(__SWITCH__)
+// std::filesystem::copy_file doesn't work properly with the Wii U's toolchain atm
+int copy_file(const char* src, const char* dst) {
+ alignas(0x40) uint8_t buf[4096];
+ FILE* r = fopen(src, "r");
+ if (!r) {
+ return -1;
+ }
+ FILE* w = fopen(dst, "w");
+ if (!w) {
+ return -2;
+ }
+
+ size_t res;
+ while ((res = fread(buf, 1, sizeof(buf), r)) > 0) {
+ if (fwrite(buf, 1, res, w) != res) {
+ break;
+ }
+ }
+
+ fclose(r);
+ fclose(w);
+ return res >= 0 ? 0 : res;
+}
+#endif
+
// Threaded SaveFile takes copy of gSaveContext for local unmodified storage
void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, int sectionID) {
@@ -910,19 +946,42 @@ void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, int se
svi.func(saveContext, sectionID, false);
}
+ std::filesystem::path fileName = GetFileName(fileNum);
+ std::filesystem::path tempFile = GetFileTempName(fileNum);
+
+ if (std::filesystem::exists(tempFile)) {
+ std::filesystem::remove(tempFile);
+ }
+
#if defined(__SWITCH__) || defined(__WIIU__)
- FILE* w = fopen(GetFileName(fileNum).c_str(), "w");
+ FILE* w = fopen(tempFile.c_str(), "w");
std::string json_string = saveBlock.dump(4);
fwrite(json_string.c_str(), sizeof(char), json_string.length(), w);
fclose(w);
#else
- std::ofstream output(GetFileName(fileNum));
+ std::ofstream output(tempFile);
output << std::setw(4) << saveBlock << std::endl;
+ output.close();
#endif
+ if (std::filesystem::exists(fileName)) {
+ std::filesystem::remove(fileName);
+ }
+
+#if defined(__SWITCH__) || defined(__WIIU__)
+ copy_file(tempFile.c_str(), fileName.c_str());
+#else
+ std::filesystem::copy_file(tempFile, fileName);
+#endif
+
+ if (std::filesystem::exists(tempFile)) {
+ std::filesystem::remove(tempFile);
+ }
+
delete saveContext;
InitMeta(fileNum);
GameInteractor::Instance->ExecuteHooks(fileNum);
+ SPDLOG_INFO("Save File Finish - fileNum: {}", fileNum);
}
// SaveSection creates a copy of gSaveContext to prevent mid-save data modification, and passes its reference to SaveFileThreaded
@@ -2105,32 +2164,6 @@ void SaveManager::LoadStruct(const std::string& name, LoadStructFunc func) {
}
}
-#if defined(__WIIU__) || defined(__SWITCH__)
-// std::filesystem::copy_file doesn't work properly with the Wii U's toolchain atm
-int copy_file(const char* src, const char* dst) {
- alignas(0x40) uint8_t buf[4096];
- FILE* r = fopen(src, "r");
- if (!r) {
- return -1;
- }
- FILE* w = fopen(dst, "w");
- if (!w) {
- return -2;
- }
-
- size_t res;
- while ((res = fread(buf, 1, sizeof(buf), r)) > 0) {
- if (fwrite(buf, 1, res, w) != res) {
- break;
- }
- }
-
- fclose(r);
- fclose(w);
- return res >= 0 ? 0 : res;
-}
-#endif
-
void SaveManager::CopyZeldaFile(int from, int to) {
assert(std::filesystem::exists(GetFileName(from)));
DeleteZeldaFile(to);
diff --git a/soh/soh/SaveManager.h b/soh/soh/SaveManager.h
index 892aec923..310ecda7d 100644
--- a/soh/soh/SaveManager.h
+++ b/soh/soh/SaveManager.h
@@ -142,6 +142,7 @@ class SaveManager {
private:
std::filesystem::path GetFileName(int fileNum);
+ std::filesystem::path GetFileTempName(int fileNum);
nlohmann::json saveBlock;
void ConvertFromUnversioned();
diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp
index a5fc12299..598ec343d 100644
--- a/soh/soh/SohMenuBar.cpp
+++ b/soh/soh/SohMenuBar.cpp
@@ -532,6 +532,8 @@ void DrawEnhancementsMenu() {
" - Small keys: Small silver chest\n"
" - Boss keys: Vanilla size and texture\n"
" - Skulltula Tokens: Small skulltula chest\n"
+ "\n"
+ "NOTE: Textures will not apply if you are using a mod pack with a custom chest model."
);
if (CVarGetInteger("gChestSizeAndTextureMatchesContents", CSMC_DISABLED) != CSMC_DISABLED) {
UIWidgets::PaddedEnhancementCheckbox("Chests of Agony", "gChestSizeDependsStoneOfAgony", true, false);
@@ -913,6 +915,8 @@ void DrawEnhancementsMenu() {
UIWidgets::Tooltip("Disables grottos rotating with the camera. To be used in conjunction with mods that want to replace grottos with 3D objects.");
UIWidgets::PaddedEnhancementCheckbox("Invisible Bunny Hood", "gHideBunnyHood", true, false);
UIWidgets::Tooltip("Turns Bunny Hood invisible while still maintaining its effects.");
+ UIWidgets::PaddedEnhancementCheckbox("Disable HUD Heart animations", "gNoHUDHeartAnimation", true, false);
+ UIWidgets::Tooltip("Disables the beating animation of the hearts on the HUD.");
ImGui::EndMenu();
}
@@ -1059,6 +1063,8 @@ void DrawEnhancementsMenu() {
UIWidgets::Tooltip("Fixes the bushes to drop items correctly rather than spawning undefined items.");
UIWidgets::PaddedEnhancementCheckbox("Fix falling from vine edges", "gFixVineFall", true, false);
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::Tooltip("Fixes Link's eyes being open in the opening cutscene when he is supposed to be sleeping.");
ImGui::EndMenu();
}
diff --git a/soh/soh/resource/importer/SkeletonFactory.cpp b/soh/soh/resource/importer/SkeletonFactory.cpp
index 559da0cea..2ce651dee 100644
--- a/soh/soh/resource/importer/SkeletonFactory.cpp
+++ b/soh/soh/resource/importer/SkeletonFactory.cpp
@@ -103,38 +103,42 @@ void SkeletonFactoryV0::ParseFileXML(tinyxml2::XMLElement* reader, std::shared_p
{
std::shared_ptr skel = std::static_pointer_cast(resource);
- std::string skeletonType = reader->Attribute("Type");
- // std::string skeletonLimbType = reader->Attribute("LimbType");
- int numLimbs = reader->IntAttribute("LimbCount");
- int numDLs = reader->IntAttribute("DisplayListCount");
+ skel->type = SkeletonType::Flex; // Default to Flex for legacy reasons
+ if (reader->FindAttribute("Type")) {
+ std::string skeletonType = reader->Attribute("Type");
- if (skeletonType == "Flex") {
- skel->type = SkeletonType::Flex;
- } else if (skeletonType == "Curve") {
- skel->type = SkeletonType::Curve;
- } else if (skeletonType == "Normal") {
- skel->type = SkeletonType::Normal;
+ if (skeletonType == "Flex") {
+ skel->type = SkeletonType::Flex;
+ } else if (skeletonType == "Curve") {
+ skel->type = SkeletonType::Curve;
+ } else if (skeletonType == "Normal") {
+ skel->type = SkeletonType::Normal;
+ }
}
- skel->type = SkeletonType::Flex;
- skel->limbType = LimbType::LOD;
+ skel->limbType = LimbType::LOD; // Default to LOD for legacy reasons
+ if (reader->FindAttribute("LimbType")) {
+ std::string skeletonLimbType = reader->Attribute("LimbType");
- // if (skeletonLimbType == "Standard")
- // skel->limbType = LimbType::Standard;
- // else if (skeletonLimbType == "LOD")
- // skel->limbType = LimbType::LOD;
- // else if (skeletonLimbType == "Curve")
- // skel->limbType = LimbType::Curve;
- // else if (skeletonLimbType == "Skin")
- // skel->limbType = LimbType::Skin;
- // else if (skeletonLimbType == "Legacy")
- // Sskel->limbType = LimbType::Legacy;
+ if (skeletonLimbType == "Standard") {
+ skel->limbType = LimbType::Standard;
+ } else if (skeletonLimbType == "LOD") {
+ skel->limbType = LimbType::LOD;
+ } else if (skeletonLimbType == "Curve") {
+ skel->limbType = LimbType::Curve;
+ } else if (skeletonLimbType == "Skin") {
+ skel->limbType = LimbType::Skin;
+ } else if (skeletonLimbType == "Legacy") {
+ skel->limbType = LimbType::Legacy;
+ }
+ }
+
+
+ skel->limbCount = reader->IntAttribute("LimbCount");
+ skel->dListCount = reader->IntAttribute("DisplayListCount");
auto child = reader->FirstChildElement();
- skel->limbCount = numLimbs;
- skel->dListCount = numDLs;
-
while (child != nullptr) {
std::string childName = child->Name();
diff --git a/soh/src/code/code_80097A00.c b/soh/src/code/code_80097A00.c
index 9e20d66aa..eb83738e3 100644
--- a/soh/src/code/code_80097A00.c
+++ b/soh/src/code/code_80097A00.c
@@ -204,6 +204,17 @@ u8 Inventory_DeleteEquipment(PlayState* play, s16 equipment) {
if (equipment == EQUIP_TYPE_TUNIC) {
gSaveContext.equips.equipment |= EQUIP_VALUE_TUNIC_KOKIRI << (EQUIP_TYPE_TUNIC * 4);
+ // non-vanilla: remove goron and zora tunics from item buttons if assignable tunics is on
+ if (CVarGetInteger("gAssignableTunicsAndBoots", 0) && equipValue != EQUIP_VALUE_TUNIC_KOKIRI) {
+ ItemID item = (equipValue == EQUIP_VALUE_TUNIC_GORON ? ITEM_TUNIC_GORON : ITEM_TUNIC_ZORA);
+ for (int i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
+ if (gSaveContext.equips.buttonItems[i] == item) {
+ gSaveContext.equips.buttonItems[i] = ITEM_NONE;
+ gSaveContext.equips.cButtonSlots[i - 1] = SLOT_NONE;
+ }
+ }
+ }
+ // end non-vanilla
}
if (equipment == EQUIP_TYPE_SWORD) {
diff --git a/soh/src/code/z_lifemeter.c b/soh/src/code/z_lifemeter.c
index 8d5e41a20..69cba24b4 100644
--- a/soh/src/code/z_lifemeter.c
+++ b/soh/src/code/z_lifemeter.c
@@ -601,13 +601,24 @@ void HealthMeter_Draw(PlayState* play) {
{
Mtx* matrix = Graph_Alloc(gfxCtx, sizeof(Mtx));
- Matrix_SetTranslateScaleMtx2(matrix,
- HeartsScale+(HeartsScale/3) - ((HeartsScale/3) * sp144),
- HeartsScale+(HeartsScale/3) - ((HeartsScale/3) * sp144),
- HeartsScale+(HeartsScale/3) - ((HeartsScale/3) * sp144),
- -130+offsetX, //Pos X
- (-94+offsetY) *-1, //Pos Y
- 0.0f);
+
+ if (CVarGetInteger("gNoHUDHeartAnimation", 0)) {
+ Matrix_SetTranslateScaleMtx2(matrix,
+ HeartsScale, // Scale X
+ HeartsScale, // Scale Y
+ HeartsScale, // Scale Z
+ -130 + offsetX, // Pos X
+ (-94 + offsetY) * -1, // Pos Y
+ 0.0f);
+ } else {
+ Matrix_SetTranslateScaleMtx2(matrix, HeartsScale + (HeartsScale / 3) - ((HeartsScale / 3) * sp144),
+ HeartsScale + (HeartsScale / 3) - ((HeartsScale / 3) * sp144),
+ HeartsScale + (HeartsScale / 3) - ((HeartsScale / 3) * sp144),
+ -130 + offsetX, // Pos X
+ (-94 + offsetY) * -1, // Pos Y
+ 0.0f);
+ }
+
gSPMatrix(OVERLAY_DISP++, matrix, G_MTX_MODELVIEW | G_MTX_LOAD);
gSPVertex(OVERLAY_DISP++, sp154, 4, 0);
gSP1Quadrangle(OVERLAY_DISP++, 0, 2, 3, 1, 0);
diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c
index e972297f6..a2a86c03d 100644
--- a/soh/src/code/z_parameter.c
+++ b/soh/src/code/z_parameter.c
@@ -1469,6 +1469,7 @@ void Inventory_SwapAgeEquipment(void) {
gSaveContext.equips.buttonItems[0] = ITEM_SWORD_MASTER;
} else {
gSaveContext.equips.buttonItems[0] = ITEM_NONE;
+ Flags_SetInfTable(INFTABLE_SWORDLESS);
}
if (gSaveContext.inventory.items[SLOT_NUT] != ITEM_NONE) {
diff --git a/soh/src/code/z_play.c b/soh/src/code/z_play.c
index 2688cf46d..7cdb5f8dd 100644
--- a/soh/src/code/z_play.c
+++ b/soh/src/code/z_play.c
@@ -33,6 +33,7 @@ u64 D_801614D0[0xA00];
#endif
PlayState* gPlayState;
+s16 firstInit = 0;
s16 gEnPartnerId;
s16 gEnChristmasTreeId;
@@ -492,6 +493,12 @@ void Play_Init(GameState* thisx) {
}
}
+ // Properly initialize the frame counter so it doesn't use garbage data
+ if (!firstInit) {
+ play->gameplayFrames = 0;
+ firstInit = 1;
+ }
+
// Invalid entrance, so immediately exit the game to opening title
if (gSaveContext.entranceIndex == -1) {
gSaveContext.entranceIndex = 0;
@@ -762,7 +769,7 @@ void Play_Init(GameState* thisx) {
GET_PLAYER(play)->actor.world.pos.z, 0, 0, 0, 1, true);
}
- if (play->sceneNum == SCENE_KAKARIKO_VILLAGE && Randomizer_GetSettingValue(RSK_TRIFORCE_HUNT)) {
+ if (play->sceneNum == SCENE_KAKARIKO_VILLAGE) {
Actor_Spawn(&play->actorCtx, play, gEnChristmasTreeId, -734, 0, 420, 0, 0, 0, 0, true);
}
@@ -2337,8 +2344,28 @@ void Play_PerformSave(PlayState* play) {
if (play != NULL && gSaveContext.fileNum != 0xFF) {
Play_SaveSceneFlags(play);
gSaveContext.savedSceneNum = play->sceneNum;
+
+ // Track values from temp B
+ uint8_t prevB = gSaveContext.equips.buttonItems[0];
+ uint8_t prevStatus = gSaveContext.buttonStatus[0];
+
+ // Replicate the B button restore from minigames/epona that kaleido does
+ if (gSaveContext.equips.buttonItems[0] == ITEM_SLINGSHOT ||
+ gSaveContext.equips.buttonItems[0] == ITEM_BOW ||
+ gSaveContext.equips.buttonItems[0] == ITEM_BOMBCHU ||
+ gSaveContext.equips.buttonItems[0] == ITEM_FISHING_POLE ||
+ (gSaveContext.equips.buttonItems[0] == ITEM_NONE && !Flags_GetInfTable(INFTABLE_SWORDLESS))) {
+
+ gSaveContext.equips.buttonItems[0] = gSaveContext.buttonStatus[0];
+ Interface_RandoRestoreSwordless();
+ }
+
Save_SaveFile();
+ // Restore temp B values back
+ gSaveContext.equips.buttonItems[0] = prevB;
+ gSaveContext.buttonStatus[0] = prevStatus;
+
uint8_t triforceHuntCompleted =
IS_RANDO &&
gSaveContext.triforcePiecesCollected == Randomizer_GetSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED) &&
diff --git a/soh/src/overlays/actors/ovl_En_Box/z_en_box.c b/soh/src/overlays/actors/ovl_En_Box/z_en_box.c
index 1e2c4d6cd..9e8705c33 100644
--- a/soh/src/overlays/actors/ovl_En_Box/z_en_box.c
+++ b/soh/src/overlays/actors/ovl_En_Box/z_en_box.c
@@ -88,6 +88,7 @@ Gfx gKeyTreasureChestChestFrontDL[128] = {0};
Gfx gChristmasRedTreasureChestChestFrontDL[128] = {0};
Gfx gChristmasGreenTreasureChestChestFrontDL[128] = {0};
u8 hasCreatedRandoChestTextures = 0;
+u8 hasCustomChestDLs = 0;
u8 hasChristmasChestTexturesAvailable = 0;
void EnBox_SetupAction(EnBox* this, EnBoxActionFunc actionFunc) {
@@ -690,7 +691,7 @@ void EnBox_UpdateSizeAndTexture(EnBox* this, PlayState* play) {
}
// Change texture
- if (!isVanilla && (csmc == CSMC_BOTH || csmc == CSMC_TEXTURE)) {
+ if (!isVanilla && hasCreatedRandoChestTextures && !hasCustomChestDLs && (csmc == CSMC_BOTH || csmc == CSMC_TEXTURE)) {
switch (getItemCategory) {
case ITEM_CATEGORY_MAJOR:
this->boxBodyDL = gGoldTreasureChestChestFrontDL;
@@ -725,7 +726,7 @@ void EnBox_UpdateSizeAndTexture(EnBox* this, PlayState* play) {
}
}
- if (CVarGetInteger("gLetItSnow", 0) && hasChristmasChestTexturesAvailable) {
+ if (CVarGetInteger("gLetItSnow", 0) && hasChristmasChestTexturesAvailable && hasCreatedRandoChestTextures && !hasCustomChestDLs) {
if (this->dyna.actor.scale.x == 0.01f) {
this->boxBodyDL = gChristmasRedTreasureChestChestFrontDL;
this->boxLidDL = gChristmasRedTreasureChestChestSideAndLidDL;
@@ -767,7 +768,18 @@ void EnBox_UpdateSizeAndTexture(EnBox* this, PlayState* play) {
}
void EnBox_CreateExtraChestTextures() {
+ // Don't patch textures for custom chest models, as they do not import textures the exact same way as vanilla chests
+ // OTRTODO: Make it so model packs can provide a unique DL per chest type, instead of us copying the brown chest and attempting to patch
+ if (ResourceMgr_FileIsCustomByName(gTreasureChestChestFrontDL) ||
+ ResourceMgr_FileIsCustomByName(gTreasureChestChestSideAndLidDL)) {
+ hasCustomChestDLs = 1;
+ return;
+ }
+
+ hasCustomChestDLs = 0;
+
if (hasCreatedRandoChestTextures) return;
+
Gfx gTreasureChestChestTextures[] = {
gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gSkullTreasureChestFrontTex),
gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gSkullTreasureChestSideAndTopTex),
diff --git a/soh/src/overlays/actors/ovl_En_ChristmasDeco/z_en_christmasdeco.c b/soh/src/overlays/actors/ovl_En_ChristmasDeco/z_en_christmasdeco.c
index 49059b6bc..0b880b71b 100644
--- a/soh/src/overlays/actors/ovl_En_ChristmasDeco/z_en_christmasdeco.c
+++ b/soh/src/overlays/actors/ovl_En_ChristmasDeco/z_en_christmasdeco.c
@@ -13,7 +13,7 @@ void EnChristmasDeco_Update(Actor* thisx, PlayState* play);
void EnChristmasDeco_Draw(Actor* thisx, PlayState* play);
void EnChristmasDeco_Init(Actor* thisx, PlayState* play) {
-
+
}
void EnChristmasDeco_Destroy(Actor* thisx, PlayState* play) {
@@ -25,17 +25,24 @@ void EnChristmasDeco_Update(Actor* thisx, PlayState* play) {
}
void EnChristmasDeco_Draw(Actor* thisx, PlayState* play) {
- float decoSize = 1000.0f;
+ float decoSize = 10.0f;
OPEN_DISPS(play->state.gfxCtx);
Gfx_SetupDL_25Opa(play->state.gfxCtx);
Matrix_Scale(decoSize, decoSize, decoSize, MTXMODE_APPLY);
+
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__), G_MTX_MODELVIEW | G_MTX_LOAD);
+ // Assertion Halt in Debug mode, switch to Release when testing.
if (play->sceneNum == SCENE_KAKARIKO_VILLAGE) {
- gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gFrontGateDecorDL);
+ gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gKakarikoDecorDL);
+ if (LINK_IS_CHILD) {
+ gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gKakarikoChildDecorDL);
+ } else {
+ gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gKakarikoAdultDecorDL);
+ }
}
CLOSE_DISPS(play->state.gfxCtx);
diff --git a/soh/src/overlays/actors/ovl_En_ChristmasTree/z_en_christmastree.c b/soh/src/overlays/actors/ovl_En_ChristmasTree/z_en_christmastree.c
index 3ce1e1125..c18e2e098 100644
--- a/soh/src/overlays/actors/ovl_En_ChristmasTree/z_en_christmastree.c
+++ b/soh/src/overlays/actors/ovl_En_ChristmasTree/z_en_christmastree.c
@@ -34,7 +34,7 @@ static ColliderCylinderInit sCylinderInit = {
BUMP_NONE,
OCELEM_ON,
},
- { 50, 150, 0, { 0, 0, 0 } },
+ { 100, 330, 0, { 0, 0, 0 } },
};
static CollisionCheckInfoInit2 sColChkInfoInit = { 0, 0, 0, 0, MASS_IMMOVABLE };
@@ -42,7 +42,7 @@ static CollisionCheckInfoInit2 sColChkInfoInit = { 0, 0, 0, 0, MASS_IMMOVABLE };
void EnChristmasTree_Init(Actor* thisx, PlayState* play) {
EnChristmasTree* this = (EnChristmasTree*)thisx;
- ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 90.0f);
+ ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 160.0f);
Collider_InitCylinder(play, &this->collider);
Collider_SetCylinder(play, &this->collider, &this->actor, &sCylinderInit);
CollisionCheck_SetInfo2(&this->actor.colChkInfo, NULL, &sColChkInfoInit);
@@ -65,7 +65,7 @@ void EnChristmasTree_Destroy(Actor* thisx, PlayState* play) {
void EnChristmasTree_Wait(EnChristmasTree* this, PlayState* play) {
if (Actor_ProcessTalkRequest(&this->actor, play)) { // if talk is initiated
this->actionFunc = EnChristmasTree_Talk;
- } else if ((this->actor.xzDistToPlayer < 170.0f)) { // talk range
+ } else if ((this->actor.xzDistToPlayer < 170.0f) && Randomizer_GetSettingValue(RSK_TRIFORCE_HUNT)) { // talk range
func_8002F2CC(&this->actor, play, 170.0f);
}
}
@@ -91,21 +91,18 @@ void EnChristmasTree_Talk(EnChristmasTree* this, PlayState* play) {
void EnChristmasTree_SetupEndTitle(EnChristmasTree* this, PlayState* play) {
Player* player = GET_PLAYER(play);
- player->actor.world.pos.x = -929.336;
- player->actor.world.pos.y = 0;
- player->actor.world.pos.z = 446.178;
- player->actor.shape.rot.x = 0;
- player->actor.shape.rot.y = 17537;
- player->actor.shape.rot.z = 0;
-
GameInteractor_SetNoUIActive(1);
- Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_END_TITLE, 0, 0, 0, 0, 0, 0, 2, false);
+ Actor_Spawn(&play->actorCtx, play, ACTOR_END_TITLE, 0, 0, 0, 0, 0, 0, 2, false);
player->stateFlags1 = PLAYER_STATE1_INPUT_DISABLED;
Flags_SetRandomizerInf(RAND_INF_GRANT_GANONS_BOSSKEY);
+ Play_PerformSave(play);
+
+ Camera_ChangeMode(Play_GetCamera(play, play->mainCamera.thisIdx), CAM_MODE_STILL);
+
this->actionFunc = EnChristmasTree_Wait;
}
@@ -118,13 +115,26 @@ void EnChristmasTree_Update(Actor* thisx, PlayState* play) {
Actor_SetFocus(&this->actor, 80.0f);
+ uint8_t triforceHuntActive = Randomizer_GetSettingValue(RSK_TRIFORCE_HUNT);
+ float percentageCompleted = (float)gSaveContext.triforcePiecesCollected /
+ (float)Randomizer_GetSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED);
+
+ if ((percentageCompleted >= 1.0f || !triforceHuntActive) && !this->spawnedRupee) {
+ Actor_Spawn(&play->actorCtx, play, ACTOR_EN_WONDER_ITEM, this->actor.world.pos.x, this->actor.world.pos.y + 280,
+ this->actor.world.pos.z, 0, 0, LINK_IS_ADULT ? 1 : 4, 0x1ABF, false);
+ this->spawnedRupee = 1;
+ }
+
this->actionFunc(this, play);
}
void EnChristmasTree_Draw(Actor* thisx, PlayState* play) {
+ EnChristmasTree* this = (EnChristmasTree*)thisx;
+
+ float treeSize = 55.0f;
+ uint8_t triforceHuntActive = Randomizer_GetSettingValue(RSK_TRIFORCE_HUNT);
float percentageCompleted = (float)gSaveContext.triforcePiecesCollected /
(float)Randomizer_GetSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED);
- float treeSize = 30.0f;
OPEN_DISPS(play->state.gfxCtx);
@@ -135,34 +145,34 @@ void EnChristmasTree_Draw(Actor* thisx, PlayState* play) {
gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gXmasTreeDL);
- if (percentageCompleted >= 0.1f) {
+ if (percentageCompleted >= 0.1f || !triforceHuntActive) {
gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gXmasDecor10DL);
}
- if (percentageCompleted >= 0.2f) {
+ if (percentageCompleted >= 0.2f || !triforceHuntActive) {
gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gXmasDecor20DL);
}
- if (percentageCompleted >= 0.3f) {
+ if (percentageCompleted >= 0.3f || !triforceHuntActive) {
gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gXmasDecor30DL);
}
- if (percentageCompleted >= 0.4f) {
+ if (percentageCompleted >= 0.4f || !triforceHuntActive) {
gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gXmasDecor40DL);
}
- if (percentageCompleted >= 0.5f) {
+ if (percentageCompleted >= 0.5f || !triforceHuntActive) {
gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gXmasDecor50DL);
}
- if (percentageCompleted >= 0.6f) {
+ if (percentageCompleted >= 0.6f || !triforceHuntActive) {
gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gXmasDecor60DL);
}
- if (percentageCompleted >= 0.7f) {
+ if (percentageCompleted >= 0.7f || !triforceHuntActive) {
gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gXmasDecor70DL);
}
- if (percentageCompleted >= 0.8f) {
+ if (percentageCompleted >= 0.8f || !triforceHuntActive) {
gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gXmasDecor80DL);
}
- if (percentageCompleted >= 0.9f) {
+ if (percentageCompleted >= 0.9f || !triforceHuntActive) {
gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gXmasDecor90DL);
}
- if (percentageCompleted >= 1.0f) {
+ if (percentageCompleted >= 1.0f || !triforceHuntActive) {
gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gXmasDecor100DL);
gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gXmasStarDL);
}
diff --git a/soh/src/overlays/actors/ovl_En_ChristmasTree/z_en_christmastree.h b/soh/src/overlays/actors/ovl_En_ChristmasTree/z_en_christmastree.h
index 1dbed3396..fd580ac71 100644
--- a/soh/src/overlays/actors/ovl_En_ChristmasTree/z_en_christmastree.h
+++ b/soh/src/overlays/actors/ovl_En_ChristmasTree/z_en_christmastree.h
@@ -12,6 +12,7 @@ typedef struct EnChristmasTree {
Actor actor;
ColliderCylinder collider;
EnChristmasTreeActionFunc actionFunc;
+ u8 spawnedRupee;
} EnChristmasTree;
#ifdef __cplusplus
diff --git a/soh/src/overlays/actors/ovl_En_Hs2/z_en_hs2.c b/soh/src/overlays/actors/ovl_En_Hs2/z_en_hs2.c
index e2f16a611..deeeee1b9 100644
--- a/soh/src/overlays/actors/ovl_En_Hs2/z_en_hs2.c
+++ b/soh/src/overlays/actors/ovl_En_Hs2/z_en_hs2.c
@@ -66,7 +66,13 @@ void EnHs2_Init(Actor* thisx, PlayState* play) {
this->unk_2A8 = 0;
this->actor.targetMode = 6;
- Actor_Kill(this);
+ if (play->sceneNum == SCENE_KAKARIKO_VILLAGE) {
+ this->actor.world.pos.x = 756.0;
+ this->actor.world.pos.y = 80.0;
+ this->actor.world.pos.z = 1378.0;
+ this->actor.shape.rot.y = 32534;
+ }
+
}
void EnHs2_Destroy(Actor* thisx, PlayState* play) {
diff --git a/soh/src/overlays/actors/ovl_En_Hy/z_en_hy.c b/soh/src/overlays/actors/ovl_En_Hy/z_en_hy.c
index b790351e4..d51c7dd92 100644
--- a/soh/src/overlays/actors/ovl_En_Hy/z_en_hy.c
+++ b/soh/src/overlays/actors/ovl_En_Hy/z_en_hy.c
@@ -829,7 +829,7 @@ s32 EnHy_ShouldSpawn(EnHy* this, PlayState* play) {
} else if ((this->actor.params & 0x7F) != ENHY_TYPE_BOJ_12 && IS_NIGHT) {
return false;
} else {
- return false;
+ return true;
}
case SCENE_IMPAS_HOUSE:
if ((this->actor.params & 0x7F) != ENHY_TYPE_BOJ_10) {
@@ -898,6 +898,21 @@ void EnHy_Init(Actor* thisx, PlayState* play) {
Actor_Kill(&this->actor);
}
+ if (play->sceneNum == SCENE_KAKARIKO_VILLAGE) {
+ if (this->actor.params == 1929) {
+ this->actor.world.pos.x = 261.826;
+ this->actor.world.pos.y = 240.0;
+ this->actor.world.pos.z = 1669.660;
+ this->actor.shape.rot.y = 23784;
+ }
+ if (this->actor.params == 1930) {
+ this->actor.world.pos.x = 262.224;
+ this->actor.world.pos.y = 240.0;
+ this->actor.world.pos.z = 1594.390;
+ this->actor.shape.rot.y = 7728;
+ }
+ }
+
this->getItemEntry = (GetItemEntry)GET_ITEM_NONE;
this->actionFunc = EnHy_InitImpl;
}
diff --git a/soh/src/overlays/actors/ovl_En_Kusa/z_en_kusa.c b/soh/src/overlays/actors/ovl_En_Kusa/z_en_kusa.c
index 9f8af9c7b..5b743c7e1 100644
--- a/soh/src/overlays/actors/ovl_En_Kusa/z_en_kusa.c
+++ b/soh/src/overlays/actors/ovl_En_Kusa/z_en_kusa.c
@@ -267,11 +267,12 @@ void EnKusa_Init(Actor* thisx, PlayState* play) {
}
if (gPlayState->sceneNum == SCENE_KAKARIKO_VILLAGE && this->actor.world.pos.z < 600.0) {
- Actor_Kill(this);
- } else {
- EnKusa_SetupWaitObject(this);
+ this->actor.world.pos.x += 1620.672;
+ this->actor.world.pos.y += 80;
+ this->actor.world.pos.z += 900.884;
}
-
+
+ EnKusa_SetupWaitObject(this);
}
void EnKusa_Destroy(Actor* thisx, PlayState* play2) {
diff --git a/soh/src/overlays/actors/ovl_En_Toryo/z_en_toryo.c b/soh/src/overlays/actors/ovl_En_Toryo/z_en_toryo.c
index 929028fdd..9979c161a 100644
--- a/soh/src/overlays/actors/ovl_En_Toryo/z_en_toryo.c
+++ b/soh/src/overlays/actors/ovl_En_Toryo/z_en_toryo.c
@@ -105,7 +105,12 @@ void EnToryo_Init(Actor* thisx, PlayState* play) {
break;
case SCENE_KAKARIKO_VILLAGE:
if ((LINK_AGE_IN_YEARS == YEARS_CHILD) && IS_DAY) {
- Actor_Kill(this);
+ this->actor.world.pos.x = 756.0;
+ this->actor.world.pos.y = 80.0;
+ this->actor.world.pos.z = 1378.0;
+ this->actor.shape.rot.y = 32534;
+
+ this->stateFlags |= 2;
}
break;
case SCENE_KAKARIKO_CENTER_GUEST_HOUSE:
diff --git a/soh/src/overlays/actors/ovl_En_Wood02/z_en_wood02.c b/soh/src/overlays/actors/ovl_En_Wood02/z_en_wood02.c
index 13c1b3edf..e257a184d 100644
--- a/soh/src/overlays/actors/ovl_En_Wood02/z_en_wood02.c
+++ b/soh/src/overlays/actors/ovl_En_Wood02/z_en_wood02.c
@@ -173,16 +173,14 @@ void EnWood02_Init(Actor* thisx, PlayState* play2) {
f32 floorY;
s16 extraRot;
- if (Randomizer_GetSettingValue(RSK_TRIFORCE_HUNT) == 1) {
- if (gPlayState->sceneNum == SCENE_KAKARIKO_VILLAGE && this->actor.params <= WOOD_TREE_KAKARIKO_ADULT) {
- Actor_Kill(this);
- }
+ if (gPlayState->sceneNum == SCENE_KAKARIKO_VILLAGE && this->actor.params <= WOOD_TREE_KAKARIKO_ADULT) {
+ Actor_Kill(this);
+ }
- if (gPlayState->sceneNum == SCENE_KAKARIKO_VILLAGE && this->actor.params >= 0) {
- this->actor.world.pos.x = 754.051;
- this->actor.world.pos.y = 80.0;
- this->actor.world.pos.z = 1429.908;
- }
+ if (gPlayState->sceneNum == SCENE_KAKARIKO_VILLAGE && this->actor.params >= 0) {
+ this->actor.world.pos.x = 754.051;
+ this->actor.world.pos.y = 80.0;
+ this->actor.world.pos.z = 1429.908;
}
// The tree in Kakariko's day scene does not have the same params to spawn the GS
diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c
index 09e33f2e4..497935a69 100644
--- a/soh/src/overlays/actors/ovl_player_actor/z_player.c
+++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c
@@ -15169,6 +15169,10 @@ void func_80852C50(PlayState* play, Player* this, CsCmdActorAction* arg2) {
sp24 = D_808547C4[this->unk_446];
func_80852B4C(play, this, linkCsAction, &D_80854E50[ABS(sp24)]);
+
+ if (CVarGetInteger("gFixEyesOpenWhileSleeping", 0) && (play->csCtx.linkAction->action == 28 || play->csCtx.linkAction->action == 29)) {
+ this->skelAnime.jointTable[22].x = 8;
+ }
}
void func_80852E14(Player* this, PlayState* play) {
diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c
index 55a5075a6..35490f079 100644
--- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c
+++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c
@@ -4290,6 +4290,8 @@ void KaleidoScope_Update(PlayState* play)
if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) {
Grotto_ForceGrottoReturn();
}
+ // Reset frame counter to prevent autosave on respawn
+ play->gameplayFrames = 0;
gSaveContext.nextTransitionType = 2;
gSaveContext.health = CVarGetInteger("gFullHealthSpawn", 0) ? gSaveContext.healthCapacity : 0x30;
Audio_QueueSeqCmd(0xF << 28 | SEQ_PLAYER_BGM_MAIN << 24 | 0xA);