things/Crown.cs
using Sandbox;
using static Manager;

public class Crown : Thing
{
	public TimeSince SpawnTime { get; private set; }

	public float Lifetime { get; set; }

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

		//OffsetY = -0.14f;

		Scale = 0.8f;

		ShadowOpacity = 0.8f;
		ShadowScale = 1.75f;
		SpawnShadow( ShadowScale, ShadowOpacity );

		Sprite.LocalScale = new Vector3( 1f ) * Scale * Globals.SPRITE_SCALE;

		if ( IsProxy )
			return;

		//BasePivotY = 0.225f;

		SpawnTime = 0f;
		Radius = 0.35f;

		CollideWith.Add( typeof( Enemy ) );
		CollideWith.Add( typeof( Player ) );
	}

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

		Manager.Instance.PlaySfxNearby( "crown", Position2D, pitch: Game.Random.Float( 0.95f, 1.05f ), volume: 2f, maxDist: 15f );
	}

	protected override void OnUpdate()
	{
		base.OnUpdate();
		//Gizmo.Draw.Color = Color.White;
		//Gizmo.Draw.Text( $"Stats[BulletStat.Damage]: {Stats[BulletStat.Damage]}\nStats[BulletStat.Lifetime]: {Stats[BulletStat.Lifetime]}", new global::Transform( (Vector3)Position2D + new Vector3( 0f, -0.4f, 0f ) ) );

		//Gizmo.Draw.Color = Color.White.WithAlpha( 0.05f );
		//Gizmo.Draw.LineSphere( (Vector3)Position2D, Radius );

		if ( !Manager.Instance.ShouldUpdateThings )
			return;

		Sprite.LocalScale = new Vector3( Scale, Scale * 1.3f, 1f ) * Utils.Map(1f + Utils.FastSin(Time.Now * 16f) * 0.05f, 0.95f, 1.05f, 0.95f, 1.05f, EasingType.ExtremeIn) * Globals.SPRITE_SCALE;

		Sprite.LocalPosition = new Vector3( 0f, 0.1f + Utils.FastSin(Time.Now * 6f) * 0.07f, 0f );

		ShadowScale = 1.75f - Utils.FastSin( Time.Now * 6f ) * 0.1f + Utils.Map( Utils.FastSin( Time.Now * 16f ) * 0.05f, -0.05f, 0.05f, 0f, 0.25f, EasingType.ExtremeIn );
		ShadowSpriteDirty = true;

		if ( IsProxy )
			return;

		float dt = Time.Delta;

		Position2D += Velocity * dt;
		Position2D = new Vector2( MathX.Clamp( Position2D.x, Manager.Instance.BOUNDS_MIN.x + Radius, Manager.Instance.BOUNDS_MAX.x - Radius ), MathX.Clamp( Position2D.y, Manager.Instance.BOUNDS_MIN.y + Radius, Manager.Instance.BOUNDS_MAX.y - Radius ) );
		WorldPosition = WorldPosition.WithZ( Globals.GetZPos(Position2D.y) );
		Velocity *= (1f - dt * 8.5f);

		Sprite.Tint = Color.Lerp( Color.Yellow, new Color( 1f, 1f, 1f ), Utils.Map(0.5f + Utils.FastSin(Time.Now * 16f) * 0.5f, 0f, 1f, 0f, 1f, EasingType.ExtremeIn ) );

		//Scale = new Vector2( 0.6f + Utils.FastSin( SpawnTime * 8f ) * 0.025f, 0.6f + MathF.Cos( SpawnTime * 8f ) * 0.025f );
		//ShadowScale = 0.8f + Utils.FastSin( SpawnTime * 8f ) * 0.025f;

		for ( int dx = -1; dx <= 1; dx++ )
		{
			for ( int dy = -1; dy <= 1; dy++ )
			{
				Manager.Instance.HandleThingCollisionForGridSquare( this, new GridSquare( GridPos.x + dx, GridPos.y + dy ), dt );

				if ( IsRemoved )
					return;
			}
		}
	}

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

		if ( other is Enemy enemy && !enemy.IsDying )
		{
			Velocity += (Position2D - other.Position2D).Normal * Utils.Map( percent, 0f, 1f, 0f, 1f ) * 20f * (1f + other.TempWeight) * dt;
		}
		else if ( other is Player player )
		{
			if ( !player.IsDead && SpawnTime > 0.1f )
			{
				Manager.Instance.Victory();
				GameObject.Destroy();
			}
		}
	}
}