summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Longstaff <JordanLongstaff@users.noreply.github.com>2026-07-25 19:07:07 -0400
committerGitHub <noreply@github.com>2026-07-25 23:07:07 +0000
commit2c5762a0f287ee9de16eb8ed916275cf230fc60c (patch)
tree3509c1569ed9efc5dee82c444d8f996cd416d4ad
parentf9512bf44670a74389afccde4266ba3d4ebfc944 (diff)
[Enhancement] Dampe's Race awards both rewards at once (#6980)
-rw-r--r--soh/soh/Enhancements/Fixes/DampeGoingBackwards.cpp19
-rw-r--r--soh/soh/Enhancements/Minigames/DampeBothPrizes.cpp24
-rw-r--r--soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h16
-rw-r--r--soh/soh/Enhancements/randomizer/hook_handlers.cpp6
-rw-r--r--soh/soh/SohGui/SohMenuEnhancements.cpp7
-rw-r--r--soh/src/overlays/actors/ovl_En_Po_Relay/z_en_po_relay.c35
6 files changed, 78 insertions, 29 deletions
diff --git a/soh/soh/Enhancements/Fixes/DampeGoingBackwards.cpp b/soh/soh/Enhancements/Fixes/DampeGoingBackwards.cpp
new file mode 100644
index 000000000..be5b25a58
--- /dev/null
+++ b/soh/soh/Enhancements/Fixes/DampeGoingBackwards.cpp
@@ -0,0 +1,19 @@
+#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
+#include "soh/ShipInit.hpp"
+
+extern "C" {
+#include "functions.h"
+#include "macros.h"
+}
+
+#define CVAR_DAMPE_BACKWARDS_NAME CVAR_ENHANCEMENT("FixDampeGoingBackwards")
+#define CVAR_DAMPE_BACKWARDS_VALUE CVarGetInteger(CVAR_DAMPE_BACKWARDS_NAME, 0)
+
+static void RegisterDampeGoingBackwardsFix() {
+ COND_VB_SHOULD(VB_DAMPE_GO_BACKWARDS, CVAR_DAMPE_BACKWARDS_VALUE, {
+ f32* speed = va_arg(args, f32*);
+ *speed = ABS(*speed);
+ });
+}
+
+static RegisterShipInitFunc initFunc(RegisterDampeGoingBackwardsFix, { CVAR_DAMPE_BACKWARDS_NAME });
diff --git a/soh/soh/Enhancements/Minigames/DampeBothPrizes.cpp b/soh/soh/Enhancements/Minigames/DampeBothPrizes.cpp
new file mode 100644
index 000000000..0b50f3eda
--- /dev/null
+++ b/soh/soh/Enhancements/Minigames/DampeBothPrizes.cpp
@@ -0,0 +1,24 @@
+#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
+#include "soh/ShipInit.hpp"
+
+extern "C" {
+#include "functions.h"
+#include "macros.h"
+extern SaveContext gSaveContext;
+extern PlayState* gPlayState;
+}
+
+#define CVAR_DAMPE_BOTH_PRIZES_NAME CVAR_ENHANCEMENT("DampeBothPrizes")
+#define CVAR_DAMPE_BOTH_PRIZES_VALUE CVarGetInteger(CVAR_DAMPE_BOTH_PRIZES_NAME, 0)
+
+static void RegisterDampeSecondPrize() {
+ COND_VB_SHOULD(VB_DAMPE_AWARD_SECOND_PRIZE, CVAR_DAMPE_BOTH_PRIZES_VALUE || IS_RANDO, {
+ if (!*should) {
+ Flags_SetTempClear(gPlayState, 4);
+ HIGH_SCORE(HS_DAMPE_RACE) = gSaveContext.timerSeconds;
+ *should = true;
+ }
+ });
+}
+
+static RegisterShipInitFunc initFunc(RegisterDampeSecondPrize, { CVAR_DAMPE_BOTH_PRIZES_NAME, "IS_RANDO" });
diff --git a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h
index 2c02cfe94..0ae138df4 100644
--- a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h
+++ b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h
@@ -462,6 +462,14 @@ typedef enum {
// #### `result`
// ```c
+ // this->hookshotSlotFull != 0
+ // ```
+ // #### `args`
+ // - None
+ VB_DAMPE_AWARD_SECOND_PRIZE,
+
+ // #### `result`
+ // ```c
// this->actionTimer == 0 && Rand_ZeroOne() < 0.03f
// ```
// #### `args`
@@ -470,6 +478,14 @@ typedef enum {
// #### `result`
// ```c
+ // true
+ // ```
+ // #### `args`
+ // - `*f32` (speed
+ VB_DAMPE_GO_BACKWARDS,
+
+ // #### `result`
+ // ```c
// !Flags_GetItemGetInf(ITEMGETINF_1C)
// ```
// #### `args`
diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp
index c9b8de0fe..75c315ca0 100644
--- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp
+++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp
@@ -1536,6 +1536,12 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l
case VB_DEKU_THEATER_FINISH_GIVING_PRIZE:
*should = true;
break;
+ case VB_DAMPE_AWARD_SECOND_PRIZE:
+ if (!*should) {
+ Flags_SetTreasure(gPlayState, 0x1E);
+ *should = true;
+ }
+ break;
case VB_FROGS_GO_TO_IDLE: {
EnFr* enFr = va_arg(args, EnFr*);
diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp
index e0dfbc5f8..5ded15373 100644
--- a/soh/soh/SohGui/SohMenuEnhancements.cpp
+++ b/soh/soh/SohGui/SohMenuEnhancements.cpp
@@ -1692,6 +1692,13 @@ void SohMenu::AddMenuEnhancements() {
"fixing a vanilla bug. Always enabled in randomizer."));
AddWidget(path, "Multiple Prizes", WIDGET_SEPARATOR_TEXT);
+ AddWidget(path, "Dampe's Race", WIDGET_CVAR_CHECKBOX)
+ .CVar(CVAR_ENHANCEMENT("DampeBothPrizes"))
+ .PreFunc([](WidgetInfo& info) {
+ info.options->disabled = IS_RANDO && GameInteractor::IsSaveLoaded(true);
+ info.options->disabledTooltip = "This setting is forcefully enabled when you are playing a Randomizer.";
+ })
+ .Options(CheckboxOptions().Tooltip("Dampe awards both prizes on the first race, not just the Hookshot."));
AddWidget(path, "Horseback Archery", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("HorsebackArcheryBothPrizes"))
.Options(CheckboxOptions().Tooltip("Link can win both Horseback Archery prizes in one attempt"));
diff --git a/soh/src/overlays/actors/ovl_En_Po_Relay/z_en_po_relay.c b/soh/src/overlays/actors/ovl_En_Po_Relay/z_en_po_relay.c
index 4ede23943..bd719a044 100644
--- a/soh/src/overlays/actors/ovl_En_Po_Relay/z_en_po_relay.c
+++ b/soh/src/overlays/actors/ovl_En_Po_Relay/z_en_po_relay.c
@@ -239,9 +239,7 @@ void EnPoRelay_Race(EnPoRelay* this, PlayState* play) {
speed = 3.5f;
}
- if (CVarGetInteger(CVAR_ENHANCEMENT("FixDampeGoingBackwards"), false)) {
- speed = ABS(speed);
- }
+ GameInteractor_Should(VB_DAMPE_GO_BACKWARDS, true, &speed);
multiplier = 250.0f - this->actor.xzDistToPlayer;
multiplier = CLAMP_MIN(multiplier, 0.0f);
@@ -338,42 +336,21 @@ void EnPoRelay_DisappearAndReward(EnPoRelay* this, PlayState* play) {
}
}
if (Math_StepToF(&this->actor.scale.x, 0.0f, 0.001f) != 0) {
- if (!IS_RANDO) {
- if (this->hookshotSlotFull != 0) {
- sp60.x = this->actor.world.pos.x;
- sp60.y = this->actor.floorHeight;
- sp60.z = this->actor.world.pos.z;
- if (gSaveContext.timerSeconds < HIGH_SCORE(HS_DAMPE_RACE)) {
- HIGH_SCORE(HS_DAMPE_RACE) = gSaveContext.timerSeconds;
- }
- if (Flags_GetCollectible(play, this->actor.params) == 0 && gSaveContext.timerSeconds <= 60) {
- Item_DropCollectible2(play, &sp60, (this->actor.params << 8) + (0x4000 | ITEM00_HEART_PIECE));
- } else {
- Actor_Spawn(&play->actorCtx, play, ACTOR_EN_ITEM00, sp60.x, sp60.y, sp60.z, 0, 0, 0, 2);
- }
- } else {
- Flags_SetTempClear(play, 4);
- HIGH_SCORE(HS_DAMPE_RACE) = gSaveContext.timerSeconds;
- }
- } else {
+ if (GameInteractor_Should(VB_DAMPE_AWARD_SECOND_PRIZE, this->hookshotSlotFull != 0)) {
sp60.x = this->actor.world.pos.x;
sp60.y = this->actor.floorHeight;
sp60.z = this->actor.world.pos.z;
-
- if (this->hookshotSlotFull == 0) {
- Flags_SetTempClear(play, 4);
- Flags_SetTreasure(gPlayState, 0x1E);
- HIGH_SCORE(HS_DAMPE_RACE) = gSaveContext.timerSeconds;
- }
-
if (gSaveContext.timerSeconds < HIGH_SCORE(HS_DAMPE_RACE)) {
HIGH_SCORE(HS_DAMPE_RACE) = gSaveContext.timerSeconds;
}
if (Flags_GetCollectible(play, this->actor.params) == 0 && gSaveContext.timerSeconds <= 60) {
Item_DropCollectible2(play, &sp60, (this->actor.params << 8) + (0x4000 | ITEM00_HEART_PIECE));
- } else if (Flags_GetCollectible(play, this->actor.params) != 0) {
+ } else {
Actor_Spawn(&play->actorCtx, play, ACTOR_EN_ITEM00, sp60.x, sp60.y, sp60.z, 0, 0, 0, 2);
}
+ } else {
+ Flags_SetTempClear(play, 4);
+ HIGH_SCORE(HS_DAMPE_RACE) = gSaveContext.timerSeconds;
}
Actor_Kill(&this->actor);
}