codemp/game/b_local.h File Reference

#include "g_local.h"
#include "b_public.h"
#include "say.h"
#include "ai.h"

Go to the source code of this file.

Data Structures

struct  navInfo_s

Defines

#define AI_TIMERS   0
#define NAVF_DUCK   0x00000001
#define NAVF_JUMP   0x00000002
#define NAVF_HOLD   0x00000004
#define NAVF_SLOW   0x00000008
#define DEBUG_LEVEL_DETAIL   4
#define DEBUG_LEVEL_INFO   3
#define DEBUG_LEVEL_WARNING   2
#define DEBUG_LEVEL_ERROR   1
#define DEBUG_LEVEL_NONE   0
#define MAX_GOAL_REACHED_DIST_SQUARED   256
#define MIN_ANGLE_ERROR   0.01f
#define MIN_ROCKET_DIST_SQUARED   16384
#define COLLISION_RADIUS   32
#define NUM_POSITIONS   30
#define SFB_SMALLHULL   1
#define SFB_RIFLEMAN   2
#define SFB_OLDBORG   2
#define SFB_PHASER   4
#define SFB_GUN   4
#define SFB_TRICORDER   8
#define SFB_TASER   8
#define SFB_DRILL   16
#define SFB_CINEMATIC   32
#define SFB_NOTSOLID   64
#define SFB_STARTINSOLID   128
#define ALERT_CLEAR_TIME   200
#define CHECK_PVS   1
#define CHECK_360   2
#define CHECK_FOV   4
#define CHECK_SHOOT   8
#define CHECK_VISRANGE   16
#define CP_ANY   0
#define CP_COVER   0x00000001
#define CP_CLEAR   0x00000002
#define CP_FLEE   0x00000004
#define CP_DUCK   0x00000008
#define CP_NEAREST   0x00000010
#define CP_AVOID_ENEMY   0x00000020
#define CP_INVESTIGATE   0x00000040
#define CP_SQUAD   0x00000080
#define CP_AVOID   0x00000100
#define CP_APPROACH_ENEMY   0x00000200
#define CP_CLOSEST   0x00000400
#define CP_FLANK   0x00000800
#define CP_HAS_ROUTE   0x00001000
#define CP_SNIPE   0x00002000
#define CP_SAFE   0x00004000
#define CP_HORZ_DIST_COLL   0x00008000
#define CP_NO_PVS   0x00010000
#define CP_RETREAT   0x00020000
#define CPF_NONE   0
#define CPF_DUCK   0x00000001
#define CPF_FLEE   0x00000002
#define CPF_INVESTIGATE   0x00000004
#define CPF_SQUAD   0x00000008
#define CPF_LEAN   0x00000010
#define CPF_SNIPE   0x00000020
#define MAX_COMBAT_POINT_CHECK   32
#define NIF_NONE   0x00000000
#define NIF_FAILED   0x00000001
#define NIF_MACRO_NAV   0x00000002
#define NIF_COLLISION   0x00000004
#define NIF_BLOCKED   0x00000008

Typedefs

typedef navInfo_s navInfo_t

Functions

void SetNPCGlobals (gentity_t *ent)
void SaveNPCGlobals (void)
void RestoreNPCGlobals (void)
void NPC_Think (gentity_t *self)
void NPC_Pain (gentity_t *self, gentity_t *attacker, int damage)
void NPC_Touch (gentity_t *self, gentity_t *other, trace_t *trace)
void NPC_Use (gentity_t *self, gentity_t *other, gentity_t *activator)
float NPC_GetPainChance (gentity_t *self, int damage)
void Debug_Printf (vmCvar_t *cv, int level, char *fmt,...)
void Debug_NPCPrintf (gentity_t *printNPC, vmCvar_t *cv, int debugLevel, char *fmt,...)
qboolean NPC_CheckInvestigate (int alertEventNum)
qboolean NPC_StandTrackAndShoot (gentity_t *NPC, qboolean canDuck)
void NPC_BSIdle (void)
void NPC_BSPointShoot (qboolean shoot)
void NPC_BSStandGuard (void)
void NPC_BSPatrol (void)
void NPC_BSHuntAndKill (void)
void NPC_BSStandAndShoot (void)
void NPC_BSRunAndShoot (void)
void NPC_BSWait (void)
void NPC_BSDefault (void)
void NPC_BSAdvanceFight (void)
void NPC_BSInvestigate (void)
void NPC_BSSleep (void)
void NPC_BSFlee (void)
void NPC_BSFollowLeader (void)
void NPC_BSJump (void)
void NPC_BSRemove (void)
void NPC_BSSearch (void)
void NPC_BSSearchStart (int homeWp, bState_t bState)
void NPC_BSWander (void)
void NPC_StartFlee (gentity_t *enemy, vec3_t dangerPoint, int dangerLevel, int fleeTimeMin, int fleeTimeMax)
void G_StartFlee (gentity_t *self, gentity_t *enemy, vec3_t dangerPoint, int dangerLevel, int fleeTimeMin, int fleeTimeMax)
int ChooseBestWeapon (void)
void NPC_ChangeWeapon (int newWeapon)
void ShootThink (void)
void WeaponThink (qboolean inCombat)
qboolean HaveWeapon (int weapon)
qboolean CanShoot (gentity_t *ent, gentity_t *shooter)
void NPC_CheckPossibleEnemy (gentity_t *other, visibility_t vis)
gentity_tNPC_PickEnemy (gentity_t *closestTo, int enemyTeam, qboolean checkVis, qboolean findPlayersFirst, qboolean findClosest)
gentity_tNPC_CheckEnemy (qboolean findNew, qboolean tooFarOk, qboolean setEnemy)
qboolean NPC_CheckAttack (float scale)
qboolean NPC_CheckDefend (float scale)
qboolean NPC_CheckCanAttack (float attack_scale, qboolean stationary)
int NPC_AttackDebounceForWeapon (void)
qboolean EntIsGlass (gentity_t *check)
qboolean ShotThroughGlass (trace_t *tr, gentity_t *target, vec3_t spot, int mask)
qboolean ValidEnemy (gentity_t *ent)
void G_ClearEnemy (gentity_t *self)
gentity_tNPC_PickAlly (qboolean facingEachOther, float range, qboolean ignoreGroup, qboolean movingOnly)
void NPC_LostEnemyDecideChase (void)
float NPC_MaxDistSquaredForWeapon (void)
qboolean NPC_EvaluateShot (int hit, qboolean glassOK)
int NPC_ShotEntity (gentity_t *ent, vec3_t impactPos)
qboolean NPC_SlideMoveToGoal (void)
float NPC_FindClosestTeammate (gentity_t *self)
void NPC_CalcClosestFormationSpot (gentity_t *self)
void G_MaintainFormations (gentity_t *self)
void NPC_BSFormation (void)
void NPC_CreateFormation (gentity_t *self)
void NPC_DropFormation (gentity_t *self)
void NPC_ReorderFormation (gentity_t *self)
void NPC_InsertIntoFormation (gentity_t *self)
void NPC_DeleteFromFormation (gentity_t *self)
void SetGoal (gentity_t *goal, float rating)
void NPC_SetGoal (gentity_t *goal, float rating)
void NPC_ClearGoal (void)
void NPC_ReachedGoal (void)
qboolean ReachedGoal (gentity_t *goal)
gentity_tUpdateGoal (void)
qboolean NPC_ClearPathToGoal (vec3_t dir, gentity_t *goal)
qboolean NPC_MoveToGoal (qboolean tryStraight)
qboolean CanSee (gentity_t *ent)
qboolean InFOV (gentity_t *ent, gentity_t *from, int hFOV, int vFOV)
qboolean InFOV2 (vec3_t origin, gentity_t *from, int hFOV, int vFOV)
qboolean InFOV3 (vec3_t spot, vec3_t from, vec3_t fromAngles, int hFOV, int vFOV)
visibility_t NPC_CheckVisibility (gentity_t *ent, int flags)
qboolean InVisrange (gentity_t *ent)
void NPC_Spawn (gentity_t *ent, gentity_t *other, gentity_t *activator)
int NPC_ReactionTime (void)
qboolean NPC_ParseParms (const char *NPCName, gentity_t *NPC)
void NPC_LoadParms (void)
void CalcEntitySpot (const gentity_t *ent, const spot_t spot, vec3_t point)
qboolean NPC_UpdateAngles (qboolean doPitch, qboolean doYaw)
void NPC_UpdateShootAngles (vec3_t angles, qboolean doPitch, qboolean doYaw)
qboolean NPC_UpdateFiringAngles (qboolean doPitch, qboolean doYaw)
void SetTeamNumbers (void)
qboolean G_ActivateBehavior (gentity_t *self, int bset)
void NPC_AimWiggle (vec3_t enemy_org)
void NPC_SetLookTarget (gentity_t *self, int entNum, int clearTime)
int NAV_FindClosestWaypointForEnt (gentity_t *ent, int targWp)
qboolean NAV_CheckAhead (gentity_t *self, vec3_t end, trace_t *trace, int clipmask)
float IdealDistance (gentity_t *self)
void NPC_SetSayState (gentity_t *self, gentity_t *to, int saying)
qboolean G_CheckInSolid (gentity_t *self, qboolean fix)
void NPC_SetAnim (gentity_t *ent, int type, int anim, int priority)
qboolean NPC_EnemyTooFar (gentity_t *enemy, float dist, qboolean toShoot)
void NPC_SetBoneAngles (gentity_t *ent, char *bone, vec3_t angles)
void NPC_SetSurfaceOnOff (gentity_t *ent, const char *surfaceName, int surfaceFlags)
qboolean NPC_ClearLOS (const vec3_t start, const vec3_t end)
qboolean NPC_ClearLOS5 (const vec3_t end)
qboolean NPC_ClearLOS4 (gentity_t *ent)
qboolean NPC_ClearLOS3 (const vec3_t start, gentity_t *ent)
qboolean NPC_ClearLOS2 (gentity_t *ent, const vec3_t end)
qboolean NPC_ClearShot (gentity_t *ent)
int NPC_FindCombatPoint (const vec3_t position, const vec3_t avoidPosition, vec3_t enemyPosition, const int flags, const float avoidDist, const int ignorePoint)
qboolean NPC_ReserveCombatPoint (int combatPointID)
qboolean NPC_FreeCombatPoint (int combatPointID, qboolean failed)
qboolean NPC_SetCombatPoint (int combatPointID)
qboolean NPC_ValidEnemy (gentity_t *ent)
qboolean NPC_CheckEnemyExt (qboolean checkAlerts)
qboolean NPC_FindPlayer (void)
qboolean NPC_CheckCanAttackExt (void)
int NPC_CheckAlertEvents (qboolean checkSight, qboolean checkSound, int ignoreAlert, qboolean mustHaveOwner, int minAlertLevel)
qboolean NPC_CheckForDanger (int alertEvent)
void G_AlertTeam (gentity_t *victim, gentity_t *attacker, float radius, float soundDist)
int NPC_FindSquadPoint (vec3_t position)
void ClearPlayerAlertEvents (void)
qboolean G_BoundsOverlap (const vec3_t mins1, const vec3_t maxs1, const vec3_t mins2, const vec3_t maxs2)
qboolean NAV_HitNavGoal (vec3_t point, vec3_t mins, vec3_t maxs, vec3_t dest, int radius, qboolean flying)
void NPC_SetMoveGoal (gentity_t *ent, vec3_t point, int radius, qboolean isNavGoal, int combatPoint, gentity_t *targetEnt)
qboolean NAV_ClearPathToPoint (gentity_t *self, vec3_t pmins, vec3_t pmaxs, vec3_t point, int clipmask, int okToHitEnt)
void NPC_ApplyWeaponFireDelay (void)
qboolean NPC_FacePosition (vec3_t position, qboolean doPitch)
qboolean NPC_FaceEntity (gentity_t *ent, qboolean doPitch)
qboolean NPC_FaceEnemy (qboolean doPitch)
int NAV_MoveToGoal (gentity_t *self, navInfo_t *info)
void NAV_GetLastMove (navInfo_t *info)
qboolean NAV_AvoidCollision (gentity_t *self, gentity_t *goal, navInfo_t *info)

Variables

vmCvar_t debugNPCAI
vmCvar_t debugNPCFreeze
vmCvar_t debugNPCAimingBeam
vmCvar_t debugBreak
vmCvar_t debugNoRoam
vmCvar_t d_JediAI
vmCvar_t d_saberCombat
gentity_tNPC
gNPC_tNPCInfo
gclient_tclient
usercmd_t ucmd
visibility_t enemyVisibility
int teamNumbers [TEAM_NUM_TEAMS]
int teamStrength [TEAM_NUM_TEAMS]
int teamCounter [TEAM_NUM_TEAMS]
vmCvar_t g_spskill


Define Documentation

#define AI_TIMERS   0
 

Definition at line 12 of file b_local.h.

#define ALERT_CLEAR_TIME   200
 

Definition at line 164 of file b_local.h.

Referenced by ClearPlayerAlertEvents(), and CorpsePhysics().

#define CHECK_360   2
 

Definition at line 166 of file b_local.h.

Referenced by NPC_BSFollowLeader(), NPC_CheckCanAttack(), NPC_CheckPossibleEnemy(), NPC_CheckVisibility(), NPC_PickAlly(), and NPC_PickEnemy().

#define CHECK_FOV   4
 

Definition at line 167 of file b_local.h.

Referenced by NPC_BSAdvanceFight(), NPC_BSFollowLeader(), NPC_BSHuntAndKill(), NPC_CheckCanAttack(), NPC_CheckPossibleEnemy(), NPC_CheckVisibility(), and NPC_PickEnemy().

#define CHECK_PVS   1
 

Definition at line 165 of file b_local.h.

Referenced by NPC_BSFollowLeader(), and NPC_CheckVisibility().

#define CHECK_SHOOT   8
 

Definition at line 168 of file b_local.h.

Referenced by NPC_BSFollowLeader(), NPC_BSHuntAndKill(), and NPC_CheckVisibility().

#define CHECK_VISRANGE   16
 

Definition at line 169 of file b_local.h.

Referenced by NPC_CheckVisibility(), NPC_PickAlly(), and NPC_PickEnemy().

#define COLLISION_RADIUS   32
 

Definition at line 133 of file b_local.h.

#define CP_ANY   0
 

Definition at line 243 of file b_local.h.

Referenced by ST_Commander().

#define CP_APPROACH_ENEMY   0x00000200
 

Definition at line 253 of file b_local.h.

Referenced by NPC_FindCombatPoint(), ST_Commander(), and ST_GetCPFlags().

#define CP_AVOID   0x00000100
 

Definition at line 252 of file b_local.h.

Referenced by NPC_FindCombatPoint(), NPC_StartFlee(), ST_Commander(), and ST_GetCPFlags().

#define CP_AVOID_ENEMY   0x00000020
 

Definition at line 249 of file b_local.h.

Referenced by NPC_FindCombatPoint(), and ST_Commander().

#define CP_CLEAR   0x00000002
 

Definition at line 245 of file b_local.h.

Referenced by NPC_FindCombatPoint(), ST_ApproachEnemy(), ST_Commander(), and ST_GetCPFlags().

#define CP_CLOSEST   0x00000400
 

Definition at line 254 of file b_local.h.

Referenced by ST_ApproachEnemy(), ST_Commander(), and ST_GetCPFlags().

#define CP_COVER   0x00000001
 

Definition at line 244 of file b_local.h.

Referenced by NPC_FindCombatPoint(), NPC_StartFlee(), ST_Commander(), and ST_GetCPFlags().

#define CP_DUCK   0x00000008
 

Definition at line 247 of file b_local.h.

Referenced by ST_Commander().

#define CP_FLANK   0x00000800
 

Definition at line 255 of file b_local.h.

Referenced by NPC_FindCombatPoint(), ST_Commander(), and ST_GetCPFlags().

#define CP_FLEE   0x00000004
 

Definition at line 246 of file b_local.h.

Referenced by ST_Commander(), and ST_GetCPFlags().

#define CP_HAS_ROUTE   0x00001000
 

Definition at line 256 of file b_local.h.

Referenced by NPC_FindCombatPoint(), NPC_StartFlee(), and ST_Commander().

#define CP_HORZ_DIST_COLL   0x00008000
 

Definition at line 259 of file b_local.h.

Referenced by NPC_FindCombatPoint().

#define CP_INVESTIGATE   0x00000040
 

Definition at line 250 of file b_local.h.

Referenced by ST_Commander().

#define CP_NEAREST   0x00000010
 

Definition at line 248 of file b_local.h.

Referenced by NPC_FindCombatPoint(), ST_Commander(), and ST_GetCPFlags().

#define CP_NO_PVS   0x00010000
 

Definition at line 260 of file b_local.h.

Referenced by NPC_FindCombatPoint(), and NPC_StartFlee().

#define CP_RETREAT   0x00020000
 

Definition at line 261 of file b_local.h.

Referenced by NPC_FindCombatPoint(), ST_Commander(), and ST_GetCPFlags().

#define CP_SAFE   0x00004000
 

Definition at line 258 of file b_local.h.

Referenced by ST_Commander(), and ST_GetCPFlags().

#define CP_SNIPE   0x00002000
 

Definition at line 257 of file b_local.h.

#define CP_SQUAD   0x00000080
 

Definition at line 251 of file b_local.h.

Referenced by ST_Commander().

#define CPF_DUCK   0x00000001
 

Definition at line 264 of file b_local.h.

Referenced by ST_Commander().

#define CPF_FLEE   0x00000002
 

Definition at line 265 of file b_local.h.

#define CPF_INVESTIGATE   0x00000004
 

Definition at line 266 of file b_local.h.

#define CPF_LEAN   0x00000010
 

Definition at line 268 of file b_local.h.

#define CPF_NONE   0
 

Definition at line 263 of file b_local.h.

#define CPF_SNIPE   0x00000020
 

Definition at line 269 of file b_local.h.

#define CPF_SQUAD   0x00000008
 

Definition at line 267 of file b_local.h.

Referenced by NPC_FindSquadPoint().

#define DEBUG_LEVEL_DETAIL   4
 

Definition at line 22 of file b_local.h.

Referenced by Debug_NPCPrintf(), and Debug_Printf().

#define DEBUG_LEVEL_ERROR   1
 

Definition at line 25 of file b_local.h.

Referenced by Debug_NPCPrintf(), and Debug_Printf().

#define DEBUG_LEVEL_INFO   3
 

Definition at line 23 of file b_local.h.

Referenced by Debug_NPCPrintf(), Debug_Printf(), and NPC_PickEnemy().

#define DEBUG_LEVEL_NONE   0
 

Definition at line 26 of file b_local.h.

#define DEBUG_LEVEL_WARNING   2
 

Definition at line 24 of file b_local.h.

Referenced by Debug_NPCPrintf(), and Debug_Printf().

#define MAX_COMBAT_POINT_CHECK   32
 

Definition at line 271 of file b_local.h.

#define MAX_GOAL_REACHED_DIST_SQUARED   256
 

Definition at line 28 of file b_local.h.

#define MIN_ANGLE_ERROR   0.01f
 

Definition at line 29 of file b_local.h.

Referenced by NPC_BSJump(), and NPC_UpdateAngles().

#define MIN_ROCKET_DIST_SQUARED   16384
 

Definition at line 31 of file b_local.h.

Referenced by Boba_FireDecide(), NPC_BSST_Attack(), and ST_Commander().

#define NAVF_DUCK   0x00000001
 

Definition at line 17 of file b_local.h.

#define NAVF_HOLD   0x00000004
 

Definition at line 19 of file b_local.h.

#define NAVF_JUMP   0x00000002
 

Definition at line 18 of file b_local.h.

#define NAVF_SLOW   0x00000008
 

Definition at line 20 of file b_local.h.

#define NIF_BLOCKED   0x00000008
 

Definition at line 306 of file b_local.h.

Referenced by NAV_AvoidCollision(), and NAV_TestForBlocked().

#define NIF_COLLISION   0x00000004
 

Definition at line 305 of file b_local.h.

Referenced by NAV_AvoidCollision(), and NAVNEW_AvoidCollision().

#define NIF_FAILED   0x00000001
 

Definition at line 303 of file b_local.h.

#define NIF_MACRO_NAV   0x00000002
 

Definition at line 304 of file b_local.h.

Referenced by NPC_GetMoveDirection(), and NPC_GetMoveDirectionAltRoute().

#define NIF_NONE   0x00000000
 

Definition at line 302 of file b_local.h.

#define NUM_POSITIONS   30
 

Definition at line 134 of file b_local.h.

#define SFB_CINEMATIC   32
 

Definition at line 147 of file b_local.h.

Referenced by NPC_Begin(), and NPC_SetMiscDefaultData().

#define SFB_DRILL   16
 

Definition at line 145 of file b_local.h.

#define SFB_GUN   4
 

Definition at line 142 of file b_local.h.

#define SFB_NOTSOLID   64
 

Definition at line 148 of file b_local.h.

Referenced by NPC_Begin().

#define SFB_OLDBORG   2
 

Definition at line 140 of file b_local.h.

#define SFB_PHASER   4
 

Definition at line 141 of file b_local.h.

Referenced by NPC_WeaponsForTeam().

#define SFB_RIFLEMAN   2
 

Definition at line 139 of file b_local.h.

Referenced by NPC_WeaponsForTeam().

#define SFB_SMALLHULL   1
 

Definition at line 137 of file b_local.h.

#define SFB_STARTINSOLID   128
 

Definition at line 149 of file b_local.h.

Referenced by NPC_Begin().

#define SFB_TASER   8
 

Definition at line 144 of file b_local.h.

#define SFB_TRICORDER   8
 

Definition at line 143 of file b_local.h.


Typedef Documentation

typedef struct navInfo_s navInfo_t
 

Referenced by AI_CheckEnemyCollision(), NAV_AvoidCollision(), NAV_GetLastMove(), NAV_MoveToGoal(), NAVNEW_AvoidCollision(), NAVNEW_MoveToGoal(), and NPC_GetMoveDirectionAltRoute().


Function Documentation

void CalcEntitySpot const gentity_t ent,
const spot_t  spot,
vec3_t  point
 

Definition at line 20 of file NPC_utils.c.

References entityShared_t::absmax, entityShared_t::absmin, AngleVectors(), CalcMuzzlePoint(), CLASS_ATST, gentity_s::client, entityShared_t::currentOrigin, trace_t::endpos, renderInfo_s::eyePoint, trace_t::fraction, gentity_t, entityState_s::groundEntityNum, MASK_PLAYERSOLID, entityShared_t::maxs, entityShared_t::mins, gentity_s::NPC, gclient_s::NPC_class, entityState_s::number, gclient_s::ps, gentity_s::r, gclient_s::renderInfo, gentity_s::s, gNPC_t::shootAngles, SPOT_CHEST, SPOT_GROUND, SPOT_HEAD, SPOT_HEAD_LEAN, SPOT_LEGS, SPOT_ORIGIN, SPOT_WEAPON, trap_Trace(), vec3_origin, vec3_t, VectorCopy, VectorMA, VectorSubtract, playerState_s::viewangles, and playerState_s::viewheight.

Referenced by Boba_FireDecide(), CanSee(), CanShoot(), G_CheckAlertEvents(), G_ClearLOS2(), G_ClearLOS3(), G_ClearLOS4(), G_ClearLOS5(), G_FindLocalInterestPoint(), ImperialProbe_FireBlaster(), InFOV(), InFOV2(), InVisrange(), Mark1_FireBlaster(), Mark1_FireRocket(), Mark2_FireBlaster(), NPC_BSAdvanceFight(), NPC_BSCinematic(), NPC_BSFollowLeader(), NPC_BSGM_Attack(), NPC_BSPointShoot(), NPC_CheckCanAttack(), NPC_ClearShot(), NPC_FaceEntity(), NPC_FacePosition(), NPC_ShotEntity(), Remote_Fire(), Seeker_Fire(), Sniper_FaceEnemy(), and Sniper_UpdateEnemyPos().

00021 {
00022         vec3_t  forward, up, right;
00023         vec3_t  start, end;
00024         trace_t tr;
00025 
00026         if ( !ent )
00027         {
00028                 return;
00029         }
00030         switch ( spot ) 
00031         {
00032         case SPOT_ORIGIN:
00033                 if(VectorCompare(ent->r.currentOrigin, vec3_origin))
00034                 {//brush
00035                         VectorSubtract(ent->r.absmax, ent->r.absmin, point);//size
00036                         VectorMA(ent->r.absmin, 0.5, point, point);
00037                 }
00038                 else
00039                 {
00040                         VectorCopy ( ent->r.currentOrigin, point );
00041                 }
00042                 break;
00043 
00044         case SPOT_CHEST:
00045         case SPOT_HEAD:
00046                 if ( ent->client && VectorLengthSquared( ent->client->renderInfo.eyePoint ) /*&& (ent->client->ps.viewEntity <= 0 || ent->client->ps.viewEntity >= ENTITYNUM_WORLD)*/ )
00047                 {//Actual tag_head eyespot!
00048                         //FIXME: Stasis aliens may have a problem here...
00049                         VectorCopy( ent->client->renderInfo.eyePoint, point );
00050                         if ( ent->client->NPC_class == CLASS_ATST )
00051                         {//adjust up some
00052                                 point[2] += 28;//magic number :)
00053                         }
00054                         if ( ent->NPC )
00055                         {//always aim from the center of my bbox, so we don't wiggle when we lean forward or backwards
00056                                 point[0] = ent->r.currentOrigin[0];
00057                                 point[1] = ent->r.currentOrigin[1];
00058                         }
00059                         /*
00060                         else if (ent->s.eType == ET_PLAYER )
00061                         {
00062                                 SubtractLeanOfs( ent, point );
00063                         }
00064                         */
00065                 }
00066                 else
00067                 {
00068                         VectorCopy ( ent->r.currentOrigin, point );
00069                         if ( ent->client ) 
00070                         {
00071                                 point[2] += ent->client->ps.viewheight;
00072                         }
00073                 }
00074                 if ( spot == SPOT_CHEST && ent->client )
00075                 {
00076                         if ( ent->client->NPC_class != CLASS_ATST )
00077                         {//adjust up some
00078                                 point[2] -= ent->r.maxs[2]*0.2f;
00079                         }
00080                 }
00081                 break;
00082 
00083         case SPOT_HEAD_LEAN:
00084                 if ( ent->client && VectorLengthSquared( ent->client->renderInfo.eyePoint ) /*&& (ent->client->ps.viewEntity <= 0 || ent->client->ps.viewEntity >= ENTITYNUM_WORLD*/ )
00085                 {//Actual tag_head eyespot!
00086                         //FIXME: Stasis aliens may have a problem here...
00087                         VectorCopy( ent->client->renderInfo.eyePoint, point );
00088                         if ( ent->client->NPC_class == CLASS_ATST )
00089                         {//adjust up some
00090                                 point[2] += 28;//magic number :)
00091                         }
00092                         if ( ent->NPC )
00093                         {//always aim from the center of my bbox, so we don't wiggle when we lean forward or backwards
00094                                 point[0] = ent->r.currentOrigin[0];
00095                                 point[1] = ent->r.currentOrigin[1];
00096                         }
00097                         /*
00098                         else if ( ent->s.eType == ET_PLAYER )
00099                         {
00100                                 SubtractLeanOfs( ent, point );
00101                         }
00102                         */
00103                         //NOTE: automatically takes leaning into account!
00104                 }
00105                 else
00106                 {
00107                         VectorCopy ( ent->r.currentOrigin, point );
00108                         if ( ent->client ) 
00109                         {
00110                                 point[2] += ent->client->ps.viewheight;
00111                         }
00112                         //AddLeanOfs ( ent, point );
00113                 }
00114                 break;
00115 
00116         //FIXME: implement...
00117         //case SPOT_CHEST:
00118                 //Returns point 3/4 from tag_torso to tag_head?
00119                 //break;
00120 
00121         case SPOT_LEGS:
00122                 VectorCopy ( ent->r.currentOrigin, point );
00123                 point[2] += (ent->r.mins[2] * 0.5);
00124                 break;
00125 
00126         case SPOT_WEAPON:
00127                 if( ent->NPC && !VectorCompare( ent->NPC->shootAngles, vec3_origin ) && !VectorCompare( ent->NPC->shootAngles, ent->client->ps.viewangles ))
00128                 {
00129                         AngleVectors( ent->NPC->shootAngles, forward, right, up );
00130                 }
00131                 else
00132                 {
00133                         AngleVectors( ent->client->ps.viewangles, forward, right, up );
00134                 }
00135                 CalcMuzzlePoint( (gentity_t*)ent, forward, right, up, point );
00136                 //NOTE: automatically takes leaning into account!
00137                 break;
00138 
00139         case SPOT_GROUND:
00140                 // if entity is on the ground, just use it's absmin
00141                 if ( ent->s.groundEntityNum != -1 ) 
00142                 {
00143                         VectorCopy( ent->r.currentOrigin, point );
00144                         point[2] = ent->r.absmin[2];
00145                         break;
00146                 }
00147 
00148                 // if it is reasonably close to the ground, give the point underneath of it
00149                 VectorCopy( ent->r.currentOrigin, start );
00150                 start[2] = ent->r.absmin[2];
00151                 VectorCopy( start, end );
00152                 end[2] -= 64;
00153                 trap_Trace( &tr, start, ent->r.mins, ent->r.maxs, end, ent->s.number, MASK_PLAYERSOLID );
00154                 if ( tr.fraction < 1.0 ) 
00155                 {
00156                         VectorCopy( tr.endpos, point);
00157                         break;
00158                 }
00159 
00160                 // otherwise just use the origin
00161                 VectorCopy( ent->r.currentOrigin, point );
00162                 break;
00163 
00164         default:
00165                 VectorCopy ( ent->r.currentOrigin, point );
00166                 break;
00167         }
00168 }

qboolean CanSee gentity_t ent  ) 
 

Definition at line 47 of file NPC_senses.c.

References CalcEntitySpot(), trace_t::fraction, gentity_t, MASK_OPAQUE, NPC, NULL, entityState_s::number, qboolean, qfalse, qtrue, gentity_s::s, ShotThroughGlass(), SPOT_HEAD, SPOT_HEAD_LEAN, SPOT_LEGS, SPOT_ORIGIN, trap_Trace(), and vec3_t.

Referenced by NPC_CheckVisibility().

00048 {
00049         trace_t         tr;
00050         vec3_t          eyes;
00051         vec3_t          spot;
00052 
00053         CalcEntitySpot( NPC, SPOT_HEAD_LEAN, eyes );
00054 
00055         CalcEntitySpot( ent, SPOT_ORIGIN, spot );
00056         trap_Trace ( &tr, eyes, NULL, NULL, spot, NPC->s.number, MASK_OPAQUE );
00057         ShotThroughGlass (&tr, ent, spot, MASK_OPAQUE);
00058         if ( tr.fraction == 1.0 ) 
00059         {
00060                 return qtrue;
00061         }
00062 
00063         CalcEntitySpot( ent, SPOT_HEAD, spot );
00064         trap_Trace ( &tr, eyes, NULL, NULL, spot, NPC->s.number, MASK_OPAQUE );
00065         ShotThroughGlass (&tr, ent, spot, MASK_OPAQUE);
00066         if ( tr.fraction == 1.0 ) 
00067         {
00068                 return qtrue;
00069         }
00070 
00071         CalcEntitySpot( ent, SPOT_LEGS, spot );
00072         trap_Trace ( &tr, eyes, NULL, NULL, spot, NPC->s.number, MASK_OPAQUE );
00073         ShotThroughGlass (&tr, ent, spot, MASK_OPAQUE);
00074         if ( tr.fraction == 1.0 ) 
00075         {
00076                 return qtrue;
00077         }
00078 
00079         return qfalse;
00080 }

qboolean CanShoot gentity_t ent,
gentity_t shooter
 

Definition at line 1150 of file NPC_combat.c.

References CalcEntitySpot(), gentity_s::client, trace_t::endpos, trace_t::entityNum, g_entities, gentity_t, gentity_s::health, MASK_SHOT, gentity_s::NPC, NULL, entityState_s::number, gclient_s::playerTeam, qboolean, qfalse, qtrue, random, gentity_s::s, ShotThroughGlass(), SPOT_HEAD, SPOT_ORIGIN, SPOT_WEAPON, trace_t::startsolid, gNPC_t::touchedByPlayer, trap_Trace(), vec3_t, and VectorSubtract.

Referenced by NPC_CheckVisibility().

01151 {
01152         trace_t         tr;
01153         vec3_t          muzzle;
01154         vec3_t          spot, diff;
01155         gentity_t       *traceEnt;
01156 
01157         CalcEntitySpot( shooter, SPOT_WEAPON, muzzle );
01158         CalcEntitySpot( ent, SPOT_ORIGIN, spot );               //FIXME preferred target locations for some weapons (feet for R/L)
01159 
01160         trap_Trace ( &tr, muzzle, NULL, NULL, spot, shooter->s.number, MASK_SHOT );
01161         traceEnt = &g_entities[ tr.entityNum ];
01162 
01163         // point blank, baby!
01164         if (tr.startsolid && (shooter->NPC) && (shooter->NPC->touchedByPlayer) ) 
01165         {
01166                 traceEnt = shooter->NPC->touchedByPlayer;
01167         }
01168         
01169         if ( ShotThroughGlass( &tr, ent, spot, MASK_SHOT ) )
01170         {
01171                 traceEnt = &g_entities[ tr.entityNum ];
01172         }
01173 
01174         // shot is dead on
01175         if ( traceEnt == ent ) 
01176         {
01177                 return qtrue;
01178         }
01179 //MCG - Begin
01180         else
01181         {//ok, can't hit them in center, try their head
01182                 CalcEntitySpot( ent, SPOT_HEAD, spot );
01183                 trap_Trace ( &tr, muzzle, NULL, NULL, spot, shooter->s.number, MASK_SHOT );
01184                 traceEnt = &g_entities[ tr.entityNum ];
01185                 if ( traceEnt == ent) 
01186                 {
01187                         return qtrue;
01188                 }
01189         }
01190 
01191         //Actually, we should just check to fire in dir we're facing and if it's close enough,
01192         //and we didn't hit someone on our own team, shoot
01193         VectorSubtract(spot, tr.endpos, diff);
01194         if(VectorLength(diff) < random() * 32)
01195         {
01196                 return qtrue;
01197         }
01198 //MCG - End
01199         // shot would hit a non-client
01200         if ( !traceEnt->client ) 
01201         {
01202                 return qfalse;
01203         }
01204 
01205         // shot is blocked by another player
01206 
01207         // he's already dead, so go ahead
01208         if ( traceEnt->health <= 0 ) 
01209         {
01210                 return qtrue;
01211         }
01212 
01213         // don't deliberately shoot a teammate
01214         if ( traceEnt->client && ( traceEnt->client->playerTeam == shooter->client->playerTeam ) ) 
01215         {
01216                 return qfalse;
01217         }
01218 
01219         // he's just in the wrong place, go ahead
01220         return qtrue;
01221 }

int ChooseBestWeapon void   ) 
 

void ClearPlayerAlertEvents void   ) 
 

Definition at line 660 of file NPC_senses.c.

Referenced by G_RunFrame().

00661 {
00662         int curNumAlerts = level.numAlertEvents;
00663         int i;
00664         //loop through them all (max 32)
00665         for ( i = 0; i < curNumAlerts; i++ )
00666         {
00667                 //see if the event is old enough to delete
00668                 if ( level.alertEvents[i].timestamp && level.alertEvents[i].timestamp + ALERT_CLEAR_TIME < level.time )
00669                 {//this event has timed out
00670                         //drop the count
00671                         level.numAlertEvents--;
00672                         //shift the rest down
00673                         if ( level.numAlertEvents > 0 )
00674                         {//still have more in the array
00675                                 if ( (i+1) < MAX_ALERT_EVENTS )
00676                                 {
00677                                         memmove( &level.alertEvents[i], &level.alertEvents[i+1], sizeof(alertEvent_t)*(MAX_ALERT_EVENTS-(i+1) ) );
00678                                 }
00679                         }
00680                         else
00681                         {//just clear this one... or should we clear the whole array?
00682                                 memset( &level.alertEvents[i], 0, sizeof( alertEvent_t ) );
00683                         }
00684                 }
00685         }
00686         //make sure this never drops below zero... if it does, something very very bad happened
00687         assert( level.numAlertEvents >= 0 );
00688 
00689         if ( eventClearTime < level.time )
00690         {//this is just a 200ms debouncer so things that generate constant alerts (like corpses and missiles) add an alert every 200 ms
00691                 eventClearTime = level.time + ALERT_CLEAR_TIME;
00692         }
00693 }

void Debug_NPCPrintf gentity_t printNPC,
vmCvar_t cv,
int  debugLevel,
char *  fmt,
... 
 

Definition at line 41 of file NPC_misc.c.

References COLOR_GREEN, COLOR_RED, COLOR_WHITE, COLOR_YELLOW, Com_Printf(), DEBUG_LEVEL_DETAIL, DEBUG_LEVEL_ERROR, DEBUG_LEVEL_INFO, DEBUG_LEVEL_WARNING, gentity_t, level, Q_COLOR_ESCAPE, gentity_s::targetname, level_locals_t::time, va_end, va_list, va_start, vmCvar_t::value, and vsprintf().

00042 {
00043         int                     color;
00044         va_list         argptr;
00045         char            msg[1024];
00046 
00047         if (cv->value < debugLevel)
00048         {
00049                 return;
00050         }
00051 
00052 //      if ( debugNPCName.string[0] && Q_stricmp( debugNPCName.string, printNPC->targetname) != 0 ) 
00053 //      {
00054 //              return;
00055 //      }
00056 
00057         if (debugLevel == DEBUG_LEVEL_DETAIL)
00058                 color = COLOR_WHITE;
00059         else if (debugLevel == DEBUG_LEVEL_INFO)
00060                 color = COLOR_GREEN;
00061         else if (debugLevel == DEBUG_LEVEL_WARNING)
00062                 color = COLOR_YELLOW;
00063         else if (debugLevel == DEBUG_LEVEL_ERROR)
00064                 color = COLOR_RED;
00065         else
00066                 color = COLOR_RED;
00067 
00068         va_start (argptr,fmt);
00069         vsprintf (msg, fmt, argptr);
00070         va_end (argptr);
00071 
00072         Com_Printf ("%c%c%5i (%s) %s", Q_COLOR_ESCAPE, color, level.time, printNPC->targetname, msg);
00073 }

void Debug_Printf vmCvar_t cv,
int  level,
char *  fmt,
... 
 

Definition at line 10 of file NPC_misc.c.

References Com_Printf(), DEBUG_LEVEL_DETAIL, DEBUG_LEVEL_ERROR, DEBUG_LEVEL_INFO, DEBUG_LEVEL_WARNING, level, S_COLOR_GREEN, S_COLOR_RED, S_COLOR_WHITE, S_COLOR_YELLOW, level_locals_t::time, va_end, va_list, va_start, vmCvar_t::value, and vsprintf().

Referenced by NPC_PickEnemy().

00011 {
00012         char            *color;
00013         va_list         argptr;
00014         char            msg[1024];
00015 
00016         if (cv->value < debugLevel)
00017                 return;
00018 
00019         if (debugLevel == DEBUG_LEVEL_DETAIL)
00020                 color = S_COLOR_WHITE;
00021         else if (debugLevel == DEBUG_LEVEL_INFO)
00022                 color = S_COLOR_GREEN;
00023         else if (debugLevel == DEBUG_LEVEL_WARNING)
00024                 color = S_COLOR_YELLOW;
00025         else if (debugLevel == DEBUG_LEVEL_ERROR)
00026                 color = S_COLOR_RED;
00027         else
00028                 color = S_COLOR_RED;
00029 
00030         va_start (argptr,fmt);
00031         vsprintf (msg, fmt, argptr);
00032         va_end (argptr);
00033 
00034         Com_Printf("%s%5i:%s", color, level.time, msg);
00035 }

qboolean EntIsGlass gentity_t check  ) 
 

Definition at line 1114 of file NPC_combat.c.

References gentity_s::classname, gentity_s::count, gentity_t, gentity_s::health, Q_stricmp(), qboolean, qfalse, and qtrue.

Referenced by G_ClearLineOfSight(), NPC_CheckCanAttack(), and ShotThroughGlass().

01115 {
01116         if(check->classname &&
01117                 !Q_stricmp("func_breakable", check->classname) &&
01118                 check->count == 1 && check->health <= 100)
01119         {
01120                 return qtrue;
01121         }
01122 
01123         return qfalse;
01124 }

qboolean G_ActivateBehavior gentity_t self,
int  bset
 

Definition at line 851 of file NPC_utils.c.

00852 {
00853         bState_t        bSID = (bState_t)-1;
00854         char *bs_name = NULL;
00855 
00856         if ( !self )
00857         {
00858                 return qfalse;
00859         }
00860 
00861         bs_name = self->behaviorSet[bset];
00862         
00863         if( !(VALIDSTRING( bs_name )) )
00864         {
00865                 return qfalse;
00866         }
00867 
00868         if ( self->NPC )
00869         {
00870                 bSID = (bState_t)(GetIDForString( BSTable, bs_name ));
00871         }
00872 
00873         if(bSID > -1)
00874         {
00875                 self->NPC->tempBehavior = BS_DEFAULT;
00876                 self->NPC->behaviorState = bSID;
00877         }
00878         else
00879         {
00880                 /*
00881                 char                    newname[MAX_FILENAME_LENGTH];           
00882                 sprintf((char *) &newname, "%s/%s", Q3_SCRIPT_DIR, bs_name );
00883                 */
00884                 
00885                 //FIXME: between here and actually getting into the ICARUS_RunScript function, the stack gets blown!
00886                 //if ( ( ICARUS_entFilter == -1 ) || ( ICARUS_entFilter == self->s.number ) )
00887                 if (0)
00888                 {
00889                         G_DebugPrint( WL_VERBOSE, "%s attempting to run bSet %s (%s)\n", self->targetname, GetStringForID( BSETTable, bset ), bs_name );
00890                 }
00891                 trap_ICARUS_RunScript( self, va( "%s/%s", Q3_SCRIPT_DIR, bs_name ) );
00892         }
00893         return qtrue;
00894 }

void G_AlertTeam gentity_t victim,
gentity_t attacker,
float  radius,
float  soundDist
 

Definition at line 1769 of file g_combat.c.

References gentity_s::client, entityShared_t::currentOrigin, gentity_s::enemy, g_entities, G_SetEnemy(), gentity_t, gentity_s::health, gNPCstats_e::hfov, InFOV(), gentity_s::NPC, NPC_ClearLOS2(), NULL, gclient_s::playerTeam, gentity_s::r, SCF_IGNORE_ALERTS, SCF_LOOK_FOR_ENEMIES, SCF_NO_GROUPS, gNPC_t::scriptFlags, gNPC_t::stats, trap_EntitiesInBox(), trap_InPVS(), vec3_t, and gNPCstats_e::vfov.

Referenced by G_AngerAlert(), and G_DeathAlert().

01770 {
01771         int                     radiusEnts[ 128 ];
01772         gentity_t       *check;
01773         vec3_t          mins, maxs;
01774         int                     numEnts;
01775         int                     i;
01776         float           distSq, sndDistSq = (soundDist*soundDist);
01777 
01778         if ( attacker == NULL || attacker->client == NULL )
01779                 return;
01780 
01781         //Setup the bbox to search in
01782         for ( i = 0; i < 3; i++ )
01783         {
01784                 mins[i] = victim->r.currentOrigin[i] - radius;
01785                 maxs[i] = victim->r.currentOrigin[i] + radius;
01786         }
01787 
01788         //Get the number of entities in a given space
01789         numEnts = trap_EntitiesInBox( mins, maxs, radiusEnts, 128 );
01790 
01791         //Cull this list
01792         for ( i = 0; i < numEnts; i++ )
01793         {
01794                 check = &g_entities[radiusEnts[i]];
01795 
01796                 //Validate clients
01797                 if ( check->client == NULL )
01798                         continue;
01799 
01800                 //only want NPCs
01801                 if ( check->NPC == NULL )
01802                         continue;
01803 
01804                 //Don't bother if they're ignoring enemies
01805 //              if ( check->svFlags & SVF_IGNORE_ENEMIES )
01806 //                      continue;
01807 
01808                 //This NPC specifically flagged to ignore alerts
01809                 if ( check->NPC->scriptFlags & SCF_IGNORE_ALERTS )
01810                         continue;
01811 
01812                 //This NPC specifically flagged to ignore alerts
01813                 if ( !(check->NPC->scriptFlags&SCF_LOOK_FOR_ENEMIES) )
01814                         continue;
01815 
01816                 //this ent does not participate in group AI
01817                 if ( (check->NPC->scriptFlags&SCF_NO_GROUPS) )
01818                         continue;
01819 
01820                 //Skip the requested avoid check if present
01821                 if ( check == victim )
01822                         continue;
01823 
01824                 //Skip the attacker
01825                 if ( check == attacker )
01826                         continue;
01827 
01828                 //Must be on the same team
01829                 if ( check->client->playerTeam != victim->client->playerTeam )
01830                         continue;
01831 
01832                 //Must be alive
01833                 if ( check->health <= 0 )
01834                         continue;
01835 
01836                 if ( check->enemy == NULL )
01837                 {//only do this if they're not already mad at someone
01838                         distSq = DistanceSquared( check->r.currentOrigin, victim->r.currentOrigin );
01839                         if ( distSq > 16384 /*128 squared*/ && !trap_InPVS( victim->r.currentOrigin, check->r.currentOrigin ) )
01840                         {//not even potentially visible/hearable
01841                                 continue;
01842                         }
01843                         //NOTE: this allows sound alerts to still go through doors/PVS if the teammate is within 128 of the victim...
01844                         if ( soundDist <= 0 || distSq > sndDistSq )
01845                         {//out of sound range
01846                                 if ( !InFOV( victim, check, check->NPC->stats.hfov, check->NPC->stats.vfov ) 
01847                                         ||  !NPC_ClearLOS2( check, victim->r.currentOrigin ) )
01848                                 {//out of FOV or no LOS
01849                                         continue;
01850                                 }
01851                         }
01852 
01853                         //FIXME: This can have a nasty cascading effect if setup wrong...
01854                         G_SetEnemy( check, attacker );
01855                 }
01856         }
01857 }

qboolean G_BoundsOverlap const vec3_t  mins1,
const vec3_t  maxs1,
const vec3_t  mins2,
const vec3_t  maxs2
 

Definition at line 94 of file NPC_goal.c.

00095 {//NOTE: flush up against counts as overlapping
00096         if(mins1[0]>maxs2[0])
00097                 return qfalse;
00098 
00099         if(mins1[1]>maxs2[1])
00100                 return qfalse;
00101 
00102         if(mins1[2]>maxs2[2])
00103                 return qfalse;
00104 
00105         if(maxs1[0]<mins2[0])
00106                 return qfalse;
00107 
00108         if(maxs1[1]<mins2[1])
00109                 return qfalse;
00110 
00111         if(maxs1[2]<mins2[2])
00112                 return qfalse;
00113 
00114         return qtrue;
00115 }

qboolean G_CheckInSolid gentity_t self,
qboolean  fix
 

Definition at line 1965 of file g_utils.c.

01966 {
01967         trace_t trace;
01968         vec3_t  end, mins;
01969 
01970         VectorCopy(self->r.currentOrigin, end);
01971         end[2] += self->r.mins[2];
01972         VectorCopy(self->r.mins, mins);
01973         mins[2] = 0;
01974 
01975         trap_Trace(&trace, self->r.currentOrigin, mins, self->r.maxs, end, self->s.number, self->clipmask);
01976         if(trace.allsolid || trace.startsolid)
01977         {
01978                 return qtrue;
01979         }
01980         
01981         if(trace.fraction < 1.0)
01982         {
01983                 if(fix)
01984                 {//Put them at end of trace and check again
01985                         vec3_t  neworg;
01986 
01987                         VectorCopy(trace.endpos, neworg);
01988                         neworg[2] -= self->r.mins[2];
01989                         G_SetOrigin(self, neworg);
01990                         trap_LinkEntity(self);
01991 
01992                         return G_CheckInSolid(self, qfalse);
01993                 }
01994                 else
01995                 {
01996                         return qtrue;
01997                 }
01998         }
01999                 
02000         return qfalse;
02001 }

void G_ClearEnemy gentity_t self  ) 
 

Definition at line 17 of file NPC_combat.c.

References gentity_s::client, gentity_s::enemy, gentity_t, gNPC_t::goalEntity, renderInfo_s::lookTarget, gentity_s::NPC, NPC_CheckLookTarget(), NPC_ClearLookTarget(), NULL, entityState_s::number, gclient_s::renderInfo, and gentity_s::s.

Referenced by ForceTelepathyCheckDirectNPCTarget(), G_SetEnemy(), NPC_BSFollowLeader(), NPC_CheckCharmed(), NPC_CheckEnemy(), NPC_ExecuteBState(), NPC_FindEnemy(), NPC_Grenadier_PlayConfusionSound(), NPC_LostEnemyDecideChase(), NPC_PlayConfusionSound(), NPC_Sniper_PlayConfusionSound(), and ST_Commander().

00018 {
00019         NPC_CheckLookTarget( self );
00020 
00021         if ( self->enemy )
00022         {
00023                 if(     self->client && self->client->renderInfo.lookTarget == self->enemy->s.number )
00024                 {
00025                         NPC_ClearLookTarget( self );
00026                 }
00027 
00028                 if ( self->NPC && self->enemy == self->NPC->goalEntity )
00029                 {
00030                         self->NPC->goalEntity = NULL;
00031                 }
00032                 //FIXME: set last enemy?
00033         }
00034 
00035         self->enemy = NULL;
00036 }

void G_MaintainFormations gentity_t self  ) 
 

void G_StartFlee gentity_t self,
gentity_t enemy,
vec3_t  dangerPoint,
int  dangerLevel,
int  fleeTimeMin,
int  fleeTimeMax
 

Definition at line 1636 of file NPC_behavior.c.

References gentity_t, gentity_s::NPC, NPC_StartFlee(), RestoreNPCGlobals(), SaveNPCGlobals(), SetNPCGlobals(), and vec3_t.

Referenced by ST_StartFlee().

01637 {
01638         if ( !self->NPC )
01639         {//player
01640                 return;
01641         }
01642         SaveNPCGlobals();
01643         SetNPCGlobals( self );
01644 
01645         NPC_StartFlee( enemy, dangerPoint, dangerLevel, fleeTimeMin, fleeTimeMax );
01646 
01647         RestoreNPCGlobals();
01648 }

qboolean HaveWeapon int  weapon  ) 
 

Definition at line 1109 of file NPC_combat.c.

References client, gclient_s::ps, qboolean, STAT_WEAPONS, and playerState_s::stats.

01110 {
01111         return ( client->ps.stats[STAT_WEAPONS] & ( 1 << weapon ) );
01112 }

float IdealDistance gentity_t self  ) 
 

Definition at line 2475 of file NPC_combat.c.

References gNPCstats_e::aggression, gentity_t, NPC, NPCInfo, gentity_s::s, gNPC_t::stats, entityState_s::weapon, WP_BLASTER, WP_BRYAR_PISTOL, WP_ROCKET_LAUNCHER, WP_SABER, and WP_THERMAL.

Referenced by NPC_BSHuntAndKill().

02476 {
02477         float   ideal;
02478 
02479         ideal = 225 - 20 * NPCInfo->stats.aggression;
02480         switch ( NPC->s.weapon ) 
02481         {
02482         case WP_ROCKET_LAUNCHER:
02483                 ideal += 200;
02484                 break;
02485 
02486         case WP_THERMAL:
02487                 ideal += 50;
02488                 break;
02489 
02490 /*      case WP_TRICORDER:
02491                 ideal = 0;
02492                 break;
02493 */
02494         case WP_SABER:
02495         case WP_BRYAR_PISTOL:
02496 //      case WP_BLASTER_PISTOL:
02497         case WP_BLASTER:
02498         default:
02499                 break;
02500         }
02501 
02502         return ideal;
02503 }

qboolean InFOV gentity_t ent,
gentity_t from,
int  hFOV,
int  vFOV
 

Definition at line 149 of file NPC_senses.c.

References AngleDelta(), entityState_s::angles, CalcEntitySpot(), gentity_s::client, renderInfo_s::eyeAngles, fabs(), gentity_t, PITCH, gclient_s::ps, qboolean, qfalse, qtrue, gclient_s::renderInfo, gentity_s::s, SPOT_HEAD, SPOT_HEAD_LEAN, SPOT_LEGS, SPOT_ORIGIN, vec3_origin, vec3_t, vectoangles(), VectorCopy, VectorSubtract, playerState_s::viewangles, and YAW.

Referenced by G_AlertTeam(), Jedi_CheckAmbushPlayer(), NPC_CheckEnemyStealth(), NPC_CheckSurrender(), NPC_CheckVisibility(), NPC_ShySpawn(), NPC_SomeoneLookingAtMe(), and NPC_TargetVisible().

00150 {
00151         vec3_t  eyes;
00152         vec3_t  spot;
00153         vec3_t  deltaVector;
00154         vec3_t  angles, fromAngles;
00155         vec3_t  deltaAngles;
00156 
00157         if( from->client )
00158         {
00159                 if( !VectorCompare( from->client->renderInfo.eyeAngles, vec3_origin ) )
00160                 {//Actual facing of tag_head!
00161                         //NOTE: Stasis aliens may have a problem with this?
00162                         VectorCopy( from->client->renderInfo.eyeAngles, fromAngles );
00163                 }
00164                 else
00165                 {
00166                         VectorCopy( from->client->ps.viewangles, fromAngles );
00167                 }
00168         }
00169         else
00170         {
00171                 VectorCopy(from->s.angles, fromAngles);
00172         }
00173 
00174         CalcEntitySpot( from, SPOT_HEAD_LEAN, eyes );
00175 
00176         CalcEntitySpot( ent, SPOT_ORIGIN, spot );
00177         VectorSubtract ( spot, eyes, deltaVector);
00178 
00179         vectoangles ( deltaVector, angles );
00180         deltaAngles[PITCH] = AngleDelta ( fromAngles[PITCH], angles[PITCH] );
00181         deltaAngles[YAW] = AngleDelta ( fromAngles[YAW], angles[YAW] );
00182         if ( fabs ( deltaAngles[PITCH] ) <= vFOV && fabs ( deltaAngles[YAW] ) <= hFOV ) 
00183         {
00184                 return qtrue;
00185         }
00186 
00187         CalcEntitySpot( ent, SPOT_HEAD, spot );
00188         VectorSubtract ( spot, eyes, deltaVector);
00189         vectoangles ( deltaVector, angles );
00190         deltaAngles[PITCH] = AngleDelta ( fromAngles[PITCH], angles[PITCH] );
00191         deltaAngles[YAW] = AngleDelta ( fromAngles[YAW], angles[YAW] );
00192         if ( fabs ( deltaAngles[PITCH] ) <= vFOV && fabs ( deltaAngles[YAW] ) <= hFOV ) 
00193         {
00194                 return qtrue;
00195         }
00196 
00197         CalcEntitySpot( ent, SPOT_LEGS, spot );
00198         VectorSubtract ( spot, eyes, deltaVector);
00199         vectoangles ( deltaVector, angles );
00200         deltaAngles[PITCH] = AngleDelta ( fromAngles[PITCH], angles[PITCH] );
00201         deltaAngles[YAW] = AngleDelta ( fromAngles[YAW], angles[YAW] );
00202         if ( fabs ( deltaAngles[PITCH] ) <= vFOV && fabs ( deltaAngles[YAW] ) <= hFOV ) 
00203         {
00204                 return qtrue;
00205         }
00206 
00207         return qfalse;
00208 }

qboolean InFOV2 vec3_t  origin,
gentity_t from,
int  hFOV,
int  vFOV
 

Definition at line 129 of file NPC_senses.c.

References entityState_s::angles, CalcEntitySpot(), gentity_s::client, gentity_t, InFOV3(), gclient_s::ps, qboolean, gentity_s::s, SPOT_HEAD, vec3_t, VectorCopy, and playerState_s::viewangles.

00130 {
00131         vec3_t  fromAngles, eyes;
00132 
00133         if( from->client )
00134         {
00135                 VectorCopy(from->client->ps.viewangles, fromAngles);
00136         }
00137         else
00138         {
00139                 VectorCopy(from->s.angles, fromAngles);
00140         }
00141 
00142         CalcEntitySpot( from, SPOT_HEAD, eyes );
00143 
00144         return InFOV3( origin, eyes, fromAngles, hFOV, vFOV );
00145 }

qboolean InFOV3 vec3_t  spot,
vec3_t  from,
vec3_t  fromAngles,
int  hFOV,
int  vFOV
 

Definition at line 109 of file NPC_senses.c.

00110 {
00111         vec3_t  deltaVector, angles, deltaAngles;
00112 
00113         VectorSubtract ( spot, from, deltaVector );
00114         vectoangles ( deltaVector, angles );
00115         
00116         deltaAngles[PITCH]      = AngleDelta ( fromAngles[PITCH], angles[PITCH] );
00117         deltaAngles[YAW]        = AngleDelta ( fromAngles[YAW], angles[YAW] );
00118 
00119         if ( fabs ( deltaAngles[PITCH] ) <= vFOV && fabs ( deltaAngles[YAW] ) <= hFOV ) 
00120         {
00121                 return qtrue;
00122         }
00123 
00124         return qfalse;
00125 }

qboolean InVisrange gentity_t ent  ) 
 

Definition at line 210 of file NPC_senses.c.

References CalcEntitySpot(), gentity_t, NPC, NPCInfo, qboolean, qfalse, qtrue, SPOT_HEAD_LEAN, SPOT_ORIGIN, gNPC_t::stats, vec3_t, VectorSubtract, and gNPCstats_e::visrange.

Referenced by NPC_CheckVisibility(), and NPC_PickEnemy().

00211 {//FIXME: make a calculate visibility for ents that takes into account
00212         //lighting, movement, turning, crouch/stand up, other anims, hide brushes, etc.
00213         vec3_t  eyes;
00214         vec3_t  spot;
00215         vec3_t  deltaVector;
00216         float   visrange = (NPCInfo->stats.visrange*NPCInfo->stats.visrange);
00217 
00218         CalcEntitySpot( NPC, SPOT_HEAD_LEAN, eyes );
00219 
00220         CalcEntitySpot( ent, SPOT_ORIGIN, spot );
00221         VectorSubtract ( spot, eyes, deltaVector);
00222 
00223         /*if(ent->client)
00224         {
00225                 float   vel, avel;
00226                 if(ent->client->ps.velocity[0] || ent->client->ps.velocity[1] || ent->client->ps.velocity[2])
00227                 {
00228                         vel = VectorLength(ent->client->ps.velocity);
00229                         if(vel > 128)
00230                         {
00231                                 visrange += visrange * (vel/256);
00232                         }
00233                 }
00234 
00235                 if(ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2])
00236                 {//FIXME: shouldn't they need to have line of sight to you to detect this?
00237                         avel = VectorLength(ent->avelocity);
00238                         if(avel > 15)
00239                         {
00240                                 visrange += visrange * (avel/60);
00241                         }
00242                 }
00243         }*/
00244 
00245         if(VectorLengthSquared(deltaVector) > visrange)
00246         {
00247                 return qfalse;
00248         }
00249 
00250         return qtrue;
00251 }

qboolean NAV_AvoidCollision gentity_t self,
gentity_t goal,
navInfo_t info
 

Definition at line 902 of file g_nav.c.

References gNPC_t::aiFlags, navInfo_s::blocker, CONTENTS_BODY, entityShared_t::currentOrigin, navInfo_s::direction, navInfo_s::distance, EDGE_PATH, trace_t::entityNum, navInfo_s::flags, G_DrawEdge(), g_entities, gentity_t, MAX_COLL_AVOID_DIST, NAV_CheckAhead(), NAV_ClearBlockedInfo(), NAV_ResolveEntityCollision(), NAV_TestForBlocked(), NAVDEBUG_showCollision, navInfo_t, NIF_BLOCKED, NIF_COLLISION, NPC, gentity_s::NPC, NPCAI_NO_COLL_AVOID, navInfo_s::pathDirection, qboolean, qfalse, qtrue, gentity_s::r, navInfo_s::trace, vec3_t, VectorCopy, and VectorMA.

Referenced by NPC_GetMoveDirection().

00903 {
00904         vec3_t  movedir;
00905         vec3_t  movepos;
00906 
00907         //Clear our block info for this frame
00908         NAV_ClearBlockedInfo( NPC );
00909 
00910         //Cap our distance
00911         if ( info->distance > MAX_COLL_AVOID_DIST )
00912         {
00913                 info->distance = MAX_COLL_AVOID_DIST;
00914         }
00915 
00916         //Get an end position
00917         VectorMA( self->r.currentOrigin, info->distance, info->direction, movepos );
00918         VectorCopy( info->direction, movedir );
00919 
00920         if ( self && self->NPC && (self->NPC->aiFlags&NPCAI_NO_COLL_AVOID) )
00921         {//pretend there's no-one in the way
00922                 return qtrue;
00923         }
00924         //Now test against entities
00925         if ( NAV_CheckAhead( self, movepos, &info->trace, CONTENTS_BODY ) == qfalse )
00926         {
00927                 //Get the blocker
00928                 info->blocker = &g_entities[ info->trace.entityNum ];
00929                 info->flags |= NIF_COLLISION;
00930 
00931                 //Ok to hit our goal entity
00932                 if ( goal == info->blocker )
00933                         return qtrue;
00934 
00935                 //See if we're moving along with them
00936                 //if ( NAV_TrueCollision( self, info.blocker, movedir, info.direction ) == qfalse )
00937                 //      return qtrue;
00938 
00939                 //Test for blocking by standing on goal
00940                 if ( NAV_TestForBlocked( self, goal, info->blocker, info->distance, &info->flags ) == qtrue )
00941                         return qfalse;
00942 
00943                 //If the above function said we're blocked, don't do the extra checks
00944                 if ( info->flags & NIF_BLOCKED )
00945                         return qtrue;
00946 
00947                 //See if we can get that entity to move out of our way
00948                 if ( NAV_ResolveEntityCollision( self, info->blocker, movedir, info->pathDirection ) == qfalse )
00949                         return qfalse;
00950 
00951                 VectorCopy( movedir, info->direction );
00952                 
00953                 return qtrue;
00954         }
00955 
00956         //Our path is clear, just move there
00957         if ( NAVDEBUG_showCollision )
00958         {
00959                 G_DrawEdge( self->r.currentOrigin, movepos, EDGE_PATH );
00960         }
00961 
00962         return qtrue;
00963 }

qboolean NAV_CheckAhead gentity_t self,
vec3_t  end,
trace_t trace,
int  clipmask
 

Definition at line 494 of file g_nav.c.

References trace_t::allsolid, gentity_s::classname, trace_t::contents, CONTENTS_BOTCLIP, entityShared_t::currentOrigin, trace_t::endpos, trace_t::entityNum, ENTITYNUM_WORLD, fabs(), trace_t::fraction, G_EntIsUnlockedDoor(), g_entities, gentity_t, entityShared_t::maxs, MIN_DOOR_BLOCK_DIST_SQR, entityShared_t::mins, entityState_s::number, qboolean, qfalse, qtrue, gentity_s::r, gentity_s::s, trace_t::startsolid, STEPSIZE, trap_Trace(), VALIDSTRING, vec3_t, and VectorSet.

00495 {
00496         vec3_t  mins;
00497         float   radius;
00498         float   dist;
00499         float   tFrac;
00500 
00501         //Offset the step height
00502         VectorSet( mins, self->r.mins[0], self->r.mins[1], self->r.mins[2] + STEPSIZE );
00503         
00504         trap_Trace( trace, self->r.currentOrigin, mins, self->r.maxs, end, self->s.number, clipmask );
00505 
00506         if ( trace->startsolid&&(trace->contents&CONTENTS_BOTCLIP) )
00507         {//started inside do not enter, so ignore them
00508                 clipmask &= ~CONTENTS_BOTCLIP;
00509                 trap_Trace( trace, self->r.currentOrigin, mins, self->r.maxs, end, self->s.number, clipmask );
00510         }
00511         //Do a simple check
00512         if ( ( trace->allsolid == qfalse ) && ( trace->startsolid == qfalse ) && ( trace->fraction == 1.0f ) )
00513                 return qtrue;
00514 
00515         //See if we're too far above
00516         if ( fabs( self->r.currentOrigin[2] - end[2] ) > 48 )
00517                 return qfalse;
00518 
00519         //This is a work around
00520         radius = ( self->r.maxs[0] > self->r.maxs[1] ) ? self->r.maxs[0] : self->r.maxs[1];
00521         dist = Distance( self->r.currentOrigin, end );
00522         tFrac = 1.0f - ( radius / dist );
00523 
00524         if ( trace->fraction >= tFrac )
00525                 return qtrue;
00526 
00527         //Do a special check for doors
00528         if ( trace->entityNum < ENTITYNUM_WORLD )
00529         {
00530                 gentity_t       *blocker = &g_entities[trace->entityNum];
00531                 
00532                 if VALIDSTRING( blocker->classname )
00533                 {
00534                         if ( G_EntIsUnlockedDoor( blocker->s.number ) )
00535                         //if ( Q_stricmp( blocker->classname, "func_door" ) == 0 )
00536                         {
00537                                 //We're too close, try and avoid the door (most likely stuck on a lip)
00538                                 if ( DistanceSquared( self->r.currentOrigin, trace->endpos ) < MIN_DOOR_BLOCK_DIST_SQR )
00539                                         return qfalse;
00540 
00541                                 return qtrue;
00542                         }
00543                 }
00544         }
00545 
00546         return qfalse;
00547 }

qboolean NAV_ClearPathToPoint gentity_t self,
vec3_t  pmins,
vec3_t  pmaxs,
vec3_t  point,
int  clipmask,
int  okToHitEnt
 

Definition at line 222 of file g_nav.c.

00223 {
00224 //      trace_t trace;
00225 //      return NAV_CheckAhead( self, point, trace, clipmask|CONTENTS_BOTCLIP );
00226 
00227         vec3_t  mins, maxs;
00228         trace_t trace;
00229 
00230         //Test if they're even conceivably close to one another
00231         if ( !trap_InPVS( self->r.currentOrigin, point ) )
00232                 return qfalse;
00233 
00234         if ( self->flags & FL_NAVGOAL )
00235         {
00236                 if ( !self->parent )
00237                 {
00238                         //SHOULD NEVER HAPPEN!!!
00239                         assert(self->parent);
00240                         return qfalse;
00241                 }
00242                 VectorCopy( self->parent->r.mins, mins );
00243                 VectorCopy( self->parent->r.maxs, maxs );
00244         }
00245         else
00246         {
00247                 VectorCopy( pmins, mins );
00248                 VectorCopy( pmaxs, maxs );
00249         }
00250         
00251         if ( self->client || ( self->flags & FL_NAVGOAL ) )
00252         {
00253                 //Clients can step up things, or if this is a navgoal check, a client will be using this info
00254                 mins[2] += STEPSIZE;
00255 
00256                 //don't let box get inverted
00257                 if ( mins[2] > maxs[2] )
00258                 {       
00259                         mins[2] = maxs[2];
00260                 }
00261         }
00262 
00263         if ( self->flags & FL_NAVGOAL )
00264         {
00265                 //Trace from point to navgoal
00266                 trap_Trace( &trace, point, mins, maxs, self->r.currentOrigin, self->parent->s.number, (clipmask|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP)&~CONTENTS_BODY );
00267                 if ( trace.startsolid&&(trace.contents&CONTENTS_BOTCLIP) )
00268                 {//started inside do not enter, so ignore them
00269                         clipmask &= ~CONTENTS_BOTCLIP;
00270                         trap_Trace( &trace, point, mins, maxs, self->r.currentOrigin, self->parent->s.number, (clipmask|CONTENTS_MONSTERCLIP)&~CONTENTS_BODY );
00271                 }
00272                 
00273                 if ( trace.startsolid || trace.allsolid )
00274                 {
00275                         return qfalse;
00276                 }
00277                 
00278                 //Made it
00279                 if ( trace.fraction == 1.0 )
00280                 {
00281                         return qtrue;
00282                 }
00283                 
00284                 if ( okToHitEntNum != ENTITYNUM_NONE && trace.entityNum == okToHitEntNum )
00285                 {
00286                         return qtrue;
00287                 }
00288 
00289                 //Okay, didn't get all the way there, let's see if we got close enough:
00290                 if ( NAV_HitNavGoal( self->r.currentOrigin, self->parent->r.mins, self->parent->r.maxs, trace.endpos, NPCInfo->goalRadius, FlyingCreature( self->parent ) ) )
00291                 {
00292                         return qtrue;
00293                 }
00294                 else
00295                 {
00296                         if ( NAVDEBUG_showCollision )
00297                         {
00298                                 if ( trace.entityNum < ENTITYNUM_WORLD && (&g_entities[trace.entityNum] != NULL) && g_entities[trace.entityNum].s.eType != ET_MOVER )
00299                                 {
00300                                         vec3_t  p1, p2;
00301                                         G_DrawEdge( point, trace.endpos, EDGE_PATH );
00302                                         VectorAdd(g_entities[trace.entityNum].r.mins, g_entities[trace.entityNum].r.currentOrigin, p1);
00303                                         VectorAdd(g_entities[trace.entityNum].r.maxs, g_entities[trace.entityNum].r.currentOrigin, p2);
00304                                         G_CubeOutline( p1, p2, FRAMETIME, 0x0000ff, 0.5 );
00305                                 }
00306                                 //FIXME: if it is a bmodel, light up the surf?
00307                         }
00308                 }
00309         }
00310         else
00311         {
00312                 trap_Trace( &trace, self->r.currentOrigin, mins, maxs, point, self->s.number, clipmask|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP);
00313                 if ( trace.startsolid&&(trace.contents&CONTENTS_BOTCLIP) )
00314                 {//started inside do not enter, so ignore them
00315                         clipmask &= ~CONTENTS_BOTCLIP;
00316                         trap_Trace( &trace, self->r.currentOrigin, mins, maxs, point, self->s.number, clipmask|CONTENTS_MONSTERCLIP);
00317                 }
00318 
00319                 if( ( ( trace.startsolid == qfalse ) && ( trace.allsolid == qfalse ) ) && ( trace.fraction == 1.0f ) )
00320                 {//FIXME: check for drops
00321                         return qtrue;
00322                 }
00323 
00324                 if ( okToHitEntNum != ENTITYNUM_NONE && trace.entityNum == okToHitEntNum )
00325                 {
00326                         return qtrue;
00327                 }
00328 
00329                 if ( NAVDEBUG_showCollision )
00330                 {
00331                         if ( trace.entityNum < ENTITYNUM_WORLD && (&g_entities[trace.entityNum] != NULL) && g_entities[trace.entityNum].s.eType != ET_MOVER )
00332                         {
00333                                 vec3_t  p1, p2;
00334                                 G_DrawEdge( self->r.currentOrigin, trace.endpos, EDGE_PATH );
00335                                 VectorAdd(g_entities[trace.entityNum].r.mins, g_entities[trace.entityNum].r.currentOrigin, p1);
00336                                 VectorAdd(g_entities[trace.entityNum].r.maxs, g_entities[trace.entityNum].r.currentOrigin, p2);
00337                                 G_CubeOutline( p1, p2, FRAMETIME, 0x0000ff, 0.5 );
00338                         }
00339                         //FIXME: if it is a bmodel, light up the surf?
00340                 }
00341         }
00342 
00343         return qfalse;
00344 }

int NAV_FindClosestWaypointForEnt gentity_t ent,
int  targWp
 

Definition at line 352 of file g_nav.c.

References gentity_t, NF_CLEAR_PATH, trap_Nav_GetNearestNode(), and gentity_s::waypoint.

Referenced by AI_SortGroupByPathCostToEnemy(), NPC_BSSearch(), NPC_BSSearchStart(), NPC_BSWander(), and ST_Commander().

00353 {
00354         //FIXME: Take the target into account
00355         return trap_Nav_GetNearestNode( ent, ent->waypoint, NF_CLEAR_PATH, targWp );
00356 }

void NAV_GetLastMove navInfo_t info  ) 
 

Definition at line 149 of file NPC_move.c.

References frameNavInfo, and navInfo_t.

Referenced by AI_CheckEnemyCollision().

00150 {
00151         *info = frameNavInfo;
00152 }

qboolean NAV_HitNavGoal vec3_t  point,
vec3_t  mins,
vec3_t  maxs,
vec3_t  dest,
int  radius,
qboolean  flying
 

Definition at line 167 of file g_nav.c.

References fabs(), G_BoundsOverlap(), NAVGOAL_USE_RADIUS, qboolean, vec3_t, VectorAdd, VectorSet, and VectorSubtract.

Referenced by NAV_ClearPathToPoint(), NAV_TestForBlocked(), NPC_BSST_Investigate(), NPC_ClearPathToGoal(), and ReachedGoal().

00168 {
00169         vec3_t  dmins, dmaxs, pmins, pmaxs;
00170 
00171         if ( radius & NAVGOAL_USE_RADIUS )
00172         {
00173                 radius &= ~NAVGOAL_USE_RADIUS;
00174                 //NOTE:  This needs to do a DistanceSquared on navgoals that had
00175                 //                      a radius manually set! We can't do the smaller navgoals against
00176                 //                      walls to get around this because player-sized traces to them
00177                 //                      from angles will not work... - MCG
00178                 if ( !flying )
00179                 {//Allow for a little z difference
00180                         vec3_t  diff;
00181                         VectorSubtract( point, dest, diff );
00182                         if ( fabs(diff[2]) <= 24 )
00183                         {
00184                                 diff[2] = 0;
00185                         }
00186                         return ( VectorLengthSquared( diff ) <= (radius*radius) );
00187                 }
00188                 else
00189                 {//must hit exactly
00190                         return ( DistanceSquared(dest, point) <= (radius*radius) );
00191                 }
00192                 //There is probably a better way to do this, either by preserving the original
00193                 //              mins and maxs of the navgoal and doing this check ONLY if the radius 
00194                 //              is non-zero (like the original implementation) or some boolean to
00195                 //              tell us to do this check rather than the fake bbox overlap check...
00196         }
00197         else
00198         {
00199                 //Construct a dummy bounding box from our radius value
00200                 VectorSet( dmins, -radius, -radius, -radius );
00201                 VectorSet( dmaxs,  radius,  radius,  radius );
00202 
00203                 //Translate it
00204                 VectorAdd( dmins, dest, dmins );
00205                 VectorAdd( dmaxs, dest, dmaxs );
00206 
00207                 //Translate the starting box
00208                 VectorAdd( point, mins, pmins );
00209                 VectorAdd( point, maxs, pmaxs );
00210 
00211                 //See if they overlap
00212                 return G_BoundsOverlap( pmins, pmaxs, dmins, dmaxs );
00213         }
00214 }

int NAV_MoveToGoal gentity_t self,
navInfo_t info
 

Definition at line 1113 of file g_nav.c.

References gentity_s::clipmask, CONTENTS_BODY, CONTENTS_BOTCLIP, entityShared_t::currentOrigin, navInfo_s::direction, navInfo_s::distance, G_DrawNode(), G_FindClosestPointOnLineSegment(), gentity_t, gNPC_t::goalEntity, gentity_s::lastWaypoint, NAV_CheckAhead(), NAV_GetNearestNode(), NAV_TestBestNode(), NAVDEBUG_showEnemyPath, navInfo_t, NODE_GOAL, NODE_NONE, NODE_START, gentity_s::NPC, NULL, entityState_s::number, navInfo_s::pathDirection, qfalse, gentity_s::r, gentity_s::s, navInfo_s::trace, trap_Nav_GetBestNode(), trap_Nav_GetNodePosition(), trap_Nav_ShowPath(), vec3_t, VectorNormalize(), VectorSubtract, gentity_s::waypoint, and WAYPOINT_NONE.

Referenced by NPC_GetMoveDirection().

01114 {
01115         int bestNode;
01116         vec3_t  origin, end;
01117 
01118         //Must have a goal entity to move there
01119         if( self->NPC->goalEntity == NULL )
01120                 return WAYPOINT_NONE;
01121 
01122         //Check special player optimizations
01123         if ( self->NPC->goalEntity->s.number == 0 )
01124         {
01125                 //If we couldn't find the point, then we won't be able to this turn
01126                 if ( self->NPC->goalEntity->waypoint == WAYPOINT_NONE )
01127                         return WAYPOINT_NONE;
01128 
01129                 //NOTENOTE: Otherwise trust this waypoint for the whole frame (reduce all unnecessary calculations)
01130         }
01131         else
01132         {
01133                 //Find the target's waypoint
01134                 if ( ( self->NPC->goalEntity->waypoint = NAV_GetNearestNode( self->NPC->goalEntity, self->NPC->goalEntity->waypoint ) ) == WAYPOINT_NONE )
01135                         return WAYPOINT_NONE;
01136         }
01137 
01138         //Find our waypoint
01139         if ( ( self->waypoint = NAV_GetNearestNode( self, self->lastWaypoint ) ) == WAYPOINT_NONE )
01140                 return WAYPOINT_NONE;
01141 
01142         bestNode = trap_Nav_GetBestNode( self->waypoint, self->NPC->goalEntity->waypoint, NODE_NONE );
01143 
01144         if ( bestNode == WAYPOINT_NONE )
01145         {
01146                 if ( NAVDEBUG_showEnemyPath )
01147                 {
01148                         vec3_t  origin, torigin;
01149 
01150                         trap_Nav_GetNodePosition( self->NPC->goalEntity->waypoint, torigin );
01151                         trap_Nav_GetNodePosition( self->waypoint, origin );
01152 
01153                         G_DrawNode( torigin, NODE_GOAL );
01154                         G_DrawNode( origin, NODE_GOAL );
01155                         G_DrawNode( self->NPC->goalEntity->r.currentOrigin, NODE_START );
01156                 }
01157                 
01158                 return WAYPOINT_NONE;
01159         }
01160 
01161         //Check this node
01162         bestNode = NAV_TestBestNode( self, bestNode, self->NPC->goalEntity->waypoint, qfalse );
01163 
01164         //trace_t       trace;
01165 
01166         //Get this position
01167         trap_Nav_GetNodePosition( bestNode, origin );
01168         trap_Nav_GetNodePosition( self->waypoint, end );
01169 
01170         //Basically, see if the path we have isn't helping
01171         //if ( NAV_MicroError( origin, end ) )
01172         //      return WAYPOINT_NONE;
01173 
01174         //Test the path connection from our current position to the best node
01175         if ( NAV_CheckAhead( self, origin, &info->trace, (self->clipmask&~CONTENTS_BODY)|CONTENTS_BOTCLIP ) == qfalse )
01176         {
01177                 //First attempt to move to the closest point on the line between the waypoints
01178                 G_FindClosestPointOnLineSegment( origin, end, self->r.currentOrigin, origin );
01179 
01180                 //See if we can go there
01181                 if ( NAV_CheckAhead( self, origin, &info->trace, (self->clipmask&~CONTENTS_BODY)|CONTENTS_BOTCLIP ) == qfalse )
01182                 {
01183                         //Just move towards our current waypoint
01184                         bestNode = self->waypoint;
01185                         trap_Nav_GetNodePosition( bestNode, origin );
01186                 }
01187         }
01188 
01189         //Setup our new move information
01190         VectorSubtract( origin, self->r.currentOrigin, info->direction );
01191         info->distance = VectorNormalize( info->direction );
01192 
01193         VectorSubtract( end, origin, info->pathDirection );
01194         VectorNormalize( info->pathDirection );
01195 
01196         //Draw any debug info, if requested
01197         if ( NAVDEBUG_showEnemyPath )
01198         {
01199                 vec3_t  dest, start;
01200 
01201                 //Get the positions
01202                 trap_Nav_GetNodePosition( self->NPC->goalEntity->waypoint, dest );
01203                 trap_Nav_GetNodePosition( bestNode, start );
01204 
01205                 //Draw the route
01206                 G_DrawNode( start, NODE_START );
01207                 G_DrawNode( dest, NODE_GOAL );
01208                 trap_Nav_ShowPath( self->waypoint, self->NPC->goalEntity->waypoint );
01209         }
01210 
01211         return bestNode;
01212 }

void NPC_AimWiggle vec3_t  enemy_org  ) 
 

Definition at line 519 of file NPC_utils.c.

References gNPC_t::aimErrorDebounceTime, gNPC_t::aimOfs, gentity_s::enemy, flrand(), level, entityShared_t::maxs, entityShared_t::mins, NPC, NPCInfo, gentity_s::r, level_locals_t::time, vec3_t, and VectorAdd.

Referenced by NPC_BSFollowLeader(), and NPC_CheckCanAttack().

00520 {
00521         //shoot for somewhere between the head and torso
00522         //NOTE: yes, I know this looks weird, but it works
00523         if ( NPCInfo->aimErrorDebounceTime < level.time )
00524         {
00525                 NPCInfo->aimOfs[0] = 0.3*flrand(NPC->enemy->r.mins[0], NPC->enemy->r.maxs[0]);
00526                 NPCInfo->aimOfs[1] = 0.3*flrand(NPC->enemy->r.mins[1], NPC->enemy->r.maxs[1]);
00527                 if ( NPC->enemy->r.maxs[2] > 0 )
00528                 {
00529                         NPCInfo->aimOfs[2] = NPC->enemy->r.maxs[2]*flrand(0.0f, -1.0f);
00530                 }
00531         }
00532         VectorAdd( enemy_org, NPCInfo->aimOfs, enemy_org );
00533 }

void NPC_ApplyWeaponFireDelay void   ) 
 

Definition at line 878 of file NPC_combat.c.

References gentity_s::attackDebounceTime, client, playerState_s::clientNum, level, NPC, gclient_s::ps, level_locals_t::time, playerState_s::weapon, playerState_s::weaponTime, WP_STUN_BATON, and WP_THERMAL.

Referenced by ShootThink().

00879 {       
00880         if ( NPC->attackDebounceTime > level.time )
00881         {//Just fired, if attacking again, must be a burst fire, so don't add delay
00882                 //NOTE: Borg AI uses attackDebounceTime "incorrectly", so this will always return for them!
00883                 return;
00884         }
00885         
00886         switch(client->ps.weapon)
00887         {
00888                 /*
00889         case WP_BOT_LASER:
00890                 NPCInfo->burstCount = 0;
00891                 client->ps.weaponTime = 500;
00892                 break;
00893                 */ //rwwFIXMEFIXME: support for this
00894 
00895         case WP_THERMAL:
00896                 if ( client->ps.clientNum )
00897                 {//NPCs delay... 
00898                         //FIXME: player should, too, but would feel weird in 1st person, even though it
00899                         //                      would look right in 3rd person.  Really should have a wind-up anim
00900                         //                      for player as he holds down the fire button to throw, then play
00901                         //                      the actual throw when he lets go...
00902                         client->ps.weaponTime = 700;
00903                 }
00904                 break;
00905 
00906         case WP_STUN_BATON:
00907                 //if ( !PM_DroidMelee( client->NPC_class ) )
00908                 if (1) //rwwFIXMEFIXME: ...
00909                 {//FIXME: should be unique per melee anim
00910                         client->ps.weaponTime = 300;
00911                 }
00912                 break;
00913 
00914         default:
00915                 client->ps.weaponTime = 0;
00916                 break;
00917         }
00918 }

int NPC_AttackDebounceForWeapon void   ) 
 

Definition at line 1288 of file NPC_combat.c.

References gNPC_t::burstSpacing, gentity_s::client, NPC, NPCInfo, gclient_s::ps, playerState_s::weapon, and WP_SABER.

Referenced by ShootThink().

01289 {
01290         switch ( NPC->client->ps.weapon ) 
01291         {
01292 /*
01293         case WP_BLASTER://scav rifle
01294                 return 1000;
01295                 break;
01296 
01297         case WP_BRYAR_PISTOL://prifle
01298                 return 3000;
01299                 break;
01300 
01301         case WP_SABER:
01302                 return 100;
01303                 break;
01304         
01305 
01306         case WP_TRICORDER:
01307                 return 0;//tricorder
01308                 break;
01309 */
01310         case WP_SABER:
01311                 return 0;
01312                 break;
01313 
01314                 /*
01315         case WP_BOT_LASER:
01316                 
01317                 if ( g_spskill.integer == 0 )
01318                         return 2000;
01319 
01320                 if ( g_spskill.integer == 1 )
01321                         return 1500;
01322 
01323                 return 1000;
01324                 break;
01325                 */
01326                 //rwwFIXMEFIXME: support
01327         default:
01328                 return NPCInfo->burstSpacing;//was 100 by default
01329                 break;
01330         }
01331 }

void NPC_BSAdvanceFight void   ) 
 

Definition at line 29 of file NPC_behavior.c.

References entityShared_t::absmin, AngleVectors(), CalcEntitySpot(), gNPC_t::captureGoal, CHECK_FOV, gentity_s::client, entityShared_t::currentOrigin, gNPC_t::desiredPitch, trace_t::endpos, gentity_s::enemy, gNPC_t::enemyLastVisibility, gclient_s::enemyTeam, enemyVisibility, trace_t::entityNum, usercmd_s::forwardmove, g_entities, gentity_t, gNPC_t::goalTime, level, MASK_SHOT, entityShared_t::maxs, NPC, gentity_s::NPC, NPC_CheckAttack(), NPC_CheckEnemy(), NPC_CheckVisibility(), NPC_EnemyTooFar(), NPC_SetMoveGoal(), NPC_UpdateShootAngles(), NPCInfo, NULL, entityState_s::number, PITCH, gclient_s::playerTeam, gclient_s::ps, qboolean, qfalse, qtrue, gentity_s::r, random, usercmd_s::rightmove, gentity_s::s, gNPC_t::shootAngles, SPOT_HEAD, SPOT_WEAPON, TID_BSTATE, level_locals_t::time, trap_ICARUS_IsInitialized(), trap_ICARUS_TaskIDComplete(), trap_Trace(), ucmd, vec3_t, vectoangles(), VectorCopy, VectorMA, VectorNormalize(), VectorSubtract, playerState_s::viewangles, VIS_FOV, VIS_SHOOT, and WeaponThink().

Referenced by NPC_BehaviorSet_Default().

00030 {//FIXME: IMPLEMENT
00031 //Head to Goal if I can
00032 
00033         //Make sure we're still headed where we want to capture
00034         if ( NPCInfo->captureGoal )
00035         {//FIXME: if no captureGoal, what do we do?
00036                 //VectorCopy( NPCInfo->captureGoal->r.currentOrigin, NPCInfo->tempGoal->r.currentOrigin );
00037                 //NPCInfo->goalEntity = NPCInfo->tempGoal;
00038 
00039                 NPC_SetMoveGoal( NPC, NPCInfo->captureGoal->r.currentOrigin, 16, qtrue, -1, NULL );
00040 
00041 //              NAV_ClearLastRoute(NPC);
00042                 NPCInfo->goalTime = level.time + 100000;
00043         }
00044 
00045 //      NPC_BSRun();
00046 
00047         NPC_CheckEnemy(qtrue, qfalse, qtrue);
00048 
00049         //FIXME: Need melee code
00050         if( NPC->enemy )
00051         {//See if we can shoot him
00052                 vec3_t          delta, forward;
00053                 vec3_t          angleToEnemy;
00054                 vec3_t          hitspot, muzzle, diff, enemy_org, enemy_head;
00055                 float           distanceToEnemy;
00056                 qboolean        attack_ok = qfalse;
00057                 qboolean        dead_on = qfalse;
00058                 float           attack_scale = 1.0;
00059                 float           aim_off;
00060                 float           max_aim_off = 64;
00061 
00062                 //Yaw to enemy
00063                 VectorMA(NPC->enemy->r.absmin, 0.5, NPC->enemy->r.maxs, enemy_org);
00064                 CalcEntitySpot( NPC, SPOT_WEAPON, muzzle );
00065                 
00066                 VectorSubtract (enemy_org, muzzle, delta);
00067                 vectoangles ( delta, angleToEnemy );
00068                 distanceToEnemy = VectorNormalize(delta);
00069 
00070                 if(!NPC_EnemyTooFar(NPC->enemy, distanceToEnemy*distanceToEnemy, qtrue))
00071                 {
00072                         attack_ok = qtrue;
00073                 }
00074 
00075                 if(attack_ok)
00076                 {
00077                         NPC_UpdateShootAngles(angleToEnemy, qfalse, qtrue);
00078 
00079                         NPCInfo->enemyLastVisibility = enemyVisibility;
00080                         enemyVisibility = NPC_CheckVisibility ( NPC->enemy, CHECK_FOV);//CHECK_360|//CHECK_PVS|
00081 
00082                         if(enemyVisibility == VIS_FOV)
00083                         {//He's in our FOV
00084                                 
00085                                 attack_ok = qtrue;
00086                                 CalcEntitySpot( NPC->enemy, SPOT_HEAD, enemy_head);
00087 
00088                                 if(attack_ok)
00089                                 {
00090                                         trace_t         tr;
00091                                         gentity_t       *traceEnt;
00092                                         //are we gonna hit him if we shoot at his center?
00093                                         trap_Trace ( &tr, muzzle, NULL, NULL, enemy_org, NPC->s.number, MASK_SHOT );
00094                                         traceEnt = &g_entities[tr.entityNum];
00095                                         if( traceEnt != NPC->enemy &&
00096                                                 (!traceEnt || !traceEnt->client || !NPC->client->enemyTeam || NPC->client->enemyTeam != traceEnt->client->playerTeam) )
00097                                         {//no, so shoot for the head
00098                                                 attack_scale *= 0.75;
00099                                                 trap_Trace ( &tr, muzzle, NULL, NULL, enemy_head, NPC->s.number, MASK_SHOT );
00100                                                 traceEnt = &g_entities[tr.entityNum];
00101                                         }
00102 
00103                                         VectorCopy( tr.endpos, hitspot );
00104 
00105                                         if( traceEnt == NPC->enemy || (traceEnt->client && NPC->client->enemyTeam && NPC->client->enemyTeam == traceEnt->client->playerTeam) )
00106                                         {
00107                                                 dead_on = qtrue;
00108                                         }
00109                                         else
00110                                         {
00111                                                 attack_scale *= 0.5;
00112                                                 if(NPC->client->playerTeam)
00113                                                 {
00114                                                         if(traceEnt && traceEnt->client && traceEnt->client->playerTeam)
00115                                                         {
00116                                                                 if(NPC->client->playerTeam == traceEnt->client->playerTeam)
00117                                                                 {//Don't shoot our own team
00118                                                                         attack_ok = qfalse;
00119                                                                 }
00120                                                         }
00121                                                 }
00122                                         }
00123                                 }
00124 
00125                                 if( attack_ok )
00126                                 {
00127                                         //ok, now adjust pitch aim
00128                                         VectorSubtract (hitspot, muzzle, delta);
00129                                         vectoangles ( delta, angleToEnemy );
00130                                         NPC->NPC->desiredPitch = angleToEnemy[PITCH];
00131                                         NPC_UpdateShootAngles(angleToEnemy, qtrue, qfalse);
00132 
00133                                         if( !dead_on )
00134                                         {//We're not going to hit him directly, try a suppressing fire
00135                                                 //see if where we're going to shoot is too far from his origin
00136                                                 AngleVectors (NPCInfo->shootAngles, forward, NULL, NULL);
00137                                                 VectorMA ( muzzle, distanceToEnemy, forward, hitspot);
00138                                                 VectorSubtract(hitspot, enemy_org, diff);
00139                                                 aim_off = VectorLength(diff);
00140                                                 if(aim_off > random() * max_aim_off)//FIXME: use aim value to allow poor aim?
00141                                                 {
00142                                                         attack_scale *= 0.75;
00143                                                         //see if where we're going to shoot is too far from his head
00144                                                         VectorSubtract(hitspot, enemy_head, diff);
00145                                                         aim_off = VectorLength(diff);
00146                                                         if(aim_off > random() * max_aim_off)
00147                                                         {
00148                                                                 attack_ok = qfalse;
00149                                                         }
00150                                                 }
00151                                                 attack_scale *= (max_aim_off - aim_off + 1)/max_aim_off;
00152                                         }
00153                                 }
00154                         }
00155                 }
00156 
00157                 if( attack_ok )
00158                 {
00159                         if( NPC_CheckAttack( attack_scale ))
00160                         {//check aggression to decide if we should shoot
00161                                 enemyVisibility = VIS_SHOOT;
00162                                 WeaponThink(qtrue);
00163                         }
00164                         else
00165                                 attack_ok = qfalse;
00166                 }
00167 //Don't do this- only for when stationary and trying to shoot an enemy
00168 //              else
00169 //                      NPC->cantHitEnemyCounter++;
00170         }
00171         else
00172         {//FIXME: 
00173                 NPC_UpdateShootAngles(NPC->client->ps.viewangles, qtrue, qtrue);
00174         }
00175 
00176         if(!ucmd.forwardmove && !ucmd.rightmove)
00177         {//We reached our captureGoal
00178                 if(trap_ICARUS_IsInitialized(NPC->s.number))
00179                 {
00180                         trap_ICARUS_TaskIDComplete( NPC, TID_BSTATE );
00181                 }
00182         }
00183 }

void NPC_BSDefault void   ) 
 

Definition at line 712 of file NPC_AI_Default.c.

References AEL_DISCOVERED, level_locals_t::alertEvents, BUTTON_WALKING, usercmd_s::buttons, gentity_s::client, gNPC_t::combatMove, entityShared_t::currentOrigin, gNPC_t::desiredPitch, gNPC_t::desiredYaw, gentity_s::enemy, gclient_s::enemyTeam, G_SetEnemy(), gNPC_t::goalEntity, gentity_s::health, alertEvent_s::ID, gNPC_t::lastAlertID, gclient_s::leader, level, alertEvent_s::level, NPC, NPC_BSFollowLeader(), NPC_BSST_Attack(), NPC_CheckAlertEvents(), NPC_CheckEnemy(), NPC_CheckGetNewWeapon(), NPC_ClearGoal(), NPC_MoveToGoal(), NPC_SetAnim(), NPC_SomeoneLookingAtMe(), NPC_UpdateAngles(), NPCInfo, alertEvent_s::owner, PITCH, gclient_s::playerTeam, gclient_s::ps, qboolean, qfalse, qtrue, gentity_s::r, SCF_FACE_MOVE_DIR, SCF_FIRE_WEAPON, SCF_FORCED_MARCH, SCF_IGNORE_ALERTS, SCF_LOOK_FOR_ENEMIES, SCF_RUNNING, SCF_WALKING, gNPC_t::scriptFlags, SETANIM_FLAG_HOLD, SETANIM_TORSO, TID_MOVE_NAV, TORSO_SURRENDER_START, playerState_s::torsoAnim, trap_ICARUS_TaskIDPending(), ucmd, UpdateGoal(), vec3_t, vectoangles(), VectorSubtract, WeaponThink(), and YAW.

Referenced by NPC_BehaviorSet_Charmed(), NPC_BehaviorSet_Default(), and NPC_RunBehavior().

00713 {
00714 //      vec3_t          enemyDir;
00715 //      float           enemyDist;
00716 //      float           shootDist;
00717 //      qboolean        enemyFOV = qfalse;
00718 //      qboolean        enemyShotFOV = qfalse;
00719 //      qboolean        enemyPVS = qfalse;
00720 //      vec3_t          enemyHead;
00721 //      vec3_t          muzzle;
00722 //      qboolean        enemyLOS = qfalse;
00723 //      qboolean        enemyCS = qfalse;
00724         qboolean        move = qtrue;
00725 //      qboolean        shoot = qfalse;
00726 
00727         
00728         if( NPCInfo->scriptFlags & SCF_FIRE_WEAPON )
00729         {
00730                 WeaponThink( qtrue );
00731         }
00732 
00733         if ( NPCInfo->scriptFlags & SCF_FORCED_MARCH )
00734         {//being forced to walk
00735                 if( NPC->client->ps.torsoAnim != TORSO_SURRENDER_START )
00736                 {
00737                         NPC_SetAnim( NPC, SETANIM_TORSO, TORSO_SURRENDER_START, SETANIM_FLAG_HOLD );
00738                 }
00739         }
00740         //look for a new enemy if don't have one and are allowed to look, validate current enemy if have one
00741         NPC_CheckEnemy( (NPCInfo->scriptFlags&SCF_LOOK_FOR_ENEMIES), qfalse, qtrue );
00742         if ( !NPC->enemy )
00743         {//still don't have an enemy
00744                 if ( !(NPCInfo->scriptFlags&SCF_IGNORE_ALERTS) )
00745                 {//check for alert events
00746                         //FIXME: Check Alert events, see if we should investigate or just look at it
00747                         int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, -1, qtrue, AEL_DISCOVERED );
00748 
00749                         //There is an event to look at
00750                         if ( alertEvent >= 0 && level.alertEvents[alertEvent].ID != NPCInfo->lastAlertID )
00751                         {//heard/saw something
00752                                 if ( level.alertEvents[alertEvent].level >= AEL_DISCOVERED && (NPCInfo->scriptFlags&SCF_LOOK_FOR_ENEMIES) )
00753                                 {//was a big event
00754                                         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 )
00755                                         {//an enemy
00756                                                 G_SetEnemy( NPC, level.alertEvents[alertEvent].owner );
00757                                         }
00758                                 }
00759                                 else
00760                                 {//FIXME: investigate lesser events
00761                                 }
00762                         }
00763                         //FIXME: also check our allies' condition?
00764                 }
00765         }
00766 
00767         if ( NPC->enemy && !(NPCInfo->scriptFlags&SCF_FORCED_MARCH) )
00768         {
00769                 // just use the stormtrooper attack AI...
00770                 NPC_CheckGetNewWeapon();
00771                 if ( NPC->client->leader 
00772                         && NPCInfo->goalEntity == NPC->client->leader 
00773                         && !trap_ICARUS_TaskIDPending( NPC, TID_MOVE_NAV ) )
00774                 {
00775                         NPC_ClearGoal();
00776                 }
00777                         NPC_BSST_Attack();
00778                 return;
00779 /*
00780                 //have an enemy
00781                 //FIXME: if one of these fails, meaning we can't shoot, do we really need to do the rest?
00782                 VectorSubtract( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, enemyDir );
00783                 enemyDist = VectorNormalize( enemyDir );
00784                 enemyDist *= enemyDist;
00785                 shootDist = NPC_MaxDistSquaredForWeapon();
00786 
00787                 enemyFOV = InFOV( NPC->enemy, NPC, NPCInfo->stats.hfov, NPCInfo->stats.vfov );
00788                 enemyShotFOV = InFOV( NPC->enemy, NPC, 20, 20 );
00789                 enemyPVS = gi.inPVS( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin );
00790 
00791                 if ( enemyPVS )
00792                 {//in the pvs
00793                         trace_t tr;
00794 
00795                         CalcEntitySpot( NPC->enemy, SPOT_HEAD, enemyHead );
00796                         enemyHead[2] -= Q_flrand( 0.0f, NPC->enemy->maxs[2]*0.5f );
00797                         CalcEntitySpot( NPC, SPOT_WEAPON, muzzle );
00798                         enemyLOS = NPC_ClearLOS( muzzle, enemyHead );
00799 
00800                         gi.trace ( &tr, muzzle, vec3_origin, vec3_origin, enemyHead, NPC->s.number, MASK_SHOT );
00801                         enemyCS = NPC_EvaluateShot( tr.entityNum, qtrue );
00802                 }
00803                 else
00804                 {//skip thr 2 traces since they would have to fail
00805                         enemyLOS = qfalse;
00806                         enemyCS = qfalse;
00807                 }
00808                 
00809                 if ( enemyCS && enemyShotFOV )
00810                 {//can hit enemy if we want
00811                         NPC->cantHitEnemyCounter = 0;
00812                 }
00813                 else
00814                 {//can't hit
00815                         NPC->cantHitEnemyCounter++;
00816                 }
00817 
00818                 if ( enemyCS && enemyShotFOV && enemyDist < shootDist )
00819                 {//can shoot
00820                         shoot = qtrue;
00821                         if ( NPCInfo->goalEntity == NPC->enemy )
00822                         {//my goal is my enemy and I have a clear shot, no need to chase right now
00823                                 move = qfalse;
00824                         }
00825                 }
00826                 else
00827                 {//don't shoot yet, keep chasing
00828                         shoot = qfalse;
00829                         move = qtrue;
00830                 }
00831 
00832                 //shoot decision
00833                 if ( !(NPCInfo->scriptFlags&SCF_DONT_FIRE) )
00834                 {//try to shoot
00835                         if ( NPC->enemy )
00836                         {
00837                                 if ( shoot )
00838                                 {
00839                                         if( !(NPCInfo->scriptFlags & SCF_FIRE_WEAPON) ) // we've already fired, no need to do it again here
00840                                         {
00841                                                 WeaponThink( qtrue );
00842                                         }
00843                                 }
00844                         }
00845                 }
00846 
00847                 //chase decision
00848                 if ( NPCInfo->scriptFlags & SCF_CHASE_ENEMIES )
00849                 {//go after him
00850                         NPCInfo->goalEntity = NPC->enemy;
00851                         //FIXME: don't need to chase when have a clear shot and in range?
00852                         if ( !enemyCS && NPC->cantHitEnemyCounter > 60 )
00853                         {//haven't been able to shoot enemy for about 6 seconds, need to do something
00854                                 //FIXME: combat points?  Just chase?
00855                                 if ( enemyPVS )
00856                                 {//in my PVS, just pick a combat point
00857                                         //FIXME: implement
00858                                 }
00859                                 else
00860                                 {//just chase him
00861                                 }
00862                         }
00863                         //FIXME: in normal behavior, should we use combat Points?  Do we care?  Is anyone actually going to ever use this AI?
00864                 }
00865                 else if ( NPC->cantHitEnemyCounter > 60 )
00866                 {//pick a new one
00867                         NPC_CheckEnemy( qtrue, qfalse, qtrue );
00868                 }
00869                 
00870                 if ( enemyPVS && enemyLOS )//&& !enemyShotFOV )
00871                 {//have a clear LOS to him//, but not looking at him
00872                         //Find the desired angles
00873                         vec3_t  angles;
00874 
00875                         GetAnglesForDirection( muzzle, enemyHead, angles );
00876 
00877                         NPCInfo->desiredYaw             = AngleNormalize180( angles[YAW] );
00878                         NPCInfo->desiredPitch   = AngleNormalize180( angles[PITCH] );
00879                 }
00880                 */
00881         }
00882 
00883         if ( UpdateGoal() )
00884         {//have a goal
00885                 if ( !NPC->enemy 
00886                         && NPC->client->leader 
00887                         && NPCInfo->goalEntity == NPC->client->leader 
00888                         && !trap_ICARUS_TaskIDPending( NPC, TID_MOVE_NAV ) )
00889                 {
00890                         NPC_BSFollowLeader();
00891                 }
00892                 else
00893                 {
00894                         //set angles
00895                         if ( (NPCInfo->scriptFlags & SCF_FACE_MOVE_DIR) || NPCInfo->goalEntity != NPC->enemy )
00896                         {//face direction of movement, NOTE: default behavior when not chasing enemy
00897                                 NPCInfo->combatMove = qfalse;
00898                         }
00899                         else
00900                         {//face goal.. FIXME: what if have a navgoal but want to face enemy while moving?  Will this do that?
00901                                 vec3_t  dir, angles;
00902 
00903                                 NPCInfo->combatMove = qfalse;
00904 
00905                                 VectorSubtract( NPCInfo->goalEntity->r.currentOrigin, NPC->r.currentOrigin, dir );
00906                                 vectoangles( dir, angles );
00907                                 NPCInfo->desiredYaw = angles[YAW];
00908                                 if ( NPCInfo->goalEntity == NPC->enemy )
00909                                 {
00910                                         NPCInfo->desiredPitch = angles[PITCH];
00911                                 }
00912                         }
00913 
00914                         //set movement
00915                         //override default walk/run behavior
00916                         //NOTE: redundant, done in NPC_ApplyScriptFlags
00917                         if ( NPCInfo->scriptFlags & SCF_RUNNING )
00918                         {
00919                                 ucmd.buttons &= ~BUTTON_WALKING;
00920                         }
00921                         else if ( NPCInfo->scriptFlags & SCF_WALKING )
00922                         {
00923                                 ucmd.buttons |= BUTTON_WALKING;
00924                         }
00925                         else if ( NPCInfo->goalEntity == NPC->enemy )
00926                         {
00927                                 ucmd.buttons &= ~BUTTON_WALKING;
00928                         }
00929                         else
00930                         {
00931                                 ucmd.buttons |= BUTTON_WALKING;
00932                         }
00933 
00934                         if ( NPCInfo->scriptFlags & SCF_FORCED_MARCH )
00935                         {//being forced to walk
00936                                 //if ( g_crosshairEntNum != NPC->s.number )
00937                                 if (!NPC_SomeoneLookingAtMe(NPC))
00938                                 {//don't walk if player isn't aiming at me
00939                                         move = qfalse;
00940                                 }
00941                         }
00942 
00943                         if ( move )
00944                         {
00945                                 //move toward goal
00946                                 NPC_MoveToGoal( qtrue );
00947                         }
00948                 }
00949         }
00950         else if ( !NPC->enemy && NPC->client->leader )
00951         {
00952                 NPC_BSFollowLeader();
00953         }
00954 
00955         //update angles
00956         NPC_UpdateAngles( qtrue, qtrue );
00957 }

void NPC_BSFlee void   ) 
 

Definition at line 1444 of file NPC_behavior.c.

References BS_DEFAULT, BS_FLEE, BUTTON_WALKING, usercmd_s::buttons, entityShared_t::currentOrigin, gNPC_t::desiredPitch, gNPC_t::desiredYaw, gNPC_t::distToGoal, DotProduct, flrand(), usercmd_s::forwardmove, gentity_t, gNPC_t::goalEntity, gNPC_t::investigateGoal, gNPC_t::lastGoalEntity, gentity_s::lastWaypoint, NAV_GetNearestNode(), NPC, NPC_CheckGetNewWeapon(), NPC_CheckSurrender(), NPC_MoveToGoal(), NPC_SetMoveGoal(), NPC_Surrender(), NPC_UpdateAngles(), NPCInfo, NULL, qboolean, qfalse, qtrue, gentity_s::r, gentity_s::s, SQUAD_IDLE, gNPC_t::squadState, gNPC_t::tempBehavior, gNPC_t::tempGoal, TIMER_Done(), trap_Nav_GetNodeEdge(), trap_Nav_GetNodeNumEdges(), trap_Nav_GetNodePosition(), ucmd, vec3_t, VectorNormalize(), VectorSubtract, vectoyaw(), gentity_s::waypoint, WAYPOINT_NONE, entityState_s::weapon, and WP_NONE.

Referenced by NPC_BehaviorSet_Charmed(), NPC_BehaviorSet_Default(), and NPC_RunBehavior().

01445 {//FIXME: keep checking for danger
01446         gentity_t *goal;
01447 
01448         if ( TIMER_Done( NPC, "flee" ) && NPCInfo->tempBehavior == BS_FLEE )
01449         {
01450                 NPCInfo->tempBehavior = BS_DEFAULT;
01451                 NPCInfo->squadState = SQUAD_IDLE;
01452                 //FIXME: should we set some timer to make him stay in this spot for a bit, 
01453                 //so he doesn't just suddenly turn around and come back at the enemy?
01454                 //OR, just stop running toward goal for last second or so of flee?
01455         }
01456         if ( NPC_CheckSurrender() )
01457         {
01458                 return;
01459         }
01460         goal = NPCInfo->goalEntity;
01461         if ( !goal )
01462         {
01463                 goal = NPCInfo->lastGoalEntity;
01464                 if ( !goal )
01465                 {//???!!!
01466                         goal = NPCInfo->tempGoal;
01467                 }
01468         }
01469 
01470         if ( goal )
01471         {
01472                 qboolean moved;
01473                 qboolean reverseCourse = qtrue;
01474 
01475                 //FIXME: if no weapon, find one and run to pick it up?
01476 
01477                 //Let's try to find a waypoint that gets me away from this thing
01478                 if ( NPC->waypoint == WAYPOINT_NONE )
01479                 {
01480                         NPC->waypoint = NAV_GetNearestNode( NPC, NPC->lastWaypoint );
01481                 }
01482                 if ( NPC->waypoint != WAYPOINT_NONE )
01483                 {
01484                         int     numEdges = trap_Nav_GetNodeNumEdges( NPC->waypoint );
01485 
01486                         if ( numEdges != WAYPOINT_NONE )
01487                         {
01488                                 vec3_t  dangerDir;
01489                                 int             nextWp;
01490                                 int             branchNum;
01491 
01492                                 VectorSubtract( NPCInfo->investigateGoal, NPC->r.currentOrigin, dangerDir );
01493                                 VectorNormalize( dangerDir );
01494 
01495                                 for ( branchNum = 0; branchNum < numEdges; branchNum++ )
01496                                 {
01497                                         vec3_t  branchPos, runDir;
01498 
01499                                         nextWp = trap_Nav_GetNodeEdge( NPC->waypoint, branchNum );
01500                                         trap_Nav_GetNodePosition( nextWp, branchPos );
01501 
01502                                         VectorSubtract( branchPos, NPC->r.currentOrigin, runDir );
01503                                         VectorNormalize( runDir );
01504                                         if ( DotProduct( runDir, dangerDir ) > flrand( 0, 0.5 ) )
01505                                         {//don't run toward danger
01506                                                 continue;
01507                                         }
01508                                         //FIXME: don't want to ping-pong back and forth
01509                                         NPC_SetMoveGoal( NPC, branchPos, 0, qtrue, -1, NULL );
01510                                         reverseCourse = qfalse;
01511                                         break;
01512                                 }
01513                         }
01514                 }
01515 
01516                 moved = NPC_MoveToGoal( qfalse );//qtrue? (do try to move straight to (away from) goal)
01517 
01518                 if ( NPC->s.weapon == WP_NONE && (moved == qfalse || reverseCourse) )
01519                 {//No weapon and no escape route... Just cower?  Need anim.
01520                         NPC_Surrender();
01521                         NPC_UpdateAngles( qtrue, qtrue );
01522                         return;
01523                 }
01524                 //If our move failed, then just run straight away from our goal
01525                 //FIXME: We really shouldn't do this.
01526                 if ( moved == qfalse )
01527                 {
01528                         vec3_t  dir;
01529                         float   dist;
01530                         if ( reverseCourse )
01531                         {
01532                                 VectorSubtract( NPC->r.currentOrigin, goal->r.currentOrigin, dir );
01533                         }
01534                         else
01535                         {
01536                                 VectorSubtract( goal->r.currentOrigin, NPC->r.currentOrigin, dir );
01537                         }
01538                         NPCInfo->distToGoal     = dist = VectorNormalize( dir );
01539                         NPCInfo->desiredYaw = vectoyaw( dir );
01540                         NPCInfo->desiredPitch = 0;
01541                         ucmd.forwardmove = 127;
01542                 }
01543                 else if ( reverseCourse )
01544                 {
01545                         //ucmd.forwardmove *= -1;
01546                         //ucmd.rightmove *= -1;
01547                         //VectorScale( NPC->client->ps.moveDir, -1, NPC->client->ps.moveDir );
01548                         NPCInfo->desiredYaw *= -1;
01549                 }
01550                 //FIXME: can stop after a safe distance?
01551                 //ucmd.upmove = 0;
01552                 ucmd.buttons &= ~BUTTON_WALKING;
01553                 //FIXME: what do we do once we've gotten to our goal?
01554         }
01555         NPC_UpdateAngles( qtrue, qtrue );
01556 
01557         NPC_CheckGetNewWeapon();
01558 }

void NPC_BSFollowLeader void   ) 
 

Definition at line 524 of file NPC_behavior.c.

References AEL_MINOR, AEL_SUSPICIOUS, level_locals_t::alertEvents, gentity_s::alliedTeam, BOTH_ATTACK1, BOTH_ATTACK2, BOTH_ATTACK3, BOTH_MELEE1, BOTH_MELEE2, BS_DEFAULT, BS_FOLLOW_LEADER, BS_HUNT_AND_KILL, BS_STAND_GUARD, BUTTON_WALKING, usercmd_s::buttons, CalcEntitySpot(), CHECK_360, CHECK_FOV, CHECK_PVS, CHECK_SHOOT, gentity_s::client, gNPC_t::confusionTime, entityShared_t::currentOrigin, gNPC_t::desiredPitch, gNPC_t::desiredYaw, gentity_s::enemy, gNPC_t::enemyCheckDebounceTime, gNPC_t::enemyLastSeenTime, gclient_s::enemyTeam, enemyVisibility, FL_NOTARGET, gentity_s::flags, gNPC_t::followDist, usercmd_s::forwardmove, G_ClearEnemy(), G_SetEnemy(), gNPC_t::goalEntity, gentity_s::health, gNPCstats_e::hfov, alertEvent_s::ID, gNPC_t::lastAlertID, gclient_s::leader, playerState_s::legsAnim, level, alertEvent_s::level, playerState_s::moveDir, NPC, gentity_s::NPC, NPC_AimAdjust(), NPC_AimWiggle(), NPC_BSStandGuard(), NPC_CheckAlertEvents(), NPC_CheckEnemy(), NPC_CheckVisibility(), NPC_GetHFOVPercentage(), NPC_MoveDirClear(), NPC_SlideMoveToGoal(), NPC_UpdateAngles(), NPC_UpdateFiringAngles(), NPCInfo, alertEvent_s::owner, PITCH, gclient_s::playerTeam, gclient_s::ps, Q_irand(), qfalse, qtrue, gentity_s::r, usercmd_s::rightmove, SCF_IGNORE_ALERTS, SCF_LOOK_FOR_ENEMIES, gNPC_t::scriptFlags, SPOT_HEAD, SPOT_WEAPON, gNPC_t::stats, gNPC_t::tempBehavior, level_locals_t::time, TIMER_Set(), ucmd, vec3_origin, vec3_t, vectoangles(), VectorNormalize(), VectorScale, VectorSubtract, gNPCstats_e::vfov, playerState_s::viewangles, VIS_PVS, VIS_SHOOT, visibility_t, playerState_s::weapon, WeaponThink(), WP_SABER, and YAW.

Referenced by NPC_BehaviorSet_Charmed(), NPC_BehaviorSet_Default(), NPC_BSDefault(), and NPC_BSJedi_FollowLeader().

00525 {
00526         vec3_t          vec;
00527         float           leaderDist;
00528         visibility_t    leaderVis;
00529         int                     curAnim;
00530 
00531         if ( !NPC->client->leader )
00532         {//ok, stand guard until we find an enemy
00533                 if( NPCInfo->tempBehavior == BS_HUNT_AND_KILL )
00534                 {
00535                         NPCInfo->tempBehavior = BS_DEFAULT;
00536                 }
00537                 else
00538                 {
00539                         NPCInfo->tempBehavior = BS_STAND_GUARD;
00540                         NPC_BSStandGuard();
00541                 }
00542                 return;
00543         }
00544 
00545         if ( !NPC->enemy  )
00546         {//no enemy, find one
00547                 NPC_CheckEnemy( NPCInfo->confusionTime<level.time, qfalse, qtrue );//don't find new enemy if this is tempbehav
00548                 if ( NPC->enemy )
00549                 {//just found one
00550                         NPCInfo->enemyCheckDebounceTime = level.time + Q_irand( 3000, 10000 );
00551                 }
00552                 else
00553                 {
00554                         if ( !(NPCInfo->scriptFlags&SCF_IGNORE_ALERTS) )
00555                         {
00556                                 int eventID = NPC_CheckAlertEvents( qtrue, qtrue, -1, qfalse, AEL_MINOR );
00557                                 if ( level.alertEvents[eventID].level >= AEL_SUSPICIOUS && (NPCInfo->scriptFlags&SCF_LOOK_FOR_ENEMIES) )
00558                                 {
00559                                         NPCInfo->lastAlertID = level.alertEvents[eventID].ID;
00560                                         if ( !level.alertEvents[eventID].owner || 
00561                                                 !level.alertEvents[eventID].owner->client || 
00562                                                 level.alertEvents[eventID].owner->health <= 0 ||
00563                                                 level.alertEvents[eventID].owner->client->playerTeam != NPC->client->enemyTeam )
00564                                         {//not an enemy
00565                                         }
00566                                         else
00567                                         {
00568                                                 //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)
00569                                                 G_SetEnemy( NPC, level.alertEvents[eventID].owner );
00570                                                 NPCInfo->enemyCheckDebounceTime = level.time + Q_irand( 3000, 10000 );
00571                                                 NPCInfo->enemyLastSeenTime = level.time;
00572                                                 TIMER_Set( NPC, "attackDelay", Q_irand( 500, 1000 ) );
00573                                         }
00574                                 }
00575 
00576                         }
00577                 }
00578                 if ( !NPC->enemy )
00579                 {
00580                         if ( NPC->client->leader 
00581                                 && NPC->client->leader->enemy 
00582                                 && NPC->client->leader->enemy != NPC
00583                                 && ( (NPC->client->leader->enemy->client&&NPC->client->leader->enemy->client->playerTeam==NPC->client->enemyTeam)
00584                                         ||(/*NPC->client->leader->enemy->r.svFlags&SVF_NONNPC_ENEMY*/0&&NPC->client->leader->enemy->alliedTeam==NPC->client->enemyTeam) )
00585                                 && NPC->client->leader->enemy->health > 0 )
00586                         { //rwwFIXMEFIXME: use SVF_NONNPC_ENEMY?
00587                                 G_SetEnemy( NPC, NPC->client->leader->enemy );
00588                                 NPCInfo->enemyCheckDebounceTime = level.time + Q_irand( 3000, 10000 );
00589                                 NPCInfo->enemyLastSeenTime = level.time;
00590                         }
00591                 }
00592         }
00593         else 
00594         {
00595                 if ( NPC->enemy->health <= 0 || (NPC->enemy->flags&FL_NOTARGET) )
00596                 {
00597                         G_ClearEnemy( NPC );
00598                         if ( NPCInfo->enemyCheckDebounceTime > level.time + 1000 )
00599                         {
00600                                 NPCInfo->enemyCheckDebounceTime = level.time + Q_irand( 1000, 2000 );
00601                         }
00602                 }
00603                 else if ( NPC->client->ps.weapon && NPCInfo->enemyCheckDebounceTime < level.time )
00604                 {
00605                         NPC_CheckEnemy( (NPCInfo->confusionTime<level.time||NPCInfo->tempBehavior!=BS_FOLLOW_LEADER), qfalse, qtrue );//don't find new enemy if this is tempbehav
00606                 }
00607         }
00608         
00609         if ( NPC->enemy && NPC->client->ps.weapon )
00610         {//If have an enemy, face him and fire
00611                 if ( NPC->client->ps.weapon == WP_SABER )//|| NPCInfo->confusionTime>level.time )
00612                 {//lightsaber user or charmed enemy
00613                         if ( NPCInfo->tempBehavior != BS_FOLLOW_LEADER )
00614                         {//not already in a temp bState
00615                                 //go after the guy
00616                                 NPCInfo->tempBehavior = BS_HUNT_AND_KILL;
00617                                 NPC_UpdateAngles(qtrue, qtrue);
00618                                 return;
00619                         }
00620                 }
00621 
00622                 enemyVisibility = NPC_CheckVisibility ( NPC->enemy, CHECK_FOV|CHECK_SHOOT );//CHECK_360|CHECK_PVS|
00623                 if ( enemyVisibility > VIS_PVS )
00624                 {//face
00625                         vec3_t  enemy_org, muzzle, delta, angleToEnemy;
00626                         float   distanceToEnemy;
00627 
00628                         CalcEntitySpot( NPC->enemy, SPOT_HEAD, enemy_org );
00629                         NPC_AimWiggle( enemy_org );
00630 
00631                         CalcEntitySpot( NPC, SPOT_WEAPON, muzzle );
00632                         
00633                         VectorSubtract( enemy_org, muzzle, delta);
00634                         vectoangles( delta, angleToEnemy );
00635                         distanceToEnemy = VectorNormalize( delta );
00636 
00637                         NPCInfo->desiredYaw = angleToEnemy[YAW];
00638                         NPCInfo->desiredPitch = angleToEnemy[PITCH];
00639                         NPC_UpdateFiringAngles( qtrue, qtrue );
00640 
00641                         if ( enemyVisibility >= VIS_SHOOT )
00642                         {//shoot
00643                                 NPC_AimAdjust( 2 );
00644                                 if ( NPC_GetHFOVPercentage( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, NPC->client->ps.viewangles, NPCInfo->stats.hfov ) > 0.6f 
00645                                         && NPC_GetHFOVPercentage( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, NPC->client->ps.viewangles, NPCInfo->stats.vfov ) > 0.5f )
00646                                 {//actually withing our front cone
00647                                         WeaponThink( qtrue );
00648                                 }
00649                         }
00650                         else
00651                         {
00652                                 NPC_AimAdjust( 1 );
00653                         }
00654                         
00655                         //NPC_CheckCanAttack(1.0, qfalse);
00656                 }
00657                 else
00658                 {
00659                         NPC_AimAdjust( -1 );
00660                 }
00661         }
00662         else
00663         {//FIXME: combine with vector calc below
00664                 vec3_t  head, leaderHead, delta, angleToLeader;
00665 
00666                 CalcEntitySpot( NPC->client->leader, SPOT_HEAD, leaderHead );
00667                 CalcEntitySpot( NPC, SPOT_HEAD, head );
00668                 VectorSubtract (leaderHead, head, delta);
00669                 vectoangles ( delta, angleToLeader );
00670                 VectorNormalize(delta);
00671                 NPC->NPC->desiredYaw = angleToLeader[YAW];
00672                 NPC->NPC->desiredPitch = angleToLeader[PITCH];
00673                 
00674                 NPC_UpdateAngles(qtrue, qtrue);
00675         }
00676 
00677         //leader visible?
00678         leaderVis = NPC_CheckVisibility( NPC->client->leader, CHECK_PVS|CHECK_360|CHECK_SHOOT );//                      ent->e_UseFunc = useF_NULL;
00679 
00680 
00681         //Follow leader, stay within visibility and a certain distance, maintain a distance from.
00682         curAnim = NPC->client->ps.legsAnim;
00683         if ( curAnim != BOTH_ATTACK1 && curAnim != BOTH_ATTACK2 && curAnim != BOTH_ATTACK3 && curAnim != BOTH_MELEE1 && curAnim != BOTH_MELEE2 )
00684         {//Don't move toward leader if we're in a full-body attack anim
00685                 //FIXME, use IdealDistance to determine if we need to close distance
00686                 float   followDist = 96.0f;//FIXME:  If there are enmies, make this larger?
00687                 float   backupdist, walkdist, minrundist;
00688                 float   leaderHDist;
00689 
00690                 if ( NPCInfo->followDist )
00691                 {
00692                         followDist = NPCInfo->followDist;
00693                 }
00694                 backupdist = followDist/2.0f;
00695                 walkdist = followDist*0.83;
00696                 minrundist = followDist*1.33;
00697 
00698                 VectorSubtract(NPC->client->leader->r.currentOrigin, NPC->r.currentOrigin, vec);
00699                 leaderDist = VectorLength( vec );//FIXME: make this just nav distance?
00700                 //never get within their radius horizontally
00701                 vec[2] = 0;
00702                 leaderHDist = VectorLength( vec );
00703                 if( leaderHDist > backupdist && (leaderVis != VIS_SHOOT || leaderDist > walkdist) )
00704                 {//We should close in?
00705                         NPCInfo->goalEntity = NPC->client->leader;
00706 
00707                         NPC_SlideMoveToGoal();
00708                         if ( leaderVis == VIS_SHOOT && leaderDist < minrundist )
00709                         {
00710                                 ucmd.buttons |= BUTTON_WALKING;
00711                         }
00712                 }
00713                 else if ( leaderDist < backupdist )
00714                 {//We should back off?
00715                         NPCInfo->goalEntity = NPC->client->leader;
00716                         NPC_SlideMoveToGoal();
00717 
00718                         //reversing direction
00719                         ucmd.forwardmove = -ucmd.forwardmove;
00720                         ucmd.rightmove   = -ucmd.rightmove;
00721                         VectorScale( NPC->client->ps.moveDir, -1, NPC->client->ps.moveDir );
00722                 }//otherwise, stay where we are
00723                 //check for do not enter and stop if there's one there...
00724                 if ( ucmd.forwardmove || ucmd.rightmove || VectorCompare( vec3_origin, NPC->client->ps.moveDir ) )
00725                 {
00726                         NPC_MoveDirClear( ucmd.forwardmove, ucmd.rightmove, qtrue );
00727                 }
00728         }
00729 }

void NPC_BSFormation void   ) 
 

void NPC_BSHuntAndKill void   ) 
 

(ucmd.buttons & BUTTON_ATTACK) ||

Definition at line 232 of file NPC_AI_Default.c.

References BOTH_ATTACK1, BOTH_ATTACK2, BOTH_ATTACK3, BOTH_MELEE1, BOTH_MELEE2, BS_DEFAULT, BS_HUNT_AND_KILL, BS_STAND_GUARD, BUTTON_WALKING, usercmd_s::buttons, CHECK_FOV, CHECK_SHOOT, gentity_s::client, entityShared_t::currentOrigin, gentity_s::enemy, enemyDist, enemyVisibility, usercmd_s::forwardmove, gNPC_t::goalEntity, gNPC_t::goalRadius, IdealDistance(), playerState_s::legsAnim, playerState_s::moveDir, NPC, NPC_BSStandGuard(), NPC_CheckCanAttack(), NPC_CheckEnemy(), NPC_CheckVisibility(), NPC_EnemyTooFar(), NPC_MaxDistSquaredForWeapon(), NPC_MoveToGoal(), NPC_UpdateAngles(), NPCInfo, gclient_s::ps, qboolean, qfalse, qtrue, gentity_s::r, usercmd_s::rightmove, gNPC_t::tempBehavior, ucmd, vec3_t, VectorScale, VectorSubtract, VIS_PVS, VIS_SHOOT, and visibility_t.

00233 {
00234         qboolean        turned = qfalse;
00235         vec3_t          vec;
00236         float           enemyDist;
00237         visibility_t    oEVis;
00238         int                     curAnim;
00239 
00240         NPC_CheckEnemy( NPCInfo->tempBehavior != BS_HUNT_AND_KILL, qfalse, qtrue );//don't find new enemy if this is tempbehav
00241 
00242         if ( NPC->enemy )
00243         {
00244                 oEVis = enemyVisibility = NPC_CheckVisibility ( NPC->enemy, CHECK_FOV|CHECK_SHOOT );//CHECK_360|//CHECK_PVS|
00245                 if(enemyVisibility > VIS_PVS)
00246                 {
00247                         if ( !NPC_EnemyTooFar( NPC->enemy, 0, qtrue ) )
00248                         {//Enemy is close enough to shoot - FIXME: this next func does this also, but need to know here for info on whether ot not to turn later
00249                                 NPC_CheckCanAttack( 1.0, qfalse );
00250                                 turned = qtrue;
00251                         }
00252                 }
00253 
00254                 curAnim = NPC->client->ps.legsAnim;
00255                 if(curAnim != BOTH_ATTACK1 && curAnim != BOTH_ATTACK2 && curAnim != BOTH_ATTACK3 && curAnim != BOTH_MELEE1 && curAnim != BOTH_MELEE2 )
00256                 {//Don't move toward enemy if we're in a full-body attack anim
00257                         //FIXME, use IdealDistance to determin if we need to close distance
00258                         VectorSubtract(NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, vec);
00259                         enemyDist = VectorLength(vec);
00260                         if( enemyDist > 48 && ((enemyDist*1.5)*(enemyDist*1.5) >= NPC_MaxDistSquaredForWeapon() ||
00261                                 oEVis != VIS_SHOOT ||
00263                                 enemyDist > IdealDistance(NPC)*3 ) )
00264                         {//We should close in?
00265                                 NPCInfo->goalEntity = NPC->enemy;
00266 
00267                                 NPC_MoveToGoal( qtrue );
00268                         }
00269                         else if(enemyDist < IdealDistance(NPC))
00270                         {//We should back off?
00271                                 //if(ucmd.buttons & BUTTON_ATTACK)
00272                                 {
00273                                         NPCInfo->goalEntity = NPC->enemy;
00274                                         NPCInfo->goalRadius = 12;
00275                                         NPC_MoveToGoal( qtrue );
00276 
00277                                         ucmd.forwardmove *= -1;
00278                                         ucmd.rightmove *= -1;
00279                                         VectorScale( NPC->client->ps.moveDir, -1, NPC->client->ps.moveDir );
00280 
00281                                         ucmd.buttons |= BUTTON_WALKING;
00282                                 }
00283                         }//otherwise, stay where we are
00284                 }
00285         }
00286         else 
00287         {//ok, stand guard until we find an enemy
00288                 if( NPCInfo->tempBehavior == BS_HUNT_AND_KILL )
00289                 {
00290                         NPCInfo->tempBehavior = BS_DEFAULT;
00291                 }
00292                 else
00293                 {
00294                         NPCInfo->tempBehavior = BS_STAND_GUARD;
00295                         NPC_BSStandGuard();
00296                 }
00297                 return;
00298         }
00299 
00300         if(!turned)
00301         {
00302                 NPC_UpdateAngles(qtrue, qtrue);
00303         }
00304 }

void NPC_BSIdle void   ) 
 

Definition at line 161 of file NPC_AI_Default.c.

References BUTTON_WALKING, usercmd_s::buttons, usercmd_s::forwardmove, NPC_MoveToGoal(), NPC_UpdateAngles(), qtrue, usercmd_s::rightmove, ucmd, UpdateGoal(), and usercmd_s::upmove.

Referenced by ATST_Idle(), ImperialProbe_Idle(), Interrogator_Idle(), Mark1_Idle(), Mark2_Idle(), Remote_Idle(), and Sentry_Idle().

00162 {
00163         //FIXME if there is no nav data, we need to do something else
00164         // if we're stuck, try to move around it
00165         if ( UpdateGoal() )
00166         {
00167                 NPC_MoveToGoal( qtrue );
00168         }
00169 
00170         if ( ( ucmd.forwardmove == 0 ) && ( ucmd.rightmove == 0 ) && ( ucmd.upmove == 0 ) )
00171         {
00172 //              NPC_StandIdle();
00173         }
00174 
00175         NPC_UpdateAngles( qtrue, qtrue );
00176         ucmd.buttons |= BUTTON_WALKING;
00177 }

void NPC_BSInvestigate void   ) 
 

Definition at line 252 of file NPC_behavior.c.

00253 {
00254 /*
00255         //FIXME: maybe allow this to be set as a tempBState in a script?  Just specify the
00256         //investigateGoal, investigateDebounceTime and investigateCount? (Needs a macro)
00257         vec3_t          invDir, invAngles, spot;
00258         gentity_t       *saveGoal;
00259         //BS_INVESTIGATE would turn toward goal, maybe take a couple steps towards it,
00260         //look for enemies, then turn away after your investigate counter was down-
00261         //investigate counter goes up every time you set it...
00262 
00263         if(level.time > NPCInfo->enemyCheckDebounceTime)
00264         {
00265                 NPCInfo->enemyCheckDebounceTime = level.time + (NPCInfo->stats.vigilance * 1000);
00266                 NPC_CheckEnemy(qtrue, qfalse);
00267                 if(NPC->enemy)
00268                 {//FIXME: do anger script
00269                         NPCInfo->goalEntity = NPC->enemy;
00270 //                      NAV_ClearLastRoute(NPC);
00271                         NPCInfo->behaviorState = BS_RUN_AND_SHOOT;
00272                         NPCInfo->tempBehavior = BS_DEFAULT;
00273                         NPC_AngerSound();
00274                         return;
00275                 }
00276         }
00277 
00278         NPC_SetAnim( NPC, SETANIM_TORSO, TORSO_WEAPONREADY3, SETANIM_FLAG_NORMAL );
00279 
00280         if(NPCInfo->stats.vigilance <= 1.0 && NPCInfo->eventOwner)
00281         {
00282                 VectorCopy(NPCInfo->eventOwner->r.currentOrigin, NPCInfo->investigateGoal);
00283         }
00284 
00285         saveGoal = NPCInfo->goalEntity;
00286         if(     level.time > NPCInfo->walkDebounceTime )
00287         {
00288                 vec3_t  vec;
00289 
00290                 VectorSubtract(NPCInfo->investigateGoal, NPC->r.currentOrigin, vec);
00291                 vec[2] = 0;
00292                 if(VectorLength(vec) > 64)
00293                 {
00294                         if(Q_irand(0, 100) < NPCInfo->investigateCount)
00295                         {//take a full step
00296                                 //NPCInfo->walkDebounceTime = level.time + 1400;
00297                                 //actually finds length of my BOTH_WALK anim
00298                                 NPCInfo->walkDebounceTime = PM_AnimLength( NPC->client->clientInfo.animFileIndex, BOTH_WALK1 );
00299                         }
00300                 }
00301         }
00302 
00303         if(     level.time < NPCInfo->walkDebounceTime )
00304         {//walk toward investigateGoal
00305                 
00306                 /*
00307                 NPCInfo->goalEntity = NPCInfo->tempGoal;
00308 //              NAV_ClearLastRoute(NPC);
00309                 VectorCopy(NPCInfo->investigateGoal, NPCInfo->tempGoal->r.currentOrigin);
00310                 */
00311 
00312 /*              NPC_SetMoveGoal( NPC, NPCInfo->investigateGoal, 16, qtrue );
00313 
00314                 NPC_MoveToGoal( qtrue );
00315 
00316                 //FIXME: walk2?
00317                 NPC_SetAnim(NPC,SETANIM_LEGS,BOTH_WALK1,SETANIM_FLAG_NORMAL);
00318 
00319                 ucmd.buttons |= BUTTON_WALKING;
00320         }
00321         else
00322         {
00323 
00324                 NPC_SetAnim(NPC,SETANIM_LEGS,BOTH_STAND1,SETANIM_FLAG_NORMAL);
00325 
00326                 if(NPCInfo->hlookCount > 30)
00327                 {
00328                         if(Q_irand(0, 10) > 7) 
00329                         {
00330                                 NPCInfo->hlookCount = 0;
00331                         }
00332                 }
00333                 else if(NPCInfo->hlookCount < -30)
00334                 {
00335                         if(Q_irand(0, 10) > 7) 
00336                         {
00337                                 NPCInfo->hlookCount = 0;
00338                         }
00339                 }
00340                 else if(NPCInfo->hlookCount == 0)
00341                 {
00342                         NPCInfo->hlookCount = Q_irand(-1, 1);
00343                 }
00344                 else if(Q_irand(0, 10) > 7) 
00345                 {
00346                         if(NPCInfo->hlookCount > 0)
00347                         {
00348                                 NPCInfo->hlookCount++;
00349                         }
00350                         else//lookCount < 0
00351                         {
00352                                 NPCInfo->hlookCount--;
00353                         }
00354                 }
00355 
00356                 if(NPCInfo->vlookCount >= 15)
00357                 {
00358                         if(Q_irand(0, 10) > 7) 
00359                         {
00360                                 NPCInfo->vlookCount = 0;
00361                         }
00362                 }
00363                 else if(NPCInfo->vlookCount <= -15)
00364                 {
00365                         if(Q_irand(0, 10) > 7) 
00366                         {
00367                                 NPCInfo->vlookCount = 0;
00368                         }
00369                 }
00370                 else if(NPCInfo->vlookCount == 0)
00371                 {
00372                         NPCInfo->vlookCount = Q_irand(-1, 1);
00373                 }
00374                 else if(Q_irand(0, 10) > 8) 
00375                 {
00376                         if(NPCInfo->vlookCount > 0)
00377                         {
00378                                 NPCInfo->vlookCount++;
00379                         }
00380                         else//lookCount < 0
00381                         {
00382                                 NPCInfo->vlookCount--;
00383                         }
00384                 }
00385 
00386                 //turn toward investigateGoal
00387                 CalcEntitySpot( NPC, SPOT_HEAD, spot );
00388                 VectorSubtract(NPCInfo->investigateGoal, spot, invDir);
00389                 VectorNormalize(invDir);
00390                 vectoangles(invDir, invAngles);
00391                 NPCInfo->desiredYaw = AngleNormalize360(invAngles[YAW] + NPCInfo->hlookCount);
00392                 NPCInfo->desiredPitch = AngleNormalize360(invAngles[PITCH] + NPCInfo->hlookCount);
00393         }
00394 
00395         NPC_UpdateAngles(qtrue, qtrue);
00396 
00397         NPCInfo->goalEntity = saveGoal;
00398 //      NAV_ClearLastRoute(NPC);
00399 
00400         if(level.time > NPCInfo->investigateDebounceTime)
00401         {
00402                 NPCInfo->tempBehavior = BS_DEFAULT;
00403         }
00404 
00405         NPC_CheckSoundEvents();
00406         */
00407 }

void NPC_BSJump void   ) 
 

Definition at line 733 of file NPC_behavior.c.

References gNPC_t::aiFlags, AngleDelta(), AngleNormalize360(), APEX_HEIGHT, BOTH_CROUCH1, BOTH_INAIR1, BOTH_LAND1, gentity_s::client, entityShared_t::currentOrigin, gNPC_t::desiredPitch, gNPC_t::desiredYaw, ENTITYNUM_NONE, FL_NO_KNOCKBACK, gentity_s::flags, usercmd_s::forwardmove, G_Cube(), gNPC_t::goalEntity, gNPC_t::goalTime, playerState_s::gravity, entityState_s::groundEntityNum, JS_CROUCHING, JS_FACING, JS_JUMPING, JS_LANDING, JS_WAITING, gNPC_t::jumpState, playerState_s::legsTimer, level, gNPC_t::lockedDesiredPitch, gNPC_t::lockedDesiredYaw, entityShared_t::maxs, MIN_ANGLE_ERROR, entityShared_t::mins, NPC, NPC_ClearGoal(), NPC_SetAnim(), NPC_UpdateAngles(), NPCAI_MOVING, NPCDEBUG_BLUE, NPCInfo, PITCH, gentity_s::pos1, gclient_s::ps, qtrue, gentity_s::r, gentity_s::s, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, SETANIM_LEGS, showBBoxes, sqrt(), TID_MOVE_NAV, level_locals_t::time, trap_ICARUS_TaskIDComplete(), ucmd, vec3_t, vectoangles(), VectorAdd, VectorClear, VectorCopy, VectorMA, VectorNormalize(), VectorScale, VectorSubtract, playerState_s::velocity, playerState_s::viewangles, and YAW.

Referenced by NPC_BehaviorSet_Default().

00734 {
00735         vec3_t          dir, angles, p1, p2, apex;
00736         float           time, height, forward, z, xy, dist, yawError, apexHeight;
00737 
00738         if( !NPCInfo->goalEntity )
00739         {//Should have task completed the navgoal
00740                 return;
00741         }
00742 
00743         if ( NPCInfo->jumpState != JS_JUMPING && NPCInfo->jumpState != JS_LANDING )
00744         {
00745                 //Face navgoal
00746                 VectorSubtract(NPCInfo->goalEntity->r.currentOrigin, NPC->r.currentOrigin, dir);
00747                 vectoangles(dir, angles);
00748                 NPCInfo->desiredPitch = NPCInfo->lockedDesiredPitch = AngleNormalize360(angles[PITCH]);
00749                 NPCInfo->desiredYaw = NPCInfo->lockedDesiredYaw = AngleNormalize360(angles[YAW]);
00750         }
00751 
00752         NPC_UpdateAngles ( qtrue, qtrue );
00753         yawError = AngleDelta ( NPC->client->ps.viewangles[YAW], NPCInfo->desiredYaw );
00754         //We don't really care about pitch here
00755 
00756         switch ( NPCInfo->jumpState )
00757         {
00758         case JS_FACING:
00759                 if ( yawError < MIN_ANGLE_ERROR )
00760                 {//Facing it, Start crouching
00761                         NPC_SetAnim(NPC, SETANIM_LEGS, BOTH_CROUCH1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD);
00762                         NPCInfo->jumpState = JS_CROUCHING;
00763                 }
00764                 break;
00765         case JS_CROUCHING:
00766                 if ( NPC->client->ps.legsTimer > 0 )
00767                 {//Still playing crouching anim
00768                         return;
00769                 }
00770 
00771                 //Create a parabola
00772 
00773                 if ( NPC->r.currentOrigin[2] > NPCInfo->goalEntity->r.currentOrigin[2] )
00774                 {
00775                         VectorCopy( NPC->r.currentOrigin, p1 );
00776                         VectorCopy( NPCInfo->goalEntity->r.currentOrigin, p2 );
00777                 }
00778                 else if ( NPC->r.currentOrigin[2] < NPCInfo->goalEntity->r.currentOrigin[2] )
00779                 {
00780                         VectorCopy( NPCInfo->goalEntity->r.currentOrigin, p1 );
00781                         VectorCopy( NPC->r.currentOrigin, p2 );
00782                 }
00783                 else
00784                 {
00785                         VectorCopy( NPC->r.currentOrigin, p1 );
00786                         VectorCopy( NPCInfo->goalEntity->r.currentOrigin, p2 );
00787                 }
00788 
00789                 //z = xy*xy
00790                 VectorSubtract( p2, p1, dir );
00791                 dir[2] = 0;
00792 
00793                 //Get xy and z diffs
00794                 xy = VectorNormalize( dir );
00795                 z = p1[2] - p2[2];
00796 
00797                 apexHeight = APEX_HEIGHT/2;
00798                 /*
00799                 //Determine most desirable apex height
00800                 apexHeight = (APEX_HEIGHT * PARA_WIDTH/xy) + (APEX_HEIGHT * z/128);
00801                 if ( apexHeight < APEX_HEIGHT * 0.5 )
00802                 {
00803                         apexHeight = APEX_HEIGHT*0.5;
00804                 }
00805                 else if ( apexHeight > APEX_HEIGHT * 2 )
00806                 {
00807                         apexHeight = APEX_HEIGHT*2;
00808                 }
00809                 */
00810 
00811                 //FIXME: length of xy will change curve of parabola, need to account for this
00812                 //somewhere... PARA_WIDTH
00813                 
00814                 z = (sqrt(apexHeight + z) - sqrt(apexHeight));
00815 
00816                 assert(z >= 0);
00817 
00818 //              Com_Printf("apex is %4.2f percent from p1: ", (xy-z)*0.5/xy*100.0f);
00819 
00820                 xy -= z;
00821                 xy *= 0.5;
00822                 
00823                 assert(xy > 0);
00824 
00825                 VectorMA( p1, xy, dir, apex );
00826                 apex[2] += apexHeight;
00827         
00828                 VectorCopy(apex, NPC->pos1);
00829                 
00830                 //Now we have the apex, aim for it
00831                 height = apex[2] - NPC->r.currentOrigin[2];
00832                 time = sqrt( height / ( .5 * NPC->client->ps.gravity ) );
00833                 if ( !time ) 
00834                 {
00835 //                      Com_Printf("ERROR no time in jump\n");
00836                         return;
00837                 }
00838 
00839                 // set s.origin2 to the push velocity
00840                 VectorSubtract ( apex, NPC->r.currentOrigin, NPC->client->ps.velocity );
00841                 NPC->client->ps.velocity[2] = 0;
00842                 dist = VectorNormalize( NPC->client->ps.velocity );
00843 
00844                 forward = dist / time;
00845                 VectorScale( NPC->client->ps.velocity, forward, NPC->client->ps.velocity );
00846 
00847                 NPC->client->ps.velocity[2] = time * NPC->client->ps.gravity;
00848 
00849 //              Com_Printf( "%s jumping %s, gravity at %4.0f percent\n", NPC->targetname, vtos(NPC->client->ps.velocity), NPC->client->ps.gravity/8.0f );
00850 
00851                 NPC->flags |= FL_NO_KNOCKBACK;
00852                 NPCInfo->jumpState = JS_JUMPING;
00853                 //FIXME: jumpsound?
00854                 break;
00855         case JS_JUMPING:
00856 
00857                 if ( showBBoxes )
00858                 {
00859                         VectorAdd(NPC->r.mins, NPC->pos1, p1);
00860                         VectorAdd(NPC->r.maxs, NPC->pos1, p2);
00861                         G_Cube( p1, p2, NPCDEBUG_BLUE, 0.5 );
00862                 }
00863 
00864                 if ( NPC->s.groundEntityNum != ENTITYNUM_NONE)
00865                 {//Landed, start landing anim
00866                         //FIXME: if the 
00867                         VectorClear(NPC->client->ps.velocity);
00868                         NPC_SetAnim(NPC, SETANIM_BOTH, BOTH_LAND1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD);
00869                         NPCInfo->jumpState = JS_LANDING;
00870                         //FIXME: landsound?
00871                 }
00872                 else if ( NPC->client->ps.legsTimer > 0 )
00873                 {//Still playing jumping anim
00874                         //FIXME: apply jump velocity here, a couple frames after start, not right away
00875                         return;
00876                 }
00877                 else
00878                 {//still in air, but done with jump anim, play inair anim
00879                         NPC_SetAnim(NPC, SETANIM_BOTH, BOTH_INAIR1, SETANIM_FLAG_OVERRIDE);
00880                 }
00881                 break;
00882         case JS_LANDING:
00883                 if ( NPC->client->ps.legsTimer > 0 )
00884                 {//Still playing landing anim
00885                         return;
00886                 }
00887                 else
00888                 {
00889                         NPCInfo->jumpState = JS_WAITING;
00890 
00891                         
00892                         //task complete no matter what...  
00893                         NPC_ClearGoal();
00894                         NPCInfo->goalTime = level.time;
00895                         NPCInfo->aiFlags &= ~NPCAI_MOVING;
00896                         ucmd.forwardmove = 0;
00897                         NPC->flags &= ~FL_NO_KNOCKBACK;
00898                         //Return that the goal was reached
00899                         trap_ICARUS_TaskIDComplete( NPC, TID_MOVE_NAV );
00900                         
00901                         //Or should we keep jumping until reached goal?
00902                         
00903                         /*
00904                         NPCInfo->goalEntity = UpdateGoal();
00905                         if ( !NPCInfo->goalEntity )
00906                         {
00907                                 NPC->flags &= ~FL_NO_KNOCKBACK;
00908                                 Q3_TaskIDComplete( NPC, TID_MOVE_NAV );
00909                         }
00910                         */
00911                         
00912                 }
00913                 break;
00914         case JS_WAITING:
00915         default:
00916                 NPCInfo->jumpState = JS_FACING;
00917                 break;
00918         }
00919 }

void NPC_BSPatrol void   ) 
 

Definition at line 664 of file NPC_AI_Default.c.

References gNPC_t::behaviorState, BS_HUNT_AND_KILL, BUTTON_WALKING, usercmd_s::buttons, gentity_s::enemy, gNPC_t::enemyCheckDebounceTime, gNPC_t::investigateSoundDebounceTime, level, NPC, NPC_CheckEnemy(), NPC_MoveToGoal(), NPC_UpdateAngles(), NPCInfo, qfalse, qtrue, gNPC_t::stats, level_locals_t::time, ucmd, UpdateGoal(), and gNPCstats_e::vigilance.

Referenced by NPC_BSST_Attack().

00665 {
00666         //int   alertEventNum;
00667 
00668         if(level.time > NPCInfo->enemyCheckDebounceTime)
00669         {
00670                 NPCInfo->enemyCheckDebounceTime = level.time + (NPCInfo->stats.vigilance * 1000);
00671                 NPC_CheckEnemy(qtrue, qfalse, qtrue);
00672                 if(NPC->enemy)
00673                 {//FIXME: do anger script
00674                         NPCInfo->behaviorState = BS_HUNT_AND_KILL;
00675                         //NPC_AngerSound();
00676                         return;
00677                 }
00678         }
00679 
00680         //FIXME: Implement generic sound alerts
00681         /*
00682         alertEventNum = NPC_CheckAlertEvents( qtrue, qtrue );
00683         if( alertEventNum != -1 )
00684         {//If we heard something, see if we should check it out
00685                 if ( NPC_CheckInvestigate( alertEventNum ) )
00686                 {
00687                         return;
00688                 }
00689         }
00690         */
00691 
00692         NPCInfo->investigateSoundDebounceTime = 0;
00693         //FIXME if there is no nav data, we need to do something else
00694         // if we're stuck, try to move around it
00695         if ( UpdateGoal() )
00696         {
00697                 NPC_MoveToGoal( qtrue );
00698         }
00699 
00700         NPC_UpdateAngles( qtrue, qtrue );
00701 
00702         ucmd.buttons |= BUTTON_WALKING;
00703 }

void NPC_BSPointShoot qboolean  shoot  ) 
 

Definition at line 505 of file NPC_AI_Default.c.

References gNPC_t::aimTime, AngleDelta(), AngleNormalize360(), BUTTON_ATTACK, usercmd_s::buttons, CalcEntitySpot(), gentity_s::client, client, DEG2RAD, gNPC_t::desiredPitch, gNPC_t::desiredYaw, gentity_s::enemy, gentity_s::health, gentity_s::inuse, gNPC_t::lockedDesiredPitch, gNPC_t::lockedDesiredYaw, entityShared_t::maxs, entityShared_t::mins, NPC, gentity_s::NPC, NPC_UpdateAngles(), NPCInfo, PITCH, gclient_s::ps, qtrue, gentity_s::r, SPOT_HEAD, SPOT_WEAPON, tan(), TID_BSTATE, trap_ICARUS_TaskIDComplete(), ucmd, vec3_t, vectoangles(), VectorSubtract, playerState_s::viewangles, playerState_s::weapon, WP_NONE, WP_SABER, WP_STUN_BATON, and YAW.

00506 {//FIXME: doesn't check for clear shot...
00507         vec3_t  muzzle, dir, angles, org;
00508 
00509         if ( !NPC->enemy || !NPC->enemy->inuse || (NPC->enemy->NPC && NPC->enemy->health <= 0) )
00510         {//FIXME: should still keep shooting for a second or two after they actually die...
00511                 trap_ICARUS_TaskIDComplete( NPC, TID_BSTATE );
00512                 goto finished;
00513                 return;
00514         }
00515 
00516         CalcEntitySpot(NPC, SPOT_WEAPON, muzzle);
00517         CalcEntitySpot(NPC->enemy, SPOT_HEAD, org);//Was spot_org
00518         //Head is a little high, so let's aim for the chest:
00519         if ( NPC->enemy->client )
00520         {
00521                 org[2] -= 12;//NOTE: is this enough?
00522         }
00523 
00524         VectorSubtract(org, muzzle, dir);
00525         vectoangles(dir, angles);
00526 
00527         switch( NPC->client->ps.weapon )
00528         {
00529         case WP_NONE:
00530 //      case WP_TRICORDER:
00531         case WP_STUN_BATON:
00532         case WP_SABER:
00533                 //don't do any pitch change if not holding a firing weapon
00534                 break;
00535         default:
00536                 NPCInfo->desiredPitch = NPCInfo->lockedDesiredPitch = AngleNormalize360(angles[PITCH]);
00537                 break;
00538         }
00539 
00540         NPCInfo->desiredYaw = NPCInfo->lockedDesiredYaw = AngleNormalize360(angles[YAW]);
00541 
00542         if ( NPC_UpdateAngles ( qtrue, qtrue ) )
00543         {//FIXME: if angles clamped, this may never work!
00544                 //NPCInfo->shotTime = NPC->attackDebounceTime = 0;
00545 
00546                 if ( shoot )
00547                 {//FIXME: needs to hold this down if using a weapon that requires it, like phaser...
00548                         ucmd.buttons |= BUTTON_ATTACK;
00549                 }
00550                 
00551                 //if ( !shoot || !(NPC->svFlags & SVF_LOCKEDENEMY) )
00552                 if (1)
00553                 {//If locked_enemy is on, dont complete until it is destroyed...
00554                         trap_ICARUS_TaskIDComplete( NPC, TID_BSTATE );
00555                         goto finished;
00556                 }
00557         }
00558         //else if ( shoot && (NPC->svFlags & SVF_LOCKEDENEMY) )
00559         if (0)
00560         {//shooting them till their dead, not aiming right at them yet...
00561                 /*
00562                 qboolean movingTarget = qfalse;
00563 
00564                 if ( NPC->enemy->client )
00565                 {
00566                         if ( VectorLengthSquared( NPC->enemy->client->ps.velocity ) )
00567                         {
00568                                 movingTarget = qtrue;
00569                         }
00570                 }
00571                 else if ( VectorLengthSquared( NPC->enemy->s.pos.trDelta ) )
00572                 {
00573                         movingTarget = qtrue;
00574                 }
00575 
00576                 if (movingTarget )
00577                 */
00578                 {
00579                         float   dist = VectorLength( dir );
00580                         float   yawMiss, yawMissAllow = NPC->enemy->r.maxs[0];
00581                         float   pitchMiss, pitchMissAllow = (NPC->enemy->r.maxs[2] - NPC->enemy->r.mins[2])/2;
00582                         
00583                         if ( yawMissAllow < 8.0f )
00584                         {
00585                                 yawMissAllow = 8.0f;
00586                         }
00587 
00588                         if ( pitchMissAllow < 8.0f )
00589                         {
00590                                 pitchMissAllow = 8.0f;
00591                         }
00592 
00593                         yawMiss = tan(DEG2RAD(AngleDelta ( NPC->client->ps.viewangles[YAW], NPCInfo->desiredYaw ))) * dist;
00594                         pitchMiss = tan(DEG2RAD(AngleDelta ( NPC->client->ps.viewangles[PITCH], NPCInfo->desiredPitch))) * dist;
00595 
00596                         if ( yawMissAllow >= yawMiss && pitchMissAllow > pitchMiss )
00597                         {
00598                                 ucmd.buttons |= BUTTON_ATTACK;
00599                         }
00600                 }
00601         }
00602         
00603         return;
00604                 
00605 finished:
00606         NPCInfo->desiredYaw = client->ps.viewangles[YAW];
00607         NPCInfo->desiredPitch = client->ps.viewangles[PITCH];
00608 
00609         NPCInfo->aimTime = 0;//ok to turn normally now
00610 }

void NPC_BSRemove void   ) 
 

Definition at line 921 of file NPC_behavior.c.

References entityShared_t::contents, entityShared_t::currentOrigin, EF_NODRAW, entityState_s::eFlags, ET_INVISIBLE, entityState_s::eType, FRAMETIME, g_entities, G_FreeEntity(), G_UseTargets2(), gentity_s::health, level, gentity_s::nextthink, NPC, NPC_UpdateAngles(), NULL, qtrue, gentity_s::r, gentity_s::s, gentity_s::target3, gentity_s::targetname, gentity_s::think, level_locals_t::time, and trap_InPVS().

Referenced by NPC_BehaviorSet_Charmed(), and NPC_BehaviorSet_Default().

00922 {
00923         NPC_UpdateAngles ( qtrue, qtrue );
00924         if( !trap_InPVS( NPC->r.currentOrigin, g_entities[0].r.currentOrigin ) )//FIXME: use cg.vieworg?
00925         { //rwwFIXMEFIXME: Care about all clients instead of just 0?
00926                 G_UseTargets2( NPC, NPC, NPC->target3 );
00927                 NPC->s.eFlags |= EF_NODRAW;
00928                 NPC->s.eType = ET_INVISIBLE;
00929                 NPC->r.contents = 0;
00930                 NPC->health = 0;
00931                 NPC->targetname = NULL;
00932 
00933                 //Disappear in half a second
00934                 NPC->think = G_FreeEntity;
00935                 NPC->nextthink = level.time + FRAMETIME;
00936         }//FIXME: else allow for out of FOV???
00937 }

void NPC_BSRunAndShoot void   ) 
 

Definition at line 394 of file NPC_AI_Default.c.

References gNPCstats_e::aggression, usercmd_s::angles, BS_DEFAULT, BS_HUNT_AND_KILL, BUTTON_ATTACK, usercmd_s::buttons, gentity_s::cantHitEnemyCounter, entityShared_t::currentOrigin, gNPC_t::duckDebounceTime, gentity_s::enemy, gNPC_t::goalEntity, gNPC_t::goalRadius, level, NPC, NPC_CheckCanAttack(), NPC_CheckEnemy(), NPC_LostEnemyDecideChase(), NPC_MoveToGoal(), NPC_StandTrackAndShoot(), NPC_UpdateAngles(), NPCInfo, PITCH, qfalse, qtrue, gentity_s::r, gNPC_t::stats, gNPC_t::tempBehavior, level_locals_t::time, ucmd, usercmd_s::upmove, vec3_t, VectorSubtract, and YAW.

Referenced by NPC_BSSearch().

00395 {
00396         /*if(NPC->playerTeam && NPC->enemyTeam)
00397         {
00398                 //FIXME: don't realize this right away- or else enemies show up and we're standing around
00399                 if( teamNumbers[NPC->enemyTeam] == 0 )
00400                 {//ok, stand guard until we find another enemy
00401                         //reset our rush counter
00402                         teamCounter[NPC->playerTeam] = 0;
00403                         NPCInfo->tempBehavior = BS_STAND_GUARD;
00404                         NPC_BSStandGuard();
00405                         return;
00406                 }
00407         }*/
00408 
00409         //NOTE: are we sure we want ALL run and shoot people to move this way?
00410         //Shouldn't it check to see if we have an enemy and our enemy is our goal?!
00411         //Moved that check into NPC_MoveToGoal
00412         //NPCInfo->combatMove = qtrue;
00413 
00414         NPC_CheckEnemy( qtrue, qfalse, qtrue );
00415         
00416         if ( NPCInfo->duckDebounceTime > level.time ) // && NPCInfo->hidingGoal )
00417         {
00418                 ucmd.upmove = -127;
00419                 if ( NPC->enemy )
00420                 {
00421                         NPC_CheckCanAttack( 1.0, qfalse );
00422                 }
00423                 return;         
00424         }
00425 
00426         if ( NPC->enemy )
00427         {
00428                 int monitor = NPC->cantHitEnemyCounter;
00429                 NPC_StandTrackAndShoot( NPC, qfalse );//(NPCInfo->hidingGoal != NULL) );
00430 
00431                 if ( !(ucmd.buttons & BUTTON_ATTACK) && ucmd.upmove >= 0 && NPC->cantHitEnemyCounter > monitor )
00432                 {//not crouching and not firing
00433                         vec3_t  vec;
00434 
00435                         VectorSubtract( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, vec );
00436                         vec[2] = 0;
00437                         if ( VectorLength( vec ) > 128 || NPC->cantHitEnemyCounter >= 10 )
00438                         {//run at enemy if too far away
00439                                 //The cantHitEnemyCounter getting high has other repercussions
00440                                 //100 (10 seconds) will make you try to pick a new enemy... 
00441                                 //But we're chasing, so we clamp it at 50 here
00442                                 if ( NPC->cantHitEnemyCounter > 60 )
00443                                 {
00444                                         NPC->cantHitEnemyCounter = 60;
00445                                 }
00446                                 
00447                                 if ( NPC->cantHitEnemyCounter >= (NPCInfo->stats.aggression+1) * 10 )
00448                                 {
00449                                         NPC_LostEnemyDecideChase();
00450                                 }
00451 
00452                                 //chase and face
00453                                 ucmd.angles[YAW] = 0;
00454                                 ucmd.angles[PITCH] = 0;
00455                                 NPCInfo->goalEntity = NPC->enemy;
00456                                 NPCInfo->goalRadius = 12;
00457                                 //NAV_ClearLastRoute(NPC);
00458                                 NPC_MoveToGoal( qtrue );
00459                                 NPC_UpdateAngles(qtrue, qtrue);
00460                         }
00461                         else
00462                         {
00463                                 //FIXME: this could happen if they're just on the other side
00464                                 //of a thin wall or something else blocking out shot.  That
00465                                 //would make us just stand there and not go around it...
00466                                 //but maybe it's okay- might look like we're waiting for
00467                                 //him to come out...?  
00468                                 //Current solution: runs around if cantHitEnemyCounter gets
00469                                 //to 10 (1 second).  
00470                         }
00471                 }
00472                 else
00473                 {//Clear the can't hit enemy counter here
00474                         NPC->cantHitEnemyCounter = 0;
00475                 }
00476         }
00477         else
00478         {
00479                 if ( NPCInfo->tempBehavior == BS_HUNT_AND_KILL )
00480                 {//lost him, go back to what we were doing before
00481                         NPCInfo->tempBehavior = BS_DEFAULT;
00482                         return;
00483                 }
00484 
00485 //              NPC_BSRun();//only moves if we have a goal
00486         }
00487 }

void NPC_BSSearch void   ) 
 

Definition at line 939 of file NPC_behavior.c.

References gNPC_t::aiFlags, AngleNormalize360(), gNPC_t::behaviorState, BOTH_GUARD_IDLE1, BOTH_GUARD_LOOKAROUND1, BS_DEFAULT, BS_HUNT_AND_KILL, BS_SEARCH, BS_STAND_GUARD, BSET_LOSTENEMY, entityShared_t::currentOrigin, gNPC_t::desiredYaw, gentity_s::enemy, flrand(), G_ActivateBehavior(), gNPC_t::goalEntity, gNPC_t::homeWp, gNPC_t::investigateDebounceTime, level, NAV_FindClosestWaypointForEnt(), NPC, NPC_BSRunAndShoot(), NPC_CheckEnemy(), NPC_MoveToGoal(), NPC_SetAnim(), NPC_UpdateAngles(), NPCAI_ENROUTE_TO_HOMEWP, NPCInfo, Q_irand(), qfalse, qtrue, gentity_s::r, SETANIM_BOTH, SETANIM_FLAG_NORMAL, gNPC_t::tempBehavior, gNPC_t::tempGoal, level_locals_t::time, trap_Nav_GetNodeEdge(), trap_Nav_GetNodeNumEdges(), trap_Nav_GetNodePosition(), vec3_t, VectorSubtract, vectoyaw(), gentity_s::waypoint, and WAYPOINT_NONE.

Referenced by NPC_BehaviorSet_Charmed(), NPC_BehaviorSet_Default(), and NPC_BSWampa_Default().

00940 {
00941         NPC_CheckEnemy(qtrue, qfalse, qtrue);
00942         //Look for enemies, if find one:
00943         if ( NPC->enemy )
00944         {
00945                 if( NPCInfo->tempBehavior == BS_SEARCH )
00946                 {//if tempbehavior, set tempbehavior to default
00947                         NPCInfo->tempBehavior = BS_DEFAULT;
00948                 }
00949                 else
00950                 {//if bState, change to run and shoot
00951                         NPCInfo->behaviorState = BS_HUNT_AND_KILL;
00952                         NPC_BSRunAndShoot();
00953                 }
00954                 return;
00955         }
00956 
00957         //FIXME: what if our goalEntity is not NULL and NOT our tempGoal - they must
00958         //want us to do something else?  If tempBehavior, just default, else set
00959         //to run and shoot...?
00960 
00961         //FIXME: Reimplement
00962 
00963         if ( !NPCInfo->investigateDebounceTime )
00964         {//On our way to a tempGoal
00965                 float   minGoalReachedDistSquared = 32*32;
00966                 vec3_t  vec;
00967 
00968                 //Keep moving toward our tempGoal
00969                 NPCInfo->goalEntity = NPCInfo->tempGoal;
00970 
00971                 VectorSubtract ( NPCInfo->tempGoal->r.currentOrigin, NPC->r.currentOrigin, vec);
00972                 if ( vec[2] < 24 )
00973                 {
00974                         vec[2] = 0;
00975                 }
00976 
00977                 if ( NPCInfo->tempGoal->waypoint != WAYPOINT_NONE )
00978                 {
00979                         /*
00980                         //FIXME: can't get the radius...
00981                         float   wpRadSq = waypoints[NPCInfo->tempGoal->waypoint].radius * waypoints[NPCInfo->tempGoal->waypoint].radius;
00982                         if ( minGoalReachedDistSquared > wpRadSq )
00983                         {
00984                                 minGoalReachedDistSquared = wpRadSq;
00985                         }
00986                         */
00987 
00988                         minGoalReachedDistSquared = 32*32;//12*12;
00989                 }
00990 
00991                 if ( VectorLengthSquared( vec ) < minGoalReachedDistSquared )
00992                 {
00993                         //Close enough, just got there
00994                         NPC->waypoint = NAV_FindClosestWaypointForEnt( NPC, WAYPOINT_NONE );
00995 
00996                         if ( ( NPCInfo->homeWp == WAYPOINT_NONE ) || ( NPC->waypoint == WAYPOINT_NONE ) )
00997                         {
00998                                 //Heading for or at an invalid waypoint, get out of this bState
00999                                 if( NPCInfo->tempBehavior == BS_SEARCH )
01000                                 {//if tempbehavior, set tempbehavior to default
01001                                         NPCInfo->tempBehavior = BS_DEFAULT;
01