From 64442a98a751d7f2a9767a772e9801184c111343 Mon Sep 17 00:00:00 2001 From: djevangelia Date: Sun, 28 Jun 2026 17:35:44 +0200 Subject: [PATCH 1/5] Allow fishing with blank B, always-on --- soh/soh/Enhancements/AlwaysOnFixes.cpp | 21 +++++++++++++++++++ .../vanilla-behavior/GIVanillaBehavior.h | 17 +++++++++++++++ .../actors/ovl_player_actor/z_player.c | 12 ++++++++--- 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/soh/soh/Enhancements/AlwaysOnFixes.cpp b/soh/soh/Enhancements/AlwaysOnFixes.cpp index f6452ffd48a..c65626b133f 100644 --- a/soh/soh/Enhancements/AlwaysOnFixes.cpp +++ b/soh/soh/Enhancements/AlwaysOnFixes.cpp @@ -7,6 +7,7 @@ extern "C" { #include "variables.h" extern void Player_UseItem(PlayState*, Player*, s32); extern PlayState* gPlayState; +extern SaveContext gSaveContext; } // Dying or using Din's Fire in the Outside Temple of Time area crashes the game. @@ -57,7 +58,27 @@ void RegisterPreventHookshotParentSoftlock() { }); } +// Vanilla bug: Not possible to fish with blank B because the blank B item value 0xFF gets saved +// as temp B, which also makes B button disabled - fishing pole gets unequipped. +// Fix: Disregard disabled B when fishing, and set used item to fishing pole on B press. +void RegisterAllowBlankBFishing() { + COND_VB_SHOULD(VB_ALLOW_BLANK_B_FISHING_EQUIP, true, { + if (gPlayState->interfaceCtx.unk_260 != 0 && gSaveContext.equips.buttonItems[0] == ITEM_FISHING_POLE) { + *should = false; + } + }); + + COND_VB_SHOULD(VB_ALLOW_BLANK_B_FISHING_ITEM, true, { + s32* i = va_arg(args, s32*); + Player* player = va_arg(args, Player*); + if (gPlayState->interfaceCtx.unk_260 != 0 && i == 0 && player->itemAction == PLAYER_IA_FISHING_POLE) { + *should = true; + } + }); +} + static RegisterShipInitFunc initFuncFixOutsideTotCrash(RegisterFixOutsideTotCrash, { "" }); static RegisterShipInitFunc initFuncFixDekuShieldDropCrash(RegisterFixDekuShieldDropCrash, { "" }); static RegisterShipInitFunc initFuncHookshotNospawnSoftlock(RegisterPreventHookshotNoSpawnSoftlock, { "" }); static RegisterShipInitFunc initFuncHookshotParentSoftlock(RegisterPreventHookshotParentSoftlock, { "" }); +static RegisterShipInitFunc initAllowBlankBFishing(RegisterAllowBlankBFishing, { "" }); diff --git a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h index 6e3f9e4a193..15ccf3a336f 100644 --- a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h +++ b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h @@ -3111,6 +3111,23 @@ typedef enum { // - `s16* (&this->actor.parent->id)` VB_PREVENT_HOOKSHOT_PARENT_SOFTLOCK, + // #### `result` + // ```c + // false if gPlayState->interfaceCtx.unk_260 != 0 && gSaveContext.equips.buttonItems[0] == ITEM_FISHING_POLE + // ``` + // #### `args` + // - none + VB_ALLOW_BLANK_B_FISHING_EQUIP, + + // #### `result` + // ```c + // gPlayState->interfaceCtx.unk_260 != 0 && i == 0 && player->itemAction == PLAYER_IA_FISHING_POLE + // ``` + // #### `args` + // - `s32* i` + // - `Player*` + VB_ALLOW_BLANK_B_FISHING_ITEM, + // true // ``` // #### `args` 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 171cb09ac68..2131ceb35ad 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -2523,8 +2523,10 @@ void Player_ProcessItemButtons(Player* this, PlayState* play) { } if (!Player_ItemIsInUse(this, B_BTN_ITEM) && !Player_ItemIsInUse(this, C_BTN_ITEM(0)) && !Player_ItemIsInUse(this, C_BTN_ITEM(1)) && !Player_ItemIsInUse(this, C_BTN_ITEM(2)) && !hasOnDpad) { - Player_UseItem(play, this, ITEM_NONE); - return; + if (GameInteractor_Should(VB_ALLOW_BLANK_B_FISHING_EQUIP, true)) { + Player_UseItem(play, this, ITEM_NONE); + return; + } } } @@ -2534,7 +2536,11 @@ void Player_ProcessItemButtons(Player* this, PlayState* play) { } } - item = Player_GetItemOnButton(play, i); + if (GameInteractor_Should(VB_ALLOW_BLANK_B_FISHING_ITEM, false, i, this)) { + item = ITEM_FISHING_POLE; + } else { + item = Player_GetItemOnButton(play, i); + } if (item >= ITEM_NONE_FE) { for (i = 0; i < ARRAY_COUNT(sItemButtons); i++) { From 54eb43c3298dc396f12420fe9bd69545c8ba3530 Mon Sep 17 00:00:00 2001 From: djevangelia Date: Sun, 28 Jun 2026 22:58:00 +0200 Subject: [PATCH 2/5] Blank B fishing, enhancement setting --- soh/soh/Enhancements/AlwaysOnFixes.cpp | 21 --------------------- soh/soh/Enhancements/Fishing.cpp | 23 ++++++++++++++++++++++- soh/soh/SohGui/SohMenuEnhancements.cpp | 4 ++++ 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/soh/soh/Enhancements/AlwaysOnFixes.cpp b/soh/soh/Enhancements/AlwaysOnFixes.cpp index c65626b133f..f6452ffd48a 100644 --- a/soh/soh/Enhancements/AlwaysOnFixes.cpp +++ b/soh/soh/Enhancements/AlwaysOnFixes.cpp @@ -7,7 +7,6 @@ extern "C" { #include "variables.h" extern void Player_UseItem(PlayState*, Player*, s32); extern PlayState* gPlayState; -extern SaveContext gSaveContext; } // Dying or using Din's Fire in the Outside Temple of Time area crashes the game. @@ -58,27 +57,7 @@ void RegisterPreventHookshotParentSoftlock() { }); } -// Vanilla bug: Not possible to fish with blank B because the blank B item value 0xFF gets saved -// as temp B, which also makes B button disabled - fishing pole gets unequipped. -// Fix: Disregard disabled B when fishing, and set used item to fishing pole on B press. -void RegisterAllowBlankBFishing() { - COND_VB_SHOULD(VB_ALLOW_BLANK_B_FISHING_EQUIP, true, { - if (gPlayState->interfaceCtx.unk_260 != 0 && gSaveContext.equips.buttonItems[0] == ITEM_FISHING_POLE) { - *should = false; - } - }); - - COND_VB_SHOULD(VB_ALLOW_BLANK_B_FISHING_ITEM, true, { - s32* i = va_arg(args, s32*); - Player* player = va_arg(args, Player*); - if (gPlayState->interfaceCtx.unk_260 != 0 && i == 0 && player->itemAction == PLAYER_IA_FISHING_POLE) { - *should = true; - } - }); -} - static RegisterShipInitFunc initFuncFixOutsideTotCrash(RegisterFixOutsideTotCrash, { "" }); static RegisterShipInitFunc initFuncFixDekuShieldDropCrash(RegisterFixDekuShieldDropCrash, { "" }); static RegisterShipInitFunc initFuncHookshotNospawnSoftlock(RegisterPreventHookshotNoSpawnSoftlock, { "" }); static RegisterShipInitFunc initFuncHookshotParentSoftlock(RegisterPreventHookshotParentSoftlock, { "" }); -static RegisterShipInitFunc initAllowBlankBFishing(RegisterAllowBlankBFishing, { "" }); diff --git a/soh/soh/Enhancements/Fishing.cpp b/soh/soh/Enhancements/Fishing.cpp index 98235c8d415..ea9a41a6f48 100644 --- a/soh/soh/Enhancements/Fishing.cpp +++ b/soh/soh/Enhancements/Fishing.cpp @@ -3,7 +3,8 @@ extern "C" { #include - +extern PlayState* gPlayState; +extern SaveContext gSaveContext; f32 Fishing_GetMinimumRequiredScore(); } @@ -18,4 +19,24 @@ void RegisterFishingMessages() { COND_ID_HOOK(OnOpenText, 0x4080, CVarGetInteger(CVAR_ENHANCEMENT("CustomizeFishing"), 0), BuildFishingMessage); } +// Vanilla bug: Not possible to fish with blank B because the blank B item value 0xFF gets saved +// as temp B, which also makes B button disabled - fishing pole gets unequipped. +// Fix: Disregard disabled B when fishing, and set used item to fishing pole on B press. +void RegisterAllowFishingBlankB() { + COND_VB_SHOULD(VB_ALLOW_BLANK_B_FISHING_EQUIP, (IS_RANDO || CVarGetInteger(CVAR_ENHANCEMENT("FishingBlankB"), 0)), { + if (gPlayState->interfaceCtx.unk_260 != 0 && gSaveContext.equips.buttonItems[0] == ITEM_FISHING_POLE) { + *should = false; + } + }); + + COND_VB_SHOULD(VB_ALLOW_BLANK_B_FISHING_ITEM, (IS_RANDO || CVarGetInteger(CVAR_ENHANCEMENT("FishingBlankB"), 0)), { + s32* i = va_arg(args, s32*); + Player* player = va_arg(args, Player*); + if (gPlayState->interfaceCtx.unk_260 != 0 && i == 0 && player->itemAction == PLAYER_IA_FISHING_POLE) { + *should = true; + } + }); +} + static RegisterShipInitFunc initFunc(RegisterFishingMessages, { CVAR_ENHANCEMENT("CustomizeFishing") }); +static RegisterShipInitFunc initAllowFishingBlankB(RegisterAllowFishingBlankB, { CVAR_ENHANCEMENT("FishingBlankB"), "IS_RANDO" }); diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp index afdb28730d9..a3b3ccdf526 100644 --- a/soh/soh/SohGui/SohMenuEnhancements.cpp +++ b/soh/soh/SohGui/SohMenuEnhancements.cpp @@ -1633,6 +1633,10 @@ void SohMenu::AddMenuEnhancements() { .PreFunc(fishingDisabledFunc) .Options(IntSliderOptions().Min(6).Max(13).DefaultValue(13).Format("%d lbs.").Tooltip( "The minimum weight for the unique fishing reward as an adult.")); + AddWidget(path, "Allow fishing with blank B", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FishingBlankB")) + .Options(CheckboxOptions().Tooltip("Allow fishing even when not having any item equipped on the B button, " + "fixing a vanilla bug.")); // Extra Modes path.sidebarName = "Extra Modes"; From ff053382d25c5f298d9495e6cf15f624e4f8f1b6 Mon Sep 17 00:00:00 2001 From: djevangelia Date: Sun, 28 Jun 2026 23:01:03 +0200 Subject: [PATCH 3/5] Fishing blank B format --- soh/soh/Enhancements/Fishing.cpp | 3 ++- soh/soh/SohGui/SohMenuEnhancements.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/soh/soh/Enhancements/Fishing.cpp b/soh/soh/Enhancements/Fishing.cpp index ea9a41a6f48..cbc6d515333 100644 --- a/soh/soh/Enhancements/Fishing.cpp +++ b/soh/soh/Enhancements/Fishing.cpp @@ -39,4 +39,5 @@ void RegisterAllowFishingBlankB() { } static RegisterShipInitFunc initFunc(RegisterFishingMessages, { CVAR_ENHANCEMENT("CustomizeFishing") }); -static RegisterShipInitFunc initAllowFishingBlankB(RegisterAllowFishingBlankB, { CVAR_ENHANCEMENT("FishingBlankB"), "IS_RANDO" }); +static RegisterShipInitFunc initAllowFishingBlankB(RegisterAllowFishingBlankB, + { CVAR_ENHANCEMENT("FishingBlankB"), "IS_RANDO" }); diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp index a3b3ccdf526..eb71864b39d 100644 --- a/soh/soh/SohGui/SohMenuEnhancements.cpp +++ b/soh/soh/SohGui/SohMenuEnhancements.cpp @@ -1636,7 +1636,7 @@ void SohMenu::AddMenuEnhancements() { AddWidget(path, "Allow fishing with blank B", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("FishingBlankB")) .Options(CheckboxOptions().Tooltip("Allow fishing even when not having any item equipped on the B button, " - "fixing a vanilla bug.")); + "fixing a vanilla bug.")); // Extra Modes path.sidebarName = "Extra Modes"; From 3d1d2b6882836ba0d7c23a220e024f3ddacc4a93 Mon Sep 17 00:00:00 2001 From: djevangelia Date: Mon, 29 Jun 2026 12:11:55 +0200 Subject: [PATCH 4/5] Blank B fishing, hook calls GetItemOnButton --- soh/soh/Enhancements/Fishing.cpp | 11 ++++++++--- soh/soh/SohGui/SohMenuEnhancements.cpp | 2 +- soh/src/overlays/actors/ovl_player_actor/z_player.c | 8 ++------ 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/soh/soh/Enhancements/Fishing.cpp b/soh/soh/Enhancements/Fishing.cpp index cbc6d515333..2be93b26213 100644 --- a/soh/soh/Enhancements/Fishing.cpp +++ b/soh/soh/Enhancements/Fishing.cpp @@ -6,6 +6,7 @@ extern "C" { extern PlayState* gPlayState; extern SaveContext gSaveContext; f32 Fishing_GetMinimumRequiredScore(); +extern s32 Player_GetItemOnButton(PlayState*, s32); } void BuildFishingMessage(uint16_t* textId, bool* loadFromMessageTable) { @@ -29,11 +30,15 @@ void RegisterAllowFishingBlankB() { } }); - COND_VB_SHOULD(VB_ALLOW_BLANK_B_FISHING_ITEM, (IS_RANDO || CVarGetInteger(CVAR_ENHANCEMENT("FishingBlankB"), 0)), { + COND_VB_SHOULD(VB_ALLOW_BLANK_B_FISHING_ITEM, true, { s32* i = va_arg(args, s32*); Player* player = va_arg(args, Player*); - if (gPlayState->interfaceCtx.unk_260 != 0 && i == 0 && player->itemAction == PLAYER_IA_FISHING_POLE) { - *should = true; + s32* item = va_arg(args, s32*); + if ((IS_RANDO || CVarGetInteger(CVAR_ENHANCEMENT("FishingBlankB"), 0)) && + (gPlayState->interfaceCtx.unk_260 != 0 && *i == 0 && player->itemAction == PLAYER_IA_FISHING_POLE)) { + *item = ITEM_FISHING_POLE; + } else { + *item = Player_GetItemOnButton(gPlayState, *i); } }); } diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp index eb71864b39d..3be1133191b 100644 --- a/soh/soh/SohGui/SohMenuEnhancements.cpp +++ b/soh/soh/SohGui/SohMenuEnhancements.cpp @@ -1636,7 +1636,7 @@ void SohMenu::AddMenuEnhancements() { AddWidget(path, "Allow fishing with blank B", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("FishingBlankB")) .Options(CheckboxOptions().Tooltip("Allow fishing even when not having any item equipped on the B button, " - "fixing a vanilla bug.")); + "fixing a vanilla bug. Always enabled in randomizer.")); // Extra Modes path.sidebarName = "Extra Modes"; 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 2131ceb35ad..aec5006238e 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -2535,12 +2535,8 @@ void Player_ProcessItemButtons(Player* this, PlayState* play) { break; } } - - if (GameInteractor_Should(VB_ALLOW_BLANK_B_FISHING_ITEM, false, i, this)) { - item = ITEM_FISHING_POLE; - } else { - item = Player_GetItemOnButton(play, i); - } + // SoH: replaces item = Player_GetItemOnButton(play, i) + GameInteractor_Should(VB_ALLOW_BLANK_B_FISHING_ITEM, true, &i, this, &item); if (item >= ITEM_NONE_FE) { for (i = 0; i < ARRAY_COUNT(sItemButtons); i++) { From 5237240df9e87bc13d71e1c3659f909077418347 Mon Sep 17 00:00:00 2001 From: djevangelia Date: Wed, 1 Jul 2026 15:12:13 +0200 Subject: [PATCH 5/5] Fishing blank B, review --- soh/soh/Enhancements/Fishing.cpp | 32 +++++++++---------- .../vanilla-behavior/GIVanillaBehavior.h | 1 + .../actors/ovl_player_actor/z_player.c | 3 +- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/soh/soh/Enhancements/Fishing.cpp b/soh/soh/Enhancements/Fishing.cpp index 2be93b26213..bbfdc554112 100644 --- a/soh/soh/Enhancements/Fishing.cpp +++ b/soh/soh/Enhancements/Fishing.cpp @@ -6,7 +6,6 @@ extern "C" { extern PlayState* gPlayState; extern SaveContext gSaveContext; f32 Fishing_GetMinimumRequiredScore(); -extern s32 Player_GetItemOnButton(PlayState*, s32); } void BuildFishingMessage(uint16_t* textId, bool* loadFromMessageTable) { @@ -24,23 +23,22 @@ void RegisterFishingMessages() { // as temp B, which also makes B button disabled - fishing pole gets unequipped. // Fix: Disregard disabled B when fishing, and set used item to fishing pole on B press. void RegisterAllowFishingBlankB() { - COND_VB_SHOULD(VB_ALLOW_BLANK_B_FISHING_EQUIP, (IS_RANDO || CVarGetInteger(CVAR_ENHANCEMENT("FishingBlankB"), 0)), { - if (gPlayState->interfaceCtx.unk_260 != 0 && gSaveContext.equips.buttonItems[0] == ITEM_FISHING_POLE) { - *should = false; - } - }); + COND_VB_SHOULD( + VB_ALLOW_BLANK_B_FISHING_EQUIP, (IS_RANDO || CVarGetInteger(CVAR_ENHANCEMENT("FishingBlankB"), IS_RANDO)), { + if (gPlayState->interfaceCtx.unk_260 != 0 && gSaveContext.equips.buttonItems[0] == ITEM_FISHING_POLE) { + *should = false; + } + }); - COND_VB_SHOULD(VB_ALLOW_BLANK_B_FISHING_ITEM, true, { - s32* i = va_arg(args, s32*); - Player* player = va_arg(args, Player*); - s32* item = va_arg(args, s32*); - if ((IS_RANDO || CVarGetInteger(CVAR_ENHANCEMENT("FishingBlankB"), 0)) && - (gPlayState->interfaceCtx.unk_260 != 0 && *i == 0 && player->itemAction == PLAYER_IA_FISHING_POLE)) { - *item = ITEM_FISHING_POLE; - } else { - *item = Player_GetItemOnButton(gPlayState, *i); - } - }); + COND_VB_SHOULD( + VB_ALLOW_BLANK_B_FISHING_ITEM, (IS_RANDO || CVarGetInteger(CVAR_ENHANCEMENT("FishingBlankB"), IS_RANDO)), { + s32* i = va_arg(args, s32*); + Player* player = va_arg(args, Player*); + s32* item = va_arg(args, s32*); + if (gPlayState->interfaceCtx.unk_260 != 0 && *i == 0 && player->itemAction == PLAYER_IA_FISHING_POLE) { + *item = ITEM_FISHING_POLE; + } + }); } static RegisterShipInitFunc initFunc(RegisterFishingMessages, { CVAR_ENHANCEMENT("CustomizeFishing") }); diff --git a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h index 15ccf3a336f..d6881deb2a0 100644 --- a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h +++ b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h @@ -3126,6 +3126,7 @@ typedef enum { // #### `args` // - `s32* i` // - `Player*` + // - `s32* item` VB_ALLOW_BLANK_B_FISHING_ITEM, // true 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 aec5006238e..be7d42aa339 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -2535,7 +2535,8 @@ void Player_ProcessItemButtons(Player* this, PlayState* play) { break; } } - // SoH: replaces item = Player_GetItemOnButton(play, i) + + item = Player_GetItemOnButton(play, i); GameInteractor_Should(VB_ALLOW_BLANK_B_FISHING_ITEM, true, &i, this, &item); if (item >= ITEM_NONE_FE) {