diff --git a/soh/soh/Enhancements/DampeFire.cpp b/soh/soh/Enhancements/DampeFire.cpp new file mode 100644 index 000000000..1378ecb04 --- /dev/null +++ b/soh/soh/Enhancements/DampeFire.cpp @@ -0,0 +1,48 @@ +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" +#include "soh/ShipInit.hpp" +#include "soh/Enhancements/enhancementTypes.h" + +extern "C" { +extern PlayState* gPlayState; +#include "src/overlays/actors/ovl_En_Po_Relay/z_en_po_relay.h" +} + +void RegisterDampeFire() { + COND_VB_SHOULD(VB_DAMPE_DROP_FLAME, CVarGetInteger(CVAR_ENHANCEMENT("DampeDropRate"), DAMPE_NORMAL) != DAMPE_NORMAL, + { + double chance; + int cooldown = 9; + switch (CVarGetInteger(CVAR_ENHANCEMENT("DampeDropRate"), DAMPE_NORMAL)) { + case DAMPE_NONE: + *should = false; + return; + default: + case DAMPE_NORMAL: + return; + case DAMPE_JALAPENO: + chance = 0.03; + break; + case DAMPE_CHIPOTLE: + chance = 0.1; + break; + case DAMPE_SCOTCH_BONNET: + chance = 0.2; + break; + case DAMPE_GHOST_PEPPER: + chance = 0.5; + cooldown = 4; + break; + case DAMPE_INFERNO: + *should = true; + return; + } + + EnPoRelay* actor = va_arg(args, EnPoRelay*); + if (actor->actionTimer > cooldown) { + actor->actionTimer = cooldown; + } + *should = actor->actionTimer == 0 && Rand_ZeroOne() < chance; + }); +} + +static RegisterShipInitFunc initFunc(RegisterDampeFire, { CVAR_ENHANCEMENT("DampeDropRate") }); diff --git a/soh/soh/Enhancements/enhancementTypes.h b/soh/soh/Enhancements/enhancementTypes.h index ee3b26d2e..c1b91cffa 100644 --- a/soh/soh/Enhancements/enhancementTypes.h +++ b/soh/soh/Enhancements/enhancementTypes.h @@ -87,6 +87,16 @@ typedef enum { DAMAGE_OHKO } DamageMultType; +typedef enum { + DAMPE_NONE, + DAMPE_NORMAL, + DAMPE_JALAPENO, + DAMPE_CHIPOTLE, + DAMPE_SCOTCH_BONNET, + DAMPE_GHOST_PEPPER, + DAMPE_INFERNO, +} DampeDropRate; + typedef enum { DEKU_STICK_NORMAL, DEKU_STICK_UNBREAKABLE, diff --git a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h index 4e607a29c..c2b8c1756 100644 --- a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h +++ b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h @@ -339,6 +339,14 @@ typedef enum { // - None VB_CRAWL_SPEED_INCREASE, + // #### `result` + // ```c + // this->actionTimer == 0 && Rand_ZeroOne() < 0.03f + // ``` + // #### `args` + // - `*EnPoRelay` + VB_DAMPE_DROP_FLAME, + // #### `result` // ```c // !Flags_GetItemGetInf(ITEMGETINF_1C) diff --git a/soh/soh/SohGui/SohMenu.h b/soh/soh/SohGui/SohMenu.h index 362cc4721..1de142299 100644 --- a/soh/soh/SohGui/SohMenu.h +++ b/soh/soh/SohGui/SohMenu.h @@ -135,6 +135,16 @@ static const std::unordered_map bonkDamageValues = { { BONK_DAMAGE_8_HEARTS, "8 Hearts" }, { BONK_DAMAGE_OHKO, "OHKO" }, }; +static const std::unordered_map dampeDropRates = { + { DAMPE_NONE, "None" }, + { DAMPE_NORMAL, "Vanilla" }, + { DAMPE_JALAPENO, "JalapeƱo" }, + { DAMPE_CHIPOTLE, "Serrano" }, + { DAMPE_SCOTCH_BONNET, "Habanero" }, + { DAMPE_GHOST_PEPPER, "Ghost Pepper" }, + { DAMPE_INFERNO, "Dampe's Inferno" }, +}; + static const std::unordered_map cursorAnywhereValues = { { PAUSE_ANY_CURSOR_RANDO_ONLY, "Only in Rando" }, { PAUSE_ANY_CURSOR_ALWAYS_ON, "Always" }, diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp index edfb1052f..4785da238 100644 --- a/soh/soh/SohGui/SohMenuEnhancements.cpp +++ b/soh/soh/SohGui/SohMenuEnhancements.cpp @@ -1150,6 +1150,12 @@ void SohMenu::AddMenuEnhancements() { .CVar(CVAR_ENHANCEMENT("TreesDropSticks")) .Options(CheckboxOptions().Tooltip( "Bonking into Trees will have a chance to drop up to 3 Sticks. Must have obtained sticks previously.")); + AddWidget(path, "Dampe Drop Rate", WIDGET_CVAR_COMBOBOX) + .CVar(CVAR_ENHANCEMENT("DampeDropRate")) + .Options(ComboboxOptions() + .ComboMap(dampeDropRates) + .DefaultIndex(DAMPE_NORMAL) + .Tooltip("Adjusts rate Dampe drops flames during race.")); AddWidget(path, "Miscellaneous", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Delete File on Death", WIDGET_CVAR_CHECKBOX) @@ -1615,6 +1621,9 @@ void SohMenu::AddMenuEnhancements() { .Options(CheckboxOptions().Tooltip( "Keese and Guay no longer target you and simply ignore you as if you were wearing the " "Skull Mask.")); + AddWidget(path, "No Dampe Fire", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_CHEAT("NoDampeFire")) + .Options(CheckboxOptions().Tooltip("Dampe won't drop fireballs during race.")); AddWidget(path, "Glitch Aids", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Easy Frame Advancing with Pause", WIDGET_CVAR_CHECKBOX) 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 41ee2d5c6..d850021a4 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 @@ -8,6 +8,8 @@ #include "overlays/actors/ovl_En_Honotrap/z_en_honotrap.h" #include "objects/object_tk/object_tk.h" #include "soh/ResourceManagerHelpers.h" +#include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #define FLAGS \ (ACTOR_FLAG_ATTENTION_ENABLED | ACTOR_FLAG_FRIENDLY | ACTOR_FLAG_UPDATE_CULLING_DISABLED | \ @@ -197,7 +199,7 @@ void EnPoRelay_Race(EnPoRelay* this, PlayState* play) { if (this->actionTimer != 0) { this->actionTimer--; } - if (this->actionTimer == 0 && Rand_ZeroOne() < 0.03f) { + if (GameInteractor_Should(VB_DAMPE_DROP_FLAME, this->actionTimer == 0 && Rand_ZeroOne() < 0.03f, this)) { this->actionTimer = 32; if (this->pathIndex < 23) { speed = Rand_ZeroOne() * 3.0f;