void AICast_Init (void) { vmCvar_t cvar; int i; numSecrets = 0; numcast = 0; numSpawningCast = 0; saveGamePending = qtrue; trap_Cvar_Register( &aicast_debug, "aicast_debug", "0", 0 ); trap_Cvar_Register( &aicast_debugname, "aicast_debugname", "", 0 ); trap_Cvar_Register( &aicast_scripts, "aicast_scripts", "1", 0 ); // (aicast_thinktime / sv_fps) * aicast_maxthink = number of cast's to think between each aicast frame // so.. // (100 / 20) * 6 = 30 // // so if the level has more than 30 AI cast's, they could start to bunch up, resulting in slower thinks trap_Cvar_Register( &cvar, "aicast_thinktime", "50", 0 ); aicast_thinktime = trap_Cvar_VariableIntegerValue( "aicast_thinktime" ); trap_Cvar_Register( &cvar, "aicast_maxthink", "12", 0 ); aicast_maxthink = trap_Cvar_VariableIntegerValue( "aicast_maxthink" ); aicast_maxclients = trap_Cvar_VariableIntegerValue( "sv_maxclients" ); aicast_skillscale = (float)trap_Cvar_VariableIntegerValue( "g_gameSkill" ) / (float)GSKILL_MAX; caststates = G_Alloc( aicast_maxclients * sizeof(cast_state_t) ); memset( caststates, 0, sizeof(caststates) ); for (i=0; i<MAX_CLIENTS; i++) { caststates[i].entityNum = i; } // try and load in the AAS now, so we can interact with it during spawning of entities i = 0; trap_AAS_SetCurrentWorld(0); while (!trap_AAS_Initialized() && (i++ < 10)) { trap_BotLibStartFrame((float) level.time / 1000); } }
/* ================== BotAIStartFrame ================== */ int BotAIStartFrame(int time) { int i; gentity_t *ent; bot_entitystate_t state; int elapsed_time, thinktime; static int local_time; static int botlib_residual; static int lastbotthink_time; G_CheckBotSpawn(); trap_Cvar_Update(&bot_rocketjump); trap_Cvar_Update(&bot_grapple); trap_Cvar_Update(&bot_fastchat); trap_Cvar_Update(&bot_nochat); trap_Cvar_Update(&bot_testrchat); trap_Cvar_Update(&bot_thinktime); trap_Cvar_Update(&bot_memorydump); trap_Cvar_Update(&bot_saveroutingcache); trap_Cvar_Update(&bot_pause); trap_Cvar_Update(&bot_report); trap_Cvar_Update(&bot_droppedweight); trap_Cvar_Update(&bot_offhandgrapple); trap_Cvar_Update(&bot_shownodechanges); trap_Cvar_Update(&bot_showteamgoals); trap_Cvar_Update(&bot_reloadcharacters); BotUpdateInfoConfigStrings(); if (bot_pause.integer) { // execute bot user commands every frame for( i = 0; i < level.maxplayers; i++ ) { if( !botstates[i] || !botstates[i]->inuse ) { continue; } if( g_entities[i].player->pers.connected != CON_CONNECTED ) { continue; } botstates[i]->lastucmd.forwardmove = 0; botstates[i]->lastucmd.rightmove = 0; botstates[i]->lastucmd.upmove = 0; botstates[i]->lastucmd.buttons = 0; botstates[i]->lastucmd.serverTime = time; trap_BotUserCommand(botstates[i]->playernum, &botstates[i]->lastucmd); } return qtrue; } if (bot_memorydump.integer) { trap_BotLibVarSet("memorydump", "1"); trap_Cvar_SetValue("bot_memorydump", 0); } if (bot_saveroutingcache.integer) { trap_BotLibVarSet("saveroutingcache", "1"); trap_Cvar_SetValue("bot_saveroutingcache", 0); } //check if bot interbreeding is activated BotInterbreeding(); //cap the bot think time if (bot_thinktime.integer > 200) { trap_Cvar_SetValue("bot_thinktime", 200); } //if the bot think time changed we should reschedule the bots if (bot_thinktime.integer != lastbotthink_time) { lastbotthink_time = bot_thinktime.integer; BotScheduleBotThink(); } elapsed_time = time - local_time; local_time = time; botlib_residual += elapsed_time; if (elapsed_time > bot_thinktime.integer) thinktime = elapsed_time; else thinktime = bot_thinktime.integer; // update the bot library if ( botlib_residual >= thinktime ) { botlib_residual -= thinktime; trap_BotLibStartFrame((float) time / 1000); if (!trap_AAS_Initialized()) return qfalse; //update entities in the botlib for (i = 0; i < MAX_GENTITIES; i++) { ent = &g_entities[i]; ent->botvalid = qfalse; if (!ent->inuse) { trap_BotLibUpdateEntity(i, NULL); continue; } if (!ent->r.linked) { trap_BotLibUpdateEntity(i, NULL); continue; } if (ent->r.svFlags & SVF_NOCLIENT) { trap_BotLibUpdateEntity(i, NULL); continue; } // do not update missiles if (ent->s.eType == ET_MISSILE && ent->s.weapon != WP_GRAPPLING_HOOK) { trap_BotLibUpdateEntity(i, NULL); continue; } // do not update event only entities if (ent->s.eType > ET_EVENTS) { trap_BotLibUpdateEntity(i, NULL); continue; } #ifdef MISSIONPACK // never link prox mine triggers if (ent->s.contents == CONTENTS_TRIGGER) { if (ent->touch == ProximityMine_Trigger) { trap_BotLibUpdateEntity(i, NULL); continue; } } #endif // ent->botvalid = qtrue; ent->update_time = trap_AAS_Time() - ent->ltime; ent->ltime = trap_AAS_Time(); // memset(&state, 0, sizeof(bot_entitystate_t)); // VectorCopy(ent->r.currentOrigin, state.origin); if (i < MAX_CLIENTS) { VectorCopy(ent->s.apos.trBase, state.angles); } else { VectorCopy(ent->r.currentAngles, state.angles); } VectorCopy( ent->r.absmin, state.absmins ); VectorCopy( ent->r.absmax, state.absmaxs ); state.type = ent->s.eType; state.flags = ent->s.eFlags; // if (ent->s.collisionType == CT_SUBMODEL) { state.solid = SOLID_BSP; //if the angles of the model changed if ( !VectorCompare( state.angles, ent->lastAngles ) ) { VectorCopy(state.angles, ent->lastAngles); state.relink = qtrue; } } else { state.solid = SOLID_BBOX; VectorCopy(state.angles, ent->lastAngles); } //previous frame visorigin VectorCopy( ent->visorigin, ent->lastvisorigin ); //if the origin changed if ( !VectorCompare( state.origin, ent->visorigin ) ) { VectorCopy( state.origin, ent->visorigin ); state.relink = qtrue; } //if the bounding box size changed if (!VectorCompare(ent->s.mins, ent->lastMins) || !VectorCompare(ent->s.maxs, ent->lastMaxs)) { VectorCopy( ent->s.mins, ent->lastMins ); VectorCopy( ent->s.maxs, ent->lastMaxs ); state.relink = qtrue; } // trap_BotLibUpdateEntity(i, &state); } BotAIRegularUpdate(); } floattime = trap_AAS_Time(); // execute scheduled bot AI for( i = 0; i < MAX_CLIENTS; i++ ) { if( !botstates[i] || !botstates[i]->inuse ) { continue; } // botstates[i]->botthink_residual += elapsed_time; // if ( botstates[i]->botthink_residual >= thinktime ) { botstates[i]->botthink_residual -= thinktime; if (!trap_AAS_Initialized()) return qfalse; if (g_entities[i].player->pers.connected == CON_CONNECTED) { BotAI(i, (float) thinktime / 1000); } } } // execute bot user commands every frame for( i = 0; i < MAX_CLIENTS; i++ ) { if( !botstates[i] || !botstates[i]->inuse ) { continue; } if( g_entities[i].player->pers.connected != CON_CONNECTED ) { continue; } BotUpdateInput(botstates[i], time, elapsed_time); trap_BotUserCommand(botstates[i]->playernum, &botstates[i]->lastucmd); } return qtrue; }
/* ================== BotAIStartFrame ================== */ int BotAIStartFrame( int time ) { int i; gentity_t *ent; bot_entitystate_t state; //entityState_t entitystate; //vec3_t mins = {-15, -15, -24}, maxs = {15, 15, 32}; int elapsed_time, thinktime; static int local_time; static int botlib_residual; static int lastbotthink_time; if ( g_gametype.integer != GT_SINGLE_PLAYER ) { G_CheckBotSpawn(); } trap_Cvar_Update( &bot_rocketjump ); trap_Cvar_Update( &bot_grapple ); trap_Cvar_Update( &bot_fastchat ); trap_Cvar_Update( &bot_nochat ); trap_Cvar_Update( &bot_testrchat ); trap_Cvar_Update( &bot_thinktime ); // Ridah, set the default AAS world trap_AAS_SetCurrentWorld( 0 ); trap_Cvar_Update( &memorydump ); if ( memorydump.integer ) { trap_BotLibVarSet( "memorydump", "1" ); trap_Cvar_Set( "memorydump", "0" ); } //if the bot think time changed we should reschedule the bots if ( bot_thinktime.integer != lastbotthink_time ) { lastbotthink_time = bot_thinktime.integer; BotScheduleBotThink(); } elapsed_time = time - local_time; local_time = time; botlib_residual += elapsed_time; if ( elapsed_time > bot_thinktime.integer ) { thinktime = elapsed_time; } else { thinktime = bot_thinktime.integer;} // update the bot library if ( botlib_residual >= thinktime ) { botlib_residual -= thinktime; trap_BotLibStartFrame( (float) time / 1000 ); // Ridah, only check the default world trap_AAS_SetCurrentWorld( 0 ); if ( !trap_AAS_Initialized() ) { return BLERR_NOERROR; } //update entities in the botlib for ( i = 0; i < MAX_GENTITIES; i++ ) { // Ridah, in single player, we only need client entity information if ( g_gametype.integer == GT_SINGLE_PLAYER && i > level.maxclients ) { break; } ent = &g_entities[i]; if ( !ent->inuse ) { continue; } if ( !ent->r.linked ) { continue; } if ( ent->r.svFlags & SVF_NOCLIENT ) { continue; } // memset( &state, 0, sizeof( bot_entitystate_t ) ); // VectorCopy( ent->r.currentOrigin, state.origin ); VectorCopy( ent->r.currentAngles, state.angles ); VectorCopy( ent->s.origin2, state.old_origin ); VectorCopy( ent->r.mins, state.mins ); VectorCopy( ent->r.maxs, state.maxs ); state.type = ent->s.eType; state.flags = ent->s.eFlags; if ( ent->r.bmodel ) { state.solid = SOLID_BSP; } else { state.solid = SOLID_BBOX;} state.groundent = ent->s.groundEntityNum; state.modelindex = ent->s.modelindex; state.modelindex2 = ent->s.modelindex2; state.frame = ent->s.frame; //state.event = ent->s.event; //state.eventParm = ent->s.eventParm; state.powerups = ent->s.powerups; state.legsAnim = ent->s.legsAnim; state.torsoAnim = ent->s.torsoAnim; // state.weapAnim = ent->s.weapAnim; //----(SA) //----(SA) didn't want to comment in as I wasn't sure of any implications of changing the aas_entityinfo_t and bot_entitystate_t structures. state.weapon = ent->s.weapon; /* if (!BotAI_GetEntityState(i, &entitystate)) continue; // memset(&state, 0, sizeof(bot_entitystate_t)); // VectorCopy(entitystate.pos.trBase, state.origin); VectorCopy(entitystate.angles, state.angles); VectorCopy(ent->s.origin2, state.old_origin); //VectorCopy(ent->r.mins, state.mins); //VectorCopy(ent->r.maxs, state.maxs); state.type = entitystate.eType; state.flags = entitystate.eFlags; if (ent->r.bmodel) state.solid = SOLID_BSP; else state.solid = SOLID_BBOX; state.modelindex = entitystate.modelindex; state.modelindex2 = entitystate.modelindex2; state.frame = entitystate.frame; state.event = entitystate.event; state.eventParm = entitystate.eventParm; state.powerups = entitystate.powerups; state.legsAnim = entitystate.legsAnim; state.torsoAnim = entitystate.torsoAnim; state.weapon = entitystate.weapon; */ // trap_BotLibUpdateEntity( i, &state ); } BotAIRegularUpdate(); } // Ridah, in single player, don't need bot's thinking if ( g_gametype.integer == GT_SINGLE_PLAYER ) { return BLERR_NOERROR; } // execute scheduled bot AI for ( i = 0; i < MAX_CLIENTS; i++ ) { if ( !botstates[i] || !botstates[i]->inuse ) { continue; } // Ridah if ( g_entities[i].r.svFlags & SVF_CASTAI ) { continue; } // done. // botstates[i]->botthink_residual += elapsed_time; // if ( botstates[i]->botthink_residual >= thinktime ) { botstates[i]->botthink_residual -= thinktime; if ( !trap_AAS_Initialized() ) { return BLERR_NOERROR; } if ( g_entities[i].client->pers.connected == CON_CONNECTED ) { BotAI( i, (float) thinktime / 1000 ); } } } // execute bot user commands every frame for ( i = 0; i < MAX_CLIENTS; i++ ) { if ( !botstates[i] || !botstates[i]->inuse ) { continue; } // Ridah if ( g_entities[i].r.svFlags & SVF_CASTAI ) { continue; } // done. if ( g_entities[i].client->pers.connected != CON_CONNECTED ) { continue; } BotUpdateInput( botstates[i], time ); trap_BotUserCommand( botstates[i]->client, &botstates[i]->lastucmd ); } return BLERR_NOERROR; }
/* ================== BotAIStartFrame ================== */ int BotAIStartFrame(int time) { int i; gentity_t *ent; bot_entitystate_t state; int elapsed_time, thinktime; static int local_time; static int botlib_residual; static int lastbotthink_time; G_CheckBotSpawn(); trap_Cvar_Update(&bot_rocketjump); trap_Cvar_Update(&bot_grapple); trap_Cvar_Update(&bot_fastchat); trap_Cvar_Update(&bot_nochat); trap_Cvar_Update(&bot_testrchat); trap_Cvar_Update(&bot_thinktime); trap_Cvar_Update(&bot_memorydump); trap_Cvar_Update(&bot_saveroutingcache); trap_Cvar_Update(&bot_pause); trap_Cvar_Update(&bot_report); if (bot_report.integer) { // BotTeamplayReport(); // trap_Cvar_Set("bot_report", "0"); BotUpdateInfoConfigStrings(); } if (bot_pause.integer) { // execute bot user commands every frame for( i = 0; i < MAX_CLIENTS; i++ ) { if( !botstates[i] || !botstates[i]->inuse ) { continue; } if( g_entities[i].client->pers.connected != CON_CONNECTED ) { continue; } botstates[i]->lastucmd.forwardmove = 0; botstates[i]->lastucmd.rightmove = 0; botstates[i]->lastucmd.upmove = 0; botstates[i]->lastucmd.buttons = 0; botstates[i]->lastucmd.serverTime = time; trap_BotUserCommand(botstates[i]->client, &botstates[i]->lastucmd); } return qtrue; } if (bot_memorydump.integer) { trap_BotLibVarSet("memorydump", "1"); trap_Cvar_Set("bot_memorydump", "0"); } if (bot_saveroutingcache.integer) { trap_BotLibVarSet("saveroutingcache", "1"); trap_Cvar_Set("bot_saveroutingcache", "0"); } //check if bot interbreeding is activated BotInterbreeding(); //cap the bot think time if (bot_thinktime.integer > 200) { trap_Cvar_Set("bot_thinktime", "200"); } //if the bot think time changed we should reschedule the bots if (bot_thinktime.integer != lastbotthink_time) { lastbotthink_time = bot_thinktime.integer; BotScheduleBotThink(); } elapsed_time = time - local_time; local_time = time; botlib_residual += elapsed_time; if (elapsed_time > bot_thinktime.integer) thinktime = elapsed_time; else thinktime = bot_thinktime.integer; // update the bot library if ( botlib_residual >= thinktime ) { botlib_residual -= thinktime; trap_BotLibStartFrame((float) time / 1000); if (!trap_AAS_Initialized()) return qfalse; //update entities in the botlib for (i = 0; i < MAX_GENTITIES; i++) { ent = &g_entities[i]; if (!ent->inuse) { trap_BotLibUpdateEntity(i, NULL); continue; } if (!ent->r.linked) { trap_BotLibUpdateEntity(i, NULL); continue; } if (ent->r.svFlags & SVF_NOCLIENT) { trap_BotLibUpdateEntity(i, NULL); continue; } // do not update missiles if (ent->s.eType == ET_MISSILE && ent->s.weapon != WP_GRAPPLING_HOOK) { trap_BotLibUpdateEntity(i, NULL); continue; } // do not update event only entities if (ent->s.eType > ET_EVENTS) { trap_BotLibUpdateEntity(i, NULL); continue; } #if 1 //def MPACK // never link prox mine triggers if (ent->r.contents == CONTENTS_TRIGGER) { if (ent->touch == ProximityMine_Trigger) { trap_BotLibUpdateEntity(i, NULL); continue; } } #endif // memset(&state, 0, sizeof(bot_entitystate_t)); // VectorCopy(ent->r.currentOrigin, state.origin); if (i < MAX_CLIENTS) { VectorCopy(ent->s.apos.trBase, state.angles); } else { VectorCopy(ent->r.currentAngles, state.angles); } VectorCopy(ent->s.origin2, state.old_origin); VectorCopy(ent->r.mins, state.mins); VectorCopy(ent->r.maxs, state.maxs); state.type = ent->s.eType; state.flags = ent->s.eFlags; if (ent->r.bmodel) state.solid = SOLID_BSP; else state.solid = SOLID_BBOX; state.groundent = ent->s.groundEntityNum; state.modelindex = ent->s.modelindex; state.modelindex2 = ent->s.modelindex2; state.frame = ent->s.frame; state.event = ent->s.event; state.eventParm = ent->s.eventParm; state.powerups = ent->s.powerups; state.legsAnim = ent->s.legsAnim; state.torsoAnim = ent->s.torsoAnim; state.weapon = ent->s.weapon; // trap_BotLibUpdateEntity(i, &state); } BotAIRegularUpdate(); } floattime = trap_AAS_Time(); // execute scheduled bot AI for( i = 0; i < MAX_CLIENTS; i++ ) { if( !botstates[i] || !botstates[i]->inuse ) { continue; } // botstates[i]->botthink_residual += elapsed_time; // if ( botstates[i]->botthink_residual >= thinktime ) { botstates[i]->botthink_residual -= thinktime; if (!trap_AAS_Initialized()) return qfalse; if (g_entities[i].client->pers.connected == CON_CONNECTED) { BotAI(i, (float) thinktime / 1000); } } } // execute bot user commands every frame for( i = 0; i < MAX_CLIENTS; i++ ) { if( !botstates[i] || !botstates[i]->inuse ) { continue; } if( g_entities[i].client->pers.connected != CON_CONNECTED ) { continue; } BotUpdateInput(botstates[i], time, elapsed_time); trap_BotUserCommand(botstates[i]->client, &botstates[i]->lastucmd); } return qtrue; }
/* ============ AICast_StartServerFrame Do movements, sighting, etc ============ */ void AICast_StartServerFrame( int time ) { int i, elapsed, count, clCount; cast_state_t *cs; int castcount; static int lasttime; static vmCvar_t aicast_disable; gentity_t *ent; cast_state_t *pcs; // int oldLegsTimer; if ( trap_Cvar_VariableIntegerValue( "savegame_loading" ) ) { return; } if ( g_gametype.integer != GT_SINGLE_PLAYER ) { return; } if ( saveGamePending ) { return; } // if waiting at intermission, don't think if ( strlen( g_missionStats.string ) > 1 ) { return; } if ( !aicast_disable.handle ) { trap_Cvar_Register( &aicast_disable, "aicast_disable", "0", CVAR_CHEAT ); } else { trap_Cvar_Update( &aicast_disable ); if ( aicast_disable.integer ) { return; } } trap_Cvar_Update( &aicast_debug ); // no need to think during the intermission if ( level.intermissiontime ) { return; } // // make sure the AAS gets updated trap_BotLibStartFrame( (float) time / 1000 ); // // elapsed = time - lasttime; if ( elapsed == 0 ) { return; // no time has elapsed } pcs = AICast_GetCastState( 0 ); //G_Printf( "AI startserverframe: %i\n", time ); if ( elapsed < 0 ) { elapsed = 0; lasttime = time; } // don't let the framerate drop below 10 if ( elapsed > 100 ) { elapsed = 100; } // // process player's current script if it exists AICast_ScriptRun( AICast_GetCastState( 0 ), qfalse ); // AICast_SightUpdate( (int)( (float)SIGHT_PER_SEC * ( (float)elapsed / 1000 ) ) ); // count = 0; castcount = 0; clCount = 0; ent = g_entities; // //update the AI characters // TTimo gcc: left-hand operand of comma expression has no effect // initial line: for (i = 0; i < aicast_maxclients, clCount < level.numPlayingClients; i++, ent++) for ( i = 0; ( i < aicast_maxclients ) && ( clCount < level.numPlayingClients ) ; i++, ent++ ) { if ( ent->client ) { clCount++; } // cs = AICast_GetCastState( i ); // is this a cast AI? if ( cs->bs ) { if ( ent->aiInactive == qfalse && ent->inuse ) { // elapsed = level.time - cs->lastMoveThink; // // optimization, if they're not in the player's PVS, and they aren't trying to move, then don't bother thinking if ( ( ( ent->health > 0 ) && ( elapsed > 300 ) ) || ( g_entities[0].client && g_entities[0].client->cameraPortal ) || ( cs->vislist[0].visible_timestamp == cs->vislist[0].lastcheck_timestamp ) || ( pcs->vislist[cs->entityNum].visible_timestamp == pcs->vislist[cs->entityNum].lastcheck_timestamp ) || ( VectorLength( ent->client->ps.velocity ) > 0 ) || ( cs->bs->lastucmd.forwardmove || cs->bs->lastucmd.rightmove || cs->bs->lastucmd.upmove > 0 || cs->bs->lastucmd.buttons || cs->bs->lastucmd.wbuttons ) || ( trap_InPVS( cs->bs->origin, g_entities[0].s.pos.trBase ) ) ) { // do pvs check last, since it's the most expensive to call // oldLegsTimer = ent->client->ps.legsTimer; // // send it's movement commands // serverTime = time; AICast_UpdateInput( cs, elapsed ); trap_BotUserCommand( cs->bs->client, &( cs->bs->lastucmd ) ); cs->lastMoveThink = level.time; // // check for anim changes that may require us to stay still // /* if (oldLegsTimer != ent->client->ps.legsTimer) { // dont move until they are finished if (cs->castScriptStatus.scriptNoMoveTime < level.time + ent->client->ps.legsTimer) { cs->castScriptStatus.scriptNoMoveTime = level.time + ent->client->ps.legsTimer; } } */ } } else { trap_UnlinkEntity( ent ); } // // see if we've checked all cast AI's if ( ++castcount >= numcast ) { break; } } } // lasttime = time; }
void AICast_StartFrame( int time ) { int i, elapsed, count, clCount; cast_state_t *cs; int castcount; static int lasttime; static vmCvar_t aicast_disable; gentity_t *ent; if ( trap_Cvar_VariableIntegerValue( "savegame_loading" ) ) { return; } if ( saveGamePending ) { return; } // if waiting at intermission, don't think if ( strlen( g_missionStats.string ) > 1 ) { return; } if ( !aicast_disable.handle ) { trap_Cvar_Register( &aicast_disable, "aicast_disable", "0", CVAR_CHEAT ); } else { trap_Cvar_Update( &aicast_disable ); if ( aicast_disable.integer ) { return; } } trap_Cvar_Update( &aicast_debug ); trap_Cvar_Update( &aicast_debugname ); trap_Cvar_Update( &aicast_scripts ); // no need to think during the intermission if ( level.intermissiontime ) { return; } // // make sure the AAS gets updated trap_BotLibStartFrame( (float) time / 1000 ); // // elapsed = time - lasttime; if ( elapsed == 0 ) { return; // no time has elapsed } //G_Printf( "AI startframe: %i\n", time ); if ( elapsed < 0 ) { elapsed = 0; lasttime = time; } // don't let the framerate drop below 10 if ( elapsed > 100 ) { elapsed = 100; } //AICast_SightUpdate( (int)((float)SIGHT_PER_SEC * ((float)elapsed / 1000)) ); // count = 0; castcount = 0; clCount = 0; ent = g_entities; // //update the AI characters // TTimo gcc: left-hand operand of comma expression has no effect // initial line was: for (i = 0; i < aicast_maxclients, clCount < level.numPlayingClients; i++, ent++) for ( i = 0; ( i < aicast_maxclients ) && ( clCount < level.numPlayingClients ) ; i++, ent++ ) { if ( ent->client ) { clCount++; } // cs = AICast_GetCastState( i ); // is this a cast AI? if ( cs->bs ) { if ( ent->inuse ) { if ( ent->aiInactive == qfalse ) { // elapsed = time - cs->lastThink; // // if they're moving/firing think every frame if ( ( elapsed >= 50 ) && ( ( ( ( !VectorCompare( ent->client->ps.velocity, vec3_origin ) ) || ( ent->client->buttons ) || ( elapsed >= aicast_thinktime ) ) && ( count <= aicast_maxthink ) ) || ( elapsed >= aicast_thinktime * 2 ) ) ) { // make it think now AICast_Think( i, (float)elapsed / 1000 ); cs->lastThink = time; // count++; } // check for any debug info updates AICast_DebugFrame( cs ); } else if ( cs->aiFlags & AIFL_WAITINGTOSPAWN ) { // check f the space is clear yet ent->AIScript_AlertEntity( ent ); } } else { trap_UnlinkEntity( ent ); } // // see if we've checked all cast AI's if ( ++castcount >= numcast ) { break; } } } // lasttime = time; }