A client-created lava puddle component that displays a decal, plays sound on spawn, sizes and tints the decal over its lifetime, and applies periodic lava damage to the local player if they stand inside the radius. It also tracks an enemy source/type for damage attribution and destroys itself after Lifetime seconds.
using System;
using Sandbox;
using static Sandbox.VertexLayout;
/// <summary>
/// LavaPuddle is created on client and can't hurt proxy players.
/// </summary>
public class LavaPuddle : Component
{
[Property] public Decal Decal { get; set; }
private Dictionary<Player, bool> _playerShockwaveChecks;
private List<Player> _shockwaveDamagedPlayers;
public Enemy EnemySource { get; set; }
public EnemyType EnemyType { get; set; }
[Property, Hide] public float Damage { get; set; }
[Property, Hide] public float Radius { get; set; }
[Property, Hide] public float Lifetime { get; set; }
[Property, Hide] public Color ColorA { get; set; }
[Property, Hide] public Color ColorB { get; set; }
[Property, Hide] public float AlphaMax { get; set; }
public TimeSince TimeSinceSpawn { get; set; }
private TimeSince _timeSinceDamagePlayer;
private const float DAMAGE_INTERVAL = 0.33f;
protected override void OnStart()
{
base.OnStart();
if ( IsProxy )
return;
_playerShockwaveChecks = new();
_shockwaveDamagedPlayers = new();
TimeSinceSpawn = 0f;
Manager.Instance.PlaySfxNearby( "lava_puddle_02", (Vector2)WorldPosition, pitch: Game.Random.Float( 0.9f, 1.1f ), volume: 1.4f, maxDist: 500f );
if ( Scene.GetAll<LavaPuddle>().Count() <= 1 )
Manager.Instance.PlaySfxNearby( "lava_puddle_01", (Vector2)WorldPosition, pitch: Game.Random.Float( 0.9f, 1.1f ), volume: 1.4f, maxDist: 500f );
}
protected override void OnUpdate()
{
base.OnUpdate();
if ( Manager.Instance.IsGameOver )
return;
var pos = (Vector2)WorldPosition;
if ( TimeSinceSpawn > Lifetime )
{
GameObject.Destroy();
return;
}
else
{
var decalSize = Radius * 0.285f * Utils.Map( TimeSinceSpawn, 0f, 0.5f, 0f, 1f, EasingType.SineOut );
Decal.Size = new Vector2( decalSize, decalSize );
var color = Color.Lerp( ColorA, ColorB, 0.5f + Utils.FastSin(Time.Now * 12f) * 0.5f );
Decal.ColorTint = color.WithAlpha( Utils.Map( TimeSinceSpawn, Lifetime - 0.5f, Lifetime, AlphaMax, 0f ) );
if ( TimeSinceSpawn > 0.5f && TimeSinceSpawn < Lifetime - 0.5f && _timeSinceDamagePlayer > DAMAGE_INTERVAL )
{
var player = Manager.Instance.LocalPlayer;
if ( !player.IsValid() )
return;
var lavaPos = (Vector2)WorldPosition;
float distSqr = (player.Position2D - lavaPos).LengthSquared;
if ( distSqr < MathF.Pow( Radius, 2f ) && !player.IsDead && player.TimeSinceHurtLava > DAMAGE_INTERVAL)
{
var dir = Utils.GetRandomVector();
player.DamageRpc( Damage, DamageType.LavaPuddle, player.Position2D, dir, upwardAmount: Game.Random.Float(0f, 0.2f), force: 0f, ragdollForce: 0f, EnemySource, EnemyType );
player.TimeSinceHurtLava = 0f;
_timeSinceDamagePlayer = 0f;
}
}
}
//Gizmo.Draw.Color = Color.White.WithAlpha( 0.8f + Utils.FastSin( Time.Now * 12f ) * 0.2f );// * Utils.Map( _shockwaveTimer, Lifetime - 0.25f, Lifetime, 1f, 0f );
//Gizmo.Draw.LineThickness = 1f;
//Gizmo.Draw.LineCircle(
// center: (Vector3)pos + Vector3.Up * 1f,
// forward: Vector3.Up,
// radius: Radius,
// startAngle: Time.Now * -150f,
// totalDegrees: 360f,
// sections: 50
//);
if ( IsProxy )
return;
}
}