things/enemies/MinibossZapper2.cs

Enemy subclass MinibossZapper2, configures stats and behavior for a miniboss enemy variant. Overrides health, visuals, movement, laser aiming and damage behavior, and sets runtime parameters in OnStart.

Networking
using System;
using Sandbox;

public class MinibossZapper2 : MinibossZapper
{
	public override EnemyType EnemyType => EnemyType.MinibossZapper2;
	public override string GibFolder => "miniboss_zapper_2";
	public override float OverrideGibChance => 1f;
	public override int ExtraDeathBloodSprayAmount => 25;
	public override float GetMaxHealth()
	{
		switch ( Manager.Instance.Difficulty )
		{
			case 0: default: return 550f;
			case 1: return 600f;
			case 2: return 625f;
			case 3: return 670f;
		}
	}

	private bool _clockwiseLaserRot;
	private float _currRotSpeed;

	public override float ParticleYPosOverride => 0.6f;
	public override float StunParticleYPosOverride => 1.1f;

	protected override float LaserWobbleAmplitude => 4f;
	protected override float LaserWobbleAmplitude2 => 1.5f;
	protected override float LaserWobbleSpeedMin => 4f;
	protected override float LaserWobbleSpeedMax => 9f;

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

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

		PushStrength = 7000f;
		Weight = 1.5f;

		_personalSpeedScale = 1f;
		_personalSpeedFreq = Game.Random.Float( 9f, 11f );

		// todo: never spawn foot gibs

		if ( IsProxy )
			return;

		AggroRange = 50f;
		DetectTargetRange = 575f;
		LoseTargetRange = 1000f;
		LoseTargetTime = 6f;
		MeleeDamage = Utils.Select( Manager.Instance.Difficulty, 10f, 12f, 13f );
		LaserDamage = Utils.Select( Manager.Instance.Difficulty, 9f, 14f, 17f );
		DamageTargetDelay = 0.55f;
		_personalTurnSpeed = Game.Random.Float( 4f, 7f );
		Acceleration = 140f * Utils.Select( Manager.Instance.Difficulty, 0.9f, 1f, 1.05f );
		AccelerationAttacking = 160f * Utils.Select( Manager.Instance.Difficulty, 0.9f, 1f, 1.05f );
		Deceleration = 2.2f;
		DecelerationAttacking = 2f;

		_shootDelayMin = 2f;
		_shootDelayMax = 7f;
		_shootDelayTimer = Game.Random.Float( _shootDelayMin, _shootDelayMax );
		_shootRange = 600f;

		_laserTotalTimeMin = 15f;
		_laserTotalTimeMax = 30f;

		_laserLengthTotal = 660f;

		_clockwiseLaserRot = Game.Random.Int( 0, 1 ) == 0;
	}

	protected override void HandleAiming()
	{
		float minRotSpeed = Utils.Map( HpPercent, 1f, 0f, -4f, -8f );
		float maxRotSpeed = Utils.Map( HpPercent, 1f, 0f, -35f, -50f );
		_currRotSpeed = Utils.MapReturn( _timeSinceShoot, 0f, _laserTotalTime, minRotSpeed, maxRotSpeed, EasingType.QuadOut ) * (_clockwiseLaserRot ? -1f : 1f);
		WorldRotation = Rotation.FromYaw( WorldRotation.Yaw() + _currRotSpeed * Time.Delta * TimeScale );
	}

	protected override void HurtPlayer( Player player, Vector2 hitPos, Vector2 dir )
	{
		dir = Utils.GetPerpendicularVector( dir ) * (_clockwiseLaserRot ? 1f : -1f);
		var force = Utils.Map( Math.Abs( _currRotSpeed ), 4f, 50f, 30f, 300f );
		var upwardAmount = Utils.Map( Math.Abs( _currRotSpeed ), 4f, 50f, 0.05f, 1f ) * Game.Random.Float( 0.75f, 1.25f );
		player.DamageRpc( LaserDamage, DamageType.Laser, hitPos, dir, upwardAmount, force, ragdollForce: force * 0.01f, this, enemyType: this.EnemyType );
	}

	protected override Color GetLaserColor()
	{
		return new Color( 1f, 0f, 0.75f ).WithAlpha( 5f + Utils.FastSin( _timeSincePrepareShoot * 15f ) * 4f );
	}

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

		if ( IsProxy )
			return;

		if ( Game.Random.Float( 0f, 1f ) < 0.9f )
			_clockwiseLaserRot = !_clockwiseLaserRot;
	}
}