diff --git a/Content.Client/Atmos/Components/FireVisualsComponent.cs b/Content.Client/Atmos/Components/FireVisualsComponent.cs
new file mode 100644
index 0000000000..3d61879132
--- /dev/null
+++ b/Content.Client/Atmos/Components/FireVisualsComponent.cs
@@ -0,0 +1,21 @@
+namespace Content.Client.Atmos.Components;
+
+///
+/// Sets which sprite RSI is used for displaying the fire visuals and what state to use based on the fire stacks
+/// accumulated.
+///
+[RegisterComponent]
+public sealed class FireVisualsComponent : Component
+{
+ [DataField("fireStackAlternateState")]
+ public int FireStackAlternateState = 3;
+
+ [DataField("normalState")]
+ public string? NormalState;
+
+ [DataField("alternateState")]
+ public string? AlternateState;
+
+ [DataField("sprite")]
+ public string? Sprite;
+}
diff --git a/Content.Client/Atmos/EntitySystems/FireVisualizerSystem.cs b/Content.Client/Atmos/EntitySystems/FireVisualizerSystem.cs
new file mode 100644
index 0000000000..7f58cbe409
--- /dev/null
+++ b/Content.Client/Atmos/EntitySystems/FireVisualizerSystem.cs
@@ -0,0 +1,59 @@
+using Content.Client.Atmos.Components;
+using Content.Shared.Atmos;
+using Robust.Client.GameObjects;
+
+namespace Content.Client.Atmos.EntitySystems;
+
+///
+/// This handles the display of fire effects on flammable entities.
+///
+public sealed class FireVisualizerSystem : VisualizerSystem
+{
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnComponentInit);
+ }
+
+ private void OnComponentInit(EntityUid uid, FireVisualsComponent component, ComponentInit args)
+ {
+ if (!TryComp(uid, out var sprite))
+ return;
+
+ sprite.LayerMapReserveBlank(FireVisualLayers.Fire);
+ sprite.LayerSetVisible(FireVisualLayers.Fire, false);
+ sprite.LayerSetShader(FireVisualLayers.Fire, "unshaded");
+ }
+
+ protected override void OnAppearanceChange(EntityUid uid, FireVisualsComponent component, ref AppearanceChangeEvent args)
+ {
+ if (!args.Component.TryGetData(FireVisuals.OnFire, out bool onFire) ||
+ !TryComp(component.Owner, out var sprite))
+ 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)
+ {
+ if (component.Sprite != null)
+ sprite.LayerSetRSI(FireVisualLayers.Fire, component.Sprite);
+
+ sprite.LayerSetVisible(FireVisualLayers.Fire, onFire);
+
+ if(fireStacks > component.FireStackAlternateState && !string.IsNullOrEmpty(component.AlternateState))
+ sprite.LayerSetState(FireVisualLayers.Fire, component.AlternateState);
+ else
+ sprite.LayerSetState(FireVisualLayers.Fire, component.NormalState);
+ }
+}
+
+public enum FireVisualLayers : byte
+{
+ Fire
+}
diff --git a/Content.Client/Atmos/Visualizers/AtmosPlaqueVisualizer.cs b/Content.Client/Atmos/Visualizers/AtmosPlaqueVisualizer.cs
deleted file mode 100644
index 80382624dd..0000000000
--- a/Content.Client/Atmos/Visualizers/AtmosPlaqueVisualizer.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using Content.Shared.Atmos.Visuals;
-using JetBrains.Annotations;
-using Robust.Client.GameObjects;
-using Robust.Shared.GameObjects;
-using Robust.Shared.IoC;
-using Robust.Shared.Serialization.Manager.Attributes;
-
-namespace Content.Client.Atmos.Visualizers
-{
- [UsedImplicitly]
- public sealed class AtmosPlaqueVisualizer : AppearanceVisualizer
- {
- [DataField("layer")]
- private int Layer { get; }
-
- public override void InitializeEntity(EntityUid entity)
- {
- base.InitializeEntity(entity);
-
- IoCManager.Resolve().GetComponentOrNull(entity);
- }
-
- public override void OnChangeData(AppearanceComponent component)
- {
- base.OnChangeData(component);
-
- if (!IoCManager.Resolve().TryGetComponent(component.Owner, out SpriteComponent? sprite))
- {
- return;
- }
-
- if (!component.TryGetData(AtmosPlaqueVisuals.State, out string state))
- {
- sprite.LayerSetState(Layer, state);
- }
- }
- }
-}
diff --git a/Content.Client/Atmos/Visualizers/FireVisualizer.cs b/Content.Client/Atmos/Visualizers/FireVisualizer.cs
deleted file mode 100644
index fe84d6bf6c..0000000000
--- a/Content.Client/Atmos/Visualizers/FireVisualizer.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-using Content.Shared.Atmos;
-using JetBrains.Annotations;
-using Robust.Client.GameObjects;
-using Robust.Shared.GameObjects;
-using Robust.Shared.IoC;
-using Robust.Shared.Serialization.Manager.Attributes;
-
-namespace Content.Client.Atmos.Visualizers
-{
- [UsedImplicitly]
- public sealed class FireVisualizer : AppearanceVisualizer
- {
- [DataField("fireStackAlternateState")]
- private int _fireStackAlternateState = 3;
-
- [DataField("normalState")]
- private string? _normalState;
-
- [DataField("alternateState")]
- private string? _alternateState;
-
- [DataField("sprite")]
- private string? _sprite;
-
- public override void InitializeEntity(EntityUid entity)
- {
- base.InitializeEntity(entity);
-
- var sprite = IoCManager.Resolve().GetComponent(entity);
-
- sprite.LayerMapReserveBlank(FireVisualLayers.Fire);
- sprite.LayerSetVisible(FireVisualLayers.Fire, false);
- sprite.LayerSetShader(FireVisualLayers.Fire, "unshaded");
- }
-
- public override void OnChangeData(AppearanceComponent component)
- {
- base.OnChangeData(component);
-
- if (component.TryGetData(FireVisuals.OnFire, out bool onFire))
- {
- var fireStacks = 0f;
-
- if (component.TryGetData(FireVisuals.FireStacks, out float stacks))
- fireStacks = stacks;
-
- SetOnFire(component, onFire, fireStacks);
- }
- }
-
- private void SetOnFire(AppearanceComponent component, bool onFire, float fireStacks)
- {
- var sprite = IoCManager.Resolve().GetComponent(component.Owner);
-
- if (_sprite != null)
- {
- sprite.LayerSetRSI(FireVisualLayers.Fire, _sprite);
- }
-
- sprite.LayerSetVisible(FireVisualLayers.Fire, onFire);
-
- if(fireStacks > _fireStackAlternateState && !string.IsNullOrEmpty(_alternateState))
- sprite.LayerSetState(FireVisualLayers.Fire, _alternateState);
- else
- sprite.LayerSetState(FireVisualLayers.Fire, _normalState);
- }
- }
-
- public enum FireVisualLayers : byte
- {
- Fire
- }
-}
diff --git a/Content.Client/Atmos/Visualizers/GasAnalyzerVisualizer.cs b/Content.Client/Atmos/Visualizers/GasAnalyzerVisualizer.cs
deleted file mode 100644
index 6875174036..0000000000
--- a/Content.Client/Atmos/Visualizers/GasAnalyzerVisualizer.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using Content.Shared.Atmos.Components;
-using JetBrains.Annotations;
-using Robust.Client.GameObjects;
-using Robust.Shared.GameObjects;
-using Robust.Shared.IoC;
-using Robust.Shared.Serialization.Manager.Attributes;
-
-namespace Content.Client.Atmos.Visualizers
-{
- [UsedImplicitly]
- public sealed class GasAnalyzerVisualizer : AppearanceVisualizer
- {
- [DataField("state_off")]
- private string? _stateOff;
- [DataField("state_working")]
- private string? _stateWorking;
-
- public override void OnChangeData(AppearanceComponent component)
- {
- base.OnChangeData(component);
-
- var entities = IoCManager.Resolve();
- if (!entities.TryGetComponent(component.Owner, out ISpriteComponent? sprite))
- {
- return;
- }
-
- if (component.TryGetData(GasAnalyzerVisuals.VisualState, out GasAnalyzerVisualState visualState))
- {
- switch (visualState)
- {
- case GasAnalyzerVisualState.Off:
- sprite.LayerSetState(0, _stateOff);
- break;
- case GasAnalyzerVisualState.Working:
- sprite.LayerSetState(0, _stateWorking);
- break;
- }
- }
- }
- }
-}
diff --git a/Content.Client/Atmos/Visualizers/GasCanisterVisualizer.cs b/Content.Client/Atmos/Visualizers/GasCanisterVisualizer.cs
deleted file mode 100644
index d89acfc342..0000000000
--- a/Content.Client/Atmos/Visualizers/GasCanisterVisualizer.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using Content.Shared.Atmos.Piping.Binary.Components;
-using JetBrains.Annotations;
-using Robust.Client.GameObjects;
-using Robust.Shared.GameObjects;
-using Robust.Shared.IoC;
-using Robust.Shared.Serialization.Manager.Attributes;
-
-namespace Content.Client.Atmos.Visualizers
-{
- [UsedImplicitly]
- public sealed class GasCanisterVisualizer : AppearanceVisualizer
- {
- [DataField("pressureStates")]
- private readonly string[] _statePressure = {"", "", "", ""};
-
- [DataField("insertedTankState")]
- private readonly string _insertedTankState = string.Empty;
-
- public override void InitializeEntity(EntityUid entity)
- {
- base.InitializeEntity(entity);
-
- var sprite = IoCManager.Resolve().GetComponent(entity);
-
- sprite.LayerMapSet(Layers.PressureLight, sprite.AddLayerState(_statePressure[0]));
- sprite.LayerSetShader(Layers.PressureLight, "unshaded");
- sprite.LayerMapSet(Layers.TankInserted, sprite.AddLayerState(_insertedTankState));
- sprite.LayerSetVisible(Layers.TankInserted, false);
- }
-
- public override void OnChangeData(AppearanceComponent component)
- {
- base.OnChangeData(component);
-
- var entities = IoCManager.Resolve();
- if (!entities.TryGetComponent(component.Owner, out ISpriteComponent? sprite))
- {
- return;
- }
-
- // Update the canister lights
- if (component.TryGetData(GasCanisterVisuals.PressureState, out int pressureState))
- if ((pressureState >= 0) && (pressureState < _statePressure.Length))
- sprite.LayerSetState(Layers.PressureLight, _statePressure[pressureState]);
-
- if(component.TryGetData(GasCanisterVisuals.TankInserted, out bool inserted))
- sprite.LayerSetVisible(Layers.TankInserted, inserted);
- }
-
- private enum Layers
- {
- PressureLight,
- TankInserted,
- }
- }
-}
diff --git a/Content.Client/Atmos/Visualizers/GasPortableVisualizer.cs b/Content.Client/Atmos/Visualizers/GasPortableVisualizer.cs
deleted file mode 100644
index de8beba07d..0000000000
--- a/Content.Client/Atmos/Visualizers/GasPortableVisualizer.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-using Content.Shared.Atmos.Piping.Unary.Components;
-using JetBrains.Annotations;
-using Robust.Client.GameObjects;
-using Robust.Shared.GameObjects;
-using Robust.Shared.IoC;
-using Robust.Shared.Serialization.Manager.Attributes;
-
-namespace Content.Client.Atmos.Visualizers
-{
- [UsedImplicitly]
- public sealed class GasPortableVisualizer : AppearanceVisualizer
- {
- [DataField("stateConnected")]
- private string? _stateConnected;
-
- public override void InitializeEntity(EntityUid entity)
- {
- base.InitializeEntity(entity);
-
- var sprite = IoCManager.Resolve().GetComponent(entity);
-
- if (_stateConnected != null)
- {
- sprite.LayerMapSet(Layers.ConnectedToPort, sprite.AddLayerState(_stateConnected));
- sprite.LayerSetVisible(Layers.ConnectedToPort, false);
- }
- }
-
- public override void OnChangeData(AppearanceComponent component)
- {
- base.OnChangeData(component);
-
- var entities = IoCManager.Resolve();
- if (!entities.TryGetComponent(component.Owner, out ISpriteComponent? sprite))
- {
- return;
- }
-
- // Update the visuals : Is the canister connected to a port or not
- if (component.TryGetData(GasPortableVisuals.ConnectedState, out bool isConnected))
- {
- sprite.LayerSetVisible(Layers.ConnectedToPort, isConnected);
- }
- }
-
- private enum Layers : byte
- {
- ConnectedToPort,
- }
- }
-}
diff --git a/Content.Server/Entry/IgnoredComponents.cs b/Content.Server/Entry/IgnoredComponents.cs
index 2e4efce527..b5530768be 100644
--- a/Content.Server/Entry/IgnoredComponents.cs
+++ b/Content.Server/Entry/IgnoredComponents.cs
@@ -35,6 +35,7 @@ namespace Content.Server.Entry
"AMEControllerVisuals",
"AMEShieldingVisuals",
"PipeColorVisuals",
+ "FireVisuals",
};
}
}
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
index 2aa24672df..3c21bb71d3 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
@@ -727,10 +727,9 @@
Dead:
Base: dead
- type: Appearance
- visuals:
- - type: FireVisualizer
- sprite: Mobs/Effects/onfire.rsi
- normalState: Monkey_burning
+ - type: FireVisuals
+ sprite: Mobs/Effects/onfire.rsi
+ normalState: Monkey_burning
- type: Butcherable
butcheringType: Spike
spawned:
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml b/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml
index a4d6c14270..eaaeabfee1 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml
@@ -125,9 +125,9 @@
- type: Appearance
visuals:
- type: BuckleVisualizer
- - type: FireVisualizer
- sprite: Mobs/Effects/onfire.rsi
- normalState: Generic_mob_burning
+ - type: FireVisuals
+ sprite: Effects/fire.rsi
+ normalState: Generic_mob_burning
- type: Actions
- type: DoAfter
- type: Climbing
diff --git a/Resources/Prototypes/Entities/Mobs/Species/human.yml b/Resources/Prototypes/Entities/Mobs/Species/human.yml
index e2eab6419a..e8359ff04f 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/human.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/human.yml
@@ -256,11 +256,6 @@
visuals:
- type: RotationVisualizer
- type: BuckleVisualizer
- - type: FireVisualizer
- sprite: Mobs/Effects/onfire.rsi
- normalState: Generic_mob_burning
- alternateState: Standing
- fireStackAlternateState: 3
- type: CreamPiedVisualizer
state: creampie_human
- type: DamageVisualizer
@@ -278,6 +273,11 @@
color: "#FF0000"
Burn:
sprite: Mobs/Effects/burn_damage.rsi
+ - type: FireVisuals
+ sprite: Mobs/Effects/onfire.rsi
+ normalState: Generic_mob_burning
+ alternateState: Standing
+ fireStackAlternateState: 3
- type: CombatMode
- type: Climbing
- type: Cuffable
diff --git a/Resources/Prototypes/Entities/Mobs/Species/skeleton.yml b/Resources/Prototypes/Entities/Mobs/Species/skeleton.yml
index bedf5f8c5d..256444a92a 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/skeleton.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/skeleton.yml
@@ -203,11 +203,6 @@
visuals:
- type: RotationVisualizer
- type: BuckleVisualizer
- - type: FireVisualizer
- sprite: Mobs/Effects/onfire.rsi
- normalState: Generic_mob_burning
- alternateState: Standing
- fireStackAlternateState: 3
- type: CreamPiedVisualizer
state: creampie_human
- type: DamageVisualizer
@@ -225,6 +220,11 @@
color: "#8a8a8a"
Burn:
sprite: Mobs/Effects/burn_damage.rsi
+ - type: FireVisuals
+ sprite: Mobs/Effects/onfire.rsi
+ normalState: Generic_mob_burning
+ alternateState: Standing
+ fireStackAlternateState: 3
- type: CombatMode
canDisarm: true
- type: Climbing
diff --git a/Resources/Prototypes/Entities/Objects/Specific/atmos.yml b/Resources/Prototypes/Entities/Objects/Specific/atmos.yml
index 69b844021b..0f944d26c4 100644
--- a/Resources/Prototypes/Entities/Objects/Specific/atmos.yml
+++ b/Resources/Prototypes/Entities/Objects/Specific/atmos.yml
@@ -6,7 +6,9 @@
components:
- type: Sprite
sprite: Objects/Specific/Atmos/gasanalyzer.rsi
- state: icon
+ layers:
+ - state: icon
+ map: ["analyzer"]
netsync: false
- type: GasAnalyzer
- type: ActivatableUI
@@ -16,10 +18,12 @@
- key: enum.GasAnalyzerUiKey.Key
type: GasAnalyzerBoundUserInterface
- type: Appearance
+ - type: GenericVisualizer
visuals:
- - type: GasAnalyzerVisualizer
- state_off: icon
- state_working: working
+ enum.GasAnalyzerVisuals.VisualState:
+ analyzer:
+ Off: { state: icon }
+ Working: { state: working }
- type: Tag
tags:
- DroneUsable
diff --git a/Resources/Prototypes/Entities/Objects/Tools/cowtools.yml b/Resources/Prototypes/Entities/Objects/Tools/cowtools.yml
index 70a4780199..4039694bbf 100644
--- a/Resources/Prototypes/Entities/Objects/Tools/cowtools.yml
+++ b/Resources/Prototypes/Entities/Objects/Tools/cowtools.yml
@@ -43,7 +43,7 @@
- type: Tool
qualities:
- Screwing
- useSound:
+ useSound:
collection: Screwdriver
speed: 0.05
@@ -138,17 +138,14 @@
components:
- type: Sprite
sprite: Objects/Tools/Cowtools/milkalyzer.rsi
- state: milkalyzer
+ layers:
+ - state: milkalyzer
- type: GasAnalyzer
- type: UserInterface
interfaces:
- key: enum.GasAnalyzerUiKey.Key
type: GasAnalyzerBoundUserInterface
- type: Appearance
- visuals:
- - type: GasAnalyzerVisualizer
- state_off: milkalyzer
- state_working: milkalyzer
- type: entity
name: cow toolbox
diff --git a/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml b/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml
index 1a29d4a95a..0645bb1542 100644
--- a/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml
+++ b/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml
@@ -11,18 +11,25 @@
- type: Sprite
netsync: false
sprite: Structures/Storage/canister.rsi
- state: grey
+ layers:
+ - state: grey
- type: Appearance
+ - type: GenericVisualizer
visuals:
- - type: GasPortableVisualizer
- stateConnected: can-connector
- - type: GasCanisterVisualizer
- insertedTankState: can-open
- pressureStates:
- - can-o0
- - can-o1
- - can-o2
- - can-o3
+ enum.GasPortableVisuals.ConnectedState:
+ connectedToPort:
+ False: { state: can-connector, visible: false }
+ True: { state: can-connector, visible: true }
+ enum.GasCanisterVisuals.TankInserted:
+ tankInserted:
+ False: { state: can-open, visible: false }
+ True: { state: can-open, visible: true }
+ enum.GasCanisterVisuals.PressureState:
+ pressureLight:
+ 0: { state: can-o0, shader: "unshaded" }
+ 1: { state: can-o1, shader: "unshaded" }
+ 2: { state: can-o2, shader: "unshaded" }
+ 3: { state: can-o3, shader: "unshaded" }
- type: UserInterface
interfaces:
- key: enum.GasCanisterUiKey.Key
@@ -80,7 +87,8 @@
name: storage canister
components:
- type: Sprite
- state: yellow # Classic toxins canister
+ layers:
+ - state: yellow
- type: GasCanister
gasMixture:
volume: 1000
@@ -117,7 +125,8 @@
name: air canister
components:
- type: Sprite
- state: grey
+ layers:
+ - state: grey
- type: GasCanister
gasMixture:
volume: 1000
@@ -148,7 +157,8 @@
name: oxygen canister
components:
- type: Sprite
- state: blue
+ layers:
+ - state: blue
- type: GasCanister
gasMixture:
volume: 1000
@@ -178,7 +188,8 @@
name: nitrogen canister
components:
- type: Sprite
- state: red
+ layers:
+ - state: red
- type: GasCanister
gasMixture:
volume: 1000
@@ -209,7 +220,8 @@
name: carbon dioxide canister
components:
- type: Sprite
- state: black
+ layers:
+ - state: black
- type: GasCanister
gasMixture:
volume: 1000
@@ -241,7 +253,8 @@
name: plasma canister
components:
- type: Sprite
- state: orange
+ layers:
+ - state: orange
- type: GasCanister
gasMixture:
volume: 1000
@@ -275,7 +288,8 @@
name: tritium canister
components:
- type: Sprite
- state: green
+ layers:
+ - state: green
- type: GasCanister
gasMixture:
volume: 1000
@@ -309,7 +323,8 @@
name: water vapor canister
components:
- type: Sprite
- state: water_vapor
+ layers:
+ - state: water_vapor
- type: GasCanister
gasMixture:
volume: 1000
@@ -344,7 +359,8 @@
name: miasma canister
components:
- type: Sprite
- state: redws
+ layers:
+ - state: redws
- type: GasCanister
gasMixture:
volume: 1000
diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/atmos_plaque.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/atmos_plaque.yml
index 24721af70f..009f7dc520 100644
--- a/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/atmos_plaque.yml
+++ b/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/atmos_plaque.yml
@@ -13,5 +13,14 @@
layer:
- MidImpassable
- type: Sprite
- state: atmosplaque
+ layers:
+ - state: atmosplaque
+ map: ["plaque"]
+ - type: Appearance
+ - type: GenericVisualizer
+ visuals:
+ enum.AtmosPlaqueVisuals.State:
+ plaque:
+ zumosplaque: { state: zumosplaque }
+ atmosplaque: { state: atmosplaque }
- type: AtmosPlaque
diff --git a/Resources/Prototypes/Entities/Structures/Walls/barricades.yml b/Resources/Prototypes/Entities/Structures/Walls/barricades.yml
index e0614ed1f6..e77f8e9bef 100644
--- a/Resources/Prototypes/Entities/Structures/Walls/barricades.yml
+++ b/Resources/Prototypes/Entities/Structures/Walls/barricades.yml
@@ -45,9 +45,6 @@
types:
Heat: 1 #per second, scales with number of fire 'stacks'
- type: Appearance
- visuals:
- - type: FireVisualizer
- sprite: Effects/fire.rsi
- normalState: 1
- Sprite:
- drawdepth: Effects
+ - type: FireVisuals
+ sprite: Effects/fire.rsi
+ normalState: 1