Player/PlayerFallDamage.cs
/// <summary>
/// Apply fall damage to the player
/// </summary>
public class PlayerFallDamage : Component, Local.IPlayerEvents
{
[RequireComponent] public Player Player { get; set; }
/// <summary>
/// Fatal fall speed, you will die if you fall at or above this speed
/// </summary>
[Property] public float FatalFallSpeed { get; set; } = 1536.0f;
/// <summary>
/// Maximum safe fall speed, you won't take damage at or below this speed
/// </summary>
[Property] public float MaxSafeFallSpeed { get; set; } = 512.0f;
/// <summary>
/// Multiply damage amount by this much
/// </summary>
[Property] public float DamageMultiplier { get; set; } = 1.0f;
/// <summary>
/// Fall damage sound
/// </summary>
[Property] public SoundEvent FallSound { get; set; }
[Rpc.Owner]
private void PlayFallSound()
{
GameObject.PlaySound( FallSound );
}
void Local.IPlayerEvents.OnLand( float distance, Vector3 velocity )
{
var fallSpeed = Math.Abs( velocity.z );
if ( fallSpeed <= MaxSafeFallSpeed )
return;
var damageAmount = MathX.Remap( fallSpeed, MaxSafeFallSpeed, FatalFallSpeed, 0f, 100f ) * DamageMultiplier;
if ( damageAmount < 1 ) return;
if ( Networking.IsHost && damageAmount >= Player.Health )
Player.PlayerData?.AddStat( "player.fall.death" );
TakeFallDamage( damageAmount );
}
[Rpc.Broadcast]
public void TakeFallDamage( float amount )
{
if ( !Networking.IsHost ) return;
if ( Player is IDamageable damage )
{
var dmg = new DamageInfo( amount.CeilToInt(), Player.GameObject, null );
dmg.Tags.Add( DamageTags.Fall );
damage.OnDamage( dmg );
PlayFallSound();
}
}
}