Boss barrage behavior for an enemy Boss. Initializes timers, chooses barrage type (Acid, Burning, Freezing), prepares and emits projectile rings with parameters varying by health and difficulty, and plays animations and SFX via RPCs.
using System;
using Sandbox;
using Sandbox.Citizen;
public partial class Boss
{
protected float _barrageDelayTimer;
protected float _barrageDelayMin;
protected float _barrageDelayMax;
private TimeSince _timeSinceBarrageShoot;
private BarrageType _barrageType;
private float _barrageEmitDelay;
private int _barrageEmitNum;
private float _barrageTotalTime;
private enum BarrageType
{
Acid,
Burning,
Freezing,
}
void InitBarrage()
{
if ( IsProxy )
return;
_barrageDelayMin = 10f;
_barrageDelayMax = 25f;
_barrageDelayTimer = Game.Random.Float( _barrageDelayMin, _barrageDelayMax ) * Utils.Select( Manager.Instance.Difficulty, 1.45f, 1f, 0.9f );
}
void HandleBarrage()
{
if ( !IsReadyForAction || !TargetUnit.IsValid() )
return;
if( HpPercent > Utils.Select( Manager.Instance.Difficulty, 0.2f, 0.3f, 0.85f ) )
return;
var targetDistSqr = (TargetUnit.Position2D - Position2D).LengthSquared;
if ( targetDistSqr < MathF.Pow( 800f, 2f ) )
{
_barrageDelayTimer -= Time.Delta * TimeScale;
if ( _barrageDelayTimer < 0f )
SetState( BossState.BarragePrepare );
}
}
[Rpc.Broadcast]
protected void StartBarrageRpc()
{
SetAnim( "SummonPrepare" );
//AnimationHelper.HoldType = CitizenAnimationHelper.HoldTypes.RPG;
//AnimationHelper.WithLook( Vector3.Up );
Manager.Instance.PlaySfxNearby( "boss.prepare", Position2D, pitch: Game.Random.Float( 0.75f, 0.85f ), volume: 1.4f, maxDist: 500f );
if ( IsProxy )
return;
_barrageEmitNum = 0;
_timeSinceBarrageShoot = 0f;
var rand = Game.Random.Float( 0f, 1f );
if ( rand < 0.35f )
_barrageType = BarrageType.Acid;
else if ( rand < 0.7f )
_barrageType = BarrageType.Burning;
else
_barrageType = BarrageType.Freezing;
switch ( _barrageType )
{
case BarrageType.Acid:
_barrageEmitDelay = Game.Random.Float( 0.2f, 0.4f );
_barrageTotalTime = Game.Random.Float( 2.8f, 3.2f ) * Utils.Map( HpPercent, 1f, 0f, 1f, 1.33f, EasingType.Linear );
break;
case BarrageType.Burning:
_barrageEmitDelay = Game.Random.Float( 0.4f, 0.5f );
_barrageTotalTime = Game.Random.Float( 2.8f, 3.2f ) * Utils.Map( HpPercent, 1f, 0f, 1f, 1.33f, EasingType.Linear );
break;
case BarrageType.Freezing:
_barrageEmitDelay = Game.Random.Float( 0.4f, 0.5f );
_barrageTotalTime = Game.Random.Float( 3.2f, 3.5f ) * Utils.Map( HpPercent, 1f, 0f, 1f, 1.33f, EasingType.Linear );
break;
}
_barrageEmitDelay *= Utils.Select( Manager.Instance.Difficulty, 1.1f, 1f, 0.9f );
_barrageTotalTime *= Utils.Select( Manager.Instance.Difficulty, 0.85f, 1f, 1.1f );
}
[Rpc.Broadcast]
protected void BarrageRpc()
{
//AnimationHelper.Target.Set( "b_attack", true );
if ( IsProxy )
return;
}
[Rpc.Broadcast]
protected void BarrageEmitRpc()
{
SetAnim( "Summon" );
Manager.Instance.PlaySfxNearby( "boss.shoot", Position2D, pitch: Utils.Map( _barrageEmitNum, 0, 10, 0.3f, 0.4f, EasingType.SineOut), volume: 0.8f, maxDist: 600f );
//AnimationHelper.Target.Set( "b_attack", true );
if ( IsProxy )
return;
var dir = Utils.GetRandomVector();
int numBullets = 0;
var lifetimeModMin = 1f;
var lifetimeModMax = 1f;
var projectileType = EnemyProjectileType.Normal;
var startVelMin = 300f;
var startVelMax = 300f;
switch (_barrageType)
{
case BarrageType.Acid:
projectileType = EnemyProjectileType.Acid;
//numBullets = MathX.FloorToInt( Utils.Map( HpPercent, 1f, 0f, 10f, 12f, EasingType.SineIn ) ) + Game.Random.Int( 0, 1 );
numBullets = MathX.FloorToInt( Utils.Map( HpPercent, 1f, 0f, 8f, 10f, EasingType.SineIn ) * Utils.Select( Manager.Instance.Difficulty, 0.65f, 1f, 1.1f ) ) + (_barrageEmitNum % 2 == 0 ? 0 : 1);
lifetimeModMin = 0.05f + _barrageEmitNum * 0.05f;
lifetimeModMax = lifetimeModMin + 0.05f;
_barrageEmitDelay = Game.Random.Float(0.5f, 0.6f);
startVelMin = startVelMax = 350f;
break;
case BarrageType.Burning:
projectileType = EnemyProjectileType.Fire;
numBullets = MathX.FloorToInt( Utils.Map( HpPercent, 1f, 0f, 4f, 6f, EasingType.SineIn ) * Utils.Select( Manager.Instance.Difficulty, 0.65f, 1f, 1.1f ) ) + _barrageEmitNum;
lifetimeModMin = 0.06f + _barrageEmitNum * 0.04f;
lifetimeModMax = lifetimeModMin + 0.04f;
_barrageEmitDelay = Game.Random.Float( 0.75f, 0.9f );
startVelMin = startVelMax = 330f;
break;
case BarrageType.Freezing:
projectileType = EnemyProjectileType.Freeze;
numBullets = MathX.FloorToInt( Utils.Map( HpPercent, 1f, 0f, 8f, 11f, EasingType.SineIn ) * Utils.Select( Manager.Instance.Difficulty, 0.65f, 1f, 1.1f ) ) + Game.Random.Int(-1, 5);
//lifetimeModifier = 1f;
_barrageEmitDelay = Game.Random.Float( 0.6f, 0.75f );
startVelMin = 240f;
startVelMax = 320f;
lifetimeModMin = 0.1f;
lifetimeModMax = 0.4f;
break;
}
Manager.Instance.SpawnEnemyProjectileRing( Position2D, numBullets, shooter: this, enemyType: this.EnemyType, startVelMin, startVelMax, lifetimeModMin, lifetimeModMax, projectileType );
_barrageEmitNum++;
}
}