diff --git a/mm/2s2h/BenGui/BenMenu.cpp b/mm/2s2h/BenGui/BenMenu.cpp index 5c11a1cbdc..8715e4ee9b 100644 --- a/mm/2s2h/BenGui/BenMenu.cpp +++ b/mm/2s2h/BenGui/BenMenu.cpp @@ -1013,6 +1013,14 @@ void BenMenu::AddEnhancements() { AddWidget(path, "Time Moves when you Move", WIDGET_CVAR_CHECKBOX) .CVar("gModes.TimeMovesWhenYouMove") .Options(CheckboxOptions().Tooltip("Time only moves when Link is not standing still.")); + AddWidget(path, "Super Hot", WIDGET_CVAR_CHECKBOX) + .CVar("gModes.SuperHot") + .PreFunc([](WidgetInfo& info) { + if (mBenMenu->disabledMap.at(DISABLE_FOR_TIME_MOVES_WHEN_YOU_MOVE).active) { + info.activeDisables.push_back(DISABLE_FOR_TIME_MOVES_WHEN_YOU_MOVE); + } + }) + .Options(CheckboxOptions().Tooltip("Actor updates are also tied to Link moving")); AddWidget(path, "Mirrored World", WIDGET_CVAR_CHECKBOX) .CVar("gModes.MirroredWorld.Mode") .Callback([](WidgetInfo& info) { @@ -2052,6 +2060,9 @@ void BenMenu::InitElement() { return CVarGetInteger("gEnhancements.Minigames.BoatArcheryInvincible", 0); }, "Koume is Invincible" } }, + { DISABLE_FOR_TIME_MOVES_WHEN_YOU_MOVE, + { [](disabledInfo& info) -> bool { return !CVarGetInteger("gModes.TimeMovesWhenYouMove", 0); }, + "'Time Moves when you Move' is Disabled" } }, }; } diff --git a/mm/2s2h/BenGui/MenuTypes.h b/mm/2s2h/BenGui/MenuTypes.h index e8a152d2c9..477edd5a12 100644 --- a/mm/2s2h/BenGui/MenuTypes.h +++ b/mm/2s2h/BenGui/MenuTypes.h @@ -32,6 +32,7 @@ typedef enum { DISABLE_FOR_VERTICAL_RESOLUTION_OFF, DISABLE_FOR_LINKS_VOICE_PITCH_MULTIPLIER_OFF, DISABLE_FOR_KOUME_INVINCIBLE, + DISABLE_FOR_TIME_MOVES_WHEN_YOU_MOVE, } DisableOption; struct WidgetInfo; diff --git a/mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.cpp b/mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.cpp index 16291a263e..fa993181ac 100644 --- a/mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.cpp +++ b/mm/2s2h/Enhancements/Modes/TimeMovesWhenYouMove.cpp @@ -4,63 +4,64 @@ extern "C" { #include "variables.h" +#include "overlays/actors/ovl_Arms_Hook/z_arms_hook.h" +void ArmsHook_Shoot(ArmsHook*, PlayState*); } -#define CVAR_NAME "gModes.TimeMovesWhenYouMove" -#define CVAR CVarGetInteger(CVAR_NAME, 0) +#define TIME_MOVES_CVAR_NAME "gModes.TimeMovesWhenYouMove" +#define TIME_MOVES_CVAR CVarGetInteger(TIME_MOVES_CVAR_NAME, 0) + +#define SUPER_HOT_CVAR_NAME "gModes.SuperHot" +#define SUPER_HOT_CVAR CVarGetInteger(SUPER_HOT_CVAR_NAME, 0) // Arbitrary speed to determine the offset is unset #define DEFAULT_TIME_OFFSET -12345 static s32 sStoredTimeOffset = DEFAULT_TIME_OFFSET; void RegisterTimeMovesWhenYouMove() { - if (!CVAR && sStoredTimeOffset != DEFAULT_TIME_OFFSET) { + if (!TIME_MOVES_CVAR && sStoredTimeOffset != DEFAULT_TIME_OFFSET) { gSaveContext.save.timeSpeedOffset = sStoredTimeOffset; sStoredTimeOffset = DEFAULT_TIME_OFFSET; } - // This is WIP code, sort of turns this enhancement into a "Super Hot" mode where - // actors update functions are also halted when not moving. The problem is this breaks - // many situations, like opening a chest or talking to actors. So it needs more time in the oven - - // COND_HOOK(ShouldActorUpdate, CVAR, [](Actor* actor, bool* should) { - // static bool hookIsFiring = false; - // if (actor->id == ACTOR_ARMS_HOOK) { - // ArmsHook* hook = (ArmsHook*)actor; - // if (hook->actionFunc == ArmsHook_Shoot) { - // hookIsFiring = true; - // } else { - // hookIsFiring = false; - // } - // } + COND_HOOK(ShouldActorUpdate, TIME_MOVES_CVAR && SUPER_HOT_CVAR, [](Actor* actor, bool* should) { + static bool hookIsFiring = false; + if (actor->id == ACTOR_ARMS_HOOK) { + ArmsHook* hook = (ArmsHook*)actor; + if (hook->actionFunc == ArmsHook_Shoot) { + hookIsFiring = true; + } else { + hookIsFiring = false; + } + } - // if (actor->id != ACTOR_EN_ARROW && - // (actor->id == ACTOR_PLAYER || actor->category == ACTORCAT_BG || actor->category == ACTORCAT_DOOR || - // actor->category == ACTORCAT_SWITCH || actor->category == ACTORCAT_ITEMACTION)) { - // return; - // } + if (actor->id != ACTOR_EN_ARROW && + (actor->id == ACTOR_PLAYER || actor->category == ACTORCAT_BG || actor->category == ACTORCAT_DOOR || + actor->category == ACTORCAT_SWITCH || actor->category == ACTORCAT_ITEMACTION)) { + return; + } - // Player* player = GET_PLAYER(gPlayState); + Player* player = GET_PLAYER(gPlayState); - // static Actor* lastTalkActor = NULL; - // if (player->talkActor != NULL && player->talkActor != lastTalkActor) { - // lastTalkActor = player->talkActor; - // } + static Actor* lastTalkActor = NULL; + if (player->talkActor != NULL && player->talkActor != lastTalkActor) { + lastTalkActor = player->talkActor; + } - // if (player->speedXZ == 0 && - // lastTalkActor != actor && !(player->stateFlags1 & PLAYER_STATE1_1) && - // !(player->stateFlags1 & PLAYER_STATE1_2) && !(player->stateFlags1 & PLAYER_STATE1_20) && - // !(player->stateFlags1 & PLAYER_STATE1_TALKING) && !(player->stateFlags1 & PLAYER_STATE1_80) && - // !(player->stateFlags1 & PLAYER_STATE1_100) && !(player->stateFlags1 & PLAYER_STATE1_400) && - // !(player->stateFlags1 & PLAYER_STATE1_1000) && !(player->stateFlags1 & PLAYER_STATE1_2000000) && - // !(player->stateFlags1 & PLAYER_STATE1_10000000) && !(player->stateFlags1 & PLAYER_STATE1_20000000) && - // !(player->stateFlags2 & PLAYER_STATE2_8) && !(player->stateFlags3 & PLAYER_STATE3_8) && - // !(player->stateFlags3 & PLAYER_STATE3_2000000) && (!hookIsFiring)) { - // *should = false; - // } - // }); + if (player->speedXZ == 0 && lastTalkActor != actor && !(player->stateFlags1 & PLAYER_STATE1_1) && + !(player->stateFlags1 & PLAYER_STATE1_2) && !(player->stateFlags1 & PLAYER_STATE1_20) && + !(player->stateFlags1 & PLAYER_STATE1_TALKING) && !(player->stateFlags1 & PLAYER_STATE1_DEAD) && + !(player->stateFlags1 & PLAYER_STATE1_100) && !(player->stateFlags1 & PLAYER_STATE1_400) && + !(player->stateFlags1 & PLAYER_STATE1_CHARGING_SPIN_ATTACK) && + !(player->stateFlags1 & PLAYER_STATE1_ZORA_BOOMERANG_THROWN) && + !(player->stateFlags1 & PLAYER_STATE1_10000000) && !(player->stateFlags1 & PLAYER_STATE1_20000000) && + !(player->stateFlags2 & PLAYER_STATE2_8) && !(player->stateFlags3 & PLAYER_STATE3_8) && + !(player->stateFlags3 & PLAYER_STATE3_2000000) && (!hookIsFiring)) { + *should = false; + } + }); - COND_ID_HOOK(OnActorUpdate, ACTOR_PLAYER, CVAR, [](Actor* actor) { + COND_ID_HOOK(OnActorUpdate, ACTOR_PLAYER, TIME_MOVES_CVAR, [](Actor* actor) { Player* player = GET_PLAYER(gPlayState); bool timeShouldMove = (player->stateFlags2 & PLAYER_STATE2_USING_OCARINA) || player->speedXZ != 0.0f; @@ -69,7 +70,9 @@ void RegisterTimeMovesWhenYouMove() { sStoredTimeOffset = DEFAULT_TIME_OFFSET; // This is for the section above, lets arrows continue flying after they were fired with time frozen - // player->unk_D57 = 4; + if (SUPER_HOT_CVAR) { + player->unk_D57 = 4; + } } else if (!timeShouldMove && sStoredTimeOffset == DEFAULT_TIME_OFFSET) { sStoredTimeOffset = gSaveContext.save.timeSpeedOffset; gSaveContext.save.timeSpeedOffset = -R_TIME_SPEED; @@ -77,4 +80,4 @@ void RegisterTimeMovesWhenYouMove() { }); } -static RegisterShipInitFunc initFunc(RegisterTimeMovesWhenYouMove, { CVAR_NAME }); +static RegisterShipInitFunc initFunc(RegisterTimeMovesWhenYouMove, { TIME_MOVES_CVAR_NAME, SUPER_HOT_CVAR_NAME });