From cf03f5d91e06302462bd5cf8a4142a6bdbea2a84 Mon Sep 17 00:00:00 2001 From: Lactozilla Date: Tue, 26 Dec 2023 19:53:12 -0300 Subject: [PATCH] Merge branch 'wipeloop-merged' into wipeloop-rebased --- src/d_main.c | 431 ++++++++----------- src/f_finale.c | 232 ++++------- src/f_finale.h | 100 +++-- src/f_wipe.c | 446 ++++++++++++++------ src/g_demo.c | 119 +++--- src/g_demo.h | 11 + src/g_game.c | 686 +++++++++++++++++++++++-------- src/g_game.h | 66 ++- src/hardware/hw_drv.h | 2 +- src/hardware/hw_main.c | 4 +- src/hardware/hw_main.h | 2 +- src/hardware/r_opengl/r_opengl.c | 143 ++++--- src/hu_stuff.c | 2 +- src/lua_hudlib.c | 4 +- src/m_menu.c | 28 +- src/netcode/d_clisrv.c | 2 +- src/netcode/d_netcmd.c | 12 +- src/p_saveg.c | 12 + src/p_setup.c | 146 ++----- src/p_setup.h | 10 +- src/screen.c | 2 +- src/st_stuff.c | 223 +++------- src/st_stuff.h | 14 +- src/v_video.c | 2 +- 24 files changed, 1543 insertions(+), 1156 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index bc821cf71..0be5475c9 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -289,113 +289,103 @@ void D_ProcessEvents(void) } // -// D_Display -// draw current display, possibly wiping it from the previous +// RENDERING // // wipegamestate can be set to -1 to force a wipe on the next draw // added comment : there is a wipe eatch change of the gamestate gamestate_t wipegamestate = GS_LEVEL; -// -1: Default; 0-n: Wipe index; INT16_MAX: do not wipe -INT16 wipetypepre = -1; -INT16 wipetypepost = -1; +INT16 wipetypepre = DEFAULTWIPE; +INT16 wipetypepost = DEFAULTWIPE; -static void D_Display(void) +static void D_Render(void) { - boolean forcerefresh = false; - static boolean wipe = false; - INT32 wipedefindex = 0; - - if (dedicated) - return; - - if (nodrawers) - return; // for comparative timing/profiling - - // Lactozilla: Switching renderers works by checking - // if the game has to do it right when the frame - // needs to render. If so, five things will happen: - // 1. Interface functions will be called so - // that switching to OpenGL creates a - // GL context, and switching to Software - // allocates screen buffers. - // 2. Software will set drawer functions, - // and OpenGL will load textures and - // create plane polygons, if necessary. - // 3. Functions related to switching video - // modes (resolution) are called. - // 4. The frame is ready to be drawn! - - // Check for change of renderer or screen size (video mode) - if ((setrenderneeded || setmodeneeded) && !wipe) - SCR_SetMode(); // change video mode - - // Recalc the screen - if (vid.recalc) - SCR_Recalc(); // NOTE! setsizeneeded is set by SCR_Recalc() - - // View morph - if (rendermode == render_soft && !splitscreen) - R_CheckViewMorph(); - - // Change the view size if needed - // Set by changing video mode or renderer - if (setsizeneeded) + if (!(gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction && curbghide && (!hidetitlemap)))) { - R_ExecuteSetViewSize(); - forcerefresh = true; // force background redraw + PS_START_TIMING(ps_uitime); + return; } - // draw buffered stuff to screen - // Used only by linux GGI version - I_UpdateNoBlit(); - - // save the current screen if about to wipe - wipe = (gamestate != wipegamestate); - if (wipe && wipetypepre != INT16_MAX) + // draw the view directly + if (!automapactive && !dedicated && (!titlecard.prelevel) && cv_renderview.value) { - // set for all later - wipedefindex = gamestate; // wipe_xxx_toblack - if (gamestate == GS_INTERMISSION) + R_ApplyLevelInterpolators(R_UsingFrameInterpolation() ? rendertimefrac : FRACUNIT); + PS_START_TIMING(ps_rendercalltime); + if (players[displayplayer].mo || players[displayplayer].playerstate == PST_DEAD) { - if (intertype == int_spec) // Special Stage - wipedefindex = wipe_specinter_toblack; - else if (intertype != int_coop) // Multiplayer - wipedefindex = wipe_multinter_toblack; + topleft = screens[0] + viewwindowy*vid.width + viewwindowx; + objectsdrawn = 0; +#ifdef HWRENDER + if (rendermode != render_soft) + HWR_RenderPlayerView(0, &players[displayplayer]); + else +#endif + if (rendermode != render_none) + R_RenderPlayerView(&players[displayplayer]); } - if (wipetypepre < 0 || !F_WipeExists(wipetypepre)) - wipetypepre = wipedefs[wipedefindex]; - - if (rendermode != render_none) + // render the second screen + if (splitscreen && players[secondarydisplayplayer].mo) { - // Fade to black first - if ((wipegamestate == (gamestate_t)FORCEWIPE || - (wipegamestate != (gamestate_t)FORCEWIPEOFF - && !(gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction))) - ) // fades to black on its own timing, always - && wipetypepre != UINT8_MAX) +#ifdef HWRENDER + if (rendermode != render_soft) + HWR_RenderPlayerView(1, &players[secondarydisplayplayer]); + else +#endif + if (rendermode != render_none) { - F_WipeStartScreen(); - // Check for Mega Genesis fade - wipestyleflags = WSF_FADEOUT; - if (wipegamestate == (gamestate_t)FORCEWIPE) - F_WipeColorFill(31); - else if (F_TryColormapFade(31)) - wipetypepost = -1; // Don't run the fade below this one - F_WipeEndScreen(); - F_RunWipe(wipetypepre, gamestate != GS_TIMEATTACK && gamestate != GS_TITLESCREEN); - } + viewwindowy = vid.height / 2; + M_Memcpy(ylookup, ylookup2, viewheight*sizeof (ylookup[0])); - F_WipeStartScreen(); + topleft = screens[0] + viewwindowy*vid.width + viewwindowx; + + R_RenderPlayerView(&players[secondarydisplayplayer]); + + viewwindowy = 0; + M_Memcpy(ylookup, ylookup1, viewheight*sizeof (ylookup[0])); + } } - wipetypepre = -1; + // Image postprocessing effect + if (rendermode == render_soft) + { + if (!splitscreen) + R_ApplyViewMorph(); + + if (postimgtype) + V_DoPostProcessor(0, postimgtype, postimgparam); + if (postimgtype2) + V_DoPostProcessor(1, postimgtype2, postimgparam2); + } + PS_STOP_TIMING(ps_rendercalltime); + R_RestoreLevelInterpolators(); + } + + if (lastdraw) + { + if (rendermode == render_soft) + { + VID_BlitLinearScreen(screens[0], screens[1], vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.rowbytes); + Y_ConsiderScreenBuffer(); + usebuffer = true; + } + lastdraw = false; + } + + PS_START_TIMING(ps_uitime); + + if (gamestate == GS_LEVEL) + { + ST_Drawer(); + F_TextPromptDrawer(); + HU_Drawer(); } else - wipetypepre = -1; + F_TitleScreenDrawer(); +} - // do buffered drawing +static void D_RenderNonLevel(void) +{ switch (gamestate) { case GS_TITLESCREEN: @@ -423,7 +413,7 @@ static void D_Display(void) case GS_INTRO: F_IntroDrawer(); if (wipegamestate == (gamestate_t)-1) - wipe = true; + WipeRunPost = true; break; case GS_ENDING: @@ -471,101 +461,75 @@ static void D_Display(void) case GS_NULL: break; } +} + +// +// Draws the entire screen frame. +// + +static void D_Display(void) +{ + boolean forcerefresh = false; + + if (dedicated) + return; + + if (nodrawers) + return; // for comparative timing/profiling + + // Check for change of renderer or screen size (video mode) + if (setrenderneeded || setmodeneeded) + { + SCR_SetMode(); // change video mode + if (WipeInAction) + F_StopWipe(); + } + + // Recalc the screen + if (vid.recalc) + SCR_Recalc(); // NOTE! setsizeneeded is set by SCR_Recalc() + + // View morph + if (rendermode == render_soft && !splitscreen) + R_CheckViewMorph(); + + // Change the view size if needed + // Set by changing video mode or renderer + if (setsizeneeded) + { + R_ExecuteSetViewSize(); + forcerefresh = true; // force background redraw + } + + // draw buffered stuff to screen + // Used only by linux GGI version + I_UpdateNoBlit(); + + // save the current screen if about to wipe + // I'm scared of moving this way down there (before CON_Drawer mayhaps) + // but it's probably not a huge deal to leave it here... + // I'd have to make sure nothing during rendering is changing wipegamestate + if ((gamestate != wipegamestate) && wipetypepre != IGNOREWIPE) + F_WipeStartPre(); + else + wipetypepre = DEFAULTWIPE; + + // do buffered drawing + if (WipeInAction) + { + F_DisplayWipe(); + + if (gamestate == GS_LEVEL && !levelstarting) + TitleCard_DrawOverWipe(); + } + else + D_RenderNonLevel(); // STUPID race condition... if (wipegamestate == GS_INTRO && gamestate == GS_TITLESCREEN) wipegamestate = FORCEWIPEOFF; - else - { - wipegamestate = gamestate; - - // clean up border stuff - // see if the border needs to be initially drawn - if (gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction && curbghide && (!hidetitlemap))) - { - // draw the view directly - - if (!automapactive && !dedicated && cv_renderview.value) - { - R_ApplyLevelInterpolators(R_UsingFrameInterpolation() ? rendertimefrac : FRACUNIT); - PS_START_TIMING(ps_rendercalltime); - if (players[displayplayer].mo || players[displayplayer].playerstate == PST_DEAD) - { - topleft = screens[0] + viewwindowy*vid.width + viewwindowx; - objectsdrawn = 0; - #ifdef HWRENDER - if (rendermode != render_soft) - HWR_RenderPlayerView(0, &players[displayplayer]); - else - #endif - if (rendermode != render_none) - R_RenderPlayerView(&players[displayplayer]); - } - - // render the second screen - if (splitscreen && players[secondarydisplayplayer].mo) - { - #ifdef HWRENDER - if (rendermode != render_soft) - HWR_RenderPlayerView(1, &players[secondarydisplayplayer]); - else - #endif - if (rendermode != render_none) - { - viewwindowy = vid.height / 2; - M_Memcpy(ylookup, ylookup2, viewheight*sizeof (ylookup[0])); - - topleft = screens[0] + viewwindowy*vid.width + viewwindowx; - - R_RenderPlayerView(&players[secondarydisplayplayer]); - - viewwindowy = 0; - M_Memcpy(ylookup, ylookup1, viewheight*sizeof (ylookup[0])); - } - } - - // Image postprocessing effect - if (rendermode == render_soft) - { - if (!splitscreen) - R_ApplyViewMorph(); - - if (postimgtype) - V_DoPostProcessor(0, postimgtype, postimgparam); - if (postimgtype2) - V_DoPostProcessor(1, postimgtype2, postimgparam2); - } - PS_STOP_TIMING(ps_rendercalltime); - R_RestoreLevelInterpolators(); - } - - if (lastdraw) - { - if (rendermode == render_soft) - { - VID_BlitLinearScreen(screens[0], screens[1], vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.rowbytes); - Y_ConsiderScreenBuffer(); - usebuffer = true; - } - lastdraw = false; - } - - PS_START_TIMING(ps_uitime); - - if (gamestate == GS_LEVEL) - { - ST_Drawer(); - F_TextPromptDrawer(); - HU_Drawer(); - } - else - F_TitleScreenDrawer(); - } - else - { - PS_START_TIMING(ps_uitime); - } - } + else if (!WipeInAction) + D_Render(); // change gamma if needed // (GS_LEVEL handles this already due to level-specific palettes) @@ -594,66 +558,35 @@ static void D_Display(void) // vid size change is now finished if it was on... vid.recalc = 0; + if (!WipeInAction || (WipeInAction && (WipeDrawMenu || G_GetRetryFlag(RETRY_CUR)))) + { #ifdef HAVE_THREADS - I_lock_mutex(&m_menu_mutex); + I_lock_mutex(&m_menu_mutex); #endif - M_Drawer(); // menu is drawn even on top of everything + M_Drawer(); // menu is drawn even on top of everything #ifdef HAVE_THREADS - I_unlock_mutex(m_menu_mutex); + I_unlock_mutex(m_menu_mutex); #endif + } // focus lost moved to M_Drawer - CON_Drawer(); - - PS_STOP_TIMING(ps_uitime); - // // wipe update // - if (wipe && wipetypepost != INT16_MAX) + if (WipeRunPost && !WipeInAction && wipetypepost != IGNOREWIPE) { - // note: moved up here because NetUpdate does input changes - // and input during wipe tends to mess things up - wipedefindex += WIPEFINALSHIFT; + F_WipeStartPost(); + F_DisplayWipe(); - if (wipetypepost < 0 || !F_WipeExists(wipetypepost)) - wipetypepost = wipedefs[wipedefindex]; - - if (rendermode != render_none) - { - F_WipeEndScreen(); - - // Funny. - if (WipeStageTitle && st_overlay) - { - lt_ticker--; - lt_lasttic = lt_ticker; - ST_preLevelTitleCardDrawer(); - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol); - F_WipeStartScreen(); - } - - // Check for Mega Genesis fade - if (F_ShouldColormapFade()) - { - wipestyleflags |= WSF_FADEIN; - wipestyleflags &= ~WSF_FADEOUT; - } - - F_RunWipe(wipetypepost, gamestate != GS_TIMEATTACK && gamestate != GS_TITLESCREEN); - } - - // reset counters so timedemo doesn't count the wipe duration - if (timingdemo) - { - framecount = 0; - demostarttime = I_GetTime(); - } - - wipetypepost = -1; + if (titlecard.running) + TitleCard_DrawOverWipe(); } else - wipetypepost = -1; + wipetypepost = DEFAULTWIPE; + + CON_Drawer(); + + PS_STOP_TIMING(ps_uitime); NetUpdate(); // send out any new accumulation @@ -667,34 +600,31 @@ static void D_Display(void) // // normal update // - if (!wipe) + if (cv_netstat.value) { - if (cv_netstat.value) - { - char s[50]; - Net_GetNetStat(); + char s[50]; + Net_GetNetStat(); - s[sizeof s - 1] = '\0'; + s[sizeof s - 1] = '\0'; - snprintf(s, sizeof s - 1, "get %d b/s", getbps); - V_DrawRightAlignedString(BASEVIDWIDTH, BASEVIDHEIGHT-ST_HEIGHT-40, V_YELLOWMAP, s); - snprintf(s, sizeof s - 1, "send %d b/s", sendbps); - V_DrawRightAlignedString(BASEVIDWIDTH, BASEVIDHEIGHT-ST_HEIGHT-30, V_YELLOWMAP, s); - snprintf(s, sizeof s - 1, "GameMiss %.2f%%", gamelostpercent); - V_DrawRightAlignedString(BASEVIDWIDTH, BASEVIDHEIGHT-ST_HEIGHT-20, V_YELLOWMAP, s); - snprintf(s, sizeof s - 1, "SysMiss %.2f%%", lostpercent); - V_DrawRightAlignedString(BASEVIDWIDTH, BASEVIDHEIGHT-ST_HEIGHT-10, V_YELLOWMAP, s); - } - - if (cv_perfstats.value) - { - M_DrawPerfStats(); - } - - PS_START_TIMING(ps_swaptime); - I_FinishUpdate(); // page flip or blit buffer - PS_STOP_TIMING(ps_swaptime); + snprintf(s, sizeof s - 1, "get %d b/s", getbps); + V_DrawRightAlignedString(BASEVIDWIDTH, BASEVIDHEIGHT-ST_HEIGHT-40, V_YELLOWMAP, s); + snprintf(s, sizeof s - 1, "send %d b/s", sendbps); + V_DrawRightAlignedString(BASEVIDWIDTH, BASEVIDHEIGHT-ST_HEIGHT-30, V_YELLOWMAP, s); + snprintf(s, sizeof s - 1, "GameMiss %.2f%%", gamelostpercent); + V_DrawRightAlignedString(BASEVIDWIDTH, BASEVIDHEIGHT-ST_HEIGHT-20, V_YELLOWMAP, s); + snprintf(s, sizeof s - 1, "SysMiss %.2f%%", lostpercent); + V_DrawRightAlignedString(BASEVIDWIDTH, BASEVIDHEIGHT-ST_HEIGHT-10, V_YELLOWMAP, s); } + + if (cv_perfstats.value) + { + M_DrawPerfStats(); + } + + PS_START_TIMING(ps_swaptime); + I_FinishUpdate(); // page flip or blit buffer + PS_STOP_TIMING(ps_swaptime); } // ========================================================================= @@ -708,7 +638,6 @@ void D_SRB2Loop(void) tic_t entertic = 0, oldentertics = 0, realtics = 0, rendertimeout = INFTICS; double deltatics = 0.0; double deltasecs = 0.0; - static lumpnum_t gstartuplumpnum; boolean interp = false; boolean doDisplay = false; @@ -756,7 +685,7 @@ void D_SRB2Loop(void) /* Smells like a hack... Don't fade Sonic's ass into the title screen. */ if (gamestate != GS_TITLESCREEN) { - gstartuplumpnum = W_CheckNumForName("STARTUP"); + lumpnum_t gstartuplumpnum = W_CheckNumForName("STARTUP"); if (gstartuplumpnum == LUMPERROR) gstartuplumpnum = W_GetNumForName("MISSING"); V_DrawScaledPatch(0, 0, 0, W_CachePatchNum(gstartuplumpnum, PU_PATCH)); @@ -777,11 +706,13 @@ void D_SRB2Loop(void) I_UpdateTime(cv_timescale.value); +#if 0 if (lastwipetic) { oldentertics = lastwipetic; lastwipetic = 0; } +#endif // get real tics entertic = I_GetTime(); diff --git a/src/f_finale.c b/src/f_finale.c index 5dc18115c..75dd94b82 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -306,9 +306,9 @@ static void F_NewCutscene(const char *basetext) // ============= #define NUMINTROSCENES 17 INT32 intro_scenenum = 0; -INT32 intro_curtime = 0; +static INT32 intro_curtime = 0; -const char *introtext[NUMINTROSCENES]; +static const char *introtext[NUMINTROSCENES]; static tic_t introscenetime[NUMINTROSCENES] = { @@ -787,7 +787,7 @@ void F_IntroDrawer(void) W_UnlockCachedPatch(background); - if (intro_scenenum == 4) // The asteroid SPINS! + if (intro_scenenum == INTRO_ASTEROID) // The asteroid SPINS! { if (intro_curtime > 1) { @@ -827,7 +827,7 @@ void F_IntroDrawer(void) V_DrawFixedPatch(x, y, scale, trans< 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_StartTitle(); wipegamestate = GS_INTRO; return; } + if (F_IntroSceneCrossfades(intro_scenenum)) + { + F_WipeDoCrossfade(); + next = false; + } + F_NewCutscene(introtext[++intro_scenenum]); timetonext = introscenetime[intro_scenenum]; - - F_WipeStartScreen(); - wipegamestate = -1; animtimer = stoptimer = 0; } @@ -949,36 +940,15 @@ void F_IntroTicker(void) if (rendermode != render_none) { - if (intro_scenenum == 0 && intro_curtime == 2*TICRATE-19) + if (next) { - S_ChangeMusicInternal("_stjr", false); - - wipestyleflags = WSF_FADEIN; - F_WipeStartScreen(); - F_TryColormapFade(31); - - F_IntroDrawer(); - - F_WipeEndScreen(); - F_RunWipe(99,true); + F_IntroSpecialWipe(lastscene); + return; } - else if ((intro_scenenum == 5 && intro_curtime == 5*TICRATE) - || (intro_scenenum == 7 && intro_curtime == 6*TICRATE) - //|| (intro_scenenum == 11 && intro_curtime == 7*TICRATE) - || (intro_scenenum == 15 && intro_curtime == 7*TICRATE)) - { - F_WipeStartScreen(); - F_WipeColorFill(31); - F_IntroDrawer(); - - F_WipeEndScreen(); - F_RunWipe(99,true); - } + F_IntroMidSceneWipe(); + F_IntroDrawer(); } - - if (animtimer) - animtimer--; } // @@ -1764,7 +1734,7 @@ static void F_CacheGoodEnding(void) void F_StartEnding(void) { G_SetGamestate(GS_ENDING); - wipetypepost = INT16_MAX; + wipetypepost = IGNOREWIPE; // Just in case they're open ... somehow M_ClearMenus(true); @@ -1788,7 +1758,7 @@ void F_EndingTicker(void) if (++finalecount > STOPPINGPOINT) { F_StartCredits(); - wipetypepre = INT16_MAX; + wipetypepre = IGNOREWIPE; return; } @@ -2425,8 +2395,6 @@ void F_StartTitleScreen(void) if (titlemap) { - mapthing_t *startpos; - gamestate_t prevwipegamestate = wipegamestate; titlemapinaction = TITLEMAP_LOADING; titlemapcameraref = NULL; @@ -2438,42 +2406,10 @@ void F_StartTitleScreen(void) maptol = mapheaderinfo[gamemap-1]->typeoflevel; globalweather = mapheaderinfo[gamemap-1]->weather; - G_DoLoadLevel(true); + G_StartLevel(true); if (!titlemap) return; - players[displayplayer].playerstate = PST_DEAD; // Don't spawn the player in dummy (I'm still a filthy cheater) - - // Set Default Position - if (playerstarts[0]) - startpos = playerstarts[0]; - else if (deathmatchstarts[0]) - startpos = deathmatchstarts[0]; - else - startpos = NULL; - - if (startpos) - { - camera.x = startpos->x << FRACBITS; - camera.y = startpos->y << FRACBITS; - camera.subsector = R_PointInSubsector(camera.x, camera.y); - camera.z = camera.subsector->sector->floorheight + (startpos->z << FRACBITS); - camera.angle = (startpos->angle % 360)*ANG1; - camera.aiming = 0; - } - else - { - camera.x = camera.y = camera.z = camera.angle = camera.aiming = 0; - camera.subsector = NULL; // toast is filthy too - } - - camera.chase = true; - camera.height = 0; - - // Run enter linedef exec for MN_MAIN, since this is where we start - if (menupres[MN_MAIN].entertag) - P_LinedefExecute(menupres[MN_MAIN].entertag, players[displayplayer].mo, NULL); - wipegamestate = prevwipegamestate; } else @@ -3850,8 +3786,8 @@ static void F_AdvanceToNextScene(void) { V_DrawFill(0,0,BASEVIDWIDTH,BASEVIDHEIGHT,cutscenes[cutnum]->scene[scenenum].fadecolor); - F_WipeEndScreen(); - F_RunWipe(cutscenes[cutnum]->scene[scenenum].fadeinid, true); + F_WipeEndScreenRestore(); + F_StartWipe(cutscenes[cutnum]->scene[scenenum].fadeinid, true); F_WipeStartScreen(); } @@ -3895,7 +3831,7 @@ static void F_AdvanceToNextScene(void) F_CutsceneDrawer(); F_WipeEndScreen(); - F_RunWipe(cutscenes[cutnum]->scene[scenenum].fadeoutid, true); + F_StartWipe(cutscenes[cutnum]->scene[scenenum].fadeoutid, true); } } @@ -4448,7 +4384,7 @@ void F_TextPromptDrawer(void) // Data patch_t *patch; - if (!promptactive) + if (!promptactive || titlecard.prelevel) return; iconlump = W_CheckNumForName(textprompts[cutnum]->page[scenenum].iconname); diff --git a/src/f_finale.h b/src/f_finale.h index cb71775d0..0728d10d3 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -18,6 +18,7 @@ #include "doomtype.h" #include "d_event.h" #include "p_mobj.h" +#include "screen.h" // // FINALE @@ -82,6 +83,23 @@ extern INT32 finalecount; extern INT32 titlescrollxspeed; extern INT32 titlescrollyspeed; +extern INT32 intro_scenenum; + +enum +{ + INTRO_STJR = 0, + + INTRO_FIRST = 1, + INTRO_ASTEROID = 4, + INTRO_RADAR = 5, + INTRO_GRASS1 = 6, + INTRO_GRASS2 = 7, + INTRO_SKYRUNNER = 10, + INTRO_SONICDO1 = 14, + INTRO_SONICDO2 = 15, + INTRO_LAST = 16 +}; + typedef enum { TTMODE_NONE = 0, @@ -103,7 +121,6 @@ extern INT16 ttloop; extern UINT16 tttics; extern boolean ttavailable[6]; - typedef enum { TITLEMAP_OFF = 0, @@ -112,7 +129,6 @@ typedef enum } titlemap_enum; // Current menu parameters - extern mobj_t *titlemapcameraref; extern char curbgname[9]; extern SINT8 curfadevalue; @@ -125,6 +141,7 @@ extern boolean hidetitlemap; extern boolean curhidepics; extern ttmode_enum curttmode; extern UINT8 curttscale; + // ttmode user vars extern char curttname[9]; extern INT16 curttx; @@ -138,17 +155,28 @@ void F_InitMenuPresValues(void); void F_MenuPresTicker(void); // -// WIPE +// WIPES // + +#if NUMSCREENS < 5 +#define NOWIPE // do not enable wipe image post processing for ARM, SH and MIPS CPUs +#endif + +#define DEFAULTWIPE -1 +#define IGNOREWIPE INT16_MAX + // HACK for menu fading while titlemapinaction; skips the level check #define FORCEWIPE -3 #define FORCEWIPEOFF -2 extern boolean WipeInAction; -extern boolean WipeStageTitle; +extern boolean WipeRunPre; +extern boolean WipeRunPost; +extern boolean WipeDrawMenu; typedef enum { + WIPESTYLE_UNDEFINED, WIPESTYLE_NORMAL, WIPESTYLE_COLORMAP } wipestyle_t; @@ -156,19 +184,47 @@ extern wipestyle_t wipestyle; typedef enum { - WSF_FADEOUT = 1, - WSF_FADEIN = 1<<1, - WSF_TOWHITE = 1<<2, - WSF_CROSSFADE = 1<<3, + WSF_FADEOUT = 1, + WSF_FADEIN = 1<<1, + WSF_TOWHITE = 1<<2, + WSF_CROSSFADE = 1<<3, + WSF_LEVELLOADING = 1<<4, + WSF_SPECIALSTAGE = 1<<5, + WSF_INTROSTART = 1<<6, + WSF_INTROEND = 1<<7, + + WSF_ACTION = (WSF_LEVELLOADING|WSF_SPECIALSTAGE|WSF_INTROSTART|WSF_INTROEND) } wipestyleflags_t; extern wipestyleflags_t wipestyleflags; -// Even my function names are borderline -boolean F_ShouldColormapFade(void); -boolean F_TryColormapFade(UINT8 wipecolor); -#ifndef NOWIPE -void F_DecideWipeStyle(void); -#endif +typedef enum +{ + SPECIALWIPE_NONE, + SPECIALWIPE_SSTAGE, + SPECIALWIPE_RETRY, +} specialwipe_t; +extern specialwipe_t ranspecialwipe; + +extern UINT8 wipetype; +extern UINT8 wipeframe; + +void F_WipeSetStyle(void); +void F_WipeStartScreen(void); +void F_WipeEndScreen(void); +void F_WipeEndScreenRestore(void); + +void F_StartWipe(UINT8 type, boolean drawMenu); +void F_RunWipe(void); +void F_DisplayWipe(void); +void F_StopWipe(void); + +void F_WipeStartPre(void); +void F_WipeStartPost(void); + +void F_WipeDoCrossfade(void); +boolean F_WipeDoTinted(void); + +#define F_WipeColorFill(c) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, c) #define FADECOLORMAPDIV 8 #define FADECOLORMAPROWS (256/FADECOLORMAPDIV) @@ -177,19 +233,9 @@ void F_DecideWipeStyle(void); #define FADEGREENFACTOR 15 #define FADEBLUEFACTOR 10 -extern INT32 lastwipetic; - -// Don't know where else to place this constant -// But this file seems appropriate -#define PRELEVELTIME 24 // frames in tics - -void F_WipeStartScreen(void); -void F_WipeEndScreen(void); -void F_RunWipe(UINT8 wipetype, boolean drawMenu); -void F_WipeStageTitle(void); -#define F_WipeColorFill(c) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, c) -tic_t F_GetWipeLength(UINT8 wipetype); -boolean F_WipeExists(UINT8 wipetype); +tic_t F_GetWipeLength(UINT8 type); +boolean F_WipeExists(UINT8 type); +boolean F_WipeCanTint(void); enum { diff --git a/src/f_wipe.c b/src/f_wipe.c index 4bcfb029b..99610f6cf 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -16,6 +16,7 @@ #include "i_video.h" #include "v_video.h" +#include "r_main.h" // framecount #include "r_state.h" // fadecolormap #include "r_draw.h" // transtable #include "p_pspr.h" // tr_transxxx @@ -26,11 +27,11 @@ #include "i_time.h" #include "i_system.h" -#include "i_threads.h" #include "m_menu.h" #include "console.h" #include "d_main.h" #include "g_game.h" +#include "y_inter.h" // intertype #include "m_misc.h" // movie mode #include "doomstat.h" @@ -41,10 +42,6 @@ #include "hardware/hw_main.h" #endif -#if NUMSCREENS < 5 -#define NOWIPE // do not enable wipe image post processing for ARM, SH and MIPS CPUs -#endif - typedef struct fademask_s { UINT8* mask; UINT16 width, height; @@ -92,11 +89,18 @@ UINT8 wipedefs[NUMWIPEDEFS] = { //-------------------------------------------------------------------------- boolean WipeInAction = false; -boolean WipeStageTitle = false; -INT32 lastwipetic = 0; +boolean WipeRunPre = false; +boolean WipeRunPost = false; +boolean WipeDrawMenu = false; -wipestyle_t wipestyle = WIPESTYLE_NORMAL; +UINT8 wipetype = 0; +UINT8 wipeframe = 0; + +wipestyle_t wipestyle = WIPESTYLE_UNDEFINED; wipestyleflags_t wipestyleflags = WSF_CROSSFADE; +specialwipe_t ranspecialwipe = SPECIALWIPE_NONE; + +static INT32 wipedefindex = 0; #ifndef NOWIPE static UINT8 *wipe_scr_start; //screen 3 @@ -110,7 +114,7 @@ static fixed_t paldiv = 0; * \return fademask_t for lump */ static fademask_t *F_GetFadeMask(UINT8 masknum, UINT8 scrnnum) { - static char lumpname[10] = "FADEmmss"; + static char lumpname[11] = "FADEmmss"; static fademask_t fm = {NULL,0,0,0,0,0}; lumpnum_t lumpnum; UINT8 *lump, *mask; @@ -186,20 +190,6 @@ static fademask_t *F_GetFadeMask(UINT8 masknum, UINT8 scrnnum) { return NULL; } -/** Draw the stage title. - */ -void F_WipeStageTitle(void) -{ - // draw level title - if ((WipeStageTitle && st_overlay) - && (wipestyle == WIPESTYLE_COLORMAP) - && G_IsTitleCardAvailable()) - { - ST_runTitleCard(); - ST_drawWipeTitleCard(); - } -} - /** Wipe ticker * * \param fademask pixels to change @@ -427,99 +417,122 @@ static void F_DoColormapWipe(fademask_t *fademask, UINT8 *colormap) } #endif -/** Save the "before" screen of a wipe. +/** Saves the "before" screen of a wipe. */ void F_WipeStartScreen(void) { #ifndef NOWIPE #ifdef HWRENDER - if(rendermode != render_soft) + if (rendermode == render_opengl) { HWR_StartScreenWipe(); return; } #endif + wipe_scr_start = screens[3]; I_ReadScreen(wipe_scr_start); #endif } -/** Save the "after" screen of a wipe. +/** Saves the "after" screen of a wipe. */ void F_WipeEndScreen(void) { #ifndef NOWIPE #ifdef HWRENDER - if(rendermode != render_soft) + if (rendermode == render_opengl) { - HWR_EndScreenWipe(); + HWR_EndScreenWipe(false); return; } #endif + wipe_scr_end = screens[4]; I_ReadScreen(wipe_scr_end); - V_DrawBlock(0, 0, 0, vid.width, vid.height, wipe_scr_start); #endif } -/** Verifies every condition for a colormapped fade. +/** Saves the "after" screen of a wipe, and copies the "before" screen into the main screen. */ -boolean F_ShouldColormapFade(void) +void F_WipeEndScreenRestore(void) { #ifndef NOWIPE +#ifdef HWRENDER + if (rendermode == render_opengl) + { + HWR_EndScreenWipe(true); + return; + } +#endif + + F_WipeEndScreen(); + VID_BlitLinearScreen(screens[3], screens[0], vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.rowbytes); +#endif +} + +/** Verifies every condition for a tinted fade. + */ +boolean F_WipeCanTint(void) +{ if ((wipestyleflags & (WSF_FADEIN|WSF_FADEOUT)) // only if one of those wipestyleflags are actually set && !(wipestyleflags & WSF_CROSSFADE)) // and if not crossfading { - // World - return (gamestate == GS_LEVEL - || gamestate == GS_TITLESCREEN - // Finales - || gamestate == GS_CONTINUING - || gamestate == GS_CREDITS - || gamestate == GS_EVALUATION - || gamestate == GS_INTRO - || gamestate == GS_ENDING - // Menus - || gamestate == GS_TIMEATTACK); + switch (gamestate) + { + case GS_LEVEL: + case GS_TITLESCREEN: + case GS_CONTINUING: + case GS_CREDITS: + case GS_EVALUATION: + case GS_ENDING: + case GS_TIMEATTACK: + return true; + case GS_INTRO: + return (intro_scenenum <= INTRO_FIRST); + default: + return false; + } } -#endif + return false; } /** Decides what wipe style to use. */ -#ifndef NOWIPE -void F_DecideWipeStyle(void) +void F_WipeSetStyle(void) { // Set default wipe style wipestyle = WIPESTYLE_NORMAL; // Check for colormap wipe style - if (F_ShouldColormapFade()) + if (F_WipeCanTint()) wipestyle = WIPESTYLE_COLORMAP; } -#endif -/** Attempt to run a colormap fade, - provided all the conditionals were properly met. - Returns true if so. - I demand you call F_RunWipe after this function. +/** Attempts to run a tinted fade. + * + * \return if true, a tinted fade can run */ -boolean F_TryColormapFade(UINT8 wipecolor) +boolean F_WipeDoTinted(void) { #ifndef NOWIPE - if (F_ShouldColormapFade()) + UINT8 color = (wipestyleflags & WSF_TOWHITE) ? 0 : 31; +#endif + + if (F_WipeCanTint()) { -#ifdef HWRENDER +#if !defined(NOWIPE) && defined(HWRENDER) if (rendermode == render_opengl) - F_WipeColorFill(wipecolor); + F_WipeColorFill(color); #endif return true; } else -#endif { - F_WipeColorFill(wipecolor); +#ifndef NOWIPE + F_WipeColorFill(color); +#endif return false; } } @@ -527,44 +540,135 @@ boolean F_TryColormapFade(UINT8 wipecolor) /** After setting up the screens you want to wipe, * calling this will do a 'typical' wipe. */ -void F_RunWipe(UINT8 wipetype, boolean drawMenu) +void F_StartWipe(UINT8 type, boolean drawMenu) { #ifdef NOWIPE - (void)wipetype; + (void)type; (void)drawMenu; #else - tic_t nowtime; - UINT8 wipeframe = 0; - fademask_t *fmask; - if (!paldiv) paldiv = FixedDiv(257< nowtime) { + while (!((nowtime = I_GetTime()) - lasttime)) + I_Sleep(); + 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(); + } +#endif + + D_StartTitle(); + wipegamestate = GS_INTRO; + } +} + +#ifndef NOWIPE +/** Renders the current wipe into wipe_scr. + */ +static void F_RenderWipe(fademask_t *fmask) +{ + switch (wipestyle) + { + case WIPESTYLE_COLORMAP: #ifdef HWRENDER if (rendermode == render_opengl) { @@ -579,12 +683,8 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu) colormap += (FADECOLORMAPROWS * 256); F_DoColormapWipe(fmask, colormap); } - - // Draw the title card above the wipe - F_WipeStageTitle(); - } - else - { + break; + case WIPESTYLE_NORMAL: #ifdef HWRENDER if (rendermode == render_opengl) { @@ -594,78 +694,186 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu) else #endif F_DoWipe(fmask); - } + break; + default: + break; + } +} +#endif - I_OsPolling(); - I_UpdateNoBlit(); +/** Displays the current wipe. + */ +void F_DisplayWipe(void) +{ +#ifndef NOWIPE + fademask_t *fmask; + wipe_scr = screens[0]; - if (drawMenu) + // get fademask first so we can tell if it exists or not + fmask = F_GetFadeMask(wipetype, wipeframe); + if (!fmask) + { + // Save screen for post-wipe + //if (WipeRunPre) + if (!(wipestyleflags & WSF_CROSSFADE)) { -#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 + fmask = F_GetFadeMask(wipetype, wipeframe-1); + WipeRunPre = false; // Disable post-wipe flag + if (!fmask) + return; + else + { + F_RenderWipe(fmask); + F_WipeStartScreen(); + } } - - I_FinishUpdate(); // page flip or blit buffer - - if (moviemode) - M_SaveFrame(); - - NetKeepAlive(); // Update the network so we don't cause timeouts + return; } - WipeInAction = false; - WipeStageTitle = false; + F_RenderWipe(fmask); #endif } +/** Starts the "pre" type of a wipe. + */ +void F_WipeStartPre(void) +{ + // set for all later + wipedefindex = gamestate; // wipe_xxx_toblack + if (gamestate == GS_INTERMISSION) + { + if (intertype == int_spec) // Special Stage + wipedefindex = wipe_specinter_toblack; + else if (intertype != int_coop) // Multiplayer + wipedefindex = wipe_multinter_toblack; + } + + if (wipetypepre == DEFAULTWIPE || !F_WipeExists(wipetypepre)) + wipetypepre = wipedefs[wipedefindex]; + + if (rendermode != render_none) + { + WipeRunPre = true; + + // Fade to black first + if ((wipegamestate == (gamestate_t)FORCEWIPE || + (wipegamestate != (gamestate_t)FORCEWIPEOFF + && !(gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction))) + ) // fades to black on its own timing, always + && wipetypepre != UINT8_MAX) + { + F_WipeStartScreen(); + + // Do a tinted wipe. + wipestyleflags = WSF_FADEOUT; + if (wipegamestate == (gamestate_t)FORCEWIPE) + F_WipeColorFill(31); + else if (F_WipeDoTinted()) + wipetypepost = DEFAULTWIPE; + + F_WipeEndScreen(); + + F_StartWipe(wipetypepre, gamestate != GS_TIMEATTACK && gamestate != GS_TITLESCREEN); + WipeRunPost = true; + } + } + + wipetypepre = DEFAULTWIPE; + wipegamestate = gamestate; +} + +/** Starts the "post" type of a wipe. + */ +void F_WipeStartPost(void) +{ + wipedefindex += WIPEFINALSHIFT; + + if (wipetypepost == DEFAULTWIPE || !F_WipeExists(wipetypepost)) + wipetypepost = wipedefs[wipedefindex]; + + if (rendermode != render_none) + { + F_WipeEndScreen(); + + // Do a tinted wipe. + if (F_WipeCanTint()) + { + wipestyleflags |= WSF_FADEIN; + wipestyleflags &= ~(WSF_FADEOUT|WSF_ACTION); + } + + F_StartWipe(wipetypepost, gamestate != GS_TIMEATTACK && gamestate != GS_TITLESCREEN); + } + + // reset counters so timedemo doesn't count the wipe duration + if (timingdemo) + { + framecount = 0; + demostarttime = I_GetTime(); + } + + wipetypepost = DEFAULTWIPE; + WipeRunPost = false; +} + +/** Does a crossfade. + */ +void F_WipeDoCrossfade(void) +{ + // Set the wipe parameters + wipetypepost = wipedefs[gamestate + wipedefindex]; + wipestyle = WIPESTYLE_NORMAL; + wipestyleflags = WSF_CROSSFADE; + + // Capture the current screen. Last, if done during gamelogic. + F_WipeStartScreen(); + WipeRunPost = true; + WipeInAction = false; +} + /** Returns tic length of wipe * One lump equals one tic */ -tic_t F_GetWipeLength(UINT8 wipetype) +tic_t F_GetWipeLength(UINT8 type) { #ifdef NOWIPE - (void)wipetype; + (void)type; return 0; #else - static char lumpname[10] = "FADEmmss"; + static char lumpname[11] = "FADEmmss"; lumpnum_t lumpnum; - UINT8 wipeframe; + UINT8 frame; - if (wipetype > 99) + if (type > 99) return 0; - for (wipeframe = 0; wipeframe < 100; wipeframe++) + for (frame = 0; frame < 100; frame++) { - sprintf(&lumpname[4], "%.2hu%.2hu", (UINT16)wipetype, (UINT16)wipeframe); + sprintf(&lumpname[4], "%.2hu%.2hu", (UINT8)type, (UINT8)frame); lumpnum = W_CheckNumForName(lumpname); if (lumpnum == LUMPERROR) - return --wipeframe; + return --frame; } - return --wipeframe; + return --frame; #endif } /** Does the specified wipe exist? */ -boolean F_WipeExists(UINT8 wipetype) +boolean F_WipeExists(UINT8 type) { #ifdef NOWIPE - (void)wipetype; + (void)type; return false; #else - static char lumpname[10] = "FADEmm00"; + static char lumpname[11] = "FADEmm00"; lumpnum_t lumpnum; - if (wipetype > 99) + if (type > 99) return false; - sprintf(&lumpname[4], "%.2hu00", (UINT16)wipetype); + sprintf(&lumpname[4], "%.2hu00", (UINT16)type); lumpnum = W_CheckNumForName(lumpname); return !(lumpnum == LUMPERROR); diff --git a/src/g_demo.c b/src/g_demo.c index f39efad8e..8db7ca870 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -60,6 +60,7 @@ boolean singledemo; // quit after playing a demo from cmdline boolean demo_start; // don't start playing demo right away boolean demo_forwardmove_rng; // old demo backwards compatibility boolean demosynced = true; // console warning message +demoplayer_t *demoplayerinfo; // starting a demo boolean metalrecording; // recording as metal sonic mobj_t *metalplayback; @@ -1990,10 +1991,8 @@ void G_DoPlayDemo(char *defdemoname) UINT8 i; lumpnum_t l; char skin[17],color[MAXCOLORNAME+1],*n,*pdemoname; - UINT8 version,subversion,charability,charability2,thrustfactor,accelstart,acceleration; - pflags_t pflags; - UINT32 randseed, followitem; - fixed_t camerascale,shieldscale,actionspd,mindash,maxdash,normalspeed,runspeed,jumpfactor,height,spinheight; + UINT8 version,subversion; + UINT32 randseed; char msg[1024]; skin[16] = '\0'; @@ -2189,35 +2188,47 @@ void G_DoPlayDemo(char *defdemoname) M_Memcpy(color, demo_p, (demoversion < 0x000d) ? 16 : MAXCOLORNAME); demo_p += (demoversion < 0x000d) ? 16 : MAXCOLORNAME; - charability = READUINT8(demo_p); - charability2 = READUINT8(demo_p); - actionspd = (demoversion < 0x0010) ? (fixed_t)READUINT8(demo_p)<charability = READUINT8(demo_p); + info->charability2 = READUINT8(demo_p); + info->actionspd = (demoversion < 0x0010) ? (fixed_t)READUINT8(demo_p)<mindash = (demoversion < 0x0010) ? (fixed_t)READUINT8(demo_p)<maxdash = (demoversion < 0x0010) ? (fixed_t)READUINT8(demo_p)<normalspeed = (demoversion < 0x0010) ? (fixed_t)READUINT8(demo_p)<runspeed = (demoversion < 0x0010) ? (fixed_t)READUINT8(demo_p)<thrustfactor = READUINT8(demo_p); + info->accelstart = READUINT8(demo_p); + info->acceleration = READUINT8(demo_p); + info->height = (demoversion < 0x000e) ? (fixed_t)READUINT8(demo_p)<spinheight = (demoversion < 0x000e) ? (fixed_t)READUINT8(demo_p)<camerascale = (demoversion < 0x0010) ? (fixed_t)READUINT8(demo_p)<shieldscale = (demoversion < 0x0010) ? (fixed_t)READUINT8(demo_p)<jumpfactor = READFIXED(demo_p); + info->followitem = READUINT32(demo_p); + + // Set color + info->color = SKINCOLOR_NONE; + for (i = 0; i < numskincolors; i++) + if (!stricmp(skincolors[i].name,color)) + { + info->color = i; + break; + } + + demoplayerinfo = info; // pflag data { UINT8 buf = READUINT8(demo_p); - pflags = 0; + info->pflags = 0; if (buf & 0x01) - pflags |= PF_FLIPCAM; + info->pflags |= PF_FLIPCAM; if (buf & 0x02) - pflags |= PF_ANALOGMODE; + info->pflags |= PF_ANALOGMODE; if (buf & 0x04) - pflags |= PF_DIRECTIONCHAR; + info->pflags |= PF_DIRECTIONCHAR; if (buf & 0x08) - pflags |= PF_AUTOBRAKE; + info->pflags |= PF_AUTOBRAKE; CV_SetValue(&cv_showinputjoy, !!(buf & 0x10)); } @@ -2239,6 +2250,8 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(demobuffer); demoplayback = false; titledemo = false; + Z_Free(demoplayerinfo); + demoplayerinfo = NULL; return; } @@ -2262,15 +2275,17 @@ void G_DoPlayDemo(char *defdemoname) playeringame[0] = true; P_SetRandSeed(randseed); G_InitNew(false, G_BuildMapName(gamemap), true, true, false); +} + +void G_FinishLoadingDemo(void) +{ + demoplayer_t *p = demoplayerinfo; + demo_start = true; + if (p == NULL) + return; // Set color - players[0].skincolor = skins[players[0].skin].prefcolor; - for (i = 0; i < numskincolors; i++) - if (!stricmp(skincolors[i].name,color)) - { - players[0].skincolor = i; - break; - } + players[0].skincolor = p->color; if (players[0].mo) { players[0].mo->color = players[0].skincolor; @@ -2282,25 +2297,23 @@ void G_DoPlayDemo(char *defdemoname) // 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[0].camerascale = camerascale; - players[0].shieldscale = shieldscale; - players[0].charability = charability; - players[0].charability2 = charability2; - players[0].actionspd = actionspd; - players[0].mindash = mindash; - players[0].maxdash = maxdash; - players[0].normalspeed = normalspeed; - players[0].runspeed = runspeed; - players[0].thrustfactor = thrustfactor; - players[0].accelstart = accelstart; - players[0].acceleration = acceleration; - players[0].height = height; - players[0].spinheight = spinheight; - players[0].jumpfactor = jumpfactor; - players[0].followitem = followitem; - players[0].pflags = pflags; - - demo_start = true; + players[0].camerascale = p->camerascale; + players[0].shieldscale = p->shieldscale; + players[0].charability = p->charability; + players[0].charability2 = p->charability2; + players[0].actionspd = p->actionspd; + players[0].mindash = p->mindash; + players[0].maxdash = p->maxdash; + players[0].normalspeed = p->normalspeed; + players[0].runspeed = p->runspeed; + players[0].thrustfactor = p->thrustfactor; + players[0].accelstart = p->accelstart; + players[0].acceleration = p->acceleration; + players[0].height = p->height; + players[0].spinheight = p->spinheight; + players[0].jumpfactor = p->jumpfactor; + players[0].followitem = p->followitem; + players[0].pflags = p->pflags; } // @@ -2858,6 +2871,10 @@ void G_StopDemo(void) timingdemo = false; singletics = false; + if (demoplayerinfo) + Z_Free(demoplayerinfo); + demoplayerinfo = NULL; + if (gamestate == GS_INTERMISSION) Y_EndIntermission(); // cleanup diff --git a/src/g_demo.h b/src/g_demo.h index 379c57428..b0d368b4e 100644 --- a/src/g_demo.h +++ b/src/g_demo.h @@ -41,6 +41,16 @@ extern boolean demo_start; extern boolean demo_forwardmove_rng; extern boolean demosynced; +typedef struct +{ + UINT8 charability,charability2,thrustfactor,accelstart,acceleration; + pflags_t pflags; + UINT32 followitem; + fixed_t camerascale,shieldscale,actionspd,mindash,maxdash,normalspeed,runspeed,jumpfactor,height,spinheight; + INT32 color; +} demoplayer_t; +extern demoplayer_t *demoplayerinfo; + extern mobj_t *metalplayback; // Only called by startup code. @@ -95,6 +105,7 @@ void G_LoadMetal(UINT8 **buffer); void G_DeferedPlayDemo(const char *demo); void G_DoPlayDemo(char *defdemoname); +void G_FinishLoadingDemo(void); void G_TimeDemo(const char *name); void G_AddGhost(char *defdemoname); void G_FreeGhosts(void); diff --git a/src/g_game.c b/src/g_game.c index 121672fa7..200bd994b 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -78,6 +78,9 @@ static void G_DoStartContinue(void); static void G_DoContinued(void); static void G_DoWorldDone(void); +static void G_CheckPlayerReborn(void); +static inline void G_TickerEnd(void); + char mapmusname[7]; // Music name UINT16 mapmusflags; // Track and reset bit UINT32 mapmusposition; // Position to jump to @@ -125,10 +128,15 @@ INT32 secondarydisplayplayer; // for splitscreen tic_t gametic; tic_t levelstarttic; // gametic at level start +boolean levelstarting; // starting the level +boolean levelresetplayer; // reset players at level load + UINT32 ssspheres; // old special stage INT16 lastmap; // last level you were at (returning from special stages) tic_t timeinmap; // Ticker for time spent in level (used for levelcard display) +titlecard_t titlecard; + INT16 spstage_start, spmarathon_start; INT16 sstage_start, sstage_end, smpstage_start, smpstage_end; @@ -175,8 +183,7 @@ struct quake quake; mapheader_t* mapheaderinfo[NUMMAPS] = {NULL}; static boolean exitgame = false; -static boolean retrying = false; -static boolean retryingmodeattack = false; +static boolean retrying[RETRY_MAX]; boolean stagefailed = false; // Used for GEMS BONUS? Also to see if you beat the stage. @@ -1171,9 +1178,11 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) !player->climbing && player->powers[pw_carry] != CR_MINECART; // why build a ticcmd if we're paused? + // Or, if the level is starting. // Or, for that matter, if we're being reborn. // ...OR if we're blindfolded. No looking into the floor. - if (ignoregameinputs || paused || P_AutoPause() || (gamestate == GS_LEVEL && (player->playerstate == PST_REBORN || ((gametyperules & GTR_TAG) + if (ignoregameinputs || paused || P_AutoPause() || (levelstarting || WipeInAction) || titlecard.prelevel + || (gamestate == GS_LEVEL && (player->playerstate == PST_REBORN || ((gametyperules & GTR_TAG) && (leveltime < hidetime * TICRATE) && (player->pflags & PF_TAGIT))))) {//@TODO splitscreen player cmd->angleturn = ticcmd_oldangleturn[forplayer]; @@ -1832,17 +1841,19 @@ static void AutoBrake2_OnChange(void) } // -// G_DoLoadLevel +// G_StartLevel // -void G_DoLoadLevel(boolean resetplayer) +void G_StartLevel(boolean resetplayer) { INT32 i; + levelstarting = true; // Make sure objectplace is OFF when you first start the level! OP_ResetObjectplace(); demosynced = true; levelstarttic = gametic; // for time calculation + levelresetplayer = resetplayer; if (wipegamestate == GS_LEVEL) wipegamestate = -1; // force a wipe @@ -1850,6 +1861,57 @@ void G_DoLoadLevel(boolean resetplayer) if (gamestate == GS_INTERMISSION) Y_EndIntermission(); + G_InitLevelGametype(); + ranspecialwipe = SPECIALWIPE_NONE; + + if (mapheaderinfo[gamemap-1]->runsoc[0] != '#') + P_RunSOC(mapheaderinfo[gamemap-1]->runsoc); + + if (cv_runscripts.value && mapheaderinfo[gamemap-1]->scriptname[0] != '#') + P_RunLevelScript(mapheaderinfo[gamemap-1]->scriptname); + + // clear cmd building stuff + memset(gamekeydown, 0, sizeof (gamekeydown)); + for (i = 0;i < JOYAXISSET; i++) + { + joyxmove[i] = joyymove[i] = 0; + joy2xmove[i] = joy2ymove[i] = 0; + } + G_SetMouseDeltas(0, 0, 1); + G_SetMouseDeltas(0, 0, 2); + +#ifndef NOWIPE + if (!G_GetRetryRA() && rendermode != render_none) + G_StartLevelWipe(); + else +#endif + { + if (G_GetRetryRA()) + { + ranspecialwipe = SPECIALWIPE_RETRY; + G_ClearRetryRA(); + } + + G_DoLoadLevel(); + } +} + +// +// G_InitLevelGametype +// +void G_InitLevelGametype(void) +{ + maptol = mapheaderinfo[gamemap-1]->typeoflevel; + gametyperules = gametypedefaultrules[gametype]; +} + +// +// G_DoLoadLevel +// +void G_DoLoadLevel(void) +{ + G_ClearAllRetryFlags(); + // cleanup if (titlemapinaction == TITLEMAP_LOADING) { @@ -1865,15 +1927,23 @@ void G_DoLoadLevel(boolean resetplayer) else titlemapinaction = TITLEMAP_OFF; - G_SetGamestate(GS_LEVEL); I_UpdateMouseGrab(); - for (i = 0; i < MAXPLAYERS; i++) + if (!titlemapinaction) { - if (resetplayer || (playeringame[i] && players[i].playerstate == PST_DEAD)) - players[i].playerstate = PST_REBORN; + INT32 i; + + G_SetGamestate(GS_LEVEL); + + for (i = 0; i < MAXPLAYERS; i++) + { + if (levelresetplayer || (playeringame[i] && players[i].playerstate == PST_DEAD)) + players[i].playerstate = PST_REBORN; + } } + levelstarting = false; + // Setup the level. if (!P_LoadLevel(false, false)) // this never returns false? { @@ -1882,6 +1952,19 @@ void G_DoLoadLevel(boolean resetplayer) return; } + if (netgame) + { + char *title = G_BuildMapTitle(gamemap); + + CONS_Printf(M_GetText("Map is now \"%s"), G_BuildMapName(gamemap)); + if (title) + { + CONS_Printf(": %s", title); + Z_Free(title); + } + CONS_Printf("\"\n"); + } + P_FindEmerald(); displayplayer = consoleplayer; // view the guy you are playing @@ -1893,81 +1976,243 @@ void G_DoLoadLevel(boolean resetplayer) Z_CheckHeap(-2); #endif - if (camera.chase) - P_ResetCamera(&players[displayplayer], &camera); - if (camera2.chase && splitscreen) - P_ResetCamera(&players[secondarydisplayplayer], &camera2); - - // clear cmd building stuff - memset(gamekeydown, 0, sizeof (gamekeydown)); - for (i = 0;i < JOYAXISSET; i++) + if (!titlemapinaction) { - joyxmove[i] = joyymove[i] = 0; - joy2xmove[i] = joy2ymove[i] = 0; + if (camera.chase) + P_ResetCamera(&players[displayplayer], &camera); + if (camera2.chase && splitscreen) + P_ResetCamera(&players[secondarydisplayplayer], &camera2); } + else + { + mapthing_t *startpos; + + players[displayplayer].playerstate = PST_DEAD; // Don't spawn the player in dummy (I'm still a filthy cheater) + + // Set Default Position + if (playerstarts[0]) + startpos = playerstarts[0]; + else if (deathmatchstarts[0]) + startpos = deathmatchstarts[0]; + else + startpos = NULL; + + if (startpos) + { + camera.x = startpos->x << FRACBITS; + camera.y = startpos->y << FRACBITS; + camera.subsector = R_PointInSubsector(camera.x, camera.y); + camera.z = camera.subsector->sector->floorheight + (startpos->z << FRACBITS); + camera.angle = (startpos->angle % 360)*ANG1; + camera.aiming = 0; + } + else + { + camera.x = camera.y = camera.z = camera.angle = camera.aiming = 0; + camera.subsector = NULL; // toast is filthy too + } + + camera.chase = true; + camera.height = 0; + + // Run enter linedef exec for MN_MAIN, since this is where we start + if (menupres[MN_MAIN].entertag) + P_LinedefExecute(menupres[MN_MAIN].entertag, players[displayplayer].mo, NULL); + } + + if (demoplayerinfo) + { + G_FinishLoadingDemo(); + Z_Free(demoplayerinfo); + } + demoplayerinfo = NULL; + G_SetMouseDeltas(0, 0, 1); G_SetMouseDeltas(0, 0, 2); // clear hud messages remains (usually from game startup) CON_ClearHUD(); + + if (demoplayback && !timingdemo) + precache = true; + if (timingdemo) + G_DoneLevelLoad(); + + if (metalrecording) + G_BeginMetal(); + if (demorecording) // Okay, level loaded, character spawned and skinned, + G_BeginRecording(); // I AM NOW READY TO RECORD. + demo_start = true; +} + +// +// Run the level's wipe. +// +void G_StartLevelWipe(void) +{ + // Cancel all d_main.c fades + WipeRunPost = false; + wipegamestate = FORCEWIPEOFF; + wipestyle = WIPESTYLE_COLORMAP; + wipestyleflags = (WSF_FADEOUT|WSF_LEVELLOADING); + + // Special stage fade to white + // This is handled BEFORE sounds are stopped. + if (rendermode != render_none && G_IsSpecialStage(gamemap)) + { + // TODO call this after rendering the frame (because of F_WipeStartScreen calls) + P_RunSpecialStageWipe(); + ranspecialwipe = SPECIALWIPE_SSTAGE; + } + + // Let's fade to black here + // But only if we didn't do the special stage wipe + if (rendermode != render_none && ranspecialwipe == SPECIALWIPE_NONE) + { + // TODO same thing as the last one + P_RunLevelWipe(); + + // Fade out music here. Deduct 2 tics so the fade volume actually reaches 0. + // But don't halt the music! S_Start will take care of that. This dodges a MIDI crash bug. + if (!titlemapinaction && (RESETMUSIC || + strnicmp(S_MusicName(), + (mapmusflags & MUSIC_RELOADRESET) ? mapheaderinfo[gamemap-1]->musname : mapmusname, 7))) + S_FadeMusic(0, FixedMul( + FixedDiv((F_GetWipeLength(wipedefs[wipe_level_toblack])-2)*NEWTICRATERATIO, NEWTICRATE), MUSICRATE)); + } } // // Start the title card. // -void G_StartTitleCard(void) +void TitleCard_Start(void) { - // The title card has been disabled for this map. - // Oh well. - if (!G_IsTitleCardAvailable()) + // The title card has been disabled for this map + if (!TitleCard_Available()) { - WipeStageTitle = false; + st_translucency = cv_translucenthud.value; // Reset the HUD translucency! + WipeRunPost = true; // Start the post wipe. return; } - // clear the hud CON_ClearHUD(); + TitleCard_LoadGraphics(); - // prepare status bar - ST_startTitleCard(); + // Actually start it + titlecard.running = true; + titlecard.prelevel = true; - // start the title card - WipeStageTitle = (!titlemapinaction); + titlecard.ticker = 0; + titlecard.exitticker = 0; + titlecard.endtime = 2*TICRATE + 10; + + titlecard.scroll = BASEVIDWIDTH * FRACUNIT; + titlecard.momentum = 0; + + if (titlecard.patches[1]) + { + patch_t *patch = (patch_t *)titlecard.patches[1]; + titlecard.zigzag = -(SHORT(patch->width) * FRACUNIT); + } + + wipetypepost = IGNOREWIPE; } // -// Run the title card before fading in to the level. +// Load the graphics for the title card. // -void G_PreLevelTitleCard(void) +void TitleCard_LoadGraphics(void) { -#ifndef NOWIPE - tic_t starttime = I_GetTime(); - tic_t endtime = starttime + (PRELEVELTIME*NEWTICRATERATIO); - tic_t nowtime = starttime; - tic_t lasttime = starttime; - while (nowtime < endtime) +#define SETPATCH(def, warning, custom, idx) \ +{ \ + lumpnum_t patlumpnum = LUMPERROR; \ + if (mapheaderinfo[gamemap-1]->custom[0] != '\0') \ + { \ + patlumpnum = W_CheckNumForName(mapheaderinfo[gamemap-1]->custom); \ + if (patlumpnum != LUMPERROR) \ + titlecard.patches[idx] = (patch_t *)W_CachePatchNum(patlumpnum, PU_HUDGFX); \ + } \ + if (patlumpnum == LUMPERROR) \ + { \ + if (!(mapheaderinfo[gamemap-1]->levelflags & LF_WARNINGTITLE)) \ + titlecard.patches[idx] = (patch_t *)W_CachePatchName(def, PU_HUDGFX); \ + else \ + titlecard.patches[idx] = (patch_t *)W_CachePatchName(warning, PU_HUDGFX); \ + } \ +} + + SETPATCH("LTACTBLU", "LTACTRED", ltactdiamond, 0) + SETPATCH("LTZIGZAG", "LTZIGRED", ltzzpatch, 1) + SETPATCH("LTZZTEXT", "LTZZWARN", ltzztext, 2) + +#undef SETPATCH +} + +// +// Run the title card. +// +void TitleCard_Run(void) +{ + if (!TitleCard_Available()) + return; + + if (titlecard.wipe) + titlecard.wipe++; + + if (titlecard.ticker >= (titlecard.endtime + TICRATE)) { - // draw loop - while (!((nowtime = I_GetTime()) - lasttime)) - { - I_Sleep(cv_sleep.value); - I_UpdateTime(cv_timescale.value); - } - lasttime = nowtime; - - 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(); + titlecard.running = false; + return; + } + else if (titlecard.ticker >= PRELEVELTIME && titlecard.prelevel) + { + // Force a wipe + wipegamestate = -1; + WipeRunPost = true; + + // TODO should be done after rendering + if (!cv_showhud.value) + F_WipeDoCrossfade(); + + // Disable prelevel flag + titlecard.prelevel = false; + titlecard.wipe = 1; + } + + if (!(paused || P_AutoPause())) + { + // scroll to screen (level title) + if (!titlecard.exitticker) + { + if (abs(titlecard.scroll) > FRACUNIT) + titlecard.scroll -= (titlecard.scroll>>2); + else + titlecard.scroll = 0; + } + // scroll away from screen (level title) + else + { + titlecard.momentum -= FRACUNIT*6; + titlecard.scroll += titlecard.momentum; + } + + // scroll to screen (zigzag) + if (!titlecard.exitticker) + { + if (abs(titlecard.zigzag) > FRACUNIT) + titlecard.zigzag -= (titlecard.zigzag>>2); + else + titlecard.zigzag = 0; + } + // scroll away from screen (zigzag) + else + titlecard.zigzag += titlecard.momentum; + + // tick + titlecard.ticker++; + if (titlecard.ticker >= titlecard.endtime) + titlecard.exitticker++; } - if (!cv_showhud.value) - wipestyleflags = WSF_CROSSFADE; -#endif } static boolean titlecardforreload = false; @@ -1975,7 +2220,7 @@ static boolean titlecardforreload = false; // // Returns true if the current level has a title card. // -boolean G_IsTitleCardAvailable(void) +boolean TitleCard_Available(void) { // The current level header explicitly disabled the title card. UINT16 titleflag = LF_NOTITLECARDFIRST; @@ -1985,6 +2230,8 @@ boolean G_IsTitleCardAvailable(void) else if (titlecardforreload) titleflag = LF_NOTITLECARDRESPAWN; + titlecardforreload = false; + if (mapheaderinfo[gamemap-1]->levelflags & titleflag) return false; @@ -2190,7 +2437,7 @@ boolean G_Responder(event_t *ev) pausedelay = 1+(NEWTICRATE/2); else if (cv_instantretry.value || ++pausedelay > 1+(NEWTICRATE/2)+(NEWTICRATE/3)) { - G_SetModeAttackRetryFlag(); + G_SetRetryRA(); return true; } pausedelay++; // counteract subsequent subtraction this frame @@ -2269,11 +2516,29 @@ boolean G_LuaResponder(event_t *ev) return cancelled; } +// see also SCR_DisplayMarathonInfo +static void G_MarathonTicker(void) +{ + if (gamestate != GS_LEVEL) + return; + if ((marathonmode & (MA_INIT|MA_INGAME)) != MA_INGAME) + return; + + // IGT doesn't increase during loads, unless the game's paused + if (!(paused || P_AutoPause())) + { + if (titlecard.prelevel || WipeInAction) + return; + } + + marathontime++; +} + // // G_Ticker // Make ticcmd_ts for the players. // -void G_Ticker(boolean run) +void G_Ticker(boolean run, tic_t tics) { UINT32 i; INT32 buf; @@ -2295,71 +2560,49 @@ void G_Ticker(boolean run) } } - // see also SCR_DisplayMarathonInfo - if ((marathonmode & (MA_INIT|MA_INGAME)) == MA_INGAME && gamestate == GS_LEVEL) - marathontime++; - - P_MapStart(); - // do player reborns if needed - if (gamestate == GS_LEVEL) + // Run the current wipe + if (WipeInAction) { - // Or, alternatively, retry. - if (!(netgame || multiplayer) && G_GetRetryFlag()) + if (run) { - G_ClearRetryFlag(); + boolean loading = (wipestyleflags & WSF_LEVELLOADING); - if (modeattacking) + switch (gamestate) { - pausedelay = INT32_MIN; - M_ModeAttackRetry(0); + case GS_LEVEL: + if ((loading && G_GetRetryFlag(RETRY_PAUSED)) || !(paused || P_AutoPause())) + F_RunWipe(); + break; + default: + F_RunWipe(); + break; } - else - { - // Costs a life to retry ... unless the player in question is dead already, or you haven't even touched the first starpost in marathon run. - if (marathonmode && gamemap == spmarathon_start && !players[consoleplayer].starposttime) - { - player_t *p = &players[consoleplayer]; - marathonmode |= MA_INIT; - marathontime = 0; - numgameovers = tokenlist = token = 0; - countdown = countdown2 = exitfadestarted = 0; + // Run the title card + if (titlecard.running && (wipestyleflags & WSF_FADEIN)) + TitleCard_Run(); - p->playerstate = PST_REBORN; - p->starpostx = p->starposty = p->starpostz = 0; + // Run Marathon Mode in-game timer + G_MarathonTicker(); - p->lives = startinglivesbalance[0]; - p->continues = 1; + // do player reborns if needed + if (!loading) + G_CheckPlayerReborn(); - p->score = p->recordscore = 0; - - // The latter two should clear by themselves, but just in case - p->pflags &= ~(PF_TAGIT|PF_GAMETYPEOVER|PF_FULLSTASIS); - - // Clear cheatcodes too, just in case. - p->pflags &= ~(PF_GODMODE|PF_NOCLIP|PF_INVIS); - - p->xtralife = 0; - - // Reset unlockable triggers - unlocktriggers = 0; - - emeralds = 0; - - memset(&luabanks, 0, sizeof(luabanks)); - } - else if (G_GametypeUsesLives() && players[consoleplayer].playerstate == PST_LIVE && players[consoleplayer].lives != INFLIVES) - players[consoleplayer].lives -= 1; - - G_DoReborn(consoleplayer); - } + G_TickerEnd(); } - - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].playerstate == PST_REBORN) - G_DoReborn(i); + return; } - P_MapEnd(); + + // Oh my God I hope this doesn't implode anything + if (levelstarting || G_GetExitGameFlag()) + return; + + // Run Marathon Mode in-game timer + G_MarathonTicker(); + + // do player reborns if needed + G_CheckPlayerReborn(); // do things to change the game state while (gameaction != ga_nothing) @@ -2418,6 +2661,16 @@ void G_Ticker(boolean run) switch (gamestate) { case GS_LEVEL: + if (titlecard.running) + { + if (run && tics <= 1) + TitleCard_Run(); + if (titlecard.prelevel) + { + G_CheckPlayerReborn(); + break; + } + } if (titledemo) F_TitleDemoTicker(); P_Ticker(run); // tic the game @@ -2498,26 +2751,100 @@ void G_Ticker(boolean run) } if (run) + G_TickerEnd(); +} + +static inline void G_TickerEnd(void) +{ + if (pausedelay && pausedelay != INT32_MIN) { - if (pausedelay && pausedelay != INT32_MIN) - { - if (pausedelay > 0) - pausedelay--; - else - pausedelay++; - } - - if (camtoggledelay) - camtoggledelay--; - - if (camtoggledelay2) - camtoggledelay2--; - - if (gametic % NAMECHANGERATE == 0) - { - memset(player_name_changes, 0, sizeof player_name_changes); - } + if (pausedelay > 0) + pausedelay--; + else + pausedelay++; } + + if (camtoggledelay) + camtoggledelay--; + + if (camtoggledelay2) + camtoggledelay2--; + + if (gametic % NAMECHANGERATE == 0) + { + memset(player_name_changes, 0, sizeof player_name_changes); + } +} + +static void G_CheckPlayerReborn(void) +{ + UINT32 i; + + P_MapStart(); + + if (gamestate == GS_LEVEL) + { + // Or, alternatively, retry. + if (!(netgame || multiplayer) && G_GetRetrySP()) + { + G_ClearRetrySP(); + + if (WipeInAction) + F_StopWipe(); + + if (modeattacking) + { + pausedelay = INT32_MIN; + M_ModeAttackRetry(0); + } + else + { + // Costs a life to retry ... unless the player in question is dead already, or you haven't even touched the first starpost in marathon run. + if (marathonmode && gamemap == spmarathon_start && !players[consoleplayer].starposttime) + { + player_t *p = &players[consoleplayer]; + marathonmode |= MA_INIT; + marathontime = 0; + + numgameovers = tokenlist = token = 0; + countdown = countdown2 = exitfadestarted = 0; + + p->playerstate = PST_REBORN; + p->starpostx = p->starposty = p->starpostz = 0; + + p->lives = startinglivesbalance[0]; + p->continues = 1; + + p->score = p->recordscore = 0; + + // The latter two should clear by themselves, but just in case + p->pflags &= ~(PF_TAGIT|PF_GAMETYPEOVER|PF_FULLSTASIS); + + // Clear cheatcodes too, just in case. + p->pflags &= ~(PF_GODMODE|PF_NOCLIP|PF_INVIS); + + p->xtralife = 0; + + // Reset unlockable triggers + unlocktriggers = 0; + + emeralds = 0; + + memset(&luabanks, 0, sizeof(luabanks)); + } + else if (G_GametypeUsesLives() && players[consoleplayer].playerstate == PST_LIVE && players[consoleplayer].lives != INFLIVES) + players[consoleplayer].lives -= 1; + + G_DoReborn(consoleplayer); + } + } + + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && players[i].playerstate == PST_REBORN) + G_DoReborn(i); + } + + P_MapEnd(); } // @@ -3217,8 +3544,8 @@ void G_DoReborn(INT32 playernum) } // Do a wipe - wipegamestate = -1; - wipestyleflags = WSF_CROSSFADE; + // TODO should be done after rendering + F_WipeDoCrossfade(); if (camera.chase) P_ResetCamera(&players[displayplayer], &camera); @@ -3263,8 +3590,7 @@ void G_DoReborn(INT32 playernum) { LUA_HookInt(gamemap, HOOK(MapChange)); titlecardforreload = true; - G_DoLoadLevel(true); - titlecardforreload = false; + G_StartLevel(true); if (metalrecording) G_BeginMetal(); return; @@ -5126,6 +5452,7 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean ultimatemode = pultmode; automapactive = false; imcontinuing = false; + titlemapinaction = TITLEMAP_OFF; if (reset_skin) D_SendPlayerConfig(); @@ -5146,20 +5473,7 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean if ((gametyperules & GTR_CUTSCENES) && !skipprecutscene && mapheaderinfo[gamemap-1]->precutscenenum && !modeattacking && !(marathonmode & MA_NOCUTSCENES)) // Start a custom cutscene. F_StartCustomCutscene(mapheaderinfo[gamemap-1]->precutscenenum-1, true, resetplayer, FLS); else - G_DoLoadLevel(resetplayer); - - if (netgame) - { - char *title = G_BuildMapTitle(gamemap); - - CONS_Printf(M_GetText("Map is now \"%s"), G_BuildMapName(gamemap)); - if (title) - { - CONS_Printf(": %s", title); - Z_Free(title); - } - CONS_Printf("\"\n"); - } + G_StartLevel(resetplayer); } @@ -5480,38 +5794,80 @@ boolean G_GetExitGameFlag(void) return exitgame; } -// Same deal with retrying. -void G_SetRetryFlag(void) -{ - retrying = true; +// +// Retrying flags +// + +#define CheckRetryFlag(type) \ +{ \ + if (type < 0 || type >= RETRY_MAX) \ + I_Error("G_SetRetryFlag: out of bounds retry flag type (%d)", type); \ } -void G_ClearRetryFlag(void) +void G_SetRetryFlag(INT32 type) { - retrying = false; + CheckRetryFlag(type); + retrying[type] = true; } -boolean G_GetRetryFlag(void) +void G_ClearRetryFlag(INT32 type) { - return retrying; + CheckRetryFlag(type); + retrying[type] = false; } -void G_SetModeAttackRetryFlag(void) +boolean G_GetRetryFlag(INT32 type) { - retryingmodeattack = true; - G_SetRetryFlag(); + CheckRetryFlag(type); + return retrying[type]; } -void G_ClearModeAttackRetryFlag(void) +void G_ClearAllRetryFlags(void) { - retryingmodeattack = false; + INT32 i = RETRY_MAX; + while (--i >= 0) + G_ClearRetryFlag(i); } -boolean G_GetModeAttackRetryFlag(void) +// Sets RETRY_CUR, may set RETRY_PAUSED. +void G_SetRetrySP(void) { - return retryingmodeattack; + G_SetRetryFlag(RETRY_SP); + G_SetRetryFlag(RETRY_CUR); + + if (paused) + G_SetRetryFlag(RETRY_PAUSED); } +void G_ClearRetrySP(void) +{ + G_ClearRetryFlag(RETRY_SP); +} + +boolean G_GetRetrySP(void) +{ + return G_GetRetryFlag(RETRY_SP); +} + +// Sets RETRY_RA and calls G_SetRetryFlag. +void G_SetRetryRA(void) +{ + G_SetRetryFlag(RETRY_RA); + G_SetRetrySP(); +} + +void G_ClearRetryRA(void) +{ + G_ClearRetryFlag(RETRY_RA); +} + +boolean G_GetRetryRA(void) +{ + return G_GetRetryFlag(RETRY_RA); +} + +#undef CheckRetryFlag + // Time utility functions INT32 G_TicsToHours(tic_t tics) { diff --git a/src/g_game.h b/src/g_game.h index 2612224a1..fe8e73813 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -36,6 +36,10 @@ extern boolean playeringame[MAXPLAYERS]; // gametic at level start extern tic_t levelstarttic; +extern boolean levelstarting; // starting the level +extern boolean leveldemoload; // starting a demo +extern boolean levelresetplayer; // reset players at level load + // for modding? extern INT16 prevmap, nextmap; extern INT32 gameovertics; @@ -177,10 +181,32 @@ void G_SpawnPlayer(INT32 playernum); // Can be called by the startup code or M_Responder. // A normal game starts at map 1, but a warp test can start elsewhere void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 character, boolean SSSG, boolean FLS); -void G_DoLoadLevel(boolean resetplayer); -void G_StartTitleCard(void); -void G_PreLevelTitleCard(void); -boolean G_IsTitleCardAvailable(void); +void G_StartLevel(boolean resetplayer); +void G_StartLevelWipe(void); +void G_InitLevelGametype(void); +void G_DoLoadLevel(void); + +// Title card +void TitleCard_Start(void); +void TitleCard_Run(void); +void TitleCard_LoadGraphics(void); +boolean TitleCard_Available(void); + +typedef struct +{ + boolean running, prelevel; + UINT8 wipe; + + tic_t ticker; + tic_t exitticker, endtime; + + fixed_t zigzag, scroll, momentum; + void *patches[3]; +} titlecard_t; + +extern titlecard_t titlecard; + +#define PRELEVELTIME 24 // frames in tics // Can be called by the startup code or M_Responder, calls P_SetupLevel. void G_LoadGame(UINT32 slot, INT16 mapoverride); @@ -223,7 +249,7 @@ void G_UseContinue(void); void G_AfterIntermission(void); void G_EndGame(void); // moved from y_inter.c/h and renamed -void G_Ticker(boolean run); +void G_Ticker(boolean run, tic_t tics); boolean G_Responder(event_t *ev); boolean G_LuaResponder(event_t *ev); @@ -233,13 +259,31 @@ void G_SetExitGameFlag(void); void G_ClearExitGameFlag(void); boolean G_GetExitGameFlag(void); -void G_SetRetryFlag(void); -void G_ClearRetryFlag(void); -boolean G_GetRetryFlag(void); +enum +{ + RETRY_SP, // Retrying in Single Player. + RETRY_RA, // Retrying in Mode Attack. -void G_SetModeAttackRetryFlag(void); -void G_ClearModeAttackRetryFlag(void); -boolean G_GetModeAttackRetryFlag(void); + // Cleared at G_DoLoadLevel. + RETRY_CUR, // Currently retrying. + RETRY_PAUSED, // Retrying while paused. + + RETRY_MAX, +}; + +void G_SetRetryFlag(INT32 type); +void G_ClearRetryFlag(INT32 type); +boolean G_GetRetryFlag(INT32 type); + +void G_SetRetrySP(void); +void G_ClearRetrySP(void); +boolean G_GetRetrySP(void); + +void G_SetRetryRA(void); +void G_ClearRetryRA(void); +boolean G_GetRetryRA(void); + +void G_ClearAllRetryFlags(void); void G_LoadGameData(gamedata_t *data); void G_LoadGameSettings(void); diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index 1c4cd99ab..f8556849e 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -58,7 +58,7 @@ EXPORT INT32 HWRAPI(GetTextureUsed) (void); EXPORT void HWRAPI(FlushScreenTextures) (void); EXPORT void HWRAPI(StartScreenWipe) (void); -EXPORT void HWRAPI(EndScreenWipe) (void); +EXPORT void HWRAPI(EndScreenWipe) (boolean restore); EXPORT void HWRAPI(DoScreenWipe) (void); EXPORT void HWRAPI(DrawIntermissionBG) (void); EXPORT void HWRAPI(MakeScreenTexture) (void); diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 4e3ff432b..f8e22318d 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -6924,10 +6924,10 @@ void HWR_StartScreenWipe(void) HWD.pfnStartScreenWipe(); } -void HWR_EndScreenWipe(void) +void HWR_EndScreenWipe(boolean restore) { //CONS_Debug(DBG_RENDER, "In HWR_EndScreenWipe()\n"); - HWD.pfnEndScreenWipe(); + HWD.pfnEndScreenWipe(restore); } void HWR_DrawIntermissionBG(void) diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index cce4e8f0a..d2353e66f 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -58,7 +58,7 @@ void transform(float *cx, float *cy, float *cz); INT32 HWR_GetTextureUsed(void); void HWR_DoPostProcessor(player_t *player); void HWR_StartScreenWipe(void); -void HWR_EndScreenWipe(void); +void HWR_EndScreenWipe(boolean restore); void HWR_DrawIntermissionBG(void); void HWR_DoWipe(UINT8 wipenum, UINT8 scrnnum); void HWR_DoTintedWipe(UINT8 wipenum, UINT8 scrnnum); diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 6c0c90fc5..47a2851e9 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -3162,71 +3162,8 @@ EXPORT void HWRAPI(FlushScreenTextures) (void) finalScreenTexture = 0; } -// Create Screen to fade from -EXPORT void HWRAPI(StartScreenWipe) (void) -{ - INT32 texsize = 2048; - boolean firstTime = (startScreenWipe == 0); - - // Use a power of two texture, dammit - if(screen_width <= 512) - texsize = 512; - else if(screen_width <= 1024) - texsize = 1024; - - // Create screen texture - if (firstTime) - pglGenTextures(1, &startScreenWipe); - pglBindTexture(GL_TEXTURE_2D, startScreenWipe); - - if (firstTime) - { - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - Clamp2D(GL_TEXTURE_WRAP_S); - Clamp2D(GL_TEXTURE_WRAP_T); - pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0); - } - else - pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize); - - tex_downloaded = startScreenWipe; -} - -// Create Screen to fade to -EXPORT void HWRAPI(EndScreenWipe)(void) -{ - INT32 texsize = 2048; - boolean firstTime = (endScreenWipe == 0); - - // Use a power of two texture, dammit - if(screen_width <= 512) - texsize = 512; - else if(screen_width <= 1024) - texsize = 1024; - - // Create screen texture - if (firstTime) - pglGenTextures(1, &endScreenWipe); - pglBindTexture(GL_TEXTURE_2D, endScreenWipe); - - if (firstTime) - { - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - Clamp2D(GL_TEXTURE_WRAP_S); - Clamp2D(GL_TEXTURE_WRAP_T); - pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0); - } - else - pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize); - - tex_downloaded = endScreenWipe; -} - - -// Draw the last scene under the intermission -EXPORT void HWRAPI(DrawIntermissionBG)(void) +// Draws a screen texture. +static void DrawScreenTexture(GLuint tex) { float xfix, yfix; INT32 texsize = 2048; @@ -3263,14 +3200,86 @@ EXPORT void HWRAPI(DrawIntermissionBG)(void) pglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); - pglBindTexture(GL_TEXTURE_2D, screentexture); + pglBindTexture(GL_TEXTURE_2D, tex); pglColor4ubv(white); pglTexCoordPointer(2, GL_FLOAT, 0, fix); pglVertexPointer(3, GL_FLOAT, 0, screenVerts); pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); - tex_downloaded = screentexture; + tex_downloaded = tex; +} + +// Create Screen to fade from +EXPORT void HWRAPI(StartScreenWipe) (void) +{ + INT32 texsize = 2048; + boolean firstTime = (startScreenWipe == 0); + + // Use a power of two texture, dammit + if(screen_width <= 512) + texsize = 512; + else if(screen_width <= 1024) + texsize = 1024; + + // Create screen texture + if (firstTime) + pglGenTextures(1, &startScreenWipe); + pglBindTexture(GL_TEXTURE_2D, startScreenWipe); + + if (firstTime) + { + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + Clamp2D(GL_TEXTURE_WRAP_S); + Clamp2D(GL_TEXTURE_WRAP_T); + pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0); + } + else + pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize); + + tex_downloaded = startScreenWipe; +} + +// Create Screen to fade to +EXPORT void HWRAPI(EndScreenWipe)(boolean restore) +{ + INT32 texsize = 2048; + boolean firstTime = (endScreenWipe == 0); + + // Use a power of two texture, dammit + if(screen_width <= 512) + texsize = 512; + else if(screen_width <= 1024) + texsize = 1024; + + // Create screen texture + if (firstTime) + pglGenTextures(1, &endScreenWipe); + pglBindTexture(GL_TEXTURE_2D, endScreenWipe); + + if (firstTime) + { + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + Clamp2D(GL_TEXTURE_WRAP_S); + Clamp2D(GL_TEXTURE_WRAP_T); + pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0); + } + else + pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize); + + tex_downloaded = endScreenWipe; + + // Draw the start screen wipe texture + if (restore) + DrawScreenTexture(startScreenWipe); +} + +// Draw the last scene under the intermission +EXPORT void HWRAPI(DrawIntermissionBG)(void) +{ + DrawScreenTexture(screentexture); } // Do screen fades! diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 0a2b71aec..f39941572 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1817,7 +1817,7 @@ static inline void HU_DrawCrosshairs(void) INT32 cross1 = cv_crosshair.value & 3; INT32 cross2 = cv_crosshair2.value & 3; - if (automapactive || demoplayback) + if (automapactive || demoplayback || titlecard.prelevel) return; stplyr = ((stplyr == &players[displayplayer]) ? &players[secondarydisplayplayer] : &players[displayplayer]); diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 2e6721a3a..94fc7bdc6 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -1437,8 +1437,8 @@ void LUA_SetHudHook(int hook, huddrawlist_h list) case HUD_HOOK(titlecard): LUA_PushUserdata(gL, stplyr, META_PLAYER); - lua_pushinteger(gL, lt_ticker); - lua_pushinteger(gL, (lt_endtime + TICRATE)); + lua_pushinteger(gL, titlecard.ticker); + lua_pushinteger(gL, titlecard.endtime + TICRATE); break; case HUD_HOOK(intermission): diff --git a/src/m_menu.c b/src/m_menu.c index 9aae59445..bcc639ea8 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -2961,19 +2961,19 @@ static void M_HandleMenuPresState(menu_t *newMenu) ) { if (gamestate == GS_TIMEATTACK) - wipetypepre = ((exitwipe && enterlevel <= exitlevel) || anceslevel < 0) ? exitwipe : -1; // force default + wipetypepre = ((exitwipe && enterlevel <= exitlevel) || anceslevel < 0) ? exitwipe : DEFAULTWIPE; // force default else // HACK: INT16_MAX signals to not wipe // because 0 is a valid index and -1 means default - wipetypepre = ((exitwipe && enterlevel <= exitlevel) || anceslevel < 0) ? exitwipe : INT16_MAX; - wipetypepost = ((enterwipe && enterlevel >= exitlevel) || anceslevel < 0) ? enterwipe : INT16_MAX; + wipetypepre = ((exitwipe && enterlevel <= exitlevel) || anceslevel < 0) ? exitwipe : IGNOREWIPE; + wipetypepost = ((enterwipe && enterlevel >= exitlevel) || anceslevel < 0) ? enterwipe : IGNOREWIPE; wipegamestate = FORCEWIPE; // If just one of the above is a force not-wipe, // mirror the other wipe. - if (wipetypepre != INT16_MAX && wipetypepost == INT16_MAX) + if (wipetypepre != IGNOREWIPE && wipetypepost == IGNOREWIPE) wipetypepost = wipetypepre; - else if (wipetypepost != INT16_MAX && wipetypepre == INT16_MAX) + else if (wipetypepost != IGNOREWIPE && wipetypepre == IGNOREWIPE) wipetypepre = wipetypepost; // D_Display runs the next step of processing @@ -3166,7 +3166,10 @@ boolean M_Responder(event_t *ev) if (gamestate == GS_TITLESCREEN && finalecount < (cv_tutorialprompt.value ? TICRATE : 0)) return false; - if (CON_Ready() && gamestate != GS_WAITINGPLAYERS) + if (gamestate == GS_TIMEATTACK && WipeInAction) + return false; + + if (CON_Ready()) return false; if (noFurtherInput) @@ -3565,15 +3568,13 @@ boolean M_Responder(event_t *ev) // void M_Drawer(void) { - boolean wipe = WipeInAction; - if (currentMenu == &MessageDef) menuactive = true; if (menuactive) { // now that's more readable with a faded background (yeah like Quake...) - if (!wipe && (curfadevalue || (gamestate != GS_TITLESCREEN && gamestate != GS_TIMEATTACK))) + if (curfadevalue || (gamestate != GS_TITLESCREEN && gamestate != GS_TIMEATTACK)) V_DrawFadeScreen(0xFF00, (gamestate != GS_TITLESCREEN && gamestate != GS_TIMEATTACK) ? 16 : curfadevalue); if (currentMenu->drawroutine) @@ -3650,7 +3651,7 @@ void M_StartControlPanel(void) } else if (!(netgame || multiplayer)) // Single Player { - if (gamestate != GS_LEVEL || ultimatemode) // intermission, so gray out stuff. + if (gamestate != GS_LEVEL || ultimatemode || G_GetRetryFlag(RETRY_CUR)) // Can't retry if you're already retrying... chief. { SPauseMenu[spause_pandora].status = (M_SecretUnlocked(SECRET_PANDORA, serverGamedata)) ? (IT_GRAYEDOUT) : (IT_DISABLED); SPauseMenu[spause_retry].status = IT_GRAYEDOUT; @@ -3734,7 +3735,7 @@ void M_StartControlPanel(void) void M_EndModeAttackRun(void) { - G_ClearModeAttackRetryFlag(); + G_ClearRetryRA(); M_ModeAttackEndGame(0); } @@ -7000,7 +7001,7 @@ static void M_RetryResponse(INT32 ch) return; M_ClearMenus(true); - G_SetRetryFlag(); + G_SetRetrySP(); } static void M_Retry(INT32 choice) @@ -9321,7 +9322,6 @@ static void M_HandleChoosePlayerMenu(INT32 choice) case KEY_ENTER: S_StartSound(NULL, sfx_menu1); char_scroll = 0; // finish scrolling the menu - M_DrawSetupChoosePlayerMenu(); // draw the finally selected character one last time for the fadeout // Is this a hack? charseltimer = 0; M_ChoosePlayer(char_on); @@ -10649,7 +10649,7 @@ static void M_SetGuestReplay(INT32 choice) void M_ModeAttackRetry(INT32 choice) { (void)choice; - // todo -- maybe seperate this out and G_SetRetryFlag() here instead? is just calling this from the menu 100% safe? + // todo -- maybe seperate this out and G_SetRetrySP() here instead? is just calling this from the menu 100% safe? G_CheckDemoStatus(); // Cancel recording if (modeattacking == ATTACKING_RECORD) M_ChooseTimeAttack(0); diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c index d222920c3..27142321b 100644 --- a/src/netcode/d_clisrv.c +++ b/src/netcode/d_clisrv.c @@ -1239,7 +1239,7 @@ boolean TryRunTics(tic_t realtics) if (update_stats) PS_START_TIMING(ps_tictime); - G_Ticker((gametic % NEWTICRATERATIO) == 0); + G_Ticker((gametic % NEWTICRATERATIO) == 0, (neededtic - gametic)); ExtraDataTicker(); gametic++; consistancy[gametic%BACKUPTICS] = Consistancy(); diff --git a/src/netcode/d_netcmd.c b/src/netcode/d_netcmd.c index ef1ef9aeb..3f967630d 100644 --- a/src/netcode/d_netcmd.c +++ b/src/netcode/d_netcmd.c @@ -2086,16 +2086,6 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) LUA_HookInt(mapnumber, HOOK(MapChange)); G_InitNew(ultimatemode, mapname, resetplayer, skipprecutscene, FLS); - if (demoplayback && !timingdemo) - precache = true; - if (timingdemo) - G_DoneLevelLoad(); - - if (metalrecording) - G_BeginMetal(); - if (demorecording) // Okay, level loaded, character spawned and skinned, - G_BeginRecording(); // I AM NOW READY TO RECORD. - demo_start = true; } static void Command_Pause(void) @@ -4599,7 +4589,7 @@ void Command_Retry_f(void) else { M_ClearMenus(true); - G_SetRetryFlag(); + G_SetRetrySP(); } } diff --git a/src/p_saveg.c b/src/p_saveg.c index 8c74ebef4..091b13293 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -15,6 +15,7 @@ #include "byteptr.h" #include "d_main.h" #include "doomstat.h" +#include "f_finale.h" #include "g_game.h" #include "m_random.h" #include "m_misc.h" @@ -4530,12 +4531,23 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) tokenlist = READUINT32(save_p); + levelstarting = false; + if (!P_LoadLevel(true, reloading)) { CONS_Alert(CONS_ERROR, M_GetText("Can't load the level!\n")); return false; } + G_StartLevelWipe(); + wipestyleflags &= ~WSF_ACTION; + F_StopWipe(); + + WipeRunPost = false; + wipetypepre = wipetypepost = IGNOREWIPE; + + titlecard.prelevel = false; + // get the time leveltime = READUINT32(save_p); ssspheres = READUINT32(save_p); diff --git a/src/p_setup.c b/src/p_setup.c index 6f5ec17dc..aacb78b1f 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -7221,7 +7221,7 @@ void P_RespawnThings(void) skyboxmo[1] = skyboxcenterpnts[(centerid >= 0) ? centerid : 0]; } -static void P_RunLevelScript(const char *scriptname) +void P_RunLevelScript(const char *scriptname) { if (!(mapheaderinfo[gamemap-1]->levelflags & LF_SCRIPTISFILE)) { @@ -7533,12 +7533,8 @@ static void P_InitCamera(void) } } -static void P_RunSpecialStageWipe(void) +void P_RunSpecialStageWipe(void) { - tic_t starttime = I_GetTime(); - tic_t endtime = starttime + (3*TICRATE)/2; - tic_t nowtime; - S_StartSound(NULL, sfx_s3kaf); // Fade music! Time it to S3KAF: 0.25 seconds is snappy. @@ -7548,7 +7544,7 @@ static void P_RunSpecialStageWipe(void) S_FadeOutStopMusic(MUSICRATE/4); //FixedMul(FixedDiv(F_GetWipeLength(wipedefs[wipe_speclevel_towhite])*NEWTICRATERATIO, NEWTICRATE), MUSICRATE) F_WipeStartScreen(); - wipestyleflags |= (WSF_FADEOUT|WSF_TOWHITE); + wipestyleflags |= WSF_TOWHITE|WSF_SPECIALSTAGE; #ifdef HWRENDER // uh.......... @@ -7557,35 +7553,12 @@ static void P_RunSpecialStageWipe(void) #endif F_WipeEndScreen(); - F_RunWipe(wipedefs[wipe_speclevel_towhite], false); - - I_OsPolling(); - I_FinishUpdate(); // page flip or blit buffer - if (moviemode) - M_SaveFrame(); - - nowtime = lastwipetic; - - // 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(); - NetKeepAlive(); // Prevent timeout - } + F_StartWipe(wipedefs[wipe_speclevel_towhite], false); } -static void P_RunLevelWipe(void) +void P_RunLevelWipe(void) { F_WipeStartScreen(); - wipestyleflags |= WSF_FADEOUT; #ifdef HWRENDER // uh.......... @@ -7594,13 +7567,15 @@ static void P_RunLevelWipe(void) #endif F_WipeEndScreen(); + // for titlemap: run a specific wipe if specified // needed for exiting time attack - if (wipetypepre != INT16_MAX) - F_RunWipe( - (wipetypepre >= 0 && F_WipeExists(wipetypepre)) ? wipetypepre : wipedefs[wipe_level_toblack], - false); - wipetypepre = -1; + if (wipetypepre != IGNOREWIPE) + F_StartWipe( + (wipetypepre != DEFAULTWIPE && F_WipeExists(wipetypepre)) ? wipetypepre : wipedefs[wipe_level_toblack], + true); + + wipetypepre = DEFAULTWIPE; } static void P_InitPlayers(void) @@ -7716,16 +7691,12 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) // use gamemap to get map number. // 99% of the things already did, so. // Map header should always be in place at this point - INT32 i, ranspecialwipe = 0; + INT32 i; sector_t *ss; levelloading = true; - // This is needed. Don't touch. - maptol = mapheaderinfo[gamemap-1]->typeoflevel; - gametyperules = gametypedefaultrules[gametype]; - - CON_Drawer(); // let the user know what we are going to do - I_FinishUpdate(); // page flip or blit buffer + if (fromnetsave) + G_InitLevelGametype(); // Reset the palette if (rendermode != render_none) @@ -7743,12 +7714,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) // Clear CECHO messages HU_ClearCEcho(); - if (mapheaderinfo[gamemap-1]->runsoc[0] != '#') - P_RunSOC(mapheaderinfo[gamemap-1]->runsoc); - - if (cv_runscripts.value && mapheaderinfo[gamemap-1]->scriptname[0] != '#') - P_RunLevelScript(mapheaderinfo[gamemap-1]->scriptname); - P_InitLevelSettings(); postimgtype = postimgtype2 = postimg_none; @@ -7780,52 +7745,13 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) // will be set by player think. players[consoleplayer].viewz = 1; - // Cancel all d_main.c fadeouts (keep fade in though). - if (reloadinggamestate) - wipegamestate = gamestate; // Don't fade if reloading the gamestate - else - wipegamestate = FORCEWIPEOFF; - wipestyleflags = 0; - - // Special stage & record attack retry fade to white - // This is handled BEFORE sounds are stopped. - if (G_GetModeAttackRetryFlag()) - { - if (modeattacking && !demoplayback) - { - ranspecialwipe = 2; - wipestyleflags |= (WSF_FADEOUT|WSF_TOWHITE); - } - G_ClearModeAttackRetryFlag(); - } - else if (rendermode != render_none && G_IsSpecialStage(gamemap)) - { - P_RunSpecialStageWipe(); - ranspecialwipe = 1; - } - // Make sure all sounds are stopped before Z_FreeTags. S_StopSounds(); S_ClearSfx(); - // Fade out music here. Deduct 2 tics so the fade volume actually reaches 0. - // But don't halt the music! S_Start will take care of that. This dodges a MIDI crash bug. - if (!(reloadinggamestate || titlemapinaction) && (RESETMUSIC || - strnicmp(S_MusicName(), - (mapmusflags & MUSIC_RELOADRESET) ? mapheaderinfo[gamemap-1]->musname : mapmusname, 7))) - { - S_FadeMusic(0, FixedMul( - FixedDiv((F_GetWipeLength(wipedefs[wipe_level_toblack])-2)*NEWTICRATERATIO, NEWTICRATE), MUSICRATE)); - } - - // Let's fade to black here - // But only if we didn't do the special stage wipe - if (rendermode != render_none && !(ranspecialwipe || reloadinggamestate)) - P_RunLevelWipe(); - if (!(reloadinggamestate || titlemapinaction)) { - if (ranspecialwipe == 2) + if (ranspecialwipe == SPECIALWIPE_RETRY) { pausedelay = -3; // preticker plus one S_StartSound(NULL, sfx_s3k73); @@ -7844,11 +7770,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) V_DrawSmallString(1, 195, V_ALLOWLOWERCASE|V_TRANSLUCENT|V_SNAPTOLEFT|V_SNAPTOBOTTOM, tx); I_UpdateNoVsync(); } - - // As oddly named as this is, this handles music only. - // We should be fine starting it here. - // Don't do this during titlemap, because the menu code handles music by itself. - S_Start(); } levelfadecol = (ranspecialwipe) ? 0 : 31; @@ -7973,6 +7894,14 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) levelloading = false; + if (!(reloadinggamestate || titlemapinaction)) + { + // As oddly named as this is, this handles music only. + // We should be fine starting it here. + // Don't do this during titlemap, because the menu code handles music by itself. + S_Start(); + } + P_RunCachedActions(); P_MapEnd(); // tmthing is no longer needed from this point onwards @@ -8015,18 +7944,27 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) R_ResetViewInterpolation(0); R_UpdateMobjInterpolators(); - // Title card! - G_StartTitleCard(); + titlecard.running = false; + titlecard.prelevel = false; + titlecard.wipe = 0; - // Can the title card actually run, though? - if (!WipeStageTitle) - return true; - if (ranspecialwipe == 2) - return true; + if (ranspecialwipe == SPECIALWIPE_RETRY) + { + // Force a wipe + wipegamestate = -1; + wipestyleflags = (WSF_TOWHITE|WSF_FADEIN); + WipeRunPost = true; - // If so... - G_PreLevelTitleCard(); + // Reset the HUD translucency! + st_translucency = cv_translucenthud.value; + } + else + { + // Start the title card. + TitleCard_Start(); + } + ranspecialwipe = SPECIALWIPE_NONE; return true; } diff --git a/src/p_setup.h b/src/p_setup.h index c6f4f741c..4e9c04c88 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -93,15 +93,23 @@ INT32 P_CheckLevelFlat(const char *flatname); extern size_t nummapthings; extern mapthing_t *mapthings; -void P_SetupLevelSky(INT32 skynum, boolean global); #ifdef SCANTHINGS void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum); #endif void P_RespawnThings(void); + boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate); +void P_SetupLevelSky(INT32 skynum, boolean global); + #ifdef HWRENDER void HWR_LoadLevel(void); #endif + +void P_RunLevelWipe(void); +void P_RunSpecialStageWipe(void); + +void P_RunLevelScript(const char *scriptname); + boolean P_AddWadFile(const char *wadfilename); boolean P_AddFolder(const char *folderpath); boolean P_RunSOC(const char *socfilename); diff --git a/src/screen.c b/src/screen.c index ca59b251d..4b2c52c8c 100644 --- a/src/screen.c +++ b/src/screen.c @@ -585,7 +585,7 @@ void SCR_DisplayMarathonInfo(void) if (gamecomplete) flags |= V_YELLOWMAP; else if (marathonmode & MA_INGAME) - ; // see also G_Ticker + ; // see also G_MarathonTicker else if (marathonmode & MA_INIT) marathonmode &= ~MA_INIT; else diff --git a/src/st_stuff.c b/src/st_stuff.c index a97537978..2a73b9b35 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -207,11 +207,9 @@ static boolean st_stopped = true; void ST_Ticker(boolean run) { + (void)run; if (st_stopped) return; - - if (run) - ST_runTitleCard(); } // 0 is default, any others are special palettes. @@ -1246,145 +1244,45 @@ static void ST_drawInput(void) V_DrawThinString(x, y, hudinfo[HUD_LIVES].f|((leveltime & 4) ? V_YELLOWMAP : V_REDMAP), "BAD DEMO!!"); } -static patch_t *lt_patches[3]; -static INT32 lt_scroll = 0; -static INT32 lt_mom = 0; -static INT32 lt_zigzag = 0; - -tic_t lt_ticker = 0, lt_lasttic = 0; -tic_t lt_exitticker = 0, lt_endtime = 0; - -// -// Load the graphics for the title card. -// Don't let LJ see this -// -static void ST_cacheLevelTitle(void) -{ -#define SETPATCH(default, warning, custom, idx) \ -{ \ - lumpnum_t patlumpnum = LUMPERROR; \ - if (mapheaderinfo[gamemap-1]->custom[0] != '\0') \ - { \ - patlumpnum = W_CheckNumForName(mapheaderinfo[gamemap-1]->custom); \ - if (patlumpnum != LUMPERROR) \ - lt_patches[idx] = (patch_t *)W_CachePatchNum(patlumpnum, PU_HUDGFX); \ - } \ - if (patlumpnum == LUMPERROR) \ - { \ - if (!(mapheaderinfo[gamemap-1]->levelflags & LF_WARNINGTITLE)) \ - lt_patches[idx] = (patch_t *)W_CachePatchName(default, PU_HUDGFX); \ - else \ - lt_patches[idx] = (patch_t *)W_CachePatchName(warning, PU_HUDGFX); \ - } \ -} - - SETPATCH("LTACTBLU", "LTACTRED", ltactdiamond, 0) - SETPATCH("LTZIGZAG", "LTZIGRED", ltzzpatch, 1) - SETPATCH("LTZZTEXT", "LTZZWARN", ltzztext, 2) - -#undef SETPATCH -} - -// -// Start the title card. -// -void ST_startTitleCard(void) -{ - // cache every HUD patch used - ST_cacheLevelTitle(); - - // initialize HUD variables - lt_ticker = lt_exitticker = lt_lasttic = 0; - lt_endtime = 2*TICRATE + (10*NEWTICRATERATIO); - lt_scroll = BASEVIDWIDTH * FRACUNIT; - lt_zigzag = -((lt_patches[1])->width * FRACUNIT); - lt_mom = 0; -} - // // What happens before drawing the title card. // Which is just setting the HUD translucency. // -void ST_preDrawTitleCard(void) +void TitleCard_PreDraw(void) { - if (!G_IsTitleCardAvailable()) + if (!TitleCard_Available() || !titlecard.running) return; - if (lt_ticker >= (lt_endtime + TICRATE)) + if (titlecard.ticker >= (titlecard.endtime + TICRATE)) return; - if (!lt_exitticker) + if (!titlecard.exitticker) st_translucency = 0; else - st_translucency = max(0, min((INT32)lt_exitticker-4, cv_translucenthud.value)); -} - -// -// Run the title card. -// Called from ST_Ticker. -// -void ST_runTitleCard(void) -{ - boolean run = !(paused || P_AutoPause()); - - if (!G_IsTitleCardAvailable()) - return; - - if (lt_ticker >= (lt_endtime + TICRATE)) - return; - - if (run || (lt_ticker < PRELEVELTIME)) - { - // tick - lt_ticker++; - if (lt_ticker >= lt_endtime) - lt_exitticker++; - - // scroll to screen (level title) - if (!lt_exitticker) - { - if (abs(lt_scroll) > FRACUNIT) - lt_scroll -= (lt_scroll>>2); - else - lt_scroll = 0; - } - // scroll away from screen (level title) - else - { - lt_mom -= FRACUNIT*6; - lt_scroll += lt_mom; - } - - // scroll to screen (zigzag) - if (!lt_exitticker) - { - if (abs(lt_zigzag) > FRACUNIT) - lt_zigzag -= (lt_zigzag>>2); - else - lt_zigzag = 0; - } - // scroll away from screen (zigzag) - else - lt_zigzag += lt_mom; - } + st_translucency = max(0, min((INT32)titlecard.exitticker-4, cv_translucenthud.value)); } // // Draw the title card itself. // -void ST_drawTitleCard(void) +void TitleCard_Draw(void) { char *lvlttl = mapheaderinfo[gamemap-1]->lvlttl; char *subttl = mapheaderinfo[gamemap-1]->subttl; UINT8 actnum = mapheaderinfo[gamemap-1]->actnum; INT32 lvlttlxpos, ttlnumxpos, zonexpos; INT32 subttlxpos = BASEVIDWIDTH/2; - INT32 ttlscroll = FixedInt(lt_scroll); - INT32 zzticker; + INT32 ttlscroll = FixedInt(titlecard.scroll); patch_t *actpat, *zigzag, *zztext; UINT8 colornum; const UINT8 *colormap; + if (!TitleCard_Available()) + return; + + if (!titlecard.running) + return; + if (players[consoleplayer].skincolor) colornum = players[consoleplayer].skincolor; else @@ -1392,22 +1290,17 @@ void ST_drawTitleCard(void) colormap = R_GetTranslationColormap(TC_DEFAULT, colornum, GTC_CACHE); - if (!G_IsTitleCardAvailable()) - return; + if (titlecard.prelevel) + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol); - if (!LUA_HudEnabled(hud_stagetitle)) + if (!LUA_HudEnabled(hud_stagetitle) || titlecard.ticker >= (titlecard.endtime + TICRATE)) + { goto luahook; + } - if (lt_ticker >= (lt_endtime + TICRATE)) - goto luahook; - - if ((lt_ticker-lt_lasttic) > 1) - lt_ticker = lt_lasttic+1; - - ST_cacheLevelTitle(); - actpat = lt_patches[0]; - zigzag = lt_patches[1]; - zztext = lt_patches[2]; + actpat = titlecard.patches[0]; + zigzag = titlecard.patches[1]; + zztext = titlecard.patches[2]; lvlttlxpos = ((BASEVIDWIDTH/2) - (V_LevelNameWidth(lvlttl)/2)); @@ -1423,11 +1316,11 @@ void ST_drawTitleCard(void) if (!splitscreen || (splitscreen && stplyr == &players[displayplayer])) { - zzticker = lt_ticker; - V_DrawMappedPatch(FixedInt(lt_zigzag), (-zzticker) % zigzag->height, V_SNAPTOTOP|V_SNAPTOLEFT, zigzag, colormap); - V_DrawMappedPatch(FixedInt(lt_zigzag), (zigzag->height-zzticker) % zigzag->height, V_SNAPTOTOP|V_SNAPTOLEFT, zigzag, colormap); - V_DrawMappedPatch(FixedInt(lt_zigzag), (-zztext->height+zzticker) % zztext->height, V_SNAPTOTOP|V_SNAPTOLEFT, zztext, colormap); - V_DrawMappedPatch(FixedInt(lt_zigzag), (zzticker) % zztext->height, V_SNAPTOTOP|V_SNAPTOLEFT, zztext, colormap); + INT32 zzticker = titlecard.ticker; + V_DrawMappedPatch(FixedInt(titlecard.zigzag), (-zzticker) % zigzag->height, V_SNAPTOTOP|V_SNAPTOLEFT, zigzag, colormap); + V_DrawMappedPatch(FixedInt(titlecard.zigzag), (zigzag->height-zzticker) % zigzag->height, V_SNAPTOTOP|V_SNAPTOLEFT, zigzag, colormap); + V_DrawMappedPatch(FixedInt(titlecard.zigzag), (-zztext->height+zzticker) % zztext->height, V_SNAPTOTOP|V_SNAPTOLEFT, zztext, colormap); + V_DrawMappedPatch(FixedInt(titlecard.zigzag), (zzticker) % zztext->height, V_SNAPTOTOP|V_SNAPTOLEFT, zztext, colormap); } if (actnum) @@ -1447,8 +1340,6 @@ void ST_drawTitleCard(void) V_DrawLevelTitle(zonexpos + ttlscroll, 104, V_PERPLAYER, M_GetText("Zone")); V_DrawCenteredString(subttlxpos - ttlscroll, 135, V_PERPLAYER|V_ALLOWLOWERCASE, subttl); - lt_lasttic = lt_ticker; - luahook: //if (renderisnewtic) { @@ -1459,30 +1350,22 @@ luahook: } // -// Drawer for G_PreLevelTitleCard. +// Draws title cards for every player. // -void ST_preLevelTitleCardDrawer(void) +void TitleCard_DrawOverWipe(void) { - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol); - ST_drawWipeTitleCard(); - I_OsPolling(); - I_UpdateNoBlit(); -} + if (!(titlecard.running && titlecard.wipe && st_overlay)) + return; -// -// Draw the title card while on a wipe. -// Also used in G_PreLevelTitleCard. -// -void ST_drawWipeTitleCard(void) -{ stplyr = &players[consoleplayer]; - ST_preDrawTitleCard(); - ST_drawTitleCard(); + TitleCard_PreDraw(); + TitleCard_Draw(); + if (splitscreen) { stplyr = &players[secondarydisplayplayer]; - ST_preDrawTitleCard(); - ST_drawTitleCard(); + TitleCard_PreDraw(); + TitleCard_Draw(); } } @@ -2666,16 +2549,16 @@ static boolean ST_doItemFinderIconsAndSound(void) // static void ST_overlayDrawer(void) { - // Decide whether to draw the stage title or not + // Decides whether to draw the stage title or not. boolean stagetitle = false; // Check for a valid level title // If the HUD is enabled // And, if Lua is running, if the HUD library has the stage title enabled - if (G_IsTitleCardAvailable() && *mapheaderinfo[gamemap-1]->lvlttl != '\0' && !(hu_showscores && (netgame || multiplayer))) + if (TitleCard_Available() && !(hu_showscores && (netgame || multiplayer))) { stagetitle = true; - ST_preDrawTitleCard(); + TitleCard_PreDraw(); } // hu_showscores = auto hide score/time/rings when tab rankings are shown @@ -2817,8 +2700,8 @@ static void ST_overlayDrawer(void) } // draw level title Tails - if (stagetitle && (!WipeInAction) && (!WipeStageTitle)) - ST_drawTitleCard(); + if (stagetitle && !WipeInAction && !titlecard.wipe) + TitleCard_Draw(); if (!hu_showscores && (netgame || multiplayer) && LUA_HudEnabled(hud_textspectator)) ST_drawTextHUD(); @@ -2831,6 +2714,8 @@ static void ST_overlayDrawer(void) void ST_Drawer(void) { + void (*drawfunc)(void) = ST_overlayDrawer; + if (cv_seenames.value && cv_allowseenames.value && displayplayer == consoleplayer && seenplayer && seenplayer->mo) { INT32 c = 0; @@ -2890,16 +2775,18 @@ void ST_Drawer(void) st_translucency = cv_translucenthud.value; - if (st_overlay) - { - // No deadview! - stplyr = &players[displayplayer]; - ST_overlayDrawer(); + if (titlecard.prelevel) + drawfunc = TitleCard_Draw; + else if (!st_overlay) + return; - if (splitscreen) - { - stplyr = &players[secondarydisplayplayer]; - ST_overlayDrawer(); - } + // No deadview! + stplyr = &players[displayplayer]; + drawfunc(); + + if (splitscreen) + { + stplyr = &players[secondarydisplayplayer]; + drawfunc(); } } diff --git a/src/st_stuff.h b/src/st_stuff.h index 603be3c30..28c67d37c 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -47,16 +47,10 @@ void ST_ReloadSkinFaceGraphics(void); void ST_doPaletteStuff(void); -// title card -void ST_startTitleCard(void); -void ST_runTitleCard(void); -void ST_drawTitleCard(void); -void ST_preDrawTitleCard(void); -void ST_preLevelTitleCardDrawer(void); -void ST_drawWipeTitleCard(void); - -extern tic_t lt_ticker, lt_lasttic; -extern tic_t lt_exitticker, lt_endtime; +// Title card +void TitleCard_Draw(void); +void TitleCard_PreDraw(void); +void TitleCard_DrawOverWipe(void); // return if player a is in the same team as player b boolean ST_SameTeam(player_t *a, player_t *b); diff --git a/src/v_video.c b/src/v_video.c index 30aef92cc..ea0ec2fe3 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -3349,7 +3349,7 @@ INT32 V_LevelNameHeight(const char *string) return w; } -// For ST_drawTitleCard +// For TitleCard_Draw // Returns the width of the act num patch(es) INT16 V_LevelActNumWidth(UINT8 num) {