From a54abbec3101c681b1f898d3b0d23a05156921fc Mon Sep 17 00:00:00 2001 From: Roman Fomin Date: Mon, 9 May 2022 13:19:21 +0700 Subject: [PATCH] demo playback QOL features (#545) * implement demo progress bar * implement demoskip and skipsec * implement game speed keys * fix gcc warning * fix music if -skipsec is used * fix game speed keys * initialize basetime * restore I_GetTime_RealTime() * rename GetTimeMS()->GetTimeMS_Scaled() * use fastdemo for demo skipping * rename skip to fast-forward * compensate fastdemo tic * refactor i_system.h * move timer functions to i_timer.c * remove unused code * remove redundant redeclaration * fix timer declaration * rename I_SetFastdemo->I_SetFastdemoTimer * fix menu game speed option * simplify I_SetFastdemoTimer * move the timer initialization parts to I_InitTimer * fix typo * restore noblit * add demo_skipping macro --- Source/CMakeLists.txt | 1 + Source/d_main.c | 44 +++++++-- Source/d_main.h | 3 - Source/doomstat.h | 8 +- Source/g_game.c | 60 +++++++++++- Source/hu_stuff.c | 27 +++++- Source/hu_stuff.h | 4 + Source/i_system.c | 204 ++++------------------------------------- Source/i_system.h | 24 +---- Source/i_timer.c | 209 ++++++++++++++++++++++++++++++++++++++++++ Source/i_timer.h | 51 +++++++++++ Source/i_video.c | 14 +-- Source/i_video.h | 5 - Source/m_input.h | 4 + Source/m_menu.c | 52 ++++++++++- Source/m_misc.c | 47 ++++++++-- Source/p_setup.c | 10 +- Source/s_sound.c | 28 ++++-- Source/s_sound.h | 2 + Source/v_video.c | 21 +++++ Source/v_video.h | 2 + 21 files changed, 552 insertions(+), 268 deletions(-) create mode 100644 Source/i_timer.c create mode 100644 Source/i_timer.h diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 47a34bab..7cc2e267 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -38,6 +38,7 @@ set(WOOF_SOURCES i_winmusic.c i_sound.c i_sound.h i_system.c i_system.h + i_timer.c i_timer.h i_video.c i_video.h info.c info.h m_argv.c m_argv.h diff --git a/Source/d_main.c b/Source/d_main.c index 9e900d69..c4e6af2f 100644 --- a/Source/d_main.c +++ b/Source/d_main.c @@ -145,6 +145,8 @@ boolean main_loop_started = false; boolean coop_spawns = false; +boolean demobar; + //jff 4/19/98 list of standard IWAD names typedef struct { @@ -232,6 +234,15 @@ void D_Display (void) int wipestart; boolean done, wipe, redrawsbar; + if (demobar && demo_skipping) + { + if (HU_DemoProgressBar(false)) + { + I_FinishUpdate(); + return; + } + } + if (nodrawers) // for comparative timing / profiling return; @@ -279,9 +290,6 @@ void D_Display (void) break; } - // draw buffered stuff to screen - I_UpdateNoBlit(); - // draw the view directly if (gamestate == GS_LEVEL && !automapactive && gametic) R_RenderPlayerView (&players[displayplayer]); @@ -344,6 +352,9 @@ void D_Display (void) M_Drawer(); // menu is drawn even on top of everything NetUpdate(); // send out any new accumulation + if (demobar && demoplayback) + HU_DemoProgressBar(true); + // normal update if (!wipe) { @@ -367,7 +378,6 @@ void D_Display (void) while (!tics); wipestart = nowtime; done = wipe_ScreenWipe(wipe_Melt,0,0,SCREENWIDTH,SCREENHEIGHT,tics); - I_UpdateNoBlit(); M_Drawer(); // menu is drawn even on top of wipes I_FinishUpdate(); // page flip or blit buffer } @@ -2038,7 +2048,7 @@ void D_DoomMain(void) } //jff end of sound/music command line parms - // killough 3/2/98: allow -nodraw -noblit generally + // killough 3/2/98: allow -nodraw generally nodrawers = M_CheckParm ("-nodraw"); noblit = M_CheckParm ("-noblit"); @@ -2193,6 +2203,23 @@ void D_DoomMain(void) coop_spawns = true; } + p = M_CheckParmWithArgs("-skipsec", 1); + if (p) + { + float min, sec; + + if (sscanf(myargv[p+1], "%f:%f", &min, &sec) == 2) + { + demoskip_tics = (int) ((60 * min + sec) * TICRATE); + } + else if (sscanf(myargv[p+1], "%f", &sec) == 1) + { + demoskip_tics = (int) (sec * TICRATE); + } + + demoskip_tics = abs(demoskip_tics); + } + // start the apropriate game based on parms // killough 12/98: @@ -2232,8 +2259,11 @@ void D_DoomMain(void) singledemo = true; // quit after one demo } else - // [FG] no demo playback - demowarp = -1; + { + // [FG] no demo playback + demowarp = -1; + demoskip_tics = -1; + } if (slot && ++slot < myargc) { diff --git a/Source/d_main.h b/Source/d_main.h index ec55220a..56287a32 100644 --- a/Source/d_main.h +++ b/Source/d_main.h @@ -50,9 +50,6 @@ extern boolean clfastparm; // checkparm of -fast extern boolean pistolstart; -extern boolean nosfxparm; -extern boolean nomusicparm; - // Called by IO functions when input is detected. void D_PostEvent(event_t* ev); diff --git a/Source/doomstat.h b/Source/doomstat.h index 7c7a69dd..5444b95d 100644 --- a/Source/doomstat.h +++ b/Source/doomstat.h @@ -220,6 +220,8 @@ extern boolean paused; // Game Pause? extern boolean viewactive; extern boolean nodrawers; extern boolean noblit; +extern boolean nosfxparm; +extern boolean nomusicparm; // This one is related to the 3-screen display mode. // ANG90 = left side, ANG270 = right @@ -267,7 +269,11 @@ extern boolean fastdemo; // [FG] fast-forward demo to the desired map extern int demowarp; // fast-forward demo to the next map -extern boolean demoskip; +extern boolean demonext; +// skipping demo +extern int demoskip_tics; + +#define demo_skipping (demowarp >= 0 || demoskip_tics > 0 || demonext) extern gamestate_t gamestate; diff --git a/Source/g_game.c b/Source/g_game.c index 05586300..7986c96c 100644 --- a/Source/g_game.c +++ b/Source/g_game.c @@ -273,6 +273,30 @@ static int G_NextWeapon(int direction) return weapon_order_table[i].weapon_num; } +int demoskip_tics = -1; + +static void G_DemoSkipTics(void) +{ + static boolean warp = false; + + if (demoskip_tics == -1) + return; + + if (demowarp >= 0) + warp = true; + + if (demowarp == -1) + { + if ((warp && demoskip_tics < gametic - levelstarttic) || + (!warp && demoskip_tics < gametic)) + { + I_EnableWarp(false); + S_RestartMusic(); + demoskip_tics = -1; + } + } +} + // // G_BuildTiccmd // Builds a ticcmd from all of the available inputs @@ -290,6 +314,8 @@ void G_BuildTiccmd(ticcmd_t* cmd) int newweapon; // phares ticcmd_t *base; + G_DemoSkipTics(); + base = I_BaseTiccmd(); // empty, or external driver memcpy(cmd, base, sizeof *cmd); @@ -878,6 +904,9 @@ boolean G_Responder(event_t* ev) // DEMO RECORDING // +// [crispy] demo progress bar +int defdemotics = 0, deftotaldemotics; + #define DEMOMARKER 0x80 static void G_ReadDemoTiccmd(ticcmd_t *cmd) @@ -907,6 +936,8 @@ static void G_ReadDemoTiccmd(ticcmd_t *cmd) cmd->buttons &= ~BTS_SAVEGAME; players[consoleplayer].message = "Game Saved (Suppressed)"; } + + defdemotics++; } } @@ -1259,16 +1290,20 @@ static void G_DoPlayDemo(void) char basename[9]; int demover; byte *option_p = NULL; // killough 11/98 + int lumpnum, lumplength; if (gameaction != ga_loadgame) // killough 12/98: support -loadgame basetic = gametic; // killough 9/29/98 ExtractFileBase(defdemoname,basename); // killough - demobuffer = demo_p = W_CacheLumpName (basename, PU_STATIC); // killough + lumpnum = W_GetNumForName(basename); + lumplength = W_LumpLength(lumpnum); + + demobuffer = demo_p = W_CacheLumpNum(lumpnum, PU_STATIC); // killough // [FG] ignore too short demo lumps - if (W_LumpLength(W_GetNumForName(basename)) < 0xd) + if (lumplength < 0xd) { INVALID_DEMO("Short demo lump %s.\n", basename); } @@ -1468,6 +1503,24 @@ static void G_DoPlayDemo(void) gameaction = ga_nothing; + // [crispy] demo progress bar + { + int i, numplayersingame = 0; + byte *demo_ptr = demo_p; + + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i]) + numplayersingame++; + + deftotaldemotics = defdemotics = 0; + + while (*demo_ptr != DEMOMARKER && (demo_ptr - demobuffer) < lumplength) + { + demo_ptr += numplayersingame * (longtics ? 5 : 4); + deftotaldemotics++; + } + } + // [FG] report compatibility mode fprintf(stderr, "G_DoPlayDemo: Playing demo with %s (%d) compatibility.\n", mbf21 ? "MBF21" : @@ -2851,6 +2904,7 @@ void G_InitNew(skill_t skill, int episode, int map) // [FG] total time for all completed levels totalleveltimes = 0; + defdemotics = 0; //jff 4/16/98 force marks on automap cleared every new level start AM_clearMarks(); @@ -3310,7 +3364,7 @@ void G_DeferedPlayDemo(char* name) gameaction = ga_playdemo; // [FG] fast-forward demo to the desired map - if (demowarp >= 0) + if (demowarp >= 0 || demoskip_tics > 0) { I_EnableWarp(true); } diff --git a/Source/hu_stuff.c b/Source/hu_stuff.c index 42ce2af2..3b505161 100644 --- a/Source/hu_stuff.c +++ b/Source/hu_stuff.c @@ -854,12 +854,12 @@ static void HU_widget_build_sttime(void) { char *s; int offset = 0; - extern int clock_rate; + extern int time_scale; - if (clock_rate != 100) + if (time_scale != 100) { offset += sprintf(hud_timestr, "SPEED \x1b%c%d \x1b%c", - '0'+CR_GREEN, clock_rate, '0'+CR_GRAY); + '0'+CR_GREEN, time_scale, '0'+CR_GRAY); } offset += sprintf(hud_timestr + offset, "TIME"); @@ -969,6 +969,27 @@ static void HU_DrawCrosshair(void) 0, crosshair.patch, crosshair.cr, 0); } +// [crispy] print a bar indicating demo progress at the bottom of the screen +boolean HU_DemoProgressBar(boolean force) +{ + const int progress = SCREENWIDTH * defdemotics / deftotaldemotics; + static int old_progress = 0; + + if (progress - old_progress) + { + old_progress = progress; + } + else if (!force) + { + return false; + } + + V_DrawHorizLine(0, SCREENHEIGHT - 2, FG, progress, colormaps[0][0]); // [crispy] black + V_DrawHorizLine(0, SCREENHEIGHT - 1, FG, progress, colormaps[0][4]); // [crispy] white + + return true; +} + // [FG] level stats and level time widgets int map_player_coords, map_level_stats, map_level_time; diff --git a/Source/hu_stuff.h b/Source/hu_stuff.h index b33186d3..2d8f56ca 100644 --- a/Source/hu_stuff.h +++ b/Source/hu_stuff.h @@ -60,6 +60,8 @@ void HU_Drawer(void); char HU_dequeueChatChar(void); void HU_Erase(void); +boolean HU_DemoProgressBar(boolean force); + // killough 5/2/98: moved from m_misc.c: //jff 2/16/98 hud supported automap colors added @@ -88,6 +90,8 @@ extern int hud_secret_message; // "A secret is revealed!" message extern int map_player_coords, map_level_stats, map_level_time; // [FG] level stats and level time widgets extern int hud_timests; // Time/STS above status bar +extern int defdemotics, deftotaldemotics; + extern int crispy_hud; extern int hud_crosshair; diff --git a/Source/i_system.c b/Source/i_system.c index 57fd5a1a..d2dc24bd 100644 --- a/Source/i_system.c +++ b/Source/i_system.c @@ -44,7 +44,6 @@ #include "m_misc.h" #include "g_game.h" #include "w_wad.h" -#include "v_video.h" #include "m_argv.h" #include "i_endoom.h" @@ -54,101 +53,10 @@ ticcmd_t *I_BaseTiccmd(void) return &emptycmd; } -void I_WaitVBL(int count) -{ - // haleyjd - SDL_Delay((count*500)/TICRATE); -} - -// [FG] let the CPU sleep if there is no tic to proceed - -void I_Sleep(int ms) -{ - SDL_Delay(ms); -} - -// Same as I_GetTime, but returns time in milliseconds - -static Uint32 basetime = 0; - -int I_GetTimeMS(void) -{ - return SDL_GetTicks() - basetime; -} - -// Most of the following has been rewritten by Lee Killough -// -// I_GetTime -// - -int I_GetTime_RealTime(void) -{ - return (int64_t)I_GetTimeMS() * TICRATE / 1000; -} - -// killough 4/13/98: Make clock rate adjustable by scale factor -int realtic_clock_rate = 100; -int clock_rate; - -static int I_GetTime_Scaled(void) -{ - return (int64_t)I_GetTimeMS() * clock_rate * TICRATE / 100000; -} - -static int I_GetTime_FastDemo(void) -{ - static int fasttic; - return fasttic++; -} - -static int I_GetTime_Error(void) -{ - I_Error("Error: GetTime() used before initialization"); - return 0; -} - -int (*I_GetTime)() = I_GetTime_Error; // killough - -// During a fast demo, no time elapses in between ticks -static int I_GetFracTimeFastDemo(void) -{ - return 0; -} - -static int I_GetFracRealTime(void) -{ - return (int64_t)I_GetTimeMS() * TICRATE % 1000 * FRACUNIT / 1000; -} - -static int I_GetFracScaledTime(void) -{ - return (int64_t)I_GetTimeMS() * clock_rate * TICRATE / 100 % 1000 * FRACUNIT / 1000; -} - -int (*I_GetFracTime)(void) = I_GetFracRealTime; - -int leds_always_off; // Tells it not to update LEDs - // pointer to current joystick device information SDL_GameController *controller = NULL; static int controller_index = -1; -static SDL_Keymod oldmod; // haleyjd: save old modifier key state - -static void I_ShutdownJoystick(void) -{ - I_CloseController(controller_index); - - SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER); -} - -void I_Shutdown(void) -{ - SDL_SetModState(oldmod); - - I_ShutdownJoystick(); -} - void I_OpenController(int which) { if (controller) @@ -184,6 +92,18 @@ void I_CloseController(int which) } } +static void I_ShutdownJoystick(void) +{ + I_CloseController(controller_index); + + SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER); +} + +void I_Shutdown(void) +{ + I_ShutdownJoystick(); +} + void I_InitJoystick(void) { if (SDL_Init(SDL_INIT_GAMECONTROLLER) < 0) @@ -198,105 +118,17 @@ void I_InitJoystick(void) printf("I_InitJoystick: Initialize game controller.\n"); } -// haleyjd -void I_InitKeyboard(void) -{ - SDL_Keymod mod; - - oldmod = SDL_GetModState(); - if (M_InputMatchKey(input_autorun, KEYD_CAPSLOCK)) - mod = KMOD_CAPS; - else if (M_InputMatchKey(input_autorun, KEYD_NUMLOCK)) - mod = KMOD_NUM; - else if (M_InputMatchKey(input_autorun, KEYD_SCROLLLOCK)) - mod = KMOD_MODE; - else - mod = KMOD_NONE; - - if(autorun) - SDL_SetModState(mod); - else - SDL_SetModState(KMOD_NONE); -} - -extern boolean nomusicparm, nosfxparm; - void I_Init(void) { - int p; + I_InitTimer(); - clock_rate = realtic_clock_rate; - - if((p = M_CheckParm("-speed")) && p < myargc-1 && - (p = atoi(myargv[p+1])) >= 10 && p <= 1000) - clock_rate = p; - - // init timer - basetime = SDL_GetTicks(); + I_InitJoystick(); - // killough 4/14/98: Adjustable speedup based on realtic_clock_rate - if(fastdemo) - { - I_GetTime = I_GetTime_FastDemo; - I_GetFracTime = I_GetFracTimeFastDemo; - } - else - if(clock_rate != 100) - { - I_GetTime = I_GetTime_Scaled; - I_GetFracTime = I_GetFracScaledTime; - } - else - { - I_GetTime = I_GetTime_RealTime; - I_GetFracTime = I_GetFracRealTime; - } + I_AtExit(I_Shutdown, true); - I_InitJoystick(); - - // killough 3/6/98: save keyboard state, initialize shift state and LEDs: - - // killough 3/6/98: end of keyboard / autorun state changes - - I_AtExit(I_Shutdown, true); - - // killough 2/21/98: avoid sound initialization if no sound & no music - { - if(!(nomusicparm && nosfxparm)) - I_InitSound(); - } -} - -// [FG] toggle demo warp mode -void I_EnableWarp (boolean warp) -{ - static int (*I_GetTime_old)() = I_GetTime_Error; - static boolean nodrawers_old, noblit_old; - static boolean nomusicparm_old, nosfxparm_old; - - if (warp) - { - I_GetTime_old = I_GetTime; - nodrawers_old = nodrawers; - noblit_old = noblit; - nomusicparm_old = nomusicparm; - nosfxparm_old = nosfxparm; - - I_GetTime = I_GetTime_FastDemo; - nodrawers = true; - noblit = true; - nomusicparm = true; - nosfxparm = true; - } - else - { - I_GetTime = I_GetTime_old; - D_StartGameLoop(); - nodrawers = nodrawers_old; - noblit = noblit_old; - nomusicparm = nomusicparm_old; - nosfxparm = nosfxparm_old; - } + // killough 2/21/98: avoid sound initialization if no sound & no music + if (!(nomusicparm && nosfxparm)) + I_InitSound(); } // diff --git a/Source/i_system.h b/Source/i_system.h index 89adb1d1..5e80c49a 100644 --- a/Source/i_system.h +++ b/Source/i_system.h @@ -30,6 +30,7 @@ #define __I_SYSTEM__ #include "d_ticcmd.h" +#include "i_timer.h" // Called by DoomMain. void I_Init(void); @@ -38,22 +39,6 @@ void I_InitJoystick(void); void I_OpenController(int which); void I_CloseController(int which); -// Called by D_DoomLoop, -// returns current time in tics. -// int I_GetTime (void); - -extern int (*I_GetTime)(); // killough -int I_GetTime_RealTime(); // killough -int I_GetTime_Adaptive(void); // killough 4/10/98 -extern int GetTime_Scale; - -extern int (*I_GetFracTime)(void); - -// [FG] Same as I_GetTime, but returns time in milliseconds -int I_GetTimeMS(); -// [FG] toggle demo warp mode -extern void I_EnableWarp (boolean warp); - // // Called by D_DoomLoop, // called before processing any tics in a frame @@ -90,19 +75,12 @@ void I_Quit (void); void I_QuitFirst (void); void I_QuitLast (void); -// Allocates from low memory under dos, just mallocs under unix - -#define I_AllocLow(length) calloc((length),1) /* killough */ #define I_Tactile(on, off, total) // killough 3/20/98: add const // killough 4/25/98: add gcc attributes void I_Error(const char *error, ...) PRINTF_ATTR(1, 2); -extern int leds_always_off; // killough 10/98 - -void I_ResetLEDs(void); // killough 10/98 - void I_EndDoom(void); // killough 2/22/98: endgame screen // Schedule a function to be called when the program exits. diff --git a/Source/i_timer.c b/Source/i_timer.c new file mode 100644 index 00000000..f2a83223 --- /dev/null +++ b/Source/i_timer.c @@ -0,0 +1,209 @@ +// +// Copyright (C) 1999 by +// id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman +// Copyright (C) 2022 Roman Fomin +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Timer functions. +// + +#include "SDL.h" + +#include "i_timer.h" +#include "m_fixed.h" +#include "doomstat.h" +#include "m_argv.h" + +static int MSToTic(Uint32 time) +{ + return time * TICRATE / 1000; +} + +static Uint32 TicToMS(int tic) +{ + return (Uint32)tic * 1000 / TICRATE; +} + +static Uint32 basetime = 0; + +int I_GetTimeMS(void) +{ + Uint32 time; + + time = SDL_GetTicks(); + + if (basetime == 0) + basetime = time; + + return time - basetime; +} + +int time_scale = 100; + +static Uint32 GetTimeMS_Scaled(void) +{ + Uint32 time; + + if (time_scale == 100) + { + time = SDL_GetTicks(); + } + else + { + time = SDL_GetTicks() * time_scale / 100; + } + + if (basetime == 0) + basetime = time; + + return time - basetime; +} + +int I_GetTime_RealTime(void) +{ + return MSToTic(I_GetTimeMS()); +} + +static int I_GetTime_Scaled(void) +{ + return MSToTic(GetTimeMS_Scaled()); +} + +static int fasttic; + +static int I_GetTime_FastDemo(void) +{ + return fasttic++; +} + +int (*I_GetTime)() = I_GetTime_Scaled; + +static int I_GetFracTime_Scaled(void) +{ + return GetTimeMS_Scaled() * TICRATE % 1000 * FRACUNIT / 1000; +} + +// During a fast demo, no time elapses in between ticks + +static int I_GetFracTime_FastDemo(void) +{ + return 0; +} + +int (*I_GetFracTime)(void) = I_GetFracTime_Scaled; + + +// killough 4/13/98: Make clock rate adjustable by scale factor +int realtic_clock_rate = 100; + +void I_InitTimer(void) +{ + int p; + + p = M_CheckParmWithArgs("-speed", 1); + if (p) + { + time_scale = BETWEEN(10, 1000, atoi(myargv[p+1])); + } + else + { + time_scale = realtic_clock_rate; + } + + if (fastdemo) + { + I_GetTime = I_GetTime_FastDemo; + I_GetFracTime = I_GetFracTime_FastDemo; + } + else + { + I_GetTime = I_GetTime_Scaled; + I_GetFracTime = I_GetFracTime_Scaled; + } +} + +void I_SetTimeScale(int scale) +{ + Uint32 time; + + time = GetTimeMS_Scaled(); + + time_scale = scale; + + basetime += (GetTimeMS_Scaled() - time); +} + +void I_SetFastdemoTimer(void) +{ + if (fastdemo) + { + fasttic = I_GetTime(); + + I_GetTime = I_GetTime_FastDemo; + I_GetFracTime = I_GetFracTime_FastDemo; + } + else + { + Uint32 time; + + time = TicToMS(I_GetTime_FastDemo()); + + basetime += (GetTimeMS_Scaled() - time); + + I_GetTime = I_GetTime_Scaled; + I_GetFracTime = I_GetFracTime_Scaled; + } +} + +// [FG] toggle demo warp mode +void I_EnableWarp(boolean warp) +{ + static int (*I_GetTime_old)() = I_GetTime_Scaled; + static boolean nodrawers_old; + static boolean nomusicparm_old, nosfxparm_old; + + if (warp) + { + I_GetTime_old = I_GetTime; + nodrawers_old = nodrawers; + nomusicparm_old = nomusicparm; + nosfxparm_old = nosfxparm; + + I_GetTime = I_GetTime_FastDemo; + nodrawers = true; + nomusicparm = true; + nosfxparm = true; + } + else + { + I_GetTime = I_GetTime_old; + D_StartGameLoop(); + nodrawers = nodrawers_old; + nomusicparm = nomusicparm_old; + nosfxparm = nosfxparm_old; + } +} + + +// Sleep for a specified number of ms + +void I_Sleep(int ms) +{ + SDL_Delay(ms); +} + +void I_WaitVBL(int count) +{ + // haleyjd + I_Sleep((count * 500) / TICRATE); +} diff --git a/Source/i_timer.h b/Source/i_timer.h new file mode 100644 index 00000000..a85a523c --- /dev/null +++ b/Source/i_timer.h @@ -0,0 +1,51 @@ +// +// Copyright (C) 1999 by +// id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman +// Copyright (C) 2022 Roman Fomin +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Timer functions. +// + +#ifndef __I_TIMER__ +#define __I_TIMER__ + +#include "doomtype.h" + +// Called by D_DoomLoop, +// returns current time in tics. +extern int (*I_GetTime)(void); +int I_GetTime_RealTime(void); // killough + +extern int (*I_GetFracTime)(void); + +// [FG] Same as I_GetTime, but returns time in milliseconds +int I_GetTimeMS(); + +void I_SetTimeScale(int scale); + +void I_SetFastdemoTimer(void); + +// [FG] toggle demo warp mode +void I_EnableWarp(boolean warp); + +// Pause for a specified number of ms +void I_Sleep(int ms); + +// Initialize timer +void I_InitTimer(void); + +// Wait for vertical retrace or pause a bit. +void I_WaitVBL(int count); + +#endif \ No newline at end of file diff --git a/Source/i_video.c b/Source/i_video.c index 5fb7bb7b..412e4b82 100644 --- a/Source/i_video.c +++ b/Source/i_video.c @@ -864,14 +864,6 @@ void I_StartTic (void) I_UpdateJoystick(); } -// -// I_UpdateNoBlit -// - -void I_UpdateNoBlit (void) -{ -} - int use_vsync; // killough 2/8/98: controls whether vsync is called int page_flip; // killough 8/15/98: enables page flipping int hires; @@ -1028,7 +1020,7 @@ void I_BeginRead(unsigned int bytes) static void I_DrawDiskIcon(void) { - if (!disk_icon || !in_graphics_mode) + if (!disk_icon || !in_graphics_mode || demo_skipping) return; if (disk_to_draw >= DISK_ICON_THRESHOLD) @@ -1051,7 +1043,7 @@ void I_EndRead(void) static void I_RestoreDiskBackground(void) { - if (!disk_icon || !in_graphics_mode) + if (!disk_icon || !in_graphics_mode || demo_skipping) return; if (disk_to_restore) @@ -1339,8 +1331,6 @@ static void I_InitGraphicsMode(void) { firsttime = false; - I_InitKeyboard(); - if (M_CheckParm("-hires")) hires = true; else if (M_CheckParm("-nohires")) diff --git a/Source/i_video.h b/Source/i_video.h index d07a63ba..8b84cc4c 100644 --- a/Source/i_video.h +++ b/Source/i_video.h @@ -53,13 +53,8 @@ void I_ShutdownGraphics(void); // Takes full 8 bit values. void I_SetPalette (byte* palette); -void I_UpdateNoBlit (void); void I_FinishUpdate (void); -// Wait for vertical retrace or pause a bit. -void I_WaitVBL(int count); -void I_Sleep(int ms); // [FG] let the CPU sleep - void I_ReadScreen (byte* scr); int I_DoomCode2ScanCode(int); // killough diff --git a/Source/m_input.h b/Source/m_input.h index f575046d..765f3fd6 100644 --- a/Source/m_input.h +++ b/Source/m_input.h @@ -89,6 +89,10 @@ enum input_pause, input_spy, input_demo_quit, + input_demo_fforward, + input_speed_up, + input_speed_down, + input_speed_default, input_map, input_map_up, diff --git a/Source/m_menu.c b/Source/m_menu.c index 943d4371..b037194d 100644 --- a/Source/m_menu.c +++ b/Source/m_menu.c @@ -2782,11 +2782,15 @@ setup_menu_t keys_settings2[] = // Key Binding screen strings {"BFG", S_INPUT ,m_scrn,KB_X,M_Y+7*M_SPC,{0},input_weapon7}, {"CHAINSAW",S_INPUT ,m_scrn,KB_X,M_Y+8*M_SPC,{0},input_weapon8}, {"SSG" ,S_INPUT ,m_scrn,KB_X,M_Y+9*M_SPC,{0},input_weapon9}, - + {"BEST" ,S_INPUT ,m_scrn,KB_X,M_Y+10*M_SPC,{0},input_weapontoggle}, // [FG] prev/next weapon keys and buttons {"PREV" ,S_INPUT ,m_scrn,KB_X,M_Y+11*M_SPC,{0},input_prevweapon}, {"NEXT" ,S_INPUT ,m_scrn,KB_X,M_Y+12*M_SPC,{0},input_nextweapon}, - {"BEST" ,S_INPUT ,m_scrn,KB_X,M_Y+13*M_SPC,{0},input_weapontoggle}, + + {"GAME SPEED",S_SKIP|S_TITLE,m_null,KB_X,M_Y+14*M_SPC}, + {"INCREASE" ,S_INPUT,m_scrn,KB_X,M_Y+15*M_SPC,{0},input_speed_up}, + {"DECREASE" ,S_INPUT,m_scrn,KB_X,M_Y+16*M_SPC,{0},input_speed_down}, + {"DEFAULT" ,S_INPUT,m_scrn,KB_X,M_Y+17*M_SPC,{0},input_speed_default}, {"<- PREV",S_SKIP|S_PREV,m_null,M_X_PREV,M_Y_PREVNEXT, {keys_settings1}}, {"NEXT ->",S_SKIP|S_NEXT,m_null,M_X_NEXT,M_Y_PREVNEXT, {keys_settings3}}, @@ -2821,7 +2825,8 @@ setup_menu_t keys_settings3[] = {"MISCELLANEOUS",S_SKIP|S_TITLE,m_null,KB_X,M_Y+11*M_SPC}, {"RELOAD LEVEL",S_INPUT,m_scrn,KB_X,M_Y+12*M_SPC,{0},input_menu_reloadlevel}, {"NEXT LEVEL" ,S_INPUT,m_scrn,KB_X,M_Y+13*M_SPC,{0},input_menu_nextlevel}, - {"FINISH DEMO" ,S_INPUT,m_scrn,KB_X,M_Y+14*M_SPC,{0},input_demo_quit}, + {"FAST-FORWARD DEMO",S_INPUT,m_scrn,KB_X,M_Y+14*M_SPC,{0},input_demo_fforward}, + {"FINISH DEMO" ,S_INPUT,m_scrn,KB_X,M_Y+15*M_SPC,{0},input_demo_quit}, {"<- PREV", S_SKIP|S_PREV,m_null,M_X_PREV,M_Y_PREVNEXT, {keys_settings2}}, {"NEXT ->", S_SKIP|S_NEXT,m_null,M_X_NEXT,M_Y_PREVNEXT, {keys_settings4}}, @@ -3712,6 +3717,7 @@ enum { general_skill, general_comp, general_endoom, + general_demobar, general_end5, }; @@ -3768,6 +3774,9 @@ setup_menu_t gen_settings2[] = { // General Settings screen2 {"Show ENDOOM screen", S_CHOICE, m_null, M_X, G_Y4 + general_endoom*M_SPC, {"show_endoom"}, 0, NULL, default_endoom_strings}, + {"Show demo progress bar", S_YESNO, m_null, M_X, + G_Y4 + general_demobar*M_SPC, {"demobar"}}, + {"<- PREV",S_SKIP|S_PREV, m_null, M_X_PREV, M_Y_PREVNEXT, {gen_settings1}}, // Final entry @@ -5076,15 +5085,48 @@ boolean M_Responder (event_t* ev) // [FG] reload current level / go to next level if (M_InputActivated(input_menu_nextlevel)) { - if (demoplayback && singledemo && !demoskip) + if (demoplayback && singledemo && !demo_skipping) { - demoskip = true; + demonext = true; I_EnableWarp(true); return true; } else if (G_GotoNextLevel(NULL, NULL)) return true; } + + if (M_InputActivated(input_demo_fforward)) + { + if (demoplayback && singledemo && !demo_skipping) + { + fastdemo = !fastdemo; + I_SetFastdemoTimer(); + return true; + } + } + + if (M_InputActivated(input_speed_up) && (!netgame || demoplayback)) + { + realtic_clock_rate += 10; + realtic_clock_rate = BETWEEN(10, 1000, realtic_clock_rate); + dprintf("Game Speed: %d", realtic_clock_rate); + I_SetTimeScale(realtic_clock_rate); + } + + if (M_InputActivated(input_speed_down) && (!netgame || demoplayback)) + { + realtic_clock_rate -= 10; + realtic_clock_rate = BETWEEN(10, 1000, realtic_clock_rate); + dprintf("Game Speed: %d", realtic_clock_rate); + I_SetTimeScale(realtic_clock_rate); + } + + if (M_InputActivated(input_speed_default) && (!netgame || demoplayback)) + { + realtic_clock_rate = 100; + dprintf("Game Speed: %d", realtic_clock_rate); + I_SetTimeScale(realtic_clock_rate); + } } // Pop-up Main menu? diff --git a/Source/m_misc.c b/Source/m_misc.c index 4f9b3b2c..0a96f434 100644 --- a/Source/m_misc.c +++ b/Source/m_misc.c @@ -95,6 +95,7 @@ extern char *soundfont_path; extern boolean mus_chorus; extern boolean mus_reverb; #endif +extern boolean demobar; extern char *chat_macros[], *wad_files[], *deh_files[]; // killough 10/98 @@ -188,6 +189,13 @@ default_t defaults[] = { "1 for linear horizontal sky scrolling " }, + { + "demobar", + (config_t *) &demobar, NULL, + {0}, {0,1}, number, ss_gen, wad_no, + "1 to enable demo progress bar" + }, + { // killough 2/21/98 "pitched_sounds", (config_t *) &pitched_sounds, NULL, @@ -399,13 +407,6 @@ default_t defaults[] = { "1 to use Doom's main menu ordering" }, - { // killough 3/6/98 - "leds_always_off", - (config_t *) &leds_always_off, NULL, - {0}, {0,1}, number, ss_gen, wad_no, - "1 to keep keyboard LEDs turned off" - }, - { //jff 4/3/98 allow unlimited sensitivity "mouse_sensitivity_horiz", (config_t *) &mouseSensitivity_horiz, NULL, @@ -859,6 +860,38 @@ default_t defaults[] = { input_demo_quit, { {0, 0} } }, + { + "input_demo_fforward", + NULL, NULL, + {0}, {UL,UL}, input, ss_keys, wad_no, + "key for fast-forward demo", + input_demo_fforward, { {0, 0} } + }, + + { + "input_speed_up", + NULL, NULL, + {0}, {UL,UL}, input, ss_keys, wad_no, + "key to increase game speed", + input_speed_up, { {0, 0} } + }, + + { + "input_speed_down", + NULL, NULL, + {0}, {UL,UL}, input, ss_keys, wad_no, + "key to decrease game speed", + input_speed_down, { {0, 0} } + }, + + { + "input_speed_default", + NULL, NULL, + {0}, {UL,UL}, input, ss_keys, wad_no, + "key to reset game speed", + input_speed_default, { {0, 0} } + }, + { "input_strafeleft", NULL, NULL, diff --git a/Source/p_setup.c b/Source/p_setup.c index 2443969d..5cc79a93 100644 --- a/Source/p_setup.c +++ b/Source/p_setup.c @@ -1419,7 +1419,7 @@ static boolean P_LoadReject(int lumpnum, int totallines) // killough 5/3/98: reformatted, cleaned up // fast-forward demo to the next map -boolean demoskip = false; +boolean demonext = false; void P_SetupLevel(int episode, int map, int playermask, skill_t skill) { @@ -1440,11 +1440,13 @@ void P_SetupLevel(int episode, int map, int playermask, skill_t skill) players[consoleplayer].viewz = 1; // [FG] fast-forward demo to the desired map - if (demowarp == map || demoskip) + if (demowarp == map || demonext) { - I_EnableWarp(false); + if (demoskip_tics == -1) + I_EnableWarp(false); + demowarp = -1; - demoskip = false; + demonext = false; } // Make sure all sounds are stopped before Z_FreeTags. diff --git a/Source/s_sound.c b/Source/s_sound.c index 51f75398..07cac54b 100644 --- a/Source/s_sound.c +++ b/Source/s_sound.c @@ -54,8 +54,6 @@ #define S_ATTENUATOR ((S_CLIPPING_DIST-S_CLOSE_DIST)>>FRACBITS) -//jff 1/22/98 make sound enabling variables readable here -extern boolean nosfxparm, nomusicparm; //jff end sound enabling variables readable here typedef struct channel_s @@ -563,20 +561,24 @@ void S_SetSfxVolume(int volume) snd_SfxVolume = volume; } +static int current_musicnum = -1; + void S_ChangeMusic(int musicnum, int looping) { musicinfo_t *music; musinfo.current_item = -1; S_music[mus_musinfo].lumpnum = -1; + + if(musicnum <= mus_None || musicnum >= NUMMUSIC) + I_Error("Bad music number %d", musicnum); + + current_musicnum = musicnum; //jff 1/22/98 return if music is not enabled if(nomusicparm) return; - if(musicnum <= mus_None || musicnum >= NUMMUSIC) - I_Error("Bad music number %d", musicnum); - music = &S_music[musicnum]; if(mus_playing == music) @@ -668,6 +670,18 @@ void S_ChangeMusInfoMusic (int lumpnum, int looping) musinfo.current_item = lumpnum; } +void S_RestartMusic(void) +{ + if (musinfo.current_item != -1) + { + S_ChangeMusInfoMusic(musinfo.current_item, true); + } + else if (current_musicnum != -1) + { + S_ChangeMusic(current_musicnum, true); + } +} + // // Starts some music with the music id found in sounds.h. // @@ -726,10 +740,6 @@ void S_Start(void) } } - //jff 1/22/98 return if music is not enabled - if (nomusicparm) - return; - // start new music for the level mus_paused = 0; diff --git a/Source/s_sound.h b/Source/s_sound.h index cfe2feb7..9634d940 100644 --- a/Source/s_sound.h +++ b/Source/s_sound.h @@ -73,6 +73,8 @@ void S_StopMusic(void); void S_PauseSound(void); void S_ResumeSound(void); +void S_RestartMusic(void); + // // Updates music & sounds // diff --git a/Source/v_video.c b/Source/v_video.c index 59cdf42f..c79f6f59 100644 --- a/Source/v_video.c +++ b/Source/v_video.c @@ -867,6 +867,27 @@ void V_PutBlock(int x, int y, int scrn, int width, int height, byte *src) } } +void V_DrawHorizLine(int x, int y, int scrn, int width, byte color) +{ + byte *dest; + int height = 1; + + // [crispy] prevent framebuffer overflows + if (x + width > (unsigned)SCREENWIDTH) + width = SCREENWIDTH - x; + + if (hires) + y<<=2, x<<=1, width<<=1, height<<=1; + + dest = screens[scrn] + y * SCREENWIDTH + x; + + while (height--) + { + memset(dest, color, width); + dest += SCREENWIDTH << hires; + } +} + // // V_Init // diff --git a/Source/v_video.h b/Source/v_video.h index 264d36ce..cb91581b 100644 --- a/Source/v_video.h +++ b/Source/v_video.h @@ -133,6 +133,8 @@ void V_GetBlock(int x, int y, int scrn, int width, int height, byte *dest); void V_PutBlock(int x, int y, int scrn, int width, int height, byte *src); +void V_DrawHorizLine(int x, int y, int scrn, int width, byte color); + #define V_MarkRect(x,y,width,height) /* killough 11/98: unused */ // [FG] colored blood and gibs