| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 |
- using Content.Client.Atmos.Components;
- using Content.Shared.Atmos;
- using Robust.Client.GameObjects;
- using Robust.Shared.Map;
- namespace Content.Client.Atmos.EntitySystems;
- /// <summary>
- /// This handles the display of fire effects on flammable entities.
- /// </summary>
- public sealed class FireVisualizerSystem : VisualizerSystem<FireVisualsComponent>
- {
- [Dependency] private readonly PointLightSystem _lights = default!;
- public override void Initialize()
- {
- base.Initialize();
- 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;
- }
- // Need LayerMapTryGet because Init fails if there's no existing sprite / appearancecomp
- // which means in some setups (most frequently no AppearanceComp) the layer never exists.
- if (TryComp<SpriteComponent>(uid, out var sprite) &&
- sprite.LayerMapTryGet(FireVisualLayers.Fire, out var layer))
- {
- sprite.RemoveLayer(layer);
- }
- }
- private void OnComponentInit(EntityUid uid, FireVisualsComponent component, ComponentInit args)
- {
- if (!TryComp<SpriteComponent>(uid, out var sprite) || !TryComp(uid, out AppearanceComponent? appearance))
- return;
- sprite.LayerMapReserveBlank(FireVisualLayers.Fire);
- sprite.LayerSetVisible(FireVisualLayers.Fire, false);
- 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)
- {
- if (args.Sprite != null)
- UpdateAppearance(uid, component, args.Sprite, args.Component);
- }
- private void UpdateAppearance(EntityUid uid, FireVisualsComponent component, SpriteComponent sprite, AppearanceComponent appearance)
- {
- if (!sprite.LayerMapTryGet(FireVisualLayers.Fire, out var index))
- return;
- AppearanceSystem.TryGetData<bool>(uid, FireVisuals.OnFire, out var onFire, appearance);
- AppearanceSystem.TryGetData<float>(uid, FireVisuals.FireStacks, out var fireStacks, appearance);
- sprite.LayerSetVisible(index, onFire);
- if (!onFire)
- {
- 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
- sprite.LayerSetState(index, component.NormalState);
- component.LightEntity ??= Spawn(null, new EntityCoordinates(uid, default));
- var light = EnsureComp<PointLightComponent>(component.LightEntity.Value);
- _lights.SetColor(component.LightEntity.Value, component.LightColor, light);
- // light needs a minimum radius to be visible at all, hence the + 1.5f
- _lights.SetRadius(component.LightEntity.Value, Math.Clamp(1.5f + component.LightRadiusPerStack * fireStacks, 0f, component.MaxLightRadius), light);
- _lights.SetEnergy(component.LightEntity.Value, Math.Clamp(1 + component.LightEnergyPerStack * fireStacks, 0f, component.MaxLightEnergy), light);
- // TODO flickering animation? Or just add a noise mask to the light? But that requires an engine PR.
- }
- }
- public enum FireVisualLayers : byte
- {
- Fire
- }
|