Enemy subclass for a miniboss called MinibossShielder. It sets stats, spawn scale, healthbar behavior, spawns orbiting shield enemies during start and as health thresholds are crossed, and destroys shields on death.
using System;
using Sandbox;
public class MinibossShielder : Enemy
{
public override EnemyType EnemyType => EnemyType.MinibossShielder;
public override string GibFolder => "miniboss_shielder";
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.6f );
public override bool ShowHealthbar => true;
public override float HealthbarOffset => 100f;
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;
private List<OrbiterShieldEnemy> _shields;
private bool _rotateClockwise;
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 = 9000f;
Weight = 1.5f;
_personalSpeedScale = 1f;
_personalSpeedFreq = 12f;
AnimSpeedModifier = 0.7f;
if ( IsProxy )
return;
AggroRange = 85f;
DetectTargetRange = 850f;
LoseTargetRange = 1300f;
LoseTargetTime = 7f;
MeleeDamage = Utils.Select( Manager.Instance.Difficulty, 11f, 15f, 16f );
DamageTargetDelay = 0.8f;
Acceleration = 265f * Utils.Select( Manager.Instance.Difficulty, 0.9f, 1f, 1.05f );
AccelerationAttacking = 305f * Utils.Select( Manager.Instance.Difficulty, 0.9f, 1f, 1.05f );
Deceleration = 2.2f;
DecelerationAttacking = 2.1f;
_personalTurnSpeed = 4.5f;
_rotateClockwise = Game.Random.Float( 0f, 1f ) < 0.5f;
_shields = new();
SpawnShield( 90f );
}
protected override void OnUpdate()
{
base.OnUpdate();
if ( IsProxy )
return;
if ( _shields.Count == 1 && HpPercent < 0.66f )
SpawnShield( _shields[0].CurrOrbitAngleDegrees - 90f );
else if ( _shields.Count == 2 && HpPercent < 0.33f )
SpawnShield( _shields[1].CurrOrbitAngleDegrees - 90f );
}
protected override float GetMoveSpeedFactor()
{
var progress = ModelRenderer.SceneModel.CurrentSequence.TimeNormalized;
return Charger.GetChargerMoveSpeedFactor( progress, IsAttacking );
}
[Rpc.Broadcast]
void SpawnShield( float degrees )
{
// todo: sfx
if ( IsProxy )
return;
var pos = Position2D;
var orbiterShieldEnemyGo = GameObject.Clone( "prefabs/orbiter_shield_enemy.prefab", new CloneConfig { StartEnabled = true, Transform = new Transform( new Vector3( pos.x, pos.y, -999f ), Rotation.From( 0f, 0f, 0f ) ) } );
var orbiterShieldEnemy = orbiterShieldEnemyGo.Components.Get<OrbiterShieldEnemy>( true );
orbiterShieldEnemy.OrbitedUnit = this;
orbiterShieldEnemy.CurrOrbitAngleDegrees = degrees;
orbiterShieldEnemy.ShieldNum = _shields.Count;
orbiterShieldEnemyGo.NetworkSpawn();
_shields.Add( orbiterShieldEnemy );
foreach ( var shield in _shields )
shield.OrbitSpeed = (_shields.Count * 40f) * (_rotateClockwise ? -1f : 1f);
}
public override void Die( Vector2 dir, float force, Player player, DamageType damageType )
{
base.Die( dir, force, player, damageType );
if ( IsProxy )
return;
foreach ( var shield in _shields )
shield.GameObject.Destroy();
}
}