doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Game_local.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 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.
23 
24 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.
25 
26 ===========================================================================
27 */
28 
29 #include "../idlib/precompiled.h"
30 #pragma hdrstop
31 
32 #include "Game_local.h"
33 
34 #ifdef GAME_DLL
35 
36 idSys * sys = NULL;
37 idCommon * common = NULL;
50 
51 idCVar com_forceGenericSIMD( "com_forceGenericSIMD", "0", CVAR_BOOL|CVAR_SYSTEM, "force generic platform independent SIMD" );
52 
53 #endif
54 
55 idRenderWorld * gameRenderWorld = NULL; // all drawing is done to this world
56 idSoundWorld * gameSoundWorld = NULL; // all audio goes to this world
57 
58 static gameExport_t gameExport;
59 
60 // global animation lib
62 
63 // the rest of the engine will only reference the "game" variable, while all local aspects stay hidden
65 idGame * game = &gameLocal; // statically pointed at an idGameLocal
66 
68  "none", "metal", "stone", "flesh", "wood", "cardboard", "liquid", "glass", "plastic",
69  "ricochet", "surftype10", "surftype11", "surftype12", "surftype13", "surftype14", "surftype15"
70 };
71 
72 #ifdef _D3XP
73 // List of all defs used by the player that will stay on the fast timeline
74 static const char* fastEntityList[] = {
75  "player_doommarine",
76  "weapon_chainsaw",
77  "weapon_fists",
78  "weapon_flashlight",
79  "weapon_rocketlauncher",
80  "projectile_rocket",
81  "weapon_machinegun",
82  "projectile_bullet_machinegun",
83  "weapon_pistol",
84  "projectile_bullet_pistol",
85  "weapon_handgrenade",
86  "projectile_grenade",
87  "weapon_bfg",
88  "projectile_bfg",
89  "weapon_chaingun",
90  "projectile_chaingunbullet",
91  "weapon_pda",
92  "weapon_plasmagun",
93  "projectile_plasmablast",
94  "weapon_shotgun",
95  "projectile_bullet_shotgun",
96  "weapon_soulcube",
97  "projectile_soulblast",
98  "weapon_shotgun_double",
99  "projectile_shotgunbullet_double",
100  "weapon_grabber",
101  "weapon_bloodstone_active1",
102  "weapon_bloodstone_active2",
103  "weapon_bloodstone_active3",
104  "weapon_bloodstone_passive",
105  NULL };
106 #endif
107 /*
108 ===========
109 GetGameAPI
110 ============
111 */
112 #if __MWERKS__
113 #pragma export on
114 #endif
115 #if __GNUC__ >= 4
116 #pragma GCC visibility push(default)
117 #endif
118 extern "C" gameExport_t *GetGameAPI( gameImport_t *import ) {
119 #if __MWERKS__
120 #pragma export off
121 #endif
122 
123  if ( import->version == GAME_API_VERSION ) {
124 
125  // set interface pointers used by the game
126  sys = import->sys;
127  common = import->common;
128  cmdSystem = import->cmdSystem;
129  cvarSystem = import->cvarSystem;
130  fileSystem = import->fileSystem;
131  networkSystem = import->networkSystem;
132  renderSystem = import->renderSystem;
133  soundSystem = import->soundSystem;
134  renderModelManager = import->renderModelManager;
135  uiManager = import->uiManager;
136  declManager = import->declManager;
137  AASFileManager = import->AASFileManager;
138  collisionModelManager = import->collisionModelManager;
139  }
140 
141  // set interface pointers used by idLib
142  idLib::sys = sys;
146 
147  // setup export interface
148  gameExport.version = GAME_API_VERSION;
149  gameExport.game = game;
150  gameExport.gameEdit = gameEdit;
151 
152  return &gameExport;
153 }
154 #if __GNUC__ >= 4
155 #pragma GCC visibility pop
156 #endif
157 
158 /*
159 ===========
160 TestGameAPI
161 ============
162 */
163 void TestGameAPI( void ) {
164  gameImport_t testImport;
165  gameExport_t testExport;
166 
167  testImport.sys = ::sys;
168  testImport.common = ::common;
169  testImport.cmdSystem = ::cmdSystem;
170  testImport.cvarSystem = ::cvarSystem;
171  testImport.fileSystem = ::fileSystem;
172  testImport.networkSystem = ::networkSystem;
173  testImport.renderSystem = ::renderSystem;
174  testImport.soundSystem = ::soundSystem;
176  testImport.uiManager = ::uiManager;
177  testImport.declManager = ::declManager;
178  testImport.AASFileManager = ::AASFileManager;
180 
181  testExport = *GetGameAPI( &testImport );
182 }
183 
184 /*
185 ===========
186 idGameLocal::idGameLocal
187 ============
188 */
190  Clear();
191 }
192 
193 /*
194 ===========
195 idGameLocal::Clear
196 ============
197 */
198 void idGameLocal::Clear( void ) {
199  int i;
200 
201  serverInfo.Clear();
202  numClients = 0;
203  for ( i = 0; i < MAX_CLIENTS; i++ ) {
204  userInfo[i].Clear();
206  }
207  memset( usercmds, 0, sizeof( usercmds ) );
208  memset( entities, 0, sizeof( entities ) );
209  memset( spawnIds, -1, sizeof( spawnIds ) );
210  firstFreeIndex = 0;
211  num_entities = 0;
215  sortPushers = false;
216  sortTeamMasters = false;
218  memset( globalShaderParms, 0, sizeof( globalShaderParms ) );
219  random.SetSeed( 0 );
220  world = NULL;
222  testmodel = NULL;
223  testFx = NULL;
224  clip.Shutdown();
225  pvs.Shutdown();
229  editEntities = NULL;
230  entityHash.Clear( 1024, MAX_GENTITIES );
231  inCinematic = false;
232  cinematicSkipTime = 0;
233  cinematicStopTime = 0;
235  framenum = 0;
236  previousTime = 0;
237  time = 0;
238  vacuumAreaNum = 0;
239  mapFileName.Clear();
240  mapFile = NULL;
242  mapSpawnCount = 0;
243  camera = NULL;
244  aasList.Clear();
245  aasNames.Clear();
247  lastAIAlertTime = 0;
248  spawnArgs.Clear();
249  gravity.Set( 0, 0, -1 );
250  playerPVS.h = -1;
251  playerConnectedAreas.h = -1;
253  skipCinematic = false;
254  influenceActive = false;
255 
256  localClientNum = 0;
257  isMultiplayer = false;
258  isServer = false;
259  isClient = false;
260  realClientTime = 0;
261  isNewFrame = true;
262  clientSmoothing = 0.1f;
263  entityDefBits = 0;
264 
265  nextGibTime = 0;
267  newInfo.Clear();
268  lastGUIEnt = NULL;
269  lastGUI = 0;
270 
271  memset( clientEntityStates, 0, sizeof( clientEntityStates ) );
272  memset( clientPVS, 0, sizeof( clientPVS ) );
273  memset( clientSnapshots, 0, sizeof( clientSnapshots ) );
274 
275  eventQueue.Init();
277 
278  memset( lagometer, 0, sizeof( lagometer ) );
279 
280 #ifdef _D3XP
281  portalSkyEnt = NULL;
282  portalSkyActive = false;
283 
284  ResetSlowTimeVars();
285 #endif
286 }
287 
288 /*
289 ===========
290 idGameLocal::Init
291 
292  initialize the game object, only happens once at startup, not each level load
293 ============
294 */
295 void idGameLocal::Init( void ) {
296  const idDict *dict;
297  idAAS *aas;
298 
299 #ifndef GAME_DLL
300 
301  TestGameAPI();
302 
303 #else
304 
305  // initialize idLib
306  idLib::Init();
307 
308  // register static cvars declared in the game
310 
311  // initialize processor specific SIMD
313 
314 #endif
315 
316  Printf( "--------- Initializing Game ----------\n" );
317  Printf( "gamename: %s\n", GAME_VERSION );
318  Printf( "gamedate: %s\n", __DATE__ );
319 
320  // register game specific decl types
321  declManager->RegisterDeclType( "model", DECL_MODELDEF, idDeclAllocator<idDeclModelDef> );
322  declManager->RegisterDeclType( "export", DECL_MODELEXPORT, idDeclAllocator<idDecl> );
323 
324  // register game specific decl folders
325  declManager->RegisterDeclFolder( "def", ".def", DECL_ENTITYDEF );
326  declManager->RegisterDeclFolder( "fx", ".fx", DECL_FX );
327  declManager->RegisterDeclFolder( "particles", ".prt", DECL_PARTICLE );
328  declManager->RegisterDeclFolder( "af", ".af", DECL_AF );
329  declManager->RegisterDeclFolder( "newpdas", ".pda", DECL_PDA );
330 
331  cmdSystem->AddCommand( "listModelDefs", idListDecls_f<DECL_MODELDEF>, CMD_FL_SYSTEM|CMD_FL_GAME, "lists model defs" );
332  cmdSystem->AddCommand( "printModelDefs", idPrintDecls_f<DECL_MODELDEF>, CMD_FL_SYSTEM|CMD_FL_GAME, "prints a model def", idCmdSystem::ArgCompletion_Decl<DECL_MODELDEF> );
333 
334  Clear();
335 
336  idEvent::Init();
337  idClass::Init();
338 
340 
341 
342 #ifdef _D3XP
343  if(!g_xp_bind_run_once.GetBool()) {
344  //The default config file contains remapped controls that support the XP weapons
345  //We want to run this once after the base doom config file has run so we can
346  //have the correct xp binds
347  cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec default.cfg\n" );
348  cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "seta g_xp_bind_run_once 1\n" );
349  cmdSystem->ExecuteCommandBuffer();
350  }
351 #endif
352 
353  // load default scripts
354  program.Startup( SCRIPT_DEFAULT );
355 
356 #ifdef _D3XP
357  //BSM Nerve: Loads a game specific main script file
358  idStr gamedir;
359  int i;
360  for ( i = 0; i < 2; i++ ) {
361  if ( i == 0 ) {
362  gamedir = cvarSystem->GetCVarString( "fs_game_base" );
363  } else if ( i == 1 ) {
364  gamedir = cvarSystem->GetCVarString( "fs_game" );
365  }
366  if( gamedir.Length() > 0 ) {
367  idStr scriptFile = va( "script/%s_main.script", gamedir.c_str() );
368  if ( fileSystem->ReadFile( scriptFile.c_str(), NULL ) > 0 ) {
369  program.CompileFile( scriptFile.c_str() );
370  program.FinishCompilation();
371  }
372  }
373  }
374 #endif
375 
377 
378  // set up the aas
379  dict = FindEntityDefDict( "aas_types" );
380  if ( !dict ) {
381  Error( "Unable to find entityDef for 'aas_types'" );
382  }
383 
384  // allocate space for the aas
385  const idKeyValue *kv = dict->MatchPrefix( "type" );
386  while( kv != NULL ) {
387  aas = idAAS::Alloc();
388  aasList.Append( aas );
389  aasNames.Append( kv->GetValue() );
390  kv = dict->MatchPrefix( "type", kv );
391  }
392 
394 
395  Printf( "...%d aas types\n", aasList.Num() );
396  Printf( "game initialized.\n" );
397  Printf( "--------------------------------------\n" );
398 }
399 
400 /*
401 ===========
402 idGameLocal::Shutdown
403 
404  shut down the entire game
405 ============
406 */
407 void idGameLocal::Shutdown( void ) {
408 
409  if ( !common ) {
410  return;
411  }
412 
413  Printf( "------------ Game Shutdown -----------\n" );
414 
415  mpGame.Shutdown();
416 
417  MapShutdown();
418 
419  aasList.DeleteContents( true );
420  aasNames.Clear();
421 
423 
424  // shutdown the model exporter
426 
428 
429  delete[] locationEntities;
431 
432  delete smokeParticles;
434 
436 
437  // clear list with forces
439 
440  // free the program data
441  program.FreeData();
442 
443  // delete the .map file
444  delete mapFile;
445  mapFile = NULL;
446 
447  // free the collision map
448  collisionModelManager->FreeMap();
449 
451 
452  // free memory allocated by class objects
453  Clear();
454 
455  // shut down the animation manager
456  animationLib.Shutdown();
457 
458  Printf( "--------------------------------------\n" );
459 
460 #ifdef GAME_DLL
461 
462  // remove auto-completion function pointers pointing into this DLL
463  cvarSystem->RemoveFlaggedAutoCompletion( CVAR_GAME );
464 
465  // enable leak test
466  Mem_EnableLeakTest( "game" );
467 
468  // shutdown idLib
469  idLib::ShutDown();
470 
471 #endif
472 }
473 
474 /*
475 ===========
476 idGameLocal::SaveGame
477 
478 save the current player state, level name, and level state
479 the session may have written some data to the file already
480 ============
481 */
483  int i;
484  idEntity *ent;
485  idEntity *link;
486 
487  idSaveGame savegame( f );
488 
489  if (g_flushSave.GetBool( ) == true ) {
490  // force flushing with each write... for tracking down
491  // save game bugs.
492  f->ForceFlush();
493  }
494 
495  savegame.WriteBuildNumber( BUILD_NUMBER );
496 
497  // go through all entities and threads and add them to the object list
498  for( i = 0; i < MAX_GENTITIES; i++ ) {
499  ent = entities[i];
500 
501  if ( ent ) {
502  if ( ent->GetTeamMaster() && ent->GetTeamMaster() != ent ) {
503  continue;
504  }
505  for ( link = ent; link != NULL; link = link->GetNextTeamEntity() ) {
506  savegame.AddObject( link );
507  }
508  }
509  }
510 
511  idList<idThread *> threads;
512  threads = idThread::GetThreads();
513 
514  for( i = 0; i < threads.Num(); i++ ) {
515  savegame.AddObject( threads[i] );
516  }
517 
518  // write out complete object list
519  savegame.WriteObjectList();
520 
521  program.Save( &savegame );
522 
523  savegame.WriteInt( g_skill.GetInteger() );
524 
525  savegame.WriteDict( &serverInfo );
526 
527  savegame.WriteInt( numClients );
528  for( i = 0; i < numClients; i++ ) {
529  savegame.WriteDict( &userInfo[ i ] );
530  savegame.WriteUsercmd( usercmds[ i ] );
531  savegame.WriteDict( &persistentPlayerInfo[ i ] );
532  }
533 
534  for( i = 0; i < MAX_GENTITIES; i++ ) {
535  savegame.WriteObject( entities[ i ] );
536  savegame.WriteInt( spawnIds[ i ] );
537  }
538 
539  savegame.WriteInt( firstFreeIndex );
540  savegame.WriteInt( num_entities );
541 
542  // enityHash is restored by idEntity::Restore setting the entity name.
543 
544  savegame.WriteObject( world );
545 
546  savegame.WriteInt( spawnedEntities.Num() );
547  for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
548  savegame.WriteObject( ent );
549  }
550 
551  savegame.WriteInt( activeEntities.Num() );
552  for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) {
553  savegame.WriteObject( ent );
554  }
555 
556  savegame.WriteInt( numEntitiesToDeactivate );
557  savegame.WriteBool( sortPushers );
558  savegame.WriteBool( sortTeamMasters );
559  savegame.WriteDict( &persistentLevelInfo );
560 
561  for( i = 0; i < MAX_GLOBAL_SHADER_PARMS; i++ ) {
562  savegame.WriteFloat( globalShaderParms[ i ] );
563  }
564 
565  savegame.WriteInt( random.GetSeed() );
566  savegame.WriteObject( frameCommandThread );
567 
568  // clip
569  // push
570  // pvs
571 
572  testmodel = NULL;
573  testFx = NULL;
574 
575  savegame.WriteString( sessionCommand );
576 
577  // FIXME: save smoke particles
578 
579  savegame.WriteInt( cinematicSkipTime );
580  savegame.WriteInt( cinematicStopTime );
581  savegame.WriteInt( cinematicMaxSkipTime );
582  savegame.WriteBool( inCinematic );
583  savegame.WriteBool( skipCinematic );
584 
585  savegame.WriteBool( isMultiplayer );
586  savegame.WriteInt( gameType );
587 
588  savegame.WriteInt( framenum );
589  savegame.WriteInt( previousTime );
590  savegame.WriteInt( time );
591 
592 #ifdef _D3XP
593  savegame.WriteInt( msec );
594 #endif
595 
596  savegame.WriteInt( vacuumAreaNum );
597 
598  savegame.WriteInt( entityDefBits );
599  savegame.WriteBool( isServer );
600  savegame.WriteBool( isClient );
601 
602  savegame.WriteInt( localClientNum );
603 
604  // snapshotEntities is used for multiplayer only
605 
606  savegame.WriteInt( realClientTime );
607  savegame.WriteBool( isNewFrame );
608  savegame.WriteFloat( clientSmoothing );
609 
610 #ifdef _D3XP
611  portalSkyEnt.Save( &savegame );
612  savegame.WriteBool( portalSkyActive );
613 
614  fast.Save( &savegame );
615  slow.Save( &savegame );
616 
617  savegame.WriteInt( slowmoState );
618  savegame.WriteFloat( slowmoMsec );
619  savegame.WriteBool( quickSlowmoReset );
620 #endif
621 
622  savegame.WriteBool( mapCycleLoaded );
623  savegame.WriteInt( spawnCount );
624 
625  if ( !locationEntities ) {
626  savegame.WriteInt( 0 );
627  } else {
628  savegame.WriteInt( gameRenderWorld->NumAreas() );
629  for( i = 0; i < gameRenderWorld->NumAreas(); i++ ) {
630  savegame.WriteObject( locationEntities[ i ] );
631  }
632  }
633 
634  savegame.WriteObject( camera );
635 
636  savegame.WriteMaterial( globalMaterial );
637 
638  lastAIAlertEntity.Save( &savegame );
639  savegame.WriteInt( lastAIAlertTime );
640 
641  savegame.WriteDict( &spawnArgs );
642 
643  savegame.WriteInt( playerPVS.i );
644  savegame.WriteInt( playerPVS.h );
645  savegame.WriteInt( playerConnectedAreas.i );
646  savegame.WriteInt( playerConnectedAreas.h );
647 
648  savegame.WriteVec3( gravity );
649 
650  // gamestate
651 
652  savegame.WriteBool( influenceActive );
653  savegame.WriteInt( nextGibTime );
654 
655  // spawnSpots
656  // initialSpots
657  // currentInitialSpot
658  // newInfo
659  // makingBuild
660  // shakeSounds
661 
662  // write out pending events
663  idEvent::Save( &savegame );
664 
665  savegame.Close();
666 }
667 
668 /*
669 ===========
670 idGameLocal::GetPersistentPlayerInfo
671 ============
672 */
674  idEntity *ent;
675 
676  persistentPlayerInfo[ clientNum ].Clear();
677  ent = entities[ clientNum ];
678  if ( ent && ent->IsType( idPlayer::Type ) ) {
679  static_cast<idPlayer *>(ent)->SavePersistantInfo();
680  }
681 
682  return persistentPlayerInfo[ clientNum ];
683 }
684 
685 /*
686 ===========
687 idGameLocal::SetPersistentPlayerInfo
688 ============
689 */
690 void idGameLocal::SetPersistentPlayerInfo( int clientNum, const idDict &playerInfo ) {
691  persistentPlayerInfo[ clientNum ] = playerInfo;
692 }
693 
694 /*
695 ============
696 idGameLocal::Printf
697 ============
698 */
699 void idGameLocal::Printf( const char *fmt, ... ) const {
700  va_list argptr;
701  char text[MAX_STRING_CHARS];
702 
703  va_start( argptr, fmt );
704  idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
705  va_end( argptr );
706 
707  common->Printf( "%s", text );
708 }
709 
710 /*
711 ============
712 idGameLocal::DPrintf
713 ============
714 */
715 void idGameLocal::DPrintf( const char *fmt, ... ) const {
716  va_list argptr;
717  char text[MAX_STRING_CHARS];
718 
719  if ( !developer.GetBool() ) {
720  return;
721  }
722 
723  va_start( argptr, fmt );
724  idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
725  va_end( argptr );
726 
727  common->Printf( "%s", text );
728 }
729 
730 /*
731 ============
732 idGameLocal::Warning
733 ============
734 */
735 void idGameLocal::Warning( const char *fmt, ... ) const {
736  va_list argptr;
737  char text[MAX_STRING_CHARS];
738  idThread * thread;
739 
740  va_start( argptr, fmt );
741  idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
742  va_end( argptr );
743 
744  thread = idThread::CurrentThread();
745  if ( thread ) {
746  thread->Warning( "%s", text );
747  } else {
748  common->Warning( "%s", text );
749  }
750 }
751 
752 /*
753 ============
754 idGameLocal::DWarning
755 ============
756 */
757 void idGameLocal::DWarning( const char *fmt, ... ) const {
758  va_list argptr;
759  char text[MAX_STRING_CHARS];
760  idThread * thread;
761 
762  if ( !developer.GetBool() ) {
763  return;
764  }
765 
766  va_start( argptr, fmt );
767  idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
768  va_end( argptr );
769 
770  thread = idThread::CurrentThread();
771  if ( thread ) {
772  thread->Warning( "%s", text );
773  } else {
774  common->DWarning( "%s", text );
775  }
776 }
777 
778 /*
779 ============
780 idGameLocal::Error
781 ============
782 */
783 void idGameLocal::Error( const char *fmt, ... ) const {
784  va_list argptr;
785  char text[MAX_STRING_CHARS];
786  idThread * thread;
787 
788  va_start( argptr, fmt );
789  idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
790  va_end( argptr );
791 
792  thread = idThread::CurrentThread();
793  if ( thread ) {
794  thread->Error( "%s", text );
795  } else {
796  common->Error( "%s", text );
797  }
798 }
799 
800 /*
801 ===============
802 gameError
803 ===============
804 */
805 void gameError( const char *fmt, ... ) {
806  va_list argptr;
807  char text[MAX_STRING_CHARS];
808 
809  va_start( argptr, fmt );
810  idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
811  va_end( argptr );
812 
813  gameLocal.Error( "%s", text );
814 }
815 
816 /*
817 ===========
818 idGameLocal::SetLocalClient
819 ============
820 */
821 void idGameLocal::SetLocalClient( int clientNum ) {
822  localClientNum = clientNum;
823 }
824 
825 /*
826 ===========
827 idGameLocal::SetUserInfo
828 ============
829 */
830 const idDict* idGameLocal::SetUserInfo( int clientNum, const idDict &userInfo, bool isClient, bool canModify ) {
831  int i;
832  bool modifiedInfo = false;
833 
834  this->isClient = isClient;
835 
836  if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {
837  idGameLocal::userInfo[ clientNum ] = userInfo;
838 
839  // server sanity
840  if ( canModify ) {
841 
842  // don't let numeric nicknames, it can be exploited to go around kick and ban commands from the server
843  if ( idStr::IsNumeric( this->userInfo[ clientNum ].GetString( "ui_name" ) ) ) {
844  idGameLocal::userInfo[ clientNum ].Set( "ui_name", va( "%s_", idGameLocal::userInfo[ clientNum ].GetString( "ui_name" ) ) );
845  modifiedInfo = true;
846  }
847 
848  // don't allow dupe nicknames
849  for ( i = 0; i < numClients; i++ ) {
850  if ( i == clientNum ) {
851  continue;
852  }
853  if ( entities[ i ] && entities[ i ]->IsType( idPlayer::Type ) ) {
854  if ( !idStr::Icmp( idGameLocal::userInfo[ clientNum ].GetString( "ui_name" ), idGameLocal::userInfo[ i ].GetString( "ui_name" ) ) ) {
855  idGameLocal::userInfo[ clientNum ].Set( "ui_name", va( "%s_", idGameLocal::userInfo[ clientNum ].GetString( "ui_name" ) ) );
856  modifiedInfo = true;
857  i = -1; // rescan
858  continue;
859  }
860  }
861  }
862  }
863 
864  if ( entities[ clientNum ] && entities[ clientNum ]->IsType( idPlayer::Type ) ) {
865  modifiedInfo |= static_cast<idPlayer *>( entities[ clientNum ] )->UserInfoChanged( canModify );
866  }
867 
868  if ( !isClient ) {
869  // now mark this client in game
870  mpGame.EnterGame( clientNum );
871  }
872  }
873 
874  if ( modifiedInfo ) {
875  assert( canModify );
876  newInfo = idGameLocal::userInfo[ clientNum ];
877  return &newInfo;
878  }
879  return NULL;
880 }
881 
882 /*
883 ===========
884 idGameLocal::GetUserInfo
885 ============
886 */
887 const idDict* idGameLocal::GetUserInfo( int clientNum ) {
888  if ( entities[ clientNum ] && entities[ clientNum ]->IsType( idPlayer::Type ) ) {
889  return &userInfo[ clientNum ];
890  }
891  return NULL;
892 }
893 
894 /*
895 ===========
896 idGameLocal::SetServerInfo
897 ============
898 */
899 void idGameLocal::SetServerInfo( const idDict &_serverInfo ) {
900  idBitMsg outMsg;
901  byte msgBuf[MAX_GAME_MESSAGE_SIZE];
902 
903  serverInfo = _serverInfo;
905 
906  if ( !isClient ) {
907  // Let our clients know the server info changed
908  outMsg.Init( msgBuf, sizeof( msgBuf ) );
910  outMsg.WriteDeltaDict( gameLocal.serverInfo, NULL );
911  networkSystem->ServerSendReliableMessage( -1, outMsg );
912  }
913 }
914 
915 
916 /*
917 ===================
918 idGameLocal::LoadMap
919 
920 Initializes all map variables common to both save games and spawned games.
921 ===================
922 */
923 void idGameLocal::LoadMap( const char *mapName, int randseed ) {
924  int i;
925  bool sameMap = (mapFile && idStr::Icmp(mapFileName, mapName) == 0);
926 
927  // clear the sound system
928  gameSoundWorld->ClearAllSoundEmitters();
929 
930 #ifdef _D3XP
931  // clear envirosuit sound fx
932  gameSoundWorld->SetEnviroSuit( false );
933  gameSoundWorld->SetSlowmo( false );
934 #endif
935 
937 
938  if ( !sameMap || ( mapFile && mapFile->NeedsReload() ) ) {
939  // load the .map file
940  if ( mapFile ) {
941  delete mapFile;
942  }
943  mapFile = new idMapFile;
944  if ( !mapFile->Parse( idStr( mapName ) + ".map" ) ) {
945  delete mapFile;
946  mapFile = NULL;
947  Error( "Couldn't load %s", mapName );
948  }
949  }
951 
952  // load the collision map
953  collisionModelManager->LoadMap( mapFile );
954 
955  numClients = 0;
956 
957  // initialize all entities for this game
958  memset( entities, 0, sizeof( entities ) );
959  memset( usercmds, 0, sizeof( usercmds ) );
960  memset( spawnIds, -1, sizeof( spawnIds ) );
962 
966  sortTeamMasters = false;
967  sortPushers = false;
968  lastGUIEnt = NULL;
969  lastGUI = 0;
970 
972 
973  memset( globalShaderParms, 0, sizeof( globalShaderParms ) );
974 
975  // always leave room for the max number of clients,
976  // even if they aren't all used, so numbers inside that
977  // range are NEVER anything but clients
980 
981  // reset the random number generator.
982  random.SetSeed( isMultiplayer ? randseed : 0 );
983 
984  camera = NULL;
985  world = NULL;
986  testmodel = NULL;
987  testFx = NULL;
988 
990  lastAIAlertTime = 0;
991 
992  previousTime = 0;
993  time = 0;
994  framenum = 0;
995  sessionCommand = "";
996  nextGibTime = 0;
997 
998 #ifdef _D3XP
999  portalSkyEnt = NULL;
1000  portalSkyActive = false;
1001 
1002  ResetSlowTimeVars();
1003 #endif
1004 
1005  vacuumAreaNum = -1; // if an info_vacuum is spawned, it will set this
1006 
1007  if ( !editEntities ) {
1009  }
1010 
1011  gravity.Set( 0, 0, -g_gravity.GetFloat() );
1012 
1013  spawnArgs.Clear();
1014 
1015  skipCinematic = false;
1016  inCinematic = false;
1017  cinematicSkipTime = 0;
1018  cinematicStopTime = 0;
1020 
1021  clip.Init();
1022  pvs.Init();
1023  playerPVS.i = -1;
1024  playerConnectedAreas.i = -1;
1025 
1026  // load navigation system for all the different monster sizes
1027  for( i = 0; i < aasNames.Num(); i++ ) {
1028  aasList[ i ]->Init( idStr( mapFileName ).SetFileExtension( aasNames[ i ] ).c_str(), mapFile->GetGeometryCRC() );
1029  }
1030 
1031  // clear the smoke particle free list
1032  smokeParticles->Init();
1033 
1034  // cache miscellanious media references
1035  FindEntityDef( "preCacheExtras", false );
1036 
1037  if ( !sameMap ) {
1039  }
1040 }
1041 
1042 /*
1043 ===================
1044 idGameLocal::LocalMapRestart
1045 ===================
1046 */
1048  int i, latchSpawnCount;
1049 
1050  Printf( "----------- Game Map Restart ------------\n" );
1051 
1053 
1054  for ( i = 0; i < MAX_CLIENTS; i++ ) {
1055  if ( entities[ i ] && entities[ i ]->IsType( idPlayer::Type ) ) {
1056  static_cast< idPlayer * >( entities[ i ] )->PrepareForRestart();
1057  }
1058  }
1059 
1060  eventQueue.Shutdown();
1062 
1063  MapClear( false );
1064 
1065 
1066 
1067  // clear the smoke particle free list
1068  smokeParticles->Init();
1069 
1070  // clear the sound system
1071  if ( gameSoundWorld ) {
1072  gameSoundWorld->ClearAllSoundEmitters();
1073 #ifdef _D3XP
1074  // clear envirosuit sound fx
1075  gameSoundWorld->SetEnviroSuit( false );
1076  gameSoundWorld->SetSlowmo( false );
1077 #endif
1078  }
1079 
1080  // the spawnCount is reset to zero temporarily to spawn the map entities with the same spawnId
1081  // if we don't do that, network clients are confused and don't show any map entities
1082  latchSpawnCount = spawnCount;
1084 
1086 
1087  program.Restart();
1088 
1089  InitScriptForMap();
1090 
1091  MapPopulate();
1092 
1093  // once the map is populated, set the spawnCount back to where it was so we don't risk any collision
1094  // (note that if there are no players in the game, we could just leave it at it's current value)
1095  spawnCount = latchSpawnCount;
1096 
1097  // setup the client entities again
1098  for ( i = 0; i < MAX_CLIENTS; i++ ) {
1099  if ( entities[ i ] && entities[ i ]->IsType( idPlayer::Type ) ) {
1100  static_cast< idPlayer * >( entities[ i ] )->Restart();
1101  }
1102  }
1103 
1105 
1106  Printf( "--------------------------------------\n" );
1107 }
1108 
1109 /*
1110 ===================
1111 idGameLocal::MapRestart
1112 ===================
1113 */
1115  idBitMsg outMsg;
1116  byte msgBuf[MAX_GAME_MESSAGE_SIZE];
1117  idDict newInfo;
1118  int i;
1119  const idKeyValue *keyval, *keyval2;
1120 
1121 #ifdef _D3XP
1122  if ( isMultiplayer && isServer ) {
1123  char buf[ MAX_STRING_CHARS ];
1124  idStr gametype;
1126  gametype = buf;
1127  if ( gametype != si_gameType.GetString() ) {
1128  cvarSystem->SetCVarString( "si_gameType", gametype );
1129  }
1130  }
1131 #endif
1132 
1133 
1134 
1135  if ( isClient ) {
1136  LocalMapRestart();
1137  } else {
1138  newInfo = *cvarSystem->MoveCVarsToDict( CVAR_SERVERINFO );
1139  for ( i = 0; i < newInfo.GetNumKeyVals(); i++ ) {
1140  keyval = newInfo.GetKeyVal( i );
1141  keyval2 = serverInfo.FindKey( keyval->GetKey() );
1142  if ( !keyval2 ) {
1143  break;
1144  }
1145  // a select set of si_ changes will cause a full restart of the server
1146  if ( keyval->GetValue().Cmp( keyval2->GetValue() ) &&
1147  ( !keyval->GetKey().Cmp( "si_pure" ) || !keyval->GetKey().Cmp( "si_map" ) ) ) {
1148  break;
1149  }
1150  }
1151  cmdSystem->BufferCommandText( CMD_EXEC_NOW, "rescanSI" );
1152 
1153  if ( i != newInfo.GetNumKeyVals() ) {
1154  cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "nextMap" );
1155  } else {
1156  outMsg.Init( msgBuf, sizeof( msgBuf ) );
1158  outMsg.WriteBits( 1, 1 );
1159  outMsg.WriteDeltaDict( serverInfo, NULL );
1160  networkSystem->ServerSendReliableMessage( -1, outMsg );
1161 
1162  LocalMapRestart();
1163  mpGame.MapRestart();
1164  }
1165  }
1166 
1167 #ifdef CTF
1168  if ( isMultiplayer ) {
1169  gameLocal.mpGame.ReloadScoreboard();
1170  // gameLocal.mpGame.Reset(); // force reconstruct the GUIs when reloading maps, different gametypes have different GUIs
1171  // gameLocal.mpGame.UpdateMainGui();
1172  // gameLocal.mpGame.StartMenu();
1173  // gameLocal.mpGame.DisableMenu();
1174  // gameLocal.mpGame.Precache();
1175  }
1176 #endif
1177 }
1178 
1179 /*
1180 ===================
1181 idGameLocal::MapRestart_f
1182 ===================
1183 */
1185  if ( !gameLocal.isMultiplayer || gameLocal.isClient ) {
1186  common->Printf( "server is not running - use spawnServer\n" );
1187  cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "spawnServer\n" );
1188  return;
1189  }
1190 
1191  gameLocal.MapRestart( );
1192 }
1193 
1194 /*
1195 ===================
1196 idGameLocal::NextMap
1197 ===================
1198 */
1199 bool idGameLocal::NextMap( void ) {
1200  const function_t *func;
1201  idThread *thread;
1202  idDict newInfo;
1203  const idKeyValue *keyval, *keyval2;
1204  int i;
1205 
1206  if ( !g_mapCycle.GetString()[0] ) {
1207  Printf( common->GetLanguageDict()->GetString( "#str_04294" ) );
1208  return false;
1209  }
1210  if ( fileSystem->ReadFile( g_mapCycle.GetString(), NULL, NULL ) < 0 ) {
1211  if ( fileSystem->ReadFile( va( "%s.scriptcfg", g_mapCycle.GetString() ), NULL, NULL ) < 0 ) {
1212  Printf( "map cycle script '%s': not found\n", g_mapCycle.GetString() );
1213  return false;
1214  } else {
1215  g_mapCycle.SetString( va( "%s.scriptcfg", g_mapCycle.GetString() ) );
1216  }
1217  }
1218 
1219  Printf( "map cycle script: '%s'\n", g_mapCycle.GetString() );
1220  func = program.FindFunction( "mapcycle::cycle" );
1221  if ( !func ) {
1222  program.CompileFile( g_mapCycle.GetString() );
1223  func = program.FindFunction( "mapcycle::cycle" );
1224  }
1225  if ( !func ) {
1226  Printf( "Couldn't find mapcycle::cycle\n" );
1227  return false;
1228  }
1229  thread = new idThread( func );
1230  thread->Start();
1231  delete thread;
1232 
1233  newInfo = *cvarSystem->MoveCVarsToDict( CVAR_SERVERINFO );
1234  for ( i = 0; i < newInfo.GetNumKeyVals(); i++ ) {
1235  keyval = newInfo.GetKeyVal( i );
1236  keyval2 = serverInfo.FindKey( keyval->GetKey() );
1237  if ( !keyval2 || keyval->GetValue().Cmp( keyval2->GetValue() ) ) {
1238  break;
1239  }
1240  }
1241  return ( i != newInfo.GetNumKeyVals() );
1242 }
1243 
1244 /*
1245 ===================
1246 idGameLocal::NextMap_f
1247 ===================
1248 */
1249 void idGameLocal::NextMap_f( const idCmdArgs &args ) {
1250  if ( !gameLocal.isMultiplayer || gameLocal.isClient ) {
1251  common->Printf( "server is not running\n" );
1252  return;
1253  }
1254 
1255  gameLocal.NextMap( );
1256  // next map was either voted for or triggered by a server command - always restart
1257  gameLocal.MapRestart( );
1258 }
1259 
1260 /*
1261 ===================
1262 idGameLocal::MapPopulate
1263 ===================
1264 */
1266 
1267  if ( isMultiplayer ) {
1268  cvarSystem->SetCVarBool( "r_skipSpecular", false );
1269  }
1270  // parse the key/value pairs and spawn entities
1271  SpawnMapEntities();
1272 
1273  // mark location entities in all connected areas
1274  SpreadLocations();
1275 
1276  // prepare the list of randomized initial spawn spots
1278 
1279  // spawnCount - 1 is the number of entities spawned into the map, their indexes started at MAX_CLIENTS (included)
1280  // mapSpawnCount is used as the max index of map entities, it's the first index of non-map entities
1282 
1283  // execute pending events before the very first game frame
1284  // this makes sure the map script main() function is called
1285  // before the physics are run so entities can bind correctly
1286  Printf( "==== Processing events ====\n" );
1288 }
1289 
1290 /*
1291 ===================
1292 idGameLocal::InitFromNewMap
1293 ===================
1294 */
1295 void idGameLocal::InitFromNewMap( const char *mapName, idRenderWorld *renderWorld, idSoundWorld *soundWorld, bool isServer, bool isClient, int randseed ) {
1296 
1297  this->isServer = isServer;
1298  this->isClient = isClient;
1299  this->isMultiplayer = isServer || isClient;
1300 
1301  if ( mapFileName.Length() ) {
1302  MapShutdown();
1303  }
1304 
1305  Printf( "----------- Game Map Init ------------\n" );
1306 
1308 
1309  gameRenderWorld = renderWorld;
1310  gameSoundWorld = soundWorld;
1311 
1312  LoadMap( mapName, randseed );
1313 
1314  InitScriptForMap();
1315 
1316  MapPopulate();
1317 
1318  mpGame.Reset();
1319 
1320  mpGame.Precache();
1321 
1322  // free up any unused animations
1323  animationLib.FlushUnusedAnims();
1324 
1326 
1327  Printf( "--------------------------------------\n" );
1328 }
1329 
1330 /*
1331 =================
1332 idGameLocal::InitFromSaveGame
1333 =================
1334 */
1335 bool idGameLocal::InitFromSaveGame( const char *mapName, idRenderWorld *renderWorld, idSoundWorld *soundWorld, idFile *saveGameFile ) {
1336  int i;
1337  int num;
1338  idEntity *ent;
1339  idDict si;
1340 
1341  if ( mapFileName.Length() ) {
1342  MapShutdown();
1343  }
1344 
1345  Printf( "------- Game Map Init SaveGame -------\n" );
1346 
1348 
1349  gameRenderWorld = renderWorld;
1350  gameSoundWorld = soundWorld;
1351 
1352  idRestoreGame savegame( saveGameFile );
1353 
1354  savegame.ReadBuildNumber();
1355 
1356  // Create the list of all objects in the game
1357  savegame.CreateObjects();
1358 
1359  // Load the idProgram, also checking to make sure scripting hasn't changed since the savegame
1360  if ( program.Restore( &savegame ) == false ) {
1361 
1362  // Abort the load process, and let the session know so that it can restart the level
1363  // with the player persistent data.
1364  savegame.DeleteObjects();
1365  program.Restart();
1366 
1367  return false;
1368  }
1369 
1370  // load the map needed for this savegame
1371  LoadMap( mapName, 0 );
1372 
1373  savegame.ReadInt( i );
1374  g_skill.SetInteger( i );
1375 
1376  // precache the player
1377  FindEntityDef( "player_doommarine", false );
1378 
1379  // precache any media specified in the map
1380  for ( i = 0; i < mapFile->GetNumEntities(); i++ ) {
1381  idMapEntity *mapEnt = mapFile->GetEntity( i );
1382 
1383  if ( !InhibitEntitySpawn( mapEnt->epairs ) ) {
1384  CacheDictionaryMedia( &mapEnt->epairs );
1385  const char *classname = mapEnt->epairs.GetString( "classname" );
1386  if ( classname != '\0' ) {
1387  FindEntityDef( classname, false );
1388  }
1389  }
1390  }
1391 
1392  savegame.ReadDict( &si );
1393  SetServerInfo( si );
1394 
1395  savegame.ReadInt( numClients );
1396  for( i = 0; i < numClients; i++ ) {
1397  savegame.ReadDict( &userInfo[ i ] );
1398  savegame.ReadUsercmd( usercmds[ i ] );
1399  savegame.ReadDict( &persistentPlayerInfo[ i ] );
1400  }
1401 
1402  for( i = 0; i < MAX_GENTITIES; i++ ) {
1403  savegame.ReadObject( reinterpret_cast<idClass *&>( entities[ i ] ) );
1404  savegame.ReadInt( spawnIds[ i ] );
1405 
1406  // restore the entityNumber
1407  if ( entities[ i ] != NULL ) {
1408  entities[ i ]->entityNumber = i;
1409  }
1410  }
1411 
1412  savegame.ReadInt( firstFreeIndex );
1413  savegame.ReadInt( num_entities );
1414 
1415  // enityHash is restored by idEntity::Restore setting the entity name.
1416 
1417  savegame.ReadObject( reinterpret_cast<idClass *&>( world ) );
1418 
1419  savegame.ReadInt( num );
1420  for( i = 0; i < num; i++ ) {
1421  savegame.ReadObject( reinterpret_cast<idClass *&>( ent ) );
1422  assert( ent );
1423  if ( ent ) {
1425  }
1426  }
1427 
1428  savegame.ReadInt( num );
1429  for( i = 0; i < num; i++ ) {
1430  savegame.ReadObject( reinterpret_cast<idClass *&>( ent ) );
1431  assert( ent );
1432  if ( ent ) {
1434  }
1435  }
1436 
1437  savegame.ReadInt( numEntitiesToDeactivate );
1438  savegame.ReadBool( sortPushers );
1439  savegame.ReadBool( sortTeamMasters );
1440  savegame.ReadDict( &persistentLevelInfo );
1441 
1442  for( i = 0; i < MAX_GLOBAL_SHADER_PARMS; i++ ) {
1443  savegame.ReadFloat( globalShaderParms[ i ] );
1444  }
1445 
1446  savegame.ReadInt( i );
1447  random.SetSeed( i );
1448 
1449  savegame.ReadObject( reinterpret_cast<idClass *&>( frameCommandThread ) );
1450 
1451  // clip
1452  // push
1453  // pvs
1454 
1455  // testmodel = "<NULL>"
1456  // testFx = "<NULL>"
1457 
1458  savegame.ReadString( sessionCommand );
1459 
1460  // FIXME: save smoke particles
1461 
1462  savegame.ReadInt( cinematicSkipTime );
1463  savegame.ReadInt( cinematicStopTime );
1464  savegame.ReadInt( cinematicMaxSkipTime );
1465  savegame.ReadBool( inCinematic );
1466  savegame.ReadBool( skipCinematic );
1467 
1468  savegame.ReadBool( isMultiplayer );
1469  savegame.ReadInt( (int &)gameType );
1470 
1471  savegame.ReadInt( framenum );
1472  savegame.ReadInt( previousTime );
1473  savegame.ReadInt( time );
1474 
1475 #ifdef _D3XP
1476  savegame.ReadInt( msec );
1477 #endif
1478 
1479  savegame.ReadInt( vacuumAreaNum );
1480 
1481  savegame.ReadInt( entityDefBits );
1482  savegame.ReadBool( isServer );
1483  savegame.ReadBool( isClient );
1484 
1485  savegame.ReadInt( localClientNum );
1486 
1487  // snapshotEntities is used for multiplayer only
1488 
1489  savegame.ReadInt( realClientTime );
1490  savegame.ReadBool( isNewFrame );
1491  savegame.ReadFloat( clientSmoothing );
1492 
1493 #ifdef _D3XP
1494  portalSkyEnt.Restore( &savegame );
1495  savegame.ReadBool( portalSkyActive );
1496 
1497  fast.Restore( &savegame );
1498  slow.Restore( &savegame );
1499 
1500  int blah;
1501  savegame.ReadInt( blah );
1502  slowmoState = (slowmoState_t)blah;
1503 
1504  savegame.ReadFloat( slowmoMsec );
1505  savegame.ReadBool( quickSlowmoReset );
1506 
1507  if ( slowmoState == SLOWMO_STATE_OFF ) {
1508  if ( gameSoundWorld ) {
1509  gameSoundWorld->SetSlowmo( false );
1510  }
1511  }
1512  else {
1513  if ( gameSoundWorld ) {
1514  gameSoundWorld->SetSlowmo( true );
1515  }
1516  }
1517  if ( gameSoundWorld ) {
1518  gameSoundWorld->SetSlowmoSpeed( slowmoMsec / (float)USERCMD_MSEC );
1519  }
1520 #endif
1521 
1522  savegame.ReadBool( mapCycleLoaded );
1523  savegame.ReadInt( spawnCount );
1524 
1525  savegame.ReadInt( num );
1526  if ( num ) {
1527  if ( num != gameRenderWorld->NumAreas() ) {
1528  savegame.Error( "idGameLocal::InitFromSaveGame: number of areas in map differs from save game." );
1529  }
1530 
1532  for( i = 0; i < num; i++ ) {
1533  savegame.ReadObject( reinterpret_cast<idClass *&>( locationEntities[ i ] ) );
1534  }
1535  }
1536 
1537  savegame.ReadObject( reinterpret_cast<idClass *&>( camera ) );
1538 
1539  savegame.ReadMaterial( globalMaterial );
1540 
1541  lastAIAlertEntity.Restore( &savegame );
1542  savegame.ReadInt( lastAIAlertTime );
1543 
1544  savegame.ReadDict( &spawnArgs );
1545 
1546  savegame.ReadInt( playerPVS.i );
1547  savegame.ReadInt( (int &)playerPVS.h );
1548  savegame.ReadInt( playerConnectedAreas.i );
1549  savegame.ReadInt( (int &)playerConnectedAreas.h );
1550 
1551  savegame.ReadVec3( gravity );
1552 
1553  // gamestate is restored after restoring everything else
1554 
1555  savegame.ReadBool( influenceActive );
1556  savegame.ReadInt( nextGibTime );
1557 
1558  // spawnSpots
1559  // initialSpots
1560  // currentInitialSpot
1561  // newInfo
1562  // makingBuild
1563  // shakeSounds
1564 
1565  // Read out pending events
1566  idEvent::Restore( &savegame );
1567 
1568  savegame.RestoreObjects();
1569 
1570  mpGame.Reset();
1571 
1572  mpGame.Precache();
1573 
1574  // free up any unused animations
1575  animationLib.FlushUnusedAnims();
1576 
1578 
1579  Printf( "--------------------------------------\n" );
1580 
1581  return true;
1582 }
1583 
1584 /*
1585 ===========
1586 idGameLocal::MapClear
1587 ===========
1588 */
1589 void idGameLocal::MapClear( bool clearClients ) {
1590  int i;
1591 
1592  for( i = ( clearClients ? 0 : MAX_CLIENTS ); i < MAX_GENTITIES; i++ ) {
1593  delete entities[ i ];
1594  // ~idEntity is in charge of setting the pointer to NULL
1595  // it will also clear pending events for this entity
1596  assert( !entities[ i ] );
1597  spawnIds[ i ] = -1;
1598  }
1599 
1600  entityHash.Clear( 1024, MAX_GENTITIES );
1601 
1602  if ( !clearClients ) {
1603  // add back the hashes of the clients
1604  for ( i = 0; i < MAX_CLIENTS; i++ ) {
1605  if ( !entities[ i ] ) {
1606  continue;
1607  }
1608  entityHash.Add( entityHash.GenerateKey( entities[ i ]->name.c_str(), true ), i );
1609  }
1610  }
1611 
1612  delete frameCommandThread;
1614 
1615  if ( editEntities ) {
1616  delete editEntities;
1617  editEntities = NULL;
1618  }
1619 
1620  delete[] locationEntities;
1622 }
1623 
1624 /*
1625 ===========
1626 idGameLocal::MapShutdown
1627 ============
1628 */
1630  Printf( "--------- Game Map Shutdown ----------\n" );
1631 
1633 
1634  if ( gameRenderWorld ) {
1635  // clear any debug lines, text, and polygons
1636  gameRenderWorld->DebugClearLines( 0 );
1637  gameRenderWorld->DebugClearPolygons( 0 );
1638  }
1639 
1640  // clear out camera if we're in a cinematic
1641  if ( inCinematic ) {
1642  camera = NULL;
1643  inCinematic = false;
1644  }
1645 
1646  MapClear( true );
1647 
1648  // reset the script to the state it was before the map was started
1649  program.Restart();
1650 
1651  if ( smokeParticles ) {
1653  }
1654 
1655  pvs.Shutdown();
1656 
1657  clip.Shutdown();
1659 
1661 
1662  mapFileName.Clear();
1663 
1664  gameRenderWorld = NULL;
1665  gameSoundWorld = NULL;
1666 
1668 
1669  Printf( "--------------------------------------\n" );
1670 }
1671 
1672 /*
1673 ===================
1674 idGameLocal::DumpOggSounds
1675 ===================
1676 */
1678  int i, j, k, size, totalSize;
1679  idFile *file;
1680  idStrList oggSounds, weaponSounds;
1681  const idSoundShader *soundShader;
1682  const soundShaderParms_t *parms;
1683  idStr soundName;
1684 
1685  for ( i = 0; i < declManager->GetNumDecls( DECL_SOUND ); i++ ) {
1686  soundShader = static_cast<const idSoundShader *>(declManager->DeclByIndex( DECL_SOUND, i, false ));
1687  parms = soundShader->GetParms();
1688 
1689  if ( soundShader->EverReferenced() && soundShader->GetState() != DS_DEFAULTED ) {
1690 
1691  const_cast<idSoundShader *>(soundShader)->EnsureNotPurged();
1692 
1693  for ( j = 0; j < soundShader->GetNumSounds(); j++ ) {
1694  soundName = soundShader->GetSound( j );
1695  soundName.BackSlashesToSlashes();
1696 
1697 #ifdef _D3XP
1698  // D3XP :: don't add sounds that are in Doom 3's pak files
1699  if ( fileSystem->FileIsInPAK( soundName ) ) {
1700  continue;
1701  } else {
1702  // Also check for a pre-ogg'd version in the pak file
1703  idStr testName = soundName;
1704 
1705  testName.SetFileExtension( ".ogg" );
1706  if ( fileSystem->FileIsInPAK( testName ) ) {
1707  continue;
1708  }
1709  }
1710 #endif
1711  // don't OGG sounds that cause a shake because that would
1712  // cause continuous seeking on the OGG file which is expensive
1713  if ( parms->shakes != 0.0f ) {
1714  shakeSounds.AddUnique( soundName );
1715  continue;
1716  }
1717 
1718  // if not voice over or combat chatter
1719  if ( soundName.Find( "/vo/", false ) == -1 &&
1720  soundName.Find( "/combat_chatter/", false ) == -1 &&
1721  soundName.Find( "/bfgcarnage/", false ) == -1 &&
1722  soundName.Find( "/enpro/", false ) == - 1 &&
1723  soundName.Find( "/soulcube/energize_01.wav", false ) == -1 ) {
1724  // don't OGG weapon sounds
1725  if ( soundName.Find( "weapon", false ) != -1 ||
1726  soundName.Find( "gun", false ) != -1 ||
1727  soundName.Find( "bullet", false ) != -1 ||
1728  soundName.Find( "bfg", false ) != -1 ||
1729  soundName.Find( "plasma", false ) != -1 ) {
1730  weaponSounds.AddUnique( soundName );
1731  continue;
1732  }
1733  }
1734 
1735  for ( k = 0; k < shakeSounds.Num(); k++ ) {
1736  if ( shakeSounds[k].IcmpPath( soundName ) == 0 ) {
1737  break;
1738  }
1739  }
1740  if ( k < shakeSounds.Num() ) {
1741  continue;
1742  }
1743 
1744  oggSounds.AddUnique( soundName );
1745  }
1746  }
1747  }
1748 
1749  file = fileSystem->OpenFileWrite( "makeogg.bat", "fs_savepath" );
1750  if ( file == NULL ) {
1751  common->Warning( "Couldn't open makeogg.bat" );
1752  return;
1753  }
1754 
1755  // list all the shake sounds
1756  totalSize = 0;
1757  for ( i = 0; i < shakeSounds.Num(); i++ ) {
1758  size = fileSystem->ReadFile( shakeSounds[i], NULL, NULL );
1759  totalSize += size;
1760  shakeSounds[i].Replace( "/", "\\" );
1761  file->Printf( "echo \"%s\" (%d kB)\n", shakeSounds[i].c_str(), size >> 10 );
1762  }
1763  file->Printf( "echo %d kB in shake sounds\n\n\n", totalSize >> 10 );
1764 
1765  // list all the weapon sounds
1766  totalSize = 0;
1767  for ( i = 0; i < weaponSounds.Num(); i++ ) {
1768  size = fileSystem->ReadFile( weaponSounds[i], NULL, NULL );
1769  totalSize += size;
1770  weaponSounds[i].Replace( "/", "\\" );
1771  file->Printf( "echo \"%s\" (%d kB)\n", weaponSounds[i].c_str(), size >> 10 );
1772  }
1773  file->Printf( "echo %d kB in weapon sounds\n\n\n", totalSize >> 10 );
1774 
1775  // list commands to convert all other sounds to ogg
1776  totalSize = 0;
1777  for ( i = 0; i < oggSounds.Num(); i++ ) {
1778  size = fileSystem->ReadFile( oggSounds[i], NULL, NULL );
1779  totalSize += size;
1780  oggSounds[i].Replace( "/", "\\" );
1781  file->Printf( "z:\\d3xp\\ogg\\oggenc -q 0 \"%s\\d3xp\\%s\"\n", cvarSystem->GetCVarString( "fs_basepath" ), oggSounds[i].c_str() );
1782  file->Printf( "del \"%s\\d3xp\\%s\"\n", cvarSystem->GetCVarString( "fs_basepath" ), oggSounds[i].c_str() );
1783  }
1784  file->Printf( "\n\necho %d kB in OGG sounds\n\n\n", totalSize >> 10 );
1785 
1786  fileSystem->CloseFile( file );
1787 
1788  shakeSounds.Clear();
1789 }
1790 
1791 /*
1792 ===================
1793 idGameLocal::GetShakeSounds
1794 ===================
1795 */
1797  const idSoundShader *soundShader;
1798  const char *soundShaderName;
1799  idStr soundName;
1800 
1801  soundShaderName = dict->GetString( "s_shader" );
1802  if ( soundShaderName != '\0' && dict->GetFloat( "s_shakes" ) != 0.0f ) {
1803  soundShader = declManager->FindSound( soundShaderName );
1804 
1805  for ( int i = 0; i < soundShader->GetNumSounds(); i++ ) {
1806  soundName = soundShader->GetSound( i );
1807  soundName.BackSlashesToSlashes();
1808 
1809  shakeSounds.AddUnique( soundName );
1810  }
1811  }
1812 }
1813 
1814 /*
1815 ===================
1816 idGameLocal::CacheDictionaryMedia
1817 
1818 This is called after parsing an EntityDef and for each entity spawnArgs before
1819 merging the entitydef. It could be done post-merge, but that would
1820 avoid the fast pre-cache check associated with each entityDef
1821 ===================
1822 */
1824  const idKeyValue *kv;
1825 
1826  if ( dict == NULL ) {
1827  if ( cvarSystem->GetCVarBool( "com_makingBuild") ) {
1828  DumpOggSounds();
1829  }
1830  return;
1831  }
1832 
1833  if ( cvarSystem->GetCVarBool( "com_makingBuild" ) ) {
1834  GetShakeSounds( dict );
1835  }
1836 
1837  kv = dict->MatchPrefix( "model" );
1838  while( kv ) {
1839  if ( kv->GetValue().Length() ) {
1840  declManager->MediaPrint( "Precaching model %s\n", kv->GetValue().c_str() );
1841  // precache model/animations
1842  if ( declManager->FindType( DECL_MODELDEF, kv->GetValue(), false ) == NULL ) {
1843  // precache the render model
1844  renderModelManager->FindModel( kv->GetValue() );
1845  // precache .cm files only
1846  collisionModelManager->LoadModel( kv->GetValue(), true );
1847  }
1848  }
1849  kv = dict->MatchPrefix( "model", kv );
1850  }
1851 
1852  kv = dict->FindKey( "s_shader" );
1853  if ( kv && kv->GetValue().Length() ) {
1854  declManager->FindType( DECL_SOUND, kv->GetValue() );
1855  }
1856 
1857  kv = dict->MatchPrefix( "snd", NULL );
1858  while( kv ) {
1859  if ( kv->GetValue().Length() ) {
1860  declManager->FindType( DECL_SOUND, kv->GetValue() );
1861  }
1862  kv = dict->MatchPrefix( "snd", kv );
1863  }
1864 
1865 
1866  kv = dict->MatchPrefix( "gui", NULL );
1867  while( kv ) {
1868  if ( kv->GetValue().Length() ) {
1869  if ( !idStr::Icmp( kv->GetKey(), "gui_noninteractive" )
1870  || !idStr::Icmpn( kv->GetKey(), "gui_parm", 8 )
1871  || !idStr::Icmp( kv->GetKey(), "gui_inventory" ) ) {
1872  // unfortunate flag names, they aren't actually a gui
1873  } else {
1874  declManager->MediaPrint( "Precaching gui %s\n", kv->GetValue().c_str() );
1875  idUserInterface *gui = uiManager->Alloc();
1876  if ( gui ) {
1877  gui->InitFromFile( kv->GetValue() );
1878  uiManager->DeAlloc( gui );
1879  }
1880  }
1881  }
1882  kv = dict->MatchPrefix( "gui", kv );
1883  }
1884 
1885  kv = dict->FindKey( "texture" );
1886  if ( kv && kv->GetValue().Length() ) {
1887  declManager->FindType( DECL_MATERIAL, kv->GetValue() );
1888  }
1889 
1890  kv = dict->MatchPrefix( "mtr", NULL );
1891  while( kv ) {
1892  if ( kv->GetValue().Length() ) {
1893  declManager->FindType( DECL_MATERIAL, kv->GetValue() );
1894  }
1895  kv = dict->MatchPrefix( "mtr", kv );
1896  }
1897 
1898  // handles hud icons
1899  kv = dict->MatchPrefix( "inv_icon", NULL );
1900  while ( kv ) {
1901  if ( kv->GetValue().Length() ) {
1902  declManager->FindType( DECL_MATERIAL, kv->GetValue() );
1903  }
1904  kv = dict->MatchPrefix( "inv_icon", kv );
1905  }
1906 
1907  // handles teleport fx.. this is not ideal but the actual decision on which fx to use
1908  // is handled by script code based on the teleport number
1909  kv = dict->MatchPrefix( "teleport", NULL );
1910  if ( kv && kv->GetValue().Length() ) {
1911  int teleportType = atoi( kv->GetValue() );
1912  const char *p = ( teleportType ) ? va( "fx/teleporter%i.fx", teleportType ) : "fx/teleporter.fx";
1913  declManager->FindType( DECL_FX, p );
1914  }
1915 
1916  kv = dict->MatchPrefix( "fx", NULL );
1917  while( kv ) {
1918  if ( kv->GetValue().Length() ) {
1919  declManager->MediaPrint( "Precaching fx %s\n", kv->GetValue().c_str() );
1920  declManager->FindType( DECL_FX, kv->GetValue() );
1921  }
1922  kv = dict->MatchPrefix( "fx", kv );
1923  }
1924 
1925  kv = dict->MatchPrefix( "smoke", NULL );
1926  while( kv ) {
1927  if ( kv->GetValue().Length() ) {
1928  idStr prtName = kv->GetValue();
1929  int dash = prtName.Find('-');
1930  if ( dash > 0 ) {
1931  prtName = prtName.Left( dash );
1932  }
1933  declManager->FindType( DECL_PARTICLE, prtName );
1934  }
1935  kv = dict->MatchPrefix( "smoke", kv );
1936  }
1937 
1938  kv = dict->MatchPrefix( "skin", NULL );
1939  while( kv ) {
1940  if ( kv->GetValue().Length() ) {
1941  declManager->MediaPrint( "Precaching skin %s\n", kv->GetValue().c_str() );
1942  declManager->FindType( DECL_SKIN, kv->GetValue() );
1943  }
1944  kv = dict->MatchPrefix( "skin", kv );
1945  }
1946 
1947  kv = dict->MatchPrefix( "def", NULL );
1948  while( kv ) {
1949  if ( kv->GetValue().Length() ) {
1950  FindEntityDef( kv->GetValue().c_str(), false );
1951  }
1952  kv = dict->MatchPrefix( "def", kv );
1953  }
1954 
1955  kv = dict->MatchPrefix( "pda_name", NULL );
1956  while( kv ) {
1957  if ( kv->GetValue().Length() ) {
1958  declManager->FindType( DECL_PDA, kv->GetValue().c_str(), false );
1959  }
1960  kv = dict->MatchPrefix( "pda_name", kv );
1961  }
1962 
1963  kv = dict->MatchPrefix( "video", NULL );
1964  while( kv ) {
1965  if ( kv->GetValue().Length() ) {
1966  declManager->FindType( DECL_VIDEO, kv->GetValue().c_str(), false );
1967  }
1968  kv = dict->MatchPrefix( "video", kv );
1969  }
1970 
1971  kv = dict->MatchPrefix( "audio", NULL );
1972  while( kv ) {
1973  if ( kv->GetValue().Length() ) {
1974  declManager->FindType( DECL_AUDIO, kv->GetValue().c_str(), false );
1975  }
1976  kv = dict->MatchPrefix( "audio", kv );
1977  }
1978 }
1979 
1980 /*
1981 ===========
1982 idGameLocal::InitScriptForMap
1983 ============
1984 */
1986  // create a thread to run frame commands on
1987  frameCommandThread = new idThread();
1989  frameCommandThread->SetThreadName( "frameCommands" );
1990 
1991  // run the main game script function (not the level specific main)
1992  const function_t *func = program.FindFunction( SCRIPT_DEFAULTFUNC );
1993  if ( func != NULL ) {
1994  idThread *thread = new idThread( func );
1995  if ( thread->Start() ) {
1996  // thread has finished executing, so delete it
1997  delete thread;
1998  }
1999  }
2000 }
2001 
2002 /*
2003 ===========
2004 idGameLocal::SpawnPlayer
2005 ============
2006 */
2007 void idGameLocal::SpawnPlayer( int clientNum ) {
2008  idEntity *ent;
2009  idDict args;
2010 
2011  // they can connect
2012  Printf( "SpawnPlayer: %i\n", clientNum );
2013 
2014  args.SetInt( "spawn_entnum", clientNum );
2015  args.Set( "name", va( "player%d", clientNum + 1 ) );
2016 #ifdef CTF
2017  if ( isMultiplayer && gameType != GAME_CTF )
2018  args.Set( "classname", "player_doommarine_mp" );
2019  else if ( isMultiplayer && gameType == GAME_CTF )
2020  args.Set( "classname", "player_doommarine_ctf" );
2021  else
2022  args.Set( "classname", "player_doommarine" );
2023 #else
2024  args.Set( "classname", isMultiplayer ? "player_doommarine_mp" : "player_doommarine" );
2025 #endif
2026  if ( !SpawnEntityDef( args, &ent ) || !entities[ clientNum ] ) {
2027  Error( "Failed to spawn player as '%s'", args.GetString( "classname" ) );
2028  }
2029 
2030  // make sure it's a compatible class
2031  if ( !ent->IsType( idPlayer::Type ) ) {
2032  Error( "'%s' spawned the player as a '%s'. Player spawnclass must be a subclass of idPlayer.", args.GetString( "classname" ), ent->GetClassname() );
2033  }
2034 
2035  if ( clientNum >= numClients ) {
2036  numClients = clientNum + 1;
2037  }
2038 
2039  mpGame.SpawnPlayer( clientNum );
2040 }
2041 
2042 /*
2043 ================
2044 idGameLocal::GetClientByNum
2045 ================
2046 */
2047 idPlayer *idGameLocal::GetClientByNum( int current ) const {
2048  if ( current < 0 || current >= numClients ) {
2049  current = 0;
2050  }
2051  if ( entities[current] ) {
2052  return static_cast<idPlayer *>( entities[ current ] );
2053  }
2054  return NULL;
2055 }
2056 
2057 /*
2058 ================
2059 idGameLocal::GetClientByName
2060 ================
2061 */
2063  int i;
2064  idEntity *ent;
2065  for ( i = 0 ; i < numClients ; i++ ) {
2066  ent = entities[ i ];
2067  if ( ent && ent->IsType( idPlayer::Type ) ) {
2068  if ( idStr::IcmpNoColor( name, userInfo[ i ].GetString( "ui_name" ) ) == 0 ) {
2069  return static_cast<idPlayer *>( ent );
2070  }
2071  }
2072  }
2073  return NULL;
2074 }
2075 
2076 /*
2077 ================
2078 idGameLocal::GetClientByCmdArgs
2079 ================
2080 */
2082  idPlayer *player;
2083  idStr client = args.Argv( 1 );
2084  if ( !client.Length() ) {
2085  return NULL;
2086  }
2087  // we don't allow numeric ui_name so this can't go wrong
2088  if ( client.IsNumeric() ) {
2089  player = GetClientByNum( atoi( client.c_str() ) );
2090  } else {
2091  player = GetClientByName( client.c_str() );
2092  }
2093  if ( !player ) {
2094  common->Printf( "Player '%s' not found\n", client.c_str() );
2095  }
2096  return player;
2097 }
2098 
2099 /*
2100 ================
2101 idGameLocal::GetNextClientNum
2102 ================
2103 */
2104 int idGameLocal::GetNextClientNum( int _current ) const {
2105  int i, current;
2106 
2107  current = 0;
2108  for ( i = 0; i < numClients; i++) {
2109  current = ( _current + i + 1 ) % numClients;
2110  if ( entities[ current ] && entities[ current ]->IsType( idPlayer::Type ) ) {
2111  return current;
2112  }
2113  }
2114 
2115  return current;
2116 }
2117 
2118 /*
2119 ================
2120 idGameLocal::GetLocalPlayer
2121 
2122 Nothing in the game tic should EVER make a decision based on what the
2123 local client number is, it shouldn't even be aware that there is a
2124 draw phase even happening. This just returns client 0, which will
2125 be correct for single player.
2126 ================
2127 */
2129  if ( localClientNum < 0 ) {
2130  return NULL;
2131  }
2132 
2133  if ( !entities[ localClientNum ] || !entities[ localClientNum ]->IsType( idPlayer::Type ) ) {
2134  // not fully in game yet
2135  return NULL;
2136  }
2137  return static_cast<idPlayer *>( entities[ localClientNum ] );
2138 }
2139 
2140 /*
2141 ================
2142 idGameLocal::SetupClientPVS
2143 ================
2144 */
2146  if ( player->GetPrivateCameraView() ) {
2148  } else if ( camera ) {
2150  } else {
2151  return pvs.SetupCurrentPVS( player->GetPVSAreas(), player->GetNumPVSAreas() );
2152  }
2153 }
2154 
2155 /*
2156 ================
2157 idGameLocal::SetupPlayerPVS
2158 ================
2159 */
2161  int i;
2162  idEntity * ent;
2163  idPlayer * player;
2164  pvsHandle_t otherPVS, newPVS;
2165 
2166  playerPVS.i = -1;
2167  for ( i = 0; i < numClients; i++ ) {
2168  ent = entities[i];
2169  if ( !ent || !ent->IsType( idPlayer::Type ) ) {
2170  continue;
2171  }
2172 
2173  player = static_cast<idPlayer *>(ent);
2174 
2175  if ( playerPVS.i == -1 ) {
2176  playerPVS = GetClientPVS( player, PVS_NORMAL );
2177  } else {
2178  otherPVS = GetClientPVS( player, PVS_NORMAL );
2179  newPVS = pvs.MergeCurrentPVS( playerPVS, otherPVS );
2181  pvs.FreeCurrentPVS( otherPVS );
2182  playerPVS = newPVS;
2183  }
2184 
2185  if ( playerConnectedAreas.i == -1 ) {
2187  } else {
2188  otherPVS = GetClientPVS( player, PVS_CONNECTED_AREAS );
2189  newPVS = pvs.MergeCurrentPVS( playerConnectedAreas, otherPVS );
2191  pvs.FreeCurrentPVS( otherPVS );
2192  playerConnectedAreas = newPVS;
2193  }
2194 
2195 #ifdef _D3XP
2196  // if portalSky is preset, then merge into pvs so we get rotating brushes, etc
2197  if ( portalSkyEnt.GetEntity() ) {
2198  idEntity *skyEnt = portalSkyEnt.GetEntity();
2199 
2200  otherPVS = pvs.SetupCurrentPVS( skyEnt->GetPVSAreas(), skyEnt->GetNumPVSAreas() );
2201  newPVS = pvs.MergeCurrentPVS( playerPVS, otherPVS );
2203  pvs.FreeCurrentPVS( otherPVS );
2204  playerPVS = newPVS;
2205 
2206  otherPVS = pvs.SetupCurrentPVS( skyEnt->GetPVSAreas(), skyEnt->GetNumPVSAreas() );
2207  newPVS = pvs.MergeCurrentPVS( playerConnectedAreas, otherPVS );
2209  pvs.FreeCurrentPVS( otherPVS );
2210  playerConnectedAreas = newPVS;
2211  }
2212 #endif
2213  }
2214 }
2215 
2216 /*
2217 ================
2218 idGameLocal::FreePlayerPVS
2219 ================
2220 */
2222  if ( playerPVS.i != -1 ) {
2224  playerPVS.i = -1;
2225  }
2226  if ( playerConnectedAreas.i != -1 ) {
2228  playerConnectedAreas.i = -1;
2229  }
2230 }
2231 
2232 /*
2233 ================
2234 idGameLocal::InPlayerPVS
2235 
2236  should only be called during entity thinking and event handling
2237 ================
2238 */
2240  if ( playerPVS.i == -1 ) {
2241  return false;
2242  }
2243  return pvs.InCurrentPVS( playerPVS, ent->GetPVSAreas(), ent->GetNumPVSAreas() );
2244 }
2245 
2246 /*
2247 ================
2248 idGameLocal::InPlayerConnectedArea
2249 
2250  should only be called during entity thinking and event handling
2251 ================
2252 */
2254  if ( playerConnectedAreas.i == -1 ) {
2255  return false;
2256  }
2258 }
2259 
2260 /*
2261 ================
2262 idGameLocal::UpdateGravity
2263 ================
2264 */
2266  idEntity *ent;
2267 
2268  if ( g_gravity.IsModified() ) {
2269  if ( g_gravity.GetFloat() == 0.0f ) {
2270  g_gravity.SetFloat( 1.0f );
2271  }
2272  gravity.Set( 0, 0, -g_gravity.GetFloat() );
2273 
2274  // update all physics objects
2275  for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
2276  if ( ent->IsType( idAFEntity_Generic::Type ) ) {
2277  idPhysics *phys = ent->GetPhysics();
2278  if ( phys ) {
2279  phys->SetGravity( gravity );
2280  }
2281  }
2282  }
2284  }
2285 }
2286 
2287 /*
2288 ================
2289 idGameLocal::GetGravity
2290 ================
2291 */
2292 const idVec3 &idGameLocal::GetGravity( void ) const {
2293  return gravity;
2294 }
2295 
2296 /*
2297 ================
2298 idGameLocal::SortActiveEntityList
2299 
2300  Sorts the active entity list such that pushing entities come first,
2301  actors come next and physics team slaves appear after their master.
2302 ================
2303 */
2305  idEntity *ent, *next_ent, *master, *part;
2306 
2307  // if the active entity list needs to be reordered to place physics team masters at the front
2308  if ( sortTeamMasters ) {
2309  for ( ent = activeEntities.Next(); ent != NULL; ent = next_ent ) {
2310  next_ent = ent->activeNode.Next();
2311  master = ent->GetTeamMaster();
2312  if ( master && master == ent ) {
2313  ent->activeNode.Remove();
2315  }
2316  }
2317  }
2318 
2319  // if the active entity list needs to be reordered to place pushers at the front
2320  if ( sortPushers ) {
2321 
2322  for ( ent = activeEntities.Next(); ent != NULL; ent = next_ent ) {
2323  next_ent = ent->activeNode.Next();
2324  master = ent->GetTeamMaster();
2325  if ( !master || master == ent ) {
2326  // check if there is an actor on the team
2327  for ( part = ent; part != NULL; part = part->GetNextTeamEntity() ) {
2328  if ( part->GetPhysics()->IsType( idPhysics_Actor::Type ) ) {
2329  break;
2330  }
2331  }
2332  // if there is an actor on the team
2333  if ( part ) {
2334  ent->activeNode.Remove();
2336  }
2337  }
2338  }
2339 
2340  for ( ent = activeEntities.Next(); ent != NULL; ent = next_ent ) {
2341  next_ent = ent->activeNode.Next();
2342  master = ent->GetTeamMaster();
2343  if ( !master || master == ent ) {
2344  // check if there is an entity on the team using parametric physics
2345  for ( part = ent; part != NULL; part = part->GetNextTeamEntity() ) {
2346  if ( part->GetPhysics()->IsType( idPhysics_Parametric::Type ) ) {
2347  break;
2348  }
2349  }
2350  // if there is an entity on the team using parametric physics
2351  if ( part ) {
2352  ent->activeNode.Remove();
2354  }
2355  }
2356  }
2357  }
2358 
2359  sortTeamMasters = false;
2360  sortPushers = false;
2361 }
2362 
2363 #ifdef _D3XP
2364 /*
2365 ================
2366 idGameLocal::RunTimeGroup2
2367 ================
2368 */
2369 void idGameLocal::RunTimeGroup2() {
2370  idEntity *ent;
2371  int num = 0;
2372 
2373  fast.Increment();
2374  fast.Get( time, previousTime, msec, framenum, realClientTime );
2375 
2376  for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) {
2377  if ( ent->timeGroup != TIME_GROUP2 ) {
2378  continue;
2379  }
2380 
2381  ent->Think();
2382  num++;
2383  }
2384 
2385  slow.Get( time, previousTime, msec, framenum, realClientTime );
2386 }
2387 #endif
2388 
2389 /*
2390 ================
2391 idGameLocal::RunFrame
2392 ================
2393 */
2395  idEntity * ent;
2396  int num;
2397  float ms;
2398  idTimer timer_think, timer_events, timer_singlethink;
2399  gameReturn_t ret;
2400  idPlayer *player;
2401  const renderView_t *view;
2402 
2403 #ifdef _DEBUG
2404  if ( isMultiplayer ) {
2405  assert( !isClient );
2406  }
2407 #endif
2408 
2409  player = GetLocalPlayer();
2410 
2411 #ifdef _D3XP
2412  ComputeSlowMsec();
2413 
2414  slow.Get( time, previousTime, msec, framenum, realClientTime );
2415  msec = slowmoMsec;
2416 #endif
2417 
2418  if ( !isMultiplayer && g_stopTime.GetBool() ) {
2419  // clear any debug lines from a previous frame
2420  gameRenderWorld->DebugClearLines( time + 1 );
2421 
2422  // set the user commands for this frame
2423  memcpy( usercmds, clientCmds, numClients * sizeof( usercmds[ 0 ] ) );
2424 
2425  if ( player ) {
2426  player->Think();
2427  }
2428  } else do {
2429  // update the game time
2430  framenum++;
2431  previousTime = time;
2432  time += msec;
2433  realClientTime = time;
2434 
2435 #ifdef _D3XP
2436  slow.Set( time, previousTime, msec, framenum, realClientTime );
2437 #endif
2438 
2439 #ifdef GAME_DLL
2440  // allow changing SIMD usage on the fly
2441  if ( com_forceGenericSIMD.IsModified() ) {
2443  }
2444 #endif
2445 
2446  // make sure the random number counter is used each frame so random events
2447  // are influenced by the player's actions
2448  random.RandomInt();
2449 
2450  if ( player ) {
2451  // update the renderview so that any gui videos play from the right frame
2452  view = player->GetRenderView();
2453  if ( view ) {
2454  gameRenderWorld->SetRenderView( view );
2455  }
2456  }
2457 
2458  // clear any debug lines from a previous frame
2459  gameRenderWorld->DebugClearLines( time );
2460 
2461  // clear any debug polygons from a previous frame
2462  gameRenderWorld->DebugClearPolygons( time );
2463 
2464  // set the user commands for this frame
2465  memcpy( usercmds, clientCmds, numClients * sizeof( usercmds[ 0 ] ) );
2466 
2467  // free old smoke particles
2469 
2470  // process events on the server
2472 
2473  // update our gravity vector if needed.
2474  UpdateGravity();
2475 
2476  // create a merged pvs for all players
2477  SetupPlayerPVS();
2478 
2479  // sort the active entity list
2481 
2482  timer_think.Clear();
2483  timer_think.Start();
2484 
2485  // let entities think
2486  if ( g_timeentities.GetFloat() ) {
2487  num = 0;
2488  for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) {
2489  if ( g_cinematic.GetBool() && inCinematic && !ent->cinematic ) {
2490  ent->GetPhysics()->UpdateTime( time );
2491  continue;
2492  }
2493  timer_singlethink.Clear();
2494  timer_singlethink.Start();
2495  ent->Think();
2496  timer_singlethink.Stop();
2497  ms = timer_singlethink.Milliseconds();
2498  if ( ms >= g_timeentities.GetFloat() ) {
2499  Printf( "%d: entity '%s': %.1f ms\n", time, ent->name.c_str(), ms );
2500  }
2501  num++;
2502  }
2503  } else {
2504  if ( inCinematic ) {
2505  num = 0;
2506  for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) {
2507  if ( g_cinematic.GetBool() && !ent->cinematic ) {
2508  ent->GetPhysics()->UpdateTime( time );
2509  continue;
2510  }
2511  ent->Think();
2512  num++;
2513  }
2514  } else {
2515  num = 0;
2516  for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) {
2517 #ifdef _D3XP
2518  if ( ent->timeGroup != TIME_GROUP1 ) {
2519  continue;
2520  }
2521 #endif
2522  ent->Think();
2523  num++;
2524  }
2525  }
2526  }
2527 
2528 #ifdef _D3XP
2529  RunTimeGroup2();
2530 #endif
2531 
2532  // remove any entities that have stopped thinking
2533  if ( numEntitiesToDeactivate ) {
2534  idEntity *next_ent;
2535  int c = 0;
2536  for( ent = activeEntities.Next(); ent != NULL; ent = next_ent ) {
2537  next_ent = ent->activeNode.Next();
2538  if ( !ent->thinkFlags ) {
2539  ent->activeNode.Remove();
2540  c++;
2541  }
2542  }
2543  //assert( numEntitiesToDeactivate == c );
2545  }
2546 
2547  timer_think.Stop();
2548  timer_events.Clear();
2549  timer_events.Start();
2550 
2551  // service any pending events
2553 
2554 #ifdef _D3XP
2555  // service pending fast events
2556  fast.Get( time, previousTime, msec, framenum, realClientTime );
2557  idEvent::ServiceFastEvents();
2558  slow.Get( time, previousTime, msec, framenum, realClientTime );
2559 #endif
2560 
2561  timer_events.Stop();
2562 
2563  // free the player pvs
2564  FreePlayerPVS();
2565 
2566  // do multiplayer related stuff
2567  if ( isMultiplayer ) {
2568  mpGame.Run();
2569  }
2570 
2571  // display how long it took to calculate the current game frame
2572  if ( g_frametime.GetBool() ) {
2573  Printf( "game %d: all:%.1f th:%.1f ev:%.1f %d ents \n",
2574  time, timer_think.Milliseconds() + timer_events.Milliseconds(),
2575  timer_think.Milliseconds(), timer_events.Milliseconds(), num );
2576  }
2577 
2578  // build the return value
2579  ret.consistencyHash = 0;
2580  ret.sessionCommand[0] = 0;
2581 
2582  if ( !isMultiplayer && player ) {
2583  ret.health = player->health;
2584  ret.heartRate = player->heartRate;
2585  ret.stamina = idMath::FtoiFast( player->stamina );
2586  // combat is a 0-100 value based on lastHitTime and lastDmgTime
2587  // each make up 50% of the time spread over 10 seconds
2588  ret.combat = 0;
2589  if ( player->lastDmgTime > 0 && time < player->lastDmgTime + 10000 ) {
2590  ret.combat += 50.0f * (float) ( time - player->lastDmgTime ) / 10000;
2591  }
2592  if ( player->lastHitTime > 0 && time < player->lastHitTime + 10000 ) {
2593  ret.combat += 50.0f * (float) ( time - player->lastHitTime ) / 10000;
2594  }
2595  }
2596 
2597  // see if a target_sessionCommand has forced a changelevel
2598  if ( sessionCommand.Length() ) {
2599  strncpy( ret.sessionCommand, sessionCommand, sizeof( ret.sessionCommand ) );
2600  break;
2601  }
2602 
2603  // make sure we don't loop forever when skipping a cinematic
2604  if ( skipCinematic && ( time > cinematicMaxSkipTime ) ) {
2605  Warning( "Exceeded maximum cinematic skip length. Cinematic may be looping infinitely." );
2606  skipCinematic = false;
2607  break;
2608  }
2609  } while( ( inCinematic || ( time < cinematicStopTime ) ) && skipCinematic );
2610 
2612  if ( skipCinematic ) {
2613  soundSystem->SetMute( false );
2614  skipCinematic = false;
2615  }
2616 
2617  // show any debug info for this frame
2618  RunDebugInfo();
2619  D_DrawDebugLines();
2620 
2621  return ret;
2622 }
2623 
2624 
2625 /*
2626 ======================================================================
2627 
2628  Game view drawing
2629 
2630 ======================================================================
2631 */
2632 
2633 /*
2634 ====================
2635 idGameLocal::CalcFov
2636 
2637 Calculates the horizontal and vertical field of view based on a horizontal field of view and custom aspect ratio
2638 ====================
2639 */
2640 void idGameLocal::CalcFov( float base_fov, float &fov_x, float &fov_y ) const {
2641  float x;
2642  float y;
2643  float ratio_x;
2644  float ratio_y;
2645 
2646  if ( !sys->FPU_StackIsEmpty() ) {
2647  Printf( sys->FPU_GetState() );
2648  Error( "idGameLocal::CalcFov: FPU stack not empty" );
2649  }
2650 
2651  // first, calculate the vertical fov based on a 640x480 view
2652  x = 640.0f / tan( base_fov / 360.0f * idMath::PI );
2653  y = atan2( 480.0f, x );
2654  fov_y = y * 360.0f / idMath::PI;
2655 
2656  // FIXME: somehow, this is happening occasionally
2657  assert( fov_y > 0 );
2658  if ( fov_y <= 0 ) {
2659  Printf( sys->FPU_GetState() );
2660  Error( "idGameLocal::CalcFov: bad result" );
2661  }
2662 
2663  switch( r_aspectRatio.GetInteger() ) {
2664  default :
2665  case 0 :
2666  // 4:3
2667  fov_x = base_fov;
2668  return;
2669  break;
2670 
2671  case 1 :
2672  // 16:9
2673  ratio_x = 16.0f;
2674  ratio_y = 9.0f;
2675  break;
2676 
2677  case 2 :
2678  // 16:10
2679  ratio_x = 16.0f;
2680  ratio_y = 10.0f;
2681  break;
2682  }
2683 
2684  y = ratio_y / tan( fov_y / 360.0f * idMath::PI );
2685  fov_x = atan2( ratio_x, y ) * 360.0f / idMath::PI;
2686 
2687  if ( fov_x < base_fov ) {
2688  fov_x = base_fov;
2689  x = ratio_x / tan( fov_x / 360.0f * idMath::PI );
2690  fov_y = atan2( ratio_y, x ) * 360.0f / idMath::PI;
2691  }
2692 
2693  // FIXME: somehow, this is happening occasionally
2694  assert( ( fov_x > 0 ) && ( fov_y > 0 ) );
2695  if ( ( fov_y <= 0 ) || ( fov_x <= 0 ) ) {
2696  Printf( sys->FPU_GetState() );
2697  Error( "idGameLocal::CalcFov: bad result" );
2698  }
2699 }
2700 
2701 /*
2702 ================
2703 idGameLocal::Draw
2704 
2705 makes rendering and sound system calls
2706 ================
2707 */
2708 bool idGameLocal::Draw( int clientNum ) {
2709  if ( isMultiplayer ) {
2710  return mpGame.Draw( clientNum );
2711  }
2712 
2713  idPlayer *player = static_cast<idPlayer *>(entities[ clientNum ]);
2714 
2715  if ( !player ) {
2716  return false;
2717  }
2718 
2719  // render the scene
2720  player->playerView.RenderPlayerView( player->hud );
2721 
2722  return true;
2723 }
2724 
2725 /*
2726 ================
2727 idGameLocal::HandleESC
2728 ================
2729 */
2731  if ( isMultiplayer ) {
2732  *gui = StartMenu();
2733  // we may set the gui back to NULL to hide it
2734  return ESC_GUI;
2735  }
2736  idPlayer *player = GetLocalPlayer();
2737  if ( player ) {
2738  if ( player->HandleESC() ) {
2739  return ESC_IGNORE;
2740  } else {
2741  return ESC_MAIN;
2742  }
2743  }
2744  return ESC_MAIN;
2745 }
2746 
2747 /*
2748 ================
2749 idGameLocal::StartMenu
2750 ================
2751 */
2753  if ( !isMultiplayer ) {
2754  return NULL;
2755  }
2756  return mpGame.StartMenu();
2757 }
2758 
2759 /*
2760 ================
2761 idGameLocal::HandleGuiCommands
2762 ================
2763 */
2764 const char* idGameLocal::HandleGuiCommands( const char *menuCommand ) {
2765  if ( !isMultiplayer ) {
2766  return NULL;
2767  }
2768  return mpGame.HandleGuiCommands( menuCommand );
2769 }
2770 
2771 /*
2772 ================
2773 idGameLocal::HandleMainMenuCommands
2774 ================
2775 */
2776 void idGameLocal::HandleMainMenuCommands( const char *menuCommand, idUserInterface *gui ) { }
2777 
2778 /*
2779 ================
2780 idGameLocal::GetLevelMap
2781 
2782  should only be used for in-game level editing
2783 ================
2784 */
2786  if ( mapFile && mapFile->HasPrimitiveData()) {
2787  return mapFile;
2788  }
2789  if ( !mapFileName.Length() ) {
2790  return NULL;
2791  }
2792 
2793  if ( mapFile ) {
2794  delete mapFile;
2795  }
2796 
2797  mapFile = new idMapFile;
2798  if ( !mapFile->Parse( mapFileName ) ) {
2799  delete mapFile;
2800  mapFile = NULL;
2801  }
2802 
2803  return mapFile;
2804 }
2805 
2806 /*
2807 ================
2808 idGameLocal::GetMapName
2809 ================
2810 */
2811 const char *idGameLocal::GetMapName( void ) const {
2812  return mapFileName.c_str();
2813 }
2814 
2815 /*
2816 ================
2817 idGameLocal::CallFrameCommand
2818 ================
2819 */
2820 void idGameLocal::CallFrameCommand( idEntity *ent, const function_t *frameCommand ) {
2821  frameCommandThread->CallFunction( ent, frameCommand, true );
2823 }
2824 
2825 /*
2826 ================
2827 idGameLocal::CallObjectFrameCommand
2828 ================
2829 */
2830 void idGameLocal::CallObjectFrameCommand( idEntity *ent, const char *frameCommand ) {
2831  const function_t *func;
2832 
2833  func = ent->scriptObject.GetFunction( frameCommand );
2834  if ( !func ) {
2835  if ( !ent->IsType( idTestModel::Type ) ) {
2836  Error( "Unknown function '%s' called for frame command on entity '%s'", frameCommand, ent->name.c_str() );
2837  }
2838  } else {
2839  frameCommandThread->CallFunction( ent, func, true );
2841  }
2842 }
2843 
2844 /*
2845 ================
2846 idGameLocal::ShowTargets
2847 ================
2848 */
2850  idMat3 axis = GetLocalPlayer()->viewAngles.ToMat3();
2851  idVec3 up = axis[ 2 ] * 5.0f;
2852  const idVec3 &viewPos = GetLocalPlayer()->GetPhysics()->GetOrigin();
2853  idBounds viewTextBounds( viewPos );
2854  idBounds viewBounds( viewPos );
2855  idBounds box( idVec3( -4.0f, -4.0f, -4.0f ), idVec3( 4.0f, 4.0f, 4.0f ) );
2856  idEntity *ent;
2857  idEntity *target;
2858  int i;
2859  idBounds totalBounds;
2860 
2861  viewTextBounds.ExpandSelf( 128.0f );
2862  viewBounds.ExpandSelf( 512.0f );
2863  for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
2864  totalBounds = ent->GetPhysics()->GetAbsBounds();
2865  for( i = 0; i < ent->targets.Num(); i++ ) {
2866  target = ent->targets[ i ].GetEntity();
2867  if ( target ) {
2868  totalBounds.AddBounds( target->GetPhysics()->GetAbsBounds() );
2869  }
2870  }
2871 
2872  if ( !viewBounds.IntersectsBounds( totalBounds ) ) {
2873  continue;
2874  }
2875 
2876  float dist;
2877  idVec3 dir = totalBounds.GetCenter() - viewPos;
2878  dir.NormalizeFast();
2879  totalBounds.RayIntersection( viewPos, dir, dist );
2880  float frac = ( 512.0f - dist ) / 512.0f;
2881  if ( frac < 0.0f ) {
2882  continue;
2883  }
2884 
2885  gameRenderWorld->DebugBounds( ( ent->IsHidden() ? colorLtGrey : colorOrange ) * frac, ent->GetPhysics()->GetAbsBounds() );
2886  if ( viewTextBounds.IntersectsBounds( ent->GetPhysics()->GetAbsBounds() ) ) {
2887  idVec3 center = ent->GetPhysics()->GetAbsBounds().GetCenter();
2888  gameRenderWorld->DrawText( ent->name.c_str(), center - up, 0.1f, colorWhite * frac, axis, 1 );
2889  gameRenderWorld->DrawText( ent->GetEntityDefName(), center, 0.1f, colorWhite * frac, axis, 1 );
2890  gameRenderWorld->DrawText( va( "#%d", ent->entityNumber ), center + up, 0.1f, colorWhite * frac, axis, 1 );
2891  }
2892 
2893  for( i = 0; i < ent->targets.Num(); i++ ) {
2894  target = ent->targets[ i ].GetEntity();
2895  if ( target ) {
2896  gameRenderWorld->DebugArrow( colorYellow * frac, ent->GetPhysics()->GetAbsBounds().GetCenter(), target->GetPhysics()->GetOrigin(), 10, 0 );
2897  gameRenderWorld->DebugBounds( colorGreen * frac, box, target->GetPhysics()->GetOrigin() );
2898  }
2899  }
2900  }
2901 }
2902 
2903 /*
2904 ================
2905 idGameLocal::RunDebugInfo
2906 ================
2907 */
2909  idEntity *ent;
2910  idPlayer *player;
2911 
2912  player = GetLocalPlayer();
2913  if ( !player ) {
2914  return;
2915  }
2916 
2917  const idVec3 &origin = player->GetPhysics()->GetOrigin();
2918 
2919  if ( g_showEntityInfo.GetBool() ) {
2920  idMat3 axis = player->viewAngles.ToMat3();
2921  idVec3 up = axis[ 2 ] * 5.0f;
2922  idBounds viewTextBounds( origin );
2923  idBounds viewBounds( origin );
2924 
2925  viewTextBounds.ExpandSelf( 128.0f );
2926  viewBounds.ExpandSelf( 512.0f );
2927  for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
2928  // don't draw the worldspawn
2929  if ( ent == world ) {
2930  continue;
2931  }
2932 
2933  // skip if the entity is very far away
2934  if ( !viewBounds.IntersectsBounds( ent->GetPhysics()->GetAbsBounds() ) ) {
2935  continue;
2936  }
2937 
2938  const idBounds &entBounds = ent->GetPhysics()->GetAbsBounds();
2939  int contents = ent->GetPhysics()->GetContents();
2940  if ( contents & CONTENTS_BODY ) {
2941  gameRenderWorld->DebugBounds( colorCyan, entBounds );
2942  } else if ( contents & CONTENTS_TRIGGER ) {
2943  gameRenderWorld->DebugBounds( colorOrange, entBounds );
2944  } else if ( contents & CONTENTS_SOLID ) {
2945  gameRenderWorld->DebugBounds( colorGreen, entBounds );
2946  } else {
2947  if ( !entBounds.GetVolume() ) {
2948  gameRenderWorld->DebugBounds( colorMdGrey, entBounds.Expand( 8.0f ) );
2949  } else {
2950  gameRenderWorld->DebugBounds( colorMdGrey, entBounds );
2951  }
2952  }
2953  if ( viewTextBounds.IntersectsBounds( entBounds ) ) {
2954  gameRenderWorld->DrawText( ent->name.c_str(), entBounds.GetCenter(), 0.1f, colorWhite, axis, 1 );
2955  gameRenderWorld->DrawText( va( "#%d", ent->entityNumber ), entBounds.GetCenter() + up, 0.1f, colorWhite, axis, 1 );
2956  }
2957  }
2958  }
2959 
2960  // debug tool to draw bounding boxes around active entities
2961  if ( g_showActiveEntities.GetBool() ) {
2962  for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) {
2963  idBounds b = ent->GetPhysics()->GetBounds();
2964  if ( b.GetVolume() <= 0 ) {
2965  b[0][0] = b[0][1] = b[0][2] = -8;
2966  b[1][0] = b[1][1] = b[1][2] = 8;
2967  }
2968  if ( ent->fl.isDormant ) {
2969  gameRenderWorld->DebugBounds( colorYellow, b, ent->GetPhysics()->GetOrigin() );
2970  } else {
2971  gameRenderWorld->DebugBounds( colorGreen, b, ent->GetPhysics()->GetOrigin() );
2972  }
2973  }
2974  }
2975 
2976  if ( g_showTargets.GetBool() ) {
2977  ShowTargets();
2978  }
2979 
2980  if ( g_showTriggers.GetBool() ) {
2982  }
2983 
2984  if ( ai_showCombatNodes.GetBool() ) {
2986  }
2987 
2988  if ( ai_showPaths.GetBool() ) {
2990  }
2991 
2992  if ( g_editEntityMode.GetBool() ) {
2994  }
2995 
2996  if ( g_showCollisionWorld.GetBool() ) {
2997  collisionModelManager->DrawModel( 0, vec3_origin, mat3_identity, origin, 128.0f );
2998  }
2999 
3000  if ( g_showCollisionModels.GetBool() ) {
3002  }
3003 
3004  if ( g_showCollisionTraces.GetBool() ) {
3006  }
3007 
3008  if ( g_showPVS.GetInteger() ) {
3009  pvs.DrawPVS( origin, ( g_showPVS.GetInteger() == 2 ) ? PVS_ALL_PORTALS_OPEN : PVS_NORMAL );
3010  }
3011 
3012  if ( aas_test.GetInteger() >= 0 ) {
3013  idAAS *aas = GetAAS( aas_test.GetInteger() );
3014  if ( aas ) {
3015  aas->Test( origin );
3016  if ( ai_testPredictPath.GetBool() ) {
3017  idVec3 velocity;
3019 
3020  velocity.x = cos( DEG2RAD( player->viewAngles.yaw ) ) * 100.0f;
3021  velocity.y = sin( DEG2RAD( player->viewAngles.yaw ) ) * 100.0f;
3022  velocity.z = 0.0f;
3023  idAI::PredictPath( player, aas, origin, velocity, 1000, 100, SE_ENTER_OBSTACLE | SE_BLOCKED | SE_ENTER_LEDGE_AREA, path );
3024  }
3025  }
3026  }
3027 
3028  if ( ai_showObstacleAvoidance.GetInteger() == 2 ) {
3029  idAAS *aas = GetAAS( 0 );
3030  if ( aas ) {
3031  idVec3 seekPos;
3033 
3034  seekPos = player->GetPhysics()->GetOrigin() + player->viewAxis[0] * 200.0f;
3035  idAI::FindPathAroundObstacles( player->GetPhysics(), aas, NULL, player->GetPhysics()->GetOrigin(), seekPos, path );
3036  }
3037  }
3038 
3039  // collision map debug output
3040  collisionModelManager->DebugOutput( player->GetEyePosition() );
3041 }
3042 
3043 /*
3044 ==================
3045 idGameLocal::NumAAS
3046 ==================
3047 */
3048 int idGameLocal::NumAAS( void ) const {
3049  return aasList.Num();
3050 }
3051 
3052 /*
3053 ==================
3054 idGameLocal::GetAAS
3055 ==================
3056 */
3057 idAAS *idGameLocal::GetAAS( int num ) const {
3058  if ( ( num >= 0 ) && ( num < aasList.Num() ) ) {
3059  if ( aasList[ num ] && aasList[ num ]->GetSettings() ) {
3060  return aasList[ num ];
3061  }
3062  }
3063  return NULL;
3064 }
3065 
3066 /*
3067 ==================
3068 idGameLocal::GetAAS
3069 ==================
3070 */
3071 idAAS *idGameLocal::GetAAS( const char *name ) const {
3072  int i;
3073 
3074  for ( i = 0; i < aasNames.Num(); i++ ) {
3075  if ( aasNames[ i ] == name ) {
3076  if ( !aasList[ i ]->GetSettings() ) {
3077  return NULL;
3078  } else {
3079  return aasList[ i ];
3080  }
3081  }
3082  }
3083  return NULL;
3084 }
3085 
3086 /*
3087 ==================
3088 idGameLocal::SetAASAreaState
3089 ==================
3090 */
3091 void idGameLocal::SetAASAreaState( const idBounds &bounds, const int areaContents, bool closed ) {
3092  int i;
3093 
3094  for( i = 0; i < aasList.Num(); i++ ) {
3095  aasList[ i ]->SetAreaState( bounds, areaContents, closed );
3096  }
3097 }
3098 
3099 /*
3100 ==================
3101 idGameLocal::AddAASObstacle
3102 ==================
3103 */
3105  int i;
3106  aasHandle_t obstacle;
3107  aasHandle_t check;
3108 
3109  if ( !aasList.Num() ) {
3110  return -1;
3111  }
3112 
3113  obstacle = aasList[ 0 ]->AddObstacle( bounds );
3114  for( i = 1; i < aasList.Num(); i++ ) {
3115  check = aasList[ i ]->AddObstacle( bounds );
3116  assert( check == obstacle );
3117  }
3118 
3119  return obstacle;
3120 }
3121 
3122 /*
3123 ==================
3124 idGameLocal::RemoveAASObstacle
3125 ==================
3126 */
3128  int i;
3129 
3130  for( i = 0; i < aasList.Num(); i++ ) {
3131  aasList[ i ]->RemoveObstacle( handle );
3132  }
3133 }
3134 
3135 /*
3136 ==================
3137 idGameLocal::RemoveAllAASObstacles
3138 ==================
3139 */
3141  int i;
3142 
3143  for( i = 0; i < aasList.Num(); i++ ) {
3144  aasList[ i ]->RemoveAllObstacles();
3145  }
3146 }
3147 
3148 /*
3149 ==================
3150 idGameLocal::CheatsOk
3151 ==================
3152 */
3153 bool idGameLocal::CheatsOk( bool requirePlayer ) {
3154  idPlayer *player;
3155 
3156  if ( isMultiplayer && !cvarSystem->GetCVarBool( "net_allowCheats" ) ) {
3157  Printf( "Not allowed in multiplayer.\n" );
3158  return false;
3159  }
3160 
3161  if ( developer.GetBool() ) {
3162  return true;
3163  }
3164 
3165  player = GetLocalPlayer();
3166  if ( !requirePlayer || ( player && ( player->health > 0 ) ) ) {
3167  return true;
3168  }
3169 
3170  Printf( "You must be alive to use this command.\n" );
3171 
3172  return false;
3173 }
3174 
3175 /*
3176 ===================
3177 idGameLocal::RegisterEntity
3178 ===================
3179 */
3181  int spawn_entnum;
3182 
3183  if ( spawnCount >= ( 1 << ( 32 - GENTITYNUM_BITS ) ) ) {
3184  Error( "idGameLocal::RegisterEntity: spawn count overflow" );
3185  }
3186 
3187  if ( !spawnArgs.GetInt( "spawn_entnum", "0", spawn_entnum ) ) {
3189  firstFreeIndex++;
3190  }
3192  Error( "no free entities" );
3193  }
3194  spawn_entnum = firstFreeIndex++;
3195  }
3196 
3197  entities[ spawn_entnum ] = ent;
3198  spawnIds[ spawn_entnum ] = spawnCount++;
3199  ent->entityNumber = spawn_entnum;
3202 
3203  if ( spawn_entnum >= num_entities ) {
3204  num_entities++;
3205  }
3206 }
3207 
3208 /*
3209 ===================
3210 idGameLocal::UnregisterEntity
3211 ===================
3212 */
3214  assert( ent );
3215 
3216  if ( editEntities ) {
3218  }
3219 
3220  if ( ( ent->entityNumber != ENTITYNUM_NONE ) && ( entities[ ent->entityNumber ] == ent ) ) {
3221  ent->spawnNode.Remove();
3222  entities[ ent->entityNumber ] = NULL;
3223  spawnIds[ ent->entityNumber ] = -1;
3224  if ( ent->entityNumber >= MAX_CLIENTS && ent->entityNumber < firstFreeIndex ) {
3226  }
3228  }
3229 }
3230 
3231 /*
3232 ================
3233 idGameLocal::SpawnEntityType
3234 ================
3235 */
3236 idEntity *idGameLocal::SpawnEntityType( const idTypeInfo &classdef, const idDict *args, bool bIsClientReadSnapshot ) {
3237  idClass *obj;
3238 
3239 #if _DEBUG
3240  if ( isClient ) {
3241  assert( bIsClientReadSnapshot );
3242  }
3243 #endif
3244 
3245  if ( !classdef.IsType( idEntity::Type ) ) {
3246  Error( "Attempted to spawn non-entity class '%s'", classdef.classname );
3247  }
3248 
3249  try {
3250  if ( args ) {
3251  spawnArgs = *args;
3252  } else {
3253  spawnArgs.Clear();
3254  }
3255  obj = classdef.CreateInstance();
3256  obj->CallSpawn();
3257  }
3258 
3259  catch( idAllocError & ) {
3260  obj = NULL;
3261  }
3262  spawnArgs.Clear();
3263 
3264  return static_cast<idEntity *>(obj);
3265 }
3266 
3267 /*
3268 ===================
3269 idGameLocal::SpawnEntityDef
3270 
3271 Finds the spawn function for the entity and calls it,
3272 returning false if not found
3273 ===================
3274 */
3275 bool idGameLocal::SpawnEntityDef( const idDict &args, idEntity **ent, bool setDefaults ) {
3276  const char *classname;
3277  const char *spawn;
3278  idTypeInfo *cls;
3279  idClass *obj;
3280  idStr error;
3281  const char *name;
3282 
3283  if ( ent ) {
3284  *ent = NULL;
3285  }
3286 
3287  spawnArgs = args;
3288 
3289  if ( spawnArgs.GetString( "name", "", &name ) ) {
3290  sprintf( error, " on '%s'", name);
3291  }
3292 
3293  spawnArgs.GetString( "classname", NULL, &classname );
3294 
3295  const idDeclEntityDef *def = FindEntityDef( classname, false );
3296 
3297  if ( !def ) {
3298  Warning( "Unknown classname '%s'%s.", classname, error.c_str() );
3299  return false;
3300  }
3301 
3302  spawnArgs.SetDefaults( &def->dict );
3303 
3304 #ifdef _D3XP
3305  if ( !spawnArgs.FindKey( "slowmo" ) ) {
3306  bool slowmo = true;
3307 
3308  for ( int i = 0; fastEntityList[i]; i++ ) {
3309  if ( !idStr::Cmp( classname, fastEntityList[i] ) ) {
3310  slowmo = false;
3311  break;
3312  }
3313  }
3314 
3315  if ( !slowmo ) {
3316  spawnArgs.SetBool( "slowmo", slowmo );
3317  }
3318  }
3319 #endif
3320 
3321  // check if we should spawn a class object
3322  spawnArgs.GetString( "spawnclass", NULL, &spawn );
3323  if ( spawn ) {
3324 
3325  cls = idClass::GetClass( spawn );
3326  if ( !cls ) {
3327  Warning( "Could not spawn '%s'. Class '%s' not found %s.", classname, spawn, error.c_str() );
3328  return false;
3329  }
3330 
3331  obj = cls->CreateInstance();
3332  if ( !obj ) {
3333  Warning( "Could not spawn '%s'. Instance could not be created %s.", classname, error.c_str() );
3334  return false;
3335  }
3336 
3337  obj->CallSpawn();
3338 
3339  if ( ent && obj->IsType( idEntity::Type ) ) {
3340  *ent = static_cast<idEntity *>(obj);
3341  }
3342 
3343  return true;
3344  }
3345 
3346  // check if we should call a script function to spawn
3347  spawnArgs.GetString( "spawnfunc", NULL, &spawn );
3348  if ( spawn ) {
3349  const function_t *func = program.FindFunction( spawn );
3350  if ( !func ) {
3351  Warning( "Could not spawn '%s'. Script function '%s' not found%s.", classname, spawn, error.c_str() );
3352  return false;
3353  }
3354  idThread *thread = new idThread( func );
3355  thread->DelayedStart( 0 );
3356  return true;
3357  }
3358 
3359  Warning( "%s doesn't include a spawnfunc or spawnclass%s.", classname, error.c_str() );
3360  return false;
3361 }
3362 
3363 /*
3364 ================
3365 idGameLocal::FindEntityDef
3366 ================
3367 */
3368 const idDeclEntityDef *idGameLocal::FindEntityDef( const char *name, bool makeDefault ) const {
3369  const idDecl *decl = NULL;
3370  if ( isMultiplayer ) {
3371  decl = declManager->FindType( DECL_ENTITYDEF, va( "%s_mp", name ), false );
3372  }
3373  if ( !decl ) {
3374  decl = declManager->FindType( DECL_ENTITYDEF, name, makeDefault );
3375  }
3376  return static_cast<const idDeclEntityDef *>( decl );
3377 }
3378 
3379 /*
3380 ================
3381 idGameLocal::FindEntityDefDict
3382 ================
3383 */
3384 const idDict *idGameLocal::FindEntityDefDict( const char *name, bool makeDefault ) const {
3385  const idDeclEntityDef *decl = FindEntityDef( name, makeDefault );
3386  return decl ? &decl->dict : NULL;
3387 }
3388 
3389 /*
3390 ================
3391 idGameLocal::InhibitEntitySpawn
3392 ================
3393 */
3395 
3396  bool result = false;
3397 
3398  if ( isMultiplayer ) {
3399  spawnArgs.GetBool( "not_multiplayer", "0", result );
3400  } else if ( g_skill.GetInteger() == 0 ) {
3401  spawnArgs.GetBool( "not_easy", "0", result );
3402  } else if ( g_skill.GetInteger() == 1 ) {
3403  spawnArgs.GetBool( "not_medium", "0", result );
3404  } else {
3405  spawnArgs.GetBool( "not_hard", "0", result );
3406 #ifdef _D3XP
3407  if ( !result && g_skill.GetInteger() == 3 ) {
3408  spawnArgs.GetBool( "not_nightmare", "0", result );
3409  }
3410 #endif
3411  }
3412 
3413 
3414  const char *name;
3415 #ifndef ID_DEMO_BUILD
3416  if ( g_skill.GetInteger() == 3 ) {
3417  name = spawnArgs.GetString( "classname" );
3418  // _D3XP :: remove moveable medkit packs also
3419  if ( idStr::Icmp( name, "item_medkit" ) == 0 || idStr::Icmp( name, "item_medkit_small" ) == 0 ||
3420  idStr::Icmp( name, "moveable_item_medkit" ) == 0 || idStr::Icmp( name, "moveable_item_medkit_small" ) == 0 ) {
3421 
3422  result = true;
3423  }
3424  }
3425 #endif
3426 
3427  if ( gameLocal.isMultiplayer ) {
3428  name = spawnArgs.GetString( "classname" );
3429  if ( idStr::Icmp( name, "weapon_bfg" ) == 0 || idStr::Icmp( name, "weapon_soulcube" ) == 0 ) {
3430  result = true;
3431  }
3432  }
3433 
3434  return result;
3435 }
3436 
3437 /*
3438 ================
3439 idGameLocal::SetSkill
3440 ================
3441 */
3443  int skill_level;
3444 
3445  if ( value < 0 ) {
3446  skill_level = 0;
3447  } else if ( value > 3 ) {
3448  skill_level = 3;
3449  } else {
3450  skill_level = value;
3451  }
3452 
3453  g_skill.SetInteger( skill_level );
3454 }
3455 
3456 /*
3457 ==============
3458 idGameLocal::GameState
3459 
3460 Used to allow entities to know if they're being spawned during the initial spawn.
3461 ==============
3462 */
3464  return gamestate;
3465 }
3466 
3467 /*
3468 ==============
3469 idGameLocal::SpawnMapEntities
3470 
3471 Parses textual entity definitions out of an entstring and spawns gentities.
3472 ==============
3473 */
3475  int i;
3476  int num;
3477  int inhibit;
3478  idMapEntity *mapEnt;
3479  int numEntities;
3480  idDict args;
3481 
3482  Printf( "Spawning entities\n" );
3483 
3484  if ( mapFile == NULL ) {
3485  Printf("No mapfile present\n");
3486  return;
3487  }
3488 
3490 
3491  numEntities = mapFile->GetNumEntities();
3492  if ( numEntities == 0 ) {
3493  Error( "...no entities" );
3494  }
3495 
3496  // the worldspawn is a special that performs any global setup
3497  // needed by a level
3498  mapEnt = mapFile->GetEntity( 0 );
3499  args = mapEnt->epairs;
3500  args.SetInt( "spawn_entnum", ENTITYNUM_WORLD );
3501  if ( !SpawnEntityDef( args ) || !entities[ ENTITYNUM_WORLD ] || !entities[ ENTITYNUM_WORLD ]->IsType( idWorldspawn::Type ) ) {
3502  Error( "Problem spawning world entity" );
3503  }
3504 
3505  num = 1;
3506  inhibit = 0;
3507 
3508  for ( i = 1 ; i < numEntities ; i++ ) {
3509  mapEnt = mapFile->GetEntity( i );
3510  args = mapEnt->epairs;
3511 
3512  if ( !InhibitEntitySpawn( args ) ) {
3513  // precache any media specified in the map entity
3514  CacheDictionaryMedia( &args );
3515 
3516  SpawnEntityDef( args );
3517  num++;
3518  } else {
3519  inhibit++;
3520  }
3521  }
3522 
3523  Printf( "...%i entities spawned, %i inhibited\n\n", num, inhibit );
3524 }
3525 
3526 /*
3527 ================
3528 idGameLocal::AddEntityToHash
3529 ================
3530 */
3531 void idGameLocal::AddEntityToHash( const char *name, idEntity *ent ) {
3532  if ( FindEntity( name ) ) {
3533  Error( "Multiple entities named '%s'", name );
3534  }
3535  entityHash.Add( entityHash.GenerateKey( name, true ), ent->entityNumber );
3536 }
3537 
3538 /*
3539 ================
3540 idGameLocal::RemoveEntityFromHash
3541 ================
3542 */
3544  int hash, i;
3545 
3546  hash = entityHash.GenerateKey( name, true );
3547  for ( i = entityHash.First( hash ); i != -1; i = entityHash.Next( i ) ) {
3548  if ( entities[i] && entities[i] == ent && entities[i]->name.Icmp( name ) == 0 ) {
3549  entityHash.Remove( hash, i );
3550  return true;
3551  }
3552  }
3553  return false;
3554 }
3555 
3556 /*
3557 ================
3558 idGameLocal::GetTargets
3559 ================
3560 */
3561 int idGameLocal::GetTargets( const idDict &args, idList< idEntityPtr<idEntity> > &list, const char *ref ) const {
3562  int i, num, refLength;
3563  const idKeyValue *arg;
3564  idEntity *ent;
3565 
3566  list.Clear();
3567 
3568  refLength = strlen( ref );
3569  num = args.GetNumKeyVals();
3570  for( i = 0; i < num; i++ ) {
3571 
3572  arg = args.GetKeyVal( i );
3573  if ( arg->GetKey().Icmpn( ref, refLength ) == 0 ) {
3574 
3575  ent = FindEntity( arg->GetValue() );
3576  if ( ent ) {
3577  idEntityPtr<idEntity> &entityPtr = list.Alloc();
3578  entityPtr = ent;
3579  }
3580  }
3581  }
3582 
3583  return list.Num();
3584 }
3585 
3586 /*
3587 =============
3588 idGameLocal::GetTraceEntity
3589 
3590 returns the master entity of a trace. for example, if the trace entity is the player's head, it will return the player.
3591 =============
3592 */
3594  idEntity *master;
3595 
3596  if ( !entities[ trace.c.entityNum ] ) {
3597  return NULL;
3598  }
3599  master = entities[ trace.c.entityNum ]->GetBindMaster();
3600  if ( master ) {
3601  return master;
3602  }
3603  return entities[ trace.c.entityNum ];
3604 }
3605 
3606 /*
3607 =============
3608 idGameLocal::ArgCompletion_EntityName
3609 
3610 Argument completion for entity names
3611 =============
3612 */
3613 void idGameLocal::ArgCompletion_EntityName( const idCmdArgs &args, void(*callback)( const char *s ) ) {
3614  int i;
3615 
3616  for( i = 0; i < gameLocal.num_entities; i++ ) {
3617  if ( gameLocal.entities[ i ] ) {
3618  callback( va( "%s %s", args.Argv( 0 ), gameLocal.entities[ i ]->name.c_str() ) );
3619  }
3620  }
3621 }
3622 
3623 /*
3624 =============
3625 idGameLocal::FindEntity
3626 
3627 Returns the entity whose name matches the specified string.
3628 =============
3629 */
3630 idEntity *idGameLocal::FindEntity( const char *name ) const {
3631  int hash, i;
3632 
3633  hash = entityHash.GenerateKey( name, true );
3634  for ( i = entityHash.First( hash ); i != -1; i = entityHash.Next( i ) ) {
3635  if ( entities[i] && entities[i]->name.Icmp( name ) == 0 ) {
3636  return entities[i];
3637  }
3638  }
3639 
3640  return NULL;
3641 }
3642 
3643 /*
3644 =============
3645 idGameLocal::FindEntityUsingDef
3646 
3647 Searches all active entities for the next one using the specified entityDef.
3648 
3649 Searches beginning at the entity after from, or the beginning if NULL
3650 NULL will be returned if the end of the list is reached.
3651 =============
3652 */
3653 idEntity *idGameLocal::FindEntityUsingDef( idEntity *from, const char *match ) const {
3654  idEntity *ent;
3655 
3656  if ( !from ) {
3657  ent = spawnedEntities.Next();
3658  } else {
3659  ent = from->spawnNode.Next();
3660  }
3661 
3662  for ( ; ent != NULL; ent = ent->spawnNode.Next() ) {
3663  assert( ent );
3664  if ( idStr::Icmp( ent->GetEntityDefName(), match ) == 0 ) {
3665  return ent;
3666  }
3667  }
3668 
3669  return NULL;
3670 }
3671 
3672 /*
3673 =============
3674 idGameLocal::FindTraceEntity
3675 
3676 Searches all active entities for the closest ( to start ) match that intersects
3677 the line start,end
3678 =============
3679 */
3681  idEntity *ent;
3682  idEntity *bestEnt;
3683  float scale;
3684  float bestScale;
3685  idBounds b;
3686 
3687  bestEnt = NULL;
3688  bestScale = 1.0f;
3689  for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
3690  if ( ent->IsType( c ) && ent != skip ) {
3691  b = ent->GetPhysics()->GetAbsBounds().Expand( 16 );
3692  if ( b.RayIntersection( start, end-start, scale ) ) {
3693  if ( scale >= 0.0f && scale < bestScale ) {
3694  bestEnt = ent;
3695  bestScale = scale;
3696  }
3697  }
3698  }
3699  }
3700 
3701  return bestEnt;
3702 }
3703 
3704 /*
3705 ================
3706 idGameLocal::EntitiesWithinRadius
3707 ================
3708 */
3709 int idGameLocal::EntitiesWithinRadius( const idVec3 org, float radius, idEntity **entityList, int maxCount ) const {
3710  idEntity *ent;
3711  idBounds bo( org );
3712  int entCount = 0;
3713 
3714  bo.ExpandSelf( radius );
3715  for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
3716  if ( ent->GetPhysics()->GetAbsBounds().IntersectsBounds( bo ) ) {
3717  entityList[entCount++] = ent;
3718  }
3719  }
3720 
3721  return entCount;
3722 }
3723 
3724 /*
3725 =================
3726 idGameLocal::KillBox
3727 
3728 Kills all entities that would touch the proposed new positioning of ent. The ent itself will not being killed.
3729 Checks if player entities are in the teleporter, and marks them to die at teleport exit instead of immediately.
3730 If catch_teleport, this only marks teleport players for death on exit
3731 =================
3732 */
3733 void idGameLocal::KillBox( idEntity *ent, bool catch_teleport ) {
3734  int i;
3735  int num;
3736  idEntity * hit;
3737  idClipModel *cm;
3738  idClipModel *clipModels[ MAX_GENTITIES ];
3739  idPhysics *phys;
3740 
3741  phys = ent->GetPhysics();
3742  if ( !phys->GetNumClipModels() ) {
3743  return;
3744  }
3745 
3746  num = clip.ClipModelsTouchingBounds( phys->GetAbsBounds(), phys->GetClipMask(), clipModels, MAX_GENTITIES );
3747  for ( i = 0; i < num; i++ ) {
3748  cm = clipModels[ i ];
3749 
3750  // don't check render entities
3751  if ( cm->IsRenderModel() ) {
3752  continue;
3753  }
3754 
3755  hit = cm->GetEntity();
3756  if ( ( hit == ent ) || !hit->fl.takedamage ) {
3757  continue;
3758  }
3759 
3760  if ( !phys->ClipContents( cm ) ) {
3761  continue;
3762  }
3763 
3764  // nail it
3765  if ( hit->IsType( idPlayer::Type ) && static_cast< idPlayer * >( hit )->IsInTeleport() ) {
3766  static_cast< idPlayer * >( hit )->TeleportDeath( ent->entityNumber );
3767  } else if ( !catch_teleport ) {
3768  hit->Damage( ent, ent, vec3_origin, "damage_telefrag", 1.0f, INVALID_JOINT );
3769  }
3770 
3771  if ( !gameLocal.isMultiplayer ) {
3772  // let the mapper know about it
3773  Warning( "'%s' telefragged '%s'", ent->name.c_str(), hit->name.c_str() );
3774  }
3775  }
3776 }
3777 
3778 /*
3779 ================
3780 idGameLocal::RequirementMet
3781 ================
3782 */
3783 bool idGameLocal::RequirementMet( idEntity *activator, const idStr &requires, int removeItem ) {
3784  if ( requires.Length() ) {
3785  if ( activator->IsType( idPlayer::Type ) ) {
3786  idPlayer *player = static_cast<idPlayer *>(activator);
3787  idDict *item = player->FindInventoryItem( requires );
3788  if ( item ) {
3789  if ( removeItem ) {
3790  player->RemoveInventoryItem( item );
3791  }
3792  return true;
3793  } else {
3794  return false;
3795  }
3796  }
3797  }
3798 
3799  return true;
3800 }
3801 
3802 /*
3803 ============
3804 idGameLocal::AlertAI
3805 ============
3806 */
3808  if ( ent && ent->IsType( idActor::Type ) ) {
3809  // alert them for the next frame
3811  lastAIAlertEntity = static_cast<idActor *>( ent );
3812  }
3813 }
3814 
3815 /*
3816 ============
3817 idGameLocal::GetAlertEntity
3818 ============
3819 */
3821 #ifdef _D3XP
3822  int timeGroup = 0;
3824  timeGroup = lastAIAlertEntity.GetEntity()->timeGroup;
3825  }
3826  SetTimeState ts( timeGroup );
3827 #endif
3828 
3829  if ( lastAIAlertTime >= time ) {
3830  return lastAIAlertEntity.GetEntity();
3831  }
3832 
3833  return NULL;
3834 }
3835 
3836 /*
3837 ============
3838 idGameLocal::RadiusDamage
3839 ============
3840 */
3841 void idGameLocal::RadiusDamage( const idVec3 &origin, idEntity *inflictor, idEntity *attacker, idEntity *ignoreDamage, idEntity *ignorePush, const char *damageDefName, float dmgPower ) {
3842  float dist, damageScale, attackerDamageScale, attackerPushScale;
3843  idEntity * ent;
3844  idEntity * entityList[ MAX_GENTITIES ];
3845  int numListedEntities;
3846  idBounds bounds;
3847  idVec3 v, damagePoint, dir;
3848  int i, e, damage, radius, push;
3849 
3850  const idDict *damageDef = FindEntityDefDict( damageDefName, false );
3851  if ( !damageDef ) {
3852  Warning( "Unknown damageDef '%s'", damageDefName );
3853  return;
3854  }
3855 
3856  damageDef->GetInt( "damage", "20", damage );
3857  damageDef->GetInt( "radius", "50", radius );
3858  damageDef->GetInt( "push", va( "%d", damage * 100 ), push );
3859  damageDef->GetFloat( "attackerDamageScale", "0.5", attackerDamageScale );
3860  damageDef->GetFloat( "attackerPushScale", "0", attackerPushScale );
3861 
3862  if ( radius < 1 ) {
3863  radius = 1;
3864  }
3865 
3866  bounds = idBounds( origin ).Expand( radius );
3867 
3868  // get all entities touching the bounds
3869  numListedEntities = clip.EntitiesTouchingBounds( bounds, -1, entityList, MAX_GENTITIES );
3870 
3871  if ( inflictor && inflictor->IsType( idAFAttachment::Type ) ) {
3872  inflictor = static_cast<idAFAttachment*>(inflictor)->GetBody();
3873  }
3874  if ( attacker && attacker->IsType( idAFAttachment::Type ) ) {
3875  attacker = static_cast<idAFAttachment*>(attacker)->GetBody();
3876  }
3877  if ( ignoreDamage && ignoreDamage->IsType( idAFAttachment::Type ) ) {
3878  ignoreDamage = static_cast<idAFAttachment*>(ignoreDamage)->GetBody();
3879  }
3880 
3881  // apply damage to the entities
3882  for ( e = 0; e < numListedEntities; e++ ) {
3883  ent = entityList[ e ];
3884  assert( ent );
3885 
3886  if ( !ent->fl.takedamage ) {
3887  continue;
3888  }
3889 
3890  if ( ent == inflictor || ( ent->IsType( idAFAttachment::Type ) && static_cast<idAFAttachment*>(ent)->GetBody() == inflictor ) ) {
3891  continue;
3892  }
3893 
3894  if ( ent == ignoreDamage || ( ent->IsType( idAFAttachment::Type ) && static_cast<idAFAttachment*>(ent)->GetBody() == ignoreDamage ) ) {
3895  continue;
3896  }
3897 
3898  // don't damage a dead player
3899  if ( isMultiplayer && ent->entityNumber < MAX_CLIENTS && ent->IsType( idPlayer::Type ) && static_cast< idPlayer * >( ent )->health < 0 ) {
3900  continue;
3901  }
3902 
3903  // find the distance from the edge of the bounding box
3904  for ( i = 0; i < 3; i++ ) {
3905  if ( origin[ i ] < ent->GetPhysics()->GetAbsBounds()[0][ i ] ) {
3906  v[ i ] = ent->GetPhysics()->GetAbsBounds()[0][ i ] - origin[ i ];
3907  } else if ( origin[ i ] > ent->GetPhysics()->GetAbsBounds()[1][ i ] ) {
3908  v[ i ] = origin[ i ] - ent->GetPhysics()->GetAbsBounds()[1][ i ];
3909  } else {
3910  v[ i ] = 0;
3911  }
3912  }
3913 
3914  dist = v.Length();
3915  if ( dist >= radius ) {
3916  continue;
3917  }
3918 
3919  if ( ent->CanDamage( origin, damagePoint ) ) {
3920  // push the center of mass higher than the origin so players
3921  // get knocked into the air more
3922  dir = ent->GetPhysics()->GetOrigin() - origin;
3923  dir[ 2 ] += 24;
3924 
3925  // get the damage scale
3926  damageScale = dmgPower * ( 1.0f - dist / radius );
3927  if ( ent == attacker || ( ent->IsType( idAFAttachment::Type ) && static_cast<idAFAttachment*>(ent)->GetBody() == attacker ) ) {
3928  damageScale *= attackerDamageScale;
3929  }
3930 
3931  ent->Damage( inflictor, attacker, dir, damageDefName, damageScale, INVALID_JOINT );
3932  }
3933  }
3934 
3935  // push physics objects
3936  if ( push ) {
3937  RadiusPush( origin, radius, push * dmgPower, attacker, ignorePush, attackerPushScale, false );
3938  }
3939 }
3940 
3941 /*
3942 ==============
3943 idGameLocal::RadiusPush
3944 ==============
3945 */
3946 void idGameLocal::RadiusPush( const idVec3 &origin, const float radius, const float push, const idEntity *inflictor, const idEntity *ignore, float inflictorScale, const bool quake ) {
3947  int i, numListedClipModels;
3948  idClipModel *clipModel;
3949  idClipModel *clipModelList[ MAX_GENTITIES ];
3950  idVec3 dir;
3951  idBounds bounds;
3953  idEntity *ent;
3954  float scale;
3955 
3956  dir.Set( 0.0f, 0.0f, 1.0f );
3957 
3958  bounds = idBounds( origin ).Expand( radius );
3959 
3960  // get all clip models touching the bounds
3961  numListedClipModels = clip.ClipModelsTouchingBounds( bounds, -1, clipModelList, MAX_GENTITIES );
3962 
3963  if ( inflictor && inflictor->IsType( idAFAttachment::Type ) ) {
3964  inflictor = static_cast<const idAFAttachment*>(inflictor)->GetBody();
3965  }
3966  if ( ignore && ignore->IsType( idAFAttachment::Type ) ) {
3967  ignore = static_cast<const idAFAttachment*>(ignore)->GetBody();
3968  }
3969 
3970  // apply impact to all the clip models through their associated physics objects
3971  for ( i = 0; i < numListedClipModels; i++ ) {
3972 
3973  clipModel = clipModelList[i];
3974 
3975  // never push render models
3976  if ( clipModel->IsRenderModel() ) {
3977  continue;
3978  }
3979 
3980  ent = clipModel->GetEntity();
3981 
3982  // never push projectiles
3983  if ( ent->IsType( idProjectile::Type ) ) {
3984  continue;
3985  }
3986 
3987  // players use "knockback" in idPlayer::Damage
3988  if ( ent->IsType( idPlayer::Type ) && !quake ) {
3989  continue;
3990  }
3991 
3992  // don't push the ignore entity
3993  if ( ent == ignore || ( ent->IsType( idAFAttachment::Type ) && static_cast<idAFAttachment*>(ent)->GetBody() == ignore ) ) {
3994  continue;
3995  }
3996 
3997  if ( gameRenderWorld->FastWorldTrace( result, origin, clipModel->GetOrigin() ) ) {
3998  continue;
3999  }
4000 
4001  // scale the push for the inflictor
4002  if ( ent == inflictor || ( ent->IsType( idAFAttachment::Type ) && static_cast<idAFAttachment*>(ent)->GetBody() == inflictor ) ) {
4003  scale = inflictorScale;
4004  } else {
4005  scale = 1.0f;
4006  }
4007 
4008  if ( quake ) {
4009  clipModel->GetEntity()->ApplyImpulse( world, clipModel->GetId(), clipModel->GetOrigin(), scale * push * dir );
4010  } else {
4011  RadiusPushClipModel( origin, scale * push, clipModel );
4012  }
4013  }
4014 }
4015 
4016 /*
4017 ==============
4018 idGameLocal::RadiusPushClipModel
4019 ==============
4020 */
4021 void idGameLocal::RadiusPushClipModel( const idVec3 &origin, const float push, const idClipModel *clipModel ) {
4022  int i, j;
4023  float dot, dist, area;
4024  const idTraceModel *trm;
4025  const traceModelPoly_t *poly;
4026  idFixedWinding w;
4027  idVec3 v, localOrigin, center, impulse;
4028 
4029  trm = clipModel->GetTraceModel();
4030  if ( !trm || 1 ) {
4031  impulse = clipModel->GetAbsBounds().GetCenter() - origin;
4032  impulse.Normalize();
4033  impulse.z += 1.0f;
4034  clipModel->GetEntity()->ApplyImpulse( world, clipModel->GetId(), clipModel->GetOrigin(), push * impulse );
4035  return;
4036  }
4037 
4038  localOrigin = ( origin - clipModel->GetOrigin() ) * clipModel->GetAxis().Transpose();
4039  for ( i = 0; i < trm->numPolys; i++ ) {
4040  poly = &trm->polys[i];
4041 
4042  center.Zero();
4043  for ( j = 0; j < poly->numEdges; j++ ) {
4044  v = trm->verts[ trm->edges[ abs(poly->edges[j]) ].v[ INTSIGNBITSET( poly->edges[j] ) ] ];
4045  center += v;
4046  v -= localOrigin;
4047  v.NormalizeFast(); // project point on a unit sphere
4048  w.AddPoint( v );
4049  }
4050  center /= poly->numEdges;
4051  v = center - localOrigin;
4052  dist = v.NormalizeFast();
4053  dot = v * poly->normal;
4054  if ( dot > 0.0f ) {
4055  continue;
4056  }
4057  area = w.GetArea();
4058  // impulse in polygon normal direction
4059  impulse = poly->normal * clipModel->GetAxis();
4060  // always push up for nicer effect
4061  impulse.z -= 1.0f;
4062  // scale impulse based on visible surface area and polygon angle
4063  impulse *= push * ( dot * area * ( 1.0f / ( 4.0f * idMath::PI ) ) );
4064  // scale away distance for nicer effect
4065  impulse *= ( dist * 2.0f );
4066  // impulse is applied to the center of the polygon
4067  center = clipModel->GetOrigin() + center * clipModel->GetAxis();
4068 
4069  clipModel->GetEntity()->ApplyImpulse( world, clipModel->GetId(), center, impulse );
4070  }
4071 }
4072 
4073 /*
4074 ===============
4075 idGameLocal::ProjectDecal
4076 ===============
4077 */
4078 void idGameLocal::ProjectDecal( const idVec3 &origin, const idVec3 &dir, float depth, bool parallel, float size, const char *material, float angle ) {
4079  float s, c;
4080  idMat3 axis, axistemp;
4081  idFixedWinding winding;
4082  idVec3 windingOrigin, projectionOrigin;
4083 
4084  static idVec3 decalWinding[4] = {
4085  idVec3( 1.0f, 1.0f, 0.0f ),
4086  idVec3( -1.0f, 1.0f, 0.0f ),
4087  idVec3( -1.0f, -1.0f, 0.0f ),
4088  idVec3( 1.0f, -1.0f, 0.0f )
4089  };
4090 
4091  if ( !g_decals.GetBool() ) {
4092  return;
4093  }
4094 
4095  // randomly rotate the decal winding
4096  idMath::SinCos16( ( angle ) ? angle : random.RandomFloat() * idMath::TWO_PI, s, c );
4097 
4098  // winding orientation
4099  axis[2] = dir;
4100  axis[2].Normalize();
4101  axis[2].NormalVectors( axistemp[0], axistemp[1] );
4102  axis[0] = axistemp[ 0 ] * c + axistemp[ 1 ] * -s;
4103  axis[1] = axistemp[ 0 ] * -s + axistemp[ 1 ] * -c;
4104 
4105  windingOrigin = origin + depth * axis[2];
4106  if ( parallel ) {
4107  projectionOrigin = origin - depth * axis[2];
4108  } else {
4109  projectionOrigin = origin;
4110  }
4111 
4112  size *= 0.5f;
4113 
4114  winding.Clear();
4115  winding += idVec5( windingOrigin + ( axis * decalWinding[0] ) * size, idVec2( 1, 1 ) );
4116  winding += idVec5( windingOrigin + ( axis * decalWinding[1] ) * size, idVec2( 0, 1 ) );
4117  winding += idVec5( windingOrigin + ( axis * decalWinding[2] ) * size, idVec2( 0, 0 ) );
4118  winding += idVec5( windingOrigin + ( axis * decalWinding[3] ) * size, idVec2( 1, 0 ) );
4119  gameRenderWorld->ProjectDecalOntoWorld( winding, projectionOrigin, parallel, depth * 0.5f, declManager->FindMaterial( material ), gameLocal.slow.time /* _D3XP */ );
4120 }
4121 
4122 /*
4123 ==============
4124 idGameLocal::BloodSplat
4125 ==============
4126 */
4127 void idGameLocal::BloodSplat( const idVec3 &origin, const idVec3 &dir, float size, const char *material ) {
4128  float halfSize = size * 0.5f;
4129  idVec3 verts[] = { idVec3( 0.0f, +halfSize, +halfSize ),
4130  idVec3( 0.0f, +halfSize, -halfSize ),
4131  idVec3( 0.0f, -halfSize, -halfSize ),
4132  idVec3( 0.0f, -halfSize, +halfSize ) };
4133  idTraceModel trm;
4134  idClipModel mdl;
4135  trace_t results;
4136 
4137  // FIXME: get from damage def
4138  if ( !g_bloodEffects.GetBool() ) {
4139  return;
4140  }
4141 
4142  size = halfSize + random.RandomFloat() * halfSize;
4143  trm.SetupPolygon( verts, 4 );
4144  mdl.LoadModel( trm );
4145  clip.Translation( results, origin, origin + dir * 64.0f, &mdl, mat3_identity, CONTENTS_SOLID, NULL );
4146  ProjectDecal( results.endpos, dir, 2.0f * size, true, size, material );
4147 }
4148 
4149 /*
4150 =============
4151 idGameLocal::SetCamera
4152 =============
4153 */
4155  int i;
4156  idEntity *ent;
4157  idAI *ai;
4158 
4159  // this should fix going into a cinematic when dead.. rare but happens
4160  idPlayer *client = GetLocalPlayer();
4161  if ( client->health <= 0 || client->AI_DEAD ) {
4162  return;
4163  }
4164 
4165  camera = cam;
4166  if ( camera ) {
4167  inCinematic = true;
4168 
4169  if ( skipCinematic && camera->spawnArgs.GetBool( "disconnect" ) ) {
4170  camera->spawnArgs.SetBool( "disconnect", false );
4171  cvarSystem->SetCVarFloat( "r_znear", 3.0f );
4172  cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "disconnect\n" );
4173  skipCinematic = false;
4174  return;
4175  }
4176 
4177  if ( time > cinematicStopTime ) {
4179  }
4180 
4181  // set r_znear so that transitioning into/out of the player's head doesn't clip through the view
4182  cvarSystem->SetCVarFloat( "r_znear", 1.0f );
4183 
4184  // hide all the player models
4185  for( i = 0; i < numClients; i++ ) {
4186  if ( entities[ i ] ) {
4187  client = static_cast< idPlayer* >( entities[ i ] );
4188  client->EnterCinematic();
4189  }
4190  }
4191 
4192  if ( !cam->spawnArgs.GetBool( "ignore_enemies" ) ) {
4193  // kill any active monsters that are enemies of the player
4194  for ( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
4195  if ( ent->cinematic || ent->fl.isDormant ) {
4196  // only kill entities that aren't needed for cinematics and aren't dormant
4197  continue;
4198  }
4199 
4200  if ( ent->IsType( idAI::Type ) ) {
4201  ai = static_cast<idAI *>( ent );
4202  if ( !ai->GetEnemy() || !ai->IsActive() ) {
4203  // no enemy, or inactive, so probably safe to ignore
4204  continue;
4205  }
4206  } else if ( ent->IsType( idProjectile::Type ) ) {
4207  // remove all projectiles
4208  } else if ( ent->spawnArgs.GetBool( "cinematic_remove" ) ) {
4209  // remove anything marked to be removed during cinematics
4210  } else {
4211  // ignore everything else
4212  continue;
4213  }
4214 
4215  // remove it
4216  DPrintf( "removing '%s' for cinematic\n", ent->GetName() );
4217  ent->PostEventMS( &EV_Remove, 0 );
4218  }
4219  }
4220 
4221  } else {
4222  inCinematic = false;
4224 
4225  // restore r_znear
4226  cvarSystem->SetCVarFloat( "r_znear", 3.0f );
4227 
4228  // show all the player models
4229  for( i = 0; i < numClients; i++ ) {
4230  if ( entities[ i ] ) {
4231  idPlayer *client = static_cast< idPlayer* >( entities[ i ] );
4232  client->ExitCinematic();
4233  }
4234  }
4235  }
4236 }
4237 
4238 /*
4239 =============
4240 idGameLocal::GetCamera
4241 =============
4242 */
4244  return camera;
4245 }
4246 
4247 /*
4248 =============
4249 idGameLocal::SkipCinematic
4250 =============
4251 */
4253  if ( camera ) {
4254  if ( camera->spawnArgs.GetBool( "disconnect" ) ) {
4255  camera->spawnArgs.SetBool( "disconnect", false );
4256  cvarSystem->SetCVarFloat( "r_znear", 3.0f );
4257  cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "disconnect\n" );
4258  skipCinematic = false;
4259  return false;
4260  }
4261 
4262  if ( camera->spawnArgs.GetBool( "instantSkip" ) ) {
4263  camera->Stop();
4264  return false;
4265  }
4266  }
4267 
4268  soundSystem->SetMute( true );
4269  if ( !skipCinematic ) {
4270  skipCinematic = true;
4272  }
4273 
4274  return true;
4275 }
4276 
4277 
4278 /*
4279 ======================
4280 idGameLocal::SpreadLocations
4281 
4282 Now that everything has been spawned, associate areas with location entities
4283 ======================
4284 */
4286  idEntity *ent;
4287 
4288  // allocate the area table
4289  int numAreas = gameRenderWorld->NumAreas();
4290  locationEntities = new idLocationEntity *[ numAreas ];
4291  memset( locationEntities, 0, numAreas * sizeof( *locationEntities ) );
4292 
4293  // for each location entity, make pointers from every area it touches
4294  for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
4295  if ( !ent->IsType( idLocationEntity::Type ) ) {
4296  continue;
4297  }
4298  idVec3 point = ent->spawnArgs.GetVector( "origin" );
4299  int areaNum = gameRenderWorld->PointInArea( point );
4300  if ( areaNum < 0 ) {
4301  Printf( "SpreadLocations: location '%s' is not in a valid area\n", ent->spawnArgs.GetString( "name" ) );
4302  continue;
4303  }
4304  if ( areaNum >= numAreas ) {
4305  Error( "idGameLocal::SpreadLocations: areaNum >= gameRenderWorld->NumAreas()" );
4306  }
4307  if ( locationEntities[areaNum] ) {
4308  Warning( "location entity '%s' overlaps '%s'", ent->spawnArgs.GetString( "name" ),
4309  locationEntities[areaNum]->spawnArgs.GetString( "name" ) );
4310  continue;
4311  }
4312  locationEntities[areaNum] = static_cast<idLocationEntity *>(ent);
4313 
4314  // spread to all other connected areas
4315  for ( int i = 0 ; i < numAreas ; i++ ) {
4316  if ( i == areaNum ) {
4317  continue;
4318  }
4319  if ( gameRenderWorld->AreasAreConnected( areaNum, i, PS_BLOCK_LOCATION ) ) {
4320  locationEntities[i] = static_cast<idLocationEntity *>(ent);
4321  }
4322  }
4323  }
4324 }
4325 
4326 /*
4327 ===================
4328 idGameLocal::LocationForPoint
4329 
4330 The player checks the location each frame to update the HUD text display
4331 May return NULL
4332 ===================
4333 */
4335  if ( !locationEntities ) {
4336  // before SpreadLocations() has been called
4337  return NULL;
4338  }
4339 
4340  int areaNum = gameRenderWorld->PointInArea( point );
4341  if ( areaNum < 0 ) {
4342  return NULL;
4343  }
4344  if ( areaNum >= gameRenderWorld->NumAreas() ) {
4345  Error( "idGameLocal::LocationForPoint: areaNum >= gameRenderWorld->NumAreas()" );
4346  }
4347 
4348  return locationEntities[ areaNum ];
4349 }
4350 
4351 /*
4352 ============
4353 idGameLocal::SetPortalState
4354 ============
4355 */
4356 void idGameLocal::SetPortalState( qhandle_t portal, int blockingBits ) {
4357  idBitMsg outMsg;
4358  byte msgBuf[ MAX_GAME_MESSAGE_SIZE ];
4359 
4360  if ( !gameLocal.isClient ) {
4361  outMsg.Init( msgBuf, sizeof( msgBuf ) );
4363  outMsg.WriteLong( portal );
4364  outMsg.WriteBits( blockingBits, NUM_RENDER_PORTAL_BITS );
4365  networkSystem->ServerSendReliableMessage( -1, outMsg );
4366  }
4367  gameRenderWorld->SetPortalState( portal, blockingBits );
4368 }
4369 
4370 /*
4371 ============
4372 idGameLocal::sortSpawnPoints
4373 ============
4374 */
4375 int idGameLocal::sortSpawnPoints( const void *ptr1, const void *ptr2 ) {
4376  const spawnSpot_t *spot1 = static_cast<const spawnSpot_t *>( ptr1 );
4377  const spawnSpot_t *spot2 = static_cast<const spawnSpot_t *>( ptr2 );
4378  float diff;
4379 
4380  diff = spot1->dist - spot2->dist;
4381  if ( diff < 0.0f ) {
4382  return 1;
4383  } else if ( diff > 0.0f ) {
4384  return -1;
4385  } else {
4386  return 0;
4387  }
4388 }
4389 
4390 /*
4391 ===========
4392 idGameLocal::RandomizeInitialSpawns
4393 randomize the order of the initial spawns
4394 prepare for a sequence of initial player spawns
4395 ============
4396 */
4398  spawnSpot_t spot;
4399  int i, j;
4400 #ifdef CTF
4401  int k;
4402 #endif
4403 
4404  idEntity *ent;
4405 
4406  if ( !isMultiplayer || isClient ) {
4407  return;
4408  }
4409  spawnSpots.Clear();
4410  initialSpots.Clear();
4411 #ifdef CTF
4412  teamSpawnSpots[0].Clear();
4413  teamSpawnSpots[1].Clear();
4414  teamInitialSpots[0].Clear();
4415  teamInitialSpots[1].Clear();
4416 #endif
4417 
4418  spot.dist = 0;
4419  spot.ent = FindEntityUsingDef( NULL, "info_player_deathmatch" );
4420  while( spot.ent ) {
4421 #ifdef CTF
4422  spot.ent->spawnArgs.GetInt( "team", "-1", spot.team );
4423 
4424  if ( mpGame.IsGametypeFlagBased() ) /* CTF */
4425  {
4426  if ( spot.team == 0 || spot.team == 1 )
4427  teamSpawnSpots[spot.team].Append( spot );
4428  else
4429  common->Warning( "info_player_deathmatch : invalid or no team attached to spawn point\n");
4430  }
4431 #endif
4432  spawnSpots.Append( spot );
4433  if ( spot.ent->spawnArgs.GetBool( "initial" ) ) {
4434 #ifdef CTF
4435  if ( mpGame.IsGametypeFlagBased() ) /* CTF */
4436  {
4437  assert( spot.team == 0 || spot.team == 1 );
4438  teamInitialSpots[ spot.team ].Append( spot.ent );
4439  }
4440 #endif
4441 
4442  initialSpots.Append( spot.ent );
4443  }
4444  spot.ent = FindEntityUsingDef( spot.ent, "info_player_deathmatch" );
4445  }
4446 
4447 #ifdef CTF
4448  if ( mpGame.IsGametypeFlagBased() ) /* CTF */
4449  {
4450  if ( !teamSpawnSpots[0].Num() )
4451  common->Warning( "red team : no info_player_deathmatch in map" );
4452  if ( !teamSpawnSpots[1].Num() )
4453  common->Warning( "blue team : no info_player_deathmatch in map" );
4454 
4455  if ( !teamSpawnSpots[0].Num() || !teamSpawnSpots[1].Num() )
4456  return;
4457  }
4458 #endif
4459 
4460  if ( !spawnSpots.Num() ) {
4461  common->Warning( "no info_player_deathmatch in map" );
4462  return;
4463  }
4464 
4465 #ifdef CTF
4466  if ( mpGame.IsGametypeFlagBased() ) /* CTF */
4467  {
4468  common->Printf( "red team : %d spawns (%d initials)\n", teamSpawnSpots[ 0 ].Num(), teamInitialSpots[ 0 ].Num() );
4469  // if there are no initial spots in the map, consider they can all be used as initial
4470  if ( !teamInitialSpots[ 0 ].Num() ) {
4471  common->Warning( "red team : no info_player_deathmatch entities marked initial in map" );
4472  for ( i = 0; i < teamSpawnSpots[ 0 ].Num(); i++ ) {
4473  teamInitialSpots[ 0 ].Append( teamSpawnSpots[ 0 ][ i ].ent );
4474  }
4475  }
4476 
4477  common->Printf( "blue team : %d spawns (%d initials)\n", teamSpawnSpots[ 1 ].Num(), teamInitialSpots[ 1 ].Num() );
4478  // if there are no initial spots in the map, consider they can all be used as initial
4479  if ( !teamInitialSpots[ 1 ].Num() ) {
4480  common->Warning( "blue team : no info_player_deathmatch entities marked initial in map" );
4481  for ( i = 0; i < teamSpawnSpots[ 1 ].Num(); i++ ) {
4482  teamInitialSpots[ 1 ].Append( teamSpawnSpots[ 1 ][ i ].ent );
4483  }
4484  }
4485  }
4486 #endif
4487 
4488 
4489  common->Printf( "%d spawns (%d initials)\n", spawnSpots.Num(), initialSpots.Num() );
4490  // if there are no initial spots in the map, consider they can all be used as initial
4491  if ( !initialSpots.Num() ) {
4492  common->Warning( "no info_player_deathmatch entities marked initial in map" );
4493  for ( i = 0; i < spawnSpots.Num(); i++ ) {
4494  initialSpots.Append( spawnSpots[ i ].ent );
4495  }
4496  }
4497 
4498 #ifdef CTF
4499  for ( k = 0; k < 2; k++ )
4500  for ( i = 0; i < teamInitialSpots[ k ].Num(); i++ ) {
4501  j = random.RandomInt( teamInitialSpots[ k ].Num() );
4502  ent = teamInitialSpots[ k ][ i ];
4503  teamInitialSpots[ k ][ i ] = teamInitialSpots[ k ][ j ];
4504  teamInitialSpots[ k ][ j ] = ent;
4505  }
4506 #endif
4507 
4508  for ( i = 0; i < initialSpots.Num(); i++ ) {
4509  j = random.RandomInt( initialSpots.Num() );
4510  ent = initialSpots[ i ];
4511  initialSpots[ i ] = initialSpots[ j ];
4512  initialSpots[ j ] = ent;
4513  }
4514  // reset the counter
4515  currentInitialSpot = 0;
4516 
4517 #ifdef CTF
4518  teamCurrentInitialSpot[0] = 0;
4519  teamCurrentInitialSpot[1] = 0;
4520 #endif
4521 }
4522 
4523 /*
4524 ===========
4525 idGameLocal::SelectInitialSpawnPoint
4526 spectators are spawned randomly anywhere
4527 in-game clients are spawned based on distance to active players (randomized on the first half)
4528 upon map restart, initial spawns are used (randomized ordered list of spawns flagged "initial")
4529  if there are more players than initial spots, overflow to regular spawning
4530 ============
4531 */
4533  int i, j, which;
4534  spawnSpot_t spot;
4535  idVec3 pos;
4536  float dist;
4537  bool alone;
4538 
4539 #ifdef CTF
4540  if ( !isMultiplayer || !spawnSpots.Num() || ( mpGame.IsGametypeFlagBased() && ( !teamSpawnSpots[0].Num() || !teamSpawnSpots[1].Num() ) ) ) { /* CTF */
4541 #else
4542  if ( !isMultiplayer || !spawnSpots.Num() ) {
4543 #endif
4544  spot.ent = FindEntityUsingDef( NULL, "info_player_start" );
4545  if ( !spot.ent ) {
4546  Error( "No info_player_start on map.\n" );
4547  }
4548  return spot.ent;
4549  }
4550 
4551 #ifdef CTF
4552  bool useInitialSpots = false;
4553  if ( mpGame.IsGametypeFlagBased() ) { /* CTF */
4554  assert( player->team == 0 || player->team == 1 );
4555  useInitialSpots = player->useInitialSpawns && teamCurrentInitialSpot[ player->team ] < teamInitialSpots[ player->team ].Num();
4556  } else {
4557  useInitialSpots = player->useInitialSpawns && currentInitialSpot < initialSpots.Num();
4558  }
4559 #endif
4560 
4561  if ( player->spectating ) {
4562  // plain random spot, don't bother
4563  return spawnSpots[ random.RandomInt( spawnSpots.Num() ) ].ent;
4564 #ifdef CTF
4565  } else if ( useInitialSpots ) {
4566  if ( mpGame.IsGametypeFlagBased() ) { /* CTF */
4567  assert( player->team == 0 || player->team == 1 );
4568  player->useInitialSpawns = false; // only use the initial spawn once
4569  return teamInitialSpots[ player->team ][ teamCurrentInitialSpot[ player->team ]++ ];
4570  }
4571  return initialSpots[ currentInitialSpot++ ];
4572 #else
4573  } else if ( player->useInitialSpawns && currentInitialSpot < initialSpots.Num() ) {
4574  return initialSpots[ currentInitialSpot++ ];
4575 #endif
4576  } else {
4577  // check if we are alone in map
4578  alone = true;
4579  for ( j = 0; j < MAX_CLIENTS; j++ ) {
4580  if ( entities[ j ] && entities[ j ] != player ) {
4581  alone = false;
4582  break;
4583  }
4584  }
4585  if ( alone ) {
4586 #ifdef CTF
4587  if ( mpGame.IsGametypeFlagBased() ) /* CTF */
4588  {
4589  assert( player->team == 0 || player->team == 1 );
4590  return teamSpawnSpots[ player->team ][ random.RandomInt( teamSpawnSpots[ player->team ].Num() ) ].ent;
4591  }
4592 #endif
4593  // don't do distance-based
4594  return spawnSpots[ random.RandomInt( spawnSpots.Num() ) ].ent;
4595  }
4596 
4597 #ifdef CTF
4598  if ( mpGame.IsGametypeFlagBased() ) /* CTF */
4599  {
4600  // TODO : make as reusable method, same code as below
4601  int team = player->team;
4602  assert( team == 0 || team == 1 );
4603 
4604  // find the distance to the closest active player for each spawn spot
4605  for( i = 0; i < teamSpawnSpots[ team ].Num(); i++ ) {
4606  pos = teamSpawnSpots[ team ][ i ].ent->GetPhysics()->GetOrigin();
4607 
4608  // skip initial spawn points for CTF
4609  if ( teamSpawnSpots[ team ][ i ].ent->spawnArgs.GetBool("initial") ) {
4610  teamSpawnSpots[ team ][ i ].dist = 0x0;
4611  continue;
4612  }
4613 
4614  teamSpawnSpots[ team ][ i ].dist = 0x7fffffff;
4615 
4616  for( j = 0; j < MAX_CLIENTS; j++ ) {
4617  if ( !entities[ j ] || !entities[ j ]->IsType( idPlayer::Type )
4618  || entities[ j ] == player
4619  || static_cast< idPlayer * >( entities[ j ] )->spectating ) {
4620  continue;
4621  }
4622 
4623  dist = ( pos - entities[ j ]->GetPhysics()->GetOrigin() ).LengthSqr();
4624  if ( dist < teamSpawnSpots[ team ][ i ].dist ) {
4625  teamSpawnSpots[ team ][ i ].dist = dist;
4626  }
4627  }
4628  }
4629 
4630  // sort the list
4631  qsort( ( void * )teamSpawnSpots[ team ].Ptr(), teamSpawnSpots[ team ].Num(), sizeof( spawnSpot_t ), ( int (*)(const void *, const void *) )sortSpawnPoints );
4632 
4633  // choose a random one in the top half
4634  which = random.RandomInt( teamSpawnSpots[ team ].Num() / 2 );
4635  spot = teamSpawnSpots[ team ][ which ];
4636 // assert( teamSpawnSpots[ team ][ which ].dist != 0 );
4637 
4638  return spot.ent;
4639  }
4640 #endif
4641 
4642  // find the distance to the closest active player for each spawn spot
4643  for( i = 0; i < spawnSpots.Num(); i++ ) {
4644  pos = spawnSpots[ i ].ent->GetPhysics()->GetOrigin();
4645  spawnSpots[ i ].dist = 0x7fffffff;
4646  for( j = 0; j < MAX_CLIENTS; j++ ) {
4647  if ( !entities[ j ] || !entities[ j ]->IsType( idPlayer::Type )
4648  || entities[ j ] == player
4649  || static_cast< idPlayer * >( entities[ j ] )->spectating ) {
4650  continue;
4651  }
4652 
4653  dist = ( pos - entities[ j ]->GetPhysics()->GetOrigin() ).LengthSqr();
4654  if ( dist < spawnSpots[ i ].dist ) {
4655  spawnSpots[ i ].dist = dist;
4656  }
4657  }
4658  }
4659 
4660  // sort the list
4661  qsort( ( void * )spawnSpots.Ptr(), spawnSpots.Num(), sizeof( spawnSpot_t ), ( int (*)(const void *, const void *) )sortSpawnPoints );
4662 
4663  // choose a random one in the top half
4664  which = random.RandomInt( spawnSpots.Num() / 2 );
4665  spot = spawnSpots[ which ];
4666  }
4667  return spot.ent;
4668 }
4669 
4670 /*
4671 ================
4672 idGameLocal::UpdateServerInfoFlags
4673 ================
4674 */
4676  gameType = GAME_SP;
4677  if ( ( idStr::Icmp( serverInfo.GetString( "si_gameType" ), "deathmatch" ) == 0 ) ) {
4678  gameType = GAME_DM;
4679  } else if ( ( idStr::Icmp( serverInfo.GetString( "si_gameType" ), "Tourney" ) == 0 ) ) {
4681  } else if ( ( idStr::Icmp( serverInfo.GetString( "si_gameType" ), "Team DM" ) == 0 ) ) {
4682  gameType = GAME_TDM;
4683  } else if ( ( idStr::Icmp( serverInfo.GetString( "si_gameType" ), "Last Man" ) == 0 ) ) {
4685  }
4686 #ifdef CTF
4687  else if ( ( idStr::Icmp( serverInfo.GetString( "si_gameType" ), "CTF" ) == 0 ) ) {
4688  gameType = GAME_CTF;
4689  }
4690 #endif
4691 
4692  if ( gameType == GAME_LASTMAN ) {
4693  if ( !serverInfo.GetInt( "si_warmup" ) ) {
4694  common->Warning( "Last Man Standing - forcing warmup on" );
4695  serverInfo.SetInt( "si_warmup", 1 );
4696  }
4697  if ( serverInfo.GetInt( "si_fraglimit" ) <= 0 ) {
4698  common->Warning( "Last Man Standing - setting fraglimit 1" );
4699  serverInfo.SetInt( "si_fraglimit", 1 );
4700  }
4701  }
4702 }
4703 
4704 
4705 /*
4706 ================
4707 idGameLocal::SetGlobalMaterial
4708 ================
4709 */
4711  globalMaterial = mat;
4712 }
4713 
4714 /*
4715 ================
4716 idGameLocal::GetGlobalMaterial
4717 ================
4718 */
4720  return globalMaterial;
4721 }
4722 
4723 /*
4724 ================
4725 idGameLocal::GetSpawnId
4726 ================
4727 */
4728 int idGameLocal::GetSpawnId( const idEntity* ent ) const {
4729  return ( gameLocal.spawnIds[ ent->entityNumber ] << GENTITYNUM_BITS ) | ent->entityNumber;
4730 }
4731 
4732 /*
4733 ================
4734 idGameLocal::ThrottleUserInfo
4735 ================
4736 */
4739 }
4740 
4741 #ifdef _D3XP
4742 /*
4743 =================
4744 idPlayer::SetPortalSkyEnt
4745 =================
4746 */
4747 void idGameLocal::SetPortalSkyEnt( idEntity *ent ) {
4748  portalSkyEnt = ent;
4749 }
4750 
4751 /*
4752 =================
4753 idPlayer::IsPortalSkyAcive
4754 =================
4755 */
4756 bool idGameLocal::IsPortalSkyAcive() {
4757  return portalSkyActive;
4758 }
4759 
4760 /*
4761 ===========
4762 idGameLocal::SelectTimeGroup
4763 ============
4764 */
4765 void idGameLocal::SelectTimeGroup( int timeGroup ) {
4766  int i = 0;
4767 
4768  if ( timeGroup ) {
4769  fast.Get( time, previousTime, msec, framenum, realClientTime );
4770  } else {
4771  slow.Get( time, previousTime, msec, framenum, realClientTime );
4772  }
4773 }
4774 
4775 /*
4776 ===========
4777 idGameLocal::GetTimeGroupTime
4778 ============
4779 */
4780 int idGameLocal::GetTimeGroupTime( int timeGroup ) {
4781  if ( timeGroup ) {
4782  return fast.time;
4783  } else {
4784  return slow.time;
4785  }
4786 }
4787 
4788 /*
4789 ===============
4790 idGameLocal::GetBestGameType
4791 ===============
4792 */
4793 void idGameLocal::GetBestGameType( const char* map, const char* gametype, char buf[ MAX_STRING_CHARS ] ) {
4794  idStr aux = mpGame.GetBestGametype( map, gametype );
4795  strncpy( buf, aux.c_str(), MAX_STRING_CHARS );
4796  buf[ MAX_STRING_CHARS - 1 ] = '\0';
4797 }
4798 
4799 /*
4800 ===========
4801 idGameLocal::ComputeSlowMsec
4802 ============
4803 */
4804 void idGameLocal::ComputeSlowMsec() {
4805  idPlayer *player;
4806  bool powerupOn;
4807  float delta;
4808 
4809  // check if we need to do a quick reset
4810  if ( quickSlowmoReset ) {
4811  quickSlowmoReset = false;
4812 
4813  // stop the sounds
4814  if ( gameSoundWorld ) {
4815  gameSoundWorld->SetSlowmo( false );
4816  gameSoundWorld->SetSlowmoSpeed( 1 );
4817  }
4818 
4819  // stop the state
4820  slowmoState = SLOWMO_STATE_OFF;
4821  slowmoMsec = USERCMD_MSEC;
4822  }
4823 
4824  // check the player state
4825  player = GetLocalPlayer();
4826  powerupOn = false;
4827 
4828  if ( player && player->PowerUpActive( HELLTIME ) ) {
4829  powerupOn = true;
4830  }
4831  else if ( g_enableSlowmo.GetBool() ) {
4832  powerupOn = true;
4833  }
4834 
4835  // determine proper slowmo state
4836  if ( powerupOn && slowmoState == SLOWMO_STATE_OFF ) {
4837  slowmoState = SLOWMO_STATE_RAMPUP;
4838 
4839  slowmoMsec = msec;
4840  if ( gameSoundWorld ) {
4841  gameSoundWorld->SetSlowmo( true );
4842  gameSoundWorld->SetSlowmoSpeed( slowmoMsec / (float)USERCMD_MSEC );
4843  }
4844  }
4845  else if ( !powerupOn && slowmoState == SLOWMO_STATE_ON ) {
4846  slowmoState = SLOWMO_STATE_RAMPDOWN;
4847 
4848  // play the stop sound
4849  if ( player ) {
4850  player->PlayHelltimeStopSound();
4851  }
4852  }
4853 
4854  // do any necessary ramping
4855  if ( slowmoState == SLOWMO_STATE_RAMPUP ) {
4856  delta = 4 - slowmoMsec;
4857 
4858  if ( fabs( delta ) < g_slowmoStepRate.GetFloat() ) {
4859  slowmoMsec = 4;
4860  slowmoState = SLOWMO_STATE_ON;
4861  }
4862  else {
4863  slowmoMsec += delta * g_slowmoStepRate.GetFloat();
4864  }
4865 
4866  if ( gameSoundWorld ) {
4867  gameSoundWorld->SetSlowmoSpeed( slowmoMsec / (float)USERCMD_MSEC );
4868  }
4869  }
4870  else if ( slowmoState == SLOWMO_STATE_RAMPDOWN ) {
4871  delta = 16 - slowmoMsec;
4872 
4873  if ( fabs( delta ) < g_slowmoStepRate.GetFloat() ) {
4874  slowmoMsec = 16;
4875  slowmoState = SLOWMO_STATE_OFF;
4876  if ( gameSoundWorld ) {
4877  gameSoundWorld->SetSlowmo( false );
4878  }
4879  }
4880  else {
4881  slowmoMsec += delta * g_slowmoStepRate.GetFloat();
4882  }
4883 
4884  if ( gameSoundWorld ) {
4885  gameSoundWorld->SetSlowmoSpeed( slowmoMsec / (float)USERCMD_MSEC );
4886  }
4887  }
4888 }
4889 
4890 /*
4891 ===========
4892 idGameLocal::ResetSlowTimeVars
4893 ============
4894 */
4895 void idGameLocal::ResetSlowTimeVars() {
4896  msec = USERCMD_MSEC;
4897  slowmoMsec = USERCMD_MSEC;
4898  slowmoState = SLOWMO_STATE_OFF;
4899 
4900  fast.framenum = 0;
4901  fast.previousTime = 0;
4902  fast.time = 0;
4903  fast.msec = USERCMD_MSEC;
4904 
4905  slow.framenum = 0;
4906  slow.previousTime = 0;
4907  slow.time = 0;
4908  slow.msec = USERCMD_MSEC;
4909 }
4910 
4911 /*
4912 ===========
4913 idGameLocal::QuickSlowmoReset
4914 ============
4915 */
4916 void idGameLocal::QuickSlowmoReset() {
4917  quickSlowmoReset = true;
4918 }
4919 
4920 /*
4921 ===============
4922 idGameLocal::NeedRestart
4923 ===============
4924 */
4925 bool idGameLocal::NeedRestart() {
4926 
4927  idDict newInfo;
4928  const idKeyValue *keyval, *keyval2;
4929 
4930  newInfo = *cvarSystem->MoveCVarsToDict( CVAR_SERVERINFO );
4931 
4932  for ( int i = 0; i < newInfo.GetNumKeyVals(); i++ ) {
4933  keyval = newInfo.GetKeyVal( i );
4934  keyval2 = serverInfo.FindKey( keyval->GetKey() );
4935  if ( !keyval2 ) {
4936  return true;
4937  }
4938  // a select set of si_ changes will cause a full restart of the server
4939  if ( keyval->GetValue().Cmp( keyval2->GetValue() ) && ( !keyval->GetKey().Cmp( "si_pure" ) || !keyval->GetKey().Cmp( "si_map" ) ) ) {
4940  return true;
4941  }
4942  }
4943  return false;
4944 }
4945 
4946 #endif
4947 
4948 /*
4949 ================
4950 idGameLocal::GetClientStats
4951 ================
4952 */
4953 void idGameLocal::GetClientStats( int clientNum, char *data, const int len ) {
4954  mpGame.PlayerStats( clientNum, data, len );
4955 }
4956 
4957 
4958 /*
4959 ================
4960 idGameLocal::SwitchTeam
4961 ================
4962 */
4963 void idGameLocal::SwitchTeam( int clientNum, int team ) {
4964 
4965  idPlayer * player;
4966  player = static_cast< idPlayer * >( entities[ clientNum ] );
4967  int oldTeam = player->team ;
4968 
4969  // Put in spectator mode
4970  if ( team == -1 ) {
4971  static_cast< idPlayer * >( entities[ clientNum ] )->Spectate( true );
4972  }
4973  // Switch to a team
4974  else {
4975  mpGame.SwitchToTeam ( clientNum, oldTeam, team );
4976  }
4977  player->forceRespawn = true ;
4978 }
4979 
4980 /*
4981 ===============
4982 idGameLocal::GetMapLoadingGUI
4983 ===============
4984 */
4985 void idGameLocal::GetMapLoadingGUI( char gui[ MAX_STRING_CHARS ] ) { }
4986 
void WriteBuildNumber(const int value)
Definition: SaveGame.cpp:767
virtual const idVec3 & GetOrigin(int id=0) const =0
virtual void SetSlowmoSpeed(float speed)=0
idPlayer * GetLocalPlayer() const
void Mem_EnableLeakTest(const char *name)
Definition: Heap.cpp:1219
void SetupPolygon(const idVec3 *v, const int count)
Definition: TraceModel.cpp:866
int ClipModelsTouchingBounds(const idBounds &bounds, int contentMask, idClipModel **clipModelList, int maxCount) const
Definition: Clip.cpp:804
idEntity * GetEntity(void) const
Definition: Clip.h:178
int vacuumAreaNum
Definition: Game_local.h:322
Definition: Game.h:65
virtual void FreeMap(void)=0
virtual void GetBestGameType(const char *map, const char *gametype, char buf[MAX_STRING_CHARS])=0
virtual void DeAlloc(idUserInterface *gui)=0
void LocalMapRestart(void)
idNetworkSystem * networkSystem
Definition: Game.h:333
idStaticList< idEntity *, MAX_GENTITIES > initialSpots
Definition: Game_local.h:575
void RandomizeInitialSpawns(void)
bool AddBounds(const idBounds &a)
Definition: Bounds.h:255
float GetFloat(const char *key, const char *defaultString="0") const
Definition: Dict.h:248
virtual void HandleMainMenuCommands(const char *menuCommand, idUserInterface *gui)
idMapEntity * GetEntity(int i) const
Definition: MapFile.h:198
GLsizei const GLfloat * value
Definition: glext.h:3614
void WriteByte(int c)
Definition: BitMsg.h:283
int num_entities
Definition: Game_local.h:278
void WriteString(const char *string)
Definition: SaveGame.cpp:231
float Normalize(void)
Definition: Vector.h:646
idVec4 colorGreen
Definition: Lib.cpp:118
int GetInt(const char *key, const char *defaultString="0") const
Definition: Dict.h:252
idStr & SetFileExtension(const char *extension)
Definition: Str.cpp:743
int qhandle_t
Definition: Lib.h:81
float GetArea(void) const
Definition: Winding.cpp:598
void void static idThread * CurrentThread(void)
unsigned int GetGeometryCRC(void) const
Definition: MapFile.h:205
void TransferKeyValues(idDict &other)
Definition: Dict.cpp:111
void DrawClipModels(const idVec3 &eye, const float radius, const idEntity *passEntity)
Definition: Clip.cpp:1617
virtual void SetEnviroSuit(bool active)=0
assert(prefInfo.fullscreenBtn)
void CreateObjects(void)
Definition: SaveGame.cpp:799
void RadiusPushClipModel(const idVec3 &origin, const float push, const idClipModel *clipModel)
static void ClearTraceModelCache(void)
Definition: Clip.cpp:81
idGame * game
Definition: Game_local.cpp:65
virtual const idSoundShader * FindSound(const char *name, bool makeDefault=true)=0
bool useInitialSpawns
Definition: Player.h:346
const idDict * FindEntityDefDict(const char *name, bool makeDefault=true) const
static const int INITIAL_SPAWN_COUNT
Definition: Game_local.h:533
void Restore(idRestoreGame *savefile)
Definition: Game_local.h:661
idLinkList< idEntity > activeEntities
Definition: Game_local.h:282
int Cmp(const char *text) const
Definition: Str.h:652
idCVarSystem * cvarSystem
Definition: CVarSystem.cpp:487
const char * HandleGuiCommands(const char *menuCommand)
idMat3 mat3_identity(idVec3(1, 0, 0), idVec3(0, 1, 0), idVec3(0, 0, 1))
const int MAX_GLOBAL_SHADER_PARMS
Definition: RenderWorld.h:44
static void Shutdown(void)
Definition: Event.cpp:727
virtual int GetClipMask(int id=-1) const =0
idNetworkSystem * networkSystem
bool forceRespawn
Definition: Player.h:339
void ReadMaterial(const idMaterial *&material)
Definition: SaveGame.cpp:1132
void CallFunction(const function_t *func, bool clearStack)
void WriteObject(const idClass *obj)
Definition: SaveGame.cpp:329
virtual void DebugArrow(const idVec4 &color, const idVec3 &start, const idVec3 &end, int size, const int lifetime=0)=0
static void ShutDown(void)
Definition: Lib.cpp:91
idVec3 GetCenter(void) const
Definition: Bounds.h:211
int Next(const int index) const
Definition: HashIndex.h:247
idClip clip
Definition: Game_local.h:296
virtual bool Draw(int clientNum)
int stamina
Definition: Game.h:50
idVec4 colorWhite
Definition: Lib.cpp:116
void PlayerStats(int clientNum, char *data, const int len)
virtual void SetCVarFloat(const char *name, const float value, int flags=0)=0
int health
Definition: Game.h:48
Definition: Timer.h:40
void Printf(const char *fmt,...) const id_attribute((format(printf
Definition: Game_local.cpp:699
idRenderSystem * renderSystem
Definition: Game.h:334
virtual bool FPU_StackIsEmpty(void)=0
void Remove(const int key, const int index)
Definition: HashIndex.h:213
struct idEntity::entityFlags_s fl
void FreeCurrentPVS(pvsHandle_t handle) const
Definition: Pvs.cpp:1127
virtual void virtual void virtual const idLangDict * GetLanguageDict(void)=0
int currentInitialSpot
Definition: Game_local.h:576
#define MAX_GENTITIES
Definition: Game_local.h:83
type * GetEntity(void) const
Definition: Game_local.h:695
void DelayedStart(int delay)
const int BUILD_NUMBER
Definition: BuildVersion.h:28
idPlayer * GetClientByCmdArgs(const idCmdArgs &args) const
virtual const char * FPU_GetState(void)=0
idActor * GetEnemy(void) const
Definition: AI.cpp:3697
idSmokeParticles * smokeParticles
Definition: Game_local.h:307
float GetFloat(void) const
Definition: CVarSystem.h:144
traceModelVert_t verts[MAX_TRACEMODEL_VERTS]
Definition: TraceModel.h:88
const GLdouble * v
Definition: glext.h:2936
virtual void ForceFlush(void)
Definition: File.cpp:226
void MapClear(bool clearClients)
const idStr & GetKey(void) const
Definition: Dict.h:52
virtual const soundShaderParms_t * GetParms() const
Definition: snd_shader.cpp:481
void ReadDict(idDict *dict)
Definition: SaveGame.cpp:1107
int GetSpawnId(const idEntity *ent) const
idDeclManager * declManager
Definition: Game.h:338
virtual escReply_t HandleESC(idUserInterface **gui)
bool isNewFrame
Definition: Game_local.h:333
bool RayIntersection(const idVec3 &start, const idVec3 &dir, float &scale) const
Definition: Bounds.cpp:184
idEntity * GetBindMaster(void) const
Definition: Entity.cpp:2153
idCVar ai_showObstacleAvoidance("ai_showObstacleAvoidance","0", CVAR_GAME|CVAR_INTEGER,"draws obstacle avoidance information for monsters. if 2, draws obstacles for player, as well", 0, 2, idCmdSystem::ArgCompletion_Integer< 0, 2 >)
void ManualDelete(void)
virtual int ReadFile(const char *relativePath, void **buffer, ID_TIME_T *timestamp=NULL)=0
void SwitchToTeam(int clientNum, int oldteam, int newteam)
GLenum GLenum GLenum GLenum GLenum scale
Definition: glext.h:4804
idMat3 Transpose(void) const
Definition: Matrix.h:677
virtual void SetRenderView(const renderView_t *renderView)=0
idRandom random
Definition: Game_local.h:291
int Length(void) const
Definition: Str.h:702
void void void void void Error(const char *fmt,...) const id_attribute((format(printf
Definition: Game_local.cpp:783
bool isMultiplayer
Definition: Game_local.h:325
idScriptObject scriptObject
Definition: Entity.h:123
bool skipCinematic
Definition: Game_local.h:314
int firstFreeIndex
Definition: Game_local.h:277
virtual void SpawnPlayer(int clientNum)
bool IsType(const idTypeInfo &c) const
Definition: Class.h:337
void EnterGame(int clientNum)
void SpawnPlayer(int clientNum)
int heartRate
Definition: Player.h:308
idStr sessionCommand
Definition: Game_local.h:303
idCVar g_mapCycle("g_mapCycle","mapcycle", CVAR_GAME|CVAR_ARCHIVE,"map cycling script for multiplayer games - see mapcycle.scriptcfg")
idCmdSystem * cmdSystem
Definition: Game.h:330
int consistencyHash
Definition: Game.h:47
virtual void LoadMap(const idMapFile *mapFile)=0
void Set(const float x, const float y, const float z)
Definition: Vector.h:409
static const float PI
Definition: Math.h:205
void RenderPlayerView(idUserInterface *hud)
Definition: PlayerView.cpp:684
GLenum GLint GLint y
Definition: glext.h:2849
const idMat3 & GetAxis(void) const
Definition: Clip.h:210
idEntity * FindEntity(const char *name) const
virtual void Stop(void)
Definition: Camera.h:48
idList< idEntityPtr< idEntity > > targets
Definition: Entity.h:132
bool EverReferenced(void) const
Definition: DeclManager.h:193
int spawnIds[MAX_GENTITIES]
Definition: Game_local.h:276
idRenderSystem * renderSystem
int previousTime
Definition: Game_local.h:318
static void DrawDebugInfo(void)
Definition: Trigger.cpp:56
float z
Definition: Vector.h:320
const idKeyValue * MatchPrefix(const char *prefix, const idKeyValue *lastMatch=NULL) const
Definition: Dict.cpp:523
idVec3 GetEyePosition(void) const
idFileSystem * fileSystem
Definition: FileSystem.cpp:500
virtual int GetNumClipModels(void) const =0
GLclampf ref
Definition: glext.h:4237
bool Start(void)
void RadiusDamage(const idVec3 &origin, idEntity *inflictor, idEntity *attacker, idEntity *ignoreDamage, idEntity *ignorePush, const char *damageDefName, float dmgPower=1.0f)
prefInfo callback
int combat
Definition: Game.h:51
void SetupPlayerPVS(void)
idCVar g_showTargets("g_showTargets","0", CVAR_GAME|CVAR_BOOL,"draws entities and thier targets. hidden entities are drawn grey.")
#define SCRIPT_DEFAULTFUNC
Definition: Game.h:43
gameState_t
Definition: Game_local.h:172
virtual idUserInterface * Alloc(void) const =0
bool isClient
Definition: Game_local.h:327
void void void void DWarning(const char *fmt,...) const id_attribute((format(printf
Definition: Game_local.cpp:757
virtual const idDict * GetUserInfo(int clientNum)
Definition: Game_local.cpp:887
Definition: Vector.h:316
case const float
Definition: Callbacks.cpp:62
void ReadBool(bool &value)
Definition: SaveGame.cpp:976
void InitAsyncNetwork(void)
void DisplayEntities(void)
Definition: GameEdit.cpp:532
idCVar si_gameType("si_gameType", si_gameTypeArgs[0], CVAR_GAME|CVAR_SERVERINFO|CVAR_ARCHIVE,"game type - singleplayer, deathmatch, Tourney, Team DM or Last Man", si_gameTypeArgs, idCmdSystem::ArgCompletion_String< si_gameTypeArgs >)
virtual void ExecuteCommandBuffer(void)=0
void Close(void)
Definition: SaveGame.cpp:93
idSoundSystem * soundSystem
Definition: Game.h:335
idLocationEntity ** locationEntities
Definition: Game_local.h:542
bool isServer
Definition: Game_local.h:326
GLint GLint GLsizei GLsizei GLsizei depth
Definition: glext.h:2878
int version
Definition: Game.h:346
const char * Left(int len, idStr &result) const
Definition: Str.h:892
virtual const idDict * SetUserInfo(int clientNum, const idDict &userInfo, bool isClient, bool canModify)
Definition: Game_local.cpp:830
int team
Definition: Actor.h:115
void MapRestart(void)
idCamera * GetPrivateCameraView(void) const
Definition: Player.h:537
idCVar com_forceGenericSIMD("com_forceGenericSIMD","0", CVAR_BOOL|CVAR_SYSTEM|CVAR_NOCHEAT,"force generic platform independent SIMD")
idSys * sys
Definition: Game.h:328
void DrawPVS(const idVec3 &source, const pvsType_t type=PVS_NORMAL) const
Definition: Pvs.cpp:1227
void Start(void)
Definition: Timer.h:144
static bool FindPathAroundObstacles(const idPhysics *physics, const idAAS *aas, const idEntity *ignore, const idVec3 &startPos, const idVec3 &seekPos, obstaclePath_t &path)
Definition: AI_pathing.cpp:925
static bool PredictPath(const idEntity *ent, const idAAS *aas, const idVec3 &start, const idVec3 &velocity, int totalTime, int frameTime, int stopEvent, predictedPath_t &path)
virtual void SetCVarString(const char *name, const char *value, int flags=0)=0
const idVec3 & GetOrigin(void) const
Definition: Clip.h:206
pvsType_t
Definition: Pvs.h:56
void Init(void)
Definition: Pvs.cpp:796
void FreePlayerPVS(void)
void ReadBuildNumber(void)
Definition: SaveGame.cpp:1546
void BloodSplat(const idVec3 &origin, const idVec3 &dir, float size, const char *material)
int GetNextClientNum(int current) const
pvsHandle_t MergeCurrentPVS(pvsHandle_t pvs1, pvsHandle_t pvs2) const
Definition: Pvs.cpp:1075
GLuint GLuint GLsizei GLenum type
Definition: glext.h:2845
void void ServerProcessEntityNetworkEventQueue(void)
idCmdSystem * cmdSystem
Definition: CmdSystem.cpp:116
void CallSpawn(void)
Definition: Class.cpp:252
traceModelEdge_t edges[MAX_TRACEMODEL_EDGES+1]
Definition: TraceModel.h:90
int entityDefBits
Definition: Game_local.h:335
virtual void SetLocalClient(int clientNum)
Definition: Game_local.cpp:821
static class idSys * sys
Definition: Lib.h:52
virtual const idMaterial * FindMaterial(const char *name, bool makeDefault=true)=0
float GetVolume(void) const
Definition: Bounds.h:215
GLdouble s
Definition: glext.h:2935
const char * GetClassname(void) const
Definition: Class.cpp:593
GLenum GLsizei len
Definition: glext.h:3472
void Set(const char *key, const char *value)
Definition: Dict.cpp:275
virtual void ApplyImpulse(idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse)
Definition: Entity.cpp:2887
double Milliseconds(void) const
Definition: Timer.h:191
bool cinematic
Definition: Entity.h:127
virtual void DrawModel(cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis, const idVec3 &viewOrigin, const float radius)=0
GLhandleARB obj
Definition: glext.h:3602
int nextGibTime
Definition: Game_local.h:561
float x
Definition: Vector.h:318
idActor * GetAlertEntity(void)
idCVar g_showCollisionWorld("g_showCollisionWorld","0", CVAR_GAME|CVAR_BOOL,"")
idDict spawnArgs
Definition: Entity.h:122
idTestModel * testmodel
Definition: Game_local.h:300
idUserInterfaceManager * uiManager
GLenum GLint x
Definition: glext.h:2849
void ReadUsercmd(usercmd_t &usercmd)
Definition: SaveGame.cpp:1429
int i
Definition: process.py:33
idFileSystem * fileSystem
Definition: Game.h:332
contactInfo_t c
idList< idAAS * > aasList
Definition: Game_local.h:547
GLuint GLuint num
Definition: glext.h:5390
idAASFileManager * AASFileManager
Definition: Game.h:339
bool HandleESC(void)
Boolean result
void WriteVec3(const idVec3 &vec)
Definition: SaveGame.cpp:253
int IcmpNoColor(const char *text) const
Definition: Str.h:682
Definition: AI.h:122
bool influenceActive
Definition: Game_local.h:560
unsigned int h
Definition: Pvs.h:45
void Clear(void)
Definition: Game_local.cpp:198
void SetThreadName(const char *name)
void SetGlobalMaterial(const idMaterial *mat)
static void ClearForceList(void)
Definition: Force.cpp:75
idEntity * ent
Definition: Game_local.h:181
int Icmp(const char *text) const
Definition: Str.h:667
idSoundWorld * gameSoundWorld
Definition: Game_local.cpp:56
int cinematicMaxSkipTime
Definition: Game_local.h:312
void WriteMaterial(const idMaterial *material)
Definition: SaveGame.cpp:380
Definition: Class.h:174
idStr & BackSlashesToSlashes(void)
Definition: Str.cpp:727
void RemoveInventoryItem(idDict *item)
idMat3 viewAxis
Definition: Actor.h:117
void Init(byte *data, int length)
Definition: BitMsg.h:155
int EntitiesTouchingBounds(const idBounds &bounds, int contentMask, idEntity **entityList, int maxCount) const
Definition: Clip.cpp:833
const char * GetMapName(void) const
int First(const int key) const
Definition: HashIndex.h:238
idVec3 endpos
virtual bool InitFromSaveGame(const char *mapName, idRenderWorld *renderWorld, idSoundWorld *soundWorld, idFile *saveGameFile)
idEntityFx * testFx
Definition: Game_local.h:301
idDict epairs
Definition: MapFile.h:166
void WriteBool(const bool value)
Definition: SaveGame.cpp:222
idCVar developer("developer","0", CVAR_GAME|CVAR_BOOL,"")
idVec4 colorLtGrey
Definition: Lib.cpp:127
idCVar g_showEntityInfo("g_showEntityInfo","0", CVAR_GAME|CVAR_BOOL,"")
int numEntitiesToDeactivate
Definition: Game_local.h:283
idGameEdit * gameEdit
Definition: GameEdit.cpp:668
pvsHandle_t playerPVS
Definition: Game_local.h:555
idLocationEntity * LocationForPoint(const idVec3 &point)
idCVar g_skill("g_skill","1", CVAR_GAME|CVAR_INTEGER,"")
void Shutdown(void)
Definition: Anim.cpp:942
virtual bool FastWorldTrace(modelTrace_t &trace, const idVec3 &start, const idVec3 &end) const =0
void WriteUsercmd(const usercmd_t &usercmd)
Definition: SaveGame.cpp:653
bool IsHidden(void) const
Definition: Entity.cpp:1217
idEntity * SpawnEntityType(const idTypeInfo &classdef, const idDict *args=NULL, bool bIsClientReadSnapshot=false)
idGameEdit * gameEdit
Definition: Game.h:348
int i
Definition: Pvs.h:44
virtual void InitFromNewMap(const char *mapName, idRenderWorld *renderWorld, idSoundWorld *soundWorld, bool isServer, bool isClient, int randSeed)
virtual void ProjectDecalOntoWorld(const idFixedWinding &winding, const idVec3 &projectionOrigin, const bool parallel, const float fadeDepth, const idMaterial *material, const int startTime)=0
void void void Warning(const char *fmt,...) const id_attribute((format(printf
Definition: Game_local.cpp:735
int Icmpn(const char *text, int n) const
Definition: Str.h:672
idCVar g_showTriggers("g_showTriggers","0", CVAR_GAME|CVAR_BOOL,"draws trigger entities (orange) and thier targets (green). disabled triggers are drawn grey.")
Definition: File.h:50
idCVar g_timeentities("g_timeEntities","0", CVAR_GAME|CVAR_FLOAT,"when non-zero, shows entities whose think functions exceeded the # of milliseconds specified")
pvsHandle_t SetupCurrentPVS(const idVec3 &source, const pvsType_t type=PVS_NORMAL) const
Definition: Pvs.cpp:948
void RemoveSelectedEntity(idEntity *ent)
Definition: GameEdit.cpp:472
int lastDmgTime
Definition: Player.h:312
virtual const idBounds & GetBounds(int id=-1) const =0
virtual void BufferCommandText(cmdExecution_t exec, const char *text)=0
virtual const idDict & GetPersistentPlayerInfo(int clientNum)
Definition: Game_local.cpp:673
static void MapRestart_f(const idCmdArgs &args)
void RemovePrimitiveData()
Definition: MapFile.cpp:946
void GetShakeSounds(const idDict *dict)
void SetPortalState(qhandle_t portal, int blockingBits)
void KillBox(idEntity *ent, bool catch_teleport=false)
class idPlayerView playerView
Definition: Player.h:251
const int USERCMD_MSEC
Definition: UsercmdGen.h:41
virtual void SetPortalState(qhandle_t portal, int blockingBits)=0
int RandomInt(void)
Definition: Random.h:70
virtual void Think(void)
Definition: Entity.cpp:891
idCVar g_maxShowDistance("g_maxShowDistance","128", CVAR_GAME|CVAR_FLOAT,"")
void CallFrameCommand(idEntity *ent, const function_t *frameCommand)
idCVar g_cinematic("g_cinematic","1", CVAR_GAME|CVAR_BOOL,"skips updating entities that aren't marked 'cinematic' '1' during cinematics")
idVec4 colorYellow
Definition: Lib.cpp:120
idEventQueue eventQueue
Definition: Game_local.h:571
void TestGameAPI(void)
Definition: Game_local.cpp:163
idEntity * FindTraceEntity(idVec3 start, idVec3 end, const idTypeInfo &c, const idEntity *skip) const
Definition: Vector.h:52
idAAS * GetAAS(int num) const
void SetString(const char *value)
Definition: CVarSystem.h:146
void SetSeed(int seed)
Definition: Random.h:62
virtual cmHandle_t LoadModel(const char *modelName, const bool precache)=0
static class idFileSystem * fileSystem
Definition: Lib.h:55
idStrList shakeSounds
Definition: Game_local.h:586
bool InhibitEntitySpawn(idDict &spawnArgs)
idPhysics * GetPhysics(void) const
Definition: Entity.cpp:2607
virtual void SetGravity(const idVec3 &newGravity)=0
void Shutdown(void)
Definition: Clip.cpp:715
const GLubyte * c
Definition: glext.h:4677
const char * GetString(const char *key, const char *defaultString="") const
Definition: Dict.h:240
void D_DrawDebugLines(void)
Definition: SysCmds.cpp:1325
void UpdateGravity(void)
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:3454
bool SpawnEntityDef(const idDict &args, idEntity **ent=NULL, bool setDefaults=true)
void ReadFloat(float &value)
Definition: SaveGame.cpp:967
bool InCurrentPVS(const pvsHandle_t handle, const idVec3 &target) const
Definition: Pvs.cpp:1139
float Length(void) const
Definition: Vector.h:631
idWorldspawn * world
Definition: Game_local.h:280
GLuint program
Definition: glext.h:3473
virtual void Init(void)
Definition: Game_local.cpp:295
bool IsType(const idTypeInfo &superclass) const
Definition: Class.h:310
#define MAX_STRING_CHARS
Definition: Lib.h:95
float RandomFloat(void)
Definition: Random.h:82
idSys * sys
Definition: maya_main.cpp:48
static int FtoiFast(float f)
Definition: Math.h:801
int GetNumEntities(void) const
Definition: MapFile.h:196
idVec3 vec3_origin(0.0f, 0.0f, 0.0f)
idCVar g_bloodEffects("g_bloodEffects","1", CVAR_GAME|CVAR_ARCHIVE|CVAR_BOOL,"show blood splats, sprays and gibs")
virtual void ClearAllSoundEmitters(void)=0
void SetDefaults(const idDict *dict)
Definition: Dict.cpp:179
bool Parse(const char *filename, bool ignoreRegion=false, bool osPath=false)
Definition: MapFile.cpp:720
void InitScriptForMap(void)
void UnregisterEntity(idEntity *ent)
virtual void SwitchTeam(int clientNum, int team)
idStrList aasNames
Definition: Game_local.h:548
void WriteLong(int c)
Definition: BitMsg.h:295
GLuint GLuint end
Definition: glext.h:2845
void gameError(const char *fmt,...)
Definition: Game_local.cpp:805
static void Save(idSaveGame *savefile)
Definition: Event.cpp:748
void WriteFloat(const float value)
Definition: SaveGame.cpp:213
bool InPlayerConnectedArea(idEntity *ent) const
idCamera * GetCamera(void) const
idCVar g_gravity("g_gravity", DEFAULT_GRAVITY_STRING, CVAR_GAME|CVAR_FLOAT,"")
virtual void virtual void virtual void DWarning(const char *fmt,...) id_attribute((format(printf
#define MAX_CLIENTS
Definition: Game_local.h:81
virtual void SetPersistentPlayerInfo(int clientNum, const idDict &playerInfo)
Definition: Game_local.cpp:690
idCommon * common
Definition: Common.cpp:206
static const char * sufaceTypeNames[MAX_SURFACE_TYPES]
Definition: Game_local.h:337
idThread * frameCommandThread
Definition: Game_local.h:294
virtual int GetNumSounds() const
Definition: snd_shader.cpp:490
void DumpOggSounds(void)
bool GetBool(const char *key, const char *defaultString="0") const
Definition: Dict.h:256
Definition: Dict.h:65
#define NULL
Definition: Lib.h:88
virtual bool InitFromFile(const char *qpath, bool rebuild=true, bool cache=true)=0
virtual const char * GetCVarString(const char *name) const =0
virtual void ThrottleUserInfo(void)
void Clear(void)
Definition: StaticList.h:119
virtual void SetServerInfo(const idDict &serverInfo)
Definition: Game_local.cpp:899
void void DPrintf(const char *fmt,...) const id_attribute((format(printf
Definition: Game_local.cpp:715
int edges[MAX_TRACEMODEL_POLYEDGES]
Definition: TraceModel.h:80
void Clear(void)
Definition: Dict.cpp:201
static void Shutdown(void)
Definition: Class.cpp:426
virtual idRenderModel * FindModel(const char *modelName)=0
virtual const idDecl * FindType(declType_t type, const char *name, bool makeDefault=true)=0
float y
Definition: Vector.h:319
void SetInteger(const int value)
Definition: CVarSystem.h:148
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:2853
renderView_t * GetRenderView(void)
virtual void Clear(void)
Definition: Winding.h:398
float stamina
Definition: Player.h:316
virtual void SetCVarBool(const char *name, const bool value, int flags=0)=0
int GetInteger(void) const
Definition: CVarSystem.h:143
idVec3 GetVector(const char *key, const char *defaultString=NULL) const
Definition: Dict.h:260
void Think(void)
idEntity * GetNextTeamEntity(void) const
Definition: Entity.cpp:2189
static idTypeInfo * GetClass(const char *name)
Definition: Class.cpp:530
void RadiusPush(const idVec3 &origin, const float radius, const float push, const idEntity *inflictor, const idEntity *ignore, float inflictorScale, const bool quake)
void PrintStatistics(void)
Definition: Clip.cpp:1606
virtual idFile * OpenFileWrite(const char *relativePath, const char *basePath="fs_savepath")=0
bool PowerUpActive(int powerup) const
const idVec3 & GetGravity(void) const
pvsHandle_t playerConnectedAreas
Definition: Game_local.h:556
const char * GetString(const char *str) const
Definition: LangDict.cpp:148
idDict persistentLevelInfo
Definition: Game_local.h:286
int lastAIAlertTime
Definition: Game_local.h:551
virtual void DebugClearLines(int time)=0
#define ENTITYNUM_MAX_NORMAL
Definition: Game_local.h:86
float clientSmoothing
Definition: Game_local.h:334
const char * path
Definition: sws.c:117
idUserInterface * StartMenu(void)
int GetNumPVSAreas(void)
Definition: Entity.cpp:1363
virtual void DebugOutput(const idVec3 &origin)=0
void ShutdownAsyncNetwork(void)
const idStr & GetValue(void) const
Definition: Dict.h:53
void RemoveAllAASObstacles(void)
int aasHandle_t
Definition: AAS.h:73
int GetId(void) const
Definition: Clip.h:186
virtual idUserInterface * StartMenu(void)
idCVar g_frametime("g_frametime","0", CVAR_GAME|CVAR_BOOL,"displays timing information for each game frame")
void DeleteContents(bool clear)
Definition: List.h:207
int EntitiesWithinRadius(const idVec3 org, float radius, idEntity **entityList, int maxCount) const
static void InitProcessor(const char *module, bool forceGeneric)
Definition: Simd.cpp:63
idMapFile * GetLevelMap(void)
float NormalizeFast(void)
Definition: Vector.h:524
void Clear(void)
Definition: Str.h:724
static idCVar * staticVars
Definition: CVarSystem.h:178
idUserInterface * hud
Definition: Player.h:293
idCVar g_showCollisionTraces("g_showCollisionTraces","0", CVAR_GAME|CVAR_BOOL,"")
virtual void DrawText(const char *text, const idVec3 &origin, float scale, const idVec4 &color, const idMat3 &viewAxis, const int align=1, const int lifetime=0, bool depthTest=false)=0
virtual void RegisterDeclType(const char *typeName, declType_t type, idDecl *(*allocator)(void))=0
int Find(const char c, int start=0, int end=-1) const
Definition: Str.h:874
void AddEntityToHash(const char *name, idEntity *ent)
static idList< idThread * > & GetThreads(void)
idLinkList< idEntity > spawnNode
Definition: Entity.h:114
void WriteObjectList(void)
Definition: SaveGame.cpp:119
gameState_t GameState(void) const
#define SCRIPT_DEFAULT
Definition: Game.h:42
idGameLocal gameLocal
Definition: Game_local.cpp:64
void SetBool(const char *key, bool val)
Definition: Dict.h:196
virtual void ServerSendReliableMessage(int clientNum, const idBitMsg &msg)
idUserInterfaceManager * uiManager
Definition: Game.h:337
void AlertAI(idEntity *ent)
virtual void Damage(idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location)
Definition: Entity.cpp:3061
virtual const char * GetSound(int index) const
Definition: snd_shader.cpp:499
const idKeyValue * FindKey(const char *key) const
Definition: Dict.cpp:451
static void RegisterStaticVars(void)
Definition: CVarSystem.h:300
void Error(const char *fmt,...) id_attribute((format(printf
Definition: SaveGame.cpp:878
virtual void Printf(const char *fmt,...) id_attribute((format(printf
idStaticList< spawnSpot_t, MAX_GENTITIES > spawnSpots
Definition: Game_local.h:574
float shakes
Definition: sound.h:64
static void SinCos16(float a, float &s, float &c)
Definition: Math.h:406
#define DEG2RAD(a)
Definition: Math.h:56
idBounds Expand(const float d) const
Definition: Bounds.h:317
virtual const char * HandleGuiCommands(const char *menuCommand)
bool InPlayerPVS(idEntity *ent) const
idLinkList< idEntity > spawnedEntities
Definition: Game_local.h:281
void ExitCinematic(void)
void RegisterEntity(idEntity *ent)
bool sortPushers
Definition: Game_local.h:284
int lastHitTime
Definition: Player.h:265
void FlushUnusedAnims(void)
Definition: Anim.cpp:1069
virtual bool FileIsInPAK(const char *relativePath)=0
bool inCinematic
Definition: Game_local.h:313
void WriteInt(const int value)
Definition: SaveGame.cpp:168
int numClients
Definition: Game_local.h:271
virtual void MediaPrint(const char *fmt,...) id_attribute((format(printf
void SpreadLocations()
virtual void CacheDictionaryMedia(const idDict *dict)
bool NextMap(void)
virtual void RegisterDeclFolder(const char *folder, const char *extension, declType_t defaultType)=0
void ShowTargets(void)
idDeclManager * declManager
entityState_t * clientEntityStates[MAX_CLIENTS][MAX_GENTITIES]
Definition: Game_local.h:565
int GetTargets(const idDict &args, idList< idEntityPtr< idEntity > > &list, const char *ref) const
bool NeedsReload()
Definition: MapFile.cpp:959
const idMaterial * GetGlobalMaterial()
static void Init(void)
Definition: Class.cpp:377
#define SEC2MS(t)
Definition: Math.h:59
int GenerateKey(const char *string, bool caseSensitive=true) const
Definition: HashIndex.h:379
idAASFileManager * AASFileManager
void SortActiveEntityList(void)
GLubyte GLubyte b
Definition: glext.h:4662
idCVar ai_testPredictPath("ai_testPredictPath","0", CVAR_GAME|CVAR_BOOL,"")
idCVar ai_showCombatNodes("ai_showCombatNodes","0", CVAR_GAME|CVAR_BOOL,"draws attack cones for monsters")
byte lagometer[LAGO_IMG_HEIGHT][LAGO_IMG_WIDTH][4]
Definition: Game_local.h:588
idEntity * entities[MAX_GENTITIES]
Definition: Game_local.h:275
idDict userInfo[MAX_CLIENTS]
Definition: Game_local.h:272
idDict spawnArgs
Definition: Game_local.h:553
void WriteDict(const idDict *dict)
Definition: SaveGame.cpp:357
gameState_t gamestate
Definition: Game_local.h:559
void Stop(void)
Definition: Timer.h:155
virtual int GetNumDecls(declType_t type)=0
idPlayer * GetClientByName(const char *name) const
idPlayer * GetClientByNum(int current) const
static const float TWO_PI
Definition: Math.h:206
idCVar aas_test("aas_test","0", CVAR_GAME|CVAR_INTEGER,"")
idPush push
Definition: Game_local.h:297
aasHandle_t AddAASObstacle(const idBounds &bounds)
const char * GetString(void) const
Definition: CVarSystem.h:141
idCVar g_flushSave("g_flushSave","0", CVAR_GAME|CVAR_BOOL,"1 = don't buffer file writing for save games.")
bool IsNumeric(void) const
Definition: Str.h:833
void CalcFov(float base_fov, float &fov_x, float &fov_y) const
gameExport_t * GetGameAPI(gameImport_t *import)
Definition: Game_local.cpp:118
int localClientNum
Definition: Game_local.h:330
int Append(const type &obj)
Definition: StaticList.h:309
int health
Definition: Entity.h:134
idEntity * GetTeamMaster(void) const
Definition: Entity.cpp:2180
idEntity * GetTraceEntity(const trace_t &trace) const
idVec4 colorCyan
Definition: Lib.cpp:122
virtual void SetMute(bool mute)=0
void CallObjectFrameCommand(idEntity *ent, const char *frameCommand)
idScriptBool AI_DEAD
Definition: Player.h:279
int Append(const type &obj)
Definition: List.h:646
LPCSTR GetString(LPCSTR psPrompt)
Definition: GetString.cpp:87
idVec4 colorOrange
Definition: Lib.cpp:123
idDict serverInfo
Definition: Game_local.h:270
void Init(void)
Definition: Clip.cpp:684
void SetInt(const char *key, int val)
Definition: Dict.h:192
float globalShaderParms[MAX_GLOBAL_SHADER_PARMS]
Definition: Game_local.h:289
idRenderModelManager * renderModelManager
Definition: Matrix.h:333
idRenderModelManager * renderModelManager
Definition: Game.h:336
idCamera * camera
Definition: Game_local.h:544
void SetAASAreaState(const idBounds &bounds, const int areaContents, bool closed)
void SetCamera(idCamera *cam)
float yaw
Definition: Angles.h:54
static int static int vsnPrintf(char *dest, int size, const char *fmt, va_list argptr)
Definition: Str.cpp:1502
idStr mapFileName
Definition: Game_local.h:535
int AddUnique(const type &obj)
Definition: List.h:742
Definition: Game.h:66
bool GetBool(void) const
Definition: CVarSystem.h:142
#define INTSIGNBITSET(i)
Definition: Math.h:71
static void DrawDebugInfo(void)
Definition: Misc.cpp:361
virtual const idDecl * DeclByIndex(declType_t type, int index, bool forceParse=true)=0
static void NextMap_f(const idCmdArgs &args)
int mapSpawnCount
Definition: Game_local.h:540
idCVar r_aspectRatio("r_aspectRatio","0", CVAR_RENDERER|CVAR_INTEGER|CVAR_ARCHIVE,"aspect ratio of view:\n0 = 4:3\n1 = 16:9\n2 = 16:10", 0, 2)
idEntityPtr< idActor > lastAIAlertEntity
Definition: Game_local.h:550
void ClearModified(void)
Definition: CVarSystem.h:139
tuple f
Definition: idal.py:89
#define ENTITYNUM_WORLD
Definition: Game_local.h:85
void ProjectDecal(const idVec3 &origin, const idVec3 &dir, float depth, bool parallel, float size, const char *material, float angle=0)
bool LoadModel(const char *name)
Definition: Clip.cpp:215
idAngles viewAngles
Definition: Player.h:258
Definition: Actor.h:111
void Shutdown(void)
Definition: Pvs.cpp:861
bool IsGametypeFlagBased(void)
idEditEntities * editEntities
Definition: Game_local.h:308
static void Init(void)
Definition: Lib.cpp:57
int Num(void) const
Definition: List.h:265
idMat3 ToMat3(void) const
Definition: Angles.cpp:199
unsigned char byte
Definition: Lib.h:75
bool syncNextGameFrame
Definition: Game.h:52
declState_t GetState(void) const
Definition: DeclManager.h:146
void InitConsoleCommands(void)
Definition: SysCmds.cpp:2395
type * Ptr(void)
Definition: StaticList.h:263
bool WriteDeltaDict(const idDict &dict, const idDict *base)
Definition: BitMsg.cpp:308
bool IntersectsBounds(const idBounds &a) const
Definition: Bounds.h:361
static void FreeObstacleAvoidanceNodes(void)
Definition: AI_pathing.cpp:999
virtual const idBounds & GetAbsBounds(int id=-1) const =0
void RunDebugInfo(void)
virtual int NumAreas(void) const =0
virtual void SetSlowmo(bool active)=0
const GLcharARB * name
Definition: glext.h:3629
GLsizeiptr size
Definition: glext.h:3112
const function_t * GetFunction(const char *name) const
idSoundSystem * soundSystem
Definition: snd_system.cpp:92
idHashIndex entityHash
Definition: Game_local.h:279
usercmd_t usercmds[MAX_CLIENTS]
Definition: Game_local.h:273
static class idCVarSystem * cvarSystem
Definition: Lib.h:54
GLsizei maxCount
Definition: glext.h:3628
idCVar pm_thirdPerson("pm_thirdPerson","0", CVAR_GAME|CVAR_NETWORKSYNC|CVAR_BOOL,"enables third person view")
bool IsModified(void) const
Definition: CVarSystem.h:137
idCommon * common
Definition: Game.h:329
escReply_t
Definition: Game.h:63
void void void void void void LoadMap(const char *mapName, int randseed)
Definition: Game_local.cpp:923
Definition: Str.h:116
static void Restore(idRestoreGame *savefile)
Definition: Event.cpp:829
virtual int ClipContents(const idClipModel *model) const =0
idDict * FindInventoryItem(const char *name)
virtual bool AreasAreConnected(int areaNum1, int areaNum2, portalConnection_t connection)=0
const char * GetName(void) const
Definition: Entity.cpp:875
static void ServiceEvents(void)
Definition: Event.cpp:493
idCVar si_map("si_map","game/mp/d3dm1", CVAR_GAME|CVAR_SERVERINFO|CVAR_ARCHIVE,"map to be played next on server", idCmdSystem::ArgCompletion_MapName)
void SpawnMapEntities(void)
void Save(idSaveGame *savefile) const
Definition: Game_local.h:656
void ReadVec3(idVec3 &vec)
Definition: SaveGame.cpp:1011
idAnimManager animationLib
Definition: Game_local.cpp:61
idEventQueue savedEventQueue
Definition: Game_local.h:572
idCVar g_cinematicMaxSkipTime("g_cinematicMaxSkipTime","600", CVAR_GAME|CVAR_FLOAT,"# of seconds to allow game to run when skipping cinematic. prevents lock-up when cinematic doesn't end.", 0, 3600)
idCVar g_showActiveEntities("g_showActiveEntities","0", CVAR_GAME|CVAR_BOOL,"draws boxes around thinking entities. dormant entities (outside of pvs) are drawn yellow. non-dormant are green.")
static void Shutdown(void)
Definition: Anim_Import.cpp:63
idGame * game
Definition: Game.h:347
const char * c_str(void) const
Definition: Str.h:487
traceModelPoly_t polys[MAX_TRACEMODEL_POLYS]
Definition: TraceModel.h:92
void RestoreObjects(void)
Definition: SaveGame.cpp:829
void Error(const char *fmt,...) const id_attribute((format(printf
int spawnCount
Definition: Game_local.h:539
const int MAX_GAME_MESSAGE_SIZE
Definition: Game_local.h:113
int GetSeed(void) const
Definition: Random.h:66
const int CINEMATIC_SKIP_DELAY
Definition: Game_local.h:748
bool RequirementMet(idEntity *activator, const idStr &requires, int removeItem)
virtual void DebugClearPolygons(int time)=0
int clientPVS[MAX_CLIENTS][ENTITY_PVS_SIZE]
Definition: Game_local.h:566
idCVar g_stopTime("g_stopTime","0", CVAR_GAME|CVAR_BOOL,"")
idCVar g_editEntityMode("g_editEntityMode","0", CVAR_GAME|CVAR_INTEGER,"0 = off\n""1 = lights\n""2 = sounds\n""3 = articulated figures\n""4 = particle systems\n""5 = monsters\n""6 = entity names\n""7 = entity models", 0, 7, idCmdSystem::ArgCompletion_Integer< 0, 7 >)
virtual bool GetCVarBool(const char *name) const =0
const idKeyValue * GetKeyVal(int index) const
Definition: Dict.h:294
const idEventDef EV_Remove("<immediateremove>", NULL)
bool IsActive(void) const
Definition: Entity.cpp:986
void Clear(void)
Definition: HashIndex.h:328
const idBounds & GetAbsBounds(void) const
Definition: Clip.h:202
char sessionCommand[MAX_STRING_CHARS]
Definition: Game.h:46
virtual int GetContents(int id=-1) const =0
idVec3 gravity
Definition: Game_local.h:558
void AddObject(const idClass *obj)
Definition: SaveGame.cpp:150
void UpdateServerInfoFlags(void)
const int * GetPVSAreas(void)
Definition: Entity.cpp:1375
const char * Argv(int arg) const
Definition: CmdArgs.h:50
idCVar ai_showPaths("ai_showPaths","0", CVAR_GAME|CVAR_BOOL,"draws path_* entities")
pvsHandle_t GetClientPVS(idPlayer *player, pvsType_t type)
virtual const idDict * MoveCVarsToDict(int flags) const =0
idDict persistentPlayerInfo[MAX_CLIENTS]
Definition: Game_local.h:274
virtual bool CanDamage(const idVec3 &origin, idVec3 &damagePoint) const
Definition: Entity.cpp:2961
void Add(const int key, const int index)
Definition: HashIndex.h:193
idCVarSystem * cvarSystem
Definition: Game.h:331
bool CheatsOk(bool requirePlayer=true)
snapshot_t * clientSnapshots[MAX_CLIENTS]
Definition: Game_local.h:567
idVec4 colorMdGrey
Definition: Lib.cpp:128
int cinematicSkipTime
Definition: Game_local.h:310
static idAAS * Alloc(void)
Definition: AAS.cpp:39
virtual void GetMapLoadingGUI(char gui[MAX_STRING_CHARS])
const int NUM_RENDER_PORTAL_BITS
Definition: Game_local.h:116
int realClientTime
Definition: Game_local.h:332
GLint j
Definition: qgl.h:264
idBounds & ExpandSelf(const float d)
Definition: Bounds.h:322
const idTraceModel * GetTraceModel(void) const
Definition: Clip.h:234
float dot(float a[], float b[])
Definition: Model_lwo.cpp:3883
Definition: Game.h:74
virtual void SaveGame(idFile *saveGameFile)
Definition: Game_local.cpp:482
virtual void RemoveFlaggedAutoCompletion(int flags)=0
virtual void MapShutdown(void)
virtual void DebugBounds(const idVec4 &color, const idBounds &bounds, const idVec3 &org=vec3_origin, const int lifetime=0)=0
virtual void UpdateTime(int endTimeMSec)=0
const char * GetEntityDefName(void) const
Definition: Entity.cpp:842
static void ArgCompletion_EntityName(const idCmdArgs &args, void(*callback)(const char *s))
virtual void Test(const idVec3 &origin)=0
virtual int GetTimeGroupTime(int timeGroup)=0
const idDeclEntityDef * FindEntityDef(const char *name, bool makeDefault=true) const
idRenderWorld * gameRenderWorld
Definition: Game_local.cpp:55
idCVar g_showPVS("g_showPVS","0", CVAR_GAME|CVAR_INTEGER,"", 0, 2)
void AddPoint(const idVec3 &v)
Definition: Winding.h:222
const char * classname
Definition: Class.h:273
char * va(const char *fmt,...)
Definition: Str.cpp:1568
virtual int PointInArea(const idVec3 &point) const =0
bool HasPrimitiveData()
Definition: MapFile.h:215
bool Translation(trace_t &results, const idVec3 &start, const idVec3 &end, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity)
Definition: Clip.cpp:1056
const int GAME_API_VERSION
Definition: Game.h:323
Definition: Pvs.h:57
void WriteBits(int value, int numBits)
Definition: BitMsg.cpp:110
virtual void CloseFile(idFile *f)=0
#define GENTITYNUM_BITS
Definition: Game_local.h:82
#define GAME_VERSION
Definition: Game_local.h:62
bool PostEventMS(const idEventDef *ev, int time)
Definition: Class.cpp:666
idMultiplayerGame mpGame
Definition: Game_local.h:305
virtual void Error(const char *fmt,...) id_attribute((format(printf
bool RemoveEntityFromHash(const char *name, idEntity *ent)
int entityNumber
Definition: Entity.h:111
const int MAX_SURFACE_TYPES
Definition: Material.h:299
idEntityPtr< idEntity > lastGUIEnt
Definition: Game_local.h:339
GLfloat GLfloat p
Definition: glext.h:4674
bool Draw(int clientNum)
idStr name
Definition: Entity.h:121
int thinkFlags
Definition: Entity.h:125
int Num(void) const
Definition: StaticList.h:159
void SetFloat(const float value)
Definition: CVarSystem.h:149
static void DrawDebugInfo(void)
Definition: AI.cpp:5250
int GetNumKeyVals(void) const
Definition: Dict.h:290
void Zero(void)
Definition: Vector.h:415
virtual void virtual void Warning(const char *fmt,...) id_attribute((format(printf
const char * GetName(void) const
Definition: MapFile.h:200
int cinematicStopTime
Definition: Game_local.h:311
virtual void SelectTimeGroup(int timeGroup)=0
void ReadString(idStr &string)
Definition: SaveGame.cpp:985
bool Execute(void)
bool spectating
Definition: Player.h:340
idCVar g_showCollisionModels("g_showCollisionModels","0", CVAR_GAME|CVAR_BOOL,"")
void EnterCinematic(void)
gameType_t gameType
Definition: Game_local.h:324
static void Init(void)
Definition: Event.cpp:693
int sprintf(idStr &string, const char *fmt,...)
Definition: Str.cpp:1528
idDict newInfo
Definition: Game_local.h:584
virtual gameReturn_t RunFrame(const usercmd_t *clientCmds)
void ReadInt(int &value)
Definition: SaveGame.cpp:922
const idMaterial * globalMaterial
Definition: Game_local.h:545
void MapPopulate(void)
idLinkList< idEntity > activeNode
Definition: Entity.h:115
virtual int Printf(const char *fmt,...) id_attribute((format(printf
Definition: File.cpp:260
int NumAAS(void) const
idCollisionModelManager * collisionModelManager
bool IsRenderModel(void) const
Definition: Clip.h:214
bool SkipCinematic(void)
GLuint start
Definition: glext.h:2845
void RemoveAASObstacle(const aasHandle_t handle)
Definition: AI.h:253
virtual void AddCommand(const char *cmdName, cmdFunction_t function, int flags, const char *description, argCompletion_t argCompletion=NULL)=0
idEntity * SelectInitialSpawnPoint(idPlayer *player)
bool mapCycleLoaded
Definition: Game_local.h:537
idCollisionModelManager * collisionModelManager
Definition: Game.h:340
virtual void Shutdown(void)
Definition: Game_local.cpp:407
void ShutdownConsoleCommands(void)
Definition: SysCmds.cpp:2508
idMapFile * mapFile
Definition: Game_local.h:536
void ReadObject(idClass *&obj)
Definition: SaveGame.cpp:1083
void DeleteObjects(void)
Definition: SaveGame.cpp:865
Definition: AAS.h:75
void void Warning(const char *fmt,...) const id_attribute((format(printf
int heartRate
Definition: Game.h:49
static class idCommon * common
Definition: Lib.h:53
void Clear(void)
Definition: Timer.h:172
static int sortSpawnPoints(const void *ptr1, const void *ptr2)
idClass *(* CreateInstance)(void)
Definition: Class.h:275
#define ENTITYNUM_NONE
Definition: Game_local.h:84
idCVar g_decals("g_decals","1", CVAR_GAME|CVAR_ARCHIVE|CVAR_BOOL,"show decals such as bullet holes")
void Clear(void)
Definition: List.h:184
virtual void GetClientStats(int clientNum, char *data, const int len)
void SetSkill(int value)
idEntity * FindEntityUsingDef(idEntity *from, const char *match) const
bool sortTeamMasters
Definition: Game_local.h:285