diff --git a/Content.Client/Cloning/CloningPodVisualizer.cs b/Content.Client/Cloning/CloningPodVisualizer.cs deleted file mode 100644 index 6a16cbe281..0000000000 --- a/Content.Client/Cloning/CloningPodVisualizer.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using JetBrains.Annotations; -using Robust.Client.GameObjects; -using static Content.Shared.Cloning.SharedCloningPodComponent; -using static Content.Shared.Cloning.SharedCloningPodComponent.CloningPodStatus; - -namespace Content.Client.Cloning -{ - [UsedImplicitly] - public class CloningPodVisualizer : AppearanceVisualizer - { - public override void OnChangeData(AppearanceComponent component) - { - base.OnChangeData(component); - - var sprite = component.Owner.GetComponent(); - if (!component.TryGetData(CloningPodVisuals.Status, out CloningPodStatus status)) return; - sprite.LayerSetState(CloningPodVisualLayers.Machine, StatusToMachineStateId(status)); - } - - private string StatusToMachineStateId(CloningPodStatus status) - { - //TODO: implement NoMind for if the mind is not yet in the body - //TODO: Find a use for GORE POD - switch (status) - { - case CloningPodStatus.Cloning: return "pod_1"; - case NoMind: return "pod_e"; - case Gore: return "pod_g"; - case Idle: return "pod_0"; - default: - throw new ArgumentOutOfRangeException(nameof(status), status, "unknown CloningPodStatus"); - } - } - - public enum CloningPodVisualLayers : byte - { - Machine, - } - } -} diff --git a/Content.Client/Visualizer/GenericEnumVisualizer.cs b/Content.Client/Visualizer/GenericEnumVisualizer.cs new file mode 100644 index 0000000000..27faff66b7 --- /dev/null +++ b/Content.Client/Visualizer/GenericEnumVisualizer.cs @@ -0,0 +1,63 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using JetBrains.Annotations; +using Robust.Client.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Log; +using Robust.Shared.Reflection; +using Robust.Shared.Serialization; +using Robust.Shared.Serialization.Manager.Attributes; + +namespace Content.Client.Visualizer +{ + [UsedImplicitly] + public class GenericEnumVisualizer : AppearanceVisualizer, ISerializationHooks + { + public Enum Key { get; set; } = default!; + + public Dictionary States { get; set; } = default!; + + [DataField("layer")] + public int Layer { get; set; } = 0; + + [DataField("key", readOnly: true, required: true)] + private string _keyRaw = default!; + + [DataField("states", readOnly: true, required: true)] + private Dictionary _statesRaw { get; set; } = default!; + + void ISerializationHooks.AfterDeserialization() + { + var reflectionManager = IoCManager.Resolve(); + + object ResolveRef(string raw) + { + if (reflectionManager.TryParseEnumReference(raw, out var @enum)) + { + return @enum; + } + else + { + Logger.WarningS("c.c.v.genum", $"Unable to convert enum reference: {raw}"); + } + + return raw; + } + + // It's important that this conversion be done here so that it may "fail-fast". + Key = (Enum) ResolveRef(_keyRaw); + States = _statesRaw.ToDictionary(kvp => ResolveRef(kvp.Key), kvp => kvp.Value); + } + + public override void OnChangeData(AppearanceComponent component) + { + base.OnChangeData(component); + + if (!component.Owner.TryGetComponent(out ISpriteComponent? sprite)) return; + if (!component.TryGetData(Key, out object status)) return; + if (!States.TryGetValue(status, out var val)) return; + sprite.LayerSetState(Layer, val); + } + } +} diff --git a/Content.Server/Kitchen/Components/KitchenSpikeComponent.cs b/Content.Server/Kitchen/Components/KitchenSpikeComponent.cs index 8d7fa8593d..8f9b6b55d9 100644 --- a/Content.Server/Kitchen/Components/KitchenSpikeComponent.cs +++ b/Content.Server/Kitchen/Components/KitchenSpikeComponent.cs @@ -55,10 +55,7 @@ namespace Content.Server.Kitchen.Components } else { - if (Owner.TryGetComponent(out sprite)) - { - sprite.LayerSetState(0, "spike"); - } + UpdateAppearance(); eventArgs.User.PopupMessage(_meatSource0); } @@ -73,6 +70,14 @@ namespace Content.Server.Kitchen.Components return true; } + private void UpdateAppearance() + { + if (Owner.TryGetComponent(out AppearanceComponent? appearance)) + { + appearance.SetData(KitchenSpikeVisuals.Status, (_meatParts > 0) ? KitchenSpikeStatus.Bloody : KitchenSpikeStatus.Empty); + } + } + private bool Spikeable(IEntity user, IEntity victim, [NotNullWhen(true)] out SharedButcherableComponent? butcherable) { butcherable = null; @@ -150,10 +155,7 @@ namespace Content.Server.Kitchen.Components _meatName = Loc.GetString("comp-kitchen-spike-meat-name", ("victim", victim)); // TODO: Visualizer - if (Owner.TryGetComponent(out var sprite)) - { - sprite.LayerSetState(0, "spikebloody"); - } + UpdateAppearance(); Owner.PopupMessageEveryone(Loc.GetString("comp-kitchen-spike-kill", ("user", user), ("victim", victim))); // TODO: Need to be able to leave them on the spike to do DoT, see ss13. diff --git a/Content.Shared/Cloning/SharedCloningPodComponent.cs b/Content.Shared/Cloning/SharedCloningPodComponent.cs index f90319bfe2..b592322424 100644 --- a/Content.Shared/Cloning/SharedCloningPodComponent.cs +++ b/Content.Shared/Cloning/SharedCloningPodComponent.cs @@ -44,13 +44,13 @@ namespace Content.Shared.Cloning } [Serializable, NetSerializable] - public enum CloningPodVisuals + public enum CloningPodVisuals : byte { Status } [Serializable, NetSerializable] - public enum CloningPodStatus + public enum CloningPodStatus : byte { Idle, Cloning, diff --git a/Content.Shared/Kitchen/Components/SharedKitchenSpikeComponent.cs b/Content.Shared/Kitchen/Components/SharedKitchenSpikeComponent.cs index ebfa220172..3649fdf8c9 100644 --- a/Content.Shared/Kitchen/Components/SharedKitchenSpikeComponent.cs +++ b/Content.Shared/Kitchen/Components/SharedKitchenSpikeComponent.cs @@ -1,7 +1,9 @@ +using System; using Content.Shared.DragDrop; using Content.Shared.Nutrition.Components; using Content.Shared.Sound; using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.ViewVariables; @@ -31,5 +33,18 @@ namespace Content.Shared.Kitchen.Components } public abstract bool DragDropOn(DragDropEvent eventArgs); + + [Serializable, NetSerializable] + public enum KitchenSpikeVisuals : byte + { + Status + } + + [Serializable, NetSerializable] + public enum KitchenSpikeStatus : byte + { + Empty, + Bloody + } } } diff --git a/Resources/Prototypes/Entities/Structures/Machines/cloning_machine.yml b/Resources/Prototypes/Entities/Structures/Machines/cloning_machine.yml index 0271ddadc6..e586ea094d 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/cloning_machine.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/cloning_machine.yml @@ -10,7 +10,6 @@ sprite: Structures/Machines/cloning.rsi layers: - state: pod_0 - map: ["enum.CloningPodVisualLayers.Machine"] - type: Physics bodyType: Static fixtures: @@ -44,7 +43,14 @@ LayoutId: CloningPod - type: Appearance visuals: - - type: CloningPodVisualizer + - type: GenericEnumVisualizer + key: enum.CloningPodVisuals.Status + layer: 0 + states: + enum.CloningPodStatus.Cloning: pod_1 + enum.CloningPodStatus.NoMind: pod_e + enum.CloningPodStatus.Gore: pod_g + enum.CloningPodStatus.Idle: pod_0 - type: UserInterface interfaces: - key: enum.CloningPodUIKey.Key diff --git a/Resources/Prototypes/Entities/Structures/meat_spike.yml b/Resources/Prototypes/Entities/Structures/meat_spike.yml index 1a06698b2d..da8b281845 100644 --- a/Resources/Prototypes/Entities/Structures/meat_spike.yml +++ b/Resources/Prototypes/Entities/Structures/meat_spike.yml @@ -32,3 +32,12 @@ - type: KitchenSpike - type: Anchorable - type: Pullable + - type: Appearance + visuals: + - type: GenericEnumVisualizer + key: enum.KitchenSpikeVisuals.Status + layer: 0 + states: + enum.KitchenSpikeStatus.Empty: spike + enum.KitchenSpikeStatus.Bloody: spikebloody +