Partial Boss class handling jump behavior. Initializes timers and delays for regular and "jump away" actions, triggers prepare RPC and animations, performs the jump effect (spawning cloud prefab, playing SFX), and applies landing effects like shockwave damage, camera shake, particles and state transitions.
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 );
}
}