#include "b_local.h"#include "g_nav.h"#include "../icarus/Q3_Interface.h"Go to the source code of this file.
Functions | |
| qboolean | NPC_SomeoneLookingAtMe (gentity_t *ent) |
| void | NPC_LostEnemyDecideChase (void) |
| void | NPC_StandIdle (void) |
| qboolean | NPC_StandTrackAndShoot (gentity_t *NPC, qboolean canDuck) |
| void | NPC_BSIdle (void) |
| void | NPC_BSRun (void) |
| void | NPC_BSStandGuard (void) |
| void | NPC_BSHuntAndKill (void) |
| void | NPC_BSStandAndShoot (void) |
| void | NPC_BSRunAndShoot (void) |
| void | NPC_BSFace (void) |
| void | NPC_BSPointShoot (qboolean shoot) |
| void | NPC_BSMove (void) |
| void | NPC_BSShoot (void) |
| void | NPC_BSPatrol (void) |
| void | NPC_CheckGetNewWeapon (void) |
| void | NPC_BSST_Attack (void) |
| void | NPC_BSDefault (void) |
|
|
Definition at line 712 of file NPC_AI_Default.c. References AEL_DISCOVERED, level_locals_t::alertEvents, BUTTON_WALKING, usercmd_s::buttons, gentity_s::client, gNPC_t::combatMove, entityShared_t::currentOrigin, gNPC_t::desiredPitch, gNPC_t::desiredYaw, gentity_s::enemy, gclient_s::enemyTeam, G_SetEnemy(), gNPC_t::goalEntity, gentity_s::health, alertEvent_s::ID, gNPC_t::lastAlertID, gclient_s::leader, alertEvent_s::level, 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 490 of file NPC_AI_Default.c. References gNPC_t::aimTime, client, gNPC_t::desiredPitch, gNPC_t::desiredYaw, NPC, NPC_UpdateAngles(), NPCInfo, PITCH, gclient_s::ps, qtrue, TID_BSTATE, trap_ICARUS_TaskIDComplete(), playerState_s::viewangles, and YAW.
00491 {
00492 //FIXME: once you stop sending turning info, they reset to whatever their delta_angles was last????
00493 //Once this is over, it snaps back to what it was facing before- WHY???
00494 if( NPC_UpdateAngles ( qtrue, qtrue ) )
00495 {
00496 trap_ICARUS_TaskIDComplete( NPC, TID_BSTATE );
00497
00498 NPCInfo->desiredYaw = client->ps.viewangles[YAW];
00499 NPCInfo->desiredPitch = client->ps.viewangles[PITCH];
00500
00501 NPCInfo->aimTime = 0;//ok to turn normally now
00502 }
00503 }
|
|
|
(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 616 of file NPC_AI_Default.c. References gentity_s::enemy, gentity_t, NPC, NPC_CheckCanAttack(), NPC_CheckEnemy(), NPC_SlideMoveToGoal(), NPC_UpdateAngles(), NULL, qfalse, qtrue, and UpdateGoal().
00617 {
00618 gentity_t *goal = NULL;
00619
00620 NPC_CheckEnemy(qtrue, qfalse, qtrue);
00621 if(NPC->enemy)
00622 {
00623 NPC_CheckCanAttack(1.0, qfalse);
00624 }
00625 else
00626 {
00627 NPC_UpdateAngles(qtrue, qtrue);
00628 }
00629
00630 goal = UpdateGoal();
00631 if(goal)
00632 {
00633 // NPCInfo->moveToGoalMod = 1.0;
00634
00635 NPC_SlideMoveToGoal();
00636 }
00637 }
|
|
|
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(), client, gentity_s::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, gentity_s::NPC, 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 179 of file NPC_AI_Default.c. References NPC_MoveToGoal(), NPC_UpdateAngles(), qtrue, and UpdateGoal().
00180 {
00181 //FIXME if there is no nav data, we need to do something else
00182 // if we're stuck, try to move around it
00183 if ( UpdateGoal() )
00184 {
00185 NPC_MoveToGoal( qtrue );
00186 }
00187
00188 NPC_UpdateAngles( qtrue, qtrue );
00189 }
|
|
|
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 644 of file NPC_AI_Default.c. References client, enemyVisibility, gclient_s::ps, qtrue, VIS_SHOOT, WEAPON_FIRING, WEAPON_READY, playerState_s::weaponstate, and WeaponThink().
00645 {
00646 // NPC_BSMove();
00647
00648 enemyVisibility = VIS_SHOOT;
00649
00650 if ( client->ps.weaponstate != WEAPON_READY && client->ps.weaponstate != WEAPON_FIRING )
00651 {
00652 client->ps.weaponstate = WEAPON_READY;
00653 }
00654
00655 WeaponThink(qtrue);
00656 }
|
|
|
NPC->enemy )// Definition at line 2409 of file NPC_AI_Stormtrooper.c. References AEL_DANGER, AI_GetGroup(), AI_GroupUpdateClearShotTime(), AI_GroupUpdateEnemyLastSeen(), AngleVectors(), BUTTON_ALT_ATTACK, BUTTON_ATTACK, usercmd_s::buttons, gentity_s::client, entityShared_t::currentOrigin, gNPC_t::desiredPitch, gNPC_t::desiredYaw, DotProduct, gentity_s::enemy, gNPC_t::enemyLastSeenLocation, gNPC_t::enemyLastSeenTime, gclient_s::enemyTeam, g_entities, g_spskill, gentity_t, GetTime(), gNPC_t::goalEntity, gNPC_t::group, gentity_s::health, vmCvar_t::integer, gNPC_t::lastPathAngles, level, MIN_ROCKET_DIST_SQUARED, NPC, NPC_AimAdjust(), NPC_BSPatrol(), NPC_BSST_Patrol(), NPC_ChangeWeapon(), NPC_CheckAlertEvents(), NPC_CheckEnemyExt(), NPC_CheckForDanger(), NPC_ClearLOS4(), NPC_FaceEnemy(), NPC_ShotEntity(), NPC_UpdateAngles(), NPCInfo, NPCTEAM_PLAYER, NULL, entityState_s::number, gentity_s::painDebounceTime, gclient_s::playerTeam, AIGroupInfo_s::processed, gclient_s::ps, Q_irand(), qfalse, qtrue, gentity_s::r, gentity_s::s, S_COLOR_GREEN, S_COLOR_RED, S_COLOR_YELLOW, SCF_ALT_FIRE, SCF_CHASE_ENEMIES, SCF_DONT_FIRE, SCF_FIRE_WEAPON, gNPC_t::scriptFlags, SPEECH_COVER, ST_Commander(), ST_ResolveBlockedShot(), startTime, SVF_GLASS_BRUSH, entityShared_t::svFlags, gentity_s::takedamage, level_locals_t::time, TIMER_Done(), TIMER_Set(), trap_InPVS(), ucmd, usercmd_s::upmove, vec3_t, VectorClear, VectorCopy, VectorNormalize(), VectorSubtract, playerState_s::viewangles, playerState_s::weapon, entityState_s::weapon, WeaponThink(), playerState_s::weaponTime, WP_DISRUPTOR, WP_EMPLACED_GUN, WP_FLECHETTE, WP_NONE, WP_REPEATER, WP_ROCKET_LAUNCHER, WP_SABER, and YAW. Referenced by NPC_BSDefault(), and NPC_BSST_Default().
02410 {
02411 vec3_t enemyDir, shootDir;
02412 float dot;
02413
02414 //Don't do anything if we're hurt
02415 if ( NPC->painDebounceTime > level.time )
02416 {
02417 NPC_UpdateAngles( qtrue, qtrue );
02418 return;
02419 }
02420
02421 //NPC_CheckEnemy( qtrue, qfalse );
02422 //If we don't have an enemy, just idle
02423 if ( NPC_CheckEnemyExt(qfalse) == qfalse )
02424 {
02425 NPC->enemy = NULL;
02426 if( NPC->client->playerTeam == NPCTEAM_PLAYER )
02427 {
02428 NPC_BSPatrol();
02429 }
02430 else
02431 {
02432 NPC_BSST_Patrol();//FIXME: or patrol?
02433 }
02434 return;
02435 }
02436
02437 //FIXME: put some sort of delay into the guys depending on how they saw you...?
02438
02439 //Get our group info
02440 if ( TIMER_Done( NPC, "interrogating" ) )
02441 {
02442 AI_GetGroup( NPC );//, 45, 512, NPC->enemy );
02443 }
02444 else
02445 {
02446 //FIXME: when done interrogating, I should send out a team alert!
02447 }
02448
02449 if ( NPCInfo->group )
02450 {//I belong to a squad of guys - we should *always* have a group
02451 if ( !NPCInfo->group->processed )
02452 {//I'm the first ent in my group, I'll make the command decisions
02453 #if AI_TIMERS
02454 int startTime = GetTime(0);
02455 #endif// AI_TIMERS
02456 ST_Commander();
02457 #if AI_TIMERS
02458 int commTime = GetTime ( startTime );
02459 if ( commTime > 20 )
02460 {
02461 gi.Printf( S_COLOR_RED"ERROR: Commander time: %d\n", commTime );
02462 }
02463 else if ( commTime > 10 )
02464 {
02465 gi.Printf( S_COLOR_YELLOW"WARNING: Commander time: %d\n", commTime );
02466 }
02467 else if ( commTime > 2 )
02468 {
02469 gi.Printf( S_COLOR_GREEN"Commander time: %d\n", commTime );
02470 }
02471 #endif// AI_TIMERS
02472 }
02473 }
02474 else if ( TIMER_Done( NPC, "flee" ) && NPC_CheckForDanger( NPC_CheckAlertEvents( qtrue, qtrue, -1, qfalse, AEL_DANGER ) ) )
02475 {//not already fleeing, and going to run
02476 ST_Speech( NPC, SPEECH_COVER, 0 );
02477 NPC_UpdateAngles( qtrue, qtrue );
02478 return;
02479 }
02480
02481 if ( !NPC->enemy )
02482 {//WTF? somehow we lost our enemy?
02483 NPC_BSST_Patrol();//FIXME: or patrol?
02484 return;
02485 }
02486
02487 enemyLOS = enemyCS = enemyInFOV = qfalse;
02488 move = qtrue;
02489 faceEnemy = qfalse;
02490 shoot = qfalse;
02491 hitAlly = qfalse;
02492 VectorClear( impactPos );
02493 enemyDist = DistanceSquared( NPC->r.currentOrigin, NPC->enemy->r.currentOrigin );
02494
02495 VectorSubtract( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, enemyDir );
02496 VectorNormalize( enemyDir );
02497 AngleVectors( NPC->client->ps.viewangles, shootDir, NULL, NULL );
02498 dot = DotProduct( enemyDir, shootDir );
02499 if ( dot > 0.5f ||( enemyDist * (1.0f-dot)) < 10000 )
02500 {//enemy is in front of me or they're very close and not behind me
02501 enemyInFOV = qtrue;
02502 }
02503
02504 if ( enemyDist < MIN_ROCKET_DIST_SQUARED )//128
02505 {//enemy within 128
02506 if ( (NPC->client->ps.weapon == WP_FLECHETTE || NPC->client->ps.weapon == WP_REPEATER) &&
02507 (NPCInfo->scriptFlags & SCF_ALT_FIRE) )
02508 {//shooting an explosive, but enemy too close, switch to primary fire
02509 NPCInfo->scriptFlags &= ~SCF_ALT_FIRE;
02510 //FIXME: we can never go back to alt-fire this way since, after this, we don't know if we were initially supposed to use alt-fire or not...
02511 }
02512 }
02513 else if ( enemyDist > 65536 )//256 squared
02514 {
02515 if ( NPC->client->ps.weapon == WP_DISRUPTOR )
02516 {//sniping... should be assumed
02517 if ( !(NPCInfo->scriptFlags&SCF_ALT_FIRE) )
02518 {//use primary fire
02519 NPCInfo->scriptFlags |= SCF_ALT_FIRE;
02520 //reset fire-timing variables
02521 NPC_ChangeWeapon( WP_DISRUPTOR );
02522 NPC_UpdateAngles( qtrue, qtrue );
02523 return;
02524 }
02525 }
02526 }
02527
02528 //can we see our target?
02529 if ( NPC_ClearLOS4( NPC->enemy ) )
02530 {
02531 AI_GroupUpdateEnemyLastSeen( NPCInfo->group, NPC->enemy->r.currentOrigin );
02532 NPCInfo->enemyLastSeenTime = level.time;
02533 enemyLOS = qtrue;
02534
02535 if ( NPC->client->ps.weapon == WP_NONE )
02536 {
02537 enemyCS = qfalse;//not true, but should stop us from firing
02538 NPC_AimAdjust( -1 );//adjust aim worse longer we have no weapon
02539 }
02540 else
02541 {//can we shoot our target?
02542 if ( (NPC->client->ps.weapon == WP_ROCKET_LAUNCHER || (NPC->client->ps.weapon == WP_FLECHETTE && (NPCInfo->scriptFlags&SCF_ALT_FIRE))) && enemyDist < MIN_ROCKET_DIST_SQUARED )//128*128
02543 {
02544 enemyCS = qfalse;//not true, but should stop us from firing
02545 hitAlly = qtrue;//us!
02546 //FIXME: if too close, run away!
02547 }
02548 else if ( enemyInFOV )
02549 {//if enemy is FOV, go ahead and check for shooting
02550 int hit = NPC_ShotEntity( NPC->enemy, impactPos );
02551 gentity_t *hitEnt = &g_entities[hit];
02552
02553 if ( hit == NPC->enemy->s.number
02554 || ( hitEnt && hitEnt->client && hitEnt->client->playerTeam == NPC->client->enemyTeam )
02555 || ( hitEnt && hitEnt->takedamage && ((hitEnt->r.svFlags&SVF_GLASS_BRUSH)||hitEnt->health < 40||NPC->s.weapon == WP_EMPLACED_GUN) ) )
02556 {//can hit enemy or enemy ally or will hit glass or other minor breakable (or in emplaced gun), so shoot anyway
02557 AI_GroupUpdateClearShotTime( NPCInfo->group );
02558 enemyCS = qtrue;
02559 NPC_AimAdjust( 2 );//adjust aim better longer we have clear shot at enemy
02560 VectorCopy( NPC->enemy->r.currentOrigin, NPCInfo->enemyLastSeenLocation );
02561 }
02562 else
02563 {//Hmm, have to get around this bastard
02564 NPC_AimAdjust( 1 );//adjust aim better longer we can see enemy
02565 ST_ResolveBlockedShot( hit );
02566 if ( hitEnt && hitEnt->client && hitEnt->client->playerTeam == NPC->client->playerTeam )
02567 {//would hit an ally, don't fire!!!
02568 hitAlly = qtrue;
02569 }
02570 else
02571 {//Check and see where our shot *would* hit... if it's not close to the enemy (within 256?), then don't fire
02572 }
02573 }
02574 }
02575 else
02576 {
02577 enemyCS = qfalse;//not true, but should stop us from firing
02578 }
02579 }
02580 }
02581 else if ( trap_InPVS( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin ) )
02582 {
02583 NPCInfo->enemyLastSeenTime = level.time;
02584 faceEnemy = qtrue;
02585 NPC_AimAdjust( -1 );//adjust aim worse longer we cannot see enemy
02586 }
02587
02588 if ( NPC->client->ps.weapon == WP_NONE )
02589 {
02590 faceEnemy = qfalse;
02591 shoot = qfalse;
02592 }
02593 else
02594 {
02595 if ( enemyLOS )
02596 {//FIXME: no need to face enemy if we're moving to some other goal and he's too far away to shoot?
02597 faceEnemy = qtrue;
02598 }
02599 if ( enemyCS )
02600 {
02601 shoot = qtrue;
02602 }
02603 }
02604
02605 //Check for movement to take care of
02606 ST_CheckMoveState();
02607
02608 //See if we should override shooting decision with any special considerations
02609 ST_CheckFireState();
02610
02611 if ( faceEnemy )
02612 {//face the enemy
02613 NPC_FaceEnemy( qtrue );
02614 }
02615
02616 if ( !(NPCInfo->scriptFlags&SCF_CHASE_ENEMIES) )
02617 {//not supposed to chase my enemies
02618 if ( NPCInfo->goalEntity == NPC->enemy )
02619 {//goal is my entity, so don't move
02620 move = qfalse;
02621 }
02622 }
02623
02624 if ( NPC->client->ps.weaponTime > 0 && NPC->s.weapon == WP_ROCKET_LAUNCHER )
02625 {
02626 move = qfalse;
02627 }
02628
02629 if ( move )
02630 {//move toward goal
02631 if ( NPCInfo->goalEntity )//&& ( NPCInfo->goalEntity != NPC->enemy || enemyDist > 10000 ) )//100 squared
02632 {
02633 move = ST_Move();
02634 }
02635 else
02636 {
02637 move = qfalse;
02638 }
02639 }
02640
02641 if ( !move )
02642 {
02643 if ( !TIMER_Done( NPC, "duck" ) )
02644 {
02645 ucmd.upmove = -127;
02646 }
02647 //FIXME: what about leaning?
02648 }
02649 else
02650 {//stop ducking!
02651 TIMER_Set( NPC, "duck", -1 );
02652 }
02653
02654 if ( !TIMER_Done( NPC, "flee" ) )
02655 {//running away
02656 faceEnemy = qfalse;
02657 }
02658
02659 //FIXME: check scf_face_move_dir here?
02660
02661 if ( !faceEnemy )
02662 {//we want to face in the dir we're running
02663 if ( !move )
02664 {//if we haven't moved, we should look in the direction we last looked?
02665 VectorCopy( NPC->client->ps.viewangles, NPCInfo->lastPathAngles );
02666 }
02667 NPCInfo->desiredYaw = NPCInfo->lastPathAngles[YAW];
02668 NPCInfo->desiredPitch = 0;
02669 NPC_UpdateAngles( qtrue, qtrue );
02670 if ( move )
02671 {//don't run away and shoot
02672 shoot = qfalse;
02673 }
02674 }
02675
02676 if ( NPCInfo->scriptFlags & SCF_DONT_FIRE )
02677 {
02678 shoot = qfalse;
02679 }
02680
02681 if ( NPC->enemy && NPC->enemy->enemy )
02682 {
02683 if ( NPC->enemy->s.weapon == WP_SABER && NPC->enemy->enemy->s.weapon == WP_SABER )
02684 {//don't shoot at an enemy jedi who is fighting another jedi, for fear of injuring one or causing rogue blaster deflections (a la Obi Wan/Vader duel at end of ANH)
02685 shoot = qfalse;
02686 }
02687 }
02688 //FIXME: don't shoot right away!
02689 if ( NPC->client->ps.weaponTime > 0 )
02690 {
02691 if ( NPC->s.weapon == WP_ROCKET_LAUNCHER )
02692 {
02693 if ( !enemyLOS || !enemyCS )
02694 {//cancel it
02695 NPC->client->ps.weaponTime = 0;
02696 }
02697 else
02698 {//delay our next attempt
02699 TIMER_Set( NPC, "attackDelay", Q_irand( 3000, 5000 ) );
02700 }
02701 }
02702 }
02703 else if ( shoot )
02704 {//try to shoot if it's time
02705 if ( TIMER_Done( NPC, "attackDelay" ) )
02706 {
02707 if( !(NPCInfo->scriptFlags & SCF_FIRE_WEAPON) ) // we've already fired, no need to do it again here
02708 {
02709 WeaponThink( qtrue );
02710 }
02711 //NASTY
02712 if ( NPC->s.weapon == WP_ROCKET_LAUNCHER
02713 && (ucmd.buttons&BUTTON_ATTACK)
02714 && !move
02715 && g_spskill.integer > 1
02716 && !Q_irand( 0, 3 ) )
02717 {//every now and then, shoot a homing rocket
02718 ucmd.buttons &= ~BUTTON_ATTACK;
02719 ucmd.buttons |= BUTTON_ALT_ATTACK;
02720 NPC->client->ps.weaponTime = Q_irand( 1000, 2500 );
02721 }
02722 }
02723 }
02724 }
|
|
|
Definition at line 306 of file NPC_AI_Default.c. References gentity_s::client, gNPC_t::desiredPitch, gNPC_t::desiredYaw, gNPC_t::duckDebounceTime, gentity_s::enemy, gclient_s::enemyTeam, level, NPC, NPC_CheckCanAttack(), NPC_CheckEnemy(), NPC_StandTrackAndShoot(), NPC_UpdateAngles(), NPCInfo, PITCH, gclient_s::playerTeam, gclient_s::ps, qfalse, qtrue, level_locals_t::time, ucmd, usercmd_s::upmove, playerState_s::viewangles, playerState_s::weapon, WP_SABER, and YAW.
00307 {
00308 //FIXME:
00309 //When our numbers outnumber enemies 3 to 1, or only one of them,
00310 //go into hunt and kill mode
00311
00312 //FIXME:
00313 //When they're all dead, go to some script or wander off to sickbay?
00314
00315 if(NPC->client->playerTeam && NPC->client->enemyTeam)
00316 {
00317 //FIXME: don't realize this right away- or else enemies show up and we're standing around
00318 /*
00319 if( teamNumbers[NPC->enemyTeam] == 0 )
00320 {//ok, stand guard until we find another enemy
00321 //reset our rush counter
00322 teamCounter[NPC->playerTeam] = 0;
00323 NPCInfo->tempBehavior = BS_STAND_GUARD;
00324 NPC_BSStandGuard();
00325 return;
00326 }*/
00327 /*
00328 //FIXME: whether to do this or not should be settable
00329 else if( NPC->playerTeam != TEAM_BORG )//Borg don't rush
00330 {
00331 //FIXME: In case reinforcements show up, we should wait a few seconds
00332 //and keep checking before rushing!
00333 //Also: what if not everyone on our team is going after playerTeam?
00334 //Also: our team count includes medics!
00335 if(NPC->health > 25)
00336 {//Can we rush the enemy?
00337 if(teamNumbers[NPC->enemyTeam] == 1 ||
00338 teamNumbers[NPC->playerTeam] >= teamNumbers[NPC->enemyTeam]*3)
00339 {//Only one of them or we outnumber 3 to 1
00340 if(teamStrength[NPC->playerTeam] >= 75 ||
00341 (teamStrength[NPC->playerTeam] >= 50 && teamStrength[NPC->playerTeam] > teamStrength[NPC->enemyTeam]))
00342 {//Our team is strong enough to rush
00343 teamCounter[NPC->playerTeam]++;
00344 if(teamNumbers[NPC->playerTeam] * 17 <= teamCounter[NPC->playerTeam])
00345 {//ok, we waited 1.7 think cycles on average and everyone is go, let's do it!
00346 //FIXME: Should we do this to everyone on our team?
00347 NPCInfo->behaviorState = BS_HUNT_AND_KILL;
00348 //FIXME: if the tide changes, we should retreat!
00349 //FIXME: when do we reset the counter?
00350 NPC_BSHuntAndKill ();
00351 return;
00352 }
00353 }
00354 else//Oops! Something's wrong, reset the counter to rush
00355 teamCounter[NPC->playerTeam] = 0;
00356 }
00357 else//Oops! Something's wrong, reset the counter to rush
00358 teamCounter[NPC->playerTeam] = 0;
00359 }
00360 }
00361 */
00362 }
00363
00364 NPC_CheckEnemy(qtrue, qfalse, qtrue);
00365
00366 if(NPCInfo->duckDebounceTime > level.time && NPC->client->ps.weapon != WP_SABER )
00367 {
00368 ucmd.upmove = -127;
00369 if(NPC->enemy)
00370 {
00371 NPC_CheckCanAttack(1.0, qtrue);
00372 }
00373 return;
00374 }
00375
00376 if(NPC->enemy)
00377 {
00378 if(!NPC_StandTrackAndShoot( NPC, qtrue ))
00379 {//That func didn't update our angles
00380 NPCInfo->desiredYaw = NPC->client->ps.viewangles[YAW];
00381 NPCInfo->desiredPitch = NPC->client->ps.viewangles[PITCH];
00382 NPC_UpdateAngles(qtrue, qtrue);
00383 }
00384 }
00385 else
00386 {
00387 NPCInfo->desiredYaw = NPC->client->ps.viewangles[YAW];
00388 NPCInfo->desiredPitch = NPC->client->ps.viewangles[PITCH];
00389 NPC_UpdateAngles(qtrue, qtrue);
00390 // NPC_BSIdle();//only moves if we have a goal
00391 }
00392 }
|
|
|
Definition at line 191 of file NPC_AI_Default.c. References gNPC_t::behaviorState, BS_DEFAULT, BS_STAND_AND_SHOOT, BS_STAND_GUARD, gentity_s::cantHitEnemyCounter, gentity_s::client, gentity_s::enemy, gclient_s::enemyTeam, G_SetEnemy(), gentity_t, NPC, NPC_PickEnemy(), NPC_UpdateAngles(), NPCInfo, NPCTEAM_PLAYER, NULL, qtrue, random, and gNPC_t::tempBehavior. Referenced by NPC_BSFollowLeader(), and NPC_BSHuntAndKill().
00192 {
00193 //FIXME: Use Snapshot info
00194 if ( NPC->enemy == NULL )
00195 {//Possible to pick one up by being shot
00196 if( random() < 0.5 )
00197 {
00198 if(NPC->client->enemyTeam)
00199 {
00200 gentity_t *newenemy = NPC_PickEnemy(NPC, NPC->client->enemyTeam, (NPC->cantHitEnemyCounter < 10), (NPC->client->enemyTeam == NPCTEAM_PLAYER), qtrue);
00201 //only checks for vis if couldn't hit last enemy
00202 if(newenemy)
00203 {
00204 G_SetEnemy( NPC, newenemy );
00205 }
00206 }
00207 }
00208 }
00209
00210 if ( NPC->enemy != NULL )
00211 {
00212 if( NPCInfo->tempBehavior == BS_STAND_GUARD )
00213 {
00214 NPCInfo->tempBehavior = BS_DEFAULT;
00215 }
00216
00217 if( NPCInfo->behaviorState == BS_STAND_GUARD )
00218 {
00219 NPCInfo->behaviorState = BS_STAND_AND_SHOOT;
00220 }
00221 }
00222
00223 NPC_UpdateAngles( qtrue, qtrue );
00224 }
|
|
|
Definition at line 3060 of file NPC_combat.c. Referenced by NPC_BSDefault(), NPC_BSFlee(), and NPC_BSST_Default().
03061 {
03062 if ( NPC->s.weapon == WP_NONE && NPC->enemy )
03063 {//if running away because dropped weapon...
03064 if ( NPCInfo->goalEntity
03065 && NPCInfo->goalEntity == NPCInfo->tempGoal
03066 && NPCInfo->goalEntity->enemy
03067 && !NPCInfo->goalEntity->enemy->inuse )
03068 {//maybe was running at a weapon that was picked up
03069 NPCInfo->goalEntity = NULL;
03070 }
03071 if ( TIMER_Done( NPC, "panic" ) && NPCInfo->goalEntity == NULL )
03072 {//need a weapon, any lying around?
03073 gentity_t *foundWeap = NPC_SearchForWeapons();
03074 if ( foundWeap )
03075 {//try to nav to it
03076 /*
03077 if ( !trap_Nav_GetBestPathBetweenEnts( NPC, foundWeap, NF_CLEAR_PATH )
03078 || trap_Nav_GetBestNodeAltRoute( NPC->waypoint, foundWeap->waypoint ) == WAYPOINT_NONE )
03079 {//can't possibly have a route to any OR can't possibly have a route to this one OR don't have a route to this one
03080 if ( !NAV_ClearPathToPoint( NPC, NPC->r.mins, NPC->r.maxs, foundWeap->r.currentOrigin, NPC->clipmask, ENTITYNUM_NONE ) )
03081 {//don't even have a clear straight path to this one
03082 }
03083 else
03084 {
03085 NPC_SetPickUpGoal( foundWeap );
03086 }
03087 }
03088 else
03089 */
03090 {
03091 NPC_SetPickUpGoal( foundWeap );
03092 }
03093 }
03094 }
03095 }
03096 }
|
|
|
Definition at line 18 of file NPC_AI_Default.c. References gNPC_t::behaviorState, BS_HUNT_AND_KILL, BS_SEARCH, gentity_s::enemy, G_ClearEnemy(), gNPC_t::goalEntity, gentity_s::lastWaypoint, NPC, NPC_BSSearchStart(), NPCInfo, and WAYPOINT_NONE. Referenced by NPC_BSRunAndShoot(), NPC_CheckEnemy(), and NPC_HandleAIFlags().
00019 {
00020 switch( NPCInfo->behaviorState )
00021 {
00022 case BS_HUNT_AND_KILL:
00023 //We were chasing him and lost him, so try to find him
00024 if ( NPC->enemy == NPCInfo->goalEntity && NPC->enemy->lastWaypoint != WAYPOINT_NONE )
00025 {//Remember his last valid Wp, then check it out
00026 //FIXME: Should we only do this if there's no other enemies or we've got LOCKED_ENEMY on?
00027 NPC_BSSearchStart( NPC->enemy->lastWaypoint, BS_SEARCH );
00028 }
00029 //If he's not our goalEntity, we're running somewhere else, so lose him
00030 break;
00031 default:
00032 break;
00033 }
00034 G_ClearEnemy( NPC );
00035 }
|
|
|
Definition at line 1042 of file NPC_utils.c.
01043 {
01044 int i = 0;
01045 gentity_t *pEnt;
01046
01047 while (i < MAX_CLIENTS)
01048 {
01049 pEnt = &g_entities[i];
01050
01051 if (pEnt && pEnt->inuse && pEnt->client && pEnt->client->sess.sessionTeam != TEAM_SPECTATOR &&
01052 !(pEnt->client->ps.pm_flags & PMF_FOLLOW) && pEnt->s.weapon != WP_NONE)
01053 {
01054 if (trap_InPVS(ent->r.currentOrigin, pEnt->r.currentOrigin))
01055 {
01056 if (InFOV( ent, pEnt, 30, 30 ))
01057 { //I'm in a 30 fov or so cone from this player.. that's enough I guess.
01058 return qtrue;
01059 }
01060 }
01061 }
01062
01063 i++;
01064 }
01065
01066 return qfalse;
01067 }
|
|
|
Definition at line 42 of file NPC_AI_Default.c.
00043 {
00044 /*
00045 //Must be done with any other animations
00046 if ( NPC->client->ps.legsAnimTimer != 0 )
00047 return;
00048
00049 //Not ready to do another one
00050 if ( TIMER_Done( NPC, "idleAnim" ) == false )
00051 return;
00052
00053 int anim = NPC->client->ps.legsAnim;
00054
00055 if ( anim != BOTH_STAND1 && anim != BOTH_STAND2 )
00056 return;
00057
00058 //FIXME: Account for STAND1 or STAND2 here and set the base anim accordingly
00059 int baseSeq = ( anim == BOTH_STAND1 ) ? BOTH_STAND1_RANDOM1 : BOTH_STAND2_RANDOM1;
00060
00061 //Must have at least one random idle animation
00062 //NOTENOTE: This relies on proper ordering of animations, which SHOULD be okay
00063 if ( PM_HasAnimation( NPC, baseSeq ) == false )
00064 return;
00065
00066 int newIdle = Q_irand( 0, MAX_IDLE_ANIMS-1 );
00067
00068 //FIXME: Technically this could never complete.. but that's not really too likely
00069 while( 1 )
00070 {
00071 if ( PM_HasAnimation( NPC, baseSeq + newIdle ) )
00072 break;
00073
00074 newIdle = Q_irand( 0, MAX_IDLE_ANIMS );
00075 }
00076
00077 //Start that animation going
00078 NPC_SetAnim( NPC, SETANIM_BOTH, baseSeq + newIdle, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00079
00080 int newTime = PM_AnimLength( NPC->client->clientInfo.animFileIndex, (animNumber_t) (baseSeq + newIdle) );
00081
00082 //Don't do this again for a random amount of time
00083 TIMER_Set( NPC, "idleAnim", newTime + Q_irand( 2000, 10000 ) );
00084 */
00085 }
|
|
||||||||||||
|
if ( NPC->client->playerTeam!= TEAM_BORG ) Definition at line 87 of file NPC_AI_Default.c. References BUTTON_ATTACK, gclient_s::buttons, gentity_s::client, client, gNPC_t::duckDebounceTime, gentity_s::enemy, gentity_t, gentity_s::health, level, NPC, NPC_CheckCanAttack(), NPC_CheckDefend(), NPCInfo, gclient_s::ps, qboolean, qfalse, qtrue, random, level_locals_t::time, ucmd, usercmd_s::upmove, and playerState_s::weaponTime. Referenced by NPC_BSRunAndShoot(), and NPC_BSStandAndShoot().
00088 {
00089 qboolean attack_ok = qfalse;
00090 qboolean duck_ok = qfalse;
00091 qboolean faced = qfalse;
00092 float attack_scale = 1.0;
00093
00094 //First see if we're hurt bad- if so, duck
00095 //FIXME: if even when ducked, we can shoot someone, we should.
00096 //Maybe is can be shot even when ducked, we should run away to the nearest cover?
00097 if ( canDuck )
00098 {
00099 if ( NPC->health < 20 )
00100 {
00101 // if( NPC->svFlags&SVF_HEALING || random() )
00102 if( random() )
00103 {
00104 duck_ok = qtrue;
00105 }
00106 }
00107 else if ( NPC->health < 40 )
00108 {
00109 // if ( NPC->svFlags&SVF_HEALING )
00110 // {//Medic is on the way, get down!
00111 // duck_ok = qtrue;
00112 // }
00113 // no more borg
00115 // {//Borg don't care if they're about to die
00116 //attack_scale will be a max of .66
00117 // attack_scale = NPC->health/60;
00118 // }
00119 }
00120 }
00121
00122 //NPC_CheckEnemy( qtrue, qfalse, qtrue );
00123
00124 if ( !duck_ok )
00125 {//made this whole part a function call
00126 attack_ok = NPC_CheckCanAttack( attack_scale, qtrue );
00127 faced = qtrue;
00128 }
00129
00130 if ( canDuck && (duck_ok || (!attack_ok && client->ps.weaponTime <= 0)) && ucmd.upmove != -127 )
00131 {//if we didn't attack check to duck if we're not already
00132 if( !duck_ok )
00133 {
00134 if ( NPC->enemy->client )
00135 {
00136 if ( NPC->enemy->enemy == NPC )
00137 {
00138 if ( NPC->enemy->client->buttons & BUTTON_ATTACK )
00139 {//FIXME: determine if enemy fire angles would hit me or get close
00140 if ( NPC_CheckDefend( 1.0 ) )//FIXME: Check self-preservation? Health?
00141 {
00142 duck_ok = qtrue;
00143 }
00144 }
00145 }
00146 }
00147 }
00148
00149 if ( duck_ok )
00150 {//duck and don't shoot
00151 attack_ok = qfalse;
00152 ucmd.upmove = -127;
00153 NPCInfo->duckDebounceTime = level.time + 1000;//duck for a full second
00154 }
00155 }
00156
00157 return faced;
00158 }
|