From ac569baeaca6cb917cb77d4c03d393f947f3d58d Mon Sep 17 00:00:00 2001 From: Unreference <87878910+unreference@users.noreply.github.com> Date: Tue, 12 May 2026 11:31:09 -0700 Subject: [PATCH 1/7] fix(actors): Initialize En_Dnt_Nomal flower position before draw --- soh/src/overlays/actors/ovl_En_Dnt_Nomal/z_en_dnt_nomal.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/soh/src/overlays/actors/ovl_En_Dnt_Nomal/z_en_dnt_nomal.c b/soh/src/overlays/actors/ovl_En_Dnt_Nomal/z_en_dnt_nomal.c index 4e66ac0bf3b..79483d1f94a 100644 --- a/soh/src/overlays/actors/ovl_En_Dnt_Nomal/z_en_dnt_nomal.c +++ b/soh/src/overlays/actors/ovl_En_Dnt_Nomal/z_en_dnt_nomal.c @@ -189,6 +189,10 @@ void EnDntNomal_WaitForObject(EnDntNomal* this, PlayState* play) { this->morphTable, 11); this->actor.draw = EnDntNomal_DrawStageScrub; } + + // Draw is now enabled but SetFlower hasn't run yet (it waits for ground contact). Default flowerPos to the + // actor's spawn position so the flower doesn't render at the origin for the intervening frames. + this->flowerPos = this->actor.world.pos; this->actionFunc = EnDntNomal_SetFlower; } } @@ -887,4 +891,4 @@ void EnDntNomal_DrawTargetScrub(Actor* thisx, PlayState* play) { gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_OPA_DISP++, gHintNutsFlowerDL); CLOSE_DISPS(play->state.gfxCtx); -} +} \ No newline at end of file From ad0db341de977d92fd4749d84e25762d5dba916d Mon Sep 17 00:00:00 2001 From: Unreference <87878910+unreference@users.noreply.github.com> Date: Wed, 13 May 2026 07:39:57 -0700 Subject: [PATCH 2/7] chore: Add issue link for clarification --- soh/src/overlays/actors/ovl_En_Dnt_Nomal/z_en_dnt_nomal.c | 1 + 1 file changed, 1 insertion(+) diff --git a/soh/src/overlays/actors/ovl_En_Dnt_Nomal/z_en_dnt_nomal.c b/soh/src/overlays/actors/ovl_En_Dnt_Nomal/z_en_dnt_nomal.c index 79483d1f94a..2246b65beb6 100644 --- a/soh/src/overlays/actors/ovl_En_Dnt_Nomal/z_en_dnt_nomal.c +++ b/soh/src/overlays/actors/ovl_En_Dnt_Nomal/z_en_dnt_nomal.c @@ -190,6 +190,7 @@ void EnDntNomal_WaitForObject(EnDntNomal* this, PlayState* play) { this->actor.draw = EnDntNomal_DrawStageScrub; } + // https://github.com/HarbourMasters/Shipwright/issues/2796 // Draw is now enabled but SetFlower hasn't run yet (it waits for ground contact). Default flowerPos to the // actor's spawn position so the flower doesn't render at the origin for the intervening frames. this->flowerPos = this->actor.world.pos; From 96662c0d5b64f09e298f818d3f2bd7127387d8fe Mon Sep 17 00:00:00 2001 From: Unreference <87878910+unreference@users.noreply.github.com> Date: Thu, 14 May 2026 00:01:49 -0700 Subject: [PATCH 3/7] fix: Move flowerPos initialization to Init --- .../overlays/actors/ovl_En_Dnt_Nomal/z_en_dnt_nomal.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/soh/src/overlays/actors/ovl_En_Dnt_Nomal/z_en_dnt_nomal.c b/soh/src/overlays/actors/ovl_En_Dnt_Nomal/z_en_dnt_nomal.c index 2246b65beb6..831a298f17c 100644 --- a/soh/src/overlays/actors/ovl_En_Dnt_Nomal/z_en_dnt_nomal.c +++ b/soh/src/overlays/actors/ovl_En_Dnt_Nomal/z_en_dnt_nomal.c @@ -157,6 +157,11 @@ void EnDntNomal_Init(Actor* thisx, PlayState* play) { } else { Actor_Kill(&this->actor); } + + // https://github.com/HarbourMasters/Shipwright/issues/2796 + // Default flowerPos to the actor's spawn position so the flower doesn't render at the origin if the draw function + // is enabled before SetFlower position (which waits for ground contact) has a chance to set the real position. + this->flowerPos = this->actor.world.pos; this->actionFunc = EnDntNomal_WaitForObject; } @@ -190,10 +195,6 @@ void EnDntNomal_WaitForObject(EnDntNomal* this, PlayState* play) { this->actor.draw = EnDntNomal_DrawStageScrub; } - // https://github.com/HarbourMasters/Shipwright/issues/2796 - // Draw is now enabled but SetFlower hasn't run yet (it waits for ground contact). Default flowerPos to the - // actor's spawn position so the flower doesn't render at the origin for the intervening frames. - this->flowerPos = this->actor.world.pos; this->actionFunc = EnDntNomal_SetFlower; } } From 90309e9be3f9d7c7b62fb079c280568e45e6a99a Mon Sep 17 00:00:00 2001 From: Unreference <87878910+unreference@users.noreply.github.com> Date: Sun, 17 May 2026 09:47:16 -0700 Subject: [PATCH 4/7] Revert "fix(actors): Initialize En_Dnt_Nomal flower position before draw" This reverts commit ac569baeaca6cb917cb77d4c03d393f947f3d58d. # Conflicts: # soh/src/overlays/actors/ovl_En_Dnt_Nomal/z_en_dnt_nomal.c --- soh/src/overlays/actors/ovl_En_Dnt_Nomal/z_en_dnt_nomal.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/soh/src/overlays/actors/ovl_En_Dnt_Nomal/z_en_dnt_nomal.c b/soh/src/overlays/actors/ovl_En_Dnt_Nomal/z_en_dnt_nomal.c index 831a298f17c..4e66ac0bf3b 100644 --- a/soh/src/overlays/actors/ovl_En_Dnt_Nomal/z_en_dnt_nomal.c +++ b/soh/src/overlays/actors/ovl_En_Dnt_Nomal/z_en_dnt_nomal.c @@ -157,11 +157,6 @@ void EnDntNomal_Init(Actor* thisx, PlayState* play) { } else { Actor_Kill(&this->actor); } - - // https://github.com/HarbourMasters/Shipwright/issues/2796 - // Default flowerPos to the actor's spawn position so the flower doesn't render at the origin if the draw function - // is enabled before SetFlower position (which waits for ground contact) has a chance to set the real position. - this->flowerPos = this->actor.world.pos; this->actionFunc = EnDntNomal_WaitForObject; } @@ -194,7 +189,6 @@ void EnDntNomal_WaitForObject(EnDntNomal* this, PlayState* play) { this->morphTable, 11); this->actor.draw = EnDntNomal_DrawStageScrub; } - this->actionFunc = EnDntNomal_SetFlower; } } @@ -893,4 +887,4 @@ void EnDntNomal_DrawTargetScrub(Actor* thisx, PlayState* play) { gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_OPA_DISP++, gHintNutsFlowerDL); CLOSE_DISPS(play->state.gfxCtx); -} \ No newline at end of file +} From cf95552e4b9c33aa70c8010ee65dd8406f3963cc Mon Sep 17 00:00:00 2001 From: Unreference <87878910+unreference@users.noreply.github.com> Date: Sun, 17 May 2026 10:20:13 -0700 Subject: [PATCH 5/7] feat(enhancement): OnActorInit hook for fixing Deku Scrub flower flash --- .../Fixes/FixDekuScrubFlowerFlash.cpp | 20 +++++++++++++++++++ soh/soh/SohGui/SohMenuEnhancements.cpp | 4 ++++ 2 files changed, 24 insertions(+) create mode 100644 soh/soh/Enhancements/Fixes/FixDekuScrubFlowerFlash.cpp diff --git a/soh/soh/Enhancements/Fixes/FixDekuScrubFlowerFlash.cpp b/soh/soh/Enhancements/Fixes/FixDekuScrubFlowerFlash.cpp new file mode 100644 index 00000000000..22e569475f4 --- /dev/null +++ b/soh/soh/Enhancements/Fixes/FixDekuScrubFlowerFlash.cpp @@ -0,0 +1,20 @@ +#include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/ShipInit.hpp" + +extern "C" { +#include "src/overlays/actors/ovl_En_Dnt_Nomal/z_en_dnt_nomal.h" +} + +#define CVAR_DEKU_SCRUB_FLOWER_FLASH_FIX_NAME CVAR_ENHANCEMENT("FixDekuScrubFlowerFlash") +#define CVAR_DEKU_SCRUB_FLOWER_FLASH_FIX_VALUE CVarGetInteger(CVAR_DEKU_SCRUB_FLOWER_FLASH_FIX_NAME, 0) + +static void FixDekuScrubFlowerFlash(void* actorRef) { + const auto enDntNomal = static_cast(actorRef); + enDntNomal->flowerPos = enDntNomal->actor.world.pos; +} + +static void RegisterFixDekuScrubFlowerFlash() { + COND_ID_HOOK(OnActorInit, ACTOR_EN_DNT_NOMAL, CVAR_DEKU_SCRUB_FLOWER_FLASH_FIX_VALUE, FixDekuScrubFlowerFlash); +} + +static RegisterShipInitFunc initFunc(RegisterFixDekuScrubFlowerFlash, { CVAR_DEKU_SCRUB_FLOWER_FLASH_FIX_NAME }); diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp index fc4f9f95c80..b9a54547840 100644 --- a/soh/soh/SohGui/SohMenuEnhancements.cpp +++ b/soh/soh/SohGui/SohMenuEnhancements.cpp @@ -1136,6 +1136,10 @@ void SohMenu::AddMenuEnhancements() { .RaceDisable(false) .Options(CheckboxOptions().Tooltip( "Fixes Adult Link having a backwards Left hand when holding the Megaton Hammer.")); + AddWidget(path, "Fix Deku Scrub Flower Flash", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FixDekuScrubFlowerFlash")) + .Options(CheckboxOptions().Tooltip( + "Fixes the Deku Scrub flower flashing briefly at the Lost Woods entrance.")); AddWidget(path, "Fix Vanishing Paths", WIDGET_CVAR_COMBOBOX) .CVar(CVAR_ENHANCEMENT("SceneSpecificDirtPathFix")) .RaceDisable(false) From 895f82d3abe392207af689a4020fc46fd95d0a91 Mon Sep 17 00:00:00 2001 From: Unreference <87878910+unreference@users.noreply.github.com> Date: Sun, 17 May 2026 10:24:13 -0700 Subject: [PATCH 6/7] chore: Link issue for reference --- soh/soh/Enhancements/Fixes/FixDekuScrubFlowerFlash.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/soh/soh/Enhancements/Fixes/FixDekuScrubFlowerFlash.cpp b/soh/soh/Enhancements/Fixes/FixDekuScrubFlowerFlash.cpp index 22e569475f4..e732c6ae082 100644 --- a/soh/soh/Enhancements/Fixes/FixDekuScrubFlowerFlash.cpp +++ b/soh/soh/Enhancements/Fixes/FixDekuScrubFlowerFlash.cpp @@ -8,6 +8,14 @@ extern "C" { #define CVAR_DEKU_SCRUB_FLOWER_FLASH_FIX_NAME CVAR_ENHANCEMENT("FixDekuScrubFlowerFlash") #define CVAR_DEKU_SCRUB_FLOWER_FLASH_FIX_VALUE CVarGetInteger(CVAR_DEKU_SCRUB_FLOWER_FLASH_FIX_NAME, 0) +// https://github.com/HarbourMasters/Shipwright/issues/2796 +// +// En_Dnt_Nomal enables its draw function in WaitForObject but doesn't set flowerPos until SetFlower (which waits for +// ground contact). Both draw functions use flowerPos with MTXMODE_NEW, so the flower renders at the zero-initialized +// origin for the intervening frames. +// +// Defaulting flowerPos to the actor's spawn position closes the gap. + static void FixDekuScrubFlowerFlash(void* actorRef) { const auto enDntNomal = static_cast(actorRef); enDntNomal->flowerPos = enDntNomal->actor.world.pos; From fdb3f9908b9cf87f3e3bfbe64018db078daead3c Mon Sep 17 00:00:00 2001 From: Unreference <87878910+unreference@users.noreply.github.com> Date: Sun, 17 May 2026 11:19:00 -0700 Subject: [PATCH 7/7] chore: Clang format --- soh/soh/Enhancements/Fixes/FixDekuScrubFlowerFlash.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/soh/Enhancements/Fixes/FixDekuScrubFlowerFlash.cpp b/soh/soh/Enhancements/Fixes/FixDekuScrubFlowerFlash.cpp index e732c6ae082..9f8a4614bd6 100644 --- a/soh/soh/Enhancements/Fixes/FixDekuScrubFlowerFlash.cpp +++ b/soh/soh/Enhancements/Fixes/FixDekuScrubFlowerFlash.cpp @@ -25,4 +25,4 @@ static void RegisterFixDekuScrubFlowerFlash() { COND_ID_HOOK(OnActorInit, ACTOR_EN_DNT_NOMAL, CVAR_DEKU_SCRUB_FLOWER_FLASH_FIX_VALUE, FixDekuScrubFlowerFlash); } -static RegisterShipInitFunc initFunc(RegisterFixDekuScrubFlowerFlash, { CVAR_DEKU_SCRUB_FLOWER_FLASH_FIX_NAME }); +static RegisterShipInitFunc initFunc(RegisterFixDekuScrubFlowerFlash, { CVAR_DEKU_SCRUB_FLOWER_FLASH_FIX_NAME }); \ No newline at end of file