#include "g_local.h"#include "b_public.h"#include "say.h"#include "ai.h"Go to the source code of this file.
|
|
|
|
|
Definition at line 164 of file b_local.h. Referenced by ClearPlayerAlertEvents(), and CorpsePhysics(). |
|
|
Definition at line 166 of file b_local.h. Referenced by NPC_BSFollowLeader(), NPC_CheckCanAttack(), NPC_CheckPossibleEnemy(), NPC_CheckVisibility(), NPC_PickAlly(), and NPC_PickEnemy(). |
|
|
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(). |
|
|
Definition at line 165 of file b_local.h. Referenced by NPC_BSFollowLeader(), and NPC_CheckVisibility(). |
|
|
Definition at line 168 of file b_local.h. Referenced by NPC_BSFollowLeader(), NPC_BSHuntAndKill(), and NPC_CheckVisibility(). |
|
|
Definition at line 169 of file b_local.h. Referenced by NPC_CheckVisibility(), NPC_PickAlly(), and NPC_PickEnemy(). |
|
|
|
|
|
Definition at line 243 of file b_local.h. Referenced by ST_Commander(). |
|
|
Definition at line 253 of file b_local.h. Referenced by NPC_FindCombatPoint(), ST_Commander(), and ST_GetCPFlags(). |
|
|
Definition at line 252 of file b_local.h. Referenced by NPC_FindCombatPoint(), NPC_StartFlee(), ST_Commander(), and ST_GetCPFlags(). |
|
|
Definition at line 249 of file b_local.h. Referenced by NPC_FindCombatPoint(), and ST_Commander(). |
|
|
Definition at line 245 of file b_local.h. Referenced by NPC_FindCombatPoint(), ST_ApproachEnemy(), ST_Commander(), and ST_GetCPFlags(). |
|
|
Definition at line 254 of file b_local.h. Referenced by ST_ApproachEnemy(), ST_Commander(), and ST_GetCPFlags(). |
|
|
Definition at line 244 of file b_local.h. Referenced by NPC_FindCombatPoint(), NPC_StartFlee(), ST_Commander(), and ST_GetCPFlags(). |
|
|
Definition at line 247 of file b_local.h. Referenced by ST_Commander(). |
|
|
Definition at line 255 of file b_local.h. Referenced by NPC_FindCombatPoint(), ST_Commander(), and ST_GetCPFlags(). |
|
|
Definition at line 246 of file b_local.h. Referenced by ST_Commander(), and ST_GetCPFlags(). |
|
|
Definition at line 256 of file b_local.h. Referenced by NPC_FindCombatPoint(), NPC_StartFlee(), and ST_Commander(). |
|
|
Definition at line 259 of file b_local.h. Referenced by NPC_FindCombatPoint(). |
|
|
Definition at line 250 of file b_local.h. Referenced by ST_Commander(). |
|
|
Definition at line 248 of file b_local.h. Referenced by NPC_FindCombatPoint(), ST_Commander(), and ST_GetCPFlags(). |
|
|
Definition at line 260 of file b_local.h. Referenced by NPC_FindCombatPoint(), and NPC_StartFlee(). |
|
|
Definition at line 261 of file b_local.h. Referenced by NPC_FindCombatPoint(), ST_Commander(), and ST_GetCPFlags(). |
|
|
Definition at line 258 of file b_local.h. Referenced by ST_Commander(), and ST_GetCPFlags(). |
|
|
|
|
|
Definition at line 251 of file b_local.h. Referenced by ST_Commander(). |
|
|
Definition at line 264 of file b_local.h. Referenced by ST_Commander(). |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Definition at line 267 of file b_local.h. Referenced by NPC_FindSquadPoint(). |
|
|
Definition at line 22 of file b_local.h. Referenced by Debug_NPCPrintf(), and Debug_Printf(). |
|
|
Definition at line 25 of file b_local.h. Referenced by Debug_NPCPrintf(), and Debug_Printf(). |
|
|
Definition at line 23 of file b_local.h. Referenced by Debug_NPCPrintf(), Debug_Printf(), and NPC_PickEnemy(). |
|
|
|
|
|
Definition at line 24 of file b_local.h. Referenced by Debug_NPCPrintf(), and Debug_Printf(). |
|
|
|
|
|
|
|
|
Definition at line 29 of file b_local.h. Referenced by NPC_BSJump(), and NPC_UpdateAngles(). |
|
|
Definition at line 31 of file b_local.h. Referenced by Boba_FireDecide(), NPC_BSST_Attack(), and ST_Commander(). |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Definition at line 306 of file b_local.h. Referenced by NAV_AvoidCollision(), and NAV_TestForBlocked(). |
|
|
Definition at line 305 of file b_local.h. Referenced by NAV_AvoidCollision(), and NAVNEW_AvoidCollision(). |
|
|
|
|
|
Definition at line 304 of file b_local.h. Referenced by NPC_GetMoveDirection(), and NPC_GetMoveDirectionAltRoute(). |
|
|
|
|
|
|
|
|
Definition at line 147 of file b_local.h. Referenced by NPC_Begin(), and NPC_SetMiscDefaultData(). |
|
|
|
|
|
|
|
|
Definition at line 148 of file b_local.h. Referenced by NPC_Begin(). |
|
|
|
|
|
Definition at line 141 of file b_local.h. Referenced by NPC_WeaponsForTeam(). |
|
|
Definition at line 139 of file b_local.h. Referenced by NPC_WeaponsForTeam(). |
|
|
|
|
|
Definition at line 149 of file b_local.h. Referenced by NPC_Begin(). |
|
|
|
|
|
|
|
|
Referenced by AI_CheckEnemyCollision(), NAV_AvoidCollision(), NAV_GetLastMove(), NAV_MoveToGoal(), NAVNEW_AvoidCollision(), NAVNEW_MoveToGoal(), and NPC_GetMoveDirectionAltRoute(). |
|
||||||||||||||||
|
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 }
|
|
|
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 }
|
|
||||||||||||
|
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 }
|
|
|
|
|
|
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 }
|
|
||||||||||||||||||||||||
|
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 }
|
|
||||||||||||||||||||
|
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 }
|
|
|
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().
|
|
||||||||||||
|
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 }
|
|
||||||||||||||||||||
|
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 }
|
|
||||||||||||||||||||
|
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 }
|
|
||||||||||||
|
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 }
|
|
|
|
|
|
||||||||||||||||||||||||||||
|
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 }
|
|
|
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 }
|
|
|
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 }
|
|
||||||||||||||||||||
|
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 }
|
|
||||||||||||||||||||
|
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 }
|
|
||||||||||||||||||||||||
|
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 }
|
|
|
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 }
|
|
||||||||||||||||
|
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 }
|
|
||||||||||||||||||||
|
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 }
|
|
||||||||||||||||||||||||||||
|
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 }
|
|
||||||||||||
|
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 }
|
|
|
Definition at line 149 of file NPC_move.c. References frameNavInfo, and navInfo_t. Referenced by AI_CheckEnemyCollision().
00150 {
00151 *info = frameNavInfo;
00152 }
|
|
||||||||||||||||||||||||||||
|
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 }
|
|
||||||||||||
|
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 }
|
|
|
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 }
|
|
|
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 }
|
|
|
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 }
|
|
|
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 }
|
|
|
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 }
|
|
|
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 }
|
|
|
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 }
|
|
|
|
|
|
(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 }
|
|
|
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 }
|
|
|
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 }
|
|
|
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 }
|
|
|
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 }
|
|
|
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 }
|
|
|
|
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 }
|
|
|
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
|