[Enhancement] Dampe's Race awards both rewards at once (#6980)

This commit is contained in:
Jordan Longstaff
2026-07-25 19:07:07 -04:00
committed by GitHub
parent f9512bf446
commit 2c5762a0f2
6 changed files with 78 additions and 29 deletions
@@ -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 });
@@ -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" });
@@ -460,6 +460,14 @@ typedef enum {
// - None
VB_CRAWL_SPEED_INCREASE,
// #### `result`
// ```c
// this->hookshotSlotFull != 0
// ```
// #### `args`
// - None
VB_DAMPE_AWARD_SECOND_PRIZE,
// #### `result`
// ```c
// this->actionTimer == 0 && Rand_ZeroOne() < 0.03f
@@ -468,6 +476,14 @@ typedef enum {
// - `*EnPoRelay`
VB_DAMPE_DROP_FLAME,
// #### `result`
// ```c
// true
// ```
// #### `args`
// - `*f32` (speed
VB_DAMPE_GO_BACKWARDS,
// #### `result`
// ```c
// !Flags_GetItemGetInf(ITEMGETINF_1C)
@@ -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*);
+7
View File
@@ -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"));
@@ -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);
}