void G_Animate ( gentity_t *self ) { if ( self->s.eFlags & EF_SHADER_ANIM ) { return; } if ( self->s.frame == self->endFrame ) { if ( self->svFlags & SVF_ANIMATING ) { // ghoul2 requires some extra checks to see if the animation is done since it doesn't set the current frame directly if ( self->ghoul2.size() ) { float frame, junk2; int junk; // I guess query ghoul2 to find out what the current frame is and see if we are done. gi.G2API_GetBoneAnimIndex( &self->ghoul2[self->playerModel], self->rootBone, (cg.time?cg.time:level.time), &frame, &junk, &junk, &junk, &junk2, NULL ); // It NEVER seems to get to what you'd think the last frame would be, so I'm doing this to try and catch when the animation has stopped if ( frame + 1 >= self->endFrame ) { self->svFlags &= ~SVF_ANIMATING; Q3_TaskIDComplete( self, TID_ANIM_BOTH ); } } else // not ghoul2 { if ( self->loopAnim ) { self->s.frame = self->startFrame; } else { self->svFlags &= ~SVF_ANIMATING; } //Finished sequence - FIXME: only do this once even on looping anims? Q3_TaskIDComplete( self, TID_ANIM_BOTH ); } } return; } self->svFlags |= SVF_ANIMATING; // With ghoul2, we'll just set the desired start and end frame and let it do it's thing. if ( self->ghoul2.size()) { self->s.frame = self->endFrame; gi.G2API_SetBoneAnimIndex( &self->ghoul2[self->playerModel], self->rootBone, self->startFrame, self->endFrame, BONE_ANIM_OVERRIDE_FREEZE, 1.0f, cg.time, -1, -1 ); return; } if ( self->startFrame < self->endFrame ) { if ( self->s.frame < self->startFrame || self->s.frame > self->endFrame ) { self->s.frame = self->startFrame; } else { self->s.frame++; } } else if ( self->startFrame > self->endFrame ) { if ( self->s.frame > self->startFrame || self->s.frame < self->endFrame ) { self->s.frame = self->startFrame; } else { self->s.frame--; } } else { self->s.frame = self->endFrame; } }
/** @brief First function called when the DLL is loaded: Server API? **/ extern "C" __declspec( dllexport ) game_export_t* __cdecl GetGameAPI( game_import_t* imports ) { // static global variables are guaranteed to be 0, I heard. Let's assert that. assert( !g_exports ); assert( !g_originalJagamex86 ); assert( !g_modJagamex86 ); assert( !g_inShutdown ); assert( !g_realDllEntry ); assert( !g_realGetGameAPI ); assert( !g_originalJagamex86 ); assert( !g_realShutdown ); assert( !g_realVmMain ); assert( !g_modShutdown ); imports->Printf( "^5Loading original_jagamex86.dll\n" ); g_inShutdown = qfalse; g_originalJagamex86 = LoadLibrary( "original_jagamex86.dll" ); if( !g_originalJagamex86 ) { // imports->Error would be a bad idea because that'd jmp out of the cleanup code for failed dll loading, causing "Sys_GetGameAPI without Sys_UnloadingGame" imports->Printf( "^1Error: Could not load original_jagamex86.dll!\n" ); return 0; } // Get the original functions if( ! (g_realGetGameAPI = (GetGameAPI_t) GetProcAddress( g_originalJagamex86, "GetGameAPI" ) ) ) { imports->Printf( "^1Error: No GetGameAPI in original_jagamex86.dll!\n" ); return 0; } if( ! (g_realDllEntry = (dllEntry_t) GetProcAddress( g_originalJagamex86, "dllEntry" ) ) ) { imports->Printf( "^1Error: No dllEntry in original_jagamex86.dll!\n" ); return 0; } if( ! (g_realVmMain = (vmMain_t) GetProcAddress( g_originalJagamex86, "vmMain" ) ) ) { imports->Printf( "^1Error: No vmMain in original_jagamex86.dll!\n" ); return 0; } // save the imports for later usage g_imports = *imports; // Get the active mod char fs_game[ 256 + 1 ]; // variables can be up to 256 chars - not sure about trailing \0, so + 1 g_imports.Cvar_VariableStringBuffer( "fs_game", fs_game, sizeof( fs_game ) / sizeof( char ) ); if( *fs_game == '\0' ) { fs_game[0] = 'b'; fs_game[1] = 'a'; fs_game[2] = 's'; fs_game[3] = 'e'; fs_game[4] = '\0'; } g_imports.Printf( "fs_game = %s\n", fs_game ); if( strcmp( fs_game, "base" ) ) { char dllName[ MAX_QPATH + 19 ]; // "/mod_jagamex86.dll\0" is 19 chars. sprintf_s( dllName, 256 + 19, "%s/mod_jagamex86.dll", fs_game ); g_modJagamex86 = LoadLibrary( dllName ); if( g_modJagamex86 ) { g_imports.Printf( "^5Found %s - looking for functions.\n", dllName ); GetGameAPI_t modGetGameAPI; vmMain_t modVmMain; dllEntry_t modDllEntry; SetOriginalFunctions_t modSetOriginalFunctions; if( !FindProcAddress( "GetGameAPI", dllName, modGetGameAPI ) || !FindProcAddress( "vmMain", dllName, modVmMain ) || !FindProcAddress( "dllEntry", dllName, modDllEntry ) || !FindProcAddress( "SetOriginalFunctions", dllName, modSetOriginalFunctions ) ) { FreeLibrary( g_modJagamex86 ); g_modJagamex86 = 0; } else { FindProcAddress( "Shutdown", dllName, g_modShutdown ); // optional - not bad if it fails. modSetOriginalFunctions( g_realGetGameAPI, g_realDllEntry, g_realVmMain ); g_realGetGameAPI = modGetGameAPI; g_realDllEntry = modDllEntry; g_realVmMain = modVmMain; } } else { g_imports.Printf( "^5No %s available - forwarding to original_jagamex86.dll.\n", dllName ); } } // call the "real" GetGameAPI g_exports = g_realGetGameAPI( &g_imports ); if( !g_exports ) { // if that failed, clean up and pass on failure g_realGetGameAPI = 0; g_realDllEntry = 0; g_realVmMain = 0; assert( FreeLibrary( g_originalJagamex86 ) ); g_originalJagamex86 = 0; return 0; } // Change Shutdown to our own wrapper which prepares for library freeing g_realShutdown = g_exports->Shutdown; g_exports->Shutdown = ShutdownWrapper; g_imports.Printf( "^5Successfully loaded original_jagamex86.dll\n" ); return g_exports; }
static void G_Cvar_Create( const char *var_name, const char *var_value, int flags ) { gi.cvar( var_name, var_value, flags ); }
void WriteInUseBits(void) { gi.AppendToSaveGame(INT_ID('I','N','U','S'), &g_entityInUseBits, sizeof(g_entityInUseBits) ); }
/* ============ G_InitCvars ============ */ void G_InitCvars( void ) { // don't override the cheat state set by the system g_cheats = gi.cvar ("helpUsObi", "", 0); g_developer = gi.cvar ("developer", "", 0); // noset vars gi.cvar( "gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_ROM ); gi.cvar( "gamedate", __DATE__ , CVAR_ROM ); g_skippingcin = gi.cvar ("skippingCinematic", "0", CVAR_ROM); // latched vars // change anytime vars g_speed = gi.cvar( "g_speed", "250", CVAR_CHEAT ); g_gravity = gi.cvar( "g_gravity", "800", CVAR_SAVEGAME|CVAR_ROM ); g_sex = gi.cvar ("sex", "male", CVAR_USERINFO | CVAR_ARCHIVE|CVAR_SAVEGAME|CVAR_NORESTART ); g_spskill = gi.cvar ("g_spskill", "0", CVAR_ARCHIVE | CVAR_SAVEGAME|CVAR_NORESTART); g_knockback = gi.cvar( "g_knockback", "1000", CVAR_CHEAT ); g_dismemberment = gi.cvar ( "g_dismemberment", "3", CVAR_ARCHIVE );//0 = none, 1 = arms and hands, 2 = legs, 3 = waist and head, 4 = mega dismemberment g_dismemberProbabilities = gi.cvar ( "g_dismemberProbabilities", "1", CVAR_ARCHIVE );//0 = ignore probabilities, 1 = use probabilities g_synchSplitAnims = gi.cvar ( "g_synchSplitAnims", "1", 0 ); g_inactivity = gi.cvar ("g_inactivity", "0", 0); g_debugMove = gi.cvar ("g_debugMove", "0", CVAR_CHEAT ); g_debugDamage = gi.cvar ("g_debugDamage", "0", CVAR_CHEAT ); g_ICARUSDebug = gi.cvar( "g_ICARUSDebug", "0", CVAR_CHEAT ); g_timescale = gi.cvar( "timescale", "1", 0 ); g_subtitles = gi.cvar( "g_subtitles", "2", CVAR_ARCHIVE ); com_buildScript = gi.cvar ("com_buildscript", "0", 0); g_saberAutoBlocking = gi.cvar( "g_saberAutoBlocking", "1", CVAR_ARCHIVE|CVAR_CHEAT );//must press +block button to do any blocking g_saberRealisticCombat = gi.cvar( "g_saberRealisticCombat", "0", CVAR_ARCHIVE|CVAR_CHEAT );//makes collision more precise, increases damage g_saberMoveSpeed = gi.cvar( "g_saberMoveSpeed", "1", CVAR_ARCHIVE|CVAR_CHEAT );//how fast you run while attacking with a saber g_saberAnimSpeed = gi.cvar( "g_saberAnimSpeed", "1", CVAR_ARCHIVE|CVAR_CHEAT );//how fast saber animations run g_saberAutoAim = gi.cvar( "g_saberAutoAim", "1", CVAR_ARCHIVE|CVAR_CHEAT );//auto-aims at enemies when not moving or when just running forward g_AIsurrender = gi.cvar( "g_AIsurrender", "0", CVAR_CHEAT ); g_numEntities = gi.cvar( "g_numEntities", "0", CVAR_CHEAT ); gi.cvar( "newTotalSecrets", "0", CVAR_ROM ); gi.cvar_set("newTotalSecrets", "0");//used to carry over the count from SP_target_secret to ClientBegin g_iscensored = gi.cvar( "ui_iscensored", "0", CVAR_ARCHIVE|CVAR_ROM|CVAR_INIT|CVAR_CHEAT|CVAR_NORESTART ); }
void InitGame( const char *mapname, const char *spawntarget, int checkSum, const char *entities, int levelTime, int randomSeed, int globalTime, SavedGameJustLoaded_e eSavedGameJustLoaded, qboolean qbLoadTransition ) { giMapChecksum = checkSum; g_eSavedGameJustLoaded = eSavedGameJustLoaded; g_qbLoadTransition = qbLoadTransition; gi.Printf ("------- Game Initialization -------\n"); gi.Printf ("gamename: %s\n", GAMEVERSION); gi.Printf ("gamedate: %s\n", __DATE__); srand( randomSeed ); G_InitCvars(); G_InitMemory(); // set some level globals memset( &level, 0, sizeof( level ) ); level.time = levelTime; level.globalTime = globalTime; Q_strncpyz( level.mapname, mapname, sizeof(level.mapname) ); if ( spawntarget != NULL && spawntarget[0] ) { Q_strncpyz( level.spawntarget, spawntarget, sizeof(level.spawntarget) ); } else { level.spawntarget[0] = 0; } G_InitWorldSession(); // initialize all entities for this game memset( g_entities, 0, MAX_GENTITIES * sizeof(g_entities[0]) ); globals.gentities = g_entities; ClearAllInUse(); // initialize all clients for this game level.maxclients = 1; level.clients = (struct gclient_s *) G_Alloc( level.maxclients * sizeof(level.clients[0]) ); memset(level.clients, 0, level.maxclients * sizeof(level.clients[0])); // set client fields on player g_entities[0].client = level.clients; // always leave room for the max number of clients, // even if they aren't all used, so numbers inside that // range are NEVER anything but clients globals.num_entities = MAX_CLIENTS; //Set up NPC init data NPC_InitGame(); TIMER_Clear(); // //ICARUS INIT START gi.Printf("------ ICARUS Initialization ------\n"); gi.Printf("ICARUS version : %1.2f\n", ICARUS_VERSION); Interface_Init( &interface_export ); ICARUS_Init(); gi.Printf ("-----------------------------------\n"); //ICARUS INIT END // IT_LoadItemParms (); ClearRegisteredItems(); //FIXME: if this is from a loadgame, it needs to be sure to write this out whenever you do a savegame since the edges and routes are dynamic... navCalculatePaths = ( navigator.Load( mapname, checkSum ) == qfalse ); // parse the key/value pairs and spawn gentities G_SpawnEntitiesFromString( entities ); // general initialization G_FindTeams(); // SaveRegisteredItems(); gi.Printf ("-----------------------------------\n"); if ( navCalculatePaths ) {//not loaded - need to calc paths navCalcPathTime = level.time + START_TIME_NAV_CALC;//make sure all ents are in and linked } else {//loaded //FIXME: if this is from a loadgame, it needs to be sure to write this //out whenever you do a savegame since the edges and routes are dynamic... //OR: always do a navigator.CheckBlockedEdges() on map startup after nav-load/calc-paths navigator.pathsCalculated = qtrue;//just to be safe? Does this get saved out? No... assumed //need to do this, because combatpoint waypoints aren't saved out...? CP_FindCombatPointWaypoints(); navCalcPathTime = 0; if ( g_eSavedGameJustLoaded == eNO ) {//clear all the failed edges unless we just loaded the game (which would include failed edges) navigator.ClearAllFailedEdges(); } } player = &g_entities[0]; //Init dynamic music level.dmState = DM_EXPLORE; level.dmDebounceTime = 0; level.dmBeatTime = 0; level.curAlertID = 1;//0 is default for lastAlertEvent, so... eventClearTime = 0; }
/* static void G_DynamicMusicUpdate( usercmd_t *ucmd ) FIXME: can we merge any of this with the G_ChooseLookEnemy stuff? */ static void G_DynamicMusicUpdate( void ) { gentity_t *ent; gentity_t *entityList[MAX_GENTITIES]; int numListedEntities; vec3_t mins, maxs; int i, e; int distSq, radius = 2048; vec3_t center; int danger = 0; int battle = 0; int entTeam; qboolean LOScalced = qfalse, clearLOS = qfalse; //FIXME: intro and/or other cues? (one-shot music sounds) //loops //player-based if ( !player ) {//WTF? player = &g_entities[0]; return; } if ( !player->client || player->client->pers.teamState.state != TEAM_ACTIVE || level.time - player->client->pers.enterTime < 100 ) {//player hasn't spawned yet return; } if ( player->health <= 0 && player->max_health > 0 ) {//defeat music if ( level.dmState != DM_DEATH ) { level.dmState = DM_DEATH; } } if ( level.dmState == DM_DEATH ) { gi.SetConfigstring( CS_DYNAMIC_MUSIC_STATE, "death" ); return; } if ( level.dmState == DM_BOSS ) { gi.SetConfigstring( CS_DYNAMIC_MUSIC_STATE, "boss" ); return; } if ( level.dmState == DM_SILENCE ) { gi.SetConfigstring( CS_DYNAMIC_MUSIC_STATE, "silence" ); return; } if ( level.dmBeatTime > level.time ) {//not on a beat return; } level.dmBeatTime = level.time + 1000;//1 second beats if ( player->health <= 20 ) { danger = 1; } //enemy-based VectorCopy( player->currentOrigin, center ); for ( i = 0 ; i < 3 ; i++ ) { mins[i] = center[i] - radius; maxs[i] = center[i] + radius; } numListedEntities = gi.EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); for ( e = 0 ; e < numListedEntities ; e++ ) { ent = entityList[ e ]; if ( !ent || !ent->inuse ) { continue; } if ( !ent->client || !ent->NPC ) { if ( ent->classname && (!Q_stricmp( "PAS", ent->classname )||!Q_stricmp( "misc_turret", ent->classname )) ) {//a turret entTeam = ent->noDamageTeam; } else { continue; } } else {//an NPC entTeam = ent->client->playerTeam; } if ( entTeam == player->client->playerTeam ) {//ally continue; } if ( entTeam == TEAM_NEUTRAL && (!ent->enemy || !ent->enemy->client || ent->enemy->client->playerTeam != player->client->playerTeam) ) {//a droid that is not mad at me or my allies continue; } if ( !gi.inPVS( player->currentOrigin, ent->currentOrigin ) ) {//not potentially visible continue; } if ( ent->client && ent->s.weapon == WP_NONE ) {//they don't have a weapon... FIXME: only do this for droids? continue; } LOScalced = clearLOS = qfalse; if ( (ent->enemy==player&&(!ent->NPC||ent->NPC->confusionTime<level.time)) || (ent->client&&ent->client->ps.weaponTime) || (!ent->client&&ent->attackDebounceTime>level.time)) {//mad if ( ent->health > 0 ) {//alive //FIXME: do I really need this check? if ( ent->s.weapon == WP_SABER && ent->client && !ent->client->ps.saberActive && ent->enemy != player ) {//a Jedi who has not yet gotten made at me continue; } if ( ent->NPC && ent->NPC->behaviorState == BS_CINEMATIC ) {//they're not actually going to do anything about being mad at me... continue; } //okay, they're in my PVS, but how close are they? Are they actively attacking me? if ( !ent->client && ent->s.weapon == WP_TURRET && ent->fly_sound_debounce_time && ent->fly_sound_debounce_time - level.time < 10000 ) {//a turret that shot at me less than ten seconds ago } else if ( ent->client && ent->client->ps.lastShotTime && ent->client->ps.lastShotTime - level.time < 10000 ) {//an NPC that shot at me less than ten seconds ago } else {//not actively attacking me lately, see how far away they are distSq = DistanceSquared( ent->currentOrigin, player->currentOrigin ); if ( distSq > 4194304/*2048*2048*/ ) {//> 2048 away continue; } else if ( distSq > 1048576/*1024*1024*/ ) {//> 1024 away clearLOS = G_ClearLOS( player, player->client->renderInfo.eyePoint, ent ); LOScalced = qtrue; if ( clearLOS == qfalse ) {//No LOS continue; } } } battle++; } } if ( level.dmState == DM_EXPLORE ) {//only do these visibility checks if you're still in exploration mode if ( !InFront( ent->currentOrigin, player->currentOrigin, player->client->ps.viewangles, 0.0f) ) {//not in front continue; } if ( !LOScalced ) { clearLOS = G_ClearLOS( player, player->client->renderInfo.eyePoint, ent ); } if ( !clearLOS ) {//can't see them directly continue; } } if ( ent->health <= 0 ) {//dead if ( !ent->client || level.time - ent->s.time > 10000 ) {//corpse has been dead for more than 10 seconds //FIXME: coming across corpses should cause danger sounds too? continue; } } //we see enemies and/or corpses danger++; } if ( !battle ) {//no active enemies, but look for missiles, shot impacts, etc... int alert = G_CheckAlertEvents( player, qtrue, qtrue, 1024, 1024, -1, qfalse, AEL_SUSPICIOUS ); if ( alert != -1 ) {//FIXME: maybe tripwires and other FIXED things need their own sound, some kind of danger/caution theme if ( G_CheckForDanger( player, alert ) ) {//found danger near by danger++; battle = 1; } else if ( level.alertEvents[alert].owner && (level.alertEvents[alert].owner == player->enemy || (level.alertEvents[alert].owner->client && level.alertEvents[alert].owner->client->playerTeam == player->client->enemyTeam) ) ) {//NPC on enemy team of player made some noise switch ( level.alertEvents[alert].level ) { case AEL_DISCOVERED: //dangerNear = qtrue; break; case AEL_SUSPICIOUS: //suspicious = qtrue; break; case AEL_MINOR: //distraction = qtrue; break; default: break; } } } } if ( battle ) {//battle - this can interrupt level.dmDebounceTime of lower intensity levels //play battle if ( level.dmState != DM_ACTION ) { gi.SetConfigstring( CS_DYNAMIC_MUSIC_STATE, "action" ); } level.dmState = DM_ACTION; if ( battle > 5 ) { //level.dmDebounceTime = level.time + 8000;//don't change again for 5 seconds } else { //level.dmDebounceTime = level.time + 3000 + 1000*battle; } } else { if ( level.dmDebounceTime > level.time ) {//not ready to switch yet return; } else {//at least 1 second (for beats) //level.dmDebounceTime = level.time + 1000;//FIXME: define beat time? } /* if ( danger || dangerNear ) {//danger //stay on whatever we were on, action or exploration if ( !danger ) {//minimum danger = 1; } if ( danger > 3 ) { level.dmDebounceTime = level.time + 5000; } else { level.dmDebounceTime = level.time + 2000 + 1000*danger; } } else */ {//still nothing dangerous going on if ( level.dmState != DM_EXPLORE ) {//just went to explore, hold it for a couple seconds at least //level.dmDebounceTime = level.time + 2000; gi.SetConfigstring( CS_DYNAMIC_MUSIC_STATE, "explore" ); } level.dmState = DM_EXPLORE; //FIXME: look for interest points and play "mysterious" music instead of exploration? //FIXME: suspicious and distraction sounds should play some cue or change music in a subtle way? //play exploration } //FIXME: when do we go to silence? } }
IGhoul2InfoArray &TheGameGhoul2InfoArray() { return gi.TheGhoul2InfoArray(); }
void G_LoadSave_ReadMiscData(void) { gi.ReadFromSaveGame(INT_ID('L','C','K','D'), &player_locked, sizeof(player_locked), NULL); }
void G_LoadSave_WriteMiscData(void) { gi.AppendToSaveGame(INT_ID('L','C','K','D'), &player_locked, sizeof(player_locked)); }
void G_RunFrame( int levelTime ) { int i; gentity_t *ent; int ents_inuse=0; // someone's gonna be pissed I put this here... #if AI_TIMERS AITime = 0; navTime = 0; #endif// AI_TIMERS level.framenum++; level.previousTime = level.time; level.time = levelTime; //msec = level.time - level.previousTime; NAV_CheckCalcPaths(); //ResetTeamCounters(); AI_UpdateGroups(); if ( d_altRoutes->integer ) { navigator.CheckAllFailedEdges(); } navigator.ClearCheckedNodes(); //remember last waypoint, clear current one // for ( i = 0, ent = &g_entities[0]; i < globals.num_entities ; i++, ent++) for ( i = 0; i < globals.num_entities ; i++) { // if ( !ent->inuse ) // continue; if(!PInUse(i)) continue; ent = &g_entities[i]; if ( ent->waypoint != WAYPOINT_NONE && ent->noWaypointTime < level.time ) { ent->lastWaypoint = ent->waypoint; ent->waypoint = WAYPOINT_NONE; } if ( d_altRoutes->integer ) { navigator.CheckFailedNodes( ent ); } } //Look to clear out old events ClearPlayerAlertEvents(); //Run the frame for all entities // for ( i = 0, ent = &g_entities[0]; i < globals.num_entities ; i++, ent++) for ( i = 0; i < globals.num_entities ; i++) { // if ( !ent->inuse ) // continue; if(!PInUse(i)) continue; ents_inuse++; ent = &g_entities[i]; // clear events that are too old if ( level.time - ent->eventTime > EVENT_VALID_MSEC ) { if ( ent->s.event ) { ent->s.event = 0; // &= EV_EVENT_BITS; if ( ent->client ) { ent->client->ps.externalEvent = 0; } } if ( ent->freeAfterEvent ) { // tempEntities or dropped items completely go away after their event G_FreeEntity( ent ); continue; } else if ( ent->unlinkAfterEvent ) { // items that will respawn will hide themselves after their pickup event ent->unlinkAfterEvent = qfalse; gi.unlinkentity( ent ); } } // temporary entities don't think if ( ent->freeAfterEvent ) continue; G_CheckTasksCompleted(ent); G_Roff( ent ); if( !ent->client ) { if ( !(ent->svFlags & SVF_SELF_ANIMATING) ) {//FIXME: make sure this is done only for models with frames? //Or just flag as animating? if ( ent->s.eFlags & EF_ANIM_ONCE ) { ent->s.frame++; } else if ( !(ent->s.eFlags & EF_ANIM_ALLFAST) ) { G_Animate( ent ); } } } G_CheckSpecialPersistentEvents( ent ); if ( ent->s.eType == ET_MISSILE ) { G_RunMissile( ent ); continue; } if ( ent->s.eType == ET_ITEM ) { G_RunItem( ent ); continue; } if ( ent->s.eType == ET_MOVER ) { if ( ent->model && Q_stricmp( "models/test/mikeg/tie_fighter.md3", ent->model ) == 0 ) { TieFighterThink( ent ); } G_RunMover( ent ); continue; } //The player if ( i == 0 ) { // decay batteries if the goggles are active if ( cg.zoomMode == 1 && ent->client->ps.batteryCharge > 0 ) { ent->client->ps.batteryCharge--; } else if ( cg.zoomMode == 3 && ent->client->ps.batteryCharge > 0 ) { ent->client->ps.batteryCharge -= 2; if ( ent->client->ps.batteryCharge < 0 ) { ent->client->ps.batteryCharge = 0; } } G_CheckEndLevelTimers( ent ); //Recalculate the nearest waypoint for the coming NPC updates NAV_FindPlayerWaypoint(); if( ent->taskManager && !stop_icarus ) { ent->taskManager->Update(); } //dead if ( ent->health <= 0 ) { if ( ent->client->ps.groundEntityNum != ENTITYNUM_NONE ) {//on the ground pitch_roll_for_slope( ent, NULL ); } } continue; // players are ucmd driven } G_RunThink( ent ); // be aware that ent may be free after returning from here, at least one func frees them ClearNPCGlobals(); // but these 2 funcs are ok //UpdateTeamCounters( ent ); // to call anyway on a freed ent. } // perform final fixups on the player ent = &g_entities[0]; if ( ent->inuse ) { ClientEndFrame( ent ); } if( g_numEntities->integer ) { gi.Printf( S_COLOR_WHITE"Number of Entities in use : %d\n", ents_inuse ); } //DEBUG STUFF NAV_ShowDebugInfo(); NPC_ShowDebugInfo(); G_DynamicMusicUpdate(); #if AI_TIMERS AITime -= navTime; if ( AITime > 20 ) { gi.Printf( S_COLOR_RED"ERROR: total AI time: %d\n", AITime ); } else if ( AITime > 10 ) { gi.Printf( S_COLOR_YELLOW"WARNING: total AI time: %d\n", AITime ); } else if ( AITime > 2 ) { gi.Printf( S_COLOR_GREEN"total AI time: %d\n", AITime ); } if ( navTime > 20 ) { gi.Printf( S_COLOR_RED"ERROR: total nav time: %d\n", navTime ); } else if ( navTime > 10 ) { gi.Printf( S_COLOR_YELLOW"WARNING: total nav time: %d\n", navTime ); } else if ( navTime > 2 ) { gi.Printf( S_COLOR_GREEN"total nav time: %d\n", navTime ); } #endif// AI_TIMERS #ifndef FINAL_BUILD if ( delayedShutDown != 0 && delayedShutDown < level.time ) { G_Error( "Game Errors. Scroll up the console to read them." ); } #endif #ifdef _DEBUG if(!(level.framenum&0xff)) { ValidateInUseBits(); } #endif }