2011-11-22 21:28:15 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Doom 3 GPL Source Code
2011-12-06 18:20:15 +00:00
Copyright ( C ) 1999 - 2011 id Software LLC , a ZeniMax Media company .
2011-11-22 21:28:15 +00:00
2011-12-06 16:14:59 +00:00
This file is part of the Doom 3 GPL Source Code ( " Doom 3 Source Code " ) .
2011-11-22 21:28:15 +00:00
Doom 3 Source Code 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 .
Doom 3 Source Code 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 Doom 3 Source Code . If not , see < http : //www.gnu.org/licenses/>.
In addition , the Doom 3 Source Code is also subject to certain additional terms . You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code . If not , please request a copy in writing from id Software at the address below .
If you have questions concerning this license or the applicable additional terms , you may contact in writing id Software LLC , c / o ZeniMax Media Inc . , Suite 120 , Rockville , Maryland 20850 USA .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2021-02-07 05:10:19 +00:00
# include "sys/Stub_SDL_endian.h"
2011-12-16 22:28:29 +00:00
# include "sys/platform.h"
# include "idlib/LangDict.h"
# include "idlib/Timer.h"
# include "framework/async/NetworkSystem.h"
# include "framework/BuildVersion.h"
# include "framework/DeclEntityDef.h"
# include "framework/FileSystem.h"
2021-02-07 05:10:19 +00:00
# include "framework/Licensee.h"
2011-12-16 22:28:29 +00:00
# include "renderer/ModelManager.h"
# include "gamesys/SysCvar.h"
# include "gamesys/SysCmds.h"
# include "script/Script_Thread.h"
# include "ai/AI.h"
# include "anim/Anim_Testmodel.h"
# include "Camera.h"
# include "SmokeParticles.h"
# include "Player.h"
# include "WorldSpawn.h"
# include "Misc.h"
# include "Trigger.h"
2011-11-22 21:28:15 +00:00
# include "Game_local.h"
2011-12-02 16:22:12 +00:00
const int NUM_RENDER_PORTAL_BITS = idMath : : BitsForInteger ( PS_BLOCK_ALL ) ;
const float DEFAULT_GRAVITY = 1066.0f ;
const idVec3 DEFAULT_GRAVITY_VEC3 ( 0 , 0 , - DEFAULT_GRAVITY ) ;
const int CINEMATIC_SKIP_DELAY = SEC2MS ( 2.0f ) ;
2011-11-22 21:28:15 +00:00
# ifdef GAME_DLL
idSys * sys = NULL ;
idCommon * common = NULL ;
idCmdSystem * cmdSystem = NULL ;
idCVarSystem * cvarSystem = NULL ;
idFileSystem * fileSystem = NULL ;
idNetworkSystem * networkSystem = NULL ;
idRenderSystem * renderSystem = NULL ;
idSoundSystem * soundSystem = NULL ;
idRenderModelManager * renderModelManager = NULL ;
idUserInterfaceManager * uiManager = NULL ;
idDeclManager * declManager = NULL ;
idAASFileManager * AASFileManager = NULL ;
idCollisionModelManager * collisionModelManager = NULL ;
idCVar * idCVar : : staticVars = NULL ;
idCVar com_forceGenericSIMD ( " com_forceGenericSIMD " , " 0 " , CVAR_BOOL | CVAR_SYSTEM , " force generic platform independent SIMD " ) ;
# endif
idRenderWorld * gameRenderWorld = NULL ; // all drawing is done to this world
idSoundWorld * gameSoundWorld = NULL ; // all audio goes to this world
static gameExport_t gameExport ;
// global animation lib
idAnimManager animationLib ;
// the rest of the engine will only reference the "game" variable, while all local aspects stay hidden
idGameLocal gameLocal ;
idGame * game = & gameLocal ; // statically pointed at an idGameLocal
const char * idGameLocal : : sufaceTypeNames [ MAX_SURFACE_TYPES ] = {
" none " , " metal " , " stone " , " flesh " , " wood " , " cardboard " , " liquid " , " glass " , " plastic " ,
" ricochet " , " surftype10 " , " surftype11 " , " surftype12 " , " surftype13 " , " surftype14 " , " surftype15 "
} ;
# ifdef _D3XP
// List of all defs used by the player that will stay on the fast timeline
2011-11-30 21:15:10 +00:00
static const char * fastEntityList [ ] = {
2011-11-22 21:28:15 +00:00
" player_doommarine " ,
" weapon_chainsaw " ,
" weapon_fists " ,
" weapon_flashlight " ,
" weapon_rocketlauncher " ,
" projectile_rocket " ,
" weapon_machinegun " ,
" projectile_bullet_machinegun " ,
" weapon_pistol " ,
" projectile_bullet_pistol " ,
" weapon_handgrenade " ,
" projectile_grenade " ,
" weapon_bfg " ,
" projectile_bfg " ,
" weapon_chaingun " ,
" projectile_chaingunbullet " ,
" weapon_pda " ,
" weapon_plasmagun " ,
" projectile_plasmablast " ,
" weapon_shotgun " ,
" projectile_bullet_shotgun " ,
" weapon_soulcube " ,
" projectile_soulblast " ,
" weapon_shotgun_double " ,
" projectile_shotgunbullet_double " ,
" weapon_grabber " ,
" weapon_bloodstone_active1 " ,
" weapon_bloodstone_active2 " ,
" weapon_bloodstone_active3 " ,
" weapon_bloodstone_passive " ,
NULL } ;
# endif
/*
= = = = = = = = = = =
GetGameAPI
= = = = = = = = = = = =
*/
2011-12-23 00:20:43 +00:00
extern " C " ID_GAME_API gameExport_t * GetGameAPI ( gameImport_t * import ) {
2011-11-22 21:28:15 +00:00
if ( import - > version = = GAME_API_VERSION ) {
// set interface pointers used by the game
sys = import - > sys ;
common = import - > common ;
cmdSystem = import - > cmdSystem ;
cvarSystem = import - > cvarSystem ;
fileSystem = import - > fileSystem ;
networkSystem = import - > networkSystem ;
renderSystem = import - > renderSystem ;
soundSystem = import - > soundSystem ;
renderModelManager = import - > renderModelManager ;
uiManager = import - > uiManager ;
declManager = import - > declManager ;
AASFileManager = import - > AASFileManager ;
collisionModelManager = import - > collisionModelManager ;
}
// set interface pointers used by idLib
idLib : : sys = sys ;
idLib : : common = common ;
idLib : : cvarSystem = cvarSystem ;
idLib : : fileSystem = fileSystem ;
// setup export interface
gameExport . version = GAME_API_VERSION ;
gameExport . game = game ;
gameExport . gameEdit = gameEdit ;
return & gameExport ;
}
/*
= = = = = = = = = = =
TestGameAPI
= = = = = = = = = = = =
*/
void TestGameAPI ( void ) {
gameImport_t testImport ;
gameExport_t testExport ;
testImport . sys = : : sys ;
testImport . common = : : common ;
testImport . cmdSystem = : : cmdSystem ;
testImport . cvarSystem = : : cvarSystem ;
testImport . fileSystem = : : fileSystem ;
testImport . networkSystem = : : networkSystem ;
testImport . renderSystem = : : renderSystem ;
testImport . soundSystem = : : soundSystem ;
testImport . renderModelManager = : : renderModelManager ;
testImport . uiManager = : : uiManager ;
testImport . declManager = : : declManager ;
testImport . AASFileManager = : : AASFileManager ;
testImport . collisionModelManager = : : collisionModelManager ;
testExport = * GetGameAPI ( & testImport ) ;
}
/*
= = = = = = = = = = =
idGameLocal : : idGameLocal
= = = = = = = = = = = =
*/
idGameLocal : : idGameLocal ( ) {
Clear ( ) ;
}
/*
= = = = = = = = = = =
idGameLocal : : Clear
= = = = = = = = = = = =
*/
void idGameLocal : : Clear ( void ) {
int i ;
serverInfo . Clear ( ) ;
numClients = 0 ;
for ( i = 0 ; i < MAX_CLIENTS ; i + + ) {
userInfo [ i ] . Clear ( ) ;
persistentPlayerInfo [ i ] . Clear ( ) ;
}
memset ( usercmds , 0 , sizeof ( usercmds ) ) ;
memset ( entities , 0 , sizeof ( entities ) ) ;
memset ( spawnIds , - 1 , sizeof ( spawnIds ) ) ;
firstFreeIndex = 0 ;
num_entities = 0 ;
spawnedEntities . Clear ( ) ;
activeEntities . Clear ( ) ;
numEntitiesToDeactivate = 0 ;
sortPushers = false ;
sortTeamMasters = false ;
persistentLevelInfo . Clear ( ) ;
memset ( globalShaderParms , 0 , sizeof ( globalShaderParms ) ) ;
random . SetSeed ( 0 ) ;
world = NULL ;
frameCommandThread = NULL ;
testmodel = NULL ;
testFx = NULL ;
clip . Shutdown ( ) ;
pvs . Shutdown ( ) ;
sessionCommand . Clear ( ) ;
locationEntities = NULL ;
smokeParticles = NULL ;
editEntities = NULL ;
entityHash . Clear ( 1024 , MAX_GENTITIES ) ;
inCinematic = false ;
cinematicSkipTime = 0 ;
cinematicStopTime = 0 ;
cinematicMaxSkipTime = 0 ;
framenum = 0 ;
previousTime = 0 ;
time = 0 ;
vacuumAreaNum = 0 ;
mapFileName . Clear ( ) ;
mapFile = NULL ;
spawnCount = INITIAL_SPAWN_COUNT ;
mapSpawnCount = 0 ;
camera = NULL ;
aasList . Clear ( ) ;
aasNames . Clear ( ) ;
lastAIAlertEntity = NULL ;
lastAIAlertTime = 0 ;
spawnArgs . Clear ( ) ;
gravity . Set ( 0 , 0 , - 1 ) ;
playerPVS . h = - 1 ;
playerConnectedAreas . h = - 1 ;
gamestate = GAMESTATE_UNINITIALIZED ;
skipCinematic = false ;
influenceActive = false ;
localClientNum = 0 ;
isMultiplayer = false ;
isServer = false ;
isClient = false ;
realClientTime = 0 ;
isNewFrame = true ;
clientSmoothing = 0.1f ;
entityDefBits = 0 ;
nextGibTime = 0 ;
globalMaterial = NULL ;
newInfo . Clear ( ) ;
lastGUIEnt = NULL ;
lastGUI = 0 ;
memset ( clientEntityStates , 0 , sizeof ( clientEntityStates ) ) ;
memset ( clientPVS , 0 , sizeof ( clientPVS ) ) ;
memset ( clientSnapshots , 0 , sizeof ( clientSnapshots ) ) ;
eventQueue . Init ( ) ;
savedEventQueue . Init ( ) ;
memset ( lagometer , 0 , sizeof ( lagometer ) ) ;
# ifdef _D3XP
portalSkyEnt = NULL ;
portalSkyActive = false ;
ResetSlowTimeVars ( ) ;
# endif
}
/*
= = = = = = = = = = =
idGameLocal : : Init
initialize the game object , only happens once at startup , not each level load
= = = = = = = = = = = =
*/
void idGameLocal : : Init ( void ) {
const idDict * dict ;
idAAS * aas ;
# ifndef GAME_DLL
TestGameAPI ( ) ;
# else
// initialize idLib
idLib : : Init ( ) ;
// register static cvars declared in the game
idCVar : : RegisterStaticVars ( ) ;
// initialize processor specific SIMD
idSIMD : : InitProcessor ( " game " , com_forceGenericSIMD . GetBool ( ) ) ;
# endif
2012-07-19 16:37:19 +00:00
Printf ( " ----- Initializing Game ----- \n " ) ;
2011-11-22 21:28:15 +00:00
Printf ( " gamename: %s \n " , GAME_VERSION ) ;
Printf ( " gamedate: %s \n " , __DATE__ ) ;
// register game specific decl types
declManager - > RegisterDeclType ( " model " , DECL_MODELDEF , idDeclAllocator < idDeclModelDef > ) ;
declManager - > RegisterDeclType ( " export " , DECL_MODELEXPORT , idDeclAllocator < idDecl > ) ;
// register game specific decl folders
declManager - > RegisterDeclFolder ( " def " , " .def " , DECL_ENTITYDEF ) ;
declManager - > RegisterDeclFolder ( " fx " , " .fx " , DECL_FX ) ;
declManager - > RegisterDeclFolder ( " particles " , " .prt " , DECL_PARTICLE ) ;
declManager - > RegisterDeclFolder ( " af " , " .af " , DECL_AF ) ;
declManager - > RegisterDeclFolder ( " newpdas " , " .pda " , DECL_PDA ) ;
cmdSystem - > AddCommand ( " listModelDefs " , idListDecls_f < DECL_MODELDEF > , CMD_FL_SYSTEM | CMD_FL_GAME , " lists model defs " ) ;
cmdSystem - > AddCommand ( " printModelDefs " , idPrintDecls_f < DECL_MODELDEF > , CMD_FL_SYSTEM | CMD_FL_GAME , " prints a model def " , idCmdSystem : : ArgCompletion_Decl < DECL_MODELDEF > ) ;
Clear ( ) ;
idEvent : : Init ( ) ;
idClass : : Init ( ) ;
InitConsoleCommands ( ) ;
# ifdef _D3XP
if ( ! g_xp_bind_run_once . GetBool ( ) ) {
//The default config file contains remapped controls that support the XP weapons
//We want to run this once after the base doom config file has run so we can
//have the correct xp binds
cmdSystem - > BufferCommandText ( CMD_EXEC_APPEND , " exec default.cfg \n " ) ;
cmdSystem - > BufferCommandText ( CMD_EXEC_APPEND , " seta g_xp_bind_run_once 1 \n " ) ;
cmdSystem - > ExecuteCommandBuffer ( ) ;
}
# endif
// load default scripts
program . Startup ( SCRIPT_DEFAULT ) ;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
# ifdef _D3XP
//BSM Nerve: Loads a game specific main script file
idStr gamedir ;
int i ;
for ( i = 0 ; i < 2 ; i + + ) {
if ( i = = 0 ) {
gamedir = cvarSystem - > GetCVarString ( " fs_game_base " ) ;
} else if ( i = = 1 ) {
gamedir = cvarSystem - > GetCVarString ( " fs_game " ) ;
}
2011-12-06 18:20:15 +00:00
if ( gamedir . Length ( ) > 0 ) {
2011-11-22 21:28:15 +00:00
idStr scriptFile = va ( " script/%s_main.script " , gamedir . c_str ( ) ) ;
if ( fileSystem - > ReadFile ( scriptFile . c_str ( ) , NULL ) > 0 ) {
program . CompileFile ( scriptFile . c_str ( ) ) ;
program . FinishCompilation ( ) ;
}
}
}
# endif
smokeParticles = new idSmokeParticles ;
// set up the aas
dict = FindEntityDefDict ( " aas_types " ) ;
if ( ! dict ) {
Error ( " Unable to find entityDef for 'aas_types' " ) ;
}
// allocate space for the aas
const idKeyValue * kv = dict - > MatchPrefix ( " type " ) ;
while ( kv ! = NULL ) {
aas = idAAS : : Alloc ( ) ;
aasList . Append ( aas ) ;
aasNames . Append ( kv - > GetValue ( ) ) ;
kv = dict - > MatchPrefix ( " type " , kv ) ;
}
gamestate = GAMESTATE_NOMAP ;
Printf ( " ...%d aas types \n " , aasList . Num ( ) ) ;
}
/*
= = = = = = = = = = =
idGameLocal : : Shutdown
shut down the entire game
= = = = = = = = = = = =
*/
void idGameLocal : : Shutdown ( void ) {
if ( ! common ) {
return ;
}
2012-07-19 16:37:19 +00:00
Printf ( " ----- Game Shutdown ----- \n " ) ;
2011-11-22 21:28:15 +00:00
mpGame . Shutdown ( ) ;
MapShutdown ( ) ;
aasList . DeleteContents ( true ) ;
aasNames . Clear ( ) ;
idAI : : FreeObstacleAvoidanceNodes ( ) ;
// shutdown the model exporter
idModelExport : : Shutdown ( ) ;
idEvent : : Shutdown ( ) ;
delete [ ] locationEntities ;
locationEntities = NULL ;
delete smokeParticles ;
smokeParticles = NULL ;
idClass : : Shutdown ( ) ;
// clear list with forces
idForce : : ClearForceList ( ) ;
// free the program data
program . FreeData ( ) ;
// delete the .map file
delete mapFile ;
mapFile = NULL ;
// free the collision map
collisionModelManager - > FreeMap ( ) ;
ShutdownConsoleCommands ( ) ;
// free memory allocated by class objects
Clear ( ) ;
// shut down the animation manager
animationLib . Shutdown ( ) ;
# ifdef GAME_DLL
// remove auto-completion function pointers pointing into this DLL
cvarSystem - > RemoveFlaggedAutoCompletion ( CVAR_GAME ) ;
// enable leak test
Mem_EnableLeakTest ( " game " ) ;
// shutdown idLib
idLib : : ShutDown ( ) ;
# endif
}
/*
= = = = = = = = = = =
idGameLocal : : SaveGame
save the current player state , level name , and level state
the session may have written some data to the file already
= = = = = = = = = = = =
*/
void idGameLocal : : SaveGame ( idFile * f ) {
int i ;
idEntity * ent ;
idEntity * link ;
idSaveGame savegame ( f ) ;
2011-12-06 18:20:15 +00:00
if ( g_flushSave . GetBool ( ) = = true ) {
2011-11-22 21:28:15 +00:00
// force flushing with each write... for tracking down
// save game bugs.
f - > ForceFlush ( ) ;
}
savegame . WriteBuildNumber ( BUILD_NUMBER ) ;
2021-02-07 05:10:19 +00:00
// DG: add some more information to savegame to make future quirks easier
savegame . WriteInt ( INTERNAL_SAVEGAME_VERSION ) ; // to be independent of BUILD_NUMBER
savegame . WriteString ( D3_OSTYPE ) ; // operating system - from CMake
savegame . WriteString ( D3_ARCH ) ; // CPU architecture (e.g. "x86" or "x86_64") - from CMake
savegame . WriteString ( ENGINE_VERSION ) ;
savegame . WriteShort ( ( short ) sizeof ( void * ) ) ; // tells us if it's from a 32bit (4) or 64bit system (8)
savegame . WriteShort ( SDL_BYTEORDER ) ; // SDL_LIL_ENDIAN or SDL_BIG_ENDIAN
// DG end
2011-11-22 21:28:15 +00:00
// go through all entities and threads and add them to the object list
for ( i = 0 ; i < MAX_GENTITIES ; i + + ) {
ent = entities [ i ] ;
if ( ent ) {
if ( ent - > GetTeamMaster ( ) & & ent - > GetTeamMaster ( ) ! = ent ) {
continue ;
}
for ( link = ent ; link ! = NULL ; link = link - > GetNextTeamEntity ( ) ) {
savegame . AddObject ( link ) ;
}
}
}
idList < idThread * > threads ;
threads = idThread : : GetThreads ( ) ;
for ( i = 0 ; i < threads . Num ( ) ; i + + ) {
savegame . AddObject ( threads [ i ] ) ;
}
// write out complete object list
savegame . WriteObjectList ( ) ;
program . Save ( & savegame ) ;
savegame . WriteInt ( g_skill . GetInteger ( ) ) ;
savegame . WriteDict ( & serverInfo ) ;
savegame . WriteInt ( numClients ) ;
for ( i = 0 ; i < numClients ; i + + ) {
savegame . WriteDict ( & userInfo [ i ] ) ;
savegame . WriteUsercmd ( usercmds [ i ] ) ;
savegame . WriteDict ( & persistentPlayerInfo [ i ] ) ;
}
for ( i = 0 ; i < MAX_GENTITIES ; i + + ) {
savegame . WriteObject ( entities [ i ] ) ;
savegame . WriteInt ( spawnIds [ i ] ) ;
}
savegame . WriteInt ( firstFreeIndex ) ;
savegame . WriteInt ( num_entities ) ;
// enityHash is restored by idEntity::Restore setting the entity name.
savegame . WriteObject ( world ) ;
savegame . WriteInt ( spawnedEntities . Num ( ) ) ;
for ( ent = spawnedEntities . Next ( ) ; ent ! = NULL ; ent = ent - > spawnNode . Next ( ) ) {
savegame . WriteObject ( ent ) ;
}
savegame . WriteInt ( activeEntities . Num ( ) ) ;
for ( ent = activeEntities . Next ( ) ; ent ! = NULL ; ent = ent - > activeNode . Next ( ) ) {
savegame . WriteObject ( ent ) ;
}
savegame . WriteInt ( numEntitiesToDeactivate ) ;
savegame . WriteBool ( sortPushers ) ;
savegame . WriteBool ( sortTeamMasters ) ;
savegame . WriteDict ( & persistentLevelInfo ) ;
for ( i = 0 ; i < MAX_GLOBAL_SHADER_PARMS ; i + + ) {
savegame . WriteFloat ( globalShaderParms [ i ] ) ;
}
savegame . WriteInt ( random . GetSeed ( ) ) ;
savegame . WriteObject ( frameCommandThread ) ;
// clip
// push
// pvs
testmodel = NULL ;
testFx = NULL ;
savegame . WriteString ( sessionCommand ) ;
// FIXME: save smoke particles
savegame . WriteInt ( cinematicSkipTime ) ;
savegame . WriteInt ( cinematicStopTime ) ;
savegame . WriteInt ( cinematicMaxSkipTime ) ;
savegame . WriteBool ( inCinematic ) ;
savegame . WriteBool ( skipCinematic ) ;
savegame . WriteBool ( isMultiplayer ) ;
savegame . WriteInt ( gameType ) ;
savegame . WriteInt ( framenum ) ;
savegame . WriteInt ( previousTime ) ;
savegame . WriteInt ( time ) ;
# ifdef _D3XP
savegame . WriteInt ( msec ) ;
# endif
savegame . WriteInt ( vacuumAreaNum ) ;
savegame . WriteInt ( entityDefBits ) ;
savegame . WriteBool ( isServer ) ;
savegame . WriteBool ( isClient ) ;
savegame . WriteInt ( localClientNum ) ;
// snapshotEntities is used for multiplayer only
savegame . WriteInt ( realClientTime ) ;
savegame . WriteBool ( isNewFrame ) ;
savegame . WriteFloat ( clientSmoothing ) ;
# ifdef _D3XP
portalSkyEnt . Save ( & savegame ) ;
savegame . WriteBool ( portalSkyActive ) ;
fast . Save ( & savegame ) ;
slow . Save ( & savegame ) ;
savegame . WriteInt ( slowmoState ) ;
savegame . WriteFloat ( slowmoMsec ) ;
savegame . WriteBool ( quickSlowmoReset ) ;
# endif
savegame . WriteBool ( mapCycleLoaded ) ;
savegame . WriteInt ( spawnCount ) ;
if ( ! locationEntities ) {
savegame . WriteInt ( 0 ) ;
} else {
savegame . WriteInt ( gameRenderWorld - > NumAreas ( ) ) ;
for ( i = 0 ; i < gameRenderWorld - > NumAreas ( ) ; i + + ) {
savegame . WriteObject ( locationEntities [ i ] ) ;
}
}
savegame . WriteObject ( camera ) ;
savegame . WriteMaterial ( globalMaterial ) ;
lastAIAlertEntity . Save ( & savegame ) ;
savegame . WriteInt ( lastAIAlertTime ) ;
savegame . WriteDict ( & spawnArgs ) ;
savegame . WriteInt ( playerPVS . i ) ;
savegame . WriteInt ( playerPVS . h ) ;
savegame . WriteInt ( playerConnectedAreas . i ) ;
savegame . WriteInt ( playerConnectedAreas . h ) ;
savegame . WriteVec3 ( gravity ) ;
// gamestate
savegame . WriteBool ( influenceActive ) ;
savegame . WriteInt ( nextGibTime ) ;
// spawnSpots
// initialSpots
// currentInitialSpot
// newInfo
// makingBuild
// shakeSounds
// write out pending events
idEvent : : Save ( & savegame ) ;
savegame . Close ( ) ;
}
/*
= = = = = = = = = = =
idGameLocal : : GetPersistentPlayerInfo
= = = = = = = = = = = =
*/
const idDict & idGameLocal : : GetPersistentPlayerInfo ( int clientNum ) {
idEntity * ent ;
persistentPlayerInfo [ clientNum ] . Clear ( ) ;
ent = entities [ clientNum ] ;
if ( ent & & ent - > IsType ( idPlayer : : Type ) ) {
static_cast < idPlayer * > ( ent ) - > SavePersistantInfo ( ) ;
}
return persistentPlayerInfo [ clientNum ] ;
}
/*
= = = = = = = = = = =
idGameLocal : : SetPersistentPlayerInfo
= = = = = = = = = = = =
*/
void idGameLocal : : SetPersistentPlayerInfo ( int clientNum , const idDict & playerInfo ) {
persistentPlayerInfo [ clientNum ] = playerInfo ;
}
/*
= = = = = = = = = = = =
idGameLocal : : Printf
= = = = = = = = = = = =
*/
void idGameLocal : : Printf ( const char * fmt , . . . ) const {
va_list argptr ;
char text [ MAX_STRING_CHARS ] ;
va_start ( argptr , fmt ) ;
idStr : : vsnPrintf ( text , sizeof ( text ) , fmt , argptr ) ;
va_end ( argptr ) ;
common - > Printf ( " %s " , text ) ;
}
/*
= = = = = = = = = = = =
idGameLocal : : DPrintf
= = = = = = = = = = = =
*/
void idGameLocal : : DPrintf ( const char * fmt , . . . ) const {
va_list argptr ;
char text [ MAX_STRING_CHARS ] ;
if ( ! developer . GetBool ( ) ) {
return ;
}
va_start ( argptr , fmt ) ;
idStr : : vsnPrintf ( text , sizeof ( text ) , fmt , argptr ) ;
va_end ( argptr ) ;
common - > Printf ( " %s " , text ) ;
}
/*
= = = = = = = = = = = =
idGameLocal : : Warning
= = = = = = = = = = = =
*/
void idGameLocal : : Warning ( const char * fmt , . . . ) const {
va_list argptr ;
char text [ MAX_STRING_CHARS ] ;
idThread * thread ;
va_start ( argptr , fmt ) ;
idStr : : vsnPrintf ( text , sizeof ( text ) , fmt , argptr ) ;
va_end ( argptr ) ;
thread = idThread : : CurrentThread ( ) ;
if ( thread ) {
thread - > Warning ( " %s " , text ) ;
} else {
common - > Warning ( " %s " , text ) ;
}
}
/*
= = = = = = = = = = = =
idGameLocal : : DWarning
= = = = = = = = = = = =
*/
void idGameLocal : : DWarning ( const char * fmt , . . . ) const {
va_list argptr ;
char text [ MAX_STRING_CHARS ] ;
idThread * thread ;
if ( ! developer . GetBool ( ) ) {
return ;
}
va_start ( argptr , fmt ) ;
idStr : : vsnPrintf ( text , sizeof ( text ) , fmt , argptr ) ;
va_end ( argptr ) ;
thread = idThread : : CurrentThread ( ) ;
if ( thread ) {
thread - > Warning ( " %s " , text ) ;
} else {
common - > DWarning ( " %s " , text ) ;
}
}
/*
= = = = = = = = = = = =
idGameLocal : : Error
= = = = = = = = = = = =
*/
void idGameLocal : : Error ( const char * fmt , . . . ) const {
va_list argptr ;
char text [ MAX_STRING_CHARS ] ;
idThread * thread ;
va_start ( argptr , fmt ) ;
idStr : : vsnPrintf ( text , sizeof ( text ) , fmt , argptr ) ;
va_end ( argptr ) ;
thread = idThread : : CurrentThread ( ) ;
if ( thread ) {
thread - > Error ( " %s " , text ) ;
} else {
common - > Error ( " %s " , text ) ;
}
}
/*
= = = = = = = = = = = = = = =
gameError
= = = = = = = = = = = = = = =
*/
void gameError ( const char * fmt , . . . ) {
va_list argptr ;
char text [ MAX_STRING_CHARS ] ;
va_start ( argptr , fmt ) ;
idStr : : vsnPrintf ( text , sizeof ( text ) , fmt , argptr ) ;
va_end ( argptr ) ;
gameLocal . Error ( " %s " , text ) ;
}
/*
= = = = = = = = = = =
idGameLocal : : SetLocalClient
= = = = = = = = = = = =
*/
void idGameLocal : : SetLocalClient ( int clientNum ) {
localClientNum = clientNum ;
}
/*
= = = = = = = = = = =
idGameLocal : : SetUserInfo
= = = = = = = = = = = =
*/
const idDict * idGameLocal : : SetUserInfo ( int clientNum , const idDict & userInfo , bool isClient , bool canModify ) {
int i ;
bool modifiedInfo = false ;
this - > isClient = isClient ;
if ( clientNum > = 0 & & clientNum < MAX_CLIENTS ) {
idGameLocal : : userInfo [ clientNum ] = userInfo ;
// server sanity
if ( canModify ) {
// don't let numeric nicknames, it can be exploited to go around kick and ban commands from the server
if ( idStr : : IsNumeric ( this - > userInfo [ clientNum ] . GetString ( " ui_name " ) ) ) {
idGameLocal : : userInfo [ clientNum ] . Set ( " ui_name " , va ( " %s_ " , idGameLocal : : userInfo [ clientNum ] . GetString ( " ui_name " ) ) ) ;
modifiedInfo = true ;
}
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
// don't allow dupe nicknames
for ( i = 0 ; i < numClients ; i + + ) {
if ( i = = clientNum ) {
continue ;
}
if ( entities [ i ] & & entities [ i ] - > IsType ( idPlayer : : Type ) ) {
if ( ! idStr : : Icmp ( idGameLocal : : userInfo [ clientNum ] . GetString ( " ui_name " ) , idGameLocal : : userInfo [ i ] . GetString ( " ui_name " ) ) ) {
idGameLocal : : userInfo [ clientNum ] . Set ( " ui_name " , va ( " %s_ " , idGameLocal : : userInfo [ clientNum ] . GetString ( " ui_name " ) ) ) ;
modifiedInfo = true ;
i = - 1 ; // rescan
continue ;
}
}
}
}
if ( entities [ clientNum ] & & entities [ clientNum ] - > IsType ( idPlayer : : Type ) ) {
modifiedInfo | = static_cast < idPlayer * > ( entities [ clientNum ] ) - > UserInfoChanged ( canModify ) ;
}
if ( ! isClient ) {
// now mark this client in game
mpGame . EnterGame ( clientNum ) ;
}
}
if ( modifiedInfo ) {
assert ( canModify ) ;
newInfo = idGameLocal : : userInfo [ clientNum ] ;
return & newInfo ;
}
return NULL ;
}
/*
= = = = = = = = = = =
idGameLocal : : GetUserInfo
= = = = = = = = = = = =
*/
const idDict * idGameLocal : : GetUserInfo ( int clientNum ) {
if ( entities [ clientNum ] & & entities [ clientNum ] - > IsType ( idPlayer : : Type ) ) {
return & userInfo [ clientNum ] ;
}
return NULL ;
}
/*
= = = = = = = = = = =
idGameLocal : : SetServerInfo
= = = = = = = = = = = =
*/
void idGameLocal : : SetServerInfo ( const idDict & _serverInfo ) {
idBitMsg outMsg ;
byte msgBuf [ MAX_GAME_MESSAGE_SIZE ] ;
serverInfo = _serverInfo ;
UpdateServerInfoFlags ( ) ;
if ( ! isClient ) {
// Let our clients know the server info changed
outMsg . Init ( msgBuf , sizeof ( msgBuf ) ) ;
outMsg . WriteByte ( GAME_RELIABLE_MESSAGE_SERVERINFO ) ;
outMsg . WriteDeltaDict ( gameLocal . serverInfo , NULL ) ;
networkSystem - > ServerSendReliableMessage ( - 1 , outMsg ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = =
idGameLocal : : LoadMap
Initializes all map variables common to both save games and spawned games .
= = = = = = = = = = = = = = = = = = =
*/
void idGameLocal : : LoadMap ( const char * mapName , int randseed ) {
int i ;
bool sameMap = ( mapFile & & idStr : : Icmp ( mapFileName , mapName ) = = 0 ) ;
// clear the sound system
gameSoundWorld - > ClearAllSoundEmitters ( ) ;
# ifdef _D3XP
// clear envirosuit sound fx
gameSoundWorld - > SetEnviroSuit ( false ) ;
gameSoundWorld - > SetSlowmo ( false ) ;
# endif
InitAsyncNetwork ( ) ;
if ( ! sameMap | | ( mapFile & & mapFile - > NeedsReload ( ) ) ) {
// load the .map file
if ( mapFile ) {
delete mapFile ;
}
mapFile = new idMapFile ;
if ( ! mapFile - > Parse ( idStr ( mapName ) + " .map " ) ) {
delete mapFile ;
mapFile = NULL ;
Error ( " Couldn't load %s " , mapName ) ;
}
}
mapFileName = mapFile - > GetName ( ) ;
// load the collision map
collisionModelManager - > LoadMap ( mapFile ) ;
numClients = 0 ;
// initialize all entities for this game
memset ( entities , 0 , sizeof ( entities ) ) ;
memset ( usercmds , 0 , sizeof ( usercmds ) ) ;
memset ( spawnIds , - 1 , sizeof ( spawnIds ) ) ;
spawnCount = INITIAL_SPAWN_COUNT ;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
spawnedEntities . Clear ( ) ;
activeEntities . Clear ( ) ;
numEntitiesToDeactivate = 0 ;
sortTeamMasters = false ;
sortPushers = false ;
lastGUIEnt = NULL ;
lastGUI = 0 ;
globalMaterial = NULL ;
memset ( globalShaderParms , 0 , sizeof ( globalShaderParms ) ) ;
// always leave room for the max number of clients,
// even if they aren't all used, so numbers inside that
// range are NEVER anything but clients
num_entities = MAX_CLIENTS ;
firstFreeIndex = MAX_CLIENTS ;
// reset the random number generator.
random . SetSeed ( isMultiplayer ? randseed : 0 ) ;
camera = NULL ;
world = NULL ;
testmodel = NULL ;
testFx = NULL ;
lastAIAlertEntity = NULL ;
lastAIAlertTime = 0 ;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
previousTime = 0 ;
time = 0 ;
framenum = 0 ;
sessionCommand = " " ;
nextGibTime = 0 ;
# ifdef _D3XP
portalSkyEnt = NULL ;
portalSkyActive = false ;
ResetSlowTimeVars ( ) ;
# endif
vacuumAreaNum = - 1 ; // if an info_vacuum is spawned, it will set this
if ( ! editEntities ) {
editEntities = new idEditEntities ;
}
gravity . Set ( 0 , 0 , - g_gravity . GetFloat ( ) ) ;
spawnArgs . Clear ( ) ;
skipCinematic = false ;
inCinematic = false ;
cinematicSkipTime = 0 ;
cinematicStopTime = 0 ;
cinematicMaxSkipTime = 0 ;
clip . Init ( ) ;
pvs . Init ( ) ;
playerPVS . i = - 1 ;
playerConnectedAreas . i = - 1 ;
// load navigation system for all the different monster sizes
for ( i = 0 ; i < aasNames . Num ( ) ; i + + ) {
aasList [ i ] - > Init ( idStr ( mapFileName ) . SetFileExtension ( aasNames [ i ] ) . c_str ( ) , mapFile - > GetGeometryCRC ( ) ) ;
}
// clear the smoke particle free list
smokeParticles - > Init ( ) ;
// cache miscellanious media references
FindEntityDef ( " preCacheExtras " , false ) ;
if ( ! sameMap ) {
mapFile - > RemovePrimitiveData ( ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = =
idGameLocal : : LocalMapRestart
= = = = = = = = = = = = = = = = = = =
*/
void idGameLocal : : LocalMapRestart ( ) {
int i , latchSpawnCount ;
2012-07-19 16:37:19 +00:00
Printf ( " ----- Game Map Restart ----- \n " ) ;
2011-11-22 21:28:15 +00:00
gamestate = GAMESTATE_SHUTDOWN ;
for ( i = 0 ; i < MAX_CLIENTS ; i + + ) {
if ( entities [ i ] & & entities [ i ] - > IsType ( idPlayer : : Type ) ) {
static_cast < idPlayer * > ( entities [ i ] ) - > PrepareForRestart ( ) ;
}
}
eventQueue . Shutdown ( ) ;
savedEventQueue . Shutdown ( ) ;
MapClear ( false ) ;
// clear the smoke particle free list
smokeParticles - > Init ( ) ;
// clear the sound system
if ( gameSoundWorld ) {
gameSoundWorld - > ClearAllSoundEmitters ( ) ;
# ifdef _D3XP
// clear envirosuit sound fx
gameSoundWorld - > SetEnviroSuit ( false ) ;
gameSoundWorld - > SetSlowmo ( false ) ;
# endif
}
// the spawnCount is reset to zero temporarily to spawn the map entities with the same spawnId
// if we don't do that, network clients are confused and don't show any map entities
latchSpawnCount = spawnCount ;
spawnCount = INITIAL_SPAWN_COUNT ;
gamestate = GAMESTATE_STARTUP ;
program . Restart ( ) ;
InitScriptForMap ( ) ;
MapPopulate ( ) ;
// once the map is populated, set the spawnCount back to where it was so we don't risk any collision
// (note that if there are no players in the game, we could just leave it at it's current value)
spawnCount = latchSpawnCount ;
// setup the client entities again
for ( i = 0 ; i < MAX_CLIENTS ; i + + ) {
if ( entities [ i ] & & entities [ i ] - > IsType ( idPlayer : : Type ) ) {
static_cast < idPlayer * > ( entities [ i ] ) - > Restart ( ) ;
}
}
gamestate = GAMESTATE_ACTIVE ;
}
/*
= = = = = = = = = = = = = = = = = = =
idGameLocal : : MapRestart
= = = = = = = = = = = = = = = = = = =
*/
void idGameLocal : : MapRestart ( ) {
idBitMsg outMsg ;
byte msgBuf [ MAX_GAME_MESSAGE_SIZE ] ;
idDict newInfo ;
int i ;
const idKeyValue * keyval , * keyval2 ;
# ifdef _D3XP
if ( isMultiplayer & & isServer ) {
char buf [ MAX_STRING_CHARS ] ;
idStr gametype ;
GetBestGameType ( si_map . GetString ( ) , si_gameType . GetString ( ) , buf ) ;
gametype = buf ;
if ( gametype ! = si_gameType . GetString ( ) ) {
cvarSystem - > SetCVarString ( " si_gameType " , gametype ) ;
}
}
# endif
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
if ( isClient ) {
LocalMapRestart ( ) ;
} else {
newInfo = * cvarSystem - > MoveCVarsToDict ( CVAR_SERVERINFO ) ;
for ( i = 0 ; i < newInfo . GetNumKeyVals ( ) ; i + + ) {
keyval = newInfo . GetKeyVal ( i ) ;
keyval2 = serverInfo . FindKey ( keyval - > GetKey ( ) ) ;
if ( ! keyval2 ) {
break ;
}
// a select set of si_ changes will cause a full restart of the server
if ( keyval - > GetValue ( ) . Cmp ( keyval2 - > GetValue ( ) ) & &
( ! keyval - > GetKey ( ) . Cmp ( " si_pure " ) | | ! keyval - > GetKey ( ) . Cmp ( " si_map " ) ) ) {
break ;
}
}
cmdSystem - > BufferCommandText ( CMD_EXEC_NOW , " rescanSI " ) ;
if ( i ! = newInfo . GetNumKeyVals ( ) ) {
cmdSystem - > BufferCommandText ( CMD_EXEC_APPEND , " nextMap " ) ;
} else {
outMsg . Init ( msgBuf , sizeof ( msgBuf ) ) ;
outMsg . WriteByte ( GAME_RELIABLE_MESSAGE_RESTART ) ;
outMsg . WriteBits ( 1 , 1 ) ;
outMsg . WriteDeltaDict ( serverInfo , NULL ) ;
networkSystem - > ServerSendReliableMessage ( - 1 , outMsg ) ;
LocalMapRestart ( ) ;
mpGame . MapRestart ( ) ;
}
}
# ifdef CTF
if ( isMultiplayer ) {
gameLocal . mpGame . ReloadScoreboard ( ) ;
// gameLocal.mpGame.Reset(); // force reconstruct the GUIs when reloading maps, different gametypes have different GUIs
// gameLocal.mpGame.UpdateMainGui();
// gameLocal.mpGame.StartMenu();
// gameLocal.mpGame.DisableMenu();
// gameLocal.mpGame.Precache();
}
# endif
}
/*
= = = = = = = = = = = = = = = = = = =
idGameLocal : : MapRestart_f
= = = = = = = = = = = = = = = = = = =
*/
void idGameLocal : : MapRestart_f ( const idCmdArgs & args ) {
if ( ! gameLocal . isMultiplayer | | gameLocal . isClient ) {
common - > Printf ( " server is not running - use spawnServer \n " ) ;
cmdSystem - > BufferCommandText ( CMD_EXEC_APPEND , " spawnServer \n " ) ;
return ;
}
gameLocal . MapRestart ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = =
idGameLocal : : NextMap
= = = = = = = = = = = = = = = = = = =
*/
bool idGameLocal : : NextMap ( void ) {
const function_t * func ;
idThread * thread ;
idDict newInfo ;
const idKeyValue * keyval , * keyval2 ;
int i ;
if ( ! g_mapCycle . GetString ( ) [ 0 ] ) {
2022-12-29 04:38:13 +00:00
Printf ( " %s " , common - > GetLanguageDict ( ) - > GetString ( " #str_04294 " ) ) ;
2011-11-22 21:28:15 +00:00
return false ;
}
if ( fileSystem - > ReadFile ( g_mapCycle . GetString ( ) , NULL , NULL ) < 0 ) {
if ( fileSystem - > ReadFile ( va ( " %s.scriptcfg " , g_mapCycle . GetString ( ) ) , NULL , NULL ) < 0 ) {
Printf ( " map cycle script '%s': not found \n " , g_mapCycle . GetString ( ) ) ;
return false ;
} else {
g_mapCycle . SetString ( va ( " %s.scriptcfg " , g_mapCycle . GetString ( ) ) ) ;
}
}
Printf ( " map cycle script: '%s' \n " , g_mapCycle . GetString ( ) ) ;
func = program . FindFunction ( " mapcycle::cycle " ) ;
if ( ! func ) {
program . CompileFile ( g_mapCycle . GetString ( ) ) ;
func = program . FindFunction ( " mapcycle::cycle " ) ;
}
if ( ! func ) {
Printf ( " Couldn't find mapcycle::cycle \n " ) ;
return false ;
}
thread = new idThread ( func ) ;
thread - > Start ( ) ;
delete thread ;
newInfo = * cvarSystem - > MoveCVarsToDict ( CVAR_SERVERINFO ) ;
for ( i = 0 ; i < newInfo . GetNumKeyVals ( ) ; i + + ) {
keyval = newInfo . GetKeyVal ( i ) ;
keyval2 = serverInfo . FindKey ( keyval - > GetKey ( ) ) ;
if ( ! keyval2 | | keyval - > GetValue ( ) . Cmp ( keyval2 - > GetValue ( ) ) ) {
break ;
}
}
return ( i ! = newInfo . GetNumKeyVals ( ) ) ;
}
/*
= = = = = = = = = = = = = = = = = = =
idGameLocal : : NextMap_f
= = = = = = = = = = = = = = = = = = =
*/
void idGameLocal : : NextMap_f ( const idCmdArgs & args ) {
if ( ! gameLocal . isMultiplayer | | gameLocal . isClient ) {
common - > Printf ( " server is not running \n " ) ;
return ;
}
gameLocal . NextMap ( ) ;
// next map was either voted for or triggered by a server command - always restart
gameLocal . MapRestart ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = =
idGameLocal : : MapPopulate
= = = = = = = = = = = = = = = = = = =
*/
void idGameLocal : : MapPopulate ( void ) {
if ( isMultiplayer ) {
cvarSystem - > SetCVarBool ( " r_skipSpecular " , false ) ;
}
// parse the key/value pairs and spawn entities
SpawnMapEntities ( ) ;
// mark location entities in all connected areas
SpreadLocations ( ) ;
// prepare the list of randomized initial spawn spots
RandomizeInitialSpawns ( ) ;
// spawnCount - 1 is the number of entities spawned into the map, their indexes started at MAX_CLIENTS (included)
// mapSpawnCount is used as the max index of map entities, it's the first index of non-map entities
mapSpawnCount = MAX_CLIENTS + spawnCount - 1 ;
// execute pending events before the very first game frame
// this makes sure the map script main() function is called
// before the physics are run so entities can bind correctly
Printf ( " ==== Processing events ==== \n " ) ;
idEvent : : ServiceEvents ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = =
idGameLocal : : InitFromNewMap
= = = = = = = = = = = = = = = = = = =
*/
void idGameLocal : : InitFromNewMap ( const char * mapName , idRenderWorld * renderWorld , idSoundWorld * soundWorld , bool isServer , bool isClient , int randseed ) {
this - > isServer = isServer ;
this - > isClient = isClient ;
this - > isMultiplayer = isServer | | isClient ;
if ( mapFileName . Length ( ) ) {
MapShutdown ( ) ;
}
2012-07-19 16:37:19 +00:00
Printf ( " ----- Game Map Init ----- \n " ) ;
2011-11-22 21:28:15 +00:00
gamestate = GAMESTATE_STARTUP ;
gameRenderWorld = renderWorld ;
gameSoundWorld = soundWorld ;
LoadMap ( mapName , randseed ) ;
InitScriptForMap ( ) ;
MapPopulate ( ) ;
mpGame . Reset ( ) ;
mpGame . Precache ( ) ;
// free up any unused animations
animationLib . FlushUnusedAnims ( ) ;
gamestate = GAMESTATE_ACTIVE ;
}
/*
= = = = = = = = = = = = = = = = =
idGameLocal : : InitFromSaveGame
= = = = = = = = = = = = = = = = =
*/
bool idGameLocal : : InitFromSaveGame ( const char * mapName , idRenderWorld * renderWorld , idSoundWorld * soundWorld , idFile * saveGameFile ) {
int i ;
int num ;
idEntity * ent ;
idDict si ;
if ( mapFileName . Length ( ) ) {
MapShutdown ( ) ;
}
2012-07-19 16:37:19 +00:00
Printf ( " ----- Game Map Init SaveGame ----- \n " ) ;
2011-11-22 21:28:15 +00:00
gamestate = GAMESTATE_STARTUP ;
gameRenderWorld = renderWorld ;
gameSoundWorld = soundWorld ;
idRestoreGame savegame ( saveGameFile ) ;
savegame . ReadBuildNumber ( ) ;
2021-02-07 05:10:19 +00:00
// DG: I enhanced the information in savegames a bit for dhewm3 1.5.1
// for which I bumped th BUILD_NUMBER to 1305
if ( savegame . GetBuildNumber ( ) > = 1305 )
{
savegame . ReadInternalSavegameVersion ( ) ;
if ( savegame . GetInternalSavegameVersion ( ) > INTERNAL_SAVEGAME_VERSION ) {
Warning ( " Savegame from newer dhewm3 version, don't know how to load! (its version is %d, only up to %d supported) " ,
savegame . GetInternalSavegameVersion ( ) , INTERNAL_SAVEGAME_VERSION ) ;
return false ;
}
idStr osType ;
idStr cpuArch ;
idStr engineVersion ;
short ptrSize = 0 ;
short byteorder = 0 ;
savegame . ReadString ( osType ) ; // operating system the savegame was crated on (written from D3_OSTYPE)
savegame . ReadString ( cpuArch ) ; // written from D3_ARCH (which is set in CMake), like "x86" or "x86_64"
savegame . ReadString ( engineVersion ) ; // written from ENGINE_VERSION
savegame . ReadShort ( ptrSize ) ; // sizeof(void*) of system that created the savegame, 4 on 32bit systems, 8 on 64bit systems
savegame . ReadShort ( byteorder ) ; // SDL_LIL_ENDIAN or SDL_BIG_ENDIAN
Printf ( " Savegame was created by %s on %s %s. BuildNumber was %d, savegameversion %d \n " ,
engineVersion . c_str ( ) , osType . c_str ( ) , cpuArch . c_str ( ) , savegame . GetBuildNumber ( ) ,
savegame . GetInternalSavegameVersion ( ) ) ;
// right now I have no further use for this information, but in the future
// it can be used for quirks for (then-) old savegames
}
// DG end
2011-11-22 21:28:15 +00:00
// Create the list of all objects in the game
savegame . CreateObjects ( ) ;
// Load the idProgram, also checking to make sure scripting hasn't changed since the savegame
if ( program . Restore ( & savegame ) = = false ) {
// Abort the load process, and let the session know so that it can restart the level
// with the player persistent data.
savegame . DeleteObjects ( ) ;
program . Restart ( ) ;
return false ;
}
// load the map needed for this savegame
LoadMap ( mapName , 0 ) ;
savegame . ReadInt ( i ) ;
g_skill . SetInteger ( i ) ;
// precache the player
FindEntityDef ( " player_doommarine " , false ) ;
// precache any media specified in the map
for ( i = 0 ; i < mapFile - > GetNumEntities ( ) ; i + + ) {
idMapEntity * mapEnt = mapFile - > GetEntity ( i ) ;
if ( ! InhibitEntitySpawn ( mapEnt - > epairs ) ) {
CacheDictionaryMedia ( & mapEnt - > epairs ) ;
2012-05-13 12:40:11 +00:00
const char * classname ;
if ( mapEnt - > epairs . GetString ( " classname " , " " , & classname ) ) {
2011-11-22 21:28:15 +00:00
FindEntityDef ( classname , false ) ;
}
}
}
savegame . ReadDict ( & si ) ;
SetServerInfo ( si ) ;
savegame . ReadInt ( numClients ) ;
for ( i = 0 ; i < numClients ; i + + ) {
savegame . ReadDict ( & userInfo [ i ] ) ;
savegame . ReadUsercmd ( usercmds [ i ] ) ;
savegame . ReadDict ( & persistentPlayerInfo [ i ] ) ;
}
for ( i = 0 ; i < MAX_GENTITIES ; i + + ) {
savegame . ReadObject ( reinterpret_cast < idClass * & > ( entities [ i ] ) ) ;
savegame . ReadInt ( spawnIds [ i ] ) ;
// restore the entityNumber
if ( entities [ i ] ! = NULL ) {
entities [ i ] - > entityNumber = i ;
}
}
savegame . ReadInt ( firstFreeIndex ) ;
savegame . ReadInt ( num_entities ) ;
// enityHash is restored by idEntity::Restore setting the entity name.
savegame . ReadObject ( reinterpret_cast < idClass * & > ( world ) ) ;
savegame . ReadInt ( num ) ;
for ( i = 0 ; i < num ; i + + ) {
savegame . ReadObject ( reinterpret_cast < idClass * & > ( ent ) ) ;
assert ( ent ) ;
if ( ent ) {
ent - > spawnNode . AddToEnd ( spawnedEntities ) ;
}
}
savegame . ReadInt ( num ) ;
for ( i = 0 ; i < num ; i + + ) {
savegame . ReadObject ( reinterpret_cast < idClass * & > ( ent ) ) ;
assert ( ent ) ;
if ( ent ) {
ent - > activeNode . AddToEnd ( activeEntities ) ;
}
}
savegame . ReadInt ( numEntitiesToDeactivate ) ;
savegame . ReadBool ( sortPushers ) ;
savegame . ReadBool ( sortTeamMasters ) ;
savegame . ReadDict ( & persistentLevelInfo ) ;
for ( i = 0 ; i < MAX_GLOBAL_SHADER_PARMS ; i + + ) {
savegame . ReadFloat ( globalShaderParms [ i ] ) ;
}
savegame . ReadInt ( i ) ;
random . SetSeed ( i ) ;
savegame . ReadObject ( reinterpret_cast < idClass * & > ( frameCommandThread ) ) ;
// clip
// push
// pvs
// testmodel = "<NULL>"
// testFx = "<NULL>"
savegame . ReadString ( sessionCommand ) ;
// FIXME: save smoke particles
savegame . ReadInt ( cinematicSkipTime ) ;
savegame . ReadInt ( cinematicStopTime ) ;
savegame . ReadInt ( cinematicMaxSkipTime ) ;
savegame . ReadBool ( inCinematic ) ;
savegame . ReadBool ( skipCinematic ) ;
savegame . ReadBool ( isMultiplayer ) ;
savegame . ReadInt ( ( int & ) gameType ) ;
savegame . ReadInt ( framenum ) ;
savegame . ReadInt ( previousTime ) ;
savegame . ReadInt ( time ) ;
# ifdef _D3XP
savegame . ReadInt ( msec ) ;
# endif
savegame . ReadInt ( vacuumAreaNum ) ;
savegame . ReadInt ( entityDefBits ) ;
savegame . ReadBool ( isServer ) ;
savegame . ReadBool ( isClient ) ;
savegame . ReadInt ( localClientNum ) ;
// snapshotEntities is used for multiplayer only
savegame . ReadInt ( realClientTime ) ;
savegame . ReadBool ( isNewFrame ) ;
savegame . ReadFloat ( clientSmoothing ) ;
# ifdef _D3XP
portalSkyEnt . Restore ( & savegame ) ;
savegame . ReadBool ( portalSkyActive ) ;
fast . Restore ( & savegame ) ;
slow . Restore ( & savegame ) ;
int blah ;
savegame . ReadInt ( blah ) ;
slowmoState = ( slowmoState_t ) blah ;
savegame . ReadFloat ( slowmoMsec ) ;
savegame . ReadBool ( quickSlowmoReset ) ;
if ( slowmoState = = SLOWMO_STATE_OFF ) {
if ( gameSoundWorld ) {
gameSoundWorld - > SetSlowmo ( false ) ;
}
}
else {
if ( gameSoundWorld ) {
gameSoundWorld - > SetSlowmo ( true ) ;
}
}
if ( gameSoundWorld ) {
gameSoundWorld - > SetSlowmoSpeed ( slowmoMsec / ( float ) USERCMD_MSEC ) ;
}
# endif
savegame . ReadBool ( mapCycleLoaded ) ;
savegame . ReadInt ( spawnCount ) ;
savegame . ReadInt ( num ) ;
if ( num ) {
if ( num ! = gameRenderWorld - > NumAreas ( ) ) {
savegame . Error ( " idGameLocal::InitFromSaveGame: number of areas in map differs from save game. " ) ;
}
locationEntities = new idLocationEntity * [ num ] ;
for ( i = 0 ; i < num ; i + + ) {
savegame . ReadObject ( reinterpret_cast < idClass * & > ( locationEntities [ i ] ) ) ;
}
}
savegame . ReadObject ( reinterpret_cast < idClass * & > ( camera ) ) ;
savegame . ReadMaterial ( globalMaterial ) ;
lastAIAlertEntity . Restore ( & savegame ) ;
savegame . ReadInt ( lastAIAlertTime ) ;
savegame . ReadDict ( & spawnArgs ) ;
savegame . ReadInt ( playerPVS . i ) ;
savegame . ReadInt ( ( int & ) playerPVS . h ) ;
savegame . ReadInt ( playerConnectedAreas . i ) ;
savegame . ReadInt ( ( int & ) playerConnectedAreas . h ) ;
savegame . ReadVec3 ( gravity ) ;
// gamestate is restored after restoring everything else
savegame . ReadBool ( influenceActive ) ;
savegame . ReadInt ( nextGibTime ) ;
// spawnSpots
// initialSpots
// currentInitialSpot
// newInfo
// makingBuild
// shakeSounds
// Read out pending events
idEvent : : Restore ( & savegame ) ;
savegame . RestoreObjects ( ) ;
mpGame . Reset ( ) ;
mpGame . Precache ( ) ;
// free up any unused animations
animationLib . FlushUnusedAnims ( ) ;
gamestate = GAMESTATE_ACTIVE ;
return true ;
}
/*
= = = = = = = = = = =
idGameLocal : : MapClear
= = = = = = = = = = =
*/
void idGameLocal : : MapClear ( bool clearClients ) {
int i ;
for ( i = ( clearClients ? 0 : MAX_CLIENTS ) ; i < MAX_GENTITIES ; i + + ) {
delete entities [ i ] ;
// ~idEntity is in charge of setting the pointer to NULL
// it will also clear pending events for this entity
assert ( ! entities [ i ] ) ;
spawnIds [ i ] = - 1 ;
}
entityHash . Clear ( 1024 , MAX_GENTITIES ) ;
if ( ! clearClients ) {
// add back the hashes of the clients
for ( i = 0 ; i < MAX_CLIENTS ; i + + ) {
if ( ! entities [ i ] ) {
continue ;
}
entityHash . Add ( entityHash . GenerateKey ( entities [ i ] - > name . c_str ( ) , true ) , i ) ;
}
}
delete frameCommandThread ;
frameCommandThread = NULL ;
if ( editEntities ) {
delete editEntities ;
editEntities = NULL ;
}
delete [ ] locationEntities ;
locationEntities = NULL ;
}
/*
= = = = = = = = = = =
idGameLocal : : MapShutdown
= = = = = = = = = = = =
*/
void idGameLocal : : MapShutdown ( void ) {
2012-07-19 16:37:19 +00:00
Printf ( " ----- Game Map Shutdown ----- \n " ) ;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
gamestate = GAMESTATE_SHUTDOWN ;
if ( gameRenderWorld ) {
// clear any debug lines, text, and polygons
gameRenderWorld - > DebugClearLines ( 0 ) ;
gameRenderWorld - > DebugClearPolygons ( 0 ) ;
}
// clear out camera if we're in a cinematic
if ( inCinematic ) {
camera = NULL ;
inCinematic = false ;
}
MapClear ( true ) ;
// reset the script to the state it was before the map was started
program . Restart ( ) ;
if ( smokeParticles ) {
smokeParticles - > Shutdown ( ) ;
}
pvs . Shutdown ( ) ;
clip . Shutdown ( ) ;
idClipModel : : ClearTraceModelCache ( ) ;
ShutdownAsyncNetwork ( ) ;
mapFileName . Clear ( ) ;
gameRenderWorld = NULL ;
gameSoundWorld = NULL ;
gamestate = GAMESTATE_NOMAP ;
}
/*
= = = = = = = = = = = = = = = = = = =
idGameLocal : : DumpOggSounds
= = = = = = = = = = = = = = = = = = =
*/
void idGameLocal : : DumpOggSounds ( void ) {
int i , j , k , size , totalSize ;
idFile * file ;
idStrList oggSounds , weaponSounds ;
const idSoundShader * soundShader ;
const soundShaderParms_t * parms ;
idStr soundName ;
for ( i = 0 ; i < declManager - > GetNumDecls ( DECL_SOUND ) ; i + + ) {
soundShader = static_cast < const idSoundShader * > ( declManager - > DeclByIndex ( DECL_SOUND , i , false ) ) ;
parms = soundShader - > GetParms ( ) ;
if ( soundShader - > EverReferenced ( ) & & soundShader - > GetState ( ) ! = DS_DEFAULTED ) {
const_cast < idSoundShader * > ( soundShader ) - > EnsureNotPurged ( ) ;
for ( j = 0 ; j < soundShader - > GetNumSounds ( ) ; j + + ) {
soundName = soundShader - > GetSound ( j ) ;
soundName . BackSlashesToSlashes ( ) ;
# ifdef _D3XP
// D3XP :: don't add sounds that are in Doom 3's pak files
if ( fileSystem - > FileIsInPAK ( soundName ) ) {
continue ;
} else {
// Also check for a pre-ogg'd version in the pak file
idStr testName = soundName ;
testName . SetFileExtension ( " .ogg " ) ;
if ( fileSystem - > FileIsInPAK ( testName ) ) {
continue ;
}
}
# endif
// don't OGG sounds that cause a shake because that would
// cause continuous seeking on the OGG file which is expensive
if ( parms - > shakes ! = 0.0f ) {
shakeSounds . AddUnique ( soundName ) ;
continue ;
}
// if not voice over or combat chatter
if ( soundName . Find ( " /vo/ " , false ) = = - 1 & &
soundName . Find ( " /combat_chatter/ " , false ) = = - 1 & &
soundName . Find ( " /bfgcarnage/ " , false ) = = - 1 & &
soundName . Find ( " /enpro/ " , false ) = = - 1 & &
soundName . Find ( " /soulcube/energize_01.wav " , false ) = = - 1 ) {
// don't OGG weapon sounds
if ( soundName . Find ( " weapon " , false ) ! = - 1 | |
soundName . Find ( " gun " , false ) ! = - 1 | |
soundName . Find ( " bullet " , false ) ! = - 1 | |
soundName . Find ( " bfg " , false ) ! = - 1 | |
soundName . Find ( " plasma " , false ) ! = - 1 ) {
weaponSounds . AddUnique ( soundName ) ;
continue ;
}
}
for ( k = 0 ; k < shakeSounds . Num ( ) ; k + + ) {
if ( shakeSounds [ k ] . IcmpPath ( soundName ) = = 0 ) {
break ;
}
}
if ( k < shakeSounds . Num ( ) ) {
continue ;
}
oggSounds . AddUnique ( soundName ) ;
}
}
}
file = fileSystem - > OpenFileWrite ( " makeogg.bat " , " fs_savepath " ) ;
if ( file = = NULL ) {
common - > Warning ( " Couldn't open makeogg.bat " ) ;
return ;
}
// list all the shake sounds
totalSize = 0 ;
for ( i = 0 ; i < shakeSounds . Num ( ) ; i + + ) {
size = fileSystem - > ReadFile ( shakeSounds [ i ] , NULL , NULL ) ;
totalSize + = size ;
shakeSounds [ i ] . Replace ( " / " , " \\ " ) ;
file - > Printf ( " echo \" %s \" (%d kB) \n " , shakeSounds [ i ] . c_str ( ) , size > > 10 ) ;
}
file - > Printf ( " echo %d kB in shake sounds \n \n \n " , totalSize > > 10 ) ;
// list all the weapon sounds
totalSize = 0 ;
for ( i = 0 ; i < weaponSounds . Num ( ) ; i + + ) {
size = fileSystem - > ReadFile ( weaponSounds [ i ] , NULL , NULL ) ;
totalSize + = size ;
weaponSounds [ i ] . Replace ( " / " , " \\ " ) ;
file - > Printf ( " echo \" %s \" (%d kB) \n " , weaponSounds [ i ] . c_str ( ) , size > > 10 ) ;
}
file - > Printf ( " echo %d kB in weapon sounds \n \n \n " , totalSize > > 10 ) ;
// list commands to convert all other sounds to ogg
totalSize = 0 ;
for ( i = 0 ; i < oggSounds . Num ( ) ; i + + ) {
size = fileSystem - > ReadFile ( oggSounds [ i ] , NULL , NULL ) ;
totalSize + = size ;
oggSounds [ i ] . Replace ( " / " , " \\ " ) ;
file - > Printf ( " z: \\ d3xp \\ ogg \\ oggenc -q 0 \" %s \\ d3xp \\ %s \" \n " , cvarSystem - > GetCVarString ( " fs_basepath " ) , oggSounds [ i ] . c_str ( ) ) ;
file - > Printf ( " del \" %s \\ d3xp \\ %s \" \n " , cvarSystem - > GetCVarString ( " fs_basepath " ) , oggSounds [ i ] . c_str ( ) ) ;
}
file - > Printf ( " \n \n echo %d kB in OGG sounds \n \n \n " , totalSize > > 10 ) ;
fileSystem - > CloseFile ( file ) ;
shakeSounds . Clear ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = =
idGameLocal : : GetShakeSounds
= = = = = = = = = = = = = = = = = = =
*/
void idGameLocal : : GetShakeSounds ( const idDict * dict ) {
const idSoundShader * soundShader ;
const char * soundShaderName ;
idStr soundName ;
2012-05-13 12:40:11 +00:00
if ( dict - > GetString ( " s_shader " , " " , & soundShaderName )
& & dict - > GetFloat ( " s_shakes " ) ! = 0.0f )
{
2011-11-22 21:28:15 +00:00
soundShader = declManager - > FindSound ( soundShaderName ) ;
for ( int i = 0 ; i < soundShader - > GetNumSounds ( ) ; i + + ) {
soundName = soundShader - > GetSound ( i ) ;
soundName . BackSlashesToSlashes ( ) ;
shakeSounds . AddUnique ( soundName ) ;
}
}
}
/*
= = = = = = = = = = = = = = = = = = =
idGameLocal : : CacheDictionaryMedia
This is called after parsing an EntityDef and for each entity spawnArgs before
merging the entitydef . It could be done post - merge , but that would
avoid the fast pre - cache check associated with each entityDef
= = = = = = = = = = = = = = = = = = =
*/
void idGameLocal : : CacheDictionaryMedia ( const idDict * dict ) {
const idKeyValue * kv ;
if ( dict = = NULL ) {
if ( cvarSystem - > GetCVarBool ( " com_makingBuild " ) ) {
DumpOggSounds ( ) ;
}
return ;
}
if ( cvarSystem - > GetCVarBool ( " com_makingBuild " ) ) {
GetShakeSounds ( dict ) ;
}
kv = dict - > MatchPrefix ( " model " ) ;
while ( kv ) {
if ( kv - > GetValue ( ) . Length ( ) ) {
declManager - > MediaPrint ( " Precaching model %s \n " , kv - > GetValue ( ) . c_str ( ) ) ;
// precache model/animations
if ( declManager - > FindType ( DECL_MODELDEF , kv - > GetValue ( ) , false ) = = NULL ) {
// precache the render model
renderModelManager - > FindModel ( kv - > GetValue ( ) ) ;
// precache .cm files only
collisionModelManager - > LoadModel ( kv - > GetValue ( ) , true ) ;
}
}
kv = dict - > MatchPrefix ( " model " , kv ) ;
}
kv = dict - > FindKey ( " s_shader " ) ;
if ( kv & & kv - > GetValue ( ) . Length ( ) ) {
declManager - > FindType ( DECL_SOUND , kv - > GetValue ( ) ) ;
}
kv = dict - > MatchPrefix ( " snd " , NULL ) ;
while ( kv ) {
if ( kv - > GetValue ( ) . Length ( ) ) {
declManager - > FindType ( DECL_SOUND , kv - > GetValue ( ) ) ;
}
kv = dict - > MatchPrefix ( " snd " , kv ) ;
}
kv = dict - > MatchPrefix ( " gui " , NULL ) ;
while ( kv ) {
if ( kv - > GetValue ( ) . Length ( ) ) {
if ( ! idStr : : Icmp ( kv - > GetKey ( ) , " gui_noninteractive " )
2011-12-06 18:20:15 +00:00
| | ! idStr : : Icmpn ( kv - > GetKey ( ) , " gui_parm " , 8 )
2011-11-22 21:28:15 +00:00
| | ! idStr : : Icmp ( kv - > GetKey ( ) , " gui_inventory " ) ) {
// unfortunate flag names, they aren't actually a gui
} else {
declManager - > MediaPrint ( " Precaching gui %s \n " , kv - > GetValue ( ) . c_str ( ) ) ;
idUserInterface * gui = uiManager - > Alloc ( ) ;
if ( gui ) {
gui - > InitFromFile ( kv - > GetValue ( ) ) ;
uiManager - > DeAlloc ( gui ) ;
}
}
}
kv = dict - > MatchPrefix ( " gui " , kv ) ;
}
kv = dict - > FindKey ( " texture " ) ;
if ( kv & & kv - > GetValue ( ) . Length ( ) ) {
declManager - > FindType ( DECL_MATERIAL , kv - > GetValue ( ) ) ;
}
kv = dict - > MatchPrefix ( " mtr " , NULL ) ;
while ( kv ) {
if ( kv - > GetValue ( ) . Length ( ) ) {
declManager - > FindType ( DECL_MATERIAL , kv - > GetValue ( ) ) ;
}
kv = dict - > MatchPrefix ( " mtr " , kv ) ;
}
// handles hud icons
kv = dict - > MatchPrefix ( " inv_icon " , NULL ) ;
while ( kv ) {
if ( kv - > GetValue ( ) . Length ( ) ) {
declManager - > FindType ( DECL_MATERIAL , kv - > GetValue ( ) ) ;
}
kv = dict - > MatchPrefix ( " inv_icon " , kv ) ;
}
// handles teleport fx.. this is not ideal but the actual decision on which fx to use
// is handled by script code based on the teleport number
kv = dict - > MatchPrefix ( " teleport " , NULL ) ;
if ( kv & & kv - > GetValue ( ) . Length ( ) ) {
int teleportType = atoi ( kv - > GetValue ( ) ) ;
const char * p = ( teleportType ) ? va ( " fx/teleporter%i.fx " , teleportType ) : " fx/teleporter.fx " ;
declManager - > FindType ( DECL_FX , p ) ;
}
kv = dict - > MatchPrefix ( " fx " , NULL ) ;
while ( kv ) {
if ( kv - > GetValue ( ) . Length ( ) ) {
declManager - > MediaPrint ( " Precaching fx %s \n " , kv - > GetValue ( ) . c_str ( ) ) ;
declManager - > FindType ( DECL_FX , kv - > GetValue ( ) ) ;
}
kv = dict - > MatchPrefix ( " fx " , kv ) ;
}
kv = dict - > MatchPrefix ( " smoke " , NULL ) ;
while ( kv ) {
if ( kv - > GetValue ( ) . Length ( ) ) {
idStr prtName = kv - > GetValue ( ) ;
int dash = prtName . Find ( ' - ' ) ;
if ( dash > 0 ) {
prtName = prtName . Left ( dash ) ;
}
declManager - > FindType ( DECL_PARTICLE , prtName ) ;
}
kv = dict - > MatchPrefix ( " smoke " , kv ) ;
}
kv = dict - > MatchPrefix ( " skin " , NULL ) ;
while ( kv ) {
if ( kv - > GetValue ( ) . Length ( ) ) {
declManager - > MediaPrint ( " Precaching skin %s \n " , kv - > GetValue ( ) . c_str ( ) ) ;
declManager - > FindType ( DECL_SKIN , kv - > GetValue ( ) ) ;
}
kv = dict - > MatchPrefix ( " skin " , kv ) ;
}
kv = dict - > MatchPrefix ( " def " , NULL ) ;
while ( kv ) {
if ( kv - > GetValue ( ) . Length ( ) ) {
FindEntityDef ( kv - > GetValue ( ) . c_str ( ) , false ) ;
}
kv = dict - > MatchPrefix ( " def " , kv ) ;
}
kv = dict - > MatchPrefix ( " pda_name " , NULL ) ;
while ( kv ) {
if ( kv - > GetValue ( ) . Length ( ) ) {
declManager - > FindType ( DECL_PDA , kv - > GetValue ( ) . c_str ( ) , false ) ;
}
kv = dict - > MatchPrefix ( " pda_name " , kv ) ;
}
kv = dict - > MatchPrefix ( " video " , NULL ) ;
while ( kv ) {
if ( kv - > GetValue ( ) . Length ( ) ) {
declManager - > FindType ( DECL_VIDEO , kv - > GetValue ( ) . c_str ( ) , false ) ;
}
kv = dict - > MatchPrefix ( " video " , kv ) ;
}
kv = dict - > MatchPrefix ( " audio " , NULL ) ;
while ( kv ) {
if ( kv - > GetValue ( ) . Length ( ) ) {
declManager - > FindType ( DECL_AUDIO , kv - > GetValue ( ) . c_str ( ) , false ) ;
}
kv = dict - > MatchPrefix ( " audio " , kv ) ;
}
}
/*
= = = = = = = = = = =
idGameLocal : : InitScriptForMap
= = = = = = = = = = = =
*/
void idGameLocal : : InitScriptForMap ( void ) {
// create a thread to run frame commands on
frameCommandThread = new idThread ( ) ;
frameCommandThread - > ManualDelete ( ) ;
frameCommandThread - > SetThreadName ( " frameCommands " ) ;
// run the main game script function (not the level specific main)
const function_t * func = program . FindFunction ( SCRIPT_DEFAULTFUNC ) ;
if ( func ! = NULL ) {
idThread * thread = new idThread ( func ) ;
if ( thread - > Start ( ) ) {
// thread has finished executing, so delete it
delete thread ;
}
}
}
/*
= = = = = = = = = = =
idGameLocal : : SpawnPlayer
= = = = = = = = = = = =
*/
void idGameLocal : : SpawnPlayer ( int clientNum ) {
idEntity * ent ;
idDict args ;
// they can connect
Printf ( " SpawnPlayer: %i \n " , clientNum ) ;
args . SetInt ( " spawn_entnum " , clientNum ) ;
args . Set ( " name " , va ( " player%d " , clientNum + 1 ) ) ;
# ifdef CTF
if ( isMultiplayer & & gameType ! = GAME_CTF )
args . Set ( " classname " , " player_doommarine_mp " ) ;
else if ( isMultiplayer & & gameType = = GAME_CTF )
args . Set ( " classname " , " player_doommarine_ctf " ) ;
else
args . Set ( " classname " , " player_doommarine " ) ;
# else
args . Set ( " classname " , isMultiplayer ? " player_doommarine_mp " : " player_doommarine " ) ;
# endif
if ( ! SpawnEntityDef ( args , & ent ) | | ! entities [ clientNum ] ) {
Error ( " Failed to spawn player as '%s' " , args . GetString ( " classname " ) ) ;
}
// make sure it's a compatible class
if ( ! ent - > IsType ( idPlayer : : Type ) ) {
Error ( " '%s' spawned the player as a '%s'. Player spawnclass must be a subclass of idPlayer. " , args . GetString ( " classname " ) , ent - > GetClassname ( ) ) ;
}
if ( clientNum > = numClients ) {
numClients = clientNum + 1 ;
}
mpGame . SpawnPlayer ( clientNum ) ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : GetClientByNum
= = = = = = = = = = = = = = = =
*/
idPlayer * idGameLocal : : GetClientByNum ( int current ) const {
if ( current < 0 | | current > = numClients ) {
current = 0 ;
}
if ( entities [ current ] ) {
return static_cast < idPlayer * > ( entities [ current ] ) ;
}
return NULL ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : GetClientByName
= = = = = = = = = = = = = = = =
*/
idPlayer * idGameLocal : : GetClientByName ( const char * name ) const {
int i ;
idEntity * ent ;
for ( i = 0 ; i < numClients ; i + + ) {
ent = entities [ i ] ;
if ( ent & & ent - > IsType ( idPlayer : : Type ) ) {
if ( idStr : : IcmpNoColor ( name , userInfo [ i ] . GetString ( " ui_name " ) ) = = 0 ) {
return static_cast < idPlayer * > ( ent ) ;
}
}
}
return NULL ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : GetClientByCmdArgs
= = = = = = = = = = = = = = = =
*/
idPlayer * idGameLocal : : GetClientByCmdArgs ( const idCmdArgs & args ) const {
idPlayer * player ;
idStr client = args . Argv ( 1 ) ;
if ( ! client . Length ( ) ) {
return NULL ;
}
// we don't allow numeric ui_name so this can't go wrong
if ( client . IsNumeric ( ) ) {
player = GetClientByNum ( atoi ( client . c_str ( ) ) ) ;
} else {
player = GetClientByName ( client . c_str ( ) ) ;
}
if ( ! player ) {
common - > Printf ( " Player '%s' not found \n " , client . c_str ( ) ) ;
}
return player ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : GetNextClientNum
= = = = = = = = = = = = = = = =
*/
int idGameLocal : : GetNextClientNum ( int _current ) const {
int i , current ;
current = 0 ;
for ( i = 0 ; i < numClients ; i + + ) {
current = ( _current + i + 1 ) % numClients ;
if ( entities [ current ] & & entities [ current ] - > IsType ( idPlayer : : Type ) ) {
return current ;
}
}
return current ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : GetLocalPlayer
Nothing in the game tic should EVER make a decision based on what the
local client number is , it shouldn ' t even be aware that there is a
draw phase even happening . This just returns client 0 , which will
be correct for single player .
= = = = = = = = = = = = = = = =
*/
idPlayer * idGameLocal : : GetLocalPlayer ( ) const {
if ( localClientNum < 0 ) {
return NULL ;
}
if ( ! entities [ localClientNum ] | | ! entities [ localClientNum ] - > IsType ( idPlayer : : Type ) ) {
// not fully in game yet
return NULL ;
}
return static_cast < idPlayer * > ( entities [ localClientNum ] ) ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : SetupClientPVS
= = = = = = = = = = = = = = = =
*/
pvsHandle_t idGameLocal : : GetClientPVS ( idPlayer * player , pvsType_t type ) {
if ( player - > GetPrivateCameraView ( ) ) {
return pvs . SetupCurrentPVS ( player - > GetPrivateCameraView ( ) - > GetPVSAreas ( ) , player - > GetPrivateCameraView ( ) - > GetNumPVSAreas ( ) ) ;
} else if ( camera ) {
return pvs . SetupCurrentPVS ( camera - > GetPVSAreas ( ) , camera - > GetNumPVSAreas ( ) ) ;
} else {
return pvs . SetupCurrentPVS ( player - > GetPVSAreas ( ) , player - > GetNumPVSAreas ( ) ) ;
}
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : SetupPlayerPVS
= = = = = = = = = = = = = = = =
*/
void idGameLocal : : SetupPlayerPVS ( void ) {
int i ;
idEntity * ent ;
idPlayer * player ;
pvsHandle_t otherPVS , newPVS ;
playerPVS . i = - 1 ;
for ( i = 0 ; i < numClients ; i + + ) {
ent = entities [ i ] ;
if ( ! ent | | ! ent - > IsType ( idPlayer : : Type ) ) {
continue ;
}
player = static_cast < idPlayer * > ( ent ) ;
if ( playerPVS . i = = - 1 ) {
playerPVS = GetClientPVS ( player , PVS_NORMAL ) ;
} else {
otherPVS = GetClientPVS ( player , PVS_NORMAL ) ;
newPVS = pvs . MergeCurrentPVS ( playerPVS , otherPVS ) ;
pvs . FreeCurrentPVS ( playerPVS ) ;
pvs . FreeCurrentPVS ( otherPVS ) ;
playerPVS = newPVS ;
}
if ( playerConnectedAreas . i = = - 1 ) {
playerConnectedAreas = GetClientPVS ( player , PVS_CONNECTED_AREAS ) ;
} else {
otherPVS = GetClientPVS ( player , PVS_CONNECTED_AREAS ) ;
newPVS = pvs . MergeCurrentPVS ( playerConnectedAreas , otherPVS ) ;
pvs . FreeCurrentPVS ( playerConnectedAreas ) ;
pvs . FreeCurrentPVS ( otherPVS ) ;
playerConnectedAreas = newPVS ;
}
# ifdef _D3XP
// if portalSky is preset, then merge into pvs so we get rotating brushes, etc
if ( portalSkyEnt . GetEntity ( ) ) {
idEntity * skyEnt = portalSkyEnt . GetEntity ( ) ;
otherPVS = pvs . SetupCurrentPVS ( skyEnt - > GetPVSAreas ( ) , skyEnt - > GetNumPVSAreas ( ) ) ;
newPVS = pvs . MergeCurrentPVS ( playerPVS , otherPVS ) ;
pvs . FreeCurrentPVS ( playerPVS ) ;
pvs . FreeCurrentPVS ( otherPVS ) ;
playerPVS = newPVS ;
otherPVS = pvs . SetupCurrentPVS ( skyEnt - > GetPVSAreas ( ) , skyEnt - > GetNumPVSAreas ( ) ) ;
newPVS = pvs . MergeCurrentPVS ( playerConnectedAreas , otherPVS ) ;
pvs . FreeCurrentPVS ( playerConnectedAreas ) ;
pvs . FreeCurrentPVS ( otherPVS ) ;
playerConnectedAreas = newPVS ;
}
# endif
}
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : FreePlayerPVS
= = = = = = = = = = = = = = = =
*/
void idGameLocal : : FreePlayerPVS ( void ) {
if ( playerPVS . i ! = - 1 ) {
pvs . FreeCurrentPVS ( playerPVS ) ;
playerPVS . i = - 1 ;
}
if ( playerConnectedAreas . i ! = - 1 ) {
pvs . FreeCurrentPVS ( playerConnectedAreas ) ;
playerConnectedAreas . i = - 1 ;
}
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : InPlayerPVS
should only be called during entity thinking and event handling
= = = = = = = = = = = = = = = =
*/
bool idGameLocal : : InPlayerPVS ( idEntity * ent ) const {
if ( playerPVS . i = = - 1 ) {
return false ;
}
2011-12-06 18:20:15 +00:00
return pvs . InCurrentPVS ( playerPVS , ent - > GetPVSAreas ( ) , ent - > GetNumPVSAreas ( ) ) ;
2011-11-22 21:28:15 +00:00
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : InPlayerConnectedArea
should only be called during entity thinking and event handling
= = = = = = = = = = = = = = = =
*/
bool idGameLocal : : InPlayerConnectedArea ( idEntity * ent ) const {
if ( playerConnectedAreas . i = = - 1 ) {
return false ;
}
2011-12-06 18:20:15 +00:00
return pvs . InCurrentPVS ( playerConnectedAreas , ent - > GetPVSAreas ( ) , ent - > GetNumPVSAreas ( ) ) ;
2011-11-22 21:28:15 +00:00
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : UpdateGravity
= = = = = = = = = = = = = = = =
*/
void idGameLocal : : UpdateGravity ( void ) {
idEntity * ent ;
if ( g_gravity . IsModified ( ) ) {
if ( g_gravity . GetFloat ( ) = = 0.0f ) {
g_gravity . SetFloat ( 1.0f ) ;
}
2011-12-06 18:20:15 +00:00
gravity . Set ( 0 , 0 , - g_gravity . GetFloat ( ) ) ;
2011-11-22 21:28:15 +00:00
// update all physics objects
for ( ent = spawnedEntities . Next ( ) ; ent ! = NULL ; ent = ent - > spawnNode . Next ( ) ) {
if ( ent - > IsType ( idAFEntity_Generic : : Type ) ) {
idPhysics * phys = ent - > GetPhysics ( ) ;
if ( phys ) {
phys - > SetGravity ( gravity ) ;
}
}
}
g_gravity . ClearModified ( ) ;
}
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : GetGravity
= = = = = = = = = = = = = = = =
*/
const idVec3 & idGameLocal : : GetGravity ( void ) const {
return gravity ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : SortActiveEntityList
Sorts the active entity list such that pushing entities come first ,
actors come next and physics team slaves appear after their master .
= = = = = = = = = = = = = = = =
*/
void idGameLocal : : SortActiveEntityList ( void ) {
idEntity * ent , * next_ent , * master , * part ;
// if the active entity list needs to be reordered to place physics team masters at the front
if ( sortTeamMasters ) {
for ( ent = activeEntities . Next ( ) ; ent ! = NULL ; ent = next_ent ) {
next_ent = ent - > activeNode . Next ( ) ;
master = ent - > GetTeamMaster ( ) ;
if ( master & & master = = ent ) {
ent - > activeNode . Remove ( ) ;
ent - > activeNode . AddToFront ( activeEntities ) ;
}
}
}
// if the active entity list needs to be reordered to place pushers at the front
if ( sortPushers ) {
for ( ent = activeEntities . Next ( ) ; ent ! = NULL ; ent = next_ent ) {
next_ent = ent - > activeNode . Next ( ) ;
master = ent - > GetTeamMaster ( ) ;
if ( ! master | | master = = ent ) {
// check if there is an actor on the team
for ( part = ent ; part ! = NULL ; part = part - > GetNextTeamEntity ( ) ) {
if ( part - > GetPhysics ( ) - > IsType ( idPhysics_Actor : : Type ) ) {
break ;
}
}
// if there is an actor on the team
if ( part ) {
ent - > activeNode . Remove ( ) ;
ent - > activeNode . AddToFront ( activeEntities ) ;
}
}
}
for ( ent = activeEntities . Next ( ) ; ent ! = NULL ; ent = next_ent ) {
next_ent = ent - > activeNode . Next ( ) ;
master = ent - > GetTeamMaster ( ) ;
if ( ! master | | master = = ent ) {
// check if there is an entity on the team using parametric physics
for ( part = ent ; part ! = NULL ; part = part - > GetNextTeamEntity ( ) ) {
if ( part - > GetPhysics ( ) - > IsType ( idPhysics_Parametric : : Type ) ) {
break ;
}
}
// if there is an entity on the team using parametric physics
if ( part ) {
ent - > activeNode . Remove ( ) ;
ent - > activeNode . AddToFront ( activeEntities ) ;
}
}
}
}
sortTeamMasters = false ;
sortPushers = false ;
}
# ifdef _D3XP
/*
= = = = = = = = = = = = = = = =
idGameLocal : : RunTimeGroup2
= = = = = = = = = = = = = = = =
*/
void idGameLocal : : RunTimeGroup2 ( ) {
idEntity * ent ;
int num = 0 ;
fast . Increment ( ) ;
fast . Get ( time , previousTime , msec , framenum , realClientTime ) ;
for ( ent = activeEntities . Next ( ) ; ent ! = NULL ; ent = ent - > activeNode . Next ( ) ) {
if ( ent - > timeGroup ! = TIME_GROUP2 ) {
continue ;
}
ent - > Think ( ) ;
num + + ;
}
slow . Get ( time , previousTime , msec , framenum , realClientTime ) ;
}
# endif
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
/*
= = = = = = = = = = = = = = = =
idGameLocal : : RunFrame
= = = = = = = = = = = = = = = =
*/
gameReturn_t idGameLocal : : RunFrame ( const usercmd_t * clientCmds ) {
idEntity * ent ;
int num ;
float ms ;
idTimer timer_think , timer_events , timer_singlethink ;
gameReturn_t ret ;
idPlayer * player ;
const renderView_t * view ;
# ifdef _DEBUG
if ( isMultiplayer ) {
assert ( ! isClient ) ;
}
# endif
player = GetLocalPlayer ( ) ;
# ifdef _D3XP
ComputeSlowMsec ( ) ;
slow . Get ( time , previousTime , msec , framenum , realClientTime ) ;
msec = slowmoMsec ;
# endif
if ( ! isMultiplayer & & g_stopTime . GetBool ( ) ) {
// clear any debug lines from a previous frame
gameRenderWorld - > DebugClearLines ( time + 1 ) ;
// set the user commands for this frame
memcpy ( usercmds , clientCmds , numClients * sizeof ( usercmds [ 0 ] ) ) ;
if ( player ) {
player - > Think ( ) ;
}
} else do {
// update the game time
framenum + + ;
previousTime = time ;
time + = msec ;
realClientTime = time ;
# ifdef _D3XP
slow . Set ( time , previousTime , msec , framenum , realClientTime ) ;
# endif
# ifdef GAME_DLL
// allow changing SIMD usage on the fly
if ( com_forceGenericSIMD . IsModified ( ) ) {
idSIMD : : InitProcessor ( " game " , com_forceGenericSIMD . GetBool ( ) ) ;
}
# endif
// make sure the random number counter is used each frame so random events
// are influenced by the player's actions
random . RandomInt ( ) ;
if ( player ) {
// update the renderview so that any gui videos play from the right frame
view = player - > GetRenderView ( ) ;
if ( view ) {
gameRenderWorld - > SetRenderView ( view ) ;
}
}
// clear any debug lines from a previous frame
gameRenderWorld - > DebugClearLines ( time ) ;
// clear any debug polygons from a previous frame
gameRenderWorld - > DebugClearPolygons ( time ) ;
// set the user commands for this frame
memcpy ( usercmds , clientCmds , numClients * sizeof ( usercmds [ 0 ] ) ) ;
// free old smoke particles
smokeParticles - > FreeSmokes ( ) ;
// process events on the server
ServerProcessEntityNetworkEventQueue ( ) ;
// update our gravity vector if needed.
UpdateGravity ( ) ;
// create a merged pvs for all players
SetupPlayerPVS ( ) ;
// sort the active entity list
SortActiveEntityList ( ) ;
timer_think . Clear ( ) ;
timer_think . Start ( ) ;
// let entities think
if ( g_timeentities . GetFloat ( ) ) {
num = 0 ;
for ( ent = activeEntities . Next ( ) ; ent ! = NULL ; ent = ent - > activeNode . Next ( ) ) {
if ( g_cinematic . GetBool ( ) & & inCinematic & & ! ent - > cinematic ) {
ent - > GetPhysics ( ) - > UpdateTime ( time ) ;
continue ;
}
timer_singlethink . Clear ( ) ;
timer_singlethink . Start ( ) ;
ent - > Think ( ) ;
timer_singlethink . Stop ( ) ;
ms = timer_singlethink . Milliseconds ( ) ;
if ( ms > = g_timeentities . GetFloat ( ) ) {
2011-12-21 15:51:54 +00:00
Printf ( " %d: entity '%s': %f ms \n " , time , ent - > name . c_str ( ) , ms ) ;
2011-11-22 21:28:15 +00:00
}
num + + ;
}
} else {
if ( inCinematic ) {
num = 0 ;
for ( ent = activeEntities . Next ( ) ; ent ! = NULL ; ent = ent - > activeNode . Next ( ) ) {
if ( g_cinematic . GetBool ( ) & & ! ent - > cinematic ) {
ent - > GetPhysics ( ) - > UpdateTime ( time ) ;
continue ;
}
ent - > Think ( ) ;
num + + ;
}
} else {
num = 0 ;
for ( ent = activeEntities . Next ( ) ; ent ! = NULL ; ent = ent - > activeNode . Next ( ) ) {
# ifdef _D3XP
if ( ent - > timeGroup ! = TIME_GROUP1 ) {
continue ;
}
# endif
ent - > Think ( ) ;
num + + ;
}
}
}
# ifdef _D3XP
RunTimeGroup2 ( ) ;
# endif
// remove any entities that have stopped thinking
if ( numEntitiesToDeactivate ) {
idEntity * next_ent ;
int c = 0 ;
for ( ent = activeEntities . Next ( ) ; ent ! = NULL ; ent = next_ent ) {
next_ent = ent - > activeNode . Next ( ) ;
if ( ! ent - > thinkFlags ) {
ent - > activeNode . Remove ( ) ;
c + + ;
}
}
//assert( numEntitiesToDeactivate == c );
numEntitiesToDeactivate = 0 ;
}
timer_think . Stop ( ) ;
timer_events . Clear ( ) ;
timer_events . Start ( ) ;
// service any pending events
idEvent : : ServiceEvents ( ) ;
# ifdef _D3XP
// service pending fast events
fast . Get ( time , previousTime , msec , framenum , realClientTime ) ;
idEvent : : ServiceFastEvents ( ) ;
slow . Get ( time , previousTime , msec , framenum , realClientTime ) ;
# endif
timer_events . Stop ( ) ;
// free the player pvs
FreePlayerPVS ( ) ;
// do multiplayer related stuff
if ( isMultiplayer ) {
mpGame . Run ( ) ;
}
// display how long it took to calculate the current game frame
if ( g_frametime . GetBool ( ) ) {
2011-12-21 15:51:54 +00:00
Printf ( " game %d: all:%u th:%u ev:%u %d ents \n " ,
2011-11-22 21:28:15 +00:00
time , timer_think . Milliseconds ( ) + timer_events . Milliseconds ( ) ,
timer_think . Milliseconds ( ) , timer_events . Milliseconds ( ) , num ) ;
}
// build the return value
ret . consistencyHash = 0 ;
ret . sessionCommand [ 0 ] = 0 ;
if ( ! isMultiplayer & & player ) {
ret . health = player - > health ;
ret . heartRate = player - > heartRate ;
ret . stamina = idMath : : FtoiFast ( player - > stamina ) ;
// combat is a 0-100 value based on lastHitTime and lastDmgTime
// each make up 50% of the time spread over 10 seconds
ret . combat = 0 ;
if ( player - > lastDmgTime > 0 & & time < player - > lastDmgTime + 10000 ) {
ret . combat + = 50.0f * ( float ) ( time - player - > lastDmgTime ) / 10000 ;
}
if ( player - > lastHitTime > 0 & & time < player - > lastHitTime + 10000 ) {
ret . combat + = 50.0f * ( float ) ( time - player - > lastHitTime ) / 10000 ;
}
}
// see if a target_sessionCommand has forced a changelevel
if ( sessionCommand . Length ( ) ) {
2022-05-17 01:23:12 +00:00
idStr : : Copynz ( ret . sessionCommand , sessionCommand , sizeof ( ret . sessionCommand ) ) ;
2011-11-22 21:28:15 +00:00
break ;
}
// make sure we don't loop forever when skipping a cinematic
if ( skipCinematic & & ( time > cinematicMaxSkipTime ) ) {
Warning ( " Exceeded maximum cinematic skip length. Cinematic may be looping infinitely. " ) ;
skipCinematic = false ;
break ;
}
} while ( ( inCinematic | | ( time < cinematicStopTime ) ) & & skipCinematic ) ;
ret . syncNextGameFrame = skipCinematic ;
if ( skipCinematic ) {
soundSystem - > SetMute ( false ) ;
2011-12-06 18:20:15 +00:00
skipCinematic = false ;
2011-11-22 21:28:15 +00:00
}
// show any debug info for this frame
RunDebugInfo ( ) ;
D_DrawDebugLines ( ) ;
return ret ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Game view drawing
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = = = = =
idGameLocal : : CalcFov
Calculates the horizontal and vertical field of view based on a horizontal field of view and custom aspect ratio
= = = = = = = = = = = = = = = = = = = =
*/
void idGameLocal : : CalcFov ( float base_fov , float & fov_x , float & fov_y ) const {
float x ;
float y ;
float ratio_x ;
float ratio_y ;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
// first, calculate the vertical fov based on a 640x480 view
x = 640.0f / tan ( base_fov / 360.0f * idMath : : PI ) ;
y = atan2 ( 480.0f , x ) ;
fov_y = y * 360.0f / idMath : : PI ;
// FIXME: somehow, this is happening occasionally
assert ( fov_y > 0 ) ;
if ( fov_y < = 0 ) {
2015-09-27 16:05:04 +00:00
Error ( " idGameLocal::CalcFov: bad result, fov_y == %f, base_fov == %f " , fov_y , base_fov ) ;
2011-11-22 21:28:15 +00:00
}
switch ( r_aspectRatio . GetInteger ( ) ) {
default :
2012-10-28 02:46:56 +00:00
case - 1 :
// auto mode => use aspect ratio from resolution, assuming screen's pixels are squares
ratio_x = renderSystem - > GetScreenWidth ( ) ;
ratio_y = renderSystem - > GetScreenHeight ( ) ;
2015-09-27 02:16:47 +00:00
if ( ratio_x < = 0.0f | | ratio_y < = 0.0f )
{
// for some reason (maybe this is a dedicated server?) GetScreenWidth()/Height()
// returned 0. Assume default 4:3 to avoid assert()/Error() below.
fov_x = base_fov ;
return ;
}
2012-10-28 02:46:56 +00:00
break ;
2011-11-22 21:28:15 +00:00
case 0 :
// 4:3
fov_x = base_fov ;
return ;
break ;
case 1 :
// 16:9
ratio_x = 16.0f ;
ratio_y = 9.0f ;
break ;
case 2 :
// 16:10
ratio_x = 16.0f ;
ratio_y = 10.0f ;
break ;
2018-12-09 03:57:32 +00:00
case 3 :
// 21:9
ratio_x = 21.0f ;
ratio_y = 9.0f ;
break ;
2011-11-22 21:28:15 +00:00
}
y = ratio_y / tan ( fov_y / 360.0f * idMath : : PI ) ;
fov_x = atan2 ( ratio_x , y ) * 360.0f / idMath : : PI ;
if ( fov_x < base_fov ) {
fov_x = base_fov ;
x = ratio_x / tan ( fov_x / 360.0f * idMath : : PI ) ;
fov_y = atan2 ( ratio_y , x ) * 360.0f / idMath : : PI ;
}
// FIXME: somehow, this is happening occasionally
assert ( ( fov_x > 0 ) & & ( fov_y > 0 ) ) ;
if ( ( fov_y < = 0 ) | | ( fov_x < = 0 ) ) {
Error ( " idGameLocal::CalcFov: bad result " ) ;
}
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : Draw
makes rendering and sound system calls
= = = = = = = = = = = = = = = =
*/
bool idGameLocal : : Draw ( int clientNum ) {
if ( isMultiplayer ) {
return mpGame . Draw ( clientNum ) ;
}
idPlayer * player = static_cast < idPlayer * > ( entities [ clientNum ] ) ;
if ( ! player ) {
return false ;
}
// render the scene
player - > playerView . RenderPlayerView ( player - > hud ) ;
return true ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : HandleESC
= = = = = = = = = = = = = = = =
*/
escReply_t idGameLocal : : HandleESC ( idUserInterface * * gui ) {
if ( isMultiplayer ) {
* gui = StartMenu ( ) ;
// we may set the gui back to NULL to hide it
return ESC_GUI ;
}
idPlayer * player = GetLocalPlayer ( ) ;
if ( player ) {
if ( player - > HandleESC ( ) ) {
return ESC_IGNORE ;
} else {
return ESC_MAIN ;
}
}
return ESC_MAIN ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : StartMenu
= = = = = = = = = = = = = = = =
*/
idUserInterface * idGameLocal : : StartMenu ( void ) {
if ( ! isMultiplayer ) {
return NULL ;
}
return mpGame . StartMenu ( ) ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : HandleGuiCommands
= = = = = = = = = = = = = = = =
*/
const char * idGameLocal : : HandleGuiCommands ( const char * menuCommand ) {
if ( ! isMultiplayer ) {
return NULL ;
}
return mpGame . HandleGuiCommands ( menuCommand ) ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : HandleMainMenuCommands
= = = = = = = = = = = = = = = =
*/
void idGameLocal : : HandleMainMenuCommands ( const char * menuCommand , idUserInterface * gui ) { }
/*
= = = = = = = = = = = = = = = =
idGameLocal : : GetLevelMap
should only be used for in - game level editing
= = = = = = = = = = = = = = = =
*/
idMapFile * idGameLocal : : GetLevelMap ( void ) {
if ( mapFile & & mapFile - > HasPrimitiveData ( ) ) {
return mapFile ;
}
if ( ! mapFileName . Length ( ) ) {
return NULL ;
}
if ( mapFile ) {
delete mapFile ;
}
mapFile = new idMapFile ;
if ( ! mapFile - > Parse ( mapFileName ) ) {
delete mapFile ;
mapFile = NULL ;
}
return mapFile ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : GetMapName
= = = = = = = = = = = = = = = =
*/
const char * idGameLocal : : GetMapName ( void ) const {
return mapFileName . c_str ( ) ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : CallFrameCommand
= = = = = = = = = = = = = = = =
*/
void idGameLocal : : CallFrameCommand ( idEntity * ent , const function_t * frameCommand ) {
frameCommandThread - > CallFunction ( ent , frameCommand , true ) ;
frameCommandThread - > Execute ( ) ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : CallObjectFrameCommand
= = = = = = = = = = = = = = = =
*/
void idGameLocal : : CallObjectFrameCommand ( idEntity * ent , const char * frameCommand ) {
const function_t * func ;
func = ent - > scriptObject . GetFunction ( frameCommand ) ;
if ( ! func ) {
if ( ! ent - > IsType ( idTestModel : : Type ) ) {
Error ( " Unknown function '%s' called for frame command on entity '%s' " , frameCommand , ent - > name . c_str ( ) ) ;
}
} else {
frameCommandThread - > CallFunction ( ent , func , true ) ;
frameCommandThread - > Execute ( ) ;
}
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : ShowTargets
= = = = = = = = = = = = = = = =
*/
void idGameLocal : : ShowTargets ( void ) {
idMat3 axis = GetLocalPlayer ( ) - > viewAngles . ToMat3 ( ) ;
idVec3 up = axis [ 2 ] * 5.0f ;
const idVec3 & viewPos = GetLocalPlayer ( ) - > GetPhysics ( ) - > GetOrigin ( ) ;
idBounds viewTextBounds ( viewPos ) ;
idBounds viewBounds ( viewPos ) ;
idBounds box ( idVec3 ( - 4.0f , - 4.0f , - 4.0f ) , idVec3 ( 4.0f , 4.0f , 4.0f ) ) ;
idEntity * ent ;
idEntity * target ;
int i ;
idBounds totalBounds ;
viewTextBounds . ExpandSelf ( 128.0f ) ;
viewBounds . ExpandSelf ( 512.0f ) ;
for ( ent = spawnedEntities . Next ( ) ; ent ! = NULL ; ent = ent - > spawnNode . Next ( ) ) {
totalBounds = ent - > GetPhysics ( ) - > GetAbsBounds ( ) ;
for ( i = 0 ; i < ent - > targets . Num ( ) ; i + + ) {
target = ent - > targets [ i ] . GetEntity ( ) ;
if ( target ) {
totalBounds . AddBounds ( target - > GetPhysics ( ) - > GetAbsBounds ( ) ) ;
}
}
if ( ! viewBounds . IntersectsBounds ( totalBounds ) ) {
continue ;
}
float dist ;
idVec3 dir = totalBounds . GetCenter ( ) - viewPos ;
dir . NormalizeFast ( ) ;
totalBounds . RayIntersection ( viewPos , dir , dist ) ;
float frac = ( 512.0f - dist ) / 512.0f ;
if ( frac < 0.0f ) {
continue ;
}
gameRenderWorld - > DebugBounds ( ( ent - > IsHidden ( ) ? colorLtGrey : colorOrange ) * frac , ent - > GetPhysics ( ) - > GetAbsBounds ( ) ) ;
if ( viewTextBounds . IntersectsBounds ( ent - > GetPhysics ( ) - > GetAbsBounds ( ) ) ) {
idVec3 center = ent - > GetPhysics ( ) - > GetAbsBounds ( ) . GetCenter ( ) ;
gameRenderWorld - > DrawText ( ent - > name . c_str ( ) , center - up , 0.1f , colorWhite * frac , axis , 1 ) ;
gameRenderWorld - > DrawText ( ent - > GetEntityDefName ( ) , center , 0.1f , colorWhite * frac , axis , 1 ) ;
gameRenderWorld - > DrawText ( va ( " #%d " , ent - > entityNumber ) , center + up , 0.1f , colorWhite * frac , axis , 1 ) ;
}
for ( i = 0 ; i < ent - > targets . Num ( ) ; i + + ) {
target = ent - > targets [ i ] . GetEntity ( ) ;
if ( target ) {
gameRenderWorld - > DebugArrow ( colorYellow * frac , ent - > GetPhysics ( ) - > GetAbsBounds ( ) . GetCenter ( ) , target - > GetPhysics ( ) - > GetOrigin ( ) , 10 , 0 ) ;
gameRenderWorld - > DebugBounds ( colorGreen * frac , box , target - > GetPhysics ( ) - > GetOrigin ( ) ) ;
}
}
}
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : RunDebugInfo
= = = = = = = = = = = = = = = =
*/
void idGameLocal : : RunDebugInfo ( void ) {
idEntity * ent ;
idPlayer * player ;
player = GetLocalPlayer ( ) ;
if ( ! player ) {
return ;
}
const idVec3 & origin = player - > GetPhysics ( ) - > GetOrigin ( ) ;
if ( g_showEntityInfo . GetBool ( ) ) {
idMat3 axis = player - > viewAngles . ToMat3 ( ) ;
idVec3 up = axis [ 2 ] * 5.0f ;
idBounds viewTextBounds ( origin ) ;
idBounds viewBounds ( origin ) ;
viewTextBounds . ExpandSelf ( 128.0f ) ;
viewBounds . ExpandSelf ( 512.0f ) ;
for ( ent = spawnedEntities . Next ( ) ; ent ! = NULL ; ent = ent - > spawnNode . Next ( ) ) {
// don't draw the worldspawn
if ( ent = = world ) {
continue ;
}
// skip if the entity is very far away
if ( ! viewBounds . IntersectsBounds ( ent - > GetPhysics ( ) - > GetAbsBounds ( ) ) ) {
continue ;
}
const idBounds & entBounds = ent - > GetPhysics ( ) - > GetAbsBounds ( ) ;
int contents = ent - > GetPhysics ( ) - > GetContents ( ) ;
if ( contents & CONTENTS_BODY ) {
gameRenderWorld - > DebugBounds ( colorCyan , entBounds ) ;
} else if ( contents & CONTENTS_TRIGGER ) {
gameRenderWorld - > DebugBounds ( colorOrange , entBounds ) ;
} else if ( contents & CONTENTS_SOLID ) {
gameRenderWorld - > DebugBounds ( colorGreen , entBounds ) ;
} else {
if ( ! entBounds . GetVolume ( ) ) {
gameRenderWorld - > DebugBounds ( colorMdGrey , entBounds . Expand ( 8.0f ) ) ;
} else {
gameRenderWorld - > DebugBounds ( colorMdGrey , entBounds ) ;
}
}
if ( viewTextBounds . IntersectsBounds ( entBounds ) ) {
gameRenderWorld - > DrawText ( ent - > name . c_str ( ) , entBounds . GetCenter ( ) , 0.1f , colorWhite , axis , 1 ) ;
gameRenderWorld - > DrawText ( va ( " #%d " , ent - > entityNumber ) , entBounds . GetCenter ( ) + up , 0.1f , colorWhite , axis , 1 ) ;
}
}
}
// debug tool to draw bounding boxes around active entities
if ( g_showActiveEntities . GetBool ( ) ) {
for ( ent = activeEntities . Next ( ) ; ent ! = NULL ; ent = ent - > activeNode . Next ( ) ) {
idBounds b = ent - > GetPhysics ( ) - > GetBounds ( ) ;
if ( b . GetVolume ( ) < = 0 ) {
b [ 0 ] [ 0 ] = b [ 0 ] [ 1 ] = b [ 0 ] [ 2 ] = - 8 ;
b [ 1 ] [ 0 ] = b [ 1 ] [ 1 ] = b [ 1 ] [ 2 ] = 8 ;
}
if ( ent - > fl . isDormant ) {
gameRenderWorld - > DebugBounds ( colorYellow , b , ent - > GetPhysics ( ) - > GetOrigin ( ) ) ;
} else {
gameRenderWorld - > DebugBounds ( colorGreen , b , ent - > GetPhysics ( ) - > GetOrigin ( ) ) ;
}
}
}
if ( g_showTargets . GetBool ( ) ) {
ShowTargets ( ) ;
}
if ( g_showTriggers . GetBool ( ) ) {
idTrigger : : DrawDebugInfo ( ) ;
}
if ( ai_showCombatNodes . GetBool ( ) ) {
idCombatNode : : DrawDebugInfo ( ) ;
}
if ( ai_showPaths . GetBool ( ) ) {
idPathCorner : : DrawDebugInfo ( ) ;
}
if ( g_editEntityMode . GetBool ( ) ) {
editEntities - > DisplayEntities ( ) ;
}
if ( g_showCollisionWorld . GetBool ( ) ) {
collisionModelManager - > DrawModel ( 0 , vec3_origin , mat3_identity , origin , 128.0f ) ;
}
if ( g_showCollisionModels . GetBool ( ) ) {
clip . DrawClipModels ( player - > GetEyePosition ( ) , g_maxShowDistance . GetFloat ( ) , pm_thirdPerson . GetBool ( ) ? NULL : player ) ;
}
if ( g_showCollisionTraces . GetBool ( ) ) {
clip . PrintStatistics ( ) ;
}
if ( g_showPVS . GetInteger ( ) ) {
pvs . DrawPVS ( origin , ( g_showPVS . GetInteger ( ) = = 2 ) ? PVS_ALL_PORTALS_OPEN : PVS_NORMAL ) ;
}
if ( aas_test . GetInteger ( ) > = 0 ) {
idAAS * aas = GetAAS ( aas_test . GetInteger ( ) ) ;
if ( aas ) {
aas - > Test ( origin ) ;
if ( ai_testPredictPath . GetBool ( ) ) {
idVec3 velocity ;
predictedPath_t path ;
velocity . x = cos ( DEG2RAD ( player - > viewAngles . yaw ) ) * 100.0f ;
velocity . y = sin ( DEG2RAD ( player - > viewAngles . yaw ) ) * 100.0f ;
velocity . z = 0.0f ;
idAI : : PredictPath ( player , aas , origin , velocity , 1000 , 100 , SE_ENTER_OBSTACLE | SE_BLOCKED | SE_ENTER_LEDGE_AREA , path ) ;
}
}
}
if ( ai_showObstacleAvoidance . GetInteger ( ) = = 2 ) {
idAAS * aas = GetAAS ( 0 ) ;
if ( aas ) {
idVec3 seekPos ;
obstaclePath_t path ;
seekPos = player - > GetPhysics ( ) - > GetOrigin ( ) + player - > viewAxis [ 0 ] * 200.0f ;
idAI : : FindPathAroundObstacles ( player - > GetPhysics ( ) , aas , NULL , player - > GetPhysics ( ) - > GetOrigin ( ) , seekPos , path ) ;
}
}
// collision map debug output
collisionModelManager - > DebugOutput ( player - > GetEyePosition ( ) ) ;
}
/*
= = = = = = = = = = = = = = = = = =
idGameLocal : : NumAAS
= = = = = = = = = = = = = = = = = =
*/
int idGameLocal : : NumAAS ( void ) const {
return aasList . Num ( ) ;
}
/*
= = = = = = = = = = = = = = = = = =
idGameLocal : : GetAAS
= = = = = = = = = = = = = = = = = =
*/
idAAS * idGameLocal : : GetAAS ( int num ) const {
if ( ( num > = 0 ) & & ( num < aasList . Num ( ) ) ) {
if ( aasList [ num ] & & aasList [ num ] - > GetSettings ( ) ) {
return aasList [ num ] ;
}
}
return NULL ;
}
/*
= = = = = = = = = = = = = = = = = =
idGameLocal : : GetAAS
= = = = = = = = = = = = = = = = = =
*/
idAAS * idGameLocal : : GetAAS ( const char * name ) const {
int i ;
for ( i = 0 ; i < aasNames . Num ( ) ; i + + ) {
if ( aasNames [ i ] = = name ) {
if ( ! aasList [ i ] - > GetSettings ( ) ) {
return NULL ;
} else {
return aasList [ i ] ;
}
}
}
return NULL ;
}
/*
= = = = = = = = = = = = = = = = = =
idGameLocal : : SetAASAreaState
= = = = = = = = = = = = = = = = = =
*/
void idGameLocal : : SetAASAreaState ( const idBounds & bounds , const int areaContents , bool closed ) {
int i ;
for ( i = 0 ; i < aasList . Num ( ) ; i + + ) {
aasList [ i ] - > SetAreaState ( bounds , areaContents , closed ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
idGameLocal : : AddAASObstacle
= = = = = = = = = = = = = = = = = =
*/
aasHandle_t idGameLocal : : AddAASObstacle ( const idBounds & bounds ) {
int i ;
aasHandle_t obstacle ;
2011-12-06 18:13:18 +00:00
aasHandle_t check id_attribute ( ( unused ) ) ;
2011-11-22 21:28:15 +00:00
if ( ! aasList . Num ( ) ) {
return - 1 ;
}
obstacle = aasList [ 0 ] - > AddObstacle ( bounds ) ;
for ( i = 1 ; i < aasList . Num ( ) ; i + + ) {
check = aasList [ i ] - > AddObstacle ( bounds ) ;
assert ( check = = obstacle ) ;
}
return obstacle ;
}
/*
= = = = = = = = = = = = = = = = = =
idGameLocal : : RemoveAASObstacle
= = = = = = = = = = = = = = = = = =
*/
void idGameLocal : : RemoveAASObstacle ( const aasHandle_t handle ) {
int i ;
for ( i = 0 ; i < aasList . Num ( ) ; i + + ) {
aasList [ i ] - > RemoveObstacle ( handle ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
idGameLocal : : RemoveAllAASObstacles
= = = = = = = = = = = = = = = = = =
*/
void idGameLocal : : RemoveAllAASObstacles ( void ) {
int i ;
for ( i = 0 ; i < aasList . Num ( ) ; i + + ) {
aasList [ i ] - > RemoveAllObstacles ( ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
idGameLocal : : CheatsOk
= = = = = = = = = = = = = = = = = =
*/
bool idGameLocal : : CheatsOk ( bool requirePlayer ) {
idPlayer * player ;
if ( isMultiplayer & & ! cvarSystem - > GetCVarBool ( " net_allowCheats " ) ) {
Printf ( " Not allowed in multiplayer. \n " ) ;
return false ;
}
if ( developer . GetBool ( ) ) {
return true ;
}
player = GetLocalPlayer ( ) ;
if ( ! requirePlayer | | ( player & & ( player - > health > 0 ) ) ) {
return true ;
}
Printf ( " You must be alive to use this command. \n " ) ;
return false ;
}
/*
= = = = = = = = = = = = = = = = = = =
idGameLocal : : RegisterEntity
= = = = = = = = = = = = = = = = = = =
*/
void idGameLocal : : RegisterEntity ( idEntity * ent ) {
int spawn_entnum ;
if ( spawnCount > = ( 1 < < ( 32 - GENTITYNUM_BITS ) ) ) {
Error ( " idGameLocal::RegisterEntity: spawn count overflow " ) ;
}
if ( ! spawnArgs . GetInt ( " spawn_entnum " , " 0 " , spawn_entnum ) ) {
while ( entities [ firstFreeIndex ] & & firstFreeIndex < ENTITYNUM_MAX_NORMAL ) {
firstFreeIndex + + ;
}
if ( firstFreeIndex > = ENTITYNUM_MAX_NORMAL ) {
Error ( " no free entities " ) ;
}
spawn_entnum = firstFreeIndex + + ;
}
entities [ spawn_entnum ] = ent ;
spawnIds [ spawn_entnum ] = spawnCount + + ;
ent - > entityNumber = spawn_entnum ;
ent - > spawnNode . AddToEnd ( spawnedEntities ) ;
ent - > spawnArgs . TransferKeyValues ( spawnArgs ) ;
if ( spawn_entnum > = num_entities ) {
num_entities + + ;
}
}
/*
= = = = = = = = = = = = = = = = = = =
idGameLocal : : UnregisterEntity
= = = = = = = = = = = = = = = = = = =
*/
void idGameLocal : : UnregisterEntity ( idEntity * ent ) {
assert ( ent ) ;
if ( editEntities ) {
editEntities - > RemoveSelectedEntity ( ent ) ;
}
if ( ( ent - > entityNumber ! = ENTITYNUM_NONE ) & & ( entities [ ent - > entityNumber ] = = ent ) ) {
ent - > spawnNode . Remove ( ) ;
entities [ ent - > entityNumber ] = NULL ;
spawnIds [ ent - > entityNumber ] = - 1 ;
if ( ent - > entityNumber > = MAX_CLIENTS & & ent - > entityNumber < firstFreeIndex ) {
firstFreeIndex = ent - > entityNumber ;
}
ent - > entityNumber = ENTITYNUM_NONE ;
}
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : SpawnEntityType
= = = = = = = = = = = = = = = =
*/
idEntity * idGameLocal : : SpawnEntityType ( const idTypeInfo & classdef , const idDict * args , bool bIsClientReadSnapshot ) {
idClass * obj ;
# if _DEBUG
if ( isClient ) {
assert ( bIsClientReadSnapshot ) ;
}
# endif
if ( ! classdef . IsType ( idEntity : : Type ) ) {
Error ( " Attempted to spawn non-entity class '%s' " , classdef . classname ) ;
}
try {
if ( args ) {
spawnArgs = * args ;
} else {
spawnArgs . Clear ( ) ;
}
obj = classdef . CreateInstance ( ) ;
obj - > CallSpawn ( ) ;
}
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
catch ( idAllocError & ) {
obj = NULL ;
}
spawnArgs . Clear ( ) ;
return static_cast < idEntity * > ( obj ) ;
}
/*
= = = = = = = = = = = = = = = = = = =
idGameLocal : : SpawnEntityDef
Finds the spawn function for the entity and calls it ,
returning false if not found
= = = = = = = = = = = = = = = = = = =
*/
bool idGameLocal : : SpawnEntityDef ( const idDict & args , idEntity * * ent , bool setDefaults ) {
const char * classname ;
const char * spawn ;
idTypeInfo * cls ;
idClass * obj ;
idStr error ;
const char * name ;
if ( ent ) {
* ent = NULL ;
}
spawnArgs = args ;
if ( spawnArgs . GetString ( " name " , " " , & name ) ) {
sprintf ( error , " on '%s' " , name ) ;
}
spawnArgs . GetString ( " classname " , NULL , & classname ) ;
const idDeclEntityDef * def = FindEntityDef ( classname , false ) ;
if ( ! def ) {
Warning ( " Unknown classname '%s'%s. " , classname , error . c_str ( ) ) ;
return false ;
}
spawnArgs . SetDefaults ( & def - > dict ) ;
# ifdef _D3XP
if ( ! spawnArgs . FindKey ( " slowmo " ) ) {
bool slowmo = true ;
for ( int i = 0 ; fastEntityList [ i ] ; i + + ) {
if ( ! idStr : : Cmp ( classname , fastEntityList [ i ] ) ) {
slowmo = false ;
break ;
}
}
if ( ! slowmo ) {
spawnArgs . SetBool ( " slowmo " , slowmo ) ;
}
}
# endif
// check if we should spawn a class object
spawnArgs . GetString ( " spawnclass " , NULL , & spawn ) ;
if ( spawn ) {
cls = idClass : : GetClass ( spawn ) ;
if ( ! cls ) {
Warning ( " Could not spawn '%s'. Class '%s' not found %s. " , classname , spawn , error . c_str ( ) ) ;
return false ;
}
obj = cls - > CreateInstance ( ) ;
if ( ! obj ) {
Warning ( " Could not spawn '%s'. Instance could not be created %s. " , classname , error . c_str ( ) ) ;
return false ;
}
obj - > CallSpawn ( ) ;
if ( ent & & obj - > IsType ( idEntity : : Type ) ) {
* ent = static_cast < idEntity * > ( obj ) ;
}
return true ;
}
// check if we should call a script function to spawn
spawnArgs . GetString ( " spawnfunc " , NULL , & spawn ) ;
if ( spawn ) {
const function_t * func = program . FindFunction ( spawn ) ;
if ( ! func ) {
Warning ( " Could not spawn '%s'. Script function '%s' not found%s. " , classname , spawn , error . c_str ( ) ) ;
return false ;
}
idThread * thread = new idThread ( func ) ;
thread - > DelayedStart ( 0 ) ;
return true ;
}
Warning ( " %s doesn't include a spawnfunc or spawnclass%s. " , classname , error . c_str ( ) ) ;
return false ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : FindEntityDef
= = = = = = = = = = = = = = = =
*/
const idDeclEntityDef * idGameLocal : : FindEntityDef ( const char * name , bool makeDefault ) const {
const idDecl * decl = NULL ;
if ( isMultiplayer ) {
decl = declManager - > FindType ( DECL_ENTITYDEF , va ( " %s_mp " , name ) , false ) ;
}
if ( ! decl ) {
decl = declManager - > FindType ( DECL_ENTITYDEF , name , makeDefault ) ;
}
return static_cast < const idDeclEntityDef * > ( decl ) ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : FindEntityDefDict
= = = = = = = = = = = = = = = =
*/
const idDict * idGameLocal : : FindEntityDefDict ( const char * name , bool makeDefault ) const {
const idDeclEntityDef * decl = FindEntityDef ( name , makeDefault ) ;
return decl ? & decl - > dict : NULL ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : InhibitEntitySpawn
= = = = = = = = = = = = = = = =
*/
bool idGameLocal : : InhibitEntitySpawn ( idDict & spawnArgs ) {
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
bool result = false ;
if ( isMultiplayer ) {
spawnArgs . GetBool ( " not_multiplayer " , " 0 " , result ) ;
} else if ( g_skill . GetInteger ( ) = = 0 ) {
spawnArgs . GetBool ( " not_easy " , " 0 " , result ) ;
} else if ( g_skill . GetInteger ( ) = = 1 ) {
spawnArgs . GetBool ( " not_medium " , " 0 " , result ) ;
} else {
spawnArgs . GetBool ( " not_hard " , " 0 " , result ) ;
# ifdef _D3XP
if ( ! result & & g_skill . GetInteger ( ) = = 3 ) {
spawnArgs . GetBool ( " not_nightmare " , " 0 " , result ) ;
}
# endif
}
const char * name ;
2011-12-06 18:20:15 +00:00
if ( g_skill . GetInteger ( ) = = 3 ) {
2011-11-22 21:28:15 +00:00
name = spawnArgs . GetString ( " classname " ) ;
// _D3XP :: remove moveable medkit packs also
if ( idStr : : Icmp ( name , " item_medkit " ) = = 0 | | idStr : : Icmp ( name , " item_medkit_small " ) = = 0 | |
idStr : : Icmp ( name , " moveable_item_medkit " ) = = 0 | | idStr : : Icmp ( name , " moveable_item_medkit_small " ) = = 0 ) {
result = true ;
}
}
if ( gameLocal . isMultiplayer ) {
name = spawnArgs . GetString ( " classname " ) ;
if ( idStr : : Icmp ( name , " weapon_bfg " ) = = 0 | | idStr : : Icmp ( name , " weapon_soulcube " ) = = 0 ) {
result = true ;
}
}
return result ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : SetSkill
= = = = = = = = = = = = = = = =
*/
void idGameLocal : : SetSkill ( int value ) {
int skill_level ;
if ( value < 0 ) {
skill_level = 0 ;
} else if ( value > 3 ) {
skill_level = 3 ;
} else {
skill_level = value ;
}
g_skill . SetInteger ( skill_level ) ;
}
/*
= = = = = = = = = = = = = =
idGameLocal : : GameState
Used to allow entities to know if they ' re being spawned during the initial spawn .
= = = = = = = = = = = = = =
*/
gameState_t idGameLocal : : GameState ( void ) const {
return gamestate ;
}
/*
= = = = = = = = = = = = = =
idGameLocal : : SpawnMapEntities
Parses textual entity definitions out of an entstring and spawns gentities .
= = = = = = = = = = = = = =
*/
void idGameLocal : : SpawnMapEntities ( void ) {
int i ;
int num ;
int inhibit ;
idMapEntity * mapEnt ;
int numEntities ;
idDict args ;
Printf ( " Spawning entities \n " ) ;
if ( mapFile = = NULL ) {
Printf ( " No mapfile present \n " ) ;
return ;
}
SetSkill ( g_skill . GetInteger ( ) ) ;
numEntities = mapFile - > GetNumEntities ( ) ;
if ( numEntities = = 0 ) {
Error ( " ...no entities " ) ;
}
// the worldspawn is a special that performs any global setup
// needed by a level
mapEnt = mapFile - > GetEntity ( 0 ) ;
args = mapEnt - > epairs ;
args . SetInt ( " spawn_entnum " , ENTITYNUM_WORLD ) ;
if ( ! SpawnEntityDef ( args ) | | ! entities [ ENTITYNUM_WORLD ] | | ! entities [ ENTITYNUM_WORLD ] - > IsType ( idWorldspawn : : Type ) ) {
Error ( " Problem spawning world entity " ) ;
}
num = 1 ;
inhibit = 0 ;
for ( i = 1 ; i < numEntities ; i + + ) {
mapEnt = mapFile - > GetEntity ( i ) ;
args = mapEnt - > epairs ;
if ( ! InhibitEntitySpawn ( args ) ) {
// precache any media specified in the map entity
CacheDictionaryMedia ( & args ) ;
SpawnEntityDef ( args ) ;
num + + ;
} else {
inhibit + + ;
}
}
Printf ( " ...%i entities spawned, %i inhibited \n \n " , num , inhibit ) ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : AddEntityToHash
= = = = = = = = = = = = = = = =
*/
void idGameLocal : : AddEntityToHash ( const char * name , idEntity * ent ) {
if ( FindEntity ( name ) ) {
Error ( " Multiple entities named '%s' " , name ) ;
}
entityHash . Add ( entityHash . GenerateKey ( name , true ) , ent - > entityNumber ) ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : RemoveEntityFromHash
= = = = = = = = = = = = = = = =
*/
bool idGameLocal : : RemoveEntityFromHash ( const char * name , idEntity * ent ) {
int hash , i ;
hash = entityHash . GenerateKey ( name , true ) ;
for ( i = entityHash . First ( hash ) ; i ! = - 1 ; i = entityHash . Next ( i ) ) {
if ( entities [ i ] & & entities [ i ] = = ent & & entities [ i ] - > name . Icmp ( name ) = = 0 ) {
entityHash . Remove ( hash , i ) ;
return true ;
}
}
return false ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : GetTargets
= = = = = = = = = = = = = = = =
*/
int idGameLocal : : GetTargets ( const idDict & args , idList < idEntityPtr < idEntity > > & list , const char * ref ) const {
int i , num , refLength ;
const idKeyValue * arg ;
idEntity * ent ;
list . Clear ( ) ;
refLength = strlen ( ref ) ;
num = args . GetNumKeyVals ( ) ;
for ( i = 0 ; i < num ; i + + ) {
arg = args . GetKeyVal ( i ) ;
if ( arg - > GetKey ( ) . Icmpn ( ref , refLength ) = = 0 ) {
ent = FindEntity ( arg - > GetValue ( ) ) ;
if ( ent ) {
idEntityPtr < idEntity > & entityPtr = list . Alloc ( ) ;
2011-12-06 18:20:15 +00:00
entityPtr = ent ;
2011-11-22 21:28:15 +00:00
}
}
}
return list . Num ( ) ;
}
/*
= = = = = = = = = = = = =
idGameLocal : : GetTraceEntity
returns the master entity of a trace . for example , if the trace entity is the player ' s head , it will return the player .
= = = = = = = = = = = = =
*/
idEntity * idGameLocal : : GetTraceEntity ( const trace_t & trace ) const {
idEntity * master ;
if ( ! entities [ trace . c . entityNum ] ) {
return NULL ;
}
master = entities [ trace . c . entityNum ] - > GetBindMaster ( ) ;
if ( master ) {
return master ;
}
return entities [ trace . c . entityNum ] ;
}
/*
= = = = = = = = = = = = =
idGameLocal : : ArgCompletion_EntityName
Argument completion for entity names
= = = = = = = = = = = = =
*/
void idGameLocal : : ArgCompletion_EntityName ( const idCmdArgs & args , void ( * callback ) ( const char * s ) ) {
int i ;
for ( i = 0 ; i < gameLocal . num_entities ; i + + ) {
if ( gameLocal . entities [ i ] ) {
callback ( va ( " %s %s " , args . Argv ( 0 ) , gameLocal . entities [ i ] - > name . c_str ( ) ) ) ;
}
}
}
/*
= = = = = = = = = = = = =
idGameLocal : : FindEntity
Returns the entity whose name matches the specified string .
= = = = = = = = = = = = =
*/
idEntity * idGameLocal : : FindEntity ( const char * name ) const {
int hash , i ;
hash = entityHash . GenerateKey ( name , true ) ;
for ( i = entityHash . First ( hash ) ; i ! = - 1 ; i = entityHash . Next ( i ) ) {
if ( entities [ i ] & & entities [ i ] - > name . Icmp ( name ) = = 0 ) {
return entities [ i ] ;
}
}
return NULL ;
}
/*
= = = = = = = = = = = = =
idGameLocal : : FindEntityUsingDef
Searches all active entities for the next one using the specified entityDef .
Searches beginning at the entity after from , or the beginning if NULL
NULL will be returned if the end of the list is reached .
= = = = = = = = = = = = =
*/
idEntity * idGameLocal : : FindEntityUsingDef ( idEntity * from , const char * match ) const {
idEntity * ent ;
if ( ! from ) {
ent = spawnedEntities . Next ( ) ;
} else {
ent = from - > spawnNode . Next ( ) ;
}
for ( ; ent ! = NULL ; ent = ent - > spawnNode . Next ( ) ) {
assert ( ent ) ;
if ( idStr : : Icmp ( ent - > GetEntityDefName ( ) , match ) = = 0 ) {
return ent ;
}
}
return NULL ;
}
/*
= = = = = = = = = = = = =
idGameLocal : : FindTraceEntity
Searches all active entities for the closest ( to start ) match that intersects
the line start , end
= = = = = = = = = = = = =
*/
idEntity * idGameLocal : : FindTraceEntity ( idVec3 start , idVec3 end , const idTypeInfo & c , const idEntity * skip ) const {
idEntity * ent ;
idEntity * bestEnt ;
float scale ;
float bestScale ;
idBounds b ;
bestEnt = NULL ;
bestScale = 1.0f ;
for ( ent = spawnedEntities . Next ( ) ; ent ! = NULL ; ent = ent - > spawnNode . Next ( ) ) {
if ( ent - > IsType ( c ) & & ent ! = skip ) {
b = ent - > GetPhysics ( ) - > GetAbsBounds ( ) . Expand ( 16 ) ;
if ( b . RayIntersection ( start , end - start , scale ) ) {
if ( scale > = 0.0f & & scale < bestScale ) {
bestEnt = ent ;
bestScale = scale ;
}
}
}
}
return bestEnt ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : EntitiesWithinRadius
= = = = = = = = = = = = = = = =
*/
int idGameLocal : : EntitiesWithinRadius ( const idVec3 org , float radius , idEntity * * entityList , int maxCount ) const {
idEntity * ent ;
idBounds bo ( org ) ;
int entCount = 0 ;
bo . ExpandSelf ( radius ) ;
for ( ent = spawnedEntities . Next ( ) ; ent ! = NULL ; ent = ent - > spawnNode . Next ( ) ) {
if ( ent - > GetPhysics ( ) - > GetAbsBounds ( ) . IntersectsBounds ( bo ) ) {
entityList [ entCount + + ] = ent ;
}
}
return entCount ;
}
/*
= = = = = = = = = = = = = = = = =
idGameLocal : : KillBox
Kills all entities that would touch the proposed new positioning of ent . The ent itself will not being killed .
Checks if player entities are in the teleporter , and marks them to die at teleport exit instead of immediately .
If catch_teleport , this only marks teleport players for death on exit
= = = = = = = = = = = = = = = = =
*/
void idGameLocal : : KillBox ( idEntity * ent , bool catch_teleport ) {
int i ;
int num ;
idEntity * hit ;
idClipModel * cm ;
idClipModel * clipModels [ MAX_GENTITIES ] ;
idPhysics * phys ;
phys = ent - > GetPhysics ( ) ;
if ( ! phys - > GetNumClipModels ( ) ) {
return ;
}
num = clip . ClipModelsTouchingBounds ( phys - > GetAbsBounds ( ) , phys - > GetClipMask ( ) , clipModels , MAX_GENTITIES ) ;
for ( i = 0 ; i < num ; i + + ) {
cm = clipModels [ i ] ;
// don't check render entities
if ( cm - > IsRenderModel ( ) ) {
continue ;
}
hit = cm - > GetEntity ( ) ;
if ( ( hit = = ent ) | | ! hit - > fl . takedamage ) {
continue ;
}
if ( ! phys - > ClipContents ( cm ) ) {
continue ;
}
// nail it
if ( hit - > IsType ( idPlayer : : Type ) & & static_cast < idPlayer * > ( hit ) - > IsInTeleport ( ) ) {
static_cast < idPlayer * > ( hit ) - > TeleportDeath ( ent - > entityNumber ) ;
} else if ( ! catch_teleport ) {
hit - > Damage ( ent , ent , vec3_origin , " damage_telefrag " , 1.0f , INVALID_JOINT ) ;
}
if ( ! gameLocal . isMultiplayer ) {
// let the mapper know about it
Warning ( " '%s' telefragged '%s' " , ent - > name . c_str ( ) , hit - > name . c_str ( ) ) ;
}
}
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : RequirementMet
= = = = = = = = = = = = = = = =
*/
bool idGameLocal : : RequirementMet ( idEntity * activator , const idStr & requires , int removeItem ) {
if ( requires . Length ( ) ) {
if ( activator - > IsType ( idPlayer : : Type ) ) {
idPlayer * player = static_cast < idPlayer * > ( activator ) ;
idDict * item = player - > FindInventoryItem ( requires ) ;
if ( item ) {
if ( removeItem ) {
player - > RemoveInventoryItem ( item ) ;
}
return true ;
} else {
return false ;
}
}
}
return true ;
}
/*
= = = = = = = = = = = =
idGameLocal : : AlertAI
= = = = = = = = = = = =
*/
void idGameLocal : : AlertAI ( idEntity * ent ) {
if ( ent & & ent - > IsType ( idActor : : Type ) ) {
// alert them for the next frame
lastAIAlertTime = time + msec ;
lastAIAlertEntity = static_cast < idActor * > ( ent ) ;
}
}
/*
= = = = = = = = = = = =
idGameLocal : : GetAlertEntity
= = = = = = = = = = = =
*/
idActor * idGameLocal : : GetAlertEntity ( void ) {
# ifdef _D3XP
int timeGroup = 0 ;
if ( lastAIAlertTime & & lastAIAlertEntity . GetEntity ( ) ) {
timeGroup = lastAIAlertEntity . GetEntity ( ) - > timeGroup ;
}
SetTimeState ts ( timeGroup ) ;
# endif
if ( lastAIAlertTime > = time ) {
return lastAIAlertEntity . GetEntity ( ) ;
}
return NULL ;
}
/*
= = = = = = = = = = = =
idGameLocal : : RadiusDamage
= = = = = = = = = = = =
*/
void idGameLocal : : RadiusDamage ( const idVec3 & origin , idEntity * inflictor , idEntity * attacker , idEntity * ignoreDamage , idEntity * ignorePush , const char * damageDefName , float dmgPower ) {
float dist , damageScale , attackerDamageScale , attackerPushScale ;
idEntity * ent ;
idEntity * entityList [ MAX_GENTITIES ] ;
int numListedEntities ;
idBounds bounds ;
2011-12-06 18:20:15 +00:00
idVec3 v , damagePoint , dir ;
2011-11-22 21:28:15 +00:00
int i , e , damage , radius , push ;
const idDict * damageDef = FindEntityDefDict ( damageDefName , false ) ;
if ( ! damageDef ) {
Warning ( " Unknown damageDef '%s' " , damageDefName ) ;
return ;
}
damageDef - > GetInt ( " damage " , " 20 " , damage ) ;
damageDef - > GetInt ( " radius " , " 50 " , radius ) ;
damageDef - > GetInt ( " push " , va ( " %d " , damage * 100 ) , push ) ;
damageDef - > GetFloat ( " attackerDamageScale " , " 0.5 " , attackerDamageScale ) ;
damageDef - > GetFloat ( " attackerPushScale " , " 0 " , attackerPushScale ) ;
if ( radius < 1 ) {
radius = 1 ;
}
bounds = idBounds ( origin ) . Expand ( radius ) ;
// get all entities touching the bounds
numListedEntities = clip . EntitiesTouchingBounds ( bounds , - 1 , entityList , MAX_GENTITIES ) ;
if ( inflictor & & inflictor - > IsType ( idAFAttachment : : Type ) ) {
inflictor = static_cast < idAFAttachment * > ( inflictor ) - > GetBody ( ) ;
}
if ( attacker & & attacker - > IsType ( idAFAttachment : : Type ) ) {
attacker = static_cast < idAFAttachment * > ( attacker ) - > GetBody ( ) ;
}
if ( ignoreDamage & & ignoreDamage - > IsType ( idAFAttachment : : Type ) ) {
ignoreDamage = static_cast < idAFAttachment * > ( ignoreDamage ) - > GetBody ( ) ;
}
// apply damage to the entities
for ( e = 0 ; e < numListedEntities ; e + + ) {
ent = entityList [ e ] ;
assert ( ent ) ;
if ( ! ent - > fl . takedamage ) {
continue ;
}
if ( ent = = inflictor | | ( ent - > IsType ( idAFAttachment : : Type ) & & static_cast < idAFAttachment * > ( ent ) - > GetBody ( ) = = inflictor ) ) {
continue ;
}
if ( ent = = ignoreDamage | | ( ent - > IsType ( idAFAttachment : : Type ) & & static_cast < idAFAttachment * > ( ent ) - > GetBody ( ) = = ignoreDamage ) ) {
continue ;
}
// don't damage a dead player
if ( isMultiplayer & & ent - > entityNumber < MAX_CLIENTS & & ent - > IsType ( idPlayer : : Type ) & & static_cast < idPlayer * > ( ent ) - > health < 0 ) {
continue ;
}
// find the distance from the edge of the bounding box
for ( i = 0 ; i < 3 ; i + + ) {
if ( origin [ i ] < ent - > GetPhysics ( ) - > GetAbsBounds ( ) [ 0 ] [ i ] ) {
v [ i ] = ent - > GetPhysics ( ) - > GetAbsBounds ( ) [ 0 ] [ i ] - origin [ i ] ;
} else if ( origin [ i ] > ent - > GetPhysics ( ) - > GetAbsBounds ( ) [ 1 ] [ i ] ) {
v [ i ] = origin [ i ] - ent - > GetPhysics ( ) - > GetAbsBounds ( ) [ 1 ] [ i ] ;
} else {
v [ i ] = 0 ;
}
}
dist = v . Length ( ) ;
if ( dist > = radius ) {
continue ;
}
if ( ent - > CanDamage ( origin , damagePoint ) ) {
// push the center of mass higher than the origin so players
// get knocked into the air more
dir = ent - > GetPhysics ( ) - > GetOrigin ( ) - origin ;
dir [ 2 ] + = 24 ;
// get the damage scale
damageScale = dmgPower * ( 1.0f - dist / radius ) ;
if ( ent = = attacker | | ( ent - > IsType ( idAFAttachment : : Type ) & & static_cast < idAFAttachment * > ( ent ) - > GetBody ( ) = = attacker ) ) {
damageScale * = attackerDamageScale ;
}
ent - > Damage ( inflictor , attacker , dir , damageDefName , damageScale , INVALID_JOINT ) ;
2011-12-06 18:20:15 +00:00
}
2011-11-22 21:28:15 +00:00
}
// push physics objects
if ( push ) {
RadiusPush ( origin , radius , push * dmgPower , attacker , ignorePush , attackerPushScale , false ) ;
}
}
/*
= = = = = = = = = = = = = =
idGameLocal : : RadiusPush
= = = = = = = = = = = = = =
*/
void idGameLocal : : RadiusPush ( const idVec3 & origin , const float radius , const float push , const idEntity * inflictor , const idEntity * ignore , float inflictorScale , const bool quake ) {
int i , numListedClipModels ;
idClipModel * clipModel ;
idClipModel * clipModelList [ MAX_GENTITIES ] ;
idVec3 dir ;
idBounds bounds ;
modelTrace_t result ;
idEntity * ent ;
float scale ;
dir . Set ( 0.0f , 0.0f , 1.0f ) ;
bounds = idBounds ( origin ) . Expand ( radius ) ;
// get all clip models touching the bounds
numListedClipModels = clip . ClipModelsTouchingBounds ( bounds , - 1 , clipModelList , MAX_GENTITIES ) ;
if ( inflictor & & inflictor - > IsType ( idAFAttachment : : Type ) ) {
inflictor = static_cast < const idAFAttachment * > ( inflictor ) - > GetBody ( ) ;
}
if ( ignore & & ignore - > IsType ( idAFAttachment : : Type ) ) {
ignore = static_cast < const idAFAttachment * > ( ignore ) - > GetBody ( ) ;
}
// apply impact to all the clip models through their associated physics objects
for ( i = 0 ; i < numListedClipModels ; i + + ) {
clipModel = clipModelList [ i ] ;
// never push render models
if ( clipModel - > IsRenderModel ( ) ) {
continue ;
}
ent = clipModel - > GetEntity ( ) ;
// never push projectiles
if ( ent - > IsType ( idProjectile : : Type ) ) {
continue ;
}
// players use "knockback" in idPlayer::Damage
if ( ent - > IsType ( idPlayer : : Type ) & & ! quake ) {
continue ;
}
// don't push the ignore entity
if ( ent = = ignore | | ( ent - > IsType ( idAFAttachment : : Type ) & & static_cast < idAFAttachment * > ( ent ) - > GetBody ( ) = = ignore ) ) {
continue ;
}
if ( gameRenderWorld - > FastWorldTrace ( result , origin , clipModel - > GetOrigin ( ) ) ) {
continue ;
}
// scale the push for the inflictor
if ( ent = = inflictor | | ( ent - > IsType ( idAFAttachment : : Type ) & & static_cast < idAFAttachment * > ( ent ) - > GetBody ( ) = = inflictor ) ) {
scale = inflictorScale ;
} else {
scale = 1.0f ;
}
if ( quake ) {
clipModel - > GetEntity ( ) - > ApplyImpulse ( world , clipModel - > GetId ( ) , clipModel - > GetOrigin ( ) , scale * push * dir ) ;
} else {
RadiusPushClipModel ( origin , scale * push , clipModel ) ;
}
}
}
/*
= = = = = = = = = = = = = =
idGameLocal : : RadiusPushClipModel
= = = = = = = = = = = = = =
*/
void idGameLocal : : RadiusPushClipModel ( const idVec3 & origin , const float push , const idClipModel * clipModel ) {
int i , j ;
float dot , dist , area ;
const idTraceModel * trm ;
const traceModelPoly_t * poly ;
idFixedWinding w ;
idVec3 v , localOrigin , center , impulse ;
trm = clipModel - > GetTraceModel ( ) ;
if ( ! trm | | 1 ) {
impulse = clipModel - > GetAbsBounds ( ) . GetCenter ( ) - origin ;
impulse . Normalize ( ) ;
impulse . z + = 1.0f ;
clipModel - > GetEntity ( ) - > ApplyImpulse ( world , clipModel - > GetId ( ) , clipModel - > GetOrigin ( ) , push * impulse ) ;
return ;
}
localOrigin = ( origin - clipModel - > GetOrigin ( ) ) * clipModel - > GetAxis ( ) . Transpose ( ) ;
for ( i = 0 ; i < trm - > numPolys ; i + + ) {
poly = & trm - > polys [ i ] ;
center . Zero ( ) ;
for ( j = 0 ; j < poly - > numEdges ; j + + ) {
v = trm - > verts [ trm - > edges [ abs ( poly - > edges [ j ] ) ] . v [ INTSIGNBITSET ( poly - > edges [ j ] ) ] ] ;
center + = v ;
v - = localOrigin ;
v . NormalizeFast ( ) ; // project point on a unit sphere
w . AddPoint ( v ) ;
}
center / = poly - > numEdges ;
v = center - localOrigin ;
dist = v . NormalizeFast ( ) ;
dot = v * poly - > normal ;
if ( dot > 0.0f ) {
continue ;
}
area = w . GetArea ( ) ;
// impulse in polygon normal direction
impulse = poly - > normal * clipModel - > GetAxis ( ) ;
// always push up for nicer effect
impulse . z - = 1.0f ;
// scale impulse based on visible surface area and polygon angle
impulse * = push * ( dot * area * ( 1.0f / ( 4.0f * idMath : : PI ) ) ) ;
// scale away distance for nicer effect
impulse * = ( dist * 2.0f ) ;
// impulse is applied to the center of the polygon
center = clipModel - > GetOrigin ( ) + center * clipModel - > GetAxis ( ) ;
clipModel - > GetEntity ( ) - > ApplyImpulse ( world , clipModel - > GetId ( ) , center , impulse ) ;
}
}
/*
= = = = = = = = = = = = = = =
idGameLocal : : ProjectDecal
= = = = = = = = = = = = = = =
*/
void idGameLocal : : ProjectDecal ( const idVec3 & origin , const idVec3 & dir , float depth , bool parallel , float size , const char * material , float angle ) {
float s , c ;
idMat3 axis , axistemp ;
idFixedWinding winding ;
idVec3 windingOrigin , projectionOrigin ;
static idVec3 decalWinding [ 4 ] = {
idVec3 ( 1.0f , 1.0f , 0.0f ) ,
idVec3 ( - 1.0f , 1.0f , 0.0f ) ,
idVec3 ( - 1.0f , - 1.0f , 0.0f ) ,
idVec3 ( 1.0f , - 1.0f , 0.0f )
} ;
if ( ! g_decals . GetBool ( ) ) {
return ;
}
// randomly rotate the decal winding
idMath : : SinCos16 ( ( angle ) ? angle : random . RandomFloat ( ) * idMath : : TWO_PI , s , c ) ;
// winding orientation
axis [ 2 ] = dir ;
axis [ 2 ] . Normalize ( ) ;
axis [ 2 ] . NormalVectors ( axistemp [ 0 ] , axistemp [ 1 ] ) ;
axis [ 0 ] = axistemp [ 0 ] * c + axistemp [ 1 ] * - s ;
axis [ 1 ] = axistemp [ 0 ] * - s + axistemp [ 1 ] * - c ;
windingOrigin = origin + depth * axis [ 2 ] ;
if ( parallel ) {
projectionOrigin = origin - depth * axis [ 2 ] ;
} else {
projectionOrigin = origin ;
}
size * = 0.5f ;
winding . Clear ( ) ;
winding + = idVec5 ( windingOrigin + ( axis * decalWinding [ 0 ] ) * size , idVec2 ( 1 , 1 ) ) ;
winding + = idVec5 ( windingOrigin + ( axis * decalWinding [ 1 ] ) * size , idVec2 ( 0 , 1 ) ) ;
winding + = idVec5 ( windingOrigin + ( axis * decalWinding [ 2 ] ) * size , idVec2 ( 0 , 0 ) ) ;
winding + = idVec5 ( windingOrigin + ( axis * decalWinding [ 3 ] ) * size , idVec2 ( 1 , 0 ) ) ;
gameRenderWorld - > ProjectDecalOntoWorld ( winding , projectionOrigin , parallel , depth * 0.5f , declManager - > FindMaterial ( material ) , gameLocal . slow . time /* _D3XP */ ) ;
}
/*
= = = = = = = = = = = = = =
idGameLocal : : BloodSplat
= = = = = = = = = = = = = =
*/
void idGameLocal : : BloodSplat ( const idVec3 & origin , const idVec3 & dir , float size , const char * material ) {
float halfSize = size * 0.5f ;
idVec3 verts [ ] = { idVec3 ( 0.0f , + halfSize , + halfSize ) ,
idVec3 ( 0.0f , + halfSize , - halfSize ) ,
idVec3 ( 0.0f , - halfSize , - halfSize ) ,
idVec3 ( 0.0f , - halfSize , + halfSize ) } ;
idTraceModel trm ;
idClipModel mdl ;
trace_t results ;
// FIXME: get from damage def
if ( ! g_bloodEffects . GetBool ( ) ) {
return ;
}
size = halfSize + random . RandomFloat ( ) * halfSize ;
trm . SetupPolygon ( verts , 4 ) ;
mdl . LoadModel ( trm ) ;
clip . Translation ( results , origin , origin + dir * 64.0f , & mdl , mat3_identity , CONTENTS_SOLID , NULL ) ;
ProjectDecal ( results . endpos , dir , 2.0f * size , true , size , material ) ;
}
/*
= = = = = = = = = = = = =
idGameLocal : : SetCamera
= = = = = = = = = = = = =
*/
void idGameLocal : : SetCamera ( idCamera * cam ) {
int i ;
idEntity * ent ;
idAI * ai ;
// this should fix going into a cinematic when dead.. rare but happens
idPlayer * client = GetLocalPlayer ( ) ;
if ( client - > health < = 0 | | client - > AI_DEAD ) {
return ;
}
camera = cam ;
if ( camera ) {
inCinematic = true ;
if ( skipCinematic & & camera - > spawnArgs . GetBool ( " disconnect " ) ) {
camera - > spawnArgs . SetBool ( " disconnect " , false ) ;
cvarSystem - > SetCVarFloat ( " r_znear " , 3.0f ) ;
cmdSystem - > BufferCommandText ( CMD_EXEC_APPEND , " disconnect \n " ) ;
skipCinematic = false ;
return ;
}
if ( time > cinematicStopTime ) {
cinematicSkipTime = time + CINEMATIC_SKIP_DELAY ;
}
// set r_znear so that transitioning into/out of the player's head doesn't clip through the view
cvarSystem - > SetCVarFloat ( " r_znear " , 1.0f ) ;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
// hide all the player models
for ( i = 0 ; i < numClients ; i + + ) {
if ( entities [ i ] ) {
client = static_cast < idPlayer * > ( entities [ i ] ) ;
client - > EnterCinematic ( ) ;
}
}
if ( ! cam - > spawnArgs . GetBool ( " ignore_enemies " ) ) {
// kill any active monsters that are enemies of the player
for ( ent = spawnedEntities . Next ( ) ; ent ! = NULL ; ent = ent - > spawnNode . Next ( ) ) {
if ( ent - > cinematic | | ent - > fl . isDormant ) {
// only kill entities that aren't needed for cinematics and aren't dormant
continue ;
}
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
if ( ent - > IsType ( idAI : : Type ) ) {
ai = static_cast < idAI * > ( ent ) ;
if ( ! ai - > GetEnemy ( ) | | ! ai - > IsActive ( ) ) {
// no enemy, or inactive, so probably safe to ignore
continue ;
}
} else if ( ent - > IsType ( idProjectile : : Type ) ) {
// remove all projectiles
} else if ( ent - > spawnArgs . GetBool ( " cinematic_remove " ) ) {
// remove anything marked to be removed during cinematics
} else {
// ignore everything else
continue ;
}
// remove it
DPrintf ( " removing '%s' for cinematic \n " , ent - > GetName ( ) ) ;
ent - > PostEventMS ( & EV_Remove , 0 ) ;
}
}
} else {
inCinematic = false ;
cinematicStopTime = time + msec ;
// restore r_znear
cvarSystem - > SetCVarFloat ( " r_znear " , 3.0f ) ;
// show all the player models
for ( i = 0 ; i < numClients ; i + + ) {
if ( entities [ i ] ) {
idPlayer * client = static_cast < idPlayer * > ( entities [ i ] ) ;
client - > ExitCinematic ( ) ;
}
}
}
}
/*
= = = = = = = = = = = = =
idGameLocal : : GetCamera
= = = = = = = = = = = = =
*/
idCamera * idGameLocal : : GetCamera ( void ) const {
return camera ;
}
/*
= = = = = = = = = = = = =
idGameLocal : : SkipCinematic
= = = = = = = = = = = = =
*/
bool idGameLocal : : SkipCinematic ( void ) {
if ( camera ) {
if ( camera - > spawnArgs . GetBool ( " disconnect " ) ) {
camera - > spawnArgs . SetBool ( " disconnect " , false ) ;
cvarSystem - > SetCVarFloat ( " r_znear " , 3.0f ) ;
cmdSystem - > BufferCommandText ( CMD_EXEC_APPEND , " disconnect \n " ) ;
skipCinematic = false ;
return false ;
}
if ( camera - > spawnArgs . GetBool ( " instantSkip " ) ) {
camera - > Stop ( ) ;
return false ;
}
}
soundSystem - > SetMute ( true ) ;
if ( ! skipCinematic ) {
skipCinematic = true ;
cinematicMaxSkipTime = gameLocal . time + SEC2MS ( g_cinematicMaxSkipTime . GetFloat ( ) ) ;
}
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = =
idGameLocal : : SpreadLocations
Now that everything has been spawned , associate areas with location entities
= = = = = = = = = = = = = = = = = = = = = =
*/
void idGameLocal : : SpreadLocations ( ) {
idEntity * ent ;
// allocate the area table
int numAreas = gameRenderWorld - > NumAreas ( ) ;
locationEntities = new idLocationEntity * [ numAreas ] ;
memset ( locationEntities , 0 , numAreas * sizeof ( * locationEntities ) ) ;
// for each location entity, make pointers from every area it touches
for ( ent = spawnedEntities . Next ( ) ; ent ! = NULL ; ent = ent - > spawnNode . Next ( ) ) {
if ( ! ent - > IsType ( idLocationEntity : : Type ) ) {
continue ;
}
idVec3 point = ent - > spawnArgs . GetVector ( " origin " ) ;
int areaNum = gameRenderWorld - > PointInArea ( point ) ;
if ( areaNum < 0 ) {
Printf ( " SpreadLocations: location '%s' is not in a valid area \n " , ent - > spawnArgs . GetString ( " name " ) ) ;
continue ;
}
if ( areaNum > = numAreas ) {
Error ( " idGameLocal::SpreadLocations: areaNum >= gameRenderWorld->NumAreas() " ) ;
}
if ( locationEntities [ areaNum ] ) {
Warning ( " location entity '%s' overlaps '%s' " , ent - > spawnArgs . GetString ( " name " ) ,
locationEntities [ areaNum ] - > spawnArgs . GetString ( " name " ) ) ;
continue ;
}
locationEntities [ areaNum ] = static_cast < idLocationEntity * > ( ent ) ;
// spread to all other connected areas
for ( int i = 0 ; i < numAreas ; i + + ) {
if ( i = = areaNum ) {
continue ;
}
if ( gameRenderWorld - > AreasAreConnected ( areaNum , i , PS_BLOCK_LOCATION ) ) {
locationEntities [ i ] = static_cast < idLocationEntity * > ( ent ) ;
}
}
}
}
/*
= = = = = = = = = = = = = = = = = = =
idGameLocal : : LocationForPoint
The player checks the location each frame to update the HUD text display
May return NULL
= = = = = = = = = = = = = = = = = = =
*/
idLocationEntity * idGameLocal : : LocationForPoint ( const idVec3 & point ) {
if ( ! locationEntities ) {
// before SpreadLocations() has been called
return NULL ;
}
int areaNum = gameRenderWorld - > PointInArea ( point ) ;
if ( areaNum < 0 ) {
return NULL ;
}
if ( areaNum > = gameRenderWorld - > NumAreas ( ) ) {
Error ( " idGameLocal::LocationForPoint: areaNum >= gameRenderWorld->NumAreas() " ) ;
}
return locationEntities [ areaNum ] ;
}
/*
= = = = = = = = = = = =
idGameLocal : : SetPortalState
= = = = = = = = = = = =
*/
void idGameLocal : : SetPortalState ( qhandle_t portal , int blockingBits ) {
idBitMsg outMsg ;
byte msgBuf [ MAX_GAME_MESSAGE_SIZE ] ;
if ( ! gameLocal . isClient ) {
outMsg . Init ( msgBuf , sizeof ( msgBuf ) ) ;
outMsg . WriteByte ( GAME_RELIABLE_MESSAGE_PORTAL ) ;
2012-06-28 11:15:40 +00:00
outMsg . WriteInt ( portal ) ;
2011-11-22 21:28:15 +00:00
outMsg . WriteBits ( blockingBits , NUM_RENDER_PORTAL_BITS ) ;
networkSystem - > ServerSendReliableMessage ( - 1 , outMsg ) ;
}
gameRenderWorld - > SetPortalState ( portal , blockingBits ) ;
}
/*
= = = = = = = = = = = =
idGameLocal : : sortSpawnPoints
= = = = = = = = = = = =
*/
int idGameLocal : : sortSpawnPoints ( const void * ptr1 , const void * ptr2 ) {
const spawnSpot_t * spot1 = static_cast < const spawnSpot_t * > ( ptr1 ) ;
const spawnSpot_t * spot2 = static_cast < const spawnSpot_t * > ( ptr2 ) ;
float diff ;
diff = spot1 - > dist - spot2 - > dist ;
if ( diff < 0.0f ) {
return 1 ;
} else if ( diff > 0.0f ) {
return - 1 ;
} else {
return 0 ;
}
}
/*
= = = = = = = = = = =
idGameLocal : : RandomizeInitialSpawns
randomize the order of the initial spawns
prepare for a sequence of initial player spawns
= = = = = = = = = = = =
*/
void idGameLocal : : RandomizeInitialSpawns ( void ) {
spawnSpot_t spot ;
int i , j ;
# ifdef CTF
int k ;
# endif
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
idEntity * ent ;
if ( ! isMultiplayer | | isClient ) {
return ;
}
spawnSpots . Clear ( ) ;
initialSpots . Clear ( ) ;
# ifdef CTF
teamSpawnSpots [ 0 ] . Clear ( ) ;
teamSpawnSpots [ 1 ] . Clear ( ) ;
teamInitialSpots [ 0 ] . Clear ( ) ;
teamInitialSpots [ 1 ] . Clear ( ) ;
# endif
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
spot . dist = 0 ;
spot . ent = FindEntityUsingDef ( NULL , " info_player_deathmatch " ) ;
while ( spot . ent ) {
# ifdef CTF
spot . ent - > spawnArgs . GetInt ( " team " , " -1 " , spot . team ) ;
if ( mpGame . IsGametypeFlagBased ( ) ) /* CTF */
{
if ( spot . team = = 0 | | spot . team = = 1 )
teamSpawnSpots [ spot . team ] . Append ( spot ) ;
else
common - > Warning ( " info_player_deathmatch : invalid or no team attached to spawn point \n " ) ;
}
2011-12-06 18:20:15 +00:00
# endif
2011-11-22 21:28:15 +00:00
spawnSpots . Append ( spot ) ;
if ( spot . ent - > spawnArgs . GetBool ( " initial " ) ) {
# ifdef CTF
if ( mpGame . IsGametypeFlagBased ( ) ) /* CTF */
{
assert ( spot . team = = 0 | | spot . team = = 1 ) ;
teamInitialSpots [ spot . team ] . Append ( spot . ent ) ;
}
# endif
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
initialSpots . Append ( spot . ent ) ;
}
spot . ent = FindEntityUsingDef ( spot . ent , " info_player_deathmatch " ) ;
}
# ifdef CTF
if ( mpGame . IsGametypeFlagBased ( ) ) /* CTF */
{
if ( ! teamSpawnSpots [ 0 ] . Num ( ) )
common - > Warning ( " red team : no info_player_deathmatch in map " ) ;
if ( ! teamSpawnSpots [ 1 ] . Num ( ) )
common - > Warning ( " blue team : no info_player_deathmatch in map " ) ;
if ( ! teamSpawnSpots [ 0 ] . Num ( ) | | ! teamSpawnSpots [ 1 ] . Num ( ) )
return ;
}
# endif
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
if ( ! spawnSpots . Num ( ) ) {
common - > Warning ( " no info_player_deathmatch in map " ) ;
return ;
}
# ifdef CTF
if ( mpGame . IsGametypeFlagBased ( ) ) /* CTF */
{
common - > Printf ( " red team : %d spawns (%d initials) \n " , teamSpawnSpots [ 0 ] . Num ( ) , teamInitialSpots [ 0 ] . Num ( ) ) ;
// if there are no initial spots in the map, consider they can all be used as initial
if ( ! teamInitialSpots [ 0 ] . Num ( ) ) {
common - > Warning ( " red team : no info_player_deathmatch entities marked initial in map " ) ;
for ( i = 0 ; i < teamSpawnSpots [ 0 ] . Num ( ) ; i + + ) {
teamInitialSpots [ 0 ] . Append ( teamSpawnSpots [ 0 ] [ i ] . ent ) ;
}
}
common - > Printf ( " blue team : %d spawns (%d initials) \n " , teamSpawnSpots [ 1 ] . Num ( ) , teamInitialSpots [ 1 ] . Num ( ) ) ;
// if there are no initial spots in the map, consider they can all be used as initial
if ( ! teamInitialSpots [ 1 ] . Num ( ) ) {
common - > Warning ( " blue team : no info_player_deathmatch entities marked initial in map " ) ;
for ( i = 0 ; i < teamSpawnSpots [ 1 ] . Num ( ) ; i + + ) {
teamInitialSpots [ 1 ] . Append ( teamSpawnSpots [ 1 ] [ i ] . ent ) ;
}
}
}
# endif
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
common - > Printf ( " %d spawns (%d initials) \n " , spawnSpots . Num ( ) , initialSpots . Num ( ) ) ;
// if there are no initial spots in the map, consider they can all be used as initial
if ( ! initialSpots . Num ( ) ) {
common - > Warning ( " no info_player_deathmatch entities marked initial in map " ) ;
for ( i = 0 ; i < spawnSpots . Num ( ) ; i + + ) {
initialSpots . Append ( spawnSpots [ i ] . ent ) ;
}
}
# ifdef CTF
for ( k = 0 ; k < 2 ; k + + )
for ( i = 0 ; i < teamInitialSpots [ k ] . Num ( ) ; i + + ) {
j = random . RandomInt ( teamInitialSpots [ k ] . Num ( ) ) ;
ent = teamInitialSpots [ k ] [ i ] ;
teamInitialSpots [ k ] [ i ] = teamInitialSpots [ k ] [ j ] ;
teamInitialSpots [ k ] [ j ] = ent ;
}
# endif
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
for ( i = 0 ; i < initialSpots . Num ( ) ; i + + ) {
j = random . RandomInt ( initialSpots . Num ( ) ) ;
ent = initialSpots [ i ] ;
initialSpots [ i ] = initialSpots [ j ] ;
initialSpots [ j ] = ent ;
}
// reset the counter
currentInitialSpot = 0 ;
# ifdef CTF
teamCurrentInitialSpot [ 0 ] = 0 ;
teamCurrentInitialSpot [ 1 ] = 0 ;
# endif
}
/*
= = = = = = = = = = =
idGameLocal : : SelectInitialSpawnPoint
spectators are spawned randomly anywhere
in - game clients are spawned based on distance to active players ( randomized on the first half )
upon map restart , initial spawns are used ( randomized ordered list of spawns flagged " initial " )
if there are more players than initial spots , overflow to regular spawning
= = = = = = = = = = = =
*/
idEntity * idGameLocal : : SelectInitialSpawnPoint ( idPlayer * player ) {
int i , j , which ;
spawnSpot_t spot ;
idVec3 pos ;
float dist ;
bool alone ;
# ifdef CTF
if ( ! isMultiplayer | | ! spawnSpots . Num ( ) | | ( mpGame . IsGametypeFlagBased ( ) & & ( ! teamSpawnSpots [ 0 ] . Num ( ) | | ! teamSpawnSpots [ 1 ] . Num ( ) ) ) ) { /* CTF */
# else
if ( ! isMultiplayer | | ! spawnSpots . Num ( ) ) {
# endif
spot . ent = FindEntityUsingDef ( NULL , " info_player_start " ) ;
if ( ! spot . ent ) {
Error ( " No info_player_start on map. \n " ) ;
}
return spot . ent ;
}
# ifdef CTF
bool useInitialSpots = false ;
if ( mpGame . IsGametypeFlagBased ( ) ) { /* CTF */
assert ( player - > team = = 0 | | player - > team = = 1 ) ;
useInitialSpots = player - > useInitialSpawns & & teamCurrentInitialSpot [ player - > team ] < teamInitialSpots [ player - > team ] . Num ( ) ;
} else {
useInitialSpots = player - > useInitialSpawns & & currentInitialSpot < initialSpots . Num ( ) ;
}
# endif
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
if ( player - > spectating ) {
// plain random spot, don't bother
return spawnSpots [ random . RandomInt ( spawnSpots . Num ( ) ) ] . ent ;
# ifdef CTF
} else if ( useInitialSpots ) {
if ( mpGame . IsGametypeFlagBased ( ) ) { /* CTF */
assert ( player - > team = = 0 | | player - > team = = 1 ) ;
player - > useInitialSpawns = false ; // only use the initial spawn once
return teamInitialSpots [ player - > team ] [ teamCurrentInitialSpot [ player - > team ] + + ] ;
}
return initialSpots [ currentInitialSpot + + ] ;
# else
} else if ( player - > useInitialSpawns & & currentInitialSpot < initialSpots . Num ( ) ) {
return initialSpots [ currentInitialSpot + + ] ;
# endif
} else {
// check if we are alone in map
alone = true ;
for ( j = 0 ; j < MAX_CLIENTS ; j + + ) {
if ( entities [ j ] & & entities [ j ] ! = player ) {
alone = false ;
break ;
}
}
if ( alone ) {
# ifdef CTF
if ( mpGame . IsGametypeFlagBased ( ) ) /* CTF */
{
assert ( player - > team = = 0 | | player - > team = = 1 ) ;
return teamSpawnSpots [ player - > team ] [ random . RandomInt ( teamSpawnSpots [ player - > team ] . Num ( ) ) ] . ent ;
}
# endif
// don't do distance-based
return spawnSpots [ random . RandomInt ( spawnSpots . Num ( ) ) ] . ent ;
}
# ifdef CTF
if ( mpGame . IsGametypeFlagBased ( ) ) /* CTF */
{
// TODO : make as reusable method, same code as below
int team = player - > team ;
assert ( team = = 0 | | team = = 1 ) ;
// find the distance to the closest active player for each spawn spot
for ( i = 0 ; i < teamSpawnSpots [ team ] . Num ( ) ; i + + ) {
pos = teamSpawnSpots [ team ] [ i ] . ent - > GetPhysics ( ) - > GetOrigin ( ) ;
// skip initial spawn points for CTF
if ( teamSpawnSpots [ team ] [ i ] . ent - > spawnArgs . GetBool ( " initial " ) ) {
teamSpawnSpots [ team ] [ i ] . dist = 0x0 ;
continue ;
}
teamSpawnSpots [ team ] [ i ] . dist = 0x7fffffff ;
for ( j = 0 ; j < MAX_CLIENTS ; j + + ) {
if ( ! entities [ j ] | | ! entities [ j ] - > IsType ( idPlayer : : Type )
| | entities [ j ] = = player
| | static_cast < idPlayer * > ( entities [ j ] ) - > spectating ) {
continue ;
}
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
dist = ( pos - entities [ j ] - > GetPhysics ( ) - > GetOrigin ( ) ) . LengthSqr ( ) ;
if ( dist < teamSpawnSpots [ team ] [ i ] . dist ) {
teamSpawnSpots [ team ] [ i ] . dist = dist ;
}
}
}
// sort the list
qsort ( ( void * ) teamSpawnSpots [ team ] . Ptr ( ) , teamSpawnSpots [ team ] . Num ( ) , sizeof ( spawnSpot_t ) , ( int ( * ) ( const void * , const void * ) ) sortSpawnPoints ) ;
// choose a random one in the top half
which = random . RandomInt ( teamSpawnSpots [ team ] . Num ( ) / 2 ) ;
spot = teamSpawnSpots [ team ] [ which ] ;
// assert( teamSpawnSpots[ team ][ which ].dist != 0 );
return spot . ent ;
}
# endif
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
// find the distance to the closest active player for each spawn spot
for ( i = 0 ; i < spawnSpots . Num ( ) ; i + + ) {
pos = spawnSpots [ i ] . ent - > GetPhysics ( ) - > GetOrigin ( ) ;
spawnSpots [ i ] . dist = 0x7fffffff ;
for ( j = 0 ; j < MAX_CLIENTS ; j + + ) {
if ( ! entities [ j ] | | ! entities [ j ] - > IsType ( idPlayer : : Type )
| | entities [ j ] = = player
| | static_cast < idPlayer * > ( entities [ j ] ) - > spectating ) {
continue ;
}
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
dist = ( pos - entities [ j ] - > GetPhysics ( ) - > GetOrigin ( ) ) . LengthSqr ( ) ;
if ( dist < spawnSpots [ i ] . dist ) {
spawnSpots [ i ] . dist = dist ;
}
}
}
// sort the list
qsort ( ( void * ) spawnSpots . Ptr ( ) , spawnSpots . Num ( ) , sizeof ( spawnSpot_t ) , ( int ( * ) ( const void * , const void * ) ) sortSpawnPoints ) ;
// choose a random one in the top half
which = random . RandomInt ( spawnSpots . Num ( ) / 2 ) ;
spot = spawnSpots [ which ] ;
}
return spot . ent ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : UpdateServerInfoFlags
= = = = = = = = = = = = = = = =
*/
void idGameLocal : : UpdateServerInfoFlags ( ) {
gameType = GAME_SP ;
if ( ( idStr : : Icmp ( serverInfo . GetString ( " si_gameType " ) , " deathmatch " ) = = 0 ) ) {
gameType = GAME_DM ;
} else if ( ( idStr : : Icmp ( serverInfo . GetString ( " si_gameType " ) , " Tourney " ) = = 0 ) ) {
gameType = GAME_TOURNEY ;
} else if ( ( idStr : : Icmp ( serverInfo . GetString ( " si_gameType " ) , " Team DM " ) = = 0 ) ) {
gameType = GAME_TDM ;
} else if ( ( idStr : : Icmp ( serverInfo . GetString ( " si_gameType " ) , " Last Man " ) = = 0 ) ) {
gameType = GAME_LASTMAN ;
}
# ifdef CTF
else if ( ( idStr : : Icmp ( serverInfo . GetString ( " si_gameType " ) , " CTF " ) = = 0 ) ) {
gameType = GAME_CTF ;
}
# endif
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
if ( gameType = = GAME_LASTMAN ) {
if ( ! serverInfo . GetInt ( " si_warmup " ) ) {
common - > Warning ( " Last Man Standing - forcing warmup on " ) ;
serverInfo . SetInt ( " si_warmup " , 1 ) ;
}
if ( serverInfo . GetInt ( " si_fraglimit " ) < = 0 ) {
common - > Warning ( " Last Man Standing - setting fraglimit 1 " ) ;
serverInfo . SetInt ( " si_fraglimit " , 1 ) ;
}
}
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : SetGlobalMaterial
= = = = = = = = = = = = = = = =
*/
void idGameLocal : : SetGlobalMaterial ( const idMaterial * mat ) {
globalMaterial = mat ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : GetGlobalMaterial
= = = = = = = = = = = = = = = =
*/
const idMaterial * idGameLocal : : GetGlobalMaterial ( ) {
return globalMaterial ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : GetSpawnId
= = = = = = = = = = = = = = = =
*/
int idGameLocal : : GetSpawnId ( const idEntity * ent ) const {
return ( gameLocal . spawnIds [ ent - > entityNumber ] < < GENTITYNUM_BITS ) | ent - > entityNumber ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : ThrottleUserInfo
= = = = = = = = = = = = = = = =
*/
void idGameLocal : : ThrottleUserInfo ( void ) {
mpGame . ThrottleUserInfo ( ) ;
}
# ifdef _D3XP
/*
= = = = = = = = = = = = = = = = =
idPlayer : : SetPortalSkyEnt
= = = = = = = = = = = = = = = = =
*/
void idGameLocal : : SetPortalSkyEnt ( idEntity * ent ) {
portalSkyEnt = ent ;
}
/*
= = = = = = = = = = = = = = = = =
idPlayer : : IsPortalSkyAcive
= = = = = = = = = = = = = = = = =
*/
bool idGameLocal : : IsPortalSkyAcive ( ) {
return portalSkyActive ;
}
/*
= = = = = = = = = = =
idGameLocal : : SelectTimeGroup
= = = = = = = = = = = =
*/
void idGameLocal : : SelectTimeGroup ( int timeGroup ) {
if ( timeGroup ) {
fast . Get ( time , previousTime , msec , framenum , realClientTime ) ;
} else {
slow . Get ( time , previousTime , msec , framenum , realClientTime ) ;
}
}
/*
= = = = = = = = = = =
idGameLocal : : GetTimeGroupTime
= = = = = = = = = = = =
*/
int idGameLocal : : GetTimeGroupTime ( int timeGroup ) {
if ( timeGroup ) {
return fast . time ;
} else {
return slow . time ;
}
}
/*
= = = = = = = = = = = = = = =
idGameLocal : : GetBestGameType
= = = = = = = = = = = = = = =
*/
void idGameLocal : : GetBestGameType ( const char * map , const char * gametype , char buf [ MAX_STRING_CHARS ] ) {
idStr aux = mpGame . GetBestGametype ( map , gametype ) ;
2022-05-17 01:23:12 +00:00
idStr : : Copynz ( buf , aux . c_str ( ) , MAX_STRING_CHARS ) ;
2011-11-22 21:28:15 +00:00
buf [ MAX_STRING_CHARS - 1 ] = ' \0 ' ;
}
/*
= = = = = = = = = = =
idGameLocal : : ComputeSlowMsec
= = = = = = = = = = = =
*/
void idGameLocal : : ComputeSlowMsec ( ) {
idPlayer * player ;
bool powerupOn ;
float delta ;
// check if we need to do a quick reset
if ( quickSlowmoReset ) {
quickSlowmoReset = false ;
// stop the sounds
if ( gameSoundWorld ) {
gameSoundWorld - > SetSlowmo ( false ) ;
gameSoundWorld - > SetSlowmoSpeed ( 1 ) ;
}
// stop the state
slowmoState = SLOWMO_STATE_OFF ;
slowmoMsec = USERCMD_MSEC ;
}
// check the player state
player = GetLocalPlayer ( ) ;
powerupOn = false ;
if ( player & & player - > PowerUpActive ( HELLTIME ) ) {
powerupOn = true ;
}
else if ( g_enableSlowmo . GetBool ( ) ) {
powerupOn = true ;
}
// determine proper slowmo state
if ( powerupOn & & slowmoState = = SLOWMO_STATE_OFF ) {
slowmoState = SLOWMO_STATE_RAMPUP ;
slowmoMsec = msec ;
if ( gameSoundWorld ) {
gameSoundWorld - > SetSlowmo ( true ) ;
gameSoundWorld - > SetSlowmoSpeed ( slowmoMsec / ( float ) USERCMD_MSEC ) ;
}
}
else if ( ! powerupOn & & slowmoState = = SLOWMO_STATE_ON ) {
slowmoState = SLOWMO_STATE_RAMPDOWN ;
// play the stop sound
if ( player ) {
player - > PlayHelltimeStopSound ( ) ;
}
}
// do any necessary ramping
if ( slowmoState = = SLOWMO_STATE_RAMPUP ) {
delta = 4 - slowmoMsec ;
if ( fabs ( delta ) < g_slowmoStepRate . GetFloat ( ) ) {
slowmoMsec = 4 ;
slowmoState = SLOWMO_STATE_ON ;
}
else {
slowmoMsec + = delta * g_slowmoStepRate . GetFloat ( ) ;
}
if ( gameSoundWorld ) {
gameSoundWorld - > SetSlowmoSpeed ( slowmoMsec / ( float ) USERCMD_MSEC ) ;
}
}
else if ( slowmoState = = SLOWMO_STATE_RAMPDOWN ) {
delta = 16 - slowmoMsec ;
if ( fabs ( delta ) < g_slowmoStepRate . GetFloat ( ) ) {
slowmoMsec = 16 ;
slowmoState = SLOWMO_STATE_OFF ;
if ( gameSoundWorld ) {
gameSoundWorld - > SetSlowmo ( false ) ;
}
}
else {
slowmoMsec + = delta * g_slowmoStepRate . GetFloat ( ) ;
}
if ( gameSoundWorld ) {
gameSoundWorld - > SetSlowmoSpeed ( slowmoMsec / ( float ) USERCMD_MSEC ) ;
}
}
}
/*
= = = = = = = = = = =
idGameLocal : : ResetSlowTimeVars
= = = = = = = = = = = =
*/
void idGameLocal : : ResetSlowTimeVars ( ) {
msec = USERCMD_MSEC ;
slowmoMsec = USERCMD_MSEC ;
slowmoState = SLOWMO_STATE_OFF ;
fast . framenum = 0 ;
fast . previousTime = 0 ;
fast . time = 0 ;
fast . msec = USERCMD_MSEC ;
slow . framenum = 0 ;
slow . previousTime = 0 ;
slow . time = 0 ;
slow . msec = USERCMD_MSEC ;
}
/*
= = = = = = = = = = =
idGameLocal : : QuickSlowmoReset
= = = = = = = = = = = =
*/
void idGameLocal : : QuickSlowmoReset ( ) {
quickSlowmoReset = true ;
}
/*
= = = = = = = = = = = = = = =
idGameLocal : : NeedRestart
= = = = = = = = = = = = = = =
*/
bool idGameLocal : : NeedRestart ( ) {
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
idDict newInfo ;
const idKeyValue * keyval , * keyval2 ;
newInfo = * cvarSystem - > MoveCVarsToDict ( CVAR_SERVERINFO ) ;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
for ( int i = 0 ; i < newInfo . GetNumKeyVals ( ) ; i + + ) {
keyval = newInfo . GetKeyVal ( i ) ;
keyval2 = serverInfo . FindKey ( keyval - > GetKey ( ) ) ;
if ( ! keyval2 ) {
return true ;
}
// a select set of si_ changes will cause a full restart of the server
if ( keyval - > GetValue ( ) . Cmp ( keyval2 - > GetValue ( ) ) & & ( ! keyval - > GetKey ( ) . Cmp ( " si_pure " ) | | ! keyval - > GetKey ( ) . Cmp ( " si_map " ) ) ) {
return true ;
}
}
return false ;
}
# endif
/*
= = = = = = = = = = = = = = = =
idGameLocal : : GetClientStats
= = = = = = = = = = = = = = = =
*/
void idGameLocal : : GetClientStats ( int clientNum , char * data , const int len ) {
mpGame . PlayerStats ( clientNum , data , len ) ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : SwitchTeam
= = = = = = = = = = = = = = = =
*/
void idGameLocal : : SwitchTeam ( int clientNum , int team ) {
idPlayer * player ;
player = static_cast < idPlayer * > ( entities [ clientNum ] ) ;
int oldTeam = player - > team ;
// Put in spectator mode
if ( team = = - 1 ) {
static_cast < idPlayer * > ( entities [ clientNum ] ) - > Spectate ( true ) ;
}
// Switch to a team
else {
mpGame . SwitchToTeam ( clientNum , oldTeam , team ) ;
}
player - > forceRespawn = true ;
}
/*
= = = = = = = = = = = = = = =
idGameLocal : : GetMapLoadingGUI
= = = = = = = = = = = = = = =
*/
void idGameLocal : : GetMapLoadingGUI ( char gui [ MAX_STRING_CHARS ] ) { }