shell: consolidate support for exit fades

Resolves #2348.
This commit is contained in:
Marcin Kurczewski 2025-01-21 22:49:59 +01:00
parent 26f1ef6ea1
commit 3fe0e6228b
21 changed files with 48 additions and 29 deletions

View file

@ -8,6 +8,7 @@
- added an optional demo number argument to the `/demo` command
- added pause screen support to demos
- added a fade-out effect when exiting the pause screen to the inventory
- added exit fade-out effects (#2348)
- ⚠️ changed the game data to use a separate strings file for text information, removing it from the game flow file
- changed the sprite limit from 512 to 1024
- changed demo to be interrupted only by esc or action keys

View file

@ -3,7 +3,8 @@
- added pause dialog (#1638)
- added a photo mode feature (#2277)
- added fade-out effect to the demos
- added the ability to hold forward/back to move through menus more quickly (#2298)
- added the ability to hold left/right to move through menus more quickly (#2298)
- added the ability to disable exit fade effects alone (#2348)
- changed default input bindings to let the photo mode binding be compatible with TR1X:
| Key | Old binding | New binding |
| ----------------------------- | ----------- | ------------ |

View file

@ -18,6 +18,7 @@ CFG_BOOL(g_Config, gameplay.enable_total_stats, true)
CFG_BOOL(g_Config, gameplay.enable_timer_in_inventory, true)
CFG_BOOL(g_Config, ui.enable_smooth_bars, true)
CFG_BOOL(g_Config, visuals.enable_fade_effects, true)
CFG_BOOL(g_Config, visuals.enable_exit_fade_effects, true)
CFG_BOOL(g_Config, audio.fix_tihocan_secret_sound, true)
CFG_BOOL(g_Config, gameplay.fix_floor_data_issues, true)
CFG_BOOL(g_Config, audio.fix_secrets_killing_music, true)

View file

@ -15,6 +15,7 @@ CFG_BOOL(g_Config, gameplay.enable_auto_item_selection, true)
CFG_INT32(g_Config, gameplay.turbo_speed, 0)
CFG_BOOL(g_Config, visuals.enable_3d_pickups, true)
CFG_BOOL(g_Config, visuals.enable_fade_effects, true)
CFG_BOOL(g_Config, visuals.enable_exit_fade_effects, true)
CFG_BOOL(g_Config, visuals.fix_item_rots, true)
CFG_INT32(g_Config, visuals.fov, 80)
CFG_BOOL(g_Config, visuals.use_pcx_fov, true)

View file

@ -1,12 +1,13 @@
#include "game/phase/executor.h"
#include "config.h"
#include "game/clock.h"
#include "game/console/common.h"
#include "game/fader.h"
#include "game/game.h"
#include "game/game_flow.h"
#include "game/interpolation.h"
#include "game/output.h"
#include "game/shell.h"
#include "game/text.h"
#define MAX_PHASES 10
@ -29,9 +30,11 @@ static PHASE_CONTROL M_Control(PHASE *const phase, const int32_t nframes)
return (PHASE_CONTROL) { .action = PHASE_ACTION_END, .gf_cmd = gf_cmd };
}
if (Game_IsExiting() && !m_Exiting) {
if (Shell_IsExiting() && !m_Exiting) {
m_Exiting = true;
Fader_Init(&m_ExitFader, FADER_ANY, FADER_BLACK, 1.0 / 3.0);
if (g_Config.visuals.enable_exit_fade_effects) {
Fader_Init(&m_ExitFader, FADER_ANY, FADER_BLACK, 1.0 / 3.0);
}
} else if (m_Exiting && !Fader_IsActive(&m_ExitFader)) {
return (PHASE_CONTROL) {
.action = PHASE_ACTION_END,
@ -86,7 +89,7 @@ GAME_FLOW_COMMAND PhaseExecutor_Run(PHASE *const phase)
if (phase->start != NULL) {
Clock_SyncTick();
const PHASE_CONTROL control = phase->start(phase);
if (Game_IsExiting()) {
if (Shell_IsExiting()) {
gf_cmd = (GAME_FLOW_COMMAND) { .action = GF_EXIT_GAME };
goto finish;
} else if (control.action == PHASE_ACTION_END) {
@ -100,7 +103,7 @@ GAME_FLOW_COMMAND PhaseExecutor_Run(PHASE *const phase)
const PHASE_CONTROL control = M_Control(phase, nframes);
if (control.action == PHASE_ACTION_END) {
if (Game_IsExiting()) {
if (Shell_IsExiting()) {
gf_cmd = (GAME_FLOW_COMMAND) { .action = GF_EXIT_GAME };
} else {
gf_cmd = control.gf_cmd;

View file

@ -7,6 +7,7 @@
#include "game/interpolation.h"
#include "game/inventory_ring.h"
#include "game/output.h"
#include "game/shell.h"
#include "game/text.h"
#include "memory.h"
@ -101,7 +102,7 @@ static PHASE_CONTROL M_Control(PHASE *const phase, const int32_t num_frames)
case STATE_FINISH:
return (PHASE_CONTROL) {
.action = PHASE_ACTION_END,
.gf_cmd = Game_IsExiting()
.gf_cmd = Shell_IsExiting()
? (GAME_FLOW_COMMAND) { .action = GF_EXIT_GAME }
: p->exit_gf_cmd,
};

View file

@ -10,6 +10,8 @@
#include <libavcodec/version.h>
static bool m_IsExiting = false;
static void M_SetupHiDPI(void);
static void M_SetupLibAV(void);
static void M_SetupSDL(void);
@ -153,3 +155,13 @@ void Shell_GetWindowSize(int32_t *const out_width, int32_t *const out_height)
SDL_GetWindowSize(window, out_width, out_height);
}
}
void Shell_ScheduleExit(void)
{
m_IsExiting = true;
}
bool Shell_IsExiting(void)
{
return m_IsExiting;
}

View file

@ -76,6 +76,7 @@ typedef struct {
struct {
bool enable_fade_effects;
bool enable_exit_fade_effects;
int32_t fov_value;
bool fov_vertical;
float brightness;

View file

@ -44,6 +44,7 @@ typedef struct {
struct {
bool enable_3d_pickups;
bool enable_fade_effects;
bool enable_exit_fade_effects;
bool fix_item_rots;
int32_t fov;
bool use_pcx_fov;

View file

@ -13,6 +13,5 @@ extern GAME_FLOW_COMMAND Game_Control(bool demo_mode);
extern void Game_Draw(bool draw_overlay);
extern bool Game_IsPlayable(void);
extern bool Game_IsExiting(void);
extern GAME_FLOW_LEVEL_TYPE Game_GetCurrentLevelType(void);
extern int32_t Game_GetCurrentLevelNum(void);

View file

@ -11,6 +11,9 @@ void Shell_Terminate(int32_t exit_code);
void Shell_ExitSystem(const char *message);
void Shell_ExitSystemFmt(const char *fmt, ...);
void Shell_ScheduleExit(void);
bool Shell_IsExiting(void);
int32_t Shell_GetCurrentDisplayWidth(void);
int32_t Shell_GetCurrentDisplayHeight(void);
void Shell_GetWindowSize(int32_t *out_width, int32_t *out_height);

View file

@ -366,11 +366,6 @@ extern int32_t Game_GetCurrentLevelNum(void)
return g_CurrentLevel;
}
bool Game_IsExiting(void)
{
return false;
}
bool Game_IsPlayable(void)
{
if (g_GameInfo.current_level_type == GFL_TITLE

View file

@ -38,11 +38,17 @@ static int m_ArgCount = 0;
static char **m_ArgStrings = NULL;
static SDL_Window *m_Window = NULL;
static void M_HandleQuit(void);
static void M_SetWindowPos(int32_t x, int32_t y, bool update);
static void M_SetWindowSize(int32_t width, int32_t height, bool update);
static void M_SetWindowMaximized(bool is_enabled, bool update);
static void M_SetFullscreen(bool is_enabled, bool update);
static void M_HandleQuit(void)
{
Shell_ScheduleExit();
}
static void M_SetWindowPos(int32_t x, int32_t y, bool update)
{
if (x <= 0 || y <= 0) {
@ -150,7 +156,7 @@ void Shell_ProcessEvents(void)
while (SDL_PollEvent(&event) != 0) {
switch (event.type) {
case SDL_QUIT:
Shell_Terminate(0);
M_HandleQuit();
break;
case SDL_WINDOWEVENT:

View file

@ -139,7 +139,8 @@ static void M_Play(const char *const file_name)
Input_Update();
Shell_ProcessInput();
if (g_InputDB.menu_back || g_InputDB.menu_confirm || g_IsGameToExit) {
if (g_InputDB.menu_back || g_InputDB.menu_confirm
|| Shell_IsExiting()) {
Video_Stop(video);
break;
}
@ -159,7 +160,7 @@ void FMV_Play(const char *const file_name)
M_Play(file_name);
if (!g_IsGameToExit) {
if (!Shell_IsExiting()) {
Render_Reset(RENDER_RESET_ALL);
}
}

View file

@ -194,11 +194,6 @@ extern int32_t Game_GetCurrentLevelNum(void)
return g_CurrentLevel;
}
bool Game_IsExiting(void)
{
return g_IsGameToExit;
}
bool Game_IsPlayable(void)
{
if (g_GameInfo.current_level.type == GFL_TITLE

View file

@ -5,6 +5,7 @@
#include "game/fmv.h"
#include "game/music.h"
#include "game/phase.h"
#include "game/shell.h"
#include "global/vars.h"
#include <libtrx/benchmark.h>
@ -163,7 +164,7 @@ GAME_FLOW_COMMAND GF_InterpretSequence(
LOG_ERROR("Invalid FMV number: %d", ptr[1]);
} else {
FMV_Play(g_GameFlow.fmvs[ptr[1]].path);
if (g_IsGameToExit) {
if (Shell_IsExiting()) {
return (GAME_FLOW_COMMAND) { .action = GF_EXIT_GAME };
}
}

View file

@ -176,7 +176,7 @@ static GAME_FLOW_COMMAND M_Finish(
GAME_FLOW_COMMAND gf_cmd = { .action = GF_NOOP };
if (g_IsGameToExit) {
if (Shell_IsExiting()) {
return (GAME_FLOW_COMMAND) { .action = GF_EXIT_GAME };
} else if (g_GF_OverrideCommand.action != GF_NOOP) {
return g_GF_OverrideCommand;
@ -343,7 +343,7 @@ static GAME_FLOW_COMMAND M_Control(INV_RING *const ring)
Stats_UpdateTimer();
}
if (g_IsGameToExit) {
if (Shell_IsExiting()) {
return (GAME_FLOW_COMMAND) { .action = GF_EXIT_GAME };
}

View file

@ -220,7 +220,7 @@ static void M_HandleKeyUp(const SDL_Event *const event)
static void M_HandleQuit(void)
{
g_IsGameToExit = true;
Shell_ScheduleExit();
}
static void M_ConfigureOpenGL(void)
@ -383,7 +383,7 @@ void Shell_Main(void)
M_DisplayLegal();
const bool is_frontend_fail = GF_DoFrontendSequence();
if (g_IsGameToExit) {
if (Shell_IsExiting()) {
Config_Write();
return;
}

View file

@ -83,7 +83,6 @@ uint16_t g_SoundOptionLine;
ASSAULT_STATS g_Assault;
int32_t g_LevelItemCount;
int32_t g_HealthBarTimer;
uint8_t g_IsGameToExit;
int32_t g_CurrentLevel;
int32_t g_LevelComplete;
RGB_888 g_GamePalette8[256];

View file

@ -80,7 +80,6 @@ extern uint16_t g_SoundOptionLine;
extern ASSAULT_STATS g_Assault;
extern int32_t g_LevelItemCount;
extern int32_t g_HealthBarTimer;
extern uint8_t g_IsGameToExit;
extern int32_t g_CurrentLevel;
extern int32_t g_LevelComplete;
extern RGB_888 g_GamePalette8[256];

View file

@ -8,7 +8,6 @@
int main(int argc, char **argv)
{
Log_Init(File_GetFullPath("TR2X.log"));
g_IsGameToExit = false;
Shell_Setup();
Shell_Main();
Shell_Shutdown();