From 42f3155c854b99b0d27c4189bac757f5ce29cf48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=C3=A4mper?= Date: Wed, 31 Aug 2022 14:12:09 +0200 Subject: [PATCH] Clean up vending machines and port their visualizer (#10465) --- .../UI/VendingMachineMenu.xaml.cs | 79 ++- .../UI/VendingMachineVisualizer.cs | 241 --------- .../VendingMachineBoundUserInterface.cs | 61 ++- .../VendingMachineComponent.cs | 50 ++ .../VendingMachines/VendingMachineSystem.cs | 141 +++++ .../Tests/VendingMachineTest.cs | 2 +- .../Thresholds/Behaviors/EjectVendorItems.cs | 16 +- .../VendingMachineComponent.cs | 37 +- .../VendingMachineEjectItemWireAction.cs | 4 +- .../VendingMachines/VendingMachineSystem.cs | 240 +++++++-- .../SharedVendingMachineComponent.cs | 147 ++---- .../SharedVendingMachineSystem.cs | 49 +- .../VendingMachineInterfaceState.cs | 33 ++ .../VendingMachineInventoryPrototype.cs | 12 +- .../VendingMachines/Inventories/ammo.yml | 2 - .../Inventories/atmosdrobe.yml | 2 - .../VendingMachines/Inventories/bardrobe.yml | 2 - .../VendingMachines/Inventories/boozeomat.yml | 2 - .../Inventories/cargodrobe.yml | 2 - .../VendingMachines/Inventories/cart.yml | 2 - .../VendingMachines/Inventories/chang.yml | 5 +- .../VendingMachines/Inventories/chapel.yml | 2 - .../VendingMachines/Inventories/chefdrobe.yml | 2 - .../VendingMachines/Inventories/chemdrobe.yml | 2 - .../VendingMachines/Inventories/cigs.yml | 3 - .../Inventories/clothesmate.yml | 1 - .../VendingMachines/Inventories/coffee.yml | 3 - .../VendingMachines/Inventories/cola.yml | 3 - .../VendingMachines/Inventories/detdrobe.yml | 2 - .../Inventories/dinnerware.yml | 2 - .../VendingMachines/Inventories/discount.yml | 2 - .../VendingMachines/Inventories/donut.yml | 2 - .../VendingMachines/Inventories/empty.yml | 2 - .../VendingMachines/Inventories/engidrobe.yml | 2 - .../VendingMachines/Inventories/engivend.yml | 3 - .../VendingMachines/Inventories/games.yml | 3 - .../VendingMachines/Inventories/genedrobe.yml | 2 - .../VendingMachines/Inventories/hydrobe.yml | 2 - .../VendingMachines/Inventories/janidrobe.yml | 2 - .../VendingMachines/Inventories/lawdrobe.yml | 2 - .../VendingMachines/Inventories/magivend.yml | 3 - .../VendingMachines/Inventories/medical.yml | 3 - .../VendingMachines/Inventories/medidrobe.yml | 4 +- .../VendingMachines/Inventories/nutri.yml | 2 - .../VendingMachines/Inventories/robodrobe.yml | 2 - .../VendingMachines/Inventories/robotics.yml | 2 - .../VendingMachines/Inventories/salvage.yml | 2 - .../VendingMachines/Inventories/scidrobe.yml | 2 - .../VendingMachines/Inventories/sec.yml | 3 - .../VendingMachines/Inventories/secdrobe.yml | 2 - .../VendingMachines/Inventories/seeds.yml | 3 - .../Inventories/smartfridge.yml | 2 - .../VendingMachines/Inventories/snack.yml | 3 - .../Inventories/sovietsoda.yml | 2 - .../Inventories/tankdispenser.yml | 8 +- .../VendingMachines/Inventories/theater.yml | 2 - .../VendingMachines/Inventories/vendomat.yml | 2 - .../VendingMachines/Inventories/virodrobe.yml | 2 - .../VendingMachines/Inventories/wallmed.yml | 2 - .../VendingMachines/Inventories/youtool.yml | 3 - .../Structures/Machines/vending_machines.yml | 495 ++++++++---------- .../VendingMachines/dinnerware.rsi/meta.json | 3 + 62 files changed, 873 insertions(+), 850 deletions(-) delete mode 100644 Content.Client/VendingMachines/UI/VendingMachineVisualizer.cs create mode 100644 Content.Shared/VendingMachines/VendingMachineInterfaceState.cs diff --git a/Content.Client/VendingMachines/UI/VendingMachineMenu.xaml.cs b/Content.Client/VendingMachines/UI/VendingMachineMenu.xaml.cs index 47a0061d73..61817f767b 100644 --- a/Content.Client/VendingMachines/UI/VendingMachineMenu.xaml.cs +++ b/Content.Client/VendingMachines/UI/VendingMachineMenu.xaml.cs @@ -1,62 +1,87 @@ -using System; -using System.Collections.Generic; +using Content.Shared.VendingMachines; using Robust.Client.AutoGenerated; using Robust.Client.GameObjects; using Robust.Client.Graphics; -using Robust.Client.ResourceManagement; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; -using Robust.Shared.IoC; using Robust.Shared.Prototypes; -using static Content.Shared.VendingMachines.SharedVendingMachineComponent; namespace Content.Client.VendingMachines.UI { [GenerateTypedNameReferences] public sealed partial class VendingMachineMenu : DefaultWindow { - [Dependency] private readonly IResourceCache _resourceCache = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - private VendingMachineBoundUserInterface Owner { get; } + public event Action? OnItemSelected; - private List _cachedInventory = new(); - - public VendingMachineMenu(VendingMachineBoundUserInterface owner) + public VendingMachineMenu() { - IoCManager.InjectDependencies(this); + MinSize = SetSize = (250, 150); RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); - Owner = owner; - VendingContents.OnItemSelected += ItemSelected; + VendingContents.OnItemSelected += args => + { + OnItemSelected?.Invoke(args); + }; } + /// + /// Populates the list of available items on the vending machine interface + /// and sets icons based on their prototypes + /// public void Populate(List inventory) { - VendingContents.Clear(); - _cachedInventory = inventory; - var longestEntry = ""; - foreach (VendingMachineInventoryEntry entry in inventory) + if (inventory.Count == 0) { - var itemName = _prototypeManager.Index(entry.ID).Name; + VendingContents.Clear(); + var outOfStockText = Loc.GetString("vending-machine-component-try-eject-out-of-stock"); + VendingContents.AddItem(outOfStockText); + SetSizeAfterUpdate(outOfStockText.Length); + return; + } + + while (inventory.Count != VendingContents.Count) + { + if (inventory.Count > VendingContents.Count) + VendingContents.AddItem(string.Empty); + else + VendingContents.RemoveAt(VendingContents.Count - 1); + } + + var longestEntry = string.Empty; + var spriteSystem = EntitySystem.Get(); + for (var i = 0; i < inventory.Count; i++) + { + var entry = inventory[i]; + var vendingItem = VendingContents[i]; + vendingItem.Text = string.Empty; + vendingItem.Icon = null; + + var itemName = entry.ID; + Texture? icon = null; + if (_prototypeManager.TryIndex(entry.ID, out var prototype)) + { + itemName = prototype.Name; + icon = spriteSystem.GetPrototypeIcon(prototype).Default; + } + if (itemName.Length > longestEntry.Length) longestEntry = itemName; - Texture? icon = null; - if(_prototypeManager.TryIndex(entry.ID, out EntityPrototype? prototype)) - icon = SpriteComponent.GetPrototypeIcon(prototype, _resourceCache).Default; - - VendingContents.AddItem($"{itemName} [{entry.Amount}]", icon); + vendingItem.Text = $"{itemName} [{entry.Amount}]"; + vendingItem.Icon = icon; } - SetSize = (Math.Clamp((longestEntry.Length + 2) * 12, 250, 300), - Math.Clamp(VendingContents.Count * 50, 150, 350)); + SetSizeAfterUpdate(longestEntry.Length); } - public void ItemSelected(ItemList.ItemListSelectedEventArgs args) + private void SetSizeAfterUpdate(int longestEntryLength) { - Owner.Eject(_cachedInventory[args.ItemIndex].Type, _cachedInventory[args.ItemIndex].ID); + SetSize = (Math.Clamp((longestEntryLength + 2) * 12, 250, 300), + Math.Clamp(VendingContents.Count * 50, 150, 350)); } } } diff --git a/Content.Client/VendingMachines/UI/VendingMachineVisualizer.cs b/Content.Client/VendingMachines/UI/VendingMachineVisualizer.cs deleted file mode 100644 index ca679a4a95..0000000000 --- a/Content.Client/VendingMachines/UI/VendingMachineVisualizer.cs +++ /dev/null @@ -1,241 +0,0 @@ -using System; -using System.Collections.Generic; -using Content.Shared.VendingMachines; -using JetBrains.Annotations; -using Robust.Client.Animations; -using Robust.Client.GameObjects; -using Robust.Client.ResourceManagement; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization; -using Robust.Shared.Serialization.Manager.Attributes; -using static Content.Shared.VendingMachines.SharedVendingMachineComponent; - -namespace Content.Client.VendingMachines.UI -{ - [UsedImplicitly] - public sealed class VendingMachineVisualizer : AppearanceVisualizer, ISerializationHooks - { - // TODO: Should default to off or broken if damaged - // - - // TODO: The length of these animations is supposed to be dictated - // by the vending machine's pack prototype's `AnimationDuration` - // but we have no good way of passing that data from the server - // to the client at the moment. Rework Visualizers? - - private Dictionary _baseStates = new(); - - private static readonly Dictionary LayerMap = - new() - { - {"off", VendingMachineVisualLayers.Unlit}, - {"screen", VendingMachineVisualLayers.Screen}, - {"normal", VendingMachineVisualLayers.Base}, - {"normal-unshaded", VendingMachineVisualLayers.BaseUnshaded}, - {"eject", VendingMachineVisualLayers.Base}, - {"eject-unshaded", VendingMachineVisualLayers.BaseUnshaded}, - {"deny", VendingMachineVisualLayers.Base}, - {"deny-unshaded", VendingMachineVisualLayers.BaseUnshaded}, - {"broken", VendingMachineVisualLayers.Unlit}, - }; - - [DataField("screen")] - private bool _screen; - - [DataField("normal")] - private bool _normal; - - [DataField("normalUnshaded")] - private bool _normalUnshaded; - - [DataField("eject")] - private bool _eject; - - [DataField("ejectUnshaded")] - private bool _ejectUnshaded; - - [DataField("deny")] - private bool _deny; - - [DataField("denyUnshaded")] - private bool _denyUnshaded; - - [DataField("broken")] - private bool _broken; - - [DataField("brokenUnshaded")] - private bool _brokenUnshaded; - - private readonly Dictionary _animations = new(); - - void ISerializationHooks.AfterDeserialization() - { - // Used a dictionary so the yaml can adhere to the style-guide and the texture states can be clear - var states = new Dictionary - { - {"off", true}, - {"screen", _screen}, - {"normal", _normal}, - {"normal-unshaded", _normalUnshaded}, - {"eject", _eject}, - {"eject-unshaded", _ejectUnshaded}, - {"deny", _deny}, - {"deny-unshaded", _denyUnshaded}, - {"broken", _broken}, - {"broken-unshaded", _brokenUnshaded}, - }; - - _baseStates = states; - - if (_baseStates["deny"]) - { - InitializeAnimation("deny"); - } - - if (_baseStates["deny-unshaded"]) - { - InitializeAnimation("deny-unshaded", true); - } - - if (_baseStates["eject"]) - { - InitializeAnimation("eject"); - } - - if (_baseStates["eject-unshaded"]) - { - InitializeAnimation("eject-unshaded", true); - } - } - - private void InitializeAnimation(string key, bool unshaded = false) - { - _animations.Add(key, new Animation {Length = TimeSpan.FromSeconds(1.2f)}); - - var flick = new AnimationTrackSpriteFlick(); - _animations[key].AnimationTracks.Add(flick); - flick.LayerKey = unshaded ? VendingMachineVisualLayers.BaseUnshaded : VendingMachineVisualLayers.Base; - flick.KeyFrames.Add(new AnimationTrackSpriteFlick.KeyFrame(key, 0f)); - } - - [Obsolete("Subscribe to your component being initialised instead.")] - public override void InitializeEntity(EntityUid entity) - { - base.InitializeEntity(entity); - - IoCManager.Resolve().EnsureComponent(entity); - } - - private void HideLayers(ISpriteComponent spriteComponent) - { - foreach (var layer in spriteComponent.AllLayers) - { - layer.Visible = false; - } - - spriteComponent.LayerSetVisible(VendingMachineVisualLayers.Unlit, true); - } - - [Obsolete("Subscribe to AppearanceChangeEvent instead.")] - public override void OnChangeData(AppearanceComponent component) - { - base.OnChangeData(component); - - var entMan = IoCManager.Resolve(); - var sprite = entMan.GetComponent(component.Owner); - - // TODO when moving to a system visualizer, re work how this is done - // Currently this only gets called during init, so unless it NEEEDS to be configurable, just make this party of the entity prototype. - if (component.TryGetData(VendingMachineVisuals.Inventory, out string? invId) && - IoCManager.Resolve().TryIndex(invId, out VendingMachineInventoryPrototype? prototype) && - IoCManager.Resolve().TryGetResource( - SharedSpriteComponent.TextureRoot / $"Structures/Machines/VendingMachines/{prototype.SpriteName}.rsi", out var res)) - { - sprite.BaseRSI = res.RSI; - } - - var animPlayer = entMan.GetComponent(component.Owner); - if (!component.TryGetData(VendingMachineVisuals.VisualState, out VendingMachineVisualState state)) - { - state = VendingMachineVisualState.Normal; - } - - // Hide last state - HideLayers(sprite); - ActivateState(sprite, "off"); - - switch (state) - { - case VendingMachineVisualState.Normal: - ActivateState(sprite, "screen"); - ActivateState(sprite, "normal-unshaded"); - ActivateState(sprite, "normal"); - break; - - case VendingMachineVisualState.Off: - break; - - case VendingMachineVisualState.Broken: - ActivateState(sprite, "broken-unshaded"); - ActivateState(sprite, "broken"); - - break; - case VendingMachineVisualState.Deny: - ActivateState(sprite, "screen"); - ActivateAnimation(sprite, animPlayer, "deny-unshaded"); - ActivateAnimation(sprite, animPlayer, "deny"); - - break; - case VendingMachineVisualState.Eject: - ActivateState(sprite, "screen"); - ActivateAnimation(sprite, animPlayer, "eject-unshaded"); - ActivateAnimation(sprite, animPlayer, "eject"); - - break; - default: - throw new ArgumentOutOfRangeException(); - } - } - - // Helper methods just to avoid all of that hard-to-read-indented code - private void ActivateState(ISpriteComponent spriteComponent, string stateId) - { - // No state for it on the rsi :( - if (!_baseStates[stateId]) - { - return; - } - - var stateLayer = LayerMap[stateId]; - spriteComponent.LayerSetVisible(stateLayer, true); - spriteComponent.LayerSetState(stateLayer, stateId); - } - - private void ActivateAnimation(ISpriteComponent spriteComponent, AnimationPlayerComponent animationPlayer, string key) - { - if (!_animations.TryGetValue(key, out var animation)) - { - return; - } - - if (!animationPlayer.HasRunningAnimation(key)) - { - spriteComponent.LayerSetVisible(LayerMap[key], true); - animationPlayer.Play(animation, key); - } - } - - public enum VendingMachineVisualLayers : byte - { - // Off / Broken. The other layers will overlay this if the machine is on. - Unlit, - // Normal / Deny / Eject - Base, - BaseUnshaded, - // Screens that are persistent (where the machine is not off or broken) - Screen, - } - } -} diff --git a/Content.Client/VendingMachines/VendingMachineBoundUserInterface.cs b/Content.Client/VendingMachines/VendingMachineBoundUserInterface.cs index 688a54f50d..fe4aaa062d 100644 --- a/Content.Client/VendingMachines/VendingMachineBoundUserInterface.cs +++ b/Content.Client/VendingMachines/VendingMachineBoundUserInterface.cs @@ -1,22 +1,20 @@ using Content.Client.VendingMachines.UI; using Content.Shared.VendingMachines; using Robust.Client.GameObjects; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.ViewVariables; -using static Content.Shared.VendingMachines.SharedVendingMachineComponent; +using Robust.Client.UserInterface.Controls; +using System.Linq; namespace Content.Client.VendingMachines { public sealed class VendingMachineBoundUserInterface : BoundUserInterface { - [ViewVariables] private VendingMachineMenu? _menu; + [ViewVariables] + private VendingMachineMenu? _menu; - public SharedVendingMachineComponent? VendingMachine { get; private set; } + private List _cachedInventory = new(); public VendingMachineBoundUserInterface(ClientUserInterfaceComponent owner, Enum uiKey) : base(owner, uiKey) { - SendMessage(new InventorySyncRequestMessage()); } protected override void Open() @@ -24,33 +22,43 @@ namespace Content.Client.VendingMachines base.Open(); var entMan = IoCManager.Resolve(); - if (!entMan.TryGetComponent(Owner.Owner, out SharedVendingMachineComponent? vendingMachine)) - { - return; - } + var vendingMachineSys = EntitySystem.Get(); - VendingMachine = vendingMachine; + _cachedInventory = vendingMachineSys.GetAllInventory(Owner.Owner); - _menu = new VendingMachineMenu(this) {Title = entMan.GetComponent(Owner.Owner).EntityName}; - _menu.Populate(VendingMachine.AllInventory); + _menu = new VendingMachineMenu {Title = entMan.GetComponent(Owner.Owner).EntityName}; _menu.OnClose += Close; + _menu.OnItemSelected += OnItemSelected; + + _menu.Populate(_cachedInventory); + _menu.OpenCentered(); } - public void Eject(InventoryType type, string id) + protected override void UpdateState(BoundUserInterfaceState state) { - SendMessage(new VendingMachineEjectMessage(type, id)); + base.UpdateState(state); + + if (state is not VendingMachineInterfaceState newState) + return; + + _cachedInventory = newState.Inventory; + + _menu?.Populate(_cachedInventory); } - protected override void ReceiveMessage(BoundUserInterfaceMessage message) + private void OnItemSelected(ItemList.ItemListSelectedEventArgs args) { - switch (message) - { - case VendingMachineInventoryMessage msg: - _menu?.Populate(msg.Inventory); - break; - } + if (_cachedInventory == null || _cachedInventory.Count == 0) + return; + + var selectedItem = _cachedInventory.ElementAtOrDefault(args.ItemIndex); + + if (selectedItem == null) + return; + + SendMessage(new VendingMachineEjectMessage(selectedItem.Type, selectedItem.ID)); } protected override void Dispose(bool disposing) @@ -59,7 +67,12 @@ namespace Content.Client.VendingMachines if (!disposing) return; - _menu?.Dispose(); + if (_menu == null) + return; + + _menu.OnItemSelected -= OnItemSelected; + _menu.OnClose -= Close; + _menu.Dispose(); } } } diff --git a/Content.Client/VendingMachines/VendingMachineComponent.cs b/Content.Client/VendingMachines/VendingMachineComponent.cs index f7c16584a3..b392a49c80 100644 --- a/Content.Client/VendingMachines/VendingMachineComponent.cs +++ b/Content.Client/VendingMachines/VendingMachineComponent.cs @@ -4,7 +4,57 @@ namespace Content.Client.VendingMachines; [RegisterComponent] [ComponentReference(typeof(SharedVendingMachineComponent))] +[Access(typeof(VendingMachineSystem))] public sealed class VendingMachineComponent : SharedVendingMachineComponent { + /// + /// RSI state for when the vending machine is unpowered. + /// Will be displayed on the layer + /// + [DataField("offState")] + public string? OffState; + /// + /// RSI state for the screen of the vending machine + /// Will be displayed on the layer + /// + [DataField("screenState")] + public string? ScreenState; + + /// + /// RSI state for the vending machine's normal state. Usually a looping animation. + /// Will be displayed on the layer + /// + [DataField("normalState")] + public string? NormalState; + + /// + /// RSI state for the vending machine's eject animation. + /// Will be displayed on the layer + /// + [DataField("ejectState")] + public string? EjectState; + + /// + /// RSI state for the vending machine's deny animation. Will either be played once as sprite flick + /// or looped depending on how is set. + /// Will be displayed on the layer + /// + [DataField("denyState")] + public string? DenyState; + + /// + /// RSI state for when the vending machine is unpowered. + /// Will be displayed on the layer + /// + [DataField("brokenState")] + public string? BrokenState; + + /// + /// If set to true (default) will loop the animation of the for the duration + /// of . If set to false will play a sprite + /// flick animation for the state and then linger on the final frame until the end of the delay. + /// + [DataField("loopDeny")] + public bool LoopDenyAnimation = true; } diff --git a/Content.Client/VendingMachines/VendingMachineSystem.cs b/Content.Client/VendingMachines/VendingMachineSystem.cs index c08f5e10d2..cb9878b119 100644 --- a/Content.Client/VendingMachines/VendingMachineSystem.cs +++ b/Content.Client/VendingMachines/VendingMachineSystem.cs @@ -1,7 +1,148 @@ using Content.Shared.VendingMachines; +using Robust.Client.Animations; +using Robust.Client.GameObjects; namespace Content.Client.VendingMachines; public sealed class VendingMachineSystem : SharedVendingMachineSystem { + [Dependency] private readonly AnimationPlayerSystem _animationPlayer = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnAppearanceChange); + SubscribeLocalEvent(OnAnimationCompleted); + } + + private void OnAnimationCompleted(EntityUid uid, VendingMachineComponent component, AnimationCompletedEvent args) + { + if (!TryComp(uid, out var sprite)) + return; + + UpdateAppearance(uid, VendingMachineVisualState.Normal, component, sprite); + } + + private void OnAppearanceChange(EntityUid uid, VendingMachineComponent component, ref AppearanceChangeEvent args) + { + if (args.Sprite == null) + return; + + if (!args.AppearanceData.TryGetValue(VendingMachineVisuals.VisualState, out var visualStateObject) || + visualStateObject is not VendingMachineVisualState visualState) + { + visualState = VendingMachineVisualState.Normal; + } + + UpdateAppearance(uid, visualState, component, args.Sprite); + } + + private void UpdateAppearance(EntityUid uid, VendingMachineVisualState visualState, VendingMachineComponent component, SpriteComponent sprite) + { + SetLayerState(VendingMachineVisualLayers.Base, component.OffState, sprite); + + switch (visualState) + { + case VendingMachineVisualState.Normal: + SetLayerState(VendingMachineVisualLayers.BaseUnshaded, component.NormalState, sprite); + SetLayerState(VendingMachineVisualLayers.Screen, component.ScreenState, sprite); + break; + + case VendingMachineVisualState.Deny: + if (component.LoopDenyAnimation) + SetLayerState(VendingMachineVisualLayers.BaseUnshaded, component.DenyState, sprite); + else + PlayAnimation(uid, VendingMachineVisualLayers.BaseUnshaded, component.DenyState, component.DenyDelay, sprite); + + SetLayerState(VendingMachineVisualLayers.Screen, component.ScreenState, sprite); + break; + + case VendingMachineVisualState.Eject: + PlayAnimation(uid, VendingMachineVisualLayers.BaseUnshaded, component.EjectState, component.EjectDelay, sprite); + SetLayerState(VendingMachineVisualLayers.Screen, component.ScreenState, sprite); + break; + + case VendingMachineVisualState.Broken: + HideLayers(sprite); + SetLayerState(VendingMachineVisualLayers.Base, component.BrokenState, sprite); + break; + + case VendingMachineVisualState.Off: + HideLayers(sprite); + break; + } + } + + private static void SetLayerState(VendingMachineVisualLayers layer, string? state, SpriteComponent sprite) + { + if (string.IsNullOrEmpty(state)) + return; + + sprite.LayerSetVisible(layer, true); + sprite.LayerSetAutoAnimated(layer, true); + sprite.LayerSetState(layer, state); + } + + private void PlayAnimation(EntityUid uid, VendingMachineVisualLayers layer, string? state, float animationTime, SpriteComponent sprite) + { + if (string.IsNullOrEmpty(state)) + return; + + if (!_animationPlayer.HasRunningAnimation(uid, state)) + { + var animation = GetAnimation(layer, state, animationTime); + sprite.LayerSetVisible(layer, true); + _animationPlayer.Play(uid, animation, state); + } + } + + private static Animation GetAnimation(VendingMachineVisualLayers layer, string state, float animationTime) + { + return new Animation + { + Length = TimeSpan.FromSeconds(animationTime), + AnimationTracks = + { + new AnimationTrackSpriteFlick + { + LayerKey = layer, + KeyFrames = + { + new AnimationTrackSpriteFlick.KeyFrame(state, 0f) + } + } + } + }; + } + + private static void HideLayers(SpriteComponent sprite) + { + HideLayer(VendingMachineVisualLayers.BaseUnshaded, sprite); + HideLayer(VendingMachineVisualLayers.Screen, sprite); + } + + private static void HideLayer(VendingMachineVisualLayers layer, SpriteComponent sprite) + { + if (!sprite.LayerMapTryGet(layer, out var actualLayer)) + return; + + sprite.LayerSetVisible(actualLayer, false); + } +} + +public enum VendingMachineVisualLayers : byte +{ + /// + /// Off / Broken. The other layers will overlay this if the machine is on. + /// + Base, + /// + /// Normal / Deny / Eject + /// + BaseUnshaded, + /// + /// Screens that are persistent (where the machine is not off or broken) + /// + Screen } diff --git a/Content.IntegrationTests/Tests/VendingMachineTest.cs b/Content.IntegrationTests/Tests/VendingMachineTest.cs index 04f2e1be97..3d3b263305 100644 --- a/Content.IntegrationTests/Tests/VendingMachineTest.cs +++ b/Content.IntegrationTests/Tests/VendingMachineTest.cs @@ -29,7 +29,7 @@ namespace Content.IntegrationTests.Tests } catch (UnknownPrototypeException) { - throw new UnknownPrototypeException($"Unknown prototype {item} on vending inventory {vendorProto.Name}"); + throw new UnknownPrototypeException($"Unknown prototype {item} on vending inventory {vendorProto.ID}"); } } } diff --git a/Content.Server/Destructible/Thresholds/Behaviors/EjectVendorItems.cs b/Content.Server/Destructible/Thresholds/Behaviors/EjectVendorItems.cs index c0d267f0d2..f4dcc3ebce 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/EjectVendorItems.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/EjectVendorItems.cs @@ -1,6 +1,4 @@ using Content.Server.VendingMachines; -using Content.Shared.Throwing; -using Robust.Shared.Random; namespace Content.Server.Destructible.Thresholds.Behaviors { @@ -30,17 +28,15 @@ namespace Content.Server.Destructible.Thresholds.Behaviors !system.EntityManager.TryGetComponent(owner, out var xform)) return; - var throwingsys = system.EntityManager.EntitySysManager.GetEntitySystem(); - var totalItems = vendingcomp.AllInventory.Count; + var vendingMachineSystem = EntitySystem.Get(); + var inventory = vendingMachineSystem.GetAvailableInventory(owner, vendingcomp); + if (inventory.Count <= 0) + return; - var toEject = Math.Min(totalItems * Percent, Max); + var toEject = Math.Min(inventory.Count * Percent, Max); for (var i = 0; i < toEject; i++) { - var entity = system.EntityManager.SpawnEntity(system.Random.PickAndTake(vendingcomp.AllInventory).ID, xform.Coordinates); - - float range = vendingcomp.NonLimitedEjectRange; - Vector2 direction = new Vector2(system.Random.NextFloat(-range, range), system.Random.NextFloat(-range, range)); - throwingsys.TryThrow(entity, direction, vendingcomp.NonLimitedEjectForce); + vendingMachineSystem.EjectRandom(owner, throwItem: true, forceEject: true, vendingcomp); } } } diff --git a/Content.Server/VendingMachines/VendingMachineComponent.cs b/Content.Server/VendingMachines/VendingMachineComponent.cs index ac3a1d076d..a35c72aa47 100644 --- a/Content.Server/VendingMachines/VendingMachineComponent.cs +++ b/Content.Server/VendingMachines/VendingMachineComponent.cs @@ -1,7 +1,5 @@ -using Content.Server.UserInterface; using Content.Shared.Actions.ActionTypes; using Content.Shared.VendingMachines; -using Robust.Server.GameObjects; using Robust.Shared.Audio; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; @@ -9,9 +7,14 @@ namespace Content.Server.VendingMachines { [RegisterComponent] [ComponentReference(typeof(SharedVendingMachineComponent))] + [Access(typeof(VendingMachineSystem))] public sealed class VendingMachineComponent : SharedVendingMachineComponent { public bool Ejecting; + public bool Denying; + public bool DispenseOnHitCoolingDown; + + public string? NextItemToEject; public bool Broken; @@ -21,6 +24,8 @@ namespace Content.Server.VendingMachines [DataField("speedLimiter")] public bool CanShoot = false; + public bool ThrowNextItem = false; + /// /// The chance that a vending machine will randomly dispense an item on hit. /// Chance is 0 if null. @@ -28,24 +33,48 @@ namespace Content.Server.VendingMachines [DataField("dispenseOnHitChance")] public float? DispenseOnHitChance; + /// + /// The minimum amount of damage that must be done per hit to have a chance + /// of dispensing an item. + /// [DataField("dispenseOnHitThreshold")] public float? DispenseOnHitThreshold; + /// + /// Amount of time in seconds that need to pass before damage can cause a vending machine to eject again. + /// This value is separate to because that value might be + /// 0 for a vending machine for legitimate reasons (no desired delay/no eject animation) + /// and can be circumvented with forced ejections. + /// + [DataField("dispenseOnHitCooldown")] + public float? DispenseOnHitCooldown = 1.0f; + + /// + /// Sound that plays when ejecting an item + /// [DataField("soundVend")] // Grabbed from: https://github.com/discordia-space/CEV-Eris/blob/f702afa271136d093ddeb415423240a2ceb212f0/sound/machines/vending_drop.ogg public SoundSpecifier SoundVend = new SoundPathSpecifier("/Audio/Machines/machine_vend.ogg"); + /// + /// Sound that plays when an item can't be ejected + /// [DataField("soundDeny")] // Yoinked from: https://github.com/discordia-space/CEV-Eris/blob/35bbad6764b14e15c03a816e3e89aa1751660ba9/sound/machines/Custom_deny.ogg public SoundSpecifier SoundDeny = new SoundPathSpecifier("/Audio/Machines/custom_deny.ogg"); + /// + /// The action available to the player controlling the vending machine + /// [DataField("action", customTypeSerializer: typeof(PrototypeIdSerializer))] public string? Action = "VendingThrow"; - [ViewVariables] public BoundUserInterface? UserInterface => Owner.GetUIOrNull(VendingMachineUiKey.Key); - public float NonLimitedEjectForce = 7.5f; public float NonLimitedEjectRange = 5f; + + public float EjectAccumulator = 0f; + public float DenyAccumulator = 0f; + public float DispenseOnHitAccumulator = 0f; } } diff --git a/Content.Server/VendingMachines/VendingMachineEjectItemWireAction.cs b/Content.Server/VendingMachines/VendingMachineEjectItemWireAction.cs index 69c95057c6..48f491d6c9 100644 --- a/Content.Server/VendingMachines/VendingMachineEjectItemWireAction.cs +++ b/Content.Server/VendingMachines/VendingMachineEjectItemWireAction.cs @@ -42,7 +42,7 @@ public sealed class VendingMachineEjectItemWireAction : BaseWireAction { if (EntityManager.TryGetComponent(wire.Owner, out VendingMachineComponent? vending)) { - vending.CanShoot = true; + _vendingMachineSystem.SetShooting(wire.Owner, true, vending); } return true; @@ -52,7 +52,7 @@ public sealed class VendingMachineEjectItemWireAction : BaseWireAction { if (EntityManager.TryGetComponent(wire.Owner, out VendingMachineComponent? vending)) { - vending.CanShoot = false; + _vendingMachineSystem.SetShooting(wire.Owner, false, vending); } return true; diff --git a/Content.Server/VendingMachines/VendingMachineSystem.cs b/Content.Server/VendingMachines/VendingMachineSystem.cs index 3d7b108da7..5eb0856332 100644 --- a/Content.Server/VendingMachines/VendingMachineSystem.cs +++ b/Content.Server/VendingMachines/VendingMachineSystem.cs @@ -1,7 +1,7 @@ -using System.Linq; using Content.Server.Popups; using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; +using Content.Server.UserInterface; using Content.Shared.Access.Components; using Content.Shared.Access.Systems; using Content.Shared.Actions; @@ -16,7 +16,6 @@ using Robust.Shared.Audio; using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; -using static Content.Shared.VendingMachines.SharedVendingMachineComponent; namespace Content.Server.VendingMachines { @@ -28,18 +27,23 @@ namespace Content.Server.VendingMachines [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly ThrowingSystem _throwingSystem = default!; [Dependency] private readonly SharedActionsSystem _action = default!; + [Dependency] private readonly AudioSystem _audioSystem = default!; + [Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!; + [Dependency] private readonly AppearanceSystem _appearanceSystem = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnPowerChanged); - SubscribeLocalEvent(OnInventoryRequestMessage); - SubscribeLocalEvent(OnInventoryEjectMessage); SubscribeLocalEvent(OnBreak); SubscribeLocalEvent(OnEmagged); SubscribeLocalEvent(OnDamage); + SubscribeLocalEvent(OnActivatableUIOpenAttempt); + SubscribeLocalEvent(OnBoundUIOpened); + SubscribeLocalEvent(OnInventoryEjectMessage); + SubscribeLocalEvent(OnSelfDispense); } @@ -49,9 +53,9 @@ namespace Content.Server.VendingMachines var component = (VendingMachineComponent) sharedComponent; - if (TryComp(component.Owner, out var receiver)) + if (HasComp(component.Owner)) { - TryUpdateVisualState(uid, null, component); + TryUpdateVisualState(uid, component); } if (component.Action != null) @@ -61,17 +65,22 @@ namespace Content.Server.VendingMachines } } - private void OnInventoryRequestMessage(EntityUid uid, VendingMachineComponent component, InventorySyncRequestMessage args) + private void OnActivatableUIOpenAttempt(EntityUid uid, VendingMachineComponent component, ActivatableUIOpenAttemptEvent args) { - if (!this.IsPowered(uid, EntityManager)) - return; + if (component.Broken) + args.Cancel(); + } - var inventory = new List(component.Inventory); + private void OnBoundUIOpened(EntityUid uid, VendingMachineComponent component, BoundUIOpenedEvent args) + { + UpdateVendingMachineInterfaceState(component); + } - if (component.Emagged) inventory.AddRange(component.EmaggedInventory); - if (component.Contraband) inventory.AddRange(component.ContrabandInventory); + private void UpdateVendingMachineInterfaceState(VendingMachineComponent component) + { + var state = new VendingMachineInterfaceState(GetAllInventory(component.Owner, component)); - component.UserInterface?.SendMessage(new VendingMachineInventoryMessage(inventory)); + _userInterfaceSystem.TrySetUiState(component.Owner, VendingMachineUiKey.Key, state); } private void OnInventoryEjectMessage(EntityUid uid, VendingMachineComponent component, VendingMachineEjectMessage args) @@ -87,13 +96,13 @@ namespace Content.Server.VendingMachines private void OnPowerChanged(EntityUid uid, VendingMachineComponent component, PowerChangedEvent args) { - TryUpdateVisualState(uid, null, component); + TryUpdateVisualState(uid, component); } private void OnBreak(EntityUid uid, VendingMachineComponent vendComponent, BreakageEventArgs eventArgs) { vendComponent.Broken = true; - TryUpdateVisualState(uid, VendingMachineVisualState.Broken, vendComponent); + TryUpdateVisualState(uid, vendComponent); } private void OnEmagged(EntityUid uid, VendingMachineComponent component, GotEmaggedEvent args) @@ -107,11 +116,17 @@ namespace Content.Server.VendingMachines private void OnDamage(EntityUid uid, VendingMachineComponent component, DamageChangedEvent args) { - if (component.DispenseOnHitChance == null || args.DamageDelta == null) + if (component.Broken || component.DispenseOnHitCoolingDown || + component.DispenseOnHitChance == null || args.DamageDelta == null) return; - if (args.DamageDelta.Total >= component.DispenseOnHitThreshold && _random.Prob(component.DispenseOnHitChance.Value)) - EjectRandom(uid, true, component); + if (args.DamageIncreased && args.DamageDelta.Total >= component.DispenseOnHitThreshold && + _random.Prob(component.DispenseOnHitChance.Value)) + { + if (component.DispenseOnHitCooldown > 0f) + component.DispenseOnHitCoolingDown = true; + EjectRandom(uid, throwItem: true, forceEject: true, component); + } } private void OnSelfDispense(EntityUid uid, VendingMachineComponent component, VendingMachineSelfDispenseEvent args) @@ -120,7 +135,18 @@ namespace Content.Server.VendingMachines return; args.Handled = true; - EjectRandom(uid, true, component); + EjectRandom(uid, throwItem: true, forceEject: false, component); + } + + /// + /// Sets the property of the vending machine. + /// + public void SetShooting(EntityUid uid, bool canShoot, VendingMachineComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + component.CanShoot = canShoot; } public void Deny(EntityUid uid, VendingMachineComponent? vendComponent = null) @@ -128,16 +154,18 @@ namespace Content.Server.VendingMachines if (!Resolve(uid, ref vendComponent)) return; - SoundSystem.Play(vendComponent.SoundDeny.GetSound(), Filter.Pvs(vendComponent.Owner), vendComponent.Owner, AudioParams.Default.WithVolume(-2f)); - // Play the Deny animation - TryUpdateVisualState(uid, VendingMachineVisualState.Deny, vendComponent); - //TODO: This duration should be a distinct value specific to the deny animation - vendComponent.Owner.SpawnTimer(vendComponent.AnimationDuration, () => - { - TryUpdateVisualState(uid, VendingMachineVisualState.Normal, vendComponent); - }); + if (vendComponent.Denying) + return; + + vendComponent.Denying = true; + _audioSystem.Play(vendComponent.SoundDeny, Filter.Pvs(vendComponent.Owner), vendComponent.Owner, AudioParams.Default.WithVolume(-2f)); + TryUpdateVisualState(uid, vendComponent); } + /// + /// Checks if the user is authorized to use this vending machine + /// + /// Entity trying to use the vending machine public bool IsAuthorized(EntityUid uid, EntityUid? sender, VendingMachineComponent? vendComponent = null) { if (!Resolve(uid, ref vendComponent) || sender == null) @@ -155,6 +183,13 @@ namespace Content.Server.VendingMachines return true; } + /// + /// Tries to eject the provided item. Will do nothing if the vending machine is incapable of ejecting, already ejecting + /// or the item doesn't exist in its inventory. + /// + /// The type of inventory the item is from + /// The prototype ID of the item + /// Whether the item should be thrown in a random direction after ejection public void TryEjectVendorItem(EntityUid uid, InventoryType type, string itemId, bool throwItem, VendingMachineComponent? vendComponent = null) { if (!Resolve(uid, ref vendComponent)) @@ -165,13 +200,7 @@ namespace Content.Server.VendingMachines return; } - var entry = type switch - { - InventoryType.Regular => vendComponent.Inventory.Find(x => x.ID == itemId), - InventoryType.Emagged when vendComponent.Emagged => vendComponent.EmaggedInventory.Find(x => x.ID == itemId), - InventoryType.Contraband when vendComponent.Contraband => vendComponent.ContrabandInventory.Find(x => x.ID == itemId), - _ => null - }; + var entry = GetEntry(itemId, type, vendComponent); if (entry == null) { @@ -195,24 +224,20 @@ namespace Content.Server.VendingMachines // Start Ejecting, and prevent users from ordering while anim playing vendComponent.Ejecting = true; + vendComponent.NextItemToEject = entry.ID; + vendComponent.ThrowNextItem = throwItem; entry.Amount--; - vendComponent.UserInterface?.SendMessage(new VendingMachineInventoryMessage(vendComponent.AllInventory)); - TryUpdateVisualState(uid, VendingMachineVisualState.Eject, vendComponent); - vendComponent.Owner.SpawnTimer(vendComponent.AnimationDuration, () => - { - vendComponent.Ejecting = false; - TryUpdateVisualState(uid, VendingMachineVisualState.Normal, vendComponent); - var ent = EntityManager.SpawnEntity(entry.ID, transformComp.Coordinates); - if (throwItem) - { - float range = vendComponent.NonLimitedEjectRange; - Vector2 direction = new Vector2(_random.NextFloat(-range, range), _random.NextFloat(-range, range)); - _throwingSystem.TryThrow(ent, direction, vendComponent.NonLimitedEjectForce); - } - }); - SoundSystem.Play(vendComponent.SoundVend.GetSound(), Filter.Pvs(vendComponent.Owner), vendComponent.Owner, AudioParams.Default.WithVolume(-2f)); + UpdateVendingMachineInterfaceState(vendComponent); + TryUpdateVisualState(uid, vendComponent); + _audioSystem.Play(vendComponent.SoundVend, Filter.Pvs(vendComponent.Owner), vendComponent.Owner, AudioParams.Default.WithVolume(-2f)); } + /// + /// Checks whether the user is authorized to use the vending machine, then ejects the provided item if true + /// + /// Entity that is trying to use the vending machine + /// The type of inventory the item is from + /// The prototype ID of the item public void AuthorizedVend(EntityUid uid, EntityUid sender, InventoryType type, string itemId, VendingMachineComponent component) { if (IsAuthorized(uid, sender, component)) @@ -221,12 +246,15 @@ namespace Content.Server.VendingMachines } } - public void TryUpdateVisualState(EntityUid uid, VendingMachineVisualState? state = VendingMachineVisualState.Normal, VendingMachineComponent? vendComponent = null) + /// + /// Tries to update the visuals of the component based on its current state. + /// + public void TryUpdateVisualState(EntityUid uid, VendingMachineComponent? vendComponent = null) { if (!Resolve(uid, ref vendComponent)) return; - var finalState = state == null ? VendingMachineVisualState.Normal : state; + var finalState = VendingMachineVisualState.Normal; if (vendComponent.Broken) { finalState = VendingMachineVisualState.Broken; @@ -235,6 +263,10 @@ namespace Content.Server.VendingMachines { finalState = VendingMachineVisualState.Eject; } + else if (vendComponent.Denying) + { + finalState = VendingMachineVisualState.Deny; + } else if (!this.IsPowered(uid, EntityManager)) { finalState = VendingMachineVisualState.Off; @@ -242,23 +274,121 @@ namespace Content.Server.VendingMachines if (TryComp(vendComponent.Owner, out var appearance)) { - appearance.SetData(VendingMachineVisuals.VisualState, finalState); + _appearanceSystem.SetData(uid, VendingMachineVisuals.VisualState, finalState, appearance); } } - public void EjectRandom(EntityUid uid, bool throwItem, VendingMachineComponent? vendComponent = null) + /// + /// Ejects a random item from the available stock. Will do nothing if the vending machine is empty. + /// + /// Whether to throw the item in a random direction after dispensing it. + /// Whether to skip the regular ejection checks and immediately dispense the item without animation. + public void EjectRandom(EntityUid uid, bool throwItem, bool forceEject = false, VendingMachineComponent? vendComponent = null) { if (!Resolve(uid, ref vendComponent)) return; - var availableItems = vendComponent.AllInventory.Where(x => x.Amount > 0).ToList(); + var availableItems = GetAvailableInventory(uid, vendComponent); if (availableItems.Count <= 0) { return; } var item = _random.Pick(availableItems); - TryEjectVendorItem(uid, item.Type, item.ID, throwItem, vendComponent); + + if (forceEject) + { + vendComponent.NextItemToEject = item.ID; + vendComponent.ThrowNextItem = throwItem; + var entry = GetEntry(item.ID, item.Type, vendComponent); + if (entry != null) + entry.Amount--; + EjectItem(vendComponent, forceEject); + } + else + TryEjectVendorItem(uid, item.Type, item.ID, throwItem, vendComponent); + } + + private void EjectItem(VendingMachineComponent vendComponent, bool forceEject = false) + { + // No need to update the visual state because we never changed it during a forced eject + if (!forceEject) + TryUpdateVisualState(vendComponent.Owner, vendComponent); + + if (string.IsNullOrEmpty(vendComponent.NextItemToEject)) + { + vendComponent.ThrowNextItem = false; + return; + } + + var ent = EntityManager.SpawnEntity(vendComponent.NextItemToEject, Transform(vendComponent.Owner).Coordinates); + if (vendComponent.ThrowNextItem) + { + var range = vendComponent.NonLimitedEjectRange; + var direction = new Vector2(_random.NextFloat(-range, range), _random.NextFloat(-range, range)); + _throwingSystem.TryThrow(ent, direction, vendComponent.NonLimitedEjectForce); + } + + vendComponent.NextItemToEject = null; + vendComponent.ThrowNextItem = false; + } + + private void DenyItem(VendingMachineComponent vendComponent) + { + TryUpdateVisualState(vendComponent.Owner, vendComponent); + } + + private VendingMachineInventoryEntry? GetEntry(string entryId, InventoryType type, VendingMachineComponent component) + { + if (type == InventoryType.Emagged && component.Emagged) + return component.EmaggedInventory.GetValueOrDefault(entryId); + + if (type == InventoryType.Contraband && component.Contraband) + return component.ContrabandInventory.GetValueOrDefault(entryId); + + return component.Inventory.GetValueOrDefault(entryId); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + foreach (var comp in EntityQuery()) + { + if (comp.Ejecting) + { + comp.EjectAccumulator += frameTime; + if (comp.EjectAccumulator >= comp.EjectDelay) + { + comp.EjectAccumulator = 0f; + comp.Ejecting = false; + + EjectItem(comp); + } + } + + if (comp.Denying) + { + comp.DenyAccumulator += frameTime; + if (comp.DenyAccumulator >= comp.DenyDelay) + { + comp.DenyAccumulator = 0f; + comp.Denying = false; + + DenyItem(comp); + } + } + + if (comp.DispenseOnHitCoolingDown) + { + comp.DispenseOnHitAccumulator += frameTime; + if (comp.DispenseOnHitAccumulator >= comp.DispenseOnHitCooldown) + { + comp.DispenseOnHitAccumulator = 0f; + comp.DispenseOnHitCoolingDown = false; + } + } + } } } } diff --git a/Content.Shared/VendingMachines/SharedVendingMachineComponent.cs b/Content.Shared/VendingMachines/SharedVendingMachineComponent.cs index f5e6e82961..c658c308f0 100644 --- a/Content.Shared/VendingMachines/SharedVendingMachineComponent.cs +++ b/Content.Shared/VendingMachines/SharedVendingMachineComponent.cs @@ -8,112 +8,79 @@ namespace Content.Shared.VendingMachines [NetworkedComponent()] public abstract class SharedVendingMachineComponent : Component { + /// + /// PrototypeID for the vending machine's inventory, see + /// [DataField("pack", customTypeSerializer: typeof(PrototypeIdSerializer))] public string PackPrototypeId = string.Empty; - public TimeSpan AnimationDuration = TimeSpan.Zero; + /// + /// Used by the server to determine how long the vending machine stays in the "Deny" state. + /// Used by the client to determine how long the deny animation should be played. + /// + [DataField("denyDelay")] + public float DenyDelay = 2.0f; - [ViewVariables] public List Inventory = new(); - [ViewVariables] public List EmaggedInventory = new(); - [ViewVariables] public List ContrabandInventory = new(); + /// + /// Used by the server to determine how long the vending machine stays in the "Eject" state. + /// The selected item is dispensed afer this delay. + /// Used by the client to determine how long the deny animation should be played. + /// + [DataField("ejectDelay")] + public float EjectDelay = 1.2f; - public List AllInventory - { - get - { - var inventory = new List(Inventory); + [ViewVariables] + public Dictionary Inventory = new(); - if (Emagged) inventory.AddRange(EmaggedInventory); - if (Contraband) inventory.AddRange(ContrabandInventory); + [ViewVariables] + public Dictionary EmaggedInventory = new(); - return inventory; - } - } + [ViewVariables] + public Dictionary ContrabandInventory = new(); public bool Emagged; public bool Contraband; + } - [Serializable, NetSerializable] - public enum VendingMachineVisuals + [Serializable, NetSerializable] + public sealed class VendingMachineInventoryEntry + { + [ViewVariables(VVAccess.ReadWrite)] + public InventoryType Type; + [ViewVariables(VVAccess.ReadWrite)] + public string ID; + [ViewVariables(VVAccess.ReadWrite)] + public uint Amount; + public VendingMachineInventoryEntry(InventoryType type, string id, uint amount) { - VisualState, - Inventory, + Type = type; + ID = id; + Amount = amount; } + } - [Serializable, NetSerializable] - public enum VendingMachineVisualState - { - Normal, - Off, - Broken, - Eject, - Deny, - } + [Serializable, NetSerializable] + public enum InventoryType : byte + { + Regular, + Emagged, + Contraband + } - [Serializable, NetSerializable] - public sealed class VendingMachineEjectMessage : BoundUserInterfaceMessage - { - public readonly InventoryType Type; - public readonly string ID; - public VendingMachineEjectMessage(InventoryType type, string id) - { - Type = type; - ID = id; - } - } + [Serializable, NetSerializable] + public enum VendingMachineVisuals + { + VisualState + } - [Serializable, NetSerializable] - public enum VendingMachineUiKey - { - Key, - } - - [Serializable, NetSerializable] - public sealed class InventorySyncRequestMessage : BoundUserInterfaceMessage - { - } - - [Serializable, NetSerializable] - public sealed class VendingMachineInventoryMessage : BoundUserInterfaceMessage - { - public readonly List Inventory; - public VendingMachineInventoryMessage(List inventory) - { - Inventory = inventory; - } - } - - [Serializable, NetSerializable] - public sealed class VendingMachineInventoryEntry - { - [ViewVariables(VVAccess.ReadWrite)] public InventoryType Type; - [ViewVariables(VVAccess.ReadWrite)] - public string ID; - [ViewVariables(VVAccess.ReadWrite)] - public uint Amount; - public VendingMachineInventoryEntry(InventoryType type, string id, uint amount) - { - Type = type; - ID = id; - Amount = amount; - } - } - [Serializable, NetSerializable] - public enum VendingMachineWireStatus : byte - { - Power, - Access, - Advertisement, - Limiter - } - - [Serializable, NetSerializable] - public enum InventoryType : byte - { - Regular, - Emagged, - Contraband - } + [Serializable, NetSerializable] + public enum VendingMachineVisualState + { + Normal, + Off, + Broken, + Eject, + Deny, } [Serializable, NetSerializable] diff --git a/Content.Shared/VendingMachines/SharedVendingMachineSystem.cs b/Content.Shared/VendingMachines/SharedVendingMachineSystem.cs index 98bd744413..96ba55c899 100644 --- a/Content.Shared/VendingMachines/SharedVendingMachineSystem.cs +++ b/Content.Shared/VendingMachines/SharedVendingMachineSystem.cs @@ -1,4 +1,5 @@ using Robust.Shared.Prototypes; +using System.Linq; using static Content.Shared.VendingMachines.SharedVendingMachineComponent; namespace Content.Shared.VendingMachines; @@ -18,17 +19,43 @@ public abstract class SharedVendingMachineSystem : EntitySystem if (!_prototypeManager.TryIndex(component.PackPrototypeId, out VendingMachineInventoryPrototype? packPrototype)) return; - MetaData(uid).EntityName = packPrototype.Name; - component.AnimationDuration = TimeSpan.FromSeconds(packPrototype.AnimationDuration); - - if (TryComp(component.Owner, out AppearanceComponent? appearance)) - appearance.SetData(VendingMachineVisuals.Inventory, component.PackPrototypeId); - AddInventoryFromPrototype(uid, packPrototype.StartingInventory, InventoryType.Regular, component); AddInventoryFromPrototype(uid, packPrototype.EmaggedInventory, InventoryType.Emagged, component); AddInventoryFromPrototype(uid, packPrototype.ContrabandInventory, InventoryType.Contraband, component); } + /// + /// Returns all of the vending machine's inventory. Only includes emagged and contraband inventories if + /// and + /// are true respectively. + /// + /// + /// + /// + public List GetAllInventory(EntityUid uid, SharedVendingMachineComponent? component = null) + { + if (!Resolve(uid, ref component)) + return new(); + + var inventory = new List(component.Inventory.Values); + + if (component.Emagged) + inventory.AddRange(component.EmaggedInventory.Values); + + if (component.Contraband) + inventory.AddRange(component.ContrabandInventory.Values); + + return inventory; + } + + public List GetAvailableInventory(EntityUid uid, SharedVendingMachineComponent? component = null) + { + if (!Resolve(uid, ref component)) + return new(); + + return GetAllInventory(uid, component).Where(_ => _.Amount > 0).ToList(); + } + private void AddInventoryFromPrototype(EntityUid uid, Dictionary? entries, InventoryType type, SharedVendingMachineComponent? component = null) @@ -38,26 +65,26 @@ public abstract class SharedVendingMachineSystem : EntitySystem return; } - var inventory = new List(); + var inventory = new Dictionary(); foreach (var (id, amount) in entries) { if (_prototypeManager.HasIndex(id)) { - inventory.Add(new VendingMachineInventoryEntry(type, id, amount)); + inventory.Add(id, new VendingMachineInventoryEntry(type, id, amount)); } } switch (type) { case InventoryType.Regular: - component.Inventory.AddRange(inventory); + component.Inventory = inventory; break; case InventoryType.Emagged: - component.EmaggedInventory.AddRange(inventory); + component.EmaggedInventory = inventory; break; case InventoryType.Contraband: - component.ContrabandInventory.AddRange(inventory); + component.ContrabandInventory = inventory; break; } } diff --git a/Content.Shared/VendingMachines/VendingMachineInterfaceState.cs b/Content.Shared/VendingMachines/VendingMachineInterfaceState.cs new file mode 100644 index 0000000000..82758b17f6 --- /dev/null +++ b/Content.Shared/VendingMachines/VendingMachineInterfaceState.cs @@ -0,0 +1,33 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared.VendingMachines +{ + [NetSerializable, Serializable] + public sealed class VendingMachineInterfaceState : BoundUserInterfaceState + { + public List Inventory; + + public VendingMachineInterfaceState(List inventory) + { + Inventory = inventory; + } + } + + [Serializable, NetSerializable] + public sealed class VendingMachineEjectMessage : BoundUserInterfaceMessage + { + public readonly InventoryType Type; + public readonly string ID; + public VendingMachineEjectMessage(InventoryType type, string id) + { + Type = type; + ID = id; + } + } + + [Serializable, NetSerializable] + public enum VendingMachineUiKey + { + Key, + } +} diff --git a/Content.Shared/VendingMachines/VendingMachineInventoryPrototype.cs b/Content.Shared/VendingMachines/VendingMachineInventoryPrototype.cs index 4e1ac78cc0..790f365cc5 100644 --- a/Content.Shared/VendingMachines/VendingMachineInventoryPrototype.cs +++ b/Content.Shared/VendingMachines/VendingMachineInventoryPrototype.cs @@ -7,19 +7,9 @@ namespace Content.Shared.VendingMachines public sealed class VendingMachineInventoryPrototype : IPrototype { [ViewVariables] - [IdDataFieldAttribute] + [IdDataField] public string ID { get; } = default!; - [DataField("name")] - public string Name { get; } = string.Empty; - - [DataField("animationDuration")] - public double AnimationDuration { get; } - - // TODO make this a proper sprite specifier for yaml linting. - [DataField("spriteName")] - public string SpriteName { get; } = string.Empty; - [DataField("startingInventory")] public Dictionary StartingInventory { get; } = new(); diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/ammo.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/ammo.yml index bd06ac0dd5..999914eb42 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/ammo.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/ammo.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: AmmoVendInventory - name: Ammovend - spriteName: ammo startingInventory: MagazineBoxCaselessRifle: 3 MagazineBoxCaselessRifleHighVelocity: 3 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/atmosdrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/atmosdrobe.yml index 218373617d..030ba44bdf 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/atmosdrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/atmosdrobe.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: AtmosDrobeInventory - name: AtmosDrobe - spriteName: atmosdrobe startingInventory: ClothingBackpackDuffelEngineering: 2 ClothingBackpackSatchelEngineering: 2 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/bardrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/bardrobe.yml index b1b7f2bc42..bb83066548 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/bardrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/bardrobe.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: BarDrobeInventory - name: BarDrobe - spriteName: bardrobe startingInventory: ClothingHeadHatTophat: 2 ClothingEyesGlassesBeer: 2 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/boozeomat.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/boozeomat.yml index 86cdd463a9..1b8b067739 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/boozeomat.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/boozeomat.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: BoozeOMatInventory - name: Booze-O-Mat - spriteName: boozeomat startingInventory: DrinkGlass: 30 #Kept glasses at top for ease to differentiate from booze. diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/cargodrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/cargodrobe.yml index d4aec401aa..c745865622 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/cargodrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/cargodrobe.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: CargoDrobeInventory - name: CargoDrobe - spriteName: cargodrobe startingInventory: AppraisalTool: 3 ClothingUniformJumpsuitCargo: 3 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/cart.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/cart.yml index ea0df18763..daac474e15 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/cart.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/cart.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: PTechInventory - name: PTech - spriteName: cart startingInventory: PassengerPDA: 5 ClearPDA: 5 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/chang.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/chang.yml index 6b7c3756f9..282f58535b 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/chang.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/chang.yml @@ -1,8 +1,5 @@ - type: vendingMachineInventory id: ChangInventory - name: Mr. Chang - animationDuration: 2.1 - spriteName: cigs startingInventory: FoodCondimentPacketSoy: 5 FoodSnackCookieFortune: 5 @@ -10,4 +7,4 @@ DrinkHellRamen: 3 FoodSnackChowMein: 3 FoodSnackDanDanNoodles: 3 -# rice? \ No newline at end of file +# rice? diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/chapel.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/chapel.yml index 28fa6b8c2c..da9e6f721b 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/chapel.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/chapel.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: PietyVendInventory - name: PietyVend - spriteName: chapel startingInventory: ClothingUniformJumpsuitChaplain: 2 ClothingUniformJumpskirtChaplain: 2 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/chefdrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/chefdrobe.yml index ec88659033..e15c9afb21 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/chefdrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/chefdrobe.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: ChefDrobeInventory - name: ChefDrobe - spriteName: chefdrobe startingInventory: ClothingHeadsetService: 2 ClothingOuterApronChef: 3 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/chemdrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/chemdrobe.yml index f571110524..c8ed50cbba 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/chemdrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/chemdrobe.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: ChemDrobeInventory - name: ChemDrobe - spriteName: chemdrobe startingInventory: ClothingUniformJumpsuitChemistry: 2 ClothingUniformJumpskirtChemistry: 2 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/cigs.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/cigs.yml index f3f15e3ddb..df481b2095 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/cigs.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/cigs.yml @@ -1,8 +1,5 @@ - type: vendingMachineInventory id: CigaretteMachineInventory - name: cigarette machine - animationDuration: 2.1 - spriteName: cigs startingInventory: CigPackGreen: 2 CigPackRed: 2 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml index b073c87981..eaabfe897c 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml @@ -1,6 +1,5 @@ - type: vendingMachineInventory id: ClothesMateInventory - name: ClothesMate startingInventory: ClothingBackpack: 5 ClothingBackpackDuffel: 5 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/coffee.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/coffee.yml index f32075ea5f..ff2f344856 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/coffee.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/coffee.yml @@ -1,8 +1,5 @@ - type: vendingMachineInventory id: HotDrinksMachineInventory - name: Hot drinks machine - animationDuration: 3.4 - spriteName: coffee startingInventory: DrinkHotCoffee: 10 DrinkTeacup: 10 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/cola.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/cola.yml index 5da494bc29..bbf72a15b1 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/cola.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/cola.yml @@ -1,8 +1,5 @@ - type: vendingMachineInventory id: RobustSoftdrinksInventory - name: Robust Softdrinks - animationDuration: 1.1 - spriteName: cola startingInventory: DrinkColaCan: 2 DrinkEnergyDrinkCan: 2 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/detdrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/detdrobe.yml index 13bc2c6e38..ba5fd7fcec 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/detdrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/detdrobe.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: DetDrobeInventory - name: DetDrobe - spriteName: detdrobe startingInventory: ClothingUniformJumpsuitDetective: 2 ClothingUniformJumpskirtDetective: 2 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/dinnerware.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/dinnerware.yml index 56de4f5c48..97266d33ed 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/dinnerware.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/dinnerware.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: DinnerwareInventory - name: Dinnerware - spriteName: dinnerware startingInventory: ButchCleaver: 1 KitchenKnife: 5 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/discount.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/discount.yml index 0c1aedf420..d175f6a5dd 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/discount.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/discount.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: DiscountDansInventory - name: Discount Dan's - spriteName: discount startingInventory: FoodSnackCheesie: 3 FoodSnackChips: 3 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/donut.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/donut.yml index a640f68a28..16dc3e628f 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/donut.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/donut.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: DonutInventory - name: Donut - spriteName: donut startingInventory: FoodDonutChocolate: 5 FoodDonutApple: 3 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/empty.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/empty.yml index f3de974409..1b74fb1a82 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/empty.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/empty.yml @@ -1,4 +1,2 @@ - type: vendingMachineInventory id: EmptyVendingMachineInventory - name: Empty vending machine - spriteName: empty diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/engidrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/engidrobe.yml index 1e0dffd54f..44e2fbe4b0 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/engidrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/engidrobe.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: EngiDrobeInventory - name: EngiDrobe - spriteName: engidrobe startingInventory: ClothingBackpackDuffelEngineering: 3 ClothingBackpackSatchelEngineering: 3 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/engivend.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/engivend.yml index dab8609747..23f320a77e 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/engivend.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/engivend.yml @@ -1,8 +1,5 @@ - type: vendingMachineInventory id: EngiVendInventory - name: Engi-Vend - animationDuration: 2.1 - spriteName: engivend startingInventory: ClothingEyesGlassesMeson: 4 ClothingHeadHatWelding: 4 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/games.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/games.yml index 3dbd6f4eb9..e791b4d669 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/games.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/games.yml @@ -1,8 +1,5 @@ - type: vendingMachineInventory id: GoodCleanFunInventory - name: Good Clean Fun - animationDuration: 1.3 - spriteName: games startingInventory: DiceBag: 4 Paper: 8 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/genedrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/genedrobe.yml index 84f9d130aa..04e54ab702 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/genedrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/genedrobe.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: GeneDrobeInventory - name: GeneDrobe - spriteName: genedrobe startingInventory: ClothingShoesColorWhite: 2 ClothingOuterCoatLab: 2 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/hydrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/hydrobe.yml index b39e55ab63..126385915b 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/hydrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/hydrobe.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: HyDrobeInventory - name: HyDrobe - spriteName: hydrobe startingInventory: ClothingBackpackHydroponics: 2 ClothingBackpackSatchelHydroponics: 2 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/janidrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/janidrobe.yml index db5762ac54..9d50fec845 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/janidrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/janidrobe.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: JaniDrobeInventory - name: JaniDrobe - spriteName: janidrobe startingInventory: ClothingUniformJumpsuitJanitor: 2 ClothingUniformJumpskirtJanitor: 2 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/lawdrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/lawdrobe.yml index 8b11e36b0a..3cb383e9cb 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/lawdrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/lawdrobe.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: LawDrobeInventory - name: LawDrobe - spriteName: lawdrobe startingInventory: ClothingUniformJumpsuitLawyerBlue: 1 ClothingUniformJumpsuitLawyerPurple: 1 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/magivend.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/magivend.yml index 921134a2de..7617186dd9 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/magivend.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/magivend.yml @@ -1,8 +1,5 @@ - type: vendingMachineInventory id: MagiVendInventory - name: MagiVend - animationDuration: 1.5 - spriteName: magivend startingInventory: ClothingHeadHatWizard: 3 ClothingOuterWizard: 3 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/medical.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/medical.yml index 3669599d2c..00c1044e91 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/medical.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/medical.yml @@ -1,8 +1,5 @@ - type: vendingMachineInventory id: NanoMedPlusInventory - name: NanoMed Plus - animationDuration: 1.8 - spriteName: medical startingInventory: HandheldHealthAnalyzer: 3 Brutepack: 5 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/medidrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/medidrobe.yml index 4467664e14..f4ce0e8d6c 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/medidrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/medidrobe.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: MediDrobeInventory - name: MediDrobe - spriteName: medidrobe startingInventory: ClothingBackpackDuffelMedical: 4 ClothingBackpackMedical: 4 @@ -17,4 +15,4 @@ ClothingOuterWinterPara: 2 ClothingHeadHelmetVoidParamed: 1 ClothingOuterHardsuitVoidParamed: 1 - + diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/nutri.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/nutri.yml index 10e5ded1be..6a3820b1dd 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/nutri.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/nutri.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: NutriMaxInventory - name: NutriMax - spriteName: nutri startingInventory: HydroponicsToolSpade: 2 HydroponicsToolMiniHoe: 2 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/robodrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/robodrobe.yml index 7b815b4544..605b8f550d 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/robodrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/robodrobe.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: RoboDrobeInventory - name: RoboDrobe - spriteName: robodrobe startingInventory: ClothingOuterCoatLab: 2 ClothingShoesColorBlack: 2 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/robotics.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/robotics.yml index 1236d446e4..a3a7301433 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/robotics.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/robotics.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: RobotechDeluxeInventory - name: Robotech Deluxe - spriteName: robotics startingInventory: #TO DO: add missing prototypes ClothingOuterCoatLab: 4 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/salvage.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/salvage.yml index 2b41c9c482..de26d18404 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/salvage.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/salvage.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: SalvageEquipmentInventory - name: Salvage Equipment - spriteName: mining startingInventory: Crowbar: 2 Pickaxe: 4 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/scidrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/scidrobe.yml index e7e6d7b2fd..b7bd7f4a98 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/scidrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/scidrobe.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: SciDrobeInventory - name: SciDrobe - spriteName: scidrobe startingInventory: ClothingBackpackScience: 3 ClothingBackpackSatchelScience: 3 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml index d6a2cd6aea..6756f54ccd 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml @@ -1,8 +1,5 @@ - type: vendingMachineInventory id: SecTechInventory - name: SecTech - animationDuration: 2.8 - spriteName: sec startingInventory: Handcuffs: 8 GrenadeFlashBang: 4 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/secdrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/secdrobe.yml index 9bd0ca4d57..fc08acc06f 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/secdrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/secdrobe.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: SecDrobeInventory - name: SecDrobe - spriteName: secdrobe startingInventory: ClothingBackpackSecurity: 3 ClothingBackpackSatchelSecurity: 3 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/seeds.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/seeds.yml index e4e061cacd..29e8b3b1ae 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/seeds.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/seeds.yml @@ -1,8 +1,5 @@ - type: vendingMachineInventory id: MegaSeedServitorInventory - name: MegaSeed Servitor - animationDuration: 1.3 - spriteName: seeds startingInventory: AloeSeeds: 3 AmbrosiaVulgarisSeeds: 3 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/smartfridge.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/smartfridge.yml index 0f3cf1e34f..919db2b140 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/smartfridge.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/smartfridge.yml @@ -1,4 +1,2 @@ - type: vendingMachineInventory id: SmartFridgeInventory - name: SmartFridge - spriteName: smartfridge diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/snack.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/snack.yml index 9fd56c6593..3285384cc2 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/snack.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/snack.yml @@ -1,8 +1,5 @@ - type: vendingMachineInventory id: GetmoreChocolateCorpInventory - name: Getmore Chocolate Corp - animationDuration: 0.5 - spriteName: snack startingInventory: FoodSnackRaisins: 3 FoodSnackChocolate: 3 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/sovietsoda.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/sovietsoda.yml index 857c92ca72..ca4d7ce2eb 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/sovietsoda.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/sovietsoda.yml @@ -1,6 +1,4 @@ - type: vendingMachineInventory id: BodaInventory - name: BODA - spriteName: sovietsoda startingInventory: DrinkColaCan: 10 #typically hacked product. Default product is "soda" diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/tankdispenser.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/tankdispenser.yml index 800c6ee0f0..760ff09b25 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/tankdispenser.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/tankdispenser.yml @@ -1,15 +1,11 @@ - type: vendingMachineInventory id: TankDispenserEVAInventory - name: tank dispenser - spriteName: tankdispenser startingInventory: OxygenTankFilled: 5 NitrogenTankFilled: 5 - + - type: vendingMachineInventory id: TankDispenserEngineeringInventory - name: tank dispenser - spriteName: tankdispenser startingInventory: PlasmaTankFilled: 5 - OxygenTankFilled: 5 \ No newline at end of file + OxygenTankFilled: 5 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/theater.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/theater.yml index 5572e82057..274a31b001 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/theater.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/theater.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: AutoDrobeInventory - name: AutoDrobe - spriteName: theater startingInventory: ClothingOuterWinterClown: 1 ClothingOuterWinterMime: 1 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/vendomat.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/vendomat.yml index 1759cdbb09..0e30abe42a 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/vendomat.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/vendomat.yml @@ -1,4 +1,2 @@ - type: vendingMachineInventory id: VendomatInventory - name: Vendomat - spriteName: vendomat diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/virodrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/virodrobe.yml index 919a16c9da..1fd3451241 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/virodrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/virodrobe.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: ViroDrobeInventory - name: ViroDrobe - spriteName: virodrobe startingInventory: ClothingShoesColorWhite: 2 ClothingOuterCoatLab: 2 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/wallmed.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/wallmed.yml index 57e62766d9..5023e703c9 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/wallmed.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/wallmed.yml @@ -1,7 +1,5 @@ - type: vendingMachineInventory id: NanoMedInventory - name: NanoMed - spriteName: wallmed startingInventory: Brutepack: 5 Ointment: 5 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/youtool.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/youtool.yml index eff047abcc..938dd6185e 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/youtool.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/youtool.yml @@ -1,8 +1,5 @@ - type: vendingMachineInventory id: YouToolInventory - name: YouTool - animationDuration: 1.1 - spriteName: youtool startingInventory: CableApcStack: 5 Crowbar: 5 diff --git a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml index 94b9a4b1fe..d717938140 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml @@ -78,6 +78,9 @@ components: - type: VendingMachine pack: AmmoVendInventory + offState: off + brokenState: broken + normalState: normal-unshaded - type: Advertise pack: AmmoVendAds - type: Speech @@ -85,17 +88,13 @@ sprite: Structures/Machines/VendingMachines/ammo.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - broken: true - type: WiresVisuals - type: entity @@ -106,6 +105,11 @@ components: - type: VendingMachine pack: BoozeOMatInventory + offState: off + brokenState: broken + normalState: normal-unshaded + denyState: deny-unshaded + loopDeny: false - type: Advertise pack: BoozeOMatAds - type: Speech @@ -113,17 +117,13 @@ sprite: Structures/Machines/VendingMachines/boozeomat.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - broken: true - type: WiresVisuals - type: AccessReader access: [["Bar"]] @@ -136,23 +136,22 @@ components: - type: VendingMachine pack: PTechInventory + offState: off + brokenState: broken + normalState: normal-unshaded + ejectState: eject-unshaded + denyState: deny-unshaded - type: Sprite sprite: Structures/Machines/VendingMachines/cart.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - ejectUnshaded: true - denyUnshaded: true - broken: true - type: WiresVisuals - type: PointLight radius: 1 @@ -171,6 +170,11 @@ pack: CigaretteMachineInventory dispenseOnHitChance: 0.25 dispenseOnHitThreshold: 2 + offState: off + brokenState: broken + normalState: normal-unshaded + ejectState: eject-unshaded + denyState: deny-unshaded - type: Advertise pack: CigaretteMachineAds - type: Speech @@ -178,19 +182,13 @@ sprite: Structures/Machines/VendingMachines/cigs.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - ejectUnshaded: true - denyUnshaded: true - broken: true - type: WiresVisuals - type: entity @@ -201,6 +199,10 @@ components: - type: VendingMachine pack: ClothesMateInventory + offState: off + brokenState: broken + normalState: normal-unshaded + denyState: deny-unshaded - type: Advertise pack: ClothesMateAds - type: Speech @@ -211,18 +213,13 @@ sprite: Structures/Machines/VendingMachines/clothing.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - denyUnshaded: true - broken: true - type: WiresVisuals - type: PointLight radius: 1.8 @@ -239,6 +236,13 @@ pack: HotDrinksMachineInventory dispenseOnHitChance: 0.25 dispenseOnHitThreshold: 2 + offState: off + brokenState: broken + normalState: normal-unshaded + ejectState: eject-unshaded + denyState: deny-unshaded + screenState: screen + ejectDelay: 5 - type: Advertise pack: HotDrinksMachineAds - type: Speech @@ -246,23 +250,16 @@ sprite: Structures/Machines/VendingMachines/coffee.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: "screen" map: ["enum.VendingMachineVisualLayers.Screen"] shader: unshaded - - texture: Structures/Machines/VendingMachines/maintenance_panel.png + - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - screen: true - normalUnshaded: true - ejectUnshaded: true - denyUnshaded: true - broken: true - type: WiresVisuals - type: PointLight radius: 1.5 @@ -279,6 +276,12 @@ pack: RobustSoftdrinksInventory dispenseOnHitChance: 0.25 dispenseOnHitThreshold: 2 + offState: off + brokenState: broken + normalState: normal-unshaded + ejectState: eject-unshaded + denyState: deny-unshaded + ejectDelay: 1.9 - type: Advertise pack: RobustSoftdrinksAds - type: Speech @@ -286,19 +289,13 @@ sprite: Structures/Machines/VendingMachines/cola.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - ejectUnshaded: true - denyUnshaded: true - broken: true - type: WiresVisuals - type: PointLight radius: 1.5 @@ -313,24 +310,23 @@ components: - type: VendingMachine pack: DinnerwareInventory + offState: off + brokenState: broken + normalState: normal-unshaded + ejectState: eject-unshaded - type: Advertise pack: DinnerwareAds - type: Sprite sprite: Structures/Machines/VendingMachines/dinnerware.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - - texture: Structures/Machines/VendingMachines/maintenance_panel.png + - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - ejectUnshaded: true - broken: true - type: WiresVisuals - type: AccessReader access: [["Service"]] @@ -347,24 +343,22 @@ components: - type: VendingMachine pack: MagiVendInventory + offState: off + brokenState: broken + normalState: normal-unshaded - type: Advertise pack: MagiVendAds - type: Sprite sprite: Structures/Machines/VendingMachines/magivend.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - - texture: Structures/Machines/VendingMachines/maintenance_panel.png + - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - ejectUnshaded: true - broken: true - type: WiresVisuals - type: PointLight radius: 1.5 @@ -381,6 +375,9 @@ pack: DiscountDansInventory dispenseOnHitChance: 0.25 dispenseOnHitThreshold: 2 + offState: off + brokenState: broken + normalState: normal-unshaded - type: Advertise pack: DiscountDansAds - type: Speech @@ -388,17 +385,13 @@ sprite: Structures/Machines/VendingMachines/discount.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - texture: Structures/Machines/VendingMachines/maintenance_panel.png map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - broken: true - type: WiresVisuals - type: PointLight radius: 1.5 @@ -413,23 +406,22 @@ components: - type: VendingMachine pack: EngiVendInventory + offState: off + brokenState: broken + normalState: normal-unshaded + ejectState: eject-unshaded + denyState: deny-unshaded - type: Sprite sprite: Structures/Machines/VendingMachines/engivend.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - ejectUnshaded: true - denyUnshaded: true - broken: true - type: WiresVisuals - type: AccessReader access: [["Engineering"]] @@ -446,25 +438,25 @@ components: - type: VendingMachine pack: NanoMedPlusInventory + offState: off + brokenState: broken + normalState: normal-unshaded + ejectState: eject-unshaded + denyState: deny-unshaded + ejectDelay: 0.6 - type: Advertise pack: NanoMedAds - type: Sprite sprite: Structures/Machines/VendingMachines/medical.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - ejectUnshaded: true - denyUnshaded: true - broken: true - type: WiresVisuals - type: AccessReader access: [["Medical"]] @@ -481,25 +473,24 @@ components: - type: VendingMachine pack: NutriMaxInventory + offState: off + brokenState: broken + normalState: normal-unshaded + ejectState: eject-unshaded + denyState: deny-unshaded - type: Advertise pack: NutriMaxAds - type: Sprite sprite: Structures/Machines/VendingMachines/nutri.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - - texture: Structures/Machines/VendingMachines/maintenance_panel.png + - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - ejectUnshaded: true - denyUnshaded: true - broken: true - type: WiresVisuals - type: AccessReader access: [["Hydroponics"]] @@ -516,25 +507,24 @@ components: - type: VendingMachine pack: SecTechInventory + offState: off + brokenState: broken + normalState: normal-unshaded + ejectState: eject-unshaded + denyState: deny-unshaded - type: Advertise pack: SecTechAds - type: Sprite sprite: Structures/Machines/VendingMachines/sec.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - ejectUnshaded: true - denyUnshaded: true - broken: true - type: WiresVisuals - type: AccessReader access: [["Security"]] @@ -552,24 +542,24 @@ components: - type: VendingMachine pack: MegaSeedServitorInventory + offState: off + brokenState: broken + normalState: normal-unshaded + ejectState: eject-unshaded + denyState: deny-unshaded - type: Advertise pack: MegaSeedAds - type: Sprite sprite: Structures/Machines/VendingMachines/seeds.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - - texture: Structures/Machines/VendingMachines/maintenance_panel.png + - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - ejectUnshaded: true - broken: true - type: WiresVisuals - type: PointLight radius: 1.5 @@ -592,24 +582,29 @@ components: - type: VendingMachine pack: SmartFridgeInventory + offState: off-real + brokenState: broken + normalState: off + denyState: deny-unshaded + screenState: normal-unshaded + loopDeny: false - type: Advertise pack: SmartFridgeAds - type: Speech - type: Sprite sprite: Structures/Machines/VendingMachines/smartfridge.rsi layers: - - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] - - state: "off" + - state: off-real + map: ["enum.VendingMachineVisualLayers.Base"] + - state: off-real map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - - texture: Structures/Machines/VendingMachines/maintenance_panel.png + - state: normal-unshaded + map: ["enum.VendingMachineVisualLayers.Screen"] + shader: unshaded + - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - broken: true - type: WiresVisuals - type: PointLight radius: 1.5 @@ -626,6 +621,11 @@ pack: GetmoreChocolateCorpInventory dispenseOnHitChance: 0.25 dispenseOnHitThreshold: 2 + offState: off + brokenState: broken + normalState: normal-unshaded + ejectState: eject-unshaded + denyState: deny-unshaded - type: Advertise pack: GetmoreChocolateCorpAds - type: Speech @@ -633,19 +633,13 @@ sprite: Structures/Machines/VendingMachines/snack.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - ejectUnshaded: true - denyUnshaded: true - broken: true - type: WiresVisuals - type: PointLight radius: 1.5 @@ -662,6 +656,11 @@ pack: BodaInventory dispenseOnHitChance: 0.25 dispenseOnHitThreshold: 2 + offState: off + brokenState: broken + normalState: normal-unshaded + ejectState: eject-unshaded + denyState: deny-unshaded - type: Advertise pack: BodaAds - type: Speech @@ -669,19 +668,13 @@ sprite: Structures/Machines/VendingMachines/sovietsoda.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - ejectUnshaded: true - denyUnshaded: true - broken: true - type: WiresVisuals - type: PointLight radius: 1.5 @@ -696,6 +689,12 @@ components: - type: VendingMachine pack: AutoDrobeInventory + offState: off + brokenState: broken + normalState: normal-unshaded + ejectState: eject-unshaded + denyState: deny-unshaded + screenState: screen - type: Advertise pack: AutoDrobeAds - type: Speech @@ -703,7 +702,7 @@ sprite: Structures/Machines/VendingMachines/theater.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded @@ -713,13 +712,6 @@ map: ["enum.VendingMachineVisualLayers.Screen"] shader: unshaded - type: Appearance - visuals: - - type: VendingMachineVisualizer - screen: true - normalUnshaded: true - ejectUnshaded: true - denyUnshaded: true - broken: true - type: WiresVisuals - type: PointLight radius: 1.5 @@ -737,6 +729,11 @@ components: - type: VendingMachine pack: VendomatInventory + offState: off + brokenState: broken + normalState: normal-unshaded + ejectState: eject-unshaded + denyState: deny-unshaded - type: Advertise pack: VendomatAds - type: Speech @@ -744,20 +741,13 @@ sprite: Structures/Machines/VendingMachines/vendomat.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - eject: true - ejectUnshaded: true - denyUnshaded: true - broken: true - type: WiresVisuals - type: PointLight radius: 1.5 @@ -772,22 +762,21 @@ components: - type: VendingMachine pack: NanoMedInventory + offState: off + brokenState: broken + normalState: normal-unshaded + denyState: deny-unshaded - type: Sprite sprite: Structures/Machines/VendingMachines/wallmed.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - texture: Structures/Machines/VendingMachines/maintenance_panel.png map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - denyUnshaded: true - broken: true - type: WiresVisuals - type: AccessReader access: [["Medical"]] @@ -800,11 +789,14 @@ components: - type: VendingMachine pack: YouToolInventory + offState: off + brokenState: broken + normalState: normal-unshaded + ejectState: eject-unshaded + denyState: deny-unshaded - type: Sprite sprite: Structures/Machines/VendingMachines/youtool.rsi layers: - - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] - state: "off" map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" @@ -813,13 +805,6 @@ - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - eject: true - ejectUnshaded: true - denyUnshaded: true - broken: true - type: WiresVisuals - type: PointLight radius: 1.5 @@ -837,24 +822,24 @@ components: - type: VendingMachine pack: GoodCleanFunInventory + offState: off + brokenState: broken + normalState: normal-unshaded + ejectState: eject-unshaded + ejectdelay: 1.8 - type: Advertise pack: GoodCleanFunAds - type: Sprite sprite: Structures/Machines/VendingMachines/games.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - ejectUnshaded: true - broken: true - type: WiresVisuals - type: PointLight radius: 1.5 @@ -871,6 +856,9 @@ pack: ChangInventory dispenseOnHitChance: 0.25 dispenseOnHitThreshold: 2 + offState: off + brokenState: broken + normalState: normal-unshaded - type: Advertise pack: ChangAds - type: Speech @@ -878,17 +866,13 @@ sprite: Structures/Machines/VendingMachines/changs.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - - texture: Structures/Machines/VendingMachines/maintenance_panel.png + - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - broken: true - type: WiresVisuals - type: PointLight radius: 1.5 @@ -903,29 +887,28 @@ components: - type: VendingMachine pack: SalvageEquipmentInventory + offState: off + brokenState: broken + normalState: normal-unshaded + denyState: deny-unshaded - type: Sprite sprite: Structures/Machines/VendingMachines/mining.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - eject: true - ejectUnshaded: false - denyUnshaded: true - broken: true - type: WiresVisuals - type: PointLight radius: 1.5 energy: 1.6 color: "#9dc5c9" + - type: AccessReader + access: [["Salvage"]] - type: entity parent: VendingMachine @@ -937,6 +920,9 @@ pack: DonutInventory dispenseOnHitChance: 0.25 dispenseOnHitThreshold: 2 + offState: off + brokenState: broken + normalState: normal-unshaded - type: Advertise pack: DonutAds - type: Speech @@ -944,17 +930,13 @@ sprite: Structures/Machines/VendingMachines/donut.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - broken: true - type: WiresVisuals - type: PointLight radius: 1.5 @@ -971,23 +953,22 @@ components: - type: VendingMachine pack: HyDrobeInventory + offState: off + brokenState: broken + normalState: normal-unshaded - type: Advertise pack: HyDrobeAds - type: Sprite sprite: Structures/Machines/VendingMachines/hydrobe.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - broken: true - type: WiresVisuals - type: AccessReader access: [["Hydroponics"]] @@ -1000,23 +981,22 @@ components: - type: VendingMachine pack: LawDrobeInventory + offState: off + brokenState: broken + normalState: normal-unshaded - type: Advertise pack: LawDrobeAds - type: Sprite sprite: Structures/Machines/VendingMachines/lawdrobe.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - broken: true - type: WiresVisuals - type: AccessReader access: [["Brig"]] @@ -1029,23 +1009,22 @@ components: - type: VendingMachine pack: SecDrobeInventory + offState: off + brokenState: broken + normalState: normal-unshaded - type: Advertise pack: SecDrobeAds - type: Sprite sprite: Structures/Machines/VendingMachines/secdrobe.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - broken: true - type: WiresVisuals - type: AccessReader access: [["Security"]] @@ -1058,23 +1037,22 @@ components: - type: VendingMachine pack: BarDrobeInventory + offState: off + brokenState: broken + normalState: normal-unshaded - type: Advertise pack: BarDrobeAds - type: Sprite sprite: Structures/Machines/VendingMachines/bardrobe.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - broken: true - type: WiresVisuals - type: AccessReader access: [["Bar"]] @@ -1086,11 +1064,15 @@ components: - type: VendingMachine pack: PietyVendInventory + offState: off + brokenState: broken + normalState: normal-unshaded + denyState: deny-unshaded - type: Sprite sprite: Structures/Machines/VendingMachines/chapdrobe.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded @@ -1099,11 +1081,6 @@ - type: AccessReader access: [["Chapel"]] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - denyUnshaded: true - broken: true - type: WiresVisuals - type: PointLight radius: 1.5 @@ -1118,23 +1095,22 @@ components: - type: VendingMachine pack: CargoDrobeInventory + offState: off + brokenState: broken + normalState: normal-unshaded - type: Advertise pack: CargoDrobeAds - type: Sprite sprite: Structures/Machines/VendingMachines/cargodrobe.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - broken: true - type: WiresVisuals - type: AccessReader access: [["Cargo"]] @@ -1147,23 +1123,22 @@ components: - type: VendingMachine pack: MediDrobeInventory + offState: off + brokenState: broken + normalState: normal-unshaded - type: Advertise pack: MediDrobeAds - type: Sprite sprite: Structures/Machines/VendingMachines/medidrobe.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - broken: true - type: WiresVisuals - type: AccessReader access: [["Medical"]] @@ -1176,23 +1151,22 @@ components: - type: VendingMachine pack: ChemDrobeInventory + offState: off + brokenState: broken + normalState: normal-unshaded - type: Advertise pack: ChemDrobeAds - type: Sprite sprite: Structures/Machines/VendingMachines/chemdrobe.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - broken: true - type: WiresVisuals - type: AccessReader access: [["Chemistry"]] @@ -1205,23 +1179,22 @@ components: - type: VendingMachine pack: AtmosDrobeInventory + offState: off + brokenState: broken + normalState: normal-unshaded - type: Advertise pack: AtmosDrobeAds - type: Sprite sprite: Structures/Machines/VendingMachines/atmosdrobe.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - broken: true - type: WiresVisuals - type: AccessReader access: [["Engineering"]] @@ -1234,23 +1207,22 @@ components: - type: VendingMachine pack: EngiDrobeInventory + offState: off + brokenState: broken + normalState: normal-unshaded - type: Advertise pack: EngiDrobeAds - type: Sprite sprite: Structures/Machines/VendingMachines/engidrobe.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - broken: true - type: WiresVisuals - type: AccessReader access: [["Engineering"]] @@ -1263,23 +1235,22 @@ components: - type: VendingMachine pack: ChefDrobeInventory + offState: off + brokenState: broken + normalState: normal-unshaded - type: Advertise pack: ChefDrobeAds - type: Sprite sprite: Structures/Machines/VendingMachines/chefdrobe.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - broken: true - type: WiresVisuals - type: AccessReader access: [["Kitchen"]] @@ -1292,23 +1263,22 @@ components: - type: VendingMachine pack: DetDrobeInventory + offState: off + brokenState: broken + normalState: normal-unshaded - type: Advertise pack: DetDrobeAds - type: Sprite sprite: Structures/Machines/VendingMachines/detdrobe.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - broken: true - type: WiresVisuals - type: AccessReader access: [["Security"]] @@ -1321,23 +1291,22 @@ components: - type: VendingMachine pack: JaniDrobeInventory + offState: off + brokenState: broken + normalState: normal-unshaded - type: Advertise pack: JaniDrobeAds - type: Sprite sprite: Structures/Machines/VendingMachines/janidrobe.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - broken: true - type: WiresVisuals - type: AccessReader access: [["Janitor"]] @@ -1350,23 +1319,22 @@ components: - type: VendingMachine pack: SciDrobeInventory + offState: off + brokenState: broken + normalState: normal-unshaded - type: Advertise pack: SciDrobeAds - type: Sprite sprite: Structures/Machines/VendingMachines/scidrobe.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - broken: true - type: WiresVisuals - type: AccessReader access: [["Research"]] @@ -1379,23 +1347,22 @@ components: - type: VendingMachine pack: RoboDrobeInventory + offState: off + brokenState: broken + normalState: normal-unshaded - type: Advertise pack: RoboDrobeAds - type: Sprite sprite: Structures/Machines/VendingMachines/robodrobe.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - broken: true - type: WiresVisuals - type: AccessReader access: [["Research"]] @@ -1408,23 +1375,22 @@ components: - type: VendingMachine pack: GeneDrobeInventory + offState: off + brokenState: broken + normalState: normal-unshaded - type: Advertise pack: GeneDrobeAds - type: Sprite sprite: Structures/Machines/VendingMachines/genedrobe.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - broken: true - type: WiresVisuals - type: AccessReader access: [["Medical"]] @@ -1437,23 +1403,22 @@ components: - type: VendingMachine pack: ViroDrobeInventory + offState: off + brokenState: broken + normalState: normal-unshaded - type: Advertise pack: ViroDrobeAds - type: Sprite sprite: Structures/Machines/VendingMachines/virodrobe.rsi layers: - state: "off" - map: ["enum.VendingMachineVisualLayers.Unlit"] + map: ["enum.VendingMachineVisualLayers.Base"] - state: "off" map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] shader: unshaded - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - visuals: - - type: VendingMachineVisualizer - normalUnshaded: true - broken: true - type: WiresVisuals - type: AccessReader access: [["Medical"]] diff --git a/Resources/Textures/Structures/Machines/VendingMachines/dinnerware.rsi/meta.json b/Resources/Textures/Structures/Machines/VendingMachines/dinnerware.rsi/meta.json index 695c3fe716..5c200a94a9 100644 --- a/Resources/Textures/Structures/Machines/VendingMachines/dinnerware.rsi/meta.json +++ b/Resources/Textures/Structures/Machines/VendingMachines/dinnerware.rsi/meta.json @@ -46,6 +46,9 @@ }, { "name": "off" + }, + { + "name": "panel" } ] }