things/enemies/MinibossRunner.cs

An enemy subclass MinibossRunner derived from Runner that configures stats, behavior parameters, movement/rotation tweaks, spawn visuals and damage handling for a miniboss runner enemy.

Networking
using System;
using Sandbox;

public class MinibossRunner : Runner
{
	public override EnemyType EnemyType => EnemyType.MinibossRunner;
	public override string GibFolder => "miniboss_runner";
	public override float OverrideGibChance => 1f;
	public override int ExtraDeathBloodSprayAmount => 25;
	protected override float MinibossHealthScale => 1.1f;
	public override float GetMaxHealth() => MinibossBaseHealth * MinibossHealthScale;

	public override Vector3 SpawnScale => new Vector3( 1.4f );
	public override bool ShowHealthbar => true;
	public override float HealthbarOffset => 105f;
	public override float HealthbarOpacity => Utils.EasePercent( SpawnProgress, EasingType.QuadIn ) * (_timeSinceHurt < 1f ? 1f : 0f);
	public override float HealthbarArmorOpacity => Utils.EasePercent( SpawnProgress, EasingType.QuadIn ) * (_timeSinceHurt < 1f ? 1f : 0f);

	public override bool IsBoss => true;
	public override bool IsMiniboss => true;

	private TimeSince _timeSinceHurt;

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

		CoinValueMin = 10;
		CoinValueMax = 18;
		CoinChance = 1f;

		PushStrength = 8000f;
		Weight = 1.4f;

		_personalSpeedScale = Game.Random.Float( 1.0f, 1.1f );
		_personalSpeedFreq = Game.Random.Float( 14f, 15f );

		_timeSinceHurt = 99f;

		if ( IsProxy )
			return;

		AggroRange = 140f;
		DetectTargetRange = 900f;
		LoseTargetRange = 1500f;
		LoseTargetTime = 9f;
		MeleeDamage = Utils.Select( Manager.Instance.Difficulty, 6f, 9f, 11f );
		DamageTargetDelay = 0.7f;
		_personalTurnSpeed = Game.Random.Float( 5f, 8f );
		Acceleration = Utils.Select( Manager.Instance.Difficulty, 90f, 105f, 108f );
		AccelerationAttacking = Utils.Select( Manager.Instance.Difficulty, 105f, 118f, 122f );
		Deceleration = 1.5f;
		DecelerationAttacking = 1.4f;

		_evadeDelayMin = 0.8f;
		_evadeDelayMax = 3.4f;
		_evadeDelay = Game.Random.Float( _evadeDelayMin, _evadeDelayMax );
		_evadeVelocityMin = 120f;
		_evadeVelocityMax = 400f;

		_nextJumpDelayMin = 2f;
		_nextJumpDelayMax = 9f;
		_delayUntilNextJump = Game.Random.Float( _nextJumpDelayMin, _nextJumpDelayMax );
		_maxJumpDist = 500f;

		_retreatVelocityMin = 150f;
		_retreatVelocityMax = 400f;
	}

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

		if ( IsProxy )
			return;

	}

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

		if ( _isRetreating )
			WorldRotation = Rotation.Lerp( WorldRotation, Rotation.FromYaw( WorldRotation.Yaw() + Utils.FastSin( TimeSinceSpawn * 0.45f ) * 75f ), _personalTurnSpeed * Time.Delta * TimeScale );
	}

	protected override Vector2 GetTargetOffset()
	{
		if ( IsAttacking || _isRetreating )
			return Vector2.Zero;

		return TargetUnit.Velocity * (0.6f + Utils.FastSin( TimeSinceSpawn * 0.32f ) * 0.5f) * (TargetUnit.Position2D - Position2D).Length * 0.025f
			+ new Vector2( Utils.FastSin( TimeSinceSpawn * 0.37f ), Utils.FastSin( TimeSinceSpawn * 0.39f ) ) * (100f + Utils.FastSin( TimeSinceSpawn * 0.85f ) * 250f);
	}

	protected override void PlayJumpSfx()
	{
		Manager.Instance.PlaySfxNearby( "jump_whoosh", Position2D, pitch: Game.Random.Float( 1.75f, 1.8f ), volume: 0.4f, maxDist: 320f );
	}

	protected override void Damage( float damage, Player player, DamageType damageType, Vector3 hitPos, Vector2 force, bool isCrit = false, bool shouldFlinch = true, DamageResultFlags damageFlags = DamageResultFlags.None )
	{
		base.Damage( damage, player, damageType, hitPos, force, isCrit, shouldFlinch, damageFlags );

		_timeSinceHurt = 0f;

		if ( IsProxy )
			return;
	}

	protected override void OnMeleePlayer( Player player )
	{
		base.OnMeleePlayer( player );

		FlashRpc( 0.075f, UnitFlashType.PlayerDmg );
	}
}