2019-12-14 19:15:15 +00:00
//-------------------------------------------------------------------------
/*
Copyright ( C ) 2019 Christoph Oelckers
This is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation ; either version 2
of the License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
See the GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*/
//-------------------------------------------------------------------------
2020-01-12 13:54:43 +00:00
# include <stdexcept>
2019-10-25 22:32:49 +00:00
# include "gamecontrol.h"
# include "tarray.h"
# include "zstring.h"
# include "name.h"
# include "sc_man.h"
2019-10-26 11:16:32 +00:00
# include "c_cvars.h"
2019-10-26 17:24:46 +00:00
# include "gameconfigfile.h"
2019-10-26 21:45:55 +00:00
# include "gamecvars.h"
2019-10-26 11:16:32 +00:00
# include "build.h"
2019-10-28 05:47:49 +00:00
# include "inputstate.h"
2019-10-28 21:19:50 +00:00
# include "m_argv.h"
# include "rts.h"
2019-11-01 18:25:42 +00:00
# include "printf.h"
2019-11-03 19:24:50 +00:00
# include "c_bind.h"
2019-11-05 19:07:16 +00:00
# include "v_font.h"
# include "c_console.h"
# include "c_dispatch.h"
# include "i_specialpaths.h"
2020-04-12 06:07:48 +00:00
# include "raze_music.h"
2019-11-14 20:07:43 +00:00
# include "statistics.h"
2020-10-04 16:31:48 +00:00
# include "razemenu.h"
2019-11-23 11:38:38 +00:00
# include "gstrings.h"
2019-12-08 23:33:14 +00:00
# include "quotemgr.h"
2019-12-09 23:01:45 +00:00
# include "mapinfo.h"
2020-04-12 06:09:38 +00:00
# include "raze_sound.h"
2019-12-23 18:37:40 +00:00
# include "i_system.h"
# include "inputstate.h"
# include "v_video.h"
# include "st_start.h"
2019-12-24 11:59:26 +00:00
# include "s_music.h"
2019-12-24 17:53:29 +00:00
# include "i_video.h"
2020-01-11 16:05:25 +00:00
# include "v_text.h"
# include "resourcefile.h"
2019-12-28 11:59:19 +00:00
# include "c_dispatch.h"
2019-12-24 17:53:29 +00:00
# include "glbackend/glbackend.h"
2020-04-11 21:50:43 +00:00
# include "engineerrors.h"
2020-04-11 22:04:02 +00:00
# include "gamestate.h"
2020-04-11 22:11:50 +00:00
# include "gstrings.h"
2020-05-24 21:13:08 +00:00
# include "texturemanager.h"
2020-04-23 19:18:40 +00:00
# include "i_interface.h"
# include "x86.h"
# include "startupinfo.h"
2020-06-14 17:20:04 +00:00
# include "mapinfo.h"
# include "menustate.h"
2020-07-19 10:48:31 +00:00
# include "screenjob.h"
2020-08-16 00:55:50 +00:00
# include "statusbar.h"
2020-08-25 16:51:56 +00:00
# include "uiinput.h"
2020-08-30 08:42:44 +00:00
# include "d_net.h"
2020-09-06 18:49:43 +00:00
# include "automap.h"
2020-10-04 16:31:48 +00:00
# include "v_draw.h"
2020-10-06 18:49:55 +00:00
# include "gi.h"
2021-04-22 17:59:45 +00:00
# include "vm.h"
2021-05-02 10:02:55 +00:00
# include "g_mapinfo.h"
2021-03-25 08:13:16 +00:00
# include "gamefuncs.h"
2021-04-05 11:55:36 +00:00
# include "hw_voxels.h"
2021-04-05 18:00:21 +00:00
# include "hw_palmanager.h"
2020-04-23 19:18:40 +00:00
CVAR ( Bool , autoloadlights , true , CVAR_ARCHIVE | CVAR_GLOBALCONFIG )
CVAR ( Bool , autoloadbrightmaps , true , CVAR_ARCHIVE | CVAR_GLOBALCONFIG )
2020-10-31 11:46:53 +00:00
CVAR ( Bool , autoloadwidescreen , true , CVAR_ARCHIVE | CVAR_GLOBALCONFIG )
2020-04-11 22:11:50 +00:00
2020-10-04 22:46:24 +00:00
EXTERN_CVAR ( Bool , ui_generic )
2020-04-11 22:11:50 +00:00
CUSTOM_CVAR ( String , language , " auto " , CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG )
{
GStrings . UpdateLanguage ( self ) ;
2020-10-04 22:46:24 +00:00
UpdateGenericUI ( ui_generic ) ;
2020-04-11 22:11:50 +00:00
}
2020-03-29 13:22:07 +00:00
2020-04-23 19:18:40 +00:00
CUSTOM_CVAR ( Int , mouse_capturemode , 1 , CVAR_GLOBALCONFIG | CVAR_ARCHIVE )
{
if ( self < 0 )
{
self = 0 ;
}
else if ( self > 2 )
{
self = 2 ;
}
}
2020-03-29 13:22:07 +00:00
// The last remains of sdlayer.cpp
GameInterface * gi ;
int myconnectindex , numplayers ;
2021-05-03 17:01:00 +00:00
int connecthead , connectpoint2 [ MAXPLAYERS ] ;
2020-03-29 13:22:07 +00:00
auto vsnprintfptr = vsnprintf ; // This is an inline in Visual Studio but we need an address for it to satisfy the MinGW compiled libraries.
2020-08-25 23:41:23 +00:00
int lastTic ;
2020-03-29 13:22:07 +00:00
2020-08-30 10:02:32 +00:00
extern bool pauseext ;
2020-08-24 17:31:43 +00:00
2020-08-29 19:20:10 +00:00
cycle_t thinktime , actortime , gameupdatetime , drawtime ;
2020-06-23 19:12:15 +00:00
2020-04-11 22:04:02 +00:00
gamestate_t gamestate = GS_STARTUP ;
2020-09-03 21:10:28 +00:00
gameaction_t gameaction = ga_nothing ;
// gameaction state
MapRecord * g_nextmap ;
int g_nextskill ;
2020-04-11 22:04:02 +00:00
2020-04-11 21:54:33 +00:00
FILE * hashfile ;
2020-04-23 19:18:40 +00:00
FStartupInfo GameStartupInfo ;
2019-12-24 17:53:29 +00:00
FMemArena dump ; // this is for memory blocks than cannot be deallocated without some huge effort. Put them in here so that they do not register on shutdown.
2019-10-27 23:24:09 +00:00
InputState inputState ;
2019-10-31 22:25:21 +00:00
int ShowStartupWindow ( TArray < GrpEntry > & ) ;
2021-04-13 15:05:53 +00:00
TArray < FString > GetGameFronUserFiles ( ) ;
2019-11-01 18:25:42 +00:00
void InitFileSystem ( TArray < GrpEntry > & ) ;
2020-01-11 16:05:25 +00:00
void I_SetWindowTitle ( const char * caption ) ;
2020-04-12 06:07:48 +00:00
void S_ParseSndInfo ( ) ;
2020-05-31 08:53:11 +00:00
void I_DetectOS ( void ) ;
2020-06-14 17:20:04 +00:00
void LoadScripts ( ) ;
2020-08-30 08:42:44 +00:00
void MainLoop ( ) ;
2020-10-25 11:47:07 +00:00
void SetConsoleNotifyBuffer ( ) ;
2020-11-10 15:22:02 +00:00
bool PreBindTexture ( FRenderState * state , FGameTexture * & tex , EUpscaleFlags & flags , int & scaleflags , int & clampmode , int & translation , int & overrideshader ) ;
2020-11-10 19:12:46 +00:00
void PostLoadSetup ( ) ;
2020-11-10 20:34:49 +00:00
void FontCharCreated ( FGameTexture * base , FGameTexture * untranslated , FGameTexture * translated ) ;
2021-04-05 11:55:36 +00:00
void LoadVoxelModels ( ) ;
2020-05-31 08:53:11 +00:00
2021-05-16 08:35:33 +00:00
DStatusBarCore * StatusBar ;
2020-10-28 18:27:12 +00:00
2020-04-12 06:07:48 +00:00
2020-08-30 10:49:21 +00:00
bool AppActive = true ;
2019-10-27 23:24:09 +00:00
2019-10-31 23:32:56 +00:00
FString currentGame ;
2019-10-28 22:46:15 +00:00
FString LumpFilter ;
2019-10-26 11:16:32 +00:00
2019-12-24 14:28:00 +00:00
CVAR ( Bool , queryiwad , true , CVAR_ARCHIVE | CVAR_GLOBALCONFIG ) ;
CVAR ( String , defaultiwad , " " , CVAR_ARCHIVE | CVAR_GLOBALCONFIG ) ;
CVAR ( Bool , disableautoload , false , CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG )
2019-10-26 11:16:32 +00:00
2020-01-22 12:53:26 +00:00
extern int hud_size_max ;
2020-05-28 23:22:45 +00:00
int paused ;
bool pausedWithKey ;
2020-11-30 20:31:47 +00:00
bool gamesetinput = false ;
2021-02-18 10:46:36 +00:00
int PlayClock ;
2020-04-11 22:11:50 +00:00
CUSTOM_CVAR ( Int , cl_gender , 0 , CVAR_ARCHIVE | CVAR_GLOBALCONFIG )
{
if ( self < 0 | | self > 3 ) self = 0 ;
}
int StrTable_GetGender ( )
{
return cl_gender ;
}
bool validFilter ( const char * str ) ;
2020-05-17 06:51:49 +00:00
extern int chatmodeon ;
2020-04-11 22:11:50 +00:00
2020-04-23 19:18:40 +00:00
bool System_WantGuiCapture ( )
{
bool wantCapt ;
if ( menuactive = = MENU_Off )
{
wantCapt = ConsoleState = = c_down | | ConsoleState = = c_falling | | chatmodeon ;
}
else
{
wantCapt = ( menuactive = = MENU_On | | menuactive = = MENU_OnNoPause ) ;
}
return wantCapt ;
}
2020-09-28 20:36:43 +00:00
bool System_DispatchEvent ( event_t * ev )
{
if ( ev - > type = = EV_Mouse & & ! System_WantGuiCapture ( ) )
{
inputState . MouseAddToPos ( ev - > x , - ev - > y ) ;
return true ;
}
inputState . AddEvent ( ev ) ;
return false ;
}
2020-04-23 19:18:40 +00:00
bool System_WantLeftButton ( )
{
2020-08-10 22:46:27 +00:00
return false ; // (gamestate == GS_MENUSCREEN || gamestate == GS_TITLELEVEL);
2020-04-23 19:18:40 +00:00
}
bool System_NetGame ( )
{
return false ; // fixme later. For now there is no netgame support.
}
bool System_WantNativeMouse ( )
{
return false ;
}
static bool System_CaptureModeInGame ( )
{
return true ;
}
2020-01-11 16:05:25 +00:00
2020-05-30 22:01:00 +00:00
static bool System_DisableTextureFilter ( )
{
return hw_useindexedcolortextures ;
}
2020-04-28 20:55:37 +00:00
static IntRect System_GetSceneRect ( )
{
2021-04-05 08:34:03 +00:00
int viewbottom = windowxy2 . y + 1 ;
int viewheight = viewbottom - windowxy1 . y ;
int viewright = windowxy2 . x + 1 ;
int viewwidth = viewright - windowxy1 . x ;
int renderheight ;
if ( viewheight = = screen - > GetHeight ( ) ) renderheight = viewheight ;
else renderheight = ( viewwidth * screen - > GetHeight ( ) / screen - > GetWidth ( ) ) & ~ 7 ;
2020-04-28 20:55:37 +00:00
IntRect mSceneViewport ;
mSceneViewport . left = windowxy1 . x ;
2021-04-05 08:34:03 +00:00
mSceneViewport . top = screen - > GetHeight ( ) - ( renderheight + windowxy1 . y - ( ( renderheight - viewheight ) / 2 ) ) ;
mSceneViewport . width = viewwidth ;
mSceneViewport . height = renderheight ;
2020-04-28 20:55:37 +00:00
return mSceneViewport ;
}
2020-01-08 00:00:57 +00:00
//==========================================================================
//
2020-04-23 19:18:40 +00:00
// DoomSpecificInfo
2020-01-08 00:00:57 +00:00
//
2020-04-23 19:18:40 +00:00
// Called by the crash logger to get application-specific information.
2020-01-08 00:00:57 +00:00
//
//==========================================================================
2020-04-23 19:18:40 +00:00
void System_CrashInfo ( char * buffer , size_t bufflen , const char * lfstr )
2020-01-08 00:00:57 +00:00
{
2020-04-23 19:18:40 +00:00
const char * arg ;
char * const buffend = buffer + bufflen - 2 ; // -2 for CRLF at end
int i ;
buffer + = mysnprintf ( buffer , buffend - buffer , GAMENAME " version %s (%s) " , GetVersionString ( ) , GetGitHash ( ) ) ;
buffer + = snprintf ( buffer , buffend - buffer , " %sCommand line: " , lfstr ) ;
for ( i = 0 ; i < Args - > NumArgs ( ) ; + + i )
{
buffer + = snprintf ( buffer , buffend - buffer , " %s " , Args - > GetArg ( i ) ) ;
}
for ( i = 0 ; ( arg = fileSystem . GetResourceFileName ( i ) ) ! = NULL ; + + i )
{
buffer + = mysnprintf ( buffer , buffend - buffer , " %sFile %d: %s " , lfstr , i , arg ) ;
}
buffer + = mysnprintf ( buffer , buffend - buffer , " %s " , lfstr ) ;
* buffer = 0 ;
2020-01-08 00:00:57 +00:00
}
2020-04-23 19:18:40 +00:00
2020-01-08 00:00:57 +00:00
//==========================================================================
//
//
//
//==========================================================================
2019-10-28 21:19:50 +00:00
UserConfig userConfig ;
2021-04-22 17:59:45 +00:00
DEFINE_GLOBAL ( userConfig )
DEFINE_FIELD_X ( UserConfigStruct , UserConfig , nomonsters )
DEFINE_FIELD_X ( UserConfigStruct , UserConfig , nosound )
DEFINE_FIELD_X ( UserConfigStruct , UserConfig , nologo )
2019-10-28 21:19:50 +00:00
void UserConfig : : ProcessOptions ( )
{
// -help etc are omitted
// -cfg / -setupfile refer to Build style config which are not supported.
if ( Args - > CheckParm ( " -cfg " ) | | Args - > CheckParm ( " -setupfile " ) )
{
2020-04-11 21:45:45 +00:00
Printf ( " Build-format config files not supported and will be ignored \n " ) ;
2019-10-28 21:19:50 +00:00
}
2019-12-11 22:41:05 +00:00
auto v = Args - > CheckValue ( " -addon " ) ;
2019-10-28 21:19:50 +00:00
if ( v )
{
auto val = strtol ( v , nullptr , 0 ) ;
static const char * const addons [ ] = { " DUKE3D.GRP " , " DUKEDC.GRP " , " NWINTER.GRP " , " VACATION.GRP " } ;
2020-02-09 08:48:55 +00:00
if ( val > = 0 & & val < 4 ) gamegrp = addons [ val ] ;
2020-04-11 21:45:45 +00:00
else Printf ( " %s: Unknown Addon \n " , v ) ;
2019-10-28 21:19:50 +00:00
}
else if ( Args - > CheckParm ( " -nam " ) )
{
gamegrp = " NAM.GRP " ;
}
else if ( Args - > CheckParm ( " -napalm " ) )
{
gamegrp = " NAPALM.GRP " ;
}
else if ( Args - > CheckParm ( " -ww2gi " ) )
{
gamegrp = " WW2GI.GRP " ;
}
2019-12-11 22:41:05 +00:00
// Set up all needed content for these two mod which feature a very messy distribution.
// As an alternative they can be zipped up - the launcher will be able to detect and set up such versions automatically.
else if ( Args - > CheckParm ( " -route66 " ) )
{
gamegrp = " REDNECK.GRP " ;
DefaultCon = " GAME66.CON " ;
const char * argv [ ] = { " tilesa66.art " , " tilesb66.art " } ;
AddArt . reset ( new FArgs ( 2 , argv ) ) ;
2020-01-10 20:36:46 +00:00
toBeDeleted . Push ( " turd66.anm*turdmov.anm " ) ;
toBeDeleted . Push ( " turd66.voc*turdmov.voc " ) ;
toBeDeleted . Push ( " end66.anm*rr_outro.anm " ) ;
toBeDeleted . Push ( " end66.voc*rr_outro.voc " ) ;
2019-12-11 22:41:05 +00:00
}
else if ( Args - > CheckParm ( " -cryptic " ) )
{
gamegrp = " BLOOD.RFF " ;
DefaultCon = " CRYPTIC.INI " ;
const char * argv [ ] = { " cpart07.ar_ " , " cpart15.ar_ " } ;
AddArt . reset ( new FArgs ( 2 , argv ) ) ;
}
2019-10-28 21:19:50 +00:00
2019-11-01 18:25:42 +00:00
v = Args - > CheckValue ( " -gamegrp " ) ;
2019-10-28 21:19:50 +00:00
if ( v )
{
gamegrp = v ;
}
else
{
// This is to enable the use of Doom launchers. that are limited to -iwad for specifying the game's main resource.
v = Args - > CheckValue ( " -iwad " ) ;
if ( v )
{
gamegrp = v ;
}
}
Args - > CollectFiles ( " -rts " , " .rts " ) ;
auto rts = Args - > CheckValue ( " -rts " ) ;
if ( rts ) RTS_Init ( rts ) ;
Args - > CollectFiles ( " -map " , " .map " ) ;
CommandMap = Args - > CheckValue ( " -map " ) ;
static const char * defs [ ] = { " -def " , " -h " , nullptr } ;
Args - > CollectFiles ( " -def " , defs , " .def " ) ;
2021-04-07 19:46:44 +00:00
UserDef = Args - > CheckValue ( " -def " ) ;
2019-10-28 21:19:50 +00:00
2020-01-10 20:36:46 +00:00
if ( DefaultCon . IsEmpty ( ) )
{
static const char * cons [ ] = { " -con " , " -x " , nullptr } ;
Args - > CollectFiles ( " -con " , cons , " .con " ) ;
DefaultCon = Args - > CheckValue ( " -con " ) ;
if ( DefaultCon . IsEmpty ( ) ) DefaultCon = Args - > CheckValue ( " -ini " ) ;
}
2019-10-28 21:19:50 +00:00
static const char * demos [ ] = { " -playback " , " -d " , " -demo " , nullptr } ;
Args - > CollectFiles ( " -demo " , demos , " .dmo " ) ;
CommandDemo = Args - > CheckValue ( " -demo " ) ;
static const char * names [ ] = { " -pname " , " -name " , nullptr } ;
Args - > CollectFiles ( " -name " , names , " .--- " ) ; // this shouldn't collect any file names at all so use a nonsense extension
CommandName = Args - > CheckValue ( " -name " ) ;
2020-08-22 18:14:00 +00:00
static const char * nomos [ ] = { " -nomonsters " , " -nodudes " , " -nocreatures " , nullptr } ;
2019-10-28 21:19:50 +00:00
Args - > CollectFiles ( " -nomonsters " , nomos , " .--- " ) ; // this shouldn't collect any file names at all so use a nonsense extension
nomonsters = Args - > CheckParm ( " -nomonsters " ) ;
static const char * acons [ ] = { " -addcon " , " -mx " , nullptr } ;
Args - > CollectFiles ( " -addcon " , acons , " .con " ) ;
AddCons . reset ( Args - > GatherFiles ( " -addcon " ) ) ;
static const char * adefs [ ] = { " -adddef " , " -mh " , nullptr } ;
Args - > CollectFiles ( " -adddef " , adefs , " .def " ) ;
AddDefs . reset ( Args - > GatherFiles ( " -adddef " ) ) ;
Args - > CollectFiles ( " -art " , " .art " ) ;
AddArt . reset ( Args - > GatherFiles ( " -art " ) ) ;
nologo = Args - > CheckParm ( " -nologo " ) | | Args - > CheckParm ( " -quick " ) ;
2020-04-12 06:07:48 +00:00
nosound = Args - > CheckParm ( " -nosfx " ) | | Args - > CheckParm ( " -nosound " ) ;
2019-12-24 14:28:00 +00:00
if ( Args - > CheckParm ( " -setup " ) ) queryiwad = 1 ;
else if ( Args - > CheckParm ( " -nosetup " ) ) queryiwad = 0 ;
2019-10-28 21:19:50 +00:00
if ( Args - > CheckParm ( " -file " ) )
{
// For file loading there's two modes:
// If -file is given, all content will be processed in order and the legacy options be ignored entirely.
//This allows mixing directories and GRP files in arbitrary order.
Args - > CollectFiles ( " -file " , NULL ) ;
AddFiles . reset ( Args - > GatherFiles ( " -file " ) ) ;
}
else
{
2019-11-01 18:25:42 +00:00
// Trying to emulate Build. This means to treat RFF files as lowest priority, then all GRPs and then all directories.
2019-10-28 21:19:50 +00:00
// This is only for people depending on lauchers. Since the semantics are so crappy it is strongly recommended to
2019-11-01 18:25:42 +00:00
// use -file instead which gives the user full control over the order in which things are added.
2019-10-28 21:19:50 +00:00
// For single mods this is no problem but don't even think about loading more stuff consistently...
static const char * grps [ ] = { " -g " , " -grp " , nullptr } ;
static const char * dirs [ ] = { " -game_dir " , " -j " , nullptr } ;
static const char * rffs [ ] = { " -rff " , " -snd " , nullptr } ;
static const char * twostep [ ] = { " -rff " , " -grp " , nullptr } ;
// Abuse the inner workings to get the files into proper order. This is not 100% accurate but should work fine for everything that doesn't intentionally fuck things up.
Args - > CollectFiles ( " -rff " , rffs , " .rff " ) ;
Args - > CollectFiles ( " -grp " , grps , nullptr ) ;
Args - > CollectFiles ( " -grp " , twostep , nullptr ) ; // The two previous calls have already brought the content in order so collecting it again gives us one list with everything.
AddFilesPre . reset ( Args - > GatherFiles ( " -grp " ) ) ;
Args - > CollectFiles ( " -game_dir " , dirs , nullptr ) ;
AddFiles . reset ( Args - > GatherFiles ( " -game_dir " ) ) ;
}
2019-12-23 19:55:12 +00:00
if ( Args - > CheckParm ( " -showcoords " ) | | Args - > CheckParm ( " -w " ) )
{
C_DoCommand ( " stat coord " ) ;
}
2019-10-28 21:19:50 +00:00
}
2020-07-15 10:34:42 +00:00
//==========================================================================
//
//
//
//==========================================================================
void CheckUserMap ( )
{
if ( userConfig . CommandMap . IsEmpty ( ) ) return ;
FString startupMap = userConfig . CommandMap ;
if ( startupMap . IndexOfAny ( " / \\ " ) < 0 ) startupMap . Insert ( 0 , " / " ) ;
DefaultExtension ( startupMap , " .map " ) ;
startupMap . Substitute ( " \\ " , " / " ) ;
NormalizeFileName ( startupMap ) ;
if ( fileSystem . FileExists ( startupMap ) )
{
Printf ( " Using level: \" %s \" . \n " , startupMap . GetChars ( ) ) ;
}
else
{
Printf ( " Level \" %s \" not found. \n " , startupMap . GetChars ( ) ) ;
startupMap = " " ;
}
userConfig . CommandMap = startupMap ;
}
2019-10-31 22:25:21 +00:00
//==========================================================================
//
//
//
//==========================================================================
2020-06-11 07:22:16 +00:00
namespace Duke3d
{
: : GameInterface * CreateInterface ( ) ;
}
2019-10-31 22:25:21 +00:00
namespace Blood
{
2019-11-03 11:32:58 +00:00
: : GameInterface * CreateInterface ( ) ;
2019-10-31 22:25:21 +00:00
}
namespace ShadowWarrior
{
2019-11-03 11:32:58 +00:00
: : GameInterface * CreateInterface ( ) ;
2019-10-31 22:25:21 +00:00
}
2020-10-10 08:11:22 +00:00
namespace Exhumed
2019-12-12 23:19:34 +00:00
{
: : GameInterface * CreateInterface ( ) ;
}
2019-10-31 22:25:21 +00:00
void CheckFrontend ( int flags )
{
if ( flags & GAMEFLAG_BLOOD )
{
2019-11-03 11:32:58 +00:00
gi = Blood : : CreateInterface ( ) ;
2019-10-31 22:25:21 +00:00
}
else if ( flags & GAMEFLAG_SW )
{
2019-11-03 11:32:58 +00:00
gi = ShadowWarrior : : CreateInterface ( ) ;
2019-10-31 22:25:21 +00:00
}
2019-12-12 23:19:34 +00:00
else if ( flags & GAMEFLAG_PSEXHUMED )
{
2020-10-10 08:11:22 +00:00
gi = Exhumed : : CreateInterface ( ) ;
2019-12-12 23:19:34 +00:00
}
2020-02-12 19:25:59 +00:00
else
{
2020-07-14 11:09:34 +00:00
gi = Duke3d : : CreateInterface ( ) ;
2020-02-12 19:25:59 +00:00
}
2019-10-31 22:25:21 +00:00
}
2019-12-14 16:15:17 +00:00
void I_StartupJoysticks ( ) ;
void I_ShutdownInput ( ) ;
int RunGame ( ) ;
2020-10-08 16:02:25 +00:00
void System_MenuClosed ( ) ;
2020-10-10 16:29:15 +00:00
void System_MenuDim ( ) ;
2019-10-31 22:25:21 +00:00
2019-11-05 19:07:16 +00:00
int GameMain ( )
{
int r ;
2020-04-23 19:18:40 +00:00
2020-10-25 11:47:07 +00:00
SetConsoleNotifyBuffer ( ) ;
2020-10-03 15:04:45 +00:00
sysCallbacks =
2020-04-23 19:18:40 +00:00
{
System_WantGuiCapture ,
System_WantLeftButton ,
System_NetGame ,
System_WantNativeMouse ,
System_CaptureModeInGame ,
2020-05-30 22:01:00 +00:00
nullptr ,
nullptr ,
nullptr ,
System_DisableTextureFilter ,
2020-04-28 20:55:37 +00:00
nullptr ,
System_GetSceneRect ,
2020-09-28 20:36:43 +00:00
nullptr ,
2020-10-10 16:29:15 +00:00
System_MenuDim ,
2020-09-28 20:36:43 +00:00
nullptr ,
System_DispatchEvent ,
2020-10-04 19:15:51 +00:00
validFilter ,
StrTable_GetGender ,
2020-10-08 16:02:25 +00:00
System_MenuClosed ,
2020-11-10 15:22:02 +00:00
nullptr ,
nullptr ,
2020-11-10 20:34:49 +00:00
PreBindTexture ,
FontCharCreated
2020-04-23 19:18:40 +00:00
} ;
2019-11-05 19:07:16 +00:00
try
{
2019-12-14 16:15:17 +00:00
r = RunGame ( ) ;
2019-11-05 19:07:16 +00:00
}
2021-05-05 21:33:24 +00:00
catch ( const CExitEvent & exit )
2019-11-05 19:07:16 +00:00
{
// Just let the rest of the function execute.
r = exit . Reason ( ) ;
}
2021-05-05 21:33:24 +00:00
catch ( const std : : exception & err )
2019-12-24 15:30:33 +00:00
{
// shut down critical systems before showing a message box.
I_ShowFatalError ( err . what ( ) ) ;
r = - 1 ;
}
2021-04-30 14:21:37 +00:00
//DeleteScreenJob();
2020-10-10 13:16:28 +00:00
DeinitMenus ( ) ;
2020-10-28 18:27:12 +00:00
if ( StatusBar ) StatusBar - > Destroy ( ) ;
StatusBar = nullptr ;
2019-12-25 10:26:19 +00:00
if ( gi )
{
gi - > FreeGameData ( ) ; // Must be done before taking down any subsystems.
}
2019-12-24 15:30:33 +00:00
S_StopMusic ( true ) ;
if ( soundEngine ) delete soundEngine ;
2019-12-24 17:53:29 +00:00
soundEngine = nullptr ;
I_CloseSound ( ) ;
2019-12-24 15:30:33 +00:00
I_ShutdownInput ( ) ;
2019-11-10 18:42:26 +00:00
G_SaveConfig ( ) ;
2019-12-24 15:09:43 +00:00
C_DeinitConsole ( ) ;
2019-12-24 15:30:33 +00:00
V_ClearFonts ( ) ;
2021-04-05 11:55:36 +00:00
voxClear ( ) ;
2021-04-05 18:00:21 +00:00
ClearPalManager ( ) ;
2020-05-24 21:26:47 +00:00
TexMan . DeleteAll ( ) ;
TileFiles . CloseAll ( ) ; // delete the texture data before shutting down graphics.
2019-12-24 17:53:29 +00:00
I_ShutdownGraphics ( ) ;
2021-03-24 18:45:42 +00:00
freeallmodels ( ) ;
2019-12-24 19:06:55 +00:00
if ( gi )
{
delete gi ;
gi = nullptr ;
}
2019-12-24 15:30:33 +00:00
DeleteStartupScreen ( ) ;
2020-06-14 17:20:04 +00:00
PClass : : StaticShutdown ( ) ;
2019-12-24 15:09:43 +00:00
if ( Args ) delete Args ;
2019-11-05 19:07:16 +00:00
return r ;
}
2019-10-26 17:24:46 +00:00
//==========================================================================
//
//
//
//==========================================================================
2019-11-24 23:02:00 +00:00
void SetDefaultStrings ( )
{
2019-12-08 23:33:14 +00:00
// Blood hard codes its skill names, so we have to define them manually.
2021-01-02 03:46:58 +00:00
if ( isBlood ( ) )
2019-11-24 23:02:00 +00:00
{
2019-12-08 23:33:14 +00:00
gSkillNames [ 0 ] = " $STILL KICKING " ;
gSkillNames [ 1 ] = " $PINK ON THE INSIDE " ;
gSkillNames [ 2 ] = " $LIGHTLY BROILED " ;
gSkillNames [ 3 ] = " $WELL DONE " ;
gSkillNames [ 4 ] = " $EXTRA CRISPY " ;
2019-11-24 23:02:00 +00:00
}
2019-12-08 23:33:14 +00:00
//Set a few quotes which are used for common handling of a few status messages
quoteMgr . InitializeQuote ( 23 , " $MESSAGES: ON " ) ;
2019-12-09 01:01:30 +00:00
quoteMgr . InitializeQuote ( 24 , " $MESSAGES: OFF " ) ;
quoteMgr . InitializeQuote ( 83 , " $FOLLOW MODE OFF " ) ;
quoteMgr . InitializeQuote ( 84 , " $FOLLOW MODE ON " ) ;
2019-12-08 23:33:14 +00:00
quoteMgr . InitializeQuote ( 85 , " $AUTORUNOFF " ) ;
quoteMgr . InitializeQuote ( 86 , " $AUTORUNON " ) ;
2019-11-24 23:02:00 +00:00
}
2019-12-08 23:33:14 +00:00
2019-10-26 17:24:46 +00:00
//==========================================================================
//
//
//
//==========================================================================
2019-12-23 18:37:40 +00:00
static TArray < GrpEntry > SetupGame ( )
2019-10-26 11:16:32 +00:00
{
2019-10-29 18:53:46 +00:00
// Startup dialog must be presented here so that everything can be set up before reading the keybinds.
2019-10-30 23:41:56 +00:00
auto groups = GrpScan ( ) ;
2019-11-01 18:25:42 +00:00
if ( groups . Size ( ) = = 0 )
{
// Abort if no game data found.
2019-11-03 09:51:47 +00:00
G_SaveConfig ( ) ;
2019-11-01 18:25:42 +00:00
I_Error ( " Unable to find any game data. Please verify your settings. " ) ;
}
decltype ( groups ) usedgroups ;
int groupno = - 1 ;
2021-04-13 15:05:53 +00:00
auto game = GetGameFronUserFiles ( ) ;
2020-01-11 16:05:25 +00:00
if ( userConfig . gamegrp . IsEmpty ( ) )
{
2021-04-13 15:05:53 +00:00
for ( auto & str : game )
{
2021-05-02 20:56:53 +00:00
int g = 0 ;
2021-04-13 15:05:53 +00:00
for ( auto & grp : groups )
{
if ( grp . FileInfo . gameid . CompareNoCase ( str ) = = 0 )
{
userConfig . gamegrp = grp . FileName ;
2021-05-02 20:56:53 +00:00
groupno = g ;
2021-04-13 15:05:53 +00:00
goto foundit ;
}
2021-05-02 20:56:53 +00:00
g + + ;
2021-04-13 15:05:53 +00:00
}
}
2020-01-11 16:05:25 +00:00
}
2021-04-13 15:05:53 +00:00
foundit :
2020-01-11 16:05:25 +00:00
2021-04-13 15:05:53 +00:00
// If the user has specified a file name, let's see if we know it.
//
2021-05-02 20:56:53 +00:00
if ( groupno = = - 1 & & userConfig . gamegrp . Len ( ) )
2019-10-31 23:32:56 +00:00
{
2021-05-02 20:56:53 +00:00
FString gamegrplower = userConfig . gamegrp . MakeLower ( ) ;
if ( gamegrplower [ 1 ] ! = ' : ' | | gamegrplower [ 2 ] ! = ' / ' ) gamegrplower . Insert ( 0 , " / " ) ;
2019-11-01 18:25:42 +00:00
int g = 0 ;
for ( auto & grp : groups )
2019-10-31 23:32:56 +00:00
{
2019-11-19 20:35:35 +00:00
auto grplower = grp . FileName . MakeLower ( ) ;
2021-05-02 20:56:53 +00:00
FixPathSeperator ( grplower ) ;
int pos = grplower . LastIndexOf ( gamegrplower ) ;
if ( pos > = 0 & & pos = = grplower . Len ( ) - gamegrplower . Len ( ) )
2019-10-31 23:32:56 +00:00
{
2019-11-02 12:27:40 +00:00
groupno = g ;
2019-10-31 23:32:56 +00:00
break ;
}
2019-11-01 18:25:42 +00:00
g + + ;
}
}
2019-12-24 14:28:00 +00:00
if ( groupno = = - 1 )
{
int pick = 0 ;
// We got more than one so present the IWAD selection box.
if ( groups . Size ( ) > 1 )
{
// Locate the user's prefered IWAD, if it was found.
if ( defaultiwad [ 0 ] ! = ' \0 ' )
{
for ( unsigned i = 0 ; i < groups . Size ( ) ; + + i )
{
FString & basename = groups [ i ] . FileName ;
if ( stricmp ( basename , defaultiwad ) = = 0 )
{
pick = i ;
break ;
}
}
}
if ( groups . Size ( ) > 1 )
{
TArray < WadStuff > wads ;
for ( auto & found : groups )
{
WadStuff stuff ;
stuff . Name = found . FileInfo . name ;
stuff . Path = ExtractFileBase ( found . FileName ) ;
wads . Push ( stuff ) ;
}
pick = I_PickIWad ( & wads [ 0 ] , ( int ) wads . Size ( ) , queryiwad , pick ) ;
if ( pick > = 0 )
{
// The newly selected IWAD becomes the new default
defaultiwad = groups [ pick ] . FileName ;
}
groupno = pick ;
}
}
2019-12-29 03:49:28 +00:00
else if ( groups . Size ( ) = = 1 )
{
groupno = 0 ;
}
2019-12-24 14:28:00 +00:00
}
2019-11-01 18:25:42 +00:00
2019-12-23 18:37:40 +00:00
if ( groupno = = - 1 ) return TArray < GrpEntry > ( ) ;
auto & group = groups [ groupno ] ;
2019-11-01 18:25:42 +00:00
// Now filter out the data we actually need and delete the rest.
usedgroups . Push ( group ) ;
auto crc = group . FileInfo . dependencyCRC ;
2019-11-02 12:27:40 +00:00
if ( crc ! = 0 ) for ( auto & dep : groups )
2019-11-01 18:25:42 +00:00
{
if ( dep . FileInfo . CRC = = crc )
{
usedgroups . Insert ( 0 , dep ) ; // Order from least dependent to most dependent, which is the loading order of data.
2019-10-31 23:32:56 +00:00
}
}
2019-11-01 18:25:42 +00:00
groups . Reset ( ) ;
FString selectedScript ;
FString selectedDef ;
for ( auto & ugroup : usedgroups )
{
// For CONs the command line has priority, aside from that, the last one wins. For Blood this handles INIs - the rules are the same.
if ( ugroup . FileInfo . scriptname . IsNotEmpty ( ) ) selectedScript = ugroup . FileInfo . scriptname ;
if ( ugroup . FileInfo . defname . IsNotEmpty ( ) ) selectedDef = ugroup . FileInfo . defname ;
// CVAR has priority. This also overwrites the global variable each time. Init here is lazy so this is ok.
2019-12-23 18:37:40 +00:00
if ( ugroup . FileInfo . rtsname . IsNotEmpty ( ) & & * * rtsname = = 0 ) RTS_Init ( ugroup . FileInfo . rtsname ) ;
2019-11-01 18:25:42 +00:00
// For the game filter the last non-empty one wins.
if ( ugroup . FileInfo . gamefilter . IsNotEmpty ( ) ) LumpFilter = ugroup . FileInfo . gamefilter ;
g_gameType | = ugroup . FileInfo . flags ;
}
2021-04-13 15:08:04 +00:00
if ( userConfig . DefaultCon . IsEmpty ( ) ) userConfig . DefaultCon = GameStartupInfo . con . IsNotEmpty ( ) ? GameStartupInfo . con : selectedScript ;
2019-11-01 18:25:42 +00:00
if ( userConfig . DefaultDef . IsEmpty ( ) ) userConfig . DefaultDef = selectedDef ;
// This can only happen with a custom game that does not define any filter.
// In this case take the display name and strip all whitespace and invaliid path characters from it.
if ( LumpFilter . IsEmpty ( ) )
{
LumpFilter = usedgroups . Last ( ) . FileInfo . name ;
LumpFilter . StripChars ( " .:/ \\ <>? \" *| \t \r \n " ) ;
}
2019-10-29 18:53:46 +00:00
2019-10-31 23:32:56 +00:00
currentGame = LumpFilter ;
currentGame . Truncate ( currentGame . IndexOf ( " . " ) ) ;
2020-10-28 18:27:12 +00:00
PClass : : StaticInit ( ) ;
2019-11-01 18:25:42 +00:00
CheckFrontend ( g_gameType ) ;
2020-10-06 18:49:55 +00:00
gameinfo . gametype = g_gameType ;
2019-12-23 18:37:40 +00:00
return usedgroups ;
}
2020-09-05 19:33:04 +00:00
//==========================================================================
//
//
//
//==========================================================================
void InitLanguages ( )
{
GStrings . LoadStrings ( language ) ;
}
2020-10-28 18:27:12 +00:00
void CreateStatusBar ( )
{
2021-05-16 08:43:47 +00:00
auto stbarclass = PClass : : FindClass ( globalCutscenes . StatusBarClass ) ;
2020-10-28 18:27:12 +00:00
if ( ! stbarclass )
{
I_FatalError ( " No status bar defined " ) ;
}
2021-05-16 08:35:33 +00:00
StatusBar = static_cast < DStatusBarCore * > ( stbarclass - > CreateNew ( ) ) ;
2021-05-12 19:46:49 +00:00
StatusBar - > SetSize ( 0 , 320 , 200 ) ;
2021-05-13 17:48:27 +00:00
InitStatusBar ( ) ;
2021-05-16 08:43:47 +00:00
GC : : AddMarkerFunc ( [ ] ( ) { GC : : Mark ( StatusBar ) ; } ) ;
2020-10-28 18:27:12 +00:00
}
2021-05-05 21:33:24 +00:00
void GetGames ( )
{
auto getgames = Args - > CheckValue ( " -getgames " ) ;
if ( getgames )
{
try
{
auto groups = GrpScan ( ) ;
FSerializer arc ;
if ( arc . OpenWriter ( ) )
{
if ( arc . BeginArray ( " games " ) )
{
for ( auto & entry : groups )
{
if ( arc . BeginObject ( nullptr ) )
{
arc ( " filename " , entry . FileName )
( " description " , entry . FileInfo . name )
( " defname " , entry . FileInfo . defname )
( " scriptname " , entry . FileInfo . scriptname )
( " gamefilter " , entry . FileInfo . gamefilter )
( " gameid " , entry . FileInfo . gameid )
( " fgcolor " , entry . FileInfo . FgColor )
( " bkcolor " , entry . FileInfo . BgColor )
( " addon " , entry . FileInfo . isAddon )
. EndObject ( ) ;
}
}
arc . EndArray ( ) ;
}
unsigned int len ;
auto p = arc . GetOutput ( & len ) ;
FILE * f = fopen ( getgames , " wb " ) ;
if ( f )
{
fwrite ( p , 1 , len , f ) ;
fclose ( f ) ;
}
}
}
catch ( . . . )
{
// Ignore all errors
}
throw CExitEvent ( 0 ) ;
}
}
2019-12-23 18:37:40 +00:00
//==========================================================================
//
//
//
//==========================================================================
int RunGame ( )
{
2021-04-10 17:14:30 +00:00
GameStartupInfo . FgColor = 0xffffff ;
2019-12-23 18:37:40 +00:00
// Set up the console before anything else so that it can receive text.
C_InitConsole ( 1024 , 768 , true ) ;
// +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 " ) ;
// As long as this engine is still in prerelease mode let's always write a log file.
2019-12-26 13:04:53 +00:00
if ( logfile . IsEmpty ( ) ) logfile . Format ( " %s " GAMENAMELOWERCASE " .log " , M_GetDocumentsPath ( ) . GetChars ( ) ) ;
2019-12-23 18:37:40 +00:00
if ( logfile . IsNotEmpty ( ) )
{
execLogfile ( logfile ) ;
}
I_DetectOS ( ) ;
userConfig . ProcessOptions ( ) ;
G_LoadConfig ( ) ;
2021-05-05 21:33:24 +00:00
GetGames ( ) ;
2019-12-23 18:37:40 +00:00
auto usedgroups = SetupGame ( ) ;
2021-04-12 17:39:42 +00:00
bool colorset = false ;
for ( int i = usedgroups . Size ( ) - 1 ; i > = 0 ; i - - )
2021-04-10 17:14:30 +00:00
{
2021-04-12 17:39:42 +00:00
auto & grp = usedgroups [ i ] ;
2021-04-10 17:14:30 +00:00
if ( grp . FileInfo . name . IsNotEmpty ( ) )
{
if ( GameStartupInfo . Name . IsEmpty ( ) ) GameStartupInfo . Name = grp . FileInfo . name ;
2021-04-12 17:39:42 +00:00
if ( ! colorset & & grp . FileInfo . FgColor ! = grp . FileInfo . BgColor & & ( GameStartupInfo . FgColor ! = 0 | | GameStartupInfo . BkColor ! = 0 ) )
2021-04-10 17:14:30 +00:00
{
GameStartupInfo . FgColor = grp . FileInfo . FgColor ;
GameStartupInfo . BkColor = grp . FileInfo . BgColor ;
2021-04-12 17:39:42 +00:00
colorset = true ;
2021-04-10 17:14:30 +00:00
}
}
}
I_SetIWADInfo ( ) ;
2019-10-28 21:19:50 +00:00
2019-11-02 19:13:00 +00:00
InitFileSystem ( usedgroups ) ;
2019-12-23 18:37:40 +00:00
if ( usedgroups . Size ( ) = = 0 ) return 0 ;
2020-01-22 15:14:01 +00:00
// Handle CVARs with game specific defaults here.
2021-01-02 03:46:58 +00:00
if ( isBlood ( ) )
2019-12-26 12:04:29 +00:00
{
2020-01-22 12:53:26 +00:00
mus_redbook . SetGenericRepDefault ( false , CVAR_Bool ) ; // Blood should default to CD Audio off - all other games must default to on.
2020-08-24 22:01:33 +00:00
am_showlabel . SetGenericRepDefault ( true , CVAR_Bool ) ;
2019-12-26 12:04:29 +00:00
}
2020-01-22 14:21:07 +00:00
if ( g_gameType & GAMEFLAG_SW )
{
2020-02-12 21:46:18 +00:00
cl_weaponswitch . SetGenericRepDefault ( 1 , CVAR_Int ) ;
if ( cl_weaponswitch > 1 ) cl_weaponswitch = 1 ;
2020-01-22 14:21:07 +00:00
}
2020-08-23 22:25:42 +00:00
if ( g_gameType & ( GAMEFLAG_BLOOD | GAMEFLAG_RR ) )
{
am_nameontop . SetGenericRepDefault ( true , CVAR_Bool ) ; // Blood and RR show the map name on the top of the screen by default.
}
2019-12-26 12:04:29 +00:00
2019-12-23 18:37:40 +00:00
G_ReadConfig ( currentGame ) ;
V_InitFontColors ( ) ;
2020-09-05 19:33:04 +00:00
InitLanguages ( ) ;
2019-12-23 18:37:40 +00:00
2020-04-23 19:18:40 +00:00
CheckCPUID ( & CPU ) ;
CalculateCPUSpeed ( ) ;
auto ci = DumpCPUInfo ( & CPU ) ;
Printf ( " %s " , ci . GetChars ( ) ) ;
2019-12-23 18:37:40 +00:00
V_InitScreenSize ( ) ;
V_InitScreen ( ) ;
2021-04-10 17:28:46 +00:00
StartScreen = FStartupScreen : : CreateInstance ( 8 ) ;
StartScreen - > Progress ( ) ;
2019-12-23 18:37:40 +00:00
2019-12-11 22:41:05 +00:00
TArray < FString > addArt ;
for ( auto & grp : usedgroups )
{
for ( auto & art : grp . FileInfo . loadart )
{
addArt . Push ( art ) ;
}
}
2019-12-17 19:08:59 +00:00
if ( userConfig . AddArt ) for ( auto & art : * userConfig . AddArt )
{
addArt . Push ( art ) ;
}
2019-12-11 22:41:05 +00:00
TileFiles . AddArt ( addArt ) ;
2019-11-02 19:13:00 +00:00
2019-12-23 18:37:40 +00:00
inputState . ClearAllInput ( ) ;
2019-11-04 22:01:50 +00:00
2019-11-02 19:13:00 +00:00
if ( ! GameConfig - > IsInitialized ( ) )
{
CONFIG_ReadCombatMacros ( ) ;
}
if ( userConfig . CommandName . IsNotEmpty ( ) )
{
playername = userConfig . CommandName ;
}
2020-08-23 15:47:05 +00:00
GameTicRate = 30 ;
2020-07-15 10:34:42 +00:00
CheckUserMap ( ) ;
2020-04-05 20:51:53 +00:00
GPalette . Init ( MAXPALOOKUPS + 2 ) ; // one slot for each translation, plus a separate one for the base palettes and the internal one
2021-04-10 17:28:46 +00:00
StartScreen - > Progress ( ) ;
2020-05-24 21:13:08 +00:00
TexMan . Init ( [ ] ( ) { } , [ ] ( BuildInfo & ) { } ) ;
2019-11-05 19:07:16 +00:00
V_InitFonts ( ) ;
2021-04-10 17:28:46 +00:00
StartScreen - > Progress ( ) ;
2020-05-24 21:26:47 +00:00
TileFiles . Init ( ) ;
2021-04-10 17:28:46 +00:00
StartScreen - > Progress ( ) ;
2020-04-12 06:07:48 +00:00
I_InitSound ( ) ;
2021-04-10 17:28:46 +00:00
StartScreen - > Progress ( ) ;
2020-04-12 06:07:48 +00:00
Mus_InitMusic ( ) ;
S_ParseSndInfo ( ) ;
2020-10-09 20:33:02 +00:00
S_ParseReverbDef ( ) ;
2019-11-14 20:07:43 +00:00
InitStatistics ( ) ;
2020-06-14 17:20:04 +00:00
LoadScripts ( ) ;
2021-04-10 17:28:46 +00:00
StartScreen - > Progress ( ) ;
2019-11-24 23:02:00 +00:00
SetDefaultStrings ( ) ;
2021-04-26 21:10:38 +00:00
Job_Init ( ) ;
2019-12-28 11:59:19 +00:00
if ( Args - > CheckParm ( " -sounddebug " ) )
C_DoCommand ( " stat sounddebug " ) ;
2019-12-23 18:37:40 +00:00
2021-02-25 11:16:21 +00:00
enginePreInit ( ) ;
2020-08-26 22:25:59 +00:00
SetupGameButtons ( ) ;
2020-10-06 23:12:57 +00:00
gameinfo . mBackButton = " engine/graphics/m_back.png " ;
2021-04-10 17:28:46 +00:00
StartScreen - > Progress ( ) ;
2021-04-05 11:55:36 +00:00
GPalette . Init ( MAXPALOOKUPS + 1 ) ; // one slot for each translation, plus a separate one for the base palettes.
gi - > loadPalette ( ) ;
voxInit ( ) ;
TileFiles . LoadArtSet ( " tiles%03d.art " ) ; // it's the same for all games.
engineInit ( ) ;
2020-08-23 15:47:05 +00:00
gi - > app_init ( ) ;
2021-04-10 17:28:46 +00:00
StartScreen - > Progress ( ) ;
2021-05-02 10:02:55 +00:00
G_ParseMapInfo ( ) ;
2020-10-28 18:27:12 +00:00
CreateStatusBar ( ) ;
2020-10-04 20:21:11 +00:00
SetDefaultMenuColors ( ) ;
2020-09-08 20:37:21 +00:00
M_Init ( ) ;
2020-10-06 23:31:41 +00:00
BuildGameMenus ( ) ;
2021-04-10 17:28:46 +00:00
StartScreen - > Progress ( ) ;
2020-09-13 18:15:46 +00:00
if ( ! ( paletteloaded & PALETTE_MAIN ) )
I_FatalError ( " No palette found. " ) ;
V_LoadTranslations ( ) ; // loading the translations must be delayed until the palettes have been fully set up.
lookups . postLoadTables ( ) ;
2020-11-10 19:12:46 +00:00
PostLoadSetup ( ) ;
2021-04-05 11:55:36 +00:00
lookups . postLoadLookups ( ) ;
2021-04-05 18:00:21 +00:00
FMaterial : : SetLayerCallback ( setpalettelayer ) ;
2021-04-10 17:14:30 +00:00
if ( GameStartupInfo . Name . IsNotEmpty ( ) ) I_SetWindowTitle ( GameStartupInfo . Name ) ;
2021-05-16 18:01:14 +00:00
DeleteStartupScreen ( ) ;
2020-08-30 08:42:44 +00:00
2021-04-05 11:55:36 +00:00
V_Init2 ( ) ;
2021-04-05 13:41:57 +00:00
twod - > Begin ( screen - > GetWidth ( ) , screen - > GetHeight ( ) ) ;
twod - > End ( ) ;
UpdateJoystickMenu ( NULL ) ;
UpdateVRModes ( ) ;
2021-04-05 11:55:36 +00:00
setVideoMode ( ) ;
LoadVoxelModels ( ) ;
GLInterface . Init ( screen - > GetWidth ( ) ) ;
screen - > BeginFrame ( ) ;
screen - > SetTextureFilterMode ( ) ;
setViewport ( hud_size ) ;
2020-08-30 08:42:44 +00:00
2020-09-02 20:55:57 +00:00
D_CheckNetGame ( ) ;
2020-10-24 19:02:00 +00:00
UpdateGenericUI ( ui_generic ) ;
2020-09-02 20:55:57 +00:00
MainLoop ( ) ;
2020-09-02 21:03:48 +00:00
return 0 ; // this is never reached. MainLoop only exits via exception.
2019-10-25 22:32:49 +00:00
}
2020-08-23 15:47:05 +00:00
//---------------------------------------------------------------------------
//
// The one and only main loop in the entire engine. Yay!
//
//---------------------------------------------------------------------------
2020-08-30 17:59:46 +00:00
void updatePauseStatus ( )
2020-08-26 14:47:30 +00:00
{
2020-08-27 20:38:52 +00:00
// This must go through the network in multiplayer games.
2021-05-16 08:53:38 +00:00
if ( M_Active ( ) | | System_WantGuiCapture ( ) | | ! AppActive )
2020-08-26 14:47:30 +00:00
{
paused = 1 ;
}
else if ( ! M_Active ( ) | | ! System_WantGuiCapture ( ) )
{
if ( ! pausedWithKey )
{
paused = 0 ;
}
if ( sendPause )
{
sendPause = false ;
paused = pausedWithKey ? 0 : 2 ;
pausedWithKey = ! ! paused ;
}
}
2021-04-16 20:14:11 +00:00
if ( paused )
S_PauseSound ( ! pausedWithKey , ! paused ) ;
else
S_ResumeSound ( paused ) ;
2020-08-26 14:47:30 +00:00
}
2020-07-14 15:35:19 +00:00
//==========================================================================
//
//
//
//==========================================================================
2021-04-05 11:55:36 +00:00
void LoadVoxelModels ( void ) ;
2020-07-14 15:35:19 +00:00
2021-02-25 11:16:21 +00:00
void setVideoMode ( )
{
xdim = screen - > GetWidth ( ) ;
ydim = screen - > GetHeight ( ) ;
V_UpdateModeSize ( xdim , ydim ) ;
videoSetViewableArea ( 0 , 0 , xdim - 1 , ydim - 1 ) ;
2019-12-24 18:59:14 +00:00
}
2019-10-27 07:14:58 +00:00
//==========================================================================
//
//
//
//==========================================================================
CVAR ( String , combatmacro0 , " " , CVAR_ARCHIVE | CVAR_USERINFO )
CVAR ( String , combatmacro1 , " " , CVAR_ARCHIVE | CVAR_USERINFO )
CVAR ( String , combatmacro2 , " " , CVAR_ARCHIVE | CVAR_USERINFO )
CVAR ( String , combatmacro3 , " " , CVAR_ARCHIVE | CVAR_USERINFO )
CVAR ( String , combatmacro4 , " " , CVAR_ARCHIVE | CVAR_USERINFO )
CVAR ( String , combatmacro5 , " " , CVAR_ARCHIVE | CVAR_USERINFO )
CVAR ( String , combatmacro6 , " " , CVAR_ARCHIVE | CVAR_USERINFO )
CVAR ( String , combatmacro7 , " " , CVAR_ARCHIVE | CVAR_USERINFO )
CVAR ( String , combatmacro8 , " " , CVAR_ARCHIVE | CVAR_USERINFO )
CVAR ( String , combatmacro9 , " " , CVAR_ARCHIVE | CVAR_USERINFO )
FStringCVar * const CombatMacros [ ] = { & combatmacro0 , & combatmacro1 , & combatmacro2 , & combatmacro3 , & combatmacro4 , & combatmacro5 , & combatmacro6 , & combatmacro7 , & combatmacro8 , & combatmacro9 } ;
void CONFIG_ReadCombatMacros ( )
{
FScanner sc ;
2019-11-24 09:03:19 +00:00
try
{
2019-12-26 13:46:14 +00:00
sc . Open ( " engine/combatmacros.txt " ) ;
2019-11-24 09:03:19 +00:00
for ( auto s : CombatMacros )
{
sc . MustGetToken ( TK_StringConst ) ;
2020-07-27 16:12:24 +00:00
UCVarValue val ;
val . String = sc . String ;
s - > SetGenericRepDefault ( val , CVAR_String ) ;
2019-11-24 09:03:19 +00:00
}
}
2020-04-11 21:50:43 +00:00
catch ( const CRecoverableError & )
2019-10-27 07:14:58 +00:00
{
2019-11-24 09:03:19 +00:00
// We do not want this to error out. Just ignore if it fails.
2019-10-27 07:14:58 +00:00
}
}
2019-10-26 19:50:49 +00:00
//==========================================================================
//
//
//
//==========================================================================
2019-10-26 21:45:55 +00:00
2019-12-15 12:34:00 +00:00
CCMD ( snd_reset )
2019-10-26 21:45:55 +00:00
{
2019-12-15 12:34:00 +00:00
Mus_Stop ( ) ;
2019-12-15 16:16:11 +00:00
if ( soundEngine ) soundEngine - > Reset ( ) ;
2019-12-26 12:04:29 +00:00
Mus_ResumeSaved ( ) ;
2019-10-26 21:45:55 +00:00
}
2020-05-28 23:22:45 +00:00
//==========================================================================
//
// S_PauseSound
//
// Stop music and sound effects, during game PAUSE.
//
//==========================================================================
void S_PauseSound ( bool notmusic , bool notsfx )
{
if ( ! notmusic )
{
S_PauseMusic ( ) ;
}
if ( ! notsfx )
{
soundEngine - > SetPaused ( true ) ;
GSnd - > SetSfxPaused ( true , 0 ) ;
2021-04-16 20:14:11 +00:00
S_PauseAllCustomStreams ( true ) ;
2020-05-28 23:22:45 +00:00
}
}
//==========================================================================
//
// S_ResumeSound
//
// Resume music and sound effects, after game PAUSE.
//
//==========================================================================
void S_ResumeSound ( bool notsfx )
{
S_ResumeMusic ( ) ;
if ( ! notsfx )
{
soundEngine - > SetPaused ( false ) ;
GSnd - > SetSfxPaused ( false , 0 ) ;
2021-04-16 20:14:11 +00:00
S_PauseAllCustomStreams ( false ) ;
2020-05-28 23:22:45 +00:00
}
}
2019-12-22 19:55:47 +00:00
//==========================================================================
//
// S_SetSoundPaused
//
// Called with state non-zero when the app is active, zero when it isn't.
//
//==========================================================================
void S_SetSoundPaused ( int state )
{
if ( state )
{
if ( paused = = 0 )
{
S_ResumeSound ( true ) ;
2021-05-16 09:51:51 +00:00
}
if ( GSnd ! = nullptr )
{
GSnd - > SetInactive ( SoundRenderer : : INACTIVE_Active ) ;
2019-12-22 19:55:47 +00:00
}
}
else
{
if ( paused = = 0 )
{
S_PauseSound ( false , true ) ;
if ( GSnd ! = nullptr )
{
2020-05-28 23:22:45 +00:00
GSnd - > SetInactive ( SoundRenderer : : INACTIVE_Complete ) ;
2019-12-22 19:55:47 +00:00
}
}
}
2020-08-30 10:49:21 +00:00
#if 0
2020-08-30 08:42:44 +00:00
if ( ! netgame
#if 0 //def _DEBUG
& & ! demoplayback
# endif
)
{
pauseext = ! state ;
}
2020-08-30 10:49:21 +00:00
# endif
2019-12-22 19:55:47 +00:00
}
2020-01-12 13:54:43 +00:00
2020-02-05 11:57:17 +00:00
FString G_GetDemoPath ( )
{
FString path = M_GetDemoPath ( ) ;
path < < LumpFilter < < ' / ' ;
CreatePath ( path ) ;
return path ;
}
2020-03-08 12:54:00 +00:00
CCMD ( printinterface )
{
Printf ( " Current interface is %s \n " , gi - > Name ( ) ) ;
}
2020-04-11 22:04:02 +00:00
CCMD ( togglemsg )
{
FBaseCVar * var , * prev ;
UCVarValue val ;
if ( argv . argc ( ) > 1 )
{
if ( ( var = FindCVar ( argv [ 1 ] , & prev ) ) )
{
var - > MarkUnsafe ( ) ;
val = var - > GetGenericRep ( CVAR_Bool ) ;
val . Bool = ! val . Bool ;
var - > SetGenericRep ( val , CVAR_Bool ) ;
const char * statestr = argv . argc ( ) < = 2 ? " * " : argv [ 2 ] ;
if ( * statestr = = ' * ' )
{
2020-06-30 20:53:15 +00:00
Printf ( PRINT_MEDIUM | PRINT_NOTIFY , " \" %s \" = \" %s \" \n " , var - > GetName ( ) , val . Bool ? " true " : " false " ) ;
2020-04-11 22:04:02 +00:00
}
else
{
int state = ( int ) strtoll ( argv [ 2 ] , nullptr , 0 ) ;
if ( state ! = 0 )
{
// Order of Duke's quote string varies, some have on first, some off, so use the sign of the parameter to decide.
// Positive means Off/On, negative means On/Off
int quote = state > 0 ? state + val . Bool : - ( state + val . Bool ) ;
auto text = quoteMgr . GetQuote ( quote ) ;
2020-06-30 20:53:15 +00:00
if ( text ) Printf ( PRINT_MEDIUM | PRINT_NOTIFY , " %s \n " , text ) ;
2020-04-11 22:04:02 +00:00
}
}
}
}
}
2020-06-14 16:57:55 +00:00
bool OkForLocalization ( FTextureID texnum , const char * substitute )
{
return false ;
}
2020-08-24 18:34:18 +00:00
// Mainly a dummy.
CCMD ( taunt )
{
if ( argv . argc ( ) > 2 )
{
int taunt = atoi ( argv [ 1 ] ) ;
int mode = atoi ( argv [ 2 ] ) ;
// In a ZDoom-style protocol this should be sent:
// Net_WriteByte(DEM_TAUNT);
// Net_WriteByte(taunt);
// Net_WriteByte(mode);
if ( mode = = 1 )
{
// todo:
//gi->PlayTaunt(taunt);
// Duke:
// startrts(taunt, 1)
// Blood:
// sndStartSample(4400 + taunt, 128, 1, 0);
// SW:
// PlaySoundRTS(taunt);
// Exhumed does not implement RTS, should be like Duke
//
}
Printf ( PRINT_NOTIFY , " %s " , * * CombatMacros [ taunt - 1 ] ) ;
}
}
2020-08-30 10:02:32 +00:00
2020-11-10 21:07:45 +00:00
void GameInterface : : loadPalette ( )
{
paletteLoadFromDisk ( ) ;
}
2020-08-30 10:02:32 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2020-09-03 21:10:28 +00:00
void GameInterface : : FreeLevelData ( )
{
// Make sure that there is no more level to toy around with.
initspritelists ( ) ;
numsectors = numwalls = 0 ;
currentLevel = nullptr ;
}
2020-09-04 22:58:25 +00:00
2020-09-05 11:57:26 +00:00
//---------------------------------------------------------------------------
//
// DrawCrosshair
//
//---------------------------------------------------------------------------
2020-10-28 15:56:00 +00:00
void ST_DrawCrosshair ( int phealth , double xpos , double ypos , double scale ) ;
//void DrawGenericCrosshair(int num, int phealth, double xdelta);
void ST_LoadCrosshair ( int num , bool alwaysload ) ;
CVAR ( Int , crosshair , 0 , CVAR_ARCHIVE )
2020-09-05 11:57:26 +00:00
2020-09-21 21:29:52 +00:00
void DrawCrosshair ( int deftile , int health , double xdelta , double ydelta , double scale , PalEntry color )
2020-09-05 11:57:26 +00:00
{
int type = - 1 ;
if ( automapMode = = am_off & & cl_crosshair )
{
if ( deftile < MAXTILES & & crosshair = = 0 )
{
auto tile = tileGetTexture ( deftile ) ;
if ( tile )
{
2020-11-13 16:56:55 +00:00
double crosshair_scale = crosshairscale * scale ;
2020-09-21 21:29:52 +00:00
DrawTexture ( twod , tile , 160 + xdelta , 100 + ydelta , DTA_Color , color ,
2020-09-05 11:57:26 +00:00
DTA_FullscreenScale , FSMode_Fit320x200 , DTA_ScaleX , crosshair_scale , DTA_ScaleY , crosshair_scale , DTA_CenterOffsetRel , true ,
DTA_ViewportX , windowxy1 . x , DTA_ViewportY , windowxy1 . y , DTA_ViewportWidth , windowxy2 . x - windowxy1 . x + 1 , DTA_ViewportHeight , windowxy2 . y - windowxy1 . y + 1 , TAG_DONE ) ;
return ;
}
}
2020-10-28 15:56:00 +00:00
// 0 means 'game provided crosshair' - use type 2 as fallback.
ST_LoadCrosshair ( crosshair = = 0 ? 2 : * crosshair , false ) ;
double xpos = ( windowxy1 . x + windowxy2 . x ) / 2 + xdelta * ( windowxy2 . y - windowxy1 . y ) / 240. ;
double ypos = ( windowxy1 . y + windowxy2 . y ) / 2 ;
ST_DrawCrosshair ( health , xpos , ypos , 1 ) ;
2020-09-05 11:57:26 +00:00
}
2020-09-16 14:42:44 +00:00
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void LoadDefinitions ( )
{
2021-04-07 19:46:44 +00:00
const char * defsfile = G_DefFile ( ) ;
FString razedefsfile = defsfile ;
razedefsfile . Substitute ( " .def " , " -raze.def " ) ;
2021-04-22 06:33:45 +00:00
loaddefinitionsfile ( " engine/engine.def " ) ; // Internal stuff that is required.
2021-04-07 19:46:44 +00:00
// check what we have.
// user .defs override the default ones and are not cumulative.
// if we fine even one Raze-specific file, all of those will be loaded cumulatively.
// otherwise the default rules inherited from older ports apply.
if ( userConfig . UserDef . IsNotEmpty ( ) )
{
2021-04-22 06:33:45 +00:00
loaddefinitionsfile ( userConfig . UserDef , false ) ;
2021-04-07 19:46:44 +00:00
}
else
{
if ( fileSystem . FileExists ( razedefsfile ) )
{
2021-04-22 06:33:45 +00:00
loaddefinitionsfile ( razedefsfile , true ) ;
2021-04-07 19:46:44 +00:00
}
2021-04-22 06:33:45 +00:00
else if ( fileSystem . FileExists ( defsfile ) )
2021-04-07 19:46:44 +00:00
{
2021-04-22 06:33:45 +00:00
loaddefinitionsfile ( defsfile , false ) ;
2021-04-07 19:46:44 +00:00
}
}
2021-04-17 21:52:45 +00:00
2021-04-22 06:33:45 +00:00
if ( userConfig . AddDefs )
2021-04-17 21:52:45 +00:00
{
2021-04-22 06:33:45 +00:00
for ( auto & m : * userConfig . AddDefs )
{
loaddefinitionsfile ( m , false ) ;
}
userConfig . AddDefs . reset ( ) ;
2021-04-17 21:52:45 +00:00
}
2021-04-22 06:33:45 +00:00
if ( GameStartupInfo . def . IsNotEmpty ( ) )
2020-09-16 14:42:44 +00:00
{
2021-04-22 06:33:45 +00:00
loaddefinitionsfile ( GameStartupInfo . def ) ; // Stuff from gameinfo.
2020-09-16 14:42:44 +00:00
}
2021-04-07 19:46:44 +00:00
// load the widescreen replacements last. This ensures that mods still get the correct CRCs for their own tile replacements.
2020-09-16 14:42:44 +00:00
if ( fileSystem . FindFile ( " engine/widescreen.def " ) > = 0 & & ! Args - > CheckParm ( " -nowidescreen " ) )
{
loaddefinitionsfile ( " engine/widescreen.def " ) ;
}
2021-04-07 19:46:44 +00:00
fileSystem . InitHashChains ( ) ; // make sure that any resources that got added can be found again.
2020-09-16 14:42:44 +00:00
}
2020-10-04 16:31:48 +00:00
bool M_Active ( )
{
return CurrentMenu ! = nullptr | | ConsoleState = = c_down | | ConsoleState = = c_falling ;
}
struct gamefilter
{
const char * gamename ;
int gameflag ;
} ;
static const gamefilter games [ ] = {
{ " Duke " , GAMEFLAG_DUKE } ,
{ " Nam " , GAMEFLAG_NAM | GAMEFLAG_NAPALM } ,
{ " NamOnly " , GAMEFLAG_NAM } , // for cases where the difference matters.
{ " Napalm " , GAMEFLAG_NAPALM } ,
{ " WW2GI " , GAMEFLAG_WW2GI } ,
{ " Redneck " , GAMEFLAG_RR } ,
{ " RedneckRides " , GAMEFLAG_RRRA } ,
{ " Deer " , GAMEFLAG_DEER } ,
{ " Blood " , GAMEFLAG_BLOOD } ,
{ " ShadowWarrior " , GAMEFLAG_SW } ,
{ " Exhumed " , GAMEFLAG_POWERSLAVE | GAMEFLAG_EXHUMED } ,
2020-10-08 20:20:41 +00:00
{ " Plutopak " , GAMEFLAG_PLUTOPAK } ,
2020-10-04 16:31:48 +00:00
{ " Worldtour " , GAMEFLAG_WORLDTOUR } ,
2020-10-07 21:22:29 +00:00
{ " Shareware " , GAMEFLAG_SHAREWARE } ,
2020-10-04 16:31:48 +00:00
} ;
bool validFilter ( const char * str )
{
for ( auto & gf : games )
{
if ( g_gameType & gf . gameflag )
{
if ( ! stricmp ( str , gf . gamename ) ) return true ;
}
}
return false ;
}
2020-10-05 18:44:30 +00:00
# include "vm.h"
DEFINE_ACTION_FUNCTION ( _Screen , GetViewWindow )
{
PARAM_PROLOGUE ;
if ( numret > 0 ) ret [ 0 ] . SetInt ( windowxy1 . x ) ;
if ( numret > 1 ) ret [ 1 ] . SetInt ( windowxy1 . y ) ;
if ( numret > 2 ) ret [ 2 ] . SetInt ( windowxy2 . x - windowxy1 . x + 1 ) ;
if ( numret > 3 ) ret [ 3 ] . SetInt ( windowxy2 . y - windowxy1 . y + 1 ) ;
return MIN ( numret , 4 ) ;
}
2021-04-23 08:07:02 +00:00
DEFINE_ACTION_FUNCTION_NATIVE ( _Raze , ShadeToLight , shadeToLight )
2020-10-06 22:50:26 +00:00
{
PARAM_PROLOGUE ;
PARAM_INT ( shade ) ;
ACTION_RETURN_INT ( shadeToLight ( shade ) ) ;
}
2021-04-23 08:07:02 +00:00
DEFINE_ACTION_FUNCTION_NATIVE ( _Raze , StopAllSounds , FX_StopAllSounds )
{
FX_StopAllSounds ( ) ;
return 0 ;
}
2021-04-25 18:02:40 +00:00
DEFINE_ACTION_FUNCTION_NATIVE ( _Raze , StopMusic , Mus_Stop )
{
Mus_Stop ( ) ;
return 0 ;
}
2021-04-23 08:07:02 +00:00
DEFINE_ACTION_FUNCTION_NATIVE ( _Raze , SoundEnabled , SoundEnabled )
{
ACTION_RETURN_INT ( SoundEnabled ( ) ) ;
}
DEFINE_ACTION_FUNCTION_NATIVE ( _Raze , MusicEnabled , MusicEnabled )
{
ACTION_RETURN_INT ( MusicEnabled ( ) ) ;
}
2021-04-25 18:02:40 +00:00
DEFINE_ACTION_FUNCTION_NATIVE ( _Raze , GetTimeFrac , I_GetTimeFrac )
{
2021-05-11 23:50:41 +00:00
ACTION_RETURN_FLOAT ( I_GetTimeFrac ( ) ) ;
2021-04-25 18:02:40 +00:00
}
2021-04-23 10:24:42 +00:00
DEFINE_ACTION_FUNCTION ( _Raze , PlayerName )
{
PARAM_PROLOGUE ;
PARAM_INT ( index ) ;
ACTION_RETURN_STRING ( unsigned ( index ) > = MAXPLAYERS ? " " : PlayerName ( index ) ) ;
}
2021-04-30 14:21:37 +00:00
DEFINE_ACTION_FUNCTION_NATIVE ( _Raze , bsin , bsin )
{
PARAM_PROLOGUE ;
PARAM_INT ( v ) ;
PARAM_INT ( shift ) ;
ACTION_RETURN_INT ( bsin ( v , shift ) ) ;
}
DEFINE_ACTION_FUNCTION_NATIVE ( _Raze , bcos , bcos )
{
PARAM_PROLOGUE ;
PARAM_INT ( v ) ;
PARAM_INT ( shift ) ;
ACTION_RETURN_INT ( bcos ( v , shift ) ) ;
}
2021-05-15 12:27:32 +00:00
DEFINE_ACTION_FUNCTION_NATIVE ( _Raze , GetBuildTime , I_GetBuildTime )
{
ACTION_RETURN_INT ( I_GetBuildTime ( ) ) ;
}
bool PickTexture ( FRenderState * state , FGameTexture * tex , int paletteid , TexturePick & pick ) ;
DEFINE_ACTION_FUNCTION ( _Raze , PickTexture )
{
PARAM_PROLOGUE ;
PARAM_INT ( texid ) ;
TexturePick pick ;
if ( PickTexture ( nullptr , TexMan . GetGameTexture ( FSetTextureID ( texid ) ) , TRANSLATION ( Translation_Remap , 0 ) , pick ) )
{
ACTION_RETURN_INT ( pick . texture - > GetID ( ) . GetIndex ( ) ) ;
}
ACTION_RETURN_INT ( texid ) ;
}
2021-05-01 22:35:56 +00:00
DEFINE_ACTION_FUNCTION ( _MapRecord , GetCluster )
{
PARAM_SELF_STRUCT_PROLOGUE ( MapRecord ) ;
ACTION_RETURN_POINTER ( FindCluster ( self - > cluster ) ) ;
}
2020-10-05 18:44:30 +00:00
extern bool demoplayback ;
DEFINE_GLOBAL ( multiplayer )
DEFINE_GLOBAL ( netgame )
DEFINE_GLOBAL ( gameaction )
DEFINE_GLOBAL ( gamestate )
DEFINE_GLOBAL ( demoplayback )
DEFINE_GLOBAL ( consoleplayer )
2021-04-23 10:24:42 +00:00
DEFINE_GLOBAL ( currentLevel )
2021-04-25 18:02:40 +00:00
DEFINE_GLOBAL ( paused )
2021-05-11 20:21:52 +00:00
DEFINE_GLOBAL ( automapMode )
DEFINE_GLOBAL ( PlayClock )
2021-04-23 10:24:42 +00:00
2021-05-01 22:35:56 +00:00
DEFINE_FIELD_X ( ClusterDef , ClusterDef , name )
DEFINE_FIELD_X ( ClusterDef , ClusterDef , InterBackground )
2021-04-23 10:24:42 +00:00
DEFINE_FIELD_X ( MapRecord , MapRecord , parTime )
DEFINE_FIELD_X ( MapRecord , MapRecord , designerTime )
DEFINE_FIELD_X ( MapRecord , MapRecord , fileName )
DEFINE_FIELD_X ( MapRecord , MapRecord , labelName )
DEFINE_FIELD_X ( MapRecord , MapRecord , name )
DEFINE_FIELD_X ( MapRecord , MapRecord , music )
DEFINE_FIELD_X ( MapRecord , MapRecord , cdSongId )
DEFINE_FIELD_X ( MapRecord , MapRecord , flags )
DEFINE_FIELD_X ( MapRecord , MapRecord , levelNumber )
2021-04-27 22:51:28 +00:00
DEFINE_FIELD_X ( MapRecord , MapRecord , cluster )
2021-05-02 08:35:43 +00:00
DEFINE_FIELD_X ( MapRecord , MapRecord , NextMap )
DEFINE_FIELD_X ( MapRecord , MapRecord , NextSecret )
2021-04-23 10:24:42 +00:00
//native readonly String messages[MAX_MESSAGES];
2021-05-01 20:52:28 +00:00
DEFINE_FIELD_X ( MapRecord , MapRecord , Author )
2021-05-01 22:35:56 +00:00
DEFINE_FIELD_X ( MapRecord , MapRecord , InterBackground )
2021-04-26 00:00:40 +00:00
DEFINE_FIELD_X ( SummaryInfo , SummaryInfo , kills )
DEFINE_FIELD_X ( SummaryInfo , SummaryInfo , maxkills )
DEFINE_FIELD_X ( SummaryInfo , SummaryInfo , secrets )
DEFINE_FIELD_X ( SummaryInfo , SummaryInfo , maxsecrets )
DEFINE_FIELD_X ( SummaryInfo , SummaryInfo , supersecrets )
2021-04-26 19:13:11 +00:00
DEFINE_FIELD_X ( SummaryInfo , SummaryInfo , playercount )
2021-04-26 00:00:40 +00:00
DEFINE_FIELD_X ( SummaryInfo , SummaryInfo , time )
DEFINE_FIELD_X ( SummaryInfo , SummaryInfo , cheated )
DEFINE_FIELD_X ( SummaryInfo , SummaryInfo , endofgame )
2021-04-05 18:12:11 +00:00
void InitBuildTiles ( )
{
// need to find a better way to handle this thing.
}