codemp/game/NPC_utils.c File Reference

#include "b_local.h"
#include "../icarus/Q3_Interface.h"
#include "../ghoul2/G2.h"

Go to the source code of this file.

Defines

#define VALID_ATTACK_CONE   2.0f
#define TURN_ON   0x00000000
#define TURN_OFF   0x00000100
#define MAX_RADIUS_ENTS   256
#define NEAR_DEFAULT_RADIUS   256

Functions

void G_DebugPrint (int level, const char *format,...)
void CalcEntitySpot (const gentity_t *ent, const spot_t spot, vec3_t point)
qboolean NPC_UpdateAngles (qboolean doPitch, qboolean doYaw)
void NPC_AimWiggle (vec3_t enemy_org)
qboolean NPC_UpdateFiringAngles (qboolean doPitch, qboolean doYaw)
void NPC_UpdateShootAngles (vec3_t angles, qboolean doPitch, qboolean doYaw)
void SetTeamNumbers (void)
qboolean G_ActivateBehavior (gentity_t *self, int bset)
void NPC_SetBoneAngles (gentity_t *ent, char *bone, vec3_t angles)
void NPC_SetSurfaceOnOff (gentity_t *ent, const char *surfaceName, int surfaceFlags)
qboolean NPC_SomeoneLookingAtMe (gentity_t *ent)
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_ValidEnemy (gentity_t *ent)
qboolean NPC_TargetVisible (gentity_t *ent)
int NPC_FindNearestEnemy (gentity_t *ent)
gentity_tNPC_PickEnemyExt (qboolean checkAlerts)
qboolean NPC_FindPlayer (void)
qboolean NPC_FindEnemy (qboolean checkAlerts)
qboolean NPC_CheckEnemyExt (qboolean checkAlerts)
qboolean NPC_FacePosition (vec3_t position, qboolean doPitch)
qboolean NPC_FaceEntity (gentity_t *ent, qboolean doPitch)
qboolean NPC_FaceEnemy (qboolean doPitch)
qboolean NPC_CheckCanAttackExt (void)
void NPC_ClearLookTarget (gentity_t *self)
void NPC_SetLookTarget (gentity_t *self, int entNum, int clearTime)
qboolean NPC_CheckLookTarget (gentity_t *self)
void G_AddVoiceEvent (gentity_t *self, int event, int speakDebounceTime)
void NPC_CheckCharmed (void)
void G_GetBoltPosition (gentity_t *self, int boltIndex, vec3_t pos, int modelIndex)
float NPC_EntRangeFromBolt (gentity_t *targEnt, int boltIndex)
float NPC_EnemyRangeFromBolt (int boltIndex)
int NPC_GetEntsNearBolt (int *radiusEnts, float radius, int boltIndex, vec3_t boltOrg)

Variables

int teamNumbers [TEAM_NUM_TEAMS]
int teamStrength [TEAM_NUM_TEAMS]
int teamCounter [TEAM_NUM_TEAMS]
stringID_table_t BSTable []
stringID_table_t BSETTable []


Define Documentation

#define MAX_RADIUS_ENTS   256
 

Definition at line 1243 of file NPC_utils.c.

#define NEAR_DEFAULT_RADIUS   256
 

Definition at line 1244 of file NPC_utils.c.

#define TURN_OFF   0x00000100
 

Definition at line 999 of file NPC_utils.c.

#define TURN_ON   0x00000000
 

Definition at line 998 of file NPC_utils.c.

#define VALID_ATTACK_CONE   2.0f
 

Definition at line 11 of file NPC_utils.c.

Referenced by NPC_FacePosition().


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 G_ActivateBehavior gentity_t self,
int  bset
 

Definition at line 851 of file NPC_utils.c.

References gentity_s::behaviorSet, gNPC_t::behaviorState, BS_DEFAULT, BSETTable, BSTable, bState_t, G_DebugPrint(), gentity_t, GetIDForString(), GetStringForID(), gentity_s::NPC, NULL, Q3_SCRIPT_DIR, qboolean, qfalse, qtrue, gentity_s::targetname, gNPC_t::tempBehavior, trap_ICARUS_RunScript(), va(), VALIDSTRING, and WL_VERBOSE.

Referenced by emplaced_gun_pain(), ForceTelepathyCheckDirectNPCTarget(), func_static_use(), func_timer_use(), func_usable_use(), funcBBrushPain(), funcBBrushUse(), G_CheckVictoryScript(), G_Damage(), G_SetEnemy(), G_SpawnGEntityFromSpawnVars(), hurt_use(), misc_dlight_use(), multi_trigger_run(), NPC_Begin(), NPC_Blocked(), NPC_BSSearch(), NPC_BSSleep(), NPC_CheckAttackScript(), NPC_CheckInvestigate(), NPC_ExecuteBState(), NPC_Pain(), NPC_StartFlee(), NPC_UseResponse(), player_die(), scriptrunner_run(), sentry_use(), target_activate_use(), target_counter_use(), target_deactivate_use(), target_kill_use(), target_level_change_use(), target_play_music_use(), target_random_use(), target_relay_use(), target_teleporter_use(), Use_BinaryMover(), Use_Target_Delay(), Use_Target_Print(), Use_target_push(), Use_Target_Speaker(), and use_wall().

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_AddVoiceEvent gentity_t self,
int  event,
int  speakDebounceTime
 

Definition at line 23 of file NPC_sounds.c.

References gNPC_t::blockedSpeechDebounceTime, gentity_s::client, EV_ANGER1, EV_CHASE1, EV_GIVEUP1, EV_SUSPICIOUS5, G_SpeechEvent(), gentity_t, level, gentity_s::NPC, PM_DEAD, playerState_s::pm_type, gclient_s::ps, SCF_NO_ALERT_TALK, SCF_NO_COMBAT_TALK, gNPC_t::scriptFlags, TID_CHAN_VOICE, level_locals_t::time, and trap_ICARUS_TaskIDPending().

Referenced by G_SetEnemy(), Jedi_Ambush(), Jedi_PlayBlockedPushSound(), Jedi_PlayDeflectSound(), NPC_BSGM_Attack(), NPC_CheckCharmed(), NPC_ChoosePainAnimation(), NPC_GM_Pain(), NPC_Grenadier_Pain(), NPC_Grenadier_PlayConfusionSound(), NPC_HandleAIFlags(), NPC_Jedi_Pain(), NPC_Jedi_PlayConfusionSound(), NPC_PlayConfusionSound(), NPC_Respond(), NPC_Sniper_Pain(), NPC_Sniper_PlayConfusionSound(), NPC_ST_Pain(), and NPC_Surrender().

00024 {
00025         if ( !self->NPC )
00026         {
00027                 return;
00028         }
00029 
00030         if ( !self->client || self->client->ps.pm_type >= PM_DEAD )
00031         {
00032                 return;
00033         }
00034 
00035         if ( self->NPC->blockedSpeechDebounceTime > level.time )
00036         {
00037                 return;
00038         }
00039 
00040         if ( trap_ICARUS_TaskIDPending( self, TID_CHAN_VOICE ) )
00041         {
00042                 return;
00043         }
00044 
00045         
00046         if ( (self->NPC->scriptFlags&SCF_NO_COMBAT_TALK) && ( (event >= EV_ANGER1 && event <= EV_VICTORY3) || (event >= EV_CHASE1 && event <= EV_SUSPICIOUS5) ) )//(event < EV_FF_1A || event > EV_FF_3C) && (event < EV_RESPOND1 || event > EV_MISSION3) )
00047         {
00048                 return;
00049         }
00050         
00051         if ( (self->NPC->scriptFlags&SCF_NO_ALERT_TALK) && (event >= EV_GIVEUP1 && event <= EV_SUSPICIOUS5) )
00052         {
00053                 return;
00054         }
00055         //FIXME: Also needs to check for teammates. Don't want
00056         //              everyone babbling at once
00057 
00058         //NOTE: was losing too many speech events, so we do it directly now, screw networking!
00059         //G_AddEvent( self, event, 0 );
00060         G_SpeechEvent( self, event );
00061 
00062         //won't speak again for 5 seconds (unless otherwise specified)
00063         self->NPC->blockedSpeechDebounceTime = level.time + ((speakDebounceTime==0) ? 5000 : speakDebounceTime);
00064 }

void G_DebugPrint int  level,
const char *  format,
... 
 

Definition at line 275 of file g_ICARUScb.c.

References Com_Printf(), g_developer, g_entities, vmCvar_t::integer, level, MAX_GENTITIES, S_COLOR_BLUE, S_COLOR_GREEN, S_COLOR_RED, S_COLOR_YELLOW, sscanf(), va_end, va_list, va_start, vsprintf(), WL_DEBUG, WL_ERROR, WL_VERBOSE, and WL_WARNING.

Referenced by G_ActivateBehavior(), NPC_Begin(), Q3_GetFloat(), Q3_GetString(), Q3_GetVector(), Q3_Kill(), Q3_Lerp2Angles(), Q3_Lerp2End(), Q3_Lerp2Origin(), Q3_Lerp2Pos(), Q3_Lerp2Start(), Q3_Remove(), Q3_RemoveEnt(), Q3_Set(), Q3_SetICARUSFreeze(), Q3_SetLoopSound(), Q3_SetParm(), Q3_SetViewEntity(), Q3_Use(), and target_counter_use().

00276 {
00277         va_list         argptr;
00278         char            text[1024];
00279 
00280         //Don't print messages they don't want to see
00281         //if ( g_ICARUSDebug->integer < level )
00282         if (g_developer.integer != 2)
00283                 return;
00284 
00285         va_start (argptr, format);
00286         vsprintf (text, format, argptr);
00287         va_end (argptr);
00288 
00289         //Add the color formatting
00290         switch ( level )
00291         {
00292                 case WL_ERROR:
00293                         Com_Printf ( S_COLOR_RED"ERROR: %s", text );
00294                         break;
00295                 
00296                 case WL_WARNING:
00297                         Com_Printf ( S_COLOR_YELLOW"WARNING: %s", text );
00298                         break;
00299                 
00300                 case WL_DEBUG:
00301                         {
00302                                 int             entNum;
00303                                 char    *buffer;
00304 
00305                                 sscanf( text, "%d", &entNum );
00306 
00307                                 //if ( ( ICARUS_entFilter >= 0 ) && ( ICARUS_entFilter != entNum ) )
00308                                 //      return;
00309 
00310                                 buffer = (char *) text;
00311                                 buffer += 5;
00312 
00313                                 if ( ( entNum < 0 ) || ( entNum > MAX_GENTITIES ) )
00314                                         entNum = 0;
00315 
00316                                 Com_Printf ( S_COLOR_BLUE"DEBUG: %s(%d): %s\n", g_entities[entNum].script_targetname, entNum, buffer );
00317                                 break;
00318                         }
00319                 default:
00320                 case WL_VERBOSE:
00321                         Com_Printf ( S_COLOR_GREEN"INFO: %s", text );
00322                         break;
00323         }
00324 }

void G_GetBoltPosition gentity_t self,
int  boltIndex,
vec3_t  pos,
int  modelIndex
 

Definition at line 1707 of file NPC_utils.c.

References gentity_s::client, entityShared_t::currentAngles, entityShared_t::currentOrigin, gentity_t, gentity_s::ghoul2, gentity_s::inuse, level, gentity_s::modelScale, NULL, ORIGIN, gclient_s::ps, gentity_s::r, level_locals_t::time, trap_G2API_GetBoltMatrix(), vec3_t, VectorCopy, VectorSet, playerState_s::viewangles, and YAW.

Referenced by NPC_EntRangeFromBolt(), NPC_GetEntsNearBolt(), and Rancor_Attack().

01708 {
01709         mdxaBone_t      boltMatrix;
01710         vec3_t          result, angles;
01711         
01712         if (!self || !self->inuse)
01713         {
01714                 return;
01715         }
01716 
01717         if (self->client)
01718         { //clients don't actually even keep r.currentAngles maintained
01719                 VectorSet(angles, 0, self->client->ps.viewangles[YAW], 0);
01720         }
01721         else
01722         {
01723                 VectorSet(angles, 0, self->r.currentAngles[YAW], 0);
01724         }
01725 
01726         if (  !self->ghoul2 )
01727         {
01728                 return;
01729         }
01730 
01731         trap_G2API_GetBoltMatrix( self->ghoul2, modelIndex, 
01732                                 boltIndex,
01733                                 &boltMatrix, angles, self->r.currentOrigin, level.time,
01734                                 NULL, self->modelScale );
01735         if ( pos )
01736         {
01737                 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, result );
01738                 VectorCopy( result, pos );
01739         }
01740 }

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 }

qboolean NPC_CheckCanAttackExt void   ) 
 

Definition at line 1588 of file NPC_utils.c.

References gentity_s::enemy, NPC, NPC_ClearShot(), NPC_FaceEnemy(), NPCInfo, qboolean, qfalse, qtrue, SCF_DONT_FIRE, and gNPC_t::scriptFlags.

01589 {
01590         //We don't want them to shoot
01591         if( NPCInfo->scriptFlags & SCF_DONT_FIRE )
01592                 return qfalse;
01593 
01594         //Turn to face
01595         if ( NPC_FaceEnemy( qtrue ) == qfalse )
01596                 return qfalse;
01597 
01598         //Must have a clear line of sight to the target
01599         if ( NPC_ClearShot( NPC->enemy ) == qfalse )
01600                 return qfalse;
01601 
01602         return qtrue;
01603 }

void NPC_CheckCharmed void   ) 
 

Definition at line 1687 of file NPC_utils.c.

References BS_DEFAULT, BS_FOLLOW_LEADER, gNPC_t::charmedTime, gentity_s::client, gclient_s::enemyTeam, EV_CONFUSE1, EV_CONFUSE3, G_AddVoiceEvent(), G_ClearEnemy(), gentity_s::genericValue1, gentity_s::genericValue2, gentity_s::genericValue3, gclient_s::leader, level, NPC, NPCInfo, NULL, gclient_s::playerTeam, Q_irand(), gentity_s::s, entityState_s::teamowner, gNPC_t::tempBehavior, and level_locals_t::time.

Referenced by NPC_RunBehavior().

01688 {
01689         if ( NPCInfo->charmedTime && NPCInfo->charmedTime < level.time && NPC->client )
01690         {//we were charmed, set us back!
01691                 NPC->client->playerTeam = NPC->genericValue1;
01692                 NPC->client->enemyTeam = NPC->genericValue2;
01693                 NPC->s.teamowner = NPC->genericValue3;
01694 
01695                 NPC->client->leader = NULL;
01696                 if ( NPCInfo->tempBehavior == BS_FOLLOW_LEADER )
01697                 {
01698                         NPCInfo->tempBehavior = BS_DEFAULT;
01699                 }
01700                 G_ClearEnemy( NPC );
01701                 NPCInfo->charmedTime = 0;
01702                 //say something to let player know you've snapped out of it
01703                 G_AddVoiceEvent( NPC, Q_irand(EV_CONFUSE1, EV_CONFUSE3), 2000 );
01704         }
01705 }

qboolean NPC_CheckEnemyExt qboolean  checkAlerts  ) 
 

Definition at line 1469 of file NPC_utils.c.

References NPC_FindEnemy(), and qboolean.

Referenced by ATST_Attack(), Howler_Patrol(), ImperialProbe_AttackDecision(), Interrogator_Attack(), Mark1_AttackDecision(), MineMonster_Patrol(), NPC_BSEmplaced(), NPC_BSGM_Attack(), NPC_BSGrenadier_Attack(), NPC_BSRancor_Default(), NPC_BSSniper_Attack(), NPC_BSST_Attack(), NPC_BSWampa_Default(), Rancor_Patrol(), Remote_Attack(), Sentry_AttackDecision(), and Wampa_Patrol().

01470 {
01471         //Make sure we're ready to think again
01472 /*
01473         if ( NPCInfo->enemyCheckDebounceTime > level.time )
01474                 return qfalse;
01475 
01476         //Get our next think time
01477         NPCInfo->enemyCheckDebounceTime = level.time + NPC_GetCheckDelta();
01478 
01479         //Attempt to find an enemy
01480         return NPC_FindEnemy();
01481 */
01482         return NPC_FindEnemy( checkAlerts );
01483 }

qboolean NPC_CheckLookTarget gentity_t self  ) 
 

Definition at line 1653 of file NPC_utils.c.

References gentity_s::client, gentity_s::enemy, ENTITYNUM_WORLD, g_entities, gentity_t, level, renderInfo_s::lookTarget, renderInfo_s::lookTargetClearTime, NPC_ClearLookTarget(), NULL, qboolean, qfalse, qtrue, gclient_s::renderInfo, and level_locals_t::time.

Referenced by G_ClearEnemy(), NPC_ExecuteBState(), and NPC_TempLookTarget().

01654 {
01655         if ( self->client )
01656         {
01657                 if ( self->client->renderInfo.lookTarget >= 0 && self->client->renderInfo.lookTarget < ENTITYNUM_WORLD )
01658                 {//within valid range
01659                         if ( (&g_entities[self->client->renderInfo.lookTarget] == NULL) || !g_entities[self->client->renderInfo.lookTarget].inuse )
01660                         {//lookTarget not inuse or not valid anymore
01661                                 NPC_ClearLookTarget( self );
01662                         }
01663                         else if ( self->client->renderInfo.lookTargetClearTime && self->client->renderInfo.lookTargetClearTime < level.time )
01664                         {//Time to clear lookTarget
01665                                 NPC_ClearLookTarget( self );
01666                         }
01667                         else if ( g_entities[self->client->renderInfo.lookTarget].client && self->enemy && (&g_entities[self->client->renderInfo.lookTarget] != self->enemy) )
01668                         {//should always look at current enemy if engaged in battle... FIXME: this could override certain scripted lookTargets...???
01669                                 NPC_ClearLookTarget( self );
01670                         }
01671                         else
01672                         {
01673                                 return qtrue;
01674                         }
01675                 }
01676         }
01677 
01678         return qfalse;
01679 }

void NPC_ClearLookTarget gentity_t self  ) 
 

Definition at line 1611 of file NPC_utils.c.

References gentity_s::client, EF2_HELD_BY_MONSTER, playerState_s::eFlags2, ENTITYNUM_NONE, gentity_t, renderInfo_s::lookTarget, renderInfo_s::lookTargetClearTime, gclient_s::ps, and gclient_s::renderInfo.

Referenced by G_ClearEnemy(), and NPC_CheckLookTarget().

01612 {
01613         if ( !self->client )
01614         {
01615                 return;
01616         }
01617 
01618         if ( (self->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
01619         {//lookTarget is set by and to the monster that's holding you, no other operations can change that
01620                 return;
01621         }
01622 
01623         self->client->renderInfo.lookTarget = ENTITYNUM_NONE;//ENTITYNUM_WORLD;
01624         self->client->renderInfo.lookTargetClearTime = 0;
01625 }

qboolean NPC_ClearLOS const vec3_t  start,
const vec3_t  end
 

Definition at line 1069 of file NPC_utils.c.

References G_ClearLOS(), NPC, qboolean, and vec3_t.

Referenced by NPC_FindCombatPoint(), and Wampa_Combat().

01070 {
01071         return G_ClearLOS( NPC, start, end );
01072 }

qboolean NPC_ClearLOS2 gentity_t ent,
const vec3_t  end
 

Definition at line 1085 of file NPC_utils.c.

References G_ClearLOS2(), gentity_t, NPC, qboolean, and vec3_t.

Referenced by G_AlertTeam(), NPC_ShySpawn(), and vmMain().

01086 {
01087         return G_ClearLOS2( NPC, ent, end );
01088 }

qboolean NPC_ClearLOS3 const vec3_t  start,
gentity_t ent
 

Definition at line 1081 of file NPC_utils.c.

References G_ClearLOS3(), gentity_t, NPC, qboolean, and vec3_t.

Referenced by NPC_FindCombatPoint().

01082 {
01083         return G_ClearLOS3( NPC, start, ent );
01084 }

qboolean NPC_ClearLOS4 gentity_t ent  ) 
 

Definition at line 1077 of file NPC_utils.c.

References G_ClearLOS4(), gentity_t, NPC, and qboolean.

Referenced by ATST_Attack(), Boba_FireDecide(), Howler_Combat(), ImperialProbe_AttackDecision(), Interrogator_Attack(), Jedi_CheckAmbushPlayer(), Mark1_AttackDecision(), Mark2_AttackDecision(), MineMonster_Combat(), NPC_BSEmplaced(), NPC_BSGM_Attack(), NPC_BSGrenadier_Attack(), NPC_BSJedi_FollowLeader(), NPC_BSSniper_Attack(), NPC_BSST_Attack(), NPC_CheckEnemyStealth(), NPC_TargetVisible(), Rancor_Combat(), Remote_Attack(), Seeker_Attack(), Seeker_FindEnemy(), Sentry_AttackDecision(), and ST_Commander().

01078 {
01079         return G_ClearLOS4( NPC, ent );
01080 }

qboolean NPC_ClearLOS5 const vec3_t  end  ) 
 

Definition at line 1073 of file NPC_utils.c.

References G_ClearLOS5(), NPC, qboolean, and vec3_t.

01074 {
01075         return G_ClearLOS5( NPC, end );
01076 }

float NPC_EnemyRangeFromBolt int  boltIndex  ) 
 

Definition at line 1756 of file NPC_utils.c.

References gentity_s::enemy, NPC, and NPC_EntRangeFromBolt().

01757 {
01758         return (NPC_EntRangeFromBolt( NPC->enemy, boltIndex ));
01759 }

float NPC_EntRangeFromBolt gentity_t targEnt,
int  boltIndex
 

Definition at line 1742 of file NPC_utils.c.

References entityShared_t::currentOrigin, G_GetBoltPosition(), gentity_t, NPC, Q3_INFINITE, gentity_s::r, and vec3_t.

Referenced by NPC_EnemyRangeFromBolt().

01743 {
01744         vec3_t  org;
01745 
01746         if ( !targEnt )
01747         {
01748                 return Q3_INFINITE;
01749         }
01750 
01751         G_GetBoltPosition( NPC, boltIndex, org, 0 );
01752 
01753         return (Distance( targEnt->r.currentOrigin, org ));
01754 }

qboolean NPC_FaceEnemy qboolean  doPitch  ) 
 

Definition at line 1571 of file NPC_utils.c.

References gentity_s::enemy, NPC, NPC_FaceEntity(), NULL, qboolean, and qfalse.

Referenced by ATST_Attack(), Howler_Combat(), ImperialProbe_AttackDecision(), Interrogator_Attack(), Interrogator_Hunt(), Mark1_AttackDecision(), Mark1_Hunt(), Mark2_AttackDecision(), Mark2_Hunt(), MineMonster_Combat(), NPC_BSEmplaced(), NPC_BSGM_Attack(), NPC_BSGrenadier_Attack(), NPC_BSRancor_Default(), NPC_BSST_Attack(), NPC_BSWampa_Default(), NPC_CheckCanAttackExt(), Rancor_Combat(), Seeker_Hunt(), Sentry_AttackDecision(), Sentry_MaintainHeight(), and Wampa_Combat().

01572 {
01573         if ( NPC == NULL )
01574                 return qfalse;
01575 
01576         if ( NPC->enemy == NULL )
01577                 return qfalse;
01578 
01579         return NPC_FaceEntity( NPC->enemy, doPitch );
01580 }

qboolean NPC_FaceEntity gentity_t ent,
qboolean  doPitch
 

Definition at line 1555 of file NPC_utils.c.

References CalcEntitySpot(), gentity_t, NPC_FacePosition(), qboolean, SPOT_HEAD_LEAN, and vec3_t.

Referenced by NAV_ResolveBlock(), NAV_ResolveEntityCollision(), NAV_TestForBlocked(), NPC_BSJedi_FollowLeader(), and NPC_FaceEnemy().

01556 {
01557         vec3_t          entPos;
01558 
01559         //Get the positions
01560         CalcEntitySpot( ent, SPOT_HEAD_LEAN, entPos );
01561 
01562         return NPC_FacePosition( entPos, doPitch );
01563 }

qboolean NPC_FacePosition vec3_t  position,
qboolean  doPitch
 

Definition at line 1491 of file NPC_utils.c.

References AngleNormalize360(), usercmd_s::angles, CalcEntitySpot(), CLASS_ATST, CLASS_GALAKMECH, CLASS_RANCOR, CLASS_WAMPA, client, gentity_s::client, playerState_s::delta_angles, gNPC_t::desiredPitch, gNPC_t::desiredYaw, gentity_s::enemy, fabs(), flrand(), GetAnglesForDirection(), level, entityShared_t::maxs, NPC, gclient_s::NPC_class, NPC_UpdateAngles(), NPCInfo, PITCH, gclient_s::ps, qboolean, qfalse, qtrue, gentity_s::r, SHORT2ANGLE, sin(), SPOT_HEAD_LEAN, SPOT_ORIGIN, SPOT_WEAPON, level_locals_t::time, ucmd, VALID_ATTACK_CONE, vec3_t, and YAW.

Referenced by NPC_FaceEntity().

01492 {
01493         vec3_t          muzzle;
01494         vec3_t          angles;
01495         float           yawDelta;
01496         qboolean        facing = qtrue;
01497 
01498         //Get the positions
01499         if ( NPC->client && (NPC->client->NPC_class == CLASS_RANCOR || NPC->client->NPC_class == CLASS_WAMPA) )// || NPC->client->NPC_class == CLASS_SAND_CREATURE) )
01500         {
01501                 CalcEntitySpot( NPC, SPOT_ORIGIN, muzzle );
01502                 muzzle[2] += NPC->r.maxs[2] * 0.75f;
01503         }
01504         else if ( NPC->client && NPC->client->NPC_class == CLASS_GALAKMECH )
01505         {
01506                 CalcEntitySpot( NPC, SPOT_WEAPON, muzzle );
01507         }
01508         else
01509         {
01510                 CalcEntitySpot( NPC, SPOT_HEAD_LEAN, muzzle );//SPOT_HEAD
01511         }
01512 
01513         //Find the desired angles
01514         GetAnglesForDirection( muzzle, position, angles );
01515 
01516         NPCInfo->desiredYaw             = AngleNormalize360( angles[YAW] );
01517         NPCInfo->desiredPitch   = AngleNormalize360( angles[PITCH] );
01518 
01519         if ( NPC->enemy && NPC->enemy->client && NPC->enemy->client->NPC_class == CLASS_ATST )
01520         {
01521                 // FIXME: this is kind of dumb, but it was the easiest way to get it to look sort of ok
01522                 NPCInfo->desiredYaw     += flrand( -5, 5 ) + sin( level.time * 0.004f ) * 7;
01523                 NPCInfo->desiredPitch += flrand( -2, 2 );
01524         }
01525         //Face that yaw
01526         NPC_UpdateAngles( qtrue, qtrue );
01527 
01528         //Find the delta between our goal and our current facing
01529         yawDelta = AngleNormalize360( NPCInfo->desiredYaw - ( SHORT2ANGLE( ucmd.angles[YAW] + client->ps.delta_angles[YAW] ) ) );
01530         
01531         //See if we are facing properly
01532         if ( fabs( yawDelta ) > VALID_ATTACK_CONE )
01533                 facing = qfalse;
01534 
01535         if ( doPitch )
01536         {
01537                 //Find the delta between our goal and our current facing
01538                 float currentAngles = ( SHORT2ANGLE( ucmd.angles[PITCH] + client->ps.delta_angles[PITCH] ) );
01539                 float pitchDelta = NPCInfo->desiredPitch - currentAngles;
01540                 
01541                 //See if we are facing properly
01542                 if ( fabs( pitchDelta ) > VALID_ATTACK_CONE )
01543                         facing = qfalse;
01544         }
01545 
01546         return facing;
01547 }

qboolean NPC_FindEnemy qboolean  checkAlerts  ) 
 

Definition at line 1407 of file NPC_utils.c.

References CLASS_RANCOR, CLASS_WAMPA, gentity_s::client, gNPC_t::confusionTime, gentity_s::enemy, G_ClearEnemy(), G_SetEnemy(), gentity_t, level, NPC, gclient_s::NPC_class, NPC_PickEnemyExt(), NPC_ValidEnemy(), NPCInfo, qboolean, qfalse, qtrue, and level_locals_t::time.

Referenced by NPC_CheckEnemyExt().

01408 {
01409         gentity_t *newenemy;
01410 
01411         //We're ignoring all enemies for now
01412         //if( NPC->svFlags & SVF_IGNORE_ENEMIES )
01413         if (0) //rwwFIXMEFIXME: support for flag
01414         {
01415                 G_ClearEnemy( NPC );
01416                 return qfalse;
01417         }
01418 
01419         //we can't pick up any enemies for now
01420         if( NPCInfo->confusionTime > level.time )
01421         {
01422                 return qfalse;
01423         }
01424 
01425         //Don't want a new enemy
01426         //rwwFIXMEFIXME: support for locked enemy
01427         //if ( ( ValidEnemy( NPC->enemy ) ) && ( NPC->svFlags & SVF_LOCKEDENEMY ) )
01428         //      return qtrue;
01429 
01430         //See if the player is closer than our current enemy
01431         if ( NPC_CheckPlayerDistance() )
01432         {
01433                 return qtrue;
01434         }
01435 
01436         //Otherwise, turn off the flag
01437 //      NPC->svFlags &= ~SVF_LOCKEDENEMY;
01438         //See if the player is closer than our current enemy
01439         if ( NPC->client->NPC_class != CLASS_RANCOR 
01440                 && NPC->client->NPC_class != CLASS_WAMPA
01441                 //&& NPC->client->NPC_class != CLASS_SAND_CREATURE
01442                 && NPC_CheckPlayerDistance() )
01443         {//rancors, wampas & sand creatures don't care if player is closer, they always go with closest
01444                 return qtrue;
01445         }
01446 
01447         //If we've gotten here alright, then our target it still valid
01448         if ( NPC_ValidEnemy( NPC->enemy ) )
01449                 return qtrue;
01450 
01451         newenemy = NPC_PickEnemyExt( checkAlerts );
01452 
01453         //if we found one, take it as the enemy
01454         if( NPC_ValidEnemy( newenemy ) )
01455         {
01456                 G_SetEnemy( NPC, newenemy );
01457                 return qtrue;
01458         }
01459 
01460         return qfalse;
01461 }

int NPC_FindNearestEnemy gentity_t ent  ) 
 

Definition at line 1246 of file NPC_utils.c.

References entityShared_t::currentOrigin, g_entities, gentity_t, MAX_RADIUS_ENTS, NPC_TargetVisible(), NPC_ValidEnemy(), NPCInfo, entityState_s::number, qfalse, gentity_s::r, gentity_s::s, gNPC_t::stats, trap_EntitiesInBox(), vec3_t, gNPCstats_e::visrange, and WORLD_SIZE.

Referenced by NPC_PickEnemyExt().

01247 {
01248         int                     iradiusEnts[ MAX_RADIUS_ENTS ];
01249         gentity_t       *radEnt;
01250         vec3_t          mins, maxs;
01251         int                     nearestEntID = -1;
01252         float           nearestDist = (float)WORLD_SIZE*(float)WORLD_SIZE;
01253         float           distance;
01254         int                     numEnts, numChecks = 0;
01255         int                     i;
01256 
01257         //Setup the bbox to search in
01258         for ( i = 0; i < 3; i++ )
01259         {
01260                 mins[i] = ent->r.currentOrigin[i] - NPCInfo->stats.visrange;
01261                 maxs[i] = ent->r.currentOrigin[i] + NPCInfo->stats.visrange;
01262         }
01263 
01264         //Get a number of entities in a given space
01265         numEnts = trap_EntitiesInBox( mins, maxs, iradiusEnts, MAX_RADIUS_ENTS );
01266 
01267         for ( i = 0; i < numEnts; i++ )
01268         {
01269                 radEnt = &g_entities[iradiusEnts[i]];
01270                 //Don't consider self
01271                 if ( radEnt == ent )
01272                         continue;
01273 
01274                 //Must be valid
01275                 if ( NPC_ValidEnemy( radEnt ) == qfalse )
01276                         continue;
01277 
01278                 numChecks++;
01279                 //Must be visible
01280                 if ( NPC_TargetVisible( radEnt ) == qfalse )
01281                         continue;
01282 
01283                 distance = DistanceSquared( ent->r.currentOrigin, radEnt->r.currentOrigin );
01284 
01285                 //Found one closer to us
01286                 if ( distance < nearestDist )
01287                 {
01288                         nearestEntID = radEnt->s.number;
01289                         nearestDist = distance;
01290                 }
01291         }
01292 
01293         return nearestEntID;
01294 }

qboolean NPC_FindPlayer void   ) 
 

Definition at line 1356 of file NPC_utils.c.

References g_entities, NPC_TargetVisible(), and qboolean.

01357 {
01358         return NPC_TargetVisible( &g_entities[0] );
01359 }

int NPC_GetEntsNearBolt int *  radiusEnts,
float  radius,
int  boltIndex,
vec3_t  boltOrg
 

Definition at line 1761 of file NPC_utils.c.

References G_GetBoltPosition(), NPC, trap_EntitiesInBox(), vec3_t, and VectorCopy.

Referenced by Rancor_Bite(), Rancor_Smash(), Rancor_Swing(), and Wampa_Slash().

01762 {
01763         vec3_t          mins, maxs;
01764         int                     i;
01765 
01766         //get my handRBolt's position
01767         vec3_t  org;
01768 
01769         G_GetBoltPosition( NPC, boltIndex, org, 0 );
01770 
01771         VectorCopy( org, boltOrg );
01772 
01773         //Setup the bbox to search in
01774         for ( i = 0; i < 3; i++ )
01775         {
01776                 mins[i] = boltOrg[i] - radius;
01777                 maxs[i] = boltOrg[i] + radius;
01778         }
01779 
01780         //Get the number of entities in a given space
01781         return (trap_EntitiesInBox( mins, maxs, radiusEnts, 128 ));
01782 }

gentity_t* NPC_PickEnemyExt qboolean  checkAlerts  ) 
 

Definition at line 1302 of file NPC_utils.c.

References AEL_DISCOVERED, alertEvent_t, level_locals_t::alertEvents, gentity_s::client, gentity_s::enemy, g_entities, gentity_t, alertEvent_s::level, level, NPC, NPC_CheckAlertEvents(), NPC_FindNearestEnemy(), NULL, alertEvent_s::owner, gclient_s::playerTeam, and qtrue.

Referenced by NPC_FindEnemy().

01303 {
01304         //Check for Hazard Team status and remove this check
01305         /*
01306         if ( NPC->client->playerTeam != TEAM_STARFLEET )
01307         {
01308                 //If we've found the player, return it
01309                 if ( NPC_FindPlayer() )
01310                         return &g_entities[0];
01311         }
01312         */
01313 
01314         //If we've asked for the closest enemy
01315         int entID = NPC_FindNearestEnemy( NPC );
01316 
01317         //If we have a valid enemy, use it
01318         if ( entID >= 0 )
01319                 return &g_entities[entID];
01320 
01321         if ( checkAlerts )
01322         {
01323                 int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, -1, qtrue, AEL_DISCOVERED );
01324 
01325                 //There is an event to look at
01326                 if ( alertEvent >= 0 )
01327                 {
01328                         alertEvent_t *event = &level.alertEvents[alertEvent];
01329 
01330                         //Don't pay attention to our own alerts
01331                         if ( event->owner == NPC )
01332                                 return NULL;
01333 
01334                         if ( event->level >= AEL_DISCOVERED )
01335                         {
01336                                 //If it's the player, attack him
01337                                 if ( event->owner == &g_entities[0] )
01338                                         return event->owner;
01339 
01340                                 //If it's on our team, then take its enemy as well
01341                                 if ( ( event->owner->client ) && ( event->owner->client->playerTeam == NPC->client->playerTeam ) )
01342                                         return event->owner->enemy;
01343                         }
01344                 }
01345         }
01346 
01347         return NULL;
01348 }

void NPC_SetBoneAngles gentity_t ent,
char *  bone,
vec3_t  angles
 

Definition at line 906 of file NPC_utils.c.

References BONE_ANGLES_POSTMULT, entityState_s::boneAngles1, entityState_s::boneAngles2, entityState_s::boneAngles3, entityState_s::boneAngles4, entityState_s::boneIndex1, entityState_s::boneIndex2, entityState_s::boneIndex3, entityState_s::boneIndex4, entityState_s::boneOrient, byte, Com_Printf(), G_BoneIndex(), gentity_t, gentity_s::ghoul2, level, NEGATIVE_Y, NEGATIVE_Z, NULL, POSITIVE_X, gentity_s::s, level_locals_t::time, trap_G2API_SetBoneAngles(), vec3_t, and VectorCopy.

Referenced by Interrogator_PartsMove(), R2D2_PartsMove(), and VEH_TurretAim().

00907 {
00908 #ifdef _XBOX
00909         byte *thebone = &ent->s.boneIndex1;
00910         byte *firstFree = NULL;
00911 #else
00912         int *thebone = &ent->s.boneIndex1;
00913         int *firstFree = NULL;
00914 #endif
00915         int i = 0;
00916         int boneIndex = G_BoneIndex(bone);
00917         int flags, up, right, forward;
00918         vec3_t *boneVector = &ent->s.boneAngles1;
00919         vec3_t *freeBoneVec = NULL;
00920 
00921         while (thebone)
00922         {
00923                 if (!*thebone && !firstFree)
00924                 { //if the value is 0 then this index is clear, we can use it if we don't find the bone we want already existing.
00925                         firstFree = thebone;
00926                         freeBoneVec = boneVector;
00927                 }
00928                 else if (*thebone)
00929                 {
00930                         if (*thebone == boneIndex)
00931                         { //this is it
00932                                 break;
00933                         }
00934                 }
00935 
00936                 switch (i)
00937                 {
00938                 case 0:
00939                         thebone = &ent->s.boneIndex2;
00940                         boneVector = &ent->s.boneAngles2;
00941                         break;
00942                 case 1:
00943                         thebone = &ent->s.boneIndex3;
00944                         boneVector = &ent->s.boneAngles3;
00945                         break;
00946                 case 2:
00947                         thebone = &ent->s.boneIndex4;
00948                         boneVector = &ent->s.boneAngles4;
00949                         break;
00950                 default:
00951                         thebone = NULL;
00952                         boneVector = NULL;
00953                         break;
00954                 }
00955 
00956                 i++;
00957         }
00958 
00959         if (!thebone)
00960         { //didn't find it, create it
00961                 if (!firstFree)
00962                 { //no free bones.. can't do a thing then.
00963                         Com_Printf("WARNING: NPC has no free bone indexes\n");
00964                         return;
00965                 }
00966 
00967                 thebone = firstFree;
00968 
00969                 *thebone = boneIndex;
00970                 boneVector = freeBoneVec;
00971         }
00972 
00973         //If we got here then we have a vector and an index.
00974 
00975         //Copy the angles over the vector in the entitystate, so we can use the corresponding index
00976         //to set the bone angles on the client.
00977         VectorCopy(angles, *boneVector);
00978 
00979         //Now set the angles on our server instance if we have one.
00980 
00981         if (!ent->ghoul2)
00982         {
00983                 return;
00984         }
00985 
00986         flags = BONE_ANGLES_POSTMULT;
00987         up = POSITIVE_X;
00988         right = NEGATIVE_Y;
00989         forward = NEGATIVE_Z;
00990 
00991         //first 3 bits is forward, second 3 bits is right, third 3 bits is up
00992         ent->s.boneOrient = ((forward)|(right<<3)|(up<<6));
00993 
00994         trap_G2API_SetBoneAngles(ent->ghoul2, 0, bone, angles, flags, up, right, forward, NULL, 100, level.time);
00995 }

void NPC_SetLookTarget gentity_t self,
int  entNum,
int  clearTime
 

Definition at line 1632 of file NPC_utils.c.

References gentity_s::client, EF2_HELD_BY_MONSTER, playerState_s::eFlags2, gentity_t, renderInfo_s::lookTarget, renderInfo_s::lookTargetClearTime, gclient_s::ps, and gclient_s::renderInfo.

Referenced by Jedi_CheckAmbushPlayer(), NPC_ExecuteBState(), and NPC_TempLookTarget().

01633 {
01634         if ( !self->client )
01635         {
01636                 return;
01637         }
01638 
01639         if ( (self->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
01640         {//lookTarget is set by and to the monster that's holding you, no other operations can change that
01641                 return;
01642         }
01643 
01644         self->client->renderInfo.lookTarget = entNum;
01645         self->client->renderInfo.lookTargetClearTime = clearTime;
01646 }

void NPC_SetSurfaceOnOff gentity_t ent,
const char *  surfaceName,
int  surfaceFlags
 

Definition at line 1001 of file NPC_utils.c.

References BG_NUM_TOGGLEABLE_SURFACES, bgToggleableSurfaces, Com_Printf(), gentity_t, gentity_s::ghoul2, Q_stricmp(), qboolean, qfalse, qtrue, gentity_s::s, entityState_s::surfacesOff, entityState_s::surfacesOn, trap_G2API_SetSurfaceOnOff(), and TURN_ON.

Referenced by GM_Dying(), GM_StartGloat(), Mark1_dying(), NPC_BSGM_Default(), NPC_Droid_Pain(), NPC_GalakMech_Init(), NPC_Mark1_Pain(), and NPC_Mark2_Pain().

01002 {
01003         int i = 0;
01004         qboolean foundIt = qfalse;
01005 
01006         while (i < BG_NUM_TOGGLEABLE_SURFACES && bgToggleableSurfaces[i])
01007         {
01008                 if (!Q_stricmp(surfaceName, bgToggleableSurfaces[i]))
01009                 { //got it
01010                         foundIt = qtrue;
01011                         break;
01012                 }
01013                 i++;
01014         }
01015 
01016         if (!foundIt)
01017         {
01018                 Com_Printf("WARNING: Tried to toggle NPC surface that isn't in toggleable surface list (%s)\n", surfaceName);
01019                 return;
01020         }
01021 
01022         if (surfaceFlags == TURN_ON)
01023         { //Make sure the entitystate values reflect this surface as on now.
01024                 ent->s.surfacesOn |= (1 << i);
01025                 ent->s.surfacesOff &= ~(1 << i);
01026         }
01027         else
01028         { //Otherwise make sure they're off.
01029                 ent->s.surfacesOn &= ~(1 << i);
01030                 ent->s.surfacesOff |= (1 << i);
01031         }
01032 
01033         if (!ent->ghoul2)
01034         {
01035                 return;
01036         }
01037 
01038         trap_G2API_SetSurfaceOnOff(ent->ghoul2, surfaceName, surfaceFlags);
01039 }

qboolean NPC_SomeoneLookingAtMe gentity_t ent  ) 
 

Definition at line 1042 of file NPC_utils.c.

References gentity_s::client, entityShared_t::currentOrigin, g_entities, gentity_t, InFOV(), gentity_s::inuse, MAX_CLIENTS, playerState_s::pm_flags, PMF_FOLLOW, gclient_s::ps, qboolean, qfalse, qtrue, gentity_s::r, gentity_s::s, gclient_s::sess, clientSession_t::sessionTeam, TEAM_SPECTATOR, trap_InPVS(), entityState_s::weapon, and WP_NONE.

Referenced by Jedi_CheckAmbushPlayer(), NPC_BSDefault(), and NPC_CheckSurrender().

01043 {
01044         int i = 0;
01045         gentity_t *pEnt;
01046 
01047         while (i < MAX_CLIENTS)
01048         {
01049                 pEnt = &g_entities[i];
01050 
01051                 if (pEnt && pEnt->inuse && pEnt->client && pEnt->client->sess.sessionTeam != TEAM_SPECTATOR &&
01052                         !(pEnt->client->ps.pm_flags & PMF_FOLLOW) && pEnt->s.weapon != WP_NONE)
01053                 {
01054                         if (trap_InPVS(ent->r.currentOrigin, pEnt->r.currentOrigin))
01055                         {
01056                                 if (InFOV( ent, pEnt, 30, 30 ))
01057                                 { //I'm in a 30 fov or so cone from this player.. that's enough I guess.
01058                                         return qtrue;
01059                                 }
01060                         }
01061                 }
01062 
01063                 i++;
01064         }
01065 
01066         return qfalse;
01067 }

qboolean NPC_TargetVisible gentity_t ent  ) 
 

Definition at line 1195 of file NPC_utils.c.

References entityShared_t::currentOrigin, gentity_t, gNPCstats_e::hfov, InFOV(), NPC, NPC_ClearLOS4(), NPCInfo, qboolean, qfalse, qtrue, gentity_s::r, gNPC_t::stats, gNPCstats_e::vfov, and gNPCstats_e::visrange.

Referenced by NPC_FindNearestEnemy(), and NPC_FindPlayer().

01196 {
01197         //Make sure we're in a valid range
01198         if ( DistanceSquared( ent->r.currentOrigin, NPC->r.currentOrigin ) > ( NPCInfo->stats.visrange * NPCInfo->stats.visrange ) )
01199                 return qfalse;
01200 
01201         //Check our FOV
01202         if ( InFOV( ent, NPC, NPCInfo->stats.hfov, NPCInfo->stats.vfov ) == qfalse )
01203                 return qfalse;
01204 
01205         //Check for sight
01206         if ( NPC_ClearLOS4( ent ) == qfalse )
01207                 return qfalse;
01208 
01209         return qtrue;
01210 }

qboolean NPC_UpdateAngles qboolean  doPitch,
qboolean  doYaw
 

Definition at line 182 of file NPC_utils.c.

References gNPC_t::aimTime, ANGLE2SHORT, AngleDelta(), usercmd_s::angles, atof(), client, gentity_s::client, playerState_s::delta_angles, gNPC_t::desiredPitch, gNPC_t::desiredYaw, gentity_s::enemy, fabs(), playerState_s::fd, forcedata_s::forcePowersActive, FP_SPEED, level, gNPC_t::lockedDesiredPitch, gNPC_t::lockedDesiredYaw, MIN_ANGLE_ERROR, NPC, NPCInfo, PITCH, gclient_s::ps, qboolean, qfalse, qtrue, ROLL, gentity_s::s, gNPC_t::stats, TID_ANGLE_FACE, level_locals_t::time, trap_Cvar_VariableStringBuffer(), trap_ICARUS_TaskIDComplete(), trap_ICARUS_TaskIDPending(), ucmd, playerState_s::viewangles, entityState_s::weapon, WP_EMPLACED_GUN, WP_SABER, YAW, and gNPCstats_e::yawSpeed.

Referenced by ATST_Patrol(), Boba_FireDecide(), Droid_Patrol(), Droid_Spin(), ImperialProbe_MaintainHeight(), ImperialProbe_Patrol(), ImperialProbe_Wait(), Interrogator_Idle(), Interrogator_MaintainHeight(), Mark1_Patrol(), Mark2_Patrol(), NPC_BSCinematic(), NPC_BSDefault(), NPC_BSDroid_Default(), NPC_BSEmplaced(), NPC_BSFace(), NPC_BSFlee(), NPC_BSFollowLeader(), NPC_BSGM_Attack(), NPC_BSGM_Patrol(), NPC_BSGrenadier_Attack(), NPC_BSGrenadier_Patrol(), NPC_BSHowler_Default(), NPC_BSHuntAndKill(), NPC_BSIdle(), NPC_BSJedi_FollowLeader(), NPC_BSJump(), NPC_BSMineMonster_Default(), NPC_BSMove(), NPC_BSNoClip(), NPC_BSPatrol(), NPC_BSPointShoot(), NPC_BSRancor_Default(), NPC_BSRemove(), NPC_BSRun(), NPC_BSRunAndShoot(), NPC_BSSearch(), NPC_BSSniper_Attack(), NPC_BSSniper_Patrol(), NPC_BSST_Attack(), NPC_BSST_Investigate(), NPC_BSST_Patrol(), NPC_BSStandAndShoot(), NPC_BSStandGuard(), NPC_BSWait(), NPC_BSWampa_Default(), NPC_BSWander(), NPC_FacePosition(), NPC_RunBehavior(), NPC_Sentry_Patrol(), NPC_Think(), Rancor_Combat(), Remote_MaintainHeight(), Remote_Patrol(), Seeker_FollowOwner(), Seeker_MaintainHeight(), Sentry_MaintainHeight(), and Sniper_FaceEnemy().

00183 {
00184 #if 1
00185 
00186         float           error;
00187         float           decay;
00188         float           targetPitch = 0;
00189         float           targetYaw = 0;
00190         float           yawSpeed;
00191         qboolean        exact = qtrue;
00192 
00193         // if angle changes are locked; just keep the current angles
00194         // aimTime isn't even set anymore... so this code was never reached, but I need a way to lock NPC's yaw, so instead of making a new SCF_ flag, just use the existing render flag... - dmv
00195         if ( !NPC->enemy && ( (level.time < NPCInfo->aimTime) /*|| NPC->client->renderInfo.renderFlags & RF_LOCKEDANGLE*/) ) 
00196         {
00197                 if(doPitch)
00198                         targetPitch = NPCInfo->lockedDesiredPitch;
00199 
00200                 if(doYaw)
00201                         targetYaw = NPCInfo->lockedDesiredYaw;
00202         }
00203         else 
00204         {
00205                 // we're changing the lockedDesired Pitch/Yaw below so it's lost it's original meaning, get rid of the lock flag
00206         //      NPC->client->renderInfo.renderFlags &= ~RF_LOCKEDANGLE;
00207 
00208                 if(doPitch)
00209                 {
00210                         targetPitch = NPCInfo->desiredPitch;
00211                         NPCInfo->lockedDesiredPitch = NPCInfo->desiredPitch;
00212                 }
00213 
00214                 if(doYaw)
00215                 {
00216                         targetYaw = NPCInfo->desiredYaw;
00217                         NPCInfo->lockedDesiredYaw = NPCInfo->desiredYaw;
00218                 }                       
00219         }
00220 
00221         if ( NPC->s.weapon == WP_EMPLACED_GUN )
00222         {
00223                 // FIXME: this seems to do nothing, actually...
00224                 yawSpeed = 20;
00225         }
00226         else
00227         {
00228                 yawSpeed = NPCInfo->stats.yawSpeed;
00229         }
00230 
00231         if ( NPC->s.weapon == WP_SABER && NPC->client->ps.fd.forcePowersActive&(1<<FP_SPEED) )
00232         {
00233                 char buf[128];
00234                 float tFVal = 0;
00235 
00236                 trap_Cvar_VariableStringBuffer("timescale", buf, sizeof(buf));
00237 
00238                 tFVal = atof(buf);
00239 
00240                 yawSpeed *= 1.0f/tFVal;
00241         }
00242         
00243         if( doYaw )
00244         {
00245                 // decay yaw error
00246                 error = AngleDelta ( NPC->client->ps.viewangles[YAW], targetYaw );
00247                 if( fabs(error) > MIN_ANGLE_ERROR )
00248                 {
00249                         if ( error ) 
00250                         {
00251                                 exact = qfalse;
00252 
00253                                 decay = 60.0 + yawSpeed * 3;
00254                                 decay *= 50.0f / 1000.0f;//msec
00255 
00256                                 if ( error < 0.0 ) 
00257                                 {
00258                                         error += decay;
00259                                         if ( error > 0.0 ) 
00260                                         {
00261                                                 error = 0.0;
00262                                         }
00263                                 }
00264                                 else 
00265                                 {
00266                                         error -= decay;
00267                                         if ( error < 0.0 ) 
00268                                         {
00269                                                 error = 0.0;
00270                                         }
00271                                 }
00272                         }
00273                 }
00274                 
00275                 ucmd.angles[YAW] = ANGLE2SHORT( targetYaw + error ) - client->ps.delta_angles[YAW];
00276         }
00277 
00278         //FIXME: have a pitchSpeed?
00279         if( doPitch )
00280         {
00281                 // decay pitch error
00282                 error = AngleDelta ( NPC->client->ps.viewangles[PITCH], targetPitch );
00283                 if ( fabs(error) > MIN_ANGLE_ERROR )
00284                 {
00285                         if ( error ) 
00286                         {
00287                                 exact = qfalse;
00288 
00289                                 decay = 60.0 + yawSpeed * 3;
00290                                 decay *= 50.0f / 1000.0f;//msec
00291 
00292                                 if ( error < 0.0 ) 
00293                                 {
00294                                         error += decay;
00295                                         if ( error > 0.0 ) 
00296                                         {
00297                                                 error = 0.0;
00298                                         }
00299                                 }
00300                                 else 
00301                                 {
00302                                         error -= decay;
00303                                         if ( error < 0.0 ) 
00304                                         {
00305                                                 error = 0.0;
00306                                         }
00307                                 }
00308                         }
00309                 }
00310 
00311                 ucmd.angles[PITCH] = ANGLE2SHORT( targetPitch + error ) - client->ps.delta_angles[PITCH];
00312         }
00313 
00314         ucmd.angles[ROLL] = ANGLE2SHORT ( NPC->client->ps.viewangles[ROLL] ) - client->ps.delta_angles[ROLL];
00315 
00316         if ( exact && trap_ICARUS_TaskIDPending( NPC, TID_ANGLE_FACE ) )
00317         {
00318                 trap_ICARUS_TaskIDComplete( NPC, TID_ANGLE_FACE );
00319         }
00320         return exact;
00321 
00322 #else
00323 
00324         float           error;
00325         float           decay;
00326         float           targetPitch = 0;
00327         float           targetYaw = 0;
00328         float           yawSpeed;
00329         //float         runningMod = NPCInfo->currentSpeed/100.0f;
00330         qboolean        exact = qtrue;
00331         qboolean        doSound = qfalse;
00332 
00333         // if angle changes are locked; just keep the current angles
00334         if ( level.time < NPCInfo->aimTime ) 
00335         {
00336                 if(doPitch)
00337                         targetPitch = NPCInfo->lockedDesiredPitch;
00338                 if(doYaw)
00339                         targetYaw = NPCInfo->lockedDesiredYaw;
00340         }
00341         else 
00342         {
00343                 if(doPitch)
00344                         targetPitch = NPCInfo->desiredPitch;
00345                 if(doYaw)
00346                         targetYaw = NPCInfo->desiredYaw;
00347 
00348 //              NPCInfo->aimTime = level.time + 250;
00349                 if(doPitch)
00350                         NPCInfo->lockedDesiredPitch = NPCInfo->desiredPitch;
00351                 if(doYaw)
00352                         NPCInfo->lockedDesiredYaw = NPCInfo->desiredYaw;
00353         }
00354 
00355         yawSpeed = NPCInfo->stats.yawSpeed;
00356 
00357         if(doYaw)
00358         {
00359                 // decay yaw error
00360                 error = AngleDelta ( NPC->client->ps.viewangles[YAW], targetYaw );
00361                 if( fabs(error) > MIN_ANGLE_ERROR )
00362                 {
00363                         /*
00364                         if(NPC->client->playerTeam == TEAM_BORG&&
00365                                 NPCInfo->behaviorState != BS_FACE&&NPCInfo->tempBehavior!= BS_FACE)
00366                         {//HACK - borg turn more jittery
00367                                 if ( error ) 
00368                                 {
00369                                         exact = qfalse;
00370 
00371                                         decay = 60.0 + yawSpeed * 3;
00372                                         decay *= 50.0 / 1000.0;//msec
00373                                         //Snap to
00374                                         if(fabs(error) > 10)
00375                                         {
00376                                                 if(random() > 0.6)
00377                                                 {
00378                                                         doSound = qtrue;
00379                                                 }
00380                                         }
00381 
00382                                         if ( error < 0.0)//-10.0 ) 
00383                                         {
00384                                                 error += decay;
00385                                                 if ( error > 0.0 ) 
00386                                                 {
00387                                                         error = 0.0;
00388                                                 }
00389                                         }
00390                                         else if ( error > 0.0)//10.0 ) 
00391                                         {
00392                                                 error -= decay;
00393                                                 if ( error < 0.0 ) 
00394                                                 {
00395                                                         error = 0.0;
00396                                                 }
00397                                         }
00398                                 }
00399                         }
00400                         else*/
00401                         
00402                         if ( error ) 
00403                         {
00404                                 exact = qfalse;
00405 
00406                                 decay = 60.0 + yawSpeed * 3;
00407                                 decay *= 50.0 / 1000.0;//msec
00408 
00409                                 if ( error < 0.0 ) 
00410                                 {
00411                                         error += decay;
00412                                         if ( error > 0.0 ) 
00413                                         {
00414                                                 error = 0.0;
00415                                         }
00416                                 }
00417                                 else 
00418                                 {
00419                                         error -= decay;
00420                                         if ( error < 0.0 ) 
00421                                         {
00422                                                 error = 0.0;
00423                                         }
00424                                 }
00425                         }
00426                 }
00427                 ucmd.angles[YAW] = ANGLE2SHORT( targetYaw + error ) - client->ps.delta_angles[YAW];
00428         }
00429 
00430         //FIXME: have a pitchSpeed?
00431         if(doPitch)
00432         {
00433                 // decay pitch error
00434                 error = AngleDelta ( NPC->client->ps.viewangles[PITCH], targetPitch );
00435                 if ( fabs(error) > MIN_ANGLE_ERROR )
00436                 {
00437                         /*
00438                         if(NPC->client->playerTeam == TEAM_BORG&&
00439                                 NPCInfo->behaviorState != BS_FACE&&NPCInfo->tempBehavior!= BS_FACE)
00440                         {//HACK - borg turn more jittery
00441                                 if ( error ) 
00442                                 {
00443                                         exact = qfalse;
00444 
00445                                         decay = 60.0 + yawSpeed * 3;
00446                                         decay *= 50.0 / 1000.0;//msec
00447                                         //Snap to
00448                                         if(fabs(error) > 10)
00449                                         {
00450                                                 if(random() > 0.6)
00451                                                 {
00452                                                         doSound = qtrue;
00453                                                 }
00454                                         }
00455 
00456                                         if ( error < 0.0)//-10.0 ) 
00457                                         {
00458                                                 error += decay;
00459                                                 if ( error > 0.0 ) 
00460                                                 {
00461                                                         error = 0.0;
00462                                                 }
00463                                         }
00464                                         else if ( error > 0.0)//10.0 ) 
00465                                         {
00466                                                 error -= decay;
00467                                                 if ( error < 0.0 ) 
00468                                                 {
00469                                                         error = 0.0;
00470                                                 }
00471                                         }
00472                                 }
00473                         }
00474                         else*/
00475                         
00476                         if ( error ) 
00477                         {
00478                                 exact = qfalse;
00479 
00480                                 decay = 60.0 + yawSpeed * 3;
00481                                 decay *= 50.0 / 1000.0;//msec
00482 
00483                                 if ( error < 0.0 ) 
00484                                 {
00485                                         error += decay;
00486                                         if ( error > 0.0 ) 
00487                                         {
00488                                                 error = 0.0;
00489                                         }
00490                                 }
00491                                 else 
00492                                 {
00493                                         error -= decay;
00494                                         if ( error < 0.0 ) 
00495                                         {
00496                                                 error = 0.0;
00497                                         }
00498                                 }
00499                         }
00500                 }
00501                 ucmd.angles[PITCH] = ANGLE2SHORT( targetPitch + error ) - client->ps.delta_angles[PITCH];
00502         }
00503 
00504         ucmd.angles[ROLL] = ANGLE2SHORT ( NPC->client->ps.viewangles[ROLL] ) - client->ps.delta_angles[ROLL];
00505 
00506         /*
00507         if(doSound)
00508         {
00509                 G_Sound(NPC, G_SoundIndex(va("sound/enemies/borg/borgservo%d.wav", Q_irand(1, 8))));
00510         }
00511         */
00512 
00513         return exact;
00514 
00515 #endif
00516 
00517 }

qboolean NPC_UpdateFiringAngles qboolean  doPitch,
qboolean  doYaw
 

Definition at line 540 of file NPC_utils.c.

References gNPCstats_e::aim, gNPC_t::aimErrorDebounceTime, gNPC_t::aimTime, ANGLE2SHORT, AngleDelta(), usercmd_s::angles, client, gentity_s::client, playerState_s::delta_angles, gNPC_t::desiredPitch, gNPC_t::desiredYaw, flrand(), gNPC_t::lastAimErrorPitch, gNPC_t::lastAimErrorYaw, level, gNPC_t::lockedDesiredPitch, gNPC_t::lockedDesiredYaw, NPC, NPCInfo, PITCH, gclient_s::ps, Q_irand(), qboolean, qfalse, qtrue, ROLL, gNPC_t::stats, level_locals_t::time, ucmd, playerState_s::viewangles, and YAW.

Referenced by NPC_BSFollowLeader(), and NPC_CheckCanAttack().

00541 {
00542 
00543 #if 0
00544 
00545         float           diff;
00546         float           error;
00547         float           targetPitch = 0;
00548         float           targetYaw = 0;
00549         qboolean        exact = qtrue;
00550 
00551         if ( level.time < NPCInfo->aimTime ) 
00552         {
00553                 if( doPitch )
00554                         targetPitch = NPCInfo->lockedDesiredPitch;
00555 
00556                 if( doYaw )
00557                         targetYaw = NPCInfo->lockedDesiredYaw;
00558         }
00559         else 
00560         {
00561                 if( doPitch )
00562                 {
00563                         targetPitch = NPCInfo->desiredPitch;
00564                         NPCInfo->lockedDesiredPitch = NPCInfo->desiredPitch;
00565                 }
00566 
00567                 if( doYaw )
00568                 {
00569                         targetYaw = NPCInfo->desiredYaw;
00570                         NPCInfo->lockedDesiredYaw = NPCInfo->desiredYaw;
00571                 }                       
00572         }
00573 
00574         if( doYaw )
00575         {
00576                 // add yaw error based on NPCInfo->aim value
00577                 error = ((float)(6 - NPCInfo->stats.aim)) * flrand(-1, 1);
00578 
00579                 if(Q_irand(0, 1))
00580                         error *= -1;
00581 
00582                 diff = AngleDelta ( NPC->client->ps.viewangles[YAW], targetYaw );
00583 
00584                 if ( diff )
00585                         exact = qfalse;
00586                 
00587                 ucmd.angles[YAW] = ANGLE2SHORT( targetYaw + diff + error ) - client->ps.delta_angles[YAW];
00588         }
00589 
00590         if( doPitch )
00591         {
00592                 // add pitch error based on NPCInfo->aim value
00593                 error = ((float)(6 - NPCInfo->stats.aim)) * flrand(-1, 1);
00594 
00595                 diff = AngleDelta ( NPC->client->ps.viewangles[PITCH], targetPitch );
00596 
00597                 if ( diff )
00598                         exact = qfalse;
00599                 
00600                 ucmd.angles[PITCH] = ANGLE2SHORT( targetPitch + diff + error ) - client->ps.delta_angles[PITCH];
00601         }
00602 
00603         ucmd.angles[ROLL] = ANGLE2SHORT ( NPC->client->ps.viewangles[ROLL] ) - client->ps.delta_angles[ROLL];
00604 
00605         return exact;
00606         
00607 #else
00608 
00609         float           error, diff;
00610         float           decay;
00611         float           targetPitch = 0;
00612         float           targetYaw = 0;
00613         qboolean        exact = qtrue;
00614 
00615         // if angle changes are locked; just keep the current angles
00616         if ( level.time < NPCInfo->aimTime ) 
00617         {
00618                 if(doPitch)
00619                         targetPitch = NPCInfo->lockedDesiredPitch;
00620                 if(doYaw)
00621                         targetYaw = NPCInfo->lockedDesiredYaw;
00622         }
00623         else 
00624         {
00625                 if(doPitch)
00626                         targetPitch = NPCInfo->desiredPitch;
00627                 if(doYaw)
00628                         targetYaw = NPCInfo->desiredYaw;
00629 
00630 //              NPCInfo->aimTime = level.time + 250;
00631                 if(doPitch)
00632                         NPCInfo->lockedDesiredPitch = NPCInfo->desiredPitch;
00633                 if(doYaw)
00634                         NPCInfo->lockedDesiredYaw = NPCInfo->desiredYaw;
00635         }
00636 
00637         if ( NPCInfo->aimErrorDebounceTime < level.time )
00638         {
00639                 if ( Q_irand(0, 1 ) )
00640                 {
00641                         NPCInfo->lastAimErrorYaw = ((float)(6 - NPCInfo->stats.aim)) * flrand(-1, 1);
00642                 }
00643                 if ( Q_irand(0, 1 ) )
00644                 {
00645                         NPCInfo->lastAimErrorPitch = ((float)(6 - NPCInfo->stats.aim)) * flrand(-1, 1);
00646                 }
00647                 NPCInfo->aimErrorDebounceTime = level.time + Q_irand(250, 2000);
00648         }
00649 
00650         if(doYaw)
00651         {
00652                 // decay yaw diff
00653                 diff = AngleDelta ( NPC->client->ps.viewangles[YAW], targetYaw );
00654                 
00655                 if ( diff) 
00656                 {
00657                         exact = qfalse;
00658 
00659                         decay = 60.0 + 80.0;
00660                         decay *= 50.0f / 1000.0f;//msec
00661                         if ( diff < 0.0 ) 
00662                         {
00663                                 diff += decay;
00664                                 if ( diff > 0.0 ) 
00665                                 {
00666                                         diff = 0.0;
00667                                 }
00668                         }
00669                         else 
00670                         {
00671                                 diff -= decay;
00672                                 if ( diff < 0.0 ) 
00673                                 {
00674                                         diff = 0.0;
00675                                 }
00676                         }
00677                 }
00678                                 
00679                 // add yaw error based on NPCInfo->aim value
00680                 error = NPCInfo->lastAimErrorYaw;
00681 
00682                 /*
00683                 if(Q_irand(0, 1))
00684                 {
00685                         error *= -1;
00686                 }
00687                 */
00688 
00689                 ucmd.angles[YAW] = ANGLE2SHORT( targetYaw + diff + error ) - client->ps.delta_angles[YAW];
00690         }
00691 
00692         if(doPitch)
00693         {
00694                 // decay pitch diff
00695                 diff = AngleDelta ( NPC->client->ps.viewangles[PITCH], targetPitch );
00696                 if ( diff) 
00697                 {
00698                         exact = qfalse;
00699 
00700                         decay = 60.0 + 80.0;
00701                         decay *= 50.0f / 1000.0f;//msec
00702                         if ( diff < 0.0 ) 
00703                         {
00704                                 diff += decay;
00705                                 if ( diff > 0.0 ) 
00706                                 {
00707                                         diff = 0.0;
00708                                 }
00709                         }
00710                         else 
00711                         {
00712                                 diff -= decay;
00713                                 if ( diff < 0.0 ) 
00714                                 {
00715                                         diff = 0.0;
00716                                 }
00717                         }
00718                 }
00719                 
00720                 error = NPCInfo->lastAimErrorPitch;
00721 
00722                 ucmd.angles[PITCH] = ANGLE2SHORT( targetPitch + diff + error ) - client->ps.delta_angles[PITCH];
00723         }
00724 
00725         ucmd.angles[ROLL] = ANGLE2SHORT ( NPC->client->ps.viewangles[ROLL] ) - client->ps.delta_angles[ROLL];
00726 
00727         return exact;
00728 
00729 #endif
00730 
00731 }

void NPC_UpdateShootAngles vec3_t  angles,
qboolean  doPitch,
qboolean  doYaw
 

Definition at line 740 of file NPC_utils.c.

References gNPCstats_e::aim, AngleDelta(), NPCInfo, PITCH, gNPC_t::shootAngles, gNPC_t::stats, vec3_t, and YAW.

Referenced by NPC_BSAdvanceFight().

00741 {//FIXME: shoot angles either not set right or not used!
00742         float           error;
00743         float           decay;
00744         float           targetPitch = 0;
00745         float           targetYaw = 0;
00746 
00747         if(doPitch)
00748                 targetPitch = angles[PITCH];
00749         if(doYaw)
00750                 targetYaw = angles[YAW];
00751 
00752 
00753         if(doYaw)
00754         {
00755                 // decay yaw error
00756                 error = AngleDelta ( NPCInfo->shootAngles[YAW], targetYaw );
00757                 if ( error ) 
00758                 {
00759                         decay = 60.0 + 80.0 * NPCInfo->stats.aim;
00760                         decay *= 100.0f / 1000.0f;//msec
00761                         if ( error < 0.0 ) 
00762                         {
00763                                 error += decay;
00764                                 if ( error > 0.0 ) 
00765                                 {
00766                                         error = 0.0;
00767                                 }
00768                         }
00769                         else 
00770                         {
00771                                 error -= decay;
00772                                 if ( error < 0.0 ) 
00773                                 {
00774                                         error = 0.0;
00775                                 }
00776                         }
00777                 }
00778                 NPCInfo->shootAngles[YAW] = targetYaw + error;
00779         }
00780 
00781         if(doPitch)
00782         {
00783                 // decay pitch error
00784                 error = AngleDelta ( NPCInfo->shootAngles[PITCH], targetPitch );
00785                 if ( error ) 
00786                 {
00787                         decay = 60.0 + 80.0 * NPCInfo->stats.aim;
00788                         decay *= 100.0f / 1000.0f;//msec
00789                         if ( error < 0.0 ) 
00790                         {
00791                                 error += decay;
00792                                 if ( error > 0.0 ) 
00793                                 {
00794                                         error = 0.0;
00795                                 }
00796                         }
00797                         else 
00798                         {
00799                                 error -= decay;
00800                                 if ( error < 0.0 ) 
00801                                 {
00802                                         error = 0.0;
00803                                 }
00804                         }
00805                 }
00806                 NPCInfo->shootAngles[PITCH] = targetPitch + error;
00807         }
00808 }

qboolean NPC_ValidEnemy gentity_t ent  ) 
 

Definition at line 1096 of file NPC_utils.c.

References gentity_s::alliedTeam, CLASS_RANCOR, CLASS_WAMPA, gentity_s::client, gentity_s::enemy, gclient_s::enemyTeam, ET_NPC, entityState_s::eType, FL_NOTARGET, gentity_s::flags, g_gametype, gentity_t, GT_TEAM, gentity_s::health, vmCvar_t::integer, gentity_s::inuse, gentity_s::NPC, NPC, gclient_s::NPC_class, NPCTEAM_ENEMY, NPCTEAM_FREE, NPCTEAM_NEUTRAL, NPCTEAM_PLAYER, NULL, gclient_s::playerTeam, qboolean, qfalse, qtrue, gentity_s::s, gclient_s::sess, clientSession_t::sessionTeam, TEAM_BLUE, TEAM_FREE, TEAM_RED, and TEAM_SPECTATOR.

Referenced by Jedi_CheckAmbushPlayer(), NPC_CheckPlayerTeamStealth(), NPC_FindEnemy(), NPC_FindNearestEnemy(), and NPC_PickEnemy().

01097 {
01098         int entTeam = TEAM_FREE;
01099         //Must be a valid pointer
01100         if ( ent == NULL )
01101                 return qfalse;
01102 
01103         //Must not be me
01104         if ( ent == NPC )
01105                 return qfalse;
01106 
01107         //Must not be deleted
01108         if ( ent->inuse == qfalse )
01109                 return qfalse;
01110 
01111         //Must be alive
01112         if ( ent->health <= 0 )
01113                 return qfalse;
01114 
01115         //In case they're in notarget mode
01116         if ( ent->flags & FL_NOTARGET )
01117                 return qfalse;
01118 
01119         //Must be an NPC
01120         if ( ent->client == NULL )
01121         {
01122         //      if ( ent->svFlags&SVF_NONNPC_ENEMY )
01123                 if (ent->s.eType != ET_NPC)
01124                 {//still potentially valid
01125                         if ( ent->alliedTeam == NPC->client->playerTeam )
01126                         {
01127                                 return qfalse;
01128                         }
01129                         else
01130                         {
01131                                 return qtrue;
01132                         }
01133                 }
01134                 else
01135                 {
01136                         return qfalse;
01137                 }
01138         }
01139         else if ( ent->client && ent->client->sess.sessionTeam == TEAM_SPECTATOR )
01140         {//don't go after spectators
01141                 return qfalse;
01142         }
01143         if ( ent->NPC && ent->client )
01144         {
01145                 entTeam = ent->client->playerTeam;
01146         }
01147         else if ( ent->client )
01148         {
01149                 if (g_gametype.integer < GT_TEAM)
01150                 {
01151                         entTeam = NPCTEAM_PLAYER;
01152                 }
01153                 else
01154                 {
01155                         if ( ent->client->sess.sessionTeam == TEAM_BLUE )
01156                         {
01157                                 entTeam = NPCTEAM_PLAYER;
01158                         }
01159                         else if ( ent->client->sess.sessionTeam == TEAM_RED )
01160                         {
01161                                 entTeam = NPCTEAM_ENEMY;
01162                         }
01163                         else
01164                         {
01165                                 entTeam = NPCTEAM_NEUTRAL;
01166                         }
01167                 }
01168         }
01169         //Can't be on the same team
01170         if ( ent->client->playerTeam == NPC->client->playerTeam )
01171                 return qfalse;
01172 
01173         //if haven't seen him in a while, give up
01174         //if ( NPCInfo->enemyLastSeenTime != 0 && level.time - NPCInfo->enemyLastSeenTime > 7000 )//FIXME: make a stat?
01175         //      return qfalse;
01176         if ( entTeam == NPC->client->enemyTeam //simplest case: they're on my enemy team
01177                 || (NPC->client->enemyTeam == NPCTEAM_FREE && ent->client->NPC_class != NPC->client->NPC_class )//I get mad at anyone and this guy isn't the same class as me
01178                 || (ent->client->NPC_class == CLASS_WAMPA && ent->enemy )//a rampaging wampa
01179                 || (ent->client->NPC_class == CLASS_RANCOR && ent->enemy )//a rampaging rancor
01180                 || (entTeam == NPCTEAM_FREE && ent->client->enemyTeam == NPCTEAM_FREE && ent->enemy && ent->enemy->client && (ent->enemy->client->playerTeam == NPC->client->playerTeam||(ent->enemy->client->playerTeam != NPCTEAM_ENEMY&&NPC->client->playerTeam==NPCTEAM_PLAYER))) //enemy is a rampaging non-aligned creature who is attacking someone on our team or a non-enemy (this last condition is used only if we're a good guy - in effect, we protect the innocent)
01181                 )
01182         {
01183                 return qtrue;
01184         }
01185 
01186         return qfalse;
01187 }

void SetTeamNumbers void   ) 
 

Definition at line 818 of file NPC_utils.c.

References gentity_s::client, floor(), g_entities, gentity_t, gentity_s::health, gclient_s::playerTeam, TEAM_NUM_TEAMS, teamNumbers, and teamStrength.

00819 {
00820         gentity_t       *found;
00821         int                     i;
00822 
00823         for( i = 0; i < TEAM_NUM_TEAMS; i++ )
00824         {
00825                 teamNumbers[i] = 0;
00826                 teamStrength[i] = 0;
00827         }
00828 
00829         for( i = 0; i < 1 ; i++ )
00830         {
00831                 found = &g_entities[i];
00832 
00833                 if( found->client )
00834                 {
00835                         if( found->health > 0 )//FIXME: or if a player!
00836                         {
00837                                 teamNumbers[found->client->playerTeam]++;
00838                                 teamStrength[found->client->playerTeam] += found->health;
00839                         }
00840                 }
00841         }
00842 
00843         for( i = 0; i < TEAM_NUM_TEAMS; i++ )
00844         {//Get the average health
00845                 teamStrength[i] = floor( ((float)(teamStrength[i])) / ((float)(teamNumbers[i])) );
00846         }
00847 }


Variable Documentation

stringID_table_t BSETTable[]
 

Definition at line 850 of file NPC_utils.c.

Referenced by G_ActivateBehavior().

stringID_table_t BSTable[]
 

Definition at line 849 of file NPC_utils.c.

int teamCounter[TEAM_NUM_TEAMS]
 

Definition at line 9 of file NPC_utils.c.

int teamNumbers[TEAM_NUM_TEAMS]
 

Definition at line 7 of file NPC_utils.c.

Referenced by SetTeamNumbers().

int teamStrength[TEAM_NUM_TEAMS]
 

Definition at line 8 of file NPC_utils.c.

Referenced by SetTeamNumbers().