void NPC_Think ( gentity_t *self)//, int msec ) { vector3 oldMoveDir; int i = 0; gentity_t *player; self->nextthink = level.time + FRAMETIME; SetNPCGlobals( self ); memset( &ucmd, 0, sizeof( ucmd ) ); VectorCopy( &self->client->ps.moveDir, &oldMoveDir ); if (self->s.NPC_class != CLASS_VEHICLE) { //YOU ARE BREAKING MY PREDICTION. Bad clear. VectorClear( &self->client->ps.moveDir ); } if(!self || !self->NPC || !self->client) { return; } // dead NPCs have a special think, don't run scripts (for now) //FIXME: this breaks deathscripts if ( self->health <= 0 ) { DeadThink(); if ( NPCInfo->nextBStateThink <= level.time ) { trap->ICARUS_MaintainTaskManager(self->s.number); } VectorCopy(&self->r.currentOrigin, &self->client->ps.origin); return; } // see if NPC ai is frozen if ( d_npcfreeze.value || (NPC->r.svFlags&SVF_ICARUS_FREEZE) ) { NPC_UpdateAngles( qtrue, qtrue ); ClientThink(self->s.number, &ucmd); //VectorCopy(self->s.origin, self->s.origin2 ); VectorCopy(&self->r.currentOrigin, &self->client->ps.origin); return; } self->nextthink = level.time + FRAMETIME/2; while (i < MAX_CLIENTS) { player = &g_entities[i]; if (player->inuse && player->client && player->client->sess.sessionTeam != TEAM_SPECTATOR && !(player->client->ps.pm_flags & PMF_FOLLOW)) { //if ( player->client->ps.viewEntity == self->s.number ) if (0) //rwwFIXMEFIXME: Allow controlling ents {//being controlled by player G_DroidSounds( self ); //FIXME: might want to at least make sounds or something? //NPC_UpdateAngles(qtrue, qtrue); //Which ucmd should we send? Does it matter, since it gets overridden anyway? NPCInfo->last_ucmd.serverTime = level.time - 50; ClientThink( NPC->s.number, &ucmd ); //VectorCopy(self->s.origin, self->s.origin2 ); VectorCopy(&self->r.currentOrigin, &self->client->ps.origin); return; } } i++; } if ( self->client->NPC_class == CLASS_VEHICLE) { if (self->client->ps.m_iVehicleNum) {//we don't think on our own //well, run scripts, though... trap->ICARUS_MaintainTaskManager(self->s.number); return; } else { VectorClear(&self->client->ps.moveDir); self->client->pers.cmd.forwardmove = 0; self->client->pers.cmd.rightmove = 0; self->client->pers.cmd.upmove = 0; self->client->pers.cmd.buttons = 0; memcpy(&self->m_pVehicle->m_ucmd, &self->client->pers.cmd, sizeof(usercmd_t)); } } else if ( NPC->s.m_iVehicleNum ) {//droid in a vehicle? G_DroidSounds( self ); } if ( NPCInfo->nextBStateThink <= level.time && !NPC->s.m_iVehicleNum )//NPCs sitting in Vehicles do NOTHING { #if AI_TIMERS int startTime = GetTime(0); #endif// AI_TIMERS if ( NPC->s.eType != ET_NPC ) {//Something drastic happened in our script return; } if ( NPC->s.weapon == WP_SABER && g_spSkill.integer >= 2 && NPCInfo->rank > RANK_LT_JG ) {//Jedi think faster on hard difficulty, except low-rank (reborn) NPCInfo->nextBStateThink = level.time + FRAMETIME/2; } else {//Maybe even 200 ms? NPCInfo->nextBStateThink = level.time + FRAMETIME; } //nextthink is set before this so something in here can override it if (self->s.NPC_class != CLASS_VEHICLE || !self->m_pVehicle) { //ok, let's not do this at all for vehicles. NPC_ExecuteBState( self ); } #if AI_TIMERS int addTime = GetTime( startTime ); if ( addTime > 50 ) { Com_Printf( S_COLOR_RED"ERROR: NPC number %d, %s %s at %s, weaponnum: %d, using %d of AI time!!!\n", NPC->s.number, NPC->NPC_type, NPC->targetname, vtos(NPC->r.currentOrigin), NPC->s.weapon, addTime ); } AITime += addTime; #endif// AI_TIMERS } else { VectorCopy( &oldMoveDir, &self->client->ps.moveDir ); //or use client->pers.lastCommand? NPCInfo->last_ucmd.serverTime = level.time - 50; if ( !NPC->next_roff_time || NPC->next_roff_time < level.time ) {//If we were following a roff, we don't do normal pmoves. //FIXME: firing angles (no aim offset) or regular angles? NPC_UpdateAngles(qtrue, qtrue); memcpy( &ucmd, &NPCInfo->last_ucmd, sizeof( usercmd_t ) ); ClientThink(NPC->s.number, &ucmd); } else { NPC_ApplyRoff(); } //VectorCopy(self->s.origin, self->s.origin2 ); } //must update icarus *every* frame because of certain animation completions in the pmove stuff that can leave a 50ms gap between ICARUS animation commands trap->ICARUS_MaintainTaskManager(self->s.number); VectorCopy(&self->r.currentOrigin, &self->client->ps.origin); }
/* =============== NPC_Think Main NPC AI - called once per frame =============== */ void NPC_Think ( gentity_t *self)//, int msec ) { self->nextthink = level.time + FRAMETIME; SetNPCGlobals( self ); memset( &ucmd, 0, sizeof( ucmd ) ); // see if NPC ai is frozen if ( debugNPCFreeze->value ) { NPC_UpdateAngles( qtrue, qtrue ); ClientThink(self->s.number, &ucmd); VectorCopy(self->s.origin, self->s.origin2 ); return; } if(!self || !self->NPC || !self->client) { return; } // dead NPCs have a special think, don't run scripts (for now) //FIXME: this breaks deathscripts if (self->health <= 0) { DeadThink(); if(NPCInfo->nextBStateThink <= level.time) { if( self->taskManager && !stop_icarus ) { self->taskManager->Update( ); } } return; } self->nextthink = level.time + FRAMETIME/2; if(NPCInfo->nextBStateThink <= level.time) { /* if( self->taskManager && !stop_icarus ) { self->taskManager->Update( ); } */ if(NPC->s.eType != ET_PLAYER) {//Something drastic happened in our script return; } NPC_ExecuteBState( self ); //Maybe even 200 ms? NPCInfo->nextBStateThink = level.time + FRAMETIME; if( self->taskManager && !stop_icarus ) { self->taskManager->Update( ); } } else { //or use client->pers.lastCommand? NPCInfo->last_ucmd.serverTime = level.time - 50; if ( !NPC->next_roff_time || NPC->next_roff_time < level.time ) {//If we were following a roff, we don't do normal pmoves. //FIXME: firing angles (no aim offset) or regular angles? NPC_UpdateAngles(qtrue, qtrue); ClientThink(NPC->s.number, &NPCInfo->last_ucmd); } else { NPC_ApplyRoff(); } VectorCopy(self->s.origin, self->s.origin2 ); } }