diff --git a/soh/assets/objects/gameplay_keep/gameplay_keep.h b/soh/assets/objects/gameplay_keep/gameplay_keep.h
index 6377e165d..638125397 100644
--- a/soh/assets/objects/gameplay_keep/gameplay_keep.h
+++ b/soh/assets/objects/gameplay_keep/gameplay_keep.h
@@ -21,6 +21,9 @@ static const ALIGN_ASSET(2) char gHilite1Tex[] = dgHilite1Tex;
#define dgHilite2Tex "__OTR__objects/gameplay_keep/gHilite2Tex"
static const ALIGN_ASSET(2) char gHilite2Tex[] = dgHilite2Tex;
+#define dgHilite2Tex_Overflow "__OTR__objects/gameplay_keep/gHilite2Tex_Overflow"
+static const ALIGN_ASSET(2) char gHilite2Tex_Overflow[] = dgHilite2Tex_Overflow;
+
#define dgHylianShieldDesignTex "__OTR__objects/gameplay_keep/gHylianShieldDesignTex"
static const ALIGN_ASSET(2) char gHylianShieldDesignTex[] = dgHylianShieldDesignTex;
diff --git a/soh/assets/xml/GC_MQ_D/objects/gameplay_keep.xml b/soh/assets/xml/GC_MQ_D/objects/gameplay_keep.xml
index 992525114..4a071ef98 100644
--- a/soh/assets/xml/GC_MQ_D/objects/gameplay_keep.xml
+++ b/soh/assets/xml/GC_MQ_D/objects/gameplay_keep.xml
@@ -7,6 +7,8 @@
+
+
diff --git a/soh/assets/xml/GC_MQ_PAL_F/objects/gameplay_keep.xml b/soh/assets/xml/GC_MQ_PAL_F/objects/gameplay_keep.xml
index 5ffc52f65..882422884 100644
--- a/soh/assets/xml/GC_MQ_PAL_F/objects/gameplay_keep.xml
+++ b/soh/assets/xml/GC_MQ_PAL_F/objects/gameplay_keep.xml
@@ -7,6 +7,8 @@
+
+
diff --git a/soh/assets/xml/GC_NMQ_D/objects/gameplay_keep.xml b/soh/assets/xml/GC_NMQ_D/objects/gameplay_keep.xml
index 5ffc52f65..905f5d272 100644
--- a/soh/assets/xml/GC_NMQ_D/objects/gameplay_keep.xml
+++ b/soh/assets/xml/GC_NMQ_D/objects/gameplay_keep.xml
@@ -7,6 +7,8 @@
+
+
diff --git a/soh/assets/xml/GC_NMQ_PAL_F/objects/gameplay_keep.xml b/soh/assets/xml/GC_NMQ_PAL_F/objects/gameplay_keep.xml
index 5ffc52f65..882422884 100644
--- a/soh/assets/xml/GC_NMQ_PAL_F/objects/gameplay_keep.xml
+++ b/soh/assets/xml/GC_NMQ_PAL_F/objects/gameplay_keep.xml
@@ -7,6 +7,8 @@
+
+
diff --git a/soh/assets/xml/N64_PAL_10/objects/gameplay_keep.xml b/soh/assets/xml/N64_PAL_10/objects/gameplay_keep.xml
index 5ffc52f65..882422884 100644
--- a/soh/assets/xml/N64_PAL_10/objects/gameplay_keep.xml
+++ b/soh/assets/xml/N64_PAL_10/objects/gameplay_keep.xml
@@ -7,6 +7,8 @@
+
+
diff --git a/soh/assets/xml/N64_PAL_11/objects/gameplay_keep.xml b/soh/assets/xml/N64_PAL_11/objects/gameplay_keep.xml
index 5ffc52f65..882422884 100644
--- a/soh/assets/xml/N64_PAL_11/objects/gameplay_keep.xml
+++ b/soh/assets/xml/N64_PAL_11/objects/gameplay_keep.xml
@@ -7,6 +7,8 @@
+
+
diff --git a/soh/soh/Enhancements/cosmetics/authenticGfxPatches.cpp b/soh/soh/Enhancements/cosmetics/authenticGfxPatches.cpp
index aad43a99d..0738ff6da 100644
--- a/soh/soh/Enhancements/cosmetics/authenticGfxPatches.cpp
+++ b/soh/soh/Enhancements/cosmetics/authenticGfxPatches.cpp
@@ -65,6 +65,63 @@ static DListPatchInfo ironKnuckleDListPatchInfos[] = {
{ object_ik_DL_01D638, 110 },
};
+static DListPatchInfo arrowTipDListPatchInfos[] = {
+ { gArrowNearDL, 46 },
+ { gArrowFarDL, 5 },
+};
+
+void PatchArrowTipTexture() {
+ // Custom texture for Arrow tips that accounts for overflow texture reading
+ Gfx arrowTipTextureWithOverflowFixGfx =
+ gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b_LOAD_BLOCK, 1, gHilite2Tex_Overflow);
+
+ // Gfx instructions to fix authentic vanilla bug where the Arrow tips texture is read as the wrong size
+ Gfx arrowTipTextureWithSizeFixGfx[] = {
+ gsDPLoadTextureBlock(gHilite2Tex, G_IM_FMT_RGBA, G_IM_SIZ_16b, 16, 16, 0, G_TX_MIRROR | G_TX_WRAP,
+ G_TX_MIRROR | G_TX_WRAP, 5, 5, 1, 1),
+ };
+
+ bool fixTexturesOOB = CVarGetInteger(CVAR_ENHANCEMENT("FixTexturesOOB"), 0);
+
+ for (const auto& patchInfo : arrowTipDListPatchInfos) {
+ const char* dlist = patchInfo.dlist;
+ int start = patchInfo.startInstruction;
+
+ // Patch using custom overflowed texture
+ if (!fixTexturesOOB) {
+ // Unpatch the other texture fix
+ for (size_t i = 4; i < 8; i++) {
+ int instruction = start + i;
+ std::string unpatchName = "arrowTipTextureWithSizeFix_" + std::to_string(instruction);
+ ResourceMgr_UnpatchGfxByName(dlist, unpatchName.c_str());
+ }
+
+ std::string patchName = "arrowTipTextureWithOverflowFix_" + std::to_string(start);
+ std::string patchName2 = "arrowTipTextureWithOverflowFix_" + std::to_string(start + 1);
+ ResourceMgr_PatchGfxByName(dlist, patchName.c_str(), start, arrowTipTextureWithOverflowFixGfx);
+ ResourceMgr_PatchGfxByName(dlist, patchName2.c_str(), start + 1, gsSPNoOp());
+ } else { // Patch texture to use correct image size/fmt
+ // Unpatch the other texture fix
+ std::string unpatchName = "arrowTipTextureWithOverflowFix_" + std::to_string(start);
+ std::string unpatchName2 = "arrowTipTextureWithOverflowFix_" + std::to_string(start + 1);
+ ResourceMgr_UnpatchGfxByName(dlist, unpatchName.c_str());
+ ResourceMgr_UnpatchGfxByName(dlist, unpatchName2.c_str());
+
+ for (size_t i = 4; i < 8; i++) {
+ int instruction = start + i;
+ std::string patchName = "arrowTipTextureWithSizeFix_" + std::to_string(instruction);
+
+ if (i == 0) {
+ ResourceMgr_PatchGfxByName(dlist, patchName.c_str(), instruction, gsSPNoOp());
+ } else {
+ ResourceMgr_PatchGfxByName(dlist, patchName.c_str(), instruction,
+ arrowTipTextureWithSizeFixGfx[i - 1]);
+ }
+ }
+ }
+ }
+}
+
void PatchDekuStickTextureOverflow() {
// Custom texture for holding Deku Stick that accounts for overflow texture reading
Gfx dekuSticTexkWithOverflowFixGfx = gsDPSetTextureImage(G_IM_FMT_I, G_IM_SIZ_8b, 1, gDekuStickOverflowTex);
@@ -216,6 +273,7 @@ void PatchIronKnuckleTextureOverflow() {
}
void ApplyAuthenticGfxPatches() {
+ PatchArrowTipTexture();
PatchDekuStickTextureOverflow();
PatchFreezardTextureOverflow();
PatchIronKnuckleTextureOverflow();