Component that represents a lava puddle effect attached to a game object. It updates a decal size and tint over its lifetime, plays ambient SFX on spawn, and periodically damages the local player if inside the puddle.
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;
}
}