Add point light to burning entities (#12959)
This commit is contained in:
@@ -18,4 +18,25 @@ public sealed class FireVisualsComponent : Component
|
|||||||
|
|
||||||
[DataField("sprite")]
|
[DataField("sprite")]
|
||||||
public string? Sprite;
|
public string? Sprite;
|
||||||
|
|
||||||
|
[DataField("lightEnergyPerStack")]
|
||||||
|
public float LightEnergyPerStack = 0.5f;
|
||||||
|
|
||||||
|
[DataField("lightRadiusPerStack")]
|
||||||
|
public float LightRadiusPerStack = 0.3f;
|
||||||
|
|
||||||
|
[DataField("maxLightEnergy")]
|
||||||
|
public float MaxLightEnergy = 10f;
|
||||||
|
|
||||||
|
[DataField("maxLightRadius")]
|
||||||
|
public float MaxLightRadius = 4f;
|
||||||
|
|
||||||
|
[DataField("lightColor")]
|
||||||
|
public Color LightColor = Color.Orange;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Client side point-light entity. We use this instead of directly adding a light to
|
||||||
|
/// the burning entity as entities don't support having multiple point-lights.
|
||||||
|
/// </summary>
|
||||||
|
public EntityUid? LightEntity;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using Content.Client.Atmos.Components;
|
using Content.Client.Atmos.Components;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
|
using OpenToolkit.Graphics.OpenGL;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
|
||||||
namespace Content.Client.Atmos.EntitySystems;
|
namespace Content.Client.Atmos.EntitySystems;
|
||||||
|
|
||||||
@@ -14,42 +16,76 @@ public sealed class FireVisualizerSystem : VisualizerSystem<FireVisualsComponent
|
|||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<FireVisualsComponent, ComponentInit>(OnComponentInit);
|
SubscribeLocalEvent<FireVisualsComponent, ComponentInit>(OnComponentInit);
|
||||||
|
SubscribeLocalEvent<FireVisualsComponent, ComponentShutdown>(OnShutdown);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnShutdown(EntityUid uid, FireVisualsComponent component, ComponentShutdown args)
|
||||||
|
{
|
||||||
|
if (component.LightEntity != null)
|
||||||
|
{
|
||||||
|
Del(component.LightEntity.Value);
|
||||||
|
component.LightEntity = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TryComp<SpriteComponent>(uid, out var sprite))
|
||||||
|
sprite.RemoveLayer(FireVisualLayers.Fire);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnComponentInit(EntityUid uid, FireVisualsComponent component, ComponentInit args)
|
private void OnComponentInit(EntityUid uid, FireVisualsComponent component, ComponentInit args)
|
||||||
{
|
{
|
||||||
if (!TryComp<SpriteComponent>(uid, out var sprite))
|
if (!TryComp<SpriteComponent>(uid, out var sprite) || !TryComp(uid, out AppearanceComponent? appearance))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
sprite.LayerMapReserveBlank(FireVisualLayers.Fire);
|
sprite.LayerMapReserveBlank(FireVisualLayers.Fire);
|
||||||
sprite.LayerSetVisible(FireVisualLayers.Fire, false);
|
sprite.LayerSetVisible(FireVisualLayers.Fire, false);
|
||||||
sprite.LayerSetShader(FireVisualLayers.Fire, "unshaded");
|
sprite.LayerSetShader(FireVisualLayers.Fire, "unshaded");
|
||||||
|
if (component.Sprite != null)
|
||||||
|
sprite.LayerSetRSI(FireVisualLayers.Fire, component.Sprite);
|
||||||
|
|
||||||
|
UpdateAppearance(uid, component, sprite, appearance);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnAppearanceChange(EntityUid uid, FireVisualsComponent component, ref AppearanceChangeEvent args)
|
protected override void OnAppearanceChange(EntityUid uid, FireVisualsComponent component, ref AppearanceChangeEvent args)
|
||||||
{
|
{
|
||||||
if (!args.Component.TryGetData(FireVisuals.OnFire, out bool onFire) ||
|
if (args.Sprite != null)
|
||||||
!TryComp<SpriteComponent>(component.Owner, out var sprite))
|
UpdateAppearance(uid, component, args.Sprite, args.Component);
|
||||||
return;
|
|
||||||
|
|
||||||
var fireStacks = 0f;
|
|
||||||
if (args.Component.TryGetData(FireVisuals.FireStacks, out float stacks))
|
|
||||||
fireStacks = stacks;
|
|
||||||
|
|
||||||
SetOnFire(sprite, args.Component, component, onFire, fireStacks);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetOnFire(SpriteComponent sprite, AppearanceComponent appearance, FireVisualsComponent component, bool onFire, float fireStacks)
|
private void UpdateAppearance(EntityUid uid, FireVisualsComponent component, SpriteComponent sprite, AppearanceComponent appearance)
|
||||||
{
|
{
|
||||||
if (component.Sprite != null)
|
if (!sprite.LayerMapTryGet(FireVisualLayers.Fire, out var index))
|
||||||
sprite.LayerSetRSI(FireVisualLayers.Fire, component.Sprite);
|
return;
|
||||||
|
|
||||||
sprite.LayerSetVisible(FireVisualLayers.Fire, onFire);
|
appearance.TryGetData(FireVisuals.OnFire, out bool onFire);
|
||||||
|
appearance.TryGetData(FireVisuals.FireStacks, out float fireStacks);
|
||||||
|
sprite.LayerSetVisible(index, onFire);
|
||||||
|
|
||||||
if(fireStacks > component.FireStackAlternateState && !string.IsNullOrEmpty(component.AlternateState))
|
if (!onFire)
|
||||||
sprite.LayerSetState(FireVisualLayers.Fire, component.AlternateState);
|
{
|
||||||
|
if (component.LightEntity != null)
|
||||||
|
{
|
||||||
|
Del(component.LightEntity.Value);
|
||||||
|
component.LightEntity = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fireStacks > component.FireStackAlternateState && !string.IsNullOrEmpty(component.AlternateState))
|
||||||
|
sprite.LayerSetState(index, component.AlternateState);
|
||||||
else
|
else
|
||||||
sprite.LayerSetState(FireVisualLayers.Fire, component.NormalState);
|
sprite.LayerSetState(index, component.NormalState);
|
||||||
|
|
||||||
|
component.LightEntity ??= Spawn(null, new EntityCoordinates(uid, default));
|
||||||
|
var light = EnsureComp<PointLightComponent>(component.LightEntity.Value);
|
||||||
|
|
||||||
|
light.Color = component.LightColor;
|
||||||
|
|
||||||
|
// light needs a minimum radius to be visible at all, hence the + 1.5f
|
||||||
|
light.Radius = Math.Clamp(1.5f + component.LightRadiusPerStack * fireStacks, 0f, component.MaxLightRadius);
|
||||||
|
light.Energy = Math.Clamp(1 + component.LightEnergyPerStack * fireStacks, 0f, component.MaxLightEnergy);
|
||||||
|
|
||||||
|
// TODO flickering animation? Or just add a noise mask to the light? But that requires an engine PR.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
Act = () =>
|
Act = () =>
|
||||||
{
|
{
|
||||||
// Fuck you. Burn Forever.
|
// Fuck you. Burn Forever.
|
||||||
flammable.FireStacks = 99999.9f;
|
flammable.FireStacks = FlammableSystem.MaximumFireStacks;
|
||||||
_flammableSystem.Ignite(args.Target);
|
_flammableSystem.Ignite(args.Target);
|
||||||
var xform = Transform(args.Target);
|
var xform = Transform(args.Target);
|
||||||
_popupSystem.PopupEntity(Loc.GetString("admin-smite-set-alight-self"), args.Target,
|
_popupSystem.PopupEntity(Loc.GetString("admin-smite-set-alight-self"), args.Target,
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ using Robust.Shared.Physics.Systems;
|
|||||||
|
|
||||||
namespace Content.Server.Atmos.EntitySystems
|
namespace Content.Server.Atmos.EntitySystems
|
||||||
{
|
{
|
||||||
internal sealed class FlammableSystem : EntitySystem
|
public sealed class FlammableSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
||||||
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
||||||
@@ -35,11 +35,11 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
[Dependency] private readonly FixtureSystem _fixture = default!;
|
[Dependency] private readonly FixtureSystem _fixture = default!;
|
||||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
||||||
|
|
||||||
private const float MinimumFireStacks = -10f;
|
public const float MinimumFireStacks = -10f;
|
||||||
private const float MaximumFireStacks = 20f;
|
public const float MaximumFireStacks = 20f;
|
||||||
private const float UpdateTime = 1f;
|
private const float UpdateTime = 1f;
|
||||||
|
|
||||||
private const float MinIgnitionTemperature = 373.15f;
|
public const float MinIgnitionTemperature = 373.15f;
|
||||||
public const string FlammableFixtureID = "flammable";
|
public const string FlammableFixtureID = "flammable";
|
||||||
|
|
||||||
private float _timer = 0f;
|
private float _timer = 0f;
|
||||||
|
|||||||
Reference in New Issue
Block a user