Merge pull request 'Wipes refactor' (#77) from bigwipes into blankart-dev
Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/77
This commit is contained in:
commit
9a3a4cfc78
13 changed files with 465 additions and 418 deletions
|
|
@ -2682,6 +2682,9 @@ void CL_Reset(void)
|
|||
if (demo.recording)
|
||||
G_CheckDemoStatus();
|
||||
|
||||
// don't carry menus into the title screen (or wherever we're going)
|
||||
M_ClearMenus(true);
|
||||
|
||||
// reset client/server code
|
||||
DEBFILE(va("\n-=-=-=-=-=-=-= Client reset =-=-=-=-=-=-=-\n\n"));
|
||||
|
||||
|
|
|
|||
311
src/d_main.cpp
311
src/d_main.cpp
|
|
@ -132,6 +132,8 @@ boolean devparm = false; // started game with -devparm
|
|||
boolean singletics = false; // timedemo
|
||||
boolean lastdraw = false;
|
||||
|
||||
static INT32 lastwipetic = 0;
|
||||
|
||||
INT32 postimgparam[MAXSPLITSCREENPLAYERS];
|
||||
|
||||
// These variables are in effect
|
||||
|
|
@ -187,6 +189,8 @@ UINT8 ctrldown = 0; // 0x1 left, 0x2 right
|
|||
UINT8 altdown = 0; // 0x1 left, 0x2 right
|
||||
boolean capslock = 0; // gee i wonder what this does.
|
||||
|
||||
static boolean recursioncheck = false;
|
||||
|
||||
//
|
||||
// D_ProcessEvents
|
||||
// Send all the events of the given timestamp down the responder chain
|
||||
|
|
@ -195,7 +199,12 @@ void D_ProcessEvents(void)
|
|||
{
|
||||
event_t *ev;
|
||||
|
||||
boolean eaten;
|
||||
boolean eaten = false;
|
||||
|
||||
if (recursioncheck == true)
|
||||
I_Error("D_ProcessEvents recursion detected");
|
||||
|
||||
recursioncheck = true;
|
||||
|
||||
// i have to reset this somewhere or else your camera just glides away!
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
|
|
@ -223,15 +232,16 @@ void D_ProcessEvents(void)
|
|||
}
|
||||
|
||||
// Menu input
|
||||
#ifdef HAVE_THREADS
|
||||
I_lock_mutex(&m_menu_mutex);
|
||||
#endif
|
||||
if (WipeInAction < 2)
|
||||
{
|
||||
eaten = M_Responder(ev);
|
||||
}
|
||||
#ifdef HAVE_THREADS
|
||||
I_unlock_mutex(m_menu_mutex);
|
||||
I_lock_mutex(&m_menu_mutex);
|
||||
#endif
|
||||
eaten = M_Responder(ev);
|
||||
#ifdef HAVE_THREADS
|
||||
I_unlock_mutex(m_menu_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (eaten)
|
||||
continue; // menu ate the event
|
||||
|
|
@ -260,6 +270,8 @@ void D_ProcessEvents(void)
|
|||
|
||||
G_Responder(ev);
|
||||
}
|
||||
|
||||
recursioncheck = false;
|
||||
}
|
||||
|
||||
static void D_RenderLevel(void)
|
||||
|
|
@ -388,9 +400,8 @@ gamestate_t wipegamestate = GS_LEVEL;
|
|||
INT16 wipetypepre = -1;
|
||||
INT16 wipetypepost = -1;
|
||||
|
||||
static bool D_Display(void)
|
||||
static void D_Display(void)
|
||||
{
|
||||
bool ranwipe = false;
|
||||
boolean forcerefresh = false;
|
||||
static boolean wipe = false;
|
||||
INT32 wipedefindex = 0;
|
||||
|
|
@ -401,7 +412,7 @@ static bool D_Display(void)
|
|||
if (!dedicated)
|
||||
{
|
||||
if (nodrawers)
|
||||
return false; // for comparative timing/profiling
|
||||
return; // for comparative timing/profiling
|
||||
|
||||
// Lactozilla: Switching renderers works by checking
|
||||
// if the game has to do it right when the frame
|
||||
|
|
@ -460,21 +471,23 @@ static bool D_Display(void)
|
|||
if (wipetypepre < 0 || !F_WipeExists(wipetypepre))
|
||||
wipetypepre = wipedefs[wipedefindex];
|
||||
|
||||
if (rendermode != render_none)
|
||||
// Fade to black first
|
||||
if ((wipegamestate == FORCEWIPE ||
|
||||
!(gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction))) // fades to black on its own timing, always
|
||||
&& wipetypepre != UINT8_MAX)
|
||||
{
|
||||
// Fade to black first
|
||||
if ((wipegamestate == FORCEWIPE ||
|
||||
!(gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction))) // fades to black on its own timing, always
|
||||
&& wipetypepre != UINT8_MAX)
|
||||
if (rendermode != render_none)
|
||||
{
|
||||
F_WipeStartScreen();
|
||||
F_WipeColorFill(31);
|
||||
F_WipeEndScreen();
|
||||
F_RunWipe(wipetypepre, gamestate != GS_TIMEATTACK && gamestate != GS_TITLESCREEN);
|
||||
ranwipe = true;
|
||||
}
|
||||
F_RunWipe(wipetypepre, gamestate != GS_TIMEATTACK && gamestate != GS_TITLESCREEN);
|
||||
}
|
||||
|
||||
if (gamestate != GS_LEVEL && rendermode != render_none)
|
||||
if (rendermode != render_none)
|
||||
{
|
||||
if (gamestate != GS_LEVEL)
|
||||
{
|
||||
V_SetPaletteLump("PLAYPAL"); // Reset the palette
|
||||
R_ReInitColormaps(0, NULL, 0, false);
|
||||
|
|
@ -482,20 +495,14 @@ static bool D_Display(void)
|
|||
|
||||
F_WipeStartScreen();
|
||||
}
|
||||
else //dedicated servers
|
||||
{
|
||||
F_RunWipe(wipedefs[wipedefindex], gamestate != GS_TIMEATTACK && gamestate != GS_TITLESCREEN);
|
||||
ranwipe = true;
|
||||
else
|
||||
wipegamestate = gamestate;
|
||||
}
|
||||
|
||||
wipetypepre = -1;
|
||||
}
|
||||
else
|
||||
wipetypepre = -1;
|
||||
|
||||
wipetypepre = -1;
|
||||
|
||||
if (dedicated) //bail out after wipe logic
|
||||
return false;
|
||||
goto dedipostwipe; // WAIT! don't forget about post wipes!
|
||||
|
||||
// Catch runaway clipping rectangles.
|
||||
V_ClearClipRect();
|
||||
|
|
@ -587,6 +594,7 @@ static bool D_Display(void)
|
|||
}
|
||||
case GS_DEDICATEDSERVER:
|
||||
case GS_NULL:
|
||||
case FORCEWIPE:
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -658,6 +666,7 @@ static bool D_Display(void)
|
|||
//
|
||||
// wipe update
|
||||
//
|
||||
dedipostwipe:
|
||||
if (wipe && wipetypepost != INT16_MAX)
|
||||
{
|
||||
// note: moved up here because NetUpdate does input changes
|
||||
|
|
@ -668,12 +677,9 @@ static bool D_Display(void)
|
|||
wipetypepost = wipedefs[wipedefindex];
|
||||
|
||||
if (rendermode != render_none)
|
||||
{
|
||||
F_WipeEndScreen();
|
||||
|
||||
F_RunWipe(wipetypepost, gamestate != GS_TIMEATTACK && gamestate != GS_TITLESCREEN);
|
||||
ranwipe = true;
|
||||
}
|
||||
F_RunWipe(wipetypepost, gamestate != GS_TIMEATTACK);
|
||||
|
||||
// reset counters so timedemo doesn't count the wipe duration
|
||||
if (demo.timing)
|
||||
|
|
@ -681,11 +687,12 @@ static bool D_Display(void)
|
|||
framecount = 0;
|
||||
demostarttime = I_GetTime();
|
||||
}
|
||||
|
||||
wipetypepost = -1;
|
||||
}
|
||||
else
|
||||
wipetypepost = -1;
|
||||
|
||||
wipetypepost = -1;
|
||||
|
||||
if (dedicated)
|
||||
return; // NOW we can bail
|
||||
|
||||
NetUpdate(); // send out any new accumulation
|
||||
|
||||
|
|
@ -730,8 +737,185 @@ static bool D_Display(void)
|
|||
I_FinishUpdate(); // page flip or blit buffer
|
||||
ps_swaptime = I_GetPreciseTime() - ps_swaptime;
|
||||
}
|
||||
}
|
||||
|
||||
return ranwipe;
|
||||
static void D_WipeTick(boolean menu)
|
||||
{
|
||||
I_OsPolling();
|
||||
D_ProcessEvents();
|
||||
|
||||
// Update the network so we don't cause timeouts
|
||||
NetKeepAlive();
|
||||
|
||||
HU_Ticker();
|
||||
if (menu)
|
||||
{
|
||||
#ifdef HAVE_THREADS
|
||||
I_lock_mutex(&m_menu_mutex);
|
||||
#endif
|
||||
M_Ticker();
|
||||
#ifdef HAVE_THREADS
|
||||
I_unlock_mutex(m_menu_mutex);
|
||||
#endif
|
||||
}
|
||||
CON_Ticker();
|
||||
}
|
||||
|
||||
static void D_WipeDraw(boolean menu)
|
||||
{
|
||||
if (rendermode == render_none)
|
||||
return;
|
||||
|
||||
I_UpdateNoBlit();
|
||||
|
||||
HU_Erase();
|
||||
HU_Drawer();
|
||||
if (menu)
|
||||
{
|
||||
#ifdef HAVE_THREADS
|
||||
I_lock_mutex(&m_menu_mutex);
|
||||
#endif
|
||||
M_Drawer();
|
||||
#ifdef HAVE_THREADS
|
||||
I_unlock_mutex(m_menu_mutex);
|
||||
#endif
|
||||
}
|
||||
CON_Drawer();
|
||||
|
||||
I_FinishUpdate(); // page flip or blit buffer
|
||||
}
|
||||
|
||||
static double D_EndFrame(precise_t enterprecise, int *frameskip)
|
||||
{
|
||||
// Fully completed frame made.
|
||||
precise_t finishprecise = I_GetPreciseTime();
|
||||
|
||||
// Use the time before sleep for frameskip calculations:
|
||||
// post-sleep time is literally being intentionally wasted
|
||||
double deltasecs = (double)((INT64)(finishprecise - enterprecise)) / I_GetPrecisePrecision();
|
||||
double deltatics = deltasecs * NEWTICRATE;
|
||||
|
||||
// If time spent this game loop exceeds a single tic,
|
||||
// it's probably because of rendering.
|
||||
//
|
||||
// Skip rendering the next frame, up to a limit of 3
|
||||
// frames before a frame is rendered no matter what.
|
||||
if (frameskip)
|
||||
{
|
||||
if (*frameskip < 3 && deltatics > 1.0)
|
||||
*frameskip += 1;
|
||||
else
|
||||
*frameskip = 0;
|
||||
}
|
||||
|
||||
if (!singletics)
|
||||
{
|
||||
precise_t elapsed = finishprecise - enterprecise;
|
||||
|
||||
// capbudget is the minimum precise_t duration of a single loop iteration
|
||||
precise_t capbudget = round((1.0 / R_GetFramerateCap()) * I_GetPrecisePrecision());
|
||||
|
||||
// in the case of "match refresh rate" + vsync, don't sleep at all
|
||||
const boolean vsync_with_match_refresh = cv_vidwait.value && cv_fpscap.value == 0;
|
||||
|
||||
if (elapsed > 0 && capbudget > elapsed && !vsync_with_match_refresh)
|
||||
{
|
||||
I_SleepDuration(capbudget - (finishprecise - enterprecise));
|
||||
}
|
||||
}
|
||||
|
||||
// Capture the time once more to get the real delta time.
|
||||
finishprecise = I_GetPreciseTime();
|
||||
deltasecs = (double)((INT64)(finishprecise - enterprecise)) / I_GetPrecisePrecision();
|
||||
return deltasecs * NEWTICRATE;
|
||||
}
|
||||
|
||||
static INT32 endtimes[] = {
|
||||
UINT8_MAX, // WIPELOOP_RUNWIPE
|
||||
PRELEVELTIME*NEWTICRATERATIO, // WIPELOOP_TITLECARD
|
||||
3*TICRATE/2, // WIPELOOP_ENCORE
|
||||
NEWTICRATE, // WIPELOOP_TITLEBLACK
|
||||
};
|
||||
|
||||
static bool ranwipe = false;
|
||||
|
||||
// one single function for all the extra main loops in this god-forsaken codebase
|
||||
// should make it easier to fold these back into D_SRB2Loop at some point...
|
||||
void D_WipeLoop(wipelooptype_t type, UINT8 wipetype, boolean drawMenu)
|
||||
{
|
||||
tic_t nowtime, endtime;
|
||||
UINT8 wipeframe = 0;
|
||||
fademask_t *fmask;
|
||||
double delta = 0.0;
|
||||
|
||||
nowtime = lastwipetic = I_GetTime();
|
||||
endtime = nowtime + endtimes[type];
|
||||
|
||||
if (gamestate != GS_TITLESCREEN && gamestate != GS_TIMEATTACK)
|
||||
drawMenu = true;
|
||||
|
||||
WipeInAction = 1 + !drawMenu;
|
||||
|
||||
// lastwipetic should either be 0 or the tic we last wiped
|
||||
// on for fade-to-black
|
||||
while (nowtime < endtime)
|
||||
{
|
||||
precise_t enterprecise = I_GetPreciseTime();
|
||||
I_UpdateTime(cv_timescale.value);
|
||||
|
||||
nowtime = I_GetTime();
|
||||
|
||||
// wait loop
|
||||
if (nowtime - lastwipetic)
|
||||
{
|
||||
renderisnewtic = true;
|
||||
wipeframe++;
|
||||
D_WipeTick(drawMenu);
|
||||
if (type == WIPELOOP_TITLECARD)
|
||||
ST_runTitleCard();
|
||||
}
|
||||
else
|
||||
renderisnewtic = false;
|
||||
|
||||
// draw loop
|
||||
rendertimefrac = g_time.timefrac;
|
||||
renderdeltatics = FLOAT_TO_FIXED(delta);
|
||||
|
||||
#ifndef NOWIPE
|
||||
if (type == WIPELOOP_RUNWIPE)
|
||||
{
|
||||
// get fademask first so we can tell if it exists or not
|
||||
fmask = F_GetFadeMask(wipetype, wipeframe);
|
||||
if (!fmask)
|
||||
break;
|
||||
|
||||
#ifdef HWRENDER
|
||||
if (rendermode == render_opengl)
|
||||
HWR_DoWipe(wipetype, wipeframe); // send in the wipe type and wipeframe because we need to cache the graphic
|
||||
else
|
||||
#endif
|
||||
if (rendermode != render_none) //this allows F_RunWipe to be called in dedicated servers
|
||||
F_DoWipe(fmask);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rendermode != render_none && type == WIPELOOP_TITLECARD)
|
||||
ST_preLevelTitleCardDrawer();
|
||||
|
||||
D_WipeDraw(drawMenu);
|
||||
|
||||
// Only take screenshots after drawing.
|
||||
if (moviemode)
|
||||
M_SaveFrame();
|
||||
if (takescreenshot)
|
||||
M_DoScreenShot();
|
||||
|
||||
delta = D_EndFrame(enterprecise, NULL);
|
||||
lastwipetic = nowtime;
|
||||
}
|
||||
|
||||
ranwipe = true;
|
||||
WipeInAction = 0;
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
|
|
@ -744,7 +928,6 @@ void D_SRB2Loop(void)
|
|||
{
|
||||
tic_t entertic = 0, oldentertics = 0, realtics = 0, rendertimeout = INFTICS;
|
||||
double deltatics = 0.0;
|
||||
double deltasecs = 0.0;
|
||||
|
||||
boolean interp = false;
|
||||
boolean doDisplay = false;
|
||||
|
|
@ -797,22 +980,11 @@ void D_SRB2Loop(void)
|
|||
|
||||
for (;;)
|
||||
{
|
||||
// capbudget is the minimum precise_t duration of a single loop iteration
|
||||
precise_t capbudget;
|
||||
precise_t enterprecise = I_GetPreciseTime();
|
||||
precise_t finishprecise = enterprecise;
|
||||
|
||||
g_dc = {};
|
||||
Z_Frame_Reset();
|
||||
|
||||
{
|
||||
// Casting the return value of a function is bad practice (apparently)
|
||||
double budget = round((1.0 / R_GetFramerateCap()) * I_GetPrecisePrecision());
|
||||
capbudget = (precise_t) budget;
|
||||
}
|
||||
|
||||
bool ranwipe = false;
|
||||
|
||||
I_UpdateTime(cv_timescale.value);
|
||||
|
||||
if (lastwipetic)
|
||||
|
|
@ -926,7 +1098,7 @@ void D_SRB2Loop(void)
|
|||
{
|
||||
if (!frameskip)
|
||||
{
|
||||
ranwipe = D_Display();
|
||||
D_Display();
|
||||
}
|
||||
else if (!dedicated && frameskip)
|
||||
{
|
||||
|
|
@ -965,47 +1137,16 @@ void D_SRB2Loop(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
// Fully completed frame made.
|
||||
finishprecise = I_GetPreciseTime();
|
||||
deltatics = D_EndFrame(enterprecise, &frameskip);
|
||||
|
||||
// Use the time before sleep for frameskip calculations:
|
||||
// post-sleep time is literally being intentionally wasted
|
||||
deltasecs = (double)((INT64)(finishprecise - enterprecise)) / I_GetPrecisePrecision();
|
||||
deltatics = deltasecs * NEWTICRATE;
|
||||
|
||||
// If time spent this game loop exceeds a single tic,
|
||||
// it's probably because of rendering.
|
||||
//
|
||||
// Skip rendering the next frame, up to a limit of 3
|
||||
// frames before a frame is rendered no matter what.
|
||||
//
|
||||
// Wipes run an inner loop and artificially increase
|
||||
// the measured time.
|
||||
if (!ranwipe && frameskip < 3 && deltatics > 1.0)
|
||||
{
|
||||
frameskip++;
|
||||
}
|
||||
else
|
||||
if (ranwipe)
|
||||
{
|
||||
deltatics = 35.0 / R_GetFramerateCap();
|
||||
frameskip = 0;
|
||||
ranwipe = false;
|
||||
}
|
||||
|
||||
if (!singletics)
|
||||
{
|
||||
INT64 elapsed = (INT64)(finishprecise - enterprecise);
|
||||
|
||||
// in the case of "match refresh rate" + vsync, don't sleep at all
|
||||
const boolean vsync_with_match_refresh = cv_vidwait.value && cv_fpscap.value == 0;
|
||||
|
||||
if (elapsed > 0 && (INT64)capbudget > elapsed && !vsync_with_match_refresh)
|
||||
{
|
||||
I_SleepDuration(capbudget - (finishprecise - enterprecise));
|
||||
}
|
||||
}
|
||||
// Capture the time once more to get the real delta time.
|
||||
finishprecise = I_GetPreciseTime();
|
||||
deltasecs = (double)((INT64)(finishprecise - enterprecise)) / I_GetPrecisePrecision();
|
||||
deltatics = deltasecs * NEWTICRATE;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
10
src/d_main.h
10
src/d_main.h
|
|
@ -61,6 +61,16 @@ extern char srb2path[256]; //Alam: SRB2's Home
|
|||
// the infinite loop of D_SRB2Loop() called from win_main for windows version
|
||||
void D_SRB2Loop(void) FUNCNORETURN;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
WIPELOOP_RUNWIPE,
|
||||
WIPELOOP_TITLECARD,
|
||||
WIPELOOP_ENCORE,
|
||||
WIPELOOP_TITLEBLACK,
|
||||
} wipelooptype_t;
|
||||
|
||||
void D_WipeLoop(wipelooptype_t type, UINT8 wipetype, boolean drawMenu);
|
||||
|
||||
//
|
||||
// D_SRB2Main()
|
||||
// Not a globally visible function, just included for source reference,
|
||||
|
|
|
|||
|
|
@ -431,34 +431,7 @@ void F_IntroTicker(void)
|
|||
}
|
||||
|
||||
// Stay on black for a bit. =)
|
||||
{
|
||||
tic_t nowtime, quittime, lasttime;
|
||||
nowtime = lasttime = I_GetTime();
|
||||
quittime = nowtime + NEWTICRATE; // Shortened the quit time, used to be 2 seconds
|
||||
while (quittime > nowtime)
|
||||
{
|
||||
while (!((nowtime = I_GetTime()) - lasttime))
|
||||
{
|
||||
I_Sleep(cv_sleep.value);
|
||||
I_UpdateTime(cv_timescale.value);
|
||||
}
|
||||
lasttime = nowtime;
|
||||
|
||||
I_OsPolling();
|
||||
I_UpdateNoBlit();
|
||||
#ifdef HAVE_THREADS
|
||||
I_lock_mutex(&m_menu_mutex);
|
||||
#endif
|
||||
M_Drawer(); // menu is drawn even on top of wipes
|
||||
#ifdef HAVE_THREADS
|
||||
I_unlock_mutex(m_menu_mutex);
|
||||
#endif
|
||||
I_FinishUpdate(); // Update the screen with the image Tails 06-19-2001
|
||||
|
||||
if (moviemode) // make sure we save frames for the white hold too
|
||||
M_SaveFrame();
|
||||
}
|
||||
}
|
||||
D_WipeLoop(WIPELOOP_TITLEBLACK, 0, false);
|
||||
|
||||
D_StartTitle();
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -26,9 +26,6 @@ extern "C" {
|
|||
//
|
||||
// FINALE
|
||||
//
|
||||
// HACK for menu fading while titlemapinaction; skips the level check
|
||||
#define FORCEWIPE -2
|
||||
|
||||
|
||||
// Called by main loop.
|
||||
boolean F_IntroResponder(event_t *ev);
|
||||
|
|
@ -142,15 +139,15 @@ void F_MenuPresTicker(boolean run);
|
|||
// WIPE
|
||||
//
|
||||
|
||||
extern boolean WipeInAction;
|
||||
extern UINT8 WipeInAction;
|
||||
extern boolean WipeStageTitle;
|
||||
|
||||
extern INT32 lastwipetic;
|
||||
|
||||
// Don't know where else to place this constant
|
||||
// But this file seems appropriate
|
||||
#define PRELEVELTIME TICRATE // frames in tics
|
||||
|
||||
fademask_t *F_GetFadeMask(UINT8 masknum, UINT8 scrnnum);
|
||||
void F_DoWipe(fademask_t *fademask);
|
||||
void F_WipeStartScreen(void);
|
||||
void F_WipeEndScreen(void);
|
||||
void F_RunWipe(UINT8 wipetype, boolean drawMenu);
|
||||
|
|
|
|||
64
src/f_wipe.c
64
src/f_wipe.c
|
|
@ -43,12 +43,12 @@
|
|||
#define NOWIPE // do not enable wipe image post processing for ARM, SH and MIPS CPUs
|
||||
#endif
|
||||
|
||||
typedef struct fademask_s {
|
||||
struct fademask_t {
|
||||
UINT8* mask;
|
||||
UINT16 width, height;
|
||||
size_t size;
|
||||
fixed_t xscale, yscale;
|
||||
} fademask_t;
|
||||
};
|
||||
|
||||
UINT8 wipedefs[NUMWIPEDEFS] = {
|
||||
99, // wipe_credits_intermediate (0)
|
||||
|
|
@ -83,9 +83,8 @@ UINT8 wipedefs[NUMWIPEDEFS] = {
|
|||
// SCREEN WIPE PACKAGE
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
boolean WipeInAction = false;
|
||||
UINT8 WipeInAction = 0;
|
||||
boolean WipeStageTitle = false;
|
||||
INT32 lastwipetic = 0;
|
||||
|
||||
#ifndef NOWIPE
|
||||
|
||||
|
|
@ -101,7 +100,7 @@ static fixed_t paldiv;
|
|||
* \param lump Lump name to get data from
|
||||
* \return fademask_t for lump
|
||||
*/
|
||||
static fademask_t *F_GetFadeMask(UINT8 masknum, UINT8 scrnnum) {
|
||||
fademask_t *F_GetFadeMask(UINT8 masknum, UINT8 scrnnum) {
|
||||
static char lumpname[9] = "FADEmmss";
|
||||
static fademask_t fm = {NULL,0,0,0,0,0};
|
||||
lumpnum_t lumpnum;
|
||||
|
|
@ -186,7 +185,7 @@ static fademask_t *F_GetFadeMask(UINT8 masknum, UINT8 scrnnum) {
|
|||
*
|
||||
* \param fademask pixels to change
|
||||
*/
|
||||
static void F_DoWipe(fademask_t *fademask)
|
||||
void F_DoWipe(fademask_t *fademask)
|
||||
{
|
||||
// Software mask wipe -- optimized; though it might not look like it!
|
||||
// Okay, to save you wondering *how* this is more optimized than the simpler
|
||||
|
|
@ -360,63 +359,12 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu)
|
|||
(void)wipetype;
|
||||
(void)drawMenu;
|
||||
#else
|
||||
tic_t nowtime;
|
||||
UINT8 wipeframe = 0;
|
||||
fademask_t *fmask;
|
||||
|
||||
paldiv = FixedDiv(257<<FRACBITS, 11<<FRACBITS);
|
||||
|
||||
// Init the wipe
|
||||
WipeInAction = true;
|
||||
wipe_scr = screens[0];
|
||||
|
||||
// lastwipetic should either be 0 or the tic we last wiped
|
||||
// on for fade-to-black
|
||||
for (;;)
|
||||
{
|
||||
// get fademask first so we can tell if it exists or not
|
||||
fmask = F_GetFadeMask(wipetype, wipeframe++);
|
||||
if (!fmask)
|
||||
break;
|
||||
|
||||
// wait loop
|
||||
while (!((nowtime = I_GetTime()) - lastwipetic))
|
||||
{
|
||||
I_Sleep(cv_sleep.value);
|
||||
I_UpdateTime(cv_timescale.value);
|
||||
}
|
||||
lastwipetic = nowtime;
|
||||
|
||||
#ifdef HWRENDER
|
||||
if (rendermode == render_opengl)
|
||||
HWR_DoWipe(wipetype, wipeframe-1); // send in the wipe type and wipeframe because we need to cache the graphic
|
||||
else
|
||||
#endif
|
||||
if (rendermode != render_none) //this allows F_RunWipe to be called in dedicated servers
|
||||
F_DoWipe(fmask);
|
||||
|
||||
I_OsPolling();
|
||||
I_UpdateNoBlit();
|
||||
|
||||
if (drawMenu && rendermode != render_none)
|
||||
{
|
||||
#ifdef HAVE_THREADS
|
||||
I_lock_mutex(&m_menu_mutex);
|
||||
#endif
|
||||
M_Drawer(); // menu is drawn even on top of wipes
|
||||
#ifdef HAVE_THREADS
|
||||
I_unlock_mutex(m_menu_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
I_FinishUpdate(); // page flip or blit buffer
|
||||
|
||||
if (moviemode)
|
||||
M_SaveFrame();
|
||||
|
||||
NetKeepAlive(); // Update the network so we don't cause timeouts
|
||||
}
|
||||
WipeInAction = false;
|
||||
D_WipeLoop(WIPELOOP_RUNWIPE, wipetype, drawMenu);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
273
src/g_demo.c
273
src/g_demo.c
|
|
@ -276,6 +276,7 @@ typedef struct
|
|||
UINT8 numplayers;
|
||||
demoplayer_t *playerdata;
|
||||
|
||||
boolean empty;
|
||||
UINT32 endofs;
|
||||
} demoheader_t;
|
||||
|
||||
|
|
@ -669,6 +670,7 @@ static headerstatus_e G_ReadDemoHeader(UINT8 *dp, demoheader_t *header)
|
|||
header->mapmusrng = 0;
|
||||
header->numlaps = 0;
|
||||
header->raflags = 0;
|
||||
header->empty = false;
|
||||
|
||||
if (memcmp(dp, DEMOHEADER, 12))
|
||||
return HEADER_BADMAGIC;
|
||||
|
|
@ -687,7 +689,6 @@ static headerstatus_e G_ReadDemoHeader(UINT8 *dp, demoheader_t *header)
|
|||
raflag = false;
|
||||
break;
|
||||
|
||||
|
||||
case 0x0001: // SRB2Kart 1.0.x (only staff ghosts supported)
|
||||
oldkart = kart = true;
|
||||
raflag = false;
|
||||
|
|
@ -847,10 +848,16 @@ skipfiles:
|
|||
if (!kart)
|
||||
header->mapmusrng = READUINT8(dp);
|
||||
|
||||
// Sigh ... it's an empty demo.
|
||||
if (*dp == DEMOMARKER || oldkart)
|
||||
if (oldkart)
|
||||
goto end;
|
||||
|
||||
// Sigh ... it's an empty demo.
|
||||
if (*dp == DEMOMARKER)
|
||||
{
|
||||
header->empty = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Load players that were in-game when the map started
|
||||
UINT8 playernum;
|
||||
header->playerdata = NULL;
|
||||
|
|
@ -901,6 +908,10 @@ skipfiles:
|
|||
plr->followitem = !kart ? READUINT32(dp) : MT_NULL;
|
||||
}
|
||||
|
||||
// Sigh ... it's an empty demo. Again.
|
||||
if (*dp == DEMOMARKER)
|
||||
header->empty = true;
|
||||
|
||||
end:
|
||||
header->endofs = dp - startdp;
|
||||
return HEADER_OK;
|
||||
|
|
@ -3390,15 +3401,15 @@ void G_DoPlayDemo(char *defdemoname)
|
|||
lumpnum_t l;
|
||||
char *n,*pdemoname;
|
||||
char msg[1024];
|
||||
|
||||
boolean spectator, bot;
|
||||
UINT8 slots[MAXPLAYERS], kartspeed[MAXPLAYERS], kartweight[MAXPLAYERS], numslots = 0;
|
||||
UINT8 pnum;
|
||||
|
||||
#if defined(SKIPERRORS) && !defined(DEVELOP)
|
||||
boolean skiperrors = false;
|
||||
#endif
|
||||
|
||||
M_ClearMenus(true);
|
||||
G_InitDemoRewind();
|
||||
gameaction = ga_nothing;
|
||||
|
||||
// No demo name means we're restarting the current demo
|
||||
if (defdemoname == NULL)
|
||||
|
|
@ -3425,10 +3436,7 @@ void G_DoPlayDemo(char *defdemoname)
|
|||
if (P_SaveBufferFromFile(&demobuf, defdemoname) == false)
|
||||
{
|
||||
snprintf(msg, 1024, M_GetText("Failed to read file '%s'.\n"), defdemoname);
|
||||
CONS_Alert(CONS_ERROR, "%s", msg);
|
||||
gameaction = ga_nothing;
|
||||
M_StartMessage(msg, NULL, MM_NOTHING);
|
||||
return;
|
||||
goto lumperror;
|
||||
}
|
||||
}
|
||||
// load demo resource from WAD
|
||||
|
|
@ -3440,11 +3448,7 @@ void G_DoPlayDemo(char *defdemoname)
|
|||
if ((l = W_CheckNumForName(defdemoname)) == LUMPERROR)
|
||||
{
|
||||
snprintf(msg, 1024, M_GetText("Failed to read lump '%s'.\n"), defdemoname);
|
||||
CONS_Alert(CONS_ERROR, "%s", msg);
|
||||
Z_Free(pdemoname);
|
||||
gameaction = ga_nothing;
|
||||
M_StartMessage(msg, NULL, MM_NOTHING);
|
||||
return;
|
||||
goto lumperror;
|
||||
}
|
||||
|
||||
P_SaveBufferFromLump(&demobuf, l);
|
||||
|
|
@ -3470,11 +3474,7 @@ void G_DoPlayDemo(char *defdemoname)
|
|||
if (mapnum >= nummapheaders || mapheaderinfo[mapnum]->lumpnum == LUMPERROR)
|
||||
{
|
||||
snprintf(msg, 1024, M_GetText("Failed to read lump '%s (couldn't find map %s)'.\n"), defdemoname, mapname);
|
||||
CONS_Alert(CONS_ERROR, "%s", msg);
|
||||
Z_Free(pdemoname);
|
||||
gameaction = ga_nothing;
|
||||
M_StartMessage(msg, NULL, MM_NOTHING);
|
||||
return;
|
||||
goto lumperror;
|
||||
}
|
||||
|
||||
vRes = vres_GetMap(mapheaderinfo[mapnum]->lumpnum);
|
||||
|
|
@ -3483,11 +3483,7 @@ void G_DoPlayDemo(char *defdemoname)
|
|||
if (vLump == NULL)
|
||||
{
|
||||
snprintf(msg, 1024, M_GetText("Failed to read lump '%s (couldn't find lump %s in %s)'.\n"), defdemoname, pdemoname, mapname);
|
||||
CONS_Alert(CONS_ERROR, "%s", msg);
|
||||
Z_Free(pdemoname);
|
||||
gameaction = ga_nothing;
|
||||
M_StartMessage(msg, NULL, MM_NOTHING);
|
||||
return;
|
||||
goto lumperror;
|
||||
}
|
||||
|
||||
P_SaveBufferAlloc(&demobuf, vLump->size);
|
||||
|
|
@ -3502,7 +3498,6 @@ void G_DoPlayDemo(char *defdemoname)
|
|||
}
|
||||
|
||||
// read demo header
|
||||
gameaction = ga_nothing;
|
||||
demo.playback = true;
|
||||
demo.buffer = &demobuf;
|
||||
|
||||
|
|
@ -3516,33 +3511,15 @@ void G_DoPlayDemo(char *defdemoname)
|
|||
|
||||
case HEADER_BADMAGIC:
|
||||
snprintf(msg, 1024, M_GetText("%s is not a SRB2Kart replay file.\n"), pdemoname);
|
||||
CONS_Alert(CONS_ERROR, "%s", msg);
|
||||
Z_Free(pdemoname);
|
||||
P_SaveBufferFree(&demobuf);
|
||||
demo.playback = false;
|
||||
demo.title = false;
|
||||
M_StartMessage(msg, NULL, MM_NOTHING);
|
||||
return;
|
||||
goto headererror;
|
||||
|
||||
case HEADER_BADVERSION:
|
||||
snprintf(msg, 1024, M_GetText("%s is an incompatible replay format and cannot be played.\n"), pdemoname);
|
||||
CONS_Alert(CONS_ERROR, "%s", msg);
|
||||
Z_Free(pdemoname);
|
||||
P_SaveBufferFree(&demobuf);
|
||||
demo.playback = false;
|
||||
demo.title = false;
|
||||
M_StartMessage(msg, NULL, MM_NOTHING);
|
||||
return;
|
||||
goto headererror;
|
||||
|
||||
case HEADER_BADFORMAT:
|
||||
snprintf(msg, 1024, M_GetText("%s is the wrong type of recording and cannot be played.\n"), pdemoname);
|
||||
CONS_Alert(CONS_ERROR, "%s", msg);
|
||||
Z_Free(pdemoname);
|
||||
P_SaveBufferFree(&demobuf);
|
||||
demo.playback = false;
|
||||
demo.title = false;
|
||||
M_StartMessage(msg, NULL, MM_NOTHING);
|
||||
return;
|
||||
goto headererror;
|
||||
}
|
||||
|
||||
demo.version = header.demoversion;
|
||||
|
|
@ -3564,54 +3541,68 @@ void G_DoPlayDemo(char *defdemoname)
|
|||
G_LoadDemoExtraFiles(&header);
|
||||
else if (demo.ignorefiles)
|
||||
;//G_SkipDemoExtraFiles(&demobuf.p);
|
||||
else
|
||||
else switch (G_CheckDemoExtraFiles(&header, false))
|
||||
{
|
||||
UINT8 error = G_CheckDemoExtraFiles(&header, false);
|
||||
case DFILE_ERROR_NOTLOADED:
|
||||
snprintf(msg, 1024,
|
||||
M_GetText("Required files for this demo are not loaded.\n\nUse\n\"playdemo %s -addfiles\"\nto load them and play the demo.\n"),
|
||||
pdemoname);
|
||||
goto error;
|
||||
|
||||
if (error)
|
||||
case DFILE_ERROR_OUTOFORDER:
|
||||
snprintf(msg, 1024,
|
||||
M_GetText("Required files for this demo are loaded out of order.\n\nUse\n\"playdemo %s -force\"\nto play the demo anyway.\n"),
|
||||
pdemoname);
|
||||
goto error;
|
||||
|
||||
case DFILE_ERROR_INCOMPLETEOUTOFORDER:
|
||||
snprintf(msg, 1024,
|
||||
M_GetText("Required files for this demo are not loaded, and some are out of order.\n\nUse\n\"playdemo %s -addfiles\"\nto load needed files and play the demo.\n"),
|
||||
pdemoname);
|
||||
goto error;
|
||||
|
||||
case DFILE_ERROR_CANNOTLOAD:
|
||||
snprintf(msg, 1024,
|
||||
M_GetText("Required files for this demo cannot be loaded.\n\nUse\n\"playdemo %s -force\"\nto play the demo anyway.\n"),
|
||||
pdemoname);
|
||||
goto error;
|
||||
|
||||
case DFILE_ERROR_EXTRAFILES:
|
||||
snprintf(msg, 1024,
|
||||
M_GetText("You have additional files loaded beyond the demo's file list.\n\nUse\n\"playdemo %s -force\"\nto play the demo anyway.\n"),
|
||||
pdemoname);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// ...*map* not loaded?
|
||||
if (!gamemap || (gamemap > nummapheaders) || !mapheaderinfo[gamemap-1] || mapheaderinfo[gamemap-1]->lumpnum == LUMPERROR)
|
||||
{
|
||||
snprintf(msg, 1024, M_GetText("%s features a course that is not currently loaded.\n"), pdemoname);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Sigh ... it's an empty demo.
|
||||
if (header.empty)
|
||||
{
|
||||
snprintf(msg, 1024, M_GetText("%s contains no data to be played.\n"), pdemoname);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// extra checks for RA replays
|
||||
if (demoflags & DF_ATTACKMASK)
|
||||
{
|
||||
const char *reason = NULL;
|
||||
if (header.numplayers != 1)
|
||||
reason = "multiple players";
|
||||
else if (header.playerdata[0].flags & DEMO_SPECTATOR)
|
||||
reason = "spectators";
|
||||
else if (header.playerdata[0].flags & DEMO_BOT)
|
||||
reason = "bots";
|
||||
|
||||
if (reason)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case DFILE_ERROR_NOTLOADED:
|
||||
snprintf(msg, 1024,
|
||||
M_GetText("Required files for this demo are not loaded.\n\nUse\n\"playdemo %s -addfiles\"\nto load them and play the demo.\n"),
|
||||
pdemoname);
|
||||
break;
|
||||
|
||||
case DFILE_ERROR_OUTOFORDER:
|
||||
snprintf(msg, 1024,
|
||||
M_GetText("Required files for this demo are loaded out of order.\n\nUse\n\"playdemo %s -force\"\nto play the demo anyway.\n"),
|
||||
pdemoname);
|
||||
break;
|
||||
|
||||
case DFILE_ERROR_INCOMPLETEOUTOFORDER:
|
||||
snprintf(msg, 1024,
|
||||
M_GetText("Required files for this demo are not loaded, and some are out of order.\n\nUse\n\"playdemo %s -addfiles\"\nto load needed files and play the demo.\n"),
|
||||
pdemoname);
|
||||
break;
|
||||
|
||||
case DFILE_ERROR_CANNOTLOAD:
|
||||
snprintf(msg, 1024,
|
||||
M_GetText("Required files for this demo cannot be loaded.\n\nUse\n\"playdemo %s -force\"\nto play the demo anyway.\n"),
|
||||
pdemoname);
|
||||
break;
|
||||
|
||||
case DFILE_ERROR_EXTRAFILES:
|
||||
snprintf(msg, 1024,
|
||||
M_GetText("You have additional files loaded beyond the demo's file list.\n\nUse\n\"playdemo %s -force\"\nto play the demo anyway.\n"),
|
||||
pdemoname);
|
||||
break;
|
||||
}
|
||||
|
||||
CONS_Alert(CONS_ERROR, "%s", msg);
|
||||
Z_Free(pdemoname);
|
||||
P_SaveBufferFree(&demobuf);
|
||||
G_FreeDemoHeader(&header);
|
||||
demo.playback = false;
|
||||
demo.title = false;
|
||||
if (!CON_Ready()) // In the console they'll just see the notice there! No point pulling them out.
|
||||
M_StartMessage(msg, NULL, MM_NOTHING);
|
||||
return;
|
||||
snprintf(msg, 1024, M_GetText("%s is a Record Attack replay with %s, and is thus invalid.\n"), pdemoname, reason);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3627,20 +3618,6 @@ void G_DoPlayDemo(char *defdemoname)
|
|||
if (modeattacking != ATTACKING_TIME && modeattacking != ATTACKING_ITEMBREAK)
|
||||
modeattacking = ATTACKING_NONE; // is this really necessary?
|
||||
|
||||
// ...*map* not loaded?
|
||||
if (!gamemap || (gamemap > nummapheaders) || !mapheaderinfo[gamemap-1] || mapheaderinfo[gamemap-1]->lumpnum == LUMPERROR)
|
||||
{
|
||||
snprintf(msg, 1024, M_GetText("%s features a course that is not currently loaded.\n"), pdemoname);
|
||||
CONS_Alert(CONS_ERROR, "%s", msg);
|
||||
Z_Free(pdemoname);
|
||||
P_SaveBufferFree(&demobuf);
|
||||
G_FreeDemoHeader(&header);
|
||||
demo.playback = false;
|
||||
demo.title = false;
|
||||
M_StartMessage(msg, NULL, MM_NOTHING);
|
||||
return;
|
||||
}
|
||||
|
||||
// net var data
|
||||
CV_LoadDemoVars(&header);
|
||||
|
||||
|
|
@ -3656,20 +3633,6 @@ void G_DoPlayDemo(char *defdemoname)
|
|||
// Load "mapmusrng" used for altmusic selection
|
||||
mapmusrng = header.mapmusrng;
|
||||
|
||||
// Sigh ... it's an empty demo.
|
||||
if (header.numplayers == 0)
|
||||
{
|
||||
snprintf(msg, 1024, M_GetText("%s contains no data to be played.\n"), pdemoname);
|
||||
CONS_Alert(CONS_ERROR, "%s", msg);
|
||||
Z_Free(pdemoname);
|
||||
P_SaveBufferFree(&demobuf);
|
||||
G_FreeDemoHeader(&header);
|
||||
demo.playback = false;
|
||||
demo.title = false;
|
||||
M_StartMessage(msg, NULL, MM_NOTHING);
|
||||
return;
|
||||
}
|
||||
|
||||
Z_Free(pdemoname);
|
||||
|
||||
memset(&oldcmd,0,sizeof(oldcmd));
|
||||
|
|
@ -3699,48 +3662,16 @@ void G_DoPlayDemo(char *defdemoname)
|
|||
memset(camera,0,sizeof(camera)); // reset freecam
|
||||
|
||||
// Load players that were in-game when the map started
|
||||
for (UINT8 pnum = 0; pnum < header.numplayers; pnum++)
|
||||
for (pnum = 0; pnum < header.numplayers; pnum++)
|
||||
{
|
||||
demoplayer_t *plr = &header.playerdata[pnum];
|
||||
UINT8 p = plr->playernum;
|
||||
spectator = !!(plr->flags & DEMO_SPECTATOR);
|
||||
bot = !!(plr->flags & DEMO_BOT);
|
||||
|
||||
if ((spectator || bot))
|
||||
{
|
||||
if (modeattacking)
|
||||
{
|
||||
snprintf(msg, 1024, M_GetText("%s is a Record Attack replay with %s, and is thus invalid.\n"), pdemoname, (bot ? "bots" : "spectators"));
|
||||
CONS_Alert(CONS_ERROR, "%s", msg);
|
||||
Z_Free(pdemoname);
|
||||
P_SaveBufferFree(&demobuf);
|
||||
demo.playback = false;
|
||||
demo.title = false;
|
||||
M_StartMessage(msg, NULL, MM_NOTHING);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
slots[numslots] = p;
|
||||
numslots++;
|
||||
|
||||
if (modeattacking && numslots > 1)
|
||||
{
|
||||
snprintf(msg, 1024, M_GetText("%s is a Record Attack replay with multiple players, and is thus invalid.\n"), pdemoname);
|
||||
CONS_Alert(CONS_ERROR, "%s", msg);
|
||||
Z_Free(pdemoname);
|
||||
P_SaveBufferFree(&demobuf);
|
||||
demo.playback = false;
|
||||
demo.title = false;
|
||||
M_StartMessage(msg, NULL, MM_NOTHING);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!playeringame[displayplayers[0]] || players[displayplayers[0]].spectator)
|
||||
displayplayers[0] = consoleplayer = serverplayer = p;
|
||||
|
||||
G_AddPlayer(p, p);
|
||||
players[p].spectator = spectator;
|
||||
players[p].spectator = !!(plr->flags & DEMO_SPECTATOR);
|
||||
|
||||
if (plr->flags & DEMO_KICKSTART)
|
||||
players[p].pflags |= PF_KICKSTARTACCEL;
|
||||
|
|
@ -3754,7 +3685,7 @@ void G_DoPlayDemo(char *defdemoname)
|
|||
|
||||
K_UpdateShrinkCheat(&players[p]);
|
||||
|
||||
if ((players[p].bot = bot) == true)
|
||||
if ((players[p].bot = !!(plr->flags & DEMO_BOT)) == true)
|
||||
{
|
||||
players[p].botvars.difficulty = plr->bot.difficulty;
|
||||
players[p].botvars.diffincrease = plr->bot.diffincrease; // needed to avoid having to duplicate logic
|
||||
|
|
@ -3797,12 +3728,10 @@ void G_DoPlayDemo(char *defdemoname)
|
|||
// Power Levels
|
||||
clientpowerlevels[p][gametype == GT_BATTLE ? PWRLV_BATTLE : PWRLV_RACE] = plr->powerlevel;
|
||||
|
||||
// Kart stats, temporarily
|
||||
kartspeed[p] = plr->kartspeed;
|
||||
kartweight[p] = plr->kartweight;
|
||||
// Kart stats (set later)
|
||||
|
||||
if (stricmp(skins[players[p].skin].name, plr->skin) != 0)
|
||||
FindClosestSkinForStats(p, kartspeed[p], kartweight[p]);
|
||||
FindClosestSkinForStats(p, plr->kartspeed, plr->kartweight);
|
||||
|
||||
// Followitem
|
||||
players[p].followitem = plr->followitem;
|
||||
|
|
@ -3824,10 +3753,10 @@ void G_DoPlayDemo(char *defdemoname)
|
|||
if (demo.title)
|
||||
{
|
||||
splitscreen = M_RandomKey(6)-1;
|
||||
splitscreen = min(min(3, numslots-1), splitscreen); // Bias toward 1p and 4p views
|
||||
splitscreen = min(min(3, header.numplayers-1), splitscreen); // Bias toward 1p and 4p views
|
||||
|
||||
for (i = 0; i <= splitscreen; i++)
|
||||
G_ResetView(i+1, slots[M_RandomKey(numslots)], false);
|
||||
G_ResetView(i+1, header.playerdata[M_RandomKey(header.numplayers)].playernum, false);
|
||||
}
|
||||
|
||||
R_ExecuteSetViewSize();
|
||||
|
|
@ -3835,19 +3764,33 @@ void G_DoPlayDemo(char *defdemoname)
|
|||
P_SetRandSeed(header.randseed);
|
||||
G_InitNew(demoflags & DF_ENCORE, gamemap, true, true, false); // Doesn't matter whether you reset or not here, given changes to resetplayer.
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
for (pnum = 0; pnum < header.numplayers; pnum++)
|
||||
{
|
||||
// oldghost init doesn't work here, players aren't immediately spawned anymore
|
||||
|
||||
// Set saved attribute values
|
||||
// No cheat checking here, because even if they ARE wrong...
|
||||
// it would only break the replay if we clipped them.
|
||||
players[i].kartspeed = kartspeed[i];
|
||||
players[i].kartweight = kartweight[i];
|
||||
demoplayer_t *plr = &header.playerdata[pnum];
|
||||
players[plr->playernum].kartspeed = plr->kartspeed;
|
||||
players[plr->playernum].kartweight = plr->kartweight;
|
||||
}
|
||||
|
||||
demo.deferstart = true;
|
||||
G_FreeDemoHeader(&header);
|
||||
return;
|
||||
|
||||
error:
|
||||
G_FreeDemoHeader(&header);
|
||||
headererror:
|
||||
P_SaveBufferFree(&demobuf);
|
||||
lumperror:
|
||||
CONS_Alert(CONS_ERROR, "%s", msg);
|
||||
Z_Free(pdemoname);
|
||||
demo.playback = false;
|
||||
demo.title = false;
|
||||
if (!CON_Ready()) // In the console they'll just see the notice there! No point pulling them out.
|
||||
M_StartMessage(msg, NULL, MM_NOTHING);
|
||||
}
|
||||
|
||||
void G_SetupDemoPlayer(INT32 i)
|
||||
|
|
@ -3956,7 +3899,7 @@ void G_AddGhost(char *defdemoname)
|
|||
return;
|
||||
}
|
||||
|
||||
if (header.numplayers == 0)
|
||||
if (header.empty)
|
||||
{
|
||||
CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Replay is empty.\n"), pdemoname);
|
||||
Z_Free(pdemoname);
|
||||
|
|
|
|||
26
src/g_game.c
26
src/g_game.c
|
|
@ -1507,30 +1507,7 @@ void G_StartTitleCard(void)
|
|||
void G_PreLevelTitleCard(void)
|
||||
{
|
||||
#ifndef NOWIPE
|
||||
tic_t strtime = I_GetTime();
|
||||
tic_t endtime = strtime + (PRELEVELTIME*NEWTICRATERATIO);
|
||||
tic_t nowtime = strtime;
|
||||
tic_t lasttime = strtime;
|
||||
while (nowtime < endtime)
|
||||
{
|
||||
// draw loop
|
||||
ST_runTitleCard();
|
||||
ST_preLevelTitleCardDrawer();
|
||||
I_FinishUpdate(); // page flip or blit buffer
|
||||
NetKeepAlive(); // Prevent timeouts
|
||||
|
||||
if (moviemode)
|
||||
M_SaveFrame();
|
||||
if (takescreenshot) // Only take screenshots after drawing.
|
||||
M_DoScreenShot();
|
||||
|
||||
while (!((nowtime = I_GetTime()) - lasttime))
|
||||
{
|
||||
I_Sleep(cv_sleep.value);
|
||||
I_UpdateTime(cv_timescale.value);
|
||||
}
|
||||
lasttime = nowtime;
|
||||
}
|
||||
D_WipeLoop(WIPELOOP_TITLECARD, 0, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -2300,6 +2277,7 @@ void G_Ticker(boolean run)
|
|||
|
||||
case GS_DEDICATEDSERVER:
|
||||
case GS_NULL:
|
||||
case FORCEWIPE:
|
||||
break; // do nothing
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ extern "C" {
|
|||
// the current state of the game
|
||||
typedef enum
|
||||
{
|
||||
FORCEWIPE = -2, // HACK for menu fading while titlemapinaction; skips the level check
|
||||
GS_NULL = 0, // At beginning.
|
||||
|
||||
// Fadable gamestates
|
||||
|
|
|
|||
|
|
@ -1083,6 +1083,9 @@ void HU_Ticker(void)
|
|||
}
|
||||
}
|
||||
|
||||
if (WipeInAction)
|
||||
return;
|
||||
|
||||
if (cechotimer)
|
||||
cechotimer--;
|
||||
|
||||
|
|
@ -2136,6 +2139,9 @@ void HU_Drawer(void)
|
|||
HU_drawMiniChat(); // draw messages in a cool fashion.
|
||||
}
|
||||
|
||||
if (WipeInAction)
|
||||
return;
|
||||
|
||||
if (cechotimer)
|
||||
HU_DrawCEcho();
|
||||
|
||||
|
|
|
|||
111
src/m_menu.c
111
src/m_menu.c
|
|
@ -1187,7 +1187,7 @@ static boolean M_ChangeStringCvar(INT32 choice)
|
|||
|
||||
// lock out further input in a tic when important buttons are pressed
|
||||
// (in other words -- stop bullshit happening by mashing buttons in fades)
|
||||
static boolean noFurtherInput = false;
|
||||
static INT32 noFurtherInput = 0;
|
||||
|
||||
static void Command_Manual_f(void)
|
||||
{
|
||||
|
|
@ -1256,6 +1256,30 @@ static boolean M_DemoBinds(INT32 ch)
|
|||
return true;
|
||||
}
|
||||
|
||||
// if the menu is being used during a wipe, running routines can be dangerous!
|
||||
// buffer a single input, then wait for the wipe to end
|
||||
static boolean M_WipeBuffer(INT32 ch, menufunc_f *routine)
|
||||
{
|
||||
if (!WipeInAction)
|
||||
return false;
|
||||
|
||||
// these routines are allowed to run during wipes
|
||||
// solely to make the menus less annoying to use
|
||||
if (routine == NULL
|
||||
|| (routine == MR_SelectableClearMenus && !currentMenu->quitroutine)
|
||||
|| routine == MR_Options
|
||||
|| routine == MR_SetupMultiPlayer
|
||||
)
|
||||
return false;
|
||||
|
||||
noFurtherInput = ch;
|
||||
S_StartSound(NULL, sfx_kc50);
|
||||
return true;
|
||||
}
|
||||
|
||||
// use this when routine being NULL isn't a free pass
|
||||
static INT32 MR_Dummy(INT32 ch) { return true; }
|
||||
|
||||
//
|
||||
// M_Responder
|
||||
//
|
||||
|
|
@ -1435,10 +1459,12 @@ boolean M_Responder(event_t *ev)
|
|||
{
|
||||
if (ch == ' ' || ch == 'n' || ch == 'y' || ch == KEY_ESCAPE || ch == KEY_ENTER)
|
||||
{
|
||||
if (M_WipeBuffer(ch, MR_Dummy))
|
||||
return true;
|
||||
if (messagebox.routine)
|
||||
messagebox.routine(ch);
|
||||
messagebox.active = false;
|
||||
noFurtherInput = true;
|
||||
noFurtherInput = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -1453,7 +1479,7 @@ boolean M_Responder(event_t *ev)
|
|||
// F-Keys
|
||||
if (!menustack[0])
|
||||
{
|
||||
noFurtherInput = true;
|
||||
noFurtherInput = -1;
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
|
|
@ -1469,7 +1495,7 @@ boolean M_Responder(event_t *ev)
|
|||
return true;
|
||||
|
||||
case KEY_F4: // Sound Volume
|
||||
if (modeattacking)
|
||||
if (modeattacking || WipeInAction)
|
||||
return true;
|
||||
M_StartControlPanel();
|
||||
M_EnterMenu(MN_OP_MAIN, true, 0);
|
||||
|
|
@ -1478,7 +1504,7 @@ boolean M_Responder(event_t *ev)
|
|||
return true;
|
||||
|
||||
case KEY_F5: // Video Mode
|
||||
if (modeattacking)
|
||||
if (modeattacking || WipeInAction)
|
||||
return true;
|
||||
M_StartControlPanel();
|
||||
M_EnterMenu(MN_OP_MAIN, true, 0);
|
||||
|
|
@ -1490,7 +1516,7 @@ boolean M_Responder(event_t *ev)
|
|||
return true;
|
||||
|
||||
case KEY_F7: // Options
|
||||
if (modeattacking)
|
||||
if (modeattacking || WipeInAction)
|
||||
return true;
|
||||
M_StartControlPanel();
|
||||
M_EnterMenu(MN_OP_MAIN, true, 0);
|
||||
|
|
@ -1519,13 +1545,15 @@ boolean M_Responder(event_t *ev)
|
|||
M_StartControlPanel();
|
||||
return true;
|
||||
}
|
||||
noFurtherInput = false; // turns out we didn't care
|
||||
noFurtherInput = 0; // turns out we didn't care
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle menuitems which need a specific key handling
|
||||
if (currentMenu->keyhandler)
|
||||
{
|
||||
if (M_WipeBuffer(ch, currentMenu->keyhandler))
|
||||
return true;
|
||||
if (shiftdown && ch >= 32 && ch <= 127)
|
||||
ch = shiftxform[ch];
|
||||
if (currentMenu->keyhandler(ch))
|
||||
|
|
@ -1537,8 +1565,14 @@ boolean M_Responder(event_t *ev)
|
|||
// G: nevermind we have combi menuitems now
|
||||
menuitem_t *item = currentMenu->numitems ? ¤tMenu->menuitems[itemOn] : NULL;
|
||||
|
||||
if (item && item->cvar && !item->cvar->PossibleValue && M_ChangeStringCvar(ch))
|
||||
return true;
|
||||
// string cvars accept any keyboard input
|
||||
if (item && item->cvar && !item->cvar->PossibleValue)
|
||||
{
|
||||
if (item->cvar->flags & CV_CALL && M_WipeBuffer(ch, MR_Dummy))
|
||||
return true;
|
||||
if (M_ChangeStringCvar(ch))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (menustack[0] == MN_PLAYBACK && !con_destlines)
|
||||
{
|
||||
|
|
@ -1589,6 +1623,9 @@ boolean M_Responder(event_t *ev)
|
|||
if (!item || !(item->cvar || item->status & IT_ARROWS))
|
||||
return true;
|
||||
|
||||
if (M_WipeBuffer(ch, item->cvar ? (item->cvar->flags & CV_CALL ? MR_Dummy : NULL) : item->routine))
|
||||
return true;
|
||||
|
||||
if (menustack[0] != MN_OP_SOUND || itemOn > 3)
|
||||
S_StartSound(NULL, sfx_menu1);
|
||||
|
||||
|
|
@ -1603,7 +1640,7 @@ boolean M_Responder(event_t *ev)
|
|||
if (!item)
|
||||
return true;
|
||||
|
||||
noFurtherInput = true;
|
||||
noFurtherInput = -1;
|
||||
currentMenu->lastOn = itemOn;
|
||||
|
||||
if (menustack[0] == MN_PLAYBACK)
|
||||
|
|
@ -1620,25 +1657,34 @@ boolean M_Responder(event_t *ev)
|
|||
|
||||
if (item->submenu)
|
||||
{
|
||||
if (M_WipeBuffer(ch, menudefs[item->submenu].enterroutine))
|
||||
return true;
|
||||
S_StartSound(NULL, sfx_menu1);
|
||||
M_EnterMenu(item->submenu, true, argument);
|
||||
}
|
||||
else if (item->routine)
|
||||
{
|
||||
if (M_WipeBuffer(ch, item->routine))
|
||||
return true;
|
||||
S_StartSound(NULL, sfx_menu1);
|
||||
item->routine(argument);
|
||||
}
|
||||
else if (item->cvar && item->cvar->PossibleValue) // not for string cvars!
|
||||
{
|
||||
if (item->cvar->flags & CV_CALL && M_WipeBuffer(ch, MR_Dummy))
|
||||
return true;
|
||||
S_StartSound(NULL, sfx_menu1);
|
||||
M_ChangeCvar(item, 1); // right arrow
|
||||
}
|
||||
return true;
|
||||
|
||||
case KEY_ESCAPE:
|
||||
noFurtherInput = true;
|
||||
noFurtherInput = -1;
|
||||
currentMenu->lastOn = itemOn;
|
||||
|
||||
if (M_WipeBuffer(ch, currentMenu->quitroutine))
|
||||
return true;
|
||||
|
||||
//If we entered the game search menu, but didn't enter a game,
|
||||
//make sure the game doesn't still think we're in a netgame.
|
||||
if (!Playing() && netgame && multiplayer)
|
||||
|
|
@ -1659,6 +1705,9 @@ boolean M_Responder(event_t *ev)
|
|||
|| item->cvar == &cv_dummymultiplayer)
|
||||
return true;
|
||||
|
||||
if (item->cvar->flags & CV_CALL && M_WipeBuffer(ch, MR_Dummy))
|
||||
return true;
|
||||
|
||||
if (menustack[0] != MN_OP_SOUND || itemOn > 3)
|
||||
S_StartSound(NULL, sfx_menu1);
|
||||
M_ResetCvar(item);
|
||||
|
|
@ -1848,7 +1897,9 @@ void M_ClearMenus(boolean callexitmenufunc)
|
|||
currentMenu->quitroutine(0);
|
||||
|
||||
// Save the config file. I'm sick of crashing the game later and losing all my changes!
|
||||
COM_BufAddText(va("saveconfig \"%s\" -silent\n", configfile));
|
||||
char buf[sizeof(configfile) + 50];
|
||||
sprintf(buf, "saveconfig \"%s\" -silent\n", configfile);
|
||||
COM_BufAddText(buf);
|
||||
|
||||
if (currentMenu->exitwipe >= 0)
|
||||
{
|
||||
|
|
@ -1960,8 +2011,18 @@ boolean M_MouseNeeded(void)
|
|||
//
|
||||
void M_Ticker(void)
|
||||
{
|
||||
// reset input trigger
|
||||
noFurtherInput = false;
|
||||
// send buffered input from wipe?
|
||||
if (noFurtherInput > 0 && !WipeInAction)
|
||||
{
|
||||
event_t fake;
|
||||
fake.device = 0;
|
||||
fake.type = ev_keydown;
|
||||
fake.data1 = noFurtherInput;
|
||||
D_PostEvent(&fake);
|
||||
noFurtherInput = 0;
|
||||
}
|
||||
else if (noFurtherInput == -1 || !WipeInAction)
|
||||
noFurtherInput = 0;
|
||||
|
||||
if (dedicated)
|
||||
return;
|
||||
|
|
@ -2695,7 +2756,9 @@ void MD_DrawGenericMenu(void)
|
|||
|
||||
// DRAW THE SKULL CURSOR
|
||||
if (M_ItemSelectable(¤tMenu->menuitems[itemOn]))
|
||||
V_DrawScaledPatch(cursorx, cursory, 0, W_CachePatchName("M_CURSOR", PU_CACHE));
|
||||
V_DrawScaledPatch(cursorx, cursory, (noFurtherInput > 0 ? V_TRANSLUCENT : 0), W_CachePatchName("M_CURSOR", PU_CACHE));
|
||||
if (noFurtherInput > 0)
|
||||
V_DrawSmallString(cursorx, cursory+3, 0, "WAIT");
|
||||
|
||||
x = currentMenu->x - 20 + currentMenu->cursoroffset;
|
||||
if (cliptop)
|
||||
|
|
@ -4220,11 +4283,9 @@ INT32 MR_HutStartReplay(INT32 choice)
|
|||
{
|
||||
(void)choice;
|
||||
|
||||
M_ClearMenus(false);
|
||||
demo.loadfiles = M_IsItemOn(MN_MISC_REPLAYSTART, "LOADWATCH");
|
||||
demo.ignorefiles = !M_IsItemOn(MN_MISC_REPLAYSTART, "LOADWATCH");
|
||||
|
||||
G_DoPlayDemo(demolist[dir_on[menudepthleft]].filepath);
|
||||
COM_BufAddText(va("playdemo %s %s",
|
||||
demolist[dir_on[menudepthleft]].filepath + strlen(srb2home) + 1, // dumb hack
|
||||
M_IsItemOn(MN_MISC_REPLAYSTART, "LOADWATCH") ? "-addfiles" : "-force"));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -5733,9 +5794,7 @@ INT32 MR_ReplayStaff(INT32 choice)
|
|||
if (l == LUMPERROR)
|
||||
return false;
|
||||
|
||||
M_ClearMenus(true);
|
||||
demo.loadfiles = false; demo.ignorefiles = true; // Just assume that record attack replays have the files needed
|
||||
G_DoPlayDemo(va("%sS%02u",G_BuildMapName(cv_nextmap.value),cv_dummystaff.value));
|
||||
COM_BufAddText(va("playdemo %sS%02u -force", G_BuildMapName(cv_nextmap.value), cv_dummystaff.value));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -5768,8 +5827,6 @@ INT32 MR_ReplayTimeAttack(INT32 arg)
|
|||
{
|
||||
const char *which;
|
||||
char *gamemode = M_AppendGametypeAndModName();
|
||||
M_ClearMenus(true);
|
||||
demo.loadfiles = false; demo.ignorefiles = true; // Just assume that record attack replays have the files needed
|
||||
|
||||
switch(arg) {
|
||||
default:
|
||||
|
|
@ -5784,12 +5841,12 @@ INT32 MR_ReplayTimeAttack(INT32 arg)
|
|||
break;
|
||||
case 3: // guest
|
||||
// srb2/replay/main/map01-guest.lmp
|
||||
G_DoPlayDemo(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), gamemode));
|
||||
COM_BufAddText(va("playdemo media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-guest.lmp -force", timeattackfolder, G_BuildMapName(cv_nextmap.value), gamemode));
|
||||
Z_Free(gamemode);
|
||||
return true;
|
||||
}
|
||||
// srb2/replay/main/map01-sonic-time-best.lmp
|
||||
G_DoPlayDemo(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value].name, gamemode, which));
|
||||
COM_BufAddText(va("playdemo media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s-%s.lmp -force", timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value].name, gamemode, which));
|
||||
Z_Free(gamemode);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8637,8 +8637,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
// This is handled BEFORE sounds are stopped.
|
||||
else if (encoremode && !prevencoremode && !demo.rewinding)
|
||||
{
|
||||
tic_t locstarttime, endtime, nowtime;
|
||||
|
||||
if (rendermode != render_none)
|
||||
{
|
||||
S_StopMusic(); // er, about that...
|
||||
|
|
@ -8663,25 +8661,8 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
F_RunWipe(wipedefs[wipe_level_final], false);
|
||||
}
|
||||
|
||||
locstarttime = nowtime = lastwipetic;
|
||||
endtime = locstarttime + (3*TICRATE)/2;
|
||||
|
||||
// Hold on white for extra effect.
|
||||
while (nowtime < endtime)
|
||||
{
|
||||
// wait loop
|
||||
while (!((nowtime = I_GetTime()) - lastwipetic))
|
||||
{
|
||||
I_Sleep(cv_sleep.value);
|
||||
I_UpdateTime(cv_timescale.value);
|
||||
}
|
||||
lastwipetic = nowtime;
|
||||
if (moviemode) // make sure we save frames for the white hold too
|
||||
M_SaveFrame();
|
||||
|
||||
// Keep the network alive
|
||||
NetKeepAlive();
|
||||
}
|
||||
D_WipeLoop(WIPELOOP_ENCORE, 0, false);
|
||||
|
||||
ranspecialwipe = 1;
|
||||
}
|
||||
|
|
@ -9031,12 +9012,14 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
levelloading = false;
|
||||
}
|
||||
|
||||
if (rendermode != render_none && reloadinggamestate == false)
|
||||
if (reloadinggamestate == false)
|
||||
{
|
||||
|
||||
R_ResetViewInterpolation(0);
|
||||
R_ResetViewInterpolation(0);
|
||||
R_UpdateMobjInterpolators();
|
||||
if (rendermode != render_none)
|
||||
{
|
||||
R_ResetViewInterpolation(0);
|
||||
R_ResetViewInterpolation(0);
|
||||
R_UpdateMobjInterpolators();
|
||||
}
|
||||
|
||||
// Title card!
|
||||
G_StartTitleCard();
|
||||
|
|
@ -9045,6 +9028,10 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
if (WipeStageTitle && ranspecialwipe != 2 && fromnetsave == false)
|
||||
{
|
||||
G_PreLevelTitleCard();
|
||||
|
||||
// don't do a fade-in if we ran the title card, it trips up dedis!
|
||||
// normal clients never see the fade-in, and it causes a very brief lag spike
|
||||
wipegamestate = gamestate;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -121,6 +121,9 @@ TYPEDEF (cupheader_t);
|
|||
TYPEDEF (exitcondition_t);
|
||||
TYPEDEF (mapheader_lighting_t);
|
||||
|
||||
// f_finale.h
|
||||
TYPEDEF (fademask_t);
|
||||
|
||||
// font.h
|
||||
TYPEDEF (font_t);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue