Added a timed pause state for use by the state history loader. When the user backs up to a previous state, give the option of temporarily pausing to give the user time to visually process the state before resuming game play. When in this state, an unpause count down can also be optionally shown on the upper left of the video display. Also, setting pause during this state down will cancel the count down and put the emulation into full pause. TODO add GUI config hooks to control video overlay and duration config options.

This commit is contained in:
harry 2023-03-31 05:34:32 -04:00
parent b6a8b46de0
commit 3e9398f973
7 changed files with 96 additions and 4 deletions

View File

@ -346,7 +346,7 @@ void FCEU_DrawRecordingStatus(uint8* XBuf)
hasPlayRecIcon = true;
}
if(FCEUI_EmulationPaused())
if( EmulationPaused & (EMULATIONPAUSED_PAUSED | EMULATIONPAUSED_TIMER) )
drawstatus(XBuf-ClipSidesOffset,3,28,hasPlayRecIcon?-16:0);
}
}

View File

@ -273,6 +273,8 @@ void FCEUI_ClearEmulationFrameStepped();
void FCEUI_SetEmulationPaused(int val);
///toggles the paused bit (bit0) for EmulationPaused. caused FCEUD_DebugUpdate() to fire if the emulation pauses
void FCEUI_ToggleEmulationPause();
void FCEUI_PauseForDuration(int secs);
int FCEUI_PauseFramesRemaining();
//indicates whether input aids should be drawn (such as crosshairs, etc; usually in fullscreen mode)
bool FCEUD_ShouldDrawInputAids();

View File

@ -116,6 +116,7 @@ bool movieSubtitles = true; //Toggle for displaying movie subtitles
bool DebuggerWasUpdated = false; //To prevent the debugger from updating things without being updated.
bool AutoResumePlay = false;
char romNameWhenClosingEmulator[2048] = {0};
static unsigned int pauseTimer = 0;
FCEUGI::FCEUGI()
@ -764,6 +765,22 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
#endif
}
if (EmulationPaused & EMULATIONPAUSED_TIMER)
{
if (pauseTimer > 0)
{
pauseTimer--;
}
else
{
EmulationPaused &= ~EMULATIONPAUSED_TIMER;
}
if (EmulationPaused & EMULATIONPAUSED_PAUSED)
{
EmulationPaused &= ~EMULATIONPAUSED_TIMER;
}
}
if (EmulationPaused & EMULATIONPAUSED_FA)
{
// the user is holding Frame Advance key
@ -787,7 +804,7 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
RefreshThrottleFPS();
}
#endif
if (EmulationPaused & EMULATIONPAUSED_PAUSED)
if (EmulationPaused & (EMULATIONPAUSED_PAUSED | EMULATIONPAUSED_TIMER) )
{
// emulator is paused
memcpy(XBuf, XBackBuf, 256*256);
@ -1263,6 +1280,33 @@ void FCEUI_FrameAdvance(void) {
frameAdvanceRequested = true;
}
void FCEUI_PauseForDuration(int secs)
{
int framesPerSec;
// If already paused, do nothing
if (EmulationPaused & EMULATIONPAUSED_PAUSED)
{
return;
}
if (PAL || dendy)
{
framesPerSec = 50;
}
else
{
framesPerSec = 60;
}
pauseTimer = framesPerSec * secs;
EmulationPaused |= EMULATIONPAUSED_TIMER;
}
int FCEUI_PauseFramesRemaining(void)
{
return (EmulationPaused & EMULATIONPAUSED_TIMER) ? pauseTimer : 0;
}
static int AutosaveCounter = 0;
void UpdateAutosave(void) {

View File

@ -181,8 +181,9 @@ extern uint8 vsdip;
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
#define EMULATIONPAUSED_PAUSED 1
#define EMULATIONPAUSED_FA 2
#define EMULATIONPAUSED_PAUSED 0x01
#define EMULATIONPAUSED_TIMER 0x02
#define EMULATIONPAUSED_FA 0x04
#define FRAMEADVANCE_DELAY_DEFAULT 10
#define NES_HEADER_SIZE 16

View File

@ -1205,6 +1205,7 @@ class StateRecorder
lastState = ringHead;
loadIndexReset = false;
lastLoadFrame = 0;
loadPauseTime = 3;
}
~StateRecorder(void)
@ -1243,6 +1244,7 @@ class StateRecorder
printf("ringBufSize:%i framesPerSnap:%i\n", ringBufSize, framesPerSnap );
compressionLevel = stateRecorderConfig.compressionLevel;
loadPauseTime = stateRecorderConfig.loadPauseTimeSeconds;
}
void update(void)
@ -1318,6 +1320,11 @@ class StateRecorder
lastState = snapIdx;
loadIndexReset = true;
if (loadPauseTime > 0)
{ // Temporary pause after loading new state for user to have time to process
FCEUI_PauseForDuration(loadPauseTime);
}
return 0;
}
@ -1362,6 +1369,7 @@ class StateRecorder
int ringStart;
int ringBufSize;
int compressionLevel;
int loadPauseTime;
unsigned int frameCounter;
unsigned int framesPerSnap;
unsigned int lastLoadFrame;

View File

@ -84,12 +84,14 @@ struct StateRecorderConfigData
float historyDurationMinutes;
float timeBetweenSnapsMinutes;
int compressionLevel;
int loadPauseTimeSeconds;
StateRecorderConfigData(void)
{
historyDurationMinutes = 15.0f;
timeBetweenSnapsMinutes = 3.0f / 60.0f;
compressionLevel = 0;
loadPauseTimeSeconds = 3;
}
};

View File

@ -87,6 +87,8 @@ std::string AsSnapshotName =""; //adelikat:this will set the snapshot name whe
void FCEUI_SetSnapshotAsName(std::string name) { AsSnapshotName = name; }
std::string FCEUI_GetSnapshotAsName() { return AsSnapshotName; }
static void FCEU_DrawPauseCountDown(uint8 *XBuf);
void FCEU_KillVirtualVideo(void)
{
if ( XBuf )
@ -254,6 +256,7 @@ void FCEU_PutImage(void)
FCEU_DrawLagCounter(XBuf);
FCEU_DrawNTSCControlBars(XBuf);
FCEU_DrawRecordingStatus(XBuf);
FCEU_DrawPauseCountDown(XBuf);
ShowFPS();
}
@ -771,3 +774,35 @@ void ShowFPS(void)
DrawTextTrans(XBuf + ((256 - ClipSidesOffset) - 40) + (FSettings.FirstSLine + 4) * 256, 256, (uint8*)fpsmsg, 0xA0);
}
bool showPauseCountDown = true;
static void FCEU_DrawPauseCountDown(uint8 *XBuf)
{
if (EmulationPaused & EMULATIONPAUSED_TIMER)
{
int pauseFramesLeft = FCEUI_PauseFramesRemaining();
if (showPauseCountDown && (pauseFramesLeft > 0) )
{
char text[32];
int framesPerSec;
if (PAL || dendy)
{
framesPerSec = 50;
}
else
{
framesPerSec = 60;
}
sprintf(text, "Unpausing in %d...", (pauseFramesLeft / framesPerSec) + 1);
if (text[0])
{
DrawTextTrans(XBuf + ClipSidesOffset + (FSettings.FirstSLine) * 256, 256, (uint8*)text, 0xA0);
}
}
}
}