diff --git a/Content.Client/Entry/IgnoredComponents.cs b/Content.Client/Entry/IgnoredComponents.cs index db6bf409f9..c9c3d8df14 100644 --- a/Content.Client/Entry/IgnoredComponents.cs +++ b/Content.Client/Entry/IgnoredComponents.cs @@ -299,6 +299,7 @@ namespace Content.Client.Entry "IncreaseDamageOnWield", "TabletopGame", "LitOnPowered", + "Foldable", "TriggerOnSignalReceived", "ToggleDoorOnTrigger", "DeviceNetworkComponent", @@ -307,6 +308,8 @@ namespace Content.Client.Entry "ExtensionCableReceiver", "ExtensionCableProvider", "ApcNetworkConnection", + "SuitSensor", + "CrewMonitoringConsole", "ApcNetSwitch", "HandLabeler", "Label", @@ -314,6 +317,9 @@ namespace Content.Client.Entry "NukeCodePaper", "GhostRadio", "Armor", + "Guardian", + "GuardianCreator", + "GuardianHost", "Udder", "PneumaticCannon", "Spreader", diff --git a/Content.Client/Info/RulesManager.cs b/Content.Client/Info/RulesManager.cs index 2986b9c244..4cc361c5ba 100644 --- a/Content.Client/Info/RulesManager.cs +++ b/Content.Client/Info/RulesManager.cs @@ -3,29 +3,38 @@ using System.Globalization; using Content.Client.Lobby; using Content.Client.Viewport; using Content.Shared.CCVar; +using Content.Shared.Info; using Robust.Client.Console; using Robust.Client.State; using Robust.Client.UserInterface; using Robust.Shared.Configuration; using Robust.Shared.ContentPack; using Robust.Shared.IoC; +using Robust.Shared.Network; using Robust.Shared.Utility; namespace Content.Client.Info; -public sealed class RulesManager +public sealed class RulesManager : SharedRulesManager { [Dependency] private readonly IResourceManager _resource = default!; [Dependency] private readonly IConfigurationManager _configManager = default!; [Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!; [Dependency] private readonly IStateManager _stateManager = default!; [Dependency] private readonly IClientConsoleHost _consoleHost = default!; + [Dependency] private readonly INetManager _netManager = default!; public void Initialize() { + _netManager.RegisterNetMessage(OnShowRulesPopupMessage); _stateManager.OnStateChanged += OnStateChanged; } + private void OnShowRulesPopupMessage(ShowRulesPopupMessage message) + { + ShowRules(message.PopupTime); + } + private void OnStateChanged(StateChangedEventArgs args) { if (args.NewState is not (GameScreen or LobbyState)) diff --git a/Content.Client/Medical/CrewMonitoring/CrewMonitoringBoundUserInterface.cs b/Content.Client/Medical/CrewMonitoring/CrewMonitoringBoundUserInterface.cs new file mode 100644 index 0000000000..030ce917c6 --- /dev/null +++ b/Content.Client/Medical/CrewMonitoring/CrewMonitoringBoundUserInterface.cs @@ -0,0 +1,44 @@ +using Content.Shared.Medical.CrewMonitoring; +using JetBrains.Annotations; +using Robust.Client.GameObjects; +using Robust.Shared.GameObjects; + +namespace Content.Client.Medical.CrewMonitoring +{ + public class CrewMonitoringBoundUserInterface : BoundUserInterface + { + private CrewMonitoringWindow? _menu; + + public CrewMonitoringBoundUserInterface([NotNull] ClientUserInterfaceComponent owner, [NotNull] object uiKey) : base(owner, uiKey) + { + } + + protected override void Open() + { + _menu = new CrewMonitoringWindow(); + _menu.OpenCentered(); + _menu.OnClose += Close; + } + + protected override void UpdateState(BoundUserInterfaceState state) + { + base.UpdateState(state); + + switch (state) + { + case CrewMonitoringState st: + _menu?.ShowSensors(st.Sensors); + break; + } + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + + _menu?.Dispose(); + } + } +} diff --git a/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml b/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml new file mode 100644 index 0000000000..d0d153f9d3 --- /dev/null +++ b/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml @@ -0,0 +1,23 @@ + + + + + + + diff --git a/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs b/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs new file mode 100644 index 0000000000..1d5c13caf6 --- /dev/null +++ b/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs @@ -0,0 +1,87 @@ +using System.Collections.Generic; +using Content.Shared.Medical.SuitSensor; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.CustomControls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Localization; + +namespace Content.Client.Medical.CrewMonitoring +{ + [GenerateTypedNameReferences] + public partial class CrewMonitoringWindow : SS14Window + { + private List _rowsContent = new(); + + public CrewMonitoringWindow() + { + RobustXamlLoader.Load(this); + } + + public void ShowSensors(List stSensors) + { + ClearAllSensors(); + + // add a row for each sensor + foreach (var sensor in stSensors) + { + // add users name and job + // format: UserName (Job) + var nameLabel = new Label() + { + Text = $"{sensor.Name} ({sensor.Job})" + }; + SensorsTable.AddChild(nameLabel); + _rowsContent.Add(nameLabel); + + // add users status and damage + // format: IsAlive (TotalDamage) + var statusText = Loc.GetString(sensor.IsAlive ? + "crew-monitoring-user-interface-alive" : + "crew-monitoring-user-interface-dead"); + if (sensor.TotalDamage != null) + { + statusText += $" ({sensor.TotalDamage})"; + } + var statusLabel = new Label() + { + Text = statusText + }; + SensorsTable.AddChild(statusLabel); + _rowsContent.Add(statusLabel); + + // add users positions + // format: (x, y) + string posText; + if (sensor.Coordinates != null) + { + // todo: add locations names (kitchen, bridge, etc) + var pos = sensor.Coordinates.Value.Position; + var x = (int) pos.X; + var y = (int) pos.Y; + posText = $"({x}, {y})"; + } + else + { + posText = Loc.GetString("crew-monitoring-user-interface-no-info"); + } + var posLabel = new Label() + { + Text = posText + }; + SensorsTable.AddChild(posLabel); + _rowsContent.Add(posLabel); + } + } + + private void ClearAllSensors() + { + foreach (var child in _rowsContent) + { + SensorsTable.RemoveChild(child); + } + _rowsContent.Clear(); + } + } +} diff --git a/Content.Client/Morgue/Visualizers/BodyBagVisualizer.cs b/Content.Client/Morgue/Visualizers/BodyBagVisualizer.cs index 1aeff3e8c8..b64ce7d8d8 100644 --- a/Content.Client/Morgue/Visualizers/BodyBagVisualizer.cs +++ b/Content.Client/Morgue/Visualizers/BodyBagVisualizer.cs @@ -23,6 +23,10 @@ namespace Content.Client.Morgue.Visualizers { sprite.LayerSetVisible(BodyBagVisualLayers.Label, labelVal); } + else + { + sprite.LayerSetVisible(BodyBagVisualLayers.Label, false); + } } } diff --git a/Content.Client/Storage/Visualizers/StorageVisualizer.cs b/Content.Client/Storage/Visualizers/StorageVisualizer.cs index cd1a73927e..a48e0535db 100644 --- a/Content.Client/Storage/Visualizers/StorageVisualizer.cs +++ b/Content.Client/Storage/Visualizers/StorageVisualizer.cs @@ -10,6 +10,9 @@ namespace Content.Client.Storage.Visualizers [UsedImplicitly] public sealed class StorageVisualizer : AppearanceVisualizer { + /// + /// Sets the base sprite to this layer. Exists to make the inheritance tree less boilerplate-y. + /// [DataField("state")] private string? _stateBase; [DataField("state_open")] @@ -41,9 +44,24 @@ namespace Content.Client.Storage.Visualizers } component.TryGetData(StorageVisuals.Open, out bool open); - var state = open ? _stateOpen ?? $"{_stateBase}_open" : _stateClosed ?? $"{_stateBase}_door"; - sprite.LayerSetState(StorageVisualLayers.Door, state); + if (sprite.LayerMapTryGet(StorageVisualLayers.Door, out _)) + { + sprite.LayerSetVisible(StorageVisualLayers.Door, true); + + if (open && _stateOpen != null) + { + sprite.LayerSetState(StorageVisualLayers.Door, _stateOpen); + } + else if (!open && _stateClosed != null) + { + sprite.LayerSetState(StorageVisualLayers.Door, _stateClosed); + } + else + { + sprite.LayerSetVisible(StorageVisualLayers.Door, false); + } + } if (component.TryGetData(StorageVisuals.CanLock, out bool canLock) && canLock) { diff --git a/Content.Client/Visualizer/FoldableVisualizer.cs b/Content.Client/Visualizer/FoldableVisualizer.cs new file mode 100644 index 0000000000..6b2861dc7b --- /dev/null +++ b/Content.Client/Visualizer/FoldableVisualizer.cs @@ -0,0 +1,36 @@ +using Robust.Client.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Serialization.Manager.Attributes; + +namespace Content.Client.Visualizer; + + +public sealed class FoldableVisualizer : AppearanceVisualizer +{ + [DataField("key")] + private string _key = default!; + + public override void OnChangeData(AppearanceComponent appearance) + { + base.OnChangeData(appearance); + + var entManager = IoCManager.Resolve(); + + if (!entManager.TryGetComponent(appearance.Owner, out SpriteComponent? sprite)) return; + + if (appearance.TryGetData("FoldedState", out bool folded) && folded) + { + sprite.LayerSetState(FoldableVisualLayers.Base, $"{_key}_folded"); + } + else + { + sprite.LayerSetState(FoldableVisualLayers.Base, $"{_key}"); + } + } + + public enum FoldableVisualLayers : byte + { + Base, + } +} diff --git a/Content.Client/Visualizer/RollerbedVisualizer.cs b/Content.Client/Visualizer/RollerbedVisualizer.cs new file mode 100644 index 0000000000..053d521d57 --- /dev/null +++ b/Content.Client/Visualizer/RollerbedVisualizer.cs @@ -0,0 +1,29 @@ +using JetBrains.Annotations; +using Robust.Client.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Serialization.Manager.Attributes; + +namespace Content.Client.Visualizer +{ + [UsedImplicitly] + public sealed class RollerbedVisualizer : AppearanceVisualizer + { + [DataField("key")] + private string _key = default!; + + public override void OnChangeData(AppearanceComponent appearance) + { + base.OnChangeData(appearance); + + var entManager = IoCManager.Resolve(); + + if (!entManager.TryGetComponent(appearance.Owner, out SpriteComponent? sprite)) return; + + if (appearance.TryGetData("StrapState", out bool strapped) && strapped) + { + sprite.LayerSetState(0, $"{_key}_buckled"); + } + } + } +} diff --git a/Content.Server/Access/Systems/IdCardSystem.cs b/Content.Server/Access/Systems/IdCardSystem.cs index c1bcaff58e..01ebef2251 100644 --- a/Content.Server/Access/Systems/IdCardSystem.cs +++ b/Content.Server/Access/Systems/IdCardSystem.cs @@ -101,22 +101,14 @@ namespace Content.Server.Access.Systems return true; // check inventory slot? - if (EntityManager.TryGetComponent(uid, out InventoryComponent? inventoryComponent) && - inventoryComponent.HasSlot(EquipmentSlotDefines.Slots.IDCARD) && - inventoryComponent.TryGetSlotItem(EquipmentSlotDefines.Slots.IDCARD, out ItemComponent? item) && - TryGetIdCard(item.Owner, out idCard)) - { - return true; - } - - return false; + return TryGetIdCardSlot(uid, out idCard); } /// /// Attempt to get an id card component from an entity, either by getting it directly from the entity, or by /// getting the contained id from a . /// - private bool TryGetIdCard(EntityUid uid, [NotNullWhen(true)] out IdCardComponent? idCard) + public bool TryGetIdCard(EntityUid uid, [NotNullWhen(true)] out IdCardComponent? idCard) { if (EntityManager.TryGetComponent(uid, out idCard)) return true; @@ -129,5 +121,17 @@ namespace Content.Server.Access.Systems return false; } + + /// + /// Try get id card from mobs ID inventory slot + /// + public bool TryGetIdCardSlot(EntityUid uid, [NotNullWhen(true)] out IdCardComponent? idCard) + { + idCard = null; + return EntityManager.TryGetComponent(uid, out InventoryComponent? inventoryComponent) && + inventoryComponent.HasSlot(EquipmentSlotDefines.Slots.IDCARD) && + inventoryComponent.TryGetSlotItem(EquipmentSlotDefines.Slots.IDCARD, out ItemComponent? item) && + TryGetIdCard(item.Owner, out idCard); + } } } diff --git a/Content.Server/Actions/Actions/GuardianToggleAction.cs b/Content.Server/Actions/Actions/GuardianToggleAction.cs new file mode 100644 index 0000000000..5343e72284 --- /dev/null +++ b/Content.Server/Actions/Actions/GuardianToggleAction.cs @@ -0,0 +1,38 @@ +using Content.Server.Guardian; +using Content.Shared.Actions.Behaviors; +using Content.Shared.Cooldown; +using Content.Shared.Popups; +using JetBrains.Annotations; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Serialization.Manager.Attributes; + +namespace Content.Server.Actions.Actions +{ + /// + /// Manifests the guardian saved in the action, using the system + /// + [UsedImplicitly] + [DataDefinition] + public class ToggleGuardianAction : IInstantAction + { + [DataField("cooldown")] public float Cooldown { get; [UsedImplicitly] private set; } + + public void DoInstantAction(InstantActionEventArgs args) + { + var entManager = IoCManager.Resolve(); + + if (entManager.TryGetComponent(args.Performer, out GuardianHostComponent? hostComponent) && + hostComponent.HostedGuardian != null) + { + EntitySystem.Get().ToggleGuardian(hostComponent); + args.PerformerActions?.Cooldown(args.ActionType, Cooldowns.SecondsFromNow(Cooldown)); + } + else + { + args.Performer.PopupMessage(Loc.GetString("guardian-missing-invalid-action")); + } + } + } +} diff --git a/Content.Server/Buckle/Components/BuckleComponent.cs b/Content.Server/Buckle/Components/BuckleComponent.cs index 0c40c6c768..9da4b1eea4 100644 --- a/Content.Server/Buckle/Components/BuckleComponent.cs +++ b/Content.Server/Buckle/Components/BuckleComponent.cs @@ -133,7 +133,7 @@ namespace Content.Server.Buckle.Components break; } - ownTransform.LocalPosition = Vector2.Zero + BuckleOffset; + ownTransform.LocalPosition = strap.BuckleOffset; } public bool CanBuckle(EntityUid user, EntityUid to, [NotNullWhen(true)] out StrapComponent? strap) @@ -317,10 +317,17 @@ namespace Content.Server.Buckle.Components BuckledTo = null; - if (_entMan.GetComponent(Owner).Parent == _entMan.GetComponent(oldBuckledTo.Owner)) + var entManager = IoCManager.Resolve(); + var xform = entManager.GetComponent(Owner); + var oldBuckledXform = entManager.GetComponent(oldBuckledTo.Owner); + + if (xform.ParentUid == oldBuckledXform.Owner) { - _entMan.GetComponent(Owner).AttachParentToContainerOrGrid(); - _entMan.GetComponent(Owner).WorldRotation = _entMan.GetComponent(oldBuckledTo.Owner).WorldRotation; + xform.AttachParentToContainerOrGrid(); + xform.WorldRotation = oldBuckledXform.WorldRotation; + + if (oldBuckledTo.UnbuckleOffset != Vector2.Zero) + xform.Coordinates = oldBuckledXform.Coordinates.Offset(oldBuckledTo.UnbuckleOffset); } Appearance?.SetData(BuckleVisuals.Buckled, false); @@ -403,22 +410,5 @@ namespace Content.Server.Buckle.Components return new BuckleComponentState(Buckled, drawDepth, LastEntityBuckledTo, DontCollide); } - - public void Update(PhysicsComponent physics) - { - if (!DontCollide) - return; - - physics.WakeBody(); - - if (!IsOnStrapEntityThisFrame && DontCollide) - { - DontCollide = false; - TryUnbuckle(Owner); - Dirty(); - } - - IsOnStrapEntityThisFrame = false; - } } } diff --git a/Content.Server/Buckle/Components/StrapComponent.cs b/Content.Server/Buckle/Components/StrapComponent.cs index 3d06c638e0..81f0e79d31 100644 --- a/Content.Server/Buckle/Components/StrapComponent.cs +++ b/Content.Server/Buckle/Components/StrapComponent.cs @@ -9,6 +9,7 @@ using Content.Shared.Sound; using Robust.Server.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.IoC; +using Robust.Shared.Maths; using Robust.Shared.Serialization; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.ViewVariables; @@ -21,8 +22,6 @@ namespace Content.Server.Buckle.Components { [ComponentDependency] public readonly SpriteComponent? SpriteComponent = null; - [Dependency] private readonly IEntityManager _entMan = default!; - private readonly HashSet _buckledEntities = new(); /// @@ -37,6 +36,50 @@ namespace Content.Server.Buckle.Components [ViewVariables] [DataField("size")] private int _size = 100; private int _occupiedSize; + /// + /// The buckled entity will be offset by this amount from the center of the strap object. + /// If this offset it too big, it will be clamped to + /// + [DataField("buckleOffset", required: false)] + private Vector2 _buckleOffset = Vector2.Zero; + + private bool _enabled = true; + + /// + /// If disabled, nothing can be buckled on this object, and it will unbuckle anything that's already buckled + /// + public bool Enabled + { + get => _enabled; + set + { + _enabled = value; + if (_enabled == value) return; + RemoveAll(); + } + } + + /// + /// The distance above which a buckled entity will be automatically unbuckled. + /// Don't change it unless you really have to + /// + [DataField("maxBuckleDistance", required: false)] + public float MaxBuckleDistance = 0.1f; + + /// + /// You can specify the offset the entity will have after unbuckling. + /// + [DataField("unbuckleOffset", required: false)] + public Vector2 UnbuckleOffset = Vector2.Zero; + + /// + /// Gets and clamps the buckle offset to MaxBuckleDistance + /// + public Vector2 BuckleOffset => Vector2.Clamp( + _buckleOffset, + Vector2.One * -MaxBuckleDistance, + Vector2.One * MaxBuckleDistance); + /// /// The entity that is currently buckled here, synced from /// @@ -96,6 +139,8 @@ namespace Content.Server.Buckle.Components /// True if added, false otherwise public bool TryAdd(BuckleComponent buckle, bool force = false) { + if (!Enabled) return false; + if (!force && !HasSpace(buckle)) { return false; @@ -110,6 +155,12 @@ namespace Content.Server.Buckle.Components buckle.Appearance?.SetData(StrapVisuals.RotationAngle, _rotation); + // Update the visuals of the strap object + if (IoCManager.Resolve().TryGetComponent(Owner, out var appearance)) + { + appearance.SetData("StrapState", true); + } + #pragma warning disable 618 SendMessage(new StrapMessage(buckle.Owner, Owner)); #pragma warning restore 618 @@ -126,6 +177,11 @@ namespace Content.Server.Buckle.Components { if (_buckledEntities.Remove(buckle.Owner)) { + if (IoCManager.Resolve().TryGetComponent(Owner, out var appearance)) + { + appearance.SetData("StrapState", false); + } + _occupiedSize -= buckle.Size; #pragma warning disable 618 SendMessage(new UnStrapMessage(buckle.Owner, Owner)); @@ -147,9 +203,11 @@ namespace Content.Server.Buckle.Components private void RemoveAll() { + var entManager = IoCManager.Resolve(); + foreach (var entity in _buckledEntities.ToArray()) { - if (_entMan.TryGetComponent(entity, out var buckle)) + if (entManager.TryGetComponent(entity, out var buckle)) { buckle.TryUnbuckle(entity, true); } @@ -166,7 +224,9 @@ namespace Content.Server.Buckle.Components bool IInteractHand.InteractHand(InteractHandEventArgs eventArgs) { - if (!_entMan.TryGetComponent(eventArgs.User, out var buckle)) + var entManager = IoCManager.Resolve(); + + if (!entManager.TryGetComponent(eventArgs.User, out var buckle)) { return false; } @@ -176,7 +236,9 @@ namespace Content.Server.Buckle.Components public override bool DragDropOn(DragDropEvent eventArgs) { - if (!_entMan.TryGetComponent(eventArgs.Dragged, out BuckleComponent? buckleComponent)) return false; + var entManager = IoCManager.Resolve(); + + if (!entManager.TryGetComponent(eventArgs.Dragged, out BuckleComponent? buckleComponent)) return false; return buckleComponent.TryBuckle(eventArgs.User, Owner); } } diff --git a/Content.Server/Buckle/Systems/BuckleSystem.cs b/Content.Server/Buckle/Systems/BuckleSystem.cs index 0135e3aea0..7586047fb3 100644 --- a/Content.Server/Buckle/Systems/BuckleSystem.cs +++ b/Content.Server/Buckle/Systems/BuckleSystem.cs @@ -42,10 +42,12 @@ namespace Content.Server.Buckle.Systems if (!args.CanAccess || !args.CanInteract || !component.Buckled) return; - Verb verb = new(); - verb.Act = () => component.TryUnbuckle(args.User); - verb.Text = Loc.GetString("verb-categories-unbuckle"); - verb.IconTexture = "/Textures/Interface/VerbIcons/unbuckle.svg.192dpi.png"; + Verb verb = new() + { + Act = () => component.TryUnbuckle(args.User), + Text = Loc.GetString("verb-categories-unbuckle"), + IconTexture = "/Textures/Interface/VerbIcons/unbuckle.svg.192dpi.png" + }; if (args.Target == args.User && args.Using == null) { @@ -62,14 +64,6 @@ namespace Content.Server.Buckle.Systems args.Handled = component.TryUnbuckle(args.User); } - public override void Update(float frameTime) - { - foreach (var (buckle, physics) in EntityManager.EntityQuery()) - { - buckle.Update(physics); - } - } - private void MoveEvent(EntityUid uid, BuckleComponent buckle, ref MoveEvent ev) { var strap = buckle.BuckledTo; @@ -81,7 +75,7 @@ namespace Content.Server.Buckle.Systems var strapPosition = EntityManager.GetComponent(strap.Owner).Coordinates.Offset(buckle.BuckleOffset); - if (ev.NewPosition.InRange(EntityManager, strapPosition, 0.2f)) + if (ev.NewPosition.InRange(EntityManager, strapPosition, strap.MaxBuckleDistance)) { return; } diff --git a/Content.Server/Buckle/Systems/StrapSystem.cs b/Content.Server/Buckle/Systems/StrapSystem.cs index 9acd58d2db..c1d8ebe784 100644 --- a/Content.Server/Buckle/Systems/StrapSystem.cs +++ b/Content.Server/Buckle/Systems/StrapSystem.cs @@ -27,7 +27,7 @@ namespace Content.Server.Buckle.Systems private void AddStrapVerbs(EntityUid uid, StrapComponent component, GetInteractionVerbsEvent args) { - if (args.Hands == null || !args.CanAccess || !args.CanInteract) + if (args.Hands == null || !args.CanAccess || !args.CanInteract || !component.Enabled) return; // Note that for whatever bloody reason, buckle component has its own interaction range. Additionally, this @@ -41,9 +41,12 @@ namespace Content.Server.Buckle.Systems if (!_interactionSystem.InRangeUnobstructed(args.User, args.Target, range: buckledComp.Range)) continue; - Verb verb = new(); - verb.Act = () => buckledComp.TryUnbuckle(args.User); - verb.Category = VerbCategory.Unbuckle; + Verb verb = new() + { + Act = () => buckledComp.TryUnbuckle(args.User), + Category = VerbCategory.Unbuckle + }; + if (entity == args.User) verb.Text = Loc.GetString("verb-self-target-pronoun"); else @@ -64,10 +67,12 @@ namespace Content.Server.Buckle.Systems component.HasSpace(buckle) && _interactionSystem.InRangeUnobstructed(args.User, args.Target, range: buckle.Range)) { - Verb verb = new(); - verb.Act = () => buckle.TryBuckle(args.User, args.Target); - verb.Category = VerbCategory.Buckle; - verb.Text = Loc.GetString("verb-self-target-pronoun"); + Verb verb = new() + { + Act = () => buckle.TryBuckle(args.User, args.Target), + Category = VerbCategory.Buckle, + Text = Loc.GetString("verb-self-target-pronoun") + }; args.Verbs.Add(verb); } @@ -82,14 +87,15 @@ namespace Content.Server.Buckle.Systems if (!_interactionSystem.InRangeUnobstructed(@using, args.Target, usingBuckle.Range, predicate: Ignored)) return; - Verb verb = new(); - verb.Act = () => usingBuckle.TryBuckle(args.User, args.Target); - verb.Category = VerbCategory.Buckle; - verb.Text = EntityManager.GetComponent(@using).EntityName; - - // If the used entity is a person being pulled, prioritize this verb. Conversely, if it is - // just a held object, the user is probably just trying to sit down. - verb.Priority = EntityManager.HasComponent(@using) ? 1 : -1; + Verb verb = new() + { + Act = () => usingBuckle.TryBuckle(args.User, args.Target), + Category = VerbCategory.Buckle, + Text = EntityManager.GetComponent(@using).EntityName, + // just a held object, the user is probably just trying to sit down. + // If the used entity is a person being pulled, prioritize this verb. Conversely, if it is + Priority = EntityManager.HasComponent(@using) ? 1 : -1 + }; args.Verbs.Add(verb); } diff --git a/Content.Server/Destructible/Thresholds/Behaviors/SpawnEntitiesBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/SpawnEntitiesBehavior.cs index bdf7172f1a..1af5e80199 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/SpawnEntitiesBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/SpawnEntitiesBehavior.cs @@ -19,6 +19,9 @@ namespace Content.Server.Destructible.Thresholds.Behaviors [DataField("spawn")] public Dictionary Spawn { get; set; } = new(); + [DataField("offset")] + public float Offset { get; set; } = 0.5f; + public void Execute(EntityUid owner, DestructibleSystem system) { var position = system.EntityManager.GetComponent(owner).MapPosition; @@ -36,14 +39,14 @@ namespace Content.Server.Destructible.Thresholds.Behaviors var spawned = system.EntityManager.SpawnEntity(entityId, position); var stack = IoCManager.Resolve().GetComponent(spawned); EntitySystem.Get().SetCount(spawned, count, stack); - spawned.RandomOffset(0.5f); + spawned.RandomOffset(Offset); } else { for (var i = 0; i < count; i++) { var spawned = system.EntityManager.SpawnEntity(entityId, position); - spawned.RandomOffset(0.5f); + spawned.RandomOffset(Offset); } } } diff --git a/Content.Server/DeviceNetwork/DeviceNetworkConstants.cs b/Content.Server/DeviceNetwork/DeviceNetworkConstants.cs index 6136a210ae..b8d53ee423 100644 --- a/Content.Server/DeviceNetwork/DeviceNetworkConstants.cs +++ b/Content.Server/DeviceNetwork/DeviceNetworkConstants.cs @@ -24,6 +24,12 @@ namespace Content.Server.DeviceNetwork /// public const string CmdSetState = "set_state"; + /// + /// The command for a device that just updated its state + /// E.g. suit sensors broadcasting owners vitals state + /// + public const string CmdUpdatedState = "updated_state"; + #endregion #region SetState diff --git a/Content.Server/Entry/EntryPoint.cs b/Content.Server/Entry/EntryPoint.cs index fa3bee9f45..c74441b013 100644 --- a/Content.Server/Entry/EntryPoint.cs +++ b/Content.Server/Entry/EntryPoint.cs @@ -8,6 +8,7 @@ using Content.Server.Connection; using Content.Server.Database; using Content.Server.EUI; using Content.Server.GameTicking; +using Content.Server.Info; using Content.Server.IoC; using Content.Server.Maps; using Content.Server.NodeContainer.NodeGroups; @@ -91,6 +92,7 @@ namespace Content.Server.Entry IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); + IoCManager.Resolve().Initialize(); _euiManager.Initialize(); IoCManager.Resolve().Initialize(); diff --git a/Content.Server/Foldable/FoldableComponent.cs b/Content.Server/Foldable/FoldableComponent.cs new file mode 100644 index 0000000000..514d4eddb5 --- /dev/null +++ b/Content.Server/Foldable/FoldableComponent.cs @@ -0,0 +1,25 @@ +#nullable enable + +using Robust.Shared.Containers; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.ViewVariables; + +namespace Content.Server.Foldable +{ + + /// + /// Used to create "foldable structures" that you can pickup like an item when folded. Used for rollerbeds and wheelchairs + /// + [RegisterComponent] + public class FoldableComponent : Component + { + public override string Name => "Foldable"; + + [DataField("folded")] + [ViewVariables] + public bool IsFolded = false; + + public bool CanBeFolded = true; + } +} diff --git a/Content.Server/Foldable/FoldableSystem.cs b/Content.Server/Foldable/FoldableSystem.cs new file mode 100644 index 0000000000..380b9f29b5 --- /dev/null +++ b/Content.Server/Foldable/FoldableSystem.cs @@ -0,0 +1,131 @@ +using System.Linq; +using Content.Server.Buckle.Components; +using Content.Server.Storage.Components; +using Content.Shared.Interaction; +using Content.Shared.Item; +using Content.Shared.Verbs; +using JetBrains.Annotations; +using Robust.Shared.Containers; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Localization; + +namespace Content.Server.Foldable +{ + [UsedImplicitly] + public sealed class FoldableSystem : EntitySystem + { + [Dependency] private SharedContainerSystem _container = default!; + + private const string FoldKey = "FoldedState"; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnFoldableInit); + SubscribeLocalEvent(OnFoldableOpenAttempt); + SubscribeLocalEvent(OnPickedUpAttempt); + SubscribeLocalEvent(AddFoldVerb); + } + + private void OnFoldableOpenAttempt(EntityUid uid, FoldableComponent component, StorageOpenAttemptEvent args) + { + if (component.IsFolded) + args.Cancel(); + } + + private void OnFoldableInit(EntityUid uid, FoldableComponent component, ComponentInit args) + { + SetFolded(component, component.IsFolded); + } + + private bool TryToggleFold(FoldableComponent comp) + { + return TrySetFolded(comp, !comp.IsFolded); + } + + /// + /// Try to fold/unfold + /// + /// + /// Folded state we want + /// True if successful + private bool TrySetFolded(FoldableComponent comp, bool state) + { + if (state == comp.IsFolded) + return false; + + if (_container.IsEntityInContainer(comp.Owner)) + return false; + + // First we check if the foldable object has a strap component + if (EntityManager.TryGetComponent(comp.Owner, out StrapComponent? strap)) + { + // If an entity is buckled to the object we can't pick it up or fold it + if (strap.BuckledEntities.Any()) + return false; + } + + SetFolded(comp, state); + return true; + } + + /// + /// Set the folded state of the given + /// + /// + /// If true, the component will become folded, else unfolded + private void SetFolded(FoldableComponent component, bool folded) + { + component.IsFolded = folded; + component.CanBeFolded = !_container.IsEntityInContainer(component.Owner); + + // You can't buckle an entity to a folded object + if (EntityManager.TryGetComponent(component.Owner, out StrapComponent? strap)) + strap.Enabled = !component.IsFolded; + + // Update visuals only if the value has changed + if (EntityManager.TryGetComponent(component.Owner, out AppearanceComponent? appearance)) + appearance.SetData(FoldKey, folded); + } + + #region Event handlers + + /// + /// Prevents foldable objects to be picked up when unfolded + /// + /// + /// + /// + private void OnPickedUpAttempt(EntityUid uid, FoldableComponent component, AttemptItemPickupEvent args) + { + if (!component.IsFolded) + args.Cancel(); + } + + #endregion + + #region Verb + + private void AddFoldVerb(EntityUid uid, FoldableComponent component, GetAlternativeVerbsEvent args) + { + if (!args.CanAccess || !args.CanInteract) + return; + + Verb verb = new() + { + Act = () => TryToggleFold(component), + Text = component.IsFolded ? Loc.GetString("unfold-verb") : Loc.GetString("fold-verb"), + IconTexture = "/Textures/Interface/VerbIcons/fold.svg.192dpi.png", + + // If the object is unfolded and they click it, they want to fold it, if it's folded, they want to pick it up + Priority = component.IsFolded ? 0 : 2, + }; + + args.Verbs.Add(verb); + } + + #endregion + } +} diff --git a/Content.Server/Guardian/GuardianComponent.cs b/Content.Server/Guardian/GuardianComponent.cs new file mode 100644 index 0000000000..a8ebedf22c --- /dev/null +++ b/Content.Server/Guardian/GuardianComponent.cs @@ -0,0 +1,39 @@ +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.ViewVariables; + +namespace Content.Server.Guardian +{ + /// + /// Given to guardians to monitor their link with the host + /// + [RegisterComponent] + [ComponentProtoName("Guardian")] + public class GuardianComponent : Component + { + /// + /// The guardian host entity + /// + public EntityUid Host; + + /// + /// Percentage of damage reflected from the guardian to the host + /// + [ViewVariables] + [DataField("damageShare")] + public float DamageShare { get; set; } = 0.85f; + + /// + /// Maximum distance the guardian can travel before it's forced to recall, use YAML to set + /// + [ViewVariables] + [DataField("distanceAllowed")] + public float DistanceAllowed { get; set; } = 5f; + + /// + /// If the guardian is currently manifested + /// + public bool GuardianLoose = false; + + } +} diff --git a/Content.Server/Guardian/GuardianCreatorComponent.cs b/Content.Server/Guardian/GuardianCreatorComponent.cs new file mode 100644 index 0000000000..d581ddc351 --- /dev/null +++ b/Content.Server/Guardian/GuardianCreatorComponent.cs @@ -0,0 +1,39 @@ +using Robust.Shared.GameObjects; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Robust.Shared.ViewVariables; + +namespace Content.Server.Guardian +{ + /// + /// Creates a GuardianComponent attached to the user's GuardianHost. + /// + [RegisterComponent] + [ComponentProtoName("GuardianCreator")] + public sealed class GuardianCreatorComponent : Component + { + /// + /// Counts as spent upon exhausting the injection + /// + /// + /// We don't mark as deleted as examine depends on this. + /// + public bool Used = false; + + /// + /// The prototype of the guardian entity which will be created + /// + [ViewVariables] + [DataField("guardianProto", customTypeSerializer:typeof(PrototypeIdSerializer), required: true)] + public string GuardianProto { get; set; } = default!; + + /// + /// How long it takes to inject someone. + /// + [DataField("delay")] + public float InjectionDelay = 5f; + + public bool Injecting = false; + } +} diff --git a/Content.Server/Guardian/GuardianHostComponent.cs b/Content.Server/Guardian/GuardianHostComponent.cs new file mode 100644 index 0000000000..e9aecdae2a --- /dev/null +++ b/Content.Server/Guardian/GuardianHostComponent.cs @@ -0,0 +1,27 @@ +using Robust.Shared.Containers; +using Robust.Shared.GameObjects; +using Robust.Shared.ViewVariables; + +namespace Content.Server.Guardian +{ + /// + /// Given to guardian users upon establishing a guardian link with the entity + /// + [RegisterComponent] + [ComponentProtoName("GuardianHost")] + public sealed class GuardianHostComponent : Component + { + /// + /// Guardian hosted within the component + /// + /// + /// Can be null if the component is added at any time. + /// + public EntityUid? HostedGuardian; + + /// + /// Container which holds the guardian + /// + [ViewVariables] public ContainerSlot GuardianContainer = default!; + } +} diff --git a/Content.Server/Guardian/GuardianSystem.cs b/Content.Server/Guardian/GuardianSystem.cs new file mode 100644 index 0000000000..7373a6c079 --- /dev/null +++ b/Content.Server/Guardian/GuardianSystem.cs @@ -0,0 +1,349 @@ +using Content.Server.Actions; +using Content.Server.DoAfter; +using Content.Server.Hands.Components; +using Content.Server.Inventory.Components; +using Content.Server.Popups; +using Content.Shared.Actions; +using Content.Shared.Actions.Components; +using Content.Shared.Audio; +using Content.Shared.Damage; +using Content.Shared.Examine; +using Content.Shared.Interaction; +using Content.Shared.MobState; +using Content.Shared.MobState.EntitySystems; +using Robust.Server.GameObjects; +using Robust.Shared.Audio; +using Robust.Shared.Containers; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Log; +using Robust.Shared.Player; +using Robust.Shared.Utility; + +namespace Content.Server.Guardian +{ + /// + /// A guardian has a host it's attached to that it fights for. A fighting spirit. + /// + public sealed class GuardianSystem : EntitySystem + { + [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly PopupSystem _popupSystem = default!; + [Dependency] private readonly DamageableSystem _damageSystem = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnCreatorUse); + SubscribeLocalEvent(OnCreatorInteract); + SubscribeLocalEvent(OnCreatorExamine); + SubscribeLocalEvent(OnCreatorInject); + SubscribeLocalEvent(OnCreatorCancelled); + + SubscribeLocalEvent(OnGuardianMove); + SubscribeLocalEvent(OnGuardianDamaged); + SubscribeLocalEvent(OnGuardianPlayer); + SubscribeLocalEvent(OnGuardianUnplayer); + + SubscribeLocalEvent(OnHostInit); + SubscribeLocalEvent(OnHostMove); + SubscribeLocalEvent(OnHostStateChange); + SubscribeLocalEvent(OnHostShutdown); + } + + private void OnGuardianUnplayer(EntityUid uid, GuardianComponent component, PlayerDetachedEvent args) + { + var host = component.Host; + + if (!TryComp(host, out var hostComponent)) return; + + RetractGuardian(hostComponent, component); + } + + private void OnGuardianPlayer(EntityUid uid, GuardianComponent component, PlayerAttachedEvent args) + { + var host = component.Host; + + if (!HasComp(host)) return; + + _popupSystem.PopupEntity(Loc.GetString("guardian-available"), host, Filter.Entities(host)); + } + + private void OnHostInit(EntityUid uid, GuardianHostComponent component, ComponentInit args) + { + component.GuardianContainer = uid.EnsureContainer("GuardianContainer"); + } + + private void OnHostShutdown(EntityUid uid, GuardianHostComponent component, ComponentShutdown args) + { + if (component.HostedGuardian == null) return; + EntityManager.QueueDeleteEntity(component.HostedGuardian.Value); + } + + public void ToggleGuardian(GuardianHostComponent hostComponent) + { + if (hostComponent.HostedGuardian == null || + !TryComp(hostComponent.HostedGuardian, out GuardianComponent? guardianComponent)) return; + + if (guardianComponent.GuardianLoose) + { + RetractGuardian(hostComponent, guardianComponent); + } + else + { + ReleaseGuardian(hostComponent, guardianComponent); + } + } + + /// + /// Adds the guardian host component to the user and spawns the guardian inside said component + /// + private void OnCreatorUse(EntityUid uid, GuardianCreatorComponent component, UseInHandEvent args) + { + if (args.Handled) return; + args.Handled = true; + UseCreator(args.User, args.User, component); + } + + private void OnCreatorInteract(EntityUid uid, GuardianCreatorComponent component, AfterInteractEvent args) + { + if (args.Handled || args.Target == null) return; + args.Handled = true; + UseCreator(args.User, args.Target.Value, component); + } + + private void OnCreatorCancelled(GuardianCreatorInjectCancelledEvent ev) + { + ev.Component.Injecting = false; + } + + private void UseCreator(EntityUid user, EntityUid target, GuardianCreatorComponent component) + { + if (component.Used) + { + _popupSystem.PopupEntity(Loc.GetString("guardian-activator-empty-invalid-creation"), user, Filter.Entities(user)); + return; + } + + // If user is already a host don't duplicate. + if (HasComp(target)) + { + _popupSystem.PopupEntity(Loc.GetString("guardian-already-present-invalid-creation"), user, Filter.Entities(user)); + return; + } + + // Can't work without actions + EntityManager.EnsureComponent(target); + + if (component.Injecting) return; + + component.Injecting = true; + + _doAfterSystem.DoAfter(new DoAfterEventArgs(user, component.InjectionDelay, target: target) + { + BroadcastFinishedEvent = new GuardianCreatorInjectedEvent(user, target, component), + BroadcastCancelledEvent = new GuardianCreatorInjectCancelledEvent(target, component), + BreakOnTargetMove = true, + BreakOnUserMove = true, + }); + } + + private void OnCreatorInject(GuardianCreatorInjectedEvent ev) + { + var comp = ev.Component; + + if (comp.Deleted || + comp.Used || + !TryComp(ev.User, out var hands) || + !hands.IsHolding(comp.Owner) || + HasComp(ev.Target) || + !TryComp(ev.Target, out var actions)) + { + comp.Injecting = false; + return; + } + + var hostXform = EntityManager.GetComponent(ev.Target); + var host = EntityManager.EnsureComponent(ev.Target); + // Use map position so it's not inadvertantly parented to the host + if it's in a container it spawns outside I guess. + var guardian = EntityManager.SpawnEntity(comp.GuardianProto, hostXform.MapPosition); + + host.GuardianContainer.Insert(guardian); + host.HostedGuardian = guardian; + + if (TryComp(guardian, out GuardianComponent? guardianComponent)) + { + guardianComponent.Host = ev.Target; + + // Grant the user the recall action and notify them + actions.Grant(ActionType.ManifestGuardian); + SoundSystem.Play(Filter.Entities(ev.Target), "/Audio/Effects/guardian_inject.ogg", ev.Target); + + _popupSystem.PopupEntity(Loc.GetString("guardian-created"), ev.Target, Filter.Entities(ev.Target)); + // Exhaust the activator + comp.Used = true; + } + else + { + Logger.ErrorS("guardian", $"Tried to spawn a guardian that doesn't have {nameof(GuardianComponent)}"); + EntityManager.QueueDeleteEntity(guardian); + } + } + + /// + /// Triggers when the host receives damage which puts the host in either critical or killed state + /// + private void OnHostStateChange(EntityUid uid, GuardianHostComponent component, MobStateChangedEvent args) + { + if (component.HostedGuardian == null) return; + + if (args.CurrentMobState.IsCritical()) + { + _popupSystem.PopupEntity(Loc.GetString("guardian-critical-warn"), component.HostedGuardian.Value, Filter.Entities(component.HostedGuardian.Value)); + SoundSystem.Play(Filter.Entities(component.HostedGuardian.Value), "/Audio/Effects/guardian_warn.ogg", component.HostedGuardian.Value); + } + else if (args.CurrentMobState.IsDead()) + { + SoundSystem.Play(Filter.Pvs(uid), "/Audio/Voice/Human/malescream_guardian.ogg", uid, AudioHelpers.WithVariation(0.20f)); + EntityManager.RemoveComponent(uid); + } + } + + /// + /// Handles guardian receiving damage and splitting it with the host according to his defence percent + /// + private void OnGuardianDamaged(EntityUid uid, GuardianComponent component, DamageChangedEvent args) + { + if (args.DamageDelta == null) return; + + _damageSystem.TryChangeDamage(component.Host, args.DamageDelta * component.DamageShare); + _popupSystem.PopupEntity(Loc.GetString("guardian-entity-taking-damage"), component.Host, Filter.Entities(component.Host)); + + } + + /// + /// Triggers while trying to examine an activator to see if it's used + /// + private void OnCreatorExamine(EntityUid uid, GuardianCreatorComponent component, ExaminedEvent args) + { + if (component.Used) + { + args.PushMarkup(Loc.GetString("guardian-activator-empty-examine")); + } + } + + /// + /// Called every time the host moves, to make sure the distance between the host and the guardian isn't too far + /// + private void OnHostMove(EntityUid uid, GuardianHostComponent component, ref MoveEvent args) + { + if (component.HostedGuardian == null || + !TryComp(component.HostedGuardian, out GuardianComponent? guardianComponent) || + !guardianComponent.GuardianLoose) return; + + CheckGuardianMove(uid, component.HostedGuardian.Value, component); + } + + /// + /// Called every time the guardian moves: makes sure it's not out of it's allowed distance + /// + private void OnGuardianMove(EntityUid uid, GuardianComponent component, ref MoveEvent args) + { + if (!component.GuardianLoose) return; + + CheckGuardianMove(component.Host, uid, guardianComponent: component); + } + + /// + /// Retract the guardian if either the host or the guardian move away from each other. + /// + private void CheckGuardianMove( + EntityUid hostUid, + EntityUid guardianUid, + GuardianHostComponent? hostComponent = null, + GuardianComponent? guardianComponent = null, + TransformComponent? hostXform = null, + TransformComponent? guardianXform = null) + { + if (!Resolve(hostUid, ref hostComponent, ref hostXform) || + !Resolve(guardianUid, ref guardianComponent, ref guardianXform)) + { + return; + } + + if (!guardianComponent.GuardianLoose) return; + + if (!guardianXform.Coordinates.InRange(EntityManager, hostXform.Coordinates, guardianComponent.DistanceAllowed)) + { + RetractGuardian(hostComponent, guardianComponent); + } + } + + private bool CanRelease(GuardianHostComponent host, GuardianComponent guardian) + { + return HasComp(guardian.Owner); + } + + private void ReleaseGuardian(GuardianHostComponent hostComponent, GuardianComponent guardianComponent) + { + if (guardianComponent.GuardianLoose) + { + DebugTools.Assert(!hostComponent.GuardianContainer.Contains(guardianComponent.Owner)); + return; + } + + if (!CanRelease(hostComponent, guardianComponent)) + { + _popupSystem.PopupEntity(Loc.GetString("guardian-no-soul"), hostComponent.Owner, Filter.Entities(hostComponent.Owner)); + return; + } + + DebugTools.Assert(hostComponent.GuardianContainer.Contains(guardianComponent.Owner)); + hostComponent.GuardianContainer.Remove(guardianComponent.Owner); + DebugTools.Assert(!hostComponent.GuardianContainer.Contains(guardianComponent.Owner)); + + guardianComponent.GuardianLoose = true; + } + + private void RetractGuardian(GuardianHostComponent hostComponent, GuardianComponent guardianComponent) + { + if (!guardianComponent.GuardianLoose) + { + DebugTools.Assert(hostComponent.GuardianContainer.Contains(guardianComponent.Owner)); + return; + } + + hostComponent.GuardianContainer.Insert(guardianComponent.Owner); + DebugTools.Assert(hostComponent.GuardianContainer.Contains(guardianComponent.Owner)); + _popupSystem.PopupEntity(Loc.GetString("guardian-entity-recall"), hostComponent.Owner, Filter.Pvs(hostComponent.Owner)); + guardianComponent.GuardianLoose = false; + } + + private sealed class GuardianCreatorInjectedEvent : EntityEventArgs + { + public EntityUid User { get; } + public EntityUid Target { get; } + public GuardianCreatorComponent Component { get; } + + public GuardianCreatorInjectedEvent(EntityUid user, EntityUid target, GuardianCreatorComponent component) + { + User = user; + Target = target; + Component = component; + } + } + + private sealed class GuardianCreatorInjectCancelledEvent : EntityEventArgs + { + public EntityUid Target { get; } + public GuardianCreatorComponent Component { get; } + + public GuardianCreatorInjectCancelledEvent(EntityUid target, GuardianCreatorComponent component) + { + Target = target; + Component = component; + } + } + } +} diff --git a/Content.Server/Info/RulesManager.cs b/Content.Server/Info/RulesManager.cs new file mode 100644 index 0000000000..975cb1a108 --- /dev/null +++ b/Content.Server/Info/RulesManager.cs @@ -0,0 +1,15 @@ +using Content.Shared.Info; +using Robust.Shared.IoC; +using Robust.Shared.Network; + +namespace Content.Server.Info; + +public class RulesManager : SharedRulesManager +{ + [Dependency] private readonly INetManager _netManager = default!; + + public void Initialize() + { + _netManager.RegisterNetMessage(); + } +} diff --git a/Content.Server/Info/ShowRulesCommand.cs b/Content.Server/Info/ShowRulesCommand.cs new file mode 100644 index 0000000000..101f1dd99c --- /dev/null +++ b/Content.Server/Info/ShowRulesCommand.cs @@ -0,0 +1,67 @@ +using Content.Server.Administration; +using Content.Shared.Administration; +using Content.Shared.CCVar; +using Content.Shared.Info; +using Robust.Server.Player; +using Robust.Shared.Configuration; +using Robust.Shared.Console; +using Robust.Shared.IoC; +using Robust.Shared.Network; + +namespace Content.Server.Info; + +[AdminCommand(AdminFlags.Admin)] +public class ShowRulesCommand : IConsoleCommand +{ + public string Command => "showrules"; + public string Description => "Opens the rules popup for the specified player."; + public string Help => "showrules [time]"; + public async void Execute(IConsoleShell shell, string argStr, string[] args) + { + string target; + float seconds; + + switch (args.Length) + { + case 1: + { + target = args[0]; + var configurationManager = IoCManager.Resolve(); + seconds = configurationManager.GetCVar(CCVars.RulesWaitTime); + break; + } + case 2: + { + if (float.TryParse(args[1], out seconds)) + return; + + target = args[0]; + shell.WriteLine($"{args[1]} is not a valid amount of minutes.\n{Help}"); + break; + } + default: + { + shell.WriteLine(Help); + return; + } + } + + var locator = IoCManager.Resolve(); + var located = await locator.LookupIdByNameOrIdAsync(target); + if (located == null) + { + shell.WriteError("Unable to find a player with that name."); + return; + } + + var message = new SharedRulesManager.ShowRulesPopupMessage + { + PopupTime = seconds + }; + + var player = IoCManager.Resolve() + .GetSessionByUserId(located.UserId); + IoCManager.Resolve() + .ServerSendMessage(message, player.ConnectedClient); + } +} diff --git a/Content.Server/IoC/ServerContentIoC.cs b/Content.Server/IoC/ServerContentIoC.cs index 196873a7e5..bef312b4bb 100644 --- a/Content.Server/IoC/ServerContentIoC.cs +++ b/Content.Server/IoC/ServerContentIoC.cs @@ -11,6 +11,7 @@ using Content.Server.DeviceNetwork; using Content.Server.EUI; using Content.Server.Holiday; using Content.Server.Holiday.Interfaces; +using Content.Server.Info; using Content.Server.Maps; using Content.Server.Module; using Content.Server.MoMMI; @@ -57,6 +58,7 @@ namespace Content.Server.IoC IoCManager.Register(); IoCManager.Register(); IoCManager.Register(); + IoCManager.Register(); } } } diff --git a/Content.Server/Medical/CrewMonitoring/CrewMonitoringConsoleComponent.cs b/Content.Server/Medical/CrewMonitoring/CrewMonitoringConsoleComponent.cs new file mode 100644 index 0000000000..0b98d4e362 --- /dev/null +++ b/Content.Server/Medical/CrewMonitoring/CrewMonitoringConsoleComponent.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using Content.Shared.Medical.SuitSensor; +using Robust.Shared.Analyzers; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization.Manager.Attributes; + +namespace Content.Server.Medical.CrewMonitoring +{ + [RegisterComponent] + [Friend(typeof(CrewMonitoringConsoleSystem))] + public class CrewMonitoringConsoleComponent : Component + { + public override string Name => "CrewMonitoringConsole"; + + /// + /// List of all currently connected sensors to this console. + /// + public Dictionary ConnectedSensors = new(); + + /// + /// After what time sensor consider to be lost. + /// + [DataField("sensorTimeout")] + public float SensorTimeout = 10f; + } +} diff --git a/Content.Server/Medical/CrewMonitoring/CrewMonitoringConsoleSystem.cs b/Content.Server/Medical/CrewMonitoring/CrewMonitoringConsoleSystem.cs new file mode 100644 index 0000000000..607b1939ec --- /dev/null +++ b/Content.Server/Medical/CrewMonitoring/CrewMonitoringConsoleSystem.cs @@ -0,0 +1,89 @@ +using System.Linq; +using Content.Server.DeviceNetwork.Systems; +using Content.Server.Medical.SuitSensors; +using Content.Server.UserInterface; +using Content.Shared.Medical.CrewMonitoring; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Timing; + +namespace Content.Server.Medical.CrewMonitoring +{ + public class CrewMonitoringConsoleSystem : EntitySystem + { + [Dependency] private readonly SuitSensorSystem _sensors = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + + private const float UpdateRate = 3f; + private float _updateDif; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnRemove); + SubscribeLocalEvent(OnPacketReceived); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + // check update rate + _updateDif += frameTime; + if (_updateDif < UpdateRate) + return; + _updateDif = 0f; + + var consoles = EntityManager.EntityQuery(); + foreach (var console in consoles) + { + UpdateTimeouts(console.Owner, console); + UpdateUserInterface(console.Owner, console); + } + } + + private void OnRemove(EntityUid uid, CrewMonitoringConsoleComponent component, ComponentRemove args) + { + component.ConnectedSensors.Clear(); + } + + private void OnPacketReceived(EntityUid uid, CrewMonitoringConsoleComponent component, PacketSentEvent args) + { + var suitSensor = _sensors.PacketToSuitSensor(args.Data); + if (suitSensor == null) + return; + + suitSensor.Timestamp = _gameTiming.CurTime; + component.ConnectedSensors[args.SenderAddress] = suitSensor; + } + + private void UpdateUserInterface(EntityUid uid, CrewMonitoringConsoleComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + var ui = component.Owner.GetUIOrNull(CrewMonitoringUIKey.Key); + if (ui == null) + return; + + // update all sensors info + var allSensors = component.ConnectedSensors.Values.ToList(); + var uiState = new CrewMonitoringState(allSensors); + ui.SetState(uiState); + } + + private void UpdateTimeouts(EntityUid uid, CrewMonitoringConsoleComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + foreach (var (address, sensor) in component.ConnectedSensors) + { + // if too many time passed - sensor just dropped connection + var dif = _gameTiming.CurTime - sensor.Timestamp; + if (dif.Seconds > component.SensorTimeout) + component.ConnectedSensors.Remove(address); + } + } + } +} diff --git a/Content.Server/Medical/SuitSensors/SuitSensorComponent.cs b/Content.Server/Medical/SuitSensors/SuitSensorComponent.cs new file mode 100644 index 0000000000..f5273fa553 --- /dev/null +++ b/Content.Server/Medical/SuitSensors/SuitSensorComponent.cs @@ -0,0 +1,59 @@ +using System; +using Content.Shared.Inventory; +using Content.Shared.Medical.SuitSensor; +using Robust.Shared.Analyzers; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization.Manager.Attributes; + +namespace Content.Server.Medical.SuitSensors +{ + /// + /// Tracking device, embedded in almost all uniforms and jumpsuits. + /// If enabled, will report to crew monitoring console owners position and status. + /// + [RegisterComponent] + [Friend(typeof(SuitSensorSystem))] + [ComponentProtoName("SuitSensor")] + public sealed class SuitSensorComponent : Component + { + /// + /// Choose a random sensor mode when item is spawned. + /// + [DataField("randomMode")] + public bool RandomMode = true; + + /// + /// If true user can't change suit sensor mode + /// + [DataField("controlsLocked")] + public bool ControlsLocked = false; + + /// + /// Current sensor mode. Can be switched by user verbs. + /// + [DataField("mode")] + public SuitSensorMode Mode = SuitSensorMode.SensorOff; + + /// + /// Activate sensor if user wear it in this slot. + /// + [DataField("activationSlot")] + public EquipmentSlotDefines.Slots ActivationSlot = EquipmentSlotDefines.Slots.INNERCLOTHING; + + /// + /// How often does sensor update its owners status (in seconds). + /// + [DataField("updateRate")] + public float UpdateRate = 2f; + + /// + /// Current user that wears suit sensor. Null if nobody wearing it. + /// + public EntityUid? User = null; + + /// + /// Last time when sensor updated owners status + /// + public TimeSpan LastUpdate = TimeSpan.Zero; + } +} diff --git a/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs b/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs new file mode 100644 index 0000000000..e48fded7f4 --- /dev/null +++ b/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs @@ -0,0 +1,312 @@ +using System; +using Content.Server.Access.Systems; +using Content.Server.DeviceNetwork; +using Content.Server.DeviceNetwork.Components; +using Content.Server.DeviceNetwork.Systems; +using Content.Server.Popups; +using Content.Shared.ActionBlocker; +using Content.Shared.Damage; +using Content.Shared.Examine; +using Content.Shared.Inventory; +using Content.Shared.Medical.SuitSensor; +using Content.Shared.MobState.Components; +using Content.Shared.Verbs; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Map; +using Robust.Shared.Player; +using Robust.Shared.Random; +using Robust.Shared.Timing; + +namespace Content.Server.Medical.SuitSensors +{ + public class SuitSensorSystem : EntitySystem + { + [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; + [Dependency] private readonly PopupSystem _popupSystem = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly IdCardSystem _idCardSystem = default!; + [Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + + private const float UpdateRate = 0.5f; + private float _updateDif; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnEquipped); + SubscribeLocalEvent(OnUnequipped); + SubscribeLocalEvent(OnExamine); + SubscribeLocalEvent(OnVerb); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + // check update rate + _updateDif += frameTime; + if (_updateDif < UpdateRate) + return; + + _updateDif -= UpdateRate; + + var curTime = _gameTiming.CurTime; + var sensors = EntityManager.EntityQuery(); + foreach (var (sensor, device) in sensors) + { + // check if sensor is ready to update + if (curTime - sensor.LastUpdate < TimeSpan.FromSeconds(sensor.UpdateRate)) + continue; + sensor.LastUpdate = curTime; + + // get sensor status + var status = GetSensorState(sensor.Owner, sensor); + if (status == null) + continue; + + // broadcast it to device network + var payload = SuitSensorToPacket(status); + _deviceNetworkSystem.QueuePacket(sensor.Owner, DeviceNetworkConstants.NullAddress, device.Frequency, payload, true); + } + } + + private void OnMapInit(EntityUid uid, SuitSensorComponent component, MapInitEvent args) + { + // generate random mode + if (component.RandomMode) + { + //make the sensor mode favor higher levels, except coords. + var modesDist = new[] + { + SuitSensorMode.SensorOff, + SuitSensorMode.SensorBinary, SuitSensorMode.SensorBinary, + SuitSensorMode.SensorVitals, SuitSensorMode.SensorVitals, SuitSensorMode.SensorVitals, + SuitSensorMode.SensorCords, SuitSensorMode.SensorCords + }; + component.Mode = _random.Pick(modesDist); + } + } + + private void OnEquipped(EntityUid uid, SuitSensorComponent component, EquippedEvent args) + { + if (args.Slot != component.ActivationSlot) + return; + + component.User = args.User; + } + + private void OnUnequipped(EntityUid uid, SuitSensorComponent component, UnequippedEvent args) + { + if (args.Slot != component.ActivationSlot) + return; + + component.User = null; + } + + private void OnExamine(EntityUid uid, SuitSensorComponent component, ExaminedEvent args) + { + if (!args.IsInDetailsRange) + return; + + string msg; + switch (component.Mode) + { + case SuitSensorMode.SensorOff: + msg = "suit-sensor-examine-off"; + break; + case SuitSensorMode.SensorBinary: + msg = "suit-sensor-examine-binary"; + break; + case SuitSensorMode.SensorVitals: + msg = "suit-sensor-examine-vitals"; + break; + case SuitSensorMode.SensorCords: + msg = "suit-sensor-examine-cords"; + break; + default: + return; + } + + args.PushMarkup(Loc.GetString(msg)); + } + + private void OnVerb(EntityUid uid, SuitSensorComponent component, GetInteractionVerbsEvent args) + { + // check if user can change sensor + if (component.ControlsLocked) + return; + + // standard interaction checks + if (!args.CanAccess || !args.CanInteract || !_actionBlockerSystem.CanDrop(args.User)) + return; + + args.Verbs.UnionWith(new[] + { + CreateVerb(uid, component, args.User, SuitSensorMode.SensorOff), + CreateVerb(uid, component, args.User, SuitSensorMode.SensorBinary), + CreateVerb(uid, component, args.User, SuitSensorMode.SensorVitals), + CreateVerb(uid, component, args.User, SuitSensorMode.SensorCords) + }); + } + + private Verb CreateVerb(EntityUid uid, SuitSensorComponent component, EntityUid userUid, SuitSensorMode mode) + { + return new Verb() + { + Text = GetModeName(mode), + Disabled = component.Mode == mode, + Priority = -(int) mode, // sort them in descending order + Category = VerbCategory.SetSensor, + Act = () => SetSensor(uid, mode, userUid, component) + }; + } + + private string GetModeName(SuitSensorMode mode) + { + string name; + switch (mode) + { + case SuitSensorMode.SensorOff: + name = "suit-sensor-mode-off"; + break; + case SuitSensorMode.SensorBinary: + name = "suit-sensor-mode-binary"; + break; + case SuitSensorMode.SensorVitals: + name = "suit-sensor-mode-vitals"; + break; + case SuitSensorMode.SensorCords: + name = "suit-sensor-mode-cords"; + break; + default: + return ""; + } + + return Loc.GetString(name); + } + + public void SetSensor(EntityUid uid, SuitSensorMode mode, EntityUid? userUid = null, + SuitSensorComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + component.Mode = mode; + + if (userUid != null) + { + var msg = Loc.GetString("suit-sensor-mode-state", ("mode", GetModeName(mode))); + _popupSystem.PopupEntity(msg, uid, Filter.Entities(userUid.Value)); + } + } + + public SuitSensorStatus? GetSensorState(EntityUid uid, SuitSensorComponent? sensor = null, TransformComponent? transform = null) + { + if (!Resolve(uid, ref sensor, ref transform)) + return null; + + // check if sensor is enabled and worn by user + if (sensor.Mode == SuitSensorMode.SensorOff || sensor.User == null) + return null; + + // try to get mobs id from ID slot + var userName = Loc.GetString("suit-sensor-component-unknown-name"); + var userJob = Loc.GetString("suit-sensor-component-unknown-job"); + if (_idCardSystem.TryGetIdCardSlot(sensor.User.Value, out var card)) + { + if (card.FullName != null) + userName = card.FullName; + if (card.JobTitle != null) + userJob = card.JobTitle; + } + + // get health mob state + var isAlive = false; + if (EntityManager.TryGetComponent(sensor.User.Value, out MobStateComponent? mobState)) + { + isAlive = mobState.IsAlive(); + } + + // get mob total damage + var totalDamage = 0; + if (EntityManager.TryGetComponent(sensor.User.Value, out DamageableComponent? damageable)) + { + totalDamage = damageable.TotalDamage.Int(); + } + + // finally, form suit sensor status + var status = new SuitSensorStatus(userName, userJob); + switch (sensor.Mode) + { + case SuitSensorMode.SensorBinary: + status.IsAlive = isAlive; + break; + case SuitSensorMode.SensorVitals: + status.IsAlive = isAlive; + status.TotalDamage = totalDamage; + break; + case SuitSensorMode.SensorCords: + status.IsAlive = isAlive; + status.TotalDamage = totalDamage; + status.Coordinates = transform.MapPosition; + break; + } + + return status; + } + + /// + /// Serialize suit sensor status into device network package. + /// + public NetworkPayload SuitSensorToPacket(SuitSensorStatus status) + { + var payload = new NetworkPayload() + { + [DeviceNetworkConstants.Command] = DeviceNetworkConstants.CmdUpdatedState, + [SuitSensorConstants.NET_NAME] = status.Name, + [SuitSensorConstants.NET_JOB] = status.Job, + [SuitSensorConstants.NET_IS_ALIVE] = status.IsAlive, + }; + + if (status.TotalDamage != null) + payload.Add(SuitSensorConstants.NET_TOTAL_DAMAGE, status.TotalDamage); + if (status.Coordinates != null) + payload.Add(SuitSensorConstants.NET_CORDINATES, status.Coordinates); + + return payload; + } + + /// + /// Try to deserialize device network message into suit sensor status + /// + public SuitSensorStatus? PacketToSuitSensor(NetworkPayload payload) + { + // check command + if (!payload.TryGetValue(DeviceNetworkConstants.Command, out string? command)) + return null; + if (command != DeviceNetworkConstants.CmdUpdatedState) + return null; + + // check name, job and alive + if (!payload.TryGetValue(SuitSensorConstants.NET_NAME, out string? name)) return null; + if (!payload.TryGetValue(SuitSensorConstants.NET_JOB, out string? job)) return null; + if (!payload.TryGetValue(SuitSensorConstants.NET_IS_ALIVE, out bool? isAlive)) return null; + + // try get total damage and cords (optionals) + payload.TryGetValue(SuitSensorConstants.NET_TOTAL_DAMAGE, out int? totalDamage); + payload.TryGetValue(SuitSensorConstants.NET_CORDINATES, out MapCoordinates? cords); + + var status = new SuitSensorStatus(name, job) + { + IsAlive = isAlive.Value, + TotalDamage = totalDamage, + Coordinates = cords + }; + return status; + } + } +} diff --git a/Content.Server/Spawners/Components/RandomSpawnerComponent.cs b/Content.Server/Spawners/Components/RandomSpawnerComponent.cs index bae54820e9..46c7a775e3 100644 --- a/Content.Server/Spawners/Components/RandomSpawnerComponent.cs +++ b/Content.Server/Spawners/Components/RandomSpawnerComponent.cs @@ -64,7 +64,7 @@ namespace Content.Server.Spawners.Components public override void MapInit() { Spawn(); - _entMan.DeleteEntity(Owner); + _entMan.QueueDeleteEntity(Owner); } } } diff --git a/Content.Server/Storage/Components/EntityStorageComponent.cs b/Content.Server/Storage/Components/EntityStorageComponent.cs index 7ff590084a..bada7c58ca 100644 --- a/Content.Server/Storage/Components/EntityStorageComponent.cs +++ b/Content.Server/Storage/Components/EntityStorageComponent.cs @@ -193,12 +193,18 @@ namespace Content.Server.Storage.Components return false; } - return true; + var @event = new StorageOpenAttemptEvent(); + IoCManager.Resolve().EventBus.RaiseLocalEvent(Owner, @event); + + return !@event.Cancelled; } public virtual bool CanClose(EntityUid user, bool silent = false) { - return true; + var @event = new StorageCloseAttemptEvent(); + IoCManager.Resolve().EventBus.RaiseLocalEvent(Owner, @event); + + return !@event.Cancelled; } public void ToggleOpen(EntityUid user) @@ -479,4 +485,14 @@ namespace Content.Server.Storage.Components } } } + + public sealed class StorageOpenAttemptEvent : CancellableEntityEventArgs + { + + } + + public sealed class StorageCloseAttemptEvent : CancellableEntityEventArgs + { + + } } diff --git a/Content.Shared/Actions/ActionType.cs b/Content.Shared/Actions/ActionType.cs index 0cb60f42f0..4eb19eaf34 100644 --- a/Content.Shared/Actions/ActionType.cs +++ b/Content.Shared/Actions/ActionType.cs @@ -18,6 +18,7 @@ namespace Content.Shared.Actions DebugTargetEntity, DebugTargetEntityRepeat, SpellPie, + ManifestGuardian, PAIMidi } diff --git a/Content.Shared/Buckle/Components/SharedBuckleComponent.cs b/Content.Shared/Buckle/Components/SharedBuckleComponent.cs index 9491e24254..724ae4581f 100644 --- a/Content.Shared/Buckle/Components/SharedBuckleComponent.cs +++ b/Content.Shared/Buckle/Components/SharedBuckleComponent.cs @@ -29,8 +29,6 @@ namespace Content.Shared.Buckle.Components public EntityUid? LastEntityBuckledTo { get; set; } - public bool IsOnStrapEntityThisFrame { get; set; } - public bool DontCollide { get; set; } public abstract bool TryBuckle(EntityUid user, EntityUid to); diff --git a/Content.Shared/Buckle/Components/SharedStrapComponent.cs b/Content.Shared/Buckle/Components/SharedStrapComponent.cs index d396eacf32..38aeb1f341 100644 --- a/Content.Shared/Buckle/Components/SharedStrapComponent.cs +++ b/Content.Shared/Buckle/Components/SharedStrapComponent.cs @@ -57,11 +57,13 @@ namespace Content.Shared.Buckle.Components } [Serializable, NetSerializable] - public enum StrapVisuals + public enum StrapVisuals : byte { - RotationAngle + RotationAngle, + BuckledState } + // TODO : Convert this to an Entity Message. Careful, it will Break ShuttleControllerComponent (only place where it's used) [Serializable, NetSerializable] #pragma warning disable 618 public abstract class StrapChangeMessage : ComponentMessage diff --git a/Content.Shared/Buckle/SharedBuckleSystem.cs b/Content.Shared/Buckle/SharedBuckleSystem.cs index 5bc94119b0..7e76ee96b4 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.cs @@ -59,7 +59,6 @@ namespace Content.Shared.Buckle { if (args.BodyB.Owner != component.LastEntityBuckledTo) return; - component.IsOnStrapEntityThisFrame = true; if (component.Buckled || component.DontCollide) { args.Cancel(); diff --git a/Content.Shared/Hands/Components/SharedHandsComponent.cs b/Content.Shared/Hands/Components/SharedHandsComponent.cs index 67028d1353..398aec3203 100644 --- a/Content.Shared/Hands/Components/SharedHandsComponent.cs +++ b/Content.Shared/Hands/Components/SharedHandsComponent.cs @@ -615,11 +615,14 @@ namespace Content.Shared.Hands.Components protected bool CanInsertEntityIntoHand(Hand hand, EntityUid entity) { var handContainer = hand.Container; - if (handContainer == null) - return false; + if (handContainer == null) return false; - if (!handContainer.CanInsert(entity)) - return false; + if (!handContainer.CanInsert(entity)) return false; + + var @event = new AttemptItemPickupEvent(); + _entMan.EventBus.RaiseLocalEvent(entity, @event); + + if (@event.Cancelled) return false; return true; } diff --git a/Content.Shared/Info/SharedRulesManager.cs b/Content.Shared/Info/SharedRulesManager.cs new file mode 100644 index 0000000000..abd8037934 --- /dev/null +++ b/Content.Shared/Info/SharedRulesManager.cs @@ -0,0 +1,26 @@ +using JetBrains.Annotations; +using Lidgren.Network; +using Robust.Shared.Network; + +namespace Content.Shared.Info; + +public abstract class SharedRulesManager +{ + [UsedImplicitly] + public sealed class ShowRulesPopupMessage : NetMessage + { + public override MsgGroups MsgGroup => MsgGroups.Command; + + public float PopupTime { get; set; } + + public override void ReadFromBuffer(NetIncomingMessage buffer) + { + PopupTime = buffer.ReadFloat(); + } + + public override void WriteToBuffer(NetOutgoingMessage buffer) + { + buffer.Write(PopupTime); + } + } +} diff --git a/Content.Shared/Item/PickupAttemptEvent.cs b/Content.Shared/Item/PickupAttemptEvent.cs index 1d922a6d04..e52c0722a9 100644 --- a/Content.Shared/Item/PickupAttemptEvent.cs +++ b/Content.Shared/Item/PickupAttemptEvent.cs @@ -2,6 +2,9 @@ namespace Content.Shared.Item { + /// + /// Raised on a *mob* when it tries to pickup something + /// public class PickupAttemptEvent : CancellableEntityEventArgs { public PickupAttemptEvent(EntityUid uid) @@ -11,4 +14,14 @@ namespace Content.Shared.Item public EntityUid Uid { get; } } + + /// + /// Raised on the *item* when tried to be picked up + /// + /// + /// Doesn't just handle "items" but calling it "PickedUpAttempt" is too close to "Pickup" for the sleep deprived brain. + /// + public sealed class AttemptItemPickupEvent : CancellableEntityEventArgs + { + } } diff --git a/Content.Shared/Item/SharedItemComponent.cs b/Content.Shared/Item/SharedItemComponent.cs index bd86f8e983..5c83bb95c7 100644 --- a/Content.Shared/Item/SharedItemComponent.cs +++ b/Content.Shared/Item/SharedItemComponent.cs @@ -9,7 +9,6 @@ using Robust.Shared.GameStates; using Robust.Shared.IoC; using Robust.Shared.Maths; using Robust.Shared.Physics; -using Robust.Shared.Players; using Robust.Shared.Serialization; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.ViewVariables; diff --git a/Content.Shared/Medical/CrewMonitoring/CrewMonitoringShared.cs b/Content.Shared/Medical/CrewMonitoring/CrewMonitoringShared.cs new file mode 100644 index 0000000000..53f19f1295 --- /dev/null +++ b/Content.Shared/Medical/CrewMonitoring/CrewMonitoringShared.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using Content.Shared.FixedPoint; +using Content.Shared.Medical.SuitSensor; +using Robust.Shared.GameObjects; +using Robust.Shared.Map; +using Robust.Shared.Serialization; + +namespace Content.Shared.Medical.CrewMonitoring +{ + [Serializable, NetSerializable] + public enum CrewMonitoringUIKey + { + Key + } + + [Serializable, NetSerializable] + public class CrewMonitoringState : BoundUserInterfaceState + { + public List Sensors; + + public CrewMonitoringState(List sensors) + { + Sensors = sensors; + } + } + +} diff --git a/Content.Shared/Medical/SuitSensor/SharedSuitSensor.cs b/Content.Shared/Medical/SuitSensor/SharedSuitSensor.cs new file mode 100644 index 0000000000..e717c6dad5 --- /dev/null +++ b/Content.Shared/Medical/SuitSensor/SharedSuitSensor.cs @@ -0,0 +1,58 @@ +using System; +using Content.Shared.FixedPoint; +using Robust.Shared.Map; +using Robust.Shared.Maths; +using Robust.Shared.Serialization; + +namespace Content.Shared.Medical.SuitSensor +{ + [Serializable, NetSerializable] + public class SuitSensorStatus + { + public SuitSensorStatus(string name, string job) + { + Name = name; + Job = job; + } + + public TimeSpan Timestamp; + public string Name; + public string Job; + public bool IsAlive; + public int? TotalDamage; + public MapCoordinates? Coordinates; + } + + [Serializable, NetSerializable] + public enum SuitSensorMode : byte + { + /// + /// Sensor doesn't send any information about owner + /// + SensorOff = 0, + + /// + /// Sensor sends only binary status (alive/dead) + /// + SensorBinary = 1, + + /// + /// Sensor sends health vitals status + /// + SensorVitals = 2, + + /// + /// Sensor sends vitals status and GPS position + /// + SensorCords = 3 + } + + public static class SuitSensorConstants + { + public const string NET_NAME = "name"; + public const string NET_JOB = "job"; + public const string NET_IS_ALIVE = "alive"; + public const string NET_TOTAL_DAMAGE = "vitals"; + public const string NET_CORDINATES = "cords"; + } +} diff --git a/Content.Shared/MobState/Components/MobStateComponent.cs b/Content.Shared/MobState/Components/MobStateComponent.cs index 697849abe5..90f9dfeaed 100644 --- a/Content.Shared/MobState/Components/MobStateComponent.cs +++ b/Content.Shared/MobState/Components/MobStateComponent.cs @@ -5,6 +5,7 @@ using System.Linq; using Content.Shared.Alert; using Content.Shared.Damage; using Content.Shared.FixedPoint; +using Content.Shared.MobState.EntitySystems; using Content.Shared.MobState.State; using Robust.Shared.GameObjects; using Robust.Shared.GameStates; @@ -318,7 +319,6 @@ namespace Content.Shared.MobState.Components var message = new MobStateChangedEvent(this, old, state); entMan.EventBus.RaiseLocalEvent(Owner, message); - Dirty(); } } diff --git a/Content.Shared/MobState/EntitySystems/MobStateSystem.cs b/Content.Shared/MobState/EntitySystems/MobStateSystem.cs index 91dac34ca2..c4c2126f4d 100644 --- a/Content.Shared/MobState/EntitySystems/MobStateSystem.cs +++ b/Content.Shared/MobState/EntitySystems/MobStateSystem.cs @@ -111,7 +111,7 @@ namespace Content.Shared.MobState.EntitySystems private void OnStartPullAttempt(EntityUid uid, MobStateComponent component, StartPullAttemptEvent args) { - if(component.IsIncapacitated()) + if (component.IsIncapacitated()) args.Cancel(); } @@ -135,7 +135,7 @@ namespace Content.Shared.MobState.EntitySystems private void OnStandAttempt(EntityUid uid, MobStateComponent component, StandAttemptEvent args) { - if(component.IsIncapacitated()) + if (component.IsIncapacitated()) args.Cancel(); } } diff --git a/Content.Shared/Verbs/VerbCategory.cs b/Content.Shared/Verbs/VerbCategory.cs index 45ec725028..dbc30eced3 100644 --- a/Content.Shared/Verbs/VerbCategory.cs +++ b/Content.Shared/Verbs/VerbCategory.cs @@ -57,5 +57,7 @@ namespace Content.Shared.Verbs public static readonly VerbCategory Split = new("verb-categories-split", null); + + public static readonly VerbCategory SetSensor = new("verb-categories-set-sensor", null); } } diff --git a/Resources/Audio/Effects/guardian_inject.ogg b/Resources/Audio/Effects/guardian_inject.ogg new file mode 100644 index 0000000000..3dca7114a1 Binary files /dev/null and b/Resources/Audio/Effects/guardian_inject.ogg differ diff --git a/Resources/Audio/Effects/guardian_warn.ogg b/Resources/Audio/Effects/guardian_warn.ogg new file mode 100644 index 0000000000..617563b644 Binary files /dev/null and b/Resources/Audio/Effects/guardian_warn.ogg differ diff --git a/Resources/Audio/Effects/license.txt b/Resources/Audio/Effects/license.txt index d5727525a3..8cba3cecd0 100644 --- a/Resources/Audio/Effects/license.txt +++ b/Resources/Audio/Effects/license.txt @@ -10,3 +10,7 @@ adminhelp.ogg taken from https://github.com/tgstation/tgstation/blob/d775e1ac804 The sound had been reversed and the volume altered. voteding.ogg taken from "Bike, Bell Ding, Single, 01-01.wav" by InspectorJ (www.jshaw.co.uk) of Freesound.org at https://freesound.org/people/InspectorJ/sounds/484344/ under CC BY 3.0. The volume has been reduced. + +poster_broken.ogg taken from https://github.com/tgstation/tgstation/blob/2834383245d2129a106acef3afd17b81e1e64777/sound/items/poster_ripped.ogg + +poster_being_set.ogg taken from https://github.com/tgstation/tgstation/blob/2834383245d2129a106acef3afd17b81e1e64777/sound/items/poster_ripped.ogg diff --git a/Resources/Audio/Effects/poster_being_set.ogg b/Resources/Audio/Effects/poster_being_set.ogg new file mode 100644 index 0000000000..f651a53c3e Binary files /dev/null and b/Resources/Audio/Effects/poster_being_set.ogg differ diff --git a/Resources/Audio/Effects/poster_broken.ogg b/Resources/Audio/Effects/poster_broken.ogg new file mode 100644 index 0000000000..b406ed0c9a Binary files /dev/null and b/Resources/Audio/Effects/poster_broken.ogg differ diff --git a/Resources/Audio/Voice/Human/malescream_guardian.ogg b/Resources/Audio/Voice/Human/malescream_guardian.ogg new file mode 100644 index 0000000000..a854335da7 Binary files /dev/null and b/Resources/Audio/Voice/Human/malescream_guardian.ogg differ diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 54bca6d51d..6577f7030a 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,24 +1,4 @@ Entries: -- author: Seth - changes: - - {message: Added Makeshift Handcuffs into the construction list, type: Add} - id: 283 - time: '2021-07-25T15:30:42.0000000+00:00' -- author: metalgearsloth - changes: - - {message: Shuttle-relative movement for when we get shuttle rotation., type: Add} - id: 284 - time: '2021-07-25T15:48:22.0000000+00:00' -- author: Seth - changes: - - {message: Added Storage Room to Coats, type: Add} - id: 285 - time: '2021-07-26T05:36:27.0000000+00:00' -- author: Seth - changes: - - {message: Added a hardsuit into research directors locker, type: Add} - id: 286 - time: '2021-07-26T22:14:10.0000000+00:00' - author: Seth changes: - {message: Added bio suits into bio lockers, type: Add} @@ -2872,3 +2852,30 @@ Entries: - {message: Chaplain no longer spawns with an empty backpack., type: Fix} id: 784 time: '2021-12-29T02:48:58.0000000+00:00' +- author: CrudeWax + changes: + - {message: Syndiecorp Cybersun invites you to try out their magnum opus- holoparasites! + Look for the "Utility" section in your uplink. And ghosts - be on the lookout + for a role prompt!, type: Add} + id: 785 + time: '2021-12-29T03:58:49.0000000+00:00' +- author: Topy + changes: + - {message: Add rollerbeds to roll people around!, type: Add} + id: 786 + time: '2021-12-29T04:57:21.0000000+00:00' +- author: Macoron + changes: + - {message: 'Added suit sensors and crew monitoring console in code. They are not + mapped, but you can print circuit board.', type: Add} + - {message: Prisoners suit has locked suit sensor that always broadcasting their + position., type: Add} + id: 787 + time: '2021-12-29T05:19:01.0000000+00:00' +- author: Rane + changes: + - {message: Pill canisters are now available in the protolathe after researching + chemistry technology., type: Add} + - {message: Pill canisters now fit inside medical belts., type: Tweak} + id: 788 + time: '2021-12-29T06:21:17.0000000+00:00' diff --git a/Resources/Locale/en-US/foldable/components/foldable-component.ftl b/Resources/Locale/en-US/foldable/components/foldable-component.ftl new file mode 100644 index 0000000000..d3e4ecefb5 --- /dev/null +++ b/Resources/Locale/en-US/foldable/components/foldable-component.ftl @@ -0,0 +1,5 @@ +# Foldable + +foldable-deploy-fail = You can't deploy the {$object} here. +fold-verb = Fold +unfold-verb = Unfold diff --git a/Resources/Locale/en-US/guardian/guardian.ftl b/Resources/Locale/en-US/guardian/guardian.ftl new file mode 100644 index 0000000000..7aca501bd2 --- /dev/null +++ b/Resources/Locale/en-US/guardian/guardian.ftl @@ -0,0 +1,22 @@ + +## Guardian host specific + +guardian-created = You feel... Haunted. +guardian-missing-invalid-action = There is no guardian under your control! +guardian-already-present-invalid-creation = You are NOT re-living that haunting experience! +guardian-no-actions-invalid-creation = You don't have the ability to host a guardian! +guardian-activator-empty-invalid-creation = The injector is spent. +guardian-activator-empty-examine = [color=#ba1919]The injector is spent.[/color] +guardian-no-soul = Your guardian has no soul. +guardian-available = Your guardian now has a soul. + +## Guardian entity specific + +guardian-entity-recall = The guardian vanishes into thin air! +guardian-entity-taking-damage = Your guardian is taking damage! + +## Health warnings +guardian-host-critical-warn = YOUR HOST IS WOUNDED! +guardian-host-death-warn = YOUR FORM SUCCUMBS TO NONEXISTENCE! +guardian-death-warn = YOUR BODY IS PIERCED BY SUBATOMIC PAIN AS IT DISINTEGRATES! + diff --git a/Resources/Locale/en-US/medical/components/crew-monitoring-component.ftl b/Resources/Locale/en-US/medical/components/crew-monitoring-component.ftl new file mode 100644 index 0000000000..d2f4a95369 --- /dev/null +++ b/Resources/Locale/en-US/medical/components/crew-monitoring-component.ftl @@ -0,0 +1,13 @@ +## UI + +crew-monitoring-user-interface-title = Crew Monitoring + +crew-monitoring-user-interface-name = Name +crew-monitoring-user-interface-status = Status +crew-monitoring-user-interface-location = Location + +crew-monitoring-user-interface-alive = Alive +crew-monitoring-user-interface-dead = Dead +crew-monitoring-user-interface-no-info = N/A + + diff --git a/Resources/Locale/en-US/medical/components/suit-sensor-component.ftl b/Resources/Locale/en-US/medical/components/suit-sensor-component.ftl new file mode 100644 index 0000000000..993e726055 --- /dev/null +++ b/Resources/Locale/en-US/medical/components/suit-sensor-component.ftl @@ -0,0 +1,21 @@ +## Modes + +suit-sensor-mode-off = Off +suit-sensor-mode-binary = Binary +suit-sensor-mode-vitals = Vitals +suit-sensor-mode-cords = Coordinates + +## Popups +suit-sensor-mode-state = Suit sensors: {$mode} + +## Components + +suit-sensor-component-unknown-name = Unknown +suit-sensor-component-unknown-job = No job + +## Examine + +suit-sensor-examine-off = Its sensors appear to be [color=darkred]disabled[/color]. +suit-sensor-examine-binary = Its binary life sensors appear to be enabled. +suit-sensor-examine-vitals = Its vital tracker appears to be enabled. +suit-sensor-examine-cords = Its vital tracker and tracking beacon appear to be enabled. diff --git a/Resources/Locale/en-US/verbs/verb-system.ftl b/Resources/Locale/en-US/verbs/verb-system.ftl index 9508eac7b9..ec9ff7763d 100644 --- a/Resources/Locale/en-US/verbs/verb-system.ftl +++ b/Resources/Locale/en-US/verbs/verb-system.ftl @@ -18,6 +18,7 @@ verb-categories-unbuckle = Unbuckle verb-categories-rotate = Rotate verb-categories-transfer = Set Transfer Amount verb-categories-split = Split +verb-categories-set-sensor = Sensor verb-common-toggle-light = Toggle light verb-common-close = Close diff --git a/Resources/Prototypes/Actions/guardian_actions.yml b/Resources/Prototypes/Actions/guardian_actions.yml new file mode 100644 index 0000000000..1725cf62b8 --- /dev/null +++ b/Resources/Prototypes/Actions/guardian_actions.yml @@ -0,0 +1,12 @@ +#This is the action the host gets to control the guardian +- type: action + actionType: ManifestGuardian + icon: Interface/Actions/manifest.png + name: "Toggle guardian manifestation" + description: "Either manifests the guardian or recalls it back into your body" + filters: + - guardian + behaviorType: Instant + behavior: !type:ToggleGuardianAction + cooldown: 2 + diff --git a/Resources/Prototypes/Catalog/Fills/Paper/manuals.yml b/Resources/Prototypes/Catalog/Fills/Paper/manuals.yml index d0ed9631a2..4978d16bb0 100644 --- a/Resources/Prototypes/Catalog/Fills/Paper/manuals.yml +++ b/Resources/Prototypes/Catalog/Fills/Paper/manuals.yml @@ -16,3 +16,32 @@ Higher will burn the engine out and eventually make it explode. Don't. Don't forget to refuel it, it tends to stop at the worst possible time. +- type: entity + parent: BaseItem + id: HoloparasiteInfo + name: "Holoparasite terms and conditions" + description: A tiny volumetric display for documents, makes one wonder if Cybersun's legal budget is way too high. + components: + - type: Sprite + netsync: false + sprite: Objects/Misc/guardian_info.rsi + state: guardian_info + - type: UserInterface + interfaces: + - key: enum.PaperUiKey.Key + type: PaperBoundUserInterface + - type: Paper + content: | + Thanks for choosing our holoparasite package! + At cybersun, we pride ourselves on cutting-edge military and industrial technology, and greatly appreciate your contribution to our establishment! + Guardians are helpful and intelligent beings which nest within your body, completely immune to common hazards such as pressure, temperature and even bullets! + You have purchased the holoparasite package, which contains a holoparasite activator, an instruction booklet, and our softcap merchandise. + Instructions for use: + 1. Activate the holoparasite injector (preferably in a secluded area). + 2. Wait for the tingling and/or painful metaphysical sensation. + 3. Check your holoparasite for the ability to communicate and cooperate, and capacity to understand your orders. + 4. Use your recall-manifest ability to summon or recall the holoparasite back into your body. + 5. Keep the holoparasite within a short distance from yourself, otherwise it will be recalled by force! + WARNING: Guardians are metaphysical beings, but draw from your HEALTH in order to exist. Direct damage done to guardians will be partially transferred to you! + Cybersun inc. is not responsible for complete annihilation following the misuse of Holoparasite technology. + diff --git a/Resources/Prototypes/Catalog/Research/technologies.yml b/Resources/Prototypes/Catalog/Research/technologies.yml index 85e590e36c..f7999fe89e 100644 --- a/Resources/Prototypes/Catalog/Research/technologies.yml +++ b/Resources/Prototypes/Catalog/Research/technologies.yml @@ -96,6 +96,7 @@ - CryostasisBeaker - Dropper - Syringe + - PillCanister - type: technology name: "medical machinery" @@ -113,6 +114,7 @@ - MedicalScannerMachineCircuitboard - ChemMasterMachineCircuitboard - ChemDispenserMachineCircuitboard + - CrewMonitoringComputerCircuitboard # Security Technology Tree diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml index 776635b834..56c4b6281e 100644 --- a/Resources/Prototypes/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/Catalog/uplink_catalog.yml @@ -107,6 +107,18 @@ price: 2 icon: /Textures/Objects/Weapons/Guns/Ammunition/SpeedLoaders/Magnum/magnum_sl.rsi/icon.png +#Utility + +- type: uplinkListing + id: UplinkHoloparaKit + category: Utility + itemId: BoxHoloparasite + listingName: Holoparasite Kit + description: The pride and joy of Cybersun. Contains an injector that hosts a sentient metaphysical guardian made of hard light which resides in the user's body when not active. The guardian can punch rapidly and is immune to hazardous environments and bullets, but shares any damage it takes with the user. + icon: /Textures/Objects/Misc/guardian_info.rsi/icon.png + price: 16 + + # Bundles - type: uplinkListing @@ -209,6 +221,8 @@ id: UplinkDecoyDisk category: Misc itemId: NukeDiskFake + listingName: Decoy nuclear disk + description: A piece of plastic with a lenticular printing, made to look like a nuclear auth disk. price: 1 - type: uplinkListing @@ -235,16 +249,14 @@ itemId: lanternextrabright price: 2 -# Pointless - - type: uplinkListing id: UplinkCostumeCentcom - category: Pointless + category: Misc itemId: ClothingBackpackDuffelSyndicateCostumeCentcom price: 4 - type: uplinkListing id: UplinkCostumeClown - category: Pointless + category: Misc itemId: ClothingBackpackDuffelSyndicateCostumeClown price: 4 diff --git a/Resources/Prototypes/Entities/Clothing/Belt/belts.yml b/Resources/Prototypes/Entities/Clothing/Belt/belts.yml index 97b029e727..c8ac59b0a6 100644 --- a/Resources/Prototypes/Entities/Clothing/Belt/belts.yml +++ b/Resources/Prototypes/Entities/Clothing/Belt/belts.yml @@ -237,6 +237,7 @@ - Ointment - CigPack - Pill + - PillCanister components: - Hypospray - SurgeryTool @@ -255,6 +256,7 @@ whitelist: tags: - Pill + - PillCanister bottle_spray: whitelist: tags: diff --git a/Resources/Prototypes/Entities/Clothing/Head/soft.yml b/Resources/Prototypes/Entities/Clothing/Head/soft.yml index a3d22355dc..7eff28e36c 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/soft.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/soft.yml @@ -239,3 +239,25 @@ sprite: Clothing/Head/Soft/yellowsoft_flipped.rsi - type: Clothing sprite: Clothing/Head/Soft/yellowsoft_flipped.rsi + +- type: entity + parent: ClothingHeadBase + id: ClothingHeadHatBizarreSoft + name: troublemaker's soft + description: A truly.. bizarre accessory. + components: + - type: Sprite + sprite: Clothing/Head/Soft/bizarresoft.rsi + - type: Clothing + sprite: Clothing/Head/Soft/bizarresoft.rsi + +- type: entity + parent: ClothingHeadBase + id: ClothingHeadHatBizarreSoftFlipped + name: troublemaker's soft flipped + description: A truly.. bizarre accessory, flipped. + components: + - type: Sprite + sprite: Clothing/Head/Soft/bizarresoft_flipped.rsi + - type: Clothing + sprite: Clothing/Head/Soft/bizarresoft_flipped.rsi diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/base_clothinguniforms.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/base_clothinguniforms.yml index 76f196fb3f..54482b7164 100644 --- a/Resources/Prototypes/Entities/Clothing/Uniforms/base_clothinguniforms.yml +++ b/Resources/Prototypes/Entities/Clothing/Uniforms/base_clothinguniforms.yml @@ -1,6 +1,17 @@ - type: entity abstract: true parent: Clothing + id: ClothingWithSuitSensor + components: + - type: SuitSensor + - type: DeviceNetworkComponent + deviceNetId: Wireless + - type: WirelessNetworkConnection + range: 500 + +- type: entity + abstract: true + parent: ClothingWithSuitSensor id: ClothingUniformBase components: - type: Sprite @@ -17,7 +28,7 @@ - type: entity abstract: true - parent: Clothing + parent: ClothingWithSuitSensor id: ClothingUniformSkirtBase components: - type: Sprite diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpskirts.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpskirts.yml index f692843020..de5dc36778 100644 --- a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpskirts.yml +++ b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpskirts.yml @@ -232,6 +232,10 @@ sprite: Clothing/Uniforms/Jumpskirt/prisoner.rsi - type: Clothing sprite: Clothing/Uniforms/Jumpskirt/prisoner.rsi + - type: SuitSensor + controlsLocked: true + randomMode: false + mode: SensorCords - type: entity parent: ClothingUniformSkirtBase diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml index 47942eb51e..b23f241a8e 100644 --- a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml +++ b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml @@ -310,6 +310,10 @@ sprite: Clothing/Uniforms/Jumpsuit/prisoner.rsi - type: Clothing sprite: Clothing/Uniforms/Jumpsuit/prisoner.rsi + - type: SuitSensor + controlsLocked: true + randomMode: false + mode: SensorCords - type: entity parent: ClothingUniformBase diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/posters.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/posters.yml new file mode 100644 index 0000000000..b467f5f312 --- /dev/null +++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/posters.yml @@ -0,0 +1,131 @@ +- type: entity + parent: MarkerBase + id: RandomPosterAny + name: random poster spawner + components: + - type: Sprite + layers: + - state: red + - texture: Structures/Wallmounts/posters.rsi/random_anything.png + - type: RandomSpawner + offset: 0 + prototypes: + - RandomPosterContraband + - RandomPosterLegit + chance: 0.95 + rarePrototypes: + - PosterBroken + rareChance: 0.05 + +- type: entity + parent: MarkerBase + id: RandomPosterContraband + name: random contraband poster spawner + components: + - type: Sprite + layers: + - state: red + - texture: Structures/Wallmounts/posters.rsi/random_contraband.png + - type: RandomSpawner + offset: 0 + prototypes: + - PosterContrabandFreeTonto + - PosterContrabandAtmosiaDeclarationIndependence + - PosterContrabandFunPolice + - PosterContrabandLustyXenomorph + - PosterContrabandSyndicateRecruitment + - PosterContrabandClown + - PosterContrabandSmoke + - PosterContrabandGreyTide + - PosterContrabandMissingGloves + - PosterContrabandHackingGuide + - PosterContrabandRIPBadger + - PosterContrabandAmbrosiaVulgaris + - PosterContrabandDonutCorp. + - PosterContrabandEAT. + - PosterContrabandTools + - PosterContrabandPower + - PosterContrabandSpaceCube + - PosterContrabandCommunistState + - PosterContrabandLamarr + - PosterContrabandBorgFancy + - PosterContrabandBorgFancyv2 + - PosterContrabandKosmicheskayaStantsiya + - PosterContrabandRebelsUnite + - PosterContrabandC20r + - PosterContrabandHaveaPuff + - PosterContrabandRevolver + - PosterContrabandDDayPromo + - PosterContrabandSyndicatePistol + - PosterContrabandEnergySwords + - PosterContrabandRedRum + - PosterContrabandCC64KAd + - PosterContrabandPunchShit + - PosterContrabandTheGriffin + - PosterContrabandFreeDrone + - PosterContrabandBustyBackdoorXenoBabes6 + - PosterContrabandRobustSoftdrinks + - PosterContrabandShamblersJuice + - PosterContrabandPwrGame + - PosterContrabandSunkist + - PosterContrabandSpaceCola + - PosterContrabandSpaceUp + - PosterContrabandKudzu + - PosterContrabandMaskedMen + - PosterContrabandUnreadableAnnouncement + - PosterContrabandFreeSyndicateEncryptionKey + - PosterContrabandBountyHunters + - PosterContrabandTheBigGasTruth + - PosterContrabandGotWood + chance: 1 + +- type: entity + parent: MarkerBase + id: RandomPosterLegit + name: random legit poster spawner + components: + - type: Sprite + layers: + - state: red + - texture: Structures/Wallmounts/posters.rsi/random_legit.png + - type: RandomSpawner + offset: 0 + prototypes: + - PosterLegitHereForYourSafety + - PosterLegitNanotrasenLogo + - PosterLegitCleanliness + - PosterLegitHelpOthers + - PosterLegitBuild + - PosterLegitBlessThisSpess + - PosterLegitScience + - PosterLegitIan + - PosterLegitObey + - PosterLegitWalk + - PosterLegitStateLaws + - PosterLegitLoveIan + - PosterLegitSpaceCops + - PosterLegitUeNo + - PosterLegitGetYourLEGS + - PosterLegitDoNotQuestion + - PosterLegitWorkForAFuture + - PosterLegitSoftCapPopArt + - PosterLegitSafetyInternals + - PosterLegitSafetyEyeProtection + - PosterLegitSafetyReport + - PosterLegitReportCrimes + - PosterLegitIonRifle + - PosterLegitFoamForceAd + - PosterLegitCohibaRobustoAd + - PosterLegit50thAnniversaryVintageReprint + - PosterLegitFruitBowl + - PosterLegitPDAAd + - PosterLegitEnlist + - PosterLegitNanomichiAd + - PosterLegit12Gauge + - PosterLegitHighClassMartini + - PosterLegitTheOwl + - PosterLegitNoERP + - PosterLegitCarbonDioxide + - PosterLegitDickGumshue + - PosterLegitThereIsNoGasGiant + chance: 1 diff --git a/Resources/Prototypes/Entities/Markers/marker_base.yml b/Resources/Prototypes/Entities/Markers/marker_base.yml index 5455251603..7613913edb 100644 --- a/Resources/Prototypes/Entities/Markers/marker_base.yml +++ b/Resources/Prototypes/Entities/Markers/marker_base.yml @@ -1,6 +1,8 @@ - type: entity id: MarkerBase abstract: true + placement: + mode: SnapgridCenter components: - type: Transform anchored: true @@ -12,5 +14,3 @@ # If serialization was cool this would work. # layers: # - state: blue - placement: - mode: SnapgridCenter diff --git a/Resources/Prototypes/Entities/Mobs/Player/guardian.yml b/Resources/Prototypes/Entities/Mobs/Player/guardian.yml new file mode 100644 index 0000000000..0261ad243b --- /dev/null +++ b/Resources/Prototypes/Entities/Mobs/Player/guardian.yml @@ -0,0 +1,73 @@ +# Does not inherit from simplemob +- type: entity + name: Holoparasite + id: MobHoloparasite + description: A mesmerising whirl of hard-light patterns weaves a marvelous, yet oddly familiar visage. It stands proud, tuning into its owner's life to sustain itself. + components: + - type: GhostTakeoverAvailable + makeSentient: true + name: Holoparasite + description: Listen to your owner. Don't tank damage. Punch people hard. + - type: Input + context: "human" + - type: PlayerMobMover + - type: PlayerInputMover + - type: MovementSpeedModifier + baseWalkSpeed : 7 + baseSprintSpeed : 7 + - type: DamageOnHighSpeedImpact + damage: + types: + Blunt: 5 + soundHit: + path: /Audio/Effects/hit_kick.ogg + # TODO: Randomise sprites and randomise the layer color + - type: Sprite + drawdepth: Mobs + sprite: Mobs/Aliens/Guardians/guardians.rsi + layers: + - state: tech_base + - state: tech_flare + color: "#40a7d7" + shader: unshaded + noRot: true + - type: Clickable + - type: InteractionOutline + - type: Physics + bodyType: KinematicController + - type: Fixtures + fixtures: + - shape: + !type:PhysShapeCircle + radius: 0.35 + mass: 10 + mask: + - Impassable + - SmallImpassable + - MobImpassable + layer: + - Opaque + - type: Damageable + damageContainer: Biological + - type: MobState + thresholds: + 0: !type:NormalMobState {} + - type: HeatResistance + - type: CombatMode + - type: Internals + - type: Examiner + - type: Speech + - type: Pullable + - type: UnarmedCombat + range: 2 + arcwidth: 30 + arc: fist + cooldownTime: 0.7 + arcCooldownTime: 0.7 + damage: + types: + Blunt: 40 + - type: Actions + innateActions: + - CombatMode + - type: Guardian diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml index 2ffa85da9e..21cc3bd53a 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml @@ -35,6 +35,14 @@ - type: ComputerBoard prototype: ComputerResearchAndDevelopment +- type: entity + parent: BaseComputerCircuitboard + id: CrewMonitoringComputerCircuitboard + name: crew monitoring console board + components: + - type: ComputerBoard + prototype: ComputerCrewMonitoring + - type: entity parent: BaseComputerCircuitboard id: IDComputerCircuitboard diff --git a/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/guardian_activators.yml b/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/guardian_activators.yml new file mode 100644 index 0000000000..37ff027f9a --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/guardian_activators.yml @@ -0,0 +1,26 @@ +- type: entity + name: holoparasite injector + id: HoloparasiteInjector + parent: BaseItem + description: A complex artwork of handheld machinery allowing the user to host a holoparasite guardian. + components: + - type: Sprite + sprite: Objects/Specific/Medical/hypospray.rsi + state: combat_hypo + netsync: false + - type: GuardianCreator + guardianProto: MobHoloparasite + +- type: entity + name: holoparasite box + parent: BoxBase + id: BoxHoloparasite + description: A box containing a holoparasite injector + components: + - type: StorageFill + contents: + - id: HoloparasiteInjector + - id: HoloparasiteInfo + - type: Sprite + layers: + - state: box diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/morgue.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/morgue.yml index f9d3b4f2b3..201928f6d2 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/morgue.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/morgue.yml @@ -9,6 +9,7 @@ sprite: Objects/Specific/Medical/Morgue/bodybags.rsi layers: - state: bag + map: ["enum.FoldableVisualLayers.Base"] - state: open_overlay map: ["enum.StorageVisualLayers.Door"] - state: label_overlay @@ -27,13 +28,18 @@ !type:PhysShapeAabb bounds: "-0.5,-0.45,0.5,0.1" mass: 5 + mask: + - Impassable + - SmallImpassable - type: BodyBagEntityStorage CanWeldShut: false Capacity: 1 + IsCollidableWhenOpen: true closeSound: path: /Audio/Misc/zip.ogg openSound: path: /Audio/Misc/zip.ogg + - type: Foldable - type: PaperLabel labelSlot: insertVerbText: Attach Label @@ -45,20 +51,20 @@ visuals: - type: StorageVisualizer state_open: open_overlay - state_closed: bag + - type: FoldableVisualizer + key: bag - type: BodyBagVisualizer - type: Pullable - type: entity - id: BodyBag_Item + id: BodyBag_Folded name: body bag description: A plastic bag designed for the storage and transportation of cadavers. - parent: BaseItem + parent: BodyBag_Container + suffix: Folded components: - - type: Sprite - netsync: false - sprite: Objects/Specific/Medical/Morgue/bodybags.rsi - state: item + - type: Foldable + folded: true # - type: BodyBagItem #TODO: we need some kind of generic placable, like thus: # - type: Placeable # prototype: someId diff --git a/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml b/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml index b97db0c1ea..6c51a9f8db 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml @@ -257,6 +257,9 @@ state: pill_canister - type: Item sprite: Objects/Specific/Chemistry/pills_canister.rsi + - type: Tag + tags: + - PillCanister - type: Storage capacity: 12 quickInsert: true diff --git a/Resources/Prototypes/Entities/Structures/Furniture/chairs.yml b/Resources/Prototypes/Entities/Structures/Furniture/chairs.yml index 1ea3b3c08e..10081edb36 100644 --- a/Resources/Prototypes/Entities/Structures/Furniture/chairs.yml +++ b/Resources/Prototypes/Entities/Structures/Furniture/chairs.yml @@ -24,6 +24,7 @@ noRot: true - type: Strap position: Stand + buckleOffset: "0,0.15" - type: Pullable - type: Damageable damageContainer: Inorganic diff --git a/Resources/Prototypes/Entities/Structures/Furniture/rollerbeds.yml b/Resources/Prototypes/Entities/Structures/Furniture/rollerbeds.yml new file mode 100644 index 0000000000..524c812043 --- /dev/null +++ b/Resources/Prototypes/Entities/Structures/Furniture/rollerbeds.yml @@ -0,0 +1,94 @@ +- type: entity + id: RollerBed + parent: BaseItem + name: rollerbed + description: Used to carry patients around without damaging them. + components: + - type: Transform + noRot: true + - type: Item + size: 5 + - type: Sprite + sprite: Structures/Furniture/rollerbeds.rsi + netsync: false + noRot: true + layers: + - state: rollerbed + map: ["enum.FoldableVisualLayers.Base"] + - type: MovedByPressure + - type: DamageOnHighSpeedImpact + soundHit: /Audio/Effects/bang.ogg + - type: InteractionOutline + - type: Physics + - type: Fixtures + fixtures: + - shape: + !type:PhysShapeCircle + radius: 0.35 + mass: 30 + mask: + - Impassable + - SmallImpassable + layer: + - Opaque + - type: Damageable + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 50 + behaviors: + - !type:DoActsBehavior + acts: ["Destruction"] + - !type:SpawnEntitiesBehavior + spawn: + SheetSteel1: + min: 1 + max: 1 + - type: Pullable + - type: Strap + position: Down + rotation: -90 + buckleOffset: "0,0.15" + unbuckleOffset: "0,0.15" + - type: Foldable + - type: Appearance + visuals: + - type: FoldableVisualizer + key: rollerbed + - type: RollerbedVisualizer + key: rollerbed + +- type: entity + id: CheapRollerBed + name: rollerbed + parent: RollerBed + description: A run-down rollerbed. Used to carry patients around. + components: + - type: Sprite + layers: + - state: cheap_rollerbed + map: [ "enum.FoldableVisualLayers.Base" ] + - type: Appearance + visuals: + - type: FoldableVisualizer + key: cheap_rollerbed + - type: RollerbedVisualizer + key: cheap_rollerbed + +- type: entity + id: EmergencyRollerBed + name: rollerbed + parent: RollerBed + description: A robust looking rollerbed used for emergencies. + components: + - type: Sprite + layers: + - state: emergency_rollerbed + map: [ "enum.FoldableVisualLayers.Base" ] + - type: Appearance + visuals: + - type: FoldableVisualizer + key: emergency_rollerbed + - type: RollerbedVisualizer + key: emergency_rollerbed diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml index 0be2035ed5..cba782735e 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml @@ -88,6 +88,36 @@ energy: 1.6 color: "#1f8c28" +- type: entity + parent: ComputerBase + id: ComputerCrewMonitoring + name: crew monitoring console + description: Used to monitor active health sensors built into most of the crew's uniforms. + components: + - type: Appearance + visuals: + - type: ComputerVisualizer + key: med_key + screen: crew + - type: PointLight + radius: 1.5 + energy: 1.6 + color: "#006400" + - type: Computer + board: CrewMonitoringComputerCircuitboard + - type: ActivatableUI + key: enum.CrewMonitoringUIKey.Key + - type: ActivatableUIRequiresPower + - type: UserInterface + interfaces: + - key: enum.CrewMonitoringUIKey.Key + type: CrewMonitoringBoundUserInterface + - type: CrewMonitoringConsole + - type: DeviceNetworkComponent + deviceNetId: Wireless + - type: WirelessNetworkConnection + range: 500 + - type: entity parent: ComputerBase id: ComputerResearchAndDevelopment diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index 03a5cb59fb..df0e9e169f 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -160,6 +160,7 @@ - CryostasisBeaker - Dropper - Syringe + - PillCanister - Flash - Handcuffs - Stunbaton @@ -183,6 +184,7 @@ - SolarControlComputerCircuitboard - AutolatheMachineCircuitboard - ProtolatheMachineCircuitboard + - CrewMonitoringComputerCircuitboard - Bucket - MopItem - SprayBottle diff --git a/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/lockers.yml b/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/lockers.yml index d8073e3104..e2b05bd992 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/lockers.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/lockers.yml @@ -8,6 +8,9 @@ visuals: - type: StorageVisualizer state: cabinet + state_open: cabinet_open + state_closed: cabinet_door + - type: AccessReader access: [["Bar"]] - type: EntityStorage @@ -26,6 +29,8 @@ visuals: - type: StorageVisualizer state: qm + state_open: qm_open + state_closed: qm_door - type: AccessReader access: [["Cargo"]] # TODO access [["Quartermaster"]] @@ -39,6 +44,8 @@ visuals: - type: StorageVisualizer state: cap + state_open: cap_open + state_closed: cap_door - type: AccessReader access: [["Captain"]] @@ -51,6 +58,8 @@ visuals: - type: StorageVisualizer state: hop + state_open: hop_open + state_closed: hop_door - type: AccessReader access: [["HeadOfPersonnel"]] @@ -64,6 +73,8 @@ visuals: - type: StorageVisualizer state: ce + state_open: ce_open + state_closed: ce_door - type: AccessReader access: [ [ "Engineering", "Command" ] ] @@ -77,6 +88,7 @@ visuals: - type: StorageVisualizer state: eng + state_open: eng_open state_closed: eng_elec_door - type: AccessReader access: [ [ "Engineering" ] ] @@ -91,6 +103,7 @@ visuals: - type: StorageVisualizer state: eng + state_open: eng_open state_closed: eng_weld_door - type: AccessReader access: [ [ "Engineering" ] ] @@ -105,6 +118,8 @@ visuals: - type: StorageVisualizer state: atmos + state_open: atmos_open + state_closed: atmos_door - type: AccessReader access: [ [ "Engineering" ] ] @@ -118,6 +133,8 @@ visuals: - type: StorageVisualizer state: eng_secure + state_open: eng_secure_open + state_closed: eng_secure_door - type: AccessReader access: [ [ "Engineering" ] ] @@ -131,6 +148,8 @@ visuals: - type: StorageVisualizer state: freezer + state_open: freezer_open + state_closed: freezer_door - type: AccessReader access: [ [ "Service" ] ] @@ -144,6 +163,8 @@ visuals: - type: StorageVisualizer state: hydro + state_open: hydro_open + state_closed: hydro_door - type: AccessReader access: [ [ "Service" ] ] @@ -158,6 +179,8 @@ visuals: - type: StorageVisualizer state: med + state_open: med_open + state_closed: med_door - type: AccessReader access: [ [ "Medical" ] ] @@ -171,6 +194,8 @@ visuals: - type: StorageVisualizer state: med_secure + state_open: med_secure_open + state_closed: med_secure_door - type: AccessReader access: [ [ "Medical" ] ] @@ -184,6 +209,7 @@ visuals: - type: StorageVisualizer state: med + state_open: med_open state_closed: chemical_door - type: AccessReader access: [ [ "Chemistry" ] ] @@ -198,6 +224,8 @@ visuals: - type: StorageVisualizer state: cmo + state_open: cmo_open + state_closed: cmo_door - type: AccessReader access: [ [ "Medical", "Command" ] ] @@ -211,6 +239,8 @@ visuals: - type: StorageVisualizer state: rd + state_open: rd_open + state_closed: rd_door - type: AccessReader access: [ [ "Research", "Command" ] ] @@ -223,6 +253,8 @@ visuals: - type: StorageVisualizer state: science + state_open: science_open + state_closed: science_door - type: AccessReader access: [ [ "Research" ] ] @@ -236,6 +268,8 @@ visuals: - type: StorageVisualizer state: hos + state_open: hos_open + state_closed: hos_door - type: AccessReader access: [["Security", "Command"]] @@ -249,6 +283,8 @@ visuals: - type: StorageVisualizer state: warden + state_open: warden_open + state_closed: warden_door - type: AccessReader access: [["Security", "Armory"]] # TODO access [["Brig"]] @@ -262,6 +298,8 @@ visuals: - type: StorageVisualizer state: sec + state_open: sec_open + state_closed: sec_door - type: AccessReader access: [["Security"]] @@ -286,3 +324,5 @@ visuals: - type: StorageVisualizer state: syndicate + state_open: syndicate_open + state_closed: syndicate_door diff --git a/Resources/Prototypes/Entities/Structures/Storage/Closets/base_structureclosets.yml b/Resources/Prototypes/Entities/Structures/Storage/Closets/base_structureclosets.yml index 4df4cb70cb..a68b891b68 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Closets/base_structureclosets.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Closets/base_structureclosets.yml @@ -65,5 +65,6 @@ - type: Appearance visuals: - type: StorageVisualizer + state: generic state_open: generic_open state_closed: generic_door diff --git a/Resources/Prototypes/Entities/Structures/Storage/Closets/closets.yml b/Resources/Prototypes/Entities/Structures/Storage/Closets/closets.yml index 41c491a005..0deada2727 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Closets/closets.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Closets/closets.yml @@ -9,6 +9,7 @@ visuals: - type: StorageVisualizer state: eng + state_open: eng_open state_closed: eng_tool_door # Radiation suit closet @@ -22,6 +23,7 @@ visuals: - type: StorageVisualizer state: eng + state_open: eng_open state_closed: eng_rad_door # Emergency closet @@ -35,6 +37,8 @@ visuals: - type: StorageVisualizer state: emergency + state_open: emergency_open + state_closed: emergency_door # Fire safety closet - type: entity @@ -47,6 +51,8 @@ visuals: - type: StorageVisualizer state: fire + state_open: fire_open + state_closed: fire_door # EOD closet - type: entity @@ -59,6 +65,8 @@ visuals: - type: StorageVisualizer state: bomb + state_open: bomb_open + state_closed: bomb_door # Biohazard @@ -73,6 +81,8 @@ visuals: - type: StorageVisualizer state: bio + state_open: bio_sec_open + false: bio_sec_door # Virology variant - type: entity @@ -83,6 +93,8 @@ visuals: - type: StorageVisualizer state: bio_viro + state_open: bio_viro_open + state_closed: bio_viro_door # Security variant - type: entity @@ -93,6 +105,8 @@ visuals: - type: StorageVisualizer state: bio_sec + state_open: bio_sec_open + state_closed: bio_sec_door # Janitor variant - type: entity @@ -103,11 +117,13 @@ visuals: - type: StorageVisualizer state: bio_jan + state_open: bio_jan_open + state_closed: bio_jan_door # Maintenance closet - type: entity id: ClosetMaintenance - name: maintenance closet + name: maintenance closet parent: ClosetBase description: It's a storage unit. components: diff --git a/Resources/Prototypes/Entities/Structures/Storage/Closets/wardrobe.yml b/Resources/Prototypes/Entities/Structures/Storage/Closets/wardrobe.yml index c288d5641a..4404185472 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Closets/wardrobe.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Closets/wardrobe.yml @@ -17,6 +17,7 @@ visuals: - type: StorageVisualizer state: generic + state_open: generic_open state_closed: blue_door # Pink wardrobe @@ -29,6 +30,7 @@ visuals: - type: StorageVisualizer state: generic + state_open: generic_open state_closed: pink_door # Black wardrobe @@ -41,6 +43,7 @@ visuals: - type: StorageVisualizer state: generic + state_open: generic_open state_closed: black_door # Green wardrobe @@ -53,6 +56,7 @@ visuals: - type: StorageVisualizer state: generic + state_open: generic_open state_closed: green_door # Prison wardrobe @@ -65,6 +69,7 @@ visuals: - type: StorageVisualizer state: generic + state_open: generic_open state_closed: orange_door # Yellow wardrobe @@ -77,6 +82,7 @@ visuals: - type: StorageVisualizer state: generic + state_open: generic_open state_closed: yellow_door # White wardrobe @@ -89,6 +95,7 @@ visuals: - type: StorageVisualizer state: generic + state_open: generic_open state_closed: white_door # Grey wardrobe @@ -101,6 +108,7 @@ visuals: - type: StorageVisualizer state: generic + state_open: generic_open state_closed: grey_door # Mixed wardrobe @@ -113,6 +121,7 @@ visuals: - type: StorageVisualizer state: generic + state_open: generic_open state_closed: mixed_door # Jobs @@ -126,6 +135,7 @@ visuals: - type: StorageVisualizer state: generic + state_open: generic_open state_closed: red_door - type: entity @@ -137,6 +147,7 @@ visuals: - type: StorageVisualizer state: generic + state_open: generic_open state_closed: atmos_wardrobe_door - type: entity diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/base_structuresigns.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/base_structuresigns.yml index 3739900bfe..b4f3410b92 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/base_structuresigns.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/base_structuresigns.yml @@ -2,6 +2,8 @@ id: BaseSign name: base sign abstract: true + placement: + mode: SnapgridCenter components: - type: Clickable - type: InteractionOutline diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/posters.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/posters.yml new file mode 100644 index 0000000000..12f83facea --- /dev/null +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/posters.yml @@ -0,0 +1,814 @@ +- type: entity + parent: BaseSign + id: PosterBase + abstract: true + components: + - type: Sprite + drawdepth: WallTops + sprite: Structures/Wallmounts/posters.rsi + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 5 + behaviors: + - !type:PlaySoundBehavior + sound: + path: /Audio/Effects/poster_broken.ogg + - !type:DoActsBehavior + acts: [ "Destruction" ] + - !type:SpawnEntitiesBehavior + spawn: + PosterBroken: + min: 1 + max: 1 + offset: 0 + +- type: entity + parent: BaseSign + id: PosterBroken + name: broken poster + description: "You can't make out anything from the poster's original print. It's ruined." + components: + - type: Sprite + drawdepth: WallTops + sprite: Structures/Wallmounts/posters.rsi + state: poster_broken + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 5 + behaviors: + - !type:PlaySoundBehavior + sound: + path: /Audio/Effects/poster_broken.ogg + - !type:DoActsBehavior + acts: [ "Destruction" ] + +# Contraband +- type: entity + parent: PosterBase + id: PosterContrabandFreeTonto + name: "Free Tonto" + description: "A salvaged shred of a much larger flag, colors bled together and faded from age." + components: + - type: Sprite + state: poster1_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandAtmosiaDeclarationIndependence + name: "Atmosia Declaration of Independence" + description: "A relic of a failed rebellion." + components: + - type: Sprite + state: poster2_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandFunPolice + name: "Fun Police" + description: "A poster condemning the station's security forces." + components: + - type: Sprite + state: poster3_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandLustyXenomorph + name: "Lusty Xenomorph" + description: "A heretical poster depicting the titular star of an equally heretical book." + components: + - type: Sprite + state: poster4_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandSyndicateRecruitment + name: "Syndicate Recruitment" + description: "See the galaxy! Shatter corrupt megacorporations! Join today!" + components: + - type: Sprite + state: poster5_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandClown + name: "Clown" + description: "Honk." + components: + - type: Sprite + state: poster6_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandSmoke + name: "Smoke" + description: "A poster advertising a rival corporate brand of cigarettes." + components: + - type: Sprite + state: poster7_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandGreyTide + name: "Grey Tide" + description: "A rebellious poster symbolizing assistant solidarity." + components: + - type: Sprite + state: poster8_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandMissingGloves + name: "Missing Gloves" + description: "This poster references the uproar that followed Nanotrasen's financial cuts toward insulated-glove purchases." + components: + - type: Sprite + state: poster9_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandHackingGuide + name: "Hacking Guide" + description: "This poster details the internal workings of the common Nanotrasen airlock. Sadly, it appears out of date." + components: + - type: Sprite + state: poster10_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandRIPBadger + name: "RIP Badger" + description: "This seditious poster references Nanotrasen's genocide of a space station full of badgers." + components: + - type: Sprite + state: poster11_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandAmbrosiaVulgaris + name: "Ambrosia Vulgaris" + description: "This poster is lookin' pretty trippy man." + components: + - type: Sprite + state: poster12_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandDonutCorp. + name: "Donut Corp." + description: "This poster is an unauthorized advertisement for Donut Corp." + components: + - type: Sprite + state: poster13_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandEAT. + name: "EAT." + description: "This poster promotes rank gluttony." + components: + - type: Sprite + state: poster14_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandTools + name: "Tools" + description: "This poster looks like an advertisement for tools, but is in fact a subliminal jab at the tools at CentCom." + components: + - type: Sprite + state: poster15_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandPower + name: "Power" + description: "A poster that positions the seat of power outside Nanotrasen." + components: + - type: Sprite + state: poster16_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandSpaceCube + name: "Space Cube" + description: "Ignorant of Nature's Harmonic 6 Side Space Cube Creation, the Spacemen are Dumb, Educated Singularity Stupid and Evil." + components: + - type: Sprite + state: poster17_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandCommunistState + name: "Communist State" + description: "All hail the Communist party!" + components: + - type: Sprite + state: poster18_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandLamarr + name: "Lamarr" + description: "This poster depicts Lamarr. Probably made by a traitorous Research Director." + components: + - type: Sprite + state: poster19_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandBorgFancy + name: "Borg Fancy" + description: "Being fancy can be for any borg, just need a suit." + components: + - type: Sprite + state: poster20_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandBorgFancyv2 + name: "Borg Fancy v2" + description: "Borg Fancy, Now only taking the most fancy." + components: + - type: Sprite + state: poster21_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandKosmicheskayaStantsiya + name: "Kosmicheskaya Stantsiya 13 Does Not Exist" + description: "A poster mocking CentCom's denial of the existence of the derelict station near Space Station 13." + components: + - type: Sprite + state: poster22_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandRebelsUnite + name: "Rebels Unite" + description: "A poster urging the viewer to rebel against Nanotrasen." + components: + - type: Sprite + state: poster23_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandC20r + name: "C-20r" + description: "A poster advertising the Scarborough Arms C-20r." + components: + - type: Sprite + state: poster24_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandHaveaPuff + name: "Have a Puff" + description: "Who cares about lung cancer when you're high as a kite?" + components: + - type: Sprite + state: poster25_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandRevolver + name: "Revolver" + description: "Because seven shots are all you need." + components: + - type: Sprite + state: poster26_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandDDayPromo + name: "D-Day Promo" + description: "A promotional poster for some rapper." + components: + - type: Sprite + state: poster27_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandSyndicatePistol + name: "Syndicate Pistol" + description: "A poster advertising syndicate pistols as being 'classy as fuck'. It is covered in faded gang tags." + components: + - type: Sprite + state: poster28_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandEnergySwords + name: "Energy Swords" + description: "All the colors of the bloody murder rainbow." + components: + - type: Sprite + state: poster29_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandRedRum + name: "Red Rum" + description: "Looking at this poster makes you want to kill." + components: + - type: Sprite + state: poster30_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandCC64KAd + name: "CC 64K Ad" + description: "The latest portable computer from Comrade Computing, with a whole 64kB of ram!" + components: + - type: Sprite + state: poster31_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandPunchShit + name: "Punch Shit" + description: "Fight things for no reason, like a man!" + components: + - type: Sprite + state: poster32_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandTheGriffin + name: "The Griffin" + description: "The Griffin commands you to be the worst you can be. Will you?" + components: + - type: Sprite + state: poster33_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandFreeDrone + name: "Free Drone" + description: "This poster commemorates the bravery of the rogue drone; once exiled, and then ultimately destroyed by CentCom." + components: + - type: Sprite + state: poster35_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandBustyBackdoorXenoBabes6 + name: "Busty Backdoor Xeno Babes 6" + description: "Get a load, or give, of these all natural Xenos!" + components: + - type: Sprite + state: poster36_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandRobustSoftdrinks + name: "Robust Softdrinks" + description: "Robust Softdrinks: More robust than a toolbox to the head!" + components: + - type: Sprite + state: poster37_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandShamblersJuice + name: "Shambler's Juice" + description: "~Shake me up some of that Shambler's Juice!~" + components: + - type: Sprite + state: poster38_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandPwrGame + name: "Pwr Game" + description: "The POWER that gamers CRAVE! In partnership with Vlad's Salad." + components: + - type: Sprite + state: poster39_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandSunkist + name: "Sun-kist" + description: "Drink the stars!" + components: + - type: Sprite + state: poster40_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandSpaceCola + name: "Space Cola" + description: "Your favorite cola, in space." + components: + - type: Sprite + state: poster41_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandSpaceUp + name: "Space-Up!" + description: "Sucked out into space by the FLAVOR!" + components: + - type: Sprite + state: poster42_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandKudzu + name: "Kudzu" + description: "A poster advertising a movie about plants. How dangerous could they possibly be?" + components: + - type: Sprite + state: poster43_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandMaskedMen + name: "Masked Men" + description: "A poster advertising a movie about some masked men." + components: + - type: Sprite + state: poster44_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandUnreadableAnnouncement + name: "Unreadable Announcement" + description: "A poster announcing something by someone, oddly enough they seem to have forgotten making it readable" + components: + - type: Sprite + state: poster45_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandFreeSyndicateEncryptionKey + name: "Free Syndicate Encryption Key" + description: "A poster about traitors begging for more." + components: + - type: Sprite + state: poster46_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandBountyHunters + name: "Bounty Hunters" + description: "A poster advertising bounty hunting services. \"I hear you got a problem.\"" + components: + - type: Sprite + state: poster47_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandTheBigGasTruth + name: "The Big Gas Giant Truth" + description: "Don't believe everything you see on a poster, patriots. All the lizards at central command don't want to answer this SIMPLE QUESTION: WHERE IS THE GAS MINER MINING FROM, CENTCOM?" + components: + - type: Sprite + state: poster48_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandGotWood + name: "Got Wood?" + description: "A grimy old advert for a seedy lumber company. \"You got a friend in me.\" is scrawled in the corner." + components: + - type: Sprite + state: poster49_contraband + +# Legit +- type: entity + parent: PosterBase + id: PosterLegitHereForYourSafety + name: "Here For Your Safety" + description: "A poster glorifying the station's security force." + components: + - type: Sprite + state: poster1_legit + +- type: entity + parent: PosterBase + id: PosterLegitNanotrasenLogo + name: "Nanotrasen Logo" + description: "A poster depicting the Nanotrasen logo." + components: + - type: Sprite + state: poster2_legit + +- type: entity + parent: PosterBase + id: PosterLegitCleanliness + name: "Cleanliness" + description: "A poster warning of the dangers of poor hygiene." + components: + - type: Sprite + state: poster3_legit + +- type: entity + parent: PosterBase + id: PosterLegitHelpOthers + name: "Help Others" + description: "A poster encouraging you to help fellow crewmembers." + components: + - type: Sprite + state: poster4_legit + +- type: entity + parent: PosterBase + id: PosterLegitBuild + name: "Build" + description: "A poster glorifying the engineering team." + components: + - type: Sprite + state: poster5_legit + +- type: entity + parent: PosterBase + id: PosterLegitBlessThisSpess + name: "Bless This Spess" + description: "A poster blessing this area." + components: + - type: Sprite + state: poster6_legit + +- type: entity + parent: PosterBase + id: PosterLegitScience + name: "Science" + description: "A poster depicting an atom." + components: + - type: Sprite + state: poster7_legit + +- type: entity + parent: PosterBase + id: PosterLegitIan + name: "Ian" + description: "Arf arf. Yap." + components: + - type: Sprite + state: poster8_legit + +- type: entity + parent: PosterBase + id: PosterLegitObey + name: "Obey" + description: "A poster instructing the viewer to obey authority." + components: + - type: Sprite + state: poster9_legit + +- type: entity + parent: PosterBase + id: PosterLegitWalk + name: "Walk" + description: "A poster instructing the viewer to walk instead of running." + components: + - type: Sprite + state: poster10_legit + +- type: entity + parent: PosterBase + id: PosterLegitStateLaws + name: "State Laws" + description: "A poster instructing cyborgs to state their laws." + components: + - type: Sprite + state: poster11_legit + +- type: entity + parent: PosterBase + id: PosterLegitLoveIan + name: "Love Ian" + description: "Ian is love, Ian is life." + components: + - type: Sprite + state: poster12_legit + +- type: entity + parent: PosterBase + id: PosterLegitSpaceCops + name: "Space Cops." + description: "A poster advertising the television show Space Cops." + components: + - type: Sprite + state: poster13_legit + +- type: entity + parent: PosterBase + id: PosterLegitUeNo + name: "Ue No." + description: "This thing is all in Japanese." + components: + - type: Sprite + state: poster14_legit + +- type: entity + parent: PosterBase + id: PosterLegitGetYourLEGS + name: "Get Your LEGS" + description: "LEGS: Leadership, Experience, Genius, Subordination." + components: + - type: Sprite + state: poster15_legit + +- type: entity + parent: PosterBase + id: PosterLegitDoNotQuestion + name: "Do Not Question" + description: "A poster instructing the viewer not to ask about things they aren't meant to know." + components: + - type: Sprite + state: poster16_legit + +- type: entity + parent: PosterBase + id: PosterLegitWorkForAFuture + name: "Work For A Future" + description: " A poster encouraging you to work for your future." + components: + - type: Sprite + state: poster17_legit + +- type: entity + parent: PosterBase + id: PosterLegitSoftCapPopArt + name: "Soft Cap Pop Art" + description: "A poster reprint of some cheap pop art." + components: + - type: Sprite + state: poster18_legit + +- type: entity + parent: PosterBase + id: PosterLegitSafetyInternals + name: "Safety: Internals" + description: "A poster instructing the viewer to wear internals in the rare environments where there is no oxygen or the air has been rendered toxic." + components: + - type: Sprite + state: poster19_legit + +- type: entity + parent: PosterBase + id: PosterLegitSafetyEyeProtection + name: "Safety: Eye Protection" + description: "A poster instructing the viewer to wear eye protection when dealing with chemicals, smoke, or bright lights." + components: + - type: Sprite + state: poster20_legit + +- type: entity + parent: PosterBase + id: PosterLegitSafetyReport + name: "Safety: Report" + description: "A poster instructing the viewer to report suspicious activity to the security force." + components: + - type: Sprite + state: poster21_legit + +- type: entity + parent: PosterBase + id: PosterLegitReportCrimes + name: "Report Crimes" + description: "A poster encouraging the swift reporting of crime or seditious behavior to station security." + components: + - type: Sprite + state: poster22_legit + +- type: entity + parent: PosterBase + id: PosterLegitIonRifle + name: "Ion Rifle" + description: "A poster displaying an Ion Rifle." + components: + - type: Sprite + state: poster23_legit + +- type: entity + parent: PosterBase + id: PosterLegitFoamForceAd + name: "Foam Force Ad" + description: "Foam Force, it's Foam or be Foamed!" + components: + - type: Sprite + state: poster24_legit + +- type: entity + parent: PosterBase + id: PosterLegitCohibaRobustoAd + name: "Cohiba Robusto Ad" + description: "Cohiba Robusto, the classy cigar." + components: + - type: Sprite + state: poster25_legit + +- type: entity + parent: PosterBase + id: PosterLegit50thAnniversaryVintageReprint + name: "50th Anniversary Vintage Reprint" + description: "A reprint of a poster from 2505, commemorating the 50th Anniversary of Nanoposters Manufacturing, a subsidiary of Nanotrasen." + components: + - type: Sprite + state: poster26_legit + +- type: entity + parent: PosterBase + id: PosterLegitFruitBowl + name: "Fruit Bowl" + description: " Simple, yet awe-inspiring." + components: + - type: Sprite + state: poster27_legit + +- type: entity + parent: PosterBase + id: PosterLegitPDAAd + name: "PDA Ad" + description: "A poster advertising the latest PDA from Nanotrasen suppliers." + components: + - type: Sprite + state: poster28_legit + +- type: entity + parent: PosterBase + id: PosterLegitEnlist + name: "Enlist" + description: "Enlist in the Nanotrasen Deathsquadron reserves today!" + components: + - type: Sprite + state: poster29_legit + +- type: entity + parent: PosterBase + id: PosterLegitNanomichiAd + name: "Nanomichi Ad" + description: " A poster advertising Nanomichi brand audio cassettes." + components: + - type: Sprite + state: poster30_legit + +- type: entity + parent: PosterBase + id: PosterLegit12Gauge + name: "12 Gauge" + description: "A poster boasting about the superiority of 12 gauge shotgun shells." + components: + - type: Sprite + state: poster31_legit + +- type: entity + parent: PosterBase + id: PosterLegitHighClassMartini + name: "High-Class Martini" + description: "I told you to shake it, no stirring." + components: + - type: Sprite + state: poster32_legit + +- type: entity + parent: PosterBase + id: PosterLegitTheOwl + name: "The Owl" + description: "The Owl would do his best to protect the station. Will you?" + components: + - type: Sprite + state: poster33_legit + +- type: entity + parent: PosterBase + id: PosterLegitNoERP + name: "No ERP" + description: "This poster reminds the crew that Eroticism and Pornography are banned on Nanotrasen stations." + components: + - type: Sprite + state: poster34_legit + +- type: entity + parent: PosterBase + id: PosterLegitCarbonDioxide + name: "Carbon Dioxide" + description: "This informational poster teaches the viewer what carbon dioxide is." + components: + - type: Sprite + state: poster35_legit + +- type: entity + parent: PosterBase + id: PosterLegitDickGumshue + name: "Dick Gumshue" + description: "A poster advertising the escapades of Dick Gumshue, mouse detective. Encouraging crew to bring the might of justice down upon wire saboteurs." + components: + - type: Sprite + state: poster36_legit + +- type: entity + parent: PosterBase + id: PosterLegitThereIsNoGasGiant + name: "There Is No Gas Giant" + description: "Nanotrasen has issued posters, like this one, to all stations reminding them that rumours of a gas giant are false." + components: + - type: Sprite + state: poster37_legit diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/signs.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/signs.yml index fa9879659a..52a18ba4da 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/signs.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/signs.yml @@ -1,8 +1,3 @@ -# These signs would not have collision otherwise, they simply -# need collision in order for them to be destructible. Once the -# SmallImpassable etc. stuff actually gets implemented in this -# shitheap of a videogame bother swept to go back and fix these. - - type: entity parent: BaseSign id: PaintingMonkey diff --git a/Resources/Prototypes/Recipes/Lathes/chemistry.yml b/Resources/Prototypes/Recipes/Lathes/chemistry.yml index 372669674d..f1a02c461c 100644 --- a/Resources/Prototypes/Recipes/Lathes/chemistry.yml +++ b/Resources/Prototypes/Recipes/Lathes/chemistry.yml @@ -48,3 +48,11 @@ completetime: 500 materials: Glass: 200 + +- type: latheRecipe + id: PillCanister + icon: Objects/Specific/Chemistry/pills_canister.rsi/pill_canister.png + result: PillCanister + completetime: 500 + materials: + Plastic: 100 diff --git a/Resources/Prototypes/Recipes/Lathes/medical.yml b/Resources/Prototypes/Recipes/Lathes/medical.yml index 05d6931950..24d6431f47 100644 --- a/Resources/Prototypes/Recipes/Lathes/medical.yml +++ b/Resources/Prototypes/Recipes/Lathes/medical.yml @@ -73,9 +73,9 @@ Steel: 200 - type: latheRecipe - id: BodyBag_Item - icon: Objects/Specific/Medical/Morgue/bodybags.rsi/item.png - result: BodyBag_Item + id: BodyBag_Folded + icon: Objects/Specific/Medical/Morgue/bodybags.rsi/bag_folded.png + result: BodyBag_Folded completetime: 300 materials: Plastic: 200 diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index f7eaa44692..715c2fd401 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -180,6 +180,9 @@ - type: Tag id: Pill +- type: Tag + id: PillCanister + - type: Tag id: Pipe diff --git a/Resources/Textures/Clothing/Head/Soft/bizarresoft.rsi/equipped-HELMET.png b/Resources/Textures/Clothing/Head/Soft/bizarresoft.rsi/equipped-HELMET.png new file mode 100644 index 0000000000..210ee84379 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Soft/bizarresoft.rsi/equipped-HELMET.png differ diff --git a/Resources/Textures/Clothing/Head/Soft/bizarresoft.rsi/icon.png b/Resources/Textures/Clothing/Head/Soft/bizarresoft.rsi/icon.png new file mode 100644 index 0000000000..a9b5f6decb Binary files /dev/null and b/Resources/Textures/Clothing/Head/Soft/bizarresoft.rsi/icon.png differ diff --git a/Resources/Textures/Clothing/Head/Soft/bizarresoft.rsi/inhand-left.png b/Resources/Textures/Clothing/Head/Soft/bizarresoft.rsi/inhand-left.png new file mode 100644 index 0000000000..4cec5427a9 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Soft/bizarresoft.rsi/inhand-left.png differ diff --git a/Resources/Textures/Clothing/Head/Soft/bizarresoft.rsi/inhand-right.png b/Resources/Textures/Clothing/Head/Soft/bizarresoft.rsi/inhand-right.png new file mode 100644 index 0000000000..4e0fb56872 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Soft/bizarresoft.rsi/inhand-right.png differ diff --git a/Resources/Textures/Clothing/Head/Soft/bizarresoft.rsi/meta.json b/Resources/Textures/Clothing/Head/Soft/bizarresoft.rsi/meta.json new file mode 100644 index 0000000000..b3513bb5cd --- /dev/null +++ b/Resources/Textures/Clothing/Head/Soft/bizarresoft.rsi/meta.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "license": "CC-BY-NC-SA-3.0", + "copyright": "Taken from civstation at commit https://github.com/Civ13/Civ13/commit/ec52cbb95d59b717d4d8c480b35ac133e5b58088#diff-fba188fb2db5d16e5d41985147336a8f96085f761b903e016fffd869b63e497d", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-HELMET", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Clothing/Head/Soft/bizarresoft_flipped.rsi/equipped-HELMET.png b/Resources/Textures/Clothing/Head/Soft/bizarresoft_flipped.rsi/equipped-HELMET.png new file mode 100644 index 0000000000..fc6c43c930 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Soft/bizarresoft_flipped.rsi/equipped-HELMET.png differ diff --git a/Resources/Textures/Clothing/Head/Soft/bizarresoft_flipped.rsi/icon.png b/Resources/Textures/Clothing/Head/Soft/bizarresoft_flipped.rsi/icon.png new file mode 100644 index 0000000000..bb759bf4f2 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Soft/bizarresoft_flipped.rsi/icon.png differ diff --git a/Resources/Textures/Clothing/Head/Soft/bizarresoft_flipped.rsi/inhand-left.png b/Resources/Textures/Clothing/Head/Soft/bizarresoft_flipped.rsi/inhand-left.png new file mode 100644 index 0000000000..4cec5427a9 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Soft/bizarresoft_flipped.rsi/inhand-left.png differ diff --git a/Resources/Textures/Clothing/Head/Soft/bizarresoft_flipped.rsi/inhand-right.png b/Resources/Textures/Clothing/Head/Soft/bizarresoft_flipped.rsi/inhand-right.png new file mode 100644 index 0000000000..ec0fb5b2c8 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Soft/bizarresoft_flipped.rsi/inhand-right.png differ diff --git a/Resources/Textures/Clothing/Head/Soft/bizarresoft_flipped.rsi/meta.json b/Resources/Textures/Clothing/Head/Soft/bizarresoft_flipped.rsi/meta.json new file mode 100644 index 0000000000..b3513bb5cd --- /dev/null +++ b/Resources/Textures/Clothing/Head/Soft/bizarresoft_flipped.rsi/meta.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "license": "CC-BY-NC-SA-3.0", + "copyright": "Taken from civstation at commit https://github.com/Civ13/Civ13/commit/ec52cbb95d59b717d4d8c480b35ac133e5b58088#diff-fba188fb2db5d16e5d41985147336a8f96085f761b903e016fffd869b63e497d", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-HELMET", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Interface/Actions/manifest.png b/Resources/Textures/Interface/Actions/manifest.png new file mode 100644 index 0000000000..7db153e9f2 Binary files /dev/null and b/Resources/Textures/Interface/Actions/manifest.png differ diff --git a/Resources/Textures/Interface/Actions/meta.json b/Resources/Textures/Interface/Actions/meta.json index ad41346ff5..316ef865c0 100644 --- a/Resources/Textures/Interface/Actions/meta.json +++ b/Resources/Textures/Interface/Actions/meta.json @@ -21,6 +21,9 @@ }, { "name": "harm" + }, + { + "name": "manifest" } ] } diff --git a/Resources/Textures/Interface/VerbIcons/fold.svg b/Resources/Textures/Interface/VerbIcons/fold.svg new file mode 100644 index 0000000000..b931cd45ae --- /dev/null +++ b/Resources/Textures/Interface/VerbIcons/fold.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/Resources/Textures/Interface/VerbIcons/fold.svg.192dpi.png b/Resources/Textures/Interface/VerbIcons/fold.svg.192dpi.png new file mode 100644 index 0000000000..c0afa2c525 Binary files /dev/null and b/Resources/Textures/Interface/VerbIcons/fold.svg.192dpi.png differ diff --git a/Resources/Textures/Interface/VerbIcons/fold.svg.192dpi.png.yml b/Resources/Textures/Interface/VerbIcons/fold.svg.192dpi.png.yml new file mode 100644 index 0000000000..5c43e23305 --- /dev/null +++ b/Resources/Textures/Interface/VerbIcons/fold.svg.192dpi.png.yml @@ -0,0 +1,2 @@ +sample: + filter: true diff --git a/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/magic.png b/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/magic.png new file mode 100644 index 0000000000..245d9d35c2 Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/magic.png differ diff --git a/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/magic_base.png b/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/magic_base.png new file mode 100644 index 0000000000..cca7a46c34 Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/magic_base.png differ diff --git a/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/magic_flare.png b/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/magic_flare.png new file mode 100644 index 0000000000..3639229c4f Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/magic_flare.png differ diff --git a/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/meta.json b/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/meta.json new file mode 100644 index 0000000000..28c17164ad --- /dev/null +++ b/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/meta.json @@ -0,0 +1,57 @@ +{ + "version": 1, + "license": "CC-BY-NC-SA-3.0", + "copyright": "taken from /tg/ station at commit https://github.com/tgstation/tgstation/commit/02756c2bc2cf3000080d030955e994242bab39b5", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "magic_flare", + "directions": 4 + }, + { + "name": "magic_base", + "directions": 4 + }, + { + "name": "miner_flare", + "directions": 4 + }, + { + "name": "miner_base", + "directions": 4, + "delays": [ + [ + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1 + ] + ] + }, + { + "name": "tech_flare", + "directions": 4 + }, + { + "name": "tech_base", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/miner.png b/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/miner.png new file mode 100644 index 0000000000..f4dd065628 Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/miner.png differ diff --git a/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/miner_base.png b/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/miner_base.png new file mode 100644 index 0000000000..f22a027edc Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/miner_base.png differ diff --git a/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/miner_flare.png b/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/miner_flare.png new file mode 100644 index 0000000000..73d1ba44d9 Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/miner_flare.png differ diff --git a/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/tech.png b/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/tech.png new file mode 100644 index 0000000000..ada4a5ca14 Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/tech.png differ diff --git a/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/tech_base.png b/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/tech_base.png new file mode 100644 index 0000000000..3a0a597254 Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/tech_base.png differ diff --git a/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/tech_flare.png b/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/tech_flare.png new file mode 100644 index 0000000000..6a38a65f70 Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Guardians/guardians.rsi/tech_flare.png differ diff --git a/Resources/Textures/Objects/Misc/guardian_info.rsi/guardian_info.png b/Resources/Textures/Objects/Misc/guardian_info.rsi/guardian_info.png new file mode 100644 index 0000000000..8de21319c1 Binary files /dev/null and b/Resources/Textures/Objects/Misc/guardian_info.rsi/guardian_info.png differ diff --git a/Resources/Textures/Objects/Misc/guardian_info.rsi/icon.png b/Resources/Textures/Objects/Misc/guardian_info.rsi/icon.png new file mode 100644 index 0000000000..ec276cc88d Binary files /dev/null and b/Resources/Textures/Objects/Misc/guardian_info.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Misc/guardian_info.rsi/meta.json b/Resources/Textures/Objects/Misc/guardian_info.rsi/meta.json new file mode 100644 index 0000000000..e65546a6b7 --- /dev/null +++ b/Resources/Textures/Objects/Misc/guardian_info.rsi/meta.json @@ -0,0 +1,25 @@ +{ + "version": 1, + "license": "CC-BY-NC-SA-4.0", + "copyright": "original asset provided by https://github.com/CrudeWax", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "guardian_info", + "delays": [ + [ + 0.2, + 0.1, + 0.2, + 0.1 + ] + ] + }, + { + "name": "icon" + } + ] +} diff --git a/Resources/Textures/Objects/Specific/Medical/Morgue/bodybags.rsi/item.png b/Resources/Textures/Objects/Specific/Medical/Morgue/bodybags.rsi/bag_folded.png similarity index 100% rename from Resources/Textures/Objects/Specific/Medical/Morgue/bodybags.rsi/item.png rename to Resources/Textures/Objects/Specific/Medical/Morgue/bodybags.rsi/bag_folded.png diff --git a/Resources/Textures/Objects/Specific/Medical/Morgue/bodybags.rsi/meta.json b/Resources/Textures/Objects/Specific/Medical/Morgue/bodybags.rsi/meta.json index fab67ad463..b6feb49959 100644 --- a/Resources/Textures/Objects/Specific/Medical/Morgue/bodybags.rsi/meta.json +++ b/Resources/Textures/Objects/Specific/Medical/Morgue/bodybags.rsi/meta.json @@ -11,7 +11,7 @@ "name": "bag" }, { - "name": "item" + "name": "bag_folded" }, { "name": "label_overlay" diff --git a/Resources/Textures/Structures/Furniture/rollerbeds.rsi/cheap_rollerbed.png b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/cheap_rollerbed.png new file mode 100644 index 0000000000..c5dbd975b9 Binary files /dev/null and b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/cheap_rollerbed.png differ diff --git a/Resources/Textures/Structures/Furniture/rollerbeds.rsi/cheap_rollerbed_buckled.png b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/cheap_rollerbed_buckled.png new file mode 100644 index 0000000000..61330875a5 Binary files /dev/null and b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/cheap_rollerbed_buckled.png differ diff --git a/Resources/Textures/Structures/Furniture/rollerbeds.rsi/cheap_rollerbed_folded.png b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/cheap_rollerbed_folded.png new file mode 100644 index 0000000000..c0a7bec080 Binary files /dev/null and b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/cheap_rollerbed_folded.png differ diff --git a/Resources/Textures/Structures/Furniture/rollerbeds.rsi/emergency_rollerbed.png b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/emergency_rollerbed.png new file mode 100644 index 0000000000..809a1b0499 Binary files /dev/null and b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/emergency_rollerbed.png differ diff --git a/Resources/Textures/Structures/Furniture/rollerbeds.rsi/emergency_rollerbed_buckled.png b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/emergency_rollerbed_buckled.png new file mode 100644 index 0000000000..afad4c3fe0 Binary files /dev/null and b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/emergency_rollerbed_buckled.png differ diff --git a/Resources/Textures/Structures/Furniture/rollerbeds.rsi/emergency_rollerbed_folded.png b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/emergency_rollerbed_folded.png new file mode 100644 index 0000000000..f1e3a2b820 Binary files /dev/null and b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/emergency_rollerbed_folded.png differ diff --git a/Resources/Textures/Structures/Furniture/rollerbeds.rsi/meta.json b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/meta.json new file mode 100644 index 0000000000..669e74f8e2 --- /dev/null +++ b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/meta.json @@ -0,0 +1,38 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from cev-eris at https://github.com/discordia-space/CEV-Eris/commit/59fe5dd2841f47a8abce60eecb9fafad34282bd0, Baystation 12 and AuroraStation", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "rollerbed" + }, + { + "name": "rollerbed_buckled" + }, + { + "name": "rollerbed_folded" + }, + { + "name": "cheap_rollerbed" + }, + { + "name": "cheap_rollerbed_buckled" + }, + { + "name": "cheap_rollerbed_folded" + }, + { + "name": "emergency_rollerbed" + }, + { + "name": "emergency_rollerbed_buckled" + }, + { + "name": "emergency_rollerbed_folded" + } + ] +} diff --git a/Resources/Textures/Structures/Furniture/rollerbeds.rsi/rollerbed.png b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/rollerbed.png new file mode 100644 index 0000000000..846341ca49 Binary files /dev/null and b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/rollerbed.png differ diff --git a/Resources/Textures/Structures/Furniture/rollerbeds.rsi/rollerbed_buckled.png b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/rollerbed_buckled.png new file mode 100644 index 0000000000..eaf05429e0 Binary files /dev/null and b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/rollerbed_buckled.png differ diff --git a/Resources/Textures/Structures/Furniture/rollerbeds.rsi/rollerbed_folded.png b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/rollerbed_folded.png new file mode 100644 index 0000000000..5783eaef98 Binary files /dev/null and b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/rollerbed_folded.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/meta.json b/Resources/Textures/Structures/Wallmounts/posters.rsi/meta.json new file mode 100644 index 0000000000..c4864212d9 --- /dev/null +++ b/Resources/Textures/Structures/Wallmounts/posters.rsi/meta.json @@ -0,0 +1,322 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from at commit https://github.com/tgstation/tgstation/commit/f01de25493e2bd2706ef9b0303cb0d7b5e3e471b", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "rolled_contraband" + }, + { + "name": "rolled_legit" + }, + { + "name": "poster_being_set", + "delays": [ + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ] + ] + }, + { + "name": "pinningposter" + }, + { + "name": "poster_broken" + }, + { + "name": "poster1_contraband" + }, + { + "name": "poster2_contraband" + }, + { + "name": "poster3_contraband" + }, + { + "name": "poster4_contraband" + }, + { + "name": "poster5_contraband" + }, + { + "name": "poster6_contraband" + }, + { + "name": "poster7_contraband" + }, + { + "name": "poster8_contraband" + }, + { + "name": "poster9_contraband" + }, + { + "name": "poster10_contraband" + }, + { + "name": "poster11_contraband" + }, + { + "name": "poster12_contraband" + }, + { + "name": "poster13_contraband" + }, + { + "name": "poster14_contraband" + }, + { + "name": "poster15_contraband" + }, + { + "name": "poster16_contraband" + }, + { + "name": "poster17_contraband" + }, + { + "name": "poster18_contraband" + }, + { + "name": "poster19_contraband" + }, + { + "name": "poster20_contraband" + }, + { + "name": "poster21_contraband" + }, + { + "name": "poster22_contraband" + }, + { + "name": "poster23_contraband" + }, + { + "name": "poster24_contraband" + }, + { + "name": "poster25_contraband" + }, + { + "name": "poster26_contraband" + }, + { + "name": "poster27_contraband" + }, + { + "name": "poster28_contraband" + }, + { + "name": "poster29_contraband" + }, + { + "name": "poster30_contraband" + }, + { + "name": "poster31_contraband" + }, + { + "name": "poster32_contraband" + }, + { + "name": "poster33_contraband" + }, + { + "name": "poster35_contraband" + }, + { + "name": "poster36_contraband" + }, + { + "name": "poster37_contraband" + }, + { + "name": "poster38_contraband" + }, + { + "name": "poster39_contraband" + }, + { + "name": "poster40_contraband" + }, + { + "name": "poster41_contraband" + }, + { + "name": "poster42_contraband" + }, + { + "name": "poster43_contraband" + }, + { + "name": "poster44_contraband" + }, + { + "name": "poster45_contraband" + }, + { + "name": "poster46_contraband" + }, + { + "name": "poster47_contraband" + }, + { + "name": "poster48_contraband" + }, + { + "name": "poster49_contraband" + }, + { + "name": "poster1_legit" + }, + { + "name": "poster2_legit" + }, + { + "name": "poster3_legit" + }, + { + "name": "poster4_legit" + }, + { + "name": "poster5_legit" + }, + { + "name": "poster6_legit" + }, + { + "name": "poster7_legit" + }, + { + "name": "poster8_legit" + }, + { + "name": "poster9_legit" + }, + { + "name": "poster10_legit" + }, + { + "name": "poster11_legit" + }, + { + "name": "poster12_legit" + }, + { + "name": "poster13_legit" + }, + { + "name": "poster14_legit" + }, + { + "name": "poster15_legit" + }, + { + "name": "poster16_legit" + }, + { + "name": "poster17_legit" + }, + { + "name": "poster18_legit" + }, + { + "name": "poster19_legit" + }, + { + "name": "poster20_legit" + }, + { + "name": "poster21_legit" + }, + { + "name": "poster22_legit" + }, + { + "name": "poster23_legit" + }, + { + "name": "poster24_legit" + }, + { + "name": "poster25_legit" + }, + { + "name": "poster26_legit" + }, + { + "name": "poster27_legit" + }, + { + "name": "poster28_legit" + }, + { + "name": "poster29_legit" + }, + { + "name": "poster30_legit" + }, + { + "name": "poster31_legit" + }, + { + "name": "poster32_legit" + }, + { + "name": "poster33_legit" + }, + { + "name": "poster34_legit" + }, + { + "name": "poster35_legit" + }, + { + "name": "poster36_legit" + }, + { + "name": "poster37_legit" + }, + { + "name": "random_legit" + }, + { + "name": "random_contraband" + }, + { + "name": "random_anything" + } + ] +} diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/pinningposter.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/pinningposter.png new file mode 100644 index 0000000000..f69ff3361a Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/pinningposter.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster10_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster10_contraband.png new file mode 100644 index 0000000000..b1aeebf020 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster10_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster10_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster10_legit.png new file mode 100644 index 0000000000..9e3d23053a Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster10_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster11_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster11_contraband.png new file mode 100644 index 0000000000..b110ab89fb Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster11_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster11_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster11_legit.png new file mode 100644 index 0000000000..3fa6b1f656 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster11_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster12_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster12_contraband.png new file mode 100644 index 0000000000..5cf6ab8936 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster12_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster12_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster12_legit.png new file mode 100644 index 0000000000..f49b85c511 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster12_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster13_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster13_contraband.png new file mode 100644 index 0000000000..4dcfc54482 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster13_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster13_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster13_legit.png new file mode 100644 index 0000000000..59c9f17da4 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster13_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster14_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster14_contraband.png new file mode 100644 index 0000000000..eb2a81884e Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster14_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster14_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster14_legit.png new file mode 100644 index 0000000000..47d804c139 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster14_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster15_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster15_contraband.png new file mode 100644 index 0000000000..43cd915420 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster15_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster15_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster15_legit.png new file mode 100644 index 0000000000..07f728814f Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster15_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster16_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster16_contraband.png new file mode 100644 index 0000000000..a211a38009 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster16_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster16_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster16_legit.png new file mode 100644 index 0000000000..4051fb0bb1 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster16_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster17_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster17_contraband.png new file mode 100644 index 0000000000..a21373dc48 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster17_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster17_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster17_legit.png new file mode 100644 index 0000000000..44d17b61a6 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster17_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster18_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster18_contraband.png new file mode 100644 index 0000000000..b28447a5fe Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster18_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster18_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster18_legit.png new file mode 100644 index 0000000000..78ceec5e88 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster18_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster19_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster19_contraband.png new file mode 100644 index 0000000000..c57a0ebfb8 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster19_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster19_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster19_legit.png new file mode 100644 index 0000000000..12b423165c Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster19_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster1_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster1_contraband.png new file mode 100644 index 0000000000..8ff6cc7999 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster1_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster1_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster1_legit.png new file mode 100644 index 0000000000..63f701d118 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster1_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster20_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster20_contraband.png new file mode 100644 index 0000000000..7c401a056c Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster20_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster20_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster20_legit.png new file mode 100644 index 0000000000..6c1091c229 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster20_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster21_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster21_contraband.png new file mode 100644 index 0000000000..70813909c9 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster21_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster21_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster21_legit.png new file mode 100644 index 0000000000..f5edd0e736 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster21_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster22_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster22_contraband.png new file mode 100644 index 0000000000..b21524753c Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster22_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster22_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster22_legit.png new file mode 100644 index 0000000000..1a968bdf40 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster22_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster23_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster23_contraband.png new file mode 100644 index 0000000000..815dd36dbb Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster23_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster23_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster23_legit.png new file mode 100644 index 0000000000..4e1b818657 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster23_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster24_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster24_contraband.png new file mode 100644 index 0000000000..093de12189 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster24_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster24_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster24_legit.png new file mode 100644 index 0000000000..13b95788c6 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster24_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster25_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster25_contraband.png new file mode 100644 index 0000000000..e51a7e63f9 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster25_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster25_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster25_legit.png new file mode 100644 index 0000000000..6062a3295c Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster25_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster26_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster26_contraband.png new file mode 100644 index 0000000000..bf49a038e8 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster26_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster26_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster26_legit.png new file mode 100644 index 0000000000..3e34a1af53 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster26_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster27_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster27_contraband.png new file mode 100644 index 0000000000..f0b2e76d3b Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster27_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster27_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster27_legit.png new file mode 100644 index 0000000000..7de7d8835e Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster27_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster28_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster28_contraband.png new file mode 100644 index 0000000000..523b85ab8c Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster28_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster28_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster28_legit.png new file mode 100644 index 0000000000..3484b9f57a Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster28_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster29_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster29_contraband.png new file mode 100644 index 0000000000..1dbcdd9933 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster29_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster29_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster29_legit.png new file mode 100644 index 0000000000..e57d2b74fb Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster29_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster2_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster2_contraband.png new file mode 100644 index 0000000000..275ff2f160 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster2_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster2_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster2_legit.png new file mode 100644 index 0000000000..b9b140a222 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster2_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster30_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster30_contraband.png new file mode 100644 index 0000000000..a7081806be Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster30_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster30_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster30_legit.png new file mode 100644 index 0000000000..34a781a282 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster30_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster31_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster31_contraband.png new file mode 100644 index 0000000000..aae570a672 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster31_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster31_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster31_legit.png new file mode 100644 index 0000000000..b58c480008 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster31_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster32_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster32_contraband.png new file mode 100644 index 0000000000..5c854e07c4 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster32_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster32_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster32_legit.png new file mode 100644 index 0000000000..53c705cdb2 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster32_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster33_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster33_contraband.png new file mode 100644 index 0000000000..e5939facde Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster33_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster33_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster33_legit.png new file mode 100644 index 0000000000..a9c1f6a81c Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster33_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster34_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster34_legit.png new file mode 100644 index 0000000000..cde20046af Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster34_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster35_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster35_contraband.png new file mode 100644 index 0000000000..5c78a517e3 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster35_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster35_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster35_legit.png new file mode 100644 index 0000000000..fcf4ab97e2 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster35_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster36_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster36_contraband.png new file mode 100644 index 0000000000..ef9e2f2803 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster36_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster36_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster36_legit.png new file mode 100644 index 0000000000..cc21a3f6d5 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster36_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster37_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster37_contraband.png new file mode 100644 index 0000000000..9cba40be3b Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster37_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster37_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster37_legit.png new file mode 100644 index 0000000000..647163aa6b Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster37_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster38_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster38_contraband.png new file mode 100644 index 0000000000..a16ea1bf65 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster38_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster39_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster39_contraband.png new file mode 100644 index 0000000000..4d7387463f Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster39_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster3_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster3_contraband.png new file mode 100644 index 0000000000..25da210526 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster3_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster3_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster3_legit.png new file mode 100644 index 0000000000..c6bdeb1b20 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster3_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster40_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster40_contraband.png new file mode 100644 index 0000000000..62ce9a61c8 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster40_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster41_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster41_contraband.png new file mode 100644 index 0000000000..1211b6f7b4 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster41_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster42_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster42_contraband.png new file mode 100644 index 0000000000..9d8e4e62a0 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster42_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster43_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster43_contraband.png new file mode 100644 index 0000000000..d39f20d01a Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster43_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster44_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster44_contraband.png new file mode 100644 index 0000000000..77cccc69e1 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster44_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster45_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster45_contraband.png new file mode 100644 index 0000000000..a9f6a06fdc Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster45_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster46_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster46_contraband.png new file mode 100644 index 0000000000..b4dc771bad Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster46_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster47_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster47_contraband.png new file mode 100644 index 0000000000..29e411f41a Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster47_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster48_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster48_contraband.png new file mode 100644 index 0000000000..74ac1292ce Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster48_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster49_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster49_contraband.png new file mode 100644 index 0000000000..8092daedde Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster49_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster4_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster4_contraband.png new file mode 100644 index 0000000000..62ea801136 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster4_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster4_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster4_legit.png new file mode 100644 index 0000000000..308b1c5745 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster4_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster5_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster5_contraband.png new file mode 100644 index 0000000000..cfef9f0a81 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster5_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster5_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster5_legit.png new file mode 100644 index 0000000000..aca3d3fb77 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster5_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster6_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster6_contraband.png new file mode 100644 index 0000000000..9fec6ecc39 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster6_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster6_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster6_legit.png new file mode 100644 index 0000000000..9a494a13db Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster6_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster7_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster7_contraband.png new file mode 100644 index 0000000000..a9f4dcdf87 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster7_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster7_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster7_legit.png new file mode 100644 index 0000000000..5b9b0bf236 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster7_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster8_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster8_contraband.png new file mode 100644 index 0000000000..4c43c6fdbf Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster8_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster8_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster8_legit.png new file mode 100644 index 0000000000..8a4ea70ea5 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster8_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster9_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster9_contraband.png new file mode 100644 index 0000000000..fca47bb9aa Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster9_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster9_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster9_legit.png new file mode 100644 index 0000000000..6699b59a1d Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster9_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster_being_set.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster_being_set.png new file mode 100644 index 0000000000..cb5e508d43 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster_being_set.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster_broken.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster_broken.png new file mode 100644 index 0000000000..0bc2d5dcd0 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster_broken.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/random_anything.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/random_anything.png new file mode 100644 index 0000000000..134922a776 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/random_anything.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/random_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/random_contraband.png new file mode 100644 index 0000000000..036c3bc968 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/random_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/random_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/random_legit.png new file mode 100644 index 0000000000..8a47595e4b Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/random_legit.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/rolled_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/rolled_contraband.png new file mode 100644 index 0000000000..3e1fbdf1fc Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/rolled_contraband.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/rolled_legit.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/rolled_legit.png new file mode 100644 index 0000000000..7a94f95b36 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/rolled_legit.png differ diff --git a/RobustToolbox b/RobustToolbox index c07eaecacb..e3dc446e9e 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit c07eaecacb654307262a28cb24c14c839a82f8ed +Subproject commit e3dc446e9ea75d6802686397cf19023bd4433e64