summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Longstaff <JordanLongstaff@users.noreply.github.com>2026-07-25 10:01:44 -0400
committerGitHub <noreply@github.com>2026-07-25 14:01:44 +0000
commit2b3521195612f83227c0d6f73dc5b0a68abe4edd (patch)
treeb58e8e9992452de32e5547ce8218a990620d879f
parent783139310ae89427ce90b0476be86b08e4261c79 (diff)
[Enhancement] Award both prizes for high score in Horseback Archery (#6982)
-rw-r--r--soh/soh/Enhancements/Minigames/HorsebackArchery.cpp85
-rw-r--r--soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h8
-rw-r--r--soh/soh/SohGui/SohMenuEnhancements.cpp5
-rw-r--r--soh/src/overlays/actors/ovl_En_Ge1/z_en_ge1.c4
4 files changed, 72 insertions, 30 deletions
diff --git a/soh/soh/Enhancements/Minigames/HorsebackArchery.cpp b/soh/soh/Enhancements/Minigames/HorsebackArchery.cpp
index f268a5b17..37d7bec40 100644
--- a/soh/soh/Enhancements/Minigames/HorsebackArchery.cpp
+++ b/soh/soh/Enhancements/Minigames/HorsebackArchery.cpp
@@ -9,37 +9,64 @@ extern SaveContext gSaveContext;
extern void EnGe1_TalkAfterGame_Archery(EnGe1* enGe1, PlayState* play);
}
-static void RegisterHorsebackArcheryEnhancements() {
- COND_VB_SHOULD(VB_PLAY_HORSEBACK_ARCHERY,
- CVarGetInteger(CVAR_ENHANCEMENT("CustomizeHorsebackArchery"), 0) &&
- CVarGetInteger(CVAR_ENHANCEMENT("InstantHorsebackArcheryWin"), 0),
- {
- EnGe1* enGe1 = va_arg(args, EnGe1*);
- PlayState* play = va_arg(args, PlayState*);
- Rupees_ChangeBy(-20);
- Flags_SetEventChkInf(EVENTCHKINF_PLAYED_HORSEBACK_ARCHERY);
- gSaveContext.minigameScore = 1500;
- Message_CloseTextbox(play);
- enGe1->actionFunc = EnGe1_TalkAfterGame_Archery;
- *should = false;
- });
-
- COND_VB_SHOULD(VB_SCORE_HORSEBACK_ARCHERY_TARGET,
- CVarGetInteger(CVAR_ENHANCEMENT("CustomizeHorsebackArchery"), 0) &&
- CVarGetInteger(CVAR_ENHANCEMENT("HorsebackArcheryAlwaysScore"), 0),
- {
- s32* scoreIndex = va_arg(args, s32*);
- *scoreIndex = 2; // inner ring = 100 points
- });
-
- COND_VB_SHOULD(VB_SET_HORSEBACK_ARCHERY_AMMO, CVarGetInteger(CVAR_ENHANCEMENT("CustomizeHorsebackArchery"), 0), {
+#define CVAR_ARCHERY_CUSTOMIZE_NAME CVAR_ENHANCEMENT("CustomizeHorsebackArchery")
+#define CVAR_ARCHERY_CUSTOMIZE_VALUE CVarGetInteger(CVAR_ARCHERY_CUSTOMIZE_NAME, 0)
+
+static constexpr s32 CVAR_ARCHERY_AMMO_DEFAULT = 20;
+
+#define CVAR_ARCHERY_AMMO_NAME CVAR_ENHANCEMENT("HorsebackArcheryAmmo")
+#define CVAR_ARCHERY_AMMO_VALUE CVarGetInteger(CVAR_ARCHERY_AMMO_NAME, CVAR_ARCHERY_AMMO_DEFAULT)
+#define CVAR_ARCHERY_AMMO_CHANGED (CVAR_ARCHERY_AMMO_VALUE != CVAR_ARCHERY_AMMO_DEFAULT)
+
+#define CVAR_ARCHERY_ALWAYS_SCORE_NAME CVAR_ENHANCEMENT("HorsebackArcheryAlwaysScore")
+#define CVAR_ARCHERY_ALWAYS_SCORE_VALUE CVarGetInteger(CVAR_ARCHERY_ALWAYS_SCORE_NAME, 0)
+
+#define CVAR_ARCHERY_INSTANT_WIN_NAME CVAR_ENHANCEMENT("InstantHorsebackArcheryWin")
+#define CVAR_ARCHERY_INSTANT_WIN_VALUE CVarGetInteger(CVAR_ARCHERY_INSTANT_WIN_NAME, 0)
+
+#define CVAR_ARCHERY_BOTH_PRIZES_NAME CVAR_ENHANCEMENT("HorsebackArcheryBothPrizes")
+#define CVAR_ARCHERY_BOTH_PRIZES_VALUE CVarGetInteger(CVAR_ARCHERY_BOTH_PRIZES_NAME, 0)
+
+static void RegisterHorsebackArcheryInstantWin() {
+ COND_VB_SHOULD(VB_PLAY_HORSEBACK_ARCHERY, CVAR_ARCHERY_CUSTOMIZE_VALUE && CVAR_ARCHERY_INSTANT_WIN_VALUE, {
+ EnGe1* enGe1 = va_arg(args, EnGe1*);
+ PlayState* play = va_arg(args, PlayState*);
+ Rupees_ChangeBy(-20);
+ Flags_SetEventChkInf(EVENTCHKINF_PLAYED_HORSEBACK_ARCHERY);
+ gSaveContext.minigameScore = 1500;
+ Message_CloseTextbox(play);
+ enGe1->actionFunc = EnGe1_TalkAfterGame_Archery;
+ *should = false;
+ });
+}
+
+static void RegisterHorsebackArcheryAlwaysScore() {
+ COND_VB_SHOULD(VB_SCORE_HORSEBACK_ARCHERY_TARGET, CVAR_ARCHERY_CUSTOMIZE_VALUE && CVAR_ARCHERY_ALWAYS_SCORE_VALUE, {
+ s32* scoreIndex = va_arg(args, s32*);
+ *scoreIndex = 2; // inner ring = 100 points
+ });
+}
+
+static void RegisterHorsebackArcheryAmmo() {
+ COND_VB_SHOULD(VB_SET_HORSEBACK_ARCHERY_AMMO, CVAR_ARCHERY_CUSTOMIZE_VALUE && CVAR_ARCHERY_AMMO_CHANGED, {
InterfaceContext* interfaceCtx = va_arg(args, InterfaceContext*);
- interfaceCtx->hbaAmmo = CVarGetInteger(CVAR_ENHANCEMENT("HorsebackArcheryAmmo"), 20);
+ interfaceCtx->hbaAmmo = CVAR_ARCHERY_AMMO_VALUE;
*should = false;
});
}
-static RegisterShipInitFunc
- initFunc(RegisterHorsebackArcheryEnhancements,
- { CVAR_ENHANCEMENT("CustomizeHorsebackArchery"), CVAR_ENHANCEMENT("InstantHorsebackArcheryWin"),
- CVAR_ENHANCEMENT("HorsebackArcheryAlwaysScore"), CVAR_ENHANCEMENT("HorsebackArcheryAmmo") });
+static void RegisterHorsebackArcheryBothPrizes() {
+ COND_VB_SHOULD(VB_END_HORSEBACK_ARCHERY, CVAR_ARCHERY_BOTH_PRIZES_VALUE, {
+ EnGe1* enGe1 = va_arg(args, EnGe1*);
+ enGe1->actionFunc = EnGe1_TalkAfterGame_Archery;
+ *should = false;
+ })
+}
+
+static RegisterShipInitFunc initFunc_InstantWin(RegisterHorsebackArcheryInstantWin,
+ { CVAR_ARCHERY_CUSTOMIZE_NAME, CVAR_ARCHERY_INSTANT_WIN_NAME });
+static RegisterShipInitFunc initFunc_AlwaysScore(RegisterHorsebackArcheryAlwaysScore,
+ { CVAR_ARCHERY_CUSTOMIZE_NAME, CVAR_ARCHERY_ALWAYS_SCORE_NAME });
+static RegisterShipInitFunc initFunc_Ammo(RegisterHorsebackArcheryAmmo,
+ { CVAR_ARCHERY_CUSTOMIZE_NAME, CVAR_ARCHERY_AMMO_NAME });
+static RegisterShipInitFunc initFunc_BothPrizes(RegisterHorsebackArcheryBothPrizes, { CVAR_ARCHERY_BOTH_PRIZES_NAME });
diff --git a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h
index f81b47c91..2c02cfe94 100644
--- a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h
+++ b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h
@@ -697,6 +697,14 @@ typedef enum {
// #### `result`
// ```c
+ // true
+ // ```
+ // #### `args`
+ // - `*EnGe1`
+ VB_END_HORSEBACK_ARCHERY,
+
+ // #### `result`
+ // ```c
// !(this->stateFlags3 & PLAYER_STATE3_PAUSE_ACTION_FUNC)
// ```
// #### `args`
diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp
index dccbb7237..e0dfbc5f8 100644
--- a/soh/soh/SohGui/SohMenuEnhancements.cpp
+++ b/soh/soh/SohGui/SohMenuEnhancements.cpp
@@ -1691,6 +1691,11 @@ void SohMenu::AddMenuEnhancements() {
.Options(CheckboxOptions().Tooltip("Allow fishing even when not having any item equipped on the B button, "
"fixing a vanilla bug. Always enabled in randomizer."));
+ AddWidget(path, "Multiple Prizes", WIDGET_SEPARATOR_TEXT);
+ AddWidget(path, "Horseback Archery", WIDGET_CVAR_CHECKBOX)
+ .CVar(CVAR_ENHANCEMENT("HorsebackArcheryBothPrizes"))
+ .Options(CheckboxOptions().Tooltip("Link can win both Horseback Archery prizes in one attempt"));
+
// Extra Modes
path.sidebarName = "Extra Modes";
AddSidebarEntry("Enhancements", path.sidebarName, 3);
diff --git a/soh/src/overlays/actors/ovl_En_Ge1/z_en_ge1.c b/soh/src/overlays/actors/ovl_En_Ge1/z_en_ge1.c
index 3f9f6cd34..b29c676e2 100644
--- a/soh/src/overlays/actors/ovl_En_Ge1/z_en_ge1.c
+++ b/soh/src/overlays/actors/ovl_En_Ge1/z_en_ge1.c
@@ -511,7 +511,9 @@ void EnGe1_WaitTillItemGiven_Archery(EnGe1* this, PlayState* play) {
return;
}
if (Actor_HasParent(&this->actor, play)) {
- this->actionFunc = EnGe1_SetupWait_Archery;
+ if (GameInteractor_Should(VB_END_HORSEBACK_ARCHERY, true, this)) {
+ this->actionFunc = EnGe1_SetupWait_Archery;
+ }
if (this->stateFlags & GE1_STATE_GIVE_QUIVER) {
Flags_SetItemGetInf(ITEMGETINF_0F);