Enemy subclass SpitterElite. Configures stats, AI ranges, timers and behavior overrides for an elite spitter enemy, including health, movement/shooting parameters, spawning scale, shooting logic and reactions to damage.
using System;
using Sandbox;
public class SpitterElite : Spitter
{
public override EnemyType EnemyType => EnemyType.SpitterElite;
public override float GetMaxHealth()
{
switch ( Manager.Instance.Difficulty )
{
case 0: default: return 82f;
case 1: return 90f;
case 2: return 90f;
}
}
public override Vector3 SpawnScale => new Vector3( 1.2f );
protected override void OnStart()
{
base.OnStart();
CoinValueMin = 3;
CoinValueMax = 5;
CoinChance = 1f;
PushStrength = 8000f;
Weight = 1.6f;
_personalSpeedScale = Game.Random.Float( 1.1f, 1.2f );
_personalSpeedFreq = Game.Random.Float( 9f, 11f );
if ( IsProxy )
return;
DetectTargetRange = 800f;
LoseTargetRange = 1300f;
LoseTargetTime = 5f;
MeleeDamage = Utils.Select( Manager.Instance.Difficulty, 10f, 11f, 12f );
DamageTargetDelay = 0.6f;
_personalTurnSpeed = Game.Random.Float( 6f, 7.5f );
Acceleration = Utils.Select( Manager.Instance.Difficulty, 200f, 220f, 225f );
AccelerationAttacking = Utils.Select(Manager.Instance.Difficulty, 240f, 275f, 275f);
Deceleration = 1.9f;
DecelerationAttacking = 1.8f;
_shootDelayMin = Utils.Select( Manager.Instance.Difficulty, 6f, 4f, 1f );
_shootDelayMax = Utils.Select( Manager.Instance.Difficulty, 15f, 13f, 12f); ;
_shootRange = Utils.Select( Manager.Instance.Difficulty, 480f, 500f, 530f );
_shootDelayTimer = Game.Random.Float( _shootDelayMin, _shootDelayMax );
_prepareShootTime = 0.9f;
_shootTime = 0.6f;
_blinkDelayMin = 9f;
_blinkDelayMax = 16f;
_blinkPrepareDelay = 0.45f;
_blinkRange = 800f;
_blinkDelayTimer = Game.Random.Float( _blinkDelayMin, _blinkDelayMax );
_personalRetreatRange = Game.Random.Float( 230f, 250f );
_personalStopRetreatRange = Game.Random.Float( 320f, 350f );
}
protected override void OnUpdate()
{
base.OnUpdate();
}
protected override Vector2 GetTargetOffset()
{
var offset = TargetUnit.Velocity * (0.5f + Utils.FastSin( TimeSinceSpawn * 2.6f ) * 0.5f) * (TargetUnit.Position2D - Position2D).Length * 0.012f;
if ( State == SpitterState.Default && !_isRetreating )
offset += new Vector2( Utils.FastSin( TimeSinceSpawn * 0.73f ), Utils.FastSin( TimeSinceSpawn * 0.64f ) ) * 85f;
return offset;
}
protected override void StartShooting()
{
base.StartShooting();
//SetPlaybackRate( 1.43f );
SetPlaybackRate( 1f );
}
protected override void Shoot()
{
Manager.Instance.PlaySfxNearby( "spitter.shoot", Position2D, pitch: Game.Random.Float( 1.2f, 1.3f ), volume: 0.85f, maxDist: 450f );
if ( IsProxy )
return;
var dir = (Vector2)WorldRotation.Forward;
var pos = Position2D + dir * 40f;
Manager.Instance.SpawnEnemyHomingProjectile( pos, dir, shooter: this, enemyType: this.EnemyType, startVel: Game.Random.Float( 50f, 70f ), projectileType: ProjectileType );
// todo: scale up the flying skull after spawn so it doesn't just snap in?
}
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 );
if ( IsProxy || IsDying )
return;
if ( State == SpitterState.Default && !IsStunned && _timeSinceBlinking > Game.Random.Float( 4f, 8f ) && Game.Random.Float( 0f, 1f ) < Utils.Map( HpPercent, 1f, 0f, 0f, 1f ) )
SetState( SpitterState.BlinkPrepare );
}
}