diff --git a/Content.Client/AirlockPainter/AirlockPainterSystem.cs b/Content.Client/AirlockPainter/AirlockPainterSystem.cs new file mode 100644 index 0000000000..dd2995d482 --- /dev/null +++ b/Content.Client/AirlockPainter/AirlockPainterSystem.cs @@ -0,0 +1,54 @@ +using Content.Shared.AirlockPainter; +using Robust.Client.Graphics; +using Robust.Client.ResourceManagement; +using Robust.Shared.Utility; +using System.Linq; +using static Robust.Shared.GameObjects.SharedSpriteComponent; + +namespace Content.Client.AirlockPainter +{ + public sealed class AirlockPainterSystem : SharedAirlockPainterSystem + { + [Dependency] private readonly IResourceCache _resourceCache = default!; + + public List Entries { get; private set; } = new(); + + public override void Initialize() + { + base.Initialize(); + + foreach (string style in Styles) + { + string? iconPath = Groups + .FindAll(x => x.StylePaths.ContainsKey(style))? + .MaxBy(x => x.IconPriority)?.StylePaths[style]; + if (iconPath == null) + { + Entries.Add(new AirlockPainterEntry(style, null)); + continue; + } + + RSIResource doorRsi = _resourceCache.GetResource(TextureRoot / new ResourcePath(iconPath)); + if (!doorRsi.RSI.TryGetState("closed", out var icon)) + { + Entries.Add(new AirlockPainterEntry(style, null)); + continue; + } + + Entries.Add(new AirlockPainterEntry(style, icon.Frame0)); + } + } + } + + public sealed class AirlockPainterEntry + { + public string Name; + public Texture? Icon; + + public AirlockPainterEntry(string name, Texture? icon) + { + Name = name; + Icon = icon; + } + } +} diff --git a/Content.Client/AirlockPainter/UI/AirlockPainterBoundUserInterface.cs b/Content.Client/AirlockPainter/UI/AirlockPainterBoundUserInterface.cs new file mode 100644 index 0000000000..ba3681cda7 --- /dev/null +++ b/Content.Client/AirlockPainter/UI/AirlockPainterBoundUserInterface.cs @@ -0,0 +1,38 @@ +using Content.Shared.AirlockPainter; +using Robust.Client.GameObjects; + +namespace Content.Client.AirlockPainter.UI +{ + public sealed class AirlockPainterBoundUserInterface : BoundUserInterface + { + private AirlockPainterWindow? _window; + public List Styles = new(); + + public AirlockPainterBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey) + { + } + + protected override void Open() + { + base.Open(); + + _window = new AirlockPainterWindow(); + if (State != null) + UpdateState(State); + + // Add styles + var painterSystem = EntitySystem.Get(); + _window.Populate(painterSystem.Entries); + + _window.OpenCentered(); + + _window.OnClose += Close; + _window.OnSpritePicked += OnSpritePicked; + } + + private void OnSpritePicked(int index) + { + SendMessage(new AirlockPainterSpritePickedMessage(index)); + } + } +} diff --git a/Content.Client/AirlockPainter/UI/AirlockPainterWindow.xaml b/Content.Client/AirlockPainter/UI/AirlockPainterWindow.xaml new file mode 100644 index 0000000000..2989ce9c4b --- /dev/null +++ b/Content.Client/AirlockPainter/UI/AirlockPainterWindow.xaml @@ -0,0 +1,14 @@ + + + + + + + diff --git a/Content.Client/AirlockPainter/UI/AirlockPainterWindow.xaml.cs b/Content.Client/AirlockPainter/UI/AirlockPainterWindow.xaml.cs new file mode 100644 index 0000000000..7ead44ca5a --- /dev/null +++ b/Content.Client/AirlockPainter/UI/AirlockPainterWindow.xaml.cs @@ -0,0 +1,28 @@ +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.CustomControls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.AirlockPainter.UI +{ + [GenerateTypedNameReferences] + public sealed partial class AirlockPainterWindow : DefaultWindow + { + public event Action? OnSpritePicked; + + public AirlockPainterWindow() + { + RobustXamlLoader.Load(this); + + SpriteList.OnItemSelected += e => OnSpritePicked?.Invoke(e.ItemIndex); + } + + public void Populate(List entries) + { + SpriteList.Clear(); + foreach (var entry in entries) + { + SpriteList.AddItem(entry.Name, entry.Icon); + } + } + } +} diff --git a/Content.Client/Doors/AirlockVisualizer.cs b/Content.Client/Doors/AirlockVisualizer.cs index b774c28cb2..6b4b877db8 100644 --- a/Content.Client/Doors/AirlockVisualizer.cs +++ b/Content.Client/Doors/AirlockVisualizer.cs @@ -4,6 +4,7 @@ using Content.Shared.Doors.Components; using JetBrains.Annotations; using Robust.Client.Animations; using Robust.Client.GameObjects; +using Robust.Client.ResourceManagement; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Serialization; @@ -17,6 +18,7 @@ namespace Content.Client.Doors { [Dependency] private readonly IEntityManager _entMan = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly IResourceCache _resourceCache = default!; private const string AnimationKey = "airlock_animation"; @@ -65,7 +67,7 @@ namespace Content.Client.Doors { IoCManager.InjectDependencies(this); - CloseAnimation = new Animation {Length = TimeSpan.FromSeconds(_delay)}; + CloseAnimation = new Animation { Length = TimeSpan.FromSeconds(_delay) }; { var flick = new AnimationTrackSpriteFlick(); CloseAnimation.AnimationTracks.Add(flick); @@ -89,7 +91,7 @@ namespace Content.Client.Doors } } - OpenAnimation = new Animation {Length = TimeSpan.FromSeconds(_delay)}; + OpenAnimation = new Animation { Length = TimeSpan.FromSeconds(_delay) }; { var flick = new AnimationTrackSpriteFlick(); OpenAnimation.AnimationTracks.Add(flick); @@ -112,7 +114,7 @@ namespace Content.Client.Doors } } } - EmaggingAnimation = new Animation {Length = TimeSpan.FromSeconds(_delay)}; + EmaggingAnimation = new Animation { Length = TimeSpan.FromSeconds(_delay) }; { var flickUnlit = new AnimationTrackSpriteFlick(); EmaggingAnimation.AnimationTracks.Add(flickUnlit); @@ -122,7 +124,7 @@ namespace Content.Client.Doors if (!_simpleVisuals) { - DenyAnimation = new Animation {Length = TimeSpan.FromSeconds(_denyDelay)}; + DenyAnimation = new Animation { Length = TimeSpan.FromSeconds(_denyDelay) }; { var flick = new AnimationTrackSpriteFlick(); DenyAnimation.AnimationTracks.Add(flick); @@ -161,6 +163,18 @@ namespace Content.Client.Doors var weldedVisible = false; var emergencyLightsVisible = false; + if (component.TryGetData(DoorVisuals.BaseRSI, out string baseRsi)) + { + if (!_resourceCache.TryGetResource(SharedSpriteComponent.TextureRoot / baseRsi, out var res)) + { + Logger.Error("Unable to load RSI '{0}'. Trace:\n{1}", baseRsi, Environment.StackTrace); + } + foreach (ISpriteLayer layer in sprite.AllLayers) + { + layer.Rsi = res?.RSI; + } + } + if (animPlayer.HasRunningAnimation(AnimationKey)) { animPlayer.Stop(AnimationKey); diff --git a/Content.Client/Entry/IgnoredComponents.cs b/Content.Client/Entry/IgnoredComponents.cs index 292bae52af..cd713ae714 100644 --- a/Content.Client/Entry/IgnoredComponents.cs +++ b/Content.Client/Entry/IgnoredComponents.cs @@ -5,6 +5,7 @@ namespace Content.Client.Entry { public static string[] List => new[] { + "AirlockPainter", "AmmoBox", "Pickaxe", "IngestionBlocker", diff --git a/Content.Server/AirlockPainter/AirlockPainterComponent.cs b/Content.Server/AirlockPainter/AirlockPainterComponent.cs new file mode 100644 index 0000000000..79a2d0afb0 --- /dev/null +++ b/Content.Server/AirlockPainter/AirlockPainterComponent.cs @@ -0,0 +1,22 @@ +using Content.Server.UserInterface; +using Content.Shared.AirlockPainter; +using Content.Shared.Sound; +using Robust.Server.GameObjects; + +namespace Content.Server.AirlockPainter +{ + [RegisterComponent] + public sealed class AirlockPainterComponent : Component + { + [DataField("spraySound")] + public SoundSpecifier SpraySound = new SoundPathSpecifier("/Audio/Effects/spray2.ogg"); + + [DataField("sprayTime")] + public float SprayTime = 3.0f; + + [DataField("isSpraying")] + public bool IsSpraying = false; + + public int Index = default!; + } +} diff --git a/Content.Server/AirlockPainter/AirlockPainterSystem.cs b/Content.Server/AirlockPainter/AirlockPainterSystem.cs new file mode 100644 index 0000000000..feec16588f --- /dev/null +++ b/Content.Server/AirlockPainter/AirlockPainterSystem.cs @@ -0,0 +1,138 @@ +using Content.Server.DoAfter; +using Content.Server.Popups; +using Content.Server.UserInterface; +using Content.Shared.AirlockPainter; +using Content.Shared.AirlockPainter.Prototypes; +using Content.Shared.Doors.Components; +using Content.Shared.Interaction; +using JetBrains.Annotations; +using Robust.Server.GameObjects; +using Robust.Shared.Audio; +using Robust.Shared.Player; + +namespace Content.Server.AirlockPainter +{ + /// + /// A system for painting airlocks using airlock painter + /// + [UsedImplicitly] + public sealed class AirlockPainterSystem : SharedAirlockPainterSystem + { + [Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!; + [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly PopupSystem _popupSystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(AfterInteractOn); + SubscribeLocalEvent(OnActivate); + SubscribeLocalEvent(OnSpritePicked); + SubscribeLocalEvent(OnDoAfterComplete); + SubscribeLocalEvent(OnDoAfterCancelled); + } + + private void OnDoAfterComplete(AirlockPainterDoAfterComplete ev) + { + ev.Component.IsSpraying = false; + if (TryComp(ev.Target, out var appearance) && + TryComp(ev.Target, out PaintableAirlockComponent? airlock)) + { + SoundSystem.Play(Filter.Pvs(ev.User, entityManager:EntityManager), ev.Component.SpraySound.GetSound(), ev.User); + appearance.SetData(DoorVisuals.BaseRSI, ev.Sprite); + } + } + + private void OnDoAfterCancelled(AirlockPainterDoAfterCancelled ev) + { + ev.Component.IsSpraying = false; + } + + private void OnActivate(EntityUid uid, AirlockPainterComponent component, ActivateInWorldEvent args) + { + if (!EntityManager.TryGetComponent(args.User, out ActorComponent? actor)) + return; + DirtyUI(uid, component); + component.Owner.GetUIOrNull(AirlockPainterUiKey.Key)?.Open(actor.PlayerSession); + args.Handled = true; + } + + private void AfterInteractOn(EntityUid uid, AirlockPainterComponent component, AfterInteractEvent args) + { + if (component.IsSpraying || args.Target is not { Valid: true } target || !args.CanReach) + return; + + if (!EntityManager.TryGetComponent(target, out var airlock)) + return; + + if (!_prototypeManager.TryIndex(airlock.Group, out var grp)) + { + Logger.Error("Group not defined: %s", airlock.Group); + return; + } + + string style = Styles[component.Index]; + if (!grp.StylePaths.TryGetValue(style, out var sprite)) + { + string msg = Loc.GetString("airlock-painter-style-not-available"); + _popupSystem.PopupEntity(msg, args.User, Filter.Entities(args.User)); + return; + } + component.IsSpraying = true; + var doAfterEventArgs = new DoAfterEventArgs(args.User, component.SprayTime, default, target) + { + BreakOnTargetMove = true, + BreakOnUserMove = true, + BreakOnDamage = true, + BreakOnStun = true, + NeedHand = true, + BroadcastFinishedEvent = new AirlockPainterDoAfterComplete(uid, target, sprite, component), + BroadcastCancelledEvent = new AirlockPainterDoAfterCancelled(component), + }; + _doAfterSystem.DoAfter(doAfterEventArgs); + } + + private sealed class AirlockPainterDoAfterComplete : EntityEventArgs + { + public readonly EntityUid User; + public readonly EntityUid Target; + public readonly string Sprite; + public readonly AirlockPainterComponent Component; + + public AirlockPainterDoAfterComplete(EntityUid user, EntityUid target, string sprite, AirlockPainterComponent component) + { + User = user; + Target = target; + Sprite = sprite; + Component = component; + } + } + + private sealed class AirlockPainterDoAfterCancelled : EntityEventArgs + { + public readonly AirlockPainterComponent Component; + + public AirlockPainterDoAfterCancelled(AirlockPainterComponent component) + { + Component = component; + } + } + + private void OnSpritePicked(EntityUid uid, AirlockPainterComponent component, AirlockPainterSpritePickedMessage args) + { + component.Index = args.Index; + DirtyUI(uid, component); + } + + private void DirtyUI(EntityUid uid, + AirlockPainterComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + _userInterfaceSystem.TrySetUiState(uid, AirlockPainterUiKey.Key, + new AirlockPainterBoundUserInterfaceState(component.Index)); + } + } +} diff --git a/Content.Shared/AirlockPainter/AirlockPainterEvents.cs b/Content.Shared/AirlockPainter/AirlockPainterEvents.cs new file mode 100644 index 0000000000..34e5518acd --- /dev/null +++ b/Content.Shared/AirlockPainter/AirlockPainterEvents.cs @@ -0,0 +1,32 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared.AirlockPainter +{ + [Serializable, NetSerializable] + public enum AirlockPainterUiKey + { + Key, + } + + [Serializable, NetSerializable] + public sealed class AirlockPainterSpritePickedMessage : BoundUserInterfaceMessage + { + public int Index { get; } + + public AirlockPainterSpritePickedMessage(int index) + { + Index = index; + } + } + + [Serializable, NetSerializable] + public sealed class AirlockPainterBoundUserInterfaceState : BoundUserInterfaceState + { + public int SelectedStyle { get; } + + public AirlockPainterBoundUserInterfaceState(int selectedStyle) + { + SelectedStyle = selectedStyle; + } + } +} diff --git a/Content.Shared/AirlockPainter/Components/PaintableAirlockComponent.cs b/Content.Shared/AirlockPainter/Components/PaintableAirlockComponent.cs new file mode 100644 index 0000000000..0453a0d081 --- /dev/null +++ b/Content.Shared/AirlockPainter/Components/PaintableAirlockComponent.cs @@ -0,0 +1,12 @@ +using Content.Shared.AirlockPainter.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Server.AirlockPainter +{ + [RegisterComponent] + public sealed class PaintableAirlockComponent : Component + { + [DataField("group", customTypeSerializer:typeof(PrototypeIdSerializer))] + public string Group = default!; + } +} diff --git a/Content.Shared/AirlockPainter/Prototypes/AirlockGroupPrototype.cs b/Content.Shared/AirlockPainter/Prototypes/AirlockGroupPrototype.cs new file mode 100644 index 0000000000..a7d8a15f2a --- /dev/null +++ b/Content.Shared/AirlockPainter/Prototypes/AirlockGroupPrototype.cs @@ -0,0 +1,20 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared.AirlockPainter.Prototypes +{ + [Prototype("AirlockGroup")] + public sealed class AirlockGroupPrototype : IPrototype + { + [IdDataField] + public string ID { get; } = default!; + + [DataField("stylePaths")] + public Dictionary StylePaths = default!; + + // The priority determines, which sprite is used when showing + // the icon for a style in the airlock painter UI. The highest priority + // gets shown. + [DataField("iconPriority")] + public int IconPriority = 0; + } +} diff --git a/Content.Shared/AirlockPainter/SharedAirlockPainterSystem.cs b/Content.Shared/AirlockPainter/SharedAirlockPainterSystem.cs new file mode 100644 index 0000000000..217ef59e04 --- /dev/null +++ b/Content.Shared/AirlockPainter/SharedAirlockPainterSystem.cs @@ -0,0 +1,30 @@ +using System.Linq; +using Content.Shared.AirlockPainter.Prototypes; +using Robust.Shared.Prototypes; + +namespace Content.Shared.AirlockPainter +{ + public abstract class SharedAirlockPainterSystem : EntitySystem + { + [Dependency] protected readonly IPrototypeManager _prototypeManager = default!; + + public List Styles { get; private set; } = new(); + public List Groups { get; private set; } = new(); + + public override void Initialize() + { + base.Initialize(); + + HashSet styles = new(); + foreach (AirlockGroupPrototype grp in _prototypeManager.EnumeratePrototypes()) + { + Groups.Add(grp); + foreach (string style in grp.StylePaths.Keys) + { + styles.Add(style); + } + } + Styles = styles.ToList(); + } + } +} diff --git a/Content.Shared/Doors/Components/DoorComponent.cs b/Content.Shared/Doors/Components/DoorComponent.cs index ad1850e5ed..5dd2e49636 100644 --- a/Content.Shared/Doors/Components/DoorComponent.cs +++ b/Content.Shared/Doors/Components/DoorComponent.cs @@ -249,6 +249,7 @@ public enum DoorVisuals Powered, BoltLights, EmergencyLights, + BaseRSI, } [Serializable, NetSerializable] diff --git a/Resources/Locale/en-US/airlock-painter/airlock-painter.ftl b/Resources/Locale/en-US/airlock-painter/airlock-painter.ftl new file mode 100644 index 0000000000..3fe6566868 --- /dev/null +++ b/Resources/Locale/en-US/airlock-painter/airlock-painter.ftl @@ -0,0 +1,3 @@ +airlock-painter-style-not-available = Cannot apply the selected style to this type of airlock +airlock-painter-window-title = Airlock painter +airlock-painter-selected-style = Selected style diff --git a/Resources/Prototypes/Entities/Objects/Tools/airlock_painter.yml b/Resources/Prototypes/Entities/Objects/Tools/airlock_painter.yml new file mode 100644 index 0000000000..760b871827 --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Tools/airlock_painter.yml @@ -0,0 +1,20 @@ +- type: entity + parent: BaseItem + id: AirlockPainter + name: airlock painter + description: An airlock painter for painting airlocks. + components: + - type: Sprite + sprite: Objects/Tools/airlock_painter.rsi + state: airlock_painter + netsync: false + - type: Item + sprite: Objects/Tools/airlock_painter.rsi + - type: UserInterface + interfaces: + - key: enum.AirlockPainterUiKey.Key + type: AirlockPainterBoundUserInterface + - type: AirlockPainter + whitelist: + tags: + - PaintableAirlock diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/airlocks.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/airlocks.yml index aeeb533f7f..13f714404d 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/airlocks.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/airlocks.yml @@ -97,7 +97,8 @@ layer: #removed opaque from the layer, allowing lasers to pass through glass airlocks - Impassable - VaultImpassable - + - type: PaintableAirlock + group: Windoor - type: entity parent: AirlockGlass @@ -106,6 +107,8 @@ components: - type: Sprite sprite: Structures/Doors/Airlocks/Glass/engineering.rsi + - type: PaintableAirlock + group: Glass - type: entity parent: AirlockGlass @@ -114,6 +117,8 @@ components: - type: Sprite sprite: Structures/Doors/Airlocks/Glass/cargo.rsi + - type: PaintableAirlock + group: Glass - type: entity parent: AirlockGlass @@ -122,6 +127,8 @@ components: - type: Sprite sprite: Structures/Doors/Airlocks/Glass/medical.rsi + - type: PaintableAirlock + group: Glass - type: entity parent: AirlockGlass @@ -130,6 +137,8 @@ components: - type: Sprite sprite: Structures/Doors/Airlocks/Glass/science.rsi + - type: PaintableAirlock + group: Glass - type: entity parent: AirlockGlass @@ -138,6 +147,8 @@ components: - type: Sprite sprite: Structures/Doors/Airlocks/Glass/command.rsi + - type: PaintableAirlock + group: Glass - type: entity parent: AirlockGlass @@ -146,3 +157,5 @@ components: - type: Sprite sprite: Structures/Doors/Airlocks/Glass/security.rsi + - type: PaintableAirlock + group: Glass diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml index 7954f67ee7..13333fc897 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml @@ -83,5 +83,7 @@ - type: IconSmooth key: walls mode: NoSprite + - type: PaintableAirlock + group: Standard placement: mode: SnapgridCenter diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/external.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/external.yml index 26e4bc9b96..ef22d221cc 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/external.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/external.yml @@ -21,6 +21,8 @@ visuals: - type: AirlockVisualizer - type: WiresVisualizer + - type: PaintableAirlock + group: External - type: entity parent: AirlockExternal @@ -30,4 +32,6 @@ - type: Occluder enabled: false - type: Sprite - sprite: Structures/Doors/Airlocks/Glass/external.rsi \ No newline at end of file + sprite: Structures/Doors/Airlocks/Glass/external.rsi + - type: PaintableAirlock + group: ExternalGlass diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/shuttle.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/shuttle.yml index 02ef306fb6..f141da935b 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/shuttle.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/shuttle.yml @@ -50,6 +50,8 @@ - type: Tag tags: - ForceNoFixRotations + - type: PaintableAirlock + group: Shuttle - type: entity id: AirlockGlassShuttle @@ -80,3 +82,5 @@ map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Occluder enabled: false + - type: PaintableAirlock + group: ShuttleGlass diff --git a/Resources/Prototypes/Entities/Structures/Doors/airlock_groups.yml b/Resources/Prototypes/Entities/Structures/Doors/airlock_groups.yml new file mode 100644 index 0000000000..8734b206b6 --- /dev/null +++ b/Resources/Prototypes/Entities/Structures/Doors/airlock_groups.yml @@ -0,0 +1,55 @@ +- type: AirlockGroup + id: Standard + iconPriority: 100 + stylePaths: + basic: Structures/Doors/Airlocks/Standard/basic.rsi + cargo: Structures/Doors/Airlocks/Standard/cargo.rsi + command: Structures/Doors/Airlocks/Standard/command.rsi + engineering: Structures/Doors/Airlocks/Standard/engineering.rsi + freezer: Structures/Doors/Airlocks/Standard/freezer.rsi + maintenance: Structures/Doors/Airlocks/Standard/maint.rsi + medical: Structures/Doors/Airlocks/Standard/medical.rsi + science: Structures/Doors/Airlocks/Standard/science.rsi + security: Structures/Doors/Airlocks/Standard/security.rsi + +- type: AirlockGroup + id: Glass + iconPriority: 90 + stylePaths: + basic: Structures/Doors/Airlocks/Glass/basic.rsi + command: Structures/Doors/Airlocks/Glass/command.rsi + science: Structures/Doors/Airlocks/Glass/science.rsi + cargo: Structures/Doors/Airlocks/Glass/cargo.rsi + engineering: Structures/Doors/Airlocks/Glass/engineering.rsi + medical: Structures/Doors/Airlocks/Glass/medical.rsi + security: Structures/Doors/Airlocks/Glass/security.rsi + +- type: AirlockGroup + id: Windoor + iconPriority: 80 + stylePaths: + basic: Structures/Doors/Airlocks/Glass/glass.rsi + +- type: AirlockGroup + id: External + iconPriority: 70 + stylePaths: + external: Structures/Doors/Airlocks/Standard/external.rsi + +- type: AirlockGroup + id: ExternalGlass + iconPriority: 60 + stylePaths: + external: Structures/Doors/Airlocks/Glass/external.rsi + +- type: AirlockGroup + id: Shuttle + iconPriority: 50 + stylePaths: + shuttle: Structures/Doors/Airlocks/Standard/shuttle.rsi + +- type: AirlockGroup + id: ShuttleGlass + iconPriority: 40 + stylePaths: + shuttle: Structures/Doors/Airlocks/Glass/shuttle.rsi diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index af86152f82..b917aa25a6 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -225,6 +225,9 @@ - type: Tag id: Payload # for grenade/bomb crafting +- type: Tag + id: PaintableAirlock + - type: Tag id: PercussionInstrument diff --git a/Resources/Textures/Objects/Tools/airlock_painter.rsi/airlock_painter.png b/Resources/Textures/Objects/Tools/airlock_painter.rsi/airlock_painter.png new file mode 100644 index 0000000000..462e22932c Binary files /dev/null and b/Resources/Textures/Objects/Tools/airlock_painter.rsi/airlock_painter.png differ diff --git a/Resources/Textures/Objects/Tools/airlock_painter.rsi/meta.json b/Resources/Textures/Objects/Tools/airlock_painter.rsi/meta.json new file mode 100644 index 0000000000..6312e9b261 --- /dev/null +++ b/Resources/Textures/Objects/Tools/airlock_painter.rsi/meta.json @@ -0,0 +1,14 @@ +{ + "copyright" : "Taken from https://github.com/tgstation/tgstation at commit a21274e56ae84b2c96e8b6beeca805df3d5402e8.", + "license" : "CC-BY-SA-3.0", + "size" : { + "x" : 32, + "y" : 32 + }, + "states" : [ + { + "name" : "airlock_painter" + } + ], + "version" : 1 +}