#include "b_local.h"#include "g_nav.h"#include "anims.h"Go to the source code of this file.
|
|
Definition at line 25 of file NPC_AI_Sniper.c. |
|
|
Definition at line 18 of file NPC_AI_Sniper.c. |
|
|
Definition at line 19 of file NPC_AI_Sniper.c. |
|
|
Definition at line 21 of file NPC_AI_Sniper.c. |
|
|
Definition at line 22 of file NPC_AI_Sniper.c. |
|
|
Definition at line 15 of file NPC_AI_Sniper.c. |
|
|
Definition at line 13 of file NPC_AI_Sniper.c. |
|
|
Definition at line 14 of file NPC_AI_Sniper.c. |
|
|
Definition at line 16 of file NPC_AI_Sniper.c. |
|
|
Definition at line 24 of file NPC_AI_Sniper.c. |
|
|
Definition at line 20 of file NPC_AI_Sniper.c. |
|
|
Definition at line 11 of file NPC_AI_Sniper.c. Referenced by NPC_BSSniper_Attack(). |
|
|
Definition at line 37 of file NPC_AI_Sniper.c.
00038 {
00039 LSTATE_NONE = 0,
00040 LSTATE_UNDERFIRE,
00041 LSTATE_INVESTIGATE,
00042 };
|
|
|
Definition at line 46 of file g_nav.c.
|
|
||||||||||||||||
|
Definition at line 23 of file NPC_sounds.c.
00024 {
00025 if ( !self->NPC )
00026 {
00027 return;
00028 }
00029
00030 if ( !self->client || self->client->ps.pm_type >= PM_DEAD )
00031 {
00032 return;
00033 }
00034
00035 if ( self->NPC->blockedSpeechDebounceTime > level.time )
00036 {
00037 return;
00038 }
00039
00040 if ( trap_ICARUS_TaskIDPending( self, TID_CHAN_VOICE ) )
00041 {
00042 return;
00043 }
00044
00045
00046 if ( (self->NPC->scriptFlags&SCF_NO_COMBAT_TALK) && ( (event >= EV_ANGER1 && event <= EV_VICTORY3) || (event >= EV_CHASE1 && event <= EV_SUSPICIOUS5) ) )//(event < EV_FF_1A || event > EV_FF_3C) && (event < EV_RESPOND1 || event > EV_MISSION3) )
00047 {
00048 return;
00049 }
00050
00051 if ( (self->NPC->scriptFlags&SCF_NO_ALERT_TALK) && (event >= EV_GIVEUP1 && event <= EV_SUSPICIOUS5) )
00052 {
00053 return;
00054 }
00055 //FIXME: Also needs to check for teammates. Don't want
00056 // everyone babbling at once
00057
00058 //NOTE: was losing too many speech events, so we do it directly now, screw networking!
00059 //G_AddEvent( self, event, 0 );
00060 G_SpeechEvent( self, event );
00061
00062 //won't speak again for 5 seconds (unless otherwise specified)
00063 self->NPC->blockedSpeechDebounceTime = level.time + ((speakDebounceTime==0) ? 5000 : speakDebounceTime);
00064 }
|
|
||||||||||||||||||||||||
|
Definition at line 2087 of file g_utils.c.
02088 {
02089 trace_t tr;
02090 vec3_t start, end;
02091 int i;
02092
02093 VectorCopy( point, start );
02094
02095 for ( i = 0; i < 3; i++ )
02096 {
02097 VectorCopy( start, end );
02098 end[i] += mins[i];
02099 trap_Trace( &tr, start, vec3_origin, vec3_origin, end, ignore, clipmask );
02100 if ( tr.allsolid || tr.startsolid )
02101 {
02102 return qfalse;
02103 }
02104 if ( tr.fraction < 1.0 )
02105 {
02106 VectorCopy( start, end );
02107 end[i] += maxs[i]-(mins[i]*tr.fraction);
02108 trap_Trace( &tr, start, vec3_origin, vec3_origin, end, ignore, clipmask );
02109 if ( tr.allsolid || tr.startsolid )
02110 {
02111 return qfalse;
02112 }
02113 if ( tr.fraction < 1.0 )
02114 {
02115 return qfalse;
02116 }
02117 VectorCopy( end, start );
02118 }
02119 }
02120 //expanded it, now see if it's all clear
02121 trap_Trace( &tr, start, mins, maxs, start, ignore, clipmask );
02122 if ( tr.allsolid || tr.startsolid )
02123 {
02124 return qfalse;
02125 }
02126 VectorCopy( start, point );
02127 return qtrue;
02128 }
|
|
||||||||||||||||
|
|
|
|
NPC->enemy )// Definition at line 640 of file NPC_AI_Sniper.c. References AEL_DANGER, trace_t::allsolid, AngleVectors(), gentity_s::attackDebounceTime, BUTTON_ALT_ATTACK, BUTTON_ATTACK, usercmd_s::buttons, CalcMuzzlePoint(), CHAN_WEAPON, gentity_s::client, gentity_s::clipmask, entityShared_t::currentOrigin, gNPC_t::desiredPitch, gNPC_t::desiredYaw, gentity_s::enemy, gNPC_t::enemyLastSeenLocation, gNPC_t::enemyLastSeenTime, trace_t::entityNum, gentity_s::fly_sound_debounce_time, trace_t::fraction, G_SoundOnEnt(), gNPC_t::goalEntity, gNPC_t::lastPathAngles, level, MASK_SHOT, entityShared_t::maxs, entityShared_t::mins, NPC, NPC_BSSniper_Patrol(), NPC_ChangeWeapon(), NPC_CheckAlertEvents(), NPC_CheckEnemyExt(), NPC_CheckForDanger(), NPC_ClearLOS4(), NPC_MaxDistSquaredForWeapon(), NPC_UpdateAngles(), NPCInfo, NULL, entityState_s::number, gentity_s::painDebounceTime, gclient_s::ps, Q_irand(), qfalse, qtrue, gentity_s::r, gentity_s::s, SCF_ALT_FIRE, SCF_DONT_FIRE, gNPC_t::scriptFlags, gNPC_t::shotTime, Sniper_EvaluateShot(), Sniper_FaceEnemy(), Sniper_StartHide(), Sniper_UpdateEnemyPos(), gentity_s::spawnflags, SPF_NO_HIDE, trace_t::startsolid, level_locals_t::time, TIMER_Done(), TIMER_Get(), TIMER_Set(), trap_Trace(), ucmd, usercmd_s::upmove, vec3_t, VectorCopy, VectorMA, playerState_s::viewangles, playerState_s::weapon, WeaponThink(), WP_DISRUPTOR, and YAW. Referenced by NPC_BSSniper_Default().
00641 {
00642 //Don't do anything if we're hurt
00643 if ( NPC->painDebounceTime > level.time )
00644 {
00645 NPC_UpdateAngles( qtrue, qtrue );
00646 return;
00647 }
00648
00649 //NPC_CheckEnemy( qtrue, qfalse );
00650 //If we don't have an enemy, just idle
00651 if ( NPC_CheckEnemyExt(qfalse) == qfalse )
00652 {
00653 NPC->enemy = NULL;
00654 NPC_BSSniper_Patrol();//FIXME: or patrol?
00655 return;
00656 }
00657
00658 if ( TIMER_Done( NPC, "flee" ) && NPC_CheckForDanger( NPC_CheckAlertEvents( qtrue, qtrue, -1, qfalse, AEL_DANGER ) ) )
00659 {//going to run
00660 NPC_UpdateAngles( qtrue, qtrue );
00661 return;
00662 }
00663
00664 if ( !NPC->enemy )
00665 {//WTF? somehow we lost our enemy?
00666 NPC_BSSniper_Patrol();//FIXME: or patrol?
00667 return;
00668 }
00669
00670 enemyLOS2 = enemyCS2 = qfalse;
00671 move2 = qtrue;
00672 faceEnemy2 = qfalse;
00673 shoot2 = qfalse;
00674 enemyDist2 = DistanceSquared( NPC->r.currentOrigin, NPC->enemy->r.currentOrigin );
00675 if ( enemyDist2 < 16384 )//128 squared
00676 {//too close, so switch to primary fire
00677 if ( NPC->client->ps.weapon == WP_DISRUPTOR )
00678 {//sniping... should be assumed
00679 if ( NPCInfo->scriptFlags & SCF_ALT_FIRE )
00680 {//use primary fire
00681 trace_t trace;
00682 trap_Trace ( &trace, NPC->enemy->r.currentOrigin, NPC->enemy->r.mins, NPC->enemy->r.maxs, NPC->r.currentOrigin, NPC->enemy->s.number, NPC->enemy->clipmask );
00683 if ( !trace.allsolid && !trace.startsolid && (trace.fraction == 1.0 || trace.entityNum == NPC->s.number ) )
00684 {//he can get right to me
00685 NPCInfo->scriptFlags &= ~SCF_ALT_FIRE;
00686 //reset fire-timing variables
00687 NPC_ChangeWeapon( WP_DISRUPTOR );
00688 NPC_UpdateAngles( qtrue, qtrue );
00689 return;
00690 }
00691 }
00692 //FIXME: switch back if he gets far away again?
00693 }
00694 }
00695 else if ( enemyDist2 > 65536 )//256 squared
00696 {
00697 if ( NPC->client->ps.weapon == WP_DISRUPTOR )
00698 {//sniping... should be assumed
00699 if ( !(NPCInfo->scriptFlags&SCF_ALT_FIRE) )
00700 {//use primary fire
00701 NPCInfo->scriptFlags |= SCF_ALT_FIRE;
00702 //reset fire-timing variables
00703 NPC_ChangeWeapon( WP_DISRUPTOR );
00704 NPC_UpdateAngles( qtrue, qtrue );
00705 return;
00706 }
00707 }
00708 }
00709
00710 Sniper_UpdateEnemyPos();
00711 //can we see our target?
00712 if ( NPC_ClearLOS4( NPC->enemy ) )//|| (NPCInfo->stats.aim >= 5 && gi.inPVS( NPC->client->renderInfo.eyePoint, NPC->enemy->currentOrigin )) )
00713 {
00714 float maxShootDist;
00715
00716 NPCInfo->enemyLastSeenTime = level.time;
00717 VectorCopy( NPC->enemy->r.currentOrigin, NPCInfo->enemyLastSeenLocation );
00718 enemyLOS2 = qtrue;
00719 maxShootDist = NPC_MaxDistSquaredForWeapon();
00720 if ( enemyDist2 < maxShootDist )
00721 {
00722 vec3_t fwd, right, up, muzzle, end;
00723 trace_t tr;
00724 int hit;
00725
00726 AngleVectors( NPC->client->ps.viewangles, fwd, right, up );
00727 CalcMuzzlePoint( NPC, fwd, right, up, muzzle );
00728 VectorMA( muzzle, 8192, fwd, end );
00729 trap_Trace ( &tr, muzzle, NULL, NULL, end, NPC->s.number, MASK_SHOT );
00730
00731 hit = tr.entityNum;
00732 //can we shoot our target?
00733 if ( Sniper_EvaluateShot( hit ) )
00734 {
00735 enemyCS2 = qtrue;
00736 }
00737 }
00738 }
00739 /*
00740 else if ( gi.inPVS( NPC->enemy->currentOrigin, NPC->currentOrigin ) )
00741 {
00742 NPCInfo->enemyLastSeenTime = level.time;
00743 faceEnemy2 = qtrue;
00744 }
00745 */
00746
00747 if ( enemyLOS2 )
00748 {//FIXME: no need to face enemy if we're moving to some other goal and he's too far away to shoot?
00749 faceEnemy2 = qtrue;
00750 }
00751 if ( enemyCS2 )
00752 {
00753 shoot2 = qtrue;
00754 }
00755 else if ( level.time - NPCInfo->enemyLastSeenTime > 3000 )
00756 {//Hmm, have to get around this bastard... FIXME: this NPCInfo->enemyLastSeenTime builds up when ducked seems to make them want to run when they uncrouch
00757 Sniper_ResolveBlockedShot();
00758 }
00759
00760 //Check for movement to take care of
00761 Sniper_CheckMoveState();
00762
00763 //See if we should override shooting decision with any special considerations
00764 Sniper_CheckFireState();
00765
00766 if ( move2 )
00767 {//move toward goal
00768 if ( NPCInfo->goalEntity )//&& ( NPCInfo->goalEntity != NPC->enemy || enemyDist2 > 10000 ) )//100 squared
00769 {
00770 move2 = Sniper_Move();
00771 }
00772 else
00773 {
00774 move2 = qfalse;
00775 }
00776 }
00777
00778 if ( !move2 )
00779 {
00780 if ( !TIMER_Done( NPC, "duck" ) )
00781 {
00782 if ( TIMER_Done( NPC, "watch" ) )
00783 {//not while watching
00784 ucmd.upmove = -127;
00785 }
00786 }
00787 //FIXME: what about leaning?
00788 //FIXME: also, when stop ducking, start looking, if enemy can see me, chance of ducking back down again
00789 }
00790 else
00791 {//stop ducking!
00792 TIMER_Set( NPC, "duck", -1 );
00793 }
00794
00795 if ( TIMER_Done( NPC, "duck" )
00796 && TIMER_Done( NPC, "watch" )
00797 && (TIMER_Get( NPC, "attackDelay" )-level.time) > 1000
00798 && NPC->attackDebounceTime < level.time )
00799 {
00800 if ( enemyLOS2 && (NPCInfo->scriptFlags&SCF_ALT_FIRE) )
00801 {
00802 if ( NPC->fly_sound_debounce_time < level.time )
00803 {
00804 NPC->fly_sound_debounce_time = level.time + 2000;
00805 }
00806 }
00807 }
00808
00809 if ( !faceEnemy2 )
00810 {//we want to face in the dir we're running
00811 if ( move2 )
00812 {//don't run away and shoot
00813 NPCInfo->desiredYaw = NPCInfo->lastPathAngles[YAW];
00814 NPCInfo->desiredPitch = 0;
00815 shoot2 = qfalse;
00816 }
00817 NPC_UpdateAngles( qtrue, qtrue );
00818 }
00819 else// if ( faceEnemy2 )
00820 {//face the enemy
00821 Sniper_FaceEnemy();
00822 }
00823
00824 if ( NPCInfo->scriptFlags&SCF_DONT_FIRE )
00825 {
00826 shoot2 = qfalse;
00827 }
00828
00829 //FIXME: don't shoot right away!
00830 if ( shoot2 )
00831 {//try to shoot if it's time
00832 if ( TIMER_Done( NPC, "attackDelay" ) )
00833 {
00834 WeaponThink( qtrue );
00835 if ( ucmd.buttons&(BUTTON_ATTACK|BUTTON_ALT_ATTACK) )
00836 {
00837 G_SoundOnEnt( NPC, CHAN_WEAPON, "sound/null.wav" );
00838 }
00839
00840 //took a shot, now hide
00841 if ( !(NPC->spawnflags&SPF_NO_HIDE) && !Q_irand( 0, 1 ) )
00842 {
00843 //FIXME: do this if in combat point and combat point has duck-type cover... also handle lean-type cover
00844 Sniper_StartHide();
00845 }
00846 else
00847 {
00848 TIMER_Set( NPC, "attackDelay", NPCInfo->shotTime-level.time );
00849 }
00850 }
00851 }
00852 }
|
|
|
Definition at line 854 of file NPC_AI_Sniper.c. References gentity_s::enemy, NPC, NPC_BSSniper_Attack(), and NPC_BSSniper_Patrol().
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 185 of file NPC_AI_Sniper.c. References AEL_DISCOVERED, AEL_SUSPICIOUS, gNPCstats_e::aim, level_locals_t::alertEvents, BUTTON_WALKING, usercmd_s::buttons, gentity_s::client, gNPC_t::confusionTime, gentity_s::count, gNPC_t::desiredPitch, gNPC_t::desiredYaw, gclient_s::enemyTeam, renderInfo_s::eyePoint, G_SetEnemy(), gentity_s::health, alertEvent_s::ID, gNPC_t::investigateDebounceTime, gNPC_t::investigateGoal, gNPC_t::lastAlertID, alertEvent_s::level, level, NPC, NPC_CheckAlertEvents(), NPC_CheckForDanger(), NPC_CheckPlayerTeamStealth(), NPC_MoveToGoal(), NPC_UpdateAngles(), NPCInfo, alertEvent_s::owner, PITCH, gclient_s::playerTeam, alertEvent_s::position, Q_irand(), qfalse, qtrue, gclient_s::renderInfo, SCF_IGNORE_ALERTS, SCF_LOOK_FOR_ENEMIES, gNPC_t::scriptFlags, gNPC_t::stats, level_locals_t::time, TIMER_Set(), ucmd, UpdateGoal(), vec3_t, vectoangles(), VectorCopy, VectorSubtract, and YAW. Referenced by NPC_BSSniper_Attack(), and NPC_BSSniper_Default().
00186 {//FIXME: pick up on bodies of dead buddies?
00187 NPC->count = 0;
00188
00189 if ( NPCInfo->confusionTime < level.time )
00190 {
00191 //Look for any enemies
00192 if ( NPCInfo->scriptFlags&SCF_LOOK_FOR_ENEMIES )
00193 {
00194 if ( NPC_CheckPlayerTeamStealth() )
00195 {
00196 //NPCInfo->behaviorState = BS_HUNT_AND_KILL;//Should be auto now
00197 //NPC_AngerSound();
00198 NPC_UpdateAngles( qtrue, qtrue );
00199 return;
00200 }
00201 }
00202
00203 if ( !(NPCInfo->scriptFlags&SCF_IGNORE_ALERTS) )
00204 {
00205 //Is there danger nearby
00206 int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, -1, qfalse, AEL_SUSPICIOUS );
00207 if ( NPC_CheckForDanger( alertEvent ) )
00208 {
00209 NPC_UpdateAngles( qtrue, qtrue );
00210 return;
00211 }
00212 else
00213 {//check for other alert events
00214 //There is an event to look at
00215 if ( alertEvent >= 0 && level.alertEvents[alertEvent].ID != NPCInfo->lastAlertID )
00216 {
00217 NPCInfo->lastAlertID = level.alertEvents[alertEvent].ID;
00218 if ( level.alertEvents[alertEvent].level == AEL_DISCOVERED )
00219 {
00220 if ( level.alertEvents[alertEvent].owner &&
00221 level.alertEvents[alertEvent].owner->client &&
00222 level.alertEvents[alertEvent].owner->health >= 0 &&
00223 level.alertEvents[alertEvent].owner->client->playerTeam == NPC->client->enemyTeam )
00224 {//an enemy
00225 G_SetEnemy( NPC, level.alertEvents[alertEvent].owner );
00226 //NPCInfo->enemyLastSeenTime = level.time;
00227 TIMER_Set( NPC, "attackDelay", Q_irand( (6-NPCInfo->stats.aim)*100, (6-NPCInfo->stats.aim)*500 ) );
00228 }
00229 }
00230 else
00231 {//FIXME: get more suspicious over time?
00232 //Save the position for movement (if necessary)
00233 //FIXME: sound?
00234 VectorCopy( level.alertEvents[alertEvent].position, NPCInfo->investigateGoal );
00235 NPCInfo->investigateDebounceTime = level.time + Q_irand( 500, 1000 );
00236 if ( level.alertEvents[alertEvent].level == AEL_SUSPICIOUS )
00237 {//suspicious looks longer
00238 NPCInfo->investigateDebounceTime += Q_irand( 500, 2500 );
00239 }
00240 }
00241 }
00242 }
00243
00244 if ( NPCInfo->investigateDebounceTime > level.time )
00245 {//FIXME: walk over to it, maybe? Not if not chase enemies flag
00246 //NOTE: stops walking or doing anything else below
00247 vec3_t dir, angles;
00248 float o_yaw, o_pitch;
00249
00250 VectorSubtract( NPCInfo->investigateGoal, NPC->client->renderInfo.eyePoint, dir );
00251 vectoangles( dir, angles );
00252
00253 o_yaw = NPCInfo->desiredYaw;
00254 o_pitch = NPCInfo->desiredPitch;
00255 NPCInfo->desiredYaw = angles[YAW];
00256 NPCInfo->desiredPitch = angles[PITCH];
00257
00258 NPC_UpdateAngles( qtrue, qtrue );
00259
00260 NPCInfo->desiredYaw = o_yaw;
00261 NPCInfo->desiredPitch = o_pitch;
00262 return;
00263 }
00264 }
00265 }
00266
00267 //If we have somewhere to go, then do that
00268 if ( UpdateGoal() )
00269 {
00270 ucmd.buttons |= BUTTON_WALKING;
00271 NPC_MoveToGoal( qtrue );
00272 }
00273
00274 NPC_UpdateAngles( qtrue, qtrue );
00275 }
|
|
|
|
|
||||||||||||||||
|
Definition at line 85 of file NPC_AI_Sniper.c. References EV_PUSHED1, EV_PUSHED3, G_AddVoiceEvent(), gentity_t, gentity_s::health, gNPC_t::localState, LSTATE_UNDERFIRE, gentity_s::NPC, NPC_Pain(), Q_irand(), and TIMER_Set().
00086 {
00087 self->NPC->localState = LSTATE_UNDERFIRE;
00088
00089 TIMER_Set( self, "duck", -1 );
00090 TIMER_Set( self, "stand", 2000 );
00091
00092 NPC_Pain( self, attacker, damage );
00093
00094 if ( !damage && self->health > 0 )
00095 {//FIXME: better way to know I was pushed
00096 G_AddVoiceEvent( self, Q_irand(EV_PUSHED1, EV_PUSHED3), 2000 );
00097 }
00098 }
|
|
|
Definition at line 60 of file NPC_AI_Sniper.c. References BS_DEFAULT, EV_CONFUSE1, EV_CONFUSE3, G_AddVoiceEvent(), G_ClearEnemy(), gentity_t, gentity_s::health, gNPC_t::investigateCount, gentity_s::NPC, Q_irand(), SQUAD_IDLE, gNPC_t::squadState, gNPC_t::tempBehavior, and TIMER_Set().
00061 {//FIXME: make this a custom sound in sound set
00062 if ( self->health > 0 )
00063 {
00064 G_AddVoiceEvent( self, Q_irand(EV_CONFUSE1, EV_CONFUSE3), 2000 );
00065 }
00066 //reset him to be totally unaware again
00067 TIMER_Set( self, "enemyLastVisible", 0 );
00068 TIMER_Set( self, "flee", 0 );
00069 self->NPC->squadState = SQUAD_IDLE;
00070 self->NPC->tempBehavior = BS_DEFAULT;
00071
00072 //self->NPC->behaviorState = BS_PATROL;
00073 G_ClearEnemy( self );//FIXME: or just self->enemy = NULL;?
00074
00075 self->NPC->investigateCount = 0;
00076 }
|
|
||||||||||||||||||||
|
Definition at line 661 of file NPC_reactions.c.
00662 {
00663 if ( !self->client )
00664 {
00665 return;
00666 }
00667
00668 if ( (self->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
00669 {//lookTarget is set by and to the monster that's holding you, no other operations can change that
00670 return;
00671 }
00672
00673 if ( !minLookTime )
00674 {
00675 minLookTime = 1000;
00676 }
00677
00678 if ( !maxLookTime )
00679 {
00680 maxLookTime = 1000;
00681 }
00682
00683 if ( !NPC_CheckLookTarget( self ) )
00684 {//Not already looking at something else
00685 //Look at him for 1 to 3 seconds
00686 NPC_SetLookTarget( self, lookEntNum, level.time + Q_irand( minLookTime, maxLookTime ) );
00687 }
00688 }
|
|
|
Definition at line 44 of file NPC_AI_Sniper.c. References gentity_t, and TIMER_Set().
00045 {
00046 TIMER_Set( ent, "chatter", 0 );
00047 TIMER_Set( ent, "duck", 0 );
00048 TIMER_Set( ent, "stand", 0 );
00049 TIMER_Set( ent, "shuffleTime", 0 );
00050 TIMER_Set( ent, "sleepTime", 0 );
00051 TIMER_Set( ent, "enemyLastVisible", 0 );
00052 TIMER_Set( ent, "roamTime", 0 );
00053 TIMER_Set( ent, "hideTime", 0 );
00054 TIMER_Set( ent, "attackDelay", 0 ); //FIXME: Slant for difficulty levels
00055 TIMER_Set( ent, "stick", 0 );
00056 TIMER_Set( ent, "scoutTime", 0 );
00057 TIMER_Set( ent, "flee", 0 );
00058 }
|
|
|
|
Definition at line 508 of file NPC_AI_Sniper.c. References gNPCstats_e::aim, AngleNormalize360(), AngleVectors(), CalcEntitySpot(), CalcMuzzlePoint(), gentity_s::client, gentity_s::count, gNPC_t::desiredPitch, gNPC_t::desiredYaw, gentity_s::enemy, ENEMY_POS_LAG_STEPS, gNPC_t::enemyLaggedPos, trace_t::entityNum, flrand(), g_spskill, GetAnglesForDirection(), vmCvar_t::integer, level, MASK_SHOT, entityShared_t::maxs, entityShared_t::mins, NPC, NPC_UpdateAngles(), NPCInfo, entityState_s::number, PITCH, gclient_s::ps, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, gentity_s::s, gNPC_t::shotTime, Sniper_EvaluateShot(), SPOT_ORIGIN, gNPC_t::stats, level_locals_t::time, TIMER_Done(), trap_Trace(), vec3_origin, vec3_t, VectorCopy, VectorMA, playerState_s::viewangles, and YAW. Referenced by NPC_BSSniper_Attack().
00509 {
00510 //FIXME: the ones behind kill holes are facing some arbitrary direction and not firing
00511 //FIXME: If actually trying to hit enemy, don't fire unless enemy is at least in front of me?
00512 //FIXME: need to give designers option to make them not miss first few shots
00513 if ( NPC->enemy )
00514 {
00515 vec3_t muzzle, target, angles, forward, right, up;
00516 //Get the positions
00517 AngleVectors( NPC->client->ps.viewangles, forward, right, up );
00518 CalcMuzzlePoint( NPC, forward, right, up, muzzle );
00519 //CalcEntitySpot( NPC, SPOT_WEAPON, muzzle );
00520 CalcEntitySpot( NPC->enemy, SPOT_ORIGIN, target );
00521
00522 if ( enemyDist2 > 65536 && NPCInfo->stats.aim < 5 )//is 256 squared, was 16384 (128*128)
00523 {
00524 if ( NPC->count < (5-NPCInfo->stats.aim) )
00525 {//miss a few times first
00526 if ( shoot2 && TIMER_Done( NPC, "attackDelay" ) && level.time >= NPCInfo->shotTime )
00527 {//ready to fire again
00528 qboolean aimError = qfalse;
00529 qboolean hit = qtrue;
00530 int tryMissCount = 0;
00531 trace_t trace;
00532
00533 GetAnglesForDirection( muzzle, target, angles );
00534 AngleVectors( angles, forward, right, up );
00535
00536 while ( hit && tryMissCount < 10 )
00537 {
00538 tryMissCount++;
00539 if ( !Q_irand( 0, 1 ) )
00540 {
00541 aimError = qtrue;
00542 if ( !Q_irand( 0, 1 ) )
00543 {
00544 VectorMA( target, NPC->enemy->r.maxs[2]*flrand(1.5, 4), right, target );
00545 }
00546 else
00547 {
00548 VectorMA( target, NPC->enemy->r.mins[2]*flrand(1.5, 4), right, target );
00549 }
00550 }
00551 if ( !aimError || !Q_irand( 0, 1 ) )
00552 {
00553 if ( !Q_irand( 0, 1 ) )
00554 {
00555 VectorMA( target, NPC->enemy->r.maxs[2]*flrand(1.5, 4), up, target );
00556 }
00557 else
00558 {
00559 VectorMA( target, NPC->enemy->r.mins[2]*flrand(1.5, 4), up, target );
00560 }
00561 }
00562 trap_Trace( &trace, muzzle, vec3_origin, vec3_origin, target, NPC->s.number, MASK_SHOT );
00563 hit = Sniper_EvaluateShot( trace.entityNum );
00564 }
00565 NPC->count++;
00566 }
00567 else
00568 {
00569 if ( !enemyLOS2 )
00570 {
00571 NPC_UpdateAngles( qtrue, qtrue );
00572 return;
00573 }
00574 }
00575 }
00576 else
00577 {//based on distance, aim value, difficulty and enemy movement, miss
00578 //FIXME: incorporate distance as a factor?
00579 int missFactor = 8-(NPCInfo->stats.aim+g_spskill.integer) * 3;
00580 if ( missFactor > ENEMY_POS_LAG_STEPS )
00581 {
00582 missFactor = ENEMY_POS_LAG_STEPS;
00583 }
00584 else if ( missFactor < 0 )
00585 {//???
00586 missFactor = 0 ;
00587 }
00588 VectorCopy( NPCInfo->enemyLaggedPos[missFactor], target );
00589 }
00590 GetAnglesForDirection( muzzle, target, angles );
00591 }
00592 else
00593 {
00594 target[2] += flrand( 0, NPC->enemy->r.maxs[2] );
00595 //CalcEntitySpot( NPC->enemy, SPOT_HEAD_LEAN, target );
00596 GetAnglesForDirection( muzzle, target, angles );
00597 }
00598
00599 NPCInfo->desiredYaw = AngleNormalize360( angles[YAW] );
00600 NPCInfo->desiredPitch = AngleNormalize360( angles[PITCH] );
00601 }
00602 NPC_UpdateAngles( qtrue, qtrue );
00603 }
|
|
|
Definition at line 631 of file NPC_AI_Sniper.c. References NPC, Q_irand(), and TIMER_Set(). Referenced by NPC_BSSniper_Attack().
|
|
|
Definition at line 605 of file NPC_AI_Sniper.c. References CalcEntitySpot(), gentity_s::enemy, ENEMY_POS_LAG_INTERVAL, gNPC_t::enemyLaggedPos, flrand(), MAX_ENEMY_POS_LAG, NPC, NPCInfo, SPOT_HEAD_LEAN, and VectorCopy. Referenced by NPC_BSSniper_Attack().
00606 {
00607 int index;
00608 int i;
00609
00610 for ( i = MAX_ENEMY_POS_LAG-ENEMY_POS_LAG_INTERVAL; i >= 0; i -= ENEMY_POS_LAG_INTERVAL )
00611 {
00612 index = i/ENEMY_POS_LAG_INTERVAL;
00613 if ( !index )
00614 {
00615 CalcEntitySpot( NPC->enemy, SPOT_HEAD_LEAN, NPCInfo->enemyLaggedPos[index] );
00616 NPCInfo->enemyLaggedPos[index][2] -= flrand( 2, 16 );
00617 }
00618 else
00619 {
00620 VectorCopy( NPCInfo->enemyLaggedPos[index-1], NPCInfo->enemyLaggedPos[index] );
00621 }
00622 }
00623 }
|