Merge remote-tracking branch 'origin/develop' into actor-accessibility-experiments

This commit is contained in:
Demur Rumed 2025-06-16 00:40:32 +00:00
commit a134c34656
17 changed files with 148 additions and 41 deletions

View file

@ -41,15 +41,28 @@ You can name your branch whatever you want, but it's recommended to name it some
The limit is your imagination. You can add new features, fix bugs, add new mods, or even change the way the game works. We will demonstrate this by creating a mod that changes the speed of the day/night cycle.
Let's being by finding where the time is updated. Thankfully in the save editor we have a slider already hooked up to the time of day so we can check there for reference. The save editor file is at `soh/soh/Enhancements/debugger/debugSaveEditor.cpp`, if we do a quick search within that file for time we will find the following at line 400:
Let's begin by finding where the time is updated. Thankfully in the save editor we have a slider already hooked up to the time of day so we can check there for reference. The save editor file is at `soh/soh/Enhancements/debugger/debugSaveEditor.cpp`, if we do a quick search within that file for time we will find the following at around line 217:
```cpp
const uint16_t dayTimeMin = 0;
const uint16_t dayTimeMax = 0xFFFF;
ImGui::SliderScalar("Time", ImGuiDataType_U16, &gSaveContext.dayTime, &dayTimeMin, &dayTimeMax);
SliderInt("Time", (int32_t*)&gSaveContext.dayTime, intSliderOptionsBase.Min(0).Max(0xFFFF).Tooltip("Time of day"));
if (Button("Dawn", buttonOptionsBase)) {
gSaveContext.dayTime = 0x4000;
}
ImGui::SameLine();
if (Button("Noon", buttonOptionsBase)) {
gSaveContext.dayTime = 0x8000;
}
ImGui::SameLine();
if (Button("Sunset", buttonOptionsBase)) {
gSaveContext.dayTime = 0xC001;
}
ImGui::SameLine();
if (Button("Midnight", buttonOptionsBase)) {
gSaveContext.dayTime = 0;
}
```
So this tells us that `gSaveContext.dayTime` is what we're looking for. Let's now do a global search for this to see if we can find where it is updated. We find the following in `soh/src/code/z_kankyo.c` line 925:
So this tells us that `gSaveContext.dayTime` is what we're looking for. Let's now do a global search for this to see if we can find where it is updated. We find the following in `soh/src/code/z_kankyo.c` around line 925:
```cpp
if (IS_DAY || gTimeIncrement >= 0x190) {
@ -71,16 +84,19 @@ if (IS_DAY || gTimeIncrement >= 0x190) {
}
```
Rebuild the game and launch it, then load a save file. You should see that the time of day is now moving much faster. Terrific! While we could wrap this up and call it a day, we could make this user configurable by making a few more changes. I think a slider would be good for this, there's a slider in the cheat menu that we can use as a reference. Let's find it in `soh/soh/SohMenuBar.cpp` around line 1120:
Rebuild the game and launch it, then load a save file. You should see that the time of day is now moving much faster. Terrific! While we could wrap this up and call it a day, we could make this user configurable by making a few more changes. I think a slider would be good for this, there's a slider in the cheat menu that we can use as a reference. Let's find it in `soh/soh/SohGui/SohMenuEnhancements.cpp` around line 1565:
```cpp
UIWidgets::EnhancementSliderFloat("Hookshot Reach Multiplier: %.1fx", "##gCheatHookshotReachMultiplier", "gCheatHookshotReachMultiplier", 1.0f, 5.0f, "", 1.0f, false);
AddWidget(path, "Hookshot Reach Multiplier: %.2fx", WIDGET_CVAR_SLIDER_FLOAT)
.CVar(CVAR_CHEAT("HookshotReachMultiplier"))
.Options(FloatSliderOptions().Format("%.2f").Min(1.0f).Max(5.0f));
```
The float values being passed in here are `minimum`, `maximum`, and `default` respectively. We'll make our minimum 0.2 to allow it to move slower, and our maximum 5.0 to allow it to move up to 5x faster. We'll also set the default to 1.0 so that it doesn't change the behavior by default. Copy this line and paste it below, then make the relevant changes:
This adds a `Widget` which sets a CVar, which then sets the options of the slider. We'll make our minimum 0.2 to allow it to move slower, and our maximum 5.0 to allow it to move up to 5x faster. We'll also set the default to 1.0 so that it doesn't change the behavior by default. Copy this line and paste it below, then make the relevant changes:
```cpp
UIWidgets::EnhancementSliderFloat("Time Multiplier: %.1fx", "##gCheatTimeMultiplier", "gCheatTimeMultiplier", 0.2f, 5.0f, "", 1.0f, false);
AddWidget(path, "Time Multiplier: %.2fx", WIDGET_CVAR_SLIDER_FLOAT)
.CVar(CVAR_CHEAT("TimeOfDayMultiplier"))
.Options(FloatSliderOptions().Format("%.2f").Min(0.2f).Max(5.0f).DefaultValue(1.0f));
```
Now we need to replace our hard coded values with the new variable. We can do this by replacing the `10` with a cvar call
@ -88,10 +104,10 @@ Now we need to replace our hard coded values with the new variable. We can do th
```diff
if (IS_DAY || gTimeIncrement >= 0x190) {
- gSaveContext.dayTime += gTimeIncrement * 10;
+ gSaveContext.dayTime += gTimeIncrement * CVarGetFloat("gCheatTimeMultiplier", 1.0f);
+ gSaveContext.dayTime += gTimeIncrement * CVarGetFloat(CVAR_CHEAT("TimeOfDayMultiplier"),1.0f);
} else {
- gSaveContext.dayTime += gTimeIncrement * 2 * 10;
+ gSaveContext.dayTime += gTimeIncrement * 2 * CVarGetFloat("gCheatTimeMultiplier", 1.0f);
+ gSaveContext.dayTime += gTimeIncrement * 2 * CVarGetFloat(CVAR_CHEAT("TimeOfDayMultiplier"),1.0f);
}
```

View file

@ -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") });

View file

@ -163,6 +163,7 @@ typedef enum {
TEXT_ANJU_ROUND_THEM_UP_OR_YOULL_PAY = 0x503C,
TEXT_ANJU_DONT_TEASE_MY_CUCCOS = 0x503D,
TEXT_BIG_POE_COLLECTED_RANDO = 0x5090,
TEXT_GERUDO_GUARD_FRIENDLY = 0x6005,
TEXT_HBA_NOT_ON_HORSE = 0x603F,
TEXT_HBA_INITIAL_EXPLAINATION = 0x6040,
TEXT_HBA_WANT_TO_TRY_AGAIN_YES_NO = 0x6041,

View file

@ -575,6 +575,14 @@ typedef enum {
// - None
VB_GANON_HEAL_BEFORE_FIGHT,
// #### `result`
// ```c
// true
// ```
// #### `args`
// - `*EnGe2`
VB_GERUDO_GUARD_SET_ACTION_AFTER_TALK,
// #### `result`
// See logic in
// ```c
@ -1992,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) &&

View file

@ -46,6 +46,7 @@ extern "C" {
#include "src/overlays/actors/ovl_En_Hy/z_en_hy.h"
#include "src/overlays/actors/ovl_En_Bom_Bowl_Pit/z_en_bom_bowl_pit.h"
#include "src/overlays/actors/ovl_En_Ge1/z_en_ge1.h"
#include "src/overlays/actors/ovl_En_Ge2/z_en_ge2.h"
#include "src/overlays/actors/ovl_En_Ds/z_en_ds.h"
#include "src/overlays/actors/ovl_En_Gm/z_en_gm.h"
#include "src/overlays/actors/ovl_En_Js/z_en_js.h"
@ -55,7 +56,6 @@ extern "C" {
#include "src/overlays/actors/ovl_En_Xc/z_en_xc.h"
#include "src/overlays/actors/ovl_Fishing/z_fishing.h"
#include "src/overlays/actors/ovl_En_Mk/z_en_mk.h"
#include "src/overlays/actors/ovl_En_Ge1/z_en_ge1.h"
#include "draw.h"
extern SaveContext gSaveContext;
@ -69,6 +69,8 @@ extern void EnMk_Wait(EnMk* enMk, PlayState* play);
extern void func_80ABA778(EnNiwLady* enNiwLady, PlayState* play);
extern void EnGe1_Wait_Archery(EnGe1* enGe1, PlayState* play);
extern void EnGe1_SetAnimationIdle(EnGe1* enGe1);
extern void EnGe1_SetAnimationIdle(EnGe1* enGe1);
extern void EnGe2_SetupCapturePlayer(EnGe2* enGe2, PlayState* play);
}
bool LocMatchesQuest(Rando::Location loc) {
@ -1435,6 +1437,13 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l
}
break;
}
case VB_GERUDO_GUARD_SET_ACTION_AFTER_TALK:
if (gPlayState->msgCtx.choiceIndex == 0) {
EnGe2* enGe2 = va_arg(args, EnGe2*);
EnGe2_SetupCapturePlayer(enGe2, gPlayState);
*should = false;
}
break;
case VB_GERUDOS_BE_FRIENDLY: {
*should = CHECK_QUEST_ITEM(QUEST_GERUDO_CARD);
break;

View file

@ -2256,7 +2256,7 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) {
(Randomizer_GetSettingValue(RSK_GOSSIP_STONE_HINTS) == RO_GOSSIP_STONES_NEED_STONE &&
CHECK_QUEST_ITEM(QUEST_STONE_OF_AGONY)))) {
Actor* stone = GET_PLAYER(play)->talkActor;
Actor* stone = player->talkActor;
RandomizerHint stoneHint = RH_NONE;
s16 hintParams = stone->params & 0xFF;
@ -2314,7 +2314,7 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) {
(RandomizerInf)((textId - TEXT_SHOP_ITEM_RANDOM_CONFIRM) + RAND_INF_SHOP_ITEMS_KF_SHOP_ITEM_1));
messageEntry = OTRGlobals::Instance->gRandomizer->GetMerchantMessage(rc, TEXT_SHOP_ITEM_RANDOM_CONFIRM);
} else if (textId == TEXT_SCRUB_RANDOM) {
EnDns* enDns = (EnDns*)GET_PLAYER(play)->talkActor;
EnDns* enDns = (EnDns*)player->talkActor;
RandomizerCheck rc = OTRGlobals::Instance->gRandomizer->GetCheckFromRandomizerInf(
(RandomizerInf)enDns->sohScrubIdentity.randomizerInf);
messageEntry = OTRGlobals::Instance->gRandomizer->GetMerchantMessage(
@ -2364,7 +2364,7 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::merchantMessageTableID, textId,
MF_AUTO_FORMAT);
} else if (textId == TEXT_SKULLTULA_PEOPLE_IM_CURSED) {
actorParams = GET_PLAYER(play)->talkActor->params;
actorParams = player->talkActor->params;
if (actorParams == 1 && ctx->GetOption(RSK_KAK_10_SKULLS_HINT)) {
messageEntry = ctx->GetHint(RH_KAK_10_SKULLS_HINT)->GetHintMessage(MF_AUTO_FORMAT);
} else if (actorParams == 2 && ctx->GetOption(RSK_KAK_20_SKULLS_HINT)) {
@ -2463,6 +2463,10 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) {
} else if (textId == TEXT_BIG_POE_COLLECTED_RANDO) {
messageEntry =
CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId, MF_AUTO_FORMAT);
} else if (textId == TEXT_GERUDO_GUARD_FRIENDLY && player->talkActor->id == ACTOR_EN_GE2) {
// TODO_TRANSLATE Translate into french and german
messageEntry = CustomMessage("Want me to throw you in jail?&\x1B#Yes please&No thanks#", { QM_GREEN });
messageEntry.AutoFormat();
}
}
if (textId == TEXT_GS_NO_FREEZE || textId == TEXT_GS_FREEZE) {

View file

@ -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."));

View file

@ -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;

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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) {

View file

@ -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);

View file

@ -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) {

View file

@ -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);

View file

@ -439,20 +439,21 @@ void EnGe2_LookAtPlayer(EnGe2* this, PlayState* play) {
void EnGe2_SetActionAfterTalk(EnGe2* this, PlayState* play) {
if (Actor_TextboxIsClosing(&this->actor, play)) {
switch (this->actor.params & 0xFF) {
case GE2_TYPE_PATROLLING:
EnGe2_ChangeAction(this, GE2_ACTION_ABOUTTURN);
break;
case GE2_TYPE_STATIONARY:
EnGe2_ChangeAction(this, GE2_ACTION_STAND);
break;
case GE2_TYPE_GERUDO_CARD_GIVER:
this->actionFunc = EnGe2_WaitLookAtPlayer;
break;
if (GameInteractor_Should(VB_GERUDO_GUARD_SET_ACTION_AFTER_TALK, true, this)) {
switch (this->actor.params & 0xFF) {
case GE2_TYPE_PATROLLING:
EnGe2_ChangeAction(this, GE2_ACTION_ABOUTTURN);
break;
case GE2_TYPE_STATIONARY:
EnGe2_ChangeAction(this, GE2_ACTION_STAND);
break;
case GE2_TYPE_GERUDO_CARD_GIVER:
this->actionFunc = EnGe2_WaitLookAtPlayer;
break;
}
this->actor.update = EnGe2_UpdateFriendly;
this->actor.flags &= ~ACTOR_FLAG_TALK_OFFER_AUTO_ACCEPTED;
}
this->actor.update = EnGe2_UpdateFriendly;
this->actor.flags &= ~ACTOR_FLAG_TALK_OFFER_AUTO_ACCEPTED;
}
EnGe2_TurnToFacePlayer(this, play);
}

View file

@ -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) {

View file

@ -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--;