unitStatus/UnitStatusFreeze.cs

A UnitStatus subclass that applies a freeze effect to a Unit. It sets frozen state and a time scale, updates lifetime, spawns frozen shard bullets and plays a sound when the frozen unit dies, and restores time scale when removed.

NetworkingFile Access
using System;
using Sandbox;

public class UnitStatusFreeze : UnitStatus
{
	public Player PlayerSource { get; set; }
	public Enemy EnemySource { get; set; }
	
	public float TimeScale { get; set; }

	public UnitStatusFreeze()
	{

	}

	public override void Init( Unit unit )
	{
		base.Init( unit );

		TimeScale = float.MaxValue;

		Unit.SetStatusFrozen( true );
	}

	public void SetValues( float timeScale, float lifetime )
	{
		timeScale = MathF.Max( timeScale, 0.01f );

		if ( timeScale < TimeScale )
		{
			Unit.SetTimeScale( timeScale );
			TimeScale = timeScale;

			Lifetime = lifetime;
		}
	}

	public override void Update( float dt )
	{
		base.Update( dt );

		if ( !Unit.IsValid() )
			return;

		//Gizmo.Draw.Color = Color.Red;
		//Gizmo.Draw.Text( $"{Damage}\n{BaseDamage}\n{_stackTimes.Count()}", new global::Transform( Unit.WorldPosition ) );

		if ( ElapsedTime > Lifetime )
			Unit.RemoveUnitStatus( this );

		//Unit.Velocity *= (1f - Utils.Map( TimeScale, 0.6f, 0f, 3f, 15f ) * dt);
	}

	public override void Die( Player player )
	{
		base.Die( player );

		//Unit.AnimSpeedModifier = 1f;
		//Unit.TimeScale = 1f;
		//Unit.IsFrozen = false;

		if ( PlayerSource.IsValid() && PlayerSource.GetSyncStat(PlayerStat.FrozenShardsNum) > 0f )
		{
			int maxShardsNum = (int)PlayerSource.GetSyncStat(PlayerStat.FrozenShardsNum);
			int numShards = Game.Random.Int( 0, maxShardsNum );
			if ( numShards == 0 && Game.Random.Float( 0f, 1f ) < 0.8f )
				numShards = 1;

			if ( numShards > 0 )
			{
				Vector2 aimDir = Utils.GetRandomVector();
				PlayerSource.SpawnBulletRingRpc( Unit.Position2D, numShards, aimDir, isFromClip: false, BulletType.FrozenShard, damageMultMin: 0.1f, damageMultMax: 0.95f );

				// todo: particle effect
				// todo: sfx

				Manager.Instance.PlaySfxNearbyRpc( "frozen", Unit.Position2D, pitch: Game.Random.Float( 2.8f, 3.00f ), volume: 1f, maxDist: 400f );
			}
		}
	}

	public override void OnRemove( bool playEffects = true )
	{
		Unit.SetStatusFrozen( false );
		Unit.SetTimeScale( 1f ); // todo: needs to be set on client too?
	}

	public override void Refresh()
	{
		base.Refresh();

		ElapsedTime = 0f;
	}

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

	}
}