diff --git a/soh/soh/Enhancements/SwitchTimerMultiplier.cpp b/soh/soh/Enhancements/SwitchTimerMultiplier.cpp new file mode 100644 index 000000000..94982837d --- /dev/null +++ b/soh/soh/Enhancements/SwitchTimerMultiplier.cpp @@ -0,0 +1,29 @@ +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" +#include "soh/ShipInit.hpp" + +extern "C" { +extern PlayState* gPlayState; +} + +void RegisterSwitchTimerMultiplier() { + COND_VB_SHOULD(VB_SWITCH_TIMER_TICK, CVarGetInteger(CVAR_ENHANCEMENT("SwitchTimerMultiplier"), 0) != 0, { + int multiplier = CVarGetInteger(CVAR_ENHANCEMENT("SwitchTimerMultiplier"), 0); + if (multiplier != 0) { + Actor* actor = va_arg(args, Actor*); + if (multiplier < -3 && actor->id == ACTOR_OBJ_SYOKUDAI) { + multiplier = -3; + } else if (multiplier < -4 && actor->id == ACTOR_BG_GND_DARKMEIRO) { + multiplier = -4; + } + + if (multiplier > 0 && gPlayState->gameplayFrames % (multiplier + 1) != 0) { + *should = false; + } else if (gPlayState->gameplayFrames % (6 + multiplier) == 0) { + s16* timer = va_arg(args, s16*); + *timer -= *timer > 1; + } + } + }); +} + +static RegisterShipInitFunc initFunc(RegisterSwitchTimerMultiplier, { CVAR_ENHANCEMENT("SwitchTimerMultiplier") }); diff --git a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h index e76a806ab..eb7bf6e23 100644 --- a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h +++ b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h @@ -2000,6 +2000,15 @@ typedef enum { // - `*ShotSun` VB_SPAWN_SONG_FAIRY, + // #### `result` + // ```c + // varies, never set should to true + // ``` + // #### `args` + // - `*Actor` + // - `*s16` - timer value + VB_SWITCH_TIMER_TICK, + // #### `result` // ```c // (this->stateFlags1 & PLAYER_STATE1_CARRYING_ACTOR) && (this->heldActor != NULL) && diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp index 58f197512..15cb81f9d 100644 --- a/soh/soh/SohGui/SohMenuEnhancements.cpp +++ b/soh/soh/SohGui/SohMenuEnhancements.cpp @@ -1123,6 +1123,11 @@ void SohMenu::AddMenuEnhancements() { .Options(CheckboxOptions().Tooltip("Dying will delete your file.\n\n" ICON_FA_EXCLAMATION_TRIANGLE " WARNING " ICON_FA_EXCLAMATION_TRIANGLE "\nTHIS IS NOT REVERSIBLE!\nUSE AT YOUR OWN RISK!")); + AddWidget(path, "Switch Timer Multiplier", WIDGET_CVAR_SLIDER_INT) + .CVar(CVAR_ENHANCEMENT("SwitchTimerMultiplier")) + .Options(IntSliderOptions().Min(-5).Max(5).DefaultValue(0).Format("%+d").Tooltip( + "-5 will be half as much time, +5 will be 6x as much time. Affects timed switches, torches, GTG statue " + "eyes, & doors in race with Dampe.")); AddWidget(path, "Always Win Goron Pot", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("GoronPot")) .Options(CheckboxOptions().Tooltip("Always get the Heart Piece/Purple Rupee from the Spinning Goron Pot.")); diff --git a/soh/src/overlays/actors/ovl_Bg_Gnd_Darkmeiro/z_bg_gnd_darkmeiro.c b/soh/src/overlays/actors/ovl_Bg_Gnd_Darkmeiro/z_bg_gnd_darkmeiro.c index 620bf18ab..4ade8918c 100644 --- a/soh/src/overlays/actors/ovl_Bg_Gnd_Darkmeiro/z_bg_gnd_darkmeiro.c +++ b/soh/src/overlays/actors/ovl_Bg_Gnd_Darkmeiro/z_bg_gnd_darkmeiro.c @@ -6,6 +6,7 @@ #include "z_bg_gnd_darkmeiro.h" #include "objects/object_demo_kekkai/object_demo_kekkai.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #define FLAGS (ACTOR_FLAG_UPDATE_CULLING_DISABLED | ACTOR_FLAG_DRAW_CULLING_DISABLED) @@ -115,7 +116,9 @@ void BgGndDarkmeiro_UpdateBlockTimer(BgGndDarkmeiro* this, PlayState* play) { if (Flags_GetSwitch(play, ((this->dyna.actor.params >> 8) & 0x3F) + 1)) { if (this->actionFlags & 4) { if (this->timer1 > 0) { - this->timer1--; + if (GameInteractor_Should(VB_SWITCH_TIMER_TICK, true, this, &this->timer1)) { + this->timer1--; + } } else { Flags_UnsetSwitch(play, ((this->dyna.actor.params >> 8) & 0x3F) + 1); this->actionFlags &= ~4; @@ -131,7 +134,9 @@ void BgGndDarkmeiro_UpdateBlockTimer(BgGndDarkmeiro* this, PlayState* play) { if (Flags_GetSwitch(play, ((this->dyna.actor.params >> 8) & 0x3F) + 2)) { if (this->actionFlags & 8) { if (this->timer2 > 0) { - this->timer2--; + if (GameInteractor_Should(VB_SWITCH_TIMER_TICK, true, &this->timer2)) { + this->timer2--; + } } else { Flags_UnsetSwitch(play, ((this->dyna.actor.params >> 8) & 0x3F) + 2); this->actionFlags &= ~8; diff --git a/soh/src/overlays/actors/ovl_Bg_Hidan_Curtain/z_bg_hidan_curtain.c b/soh/src/overlays/actors/ovl_Bg_Hidan_Curtain/z_bg_hidan_curtain.c index d818bf03e..de1578b24 100644 --- a/soh/src/overlays/actors/ovl_Bg_Hidan_Curtain/z_bg_hidan_curtain.c +++ b/soh/src/overlays/actors/ovl_Bg_Hidan_Curtain/z_bg_hidan_curtain.c @@ -6,6 +6,7 @@ #include "z_bg_hidan_curtain.h" #include "objects/gameplay_keep/gameplay_keep.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #define FLAGS ACTOR_FLAG_UPDATE_CULLING_DISABLED @@ -191,7 +192,10 @@ void BgHidanCurtain_TurnOff(BgHidanCurtain* this, PlayState* play) { } void BgHidanCurtain_WaitForTimer(BgHidanCurtain* this, PlayState* play) { - DECR(this->timer); + if (GameInteractor_Should(VB_SWITCH_TIMER_TICK, true, this, &this->timer)) { + DECR(this->timer); + } + if (this->timer == 0) { this->actionFunc = BgHidanCurtain_TurnOn; } diff --git a/soh/src/overlays/actors/ovl_Bg_Hidan_Fwbig/z_bg_hidan_fwbig.c b/soh/src/overlays/actors/ovl_Bg_Hidan_Fwbig/z_bg_hidan_fwbig.c index 2caf4183d..3d46f41c5 100644 --- a/soh/src/overlays/actors/ovl_Bg_Hidan_Fwbig/z_bg_hidan_fwbig.c +++ b/soh/src/overlays/actors/ovl_Bg_Hidan_Fwbig/z_bg_hidan_fwbig.c @@ -8,6 +8,7 @@ #include "z_bg_hidan_fwbig.h" #include "objects/gameplay_keep/gameplay_keep.h" #include "objects/object_hidan_objects/object_hidan_objects.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #define FLAGS ACTOR_FLAG_UPDATE_CULLING_DISABLED @@ -165,9 +166,10 @@ void BgHidanFwbig_Lower(BgHidanFwbig* this, PlayState* play) { } void BgHidanFwbig_WaitForTimer(BgHidanFwbig* this, PlayState* play) { - if (this->timer != 0) { + if (GameInteractor_Should(VB_SWITCH_TIMER_TICK, this->timer != 0, this, &this->timer)) { this->timer--; } + if (this->timer == 0) { this->actionFunc = BgHidanFwbig_Rise; } diff --git a/soh/src/overlays/actors/ovl_Bg_Menkuri_Eye/z_bg_menkuri_eye.c b/soh/src/overlays/actors/ovl_Bg_Menkuri_Eye/z_bg_menkuri_eye.c index 981e13839..20851b200 100644 --- a/soh/src/overlays/actors/ovl_Bg_Menkuri_Eye/z_bg_menkuri_eye.c +++ b/soh/src/overlays/actors/ovl_Bg_Menkuri_Eye/z_bg_menkuri_eye.c @@ -6,6 +6,7 @@ #include "z_bg_menkuri_eye.h" #include "objects/object_menkuri_objects/object_menkuri_objects.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #define FLAGS ACTOR_FLAG_DRAW_CULLING_DISABLED @@ -90,7 +91,8 @@ void BgMenkuriEye_Update(Actor* thisx, PlayState* play) { if (!Flags_GetSwitch(play, this->actor.params)) { if (this->framesUntilDisable != -1) { - if (this->framesUntilDisable != 0) { + if (GameInteractor_Should(VB_SWITCH_TIMER_TICK, this->framesUntilDisable != 0, this, + &this->framesUntilDisable)) { this->framesUntilDisable -= 1; } if (this->framesUntilDisable == 0) { diff --git a/soh/src/overlays/actors/ovl_Bg_Mizu_Shutter/z_bg_mizu_shutter.c b/soh/src/overlays/actors/ovl_Bg_Mizu_Shutter/z_bg_mizu_shutter.c index ffa56a074..19985b2ce 100644 --- a/soh/src/overlays/actors/ovl_Bg_Mizu_Shutter/z_bg_mizu_shutter.c +++ b/soh/src/overlays/actors/ovl_Bg_Mizu_Shutter/z_bg_mizu_shutter.c @@ -1,5 +1,6 @@ #include "z_bg_mizu_shutter.h" #include "objects/object_mizu_objects/object_mizu_objects.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #define FLAGS ACTOR_FLAG_UPDATE_CULLING_DISABLED @@ -137,7 +138,9 @@ void BgMizuShutter_Move(BgMizuShutter* this, PlayState* play) { void BgMizuShutter_WaitForTimer(BgMizuShutter* this, PlayState* play) { if (this->timerMax != 0x3F * 20) { - this->timer--; + if (GameInteractor_Should(VB_SWITCH_TIMER_TICK, true, this, &this->timer)) { + this->timer--; + } func_8002F994(&this->dyna.actor, this->timer); if (this->timer == 0) { Audio_PlayActorSound2(&this->dyna.actor, NA_SE_EV_METALDOOR_CLOSE); diff --git a/soh/src/overlays/actors/ovl_Bg_Relay_Objects/z_bg_relay_objects.c b/soh/src/overlays/actors/ovl_Bg_Relay_Objects/z_bg_relay_objects.c index f7b663cf9..40887b202 100644 --- a/soh/src/overlays/actors/ovl_Bg_Relay_Objects/z_bg_relay_objects.c +++ b/soh/src/overlays/actors/ovl_Bg_Relay_Objects/z_bg_relay_objects.c @@ -6,6 +6,7 @@ #include "z_bg_relay_objects.h" #include "objects/object_relay_objects/object_relay_objects.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #define FLAGS ACTOR_FLAG_UPDATE_CULLING_DISABLED @@ -133,7 +134,7 @@ void func_808A90F4(BgRelayObjects* this, PlayState* play) { void func_808A91AC(BgRelayObjects* this, PlayState* play) { if (this->unk_169 != 5) { - if (this->timer != 0) { + if (GameInteractor_Should(VB_SWITCH_TIMER_TICK, this->timer != 0, this, &this->timer)) { this->timer--; } func_8002F994(&this->dyna.actor, this->timer); @@ -168,7 +169,7 @@ void BgRelayObjects_DoNothing(BgRelayObjects* this, PlayState* play) { } void func_808A932C(BgRelayObjects* this, PlayState* play) { - if (this->timer != 0) { + if (GameInteractor_Should(VB_SWITCH_TIMER_TICK, this->timer != 0, &this->timer)) { this->timer--; } if (this->timer == 0) { diff --git a/soh/src/overlays/actors/ovl_Bg_Ydan_Hasi/z_bg_ydan_hasi.c b/soh/src/overlays/actors/ovl_Bg_Ydan_Hasi/z_bg_ydan_hasi.c index 4c8ca0050..6715d140c 100644 --- a/soh/src/overlays/actors/ovl_Bg_Ydan_Hasi/z_bg_ydan_hasi.c +++ b/soh/src/overlays/actors/ovl_Bg_Ydan_Hasi/z_bg_ydan_hasi.c @@ -6,6 +6,7 @@ #include "z_bg_ydan_hasi.h" #include "objects/object_ydan_objects/object_ydan_objects.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #define FLAGS (ACTOR_FLAG_UPDATE_CULLING_DISABLED | ACTOR_FLAG_DRAW_CULLING_DISABLED) @@ -126,9 +127,10 @@ void BgYdanHasi_MoveWater(BgYdanHasi* this, PlayState* play) { } void BgYdanHasi_DecWaterTimer(BgYdanHasi* this, PlayState* play) { - if (this->timer != 0) { + if (GameInteractor_Should(VB_SWITCH_TIMER_TICK, this->timer != 0, this, &this->timer)) { this->timer--; } + func_8002F994(&this->dyna.actor, this->timer); if (this->timer == 0) { this->actionFunc = BgYdanHasi_MoveWater; @@ -145,9 +147,10 @@ void BgYdanHasi_SetupThreeBlocks(BgYdanHasi* this, PlayState* play) { } void BgYdanHasi_UpdateThreeBlocks(BgYdanHasi* this, PlayState* play) { - if (this->timer != 0) { + if (GameInteractor_Should(VB_SWITCH_TIMER_TICK, this->timer != 0, this, &this->timer)) { this->timer--; } + if (this->timer == 0) { if (Math_StepToF(&this->dyna.actor.world.pos.y, this->dyna.actor.home.pos.y, 3.0f) != 0) { Flags_UnsetSwitch(play, this->type); diff --git a/soh/src/overlays/actors/ovl_En_Siofuki/z_en_siofuki.c b/soh/src/overlays/actors/ovl_En_Siofuki/z_en_siofuki.c index 664c75f82..7587b7a8b 100644 --- a/soh/src/overlays/actors/ovl_En_Siofuki/z_en_siofuki.c +++ b/soh/src/overlays/actors/ovl_En_Siofuki/z_en_siofuki.c @@ -6,6 +6,7 @@ #include "z_en_siofuki.h" #include "objects/object_siofuki/object_siofuki.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #define FLAGS (ACTOR_FLAG_UPDATE_CULLING_DISABLED | ACTOR_FLAG_DRAW_CULLING_DISABLED) @@ -188,7 +189,10 @@ void func_80AFC218(EnSiofuki* this, PlayState* play) { func_80AFBE8C(this, play); func_80AFC1D0(this, play); - this->timer--; + if (GameInteractor_Should(VB_SWITCH_TIMER_TICK, true, this, &this->timer)) { + this->timer--; + } + if (this->timer < 0) { Flags_UnsetSwitch(play, ((u16)this->dyna.actor.params >> 6) & 0x3F); switch (((u16)this->dyna.actor.params >> 0xC) & 0xF) { diff --git a/soh/src/overlays/actors/ovl_Obj_Syokudai/z_obj_syokudai.c b/soh/src/overlays/actors/ovl_Obj_Syokudai/z_obj_syokudai.c index 4758066e2..ab81c8421 100644 --- a/soh/src/overlays/actors/ovl_Obj_Syokudai/z_obj_syokudai.c +++ b/soh/src/overlays/actors/ovl_Obj_Syokudai/z_obj_syokudai.c @@ -8,6 +8,7 @@ #include "overlays/actors/ovl_En_Arrow/z_en_arrow.h" #include "objects/gameplay_keep/gameplay_keep.h" #include "objects/object_syokudai/object_syokudai.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #define FLAGS (ACTOR_FLAG_UPDATE_CULLING_DISABLED | ACTOR_FLAG_HOOKSHOT_PULLS_PLAYER) @@ -239,7 +240,7 @@ void ObjSyokudai_Update(Actor* thisx, PlayState* play2) { Collider_UpdateCylinder(&this->actor, &this->colliderFlame); CollisionCheck_SetAC(play, &play->colChkCtx, &this->colliderFlame.base); - if (this->litTimer > 0) { + if (GameInteractor_Should(VB_SWITCH_TIMER_TICK, this->litTimer > 0, this, &this->litTimer)) { this->litTimer--; if ((this->litTimer == 0) && (torchType != 0)) { sLitTorchCount--;