#include "b_local.h"#include "g_nav.h"Go to the source code of this file.
|
|
Definition at line 10 of file NPC_AI_Utils.c. |
|
|
Definition at line 1063 of file NPC_AI_Utils.c. |
|
|
Definition at line 1063 of file NPC_AI_Utils.c. Referenced by AI_DistributeAttack(), AI_GetGroupSize(), and NPC_FindNearestEnemy(). |
|
||||||||||||
|
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 80 of file NPC_AI_Utils.c. References AIGroupInfo_t, ENTITYNUM_NONE, g_entities, AIGroupInfo_s::member, NAV_FindClosestWaypointForPoint(), NULL, AIGroupMember_s::number, AIGroupInfo_s::numGroup, Q3_INFINITE, trap_Nav_GetPathCost(), vec3_t, AIGroupMember_s::waypoint, and WAYPOINT_NONE.
00081 {
00082 int markerWP = WAYPOINT_NONE;
00083 int cost, bestCost = Q3_INFINITE;
00084 int closest = ENTITYNUM_NONE;
00085 int i;
00086
00087 if ( group == NULL || group->numGroup <= 0 )
00088 {
00089 return ENTITYNUM_NONE;
00090 }
00091
00092 markerWP = NAV_FindClosestWaypointForPoint( &g_entities[group->member[0].number], point );
00093
00094 if ( markerWP == WAYPOINT_NONE )
00095 {
00096 return ENTITYNUM_NONE;
00097 }
00098
00099 for ( i = 0; i < group->numGroup; i++ )
00100 {
00101 cost = trap_Nav_GetPathCost( group->member[i].waypoint, markerWP );
00102 if ( cost < bestCost )
00103 {
00104 bestCost = cost;
00105 closest = group->member[i].number;
00106 }
00107 }
00108
00109 return closest;
00110 }
|
|
||||||||||||
|
Definition at line 570 of file NPC_AI_Utils.c. References AIGroupInfo_s::activeMemberNum, AI_SetNewGroupCommander(), AIGroupInfo_t, AIGroupInfo_s::commander, g_entities, AIGroupInfo_s::member, memcpy(), NULL, AIGroupMember_s::number, entityState_s::number, AIGroupInfo_s::numGroup, and gentity_s::s. Referenced by AI_DeleteSelfFromGroup(), and AI_RefreshGroup().
00571 {
00572 int i;
00573
00574 if ( group->commander && group->commander->s.number == group->member[memberNum].number )
00575 {
00576 group->commander = NULL;
00577 }
00578 if ( g_entities[group->member[memberNum].number].NPC )
00579 {
00580 g_entities[group->member[memberNum].number].NPC->group = NULL;
00581 }
00582 for ( i = memberNum; i < (group->numGroup-1); i++ )
00583 {
00584 memcpy( &group->member[i], &group->member[i+1], sizeof( group->member[i] ) );
00585 }
00586 if ( memberNum < group->activeMemberNum )
00587 {
00588 group->activeMemberNum--;
00589 if ( group->activeMemberNum < 0 )
00590 {
00591 group->activeMemberNum = 0;
00592 }
00593 }
00594 group->numGroup--;
00595 if ( group->numGroup < 0 )
00596 {
00597 group->numGroup = 0;
00598 }
00599 AI_SetNewGroupCommander( group );
00600 }
|
|
|
Definition at line 602 of file NPC_AI_Utils.c. References AI_DeleteGroupMember(), gentity_t, gNPC_t::group, AIGroupInfo_s::member, gentity_s::NPC, entityState_s::number, AIGroupMember_s::number, AIGroupInfo_s::numGroup, and gentity_s::s. Referenced by player_die().
00603 {
00604 int i;
00605
00606 //FIXME: if killed, keep track of how many in group killed? To affect morale?
00607 for ( i = 0; i < self->NPC->group->numGroup; i++ )
00608 {
00609 if ( self->NPC->group->member[i].number == self->s.number )
00610 {
00611 AI_DeleteGroupMember( self->NPC->group, i );
00612 return;
00613 }
00614 }
00615 }
|
|
||||||||||||||||||||
|
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 212 of file NPC_AI_Utils.c. References gentity_t, gNPC_t::group, level_locals_t::groups, level, MAX_FRAME_GROUPS, AIGroupInfo_s::member, gentity_s::NPC, entityState_s::number, AIGroupMember_s::number, AIGroupInfo_s::numGroup, qboolean, qfalse, qtrue, and gentity_s::s. Referenced by AI_GetNextEmptyGroup().
00213 {//go through other groups made this frame and see if any of those contain me already
00214 int i, j;
00215 for ( i = 0; i < MAX_FRAME_GROUPS; i++ )
00216 {
00217 if ( level.groups[i].numGroup )//&& level.groups[i].enemy != NULL )
00218 {//check this one
00219 for ( j = 0; j < level.groups[i].numGroup; j++ )
00220 {
00221 if ( level.groups[i].member[j].number == self->s.number )
00222 {
00223 self->NPC->group = &level.groups[i];
00224 return qtrue;
00225 }
00226 }
00227 }
00228 }
00229 return qfalse;
00230 }
|
|
|
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, AIGroupInfo_s::enemy, gentity_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 279 of file NPC_AI_Utils.c. References AI_FindSelfInPreviousGroup(), AI_TryJoinPreviousGroup(), gentity_t, gNPC_t::group, level_locals_t::groups, level, MAX_FRAME_GROUPS, gentity_s::NPC, NULL, AIGroupInfo_s::numGroup, qboolean, qfalse, and qtrue. Referenced by AI_GetGroup().
00280 {
00281 int i;
00282
00283 if ( AI_FindSelfInPreviousGroup( self ) )
00284 {//already in one, no need to make a new one
00285 return qfalse;
00286 }
00287
00288 if ( AI_TryJoinPreviousGroup( self ) )
00289 {//try to just put us in one that already exists
00290 return qfalse;
00291 }
00292
00293 //okay, make a whole new one, then
00294 for ( i = 0; i < MAX_FRAME_GROUPS; i++ )
00295 {
00296 if ( !level.groups[i].numGroup )
00297 {//make a new one
00298 self->NPC->group = &level.groups[i];
00299 return qtrue;
00300 }
00301 }
00302
00303 //if ( i >= MAX_FRAME_GROUPS )
00304 {//WTF? Out of groups!
00305 self->NPC->group = NULL;
00306 return qfalse;
00307 }
00308 }
|
|
||||||||||||
|
Definition at line 982 of file NPC_AI_Utils.c. References AIGroupInfo_t, AIGroupInfo_s::member, AIGroupMember_s::number, AIGroupInfo_s::numGroup, qboolean, qfalse, and qtrue. Referenced by ST_ResolveBlockedShot().
|
|
|
Definition at line 620 of file NPC_AI_Utils.c. References AEL_DANGER_GREAT, AIGroupInfo_t, AIGroupInfo_s::commander, gNPC_t::currentAim, entityShared_t::currentOrigin, AIGroupInfo_s::enemy, g_entities, gentity_t, gNPC_t::group, AIGroupInfo_s::member, AIGroupInfo_s::moraleAdjust, gentity_s::NPC, AIGroupMember_s::number, AIGroupInfo_s::numGroup, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, gNPC_t::rank, RANK_ENSIGN, AIGroupInfo_s::speechDebounceTime, ST_AggressionAdjust(), ST_MarkToCover(), and ST_StartFlee(). Referenced by player_die().
00621 {
00622 AIGroupInfo_t *group = self->NPC->group;
00623 gentity_t *member;
00624 qboolean noflee = qfalse;
00625 int i;
00626
00627 if ( !group )
00628 {//what group?
00629 return;
00630 }
00631 if ( !self || !self->NPC || self->NPC->rank < RANK_ENSIGN )
00632 {//I'm not an officer, let's not really care for now
00633 return;
00634 }
00635 //temporarily drop group morale for a few seconds
00636 group->moraleAdjust -= self->NPC->rank;
00637 //go through and drop aggression on my teammates (more cover, worse aim)
00638 for ( i = 0; i < group->numGroup; i++ )
00639 {
00640 member = &g_entities[group->member[i].number];
00641 if ( member == self )
00642 {
00643 continue;
00644 }
00645 if ( member->NPC->rank > RANK_ENSIGN )
00646 {//officers do not panic
00647 noflee = qtrue;
00648 }
00649 else
00650 {
00651 ST_AggressionAdjust( member, -1 );
00652 member->NPC->currentAim -= Q_irand( 0, 10 );//Q_irand( 0, 2);//drop their aim accuracy
00653 }
00654 }
00655 //okay, if I'm the group commander, make everyone else flee
00656 if ( group->commander != self )
00657 {//I'm not the commander... hmm, should maybe a couple flee... maybe those near me?
00658 return;
00659 }
00660 //now see if there is another of sufficient rank to keep them from fleeing
00661 if ( !noflee )
00662 {
00663 self->NPC->group->speechDebounceTime = 0;
00664 for ( i = 0; i < group->numGroup; i++ )
00665 {
00666 member = &g_entities[group->member[i].number];
00667 if ( member == self )
00668 {
00669 continue;
00670 }
00671 if ( member->NPC->rank < RANK_ENSIGN )
00672 {//grunt
00673 if ( group->enemy && DistanceSquared( member->r.currentOrigin, group->enemy->r.currentOrigin ) < 65536/*256*256*/ )
00674 {//those close to enemy run away!
00675 ST_StartFlee( member, group->enemy, member->r.currentOrigin, AEL_DANGER_GREAT, 3000, 5000 );
00676 }
00677 else if ( DistanceSquared( member->r.currentOrigin, self->r.currentOrigin ) < 65536/*256*256*/ )
00678 {//those close to me run away!
00679 ST_StartFlee( member, group->enemy, member->r.currentOrigin, AEL_DANGER_GREAT, 3000, 5000 );
00680 }
00681 else
00682 {//else, maybe just a random chance
00683 if ( Q_irand( 0, self->NPC->rank ) > member->NPC->rank )
00684 {//lower rank they are, higher rank I am, more likely they are to flee
00685 ST_StartFlee( member, group->enemy, member->r.currentOrigin, AEL_DANGER_GREAT, 3000, 5000 );
00686 }
00687 else
00688 {
00689 ST_MarkToCover( member );
00690 }
00691 }
00692 member->NPC->currentAim -= Q_irand( 1, 15 ); //Q_irand( 1, 3 );//drop their aim accuracy even more
00693 }
00694 member->NPC->currentAim -= Q_irand( 1, 15 ); //Q_irand( 1, 3 );//drop their aim accuracy even more
00695 }
00696 }
00697 }
|
|
|
Definition at line 709 of file NPC_AI_Utils.c. References AIGroupInfo_t, AIGroupInfo_s::lastClearShotTime, level, and level_locals_t::time. Referenced by NPC_BSST_Attack().
00710 {
00711 if ( !group )
00712 {
00713 return;
00714 }
00715 group->lastClearShotTime = level.time;
00716 }
|
|
||||||||||||
|
Definition at line 699 of file NPC_AI_Utils.c. References AIGroupInfo_t, AIGroupInfo_s::enemyLastSeenPos, AIGroupInfo_s::lastSeenEnemyTime, level, level_locals_t::time, vec3_t, and VectorCopy. Referenced by NPC_BSST_Attack().
00700 {
00701 if ( !group )
00702 {
00703 return;
00704 }
00705 group->lastSeenEnemyTime = level.time;
00706 VectorCopy( spot, group->enemyLastSeenPos );
00707 }
|
|
||||||||||||||||
|
Definition at line 718 of file NPC_AI_Utils.c. References AIGroupInfo_t, gentity_t, AIGroupInfo_s::member, gentity_s::NPC, entityState_s::number, AIGroupMember_s::number, AIGroupInfo_s::numGroup, AIGroupInfo_s::numState, gentity_s::s, and gNPC_t::squadState. Referenced by ST_Commander(), and ST_TransferMoveGoal().
00719 {
00720 int i;
00721
00722 if ( !group )
00723 {
00724 member->NPC->squadState = newSquadState;
00725 return;
00726 }
00727
00728 for ( i = 0; i < group->numGroup; i++ )
00729 {
00730 if ( group->member[i].number == member->s.number )
00731 {
00732 group->numState[member->NPC->squadState]--;
00733 member->NPC->squadState = newSquadState;
00734 group->numState[member->NPC->squadState]++;
00735 return;
00736 }
00737 }
00738 }
|
|
||||||||||||
|
Definition at line 232 of file NPC_AI_Utils.c. References AIGroupInfo_t, AIGroupInfo_s::commander, gentity_t, gNPC_t::group, AIGroupInfo_s::member, gentity_s::NPC, entityState_s::number, AIGroupMember_s::number, AIGroupInfo_s::numGroup, AIGroupInfo_s::numState, gNPC_t::rank, gentity_s::s, and gNPC_t::squadState. Referenced by AI_GetGroup(), AI_RefreshGroup(), and AI_TryJoinPreviousGroup().
00233 {
00234 int i;
00235
00236 //okay, you know what? Check this damn group and make sure we're not already in here!
00237 for ( i = 0; i < group->numGroup; i++ )
00238 {
00239 if ( group->member[i].number == member->s.number )
00240 {//already in here
00241 break;
00242 }
00243 }
00244 if ( i < group->numGroup )
00245 {//found him in group already
00246 }
00247 else
00248 {//add him in
00249 group->member[group->numGroup++].number = member->s.number;
00250 group->numState[member->NPC->squadState]++;
00251 }
00252 if ( !group->commander || (member->NPC->rank > group->commander->NPC->rank) )
00253 {//keep track of highest rank
00254 group->commander = member;
00255 }
00256 member->NPC->group = group;
00257 }
|
|
|
Definition at line 740 of file NPC_AI_Utils.c. References AI_DeleteGroupMember(), AI_InsertGroupMember(), AI_ValidateGroupMember(), AI_ValidateNoEnemyGroupMember(), AIGroupInfo_t, AIGroupInfo_s::commander, entityShared_t::currentOrigin, debugNPCAI, AIGroupInfo_s::enemy, FRAMETIME, g_entities, G_TestLine(), gentity_t, level_locals_t::groups, gentity_s::health, vmCvar_t::integer, level, MAX_FRAME_GROUPS, MAX_GROUP_MEMBERS, AIGroupInfo_s::member, AIGroupInfo_s::memberValidateTime, AIGroupInfo_s::morale, AIGroupInfo_s::moraleAdjust, AIGroupInfo_s::moraleDebounce, gentity_s::NPC, NULL, NUM_SQUAD_STATES, AIGroupMember_s::number, AIGroupInfo_s::numGroup, AIGroupInfo_s::numState, AIGroupInfo_s::processed, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, gNPC_t::rank, RANK_ENSIGN, gentity_s::s, gNPC_t::squadState, level_locals_t::time, entityState_s::weapon, WP_BRYAR_PISTOL, WP_DET_PACK, WP_DISRUPTOR, WP_EMPLACED_GUN, WP_FLECHETTE, WP_REPEATER, WP_ROCKET_LAUNCHER, WP_SABER, WP_STUN_BATON, WP_THERMAL, and WP_TRIP_MINE. Referenced by AI_UpdateGroups().
00741 {
00742 gentity_t *member;
00743 int i;//, j;
00744
00745 //see if we should merge with another group
00746 for ( i = 0; i < MAX_FRAME_GROUPS; i++ )
00747 {
00748 if ( &level.groups[i] == group )
00749 {
00750 break;
00751 }
00752 else
00753 {
00754 if ( level.groups[i].enemy == group->enemy )
00755 {//2 groups with same enemy
00756 if ( level.groups[i].numGroup+group->numGroup < (MAX_GROUP_MEMBERS - 1) )
00757 {//combining the members would fit in one group
00758 qboolean deleteWhenDone = qtrue;
00759 int j;
00760
00761 //combine the members of mine into theirs
00762 for ( j = 0; j < group->numGroup; j++ )
00763 {
00764 member = &g_entities[group->member[j].number];
00765 if ( level.groups[i].enemy == NULL )
00766 {//special case for groups without enemies, must be in range
00767 if ( !AI_ValidateNoEnemyGroupMember( &level.groups[i], member ) )
00768 {
00769 deleteWhenDone = qfalse;
00770 continue;
00771 }
00772 }
00773 //remove this member from this group
00774 AI_DeleteGroupMember( group, j );
00775 //keep marker at same place since we deleted this guy and shifted everyone up one
00776 j--;
00777 //add them to the earlier group
00778 AI_InsertGroupMember( &level.groups[i], member );
00779 }
00780 //return and delete this group
00781 if ( deleteWhenDone )
00782 {
00783 return qfalse;
00784 }
00785 }
00786 }
00787 }
00788 }
00789 //clear numStates
00790 for ( i = 0; i < NUM_SQUAD_STATES; i++ )
00791 {
00792 group->numState[i] = 0;
00793 }
00794
00795 //go through group and validate each membership
00796 group->commander = NULL;
00797 for ( i = 0; i < group->numGroup; i++ )
00798 {
00799 /*
00800 //this checks for duplicate copies of one member in a group
00801 for ( j = 0; j < group->numGroup; j++ )
00802 {
00803 if ( i != j )
00804 {
00805 if ( group->member[i].number == group->member[j].number )
00806 {
00807 break;
00808 }
00809 }
00810 }
00811 if ( j < group->numGroup )
00812 {//found a dupe!
00813 gi.Printf( S_COLOR_RED"ERROR: member %s(%d) a duplicate group member!!!\n", g_entities[group->member[i].number].targetname, group->member[i].number );
00814 AI_DeleteGroupMember( group, i );
00815 i--;
00816 continue;
00817 }
00818 */
00819 member = &g_entities[group->member[i].number];
00820
00821 //Must be alive
00822 if ( member->health <= 0 )
00823 {
00824 AI_DeleteGroupMember( group, i );
00825 //keep marker at same place since we deleted this guy and shifted everyone up one
00826 i--;
00827 }
00828 else if ( group->memberValidateTime < level.time && !AI_ValidateGroupMember( group, member ) )
00829 {
00830 //remove this one from the group
00831 AI_DeleteGroupMember( group, i );
00832 //keep marker at same place since we deleted this guy and shifted everyone up one
00833 i--;
00834 }
00835 else
00836 {//membership is valid
00837 //keep track of squadStates
00838 group->numState[member->NPC->squadState]++;
00839 if ( !group->commander || member->NPC->rank > group->commander->NPC->rank )
00840 {//keep track of highest rank
00841 group->commander = member;
00842 }
00843 }
00844 }
00845 if ( group->memberValidateTime < level.time )
00846 {
00847 group->memberValidateTime = level.time + Q_irand( 500, 2500 );
00848 }
00849 //Now add any new guys as long as we're not full
00850 /*
00851 for ( i = 0, member = &g_entities[0]; i < globals.num_entities && group->numGroup < (MAX_GROUP_MEMBERS - 1); i++, member++)
00852 {
00853 if ( !AI_ValidateGroupMember( group, member ) )
00854 {//FIXME: keep track of those who aren't angry yet and see if we should wake them after we assemble the core group
00855 continue;
00856 }
00857 if ( member->NPC->group == group )
00858 {//DOH, already in our group
00859 continue;
00860 }
00861
00862 //store it
00863 AI_InsertGroupMember( group, member );
00864 }
00865 */
00866
00867 //calc the morale of this group
00868 group->morale = group->moraleAdjust;
00869 for ( i = 0; i < group->numGroup; i++ )
00870 {
00871 member = &g_entities[group->member[i].number];
00872 if ( member->NPC->rank < RANK_ENSIGN )
00873 {//grunts
00874 group->morale++;
00875 }
00876 else
00877 {
00878 group->morale += member->NPC->rank;
00879 }
00880 if ( group->commander && debugNPCAI.integer )
00881 {
00882 //G_DebugLine( group->commander->r.currentOrigin, member->r.currentOrigin, FRAMETIME, 0x00ff00ff, qtrue );
00883 G_TestLine(group->commander->r.currentOrigin, member->r.currentOrigin, 0x00000ff, FRAMETIME);
00884 }
00885 }
00886 if ( group->enemy )
00887 {//modify morale based on enemy health and weapon
00888 if ( group->enemy->health < 10 )
00889 {
00890 group->morale += 10;
00891 }
00892 else if ( group->enemy->health < 25 )
00893 {
00894 group->morale += 5;
00895 }
00896 else if ( group->enemy->health < 50 )
00897 {
00898 group->morale += 2;
00899 }
00900 switch( group->enemy->s.weapon )
00901 {
00902 case WP_SABER:
00903 group->morale -= 5;
00904 break;
00905 case WP_BRYAR_PISTOL:
00906 group->morale += 3;
00907 break;
00908 case WP_DISRUPTOR:
00909 group->morale += 2;
00910 break;
00911 case WP_REPEATER:
00912 group->morale -= 1;
00913 break;
00914 case WP_FLECHETTE:
00915 group->morale -= 2;
00916 break;
00917 case WP_ROCKET_LAUNCHER:
00918 group->morale -= 10;
00919 break;
00920 case WP_THERMAL:
00921 group->morale -= 5;
00922 break;
00923 case WP_TRIP_MINE:
00924 group->morale -= 3;
00925 break;
00926 case WP_DET_PACK:
00927 group->morale -= 10;
00928 break;
00929 // case WP_MELEE: // Any ol' melee attack
00930 // group->morale += 20;
00931 // break;
00932 case WP_STUN_BATON:
00933 group->morale += 10;
00934 break;
00935 case WP_EMPLACED_GUN:
00936 group->morale -= 8;
00937 break;
00938 // case WP_ATST_MAIN:
00939 // group->morale -= 8;
00940 // break;
00941 // case WP_ATST_SIDE:
00942 // group->morale -= 20;
00943 // break;
00944 }
00945 }
00946 if ( group->moraleDebounce < level.time )
00947 {//slowly degrade whatever moraleAdjusters we may have
00948 if ( group->moraleAdjust > 0 )
00949 {
00950 group->moraleAdjust--;
00951 }
00952 else if ( group->moraleAdjust < 0 )
00953 {
00954 group->moraleAdjust++;
00955 }
00956 group->moraleDebounce = level.time + 1000;//FIXME: define?
00957 }
00958 //mark this group as not having been run this frame
00959 group->processed = qfalse;
00960
00961 return (group->numGroup>0);
00962 }
|
|
|
Definition at line 112 of file NPC_AI_Utils.c. References AIGroupInfo_t, AIGroupMember_s::closestBuddy, ENTITYNUM_NONE, g_entities, AIGroupInfo_s::member, AIGroupMember_s::number, AIGroupInfo_s::numGroup, and Q3_INFINITE. Referenced by AI_GetGroup().
00113 {
00114 int i, j;
00115 int dist, bestDist;
00116
00117 for ( i = 0; i < group->numGroup; i++ )
00118 {
00119 group->member[i].closestBuddy = ENTITYNUM_NONE;
00120
00121 bestDist = Q3_INFINITE;
00122 for ( j = 0; j < group->numGroup; j++ )
00123 {
00124 dist = DistanceSquared( g_entities[group->member[i].number].r.currentOrigin, g_entities[group->member[j].number].r.currentOrigin );
00125 if ( dist < bestDist )
00126 {
00127 bestDist = dist;
00128 group->member[i].closestBuddy = group->member[j].number;
00129 }
00130 }
00131 }
00132 }
|
|
|
Definition at line 553 of file NPC_AI_Utils.c. References AIGroupInfo_t, AIGroupInfo_s::commander, g_entities, gentity_t, AIGroupInfo_s::member, gentity_s::NPC, NULL, AIGroupMember_s::number, AIGroupInfo_s::numGroup, and gNPC_t::rank. Referenced by AI_DeleteGroupMember().
00554 {
00555 gentity_t *member = NULL;
00556 int i;
00557
00558 group->commander = NULL;
00559 for ( i = 0; i < group->numGroup; i++ )
00560 {
00561 member = &g_entities[group->member[i].number];
00562
00563 if ( !group->commander || (member && member->NPC && group->commander->NPC && member->NPC->rank > group->commander->NPC->rank) )
00564 {//keep track of highest rank
00565 group->commander = member;
00566 }
00567 }
00568 }
|
|
|
Definition at line 134 of file NPC_AI_Utils.c. References AIGroupInfo_t, AIGroupMember_t, AIGroupInfo_s::enemy, AIGroupInfo_s::enemyWP, ENTITYNUM_NONE, MAX_GROUP_MEMBERS, AIGroupInfo_s::member, memcpy(), NAV_FindClosestWaypointForEnt(), NULL, AIGroupMember_s::number, AIGroupInfo_s::numGroup, AIGroupMember_s::pathCostToEnemy, Q3_INFINITE, qboolean, qfalse, qtrue, trap_Nav_GetPathCost(), AIGroupMember_s::waypoint, and WAYPOINT_NONE. Referenced by AI_GetGroup().
00135 {
00136 AIGroupMember_t bestMembers[MAX_GROUP_MEMBERS];
00137 int i, j, k;
00138 qboolean sort = qfalse;
00139
00140 if ( group->enemy != NULL )
00141 {//FIXME: just use enemy->waypoint?
00142 group->enemyWP = NAV_FindClosestWaypointForEnt( group->enemy, WAYPOINT_NONE );
00143 }
00144 else
00145 {
00146 group->enemyWP = WAYPOINT_NONE;
00147 }
00148
00149 for ( i = 0; i < group->numGroup; i++ )
00150 {
00151 if ( group->enemyWP == WAYPOINT_NONE )
00152 {//FIXME: just use member->waypoint?
00153 group->member[i].waypoint = WAYPOINT_NONE;
00154 group->member[i].pathCostToEnemy = Q3_INFINITE;
00155 }
00156 else
00157 {//FIXME: just use member->waypoint?
00158 group->member[i].waypoint = NAV_FindClosestWaypointForEnt( group->enemy, WAYPOINT_NONE );
00159 if ( group->member[i].waypoint != WAYPOINT_NONE )
00160 {
00161 group->member[i].pathCostToEnemy = trap_Nav_GetPathCost( group->member[i].waypoint, group->enemyWP );
00162 //at least one of us has a path, so do sorting
00163 sort = qtrue;
00164 }
00165 else
00166 {
00167 group->member[i].pathCostToEnemy = Q3_INFINITE;
00168 }
00169 }
00170 }
00171 //Now sort
00172 if ( sort )
00173 {
00174 //initialize bestMembers data
00175 for ( j = 0; j < group->numGroup; j++ )
00176 {
00177 bestMembers[j].number = ENTITYNUM_NONE;
00178 }
00179
00180 for ( i = 0; i < group->numGroup; i++ )
00181 {
00182 for ( j = 0; j < group->numGroup; j++ )
00183 {
00184 if ( bestMembers[j].number != ENTITYNUM_NONE )
00185 {//slot occupied
00186 if ( group->member[i].pathCostToEnemy < bestMembers[j].pathCostToEnemy )
00187 {//this guy has a shorter path than the one currenly in this spot, bump him and put myself in here
00188 for ( k = group->numGroup; k > j; k++ )
00189 {
00190 memcpy( &bestMembers[k], &bestMembers[k-1], sizeof( bestMembers[k] ) );
00191 }
00192 memcpy( &bestMembers[j], &group->member[i], sizeof( bestMembers[j] ) );
00193 break;
00194 }
00195 }
00196 else
00197 {//slot unoccupied, reached end of list, throw self in here
00198 memcpy( &bestMembers[j], &group->member[i], sizeof( bestMembers[j] ) );
00199 break;
00200 }
00201 }
00202 }
00203
00204 //Okay, now bestMembers is a sorted list, just copy it into group->members
00205 for ( i = 0; i < group->numGroup; i++ )
00206 {
00207 memcpy( &group->member[i], &bestMembers[i], sizeof( group->member[i] ) );
00208 }
00209 }
00210 }
|
|
|
Definition at line 259 of file NPC_AI_Utils.c. References AI_InsertGroupMember(), AI_ValidateGroupMember(), gentity_s::enemy, AIGroupInfo_s::enemy, gentity_t, level_locals_t::groups, level, MAX_FRAME_GROUPS, MAX_GROUP_MEMBERS, AIGroupInfo_s::numGroup, qboolean, qfalse, and qtrue. Referenced by AI_GetNextEmptyGroup().
00260 {//go through other groups made this frame and see if any of those have the same enemy as me... if so, add me in!
00261 int i;
00262 for ( i = 0; i < MAX_FRAME_GROUPS; i++ )
00263 {
00264 if ( level.groups[i].numGroup
00265 && level.groups[i].numGroup < (MAX_GROUP_MEMBERS - 1)
00266 //&& level.groups[i].enemy != NULL
00267 && level.groups[i].enemy == self->enemy )
00268 {//has members, not full and has my enemy
00269 if ( AI_ValidateGroupMember( &level.groups[i], self ) )
00270 {//I am a valid member for this group
00271 AI_InsertGroupMember( &level.groups[i], self );
00272 return qtrue;
00273 }
00274 }
00275 }
00276 return qfalse;
00277 }
|
|
|
Definition at line 964 of file NPC_AI_Utils.c. References AI_RefreshGroup(), d_noGroupAI, level_locals_t::groups, vmCvar_t::integer, level, MAX_FRAME_GROUPS, memset(), AIGroupInfo_s::numGroup, and qfalse. Referenced by G_RunFrame().
00965 {
00966 int i;
00967
00968 if ( d_noGroupAI.integer )
00969 {
00970 return;
00971 }
00972 //Clear all Groups
00973 for ( i = 0; i < MAX_FRAME_GROUPS; i++ )
00974 {
00975 if ( !level.groups[i].numGroup || AI_RefreshGroup( &level.groups[i] ) == qfalse )//level.groups[i].enemy == NULL ||
00976 {
00977 memset( &level.groups[i], 0, sizeof( level.groups[i] ) );
00978 }
00979 }
00980 }
|
|
||||||||||||
|
= self->s.weapon ) Definition at line 342 of file NPC_AI_Utils.c. References AI_ValidateNoEnemyGroupMember(), AIGroupInfo_t, CLASS_ATST, CLASS_HOWLER, CLASS_INTERROGATOR, CLASS_MARK1, CLASS_MARK2, CLASS_MINEMONSTER, CLASS_PROBE, CLASS_REMOTE, CLASS_SEEKER, CLASS_SENTRY, gentity_s::client, gNPC_t::confusionTime, entityShared_t::currentOrigin, AIGroupInfo_s::enemy, gentity_s::enemy, gentity_t, gNPC_t::group, gentity_s::health, level, gentity_s::NPC, gclient_s::NPC_class, NULL, gclient_s::playerTeam, gclient_s::ps, qboolean, qfalse, qtrue, gentity_s::r, SCF_NO_GROUPS, gNPC_t::scriptFlags, AIGroupInfo_s::team, level_locals_t::time, TIMER_Done(), trap_InPVS(), playerState_s::weapon, WP_DISRUPTOR, WP_EMPLACED_GUN, WP_SABER, WP_STUN_BATON, WP_THERMAL, and WP_TURRET. Referenced by AI_GetGroup(), AI_RefreshGroup(), and AI_TryJoinPreviousGroup().
00343 {
00344 //Validate ents
00345 if ( member == NULL )
00346 return qfalse;
00347
00348 //Validate clients
00349 if ( member->client == NULL )
00350 return qfalse;
00351
00352 //Validate NPCs
00353 if ( member->NPC == NULL )
00354 return qfalse;
00355
00356 //must be aware
00357 if ( member->NPC->confusionTime > level.time )
00358 return qfalse;
00359
00360 //must be allowed to join groups
00361 if ( member->NPC->scriptFlags&SCF_NO_GROUPS )
00362 return qfalse;
00363
00364 //Must not be in another group
00365 if ( member->NPC->group != NULL && member->NPC->group != group )
00366 {//FIXME: if that group's enemy is mine, why not absorb that group into mine?
00367 return qfalse;
00368 }
00369
00370 //Must be alive
00371 if ( member->health <= 0 )
00372 return qfalse;
00373
00374 //can't be in an emplaced gun
00375 // if( member->s.eFlags & EF_LOCKED_TO_WEAPON )
00376 // return qfalse;
00377 //rwwFIXMEFIXME: support this flag
00378
00379 //Must be on the same team
00380 if ( member->client->playerTeam != group->team )
00381 return qfalse;
00382
00383 if ( member->client->ps.weapon == WP_SABER ||
00384 member->client->ps.weapon == WP_THERMAL ||
00385 member->client->ps.weapon == WP_DISRUPTOR ||
00386 member->client->ps.weapon == WP_EMPLACED_GUN ||
00387 // member->client->ps.weapon == WP_BOT_LASER || // Probe droid - Laser blast
00388 member->client->ps.weapon == WP_STUN_BATON ||
00389 member->client->ps.weapon == WP_TURRET /*|| // turret guns
00390 member->client->ps.weapon == WP_ATST_MAIN ||
00391 member->client->ps.weapon == WP_ATST_SIDE ||
00392 member->client->ps.weapon == WP_TIE_FIGHTER*/ )
00393 {//not really a squad-type guy
00394 return qfalse;
00395 }
00396
00397 if ( member->client->NPC_class == CLASS_ATST ||
00398 member->client->NPC_class == CLASS_PROBE ||
00399 member->client->NPC_class == CLASS_SEEKER ||
00400 member->client->NPC_class == CLASS_REMOTE ||
00401 member->client->NPC_class == CLASS_SENTRY ||
00402 member->client->NPC_class == CLASS_INTERROGATOR ||
00403 member->client->NPC_class == CLASS_MINEMONSTER ||
00404 member->client->NPC_class == CLASS_HOWLER ||
00405 member->client->NPC_class == CLASS_MARK1 ||
00406 member->client->NPC_class == CLASS_MARK2 )
00407 {//these kinds of enemies don't actually use this group AI
00408 return qfalse;
00409 }
00410
00411 //should have same enemy
00412 if ( member->enemy != group->enemy )
00413 {
00414 if ( member->enemy != NULL )
00415 {//he's fighting someone else, leave him out
00416 return qfalse;
00417 }
00418 if ( !trap_InPVS( member->r.currentOrigin, group->enemy->r.currentOrigin ) )
00419 {//not within PVS of the group enemy
00420 return qfalse;
00421 }
00422 }
00423 else if ( group->enemy == NULL )
00424 {//if the group is a patrol group, only take those within the room and radius
00425 if ( !AI_ValidateNoEnemyGroupMember( group, member ) )
00426 {
00427 return qfalse;
00428 }
00429 }
00430 //must be actually in combat mode
00431 if ( !TIMER_Done( member, "interrogating" ) )
00432 return qfalse;
00433 //FIXME: need to have a route to enemy and/or clear shot?
00434 return qtrue;
00435 }
|
|
||||||||||||
|
Definition at line 310 of file NPC_AI_Utils.c. References AIGroupInfo_t, AIGroupInfo_s::commander, entityShared_t::currentOrigin, ENTITYNUM_WORLD, g_entities, gentity_t, AIGroupInfo_s::member, AIGroupMember_s::number, qboolean, qfalse, qtrue, gentity_s::r, trap_InPVS(), vec3_t, and VectorCopy. Referenced by AI_RefreshGroup(), and AI_ValidateGroupMember().
00311 {
00312 vec3_t center;
00313
00314 if ( !group )
00315 {
00316 return qfalse;
00317 }
00318 if ( group->commander )
00319 {
00320 VectorCopy( group->commander->r.currentOrigin, center );
00321 }
00322 else
00323 {//hmm, just pick the first member
00324 if ( group->member[0].number < 0 || group->member[0].number >= ENTITYNUM_WORLD )
00325 {
00326 return qfalse;
00327 }
00328 VectorCopy( g_entities[group->member[0].number].r.currentOrigin, center );
00329 }
00330 //FIXME: maybe it should be based on the center of the mass of the group, not the commander?
00331 if ( DistanceSquared( center, member->r.currentOrigin ) > 147456/*384*384*/ )
00332 {
00333 return qfalse;
00334 }
00335 if ( !trap_InPVS( member->r.currentOrigin, center ) )
00336 {//not within PVS of the group enemy
00337 return qfalse;
00338 }
00339 return qtrue;
00340 }
|
|
||||||||||||||||||||
|
Definition at line 212 of file ai_wpnav.c.
00213 {
00214 gentity_t *te;
00215
00216 te = G_TempEntity( start, EV_TESTLINE );
00217 VectorCopy(start, te->s.origin);
00218 VectorCopy(end, te->s.origin2);
00219 te->s.time2 = time;
00220 te->s.weapon = color;
00221 te->r.svFlags |= SVF_BROADCAST;
00222 }
|
|
||||||||||||
|
Definition at line 358 of file g_nav.c. References gentity_s::clipmask, G_FreeEntity(), G_SetOrigin(), G_Spawn(), gentity_t, entityShared_t::maxs, entityShared_t::mins, NF_CLEAR_PATH, gentity_s::r, trap_Nav_GetNearestNode(), vec3_t, VectorCopy, gentity_s::waypoint, and WAYPOINT_NONE. Referenced by AI_ClosestGroupEntityNumToPoint().
00359 {
00360 int bestWP;
00361 //FIXME: can we make this a static ent?
00362 gentity_t *marker = G_Spawn();
00363
00364 if ( !marker )
00365 {
00366 return WAYPOINT_NONE;
00367 }
00368
00369 G_SetOrigin( marker, point );
00370
00371 VectorCopy( ent->r.mins, marker->r.mins );//stepsize?
00372 VectorCopy( ent->r.mins, marker->r.maxs );//crouching?
00373
00374 marker->clipmask = ent->clipmask;
00375 marker->waypoint = WAYPOINT_NONE;
00376
00377 bestWP = trap_Nav_GetNearestNode( marker, marker->waypoint, NF_CLEAR_PATH, WAYPOINT_NONE );
00378
00379 G_FreeEntity( marker );
00380
00381 return bestWP;
00382 }
|
|
||||||||||||
|
Definition at line 60 of file NPC_AI_Stormtrooper.c. References gNPCstats_e::aggression, gentity_s::client, gentity_t, gentity_s::NPC, NPCTEAM_PLAYER, gclient_s::playerTeam, and gNPC_t::stats. Referenced by AI_GroupMemberKilled(), and ST_MarkToCover().
00061 {
00062 int upper_threshold, lower_threshold;
00063
00064 self->NPC->stats.aggression += change;
00065
00066 //FIXME: base this on initial NPC stats
00067 if ( self->client->playerTeam == NPCTEAM_PLAYER )
00068 {//good guys are less aggressive
00069 upper_threshold = 7;
00070 lower_threshold = 1;
00071 }
00072 else
00073 {//bad guys are more aggressive
00074 upper_threshold = 10;
00075 lower_threshold = 3;
00076 }
00077
00078 if ( self->NPC->stats.aggression > upper_threshold )
00079 {
00080 self->NPC->stats.aggression = upper_threshold;
00081 }
00082 else if ( self->NPC->stats.aggression < lower_threshold )
00083 {
00084 self->NPC->stats.aggression = lower_threshold;
00085 }
00086 }
|
|
|
Definition at line 227 of file NPC_AI_Stormtrooper.c. References gentity_t, gNPC_t::group, gNPC_t::localState, LSTATE_UNDERFIRE, gentity_s::NPC, AIGroupInfo_s::numGroup, Q_irand(), SPEECH_COVER, ST_AggressionAdjust(), and TIMER_Set(). Referenced by AI_GroupMemberKilled().
00228 {
00229 if ( !self || !self->NPC )
00230 {
00231 return;
00232 }
00233 self->NPC->localState = LSTATE_UNDERFIRE;
00234 TIMER_Set( self, "attackDelay", Q_irand( 500, 2500 ) );
00235 ST_AggressionAdjust( self, -3 );
00236 if ( self->NPC->group && self->NPC->group->numGroup > 1 )
00237 {
00238 ST_Speech( self, SPEECH_COVER, 0 );//FIXME: flee sound?
00239 }
00240 }
|
|
||||||||||||||||||||||||||||
|
Definition at line 242 of file NPC_AI_Stormtrooper.c. References G_StartFlee(), gentity_t, gNPC_t::group, gentity_s::NPC, AIGroupInfo_s::numGroup, SPEECH_COVER, and vec3_t. Referenced by AI_GroupMemberKilled().
|
|
|
Definition at line 12 of file NPC_AI_Utils.c. Referenced by AI_GetGroup(), and AI_UpdateGroups(). |