things/enemies/Boss.Jumping.cs

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.

NetworkingExternal DownloadFile Access
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 );
	}
}