Esempio n. 1
0
/*
-------------------------
NPC_CheckSightEvents
-------------------------
*/
static int G_CheckSightEvents( gentity_t *self, int hFOV, int vFOV, float maxSeeDist, int ignoreAlert, qboolean mustHaveOwner, int minAlertLevel )
{
	int	bestEvent = -1;
	int bestAlert = -1;
	int	bestTime = -1;
	float	dist, radius;

	maxSeeDist *= maxSeeDist;
	for ( int i = 0; i < level.numAlertEvents; i++ )
	{
		//are we purposely ignoring this alert?
		if ( level.alertEvents[i].ID == ignoreAlert )
			continue;
		//We're only concerned about sounds
		if ( level.alertEvents[i].type != AET_SIGHT )
			continue;
		//must be at least this noticable
		if ( level.alertEvents[i].level < minAlertLevel )
			continue;
		//must have an owner?
		if ( mustHaveOwner && !level.alertEvents[i].owner )
			continue;

		//Must be within range
		dist = DistanceSquared( level.alertEvents[i].position, self->currentOrigin );

		//can't see it
		if ( dist > maxSeeDist )
			continue;

		radius = level.alertEvents[i].radius * level.alertEvents[i].radius;
		if ( dist > radius )
			continue;

		//Must be visible
		if ( InFOV( level.alertEvents[i].position, self, hFOV, vFOV ) == qfalse )
			continue;

		if ( G_ClearLOS( self, level.alertEvents[i].position ) == qfalse )
			continue;

		//FIXME: possibly have the light level at this point affect the
		//			visibility/alert level of this event?  Would also
		//			need to take into account how bright the event
		//			itself is.  A lightsaber would stand out more
		//			in the dark... maybe pass in a light level that
		//			is added to the actual light level at this position?

		//See if this one takes precedence over the previous one
		if ( level.alertEvents[i].level >= bestAlert //higher alert level
			|| (level.alertEvents[i].level==bestAlert&&level.alertEvents[i].timestamp >= bestTime) )//same alert level, but this one is newer
		{//NOTE: equal is better because it's later in the array
			bestEvent = i;
			bestAlert = level.alertEvents[i].level;
			bestTime = level.alertEvents[i].timestamp;
		}
	}

	return bestEvent;
}
Esempio n. 2
0
static qboolean NPC_CheckPlayerDistance( void )
{
	//Make sure we have an enemy
	if ( NPC->enemy == NULL )
		return qfalse;

	//Only do this for non-players
	if ( NPC->enemy->s.number == 0 )
		return qfalse;

	//must be set up to get mad at player
	if ( !NPC->client || NPC->client->enemyTeam != TEAM_PLAYER )
		return qfalse;

	//Must be within our FOV
	if ( InFOV( &g_entities[0], NPC, NPCInfo->stats.hfov, NPCInfo->stats.vfov ) == qfalse )
		return qfalse;

	float	distance = DistanceSquared( NPC->currentOrigin, NPC->enemy->currentOrigin );

	if ( distance > DistanceSquared( NPC->currentOrigin, g_entities[0].currentOrigin ) )
	{
		G_SetEnemy( NPC, &g_entities[0] );
		return qtrue;
	}

	return qfalse;
}
qboolean SensoryPerception::CanSeePosition( const Vector &start, const Vector &position, qboolean useFOV , qboolean useVisionDistance )
{
	
	// Check if This Actor can even see at all
	if ( !ShouldRespondToStimuli( StimuliSight ) )
		return false;
	
	// Check for FOV
	if ( useFOV )
	{
		if ( !InFOV( position ) )
			return false;
	}
	
	// Check for vision distance
	if ( useVisionDistance )
	{
		if ( !WithinVisionDistance( position ) )
			return false;
	}
	
	// Do Trace
	// Check if he's visible
	auto trace = G_Trace( start, vec_zero, vec_zero, position, act, MASK_OPAQUE, false, "SensoryPerception::CanSeeEntity" );
	if ( trace.fraction == 1.0f )
		return true;
	
	return false;
}
Esempio n. 4
0
//rww - cheap check to see if an armed client is looking in our general direction
qboolean NPC_SomeoneLookingAtMe(gentity_t *ent)
{
	int i = 0;
	gentity_t *pEnt;

	while (i < MAX_CLIENTS)
	{
		pEnt = &g_entities[i];

		if (pEnt && pEnt->inuse && pEnt->client && pEnt->client->sess.sessionTeam != TEAM_SPECTATOR &&
			!(pEnt->client->ps.pm_flags & PMF_FOLLOW) && pEnt->s.weapon != WP_NONE)
		{
			if (trap_InPVS(ent->r.currentOrigin, pEnt->r.currentOrigin))
			{
				if (InFOV( ent, pEnt, 30, 30 ))
				{ //I'm in a 30 fov or so cone from this player.. that's enough I guess.
					return qtrue;
				}
			}
		}

		i++;
	}

	return qfalse;
}
//
// Name:        CanSeeEntity()
// Parameters:  Entity *start - The entity trying to see
//              Entity *target - The entity that needs to be seen
//              qboolean useFOV - take FOV into consideration or not
//              qboolean useVisionDistance - take visionDistance into consideration
// Description: Wraps a lot of the different CanSee Functions into one
//
qboolean SensoryPerception::CanSeeEntity( Entity *start, const Entity *target, qboolean useFOV, qboolean useVisionDistance )
{
	
	// Check for NULL
	if ( !start || !target )
		return false;
	
	// Check if This Actor can even see at all
	if ( !ShouldRespondToStimuli( StimuliSight ) )
		return false;
	
	// Check for FOV
	if ( useFOV )
	{
		if ( !InFOV( target ) )
			return false;
	}
	
	// Check for vision distance
	if ( useVisionDistance )
	{
		if ( !WithinVisionDistance( target ) )
			return false;
	}
	
	// Do Trace
	auto p = target->centroid;
	auto eyePos = vec_zero;
	
	// If the start entity is an actor, then we want to add in the eyeposition
	if ( start->isSubclassOf ( Actor ) )
	{
		Actor *a;
		a = dynamic_cast<Actor*>(start);
		
		if ( !a )
			return false;
		
		eyePos = a->EyePosition();
		
	}
	
	// Check if he's visible
	auto trace = G_Trace( eyePos, vec_zero, vec_zero, p, target, MASK_OPAQUE, false, "SensoryPerception::CanSeeEntity" );
	
	if ( trace.fraction == 1.0f || trace.ent == target->edict )
		return true;
	
	// Check if his head is visible
	p.z = target->absmax.z;
	trace = G_Trace( eyePos, vec_zero, vec_zero, p, target, MASK_OPAQUE, false, "SensoryPerception::CanSeeEntity" );
	if ( trace.fraction == 1.0f || trace.ent == target->edict )
		return true;			
	
	return false;
	
}
//
// Name:        CanSeeEntity()
// Parameters:  Vector &start -- The starting position
//              Entity *target - The entity that needs to be seen
//              qboolean useFOV - take FOV into consideration or not
//              qboolean useVisionDistance - take visionDistance into consideration
// Description: Wraps a lot of the different CanSee Functions into one
//
qboolean SensoryPerception::CanSeeEntity( const Vector &start , const Entity *target, qboolean useFOV , qboolean useVisionDistance )
{
	// Check for NULL
	if ( !target )
		return false;
	
	// Check if This Actor can even see at all
	if ( !ShouldRespondToStimuli( StimuliSight ) )
		return false;
	
	
	// Check for FOV
	if ( useFOV )
	{
		if ( !InFOV( target ) )
			return false;
	}
	
	// Check for vision distance
	if ( useVisionDistance )
	{
		if ( !WithinVisionDistance( target ) )
			return false;
	}
	
	// Do Trace
	auto realStart = start;	
	auto p = target->centroid;
	
	// Add in the eye offset
	
	auto eyePos = act->EyePosition() - act->origin;
	realStart += eyePos;
	
	// Check if he's visible
	auto trace = G_Trace( realStart, vec_zero, vec_zero, p, act, MASK_OPAQUE, false, "SensoryPerception::CanSeeEntity" );
	if ( trace.fraction == 1.0f || trace.ent == target->edict )
		return true;
	
	// Check if his head is visible
	p.z = target->absmax.z;
	trace = G_Trace( realStart, vec_zero, vec_zero, p, act, MASK_OPAQUE, false, "SensoryPerception::CanSeeEntity" );
	if ( trace.fraction == 1.0f || trace.ent == target->edict )
		return true;			
	
	
	return false;
}
Esempio n. 7
0
qboolean NPC_TargetVisible( gentity_t *ent )
{
	//Make sure we're in a valid range
	if ( DistanceSquared( ent->currentOrigin, NPC->currentOrigin ) > ( NPCInfo->stats.visrange * NPCInfo->stats.visrange ) )
		return qfalse;

	//Check our FOV
	if ( InFOV( ent, NPC, NPCInfo->stats.hfov, NPCInfo->stats.vfov ) == qfalse )
		return qfalse;

	//Check for sight
	if ( NPC_ClearLOS( ent ) == qfalse )
		return qfalse;

	return qtrue;
}
Esempio n. 8
0
qboolean InFOV( vec3_t origin, gentity_t *from, int hFOV, int vFOV )
{
	vec3_t	fromAngles, eyes;

	if( from->client )
	{
		VectorCopy(from->client->ps.viewangles, fromAngles);
	}
	else
	{
		VectorCopy(from->s.angles, fromAngles);
	}

	CalcEntitySpot( from, SPOT_HEAD, eyes );

	return InFOV( origin, eyes, fromAngles, hFOV, vFOV );
}
Esempio n. 9
0
void NPC_RemoveBody( gentity_t *self )
{
	// Only do all of this nonsense for Scav boys ( and girls )
	if ( self->client->playerTeam == TEAM_SCAVENGERS || self->client->playerTeam == TEAM_KLINGON 
		|| self->client->playerTeam == TEAM_HIROGEN || self->client->playerTeam == TEAM_MALON )
	{
		self->nextthink = level.time + 1000; // try back in a second

		if ( DistanceSquared( g_entities[0].currentOrigin, self->currentOrigin ) <= REMOVE_DISTANCE_SQR )
		{
			return;
		}

		if ( (InFOV( self, &g_entities[0], 110, 90 )) ) // generous FOV check
		{
			if ( (NPC_ClearLOS( &g_entities[0], self->currentOrigin )) )
			{
				return;
			}
		}
	}

	G_FreeEntity( self );
}
Esempio n. 10
0
qboolean NPC_CheckSurrender( void )
{
	if ( !g_AIsurrender->integer )
	{//not enabled
		return qfalse;
	}
	if ( !Q3_TaskIDPending( NPC, TID_MOVE_NAV ) 
		&& NPC->client->ps.groundEntityNum != ENTITYNUM_NONE 
		&& !NPC->client->ps.weaponTime && !PM_InKnockDown( &NPC->client->ps )
		&& NPC->enemy && NPC->enemy->client && NPC->enemy->enemy == NPC && NPC->enemy->s.weapon != WP_NONE && NPC->enemy->s.weapon != WP_MELEE 
		&& NPC->enemy->health > 20 && NPC->enemy->painDebounceTime < level.time - 3000 && NPC->enemy->client->ps.forcePowerDebounce[FP_SABER_DEFENSE] < level.time - 1000 )
	{//don't surrender if scripted to run somewhere or if we're in the air or if we're busy or if we don't have an enemy or if the enemy is not mad at me or is hurt or not a threat or busy being attacked
		//FIXME: even if not in a group, don't surrender if there are other enemies in the PVS and within a certain range?
		if ( NPC->s.weapon != WP_ROCKET_LAUNCHER 
			&& NPC->s.weapon != WP_REPEATER
			&& NPC->s.weapon != WP_FLECHETTE
			&& NPC->s.weapon != WP_SABER )
		{//jedi and heavy weapons guys never surrender
			//FIXME: rework all this logic into some orderly fashion!!!
			if ( NPC->s.weapon != WP_NONE )
			{//they have a weapon so they'd have to drop it to surrender
				//don't give up unless low on health
				if ( NPC->health > 25 || NPC->health >= NPC->max_health )
				{
					return qfalse;
				}
				if ( g_crosshairEntNum == NPC->s.number && NPC->painDebounceTime > level.time )
				{//if he just shot me, always give up
					//fall through
				}
				else
				{//don't give up unless facing enemy and he's very close
					if ( !InFOV( player, NPC, 60, 30 ) )
					{//I'm not looking at them
						return qfalse;
					}
					else if ( DistanceSquared( NPC->currentOrigin, player->currentOrigin ) < 65536/*256*256*/ )
					{//they're not close
						return qfalse;
					}
					else if ( !gi.inPVS( NPC->currentOrigin, player->currentOrigin ) )
					{//they're not in the same room
						return qfalse;
					}
				}
			}
			if ( NPCInfo->group && NPCInfo->group->numGroup <= 1 )
			{//I'm alone but I was in a group//FIXME: surrender anyway if just melee or no weap?
				if ( NPC->s.weapon == WP_NONE 
					//NPC has a weapon
					|| NPC->enemy == player
					|| (NPC->enemy->s.weapon == WP_SABER&&NPC->enemy->client&&NPC->enemy->client->ps.saberActive)
					|| (NPC->enemy->NPC && NPC->enemy->NPC->group && NPC->enemy->NPC->group->numGroup > 2) )
				{//surrender only if have no weapon or fighting a player or jedi or if we are outnumbered at least 3 to 1
					if ( NPC->enemy == player )
					{//player is the guy I'm running from
						if ( g_crosshairEntNum == NPC->s.number )
						{//give up if player is aiming at me
							NPC_Surrender();
							NPC_UpdateAngles( qtrue, qtrue );
							return qtrue;
						}
						else if ( player->s.weapon == WP_SABER )
						{//player is using saber
							if ( InFOV( NPC, player, 60, 30 ) )
							{//they're looking at me
								if ( DistanceSquared( NPC->currentOrigin, player->currentOrigin ) < 16384/*128*128*/ )
								{//they're close
									if ( gi.inPVS( NPC->currentOrigin, player->currentOrigin ) )
									{//they're in the same room
										NPC_Surrender();
										NPC_UpdateAngles( qtrue, qtrue );
										return qtrue;
									}
								}
							}
						}
					}
					else if ( NPC->enemy )
					{//???
						//should NPC's surrender to others?
						if ( InFOV( NPC, NPC->enemy, 30, 30 ) )
						{//they're looking at me
							if ( DistanceSquared( NPC->currentOrigin, NPC->enemy->currentOrigin ) < 4096 )
							{//they're close
								if ( gi.inPVS( NPC->currentOrigin, NPC->enemy->currentOrigin ) )
								{//they're in the same room
									//FIXME: should player-team NPCs not fire on surrendered NPCs?
									NPC_Surrender();
									NPC_UpdateAngles( qtrue, qtrue );
									return qtrue;
								}
							}
						}
					}
				}
			}
		}
	}
	return qfalse;
}
Esempio n. 11
0
visibility_t NPC_CheckVisibility ( gentity_t *ent, int flags )
{
	// flags should never be 0
	if ( !flags )
	{
		return VIS_NOT;
	}

	// check PVS
	if ( flags & CHECK_PVS )
	{
		if ( !gi.inPVS ( ent->currentOrigin, NPC->currentOrigin ) )
		{
			return VIS_NOT;
		}
	}
	if ( !(flags & (CHECK_360|CHECK_FOV|CHECK_SHOOT)) )
	{
		return VIS_PVS;
	}

	// check within visrange
	if (flags & CHECK_VISRANGE)
	{
		if( !InVisrange ( ent ) )
		{
			return VIS_PVS;
		}
	}

	// check 360 degree visibility
	//Meaning has to be a direct line of site
	if ( flags & CHECK_360 )
	{
		if ( !CanSee ( ent ) )
		{
			return VIS_PVS;
		}
	}
	if ( !(flags & (CHECK_FOV|CHECK_SHOOT)) )
	{
		return VIS_360;
	}

	// check FOV
	if ( flags & CHECK_FOV )
	{
		if ( !InFOV ( ent, NPC, NPCInfo->stats.hfov, NPCInfo->stats.vfov) )
		{
			return VIS_360;
		}
	}

	if ( !(flags & CHECK_SHOOT) )
	{
		return VIS_FOV;
	}

	// check shootability
	if ( flags & CHECK_SHOOT )
	{
		if ( !CanShoot ( ent, NPC ) )
		{
			return VIS_FOV;
		}
	}

	return VIS_SHOOT;
}
Esempio n. 12
0
static qboolean NPC_CheckPlayerDistance( void )
{//racc - check for a closer player to the NPC than it's current enemy.
	//qtrue = changed to closer player
	//qfalse = no change.

	//[CoOp] added SP Code
	//also set it up to work for multiple players.

	//return qfalse;//MOOT in MP
	int i; //counter

	//closest current distance
	gentity_t* player;
	float ClosestDistance;
	int ClosestPlayer = -1; //current closest player
	
	float distance;

	//Make sure we have an enemy
	if ( NPC->enemy == NULL )
		return qfalse;

	ClosestDistance = DistanceSquared( NPC->r.currentOrigin, NPC->enemy->r.currentOrigin );

	/*
	//Only do this for non-players
	if ( NPC->enemy->s.number == 0 )
		return qfalse;
	*/
	//must be set up to get mad at player
	if ( !NPC->client || NPC->client->enemyTeam != NPCTEAM_PLAYER )
		return qfalse;

	//go into the scan loop.
	for( i = 0; i < MAX_CLIENTS; i++ )
	{
		player = &g_entities[i];

		if(!player->inuse || !player->client 
			|| player->client->pers.connected != CON_CONNECTED
			|| player->client->sess.sessionTeam == TEAM_SPECTATOR 
			|| player->health < 0)
		{//not a good player
			continue;
		}

		//Must be within our FOV
		if ( InFOV( player, NPC, NPCInfo->stats.hfov, NPCInfo->stats.vfov ) == qfalse )
			continue;

		distance = DistanceSquared( NPC->r.currentOrigin, player->r.currentOrigin );

		if( distance < ClosestDistance )
		{//we're closer than the current closest
			ClosestDistance = distance;
			ClosestPlayer = player->s.number;
		}
	}

	if(ClosestPlayer != -1)
	{
		
		if(ClosestDistance + 128 * 128 < DistanceSquared( NPC->r.currentOrigin, NPC->enemy->r.currentOrigin ) )
		{//player has too be reasonably closer than the current enemy
			G_SetEnemy( NPC, &g_entities[ClosestPlayer] );
			return qtrue;
		}
	}

	/*
	//Must be within our FOV
	if ( InFOV( &g_entities[0], NPC, NPCInfo->stats.hfov, NPCInfo->stats.vfov ) == qfalse )
		return qfalse;

	distance = DistanceSquared( NPC->r.currentOrigin, NPC->enemy->r.currentOrigin );
	
	if ( distance > DistanceSquared( NPC->r.currentOrigin, g_entities[0].r.currentOrigin ) )
	{ //rwwFIXMEFIXME: care about all clients not just client 0
		G_SetEnemy( NPC, &g_entities[0] );
		return qtrue;
	}
	*/
	//[/CoOp] SP Code

	return qfalse;	
}
Esempio n. 13
0
void NPC_BSGrenadier_Attack( void )
{
	//Don't do anything if we're hurt
	if ( NPC->painDebounceTime > level.time )
	{
		NPC_UpdateAngles( qtrue, qtrue );
		return;
	}

	//NPC_CheckEnemy( qtrue, qfalse );
	//If we don't have an enemy, just idle
	if ( NPC_CheckEnemyExt() == qfalse )//!NPC->enemy )//
	{
		NPC->enemy = NULL;
		NPC_BSGrenadier_Patrol();//FIXME: or patrol?
		return;
	}

	if ( TIMER_Done( NPC, "flee" ) && NPC_CheckForDanger( NPC_CheckAlertEvents( qtrue, qtrue, -1, qfalse, AEL_DANGER ) ) )
	{//going to run
		NPC_UpdateAngles( qtrue, qtrue );
		return;
	}

	if ( !NPC->enemy )
	{//WTF?  somehow we lost our enemy?
		NPC_BSGrenadier_Patrol();//FIXME: or patrol?
		return;
	}

	enemyLOS = enemyCS = qfalse;
	move = qtrue;
	faceEnemy = qfalse;
	shoot = qfalse;
	enemyDist = DistanceSquared( NPC->enemy->currentOrigin, NPC->currentOrigin );

	//See if we should switch to melee attack
	if ( enemyDist < 16384 && (!NPC->enemy->client||NPC->enemy->client->ps.weapon != WP_SABER||!NPC->enemy->client->ps.saberActive) )//128
	{//enemy is close and not using saber
		if ( NPC->client->ps.weapon == WP_THERMAL )
		{//grenadier
			trace_t	trace;
			gi.trace ( &trace, NPC->currentOrigin, NPC->enemy->mins, NPC->enemy->maxs, NPC->enemy->currentOrigin, NPC->s.number, NPC->enemy->clipmask );
			if ( !trace.allsolid && !trace.startsolid && (trace.fraction == 1.0 || trace.entityNum == NPC->enemy->s.number ) )
			{//I can get right to him
				//reset fire-timing variables
				NPC_ChangeWeapon( WP_MELEE );
				if ( !(NPCInfo->scriptFlags&SCF_CHASE_ENEMIES) )//NPCInfo->behaviorState == BS_STAND_AND_SHOOT )
				{//FIXME: should we be overriding scriptFlags?
					NPCInfo->scriptFlags |= SCF_CHASE_ENEMIES;//NPCInfo->behaviorState = BS_HUNT_AND_KILL;
				}
			}
		}
	}
	else if ( enemyDist > 65536 || (NPC->enemy->client && NPC->enemy->client->ps.weapon == WP_SABER && NPC->enemy->client->ps.saberActive) )//256
	{//enemy is far or using saber
		if ( NPC->client->ps.weapon == WP_MELEE && (NPC->client->ps.stats[STAT_WEAPONS]&(1<<WP_THERMAL)) )
		{//fisticuffs, make switch to thermal if have it
			//reset fire-timing variables
			NPC_ChangeWeapon( WP_THERMAL );
		}
	}

	//can we see our target?
	if ( NPC_ClearLOS( NPC->enemy ) )
	{
		NPCInfo->enemyLastSeenTime = level.time;
		enemyLOS = qtrue;

		if ( NPC->client->ps.weapon == WP_MELEE )
		{
			if ( enemyDist <= 4096 && InFOV( NPC->enemy->currentOrigin, NPC->currentOrigin, NPC->client->ps.viewangles, 90, 45 ) )//within 64 & infront
			{
				VectorCopy( NPC->enemy->currentOrigin, NPCInfo->enemyLastSeenLocation );
				enemyCS = qtrue;
			}
		}
		else if ( InFOV( NPC->enemy->currentOrigin, NPC->currentOrigin, NPC->client->ps.viewangles, 45, 90 ) )
		{//in front of me 
			//can we shoot our target?
			//FIXME: how accurate/necessary is this check?
			int hit = NPC_ShotEntity( NPC->enemy );
			gentity_t *hitEnt = &g_entities[hit];
			if ( hit == NPC->enemy->s.number 
				|| ( hitEnt && hitEnt->client && hitEnt->client->playerTeam == NPC->client->enemyTeam ) )
			{
				VectorCopy( NPC->enemy->currentOrigin, NPCInfo->enemyLastSeenLocation );
				float enemyHorzDist = DistanceHorizontalSquared( NPC->enemy->currentOrigin, NPC->currentOrigin );
				if ( enemyHorzDist < 1048576 )
				{//within 1024
					enemyCS = qtrue;
					NPC_AimAdjust( 2 );//adjust aim better longer we have clear shot at enemy
				}
				else
				{
					NPC_AimAdjust( 1 );//adjust aim better longer we can see enemy
				}
			}
		}
	}
	else
	{
		NPC_AimAdjust( -1 );//adjust aim worse longer we cannot see enemy
	}
	/*
	else if ( gi.inPVS( NPC->enemy->currentOrigin, NPC->currentOrigin ) )
	{
		NPCInfo->enemyLastSeenTime = level.time;
		faceEnemy = qtrue;
	}
	*/

	if ( enemyLOS )
	{//FIXME: no need to face enemy if we're moving to some other goal and he's too far away to shoot?
		faceEnemy = qtrue;
	}

	if ( enemyCS )
	{
		shoot = qtrue;
		if ( NPC->client->ps.weapon == WP_THERMAL )
		{//don't chase and throw
			move = qfalse;
		}
		else if ( NPC->client->ps.weapon == WP_MELEE && enemyDist < (NPC->maxs[0]+NPC->enemy->maxs[0]+16)*(NPC->maxs[0]+NPC->enemy->maxs[0]+16) )
		{//close enough
			move = qfalse;
		}
	}//this should make him chase enemy when out of range...?

	//Check for movement to take care of
	Grenadier_CheckMoveState();

	//See if we should override shooting decision with any special considerations
	Grenadier_CheckFireState();

	if ( move )
	{//move toward goal
		if ( NPCInfo->goalEntity )//&& ( NPCInfo->goalEntity != NPC->enemy || enemyDist > 10000 ) )//100 squared
		{
			move = Grenadier_Move();
		}
		else
		{
			move = qfalse;
		}
	}

	if ( !move )
	{
		if ( !TIMER_Done( NPC, "duck" ) )
		{
			ucmd.upmove = -127;
		}
		//FIXME: what about leaning?
	}
	else
	{//stop ducking!
		TIMER_Set( NPC, "duck", -1 );
	}

	if ( !faceEnemy )
	{//we want to face in the dir we're running
		if ( move )
		{//don't run away and shoot
			NPCInfo->desiredYaw = NPCInfo->lastPathAngles[YAW];
			NPCInfo->desiredPitch = 0;
			shoot = qfalse;
		}
		NPC_UpdateAngles( qtrue, qtrue );
	}
	else// if ( faceEnemy )
	{//face the enemy
		NPC_FaceEnemy();
	}

	if ( NPCInfo->scriptFlags&SCF_DONT_FIRE )
	{
		shoot = qfalse;
	}

	//FIXME: don't shoot right away!
	if ( shoot )
	{//try to shoot if it's time
		if ( TIMER_Done( NPC, "attackDelay" ) )
		{	
			if( !(NPCInfo->scriptFlags & SCF_FIRE_WEAPON) ) // we've already fired, no need to do it again here
			{
				WeaponThink( qtrue );
				TIMER_Set( NPC, "attackDelay", NPCInfo->shotTime-level.time );
			}
			
		}
	}
}
//
// Name:        InFOV()
// Parameters:  Entity* ent -- Provides the Position to check
// Description: Calls another version InFOV 
//
qboolean SensoryPerception::InFOV( const Entity *ent )
{
	return InFOV( ent->centroid );
}
//
// Name:        InFOV()
// Parameters:  Vector &pos -- The position to be checked
// Description: Calls another version of InFOV
//
qboolean SensoryPerception::InFOV( const Vector &pos )
{
	return InFOV( pos, _fov, _fovdot );
}