things/orbiters/OrbiterLens.cs

An OrbiterLens game entity that orbits a unit and visually pulses. It tints its model based on whether its orbited unit is alive, follows the unit at a distance based on the unit radius, bobs in Z, and when colliding with Bullet instances it applies a lens buff to the bullet and briefly scales up.

Networking
using System;
using Sandbox;

public class OrbiterLens : Orbiter
{
	[Sync] public float DamagePercent { get; set; }

	private TimeSince _timeSinceBuff;

	private float _lastAlpha;

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

		if ( IsProxy )
			return;

		CollideWithTags.Add( "bullet" );

		OrbitDistance = 35f;

		_lastAlpha = -1f;
	}

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

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

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

		if ( IsProxy )
			return;

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

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

		OrbitDistance = OrbitedUnit.Radius + 35f;

		if ( _timeSinceBuff < 0.3f )
		{
			WorldScale = new Vector3( Utils.Map( _timeSinceBuff, 0f, 0.275f, 1.3f, 1f, EasingType.SineOut ) );
		}
	}

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

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

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

		if ( other is Bullet bullet && !bullet.IsLensBuffed )
		{
			bullet.LensBuff( 1f + DamagePercent );
			WorldScale = new Vector3( 1.3f );
			_timeSinceBuff = 0f;
		}
	}
}