diff --git a/soh/assets/custom/objects/gameplay_holiday/BaubleHilite b/soh/assets/custom/objects/gameplay_holiday/BaubleHilite
new file mode 100644
index 0000000000..4cb27947f0
Binary files /dev/null and b/soh/assets/custom/objects/gameplay_holiday/BaubleHilite differ
diff --git a/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_bauble_b_f3dlite_BaubleBlue b/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_bauble_b_f3dlite_BaubleBlue
new file mode 100644
index 0000000000..9d8829650f
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_bauble_b_f3dlite_BaubleBlue
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_bauble_g_f3dlite_BaubleGreen b/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_bauble_g_f3dlite_BaubleGreen
new file mode 100644
index 0000000000..8ba44c27bd
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_bauble_g_f3dlite_BaubleGreen
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_bauble_r_f3dlite_BaubleRed b/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_bauble_r_f3dlite_BaubleRed
new file mode 100644
index 0000000000..539187c2af
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_bauble_r_f3dlite_BaubleRed
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_bauble_s_f3dlite_BaubleSilver b/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_bauble_s_f3dlite_BaubleSilver
new file mode 100644
index 0000000000..2c5de1ab2f
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_bauble_s_f3dlite_BaubleSilver
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_f3dlite_TreeBrown b/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_f3dlite_TreeBrown
new file mode 100644
index 0000000000..e8215b8916
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_f3dlite_TreeBrown
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_f3dlite_TreeGreen b/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_f3dlite_TreeGreen
new file mode 100644
index 0000000000..bb926c31e0
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_f3dlite_TreeGreen
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_presents_f3dlite_PresentBlue b/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_presents_f3dlite_PresentBlue
new file mode 100644
index 0000000000..95a98809cc
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_presents_f3dlite_PresentBlue
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_presents_f3dlite_PresentGreen b/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_presents_f3dlite_PresentGreen
new file mode 100644
index 0000000000..e6bea0b6c5
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_presents_f3dlite_PresentGreen
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_presents_f3dlite_PresentRed b/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_presents_f3dlite_PresentRed
new file mode 100644
index 0000000000..b42644ae81
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_presents_f3dlite_PresentRed
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_star_f3dlite_GoldStar b/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_star_f3dlite_GoldStar
new file mode 100644
index 0000000000..3d82334c6e
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/mat_xmas_tree_star_f3dlite_GoldStar
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree b/soh/assets/custom/objects/gameplay_holiday/xmas_tree
new file mode 100644
index 0000000000..2691067888
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_b b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_b
new file mode 100644
index 0000000000..4498e24fe7
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_b
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_b_tri_0 b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_b_tri_0
new file mode 100644
index 0000000000..792d47536e
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_b_tri_0
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_b_vtx_0 b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_b_vtx_0
new file mode 100644
index 0000000000..db948f00be
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_b_vtx_0
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_g b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_g
new file mode 100644
index 0000000000..fbb02006b7
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_g
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_g_tri_0 b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_g_tri_0
new file mode 100644
index 0000000000..471f208c6e
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_g_tri_0
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_g_vtx_0 b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_g_vtx_0
new file mode 100644
index 0000000000..3e9f85ec7f
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_g_vtx_0
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_r b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_r
new file mode 100644
index 0000000000..b93e0da35a
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_r
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_r_tri_0 b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_r_tri_0
new file mode 100644
index 0000000000..7aa1828a1b
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_r_tri_0
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_r_vtx_0 b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_r_vtx_0
new file mode 100644
index 0000000000..e8fc7a8dcd
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_r_vtx_0
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_s b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_s
new file mode 100644
index 0000000000..71f8877ae0
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_s
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_s_tri_0 b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_s_tri_0
new file mode 100644
index 0000000000..f88b6f2087
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_s_tri_0
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_s_vtx_0 b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_s_vtx_0
new file mode 100644
index 0000000000..653d4a071c
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_bauble_s_vtx_0
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_presents b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_presents
new file mode 100644
index 0000000000..458e405750
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_presents
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_presents_tri_0 b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_presents_tri_0
new file mode 100644
index 0000000000..3e2b4441fc
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_presents_tri_0
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_presents_tri_1 b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_presents_tri_1
new file mode 100644
index 0000000000..cecbe09a2b
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_presents_tri_1
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_presents_tri_2 b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_presents_tri_2
new file mode 100644
index 0000000000..efc528078e
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_presents_tri_2
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_presents_vtx_0 b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_presents_vtx_0
new file mode 100644
index 0000000000..fd5885c08c
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_presents_vtx_0
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_presents_vtx_1 b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_presents_vtx_1
new file mode 100644
index 0000000000..fdc4bf6e8a
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_presents_vtx_1
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_presents_vtx_2 b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_presents_vtx_2
new file mode 100644
index 0000000000..3c4703e1b6
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_presents_vtx_2
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_star b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_star
new file mode 100644
index 0000000000..4cefe078a1
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_star
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_star_tri_0 b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_star_tri_0
new file mode 100644
index 0000000000..73507855d1
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_star_tri_0
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_star_vtx_0 b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_star_vtx_0
new file mode 100644
index 0000000000..107d0a5c7d
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_star_vtx_0
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_tri_0 b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_tri_0
new file mode 100644
index 0000000000..688a578613
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_tri_0
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_tri_1 b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_tri_1
new file mode 100644
index 0000000000..34c37bef70
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_tri_1
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_vtx_0 b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_vtx_0
new file mode 100644
index 0000000000..6b65e8a813
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_vtx_0
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/gameplay_holiday/xmas_tree_vtx_1 b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_vtx_1
new file mode 100644
index 0000000000..23934fa7f5
--- /dev/null
+++ b/soh/assets/custom/objects/gameplay_holiday/xmas_tree_vtx_1
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/soh_assets.h b/soh/assets/soh_assets.h
index 2b193053c3..0eee73bb08 100644
--- a/soh/assets/soh_assets.h
+++ b/soh/assets/soh_assets.h
@@ -56,6 +56,27 @@ static const ALIGN_ASSET(2) char gTriforcePiece2DL[] = dgTriforcePiece2DL;
#define dgTriforcePieceCompletedDL "__OTR__objects/object_triforce_completed/gTriforcePieceCompletedDL"
static const ALIGN_ASSET(2) char gTriforcePieceCompletedDL[] = dgTriforcePieceCompletedDL;
+#define dxmas_tree "__OTR__objects/gameplay_holiday/xmas_tree"
+static const ALIGN_ASSET(2) char xmas_tree[] = dxmas_tree;
+
+#define dxmas_tree_presents "__OTR__objects/gameplay_holiday/xmas_tree_presents"
+static const ALIGN_ASSET(2) char xmas_tree_presents[] = dxmas_tree_presents;
+
+#define dxmas_tree_star "__OTR__objects/gameplay_holiday/xmas_tree_star"
+static const ALIGN_ASSET(2) char xmas_tree_star[] = dxmas_tree_star;
+
+#define dxmas_tree_bauble_r "__OTR__objects/gameplay_holiday/xmas_tree_bauble_r"
+static const ALIGN_ASSET(2) char xmas_tree_bauble_r[] = dxmas_tree_bauble_r;
+
+#define dxmas_tree_bauble_g "__OTR__objects/gameplay_holiday/xmas_tree_bauble_g"
+static const ALIGN_ASSET(2) char xmas_tree_bauble_g[] = dxmas_tree_bauble_g;
+
+#define dxmas_tree_bauble_b "__OTR__objects/gameplay_holiday/xmas_tree_bauble_b"
+static const ALIGN_ASSET(2) char xmas_tree_bauble_b[] = dxmas_tree_bauble_b;
+
+#define dxmas_tree_bauble_s "__OTR__objects/gameplay_holiday/xmas_tree_bauble_s"
+static const ALIGN_ASSET(2) char xmas_tree_bauble_s[] = dxmas_tree_bauble_s;
+
// overlays
#define dgOptionsDividerChangeLangVtx "__OTR__overlays/ovl_file_choose/gOptionsDividerChangeLangVtx"
static const ALIGN_ASSET(2) char gOptionsDividerChangeLangVtx[] = dgOptionsDividerChangeLangVtx;
diff --git a/soh/include/z64save.h b/soh/include/z64save.h
index 9458f28c7b..24ad694487 100644
--- a/soh/include/z64save.h
+++ b/soh/include/z64save.h
@@ -324,6 +324,7 @@ typedef struct {
/* */ u16 randomizerInf[10];
/* */ u16 adultTradeItems;
/* */ u8 triforcePiecesCollected;
+ /* */ u8 grantBossKey;
// #endregion
} SaveContext; // size = 0x1428
diff --git a/soh/soh/ActorDB.cpp b/soh/soh/ActorDB.cpp
index 2cf4d8fe77..4e36f5e51f 100644
--- a/soh/soh/ActorDB.cpp
+++ b/soh/soh/ActorDB.cpp
@@ -604,8 +604,25 @@ static ActorDBInit EnPartnerInit = {
};
extern "C" s16 gEnPartnerId;
+#include "src/overlays/actors/ovl_En_ChristmasTree/z_en_christmastree.h"
+static ActorDBInit EnChristmasTreeInit = {
+ "En_ChristmasTree",
+ "Christmas Tree",
+ ACTORCAT_PROP,
+ (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY),
+ OBJECT_GAMEPLAY_KEEP,
+ sizeof(EnChristmasTree),
+ (ActorFunc)EnChristmasTree_Init,
+ (ActorFunc)EnChristmasTree_Destroy,
+ (ActorFunc)EnChristmasTree_Update,
+ (ActorFunc)EnChristmasTree_Draw,
+ nullptr,
+};
+extern "C" s16 gEnChristmasTreeId;
+
void ActorDB::AddBuiltInCustomActors() {
gEnPartnerId = ActorDB::Instance->AddEntry(EnPartnerInit).entry.id;
+ gEnChristmasTreeId = ActorDB::Instance->AddEntry(EnChristmasTreeInit).entry.id;
}
extern "C" ActorDBEntry* ActorDB_Retrieve(const int id) {
diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp
index cb16a99151..945a826042 100644
--- a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp
+++ b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp
@@ -517,6 +517,11 @@ void DrawInfoTab() {
if (IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT)) {
ImGui::InputScalar("Triforce Pieces", ImGuiDataType_U16, &gSaveContext.triforcePiecesCollected);
UIWidgets::InsertHelpHoverText("Currently obtained Triforce Pieces. For Triforce Hunt.");
+
+ bool thFlag = gSaveContext.grantBossKey != 0;
+ if (ImGui::Checkbox("Finished Triforce Hunt", &thFlag)) {
+ gSaveContext.grantBossKey = thFlag;
+ }
}
ImGui::PushItemWidth(ImGui::GetFontSize() * 10);
diff --git a/soh/soh/Enhancements/mods.cpp b/soh/soh/Enhancements/mods.cpp
index 2cab1a754a..849dbbb1d3 100644
--- a/soh/soh/Enhancements/mods.cpp
+++ b/soh/soh/Enhancements/mods.cpp
@@ -656,12 +656,9 @@ void RegisterTriforceHunt() {
triforcePieceScale = 0.0f;
GameInteractor::State::TriforceHuntPieceGiven = 0;
}
-
- uint8_t currentPieces = gSaveContext.triforcePiecesCollected;
- uint8_t requiredPieces = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED);
// Give Boss Key when player loads back into the savefile.
- if (currentPieces >= requiredPieces && gPlayState->sceneLoadFlag != 0x14 &&
+ if (gSaveContext.grantBossKey &&
(1 << 0 & gSaveContext.inventory.dungeonItems[SCENE_GANONS_TOWER]) == 0) {
GetItemEntry getItemEntry = ItemTableManager::Instance->RetrieveItemEntry(MOD_RANDOMIZER, RG_GANONS_CASTLE_BOSS_KEY);
GiveItemEntryWithoutActor(gPlayState, getItemEntry);
diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp
index 1a46b03907..955bfc17af 100644
--- a/soh/soh/Enhancements/randomizer/randomizer.cpp
+++ b/soh/soh/Enhancements/randomizer/randomizer.cpp
@@ -60,6 +60,7 @@ const std::string Randomizer::hintMessageTableID = "RandomizerHints";
const std::string Randomizer::merchantMessageTableID = "RandomizerMerchants";
const std::string Randomizer::rupeeMessageTableID = "RandomizerRupees";
const std::string Randomizer::triforcePieceMessageTableID = "RandomizerTriforcePiece";
+const std::string Randomizer::christmasTreeMessageTableID = "RandomizerChristmasTree";
const std::string Randomizer::NaviRandoMessageTableID = "RandomizerNavi";
const std::string Randomizer::IceTrapRandoMessageTableID = "RandomizerIceTrap";
const std::string Randomizer::randoMiscHintsTableID = "RandomizerMiscHints";
@@ -5515,27 +5516,27 @@ CustomMessage Randomizer::GetRupeeMessage(u16 rupeeTextId) {
void CreateTriforcePieceMessages() {
CustomMessage TriforcePieceMessages[NUM_TRIFORCE_PIECE_MESSAGES] = {
- { "You found a %yTriforce Piece%w!&%g{{current}}%w down, %c{{remaining}}%w to go. It's a start!",
+ { "You found a %yChristmas Ornament%w!&%g{{current}}%w down, %c{{remaining}}%w to go. It's a start!",
"Ein %yTriforce-Splitter%w! Du hast&%g{{current}}%w von %c{{required}}%w gefunden. Es ist ein&Anfang!",
"Vous trouvez un %yFragment de la&Triforce%w! Vous en avez %g{{current}}%w, il en&reste %c{{remaining}}%w à trouver. C'est un début!" },
- { "You found a %yTriforce Piece%w!&%g{{current}}%w down, %c{{remaining}}%w to go. Progress!",
+ { "You found a %yChristmas Ornament%w!&%g{{current}}%w down, %c{{remaining}}%w to go. Progress!",
"Ein %yTriforce-Splitter%w! Du hast&%g{{current}}%w von %c{{required}}%w gefunden. Es geht voran!",
"Vous trouvez un %yFragment de la&Triforce%w! Vous en avez %g{{current}}%w, il en&reste %c{{remaining}}%w à trouver. Ça avance!" },
- { "You found a %yTriforce Piece%w!&%g{{current}}%w down, %c{{remaining}}%w to go. Over half-way&there!",
+ { "You found a %yChristmas Ornament%w!&%g{{current}}%w down, %c{{remaining}}%w to go. Over half-way&there!",
"Ein %yTriforce-Splitter%w! Du hast&schon %g{{current}}%w von %c{{required}}%w gefunden. Schon&über die Hälfte!",
"Vous trouvez un %yFragment de la&Triforce%w! Vous en avez %g{{current}}%w, il en&reste %c{{remaining}}%w à trouver. Il en reste un&peu moins que la moitié!" },
- { "You found a %yTriforce Piece%w!&%g{{current}}%w down, %c{{remaining}}%w to go. Almost done!",
+ { "You found a %yChristmas Ornament%w!&%g{{current}}%w down, %c{{remaining}}%w to go. Almost done!",
"Ein %yTriforce-Splitter%w! Du hast&schon %g{{current}}%w von %c{{required}}%w gefunden. Fast&geschafft!",
"Vous trouvez un %yFragment de la&Triforce%w! Vous en avez %g{{current}}%w, il en&reste %c{{remaining}}%w à trouver. C'est presque&terminé!" },
- { "You completed the %yTriforce of&Courage%w! %gGG%w!",
+ { "You found all of the %yChristmas&Ornaments%w! Visit the %gChristmas&tree%w in Kakariko Village!",
"Das %yTriforce des Mutes%w! Du hast&alle Splitter gefunden. %gGut gemacht%w!",
"Vous avez complété la %yTriforce&du Courage%w! %gFélicitations%w!" },
- { "You found a spare %yTriforce Piece%w!&You only needed %c{{required}}%w, but you have %g{{current}}%w!",
+ { "You found a spare %yChristmas Ornament%w!&You only needed %c{{required}}%w, but you have %g{{current}}%w!",
"Ein übriger %yTriforce-Splitter%w! Du&hast nun %g{{current}}%w von %c{{required}}%w nötigen gefunden.",
"Vous avez trouvé un %yFragment de&Triforce%w en plus! Vous n'aviez besoin&que de %c{{required}}%w, mais vous en avez %g{{current}}%w en&tout!" },
};
@@ -5575,6 +5576,39 @@ CustomMessage Randomizer::GetTriforcePieceMessage() {
messageEntry.Replace("{{required}}", std::to_string(required), std::to_string(required), std::to_string(required));
return messageEntry;
}
+void CreateChristmasTreeMessages() {
+ CustomMessage ChristmasTreeMessages[2] = {
+
+ { "The %yChristmas tree%w seems to be&missing some of %gits magic%w... Find all&ornaments to save %rChristmas%w!",
+ "The Christmas tree seems to be&missing some of its magic...",
+ "The Christmas tree seems to be&missing some of its magic..." },
+
+ { "The tree's magic has been fully&restored. %gMerry %rChristmas%w!",
+ "The tree's magic has been fully restored. Merry Christmas!",
+ "The tree's magic has been fully restored. Merry Christmas!" }
+ };
+ CustomMessageManager* customMessageManager = CustomMessageManager::Instance;
+ customMessageManager->AddCustomMessageTable(Randomizer::christmasTreeMessageTableID);
+ for (unsigned int i = 0; i <= 1; i++) {
+ customMessageManager->CreateMessage(Randomizer::christmasTreeMessageTableID, i, ChristmasTreeMessages[i]);
+ }
+}
+
+CustomMessage Randomizer::GetChristmasTreeMessage() {
+ // Item is only given after the textbox, so reflect that inside the textbox.
+ uint16_t current = gSaveContext.triforcePiecesCollected;
+ uint16_t required = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED);
+ uint8_t messageIndex;
+
+ if (current < required) {
+ messageIndex = 0;
+ } else {
+ messageIndex = 1;
+ }
+
+ CustomMessage messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::christmasTreeMessageTableID, messageIndex);
+ return messageEntry;
+}
void CreateNaviRandoMessages() {
CustomMessage NaviMessages[NUM_NAVI_MESSAGES] = {
@@ -6108,6 +6142,7 @@ void Randomizer::CreateCustomMessages() {
CreateGetItemMessages(&getItemMessages);
CreateRupeeMessages();
CreateTriforcePieceMessages();
+ CreateChristmasTreeMessages();
CreateNaviRandoMessages();
CreateIceTrapRandoMessages();
CreateFireTempleGoronMessages();
diff --git a/soh/soh/Enhancements/randomizer/randomizer.h b/soh/soh/Enhancements/randomizer/randomizer.h
index a726cecdee..3ad363d2a9 100644
--- a/soh/soh/Enhancements/randomizer/randomizer.h
+++ b/soh/soh/Enhancements/randomizer/randomizer.h
@@ -49,6 +49,7 @@ class Randomizer {
static const std::string merchantMessageTableID;
static const std::string rupeeMessageTableID;
static const std::string triforcePieceMessageTableID;
+ static const std::string christmasTreeMessageTableID;
static const std::string NaviRandoMessageTableID;
static const std::string IceTrapRandoMessageTableID;
static const std::string randoMiscHintsTableID;
@@ -105,6 +106,7 @@ class Randomizer {
static void CreateCustomMessages();
static CustomMessage GetRupeeMessage(u16 rupeeTextId);
static CustomMessage GetTriforcePieceMessage();
+ static CustomMessage GetChristmasTreeMessage();
bool CheckContainsVanillaItem(RandomizerCheck randoCheck);
};
diff --git a/soh/soh/Enhancements/randomizer/savefile.cpp b/soh/soh/Enhancements/randomizer/savefile.cpp
index 33278d0b75..fba89082a3 100644
--- a/soh/soh/Enhancements/randomizer/savefile.cpp
+++ b/soh/soh/Enhancements/randomizer/savefile.cpp
@@ -444,6 +444,7 @@ extern "C" void Randomizer_InitSaveFile() {
// Reset triforce pieces collected
gSaveContext.triforcePiecesCollected = 0;
+ gSaveContext.grantBossKey = 0;
SetStartingItems();
}
diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp
index eee6a622a9..d977b6202a 100644
--- a/soh/soh/OTRGlobals.cpp
+++ b/soh/soh/OTRGlobals.cpp
@@ -1968,7 +1968,9 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) {
s16 actorParams = 0;
if (IS_RANDO) {
Player* player = GET_PLAYER(play);
- if (textId == TEXT_RANDOMIZER_CUSTOM_ITEM) {
+ if (textId == 0x406B && play->sceneNum == SCENE_KAKARIKO_VILLAGE) {
+ messageEntry = Randomizer::GetChristmasTreeMessage();
+ } else if (textId == TEXT_RANDOMIZER_CUSTOM_ITEM) {
if (player->getItemEntry.getItemId == RG_ICE_TRAP) {
u16 iceTrapTextId = Random(0, NUM_ICE_TRAP_MESSAGES);
messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::IceTrapRandoMessageTableID, iceTrapTextId);
diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp
index bf1144b458..a2b3189d22 100644
--- a/soh/soh/SaveManager.cpp
+++ b/soh/soh/SaveManager.cpp
@@ -138,6 +138,8 @@ void SaveManager::LoadRandomizerVersion1() {
SaveManager::Instance->LoadData("triforcePiecesCollected", gSaveContext.triforcePiecesCollected);
+ SaveManager::Instance->LoadData("grantBossKey", gSaveContext.grantBossKey);
+
SaveManager::Instance->LoadData("pendingIceTrapCount", gSaveContext.pendingIceTrapCount);
std::shared_ptr randomizer = OTRGlobals::Instance->gRandomizer;
@@ -240,6 +242,8 @@ void SaveManager::LoadRandomizerVersion2() {
SaveManager::Instance->LoadData("triforcePiecesCollected", gSaveContext.triforcePiecesCollected);
+ SaveManager::Instance->LoadData("grantBossKey", gSaveContext.grantBossKey);
+
SaveManager::Instance->LoadData("pendingIceTrapCount", gSaveContext.pendingIceTrapCount);
std::shared_ptr randomizer = OTRGlobals::Instance->gRandomizer;
@@ -329,6 +333,8 @@ void SaveManager::SaveRandomizer(SaveContext* saveContext, int sectionID, bool f
SaveManager::Instance->SaveData("triforcePiecesCollected", saveContext->triforcePiecesCollected);
+ SaveManager::Instance->SaveData("grantBossKey", saveContext->grantBossKey);
+
SaveManager::Instance->SaveData("pendingIceTrapCount", saveContext->pendingIceTrapCount);
std::shared_ptr randomizer = OTRGlobals::Instance->gRandomizer;
diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c
index cf3192c3d6..cbc317f14f 100644
--- a/soh/src/code/z_parameter.c
+++ b/soh/src/code/z_parameter.c
@@ -2585,14 +2585,6 @@ u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) {
gSaveContext.triforcePiecesCollected++;
GameInteractor_SetTriforceHuntPieceGiven(true);
- // Teleport to credits when goal is reached.
- if (gSaveContext.triforcePiecesCollected == Randomizer_GetSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED)) {
- gSaveContext.sohStats.itemTimestamp[TIMESTAMP_TRIFORCE_COMPLETED] = GAMEPLAYSTAT_TOTAL_TIME;
- gSaveContext.sohStats.gameComplete = 1;
- Play_PerformSave(play);
- GameInteractor_SetTriforceHuntCreditsWarpActive(true);
- }
-
return Return_Item_Entry(giEntry, RG_NONE);
}
diff --git a/soh/src/code/z_play.c b/soh/src/code/z_play.c
index 112a71888f..de13f78e94 100644
--- a/soh/src/code/z_play.c
+++ b/soh/src/code/z_play.c
@@ -35,6 +35,7 @@ u64 D_801614D0[0xA00];
PlayState* gPlayState;
s16 gEnPartnerId;
+s16 gEnChristmasTreeId;
void OTRPlay_SpawnScene(PlayState* play, s32 sceneNum, s32 spawn);
@@ -759,6 +760,10 @@ void Play_Init(GameState* thisx) {
GET_PLAYER(play)->actor.world.pos.y + Player_GetHeight(GET_PLAYER(play)) + 5.0f,
GET_PLAYER(play)->actor.world.pos.z, 0, 0, 0, 1, true);
}
+
+ if (play->sceneNum == SCENE_KAKARIKO_VILLAGE && Randomizer_GetSettingValue(RSK_TRIFORCE_HUNT)) {
+ Actor_Spawn(&play->actorCtx, play, gEnChristmasTreeId, -734, 0, 420, 0, 0, 0, 1, true);
+ }
}
void Play_Update(PlayState* play) {
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
new file mode 100644
index 0000000000..f67812fe6d
--- /dev/null
+++ b/soh/src/overlays/actors/ovl_En_ChristmasTree/z_en_christmastree.c
@@ -0,0 +1,134 @@
+/*
+ * File: z_en_christmastree.c
+ * Overlay: ovl_En_ChristmasTree
+ * Description: Custom Christmas Tree for Ornament Hunt
+ */
+
+#include "z_en_christmastree.h"
+#include "soh_assets.h"
+
+void EnChristmasTree_Init(Actor* thisx, PlayState* play);
+void EnChristmasTree_Destroy(Actor* thisx, PlayState* play);
+void EnChristmasTree_Update(Actor* thisx, PlayState* play);
+void EnChristmasTree_Draw(Actor* thisx, PlayState* play);
+
+void EnChristmasTree_Wait(EnChristmasTree* this, PlayState* play);
+void EnChristmasTree_Talk(EnChristmasTree* this, PlayState* play);
+
+static ColliderCylinderInit sCylinderInit = {
+ {
+ COLTYPE_NONE,
+ AT_NONE,
+ AC_NONE,
+ OC1_ON | OC1_TYPE_ALL,
+ OC2_TYPE_2,
+ COLSHAPE_CYLINDER,
+ },
+ {
+ ELEMTYPE_UNK0,
+ { 0x00000000, 0x00, 0x00 },
+ { 0x00000000, 0x00, 0x00 },
+ TOUCH_NONE,
+ BUMP_NONE,
+ OCELEM_ON,
+ },
+ { 50, 150, 0, { 0, 0, 0 } },
+};
+
+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);
+ Collider_InitCylinder(play, &this->collider);
+ Collider_SetCylinder(play, &this->collider, &this->actor, &sCylinderInit);
+ CollisionCheck_SetInfo2(&this->actor.colChkInfo, NULL, &sColChkInfoInit);
+ Actor_UpdateBgCheckInfo(play, &this->actor, 0.0f, 0.0f, 0.0f, 4);
+
+ this->actor.targetMode = 1;
+ this->actor.textId = 0x406B; // Hijacking bean seller text ID so I'm sure it doesn't clash
+
+ this->actionFunc = EnChristmasTree_Wait;
+}
+
+void EnChristmasTree_Destroy(Actor* thisx, PlayState* play) {
+ EnChristmasTree* this = (EnChristmasTree*)thisx;
+
+ Collider_DestroyCylinder(play, &this->collider);
+}
+
+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
+ func_8002F2CC(&this->actor, play, 170.0f);
+ }
+}
+
+void EnChristmasTree_Talk(EnChristmasTree* this, PlayState* play) {
+ u8 dialogState = Message_GetState(&play->msgCtx);
+ if (dialogState != TEXT_STATE_CHOICE) {
+ if ((dialogState == TEXT_STATE_DONE) && Message_ShouldAdvance(play)) { // advanced final textbox
+ this->actionFunc = EnChristmasTree_Wait;
+
+ // Teleport to credits when goal is reached.
+ if (gSaveContext.triforcePiecesCollected >= Randomizer_GetSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED)) {
+ gSaveContext.sohStats.itemTimestamp[TIMESTAMP_TRIFORCE_COMPLETED] = GAMEPLAYSTAT_TOTAL_TIME;
+ gSaveContext.sohStats.gameComplete = 1;
+ gSaveContext.grantBossKey = 1;
+ Play_PerformSave(play);
+ GameInteractor_SetTriforceHuntCreditsWarpActive(true);
+ }
+ }
+ }
+
+
+}
+
+void EnChristmasTree_Update(Actor* thisx, PlayState* play) {
+ EnChristmasTree* this = (EnChristmasTree*)thisx;
+ ColliderCylinder* collider = &this->collider;
+
+ Collider_UpdateCylinder(thisx, collider);
+ CollisionCheck_SetOC(play, &play->colChkCtx, (Collider*)collider);
+
+ Actor_SetFocus(&this->actor, 80.0f);
+
+ this->actionFunc(this, play);
+}
+
+void EnChristmasTree_Draw(Actor* thisx, PlayState* play) {
+ float percentageCompleted = (float)gSaveContext.triforcePiecesCollected /
+ (float)Randomizer_GetSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED);
+ float treeSize = 30.0f;
+
+ OPEN_DISPS(play->state.gfxCtx);
+
+ Gfx_SetupDL_25Xlu(play->state.gfxCtx);
+
+ Matrix_Scale(treeSize, treeSize, treeSize, MTXMODE_APPLY);
+ gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__),
+ G_MTX_MODELVIEW | G_MTX_LOAD);
+ gSPDisplayList(POLY_XLU_DISP++, (Gfx*)xmas_tree);
+ if (percentageCompleted >= 0.17f) {
+ gSPDisplayList(POLY_XLU_DISP++, (Gfx*)xmas_tree_presents);
+ }
+ if (percentageCompleted >= 0.34f) {
+ gSPDisplayList(POLY_XLU_DISP++, (Gfx*)xmas_tree_bauble_r);
+ }
+ if (percentageCompleted >= 0.51f) {
+ gSPDisplayList(POLY_XLU_DISP++, (Gfx*)xmas_tree_bauble_g);
+ }
+ if (percentageCompleted >= 0.68f) {
+ gSPDisplayList(POLY_XLU_DISP++, (Gfx*)xmas_tree_bauble_b);
+ }
+ if (percentageCompleted >= 0.85f) {
+ gSPDisplayList(POLY_XLU_DISP++, (Gfx*)xmas_tree_bauble_s);
+ }
+ if (percentageCompleted >= 1.0f) {
+ gSPDisplayList(POLY_XLU_DISP++, (Gfx*)xmas_tree_star);
+ }
+
+ CLOSE_DISPS(play->state.gfxCtx);
+}
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
new file mode 100644
index 0000000000..1dbed3396b
--- /dev/null
+++ b/soh/src/overlays/actors/ovl_En_ChristmasTree/z_en_christmastree.h
@@ -0,0 +1,28 @@
+#ifndef Z_EN_CHRISTMASTREE_H
+#define Z_EN_CHRISTMASTREE_H
+
+#include
+#include "global.h"
+
+struct EnChristmasTree;
+
+typedef void (*EnChristmasTreeActionFunc)(struct EnChristmasTree*, PlayState*);
+
+typedef struct EnChristmasTree {
+ Actor actor;
+ ColliderCylinder collider;
+ EnChristmasTreeActionFunc actionFunc;
+} EnChristmasTree;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void EnChristmasTree_Init(Actor* thisx, PlayState* play);
+void EnChristmasTree_Destroy(Actor* thisx, PlayState* play);
+void EnChristmasTree_Update(Actor* thisx, PlayState* play);
+void EnChristmasTree_Draw(Actor* thisx, PlayState* play);
+#ifdef __cplusplus
+}
+#endif
+
+#endif