2016-03-01 15:47:10 +00:00
//-----------------------------------------------------------------------------
//
2017-04-17 11:33:19 +00:00
// Copyright 1993-1996 id Software
// Copyright 1999-2016 Randy Heit
// Copyright 2002-2016 Christoph Oelckers
2016-03-01 15:47:10 +00:00
//
2017-04-17 11:33:19 +00:00
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
2016-03-01 15:47:10 +00:00
//
2017-04-17 11:33:19 +00:00
// This program is distributed in the hope that it will be useful,
2016-03-01 15:47:10 +00:00
// but WITHOUT ANY WARRANTY; without even the implied warranty of
2017-04-17 11:33:19 +00:00
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
2016-03-01 15:47:10 +00:00
//
//
// DESCRIPTION:
// DOOM main program (D_DoomMain) and game loop (D_DoomLoop),
// plus functions to determine game mode (shareware, registered),
// parse command line parameters, configure game parameters (turbo),
// and call the startup functions.
//
//-----------------------------------------------------------------------------
// HEADER FILES ------------------------------------------------------------
2018-06-18 11:39:23 +00:00
# ifdef _WIN32
# include <direct.h>
# endif
2016-03-01 15:47:10 +00:00
# ifdef HAVE_FPU_CONTROL
# include <fpu_control.h>
# endif
# if defined(__unix__) || defined(__APPLE__)
# include <unistd.h>
# endif
# include <math.h>
# include <assert.h>
# include "doomerrors.h"
2017-11-12 08:06:40 +00:00
# include "i_time.h"
2016-03-01 15:47:10 +00:00
# include "d_gui.h"
# include "m_random.h"
# include "doomdef.h"
# include "doomstat.h"
# include "gstrings.h"
# include "w_wad.h"
# include "s_sound.h"
# include "v_video.h"
# include "intermission/intermission.h"
# include "f_wipe.h"
# include "m_argv.h"
# include "m_misc.h"
# include "menu/menu.h"
# include "c_console.h"
# include "c_dispatch.h"
# include "i_sound.h"
# include "i_video.h"
# include "g_game.h"
# include "hu_stuff.h"
# include "wi_stuff.h"
# include "st_stuff.h"
# include "am_map.h"
# include "p_setup.h"
# include "r_utility.h"
# include "r_sky.h"
# include "d_main.h"
# include "d_dehacked.h"
# include "cmdlib.h"
# include "v_text.h"
# include "gi.h"
2018-05-03 19:27:45 +00:00
# include "a_dynlight.h"
2016-03-01 15:47:10 +00:00
# include "gameconfigfile.h"
# include "sbar.h"
# include "decallib.h"
# include "version.h"
# include "st_start.h"
# include "teaminfo.h"
# include "hardware.h"
# include "sbarinfo.h"
# include "d_net.h"
# include "d_event.h"
# include "d_netinf.h"
# include "m_cheat.h"
# include "m_joy.h"
# include "po_man.h"
# include "p_local.h"
# include "autosegs.h"
# include "fragglescript/t_fs.h"
2017-01-08 17:45:30 +00:00
# include "g_levellocals.h"
2017-01-22 00:33:53 +00:00
# include "events.h"
2017-04-12 23:12:04 +00:00
# include "vm.h"
# include "types.h"
2019-01-31 18:38:04 +00:00
# include "i_system.h"
2019-01-31 01:05:16 +00:00
# include "g_cvars.h"
2017-06-04 00:00:53 +00:00
# include "r_data/r_vanillatrans.h"
2019-08-23 15:15:19 +00:00
# include "s_music.h"
2019-10-07 18:28:55 +00:00
# include "swrenderer/r_swcolormaps.h"
2016-03-01 15:47:10 +00:00
EXTERN_CVAR ( Bool , hud_althud )
2018-06-24 07:32:46 +00:00
EXTERN_CVAR ( Int , vr_mode )
2016-03-01 15:47:10 +00:00
void DrawHUD ( ) ;
2018-02-13 22:06:59 +00:00
void D_DoAnonStats ( ) ;
2019-10-01 13:24:17 +00:00
void I_DetectOS ( ) ;
2018-02-13 22:06:59 +00:00
2016-03-01 15:47:10 +00:00
// MACROS ------------------------------------------------------------------
// TYPES -------------------------------------------------------------------
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
2017-10-31 23:47:56 +00:00
extern void I_SetWindowTitle ( const char * caption ) ;
2016-03-01 15:47:10 +00:00
extern void ReadStatistics ( ) ;
extern void M_SetDefaultMode ( ) ;
extern void G_NewInit ( ) ;
extern void SetupPlayerClasses ( ) ;
2017-04-18 14:54:06 +00:00
void DeinitMenus ( ) ;
2019-10-07 18:28:55 +00:00
void CloseNetwork ( ) ;
void P_Shutdown ( ) ;
void M_SaveDefaultsFinal ( ) ;
void R_Shutdown ( ) ;
void I_ShutdownInput ( ) ;
2016-03-01 15:47:10 +00:00
const FIWADInfo * D_FindIWAD ( TArray < FString > & wadfiles , const char * iwad , const char * basewad ) ;
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
2019-10-06 22:55:14 +00:00
bool D_CheckNetGame ( ) ;
2016-03-01 15:47:10 +00:00
void D_ProcessEvents ( ) ;
void G_BuildTiccmd ( ticcmd_t * cmd ) ;
void D_DoAdvanceDemo ( ) ;
void D_AddWildFile ( TArray < FString > & wadfiles , const char * pattern ) ;
void D_LoadWadSettings ( ) ;
2017-03-12 15:56:00 +00:00
void ParseGLDefs ( ) ;
2019-05-19 08:28:07 +00:00
void DrawFullscreenSubtitle ( const char * text ) ;
2019-09-30 22:30:44 +00:00
void D_Cleanup ( ) ;
2019-10-07 18:28:55 +00:00
void FreeSBarInfoScript ( ) ;
2016-03-01 15:47:10 +00:00
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
void D_DoomLoop ( ) ;
2017-05-13 10:33:14 +00:00
const char * BaseFileSearch ( const char * file , const char * ext , bool lookfirstinprogdir = false ) ;
2016-03-01 15:47:10 +00:00
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
EXTERN_CVAR ( Float , turbo )
EXTERN_CVAR ( Bool , freelook )
EXTERN_CVAR ( Float , m_pitch )
EXTERN_CVAR ( Float , m_yaw )
EXTERN_CVAR ( Bool , invertmouse )
EXTERN_CVAR ( Bool , lookstrafe )
EXTERN_CVAR ( Int , screenblocks )
EXTERN_CVAR ( Bool , sv_cheats )
EXTERN_CVAR ( Bool , sv_unlimited_pickup )
2017-10-31 23:47:56 +00:00
EXTERN_CVAR ( Bool , I_FriendlyWindowTitle )
2019-11-03 08:51:22 +00:00
EXTERN_CVAR ( Bool , r_drawplayersprites )
EXTERN_CVAR ( Bool , show_messages )
2016-03-01 15:47:10 +00:00
extern bool setmodeneeded ;
extern bool gameisdead ;
extern bool demorecording ;
extern bool M_DemoNoPlay ; // [RH] if true, then skip any demos in the loop
extern bool insave ;
2018-04-02 10:28:20 +00:00
extern TDeletingArray < FLightDefaults * > LightDefaults ;
2016-03-01 15:47:10 +00:00
// PUBLIC DATA DEFINITIONS -------------------------------------------------
CUSTOM_CVAR ( Int , fraglimit , 0 , CVAR_SERVERINFO )
{
// Check for the fraglimit being hit because the fraglimit is being
// lowered below somebody's current frag count.
if ( deathmatch & & self > 0 )
{
for ( int i = 0 ; i < MAXPLAYERS ; + + i )
{
if ( playeringame [ i ] & & self < = D_GetFragCount ( & players [ i ] ) )
{
Printf ( " %s \n " , GStrings ( " TXT_FRAGLIMIT " ) ) ;
2019-02-01 23:24:43 +00:00
primaryLevel - > ExitLevel ( 0 , false ) ;
2016-03-01 15:47:10 +00:00
break ;
}
}
}
}
CVAR ( Float , timelimit , 0.f , CVAR_SERVERINFO ) ;
CVAR ( Int , wipetype , 1 , CVAR_ARCHIVE ) ;
CVAR ( Int , snd_drawoutput , 0 , 0 ) ;
CUSTOM_CVAR ( String , vid_cursor , " None " , CVAR_ARCHIVE | CVAR_NOINITCALL )
{
bool res = false ;
2018-12-07 01:43:27 +00:00
2016-03-01 15:47:10 +00:00
if ( ! stricmp ( self , " None " ) & & gameinfo . CursorPic . IsNotEmpty ( ) )
{
2018-12-07 01:43:27 +00:00
res = I_SetCursor ( TexMan . GetTextureByName ( gameinfo . CursorPic ) ) ;
2016-03-01 15:47:10 +00:00
}
else
{
2018-12-07 01:43:27 +00:00
res = I_SetCursor ( TexMan . GetTextureByName ( self ) ) ;
2016-03-01 15:47:10 +00:00
}
if ( ! res )
{
2018-12-07 01:43:27 +00:00
I_SetCursor ( TexMan . GetTextureByName ( " cursor " ) ) ;
2016-03-01 15:47:10 +00:00
}
}
2016-12-21 10:11:29 +00:00
// Controlled by startup dialog
CVAR ( Bool , disableautoload , false , CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG )
CVAR ( Bool , autoloadbrightmaps , false , CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG )
CVAR ( Bool , autoloadlights , false , CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG )
2017-07-29 20:26:16 +00:00
CVAR ( Bool , r_debug_disable_vis_filter , false , 0 )
2016-12-21 04:03:06 +00:00
2019-11-03 08:51:22 +00:00
bool hud_toggled = false ;
2016-03-08 12:07:21 +00:00
bool wantToRestart ;
2016-03-01 15:47:10 +00:00
bool DrawFSHUD ; // [RH] Draw fullscreen HUD?
TArray < FString > allwads ;
bool devparm ; // started game with -devparm
const char * D_DrawIcon ; // [RH] Patch name of icon to draw on next refresh
int NoWipe ; // [RH] Allow wipe? (Needs to be set each time)
bool singletics = false ; // debug flag to cancel adaptiveness
FString startmap ;
bool autostart ;
FString StoredWarp ;
bool advancedemo ;
FILE * debugfile ;
FILE * hashfile ;
event_t events [ MAXEVENTS ] ;
int eventhead ;
int eventtail ;
gamestate_t wipegamestate = GS_DEMOSCREEN ; // can be -1 to force a wipe
bool PageBlank ;
FTexture * Advisory ;
2018-07-15 20:51:25 +00:00
FTextureID Page ;
2019-05-19 08:28:07 +00:00
const char * Subtitle ;
2016-03-01 15:47:10 +00:00
bool nospriterename ;
FStartupInfo DoomStartupInfo ;
FString lastIWAD ;
int restart = 0 ;
bool batchrun ; // just run the startup and collect all error messages in a logfile, then quit without any interaction
2018-05-04 08:24:37 +00:00
bool AppActive = true ;
2016-03-01 15:47:10 +00:00
cycle_t FrameCycles ;
2017-07-29 15:03:40 +00:00
// [SP] Store the capabilities of the renderer in a global variable, to prevent excessive per-frame processing
uint32_t r_renderercaps = 0 ;
2016-03-01 15:47:10 +00:00
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static int demosequence ;
static int pagetic ;
// CODE --------------------------------------------------------------------
2019-11-03 08:51:22 +00:00
//==========================================================================
//
// D_ToggleHud
//
// Turns off 2D drawing temporarily.
//
//==========================================================================
void D_ToggleHud ( )
{
static int saved_screenblocks ;
static bool saved_drawplayersprite , saved_showmessages ;
if ( hud_toggled = ! hud_toggled )
{
saved_screenblocks = screenblocks ;
saved_drawplayersprite = r_drawplayersprites ;
saved_showmessages = show_messages ;
screenblocks = 12 ;
r_drawplayersprites = false ;
show_messages = false ;
C_HideConsole ( ) ;
M_ClearMenus ( ) ;
}
else
{
screenblocks = saved_screenblocks ;
r_drawplayersprites = saved_drawplayersprite ;
show_messages = saved_showmessages ;
}
}
CCMD ( togglehud )
{
D_ToggleHud ( ) ;
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// D_ProcessEvents
//
// Send all the events of the given timestamp down the responder chain.
// Events are asynchronous inputs generally generated by the game user.
// Events can be discarded if no responder claims them
//
//==========================================================================
void D_ProcessEvents ( void )
{
event_t * ev ;
for ( ; eventtail ! = eventhead ; eventtail = ( eventtail + 1 ) & ( MAXEVENTS - 1 ) )
{
ev = & events [ eventtail ] ;
if ( ev - > type = = EV_None )
continue ;
if ( ev - > type = = EV_DeviceChange )
UpdateJoystickMenu ( I_UpdateDeviceList ( ) ) ;
if ( C_Responder ( ev ) )
continue ; // console ate the event
if ( M_Responder ( ev ) )
continue ; // menu ate the event
2017-02-03 10:28:40 +00:00
// check events
2019-02-02 15:43:11 +00:00
if ( ev - > type ! = EV_Mouse & & primaryLevel - > localEventManager - > Responder ( ev ) ) // [ZZ] ZScript ate the event // update 07.03.17: mouse events are handled directly
2017-02-03 10:28:40 +00:00
continue ;
2016-03-01 15:47:10 +00:00
G_Responder ( ev ) ;
}
}
//==========================================================================
//
// D_PostEvent
//
// Called by the I/O functions when input is detected.
//
//==========================================================================
void D_PostEvent ( const event_t * ev )
{
// Do not post duplicate consecutive EV_DeviceChange events.
if ( ev - > type = = EV_DeviceChange & & events [ eventhead ] . type = = EV_DeviceChange )
{
return ;
}
events [ eventhead ] = * ev ;
2019-02-02 15:43:11 +00:00
if ( ev - > type = = EV_Mouse & & menuactive = = MENU_Off & & ConsoleState ! = c_down & & ConsoleState ! = c_falling & & ! primaryLevel - > localEventManager - > Responder ( ev ) & & ! paused )
2016-03-01 15:47:10 +00:00
{
if ( Button_Mlook . bDown | | freelook )
{
int look = int ( ev - > y * m_pitch * mouse_sensitivity * 16.0 ) ;
if ( invertmouse )
look = - look ;
2017-10-11 15:22:22 +00:00
G_AddViewPitch ( look , true ) ;
2016-03-01 15:47:10 +00:00
events [ eventhead ] . y = 0 ;
}
if ( ! Button_Strafe . bDown & & ! lookstrafe )
{
2017-10-11 15:22:22 +00:00
G_AddViewAngle ( int ( ev - > x * m_yaw * mouse_sensitivity * 8.0 ) , true ) ;
2016-03-01 15:47:10 +00:00
events [ eventhead ] . x = 0 ;
}
if ( ( events [ eventhead ] . x | events [ eventhead ] . y ) = = 0 )
{
return ;
}
}
eventhead = ( eventhead + 1 ) & ( MAXEVENTS - 1 ) ;
}
//==========================================================================
//
// D_RemoveNextCharEvent
//
// Removes the next EV_GUI_Char event in the input queue. Used by the menu,
// since it (generally) consumes EV_GUI_KeyDown events and not EV_GUI_Char
// events, and it needs to ensure that there is no left over input when it's
// done. If there are multiple EV_GUI_KeyDowns before the EV_GUI_Char, then
// there are dead chars involved, so those should be removed, too. We do
// this by changing the message type to EV_None rather than by actually
// removing the event from the queue.
//
//==========================================================================
void D_RemoveNextCharEvent ( )
{
assert ( events [ eventtail ] . type = = EV_GUI_Event & & events [ eventtail ] . subtype = = EV_GUI_KeyDown ) ;
for ( int evnum = eventtail ; evnum ! = eventhead ; evnum = ( evnum + 1 ) & ( MAXEVENTS - 1 ) )
{
event_t * ev = & events [ evnum ] ;
if ( ev - > type ! = EV_GUI_Event )
break ;
if ( ev - > subtype = = EV_GUI_KeyDown | | ev - > subtype = = EV_GUI_Char )
{
ev - > type = EV_None ;
if ( ev - > subtype = = EV_GUI_Char )
break ;
}
else
{
break ;
}
}
}
2019-01-29 00:09:02 +00:00
//==========================================================================
//
// Render wrapper.
// This function contains all the needed setup and cleanup for starting a render job.
//
//==========================================================================
void D_Render ( std : : function < void ( ) > action , bool interpolate )
{
for ( auto Level : AllLevels ( ) )
{
// Check for the presence of dynamic lights at the start of the frame once.
if ( ( gl_lights & & vid_rendermode = = 4 ) | | ( r_dynlights & & vid_rendermode ! = 4 ) )
{
2019-02-01 21:02:16 +00:00
Level - > HasDynamicLights = ! ! Level - > lights ;
2019-01-29 00:09:02 +00:00
}
else Level - > HasDynamicLights = false ; // lights are off so effectively we have none.
if ( interpolate ) Level - > interpolator . DoInterpolations ( I_GetTimeFrac ( ) ) ;
P_FindParticleSubsectors ( Level ) ;
PO_LinkToSubsectors ( Level ) ;
}
action ( ) ;
if ( interpolate ) for ( auto Level : AllLevels ( ) )
{
Level - > interpolator . RestoreInterpolations ( ) ;
}
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// CVAR dmflags
//
//==========================================================================
2019-02-24 08:57:46 +00:00
CUSTOM_CVAR ( Int , dmflags , 0 , CVAR_SERVERINFO | CVAR_NOINITCALL )
2016-03-01 15:47:10 +00:00
{
// In case DF_NO_FREELOOK was changed, reinitialize the sky
// map. (If no freelook, then no need to stretch the sky.)
2019-01-29 03:44:44 +00:00
R_InitSkyMap ( ) ;
2016-03-01 15:47:10 +00:00
if ( self & DF_NO_FREELOOK )
{
Net_WriteByte ( DEM_CENTERVIEW ) ;
}
// If nofov is set, force everybody to the arbitrator's FOV.
if ( ( self & DF_NO_FOV ) & & consoleplayer = = Net_Arbitrator )
{
2017-08-31 01:53:37 +00:00
float fov ;
2016-03-01 15:47:10 +00:00
Net_WriteByte ( DEM_FOV ) ;
// If the game is started with DF_NO_FOV set, the arbitrator's
// DesiredFOV will not be set when this callback is run, so
// be sure not to transmit a 0 FOV.
2017-08-31 00:20:25 +00:00
fov = players [ consoleplayer ] . DesiredFOV ;
2016-03-01 15:47:10 +00:00
if ( fov = = 0 )
{
fov = 90 ;
}
2017-08-31 00:20:25 +00:00
Net_WriteFloat ( fov ) ;
2016-03-01 15:47:10 +00:00
}
}
CVAR ( Flag , sv_nohealth , dmflags , DF_NO_HEALTH ) ;
CVAR ( Flag , sv_noitems , dmflags , DF_NO_ITEMS ) ;
CVAR ( Flag , sv_weaponstay , dmflags , DF_WEAPONS_STAY ) ;
CVAR ( Flag , sv_falldamage , dmflags , DF_FORCE_FALLINGHX ) ;
CVAR ( Flag , sv_oldfalldamage , dmflags , DF_FORCE_FALLINGZD ) ;
CVAR ( Flag , sv_samelevel , dmflags , DF_SAME_LEVEL ) ;
CVAR ( Flag , sv_spawnfarthest , dmflags , DF_SPAWN_FARTHEST ) ;
CVAR ( Flag , sv_forcerespawn , dmflags , DF_FORCE_RESPAWN ) ;
CVAR ( Flag , sv_noarmor , dmflags , DF_NO_ARMOR ) ;
CVAR ( Flag , sv_noexit , dmflags , DF_NO_EXIT ) ;
CVAR ( Flag , sv_infiniteammo , dmflags , DF_INFINITE_AMMO ) ;
CVAR ( Flag , sv_nomonsters , dmflags , DF_NO_MONSTERS ) ;
CVAR ( Flag , sv_monsterrespawn , dmflags , DF_MONSTERS_RESPAWN ) ;
CVAR ( Flag , sv_itemrespawn , dmflags , DF_ITEMS_RESPAWN ) ;
CVAR ( Flag , sv_fastmonsters , dmflags , DF_FAST_MONSTERS ) ;
CVAR ( Flag , sv_nojump , dmflags , DF_NO_JUMP ) ;
CVAR ( Flag , sv_allowjump , dmflags , DF_YES_JUMP ) ;
CVAR ( Flag , sv_nofreelook , dmflags , DF_NO_FREELOOK ) ;
CVAR ( Flag , sv_allowfreelook , dmflags , DF_YES_FREELOOK ) ;
CVAR ( Flag , sv_nofov , dmflags , DF_NO_FOV ) ;
CVAR ( Flag , sv_noweaponspawn , dmflags , DF_NO_COOP_WEAPON_SPAWN ) ;
CVAR ( Flag , sv_nocrouch , dmflags , DF_NO_CROUCH ) ;
CVAR ( Flag , sv_allowcrouch , dmflags , DF_YES_CROUCH ) ;
CVAR ( Flag , sv_cooploseinventory , dmflags , DF_COOP_LOSE_INVENTORY ) ;
CVAR ( Flag , sv_cooplosekeys , dmflags , DF_COOP_LOSE_KEYS ) ;
CVAR ( Flag , sv_cooploseweapons , dmflags , DF_COOP_LOSE_WEAPONS ) ;
CVAR ( Flag , sv_cooplosearmor , dmflags , DF_COOP_LOSE_ARMOR ) ;
CVAR ( Flag , sv_cooplosepowerups , dmflags , DF_COOP_LOSE_POWERUPS ) ;
CVAR ( Flag , sv_cooploseammo , dmflags , DF_COOP_LOSE_AMMO ) ;
CVAR ( Flag , sv_coophalveammo , dmflags , DF_COOP_HALVE_AMMO ) ;
// Some (hopefully cleaner) interface to these settings.
CVAR ( Mask , sv_crouch , dmflags , DF_NO_CROUCH | DF_YES_CROUCH ) ;
CVAR ( Mask , sv_jump , dmflags , DF_NO_JUMP | DF_YES_JUMP ) ;
CVAR ( Mask , sv_fallingdamage , dmflags , DF_FORCE_FALLINGHX | DF_FORCE_FALLINGZD ) ;
CVAR ( Mask , sv_freelook , dmflags , DF_NO_FREELOOK | DF_YES_FREELOOK ) ;
//==========================================================================
//
// CVAR dmflags2
//
// [RH] From Skull Tag. Some of these were already done as separate cvars
// (such as bfgaiming), but I collected them here like Skull Tag does.
//
//==========================================================================
2019-02-24 08:57:46 +00:00
CUSTOM_CVAR ( Int , dmflags2 , 0 , CVAR_SERVERINFO | CVAR_NOINITCALL )
2016-03-01 15:47:10 +00:00
{
// Stop the automap if we aren't allowed to use it.
if ( ( self & DF2_NO_AUTOMAP ) & & automapactive )
AM_Stop ( ) ;
for ( int i = 0 ; i < MAXPLAYERS ; i + + )
{
player_t * p = & players [ i ] ;
if ( ! playeringame [ i ] )
continue ;
// Revert our view to our own eyes if spying someone else.
if ( self & DF2_DISALLOW_SPYING )
{
// The player isn't looking through its own eyes, so make it.
if ( p - > camera ! = p - > mo )
{
p - > camera = p - > mo ;
S_UpdateSounds ( p - > camera ) ;
2017-03-22 16:29:13 +00:00
StatusBar - > AttachToPlayer ( p ) ;
2016-03-01 15:47:10 +00:00
if ( demoplayback | | multiplayer )
StatusBar - > ShowPlayerName ( ) ;
}
}
// Come out of chasecam mode if we're not allowed to use chasecam.
if ( ! ( dmflags2 & DF2_CHASECAM ) & & CheckCheatmode ( false ) )
{
// Take us out of chasecam mode only.
if ( p - > cheats & CF_CHASECAM )
cht_DoCheat ( p , CHT_CHASECAM ) ;
}
}
}
CVAR ( Flag , sv_weapondrop , dmflags2 , DF2_YES_WEAPONDROP ) ;
CVAR ( Flag , sv_noteamswitch , dmflags2 , DF2_NO_TEAM_SWITCH ) ;
CVAR ( Flag , sv_doubleammo , dmflags2 , DF2_YES_DOUBLEAMMO ) ;
CVAR ( Flag , sv_degeneration , dmflags2 , DF2_YES_DEGENERATION ) ;
CVAR ( Flag , sv_nobfgaim , dmflags2 , DF2_NO_FREEAIMBFG ) ;
CVAR ( Flag , sv_barrelrespawn , dmflags2 , DF2_BARRELS_RESPAWN ) ;
CVAR ( Flag , sv_keepfrags , dmflags2 , DF2_YES_KEEPFRAGS ) ;
CVAR ( Flag , sv_norespawn , dmflags2 , DF2_NO_RESPAWN ) ;
CVAR ( Flag , sv_losefrag , dmflags2 , DF2_YES_LOSEFRAG ) ;
CVAR ( Flag , sv_respawnprotect , dmflags2 , DF2_YES_RESPAWN_INVUL ) ;
CVAR ( Flag , sv_samespawnspot , dmflags2 , DF2_SAME_SPAWN_SPOT ) ;
CVAR ( Flag , sv_infiniteinventory , dmflags2 , DF2_INFINITE_INVENTORY ) ;
CVAR ( Flag , sv_killallmonsters , dmflags2 , DF2_KILL_MONSTERS ) ;
CVAR ( Flag , sv_noautomap , dmflags2 , DF2_NO_AUTOMAP ) ;
CVAR ( Flag , sv_noautomapallies , dmflags2 , DF2_NO_AUTOMAP_ALLIES ) ;
CVAR ( Flag , sv_disallowspying , dmflags2 , DF2_DISALLOW_SPYING ) ;
CVAR ( Flag , sv_chasecam , dmflags2 , DF2_CHASECAM ) ;
CVAR ( Flag , sv_disallowsuicide , dmflags2 , DF2_NOSUICIDE ) ;
CVAR ( Flag , sv_noautoaim , dmflags2 , DF2_NOAUTOAIM ) ;
CVAR ( Flag , sv_dontcheckammo , dmflags2 , DF2_DONTCHECKAMMO ) ;
CVAR ( Flag , sv_killbossmonst , dmflags2 , DF2_KILLBOSSMONST ) ;
CVAR ( Flag , sv_nocountendmonst , dmflags2 , DF2_NOCOUNTENDMONST ) ;
CVAR ( Flag , sv_respawnsuper , dmflags2 , DF2_RESPAWN_SUPER ) ;
//==========================================================================
//
// CVAR compatflags
//
//==========================================================================
EXTERN_CVAR ( Int , compatmode )
2019-02-24 08:57:46 +00:00
CUSTOM_CVAR ( Int , compatflags , 0 , CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_NOINITCALL )
2016-03-01 15:47:10 +00:00
{
2019-01-29 18:28:22 +00:00
for ( auto Level : AllLevels ( ) )
2016-03-01 15:47:10 +00:00
{
2019-03-23 14:28:10 +00:00
Level - > ApplyCompatibility ( ) ;
2016-03-01 15:47:10 +00:00
}
}
2019-02-24 08:57:46 +00:00
CUSTOM_CVAR ( Int , compatflags2 , 0 , CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_NOINITCALL )
2016-03-01 15:47:10 +00:00
{
2019-01-29 18:28:22 +00:00
for ( auto Level : AllLevels ( ) )
{
2019-03-23 14:28:10 +00:00
Level - > ApplyCompatibility2 ( ) ;
2019-01-29 18:28:22 +00:00
Level - > SetCompatLineOnSide ( true ) ;
}
2016-03-01 15:47:10 +00:00
}
CUSTOM_CVAR ( Int , compatmode , 0 , CVAR_ARCHIVE | CVAR_NOINITCALL )
{
int v , w = 0 ;
switch ( self )
{
default :
case 0 :
v = 0 ;
break ;
case 1 : // Doom2.exe compatible with a few relaxed settings
2019-03-24 08:38:26 +00:00
v = COMPATF_SHORTTEX | COMPATF_STAIRINDEX | COMPATF_USEBLOCKING | COMPATF_NODOORLIGHT | COMPATF_SPRITESORT |
COMPATF_TRACE | COMPATF_MISSILECLIP | COMPATF_SOUNDTARGET | COMPATF_DEHHEALTH | COMPATF_CROSSDROPOFF |
COMPATF_LIGHT | COMPATF_MASKEDMIDTEX ;
w = COMPATF2_FLOORMOVE | COMPATF2_EXPLODE1 ;
2016-03-01 15:47:10 +00:00
break ;
case 2 : // same as 1 but stricter (NO_PASSMOBJ and INVISIBILITY are also set)
2019-03-24 08:38:26 +00:00
v = COMPATF_SHORTTEX | COMPATF_STAIRINDEX | COMPATF_USEBLOCKING | COMPATF_NODOORLIGHT | COMPATF_SPRITESORT |
COMPATF_TRACE | COMPATF_MISSILECLIP | COMPATF_SOUNDTARGET | COMPATF_NO_PASSMOBJ | COMPATF_LIMITPAIN |
COMPATF_DEHHEALTH | COMPATF_INVISIBILITY | COMPATF_CROSSDROPOFF | COMPATF_CORPSEGIBS | COMPATF_HITSCAN |
COMPATF_WALLRUN | COMPATF_NOTOSSDROPS | COMPATF_LIGHT | COMPATF_MASKEDMIDTEX ;
w = COMPATF2_BADANGLES | COMPATF2_FLOORMOVE | COMPATF2_POINTONLINE | COMPATF2_EXPLODE2 ;
2016-03-01 15:47:10 +00:00
break ;
case 3 : // Boom compat mode
2016-06-21 08:45:17 +00:00
v = COMPATF_TRACE | COMPATF_SOUNDTARGET | COMPATF_BOOMSCROLL | COMPATF_MISSILECLIP | COMPATF_MASKEDMIDTEX ;
2019-03-24 08:38:26 +00:00
w = COMPATF2_EXPLODE1 ;
2016-03-01 15:47:10 +00:00
break ;
case 4 : // Old ZDoom compat mode
v = COMPATF_SOUNDTARGET | COMPATF_LIGHT ;
2019-02-11 14:26:11 +00:00
w = COMPATF2_MULTIEXIT | COMPATF2_TELEPORT | COMPATF2_PUSHWINDOW | COMPATF2_CHECKSWITCHRANGE ;
2016-03-01 15:47:10 +00:00
break ;
case 5 : // MBF compat mode
2019-03-24 08:38:26 +00:00
v = COMPATF_TRACE | COMPATF_SOUNDTARGET | COMPATF_BOOMSCROLL | COMPATF_MISSILECLIP | COMPATF_MUSHROOM |
COMPATF_MBFMONSTERMOVE | COMPATF_NOBLOCKFRIENDS | COMPATF_MASKEDMIDTEX ;
w = COMPATF2_EXPLODE1 ;
2016-03-01 15:47:10 +00:00
break ;
case 6 : // Boom with some added settings to reenable some 'broken' behavior
2019-03-24 08:38:26 +00:00
v = COMPATF_TRACE | COMPATF_SOUNDTARGET | COMPATF_BOOMSCROLL | COMPATF_MISSILECLIP | COMPATF_NO_PASSMOBJ |
COMPATF_INVISIBILITY | COMPATF_CORPSEGIBS | COMPATF_HITSCAN | COMPATF_WALLRUN | COMPATF_NOTOSSDROPS | COMPATF_MASKEDMIDTEX ;
w = COMPATF2_POINTONLINE | COMPATF2_EXPLODE2 ;
2016-03-01 15:47:10 +00:00
break ;
}
compatflags = v ;
compatflags2 = w ;
}
CVAR ( Flag , compat_shortTex , compatflags , COMPATF_SHORTTEX ) ;
CVAR ( Flag , compat_stairs , compatflags , COMPATF_STAIRINDEX ) ;
CVAR ( Flag , compat_limitpain , compatflags , COMPATF_LIMITPAIN ) ;
CVAR ( Flag , compat_silentpickup , compatflags , COMPATF_SILENTPICKUP ) ;
CVAR ( Flag , compat_nopassover , compatflags , COMPATF_NO_PASSMOBJ ) ;
CVAR ( Flag , compat_soundslots , compatflags , COMPATF_MAGICSILENCE ) ;
CVAR ( Flag , compat_wallrun , compatflags , COMPATF_WALLRUN ) ;
CVAR ( Flag , compat_notossdrops , compatflags , COMPATF_NOTOSSDROPS ) ;
CVAR ( Flag , compat_useblocking , compatflags , COMPATF_USEBLOCKING ) ;
CVAR ( Flag , compat_nodoorlight , compatflags , COMPATF_NODOORLIGHT ) ;
CVAR ( Flag , compat_ravenscroll , compatflags , COMPATF_RAVENSCROLL ) ;
CVAR ( Flag , compat_soundtarget , compatflags , COMPATF_SOUNDTARGET ) ;
CVAR ( Flag , compat_dehhealth , compatflags , COMPATF_DEHHEALTH ) ;
CVAR ( Flag , compat_trace , compatflags , COMPATF_TRACE ) ;
CVAR ( Flag , compat_dropoff , compatflags , COMPATF_DROPOFF ) ;
CVAR ( Flag , compat_boomscroll , compatflags , COMPATF_BOOMSCROLL ) ;
CVAR ( Flag , compat_invisibility , compatflags , COMPATF_INVISIBILITY ) ;
CVAR ( Flag , compat_silentinstantfloors , compatflags , COMPATF_SILENT_INSTANT_FLOORS ) ;
CVAR ( Flag , compat_sectorsounds , compatflags , COMPATF_SECTORSOUNDS ) ;
CVAR ( Flag , compat_missileclip , compatflags , COMPATF_MISSILECLIP ) ;
CVAR ( Flag , compat_crossdropoff , compatflags , COMPATF_CROSSDROPOFF ) ;
CVAR ( Flag , compat_anybossdeath , compatflags , COMPATF_ANYBOSSDEATH ) ;
CVAR ( Flag , compat_minotaur , compatflags , COMPATF_MINOTAUR ) ;
CVAR ( Flag , compat_mushroom , compatflags , COMPATF_MUSHROOM ) ;
CVAR ( Flag , compat_mbfmonstermove , compatflags , COMPATF_MBFMONSTERMOVE ) ;
CVAR ( Flag , compat_corpsegibs , compatflags , COMPATF_CORPSEGIBS ) ;
CVAR ( Flag , compat_noblockfriends , compatflags , COMPATF_NOBLOCKFRIENDS ) ;
CVAR ( Flag , compat_spritesort , compatflags , COMPATF_SPRITESORT ) ;
CVAR ( Flag , compat_hitscan , compatflags , COMPATF_HITSCAN ) ;
CVAR ( Flag , compat_light , compatflags , COMPATF_LIGHT ) ;
CVAR ( Flag , compat_polyobj , compatflags , COMPATF_POLYOBJ ) ;
CVAR ( Flag , compat_maskedmidtex , compatflags , COMPATF_MASKEDMIDTEX ) ;
CVAR ( Flag , compat_badangles , compatflags2 , COMPATF2_BADANGLES ) ;
CVAR ( Flag , compat_floormove , compatflags2 , COMPATF2_FLOORMOVE ) ;
CVAR ( Flag , compat_soundcutoff , compatflags2 , COMPATF2_SOUNDCUTOFF ) ;
CVAR ( Flag , compat_pointonline , compatflags2 , COMPATF2_POINTONLINE ) ;
CVAR ( Flag , compat_multiexit , compatflags2 , COMPATF2_MULTIEXIT ) ;
2016-08-07 20:03:36 +00:00
CVAR ( Flag , compat_teleport , compatflags2 , COMPATF2_TELEPORT ) ;
2016-08-09 18:15:13 +00:00
CVAR ( Flag , compat_pushwindow , compatflags2 , COMPATF2_PUSHWINDOW ) ;
2019-02-11 14:26:11 +00:00
CVAR ( Flag , compat_checkswitchrange , compatflags2 , COMPATF2_CHECKSWITCHRANGE ) ;
2019-03-24 08:38:26 +00:00
CVAR ( Flag , compat_explode1 , compatflags2 , COMPATF2_EXPLODE1 ) ;
CVAR ( Flag , compat_explode2 , compatflags2 , COMPATF2_EXPLODE2 ) ;
2019-05-09 08:20:47 +00:00
CVAR ( Flag , compat_railing , compatflags2 , COMPATF2_RAILING ) ;
2016-03-01 15:47:10 +00:00
2018-05-04 08:24:37 +00:00
CVAR ( Bool , vid_activeinbackground , false , CVAR_ARCHIVE | CVAR_GLOBALCONFIG )
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// D_Display
//
// Draw current display, possibly wiping it from the previous
//
//==========================================================================
void D_Display ( )
{
2018-09-02 19:13:36 +00:00
FTexture * wipe = nullptr ;
2018-08-28 13:11:35 +00:00
int wipe_type ;
2018-05-05 09:20:37 +00:00
sector_t * viewsec ;
2016-03-01 15:47:10 +00:00
if ( nodrawers | | screen = = NULL )
return ; // for comparative timing / profiling
2018-05-04 08:24:37 +00:00
if ( ! AppActive & & ( screen - > IsFullscreen ( ) | | ! vid_activeinbackground ) )
{
return ;
}
2016-03-01 15:47:10 +00:00
cycle_t cycles ;
cycles . Reset ( ) ;
cycles . Clock ( ) ;
2017-06-04 10:05:40 +00:00
r_UseVanillaTransparency = UseVanillaTransparency ( ) ; // [SP] Cache UseVanillaTransparency() call
2018-04-03 20:50:47 +00:00
r_renderercaps = screen - > GetCaps ( ) ; // [SP] Get the current capabilities of the renderer
2017-06-04 10:05:40 +00:00
2016-03-01 15:47:10 +00:00
if ( players [ consoleplayer ] . camera = = NULL )
{
players [ consoleplayer ] . camera = players [ consoleplayer ] . mo ;
}
2018-06-19 09:20:36 +00:00
auto & vp = r_viewpoint ;
2016-03-01 15:47:10 +00:00
if ( viewactive )
{
2017-08-28 11:17:42 +00:00
DAngle fov = 90.f ;
2017-08-28 16:39:03 +00:00
AActor * cam = players [ consoleplayer ] . camera ;
if ( cam )
2017-08-28 11:17:42 +00:00
{
2017-08-28 16:39:03 +00:00
if ( cam - > player )
fov = cam - > player - > FOV ;
else fov = cam - > CameraFOV ;
2017-08-28 11:17:42 +00:00
}
2018-06-19 09:20:36 +00:00
R_SetFOV ( vp , fov ) ;
2016-03-01 15:47:10 +00:00
}
2018-06-17 14:19:14 +00:00
// fullscreen toggle has been requested
2016-03-01 15:47:10 +00:00
if ( setmodeneeded )
{
2018-07-21 19:32:02 +00:00
setmodeneeded = false ;
2018-06-17 20:09:25 +00:00
screen - > ToggleFullscreen ( fullscreen ) ;
2018-06-17 21:33:22 +00:00
V_OutputResized ( screen - > GetWidth ( ) , screen - > GetHeight ( ) ) ;
2018-07-21 19:32:02 +00:00
}
2016-03-01 15:47:10 +00:00
// change the view size if needed
2018-06-17 13:08:41 +00:00
if ( setsizeneeded )
2016-03-01 15:47:10 +00:00
{
2018-06-17 13:08:41 +00:00
if ( StatusBar = = nullptr )
{
viewwidth = SCREENWIDTH ;
viewheight = SCREENHEIGHT ;
setsizeneeded = false ;
}
else
{
2018-06-19 17:40:52 +00:00
R_ExecuteSetViewSize ( vp , r_viewwindow ) ;
}
2016-03-01 15:47:10 +00:00
}
// [RH] Allow temporarily disabling wipes
if ( NoWipe )
{
NoWipe - - ;
2018-08-28 13:11:35 +00:00
wipe = nullptr ;
2016-03-01 15:47:10 +00:00
wipegamestate = gamestate ;
}
2018-06-24 08:47:42 +00:00
// No wipes when in a stereo3D VR mode
2019-06-26 19:26:14 +00:00
else if ( gamestate ! = wipegamestate & & gamestate ! = GS_FULLCONSOLE & & gamestate ! = GS_TITLELEVEL )
{
if ( vr_mode = = 0 | | vid_rendermode ! = 4 )
2016-03-01 15:47:10 +00:00
{
2019-06-26 19:26:14 +00:00
// save the current screen if about to wipe
wipe = screen - > WipeStartScreen ( ) ;
2016-03-01 15:47:10 +00:00
2019-06-26 19:26:14 +00:00
switch ( wipegamestate )
{
default :
wipe_type = wipetype ;
break ;
2016-03-01 15:47:10 +00:00
2019-06-26 19:26:14 +00:00
case GS_FORCEWIPEFADE :
wipe_type = wipe_Fade ;
break ;
2016-03-01 15:47:10 +00:00
2019-06-26 19:26:14 +00:00
case GS_FORCEWIPEBURN :
wipe_type = wipe_Burn ;
break ;
case GS_FORCEWIPEMELT :
wipe_type = wipe_Melt ;
break ;
}
2016-03-01 15:47:10 +00:00
}
2019-06-26 19:26:14 +00:00
2016-03-01 15:47:10 +00:00
wipegamestate = gamestate ;
}
else
{
2018-08-28 13:11:35 +00:00
wipe = nullptr ;
2016-03-01 15:47:10 +00:00
}
2018-08-28 10:58:57 +00:00
screen - > FrameTime = I_msTimeFS ( ) ;
TexMan . UpdateAnimations ( screen - > FrameTime ) ;
R_UpdateSky ( screen - > FrameTime ) ;
screen - > BeginFrame ( ) ;
screen - > ClearClipRect ( ) ;
if ( ( gamestate = = GS_LEVEL | | gamestate = = GS_TITLELEVEL ) & & gametic ! = 0 )
2016-03-01 15:47:10 +00:00
{
2018-08-28 10:58:57 +00:00
// [ZZ] execute event hook that we just started the frame
//E_RenderFrame();
//
2019-01-29 00:09:02 +00:00
D_Render ( [ & ] ( )
2019-01-28 17:26:14 +00:00
{
2019-01-29 00:09:02 +00:00
viewsec = screen - > RenderView ( & players [ consoleplayer ] ) ;
} , true ) ;
2019-01-28 17:26:14 +00:00
2018-08-28 10:58:57 +00:00
screen - > Begin2D ( ) ;
2019-11-03 08:51:22 +00:00
if ( ! hud_toggled )
2018-08-28 10:58:57 +00:00
{
2019-11-03 08:51:22 +00:00
screen - > DrawBlend ( viewsec ) ;
if ( automapactive )
{
primaryLevel - > automap - > Drawer ( ( hud_althud & & viewheight = = SCREENHEIGHT ) ? viewheight : StatusBar - > GetTopOfStatusbar ( ) ) ;
}
2018-08-28 10:58:57 +00:00
2019-11-03 08:51:22 +00:00
// for timing the statusbar code.
//cycle_t stb;
//stb.Reset();
//stb.Clock();
if ( ! automapactive | | viewactive )
2016-03-01 15:47:10 +00:00
{
2019-11-03 08:51:22 +00:00
StatusBar - > RefreshViewBorder ( ) ;
2016-03-01 15:47:10 +00:00
}
2019-11-03 08:51:22 +00:00
if ( hud_althud & & viewheight = = SCREENHEIGHT & & screenblocks > 10 )
{
StatusBar - > DrawBottomStuff ( HUD_AltHud ) ;
if ( DrawFSHUD | | automapactive ) StatusBar - > DrawAltHUD ( ) ;
if ( players [ consoleplayer ] . camera & & players [ consoleplayer ] . camera - > player & & ! automapactive )
{
StatusBar - > DrawCrosshair ( ) ;
}
StatusBar - > CallDraw ( HUD_AltHud , vp . TicFrac ) ;
StatusBar - > DrawTopStuff ( HUD_AltHud ) ;
}
else if ( viewheight = = SCREENHEIGHT & & viewactive & & screenblocks > 10 )
{
EHudState state = DrawFSHUD ? HUD_Fullscreen : HUD_None ;
StatusBar - > DrawBottomStuff ( state ) ;
StatusBar - > CallDraw ( state , vp . TicFrac ) ;
StatusBar - > DrawTopStuff ( state ) ;
}
else
{
StatusBar - > DrawBottomStuff ( HUD_StatusBar ) ;
StatusBar - > CallDraw ( HUD_StatusBar , vp . TicFrac ) ;
StatusBar - > DrawTopStuff ( HUD_StatusBar ) ;
}
//stb.Unclock();
//Printf("Stbar = %f\n", stb.TimeMS());
2018-08-28 10:58:57 +00:00
}
}
else
{
screen - > Begin2D ( ) ;
switch ( gamestate )
{
case GS_FULLCONSOLE :
screen - > Begin2D ( ) ;
C_DrawConsole ( ) ;
M_Drawer ( ) ;
screen - > End2DAndUpdate ( ) ;
return ;
case GS_INTERMISSION :
WI_Drawer ( ) ;
break ;
case GS_FINALE :
F_Drawer ( ) ;
break ;
case GS_DEMOSCREEN :
D_PageDrawer ( ) ;
break ;
default :
break ;
2016-03-01 15:47:10 +00:00
}
}
2019-11-03 08:51:22 +00:00
if ( ! hud_toggled )
2016-03-01 15:47:10 +00:00
{
2019-11-03 08:51:22 +00:00
CT_Drawer ( ) ;
// draw pause pic
if ( ( paused | | pauseext ) & & menuactive = = MENU_Off )
2016-03-01 15:47:10 +00:00
{
2019-11-03 08:51:22 +00:00
FTexture * tex ;
int x ;
tex = TexMan . GetTextureByName ( gameinfo . PauseSign , true ) ;
x = ( SCREENWIDTH - tex - > GetDisplayWidth ( ) * CleanXfac ) / 2 +
tex - > GetDisplayLeftOffset ( ) * CleanXfac ;
screen - > DrawTexture ( tex , x , 4 , DTA_CleanNoMove , true , TAG_DONE ) ;
if ( paused & & multiplayer )
{
FFont * font = generic_ui ? NewSmallFont : SmallFont ;
FString pstring = GStrings ( " TXT_BY " ) ;
pstring . Substitute ( " %s " , players [ paused - 1 ] . userinfo . GetName ( ) ) ;
screen - > DrawText ( font , CR_RED ,
( screen - > GetWidth ( ) - font - > StringWidth ( pstring ) * CleanXfac ) / 2 ,
( tex - > GetDisplayHeight ( ) * CleanYfac ) + 4 , pstring , DTA_CleanNoMove , true , TAG_DONE ) ;
}
2016-03-01 15:47:10 +00:00
}
2019-11-03 08:51:22 +00:00
// [RH] Draw icon, if any
if ( D_DrawIcon )
2016-03-01 15:47:10 +00:00
{
2019-11-03 08:51:22 +00:00
FTextureID picnum = TexMan . CheckForTexture ( D_DrawIcon , ETextureType : : MiscPatch ) ;
D_DrawIcon = NULL ;
if ( picnum . isValid ( ) )
{
FTexture * tex = TexMan . GetTexture ( picnum ) ;
screen - > DrawTexture ( tex , 160 - tex - > GetDisplayWidth ( ) / 2 , 100 - tex - > GetDisplayHeight ( ) / 2 ,
DTA_320x200 , true , TAG_DONE ) ;
}
NoWipe = 10 ;
2016-03-01 15:47:10 +00:00
}
2019-11-03 08:51:22 +00:00
if ( snd_drawoutput )
{
GSnd - > DrawWaveDebug ( snd_drawoutput ) ;
}
2016-03-01 15:47:10 +00:00
}
2019-11-03 08:51:22 +00:00
if ( ! wipe | | NoWipe < 0 | | wipe_type = = wipe_None | | hud_toggled )
2016-03-01 15:47:10 +00:00
{
2018-09-02 19:13:36 +00:00
if ( wipe ! = nullptr ) delete wipe ;
wipe = nullptr ;
2016-03-01 15:47:10 +00:00
NetUpdate ( ) ; // send out any new accumulation
// normal update
2017-02-03 11:29:17 +00:00
// draw ZScript UI stuff
2018-03-27 18:02:44 +00:00
C_DrawConsole ( ) ; // draw console
2016-03-01 15:47:10 +00:00
M_Drawer ( ) ; // menu is drawn even on top of everything
2019-11-03 08:51:22 +00:00
if ( ! hud_toggled )
FStat : : PrintStat ( ) ;
2018-08-28 10:58:57 +00:00
screen - > End2DAndUpdate ( ) ;
2016-03-01 15:47:10 +00:00
}
else
{
// wipe update
2017-11-16 01:33:08 +00:00
uint64_t wipestart , nowtime , diff ;
2016-03-01 15:47:10 +00:00
bool done ;
GSnd - > SetSfxPaused ( true , 1 ) ;
I_FreezeTime ( true ) ;
2018-08-28 10:58:57 +00:00
screen - > End2D ( ) ;
2018-08-28 13:11:35 +00:00
auto wipend = screen - > WipeEndScreen ( ) ;
2018-08-28 18:25:07 +00:00
auto wiper = Wiper : : Create ( wipe_type ) ;
2018-08-28 20:58:21 +00:00
wiper - > SetTextures ( wipe , wipend ) ;
2016-03-01 15:47:10 +00:00
2017-11-12 23:54:32 +00:00
wipestart = I_msTime ( ) ;
2016-03-01 15:47:10 +00:00
NetUpdate ( ) ; // send out any new accumulation
do
{
do
{
I_WaitVBL ( 2 ) ;
2017-11-12 23:54:32 +00:00
nowtime = I_msTime ( ) ;
2016-03-01 15:47:10 +00:00
diff = ( nowtime - wipestart ) * 40 / 1000 ; // Using 35 here feels too slow.
} while ( diff < 1 ) ;
wipestart = nowtime ;
2018-08-28 10:58:57 +00:00
screen - > Begin2D ( ) ;
2018-08-28 20:58:21 +00:00
done = wiper - > Run ( 1 ) ;
2018-03-27 18:02:44 +00:00
C_DrawConsole ( ) ; // console and
2016-03-01 15:47:10 +00:00
M_Drawer ( ) ; // menu are drawn even on top of wipes
2018-08-28 10:58:57 +00:00
screen - > End2DAndUpdate ( ) ;
2016-03-01 15:47:10 +00:00
NetUpdate ( ) ; // [RH] not sure this is needed anymore
} while ( ! done ) ;
2018-08-28 18:25:07 +00:00
delete wiper ;
2016-03-01 15:47:10 +00:00
I_FreezeTime ( false ) ;
GSnd - > SetSfxPaused ( false , 1 ) ;
}
cycles . Unclock ( ) ;
FrameCycles = cycles ;
}
//==========================================================================
//
// D_ErrorCleanup ()
//
// Cleanup after a recoverable error or a restart
//==========================================================================
void D_ErrorCleanup ( )
{
savegamerestore = false ;
2019-02-01 23:24:43 +00:00
primaryLevel - > BotInfo . RemoveAllBots ( primaryLevel , true ) ;
2016-03-01 15:47:10 +00:00
D_QuitNetGame ( ) ;
if ( demorecording | | demoplayback )
G_CheckDemoStatus ( ) ;
Net_ClearBuffers ( ) ;
G_NewInit ( ) ;
2017-08-25 12:36:06 +00:00
M_ClearMenus ( ) ;
2016-03-01 15:47:10 +00:00
singletics = false ;
playeringame [ 0 ] = 1 ;
players [ 0 ] . playerstate = PST_LIVE ;
gameaction = ga_fullconsole ;
if ( gamestate = = GS_DEMOSCREEN )
{
menuactive = MENU_Off ;
}
2017-03-18 20:19:32 +00:00
if ( gamestate = = GS_INTERMISSION ) gamestate = GS_DEMOSCREEN ;
2016-03-01 15:47:10 +00:00
insave = false ;
2019-10-21 12:54:13 +00:00
ClearGlobalVMStack ( ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// D_DoomLoop
//
// Manages timing and IO, calls all ?_Responder, ?_Ticker, and ?_Drawer,
// calls I_GetTime, I_StartFrame, and I_StartTic
//
//==========================================================================
void D_DoomLoop ( )
{
int lasttic = 0 ;
// Clamp the timer to TICRATE until the playloop has been entered.
r_NoInterpolate = true ;
2018-07-15 20:51:25 +00:00
Page . SetInvalid ( ) ;
2019-05-19 08:28:07 +00:00
Subtitle = nullptr ;
2018-07-15 20:51:25 +00:00
Advisory = nullptr ;
2016-03-01 15:47:10 +00:00
vid_cursor . Callback ( ) ;
for ( ; ; )
{
try
{
// frame syncronous IO operations
if ( gametic > lasttic )
{
lasttic = gametic ;
I_StartFrame ( ) ;
}
2017-07-20 12:20:50 +00:00
I_SetFrameTime ( ) ;
2016-03-01 15:47:10 +00:00
// process one or more tics
if ( singletics )
{
I_StartTic ( ) ;
D_ProcessEvents ( ) ;
G_BuildTiccmd ( & netcmds [ consoleplayer ] [ maketic % BACKUPTICS ] ) ;
if ( advancedemo )
D_DoAdvanceDemo ( ) ;
C_Ticker ( ) ;
M_Ticker ( ) ;
G_Ticker ( ) ;
// [RH] Use the consoleplayer's camera to update sounds
S_UpdateSounds ( players [ consoleplayer ] . camera ) ; // move positional sounds
gametic + + ;
maketic + + ;
GC : : CheckGC ( ) ;
Net_NewMakeTic ( ) ;
}
else
{
TryRunTics ( ) ; // will run at least one tic
}
// Update display, next frame, with current state.
2017-11-16 03:20:55 +00:00
I_StartTic ( ) ;
2016-03-01 15:47:10 +00:00
D_Display ( ) ;
2019-08-23 15:15:19 +00:00
S_UpdateMusic ( ) ;
2016-03-08 12:07:21 +00:00
if ( wantToRestart )
{
wantToRestart = false ;
return ;
}
2016-03-01 15:47:10 +00:00
}
catch ( CRecoverableError & error )
{
if ( error . GetMessage ( ) )
{
Printf ( PRINT_BOLD , " \n %s \n " , error . GetMessage ( ) ) ;
}
D_ErrorCleanup ( ) ;
}
2016-12-03 11:23:13 +00:00
catch ( CVMAbortException & error )
{
error . MaybePrintMessage ( ) ;
2016-12-07 10:28:40 +00:00
Printf ( " %s " , error . stacktrace . GetChars ( ) ) ;
2016-12-03 11:23:13 +00:00
D_ErrorCleanup ( ) ;
}
2016-03-01 15:47:10 +00:00
}
}
//==========================================================================
//
// D_PageTicker
//
//==========================================================================
void D_PageTicker ( void )
{
if ( - - pagetic < 0 )
D_AdvanceDemo ( ) ;
}
//==========================================================================
//
// D_PageDrawer
//
//==========================================================================
void D_PageDrawer ( void )
{
2017-02-01 10:44:13 +00:00
screen - > Clear ( 0 , 0 , SCREENWIDTH , SCREENHEIGHT , 0 , 0 ) ;
2018-07-15 20:51:25 +00:00
if ( Page . Exists ( ) )
2016-03-01 15:47:10 +00:00
{
2018-12-07 01:53:18 +00:00
screen - > DrawTexture ( TexMan . GetTexture ( Page , true ) , 0 , 0 ,
2016-03-01 15:47:10 +00:00
DTA_Fullscreen , true ,
DTA_Masked , false ,
DTA_BilinearFilter , true ,
TAG_DONE ) ;
}
2019-05-19 08:28:07 +00:00
if ( Subtitle ! = nullptr )
{
DrawFullscreenSubtitle ( GStrings [ Subtitle ] ) ;
}
if ( Advisory ! = nullptr )
2016-03-01 15:47:10 +00:00
{
screen - > DrawTexture ( Advisory , 4 , 160 , DTA_320x200 , true , TAG_DONE ) ;
}
}
//==========================================================================
//
// D_AdvanceDemo
//
// Called after each demo or intro demosequence finishes
//
//==========================================================================
void D_AdvanceDemo ( void )
{
advancedemo = true ;
}
//==========================================================================
//
// D_DoStrifeAdvanceDemo
//
//==========================================================================
void D_DoStrifeAdvanceDemo ( )
{
static const char * const fullVoices [ 6 ] =
{
" svox/pro1 " , " svox/pro2 " , " svox/pro3 " , " svox/pro4 " , " svox/pro5 " , " svox/pro6 "
} ;
static const char * const teaserVoices [ 6 ] =
{
" svox/voc91 " , " svox/voc92 " , " svox/voc93 " , " svox/voc94 " , " svox/voc95 " , " svox/voc96 "
} ;
const char * const * voices = gameinfo . flags & GI_SHAREWARE ? teaserVoices : fullVoices ;
2019-05-19 08:28:07 +00:00
const char * pagename = nullptr ;
const char * subtitle = nullptr ;
2016-03-01 15:47:10 +00:00
gamestate = GS_DEMOSCREEN ;
PageBlank = false ;
switch ( demosequence )
{
default :
case 0 :
pagetic = 6 * TICRATE ;
pagename = " TITLEPIC " ;
if ( Wads . CheckNumForName ( " d_logo " , ns_music ) < 0 )
{ // strife0.wad does not have d_logo
S_StartMusic ( " " ) ;
}
else
{
S_StartMusic ( " d_logo " ) ;
}
C_HideConsole ( ) ;
break ;
case 1 :
// [RH] Strife fades to black and then to the Rogue logo, but
// I think it looks better if it doesn't fade.
pagetic = 10 * TICRATE / 35 ;
pagename = " " ; // PANEL0, but strife0.wad doesn't have it, so don't use it.
PageBlank = true ;
S_Sound ( CHAN_VOICE | CHAN_UI , " bishop/active " , 1 , ATTN_NORM ) ;
break ;
case 2 :
pagetic = 4 * TICRATE ;
pagename = " RGELOGO " ;
break ;
case 3 :
pagetic = 7 * TICRATE ;
pagename = " PANEL1 " ;
2019-05-19 08:28:07 +00:00
subtitle = " TXT_SUB_INTRO1 " ;
2016-03-01 15:47:10 +00:00
S_Sound ( CHAN_VOICE | CHAN_UI , voices [ 0 ] , 1 , ATTN_NORM ) ;
// The new Strife teaser has D_FMINTR.
// The full retail Strife has D_INTRO.
// And the old Strife teaser has both. (I do not know which one it actually uses, nor do I care.)
S_StartMusic ( gameinfo . flags & GI_TEASER2 ? " d_fmintr " : " d_intro " ) ;
break ;
case 4 :
pagetic = 9 * TICRATE ;
pagename = " PANEL2 " ;
2019-05-19 08:28:07 +00:00
subtitle = " TXT_SUB_INTRO2 " ;
2016-03-01 15:47:10 +00:00
S_Sound ( CHAN_VOICE | CHAN_UI , voices [ 1 ] , 1 , ATTN_NORM ) ;
break ;
case 5 :
pagetic = 12 * TICRATE ;
pagename = " PANEL3 " ;
2019-05-19 08:28:07 +00:00
subtitle = " TXT_SUB_INTRO3 " ;
2016-03-01 15:47:10 +00:00
S_Sound ( CHAN_VOICE | CHAN_UI , voices [ 2 ] , 1 , ATTN_NORM ) ;
break ;
case 6 :
pagetic = 11 * TICRATE ;
pagename = " PANEL4 " ;
2019-05-19 08:28:07 +00:00
subtitle = " TXT_SUB_INTRO4 " ;
2016-03-01 15:47:10 +00:00
S_Sound ( CHAN_VOICE | CHAN_UI , voices [ 3 ] , 1 , ATTN_NORM ) ;
break ;
case 7 :
pagetic = 10 * TICRATE ;
pagename = " PANEL5 " ;
2019-05-19 08:28:07 +00:00
subtitle = " TXT_SUB_INTRO5 " ;
2016-03-01 15:47:10 +00:00
S_Sound ( CHAN_VOICE | CHAN_UI , voices [ 4 ] , 1 , ATTN_NORM ) ;
break ;
case 8 :
pagetic = 16 * TICRATE ;
pagename = " PANEL6 " ;
2019-05-19 08:28:07 +00:00
subtitle = " TXT_SUB_INTRO6 " ;
2016-03-01 15:47:10 +00:00
S_Sound ( CHAN_VOICE | CHAN_UI , voices [ 5 ] , 1 , ATTN_NORM ) ;
break ;
case 9 :
pagetic = 6 * TICRATE ;
pagename = " vellogo " ;
wipegamestate = GS_FORCEWIPEFADE ;
break ;
case 10 :
pagetic = 12 * TICRATE ;
pagename = " CREDIT " ;
wipegamestate = GS_FORCEWIPEFADE ;
break ;
}
if ( demosequence + + > 10 )
demosequence = 0 ;
if ( demosequence = = 9 & & ! ( gameinfo . flags & GI_SHAREWARE ) )
demosequence = 10 ;
2019-05-19 08:28:07 +00:00
if ( pagename ! = nullptr )
{
Page = TexMan . CheckForTexture ( pagename , ETextureType : : MiscPatch ) ;
Subtitle = subtitle ;
}
else
{
Subtitle = nullptr ;
}
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// D_DoAdvanceDemo
//
//==========================================================================
void D_DoAdvanceDemo ( void )
{
static char demoname [ 8 ] = " DEMO1 " ;
static int democount = 0 ;
static int pagecount ;
FString pagename ;
advancedemo = false ;
if ( gameaction ! = ga_nothing )
{
return ;
}
players [ consoleplayer ] . playerstate = PST_LIVE ; // not reborn
usergame = false ; // no save / end game here
paused = 0 ;
// [RH] If you want something more dynamic for your title, create a map
// and name it TITLEMAP. That map will be loaded and used as the title.
if ( P_CheckMapData ( " TITLEMAP " ) )
{
G_InitNew ( " TITLEMAP " , true ) ;
return ;
}
if ( gameinfo . gametype = = GAME_Strife )
{
D_DoStrifeAdvanceDemo ( ) ;
return ;
}
switch ( demosequence )
{
case 3 :
if ( gameinfo . advisoryTime )
{
2018-12-07 01:43:27 +00:00
Advisory = TexMan . GetTextureByName ( " ADVISOR " ) ;
2016-03-01 15:47:10 +00:00
demosequence = 1 ;
pagetic = ( int ) ( gameinfo . advisoryTime * TICRATE ) ;
break ;
}
// fall through to case 1 if no advisory notice
case 1 :
Advisory = NULL ;
if ( ! M_DemoNoPlay )
{
democount + + ;
mysnprintf ( demoname + 4 , countof ( demoname ) - 4 , " %d " , democount ) ;
if ( Wads . CheckNumForName ( demoname ) < 0 )
{
demosequence = 0 ;
democount = 0 ;
// falls through to case 0 below
}
else
{
2019-03-14 23:16:08 +00:00
singledemo = false ;
2016-03-01 15:47:10 +00:00
G_DeferedPlayDemo ( demoname ) ;
demosequence = 2 ;
break ;
}
}
default :
case 0 :
gamestate = GS_DEMOSCREEN ;
pagename = gameinfo . TitlePage ;
pagetic = ( int ) ( gameinfo . titleTime * TICRATE ) ;
S_ChangeMusic ( gameinfo . titleMusic , gameinfo . titleOrder , false ) ;
demosequence = 3 ;
pagecount = 0 ;
C_HideConsole ( ) ;
break ;
case 2 :
pagetic = ( int ) ( gameinfo . pageTime * TICRATE ) ;
gamestate = GS_DEMOSCREEN ;
if ( gameinfo . creditPages . Size ( ) > 0 )
{
pagename = gameinfo . creditPages [ pagecount ] ;
pagecount = ( pagecount + 1 ) % gameinfo . creditPages . Size ( ) ;
}
demosequence = 1 ;
break ;
}
2018-07-15 20:51:25 +00:00
2016-03-01 15:47:10 +00:00
if ( pagename . IsNotEmpty ( ) )
{
2018-07-15 20:51:25 +00:00
Page = TexMan . CheckForTexture ( pagename , ETextureType : : MiscPatch ) ;
2016-03-01 15:47:10 +00:00
}
}
//==========================================================================
//
// D_StartTitle
//
//==========================================================================
void D_StartTitle ( void )
{
gameaction = ga_nothing ;
demosequence = - 1 ;
D_AdvanceDemo ( ) ;
}
//==========================================================================
//
// Cmd_Endgame
//
// [RH] Quit the current game and go to fullscreen console
//
//==========================================================================
CCMD ( endgame )
{
if ( ! netgame )
{
gameaction = ga_fullconsole ;
demosequence = - 1 ;
G_CheckDemoStatus ( ) ;
}
}
//==========================================================================
//
// ParseCVarInfo
//
//==========================================================================
void ParseCVarInfo ( )
{
int lump , lastlump = 0 ;
bool addedcvars = false ;
while ( ( lump = Wads . FindLump ( " CVARINFO " , & lastlump ) ) ! = - 1 )
{
FScanner sc ( lump ) ;
sc . SetCMode ( true ) ;
while ( sc . GetToken ( ) )
{
FString cvarname ;
char * cvardefault = NULL ;
ECVarType cvartype = CVAR_Dummy ;
int cvarflags = CVAR_MOD | CVAR_ARCHIVE ;
FBaseCVar * cvar ;
// Check for flag tokens.
while ( sc . TokenType = = TK_Identifier )
{
if ( stricmp ( sc . String , " server " ) = = 0 )
{
cvarflags | = CVAR_SERVERINFO ;
}
else if ( stricmp ( sc . String , " user " ) = = 0 )
{
cvarflags | = CVAR_USERINFO ;
}
else if ( stricmp ( sc . String , " noarchive " ) = = 0 )
{
cvarflags & = ~ CVAR_ARCHIVE ;
}
2017-01-31 09:05:29 +00:00
else if ( stricmp ( sc . String , " cheat " ) = = 0 )
{
cvarflags | = CVAR_CHEAT ;
}
2017-11-11 14:37:41 +00:00
else if ( stricmp ( sc . String , " latch " ) = = 0 )
{
cvarflags | = CVAR_LATCH ;
}
2016-03-01 15:47:10 +00:00
else
{
sc . ScriptError ( " Unknown cvar attribute '%s' " , sc . String ) ;
}
sc . MustGetAnyToken ( ) ;
}
// Do some sanity checks.
if ( ( cvarflags & ( CVAR_SERVERINFO | CVAR_USERINFO ) ) = = 0 | |
( cvarflags & ( CVAR_SERVERINFO | CVAR_USERINFO ) ) = = ( CVAR_SERVERINFO | CVAR_USERINFO ) )
{
sc . ScriptError ( " One of 'server' or 'user' must be specified " ) ;
}
// The next token must be the cvar type.
if ( sc . TokenType = = TK_Bool )
{
cvartype = CVAR_Bool ;
}
else if ( sc . TokenType = = TK_Int )
{
cvartype = CVAR_Int ;
}
else if ( sc . TokenType = = TK_Float )
{
cvartype = CVAR_Float ;
}
else if ( sc . TokenType = = TK_Color )
{
cvartype = CVAR_Color ;
}
else if ( sc . TokenType = = TK_String )
{
cvartype = CVAR_String ;
}
else
{
sc . ScriptError ( " Bad cvar type '%s' " , sc . String ) ;
}
// The next token must be the cvar name.
sc . MustGetToken ( TK_Identifier ) ;
if ( FindCVar ( sc . String , NULL ) ! = NULL )
{
sc . ScriptError ( " cvar '%s' already exists " , sc . String ) ;
}
cvarname = sc . String ;
// A default value is optional and signalled by a '=' token.
if ( sc . CheckToken ( ' = ' ) )
{
switch ( cvartype )
{
case CVAR_Bool :
if ( ! sc . CheckToken ( TK_True ) & & ! sc . CheckToken ( TK_False ) )
{
sc . ScriptError ( " Expected true or false " ) ;
}
cvardefault = sc . String ;
break ;
case CVAR_Int :
sc . MustGetNumber ( ) ;
cvardefault = sc . String ;
break ;
case CVAR_Float :
sc . MustGetFloat ( ) ;
cvardefault = sc . String ;
break ;
default :
sc . MustGetString ( ) ;
cvardefault = sc . String ;
break ;
}
}
// Now create the cvar.
cvar = C_CreateCVar ( cvarname , cvartype , cvarflags ) ;
if ( cvardefault ! = NULL )
{
UCVarValue val ;
val . String = cvardefault ;
cvar - > SetGenericRepDefault ( val , CVAR_String ) ;
}
// To be like C and ACS, require a semicolon after everything.
sc . MustGetToken ( ' ; ' ) ;
addedcvars = true ;
}
}
// Only load mod cvars from the config if we defined some, so we don't
// clutter up the cvar space when not playing mods with custom cvars.
if ( addedcvars )
{
GameConfig - > DoModSetup ( gameinfo . ConfigName ) ;
}
2018-02-22 06:21:19 +00:00
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// D_AddFile
//
//==========================================================================
bool D_AddFile ( TArray < FString > & wadfiles , const char * file , bool check , int position )
{
if ( file = = NULL | | * file = = ' \0 ' )
{
return false ;
}
if ( check & & ! DirEntryExists ( file ) )
{
const char * f = BaseFileSearch ( file , " .wad " ) ;
if ( f = = NULL )
{
Printf ( " Can't find '%s' \n " , file ) ;
return false ;
}
file = f ;
}
FString f = file ;
FixPathSeperator ( f ) ;
if ( position = = - 1 ) wadfiles . Push ( f ) ;
else wadfiles . Insert ( position , f ) ;
return true ;
}
//==========================================================================
//
// D_AddWildFile
//
//==========================================================================
void D_AddWildFile ( TArray < FString > & wadfiles , const char * value )
{
if ( value = = NULL | | * value = = ' \0 ' )
{
return ;
}
const char * wadfile = BaseFileSearch ( value , " .wad " ) ;
if ( wadfile ! = NULL )
{
D_AddFile ( wadfiles , wadfile ) ;
}
else
{ // Try pattern matching
findstate_t findstate ;
char path [ PATH_MAX ] ;
char * sep ;
void * handle = I_FindFirst ( value , & findstate ) ;
strcpy ( path , value ) ;
sep = strrchr ( path , ' / ' ) ;
if ( sep = = NULL )
{
sep = strrchr ( path , ' \\ ' ) ;
# ifdef _WIN32
if ( sep = = NULL & & path [ 1 ] = = ' : ' )
{
sep = path + 1 ;
}
# endif
}
if ( handle ! = ( ( void * ) - 1 ) )
{
do
{
if ( ! ( I_FindAttr ( & findstate ) & FA_DIREC ) )
{
if ( sep = = NULL )
{
D_AddFile ( wadfiles , I_FindName ( & findstate ) ) ;
}
else
{
strcpy ( sep + 1 , I_FindName ( & findstate ) ) ;
D_AddFile ( wadfiles , path ) ;
}
}
} while ( I_FindNext ( handle , & findstate ) = = 0 ) ;
}
I_FindClose ( handle ) ;
}
}
//==========================================================================
//
// D_AddConfigWads
//
// Adds all files in the specified config file section.
//
//==========================================================================
void D_AddConfigWads ( TArray < FString > & wadfiles , const char * section )
{
if ( GameConfig - > SetSection ( section ) )
{
const char * key ;
const char * value ;
FConfigFile : : Position pos ;
while ( GameConfig - > NextInSection ( key , value ) )
{
if ( stricmp ( key , " Path " ) = = 0 )
{
// D_AddWildFile resets GameConfig's position, so remember it
GameConfig - > GetPosition ( pos ) ;
D_AddWildFile ( wadfiles , ExpandEnvVars ( value ) ) ;
// Reset GameConfig's position to get next wad
GameConfig - > SetPosition ( pos ) ;
}
}
}
}
//==========================================================================
//
// D_AddDirectory
//
// Add all .wad files in a directory. Does not descend into subdirectories.
//
//==========================================================================
static void D_AddDirectory ( TArray < FString > & wadfiles , const char * dir )
{
char curdir [ PATH_MAX ] ;
if ( getcwd ( curdir , PATH_MAX ) )
{
char skindir [ PATH_MAX ] ;
findstate_t findstate ;
void * handle ;
size_t stuffstart ;
stuffstart = strlen ( dir ) ;
memcpy ( skindir , dir , stuffstart * sizeof ( * dir ) ) ;
skindir [ stuffstart ] = 0 ;
if ( skindir [ stuffstart - 1 ] = = ' / ' )
{
skindir [ - - stuffstart ] = 0 ;
}
if ( ! chdir ( skindir ) )
{
skindir [ stuffstart + + ] = ' / ' ;
if ( ( handle = I_FindFirst ( " *.wad " , & findstate ) ) ! = ( void * ) - 1 )
{
do
{
if ( ! ( I_FindAttr ( & findstate ) & FA_DIREC ) )
{
strcpy ( skindir + stuffstart , I_FindName ( & findstate ) ) ;
D_AddFile ( wadfiles , skindir ) ;
}
} while ( I_FindNext ( handle , & findstate ) = = 0 ) ;
I_FindClose ( handle ) ;
}
}
chdir ( curdir ) ;
}
}
//==========================================================================
//
// BaseFileSearch
//
// If a file does not exist at <file>, looks for it in the directories
// specified in the config file. Returns the path to the file, if found,
// or NULL if it could not be found.
//
//==========================================================================
2017-05-13 10:33:14 +00:00
const char * BaseFileSearch ( const char * file , const char * ext , bool lookfirstinprogdir )
2016-03-01 15:47:10 +00:00
{
static char wad [ PATH_MAX ] ;
if ( file = = NULL | | * file = = ' \0 ' )
{
return NULL ;
}
if ( lookfirstinprogdir )
{
2017-10-23 08:55:20 +00:00
mysnprintf ( wad , countof ( wad ) , " %s%s%s " , progdir . GetChars ( ) , progdir . Back ( ) = = ' / ' ? " " : " / " , file ) ;
2016-03-01 15:47:10 +00:00
if ( DirEntryExists ( wad ) )
{
return wad ;
}
}
if ( DirEntryExists ( file ) )
{
mysnprintf ( wad , countof ( wad ) , " %s " , file ) ;
return wad ;
}
if ( GameConfig ! = NULL & & GameConfig - > SetSection ( " FileSearch.Directories " ) )
{
const char * key ;
const char * value ;
while ( GameConfig - > NextInSection ( key , value ) )
{
if ( stricmp ( key , " Path " ) = = 0 )
{
FString dir ;
dir = NicePath ( value ) ;
if ( dir . IsNotEmpty ( ) )
{
2017-10-23 08:55:20 +00:00
mysnprintf ( wad , countof ( wad ) , " %s%s%s " , dir . GetChars ( ) , dir . Back ( ) = = ' / ' ? " " : " / " , file ) ;
2016-03-01 15:47:10 +00:00
if ( DirEntryExists ( wad ) )
{
return wad ;
}
}
}
}
}
// Retry, this time with a default extension
if ( ext ! = NULL )
{
FString tmp = file ;
DefaultExtension ( tmp , ext ) ;
return BaseFileSearch ( tmp , NULL ) ;
}
return NULL ;
}
//==========================================================================
//
// ConsiderPatches
//
// Tries to add any deh/bex patches from the command line.
//
//==========================================================================
bool ConsiderPatches ( const char * arg )
{
int i , argc ;
FString * args ;
const char * f ;
argc = Args - > CheckParmList ( arg , & args ) ;
for ( i = 0 ; i < argc ; + + i )
{
if ( ( f = BaseFileSearch ( args [ i ] , " .deh " ) ) | |
( f = BaseFileSearch ( args [ i ] , " .bex " ) ) )
{
D_LoadDehFile ( f ) ;
}
}
return argc > 0 ;
}
//==========================================================================
//
// D_MultiExec
//
//==========================================================================
2017-04-14 11:31:58 +00:00
FExecList * D_MultiExec ( FArgs * list , FExecList * exec )
2016-03-01 15:47:10 +00:00
{
for ( int i = 0 ; i < list - > NumArgs ( ) ; + + i )
{
exec = C_ParseExecFile ( list - > GetArg ( i ) , exec ) ;
}
return exec ;
}
static void GetCmdLineFiles ( TArray < FString > & wadfiles )
{
FString * args ;
int i , argc ;
argc = Args - > CheckParmList ( " -file " , & args ) ;
for ( i = 0 ; i < argc ; + + i )
{
D_AddWildFile ( wadfiles , args [ i ] ) ;
}
}
static void CopyFiles ( TArray < FString > & to , TArray < FString > & from )
{
unsigned int ndx = to . Reserve ( from . Size ( ) ) ;
for ( unsigned i = 0 ; i < from . Size ( ) ; i + + )
{
to [ ndx + i ] = from [ i ] ;
}
}
static FString ParseGameInfo ( TArray < FString > & pwads , const char * fn , const char * data , int size )
{
FScanner sc ;
FString iwad ;
int pos = 0 ;
const char * lastSlash = strrchr ( fn , ' / ' ) ;
sc . OpenMem ( " GAMEINFO " , data , size ) ;
while ( sc . GetToken ( ) )
{
sc . TokenMustBe ( TK_Identifier ) ;
FString nextKey = sc . String ;
sc . MustGetToken ( ' = ' ) ;
if ( ! nextKey . CompareNoCase ( " IWAD " ) )
{
sc . MustGetString ( ) ;
iwad = sc . String ;
}
else if ( ! nextKey . CompareNoCase ( " LOAD " ) )
{
do
{
sc . MustGetString ( ) ;
// Try looking for the wad in the same directory as the .wad
// before looking for it in the current directory.
FString checkpath ;
if ( lastSlash ! = NULL )
{
checkpath = FString ( fn , ( lastSlash - fn ) + 1 ) ;
checkpath + = sc . String ;
}
else
{
checkpath = sc . String ;
}
if ( ! FileExists ( checkpath ) )
{
pos + = D_AddFile ( pwads , sc . String , true , pos ) ;
}
else
{
pos + = D_AddFile ( pwads , checkpath , true , pos ) ;
}
}
while ( sc . CheckToken ( ' , ' ) ) ;
}
else if ( ! nextKey . CompareNoCase ( " NOSPRITERENAME " ) )
{
sc . MustGetString ( ) ;
nospriterename = sc . Compare ( " true " ) ;
}
else if ( ! nextKey . CompareNoCase ( " STARTUPTITLE " ) )
{
sc . MustGetString ( ) ;
DoomStartupInfo . Name = sc . String ;
}
else if ( ! nextKey . CompareNoCase ( " STARTUPCOLORS " ) )
{
sc . MustGetString ( ) ;
2016-12-03 15:27:53 +00:00
DoomStartupInfo . FgColor = V_GetColor ( NULL , sc ) ;
2016-03-01 15:47:10 +00:00
sc . MustGetStringName ( " , " ) ;
sc . MustGetString ( ) ;
2016-12-03 15:27:53 +00:00
DoomStartupInfo . BkColor = V_GetColor ( NULL , sc ) ;
2016-03-01 15:47:10 +00:00
}
else if ( ! nextKey . CompareNoCase ( " STARTUPTYPE " ) )
{
sc . MustGetString ( ) ;
FString sttype = sc . String ;
if ( ! sttype . CompareNoCase ( " DOOM " ) )
DoomStartupInfo . Type = FStartupInfo : : DoomStartup ;
else if ( ! sttype . CompareNoCase ( " HERETIC " ) )
DoomStartupInfo . Type = FStartupInfo : : HereticStartup ;
else if ( ! sttype . CompareNoCase ( " HEXEN " ) )
DoomStartupInfo . Type = FStartupInfo : : HexenStartup ;
else if ( ! sttype . CompareNoCase ( " STRIFE " ) )
DoomStartupInfo . Type = FStartupInfo : : StrifeStartup ;
else DoomStartupInfo . Type = FStartupInfo : : DefaultStartup ;
}
else if ( ! nextKey . CompareNoCase ( " STARTUPSONG " ) )
{
sc . MustGetString ( ) ;
DoomStartupInfo . Song = sc . String ;
}
2018-12-19 00:37:48 +00:00
else if ( ! nextKey . CompareNoCase ( " LOADLIGHTS " ) )
{
sc . MustGetNumber ( ) ;
DoomStartupInfo . LoadLights = ! ! sc . Number ;
}
else if ( ! nextKey . CompareNoCase ( " LOADBRIGHTMAPS " ) )
{
sc . MustGetNumber ( ) ;
DoomStartupInfo . LoadBrightmaps = ! ! sc . Number ;
}
2016-03-01 15:47:10 +00:00
else
{
// Silently ignore unknown properties
do
{
sc . MustGetAnyToken ( ) ;
}
while ( sc . CheckToken ( ' , ' ) ) ;
}
}
return iwad ;
}
static FString CheckGameInfo ( TArray < FString > & pwads )
{
// scan the list of WADs backwards to find the last one that contains a GAMEINFO lump
for ( int i = pwads . Size ( ) - 1 ; i > = 0 ; i - - )
{
bool isdir = false ;
FResourceFile * resfile ;
const char * filename = pwads [ i ] ;
// Does this exist? If so, is it a directory?
2017-12-02 15:07:09 +00:00
if ( ! DirEntryExists ( pwads [ i ] , & isdir ) )
2016-03-01 15:47:10 +00:00
{
Printf ( TEXTCOLOR_RED " Could not stat %s \n " , filename ) ;
continue ;
}
if ( ! isdir )
{
2018-03-11 17:32:00 +00:00
FileReader fr ;
2018-03-11 11:33:46 +00:00
if ( ! fr . OpenFile ( filename ) )
2016-03-01 15:47:10 +00:00
{
// Didn't find file
continue ;
}
2018-03-11 11:33:46 +00:00
resfile = FResourceFile : : OpenResourceFile ( filename , fr , true ) ;
2016-03-01 15:47:10 +00:00
}
else
resfile = FResourceFile : : OpenDirectory ( filename , true ) ;
if ( resfile ! = NULL )
{
2017-03-08 17:50:37 +00:00
uint32_t cnt = resfile - > LumpCount ( ) ;
2016-03-01 15:47:10 +00:00
for ( int i = cnt - 1 ; i > = 0 ; i - - )
{
FResourceLump * lmp = resfile - > GetLump ( i ) ;
if ( lmp - > Namespace = = ns_global & & ! stricmp ( lmp - > Name , " GAMEINFO " ) )
{
// Found one!
2018-11-10 13:19:55 +00:00
FString iwad = ParseGameInfo ( pwads , resfile - > FileName , ( const char * ) lmp - > CacheLump ( ) , lmp - > LumpSize ) ;
2016-03-01 15:47:10 +00:00
delete resfile ;
return iwad ;
}
}
delete resfile ;
}
}
return " " ;
}
//==========================================================================
//
// Checks the IWAD for MAP01 and if found sets GI_MAPxx
//
//==========================================================================
static void SetMapxxFlag ( )
{
2017-09-13 08:19:03 +00:00
int lump_name = Wads . CheckNumForName ( " MAP01 " , ns_global , Wads . GetIwadNum ( ) ) ;
int lump_wad = Wads . CheckNumForFullName ( " maps/map01.wad " , Wads . GetIwadNum ( ) ) ;
int lump_map = Wads . CheckNumForFullName ( " maps/map01.map " , Wads . GetIwadNum ( ) ) ;
2016-03-01 15:47:10 +00:00
if ( lump_name > = 0 | | lump_wad > = 0 | | lump_map > = 0 ) gameinfo . flags | = GI_MAPxx ;
}
//==========================================================================
//
// Initialize
//
//==========================================================================
static void D_DoomInit ( )
{
// Set the FPU precision to 53 significant bits. This is the default
// for Visual C++, but not for GCC, so some slight math variances
// might crop up if we leave it alone.
2016-03-09 04:00:16 +00:00
# if defined(_FPU_GETCW) && defined(_FPU_EXTENDED) && defined(_FPU_DOUBLE)
2016-03-01 15:47:10 +00:00
{
int cw ;
_FPU_GETCW ( cw ) ;
cw = ( cw & ~ _FPU_EXTENDED ) | _FPU_DOUBLE ;
_FPU_SETCW ( cw ) ;
}
# elif defined(_PC_53)
// On the x64 architecture, changing the floating point precision is not supported.
# ifndef _WIN64
int cfp = _control87 ( _PC_53 , _MCW_PC ) ;
# endif
# endif
// Check response files before coalescing file parameters.
M_FindResponseFile ( ) ;
// Combine different file parameters with their pre-switch bits.
Args - > CollectFiles ( " -deh " , " .deh " ) ;
Args - > CollectFiles ( " -bex " , " .bex " ) ;
Args - > CollectFiles ( " -exec " , " .cfg " ) ;
Args - > CollectFiles ( " -playdemo " , " .lmp " ) ;
Args - > CollectFiles ( " -file " , NULL ) ; // anything left goes after -file
gamestate = GS_STARTUP ;
const char * v = Args - > CheckValue ( " -rngseed " ) ;
if ( v )
{
rngseed = staticrngseed = atoi ( v ) ;
use_staticrng = true ;
if ( ! batchrun ) Printf ( " D_DoomInit: Static RNGseed %d set. \n " , rngseed ) ;
}
else
{
rngseed = I_MakeRNGSeed ( ) ;
use_staticrng = false ;
}
2017-07-15 07:34:07 +00:00
srand ( rngseed ) ;
2016-03-01 15:47:10 +00:00
FRandom : : StaticClearRandom ( ) ;
if ( ! batchrun ) Printf ( " M_LoadDefaults: Load system defaults. \n " ) ;
M_LoadDefaults ( ) ; // load before initing other systems
}
//==========================================================================
//
// AddAutoloadFiles
//
//==========================================================================
static void AddAutoloadFiles ( const char * autoname )
{
LumpFilterIWAD . Format ( " %s. " , autoname ) ; // The '.' is appened to simplify parsing the string
2016-12-21 10:11:29 +00:00
// [SP] Dialog reaction - load lights.pk3 and brightmaps.pk3 based on user choices
if ( ! ( gameinfo . flags & GI_SHAREWARE ) )
{
2018-12-19 00:37:48 +00:00
if ( DoomStartupInfo . LoadLights = = 1 | | ( DoomStartupInfo . LoadLights ! = 0 & & autoloadlights ) )
2016-12-21 10:11:29 +00:00
{
const char * lightswad = BaseFileSearch ( " lights.pk3 " , NULL ) ;
if ( lightswad )
D_AddFile ( allwads , lightswad ) ;
}
2018-12-19 00:37:48 +00:00
if ( DoomStartupInfo . LoadBrightmaps = = 1 | | ( DoomStartupInfo . LoadBrightmaps ! = 0 & & autoloadbrightmaps ) )
2016-12-21 10:11:29 +00:00
{
const char * bmwad = BaseFileSearch ( " brightmaps.pk3 " , NULL ) ;
if ( bmwad )
D_AddFile ( allwads , bmwad ) ;
}
}
2016-12-21 04:03:06 +00:00
if ( ! ( gameinfo . flags & GI_SHAREWARE ) & & ! Args - > CheckParm ( " -noautoload " ) & & ! disableautoload )
2016-03-01 15:47:10 +00:00
{
FString file ;
// [RH] zvox.wad - A wad I had intended to be automatically generated
// from Q2's pak0.pak so the female and cyborg player could have
// voices. I never got around to writing the utility to do it, though.
// And I probably never will now. But I know at least one person uses
// it for something else, so this gets to stay here.
const char * wad = BaseFileSearch ( " zvox.wad " , NULL ) ;
if ( wad )
D_AddFile ( allwads , wad ) ;
// [RH] Add any .wad files in the skins directory
# ifdef __unix__
file = SHARE_DIR ;
# else
file = progdir ;
# endif
file + = " skins " ;
D_AddDirectory ( allwads , file ) ;
# ifdef __unix__
2017-12-10 16:27:36 +00:00
file = NicePath ( " $HOME/ " GAME_DIR " /skins " ) ;
2016-03-01 15:47:10 +00:00
D_AddDirectory ( allwads , file ) ;
# endif
// Add common (global) wads
D_AddConfigWads ( allwads , " Global.Autoload " ) ;
long len ;
int lastpos = - 1 ;
while ( ( len = LumpFilterIWAD . IndexOf ( ' . ' , lastpos + 1 ) ) > 0 )
{
file = LumpFilterIWAD . Left ( len ) + " .Autoload " ;
D_AddConfigWads ( allwads , file ) ;
lastpos = len ;
}
}
}
//==========================================================================
//
// CheckCmdLine
//
//==========================================================================
static void CheckCmdLine ( )
{
int flags = dmflags ;
int p ;
const char * v ;
if ( ! batchrun ) Printf ( " Checking cmd-line parameters... \n " ) ;
if ( Args - > CheckParm ( " -nomonsters " ) ) flags | = DF_NO_MONSTERS ;
if ( Args - > CheckParm ( " -respawn " ) ) flags | = DF_MONSTERS_RESPAWN ;
if ( Args - > CheckParm ( " -fast " ) ) flags | = DF_FAST_MONSTERS ;
devparm = ! ! Args - > CheckParm ( " -devparm " ) ;
if ( Args - > CheckParm ( " -altdeath " ) )
{
deathmatch = 1 ;
flags | = DF_ITEMS_RESPAWN ;
}
else if ( Args - > CheckParm ( " -deathmatch " ) )
{
deathmatch = 1 ;
flags | = DF_WEAPONS_STAY | DF_ITEMS_RESPAWN ;
}
dmflags = flags ;
// get skill / episode / map from parms
if ( gameinfo . gametype ! = GAME_Hexen )
{
startmap = ( gameinfo . flags & GI_MAPxx ) ? " MAP01 " : " E1M1 " ;
}
else
{
startmap = " &wt@01 " ;
}
autostart = StoredWarp . IsNotEmpty ( ) ;
const char * val = Args - > CheckValue ( " -skill " ) ;
if ( val )
{
gameskill = val [ 0 ] - ' 1 ' ;
autostart = true ;
}
p = Args - > CheckParm ( " -warp " ) ;
if ( p & & p < Args - > NumArgs ( ) - 1 )
{
int ep , map ;
if ( gameinfo . flags & GI_MAPxx )
{
ep = 1 ;
map = atoi ( Args - > GetArg ( p + 1 ) ) ;
}
else
{
ep = atoi ( Args - > GetArg ( p + 1 ) ) ;
map = p < Args - > NumArgs ( ) - 2 ? atoi ( Args - > GetArg ( p + 2 ) ) : 10 ;
if ( map < 1 | | map > 9 )
{
map = ep ;
ep = 1 ;
}
}
startmap = CalcMapName ( ep , map ) ;
autostart = true ;
}
// [RH] Hack to handle +map. The standard console command line handler
// won't be able to handle it, so we take it out of the command line and set
// it up like -warp.
FString mapvalue = Args - > TakeValue ( " +map " ) ;
if ( mapvalue . IsNotEmpty ( ) )
{
if ( ! P_CheckMapData ( mapvalue ) )
{
Printf ( " Can't find map %s \n " , mapvalue . GetChars ( ) ) ;
}
else
{
startmap = mapvalue ;
autostart = true ;
}
}
if ( devparm )
{
Printf ( " %s " , GStrings ( " D_DEVSTR " ) ) ;
}
// turbo option // [RH] (now a cvar)
v = Args - > CheckValue ( " -turbo " ) ;
if ( v ! = NULL )
{
double amt = atof ( v ) ;
Printf ( " turbo scale: %.0f%% \n " , amt ) ;
turbo = ( float ) amt ;
}
v = Args - > CheckValue ( " -timer " ) ;
if ( v )
{
double time = strtod ( v , NULL ) ;
Printf ( " Levels will end after %g minute%s. \n " , time , time > 1 ? " s " : " " ) ;
timelimit = ( float ) time ;
}
v = Args - > CheckValue ( " -avg " ) ;
if ( v )
{
Printf ( " Austin Virtual Gaming: Levels will end after 20 minutes \n " ) ;
timelimit = 20.f ;
}
//
// Build status bar line!
//
if ( deathmatch )
StartScreen - > AppendStatusLine ( " DeathMatch... " ) ;
if ( dmflags & DF_NO_MONSTERS )
StartScreen - > AppendStatusLine ( " No Monsters... " ) ;
if ( dmflags & DF_MONSTERS_RESPAWN )
StartScreen - > AppendStatusLine ( " Respawning... " ) ;
if ( autostart )
{
FString temp ;
temp . Format ( " Warp to map %s, Skill %d " , startmap . GetChars ( ) , gameskill + 1 ) ;
StartScreen - > AppendStatusLine ( temp ) ;
}
}
2019-10-06 22:01:12 +00:00
//==========================================================================
//
// I_Error
//
// Throw an error that will send us to the console if we are far enough
// along in the startup process.
//
//==========================================================================
void I_Error ( const char * error , . . . )
{
va_list argptr ;
char errortext [ MAX_ERRORTEXT ] ;
va_start ( argptr , error ) ;
myvsnprintf ( errortext , MAX_ERRORTEXT , error , argptr ) ;
va_end ( argptr ) ;
I_DebugPrint ( errortext ) ;
throw CRecoverableError ( errortext ) ;
}
2019-10-06 22:20:07 +00:00
//==========================================================================
//
// I_FatalError
//
// Throw an error that will end the game.
//
//==========================================================================
extern FILE * Logfile ;
void I_FatalError ( const char * error , . . . )
{
static bool alreadyThrown = false ;
gameisdead = true ;
if ( ! alreadyThrown ) // ignore all but the first message -- killough
{
alreadyThrown = true ;
char errortext [ MAX_ERRORTEXT ] ;
va_list argptr ;
va_start ( argptr , error ) ;
myvsnprintf ( errortext , MAX_ERRORTEXT , error , argptr ) ;
va_end ( argptr ) ;
I_DebugPrint ( errortext ) ;
// Record error to log (if logging)
if ( Logfile )
{
fprintf ( Logfile , " \n **** DIED WITH FATAL ERROR: \n %s \n " , errortext ) ;
fflush ( Logfile ) ;
}
throw CFatalError ( errortext ) ;
}
std : : terminate ( ) ; // recursive I_FatalErrors must immediately terminate.
}
2019-10-06 22:37:56 +00:00
static void NewFailure ( )
{
I_FatalError ( " Failed to allocate memory from system heap " ) ;
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// D_DoomMain
//
//==========================================================================
2019-10-06 22:55:14 +00:00
static int D_DoomMain_Internal ( void )
2016-03-01 15:47:10 +00:00
{
int p ;
const char * v ;
const char * wad ;
TArray < FString > pwads ;
FString * args ;
int argcount ;
FIWadManager * iwad_man ;
2019-10-06 22:37:56 +00:00
std : : set_new_handler ( NewFailure ) ;
2016-03-01 15:47:10 +00:00
const char * batchout = Args - > CheckValue ( " -errorlog " ) ;
2019-09-30 23:00:37 +00:00
C_InitConsole ( 80 * 8 , 25 * 8 , false ) ;
2019-09-30 23:02:49 +00:00
I_DetectOS ( ) ;
2016-03-01 15:47:10 +00:00
// +logfile gets checked too late to catch the full startup log in the logfile so do some extra check for it here.
FString logfile = Args - > TakeValue ( " +logfile " ) ;
if ( logfile . IsNotEmpty ( ) )
{
execLogfile ( logfile ) ;
}
else if ( batchout ! = NULL & & * batchout ! = 0 )
{
batchrun = true ;
execLogfile ( batchout , true ) ;
Printf ( " Command line: " ) ;
for ( int i = 0 ; i < Args - > NumArgs ( ) ; i + + )
{
Printf ( " %s " , Args - > GetArg ( i ) ) ;
}
Printf ( " \n " ) ;
}
if ( Args - > CheckParm ( " -hashfiles " ) )
{
const char * filename = " fileinfo.txt " ;
Printf ( " Hashing loaded content to: %s \n " , filename ) ;
hashfile = fopen ( filename , " w " ) ;
if ( hashfile )
{
fprintf ( hashfile , " %s version %s (%s) \n " , GAMENAME , GetVersionString ( ) , GetGitHash ( ) ) ;
# ifdef __VERSION__
fprintf ( hashfile , " Compiler version: %s \n " , __VERSION__ ) ;
# endif
fprintf ( hashfile , " Command line: " ) ;
for ( int i = 0 ; i < Args - > NumArgs ( ) ; + + i )
{
fprintf ( hashfile , " %s " , Args - > GetArg ( i ) ) ;
}
fprintf ( hashfile , " \n " ) ;
}
}
2017-08-19 18:13:12 +00:00
if ( ! batchrun ) Printf ( PRINT_LOG , " %s version %s \n " , GAMENAME , GetVersionString ( ) ) ;
2016-03-01 15:47:10 +00:00
D_DoomInit ( ) ;
2018-03-14 08:20:46 +00:00
extern void D_ConfirmSendStats ( ) ;
D_ConfirmSendStats ( ) ;
2016-03-01 15:47:10 +00:00
// [RH] Make sure zdoom.pk3 is always loaded,
// as it contains magic stuff we need.
wad = BaseFileSearch ( BASEWAD , NULL , true ) ;
if ( wad = = NULL )
{
I_FatalError ( " Cannot find " BASEWAD ) ;
}
FString basewad = wad ;
2017-09-09 10:36:20 +00:00
FString optionalwad = BaseFileSearch ( OPTIONALWAD , NULL , true ) ;
2019-07-16 18:22:15 +00:00
iwad_man = new FIWadManager ( basewad , optionalwad ) ;
2016-03-01 15:47:10 +00:00
// Now that we have the IWADINFO, initialize the autoload ini sections.
GameConfig - > DoAutoloadSetup ( iwad_man ) ;
// reinit from here
do
{
PClass : : StaticInit ( ) ;
PType : : StaticInit ( ) ;
if ( restart )
{
C_InitConsole ( SCREENWIDTH , SCREENHEIGHT , false ) ;
}
nospriterename = false ;
// Load zdoom.pk3 alone so that we can get access to the internal gameinfos before
// the IWAD is known.
GetCmdLineFiles ( pwads ) ;
FString iwad = CheckGameInfo ( pwads ) ;
// The IWAD selection dialogue does not show in fullscreen so if the
// restart is initiated without a defined IWAD assume for now that it's not going to change.
if ( iwad . IsEmpty ( ) ) iwad = lastIWAD ;
if ( iwad_man = = NULL )
{
2019-07-16 18:22:15 +00:00
iwad_man = new FIWadManager ( basewad , optionalwad ) ;
2016-03-01 15:47:10 +00:00
}
2017-09-09 10:36:20 +00:00
const FIWADInfo * iwad_info = iwad_man - > FindIWAD ( allwads , iwad , basewad , optionalwad ) ;
2019-10-06 23:24:51 +00:00
if ( ! iwad_info ) return 0 ; // user exited the selection popup via cancel button.
2016-03-01 15:47:10 +00:00
gameinfo . gametype = iwad_info - > gametype ;
gameinfo . flags = iwad_info - > flags ;
gameinfo . ConfigName = iwad_info - > Configname ;
lastIWAD = iwad ;
if ( ( gameinfo . flags & GI_SHAREWARE ) & & pwads . Size ( ) > 0 )
{
I_FatalError ( " You cannot -file with the shareware version. Register! " ) ;
}
FBaseCVar : : DisableCallbacks ( ) ;
GameConfig - > DoGameSetup ( gameinfo . ConfigName ) ;
AddAutoloadFiles ( iwad_info - > Autoname ) ;
// Process automatically executed files
FExecList * exec ;
2017-04-14 11:31:58 +00:00
FArgs * execFiles = new FArgs ;
2016-03-01 15:47:10 +00:00
GameConfig - > AddAutoexec ( execFiles , gameinfo . ConfigName ) ;
exec = D_MultiExec ( execFiles , NULL ) ;
2017-04-14 11:31:58 +00:00
delete execFiles ;
2016-03-01 15:47:10 +00:00
// Process .cfg files at the start of the command line.
execFiles = Args - > GatherFiles ( " -exec " ) ;
exec = D_MultiExec ( execFiles , exec ) ;
2017-04-14 11:31:58 +00:00
delete execFiles ;
2016-03-01 15:47:10 +00:00
// [RH] process all + commands on the command line
exec = C_ParseCmdLineParams ( exec ) ;
CopyFiles ( allwads , pwads ) ;
if ( exec ! = NULL )
{
exec - > AddPullins ( allwads ) ;
}
// Since this function will never leave we must delete this array here manually.
pwads . Clear ( ) ;
pwads . ShrinkToFit ( ) ;
if ( hashfile )
{
Printf ( " Notice: File hashing is incredibly verbose. Expect loading files to take much longer than usual. \n " ) ;
}
if ( ! batchrun ) Printf ( " W_Init: Init WADfiles. \n " ) ;
2019-04-14 20:46:03 +00:00
Wads . InitMultipleFiles ( allwads , iwad_info - > DeleteLumps ) ;
2016-03-01 15:47:10 +00:00
allwads . Clear ( ) ;
allwads . ShrinkToFit ( ) ;
SetMapxxFlag ( ) ;
GameConfig - > DoKeySetup ( gameinfo . ConfigName ) ;
// Now that wads are loaded, define mod-specific cvars.
ParseCVarInfo ( ) ;
// Actually exec command line commands and exec files.
if ( exec ! = NULL )
{
exec - > ExecCommands ( ) ;
delete exec ;
exec = NULL ;
}
// [RH] Initialize localizable strings.
2019-02-06 12:59:41 +00:00
GStrings . LoadStrings ( ) ;
2016-03-01 15:47:10 +00:00
V_InitFontColors ( ) ;
// [RH] Moved these up here so that we can do most of our
// startup output in a fullscreen console.
CT_Init ( ) ;
if ( ! restart )
{
if ( ! batchrun ) Printf ( " I_Init: Setting up machine state. \n " ) ;
I_Init ( ) ;
}
2019-09-30 22:21:51 +00:00
// [RH] Initialize palette management
InitPalette ( ) ;
2016-03-01 15:47:10 +00:00
if ( ! batchrun ) Printf ( " V_Init: allocate screen. \n " ) ;
2019-09-30 22:21:51 +00:00
if ( ! restart )
{
V_InitScreenSize ( ) ;
}
if ( ! restart )
{
// This allocates a dummy framebuffer as a stand-in until V_Init2 is called.
V_InitScreen ( ) ;
}
if ( restart )
{
// Update screen palette when restarting
screen - > UpdatePalette ( ) ;
}
2016-03-01 15:47:10 +00:00
// Base systems have been inited; enable cvar callbacks
FBaseCVar : : EnableCallbacks ( ) ;
if ( ! batchrun ) Printf ( " S_Init: Setting up sound. \n " ) ;
S_Init ( ) ;
if ( ! batchrun ) Printf ( " ST_Init: Init startup screen. \n " ) ;
if ( ! restart )
{
StartScreen = FStartupScreen : : CreateInstance ( TexMan . GuesstimateNumTextures ( ) + 5 ) ;
}
else
{
StartScreen = new FStartupScreen ( 0 ) ;
}
CheckCmdLine ( ) ;
// [RH] Load sound environments
S_ParseReverbDef ( ) ;
// [RH] Parse any SNDINFO lumps
if ( ! batchrun ) Printf ( " S_InitData: Load sound definitions. \n " ) ;
S_InitData ( ) ;
// [RH] Parse through all loaded mapinfo lumps
if ( ! batchrun ) Printf ( " G_ParseMapInfo: Load map definitions. \n " ) ;
G_ParseMapInfo ( iwad_info - > MapInfo ) ;
ReadStatistics ( ) ;
// MUSINFO must be parsed after MAPINFO
S_ParseMusInfo ( ) ;
if ( ! batchrun ) Printf ( " Texman.Init: Init texture manager. \n " ) ;
TexMan . Init ( ) ;
C_InitConback ( ) ;
2017-02-05 12:14:22 +00:00
StartScreen - > Progress ( ) ;
V_InitFonts ( ) ;
2016-03-01 15:47:10 +00:00
// [CW] Parse any TEAMINFO lumps.
if ( ! batchrun ) Printf ( " ParseTeamInfo: Load team definitions. \n " ) ;
TeamLibrary . ParseTeamInfo ( ) ;
2016-10-02 11:35:25 +00:00
R_ParseTrnslate ( ) ;
2016-03-01 15:47:10 +00:00
PClassActor : : StaticInit ( ) ;
// [GRB] Initialize player class list
SetupPlayerClasses ( ) ;
// [RH] Load custom key and weapon settings from WADs
D_LoadWadSettings ( ) ;
// [GRB] Check if someone used clearplayerclasses but not addplayerclass
if ( PlayerClasses . Size ( ) = = 0 )
{
I_FatalError ( " No player classes defined " ) ;
}
StartScreen - > Progress ( ) ;
2017-03-12 15:56:00 +00:00
ParseGLDefs ( ) ;
2016-03-01 15:47:10 +00:00
if ( ! batchrun ) Printf ( " R_Init: Init %s refresh subsystem. \n " , gameinfo . ConfigName . GetChars ( ) ) ;
StartScreen - > LoadingStatus ( " Loading graphics " , 0x3f ) ;
R_Init ( ) ;
if ( ! batchrun ) Printf ( " DecalLibrary: Load decals. \n " ) ;
DecalLibrary . ReadAllDecals ( ) ;
2017-04-04 09:20:12 +00:00
// Load embedded Dehacked patches
D_LoadDehLumps ( FromIWAD ) ;
2016-03-01 15:47:10 +00:00
// [RH] Add any .deh and .bex files on the command line.
// If there are none, try adding any in the config file.
// Note that the command line overrides defaults from the config.
if ( ( ConsiderPatches ( " -deh " ) | ConsiderPatches ( " -bex " ) ) = = 0 & &
gameinfo . gametype = = GAME_Doom & & GameConfig - > SetSection ( " Doom.DefaultDehacked " ) )
{
const char * key ;
const char * value ;
while ( GameConfig - > NextInSection ( key , value ) )
{
if ( stricmp ( key , " Path " ) = = 0 & & FileExists ( value ) )
{
if ( ! batchrun ) Printf ( " Applying patch %s \n " , value ) ;
D_LoadDehFile ( value ) ;
}
}
}
// Load embedded Dehacked patches
2017-04-04 09:20:12 +00:00
D_LoadDehLumps ( FromPWADs ) ;
2016-03-01 15:47:10 +00:00
// Create replacements for dehacked pickups
FinishDehPatch ( ) ;
2017-02-11 20:28:48 +00:00
if ( ! batchrun ) Printf ( " M_Init: Init menus. \n " ) ;
M_Init ( ) ;
2017-01-24 10:57:42 +00:00
// clean up the compiler symbols which are not needed any longer.
RemoveUnusedSymbols ( ) ;
2016-03-01 15:47:10 +00:00
InitActorNumsFromMapinfo ( ) ;
InitSpawnablesFromMapinfo ( ) ;
PClassActor : : StaticSetActorNums ( ) ;
//Added by MC:
2019-02-01 23:24:43 +00:00
primaryLevel - > BotInfo . getspawned . Clear ( ) ;
2016-03-01 15:47:10 +00:00
argcount = Args - > CheckParmList ( " -bots " , & args ) ;
for ( p = 0 ; p < argcount ; + + p )
{
2019-02-01 23:24:43 +00:00
primaryLevel - > BotInfo . getspawned . Push ( args [ p ] ) ;
2016-03-01 15:47:10 +00:00
}
2019-02-01 23:24:43 +00:00
primaryLevel - > BotInfo . spawn_tries = 0 ;
primaryLevel - > BotInfo . wanted_botnum = primaryLevel - > BotInfo . getspawned . Size ( ) ;
2016-03-01 15:47:10 +00:00
if ( ! batchrun ) Printf ( " P_Init: Init Playloop state. \n " ) ;
StartScreen - > LoadingStatus ( " Init game engine " , 0x3f ) ;
AM_StaticInit ( ) ;
P_Init ( ) ;
P_SetupWeapons_ntohton ( ) ;
2017-03-26 20:04:58 +00:00
//SBarInfo support. Note that the first SBARINFO lump contains the mugshot definition so it even needs to be read when a regular status bar is being used.
SBarInfo : : Load ( ) ;
2016-03-01 15:47:10 +00:00
if ( ! batchrun )
{
// [RH] User-configurable startup strings. Because BOOM does.
static const char * startupString [ 5 ] = {
" STARTUP1 " , " STARTUP2 " , " STARTUP3 " , " STARTUP4 " , " STARTUP5 "
} ;
for ( p = 0 ; p < 5 ; + + p )
{
2019-03-02 11:06:24 +00:00
// At this point we cannot use the player's gender info yet so force 'male' here.
const char * str = GStrings . GetString ( startupString [ p ] , nullptr , 0 ) ;
2016-03-01 15:47:10 +00:00
if ( str ! = NULL & & str [ 0 ] ! = ' \0 ' )
{
Printf ( " %s \n " , str ) ;
}
}
}
if ( ! restart )
{
if ( ! batchrun ) Printf ( " D_CheckNetGame: Checking network game status. \n " ) ;
StartScreen - > LoadingStatus ( " Checking network game status. " , 0x3f ) ;
2019-10-06 22:55:14 +00:00
if ( ! D_CheckNetGame ( ) )
{
return 0 ;
}
2016-03-01 15:47:10 +00:00
}
2017-06-04 00:00:53 +00:00
// [SP] Force vanilla transparency auto-detection to re-detect our game lumps now
UpdateVanillaTransparency ( ) ;
2016-03-01 15:47:10 +00:00
// [RH] Lock any cvars that should be locked now that we're
// about to begin the game.
FBaseCVar : : EnableNoSet ( ) ;
delete iwad_man ; // now we won't need this anymore
iwad_man = NULL ;
// [RH] Run any saved commands from the command line or autoexec.cfg now.
gamestate = GS_FULLCONSOLE ;
Net_NewMakeTic ( ) ;
2019-01-27 09:23:47 +00:00
C_RunDelayedCommands ( ) ;
2016-03-01 15:47:10 +00:00
gamestate = GS_STARTUP ;
if ( ! restart )
{
// start the apropriate game based on parms
v = Args - > CheckValue ( " -record " ) ;
if ( v )
{
G_RecordDemo ( v ) ;
autostart = true ;
}
delete StartScreen ;
StartScreen = NULL ;
S_Sound ( CHAN_BODY , " misc/startupdone " , 1 , ATTN_NONE ) ;
if ( Args - > CheckParm ( " -norun " ) | | batchrun )
{
2019-10-06 22:55:14 +00:00
return 1337 ; // special exit
2016-03-01 15:47:10 +00:00
}
V_Init2 ( ) ;
UpdateJoystickMenu ( NULL ) ;
2019-03-01 05:19:09 +00:00
UpdateVRModes ( ) ;
2016-03-01 15:47:10 +00:00
v = Args - > CheckValue ( " -loadgame " ) ;
if ( v )
{
FString file ( v ) ;
FixPathSeperator ( file ) ;
2016-09-21 15:37:56 +00:00
DefaultExtension ( file , " . " SAVEGAME_EXT ) ;
2016-03-01 15:47:10 +00:00
G_LoadGame ( file ) ;
}
v = Args - > CheckValue ( " -playdemo " ) ;
if ( v ! = NULL )
{
singledemo = true ; // quit after one demo
G_DeferedPlayDemo ( v ) ;
D_DoomLoop ( ) ; // never returns
}
2016-12-03 14:44:46 +00:00
else
2016-03-01 15:47:10 +00:00
{
2016-12-03 14:44:46 +00:00
v = Args - > CheckValue ( " -timedemo " ) ;
if ( v )
2016-03-01 15:47:10 +00:00
{
2016-12-03 14:44:46 +00:00
G_TimeDemo ( v ) ;
D_DoomLoop ( ) ; // never returns
}
else
{
if ( gameaction ! = ga_loadgame & & gameaction ! = ga_loadgamehidecon )
2016-03-01 15:47:10 +00:00
{
2016-12-03 14:44:46 +00:00
if ( autostart | | netgame )
{
// Do not do any screenwipes when autostarting a game.
if ( ! Args - > CheckParm ( " -warpwipe " ) )
{
NoWipe = TICRATE ;
}
CheckWarpTransMap ( startmap , true ) ;
if ( demorecording )
G_BeginRecording ( startmap ) ;
G_InitNew ( startmap , false ) ;
if ( StoredWarp . IsNotEmpty ( ) )
{
2019-01-27 09:23:47 +00:00
AddCommandString ( StoredWarp ) ;
2019-02-14 21:22:15 +00:00
StoredWarp = " " ;
2016-12-03 14:44:46 +00:00
}
}
else
{
D_StartTitle ( ) ; // start up intro loop
}
2016-03-01 15:47:10 +00:00
}
2016-12-03 14:44:46 +00:00
else if ( demorecording )
2016-03-01 15:47:10 +00:00
{
2016-12-03 14:44:46 +00:00
G_BeginRecording ( NULL ) ;
2016-03-01 15:47:10 +00:00
}
}
}
}
else
{
// These calls from inside V_Init2 are still necessary
C_NewModeAdjust ( ) ;
D_StartTitle ( ) ; // start up intro loop
setmodeneeded = false ; // This may be set to true here, but isn't needed for a restart
}
2018-03-05 04:49:01 +00:00
D_DoAnonStats ( ) ;
2017-10-31 23:47:56 +00:00
if ( I_FriendlyWindowTitle )
I_SetWindowTitle ( DoomStartupInfo . Name . GetChars ( ) ) ;
2016-03-08 12:07:21 +00:00
D_DoomLoop ( ) ; // this only returns if a 'restart' CCMD is given.
//
// Clean up after a restart
//
2016-03-01 15:47:10 +00:00
2019-09-30 22:30:44 +00:00
D_Cleanup ( ) ;
2018-05-27 13:15:05 +00:00
gamestate = GS_STARTUP ;
2016-03-01 15:47:10 +00:00
}
while ( 1 ) ;
}
2019-10-06 22:37:56 +00:00
int D_DoomMain ( )
{
int ret = 0 ;
try
{
2019-10-06 22:55:14 +00:00
ret = D_DoomMain_Internal ( ) ;
2019-10-06 22:37:56 +00:00
}
2019-10-06 23:24:51 +00:00
catch ( const CExitEvent & exit ) // This is a regular exit initiated from deeply nested code.
{
ret = exit . Reason ( ) ;
}
catch ( const std : : exception & error )
2019-10-06 22:37:56 +00:00
{
I_ShowFatalError ( error . what ( ) ) ;
ret = - 1 ;
}
// Unless something really bad happened, the game should only exit through this single point in the code.
// No more 'exit', please.
// Todo: Move all engine cleanup here instead of using exit handlers and replace the scattered 'exit' calls with a special exception.
2019-10-07 18:28:55 +00:00
D_Cleanup ( ) ;
CloseNetwork ( ) ;
GC : : FinalGC = true ;
GC : : FullGC ( ) ;
GC : : DelSoftRootHead ( ) ; // the soft root head will not be collected by a GC so we have to do it explicitly
C_DeinitConsole ( ) ;
R_DeinitColormaps ( ) ;
R_Shutdown ( ) ;
I_ShutdownGraphics ( ) ;
I_ShutdownInput ( ) ;
M_SaveDefaultsFinal ( ) ;
DeleteStartupScreen ( ) ;
delete Args ;
Args = nullptr ;
2019-10-06 22:37:56 +00:00
return ret ;
}
2019-09-30 22:30:44 +00:00
//==========================================================================
//
// clean up the resources
//
//==========================================================================
void D_Cleanup ( )
{
2019-10-07 18:28:55 +00:00
if ( demorecording )
{
G_CheckDemoStatus ( ) ;
}
2019-09-30 22:30:44 +00:00
// Music and sound should be stopped first
S_StopMusic ( true ) ;
S_StopAllChannels ( ) ;
2019-10-07 18:28:55 +00:00
S_ClearSoundData ( ) ;
S_UnloadReverbDef ( ) ;
G_ClearMapinfo ( ) ;
2019-09-30 22:30:44 +00:00
M_ClearMenus ( ) ; // close menu if open
F_EndFinale ( ) ; // If an intermission is active, end it now
AM_ClearColorsets ( ) ;
2019-10-07 18:28:55 +00:00
DeinitSWColorMaps ( ) ;
FreeSBarInfoScript ( ) ;
2019-09-30 22:30:44 +00:00
// clean up game state
ST_Clear ( ) ;
D_ErrorCleanup ( ) ;
2019-10-07 18:28:55 +00:00
P_Shutdown ( ) ;
2019-09-30 22:30:44 +00:00
M_SaveDefaults ( NULL ) ; // save config before the restart
// delete all data that cannot be left until reinitialization
2019-10-08 10:18:59 +00:00
if ( screen ) screen - > CleanForRestart ( ) ;
2019-09-30 22:30:44 +00:00
V_ClearFonts ( ) ; // must clear global font pointers
ColorSets . Clear ( ) ;
PainFlashes . Clear ( ) ;
R_DeinitTranslationTables ( ) ; // some tables are initialized from outside the translation code.
gameinfo . ~ gameinfo_t ( ) ;
new ( & gameinfo ) gameinfo_t ; // Reset gameinfo
S_Shutdown ( ) ; // free all channels and delete playlist
C_ClearAliases ( ) ; // CCMDs won't be reinitialized so these need to be deleted here
DestroyCVarsFlagged ( CVAR_MOD ) ; // Delete any cvar left by mods
DeinitMenus ( ) ;
LightDefaults . DeleteAndClear ( ) ; // this can leak heap memory if it isn't cleared.
// delete DoomStartupInfo data
DoomStartupInfo . Name = " " ;
DoomStartupInfo . BkColor = DoomStartupInfo . FgColor = DoomStartupInfo . Type = 0 ;
DoomStartupInfo . LoadLights = DoomStartupInfo . LoadBrightmaps = - 1 ;
GC : : FullGC ( ) ; // clean up before taking down the object list.
// Delete the reference to the VM functions here which were deleted and will be recreated after the restart.
FAutoSegIterator probe ( ARegHead , ARegTail ) ;
while ( * + + probe ! = NULL )
{
AFuncDesc * afunc = ( AFuncDesc * ) * probe ;
* ( afunc - > VMPointer ) = NULL ;
}
GC : : DelSoftRootHead ( ) ;
PClass : : StaticShutdown ( ) ;
GC : : FullGC ( ) ; // perform one final garbage collection after shutdown
assert ( GC : : Root = = nullptr ) ;
restart + + ;
PClass : : bShutdown = false ;
PClass : : bVMOperational = false ;
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// restart the game
//
//==========================================================================
2018-01-07 13:03:49 +00:00
UNSAFE_CCMD ( restart )
2016-03-01 15:47:10 +00:00
{
// remove command line args that would get in the way during restart
Args - > RemoveArgs ( " -iwad " ) ;
Args - > RemoveArgs ( " -deh " ) ;
Args - > RemoveArgs ( " -bex " ) ;
Args - > RemoveArgs ( " -playdemo " ) ;
Args - > RemoveArgs ( " -file " ) ;
Args - > RemoveArgs ( " -altdeath " ) ;
Args - > RemoveArgs ( " -deathmatch " ) ;
Args - > RemoveArgs ( " -skill " ) ;
Args - > RemoveArgs ( " -savedir " ) ;
Args - > RemoveArgs ( " -xlat " ) ;
Args - > RemoveArgs ( " -oldsprites " ) ;
if ( argv . argc ( ) > 1 )
{
2016-03-08 12:07:21 +00:00
for ( int i = 1 ; i < argv . argc ( ) ; i + + )
2016-03-01 15:47:10 +00:00
{
Args - > AppendArg ( argv [ i ] ) ;
}
}
2016-03-08 12:07:21 +00:00
wantToRestart = true ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// FStartupScreen Constructor
//
//==========================================================================
FStartupScreen : : FStartupScreen ( int max_progress )
{
MaxPos = max_progress ;
CurPos = 0 ;
NotchPos = 0 ;
}
//==========================================================================
//
// FStartupScreen Destructor
//
//==========================================================================
FStartupScreen : : ~ FStartupScreen ( )
{
}
//==========================================================================
//
// FStartupScreen :: LoadingStatus
//
// Used by Heretic for the Loading Status "window."
//
//==========================================================================
void FStartupScreen : : LoadingStatus ( const char * message , int colors )
{
}
//==========================================================================
//
// FStartupScreen :: AppendStatusLine
//
// Used by Heretic for the "status line" at the bottom of the screen.
//
//==========================================================================
void FStartupScreen : : AppendStatusLine ( const char * status )
{
}
2019-10-07 18:28:55 +00:00
//===========================================================================
//
// DeleteStartupScreen
//
// Makes sure the startup screen has been deleted before quitting.
//
//===========================================================================
void DeleteStartupScreen ( )
{
if ( StartScreen ! = nullptr )
{
delete StartScreen ;
StartScreen = nullptr ;
}
}
2016-03-01 15:47:10 +00:00
void FStartupScreen : : Progress ( void ) { }
void FStartupScreen : : NetInit ( char const * , int ) { }
void FStartupScreen : : NetProgress ( int ) { }
void FStartupScreen : : NetMessage ( char const * , . . . ) { }
void FStartupScreen : : NetDone ( void ) { }
bool FStartupScreen : : NetLoop ( bool ( * ) ( void * ) , void * ) { return false ; }
2017-02-14 18:34:01 +00:00
DEFINE_FIELD_X ( InputEventData , event_t , type )
DEFINE_FIELD_X ( InputEventData , event_t , subtype )
DEFINE_FIELD_X ( InputEventData , event_t , data1 )
DEFINE_FIELD_X ( InputEventData , event_t , data2 )
DEFINE_FIELD_X ( InputEventData , event_t , data3 )
DEFINE_FIELD_X ( InputEventData , event_t , x )
DEFINE_FIELD_X ( InputEventData , event_t , y )
2017-10-31 23:47:56 +00:00
2017-11-18 05:53:16 +00:00
CUSTOM_CVAR ( Bool , I_FriendlyWindowTitle , true , CVAR_GLOBALCONFIG | CVAR_ARCHIVE | CVAR_NOINITCALL )
2017-10-31 23:47:56 +00:00
{
if ( self )
I_SetWindowTitle ( DoomStartupInfo . Name . GetChars ( ) ) ;
else
I_SetWindowTitle ( NULL ) ;
2018-01-07 13:03:49 +00:00
}