//-----------------------------------------------------------------------------
// 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;
}
Esempio n. 2
0
//-----------------------------------------------------------------------------
// 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();
		}
	}
}