Partial Boss class handling jump behavior. Initializes jump timers and distances, decides when to start jump or jump-away states, broadcasts a prepare-jump RPC, performs jump effects when jumping, and spawns shockwave, clouds, sounds and camera shake on landing.
using System;
using Sandbox;
using Sandbox.Citizen;
public partial class Boss
{
protected float _prepareJumpTime;
protected TimeSince _timeSinceJumping;
protected float _delayUntilNextJump;
protected Vector2 _jumpTargetPos;
protected float _nextJumpDelayMin;
protected float _nextJumpDelayMax;
protected float _maxJumpDist;
protected TimeSince _timeSinceJumpingAway;
protected float _delayUntilNextJumpAway;
protected float _nextJumpAwayDelayMin;
protected float _nextJumpAwayDelayMax;
protected TimeSince _timeSinceLanding;
void InitJumping()
{
if ( IsProxy )
return;
_nextJumpDelayMin = 8f;
_nextJumpDelayMax = 15f;
_delayUntilNextJump = Game.Random.Float( _nextJumpDelayMin, _nextJumpDelayMax ) * Utils.Select(Manager.Instance.Difficulty, 1.75f, 1.5f, 1.2f);
_timeSinceJumping = 0f;
_maxJumpDist = 800f;
_nextJumpAwayDelayMin = 22f;
_nextJumpAwayDelayMax = 37f;
_delayUntilNextJumpAway = Game.Random.Float( _nextJumpAwayDelayMin, _nextJumpAwayDelayMax ) * Utils.Select( Manager.Instance.Difficulty, 1.45f, 1.25f, 1f );
_timeSinceJumpingAway = 0f;
_timeSinceLanding = 0f;
}
void HandleJumping()
{
if ( !IsReadyForAction || !HasTarget || _timeSinceChangeState < 1f || _timeSinceLanding < 3f )
return;
// todo: jumping should be on countdown timer so delay doesn't progress unless State is Default?
if ( _timeSinceJumping > _delayUntilNextJump * (1f / TimeScale) * (IsAttacking ? 2f : 1f) )
SetState( BossState.JumpPrepare );
else if( _timeSinceJumpingAway > _delayUntilNextJumpAway * (1f / TimeScale) * (IsAttacking ? 2f : 1f) )
SetState( BossState.JumpAwayPrepare );
}
[Rpc.Broadcast]
public void PrepareJumpRpc()
{
SetAnim( "JumpPrepare" );
//AnimationHelper.DuckLevel = 0.5f;
Manager.Instance.PlaySfxNearby( "boss.prepare", Position2D, pitch: Game.Random.Float( 0.85f, 0.9f ), volume: 1.4f, maxDist: 500f );
}
protected override void Jump( Vector2 targetPos, float height, float lifetime )
{
base.Jump( targetPos, height, lifetime );
//CanAnimate = true;
//AnimationHelper.IsGrounded = false;
//AnimationHelper.DuckLevel = 0f;
GameObject.Clone( "prefabs/effects/cloud.prefab", new CloneConfig { StartEnabled = true, Transform = new Transform( WorldPosition.WithZ( 10f ) ) } );
Manager.Instance.PlaySfxNearby( "jump_whoosh", Position2D, pitch: Game.Random.Float( 1.35f, 1.4f ), volume: 1f, maxDist: 600f );
}
public override void JumpFinish()
{
base.JumpFinish();
//AnimationHelper.IsGrounded = true;
SetAnim( "JumpLand" );
var shockwaveDmg = 10f + Manager.Instance.Difficulty * 3f;
var shockwaveRadius = Utils.Select( Manager.Instance.Difficulty, 550f, 800f, 900f );
var shockwaveLifetime = 3.5f;
var shockwaveGradient = new Gradient();
shockwaveGradient.AddColor( 0.0f, new Color( 0.9f, 0.05f, 0.05f ) );
shockwaveGradient.AddColor( 0.4f, new Color( 0.4f, 0f, 0f ).WithAlpha( 0.5f ) );
shockwaveGradient.AddColor( 0.5f, new Color( 1f, 0.55f, 0.1f ) );
shockwaveGradient.AddColor( 0.6f, new Color( 0.4f, 0f, 0f ).WithAlpha( 0.5f ) );
shockwaveGradient.AddColor( 1.0f, new Color( 0.9f, 0.05f, 0.05f ) );
Manager.Instance.SpawnShockwave( JumpTargetPos, shockwaveDmg, shockwaveRadius, shockwaveLifetime, force: 400f, gradient: shockwaveGradient, enemySource: this, enemyType: this.EnemyType );
Manager.Instance.ShakeCamsNearby( JumpTargetPos, radius: 400f, maxStrength: 6f, time: 0.4f );
Manager.Instance.PlaySfxNearby( "slam", JumpTargetPos, pitch: Game.Random.Float( 0.85f, 0.95f ), volume: 1f, maxDist: 2000f );
// todo: deeper sfx
int numClouds = Game.Random.Int( 7, 11 );
var startAngle = Game.Random.Float( 0f, 360f );
var increment = 360f / numClouds;
for ( int i = 0; i < numClouds; i++ )
{
var offsetDir = Utils.GetVector2FromAngleDegrees( startAngle );
var pos = WorldPosition + (Vector3)offsetDir * Game.Random.Float( 0.5f, 1f );
pos = pos.WithZ( Game.Random.Float( 9f, 1f ) );
Vector2 velocity = ((Vector2)pos - Position2D).Normal * Game.Random.Float( 700f, 1400f );
var deceleration = Game.Random.Float( 5f, 9f );
Manager.Instance.SpawnCloud( pos, velocity, deceleration, lifetime: Game.Random.Float( 0.5f, 3f ), bright: true );
startAngle += increment * Game.Random.Float( 0.8f, 1.2f );
}
if ( IsProxy )
return;
_timeSinceLanding = 0f;
var dir = (Position2D - JumpStartPos).Normal;
Velocity += dir * Game.Random.Float( 50f, 150f );
SetState( BossState.JumpFinish );
}
}