//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- Vector CNPC_Monk::GetActualShootTrajectory( const Vector &shootOrigin ) { if( GetEnemy() && GetEnemy()->Classify() == CLASS_ZOMBIE ) { Vector vecShootDir; if( m_bPerfectAccuracy || random->RandomInt( 1, monk_headshot_freq.GetInt() ) == 1 ) { vecShootDir = GetEnemy()->HeadTarget( shootOrigin ) - shootOrigin; } else { vecShootDir = GetEnemy()->BodyTarget( shootOrigin ) - shootOrigin; } VectorNormalize( vecShootDir ); return vecShootDir; } return BaseClass::GetActualShootTrajectory( shootOrigin ); }
//----------------------------------------------------------------------------- // Purpose: Fire! //----------------------------------------------------------------------------- void CNPC_CeilingTurret::Shoot( const Vector &vecSrc, const Vector &vecDirToEnemy ) { if ( m_spawnflags & SF_CEILING_TURRET_OUT_OF_AMMO ) { EmitSound( "NPC_FloorTurret.DryFire"); EmitSound( "NPC_CeilingTurret.Activate" ); if ( RandomFloat( 0, 1 ) > 0.7 ) { m_flShotTime = gpGlobals->curtime + random->RandomFloat( 0.5, 1.5 ); } else { m_flShotTime = gpGlobals->curtime; } return; } FireBulletsInfo_t info; if ( GetEnemy() != NULL ) { Vector vecDir = GetActualShootTrajectory( vecSrc ); info.m_vecSrc = vecSrc; info.m_vecDirShooting = vecDir; info.m_iTracerFreq = 1; info.m_iShots = 1; info.m_pAttacker = this; info.m_vecSpread = VECTOR_CONE_PRECALCULATED; info.m_flDistance = MAX_COORD_RANGE; info.m_iAmmoType = m_iAmmoType; } else { // Just shoot where you're facing! Vector vecMuzzle, vecMuzzleDir; QAngle vecMuzzleAng; info.m_vecSrc = vecSrc; info.m_vecDirShooting = vecDirToEnemy; info.m_iTracerFreq = 1; info.m_iShots = 1; info.m_pAttacker = this; info.m_vecSpread = GetAttackSpread( NULL, NULL ); info.m_flDistance = MAX_COORD_RANGE; info.m_iAmmoType = m_iAmmoType; } FireBullets( info ); EmitSound( "NPC_CeilingTurret.ShotSounds" ); DoMuzzleFlash(); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- int CNPC_Crow::DrawDebugTextOverlays( void ) { int nOffset = BaseClass::DrawDebugTextOverlays(); if (m_debugOverlays & OVERLAY_TEXT_BIT) { char tempstr[512]; Q_snprintf( tempstr, sizeof( tempstr ), "morale: %d", m_nMorale ); EntityText( nOffset, tempstr, 0 ); nOffset++; if ( GetEnemy() != NULL ) { Q_snprintf( tempstr, sizeof( tempstr ), "enemy (dist): %s (%g)", GetEnemy()->GetClassname(), ( double )m_flEnemyDist ); EntityText( nOffset, tempstr, 0 ); nOffset++; } } return nOffset; }
// here bot updates important info that is used multiple times along the thinking process void CSDKBot::InfoGathering() { if (!GetEnemy()) { m_flBotToEnemyDist = 9999; m_flHeightDifToEnemy = 0; m_bEnemyOnSights = false; m_flDistTraveled += fabs(GetLocalVelocity().Length()); // this is used for stuck checking, return; } m_flBotToEnemyDist = (GetLocalOrigin() - GetEnemy()->GetLocalOrigin()).Length(); trace_t tr; UTIL_TraceHull( EyePosition(), GetEnemy()->EyePosition() - Vector(0,0,20), -BotTestHull, BotTestHull, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); if( tr.m_pEnt == GetEnemy() ) // vision line between both m_bEnemyOnSights = true; else m_bEnemyOnSights = false; m_bInRangeToAttack = (m_flBotToEnemyDist < m_flMinRangeAttack) && FInViewCone( GetEnemy() ); m_flDistTraveled += fabs(GetLocalVelocity().Length()); // this is used for stuck checking, m_flHeightDifToEnemy = GetLocalOrigin().z - GetEnemy()->GetLocalOrigin().z; }
void CNPC_Stalker::UpdateAttackBeam( void ) { CBaseEntity *pEnemy = GetEnemy(); // If not burning at a target if (pEnemy) { if (gpGlobals->curtime > m_fBeamEndTime) { TaskComplete(); } else { Vector enemyLKP = GetEnemyLKP(); m_vLaserTargetPos = enemyLKP + pEnemy->GetViewOffset(); // Face my enemy GetMotor()->SetIdealYawToTargetAndUpdate( enemyLKP ); // --------------------------------------------- // Get beam end point // --------------------------------------------- Vector vecSrc = LaserStartPosition(GetAbsOrigin()); Vector targetDir = m_vLaserTargetPos - vecSrc; VectorNormalize(targetDir); // -------------------------------------------------------- // If beam position and laser dir are way off, end attack // -------------------------------------------------------- if ( DotProduct(targetDir,m_vLaserDir) < 0.5 ) { TaskComplete(); return; } trace_t tr; AI_TraceLine( vecSrc, vecSrc + m_vLaserDir * MAX_STALKER_FIRE_RANGE, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr); // --------------------------------------------- // If beam not long enough, stop attacking // --------------------------------------------- if (tr.fraction == 1.0) { TaskComplete(); return; } CSoundEnt::InsertSound(SOUND_DANGER, tr.endpos, 60, 0.025, this); } } else { TaskFail(FAIL_NO_ENEMY); } }
//========================================================= // RunAI //========================================================= void CBaseMonster :: RunAI ( void ) { // to test model's eye height //UTIL_ParticleEffect ( pev->origin + pev->view_ofs, g_vecZero, 255, 10 ); // IDLE sound permitted in ALERT state is because monsters were silent in ALERT state. Only play IDLE sound in IDLE state // once we have sounds for that state. if ( ( m_MonsterState == MONSTERSTATE_IDLE || m_MonsterState == MONSTERSTATE_ALERT ) && RANDOM_LONG(0,99) == 0 && !(pev->flags & SF_MONSTER_GAG) ) { IdleSound(); } if ( m_MonsterState != MONSTERSTATE_NONE && m_MonsterState != MONSTERSTATE_PRONE && m_MonsterState != MONSTERSTATE_DEAD )// don't bother with this crap if monster is prone. { // collect some sensory Condition information. // don't let monsters outside of the player's PVS act up, or most of the interesting // things will happen before the player gets there! // UPDATE: We now let COMBAT state monsters think and act fully outside of player PVS. This allows the player to leave // an area where monsters are fighting, and the fight will continue. if ( !FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) || ( m_MonsterState == MONSTERSTATE_COMBAT ) ) { Look( m_flDistLook ); Listen();// check for audible sounds. // now filter conditions. ClearConditions( IgnoreConditions() ); GetEnemy(); } // do these calculations if monster has an enemy. if ( m_hEnemy != NULL ) { CheckEnemy( m_hEnemy ); } CheckAmmo(); } FCheckAITrigger(); PrescheduleThink(); MaintainSchedule(); // if the monster didn't use these conditions during the above call to MaintainSchedule() or CheckAITrigger() // we throw them out cause we don't want them sitting around through the lifespan of a schedule // that doesn't use them. m_afConditions &= ~( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ); }
//----------------------------------------------------------------------------- // Purpose: Handles movement towards the last move target. // Input : flInterval - //----------------------------------------------------------------------------- bool CNPC_Controller::OverridePathMove( float flInterval ) { CBaseEntity *pMoveTarget = (GetTarget()) ? GetTarget() : GetEnemy(); Vector waypointDir = GetNavigator()->GetCurWaypointPos() - GetLocalOrigin(); float flWaypointDist = waypointDir.Length2D(); VectorNormalize(waypointDir); // cut corner? if (flWaypointDist < 128) { if (m_flGroundSpeed > 100) m_flGroundSpeed -= 40; } else { if (m_flGroundSpeed < 400) m_flGroundSpeed += 10; } m_velocity = m_velocity * 0.8 + m_flGroundSpeed * waypointDir * 0.5; SetAbsVelocity( m_velocity ); // ----------------------------------------------------------------- // Check route is blocked // ------------------------------------------------------------------ Vector checkPos = GetLocalOrigin() + (waypointDir * (m_flGroundSpeed * flInterval)); AIMoveTrace_t moveTrace; GetMoveProbe()->MoveLimit( NAV_FLY, GetLocalOrigin(), checkPos, MASK_NPCSOLID|CONTENTS_WATER, pMoveTarget, &moveTrace); if (IsMoveBlocked( moveTrace )) { TaskFail(FAIL_NO_ROUTE); GetNavigator()->ClearGoal(); return true; } // ---------------------------------------------- Vector lastPatrolDir = GetNavigator()->GetCurWaypointPos() - GetLocalOrigin(); if ( ProgressFlyPath( flInterval, pMoveTarget, MASK_NPCSOLID, false, 64 ) == AINPP_COMPLETE ) { { m_vLastPatrolDir = lastPatrolDir; VectorNormalize(m_vLastPatrolDir); } return true; } return false; }
bool CNPC_Zombine::AllowedToSprint( void ) { if ( IsOnFire() ) return false; //If you're sprinting then there's no reason to sprint again. if ( IsSprinting() ) return false; int iChance = SPRINT_CHANCE_VALUE; CHL2_Player *pPlayer = dynamic_cast <CHL2_Player*> ( AI_GetSinglePlayer() ); if ( pPlayer ) { if ( HL2GameRules()->IsAlyxInDarknessMode() && pPlayer->FlashlightIsOn() == false ) { iChance = SPRINT_CHANCE_VALUE_DARKNESS; } //Bigger chance of this happening if the player is not looking at the zombie if ( pPlayer->FInViewCone( this ) == false ) { iChance *= 2; } } if ( HasGrenade() ) { iChance *= 4; } //Below 25% health they'll always sprint if ( ( GetHealth() > GetMaxHealth() * 0.5f ) ) { if ( IsStrategySlotRangeOccupied( SQUAD_SLOT_ZOMBINE_SPRINT1, SQUAD_SLOT_ZOMBINE_SPRINT2 ) == true ) return false; if ( random->RandomInt( 0, 100 ) > iChance ) return false; if ( m_flSprintRestTime > gpGlobals->curtime ) return false; } float flLength = ( GetEnemy()->WorldSpaceCenter() - WorldSpaceCenter() ).Length(); if ( flLength > MAX_SPRINT_DISTANCE ) return false; return true; }
//------------------------------------------------------------------------------ // Purpose : For innate range attack // Input : // Output : //------------------------------------------------------------------------------ int CNPC_Vortigaunt::RangeAttack1Conditions( float flDot, float flDist ) { if ( GetEnemy() == NULL ) return( COND_LOST_ENEMY ); if ( gpGlobals->curtime < m_flNextAttack ) return COND_NONE; if ( HasCondition( COND_CAN_MELEE_ATTACK1 ) ) return COND_NONE; return COND_CAN_RANGE_ATTACK1; }
//----------------------------------------------------------------------------- // Purpose: // Input : flDot - // flDist - // Output : int //----------------------------------------------------------------------------- int CNPC_AntlionGrub::MeleeAttack1Conditions( float flDot, float flDist ) { ClearCondition( COND_ANTLIONGRUB_IN_HEAL_RANGE ); //If we're outside the heal range, then reset our timer if ( flDist > ANTLIONGRUB_HEAL_RANGE ) { m_flNearTime = gpGlobals->curtime + 2.0f; return COND_TOO_FAR_TO_ATTACK; } //Otherwise if we've been in range for long enough signal it if ( m_flNearTime < gpGlobals->curtime ) { if ( ( m_nHealthReserve > 0 ) && ( GetEnemy()->m_iHealth < GetEnemy()->m_iMaxHealth ) ) { SetCondition( COND_ANTLIONGRUB_IN_HEAL_RANGE ); } } return COND_CAN_MELEE_ATTACK1; }
//========================================================= // TakeDamage - overridden for bullsquid so we can keep track // of how much time has passed since it was last injured //========================================================= int CNPC_Bullsquid::OnTakeDamage_Alive( const CTakeDamageInfo &inputInfo ) { #if 0 //Fix later. float flDist; Vector vecApex, vOffset; // if the squid is running, has an enemy, was hurt by the enemy, hasn't been hurt in the last 3 seconds, and isn't too close to the enemy, // it will swerve. (whew). if ( GetEnemy() != NULL && IsMoving() && pevAttacker == GetEnemy() && gpGlobals->curtime - m_flLastHurtTime > 3 ) { flDist = ( GetAbsOrigin() - GetEnemy()->GetAbsOrigin() ).Length2D(); if ( flDist > SQUID_SPRINT_DIST ) { AI_Waypoint_t* pRoute = GetNavigator()->GetPath()->Route(); if ( pRoute ) { flDist = ( GetAbsOrigin() - pRoute[ pRoute->iNodeID ].vecLocation ).Length2D();// reusing flDist. if ( GetNavigator()->GetPath()->BuildTriangulationRoute( GetAbsOrigin(), pRoute[ pRoute->iNodeID ].vecLocation, flDist * 0.5, GetEnemy(), &vecApex, &vOffset, NAV_GROUND ) ) { GetNavigator()->PrependWaypoint( vecApex, bits_WP_TO_DETOUR | bits_WP_DONT_SIMPLIFY ); } } } } #endif if ( !FClassnameIs ( inputInfo.GetAttacker(), "monster_headcrab" ) ) { // don't forget about headcrabs if it was a headcrab that hurt the squid. m_flLastHurtTime = gpGlobals->curtime; } return BaseClass::OnTakeDamage_Alive ( inputInfo ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CAI_AssaultBehavior::IsAllowedToDivert( void ) { if ( m_hAssaultPoint && m_hAssaultPoint->m_bAllowDiversion ) { if ( m_hAssaultPoint->m_flAllowDiversionRadius == 0.0f || (m_bHitAssaultPoint && GetEnemy() != NULL && GetEnemy()->GetAbsOrigin().DistToSqr(m_hAssaultPoint->GetAbsOrigin()) <= Square(m_hAssaultPoint->m_flAllowDiversionRadius)) ) { if ( m_flLastSawAnEnemyAt && ((gpGlobals->curtime - m_flLastSawAnEnemyAt) < ASSAULT_DIVERSION_TIME) ) return true; } } return false; }
int CASW_Harvester::TranslateSchedule( int scheduleType ) { if ( scheduleType == SCHED_RANGE_ATTACK1 ) { RemoveAllGestures(); return SCHED_ASW_HARVESTER_LAY_CRITTER; } if ( scheduleType == SCHED_COMBAT_FACE && IsUnreachable( GetEnemy() ) ) return SCHED_TAKE_COVER_FROM_ENEMY; return BaseClass::TranslateSchedule( scheduleType ); }
//========================================================= // CheckMeleeAttack1 - alien grunts zap the crap out of // any enemy that gets too close. //========================================================= int CNPC_AlienGrunt::MeleeAttack1Conditions ( float flDot, float flDist ) { if ( flDist > AGRUNT_MELEE_DIST ) return COND_NONE; if ( flDot < 0.6 ) return COND_NONE; if ( HasCondition ( COND_SEE_ENEMY ) && GetEnemy() != NULL ) return COND_CAN_MELEE_ATTACK1; return COND_NONE; }
//----------------------------------------------------------------------------- // Purpose: // Input : flDot - // flDist - // Output : int CNPC_Assassin::MeleeAttack1Conditions //----------------------------------------------------------------------------- int CNPC_Assassin::MeleeAttack1Conditions ( float flDot, float flDist ) { if ( flDist > 84 ) return COND_TOO_FAR_TO_ATTACK; if ( flDot < 0.7f ) return 0; if ( GetEnemy() == NULL ) return 0; return COND_CAN_MELEE_ATTACK1; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CUnitBase::AimGun() { if( GetEnemy() ) { Vector vecShootOrigin = Weapon_ShootPosition(); Vector vecShootDir = GetShootEnemyDir( vecShootOrigin, false ); SetAim(vecShootDir); } else { RelaxAim(); } }
//========================================================= // Start task - selects the correct activity and performs // any necessary calculations to start the next task on the // schedule. OVERRIDDEN for bullsquid because it needs to // know explicitly when the last attempt to chase the enemy // failed, since that impacts its attack choices. //========================================================= void CNPC_Bullsquid::StartTask ( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_MELEE_ATTACK2: { CPASAttenuationFilter filter( this ); EmitSound( filter, entindex(), "Bullsquid.Growl" ); BaseClass::StartTask ( pTask ); break; } case TASK_SQUID_HOPTURN: { SetActivity ( ACT_HOP ); if ( GetEnemy() ) { Vector vecFacing = ( GetEnemy()->GetAbsOrigin() - GetAbsOrigin() ); VectorNormalize( vecFacing ); GetMotor()->SetIdealYaw( vecFacing ); } break; } case TASK_SQUID_EAT: { m_flHungryTime = gpGlobals->curtime + pTask->flTaskData; break; } default: { BaseClass::StartTask ( pTask ); break; } } }
int CNPC_HL1Barney::OnTakeDamage_Alive( const CTakeDamageInfo &inputInfo ) { // make sure friends talk about it if player hurts talkmonsters... int ret = BaseClass::OnTakeDamage_Alive( inputInfo ); if ( !IsAlive() || m_lifeState == LIFE_DYING ) return ret; if ( m_NPCState != NPC_STATE_PRONE && ( inputInfo.GetAttacker()->GetFlags() & FL_CLIENT ) ) { // This is a heurstic to determine if the player intended to harm me // If I have an enemy, we can't establish intent (may just be crossfire) if ( GetEnemy() == NULL ) { // If the player was facing directly at me, or I'm already suspicious, get mad if ( HasMemory( bits_MEMORY_SUSPICIOUS ) || IsFacing( inputInfo.GetAttacker(), GetAbsOrigin() ) ) { // Alright, now I'm pissed! Speak( BA_MAD ); Remember( bits_MEMORY_PROVOKED ); StopFollowing(); } else { // Hey, be careful with that Speak( BA_SHOT ); Remember( bits_MEMORY_SUSPICIOUS ); } } else if ( !(GetEnemy()->IsPlayer()) && m_lifeState == LIFE_ALIVE ) { Speak( BA_SHOT ); } } return ret; }
bool rvMonsterStroggHover::MarkerPosValid ( void ) { //debouncer ftw if( markerCheckTime > gameLocal.GetTime() ) { return true; } markerCheckTime = gameLocal.GetTime() + 500 + (gameLocal.random.RandomFloat() * 500); trace_t trace; gameLocal.TracePoint( this, trace, marker.GetEntity()->GetPhysics()->GetOrigin(), marker.GetEntity()->GetPhysics()->GetOrigin(), GetPhysics()->GetClipMask(), NULL ); if ( !(trace.c.contents&GetPhysics()->GetClipMask()) ) {//not in solid gameLocal.TracePoint( this, trace, marker.GetEntity()->GetPhysics()->GetOrigin(), GetEnemy()->GetEyePosition(), MASK_SHOT_BOUNDINGBOX, GetEnemy() ); idActor* enemyAct = NULL; rvVehicle* enemyVeh = NULL; if ( GetEnemy()->IsType( rvVehicle::GetClassType() ) ) { enemyVeh = static_cast<rvVehicle*>(GetEnemy()); } else if ( GetEnemy()->IsType( idActor::GetClassType() ) ) { enemyAct = static_cast<idActor*>(GetEnemy()); } idEntity* hitEnt = gameLocal.entities[trace.c.entityNum]; idActor* hitAct = NULL; if ( hitEnt && hitEnt->IsType( idActor::GetClassType() ) ) { hitAct = static_cast<idActor*>(hitEnt); } if ( trace.fraction >= 1.0f || (enemyAct && enemyAct->IsInVehicle() && enemyAct->GetVehicleController().GetVehicle() == gameLocal.entities[trace.c.entityNum]) || (enemyVeh && hitAct && hitAct->IsInVehicle() && hitAct->GetVehicleController().GetVehicle() == enemyVeh) ) {//have a clear LOS to enemy if ( PointReachableAreaNum( marker.GetEntity()->GetPhysics()->GetOrigin() ) ) {//valid AAS there... return true; } } } return false; }
//----------------------------------------------------------------------------- // Purpose: Causes the assassin to prefer to run away, rather than towards her target //----------------------------------------------------------------------------- bool CNPC_Assassin::MovementCost( int moveType, const Vector &vecStart, const Vector &vecEnd, float *pCost ) { if ( GetEnemy() == NULL ) return true; float multiplier = 1.0f; Vector moveDir = ( vecEnd - vecStart ); VectorNormalize( moveDir ); Vector enemyDir = ( GetEnemy()->GetAbsOrigin() - vecStart ); VectorNormalize( enemyDir ); // If we're moving towards our enemy, then the cost is much higher than normal if ( DotProduct( enemyDir, moveDir ) > 0.5f ) { multiplier = 16.0f; } *pCost *= multiplier; return ( multiplier != 1 ); }
//------------------------------------------------------------------------------ // Purpose: determines if we can use this behavior currently // Output : returns true if this behavior is able to run //------------------------------------------------------------------------------ bool CAI_ASW_PrepareToEngageBehavior::CanSelectSchedule() { if ( !GetOuter()->IsInterruptable() ) return false; if ( GetEnemy() == NULL ) return false; if ( GetEnemy()->Classify() != CLASS_ASW_MARINE ) return false; // don't select this schedule if we're in a target slot and can actually attack //CASW_Marine *pMarine = assert_cast<CASW_Marine*>( GetEnemy() ); //CASW_Alien *pAlien = assert_cast<CASW_Alien*>( GetOuter() ); //if ( pMarine->IsInTargetSlot( pAlien, pAlien->GetTargetSlotType() ) ) //return false; // TODO: Do we want to grab a target slot here? This assumes our attack/chase schedules are higher priority than anything else below us... //if ( pMarine->OccupyTargetSlot( pAlien, pAlien->GetTargetSlotType() ) ) //return false; return BaseClass::CanSelectSchedule(); }
//----------------------------------------------------------------------------- // Purpose: override/translate a schedule by type // Input : Type - schedule type // Output : int - translated type //----------------------------------------------------------------------------- int CNPC_Bug_Warrior::TranslateSchedule( int scheduleType ) { if ( scheduleType == SCHED_CHASE_ENEMY ) { // Tell my squad that I'm attacking this guy if ( m_pSquad ) { m_pSquad->BroadcastInteraction( g_interactionBugSquadAttacking, (void *)GetEnemy(), this ); } return SCHED_WBUG_CHASE_ENEMY; } return BaseClass::TranslateSchedule(scheduleType); }
//----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CAI_AssaultBehavior::CanSelectSchedule() { if ( !GetOuter()->IsInterruptable() ) return false; if ( GetOuter()->HasCondition( COND_RECEIVED_ORDERS ) ) return false; // We're letting other AI run for a little while because the assault AI failed recently. if ( m_flTimeDeferScheduleSelection > gpGlobals->curtime ) return false; // No schedule selection if no assault is being conducted. if( m_AssaultCue == CUE_NO_ASSAULT ) return false; if ( !m_hAssaultPoint || !m_hRallyPoint ) { Disable(); return false; } // Remember when we last saw an enemy if ( GetEnemy() ) { m_flLastSawAnEnemyAt = gpGlobals->curtime; } // If we've seen an enemy in the last few seconds, and we're allowed to divert, // let the base AI decide what I should do. if ( IsAllowedToDivert() ) { // Return true, but remember that we're actually allowing them to divert // This is done because we don't want the assault behaviour to think it's finished with the assault. m_bDiverting = true; } else if ( m_bDiverting ) { // If we were diverting, provoke us to make a new schedule selection SetCondition( COND_PROVOKED ); m_bDiverting = false; } // If we're diverting, let the base AI decide everything if ( m_bDiverting ) return false; return true; }
//------------------------------------------------------------------------------ // Purpose: //------------------------------------------------------------------------------ bool CAI_ASW_RangedAttackBehavior::FindFiringLocation( ) { CBaseEntity *pBestEnt = NULL; float flBestDistSq = FLT_MAX; AIEnemiesIter_t iter; CBaseEntity *pEnemy; pEnemy = GetEnemy(); if ( pEnemy && pEnemy->IsAlive() && GetOuter()->FVisible( pEnemy ) ) { m_hTarget = pEnemy; UpdateTargetLocation(); return true; } for( AI_EnemyInfo_t *pEMemory = GetEnemies()->GetFirst( &iter ); pEMemory != NULL; pEMemory = GetEnemies()->GetNext( &iter ) ) { pEnemy = pEMemory->hEnemy; if ( !pEnemy || !pEnemy->IsAlive() || !GetOuter()->FVisible( pEnemy ) ) { continue; } Vector vDelta = GetAbsOrigin() - pEnemy->GetAbsOrigin(); float flLenSq = vDelta.LengthSqr(); if ( flLenSq <= flBestDistSq ) { pBestEnt = pEnemy; flBestDistSq = flLenSq; } } if ( !pBestEnt ) { // just try shooting at our enemy for now if ( pEnemy && pEnemy->IsAlive() ) { UpdateTargetLocation(); return true; } return false; } m_hTarget = pBestEnt; GetOuter()->SetEnemy( pBestEnt ); UpdateTargetLocation(); return true; }
/* ================ rvMonsterStroggMarine::CheckAction_SprayAttack ================ */ bool rvMonsterStroggMarine::CheckAction_SprayAttack ( rvAIAction* action, int animNum ) { if ( !enemy.ent || !enemy.fl.inFov ) { return false; } if ( !IsEnemyRecentlyVisible ( ) || enemy.ent->DistanceTo ( enemy.lastKnownPosition ) > 128.0f ) { return false; } if ( GetEnemy()->GetPhysics()->GetLinearVelocity().Compare( vec3_origin ) ) {//not moving return false; } return true; }
void CTibia::ShootMagwall(int nTarget, int nSqm) { SCreature *c = 0; switch(nTarget) { case HotkeyCreature::Self: c = (SCreature*)GetPlayer(); break; case HotkeyCreature::Target: if(PlayerTarget == 0) return; c = (SCreature*)GetPlayer(PlayerTarget, true); break; case HotkeyCreature::Friend: c = (SCreature*)GetFriend(100); break; case HotkeyCreature::Enemy: c = (SCreature*)GetEnemy(100); break; } SContainerInfo cInfo; if(c > 0) { int x = c->X, y = c->Y; switch(c->Direction) { case Direction::North: y = y - nSqm; break; case Direction::East: x = x + nSqm; break; case Direction::South: y = y + nSqm; break; case Direction::West: x = x - nSqm; break; } if(bShootFromClosedBp == true) { CPacket::UseOnXYZ(Items::MagicwallRune, 0, 0, x, y, c->Z); } else if(FindItem(Items::MagicwallRune, &cInfo) == true) { CPacket::UseOnXYZ(Items::MagicwallRune, 0x40 + cInfo.Container, cInfo.Position, x, y, c->Z); } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CNPC_RocketTurret::SearchThink() { if ( PreThink() || GetEnemy() == NULL ) return; SetSequence ( LookupSequence( "idle" ) ); UpdateAimPoint(); //Update our think time SetNextThink( gpGlobals->curtime + ROCKET_TURRET_THINK_RATE ); // Still can't see enemy, zip around frantically if ( !m_bHasSightOfEnemy ) { if ( m_flTimeSpentPaused >= m_flPauseLength ) { float flOffsetX = RandomFloat( -5.0f, 5.0f ); float flOffsetY = RandomFloat( -5.0f, 5.0f ); if ( fabs(m_flTotalDivergenceX) <= MAX_DIVERGENCE_X || SignDiffers( m_flTotalDivergenceX, flOffsetX ) ) { m_flTotalDivergenceX += flOffsetX; m_vecGoalAngles.x += flOffsetX; } if ( fabs(m_flTotalDivergenceY) <= MAX_DIVERGENCE_Y || SignDiffers( m_flTotalDivergenceY, flOffsetY ) ) { m_flTotalDivergenceY += flOffsetY; m_vecGoalAngles.y += flOffsetY; } // Reset pause timer m_flTimeSpentPaused = 0.0f; m_flPauseLength = RandomFloat( 0.3f, 2.5f ); } m_flTimeSpentPaused += ROCKET_TURRET_THINK_RATE; } else { // Found target, go back to following it SetThink( &CNPC_RocketTurret::FollowThink ); SetNextThink( gpGlobals->curtime + ROCKET_TURRET_THINK_RATE ); } // Move beam towards goal angles UpdateFacing(); }
//----------------------------------------------------------------------------- // Purpose: // Input : *pTask - //----------------------------------------------------------------------------- void CAI_RappelBehavior::RunTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_RAPPEL: { // If we don't do this, the beam won't show up sometimes. Ideally, all beams would update their // bboxes correctly, but we're close to shipping and we can't change that now. if ( m_hLine ) { m_hLine->RelinkBeam(); } if( GetEnemy() ) { // Face the enemy if there's one. Vector vecEnemyLKP = GetEnemyLKP(); GetOuter()->GetMotor()->SetIdealYawToTargetAndUpdate( vecEnemyLKP ); } SetDescentSpeed(); if( GetOuter()->GetFlags() & FL_ONGROUND ) { CBaseEntity *pGroundEnt = GetOuter()->GetGroundEntity(); if( pGroundEnt && pGroundEnt->IsPlayer() ) { // try to shove the player in the opposite direction as they are facing (so they'll see me) Vector vecForward; pGroundEnt->GetVectors( &vecForward, NULL, NULL ); pGroundEnt->SetAbsVelocity( vecForward * -500 ); break; } GetOuter()->m_OnRappelTouchdown.FireOutput( GetOuter(), GetOuter(), 0 ); GetOuter()->RemoveFlag( FL_FLY ); CutZipline(); TaskComplete(); } } break; default: BaseClass::RunTask( pTask ); break; } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- Activity CNPC_Monk::NPC_TranslateActivity( Activity eNewActivity ) { eNewActivity = BaseClass::NPC_TranslateActivity( eNewActivity ); if ( (m_NPCState == NPC_STATE_COMBAT || m_NPCState == NPC_STATE_ALERT) ) { bool bGunUp = false; bGunUp = (gpGlobals->curtime - m_flLastAttackTime < 4); bGunUp = bGunUp || (GetEnemy() && !HasCondition( COND_TOO_FAR_TO_ATTACK )); if (bGunUp) { if ( eNewActivity == ACT_IDLE ) { eNewActivity = ACT_IDLE_ANGRY; } // keep aiming a little longer than normal since the shot takes so long and there's no good way to do a transitions between movement types :/ else if ( eNewActivity == ACT_WALK ) { eNewActivity = ACT_WALK_AIM; } else if ( eNewActivity == ACT_RUN ) { eNewActivity = ACT_RUN_AIM; } } } // We need these so that we can pick up the shotgun to throw it in the balcony scene if ( eNewActivity == ACT_IDLE_ANGRY_SHOTGUN ) { eNewActivity = ACT_IDLE_ANGRY_SMG1; } else if ( eNewActivity == ACT_WALK_AIM_SHOTGUN ) { eNewActivity = ACT_WALK_AIM_RIFLE; } else if ( eNewActivity == ACT_RUN_AIM_SHOTGUN ) { eNewActivity = ACT_RUN_AIM_RIFLE; } else if ( eNewActivity == ACT_RANGE_ATTACK_SHOTGUN_LOW ) { return ACT_RANGE_ATTACK_SMG1_LOW; } return eNewActivity; }
//----------------------------------------------------------------------------- // Purpose: The turret doesn't run base AI properly, which is a bad decision. // As a result, it has to manually find enemies. //----------------------------------------------------------------------------- void CNPC_Portal_FloorTurret::HackFindEnemy( void ) { // We have to refresh our memories before finding enemies, so // dead enemies are cleared out before new ones are added. GetEnemies()->RefreshMemories(); GetSenses()->Look( PORTAL_FLOOR_TURRET_RANGE ); SetEnemy( BestEnemy() ); if ( GetEnemy() == NULL ) { // Look through the list of sensed objects for possible targets AISightIter_t iter; CBaseEntity *pObject; CBaseEntity *pNearest = NULL; float flClosestDistSqr = PORTAL_FLOOR_TURRET_RANGE * PORTAL_FLOOR_TURRET_RANGE; for ( pObject = GetSenses()->GetFirstSeenEntity( &iter, SEEN_MISC ); pObject; pObject = GetSenses()->GetNextSeenEntity( &iter ) ) { Vector vVelocity; pObject->GetVelocity( &vVelocity ); // Ignore objects going too slowly if ( vVelocity.LengthSqr() < m_fMovingTargetThreashold ) continue; float flDistSqr = pObject->WorldSpaceCenter().DistToSqr( GetAbsOrigin() ); if ( flDistSqr < flClosestDistSqr ) { flClosestDistSqr = flDistSqr; pNearest = pObject; } } if ( pNearest ) { SetEnemy( pNearest ); m_fMovingTargetThreashold += gpGlobals->curtime * 15.0f; if ( m_fMovingTargetThreashold > 800.0f ) { m_fMovingTargetThreashold = 800.0f; } } } else { m_fMovingTargetThreashold = 20.0f; } }