Go to the source code of this file.
|
|
Definition at line 85 of file ai.h. Referenced by AI_FindSelfInPreviousGroup(), AI_GetNextEmptyGroup(), AI_RefreshGroup(), AI_TryJoinPreviousGroup(), and AI_UpdateGroups(). |
|
|
Definition at line 95 of file ai.h. Referenced by AI_GetGroup(), AI_RefreshGroup(), AI_SortGroupByPathCostToEnemy(), and AI_TryJoinPreviousGroup(). |
|
|
|
Referenced by AI_SortGroupByPathCostToEnemy(). |
|
|
Definition at line 18 of file ai.h.
00019 {
00020 SQUAD_IDLE, //No target found, waiting
00021 SQUAD_STAND_AND_SHOOT, //Standing in position and shoot (no cover)
00022 SQUAD_RETREAT, //Running away from combat
00023 SQUAD_COVER, //Under protective cover
00024 SQUAD_TRANSITION, //Moving between points, not firing
00025 SQUAD_POINT, //On point, laying down suppressive fire
00026 SQUAD_SCOUT, //Poking out to draw enemy
00027 NUM_SQUAD_STATES,
00028 };
|
|
|
Definition at line 12 of file ai.h.
00013 {
00014 ATTACK_MELEE,
00015 ATTACK_RANGE,
00016 } attack_e;
|
|
|
Definition at line 5 of file ai.h. Referenced by ATST_Attack(), and Mark1_AttackDecision().
00006 {
00007 DIST_MELEE,
00008 DIST_LONG,
00009 } distance_e;
|
|
|
Definition at line 31 of file ai.h.
00032 {
00033 RANK_CIVILIAN,
00034 RANK_CREWMAN,
00035 RANK_ENSIGN,
00036 RANK_LT_JG,
00037 RANK_LT,
00038 RANK_LT_COMM,
00039 RANK_COMMANDER,
00040 RANK_CAPTAIN
00041 } rank_t;
|
|
||||||||||||
|
Definition at line 1030 of file NPC_AI_Utils.c. References navInfo_s::blocker, gentity_s::client, gentity_s::enemy, gclient_s::enemyTeam, G_SetEnemy(), gentity_t, NAV_GetLastMove(), navInfo_t, NULL, gclient_s::playerTeam, qboolean, qfalse, and qtrue.
01031 {
01032 navInfo_t info;
01033
01034 if ( ent == NULL )
01035 return qfalse;
01036
01037 // if ( ent->svFlags & SVF_LOCKEDENEMY )
01038 // return qfalse;
01039
01040 NAV_GetLastMove( &info );
01041
01042 //See if we've hit something
01043 if ( ( info.blocker ) && ( info.blocker != ent->enemy ) )
01044 {
01045 if ( ( info.blocker->client ) && ( info.blocker->client->playerTeam == ent->client->enemyTeam ) )
01046 {
01047 if ( takeEnemy )
01048 G_SetEnemy( ent, info.blocker );
01049
01050 return qtrue;
01051 }
01052 }
01053
01054 return qfalse;
01055 }
|
|
||||||||||||||||||||
|
Definition at line 1065 of file NPC_AI_Utils.c. References AI_GetGroupSize(), gentity_s::client, entityShared_t::currentOrigin, g_entities, gentity_t, gentity_s::health, MAX_RADIUS_ENTS, NULL, gclient_s::playerTeam, gentity_s::r, team_t, trap_EntitiesInBox(), and vec3_t.
01066 {
01067 int radiusEnts[ MAX_RADIUS_ENTS ];
01068 gentity_t *check;
01069 int numEnts;
01070 int numSurrounding;
01071 int i;
01072 int j;
01073 vec3_t mins, maxs;
01074
01075 //Don't take new targets
01076 // if ( NPC->svFlags & SVF_LOCKEDENEMY )
01077 // return enemy;
01078
01079 numSurrounding = AI_GetGroupSize( enemy->r.currentOrigin, 48, team, attacker );
01080
01081 //First, see if we should look for the player
01082 if ( enemy != &g_entities[0] )
01083 {
01084 //rwwFIXMEFIXME: care about all clients not just 0
01085 int aroundPlayer = AI_GetGroupSize( g_entities[0].r.currentOrigin, 48, team, attacker );
01086
01087 //See if we're above our threshold
01088 if ( aroundPlayer < threshold )
01089 {
01090 return &g_entities[0];
01091 }
01092 }
01093
01094 //See if our current enemy is still ok
01095 if ( numSurrounding < threshold )
01096 return enemy;
01097
01098 //Otherwise we need to take a new enemy if possible
01099
01100 //Setup the bbox to search in
01101 for ( i = 0; i < 3; i++ )
01102 {
01103 mins[i] = enemy->r.currentOrigin[i] - 512;
01104 maxs[i] = enemy->r.currentOrigin[i] + 512;
01105 }
01106
01107 //Get the number of entities in a given space
01108 numEnts = trap_EntitiesInBox( mins, maxs, radiusEnts, MAX_RADIUS_ENTS );
01109
01110 //Cull this list
01111 for ( j = 0; j < numEnts; j++ )
01112 {
01113 check = &g_entities[radiusEnts[j]];
01114
01115 //Validate clients
01116 if ( check->client == NULL )
01117 continue;
01118
01119 //Skip the requested avoid ent if present
01120 if ( ( check == enemy ) )
01121 continue;
01122
01123 //Must be on the same team
01124 if ( check->client->playerTeam != enemy->client->playerTeam )
01125 continue;
01126
01127 //Must be alive
01128 if ( check->health <= 0 )
01129 continue;
01130
01131 //Must not be overwhelmed
01132 if ( AI_GetGroupSize( check->r.currentOrigin, 48, team, attacker ) > threshold )
01133 continue;
01134
01135 return check;
01136 }
01137
01138 return NULL;
01139 }
|
|
|
Definition at line 443 of file NPC_AI_Utils.c. References AIGroupInfo_s::activeMemberNum, AI_GetNextEmptyGroup(), AI_InsertGroupMember(), AI_SetClosestBuddy(), AI_SortGroupByPathCostToEnemy(), AI_ValidateGroupMember(), AIGroupInfo_t, gentity_s::client, AIGroupInfo_s::commander, entityShared_t::currentOrigin, d_noGroupAI, gentity_s::enemy, AIGroupInfo_s::enemy, AIGroupInfo_s::enemyLastSeenPos, gNPC_t::enemyLastSeenTime, g_entities, gentity_t, gNPC_t::group, vmCvar_t::integer, gentity_s::inuse, AIGroupInfo_s::lastClearShotTime, AIGroupInfo_s::lastSeenEnemyTime, level, MAX_GROUP_MEMBERS, AIGroupInfo_s::memberValidateTime, memset(), gentity_s::NPC, NULL, level_locals_t::num_entities, AIGroupInfo_s::numGroup, gclient_s::playerTeam, AIGroupInfo_s::processed, qfalse, gentity_s::r, SCF_NO_GROUPS, gNPC_t::scriptFlags, AIGroupInfo_s::team, level_locals_t::time, and VectorCopy. Referenced by NPC_BSST_Attack(), NPC_BSST_Investigate(), and NPC_BSST_Patrol().
00444 {
00445 int i;
00446 gentity_t *member;//, *waiter;
00447 //int waiters[MAX_WAITERS];
00448
00449 if ( !self || !self->NPC )
00450 {
00451 return;
00452 }
00453
00454 if ( d_noGroupAI.integer )
00455 {
00456 self->NPC->group = NULL;
00457 return;
00458 }
00459
00460 if ( !self->client )
00461 {
00462 self->NPC->group = NULL;
00463 return;
00464 }
00465
00466 if ( self->NPC->scriptFlags&SCF_NO_GROUPS )
00467 {
00468 self->NPC->group = NULL;
00469 return;
00470 }
00471
00472 if ( self->enemy && (!self->enemy->client || (level.time - self->NPC->enemyLastSeenTime > 7000 )))
00473 {
00474 self->NPC->group = NULL;
00475 return;
00476 }
00477
00478 if ( !AI_GetNextEmptyGroup( self ) )
00479 {//either no more groups left or we're already in a group built earlier
00480 return;
00481 }
00482
00483 //create a new one
00484 memset( self->NPC->group, 0, sizeof( AIGroupInfo_t ) );
00485
00486 self->NPC->group->enemy = self->enemy;
00487 self->NPC->group->team = self->client->playerTeam;
00488 self->NPC->group->processed = qfalse;
00489 self->NPC->group->commander = self;
00490 self->NPC->group->memberValidateTime = level.time + 2000;
00491 self->NPC->group->activeMemberNum = 0;
00492
00493 if ( self->NPC->group->enemy )
00494 {
00495 self->NPC->group->lastSeenEnemyTime = level.time;
00496 self->NPC->group->lastClearShotTime = level.time;
00497 VectorCopy( self->NPC->group->enemy->r.currentOrigin, self->NPC->group->enemyLastSeenPos );
00498 }
00499
00500 // for ( i = 0, member = &g_entities[0]; i < globals.num_entities ; i++, member++)
00501 for ( i = 0; i < level.num_entities ; i++)
00502 {
00503 member = &g_entities[i];
00504
00505 if (!member->inuse)
00506 {
00507 continue;
00508 }
00509
00510 if ( !AI_ValidateGroupMember( self->NPC->group, member ) )
00511 {//FIXME: keep track of those who aren't angry yet and see if we should wake them after we assemble the core group
00512 continue;
00513 }
00514
00515 //store it
00516 AI_InsertGroupMember( self->NPC->group, member );
00517
00518 if ( self->NPC->group->numGroup >= (MAX_GROUP_MEMBERS - 1) )
00519 {//full
00520 break;
00521 }
00522 }
00523
00524 /*
00525 //now go through waiters and see if any should join the group
00526 //NOTE: Some should hang back and probably not attack, so we can ambush
00527 //NOTE: only do this if calling for reinforcements?
00528 for ( i = 0; i < numWaiters; i++ )
00529 {
00530 waiter = &g_entities[waiters[i]];
00531
00532 for ( j = 0; j < self->NPC->group->numGroup; j++ )
00533 {
00534 member = &g_entities[self->NPC->group->member[j];
00535
00536 if ( trap_InPVS( waiter->r.currentOrigin, member->r.currentOrigin ) )
00537 {//this waiter is within PVS of a current member
00538 }
00539 }
00540 }
00541 */
00542
00543 if ( self->NPC->group->numGroup <= 0 )
00544 {//none in group
00545 self->NPC->group = NULL;
00546 return;
00547 }
00548
00549 AI_SortGroupByPathCostToEnemy( self->NPC->group );
00550 AI_SetClosestBuddy( self->NPC->group );
00551 }
|
|
||||||||||||||||||||
|
Definition at line 23 of file NPC_AI_Utils.c. References gentity_s::client, g_entities, gentity_t, gentity_s::health, MAX_RADIUS_ENTS, NULL, gclient_s::playerTeam, team_t, trap_EntitiesInBox(), and vec3_t. Referenced by AI_DistributeAttack(), and AI_GetGroupSize2().
00024 {
00025 int radiusEnts[ MAX_RADIUS_ENTS ];
00026 gentity_t *check;
00027 vec3_t mins, maxs;
00028 int numEnts, realCount = 0;
00029 int i;
00030 int j;
00031
00032 //Setup the bbox to search in
00033 for ( i = 0; i < 3; i++ )
00034 {
00035 mins[i] = origin[i] - radius;
00036 maxs[i] = origin[i] + radius;
00037 }
00038
00039 //Get the number of entities in a given space
00040 numEnts = trap_EntitiesInBox( mins, maxs, radiusEnts, MAX_RADIUS_ENTS );
00041
00042 //Cull this list
00043 for ( j = 0; j < numEnts; j++ )
00044 {
00045 check = &g_entities[radiusEnts[j]];
00046
00047 //Validate clients
00048 if ( check->client == NULL )
00049 continue;
00050
00051 //Skip the requested avoid ent if present
00052 if ( ( avoid != NULL ) && ( check == avoid ) )
00053 continue;
00054
00055 //Must be on the same team
00056 if ( check->client->playerTeam != playerTeam )
00057 continue;
00058
00059 //Must be alive
00060 if ( check->health <= 0 )
00061 continue;
00062
00063 realCount++;
00064 }
00065
00066 return realCount;
00067 }
|
|
||||||||||||
|
Definition at line 71 of file NPC_AI_Utils.c. References AI_GetGroupSize(), gentity_s::client, entityShared_t::currentOrigin, gentity_t, NULL, gclient_s::playerTeam, and gentity_s::r.
00072 {
00073 if ( ( ent == NULL ) || ( ent->client == NULL ) )
00074 return -1;
00075
00076 return AI_GetGroupSize( ent->r.currentOrigin, radius, ent->client->playerTeam, ent );
00077 }
|
|
|
Definition at line 310 of file NPC_AI_Atst.c. References ATST_Attack(), ATST_Idle(), ATST_Patrol(), gentity_s::enemy, gNPC_t::goalEntity, NPC, NPCInfo, SCF_CHASE_ENEMIES, SCF_LOOK_FOR_ENEMIES, and gNPC_t::scriptFlags. Referenced by NPC_BehaviorSet_ATST().
00311 {
00312 if ( NPC->enemy )
00313 {
00314 if( (NPCInfo->scriptFlags & SCF_CHASE_ENEMIES) )
00315 {
00316 NPCInfo->goalEntity = NPC->enemy;
00317 }
00318 ATST_Attack();
00319 }
00320 else if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
00321 {
00322 ATST_Patrol();
00323 }
00324 else
00325 {
00326 ATST_Idle();
00327 }
00328 }
|
|
|
Definition at line 597 of file NPC_AI_Droid.c. References crandom, Droid_Pain(), Droid_Patrol(), Droid_Run(), Droid_Spin(), gNPC_t::localState, LSTATE_DROP, LSTATE_PAIN, LSTATE_SPINNING, NPC_UpdateAngles(), NPCInfo, qtrue, SCF_LOOK_FOR_ENEMIES, gNPC_t::scriptFlags, ucmd, and usercmd_s::upmove. Referenced by NPC_BehaviorSet_Droid().
00598 {
00599
00600 if ( NPCInfo->localState == LSTATE_SPINNING )
00601 {
00602 Droid_Spin();
00603 }
00604 else if ( NPCInfo->localState == LSTATE_PAIN )
00605 {
00606 Droid_Pain();
00607 }
00608 else if ( NPCInfo->localState == LSTATE_DROP )
00609 {
00610 NPC_UpdateAngles( qtrue, qtrue );
00611 ucmd.upmove = crandom() * 64;
00612 }
00613 else if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
00614 {
00615 Droid_Patrol();
00616 }
00617 else
00618 {
00619 Droid_Run();
00620 }
00621 }
|
|
|
Definition at line 664 of file NPC_AI_Grenadier.c. References gentity_s::enemy, NPC, NPC_BSGrenadier_Attack(), NPC_BSGrenadier_Patrol(), NPCInfo, qtrue, SCF_FIRE_WEAPON, gNPC_t::scriptFlags, and WeaponThink(). Referenced by NPC_BehaviorSet_Grenadier().
00665 {
00666 if( NPCInfo->scriptFlags & SCF_FIRE_WEAPON )
00667 {
00668 WeaponThink( qtrue );
00669 }
00670
00671 if( !NPC->enemy )
00672 {//don't have an enemy, look for one
00673 NPC_BSGrenadier_Patrol();
00674 }
00675 else//if ( NPC->enemy )
00676 {//have an enemy
00677 NPC_BSGrenadier_Attack();
00678 }
00679 }
|
|
|
Definition at line 202 of file NPC_AI_Howler.c. References gentity_s::enemy, Howler_Combat(), Howler_Idle(), Howler_Patrol(), NPC, NPC_UpdateAngles(), NPCInfo, qtrue, SCF_LOOK_FOR_ENEMIES, and gNPC_t::scriptFlags. Referenced by NPC_BehaviorSet_Howler().
00203 {
00204 if ( NPC->enemy )
00205 {
00206 Howler_Combat();
00207 }
00208 else if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
00209 {
00210 Howler_Patrol();
00211 }
00212 else
00213 {
00214 Howler_Idle();
00215 }
00216
00217 NPC_UpdateAngles( qtrue, qtrue );
00218 }
|
|
|
Definition at line 589 of file NPC_AI_ImperialProbe.c. References gentity_s::enemy, gNPC_t::goalEntity, ImperialProbe_AttackDecision(), ImperialProbe_Idle(), ImperialProbe_Patrol(), ImperialProbe_Wait(), gNPC_t::localState, LSTATE_DROP, NPC, NPCInfo, SCF_LOOK_FOR_ENEMIES, and gNPC_t::scriptFlags. Referenced by NPC_BehaviorSet_ImperialProbe().
00590 {
00591
00592 if ( NPC->enemy )
00593 {
00594 NPCInfo->goalEntity = NPC->enemy;
00595 ImperialProbe_AttackDecision();
00596 }
00597 else if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
00598 {
00599 ImperialProbe_Patrol();
00600 }
00601 else if ( NPCInfo->localState == LSTATE_DROP )
00602 {
00603 ImperialProbe_Wait();
00604 }
00605 else
00606 {
00607 ImperialProbe_Idle();
00608 }
00609 }
|
|
|
Definition at line 454 of file NPC_AI_Interrogator.c. References gentity_s::enemy, Interrogator_Attack(), Interrogator_Idle(), and NPC. Referenced by NPC_BehaviorSet_Interrogator().
00455 {
00456 //NPC->e_DieFunc = dieF_Interrogator_die;
00457
00458 if ( NPC->enemy )
00459 {
00460 Interrogator_Attack();
00461 }
00462 else
00463 {
00464 Interrogator_Idle();
00465 }
00466
00467 }
|
|
|
Definition at line 6170 of file NPC_AI_Jedi.c. References Boba_ChangeWeapon(), usercmd_s::buttons, CLASS_BOBAFETT, gentity_s::client, gNPC_t::confusionTime, entityShared_t::currentOrigin, gentity_s::enemy, gNPC_t::enemyCheckDebounceTime, playerState_s::fd, forcedata_s::forcePowersActive, G_SetEnemy(), gentity_t, gentity_s::health, Jedi_Ambush(), Jedi_CheckCloak(), Jedi_WaitingAmbush(), gentity_s::lastEnemy, level, clientPersistant_t::maxHealth, NPC, NPC_BSSniper_Default(), NPC_BSST_Patrol(), NPC_CheckEnemy(), gclient_s::NPC_class, NPCInfo, NULL, gclient_s::pers, gclient_s::ps, Q_irand(), qfalse, gentity_s::r, SCF_ALT_FIRE, gNPC_t::scriptFlags, level_locals_t::time, ucmd, and WP_DISRUPTOR. Referenced by NPC_BehaviorSet_Jedi().
06171 {
06172
06173 Jedi_CheckCloak();
06174 if( !NPC->enemy )
06175 {//don't have an enemy, look for one
06176 if ( NPC->client->NPC_class == CLASS_BOBAFETT )
06177 {
06178 NPC_BSST_Patrol();
06179 }
06180 else
06181 {
06182 Jedi_Patrol();
06183 }
06184 }
06185 else//if ( NPC->enemy )
06186 {//have an enemy
06187 if ( Jedi_WaitingAmbush( NPC ) )
06188 {//we were still waiting to drop down - must have had enemy set on me outside my AI
06189 Jedi_Ambush( NPC );
06190 }
06191 if ( NPC->client->NPC_class == CLASS_BOBAFETT )
06192 {
06193 if ( NPC->enemy->enemy != NPC && NPC->health == NPC->client->pers.maxHealth && DistanceSquared( NPC->r.currentOrigin, NPC->enemy->r.currentOrigin )>(800*800) )
06194 {
06195 NPCInfo->scriptFlags |= SCF_ALT_FIRE;
06196 Boba_ChangeWeapon( WP_DISRUPTOR );
06197 NPC_BSSniper_Default();
06198 return;
06199 }
06200 }
06201 Jedi_Attack();
06202 //if we have multiple-jedi combat, probably need to keep checking (at certain debounce intervals) for a better (closer, more active) enemy and switch if needbe...
06203 if ( ((!ucmd.buttons&&!NPC->client->ps.fd.forcePowersActive)||(NPC->enemy&&NPC->enemy->health<=0)) && NPCInfo->enemyCheckDebounceTime < level.time )
06204 {//not doing anything (or walking toward a vanquished enemy - fixme: always taunt the player?), not using force powers and it's time to look again
06205 //FIXME: build a list of all local enemies (since we have to find best anyway) for other AI factors- like when to use group attacks, determine when to change tactics, when surrounded, when blocked by another in the enemy group, etc. Should we build this group list or let the enemies maintain their own list and we just access it?
06206 gentity_t *sav_enemy = NPC->enemy;//FIXME: what about NPC->lastEnemy?
06207 gentity_t *newEnemy;
06208
06209 NPC->enemy = NULL;
06210 newEnemy = NPC_CheckEnemy( NPCInfo->confusionTime < level.time, qfalse, qfalse );
06211 NPC->enemy = sav_enemy;
06212 if ( newEnemy && newEnemy != sav_enemy )
06213 {//picked up a new enemy!
06214 NPC->lastEnemy = NPC->enemy;
06215 G_SetEnemy( NPC, newEnemy );
06216 }
06217 NPCInfo->enemyCheckDebounceTime = level.time + Q_irand( 1000, 3000 );
06218 }
06219 }
06220 }
|
|
|
Definition at line 5758 of file NPC_AI_Jedi.c. References gNPC_t::aiFlags, BLOCKED_NONE, gNPC_t::blockedDest, BUTTON_ATTACK, usercmd_s::buttons, gentity_s::client, gentity_s::clipmask, CONTENTS_BODY, CONTENTS_BOTCLIP, entityShared_t::currentOrigin, gentity_s::enemy, ENTITYNUM_NONE, fabs(), g_entities, G_FreeEntity(), G_SetOrigin(), G_Spawn(), gentity_t, gNPC_t::goalEntity, gentity_s::health, Jedi_CanPullBackSaber(), NAV_CheckAhead(), NPC, NPC_BSFollowLeader(), NPC_ClearLOS4(), NPC_FaceEntity(), NPC_MoveToGoal(), NPC_UpdateAngles(), NPCAI_BLOCKED, NPCInfo, gclient_s::ps, qtrue, gentity_s::r, playerState_s::saberBlocked, playerState_s::saberEntityNum, playerState_s::saberInFlight, TIMER_Set(), TR_STATIONARY, trap_LinkEntity(), and ucmd. Referenced by NPC_BehaviorSet_Jedi().
05759 {
05760 NPC->client->ps.saberBlocked = BLOCKED_NONE;
05761 if ( !NPC->enemy )
05762 {
05763 //Com_Printf( "(%d) drop agg - no enemy (follow)\n", level.time );
05764 Jedi_AggressionErosion(-1);
05765 }
05766
05767 //did we drop our saber? If so, go after it!
05768 if ( NPC->client->ps.saberInFlight )
05769 {//saber is not in hand
05770 if ( NPC->client->ps.saberEntityNum < ENTITYNUM_NONE && NPC->client->ps.saberEntityNum > 0 )//player is 0
05771 {//
05772 if ( g_entities[NPC->client->ps.saberEntityNum].s.pos.trType == TR_STATIONARY )
05773 {//fell to the ground, try to pick it up...
05774 if ( Jedi_CanPullBackSaber( NPC ) )
05775 {
05776 //FIXME: if it's on the ground and we just pulled it back to us, should we
05777 // stand still for a bit to make sure it gets to us...?
05778 // otherwise we could end up running away from it while it's on its
05779 // way back to us and we could lose it again.
05780 NPC->client->ps.saberBlocked = BLOCKED_NONE;
05781 NPCInfo->goalEntity = &g_entities[NPC->client->ps.saberEntityNum];
05782 ucmd.buttons |= BUTTON_ATTACK;
05783 if ( NPC->enemy && NPC->enemy->health > 0 )
05784 {//get our saber back NOW!
05785 if ( !NPC_MoveToGoal( qtrue ) )//Jedi_Move( NPCInfo->goalEntity, qfalse );
05786 {//can't nav to it, try jumping to it
05787 NPC_FaceEntity( NPCInfo->goalEntity, qtrue );
05788 Jedi_TryJump( NPCInfo->goalEntity );
05789 }
05790 NPC_UpdateAngles( qtrue, qtrue );
05791 return;
05792 }
05793 }
05794 }
05795 }
05796 }
05797
05798 if ( NPCInfo->goalEntity )
05799 {
05800 trace_t trace;
05801
05802 if ( Jedi_Jumping( NPCInfo->goalEntity ) )
05803 {//in mid-jump
05804 return;
05805 }
05806
05807 if ( !NAV_CheckAhead( NPC, NPCInfo->goalEntity->r.currentOrigin, &trace, ( NPC->clipmask & ~CONTENTS_BODY )|CONTENTS_BOTCLIP ) )
05808 {//can't get straight to him
05809 if ( NPC_ClearLOS4( NPCInfo->goalEntity ) && NPC_FaceEntity( NPCInfo->goalEntity, qtrue ) )
05810 {//no line of sight
05811 if ( Jedi_TryJump( NPCInfo->goalEntity ) )
05812 {//started a jump
05813 return;
05814 }
05815 }
05816 }
05817 if ( NPCInfo->aiFlags & NPCAI_BLOCKED )
05818 {//try to jump to the blockedDest
05819 if ( fabs(NPCInfo->blockedDest[2]-NPC->r.currentOrigin[2]) > 64 )
05820 {
05821 gentity_t *tempGoal = G_Spawn();//ugh, this is NOT good...?
05822 G_SetOrigin( tempGoal, NPCInfo->blockedDest );
05823 trap_LinkEntity( tempGoal );
05824 TIMER_Set( NPC, "jumpChaseDebounce", -1 );
05825 if ( Jedi_TryJump( tempGoal ) )
05826 {//going to jump to the dest
05827 G_FreeEntity( tempGoal );
05828 return;
05829 }
05830 G_FreeEntity( tempGoal );
05831 }
05832 }
05833 }
05834 //try normal movement
05835 NPC_BSFollowLeader();
05836 }
|
|
|
|
|
|
Definition at line 747 of file NPC_AI_Mark1.c. References gentity_s::enemy, gNPC_t::goalEntity, Mark1_AttackDecision(), Mark1_Idle(), Mark1_Patrol(), NPC, NPCInfo, SCF_LOOK_FOR_ENEMIES, and gNPC_t::scriptFlags. Referenced by NPC_BehaviorSet_Mark1().
00748 {
00749 //NPC->e_DieFunc = dieF_Mark1_die;
00750
00751 if ( NPC->enemy )
00752 {
00753 NPCInfo->goalEntity = NPC->enemy;
00754 Mark1_AttackDecision();
00755 }
00756 else if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
00757 {
00758 Mark1_Patrol();
00759 }
00760 else
00761 {
00762 Mark1_Idle();
00763 }
00764 }
|
|
|
Definition at line 347 of file NPC_AI_Mark2.c. References gentity_s::enemy, gNPC_t::goalEntity, Mark2_AttackDecision(), Mark2_Idle(), Mark2_Patrol(), NPC, NPCInfo, SCF_LOOK_FOR_ENEMIES, and gNPC_t::scriptFlags. Referenced by NPC_BehaviorSet_Mark2().
00348 {
00349 if ( NPC->enemy )
00350 {
00351 NPCInfo->goalEntity = NPC->enemy;
00352 Mark2_AttackDecision();
00353 }
00354 else if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
00355 {
00356 Mark2_Patrol();
00357 }
00358 else
00359 {
00360 Mark2_Idle();
00361 }
00362 }
|
|
|
Definition at line 262 of file NPC_AI_MineMonster.c. References gentity_s::enemy, MineMonster_Combat(), MineMonster_Idle(), MineMonster_Patrol(), NPC, NPC_UpdateAngles(), NPCInfo, qtrue, SCF_LOOK_FOR_ENEMIES, and gNPC_t::scriptFlags. Referenced by NPC_BehaviorSet_MineMonster().
00263 {
00264 if ( NPC->enemy )
00265 {
00266 MineMonster_Combat();
00267 }
00268 else if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
00269 {
00270 MineMonster_Patrol();
00271 }
00272 else
00273 {
00274 MineMonster_Idle();
00275 }
00276
00277 NPC_UpdateAngles( qtrue, qtrue );
00278 }
|
|
|
Definition at line 828 of file NPC_AI_Rancor.c. References gentity_s::activator, AddSightEvent(), AddSoundEvent(), AEL_DANGER, AEL_DANGER_GREAT, BOTH_ATTACK3, BOTH_PAIN2, CHAN_AUTO, CLASS_RANCOR, gentity_s::client, gNPC_t::confusionTime, gentity_s::count, entityShared_t::currentOrigin, EF2_GENERIC_NPC_FLAG, EF2_USE_ALT_ANIM, playerState_s::eFlags2, gentity_s::enemy, G_SetEnemy(), G_Sound(), G_SoundIndex(), gentity_t, gentity_s::inuse, gentity_s::lastEnemy, playerState_s::legsAnim, level, NPC, NPC_CheckEnemy(), NPC_CheckEnemyExt(), gclient_s::NPC_class, NPC_FaceEnemy(), NPC_UpdateAngles(), NPCInfo, NULL, gclient_s::ps, Q_irand(), qfalse, qtrue, gentity_s::r, Rancor_CheckDropVictim(), Rancor_Combat(), Rancor_Crush(), Rancor_DropVictim(), Rancor_Idle(), Rancor_Patrol(), gentity_s::s, SCF_LOOK_FOR_ENEMIES, gNPC_t::scriptFlags, level_locals_t::time, entityState_s::time, TIMER_Done(), TIMER_Done2(), TIMER_Remove(), TIMER_Set(), va(), and ValidEnemy(). Referenced by NPC_BehaviorSet_Rancor().
00829 {
00830 AddSightEvent( NPC, NPC->r.currentOrigin, 1024, AEL_DANGER_GREAT, 50 );
00831
00832 Rancor_Crush();
00833
00834 NPC->client->ps.eFlags2 &= ~(EF2_USE_ALT_ANIM|EF2_GENERIC_NPC_FLAG);
00835 if ( NPC->count )
00836 {//holding someone
00837 NPC->client->ps.eFlags2 |= EF2_USE_ALT_ANIM;
00838 if ( NPC->count == 2 )
00839 {//in my mouth
00840 NPC->client->ps.eFlags2 |= EF2_GENERIC_NPC_FLAG;
00841 }
00842 }
00843 else
00844 {
00845 NPC->client->ps.eFlags2 &= ~(EF2_USE_ALT_ANIM|EF2_GENERIC_NPC_FLAG);
00846 }
00847
00848 if ( TIMER_Done2( NPC, "clearGrabbed", qtrue ) )
00849 {
00850 Rancor_DropVictim( NPC );
00851 }
00852 else if ( NPC->client->ps.legsAnim == BOTH_PAIN2
00853 && NPC->count == 1
00854 && NPC->activator )
00855 {
00856 if ( !Q_irand( 0, 3 ) )
00857 {
00858 Rancor_CheckDropVictim();
00859 }
00860 }
00861 if ( !TIMER_Done( NPC, "rageTime" ) )
00862 {//do nothing but roar first time we see an enemy
00863 AddSoundEvent( NPC, NPC->r.currentOrigin, 1024, AEL_DANGER_GREAT, qfalse );//, qfalse );
00864 NPC_FaceEnemy( qtrue );
00865 return;
00866 }
00867 if ( NPC->enemy )
00868 {
00869 /*
00870 if ( NPC->enemy->client //enemy is a client
00871 && (NPC->enemy->client->NPC_class == CLASS_UGNAUGHT || NPC->enemy->client->NPC_class == CLASS_JAWA )//enemy is a lowly jawa or ugnaught
00872 && NPC->enemy->enemy != NPC//enemy's enemy is not me
00873 && (!NPC->enemy->enemy || !NPC->enemy->enemy->client || NPC->enemy->enemy->client->NPC_class!=CLASS_RANCOR) )//enemy's enemy is not a client or is not a rancor (which is as scary as me anyway)
00874 {//they should be scared of ME and no-one else
00875 G_SetEnemy( NPC->enemy, NPC );
00876 }
00877 */
00878 if ( TIMER_Done(NPC,"angrynoise") )
00879 {
00880 G_Sound( NPC, CHAN_AUTO, G_SoundIndex( va("sound/chars/rancor/misc/anger%d.wav", Q_irand(1, 3))) );
00881
00882 TIMER_Set( NPC, "angrynoise", Q_irand( 5000, 10000 ) );
00883 }
00884 else
00885 {
00886 AddSoundEvent( NPC, NPC->r.currentOrigin, 512, AEL_DANGER_GREAT, qfalse );//, qfalse );
00887 }
00888 if ( NPC->count == 2 && NPC->client->ps.legsAnim == BOTH_ATTACK3 )
00889 {//we're still chewing our enemy up
00890 NPC_UpdateAngles( qtrue, qtrue );
00891 return;
00892 }
00893 //else, if he's in our hand, we eat, else if he's on the ground, we keep attacking his dead body for a while
00894 if( NPC->enemy->client && NPC->enemy->client->NPC_class == CLASS_RANCOR )
00895 {//got mad at another Rancor, look for a valid enemy
00896 if ( TIMER_Done( NPC, "rancorInfight" ) )
00897 {
00898 NPC_CheckEnemyExt( qtrue );
00899 }
00900 }
00901 else if ( !NPC->count )
00902 {
00903 if ( ValidEnemy( NPC->enemy ) == qfalse )
00904 {
00905 TIMER_Remove( NPC, "lookForNewEnemy" );//make them look again right now
00906 if ( !NPC->enemy->inuse || level.time - NPC->enemy->s.time > Q_irand( 10000, 15000 ) )
00907 {//it's been a while since the enemy died, or enemy is completely gone, get bored with him
00908 NPC->enemy = NULL;
00909 Rancor_Patrol();
00910 NPC_UpdateAngles( qtrue, qtrue );
00911 return;
00912 }
00913 }
00914 if ( TIMER_Done( NPC, "lookForNewEnemy" ) )
00915 {
00916 gentity_t *newEnemy, *sav_enemy = NPC->enemy;//FIXME: what about NPC->lastEnemy?
00917 NPC->enemy = NULL;
00918 newEnemy = NPC_CheckEnemy( NPCInfo->confusionTime < level.time, qfalse, qfalse );
00919 NPC->enemy = sav_enemy;
00920 if ( newEnemy && newEnemy != sav_enemy )
00921 {//picked up a new enemy!
00922 NPC->lastEnemy = NPC->enemy;
00923 G_SetEnemy( NPC, newEnemy );
00924 //hold this one for at least 5-15 seconds
00925 TIMER_Set( NPC, "lookForNewEnemy", Q_irand( 5000, 15000 ) );
00926 }
00927 else
00928 {//look again in 2-5 secs
00929 TIMER_Set( NPC, "lookForNewEnemy", Q_irand( 2000, 5000 ) );
00930 }
00931 }
00932 }
00933 Rancor_Combat();
00934 }
00935 else
00936 {
00937 if ( TIMER_Done(NPC,"idlenoise") )
00938 {
00939 G_Sound( NPC, CHAN_AUTO, G_SoundIndex( va("sound/chars/rancor/snort_%d.wav", Q_irand(1, 2))) );
00940
00941 TIMER_Set( NPC, "idlenoise", Q_irand( 2000, 4000 ) );
00942 AddSoundEvent( NPC, NPC->r.currentOrigin, 384, AEL_DANGER, qfalse );//, qfalse );
00943 }
00944 if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
00945 {
00946 Rancor_Patrol();
00947 }
00948 else
00949 {
00950 Rancor_Idle();
00951 }
00952 }
00953
00954 NPC_UpdateAngles( qtrue, qtrue );
00955 }
|
|
|
Definition at line 854 of file NPC_AI_Sniper.c. Referenced by NPC_BehaviorSet_Sniper(), and NPC_BSJedi_Default().
00855 {
00856 if( !NPC->enemy )
00857 {//don't have an enemy, look for one
00858 NPC_BSSniper_Patrol();
00859 }
00860 else//if ( NPC->enemy )
00861 {//have an enemy
00862 NPC_BSSniper_Attack();
00863 }
00864 }
|
|
|
Definition at line 2726 of file NPC_AI_Stormtrooper.c. References gentity_s::enemy, NPC, NPC_BSST_Attack(), NPC_BSST_Patrol(), NPC_CheckGetNewWeapon(), NPCInfo, qtrue, SCF_FIRE_WEAPON, gNPC_t::scriptFlags, and WeaponThink(). Referenced by NPC_BehaviorSet_Stormtrooper().
02727 {
02728 if( NPCInfo->scriptFlags & SCF_FIRE_WEAPON )
02729 {
02730 WeaponThink( qtrue );
02731 }
02732
02733 if( !NPC->enemy )
02734 {//don't have an enemy, look for one
02735 NPC_BSST_Patrol();
02736 }
02737 else //if ( NPC->enemy )
02738 {//have an enemy
02739 NPC_CheckGetNewWeapon();
02740 NPC_BSST_Attack();
02741 }
02742 }
|
|
|
Definition at line 978 of file NPC_AI_Stormtrooper.c. References AEL_MINOR, AI_GetGroup(), level_locals_t::alertEvents, BS_DEFAULT, BUTTON_WALKING, usercmd_s::buttons, gNPC_t::confusionTime, entityShared_t::currentOrigin, FlyingCreature(), gNPC_t::goalEntity, alertEvent_s::ID, gNPC_t::investigateCount, gNPC_t::investigateDebounceTime, gNPC_t::lastAlertID, level, gNPC_t::localState, LSTATE_INVESTIGATE, LSTATE_NONE, entityShared_t::maxs, entityShared_t::mins, NAV_HitNavGoal(), NPC, NPC_CheckAlertEvents(), NPC_CheckForDanger(), NPC_CheckPlayerTeamStealth(), NPC_MoveToGoal(), NPC_UpdateAngles(), NPCInfo, NULL, gNPC_t::pauseTime, qfalse, qtrue, gentity_s::r, SCF_FIRE_WEAPON, SCF_IGNORE_ALERTS, SCF_LOOK_FOR_ENEMIES, gNPC_t::scriptFlags, SPEECH_COVER, SPEECH_DETECTED, SPEECH_GIVEUP, gNPC_t::tempBehavior, level_locals_t::time, ucmd, UpdateGoal(), and WeaponThink(). Referenced by NPC_BehaviorSet_Stormtrooper().
00979 {
00980 //get group- mainly for group speech debouncing, but may use for group scouting/investigating AI, too
00981 AI_GetGroup( NPC );
00982
00983 if( NPCInfo->scriptFlags & SCF_FIRE_WEAPON )
00984 {
00985 WeaponThink( qtrue );
00986 }
00987
00988 if ( NPCInfo->confusionTime < level.time )
00989 {
00990 if ( NPCInfo->scriptFlags&SCF_LOOK_FOR_ENEMIES )
00991 {
00992 //Look for an enemy
00993 if ( NPC_CheckPlayerTeamStealth() )
00994 {
00995 //NPCInfo->behaviorState = BS_HUNT_AND_KILL;//should be auto now
00996 ST_Speech( NPC, SPEECH_DETECTED, 0 );
00997 NPCInfo->tempBehavior = BS_DEFAULT;
00998 NPC_UpdateAngles( qtrue, qtrue );
00999 return;
01000 }
01001 }
01002 }
01003
01004 if ( !(NPCInfo->scriptFlags&SCF_IGNORE_ALERTS) )
01005 {
01006 int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, NPCInfo->lastAlertID, qfalse, AEL_MINOR );
01007
01008 //There is an event to look at
01009 if ( alertEvent >= 0 )
01010 {
01011 if ( NPCInfo->confusionTime < level.time )
01012 {
01013 if ( NPC_CheckForDanger( alertEvent ) )
01014 {//running like hell
01015 ST_Speech( NPC, SPEECH_COVER, 0 );//FIXME: flee sound?
01016 return;
01017 }
01018 }
01019
01020 if ( level.alertEvents[alertEvent].ID != NPCInfo->lastAlertID )
01021 {
01022 NPC_ST_InvestigateEvent( alertEvent, qtrue );
01023 }
01024 }
01025 }
01026
01027 //If we're done looking, then just return to what we were doing
01028 if ( ( NPCInfo->investigateDebounceTime + NPCInfo->pauseTime ) < level.time )
01029 {
01030 NPCInfo->tempBehavior = BS_DEFAULT;
01031 NPCInfo->goalEntity = UpdateGoal();
01032
01033 NPC_UpdateAngles( qtrue, qtrue );
01034 //Say something
01035 ST_Speech( NPC, SPEECH_GIVEUP, 0 );
01036 return;
01037 }
01038
01039 //FIXME: else, look for new alerts
01040
01041 //See if we're searching for the noise's origin
01042 if ( NPCInfo->localState == LSTATE_INVESTIGATE && (NPCInfo->goalEntity!=NULL) )
01043 {
01044 //See if we're there
01045 if ( NAV_HitNavGoal( NPC->r.currentOrigin, NPC->r.mins, NPC->r.maxs, NPCInfo->goalEntity->r.currentOrigin, 32, FlyingCreature( NPC ) ) == qfalse )
01046 {
01047 ucmd.buttons |= BUTTON_WALKING;
01048
01049 //Try and move there
01050 if ( NPC_MoveToGoal( qtrue ) )
01051 {
01052 //Bump our times
01053 NPCInfo->investigateDebounceTime = NPCInfo->investigateCount * 5000;
01054 NPCInfo->pauseTime = level.time;
01055
01056 NPC_UpdateAngles( qtrue, qtrue );
01057 return;
01058 }
01059 }
01060
01061 //Otherwise we're done or have given up
01062 //Say something
01063 //ST_Speech( NPC, SPEECH_LOOK, 0.33f );
01064 NPCInfo->localState = LSTATE_NONE;
01065 }
01066
01067 //Look around
01068 ST_LookAround();
01069 }
|
|
|
Definition at line 447 of file NPC_AI_Stormtrooper.c. References AEL_DISCOVERED, AEL_MINOR, level_locals_t::alertEvents, g_entities, G_SetEnemy(), gentity_s::health, level, alertEvent_s::level, NPC, NPC_CheckAlertEvents(), NPCInfo, qfalse, qtrue, SCF_LOOK_FOR_ENEMIES, and gNPC_t::scriptFlags. Referenced by NPC_BehaviorSet_Stormtrooper().
00448 {
00449 int alertEvent = NPC_CheckAlertEvents( qfalse, qtrue, -1, qfalse, AEL_MINOR );//only check sounds since we're alseep!
00450
00451 //There is an event we heard
00452 if ( alertEvent >= 0 )
00453 {
00454 //See if it was enough to wake us up
00455 if ( level.alertEvents[alertEvent].level == AEL_DISCOVERED && (NPCInfo->scriptFlags&SCF_LOOK_FOR_ENEMIES) )
00456 { //rwwFIXMEFIXME: Care about all clients not just 0
00457 if ( &g_entities[0] && g_entities[0].health > 0 )
00458 {
00459 G_SetEnemy( NPC, &g_entities[0] );
00460 return;
00461 }
00462 }
00463
00464 //Otherwise just stir a bit
00465 NPC_ST_SleepShuffle();
00466 return;
00467 }
00468 }
|
|
|
Definition at line 727 of file NPC_AI_Stormtrooper.c. References gentity_s::client, gclient_s::enemyTeam, ENTITYNUM_WORLD, g_entities, gentity_t, gentity_s::inuse, NPC, NPC_CheckEnemyStealth(), NPC_ValidEnemy(), gclient_s::playerTeam, qboolean, qfalse, and qtrue. Referenced by ATST_Patrol(), ImperialProbe_Patrol(), Interrogator_Idle(), Mark1_Patrol(), Mark2_Patrol(), NPC_BSGM_Patrol(), NPC_BSGrenadier_Patrol(), NPC_BSSniper_Patrol(), NPC_BSST_Investigate(), NPC_BSST_Patrol(), and NPC_Sentry_Patrol().
00728 {
00729 /*
00730 //NOTENOTE: For now, all stealh checks go against the player, since
00731 // he is the main focus. Squad members and rivals do not
00732 // fall into this category and will be ignored.
00733
00734 NPC_CheckEnemyStealth( &g_entities[0] ); //Change this pointer to assess other entities
00735 */
00736 gentity_t *enemy;
00737 int i;
00738
00739 for ( i = 0; i < ENTITYNUM_WORLD; i++ )
00740 {
00741 enemy = &g_entities[i];
00742
00743 if (!enemy->inuse)
00744 {
00745 continue;
00746 }
00747
00748 if ( enemy && enemy->client && NPC_ValidEnemy( enemy ) && enemy->client->playerTeam == NPC->client->enemyTeam )
00749 {
00750 if ( NPC_CheckEnemyStealth( enemy ) ) //Change this pointer to assess other entities
00751 {
00752 return qtrue;
00753 }
00754 }
00755 }
00756 return qfalse;
00757 }
|