things/enemies/SpikerSpecial.cs
using Sandbox;
using static Sandbox.VertexLayout;

public class SpikerSpecial : Spiker
{
	private Vector2 _wanderPos;

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

		Health = 270f;
		MaxHealth = Health;

		Radius = 0.318f;
		Scale = 1.65f;
		Sprite.LocalScale = new Vector3( Scale * Game.Random.Float( 1f - HeightVariance, 1f + HeightVariance ), Scale * Game.Random.Float( 1f - WidthVariance, 1f + WidthVariance ), 1f ) * Globals.SPRITE_SCALE;

		ShootRange = 7f;
		MoveSpeed = 3f;

		AggroRange = 0f;

		_wanderPos = new Vector2( Game.Random.Float( Manager.Instance.BOUNDS_MIN.x + 1f, Manager.Instance.BOUNDS_MAX.x - 1f ), Game.Random.Float( Manager.Instance.BOUNDS_MIN.y + 1f, Manager.Instance.BOUNDS_MAX.y - 2f ) );

		PushStrength = 50f;

		CoinChance = 1f;
		CoinValueMin = 3;
		CoinValueMax = 7;
	}

	protected override Vector2 GetTargetPos()
	{
		var wander_dist_sqr = (_wanderPos - Position2D).LengthSquared;
		if ( wander_dist_sqr < 0.25f )
		{
			_wanderPos = new Vector2( Game.Random.Float( Manager.Instance.BOUNDS_MIN.x + 1f, Manager.Instance.BOUNDS_MAX.x - 1f ), Game.Random.Float( Manager.Instance.BOUNDS_MIN.y + 1f, Manager.Instance.BOUNDS_MAX.y - 2f ) );
		}

		return Position2D + (_wanderPos - Position2D);
	}

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

		FlipX = _wanderPos.x > Position2D.x;
	}

	public override void CreateSpike()
	{
		var target_pos = Target.IsValid()
			? Target.Position2D + Target.Velocity * Game.Random.Float( 0.2f, 2f ) + Utils.GetRandomVector() * Game.Random.Float( 2f, 4f )
			: Position2D + Utils.GetRandomVector() * Game.Random.Float( 3f, 6f );

		var BUFFER = 0.1f;

		var spike = Manager.Instance.SpawnEnemySpike( 
			new Vector2( Math.Clamp( target_pos.x, Manager.Instance.BOUNDS_MIN.x + BUFFER, Manager.Instance.BOUNDS_MAX.x - BUFFER ), Math.Clamp( target_pos.y, Manager.Instance.BOUNDS_MIN.y + BUFFER, Manager.Instance.BOUNDS_MAX.y - BUFFER ) ),
			special: true
		);

		if ( IsCharmed )
		{
			spike.BecomeCharmed();
		}

		Manager.Instance.PlaySfxNearby( "spike.prepare", target_pos, pitch: Game.Random.Float( 0.95f, 1.05f ), volume: 1.5f, maxDist: 5f );
	}
}