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