Enemy class MinibossCharger, a subclass of Charger. It sets miniboss-specific properties like health scale, visuals, coin values, movement and charge parameters, and overrides Colliding to fling nearby enemies or players when charging.
using System;
using Sandbox;
public class MinibossCharger : Charger
{
public override EnemyType EnemyType => EnemyType.MinibossCharger;
public override string GibFolder => "miniboss_charger";
public override float OverrideGibChance => 1f;
public override int ExtraDeathBloodSprayAmount => 25;
protected override float MinibossHealthScale => 1.2f;
public override float GetMaxHealth() => MinibossBaseHealth * MinibossHealthScale;
public override Vector3 SpawnScale => new Vector3( 1.5f );
public override bool ShowHealthbar => true;
public override float HealthbarOffset => State == ChargerState.Charge ? 70f : 105f;
public override float HealthbarOpacity => Utils.EasePercent( SpawnProgress, EasingType.QuadIn );
public override float HealthbarArmorOpacity => Utils.EasePercent( SpawnProgress, EasingType.QuadIn );
public override bool IsBoss => true;
public override bool IsMiniboss => true;
public override float ParticleYPosOverride => 0.5f;
public override float StunParticleYPosOverride => 0.85f;
protected override void OnStart()
{
base.OnStart();
CoinValueMin = 10;
CoinValueMax = 18;
CoinChance = 1f;
PushStrength = 8000f;
Weight = _baseWeight = 2.3f;
_chargeWeight = 4.5f;
_personalSpeedScale = 1f;
_personalSpeedFreq = Game.Random.Float( 9f, 11f );
if ( IsProxy )
return;
AggroRange = 70f;
DetectTargetRange = 900f;
LoseTargetRange = 1400f;
LoseTargetTime = 9f;
MeleeDamage = Utils.Select( Manager.Instance.Difficulty, 9f, 13f, 14f );
DamageTargetDelay = 0.8f;
Acceleration = 300f;
AccelerationAttacking = 350f;
Deceleration = 1.5f;
DecelerationAttacking = 1.4f;
_personalTurnSpeed = Game.Random.Float( 5f, 7f );
_personalChargeRange = 650f;
_chargeTimeMin = 2.5f;
_chargeTimeMax = 5f;
_chargeDelayMin = 2.2f;
_chargeDelayMax = 5f;
_chargeDelayTimer = Game.Random.Float( _chargeDelayMin, _chargeDelayMax );
_chargeRotateSpeed = 9f;
_chargeVelMax = 500f;
}
protected override void OnUpdate()
{
base.OnUpdate();
if ( IsProxy )
return;
}
public override void Colliding( Thing other, float percent, float dt )
{
base.Colliding( other, percent, dt );
if ( IsInTheAir )
return;
if ( State == ChargerState.Charge && _timeSinceChangeState < _chargeTime - 0.4f )
{
if ( other is Enemy enemy && !(enemy is Boss) )
{
if ( !enemy.IsInTheAir && !enemy.IsSpawning )
{
var targetPos = TargetUnit.IsValid() && Game.Random.Float( 0f, 1f ) < 0.5f
? TargetUnit.Position2D + TargetUnit.Velocity * Game.Random.Float( 0f, 4f ) + Velocity * Game.Random.Float( 0f, 3f ) + Utils.GetRandomVector() * Game.Random.Float(80f, 350f)
: Position2D + Velocity * Game.Random.Float( 0.5f, 4f ) + new Vector2( Game.Random.Float( -1f, 1f ), Game.Random.Float( -1f, 1f ) ) * 120f;
enemy.JumpRpc( Manager.Instance.ClampPosToBounds( targetPos ), height: Game.Random.Float( 270f, 320f ), lifetime: Game.Random.Float( 1.1f, 1.5f ) );
// todo: sfx
}
}
else if ( other is Player player && !player.IsDead && !player.IsInTheAir && !player.IsInvincible )
{
var targetPos = TargetUnit.IsValid()
? TargetUnit.Position2D + _chargeDir * Game.Random.Float( 200f, 400f ) + Velocity * Game.Random.Float( 0f, 3f ) + new Vector2( Game.Random.Float( -1f, 1f ), Game.Random.Float( -1f, 1f ) ) * 120f
: Position2D + _chargeDir * Game.Random.Float( 200f, 400f ) + new Vector2( Game.Random.Float( -1f, 1f ), Game.Random.Float( -1f, 1f ) ) * 120f;
player.JumpRpc( Manager.Instance.ClampPosToBounds( targetPos ), height: Game.Random.Float( 270f, 320f ), lifetime: Game.Random.Float( 1.1f, 1.5f ) );
// todo: sfx
// todo: if player dodges, don't fling them?
}
}
}
}