Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace old pause buffer input experience with a more accurate one #4918

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions soh/soh/Enhancements/Cheats/EasyFrameAdvance.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include <libultraship/libultraship.h>
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "soh/ShipInit.hpp"

extern "C" {
#include "variables.h"
#include "overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h"
}

#define CVAR_FRAME_ADVANCE_NAME CVAR_CHEAT("EasyFrameAdvance")
#define CVAR_FRAME_ADVANCE_DEFAULT 0
#define CVAR_FRAME_ADVANCE_VALUE CVarGetInteger(CVAR_FRAME_ADVANCE_NAME, CVAR_FRAME_ADVANCE_DEFAULT)

static int frameAdvanceTimer = 0;
#define PAUSE_STATE_OFF 0
#define PAUSE_STATE_UNPAUSE_CLOSE 19

void RegisterEasyFrameAdvance() {
COND_HOOK(OnGameStateMainStart, CVAR_FRAME_ADVANCE_VALUE, []() {
if (gPlayState == NULL) {
return;
}

Input* input = &gPlayState->state.input[0];
PauseContext* pauseCtx = &gPlayState->pauseCtx;

if (frameAdvanceTimer > 0 && pauseCtx->state == PAUSE_STATE_OFF) {
frameAdvanceTimer--;
if (frameAdvanceTimer == 0 && CHECK_BTN_ALL(input->cur.button, BTN_START)) {
input->press.button |= BTN_START;
}
}

if (pauseCtx->state == PAUSE_STATE_UNPAUSE_CLOSE) {
frameAdvanceTimer = 2;
}
});
}

static RegisterShipInitFunc initFunc(RegisterEasyFrameAdvance, { CVAR_FRAME_ADVANCE_NAME });
75 changes: 75 additions & 0 deletions soh/soh/Enhancements/Restorations/PauseBufferInputs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include <libultraship/libultraship.h>
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "soh/ShipInit.hpp"

extern "C" {
#include "variables.h"
#include "overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h"
}

#define CVAR_BUFFER_NAME CVAR_ENHANCEMENT("PauseBufferWindow")
#define CVAR_BUFFER_DEFAULT 0
#define CVAR_BUFFER_VALUE CVarGetInteger(CVAR_BUFFER_NAME, CVAR_BUFFER_DEFAULT)

#define CVAR_INCLUDE_NAME CVAR_ENHANCEMENT("IncludeHeldInputsBufferWindow")
#define CVAR_INCLUDE_DEFAULT 0
#define CVAR_INCLUDE_VALUE CVarGetInteger(CVAR_INCLUDE_NAME, CVAR_INCLUDE_DEFAULT)

#define CVAR_FRAME_ADVANCE_NAME CVAR_CHEAT("EasyFrameAdvance")
#define CVAR_FRAME_ADVANCE_DEFAULT 0
#define CVAR_FRAME_ADVANCE_VALUE CVarGetInteger(CVAR_FRAME_ADVANCE_NAME, CVAR_FRAME_ADVANCE_DEFAULT)

static u16 inputBufferTimer = 0;
static u16 pauseInputs = 0;
#define PAUSE_STATE_OFF 0
#define PAUSE_STATE_UNPAUSE_SETUP 18

void RegisterPauseBufferInputs() {
COND_VB_SHOULD(VB_KALEIDO_UNPAUSE_CLOSE, CVAR_BUFFER_VALUE || CVAR_INCLUDE_VALUE, {
Input* input = &gPlayState->state.input[0];

// Store all inputs that were pressed during the buffer window
pauseInputs |= input->press.button;

// If the user opts to include held inputs in the buffer window, store the held inputs as well
if (CVAR_INCLUDE_VALUE && inputBufferTimer == 0) {
pauseInputs |= input->cur.button;
}

// Wait a specified number of frames before continuing the unpause
inputBufferTimer++;
if (inputBufferTimer < CVAR_BUFFER_VALUE) {
*should = false;
}
});

COND_HOOK(OnGameStateMainStart, CVAR_BUFFER_VALUE || CVAR_INCLUDE_VALUE, []() {
if (gPlayState == NULL) {
return;
}

Input* input = &gPlayState->state.input[0];
PauseContext* pauseCtx = &gPlayState->pauseCtx;

// if the input buffer timer is not 0 and the pause state is off, then the player just unpaused
if (inputBufferTimer != 0 && pauseCtx->state == PAUSE_STATE_OFF) {
inputBufferTimer = 0;

// If the user opts into easy frame advance, remove START input
if (CVAR_FRAME_ADVANCE_VALUE) {
pauseInputs &= ~BTN_START;
}

// So we need to re-apply the inputs that were pressed during the buffer window
input->press.button |= pauseInputs;
}

// Reset the timer and stored inputs at the beginning of the unpause process
if (pauseCtx->state == PAUSE_STATE_UNPAUSE_SETUP && pauseCtx->unk_1F4 != 160.0f) {
inputBufferTimer = 0;
pauseInputs = 0;
}
});
}

static RegisterShipInitFunc initFunc(RegisterPauseBufferInputs, { CVAR_BUFFER_NAME, CVAR_INCLUDE_NAME });
2 changes: 0 additions & 2 deletions soh/soh/Enhancements/bootcommands.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ void BootCommands_Init()
CVarClear(CVAR_GENERAL("OnFileSelectNameEntry")); // Clear when soh is killed on the file name entry page
CVarClear(CVAR_GENERAL("BetterDebugWarpScreenMQMode"));
CVarClear(CVAR_GENERAL("BetterDebugWarpScreenMQModeScene"));
CVarClear(CVAR_GENERAL("CheatEasyPauseBufferLastInputs"));
CVarClear(CVAR_GENERAL("CheatEasyPauseBufferTimer"));
#if defined(__SWITCH__) || defined(__WIIU__)
CVarRegisterInteger(CVAR_IMGUI_CONTROLLER_NAV, 1); // always enable controller nav on switch/wii u
#endif
Expand Down
1 change: 1 addition & 0 deletions soh/soh/Enhancements/game-interactor/GameInteractor.h
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ typedef enum {
VB_RENDER_YES_ON_CONTINUE_PROMPT,
// Vanilla condition: CHECK_BTN_ALL(input->press.button, BTN_START)
VB_CLOSE_PAUSE_MENU,
VB_KALEIDO_UNPAUSE_CLOSE,
// Vanilla condition: true
VB_SPAWN_BLUE_WARP,
// Vanilla condition: this->warpTimer > sWarpTimerTarget && gSaveContext.nextCutsceneIndex == 0xFFEF
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/
DEFINE_HOOK(OnLoadGame, (int32_t fileNum));
DEFINE_HOOK(OnExitGame, (int32_t fileNum));
DEFINE_HOOK(OnGameStateMainStart, ());
DEFINE_HOOK(OnGameFrameUpdate, ());
DEFINE_HOOK(OnItemReceive, (GetItemEntry itemEntry));
DEFINE_HOOK(OnSaleEnd, (GetItemEntry itemEntry));
Expand Down
4 changes: 4 additions & 0 deletions soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ void GameInteractor_ExecuteOnExitGame(int32_t fileNum) {
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnExitGame>(fileNum);
}

void GameInteractor_ExecuteOnGameStateMainStart() {
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnGameStateMainStart>();
}

void GameInteractor_ExecuteOnGameFrameUpdate() {
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnGameFrameUpdate>();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ extern "C" {
// MARK: - Gameplay
void GameInteractor_ExecuteOnLoadGame(int32_t fileNum);
void GameInteractor_ExecuteOnExitGame(int32_t fileNum);
void GameInteractor_ExecuteOnGameStateMainStart();
void GameInteractor_ExecuteOnGameFrameUpdate();
void GameInteractor_ExecuteOnItemReceiveHooks(GetItemEntry itemEntry);
void GameInteractor_ExecuteOnSaleEndHooks(GetItemEntry itemEntry);
Expand Down
4 changes: 0 additions & 4 deletions soh/soh/Enhancements/presets.h
Original file line number Diff line number Diff line change
Expand Up @@ -342,8 +342,6 @@ const std::vector<const char*> cheatCvars = {
CVAR_CHEAT("EasyISG"),
CVAR_CHEAT("EasyQPA"),
CVAR_CHEAT("TimelessEquipment"),
CVAR_CHEAT("EasyPauseBuffer"),
CVAR_CHEAT("EasyInputBuffer"),
CVAR_CHEAT("NoRestrictItems"),
CVAR_CHEAT("FreezeTime"),
CVAR_GENERAL("PrevTime"),
Expand Down Expand Up @@ -1010,7 +1008,6 @@ const std::vector<PresetEntry> spockRacePresetEntries = {
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("MinimumFishWeightChild"), 3),
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("GoronPot"), 1),
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("ForgeTime"), 0),
PRESET_ENTRY_S32(CVAR_CHEAT("EasyPauseBuffer"), 1),
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("DampeAllNight"), 1),
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("10GSHint"), 1),
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("20GSHint"), 1),
Expand Down Expand Up @@ -1062,7 +1059,6 @@ const std::vector<PresetEntry> spockRaceNoLogicPresetEntries = {
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("AdultMasks"), 1),
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("MinimumFishWeightAdult"), 6),
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("AssignableTunicsAndBoots"), 1),
PRESET_ENTRY_S32(CVAR_CHEAT("EasyPauseBuffer"), 1),
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("MinimumFishWeightChild"), 3),
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("ClimbSpeed"), 4),
PRESET_ENTRY_S32(CVAR_COSMETIC("Goron.NeckLength"), 1000),
Expand Down
16 changes: 7 additions & 9 deletions soh/soh/SohMenuBar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,9 +310,6 @@ void DrawSettingsMenu() {
ImGui::PopStyleColor(1);
ImGui::PopStyleVar(3);

UIWidgets::PaddedEnhancementSliderInt("Simulated Input Lag: %d frames", "##SimulatedInputLag", CVAR_SIMULATED_INPUT_LAG, 0, 6, "", 0, true, true, false);
UIWidgets::Tooltip("Buffers your inputs to be executed a specified amount of frames later");

ImGui::EndMenu();
}

Expand Down Expand Up @@ -1569,7 +1566,11 @@ void DrawEnhancementsMenu() {
UIWidgets::Tooltip("Restores a bug from NTSC 1.0/1.1 that allows you to obtain the eyeball frog from King Zora instead of the Zora Tunic by holding shield.");
UIWidgets::PaddedEnhancementCheckbox("Pulsate boss icon", CVAR_ENHANCEMENT("PulsateBossIcon"), true, false);
UIWidgets::Tooltip("Restores an unfinished feature to pulsate the boss room icon when you are in the boss room.");

UIWidgets::PaddedEnhancementSliderInt("Pause Buffer Input Window: %d", "##PauseBufferWindow", CVAR_ENHANCEMENT("PauseBufferWindow"), 0, 40, "", 0, true, true, false);
UIWidgets::PaddedEnhancementCheckbox("Include held inputs at start of Buffer Input Window", CVAR_ENHANCEMENT("IncludeHeldInputsBufferWindow"), true, false);
UIWidgets::Tooltip("Typically, inputs that are held prior to the buffer window are not included in the buffer. This setting changes that behavior to include them. This may cause some inputs to be re-triggered undesireably, for instance Z-Targetting something you might not want to.");
UIWidgets::PaddedEnhancementSliderInt("Simulated Input Lag: %d frames", "##SimulatedInputLag", CVAR_SIMULATED_INPUT_LAG, 0, 6, "", 0, true, true, false);
UIWidgets::Tooltip("Buffers your inputs to be executed a specified amount of frames later");
ImGui::EndMenu();
}

Expand Down Expand Up @@ -1883,11 +1884,8 @@ void DrawCheatsMenu() {
UIWidgets::Tooltip("Makes every surface in the game climbable");
UIWidgets::PaddedEnhancementCheckbox("Moon Jump on L", CVAR_CHEAT("MoonJumpOnL"), true, false);
UIWidgets::Tooltip("Holding L makes you float into the air");
UIWidgets::PaddedEnhancementCheckbox("Easy Frame Advancing", CVAR_CHEAT("EasyPauseBuffer"), true, false);
UIWidgets::Tooltip("Continue holding START button when unpausing to only advance a single frame and then re-pause");
const bool bEasyFrameAdvanceEnabled = CVarGetInteger(CVAR_CHEAT("EasyPauseBuffer"), 0);
UIWidgets::PaddedEnhancementCheckbox("Easy Input Buffering", CVAR_CHEAT("EasyInputBuffer"), true, false, bEasyFrameAdvanceEnabled, "Forced enabled when Easy Frame Advancing is enabled", UIWidgets::CheckboxGraphics::Checkmark);
UIWidgets::Tooltip("Inputs that are held down while the Subscreen is closing will be pressed when the game is resumed");
UIWidgets::PaddedEnhancementCheckbox("New Easy Frame Advancing", CVAR_CHEAT("EasyFrameAdvance"), true, false);
UIWidgets::Tooltip("Continue holding START button when unpausing to only advance a single frame and then re-pause.");
UIWidgets::PaddedEnhancementCheckbox("Drops Don't Despawn", CVAR_CHEAT("DropsDontDie"), true, false);
UIWidgets::Tooltip("Drops from enemies, grass, etc. don't disappear after a set amount of time");
UIWidgets::PaddedEnhancementCheckbox("Fish Don't despawn", CVAR_CHEAT("NoFishDespawn"), true, false);
Expand Down
1 change: 1 addition & 0 deletions soh/soh/UIWidgets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ namespace UIWidgets {
if (changed && (oldVal != val)) {
CVarSetInteger(cvarName, val);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
ShipInit::Init(cvarName);
} else {
changed = false;
}
Expand Down
2 changes: 2 additions & 0 deletions soh/src/code/game.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,8 @@ void GameState_Update(GameState* gameState) {

GameState_SetFrameBuffer(gfxCtx);

GameInteractor_ExecuteOnGameStateMainStart();

gameState->main(gameState);

func_800C4344(gameState);
Expand Down
7 changes: 0 additions & 7 deletions soh/src/code/padmgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,13 +286,6 @@ void PadMgr_ProcessInputs(PadMgr* padMgr) {
Fault_AddHungupAndCrash(__FILE__, __LINE__);
}

// When 3 frames are left on easy pause buffer, re-apply the last held inputs to the prev inputs
// to compute the pressed difference. This makes it so previously held inputs are continued as "held",
// but new inputs when unpausing are "pressed" out of the pause menu.
if (CVarGetInteger(CVAR_GENERAL("CheatEasyPauseBufferTimer"), 0) == 3) {
input->prev.button = CVarGetInteger(CVAR_GENERAL("CheatEasyPauseBufferLastInputs"), 0);
}

buttonDiff = input->prev.button ^ input->cur.button;
input->press.button |= (u16)(buttonDiff & input->cur.button);
input->rel.button |= (u16)(buttonDiff & input->prev.button);
Expand Down
14 changes: 1 addition & 13 deletions soh/src/code/z_kaleido_setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,11 @@ void KaleidoSetup_Update(PlayState* play) {
play->shootingGalleryStatus <= 1 && gSaveContext.magicState != MAGIC_STATE_STEP_CAPACITY && gSaveContext.magicState != MAGIC_STATE_FILL &&
(play->sceneNum != SCENE_BOMBCHU_BOWLING_ALLEY || !Flags_GetSwitch(play, 0x38))) {

u8 easyPauseBufferEnabled = CVarGetInteger(CVAR_CHEAT("EasyPauseBuffer"), 0);
u8 easyPauseBufferTimer = CVarGetInteger(CVAR_GENERAL("CheatEasyPauseBufferTimer"), 0);

// If start is not seen as pressed on the 2nd to last frame then we should end the easy frame advance flow
if (easyPauseBufferEnabled && easyPauseBufferTimer == 2 &&
!CHECK_BTN_ALL(input->press.button, BTN_START)) {
CVarSetInteger(CVAR_GENERAL("CheatEasyPauseBufferTimer"), 0);
}

if (CHECK_BTN_ALL(input->cur.button, BTN_L) && CHECK_BTN_ALL(input->press.button, BTN_CUP)) {
if (BREG(0)) {
pauseCtx->debugState = 3;
}
} else if ((CHECK_BTN_ALL(input->press.button, BTN_START) && (!easyPauseBufferEnabled || !easyPauseBufferTimer)) ||
(easyPauseBufferEnabled && easyPauseBufferTimer == 1)) { // Force Kaleido open when easy pause buffer reaches 0
// Remember last held buttons for pause buffer cheat (minus start so easy frame advance works)
CVarSetInteger(CVAR_GENERAL("CheatEasyPauseBufferLastInputs"), input->cur.button & ~(BTN_START));
} else if (CHECK_BTN_ALL(input->press.button, BTN_START)) {

gSaveContext.unk_13EE = gSaveContext.unk_13EA;

Expand Down
5 changes: 0 additions & 5 deletions soh/src/code/z_play.c
Original file line number Diff line number Diff line change
Expand Up @@ -1668,11 +1668,6 @@ time_t Play_GetRealTime() {
void Play_Main(GameState* thisx) {
PlayState* play = (PlayState*)thisx;

// Decrease the easy pause buffer timer every frame
if (CVarGetInteger(CVAR_GENERAL("CheatEasyPauseBufferTimer"), 0) > 0) {
CVarSetInteger(CVAR_GENERAL("CheatEasyPauseBufferTimer"), CVarGetInteger(CVAR_GENERAL("CheatEasyPauseBufferTimer"), 0) - 1);
}

if (play->envCtx.unk_EE[2] == 0 && CVarGetInteger(CVAR_GENERAL("LetItSnow"), 0)) {
play->envCtx.unk_EE[3] = 64;
Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_OBJECT_KANKYO, 0, 0, 0, 0, 0, 0, 3, 0);
Expand Down
8 changes: 4 additions & 4 deletions soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c
Original file line number Diff line number Diff line change
Expand Up @@ -3992,10 +3992,6 @@ void KaleidoScope_Update(PlayState* play)
switch (pauseCtx->unk_1E4) {
case 0:
if (GameInteractor_Should(VB_CLOSE_PAUSE_MENU, CHECK_BTN_ALL(input->press.button, BTN_START))) {
if (CVarGetInteger(CVAR_CHEAT("EasyPauseBuffer"), 0) || CVarGetInteger(CVAR_CHEAT("EasyInputBuffer"), 0)) {
// Easy pause buffer is 13 frames, 12 for kaledio to end, and one more to advance a single frame
CVarSetInteger(CVAR_GENERAL("CheatEasyPauseBufferTimer"), 13);
}
Interface_SetDoAction(play, DO_ACTION_NONE);
pauseCtx->state = 0x12;
WREG(2) = -6240;
Expand Down Expand Up @@ -4546,6 +4542,10 @@ void KaleidoScope_Update(PlayState* play)
break;

case 0x13:
if (!GameInteractor_Should(VB_KALEIDO_UNPAUSE_CLOSE, true)) {
break;
}

pauseCtx->state = 0;
R_UPDATE_RATE = 3;
R_PAUSE_MENU_MODE = 0;
Expand Down