void NPC_CheckAttackHold(void) { vec3_t vec; // If they don't have an enemy they shouldn't hold their attack anim. if ( !NPC->enemy ) { NPCInfo->attackHoldTime = 0; return; } {//everyone else...? FIXME: need to tie this into AI somehow? VectorSubtract(NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, vec); if( VectorLengthSquared(vec) > NPC_MaxDistSquaredForWeapon() ) { NPCInfo->attackHoldTime = 0; } else if( NPCInfo->attackHoldTime && NPCInfo->attackHoldTime > level.time ) { ucmd.buttons |= BUTTON_ATTACK; } else if ( ( NPCInfo->attackHold ) && ( ucmd.buttons & BUTTON_ATTACK ) ) { NPCInfo->attackHoldTime = level.time + NPCInfo->attackHold; } else { NPCInfo->attackHoldTime = 0; } } }
void NPC_BSSniper_Attack( void ) { //Don't do anything if we're hurt if ( NPC->painDebounceTime > level.time ) { NPC_UpdateAngles( qtrue, qtrue ); return; } //NPC_CheckEnemy( qtrue, qfalse ); //If we don't have an enemy, just idle if ( NPC_CheckEnemyExt() == qfalse )//!NPC->enemy )// { NPC->enemy = NULL; NPC_BSSniper_Patrol();//FIXME: or patrol? return; } if ( TIMER_Done( NPC, "flee" ) && NPC_CheckForDanger( NPC_CheckAlertEvents( qtrue, qtrue, -1, qfalse, AEL_DANGER ) ) ) {//going to run NPC_UpdateAngles( qtrue, qtrue ); return; } if ( !NPC->enemy ) {//WTF? somehow we lost our enemy? NPC_BSSniper_Patrol();//FIXME: or patrol? return; } enemyLOS = enemyCS = qfalse; AImove = qtrue; faceEnemy = qfalse; shoot = qfalse; enemyDist = DistanceSquared( NPC->currentOrigin, NPC->enemy->currentOrigin ); if ( enemyDist < 16384 )//128 squared {//too close, so switch to primary fire if ( NPC->client->ps.weapon == WP_DISRUPTOR ) {//sniping... should be assumed if ( NPCInfo->scriptFlags & SCF_ALT_FIRE ) {//use primary fire trace_t trace; gi.trace ( &trace, NPC->enemy->currentOrigin, NPC->enemy->mins, NPC->enemy->maxs, NPC->currentOrigin, NPC->enemy->s.number, NPC->enemy->clipmask, G2_NOCOLLIDE, 0 ); if ( !trace.allsolid && !trace.startsolid && (trace.fraction == 1.0 || trace.entityNum == NPC->s.number ) ) {//he can get right to me NPCInfo->scriptFlags &= ~SCF_ALT_FIRE; //reset fire-timing variables NPC_ChangeWeapon( WP_DISRUPTOR ); NPC_UpdateAngles( qtrue, qtrue ); return; } } //FIXME: switch back if he gets far away again? } } else if ( enemyDist > 65536 )//256 squared { if ( NPC->client->ps.weapon == WP_DISRUPTOR ) {//sniping... should be assumed if ( !(NPCInfo->scriptFlags&SCF_ALT_FIRE) ) {//use primary fire NPCInfo->scriptFlags |= SCF_ALT_FIRE; //reset fire-timing variables NPC_ChangeWeapon( WP_DISRUPTOR ); NPC_UpdateAngles( qtrue, qtrue ); return; } } } Sniper_UpdateEnemyPos(); //can we see our target? if ( NPC_ClearLOS( NPC->enemy ) )//|| (NPCInfo->stats.aim >= 5 && gi.inPVS( NPC->client->renderInfo.eyePoint, NPC->enemy->currentOrigin )) ) { NPCInfo->enemyLastSeenTime = level.time; VectorCopy( NPC->enemy->currentOrigin, NPCInfo->enemyLastSeenLocation ); enemyLOS = qtrue; float maxShootDist = NPC_MaxDistSquaredForWeapon(); if ( enemyDist < maxShootDist ) { vec3_t fwd, right, up, muzzle, end; trace_t tr; AngleVectors( NPC->client->ps.viewangles, fwd, right, up ); CalcMuzzlePoint( NPC, fwd, right, up, muzzle, 0 ); VectorMA( muzzle, 8192, fwd, end ); gi.trace ( &tr, muzzle, NULL, NULL, end, NPC->s.number, MASK_SHOT, G2_RETURNONHIT, 0 ); int hit = tr.entityNum; //can we shoot our target? if ( Sniper_EvaluateShot( hit ) ) { enemyCS = qtrue; } } } /* else if ( gi.inPVS( NPC->enemy->currentOrigin, NPC->currentOrigin ) ) { NPCInfo->enemyLastSeenTime = level.time; faceEnemy = qtrue; } */ if ( enemyLOS ) {//FIXME: no need to face enemy if we're moving to some other goal and he's too far away to shoot? faceEnemy = qtrue; } if ( enemyCS ) { shoot = qtrue; } else if ( level.time - NPCInfo->enemyLastSeenTime > 3000 ) {//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 Sniper_ResolveBlockedShot(); } //Check for movement to take care of Sniper_CheckMoveState(); //See if we should override shooting decision with any special considerations Sniper_CheckFireState(); if ( AImove ) {//move toward goal if ( NPCInfo->goalEntity )//&& ( NPCInfo->goalEntity != NPC->enemy || enemyDist > 10000 ) )//100 squared { AImove = Sniper_Move(); } else { AImove = qfalse; } } if ( !AImove ) { if ( !TIMER_Done( NPC, "duck" ) ) { if ( TIMER_Done( NPC, "watch" ) ) {//not while watching ucmd.upmove = -127; } } //FIXME: what about leaning? //FIXME: also, when stop ducking, start looking, if enemy can see me, chance of ducking back down again } else {//stop ducking! TIMER_Set( NPC, "duck", -1 ); } if ( TIMER_Done( NPC, "duck" ) && TIMER_Done( NPC, "watch" ) && (TIMER_Get( NPC, "attackDelay" )-level.time) > 1000 && NPC->attackDebounceTime < level.time ) { if ( enemyLOS && (NPCInfo->scriptFlags&SCF_ALT_FIRE) ) { if ( NPC->fly_sound_debounce_time < level.time ) { NPC->fly_sound_debounce_time = level.time + 2000; } } } if ( !faceEnemy ) {//we want to face in the dir we're running if ( AImove ) {//don't run away and shoot NPCInfo->desiredYaw = NPCInfo->lastPathAngles[YAW]; NPCInfo->desiredPitch = 0; shoot = qfalse; } NPC_UpdateAngles( qtrue, qtrue ); } else// if ( faceEnemy ) {//face the enemy Sniper_FaceEnemy(); } if ( NPCInfo->scriptFlags&SCF_DONT_FIRE ) { shoot = qfalse; } //FIXME: don't shoot right away! if ( shoot ) {//try to shoot if it's time if ( TIMER_Done( NPC, "attackDelay" ) ) { WeaponThink( qtrue ); if ( ucmd.buttons&(BUTTON_ATTACK|BUTTON_ALT_ATTACK) ) { G_SoundOnEnt( NPC, CHAN_WEAPON, "sound/null.wav" ); } //took a shot, now hide if ( !(NPC->spawnflags&SPF_NO_HIDE) && !Q_irand( 0, 1 ) ) { //FIXME: do this if in combat point and combat point has duck-type cover... also handle lean-type cover Sniper_StartHide(); } else { TIMER_Set( NPC, "attackDelay", NPCInfo->shotTime-level.time ); } } } }
void NPC_BSHuntAndKill( void ) { qboolean turned = qfalse; vec3_t vec; float enemyDist; visibility_t oEVis; int curAnim; NPC_CheckEnemy( /*NPCInfo->tempBehavior != BS_HUNT_AND_KILL*/qtrue, qfalse, qtrue );//don't find new enemy if this is tempbehav if ( NPC->enemy ) { oEVis = enemyVisibility = NPC_CheckVisibility ( NPC->enemy, CHECK_FOV|CHECK_SHOOT );//CHECK_360|//CHECK_PVS| if(enemyVisibility > VIS_PVS) { if ( !NPC_EnemyTooFar( NPC->enemy, 0, qtrue ) ) {//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 NPC_CheckCanAttack( 1.0, qfalse ); turned = qtrue; } } curAnim = NPC->client->ps.legsAnim; if(curAnim != BOTH_ATTACK1 && curAnim != BOTH_ATTACK2 && curAnim != BOTH_ATTACK3 && curAnim != BOTH_MELEE1 && curAnim != BOTH_MELEE2 ) {//Don't move toward enemy if we're in a full-body attack anim //FIXME, use IdealDistance to determin if we need to close distance VectorSubtract(NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, vec); enemyDist = VectorLength(vec); if( enemyDist > 48 && ((enemyDist*1.5)*(enemyDist*1.5) >= NPC_MaxDistSquaredForWeapon() || oEVis != VIS_SHOOT || //!(ucmd.buttons & BUTTON_ATTACK) || enemyDist > IdealDistance(NPC)*3 ) ) {//We should close in? NPCInfo->goalEntity = NPC->enemy; NPC_MoveToGoal( qtrue ); } else if(enemyDist < IdealDistance(NPC)) {//We should back off? //if(ucmd.buttons & BUTTON_ATTACK) { NPCInfo->goalEntity = NPC->enemy; NPCInfo->goalRadius = 12; NPC_MoveToGoal( qtrue ); ucmd.forwardmove *= -1; ucmd.rightmove *= -1; VectorScale( NPC->client->ps.moveDir, -1, NPC->client->ps.moveDir ); ucmd.buttons |= BUTTON_WALKING; } }//otherwise, stay where we are } } else {//ok, stand guard until we find an enemy if( NPCInfo->tempBehavior == BS_HUNT_AND_KILL ) { NPCInfo->tempBehavior = BS_DEFAULT; } else { NPCInfo->tempBehavior = BS_STAND_GUARD; NPC_BSStandGuard(); } return; } if(!turned) { NPC_UpdateAngles(qtrue, qtrue); } }
void NPC_CheckAttackHold(void) { vector3 vec; // If they don't have an enemy they shouldn't hold their attack anim. if ( !NPC->enemy ) { NPCInfo->attackHoldTime = 0; return; } /* if ( ( NPC->client->ps.weapon == WP_BORG_ASSIMILATOR ) || ( NPC->client->ps.weapon == WP_BORG_DRILL ) ) {//FIXME: don't keep holding this if can't hit enemy? // If they don't have shields ( been disabled) they shouldn't hold their attack anim. if ( !(NPC->NPC->aiFlags & NPCAI_SHIELDS) ) { NPCInfo->attackHoldTime = 0; return; } VectorSubtract(NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, vec); if( VectorLengthSquared(vec) > NPC_MaxDistSquaredForWeapon() ) { NPCInfo->attackHoldTime = 0; PM_SetTorsoAnimTimer(NPC, &NPC->client->ps.torsoAnimTimer, 0); } else if( NPCInfo->attackHoldTime && NPCInfo->attackHoldTime > level.time ) { ucmd.buttons |= BUTTON_ATTACK; } else if ( ( NPCInfo->attackHold ) && ( ucmd.buttons & BUTTON_ATTACK ) ) { NPCInfo->attackHoldTime = level.time + NPCInfo->attackHold; PM_SetTorsoAnimTimer(NPC, &NPC->client->ps.torsoAnimTimer, NPCInfo->attackHold); } else { NPCInfo->attackHoldTime = 0; PM_SetTorsoAnimTimer(NPC, &NPC->client->ps.torsoAnimTimer, 0); } } else*/ {//everyone else...? FIXME: need to tie this into AI somehow? VectorSubtract(&NPC->enemy->r.currentOrigin, &NPC->r.currentOrigin, &vec); if( VectorLengthSquared(&vec) > NPC_MaxDistSquaredForWeapon() ) { NPCInfo->attackHoldTime = 0; } else if( NPCInfo->attackHoldTime && NPCInfo->attackHoldTime > level.time ) { ucmd.buttons |= BUTTON_ATTACK; } else if ( ( NPCInfo->attackHold ) && ( ucmd.buttons & BUTTON_ATTACK ) ) { NPCInfo->attackHoldTime = level.time + NPCInfo->attackHold; } else { NPCInfo->attackHoldTime = 0; } } }