Boss partial class code that implements an invincible phase. It decides when to enter that phase based on HP percent, spawns generator enemies around the arena via RPC, plays sounds/animations, prevents death to trigger the phase, and tracks when generators are destroyed to end invincibility.
using System;
using Sandbox;
using Sandbox.Citizen;
public partial class Boss
{
private bool _hasSpawnedGenerators;
private int _numGenerators;
private float _invincibleHpPercent;
void InitInvincible()
{
if ( IsProxy )
return;
_invincibleHpPercent = Game.Random.Float( 0.25f, 0.33f );
}
void HandleInvincible()
{
if ( _hasSpawnedGenerators || IsSpawning || IsDying || IsInTheAir || IsProxy )
return;
if ( State == BossState.InvinciblePrepare || State == BossState.Invincible )
return;
if ( HpPercent < _invincibleHpPercent )
{
_hasSpawnedGenerators = true;
EnterDefaultStateRpc();
SetState( BossState.InvinciblePrepare );
}
}
protected override void StartDying( Vector2 dir, float force, Player player, DamageType damageType )
{
// If the invincible phase hasn't triggered yet, prevent death and enter it now instead.
if ( !_hasSpawnedGenerators && !IsSpawning )
{
Health = 1f;
_hasSpawnedGenerators = true;
EnterDefaultStateRpc();
SetState( BossState.InvinciblePrepare );
return;
}
base.StartDying( dir, force, player, damageType );
}
[Rpc.Broadcast( NetFlags.Reliable )]
protected void StartInvincibleRpc()
{
SetAnim( "SummonPrepare" );
Manager.Instance.PlaySfxNearby( "boss_invincible_start", Position2D, pitch: Game.Random.Float( 0.8f, 0.85f ), volume: 2.3f, maxDist: 2000f );
//AnimationHelper.HoldType = CitizenAnimationHelper.HoldTypes.Punch;
if ( IsProxy )
return;
_numGenerators = Utils.Select( Manager.Instance.Difficulty, 1, 2, 3 );
if( _numGenerators <= 0 )
return;
var min = Manager.Instance.BOUNDS_MIN;
var max = Manager.Instance.BOUNDS_MAX;
var center = (min + max) * 0.5f;
var radius = (max.x - min.x) * 0.5f - 200f;
var startAngle = Game.Random.Float( 0f, 360f );
var angleStep = 360f / _numGenerators;
for ( int i = 0; i < _numGenerators; i++ )
{
var angle = startAngle + i * angleStep;
var radians = angle * MathF.PI / 180f;
var pos = center + new Vector2( MathF.Cos( radians ), MathF.Sin( radians ) ) * radius;
Manager.Instance.SpawnEnemyRpc( EnemyType.BossInvincibleGenerator, pos );
}
BecomeInvincible();
}
[Rpc.Broadcast]
protected void FinishInvincibleRpc()
{
SetAnim( "Summon" );
}
public void InvincibleGeneratorDestroyed()
{
_numGenerators--;
if( _numGenerators <= 0 )
{
var invincible = GetUnitStatus<UnitStatusInvincible>();
if( invincible != null )
{
RemoveUnitStatus( invincible );
}
}
}
}