combat/CombatVolume.cs
// CombatVolume.cs
using System;
using System.Collections.Generic;
using Sandbox;
public static class CombatVolume
{
public static T FindBestInCone<T>( Vector3 origin, Vector3 direction, float maxDistance, float coneAngleDegrees, Func<T, bool> filter = null ) where T : Component
{
T bestTarget = null;
var bestScore = -1f;
var halfAngleRad = MathX.DegreeToRadian( coneAngleDegrees * 0.5f );
var cosHalfAngle = MathF.Cos( halfAngleRad );
var dirNorm = direction.Normal;
var maxDistSq = maxDistance * maxDistance;
foreach ( var comp in Game.ActiveScene.GetAllComponents<T>() )
{
if ( !comp.IsValid ) continue;
if ( filter != null && !filter( comp ) ) continue;
var toTarget = comp.WorldPosition - origin;
var distSq = toTarget.LengthSquared;
if ( distSq > maxDistSq || distSq < 0.001f ) continue;
var dist = MathF.Sqrt( distSq );
var dirToTarget = toTarget / dist;
var dot = Vector3.Dot( dirNorm, dirToTarget );
if ( dot < cosHalfAngle ) continue;
var score = dot * (1.0f - (dist / maxDistance) * 0.4f);
if ( score > bestScore )
{
bestScore = score;
bestTarget = comp;
}
}
return bestTarget;
}
}