//----------------------------------------------------------------------------- // Purpose: Check the weapon LOS for an owner at an arbitrary position // If bSetConditions is true, LOS related conditions will also be set //----------------------------------------------------------------------------- bool CASW_Weapon::WeaponLOSCondition( const Vector &ownerPos, const Vector &targetPos, bool bSetConditions ) { bool bHasLOS = BaseClass::WeaponLOSCondition(ownerPos, targetPos, bSetConditions); // if the weapon has LOS, then do another wider trace to check we don't hit any friendlies // this is to stop the AI marines shooting way too close to other marines, which stops the player thinking about positioning so much if (bHasLOS && GetOwner() && asw_weapon_safety_hull.GetFloat() > 0) { CAI_BaseNPC* npcOwner = GetOwner()->MyNPCPointer(); Vector vecRelativeShootPosition; VectorSubtract( npcOwner->Weapon_ShootPosition(), npcOwner->GetAbsOrigin(), vecRelativeShootPosition ); // Find its relative shoot position Vector barrelPos = ownerPos + vecRelativeShootPosition; CASWWeaponLOSFilter traceFilter( GetOwner(), npcOwner->GetEnemy(), COLLISION_GROUP_BREAKABLE_GLASS ); // Use the custom LOS trace filter trace_t tr; UTIL_TraceHull( barrelPos, targetPos, Vector(-asw_weapon_safety_hull.GetFloat(), -asw_weapon_safety_hull.GetFloat(), -asw_weapon_safety_hull.GetFloat()), Vector(asw_weapon_safety_hull.GetFloat(), asw_weapon_safety_hull.GetFloat(), asw_weapon_safety_hull.GetFloat()), MASK_SHOT, &traceFilter, &tr ); if ( tr.fraction == 1.0 || tr.m_pEnt == npcOwner->GetEnemy() ) return true; // if a friendly is in the way, then we report failure CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( tr.m_pEnt ); if ( pBCC ) { if ( npcOwner->IRelationType( pBCC ) == D_HT ) return true; if ( bSetConditions ) { npcOwner->SetCondition( COND_WEAPON_BLOCKED_BY_FRIEND ); } return false; } } return bHasLOS; }
//----------------------------------------------------------------------------- // Purpose: Check the weapon LOS for an owner at an arbitrary position // If bSetConditions is true, LOS related conditions will also be set //----------------------------------------------------------------------------- bool CBaseCombatWeapon::WeaponLOSCondition( const Vector &ownerPos, const Vector &targetPos, bool bSetConditions ) { // -------------------- // Check for occlusion // -------------------- CAI_BaseNPC* npcOwner = m_hOwner.Get()->MyNPCPointer(); // Find its relative shoot position Vector vecRelativeShootPosition; VectorSubtract( npcOwner->Weapon_ShootPosition(), npcOwner->GetAbsOrigin(), vecRelativeShootPosition ); Vector barrelPos = ownerPos + vecRelativeShootPosition; // Use the custom LOS trace filter CWeaponLOSFilter traceFilter( m_hOwner.Get(), npcOwner->GetEnemy(), COLLISION_GROUP_BREAKABLE_GLASS ); trace_t tr; UTIL_TraceLine( barrelPos, targetPos, MASK_SHOT, &traceFilter, &tr ); // See if we completed the trace without interruption if ( tr.fraction == 1.0 ) { if ( ai_debug_shoot_positions.GetBool() ) { NDebugOverlay::Line( barrelPos, targetPos, 0, 255, 0, false, 1.0 ); } return true; } CBaseEntity *pHitEnt = tr.m_pEnt; CBasePlayer *pEnemyPlayer = ToBasePlayer( npcOwner->GetEnemy() ); // is player in a vehicle? if so, verify vehicle is target and return if so (so npc shoots at vehicle) if ( pEnemyPlayer && pEnemyPlayer->IsInAVehicle() ) { // Ok, player in vehicle, check if vehicle is target we're looking at, fire if it is // Also, check to see if the owner of the entity is the vehicle, in which case it's valid too. // This catches vehicles that use bone followers. CBaseEntity *pVehicle = pEnemyPlayer->GetVehicle()->GetVehicleEnt(); if ( pHitEnt == pVehicle || pHitEnt->GetOwnerEntity() == pVehicle ) return true; } // Hitting our enemy is a success case if ( pHitEnt == npcOwner->GetEnemy() ) { if ( ai_debug_shoot_positions.GetBool() ) { NDebugOverlay::Line( barrelPos, targetPos, 0, 255, 0, false, 1.0 ); } return true; } // If a vehicle is blocking the view, grab its driver and use that as the combat character CBaseCombatCharacter *pBCC; IServerVehicle *pVehicle = pHitEnt->GetServerVehicle(); if ( pVehicle ) { pBCC = pVehicle->GetPassenger( ); } else { pBCC = ToBaseCombatCharacter( pHitEnt ); } if ( pBCC ) { if ( npcOwner->IRelationType( pBCC ) == D_HT ) return true; if ( bSetConditions ) { npcOwner->SetCondition( COND_WEAPON_BLOCKED_BY_FRIEND ); } } else if ( bSetConditions ) { npcOwner->SetCondition( COND_WEAPON_SIGHT_OCCLUDED ); npcOwner->SetEnemyOccluder( pHitEnt ); if( ai_debug_shoot_positions.GetBool() ) { NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 0, 0, false, 1.0 ); } } return false; }
void CAI_MoveAndShootOverlay::RunShootWhileMove() { if ( m_flNextMoveShootTime == FLT_MAX ) return; CAI_BaseNPC *pOuter = GetOuter(); // keep enemy if dead but try to look for a new one if (!pOuter->GetEnemy() || !pOuter->GetEnemy()->IsAlive()) { CBaseEntity *pNewEnemy = pOuter->BestEnemy(); if( pNewEnemy != NULL ) { //New enemy! Clear the timers and set conditions. pOuter->SetCondition( COND_NEW_ENEMY ); pOuter->SetEnemy( pNewEnemy ); pOuter->SetState( NPC_STATE_COMBAT ); } else { pOuter->ClearAttackConditions(); } // SetEnemy( NULL ); } if ( GetEnemy() == NULL || !pOuter->GetNavigator()->IsGoalActive() ) return; bool bMoveAimAtEnemy = CanAimAtEnemy(); UpdateMoveShootActivity( bMoveAimAtEnemy ); if (bMoveAimAtEnemy) { Assert( pOuter->GetActiveWeapon() ); // This should have been caught at task start // time to fire? if ( pOuter->HasCondition( COND_CAN_RANGE_ATTACK1 ) && gpGlobals->curtime >= m_flNextMoveShootTime ) { if ( m_bMovingAndShooting || GetOuter()->OnBeginMoveAndShoot() ) { m_bMovingAndShooting = true; Activity activity = pOuter->TranslateActivity( ACT_GESTURE_RANGE_ATTACK1 ); Assert( activity != ACT_INVALID ); if (--m_nMoveShots > 0) { pOuter->SetLastAttackTime( gpGlobals->curtime ); pOuter->AddGesture( activity ); // FIXME: this seems a bit wacked pOuter->Weapon_SetActivity( pOuter->Weapon_TranslateActivity( ACT_RANGE_ATTACK1 ), 0 ); m_flNextMoveShootTime = gpGlobals->curtime + pOuter->GetActiveWeapon()->GetFireRate() - 0.1; } else { m_nMoveShots = random->RandomInt( m_minBurst, m_maxBurst ); m_flNextMoveShootTime = gpGlobals->curtime + random->RandomFloat( m_minPause, m_maxPause ); m_bMovingAndShooting = false; GetOuter()->OnEndMoveAndShoot(); } } } // try to keep facing towards the last known position of the enemy Vector vecEnemyLKP = pOuter->GetEnemyLKP(); pOuter->AddFacingTarget( pOuter->GetEnemy(), vecEnemyLKP, 1.0, 0.8 ); } else { if ( m_bMovingAndShooting ) { m_bMovingAndShooting = false; GetOuter()->OnEndMoveAndShoot(); } } }