things/orbiters/OrbiterShield.cs

OrbiterShield is a game entity derived from Orbiter that acts as a protective shield orbiting a unit. It handles activation/recharge, scales/alphas its model based on state and time, blocks EnemyProjectile instances by removing them and plays a sound when blocking.

Networking
using System;
using Sandbox;

public class OrbiterShield : Orbiter
{
	[Sync] public bool IsActive { get; set; }
	public float RechargeTime { get; set; }
	private TimeSince _timeSinceBlock;
	public int ShieldNum { get; set; }

	private float _lastAlpha;

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

		if ( IsProxy )
			return;

		CollideWithTags.Add( "enemy_projectile" );

		OrbitDistance = 25f;

		IsActive = true;
		RechargeTime = 1.5f;

		_lastAlpha = -1f;
	}

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

		float alpha = OrbitedUnit.IsValid() && !OrbitedUnit.IsDying
			? (IsActive ? 1f : 0.3f)
			: 0f;

		if ( alpha != _lastAlpha )
		{
			Model.Tint = Model.Tint.WithAlpha( alpha );
			_lastAlpha = alpha;
		}

		if ( IsProxy )
			return;

		if ( !OrbitedUnit.IsValid() || OrbitedUnit.IsDying )
			return;

		if ( !IsActive )
		{
			if ( _timeSinceBlock > RechargeTime )
			{
				IsActive = true;
				WorldScale = new Vector3( 1f );
			}
			else
			{
				WorldScale = new Vector3( Utils.Map( _timeSinceBlock, 0f, 0.375f, 0.5f, 1f, EasingType.Linear ) );
			}
		}

		WorldRotation = Rotation.LookAt( Position2D - OrbitedUnit.Position2D );

		OrbitDistance = OrbitedUnit.Radius + 10f;
	}

	protected override float GetZPos()
	{
		return OrbitedUnit.WorldPosition.z + 45f * (1f + Utils.FastSin( Time.Now * 9f ) * 0.185f);
	}

	public override void Colliding( Thing other, float percent, float dt )
	{
		base.Colliding( other, percent, dt );

		if ( !IsActive || !OrbitedUnit.IsValid() || OrbitedUnit.IsDying )
			return;

		var enemyProjectile = other as EnemyProjectile;
		if ( !enemyProjectile.IsValid() )
			return;

		enemyProjectile.RemoveRpc( shouldSpawnEffects: false );
		Block();
	}

	void Block()
	{
		WorldScale = new Vector3( 0.5f );
		IsActive = false;
		_timeSinceBlock = 0f;

		//Manager.Instance.PlaySfxNearbyRpc( "bullet.impact", Position2D, pitch: Game.Random.Float( 0.9f, 1f ), volume: 1.15f, maxDist: 300f );
		Manager.Instance.PlaySfxNearbyRpc( "metal_hit", Position2D, pitch: Game.Random.Float( 0.9f, 1f ), volume: 1.15f, maxDist: 300f );
	}
}