Exemplo n.º 1
0
//[SPPortComplete]
gentity_t *NPC_PickEnemyExt( qboolean checkAlerts )
{
	//Check for Hazard Team status and remove this check
	/*
	if ( NPC->client->playerTeam != TEAM_STARFLEET )
	{
		//If we've found the player, return it
		if ( NPC_FindPlayer() )
			return &g_entities[0];
	}
	*/

	//If we've asked for the closest enemy
	int entID = NPC_FindNearestEnemy( NPC );

	//If we have a valid enemy, use it
	if ( entID >= 0 )
		return &g_entities[entID];

	if ( checkAlerts )
	{
		//[CoOp]
		int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, -1, qtrue, AEL_DISCOVERED, qfalse );
		//int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, -1, qtrue, AEL_DISCOVERED );
		//[/CoOp]

		//There is an event to look at
		if ( alertEvent >= 0 )
		{
			alertEvent_t *event = &level.alertEvents[alertEvent];

			//Don't pay attention to our own alerts
			if ( event->owner == NPC )
				return NULL;

			if ( event->level >= AEL_DISCOVERED )
			{
				//If it's the player, attack him
				//[CoOp]
				//account for all players
				if ( event->owner->s.number < MAX_CLIENTS )
				//if ( event->owner == &g_entities[0] )
					return event->owner;

				//If it's on our team, then take its enemy as well
				if ( ( event->owner->client ) && ( event->owner->client->playerTeam == NPC->client->playerTeam ) )
				//racc - communicate enemies with allies if our allies are making a lot of noise.				
					return event->owner->enemy;
			}
		}
	}

	return NULL;
}
Exemplo n.º 2
0
gentity_t *NPC_PickEnemyExt( qboolean checkAlerts )
{

	//Check for Hazard Team status and remove this check
	/*
	if ( NPC->client->playerTeam != TEAM_STARFLEET )
	{
		//If we've found the player, return it
		if ( NPC_FindPlayer() )
			return &g_entities[0];
	}
	*/

	//If we've asked for the closest enemy
	int entID = NPC_FindNearestEnemy( NPCS.NPC );

	//If we have a valid enemy, use it
	if ( entID >= 0 )
		return &g_entities[entID];

	if ( checkAlerts )
	{
		int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, -1, qtrue, AEL_DISCOVERED );

		//There is an event to look at
		if ( alertEvent >= 0 )
		{
			alertEvent_t *event = &level.alertEvents[alertEvent];

			//Don't pay attention to our own alerts
			if ( event->owner == NPCS.NPC )
				return NULL;

			if ( event->level >= AEL_DISCOVERED )
			{
				//If it's the player, attack him
				//OJKFIXME: clientnum 0
				if ( event->owner == &g_entities[0] )
					return event->owner;

				//If it's on our team, then take its enemy as well
				if ( ( event->owner->client ) && ( event->owner->client->playerTeam == NPCS.NPC->client->playerTeam ) )
					return event->owner->enemy;
			}
		}
	}

	return NULL;
}
Exemplo n.º 3
0
void SandCreature_CheckAlerts( void )
{
	if ( !(NPCInfo->scriptFlags&SCF_IGNORE_ALERTS) )
	{
		int alertEvent = NPC_CheckAlertEvents( qfalse, qtrue, NPCInfo->lastAlertID, qfalse, AEL_MINOR, qtrue );

		//There is an event to look at
		if ( alertEvent >= 0 )
		{
			//if ( level.alertEvents[alertEvent].ID != NPCInfo->lastAlertID )
			{
				SandCreature_SeekAlert( alertEvent );
			}
		}
	}
}
Exemplo n.º 4
0
/*
void NPC_BSSleep( void ) 
*/
void NPC_BSSleep( void ) 
{
	int alertEvent = NPC_CheckAlertEvents( qtrue, qfalse );

	//There is an event to look at
	if ( alertEvent >= 0 )
	{
		G_ActivateBehavior(NPC, BSET_AWAKE);
		return;
	}

	/*
	if ( level.time > NPCInfo->enemyCheckDebounceTime )
	{
		if ( NPC_CheckSoundEvents() != -1 )
		{//only 1 alert per second per 0.1 of vigilance
			NPCInfo->enemyCheckDebounceTime = level.time + (NPCInfo->stats.vigilance * 10000);
			G_ActivateBehavior(NPC, BSET_AWAKE);
		}
	}
	*/
}
Exemplo n.º 5
0
gentity_t *NPC_PickEnemyExt( qboolean checkAlerts = qfalse )
{
	//If we've asked for the closest enemy
	int entID = NPC_FindNearestEnemy( NPC );

	//If we have a valid enemy, use it
	if ( entID >= 0 )
		return &g_entities[entID];

	if ( checkAlerts )
	{
		int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, -1, qtrue, AEL_DISCOVERED );

		//There is an event to look at
		if ( alertEvent >= 0 )
		{
			alertEvent_t *event = &level.alertEvents[alertEvent];

			//Don't pay attention to our own alerts
			if ( event->owner == NPC )
				return NULL;

			if ( event->level >= AEL_DISCOVERED )
			{
				//If it's the player, attack him
				if ( event->owner == &g_entities[0] )
					return event->owner;

				//If it's on our team, then take its enemy as well
				if ( ( event->owner->client ) && ( event->owner->client->playerTeam == NPC->client->playerTeam ) )
					return event->owner->enemy;
			}
		}
	}

	return NULL;
}
Exemplo n.º 6
0
void NPC_BSFollowLeader (void)
{
	vec3_t		vec;
	float		leaderDist;
	visibility_t	leaderVis;
	int			curAnim;

	if ( !NPC->client->leader )
	{//ok, stand guard until we find an enemy
		if( NPCInfo->tempBehavior == BS_HUNT_AND_KILL )
		{
			NPCInfo->tempBehavior = BS_DEFAULT;
		}
		else
		{
			NPCInfo->tempBehavior = BS_STAND_GUARD;
			NPC_BSStandGuard();
		}
		return;
	}

	if ( !NPC->enemy  )
	{//no enemy, find one
		NPC_CheckEnemy( NPCInfo->confusionTime<level.time, qfalse );//don't find new enemy if this is tempbehav
		if ( NPC->enemy )
		{//just found one
			NPCInfo->enemyCheckDebounceTime = level.time + Q_irand( 3000, 10000 );
		}
		else
		{
			if ( !(NPCInfo->scriptFlags&SCF_IGNORE_ALERTS) )
			{
				int eventID = NPC_CheckAlertEvents( qtrue, qtrue );
				if ( level.alertEvents[eventID].level >= AEL_SUSPICIOUS && (NPCInfo->scriptFlags&SCF_LOOK_FOR_ENEMIES) )
				{
					NPCInfo->lastAlertID = level.alertEvents[eventID].ID;
					if ( !level.alertEvents[eventID].owner || 
						!level.alertEvents[eventID].owner->client || 
						level.alertEvents[eventID].owner->health <= 0 ||
						level.alertEvents[eventID].owner->client->playerTeam != NPC->client->enemyTeam )
					{//not an enemy
					}
					else
					{
						//FIXME: what if can't actually see enemy, don't know where he is... should we make them just become very alert and start looking for him?  Or just let combat AI handle this... (act as if you lost him)
						G_SetEnemy( NPC, level.alertEvents[eventID].owner );
						NPCInfo->enemyCheckDebounceTime = level.time + Q_irand( 3000, 10000 );
						NPCInfo->enemyLastSeenTime = level.time;
						TIMER_Set( NPC, "attackDelay", Q_irand( 500, 1000 ) );
					}
				}

			}
		}
		if ( !NPC->enemy )
		{
			if ( NPC->client->leader 
				&& NPC->client->leader->enemy 
				&& NPC->client->leader->enemy != NPC
				&& ( (NPC->client->leader->enemy->client&&NPC->client->leader->enemy->client->playerTeam==NPC->client->enemyTeam)
					||(NPC->client->leader->enemy->svFlags&SVF_NONNPC_ENEMY&&NPC->client->leader->enemy->noDamageTeam==NPC->client->enemyTeam) )
				&& NPC->client->leader->enemy->health > 0 )
			{
				G_SetEnemy( NPC, NPC->client->leader->enemy );
				NPCInfo->enemyCheckDebounceTime = level.time + Q_irand( 3000, 10000 );
				NPCInfo->enemyLastSeenTime = level.time;
			}
		}
	}
	else 
	{
		if ( NPC->enemy->health <= 0 || (NPC->enemy->flags&FL_NOTARGET) )
		{
			G_ClearEnemy( NPC );
			if ( NPCInfo->enemyCheckDebounceTime > level.time + 1000 )
			{
				NPCInfo->enemyCheckDebounceTime = level.time + Q_irand( 1000, 2000 );
			}
		}
		else if ( NPC->client->ps.weapon && NPCInfo->enemyCheckDebounceTime < level.time )
		{
			NPC_CheckEnemy( (NPCInfo->confusionTime<level.time||NPCInfo->tempBehavior!=BS_FOLLOW_LEADER), qfalse );//don't find new enemy if this is tempbehav
		}
	}
	
	if ( NPC->enemy && NPC->client->ps.weapon )
	{//If have an enemy, face him and fire
		if ( NPC->client->ps.weapon == WP_SABER )//|| NPCInfo->confusionTime>level.time )
		{//lightsaber user or charmed enemy
			if ( NPCInfo->tempBehavior != BS_FOLLOW_LEADER )
			{//not already in a temp bState
				//go after the guy
				NPCInfo->tempBehavior = BS_HUNT_AND_KILL;
				NPC_UpdateAngles(qtrue, qtrue);
				return;
			}
		}

		enemyVisibility = NPC_CheckVisibility ( NPC->enemy, CHECK_FOV|CHECK_SHOOT );//CHECK_360|CHECK_PVS|
		if ( enemyVisibility > VIS_PVS )
		{//face
			vec3_t	enemy_org, muzzle, delta, angleToEnemy;
			float	distanceToEnemy;

			CalcEntitySpot( NPC->enemy, SPOT_HEAD, enemy_org );
			NPC_AimWiggle( enemy_org );

			CalcEntitySpot( NPC, SPOT_WEAPON, muzzle );
			
			VectorSubtract( enemy_org, muzzle, delta);
			vectoangles( delta, angleToEnemy );
			distanceToEnemy = VectorNormalize( delta );

			NPCInfo->desiredYaw = angleToEnemy[YAW];
			NPCInfo->desiredPitch = angleToEnemy[PITCH];
			NPC_UpdateFiringAngles( qtrue, qtrue );

			if ( enemyVisibility >= VIS_SHOOT )
			{//shoot
				NPC_AimAdjust( 2 );
				if ( NPC_GetHFOVPercentage( NPC->enemy->currentOrigin, NPC->currentOrigin, NPC->client->ps.viewangles, NPCInfo->stats.hfov ) > 0.6f 
					&& NPC_GetHFOVPercentage( NPC->enemy->currentOrigin, NPC->currentOrigin, NPC->client->ps.viewangles, NPCInfo->stats.vfov ) > 0.5f )
				{//actually withing our front cone
					WeaponThink( qtrue );
				}
			}
			else
			{
				NPC_AimAdjust( 1 );
			}
			
			//NPC_CheckCanAttack(1.0, qfalse);
		}
		else
		{
			NPC_AimAdjust( -1 );
		}
	}
	else
	{//FIXME: combine with vector calc below
		vec3_t	head, leaderHead, delta, angleToLeader;

		CalcEntitySpot( NPC->client->leader, SPOT_HEAD, leaderHead );
		CalcEntitySpot( NPC, SPOT_HEAD, head );
		VectorSubtract (leaderHead, head, delta);
		vectoangles ( delta, angleToLeader );
		VectorNormalize(delta);
		NPC->NPC->desiredYaw = angleToLeader[YAW];
		NPC->NPC->desiredPitch = angleToLeader[PITCH];
		
		NPC_UpdateAngles(qtrue, qtrue);
	}

	//leader visible?
	leaderVis = NPC_CheckVisibility( NPC->client->leader, CHECK_PVS|CHECK_360|CHECK_SHOOT );//			ent->e_UseFunc = useF_NULL;


	//Follow leader, stay within visibility and a certain distance, maintain a distance from.
	curAnim = NPC->client->ps.legsAnim;
	if ( curAnim != BOTH_ATTACK1 && curAnim != BOTH_ATTACK2 && curAnim != BOTH_ATTACK3 && curAnim != BOTH_MELEE1 && curAnim != BOTH_MELEE2 )
	{//Don't move toward leader if we're in a full-body attack anim
		//FIXME, use IdealDistance to determine if we need to close distance
		float	followDist = 96.0f;//FIXME:  If there are enmies, make this larger?
		float	backupdist, walkdist, minrundist;

		if ( NPCInfo->followDist )
		{
			followDist = NPCInfo->followDist;
		}
		backupdist = followDist/2.0f;
		walkdist = followDist*0.83;
		minrundist = followDist*1.33;

		VectorSubtract(NPC->client->leader->currentOrigin, NPC->currentOrigin, vec);
		leaderDist = VectorLength( vec );//FIXME: make this just nav distance?
		//never get within their radius horizontally
		vec[2] = 0;
		float leaderHDist = VectorLength( vec );
		if( leaderHDist > backupdist && (leaderVis != VIS_SHOOT || leaderDist > walkdist) )
		{//We should close in?
			NPCInfo->goalEntity = NPC->client->leader;

			NPC_SlideMoveToGoal();
			if ( leaderVis == VIS_SHOOT && leaderDist < minrundist )
			{
				ucmd.buttons |= BUTTON_WALKING;
			}
		}
		else if ( leaderDist < backupdist )
		{//We should back off?
			NPCInfo->goalEntity = NPC->client->leader;
			NPC_SlideMoveToGoal();

			//reversing direction
			ucmd.forwardmove = -ucmd.forwardmove;
			ucmd.rightmove   = -ucmd.rightmove;
			VectorScale( NPC->client->ps.moveDir, -1, NPC->client->ps.moveDir );
		}//otherwise, stay where we are
		//check for do not enter and stop if there's one there...
		if ( ucmd.forwardmove || ucmd.rightmove || VectorCompare( vec3_origin, NPC->client->ps.moveDir ) )
		{
			NPC_MoveDirClear( ucmd.forwardmove, ucmd.rightmove, qtrue );
		}
	}
}
Exemplo n.º 7
0
void NPC_BSSniper_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_BSSniper_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_BSSniper_Patrol();//FIXME: or patrol?
		return;
	}

	enemyLOS = enemyCS = qfalse;
	AImove = qtrue;
	faceEnemy = qfalse;
	shoot = qfalse;
	enemyDist = DistanceSquared( NPC->currentOrigin, NPC->enemy->currentOrigin );
	if ( enemyDist < 16384 )//128 squared
	{//too close, so switch to primary fire
		if ( NPC->client->ps.weapon == WP_DISRUPTOR )
		{//sniping... should be assumed
			if ( NPCInfo->scriptFlags & SCF_ALT_FIRE )
			{//use primary fire
				trace_t	trace;
				gi.trace ( &trace, NPC->enemy->currentOrigin, NPC->enemy->mins, NPC->enemy->maxs, NPC->currentOrigin, NPC->enemy->s.number, NPC->enemy->clipmask, G2_NOCOLLIDE, 0 );
				if ( !trace.allsolid && !trace.startsolid && (trace.fraction == 1.0 || trace.entityNum == NPC->s.number ) )
				{//he can get right to me
					NPCInfo->scriptFlags &= ~SCF_ALT_FIRE;
					//reset fire-timing variables
					NPC_ChangeWeapon( WP_DISRUPTOR );
					NPC_UpdateAngles( qtrue, qtrue );
					return;
				}
			}
			//FIXME: switch back if he gets far away again?
		}
	}
	else if ( enemyDist > 65536 )//256 squared
	{
		if ( NPC->client->ps.weapon == WP_DISRUPTOR )
		{//sniping... should be assumed
			if ( !(NPCInfo->scriptFlags&SCF_ALT_FIRE) )
			{//use primary fire
				NPCInfo->scriptFlags |= SCF_ALT_FIRE;
				//reset fire-timing variables
				NPC_ChangeWeapon( WP_DISRUPTOR );
				NPC_UpdateAngles( qtrue, qtrue );
				return;
			}
		}
	}

	Sniper_UpdateEnemyPos();
	//can we see our target?
	if ( NPC_ClearLOS( NPC->enemy ) )//|| (NPCInfo->stats.aim >= 5 && gi.inPVS( NPC->client->renderInfo.eyePoint, NPC->enemy->currentOrigin )) )
	{
		NPCInfo->enemyLastSeenTime = level.time;
		VectorCopy( NPC->enemy->currentOrigin, NPCInfo->enemyLastSeenLocation );
		enemyLOS = qtrue;
		float maxShootDist = NPC_MaxDistSquaredForWeapon();
		if ( enemyDist < maxShootDist )
		{
			vec3_t fwd, right, up, muzzle, end;
			trace_t	tr;
			AngleVectors( NPC->client->ps.viewangles, fwd, right, up );
			CalcMuzzlePoint( NPC, fwd, right, up, muzzle, 0 );
			VectorMA( muzzle, 8192, fwd, end );
			gi.trace ( &tr, muzzle, NULL, NULL, end, NPC->s.number, MASK_SHOT, G2_RETURNONHIT, 0 );

			int hit = tr.entityNum;
			//can we shoot our target?
			if ( Sniper_EvaluateShot( hit ) )
			{
				enemyCS = qtrue;
			}
		}
	}
	/*
	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;
	}
	else if ( level.time - NPCInfo->enemyLastSeenTime > 3000 )
	{//Hmm, have to get around this bastard... FIXME: this NPCInfo->enemyLastSeenTime builds up when ducked seems to make them want to run when they uncrouch
		Sniper_ResolveBlockedShot();
	}

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

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

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

	if ( !AImove )
	{
		if ( !TIMER_Done( NPC, "duck" ) )
		{
			if ( TIMER_Done( NPC, "watch" ) )
			{//not while watching
				ucmd.upmove = -127;
			}
		}
		//FIXME: what about leaning?
		//FIXME: also, when stop ducking, start looking, if enemy can see me, chance of ducking back down again
	}
	else
	{//stop ducking!
		TIMER_Set( NPC, "duck", -1 );
	}

	if ( TIMER_Done( NPC, "duck" ) 
		&& TIMER_Done( NPC, "watch" ) 
		&& (TIMER_Get( NPC, "attackDelay" )-level.time) > 1000 
		&& NPC->attackDebounceTime < level.time )
	{
		if ( enemyLOS && (NPCInfo->scriptFlags&SCF_ALT_FIRE) )
		{
			if ( NPC->fly_sound_debounce_time < level.time )
			{
				NPC->fly_sound_debounce_time = level.time + 2000;
			}
		}
	}

	if ( !faceEnemy )
	{//we want to face in the dir we're running
		if ( AImove )
		{//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
		Sniper_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" ) )
		{
			WeaponThink( qtrue );
			if ( ucmd.buttons&(BUTTON_ATTACK|BUTTON_ALT_ATTACK) )
			{
				G_SoundOnEnt( NPC, CHAN_WEAPON, "sound/null.wav" );
			}

			//took a shot, now hide
			if ( !(NPC->spawnflags&SPF_NO_HIDE) && !Q_irand( 0, 1 ) )
			{
				//FIXME: do this if in combat point and combat point has duck-type cover... also handle lean-type cover
				Sniper_StartHide();
			}
			else
			{
				TIMER_Set( NPC, "attackDelay", NPCInfo->shotTime-level.time );
			}
		}
	}
}
Exemplo n.º 8
0
void NPC_BSSniper_Patrol( void )
{//FIXME: pick up on bodies of dead buddies?
	NPC->count = 0;

	if ( NPCInfo->confusionTime < level.time )
	{
		//Look for any enemies
		if ( NPCInfo->scriptFlags&SCF_LOOK_FOR_ENEMIES )
		{
			if ( NPC_CheckPlayerTeamStealth() )
			{
				//NPCInfo->behaviorState = BS_HUNT_AND_KILL;//Should be auto now
				//NPC_AngerSound();
				NPC_UpdateAngles( qtrue, qtrue );
				return;
			}
		}

		if ( !(NPCInfo->scriptFlags&SCF_IGNORE_ALERTS) )
		{
			//Is there danger nearby
			int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, -1, qfalse, AEL_SUSPICIOUS );
			if ( NPC_CheckForDanger( alertEvent ) )
			{
				NPC_UpdateAngles( qtrue, qtrue );
				return;
			}
			else
			{//check for other alert events
				//There is an event to look at
				if ( alertEvent >= 0 && level.alertEvents[alertEvent].ID != NPCInfo->lastAlertID )
				{
					NPCInfo->lastAlertID = level.alertEvents[alertEvent].ID;
					if ( level.alertEvents[alertEvent].level == AEL_DISCOVERED )
					{
						if ( level.alertEvents[alertEvent].owner && 
							level.alertEvents[alertEvent].owner->client && 
							level.alertEvents[alertEvent].owner->health >= 0 &&
							level.alertEvents[alertEvent].owner->client->playerTeam == NPC->client->enemyTeam )
						{//an enemy
							G_SetEnemy( NPC, level.alertEvents[alertEvent].owner );
							//NPCInfo->enemyLastSeenTime = level.time;
							TIMER_Set( NPC, "attackDelay", Q_irand( (6-NPCInfo->stats.aim)*100, (6-NPCInfo->stats.aim)*500 ) );
						}
					}
					else
					{//FIXME: get more suspicious over time?
						//Save the position for movement (if necessary)
						//FIXME: sound?
						VectorCopy( level.alertEvents[alertEvent].position, NPCInfo->investigateGoal );
						NPCInfo->investigateDebounceTime = level.time + Q_irand( 500, 1000 );
						if ( level.alertEvents[alertEvent].level == AEL_SUSPICIOUS )
						{//suspicious looks longer
							NPCInfo->investigateDebounceTime += Q_irand( 500, 2500 );
						}
					}
				}
			}

			if ( NPCInfo->investigateDebounceTime > level.time )
			{//FIXME: walk over to it, maybe?  Not if not chase enemies flag
				//NOTE: stops walking or doing anything else below
				vec3_t	dir, angles;
				float	o_yaw, o_pitch;
				
				VectorSubtract( NPCInfo->investigateGoal, NPC->client->renderInfo.eyePoint, dir );
				vectoangles( dir, angles );
				
				o_yaw = NPCInfo->desiredYaw;
				o_pitch = NPCInfo->desiredPitch;
				NPCInfo->desiredYaw = angles[YAW];
				NPCInfo->desiredPitch = angles[PITCH];
				
				NPC_UpdateAngles( qtrue, qtrue );

				NPCInfo->desiredYaw = o_yaw;
				NPCInfo->desiredPitch = o_pitch;
				return;
			}
		}
	}

	//If we have somewhere to go, then do that
	if ( UpdateGoal() )
	{
		ucmd.buttons |= BUTTON_WALKING;
		NPC_MoveToGoal( qtrue );
	}

	NPC_UpdateAngles( qtrue, qtrue );
}
Exemplo n.º 9
0
void NPC_BSDefault( void ) 
{
//	vec3_t		enemyDir;
//	float		enemyDist;
//	float		shootDist;
//	qboolean	enemyFOV = qfalse;
//	qboolean	enemyShotFOV = qfalse;
//	qboolean	enemyPVS = qfalse;
//	vec3_t		enemyHead;
//	vec3_t		muzzle;
//	qboolean	enemyLOS = qfalse;
//	qboolean	enemyCS = qfalse;
	qboolean	move = qtrue;
//	qboolean	shoot = qfalse;

	
	if( NPCInfo->scriptFlags & SCF_FIRE_WEAPON )
	{
		WeaponThink( qtrue );
	}

	if ( NPCInfo->scriptFlags & SCF_FORCED_MARCH )
	{//being forced to walk
		if( NPC->client->ps.torsoAnim != TORSO_SURRENDER_START )
		{
			NPC_SetAnim( NPC, SETANIM_TORSO, TORSO_SURRENDER_START, SETANIM_FLAG_HOLD );
		}
	}
	//look for a new enemy if don't have one and are allowed to look, validate current enemy if have one
	NPC_CheckEnemy( (NPCInfo->scriptFlags&SCF_LOOK_FOR_ENEMIES), qfalse, qtrue );
	if ( !NPC->enemy )
	{//still don't have an enemy
		if ( !(NPCInfo->scriptFlags&SCF_IGNORE_ALERTS) )
		{//check for alert events
			//FIXME: Check Alert events, see if we should investigate or just look at it
			int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, -1, qtrue, AEL_DISCOVERED );

			//There is an event to look at
			if ( alertEvent >= 0 && level.alertEvents[alertEvent].ID != NPCInfo->lastAlertID )
			{//heard/saw something
				if ( level.alertEvents[alertEvent].level >= AEL_DISCOVERED && (NPCInfo->scriptFlags&SCF_LOOK_FOR_ENEMIES) )
				{//was a big event
					if ( level.alertEvents[alertEvent].owner && level.alertEvents[alertEvent].owner->client && level.alertEvents[alertEvent].owner->health >= 0 && level.alertEvents[alertEvent].owner->client->playerTeam == NPC->client->enemyTeam )
					{//an enemy
						G_SetEnemy( NPC, level.alertEvents[alertEvent].owner );
					}
				}
				else
				{//FIXME: investigate lesser events
				}
			}
			//FIXME: also check our allies' condition?
		}
	}

	if ( NPC->enemy && !(NPCInfo->scriptFlags&SCF_FORCED_MARCH) )
	{
		// just use the stormtrooper attack AI...
		NPC_CheckGetNewWeapon();
		if ( NPC->client->leader 
			&& NPCInfo->goalEntity == NPC->client->leader 
			&& !trap_ICARUS_TaskIDPending( NPC, TID_MOVE_NAV ) )
		{
			NPC_ClearGoal();
		}
			NPC_BSST_Attack();
		return;
/*
		//have an enemy
		//FIXME: if one of these fails, meaning we can't shoot, do we really need to do the rest?
		VectorSubtract( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, enemyDir );
		enemyDist = VectorNormalize( enemyDir );
		enemyDist *= enemyDist;
		shootDist = NPC_MaxDistSquaredForWeapon();

		enemyFOV = InFOV( NPC->enemy, NPC, NPCInfo->stats.hfov, NPCInfo->stats.vfov );
		enemyShotFOV = InFOV( NPC->enemy, NPC, 20, 20 );
		enemyPVS = gi.inPVS( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin );

		if ( enemyPVS )
		{//in the pvs
			trace_t	tr;

			CalcEntitySpot( NPC->enemy, SPOT_HEAD, enemyHead );
			enemyHead[2] -= Q_flrand( 0.0f, NPC->enemy->maxs[2]*0.5f );
			CalcEntitySpot( NPC, SPOT_WEAPON, muzzle );
			enemyLOS = NPC_ClearLOS( muzzle, enemyHead );

			gi.trace ( &tr, muzzle, vec3_origin, vec3_origin, enemyHead, NPC->s.number, MASK_SHOT );
			enemyCS = NPC_EvaluateShot( tr.entityNum, qtrue );
		}
		else
		{//skip thr 2 traces since they would have to fail
			enemyLOS = qfalse;
			enemyCS = qfalse;
		}
		
		if ( enemyCS && enemyShotFOV )
		{//can hit enemy if we want
			NPC->cantHitEnemyCounter = 0;
		}
		else
		{//can't hit
			NPC->cantHitEnemyCounter++;
		}

		if ( enemyCS && enemyShotFOV && enemyDist < shootDist )
		{//can shoot
			shoot = qtrue;
			if ( NPCInfo->goalEntity == NPC->enemy )
			{//my goal is my enemy and I have a clear shot, no need to chase right now
				move = qfalse;
			}
		}
		else
		{//don't shoot yet, keep chasing
			shoot = qfalse;
			move = qtrue;
		}

		//shoot decision
		if ( !(NPCInfo->scriptFlags&SCF_DONT_FIRE) )
		{//try to shoot
			if ( NPC->enemy )
			{
				if ( shoot )
				{
					if( !(NPCInfo->scriptFlags & SCF_FIRE_WEAPON) ) // we've already fired, no need to do it again here
					{
						WeaponThink( qtrue );
					}
				}
			}
		}

		//chase decision
		if ( NPCInfo->scriptFlags & SCF_CHASE_ENEMIES )
		{//go after him
			NPCInfo->goalEntity = NPC->enemy;
			//FIXME: don't need to chase when have a clear shot and in range?
			if ( !enemyCS && NPC->cantHitEnemyCounter > 60 )
			{//haven't been able to shoot enemy for about 6 seconds, need to do something
				//FIXME: combat points?  Just chase?
				if ( enemyPVS )
				{//in my PVS, just pick a combat point
					//FIXME: implement
				}
				else
				{//just chase him
				}
			}
			//FIXME: in normal behavior, should we use combat Points?  Do we care?  Is anyone actually going to ever use this AI?
		}
		else if ( NPC->cantHitEnemyCounter > 60 )
		{//pick a new one
			NPC_CheckEnemy( qtrue, qfalse, qtrue );
		}
		
		if ( enemyPVS && enemyLOS )//&& !enemyShotFOV )
		{//have a clear LOS to him//, but not looking at him
			//Find the desired angles
			vec3_t	angles;

			GetAnglesForDirection( muzzle, enemyHead, angles );

			NPCInfo->desiredYaw		= AngleNormalize180( angles[YAW] );
			NPCInfo->desiredPitch	= AngleNormalize180( angles[PITCH] );
		}
		*/
	}

	if ( UpdateGoal() )
	{//have a goal
		if ( !NPC->enemy 
			&& NPC->client->leader 
			&& NPCInfo->goalEntity == NPC->client->leader 
			&& !trap_ICARUS_TaskIDPending( NPC, TID_MOVE_NAV ) )
		{
			NPC_BSFollowLeader();
		}
		else
		{
			//set angles
			if ( (NPCInfo->scriptFlags & SCF_FACE_MOVE_DIR) || NPCInfo->goalEntity != NPC->enemy )
			{//face direction of movement, NOTE: default behavior when not chasing enemy
				NPCInfo->combatMove = qfalse;
			}
			else
			{//face goal.. FIXME: what if have a navgoal but want to face enemy while moving?  Will this do that?
				vec3_t	dir, angles;

				NPCInfo->combatMove = qfalse;

				VectorSubtract( NPCInfo->goalEntity->r.currentOrigin, NPC->r.currentOrigin, dir );
				vectoangles( dir, angles );
				NPCInfo->desiredYaw = angles[YAW];
				if ( NPCInfo->goalEntity == NPC->enemy )
				{
					NPCInfo->desiredPitch = angles[PITCH];
				}
			}

			//set movement
			//override default walk/run behavior
			//NOTE: redundant, done in NPC_ApplyScriptFlags
			if ( NPCInfo->scriptFlags & SCF_RUNNING )
			{
				ucmd.buttons &= ~BUTTON_WALKING;
			}
			else if ( NPCInfo->scriptFlags & SCF_WALKING )
			{
				ucmd.buttons |= BUTTON_WALKING;
			}
			else if ( NPCInfo->goalEntity == NPC->enemy )
			{
				ucmd.buttons &= ~BUTTON_WALKING;
			}
			else
			{
				ucmd.buttons |= BUTTON_WALKING;
			}

			if ( NPCInfo->scriptFlags & SCF_FORCED_MARCH )
			{//being forced to walk
				//if ( g_crosshairEntNum != NPC->s.number )
				if (!NPC_SomeoneLookingAtMe(NPC))
				{//don't walk if player isn't aiming at me
					move = qfalse;
				}
			}

			if ( move )
			{
				//move toward goal
				NPC_MoveToGoal( qtrue );
			}
		}
	}
	else if ( !NPC->enemy && NPC->client->leader )
	{
		NPC_BSFollowLeader();
	}

	//update angles
	NPC_UpdateAngles( qtrue, qtrue );
}
Exemplo n.º 10
0
void SandCreature_Chase( void )
{
	if ( !NPC->enemy->inuse )
	{//freed
		NPC->enemy = NULL;
		return;
	}

	if ( (NPC->svFlags&SVF_LOCKEDENEMY) )
	{//always know where he is
		NPCInfo->enemyLastSeenTime = level.time;
	}

	if ( !(NPC->svFlags&SVF_LOCKEDENEMY) )
	{
		if ( level.time-NPCInfo->enemyLastSeenTime > 10000 )
		{
			NPC->enemy = NULL;
			return;
		}
	}

	if ( NPC->enemy->client )
	{
		if ( (NPC->enemy->client->ps.eFlags&EF_HELD_BY_SAND_CREATURE)
			|| (NPC->enemy->client->ps.eFlags&EF_HELD_BY_RANCOR)
			|| (NPC->enemy->client->ps.eFlags&EF_HELD_BY_WAMPA) )
		{//was picked up by another monster, forget about him
			NPC->enemy = NULL;
			NPC->svFlags &= ~SVF_LOCKEDENEMY;
			return;
		}
	}
	//chase the enemy
	if ( NPC->enemy->client
		&& NPC->enemy->client->ps.groundEntityNum != ENTITYNUM_WORLD
		&& !(NPC->svFlags&SVF_LOCKEDENEMY) )
	{//off the ground!
		//FIXME: keep moving in the dir we were moving for a little bit...
	}
	else
	{
		float enemyScore = SandCreature_EntScore( NPC->enemy );
		if ( enemyScore < MIN_SCORE
			&& !(NPC->svFlags&SVF_LOCKEDENEMY) )
		{//too slow or too far away
		}
		else
		{
			float moveSpeed;
			if ( NPC->enemy->client )
			{
				moveSpeed = VectorLengthSquared( NPC->enemy->client->ps.velocity );
			}
			else
			{
				moveSpeed = VectorLengthSquared( NPC->enemy->s.pos.trDelta );
			}
			if ( moveSpeed )
			{//he's still moving, update my goalEntity's origin
				SandCreature_SeekEnt( NPC->enemy, 0 );
				NPCInfo->enemyLastSeenTime = level.time;
			}
		}
	}

	if ( (level.time-NPCInfo->enemyLastSeenTime) > 5000
		&& !(NPC->svFlags&SVF_LOCKEDENEMY) )
	{//enemy hasn't moved in about 5 seconds, see if there's anything else of interest
		SandCreature_CheckAlerts();
		SandCreature_CheckMovingEnts();
	}

	float enemyDistSq = SandCreature_DistSqToGoal( qtrue );

	//FIXME: keeps chasing goalEntity even when it's already reached it...?
	if ( enemyDistSq >= MIN_ATTACK_DIST_SQ//NPCInfo->goalEntity &&
		&& (level.time-NPCInfo->enemyLastSeenTime) <= 3000 )
	{//sensed enemy (or something) less than 3 seconds ago
		ucmd.buttons &= ~BUTTON_WALKING;
		if ( SandCreature_Move() )
		{
			SandCreature_MoveEffect();
		}
	}
	else if ( (level.time-NPCInfo->enemyLastSeenTime) <= 5000
		&& !(NPC->svFlags&SVF_LOCKEDENEMY) )
	{//NOTE: this leaves a 2-second dead zone in which they'll just sit there unless their enemy moves
		//If there is an event we might be interested in if we weren't still interested in our enemy
		if ( NPC_CheckAlertEvents( qfalse, qtrue, NPCInfo->lastAlertID, qfalse, AEL_MINOR, qtrue ) >= 0 )
		{//just stir
			SandCreature_MoveEffect();
		}
	}

	if ( enemyDistSq < MIN_ATTACK_DIST_SQ )
	{
		if ( NPC->enemy->client )
		{
			NPC->client->ps.viewangles[YAW] = NPC->enemy->client->ps.viewangles[YAW];
		}
		if ( TIMER_Done( NPC, "breaching" ) )
		{
			//okay to attack
			SandCreature_Attack( qfalse );
		}
	}
	else if ( enemyDistSq < MAX_MISS_DIST_SQ
		&& enemyDistSq > MIN_MISS_DIST_SQ
		&& NPC->enemy->client
		&& TIMER_Done( NPC, "breaching" )
		&& TIMER_Done( NPC, "missDebounce" )
		&& !VectorCompare( NPC->pos1, NPC->currentOrigin ) //so we don't come up again in the same spot
		&& !Q_irand( 0, 10 ) )
	{
		if ( !(NPC->svFlags&SVF_LOCKEDENEMY) )
		{
			//miss them
			SandCreature_Attack( qtrue );
			VectorCopy( NPC->currentOrigin, NPC->pos1 );
			TIMER_Set( NPC, "missDebounce", Q_irand( 3000, 10000 ) );
		}
	}
}
Exemplo n.º 11
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 );
			}
			
		}
	}
}
Exemplo n.º 12
0
void NPC_BSSaberDroid_Patrol( void )
{//FIXME: pick up on bodies of dead buddies?
	if ( NPCInfo->confusionTime < level.time )
	{//not confused by mindtrick
		//Look for any enemies
		if ( NPCInfo->scriptFlags&SCF_LOOK_FOR_ENEMIES )
		{
			if ( NPC_CheckPlayerTeamStealth() )
			{//found an enemy
				//NPCInfo->behaviorState = BS_HUNT_AND_KILL;//should be automatic now
				//NPC_AngerSound();
				NPC_UpdateAngles( qtrue, qtrue );
				return;
			}
		}

		if ( !(NPCInfo->scriptFlags&SCF_IGNORE_ALERTS) )
		{//alert reaction behavior.
			//Is there danger nearby
			//[CoOp]
			int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, -1, qfalse, AEL_SUSPICIOUS, qfalse );
			//int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, -1, qfalse, AEL_SUSPICIOUS );
			//[/CoOp]
			//There is an event to look at
			if ( alertEvent >= 0 )//&& level.alertEvents[alertEvent].ID != NPCInfo->lastAlertID )
			{
				//NPCInfo->lastAlertID = level.alertEvents[alertEvent].ID;
				if ( level.alertEvents[alertEvent].level >= AEL_DISCOVERED )
				{
					if ( level.alertEvents[alertEvent].owner && 
						level.alertEvents[alertEvent].owner->client && 
						level.alertEvents[alertEvent].owner->health >= 0 &&
						level.alertEvents[alertEvent].owner->client->playerTeam == NPC->client->enemyTeam )
					{//an enemy
						G_SetEnemy( NPC, level.alertEvents[alertEvent].owner );
						//NPCInfo->enemyLastSeenTime = level.time;
						TIMER_Set( NPC, "attackDelay", Q_irand( 500, 2500 ) );
					}
				}
				else
				{//FIXME: get more suspicious over time?
					//Save the position for movement (if necessary)
					VectorCopy( level.alertEvents[alertEvent].position, NPCInfo->investigateGoal );
					NPCInfo->investigateDebounceTime = level.time + Q_irand( 500, 1000 );
					if ( level.alertEvents[alertEvent].level == AEL_SUSPICIOUS )
					{//suspicious looks longer
						NPCInfo->investigateDebounceTime += Q_irand( 500, 2500 );
					}
				}
			}

			if ( NPCInfo->investigateDebounceTime > level.time )
			{//FIXME: walk over to it, maybe?  Not if not chase enemies
				//NOTE: stops walking or doing anything else below
				vec3_t	dir, angles;
				float	o_yaw, o_pitch;
				
				VectorSubtract( NPCInfo->investigateGoal, NPC->client->renderInfo.eyePoint, dir );
				vectoangles( dir, angles );
				
				o_yaw = NPCInfo->desiredYaw;
				o_pitch = NPCInfo->desiredPitch;
				NPCInfo->desiredYaw = angles[YAW];
				NPCInfo->desiredPitch = angles[PITCH];
				
				NPC_UpdateAngles( qtrue, qtrue );

				NPCInfo->desiredYaw = o_yaw;
				NPCInfo->desiredPitch = o_pitch;
				return;
			}
		}
	}

	//If we have somewhere to go, then do that
	if ( UpdateGoal() )
	{
		ucmd.buttons |= BUTTON_WALKING;
		NPC_MoveToGoal( qtrue );
	}
	else if ( !NPC->client->ps.weaponTime
		&& TIMER_Done( NPC, "attackDelay" )
		&& TIMER_Done( NPC, "inactiveDelay" ) )
	{//we want to turn off our saber if we need to.
		if ( !NPC->client->ps.saberHolstered )
		{//saber is on.
			WP_DeactivateSaber( NPC, qfalse );
			NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_TURNOFF, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
		}
	}

	NPC_UpdateAngles( qtrue, qtrue );
}
Exemplo n.º 13
0
/*
-------------------------
NPC_BSAnimal_Default
-------------------------
*/
void NPC_BSAnimal_Default( void )
{
	if (!NPC || !NPC->client)
	{
		return;
	}

	// Update Some Positions
	//-----------------------
	CVec3	CurrentLocation(NPC->currentOrigin);


	// Update The Leader
	//-------------------
	gentity_t*	leader = NPC_AnimalUpdateLeader();


	// Select Closest Threat Location
	//--------------------------------
	CVec3	ThreatLocation(0,0,0);
	qboolean PlayerSpawned = G_PlayerSpawned();
	if ( PlayerSpawned )
	{//player is actually in the level now
		ThreatLocation = player->currentOrigin;
	}
	int	alertEvent = NPC_CheckAlertEvents(qtrue, qtrue, -1, qfalse, AEL_MINOR, qfalse);
	if ( alertEvent >= 0 )
	{
		alertEvent_t *event = &level.alertEvents[alertEvent];
		if (event->owner!=NPC  &&  Distance(event->position, CurrentLocation.v)<event->radius)
		{
			ThreatLocation = event->position;
		}
	}



//	float	DistToThreat	= CurrentLocation.Dist(ThreatLocation);
//	float	DistFromHome	= CurrentLocation.Dist(mHome);



	bool	EvadeThreat		= (level.time<NPCInfo->investigateSoundDebounceTime);
	bool	CharmedDocile	= (level.time<NPCInfo->confusionTime);
	bool	CharmedApproach = (level.time<NPCInfo->charmedTime);



	// If Not Already Evading, Test To See If We Should "Know" About The Threat
	//--------------------------------------------------------------------------
/*	if (false && !EvadeThreat && PlayerSpawned && (DistToThreat<FRIGHTEN_DISTANCE))
	{
		CVec3	LookAim(NPC->currentAngles);
		LookAim.AngToVec();
		CVec3	MyPos(CurrentLocation);
		MyPos -= ThreatLocation;
		MyPos.SafeNorm();

		float	DirectionSimilarity = MyPos.Dot(LookAim);

		if (fabsf(DirectionSimilarity)<0.8f)
		{
			EvadeThreat = true;
			NPCInfo->investigateSoundDebounceTime = level.time + Q_irand(0, 1000);
			VectorCopy(ThreatLocation.v, NPCInfo->investigateGoal);
		}
	}*/





	STEER::Activate(NPC);
	{
		// Charmed Approach - Walk TOWARD The Threat Location
		//----------------------------------------------------
		if (CharmedApproach)
		{
			NAV::GoTo(NPC, NPCInfo->investigateGoal);
		}

		// Charmed Docile - Stay Put
		//---------------------------
		else if (CharmedDocile)
		{
			NAV::ClearPath(NPC);
			STEER::Stop(NPC);
		}

		// Run Away From This Threat
		//---------------------------
		else if (EvadeThreat)
		{
			NAV::ClearPath(NPC);
			STEER::Flee(NPC, NPCInfo->investigateGoal);
		}

		// Normal Behavior
		//-----------------
		else
		{
			// Follow Our Pack Leader!
			//-------------------------
			if (leader && leader!=NPC)
			{
				float	followDist	= 100.0f;
				float	curDist		= Distance(NPC->currentOrigin, leader->followPos);


				// Update The Leader's Follow Position
				//-------------------------------------
				STEER::FollowLeader(NPC, leader, followDist);

				bool	inSeekRange = (curDist<followDist*10.0f);
				bool	onNbrPoints = (NAV::OnNeighboringPoints(NAV::GetNearestNode(NPC), leader->followPosWaypoint));
				bool	leaderStop	= ((level.time - leader->lastMoveTime)>500);

				// If Close Enough, Dump Any Existing Path
				//-----------------------------------------
				if (inSeekRange || onNbrPoints)
				{
					NAV::ClearPath(NPC);

					// If The Leader Isn't Moving, Stop
					//----------------------------------
					if (leaderStop)
					{
						STEER::Stop(NPC);
					}

					// Otherwise, Try To Get To The Follow Position
					//----------------------------------------------
					else
					{
						STEER::Seek(NPC, leader->followPos, fabsf(followDist)/2.0f/*slowing distance*/, 1.0f/*wight*/, leader->resultspeed);
					}
				}

				// Otherwise, Get A Path To The Follow Position
				//----------------------------------------------
				else
				{
					NAV::GoTo(NPC, leader->followPosWaypoint);
				}
				STEER::Separation(NPC, 4.0f);
				STEER::AvoidCollisions(NPC, leader);
			}

			// Leader AI - Basically Wander
			//------------------------------
			else
			{
				// Are We Doing A Path?
				//----------------------
				bool	HasPath = NAV::HasPath(NPC);
				if (HasPath)
				{
					HasPath = NAV::UpdatePath(NPC);
					if (HasPath)
					{
						STEER::Path(NPC);	// Follow The Path
						STEER::AvoidCollisions(NPC);
					}
				}

				if (!HasPath)
				{
					// If Debounce Time Has Expired, Choose A New Sub State
					//------------------------------------------------------
					if (NPCInfo->investigateDebounceTime<level.time)
					{
						// Clear Out Flags From The Previous Substate
						//--------------------------------------------
						NPCInfo->aiFlags	&= ~NPCAI_OFF_PATH;
						NPCInfo->aiFlags	&= ~NPCAI_WALKING;


						// Pick Another Spot
						//-------------------
						int		NEXTSUBSTATE = Q_irand(0, 10);

						bool	RandomPathNode = (NEXTSUBSTATE<8); //(NEXTSUBSTATE<9);  
						bool	PathlessWander = (NEXTSUBSTATE<9); //false;				

						

						// Random Path Node
						//------------------
						if (RandomPathNode)
						{
							// Sometimes, Walk
							//-----------------
							if (Q_irand(0, 1)==0)
							{
								NPCInfo->aiFlags	|= NPCAI_WALKING;
							}

							NPCInfo->investigateDebounceTime = level.time + Q_irand(3000, 10000);
							NAV::FindPath(NPC, NAV::ChooseRandomNeighbor(NAV::GetNearestNode(NPC)));//, mHome.v, WANDER_RANGE));
						}

						// Pathless Wandering
						//--------------------
						else if (PathlessWander)
						{
							// Sometimes, Walk
							//-----------------
							if (Q_irand(0, 1)==0)
							{
								NPCInfo->aiFlags	|= NPCAI_WALKING;
							}

							NPCInfo->investigateDebounceTime = level.time + Q_irand(3000, 10000);
							NPCInfo->aiFlags |= NPCAI_OFF_PATH;
						}

						// Just Stand Here
						//-----------------
						else
						{
							NPCInfo->investigateDebounceTime = level.time + Q_irand(2000, 6000);
							//NPC_SetAnim(NPC, SETANIM_BOTH, ((Q_irand(0, 1)==0)?(BOTH_GUARD_LOOKAROUND1):(BOTH_GUARD_IDLE1)), SETANIM_FLAG_NORMAL);
						}
					}

					// Ok, So We Don't Have A Path, And Debounce Time Is Still Active, So We Are Either Wandering Or Looking Around
					//--------------------------------------------------------------------------------------------------------------
					else
					{
					//	if (DistFromHome>(WANDER_RANGE))
					//	{
					//		STEER::Seek(NPC, mHome);
					//	}
					//	else
						{
							if (NPCInfo->aiFlags & NPCAI_OFF_PATH)
							{
								STEER::Wander(NPC);
								STEER::AvoidCollisions(NPC);
							}
							else
							{
								STEER::Stop(NPC);
							}
						}
					}
				}
			}
		}
	}
	STEER::DeActivate(NPC, &ucmd); 

	NPC_UpdateAngles( qtrue, qtrue );
}