mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-01-02 19:38:24 -05:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
154 lines
4.0 KiB
C#
154 lines
4.0 KiB
C#
namespace Sandbox;
|
|
|
|
/// <summary>
|
|
/// Applies damage in a radius, with physics force, and optional occlusion
|
|
/// </summary>
|
|
[Category( "Game" ), Icon( "flare" ), EditorHandle( Icon = "💥" )]
|
|
public sealed class RadiusDamage : Component
|
|
{
|
|
/// <summary>
|
|
/// Should the world shield victims from damage?
|
|
/// </summary>
|
|
[Property]
|
|
public float Radius { get; set; } = 512;
|
|
|
|
/// <summary>
|
|
/// How much physics force should be applied on explosion?
|
|
/// </summary>
|
|
[Property]
|
|
public float PhysicsForceScale { get; set; } = 1;
|
|
|
|
/// <summary>
|
|
/// If enabled we'll apply damage once as soon as enabled
|
|
/// </summary>
|
|
[Property]
|
|
public bool DamageOnEnabled { get; set; } = true;
|
|
|
|
/// <summary>
|
|
/// Should the world shield victims from damage?
|
|
/// </summary>
|
|
[Property]
|
|
public bool Occlusion { get; set; } = true;
|
|
|
|
/// <summary>
|
|
/// The amount of damage inflicted
|
|
/// </summary>
|
|
[Property]
|
|
public float DamageAmount { get; set; } = 100;
|
|
|
|
/// <summary>
|
|
/// Tags to apply to the damage
|
|
/// </summary>
|
|
[Property]
|
|
public TagSet DamageTags { get; set; } = new TagSet();
|
|
|
|
/// <summary>
|
|
/// Who should we credit with this attack?
|
|
/// </summary>
|
|
[Property]
|
|
public GameObject Attacker { get; set; }
|
|
|
|
protected override void OnEnabled()
|
|
{
|
|
base.OnEnabled();
|
|
|
|
if ( DamageOnEnabled )
|
|
{
|
|
Apply();
|
|
}
|
|
}
|
|
|
|
protected override void DrawGizmos()
|
|
{
|
|
if ( !Gizmo.IsSelected )
|
|
return;
|
|
|
|
Gizmo.Draw.LineSphere( new Sphere( 0, Radius ), 16 );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Apply the damage now
|
|
/// </summary>
|
|
public void Apply()
|
|
{
|
|
var sphere = new Sphere( WorldPosition, Radius );
|
|
|
|
var dmg = new DamageInfo();
|
|
dmg.Weapon = GameObject;
|
|
dmg.Damage = DamageAmount;
|
|
dmg.Tags.Add( DamageTags );
|
|
dmg.Attacker = Attacker;
|
|
|
|
ApplyDamage( sphere, dmg, PhysicsForceScale );
|
|
}
|
|
|
|
public static void ApplyDamage( Sphere sphere, DamageInfo damage, float physicsForce = 1, GameObject ignore = null )
|
|
{
|
|
var scene = Game.ActiveScene;
|
|
if ( !scene.IsValid() ) return;
|
|
|
|
var point = sphere.Center;
|
|
var damageAmount = damage.Damage;
|
|
var objectsInArea = scene.FindInPhysics( sphere );
|
|
|
|
var losTrace = scene.Trace.WithTag( "map" ).WithoutTags( "trigger", "gib", "debris", "player" );
|
|
|
|
foreach ( var rb in objectsInArea.SelectMany( x => x.GetComponents<Rigidbody>() ).Distinct() )
|
|
{
|
|
if ( rb.IsProxy ) continue;
|
|
if ( !rb.MotionEnabled ) continue;
|
|
|
|
if ( ignore.IsValid() && ignore.IsDescendant( rb.GameObject ) )
|
|
continue;
|
|
|
|
// If the object isn't in line of sight, fuck it off
|
|
var tr = losTrace.Ray( point, rb.WorldPosition ).Run();
|
|
if ( tr.Hit && tr.GameObject.IsValid() )
|
|
{
|
|
if ( !rb.GameObject.Root.IsDescendant( tr.GameObject ) )
|
|
continue;
|
|
}
|
|
|
|
var dir = (rb.WorldPosition - point).Normal;
|
|
var distance = rb.WorldPosition.Distance( sphere.Center );
|
|
|
|
var forceMagnitude = Math.Clamp( 10000000000f / (distance * distance + 1), 0, 10000000000f );
|
|
forceMagnitude += physicsForce * (1 - (distance / sphere.Radius));
|
|
|
|
rb.ApplyForceAt( point, dir * forceMagnitude );
|
|
}
|
|
|
|
foreach ( var damageable in objectsInArea.SelectMany( x => x.GetComponentsInParent<Component.IDamageable>().Distinct() ) )
|
|
{
|
|
// no proxy checks needed, it's up to the OnDamage call to filter
|
|
|
|
var target = damageable as Component;
|
|
|
|
if ( ignore.IsValid() && ignore.IsDescendant( target.GameObject ) )
|
|
continue;
|
|
|
|
// If the object isn't in line of sight, fuck it off
|
|
var tr = losTrace.Ray( point, target.WorldPosition ).Run();
|
|
if ( tr.Hit && tr.GameObject.IsValid() )
|
|
{
|
|
if ( !target.GameObject.Root.IsDescendant( tr.GameObject ) )
|
|
continue;
|
|
}
|
|
|
|
var distance = target.WorldPosition.Distance( point );
|
|
var distanceLinear = distance / sphere.Radius;
|
|
distanceLinear = distanceLinear.Clamp( 0, 1 );
|
|
|
|
damage.Damage = damageAmount * distanceLinear;
|
|
var direction = (target.WorldPosition - point).Normal;
|
|
var force = direction * distance * 50f;
|
|
|
|
damage.Origin = sphere.Center;
|
|
damage.Position = tr.HitPosition;
|
|
damageable.OnDamage( damage );
|
|
}
|
|
|
|
damage.Damage = damageAmount;
|
|
}
|
|
}
|