Weapons/TripminePlaced.cs
public sealed class TripminePlaced : Component, Component.ITriggerListener, Component.IDamageable, IKillIcon, IInstigator
{
	[RequireComponent] CapsuleCollider Collider { get; set; }

	[Property] float TimeToActive { get; set; } = 5f;
	[Property] public float MaxDamage { get; set; } = 125;
	[Property] public float Radius { get; set; } = 256;
	[Property] GameObject HitObject { get; set; }

	public PlayerData Instigator { get; set; }

	[Property] public Curve DamageFalloff { get; set; } = new Curve( new Curve.Frame( 1.0f, 1.0f ), new Curve.Frame( 0.0f, 0.0f ) );
	[Property] Texture IKillIcon.DisplayIcon { get; set; }

	TimeUntil timeUntilActive { get; set; }
	bool IsActive { get; set; }

	protected override void OnStart()
	{
		base.OnStart();

		timeUntilActive = TimeToActive;
		Collider.Enabled = false;
	}

	protected override void OnFixedUpdate()
	{
		base.OnFixedUpdate();

		if ( !IsActive )
		{
			ActivateLaser();
		}
	}

	void ActivateLaser()
	{
		if ( timeUntilActive > 0 ) return;

		IsActive = true;

		Sound.Play( "notify_beep", WorldPosition );

		var tr = Scene.Trace.Ray( WorldPosition, WorldPosition + WorldRotation.Forward * 10000 )
			.IgnoreGameObjectHierarchy( GameObject.Root )
			.WithoutTags( "player" )
			.Run();

		Collider.End = Vector3.Forward * tr.Distance;
		Collider.Radius = 0.2f;
		Collider.Enabled = true;

		HitObject.WorldPosition = tr.EndPosition;
		timeUntilActive = 0.33f;
	}

	public void Explode( PlayerData instigator = default, GameObject weapon = default )
	{
		var actualInstigator = instigator ?? Instigator;
		Damage.Radius( WorldPosition, Radius, MaxDamage, [DamageTags.Explosion], GameObject, weapon.IsValid() ? weapon : GameObject, DamageFalloff, actualInstigator );

		CreateEffects();
		GameObject.Destroy();
	}

	[Rpc.Broadcast( NetFlags.HostOnly )]
	private void CreateEffects()
	{
		if ( Application.IsDedicatedServer ) return;

		Effects.SpawnScorch( WorldPosition, WorldRotation.Forward, GameObject );
		Effects.SpawnExplosion( WorldPosition );
	}

	void ITriggerListener.OnTriggerEnter( GameObject other )
	{
		if ( !Networking.IsHost ) return;
		if ( GameObject.IsDestroyed ) return;
		if ( other.Tags.Has( "tripmine" ) ) return;
		if ( timeUntilActive > 0 ) return;

		Explode();
	}

	void IDamageable.OnDamage( in DamageInfo damage )
	{
		if ( damage.Weapon == GameObject ) return;

		if ( damage is not DamageInfo dmg )
			return;

		if ( dmg.Tags.Has( DamageTags.Explosion ) )
		{
			DelayedExplode();
			return;
		}

		// Get the instigator from the damage info
		var damageInstigator = dmg.Attacker?.GetComponent<Player>()?.PlayerData;
		Explode( damageInstigator, dmg.Weapon );
	}

	async void DelayedExplode()
	{
		await Task.Delay( 400 );

		if ( GameObject.IsDestroyed ) return;

		Explode();
		GameObject.Destroy();
	}
}