spray painter rework (#23287)
* refactor and add Department to PaintableAirlock, move it to server dir since its in namespace * add departments to doors, cleanup * add style -> departments mapping * AirlockDepartmentsPrototype * update shared spray stuff to have department * name file the same as the class name * department optional * refactor spray painter system + send department * fixy * client * no need to rewrite ActivateableUi * pro ops * the reckoning * hiss * . * :trollface: * add standard atmos colors to palette * Update Content.Shared/SprayPainter/SharedSprayPainterSystem.cs --------- Co-authored-by: deltanedas <@deltanedas:kde.org> Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
This commit is contained in:
@@ -14,29 +14,31 @@ public sealed class SprayPainterSystem : SharedSprayPainterSystem
|
|||||||
|
|
||||||
public List<SprayPainterEntry> Entries { get; private set; } = new();
|
public List<SprayPainterEntry> Entries { get; private set; } = new();
|
||||||
|
|
||||||
public override void Initialize()
|
protected override void CacheStyles()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.CacheStyles();
|
||||||
|
|
||||||
foreach (string style in Styles)
|
Entries.Clear();
|
||||||
|
foreach (var style in Styles)
|
||||||
{
|
{
|
||||||
|
var name = style.Name;
|
||||||
string? iconPath = Groups
|
string? iconPath = Groups
|
||||||
.FindAll(x => x.StylePaths.ContainsKey(style))?
|
.FindAll(x => x.StylePaths.ContainsKey(name))?
|
||||||
.MaxBy(x => x.IconPriority)?.StylePaths[style];
|
.MaxBy(x => x.IconPriority)?.StylePaths[name];
|
||||||
if (iconPath == null)
|
if (iconPath == null)
|
||||||
{
|
{
|
||||||
Entries.Add(new SprayPainterEntry(style, null));
|
Entries.Add(new SprayPainterEntry(name, null));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
RSIResource doorRsi = _resourceCache.GetResource<RSIResource>(SpriteSpecifierSerializer.TextureRoot / new ResPath(iconPath));
|
RSIResource doorRsi = _resourceCache.GetResource<RSIResource>(SpriteSpecifierSerializer.TextureRoot / new ResPath(iconPath));
|
||||||
if (!doorRsi.RSI.TryGetState("closed", out var icon))
|
if (!doorRsi.RSI.TryGetState("closed", out var icon))
|
||||||
{
|
{
|
||||||
Entries.Add(new SprayPainterEntry(style, null));
|
Entries.Add(new SprayPainterEntry(name, null));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entries.Add(new SprayPainterEntry(style, icon.Frame0));
|
Entries.Add(new SprayPainterEntry(name, icon.Frame0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Shared.SprayPainter;
|
using Content.Shared.SprayPainter;
|
||||||
|
using Content.Shared.SprayPainter.Components;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
|
||||||
@@ -20,14 +21,20 @@ public sealed class SprayPainterBoundUserInterface : BoundUserInterface
|
|||||||
{
|
{
|
||||||
base.Open();
|
base.Open();
|
||||||
|
|
||||||
|
if (!EntMan.TryGetComponent<SprayPainterComponent>(Owner, out var comp))
|
||||||
|
return;
|
||||||
|
|
||||||
_window = new SprayPainterWindow();
|
_window = new SprayPainterWindow();
|
||||||
|
|
||||||
_painter = EntMan.System<SprayPainterSystem>();
|
_painter = EntMan.System<SprayPainterSystem>();
|
||||||
|
|
||||||
_window.OpenCentered();
|
|
||||||
_window.OnClose += Close;
|
_window.OnClose += Close;
|
||||||
_window.OnSpritePicked = OnSpritePicked;
|
_window.OnSpritePicked = OnSpritePicked;
|
||||||
_window.OnColorPicked = OnColorPicked;
|
_window.OnColorPicked = OnColorPicked;
|
||||||
|
|
||||||
|
_window.Populate(_painter.Entries, comp.Index, comp.PickedColor, comp.ColorPalette);
|
||||||
|
|
||||||
|
_window.OpenCentered();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
@@ -37,25 +44,6 @@ public sealed class SprayPainterBoundUserInterface : BoundUserInterface
|
|||||||
_window?.Dispose();
|
_window?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateState(BoundUserInterfaceState state)
|
|
||||||
{
|
|
||||||
base.UpdateState(state);
|
|
||||||
|
|
||||||
if (_window == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_painter == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (state is not SprayPainterBoundUserInterfaceState stateCast)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_window.Populate(_painter.Entries,
|
|
||||||
stateCast.SelectedStyle,
|
|
||||||
stateCast.SelectedColorKey,
|
|
||||||
stateCast.Palette);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSpritePicked(ItemList.ItemListSelectedEventArgs args)
|
private void OnSpritePicked(ItemList.ItemListSelectedEventArgs args)
|
||||||
{
|
{
|
||||||
SendMessage(new SprayPainterSpritePickedMessage(args.ItemIndex));
|
SendMessage(new SprayPainterSpritePickedMessage(args.ItemIndex));
|
||||||
|
|||||||
@@ -1,186 +1,69 @@
|
|||||||
using System.Linq;
|
|
||||||
using Content.Server.Administration.Logs;
|
|
||||||
using Content.Server.Atmos.Piping.Components;
|
using Content.Server.Atmos.Piping.Components;
|
||||||
using Content.Server.Atmos.Piping.EntitySystems;
|
using Content.Server.Atmos.Piping.EntitySystems;
|
||||||
using Content.Server.Popups;
|
|
||||||
using Content.Shared.Database;
|
|
||||||
using Content.Shared.DoAfter;
|
using Content.Shared.DoAfter;
|
||||||
using Content.Shared.Doors.Components;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.SprayPainter;
|
using Content.Shared.SprayPainter;
|
||||||
using Content.Shared.SprayPainter.Components;
|
using Content.Shared.SprayPainter.Components;
|
||||||
using Content.Shared.SprayPainter.Prototypes;
|
|
||||||
using Content.Shared.Interaction;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Robust.Server.GameObjects;
|
|
||||||
using Robust.Shared.Audio;
|
|
||||||
using Robust.Shared.Audio.Systems;
|
|
||||||
using Robust.Shared.Player;
|
|
||||||
|
|
||||||
namespace Content.Server.SprayPainter;
|
namespace Content.Server.SprayPainter;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A system for painting airlocks and pipes using enginner painter
|
/// Handles spraying pipes using a spray painter.
|
||||||
|
/// Airlocks are handled in shared.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[UsedImplicitly]
|
|
||||||
public sealed class SprayPainterSystem : SharedSprayPainterSystem
|
public sealed class SprayPainterSystem : SharedSprayPainterSystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
[Dependency] private readonly AtmosPipeColorSystem _pipeColor = default!;
|
||||||
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
|
|
||||||
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
|
||||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
|
||||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
|
||||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
|
||||||
[Dependency] private readonly AtmosPipeColorSystem _pipeColorSystem = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<SprayPainterComponent, ComponentInit>(OnInit);
|
SubscribeLocalEvent<SprayPainterComponent, SprayPainterPipeDoAfterEvent>(OnPipeDoAfter);
|
||||||
SubscribeLocalEvent<SprayPainterComponent, AfterInteractEvent>(AfterInteractOn);
|
|
||||||
SubscribeLocalEvent<SprayPainterComponent, ActivateInWorldEvent>(OnActivate);
|
SubscribeLocalEvent<AtmosPipeColorComponent, InteractUsingEvent>(OnPipeInteract);
|
||||||
SubscribeLocalEvent<SprayPainterComponent, SprayPainterSpritePickedMessage>(OnSpritePicked);
|
|
||||||
SubscribeLocalEvent<SprayPainterComponent, SprayPainterColorPickedMessage>(OnColorPicked);
|
|
||||||
SubscribeLocalEvent<SprayPainterComponent, SprayPainterDoAfterEvent>(OnDoAfter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnInit(EntityUid uid, SprayPainterComponent component, ComponentInit args)
|
private void OnPipeDoAfter(Entity<SprayPainterComponent> ent, ref SprayPainterPipeDoAfterEvent args)
|
||||||
{
|
{
|
||||||
if (component.ColorPalette.Count == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
SetColor(uid, component, component.ColorPalette.First().Key);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDoAfter(EntityUid uid, SprayPainterComponent component, SprayPainterDoAfterEvent args)
|
|
||||||
{
|
|
||||||
component.IsSpraying = false;
|
|
||||||
|
|
||||||
if (args.Handled || args.Cancelled)
|
if (args.Handled || args.Cancelled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (args.Args.Target == null)
|
if (args.Args.Target is not {} target)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
EntityUid target = (EntityUid) args.Args.Target;
|
if (!TryComp<AtmosPipeColorComponent>(target, out var color))
|
||||||
|
return;
|
||||||
|
|
||||||
_audio.PlayPvs(component.SpraySound, uid);
|
Audio.PlayPvs(ent.Comp.SpraySound, ent);
|
||||||
|
|
||||||
if (TryComp<AtmosPipeColorComponent>(target, out var atmosPipeColorComp))
|
_pipeColor.SetColor(target, color, args.Color);
|
||||||
{
|
|
||||||
_pipeColorSystem.SetColor(target, atmosPipeColorComp, args.Color ?? Color.White);
|
|
||||||
} else { // Target is an airlock
|
|
||||||
if (args.Sprite != null)
|
|
||||||
{
|
|
||||||
_appearance.SetData(target, DoorVisuals.BaseRSI, args.Sprite);
|
|
||||||
_adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(args.Args.User):user} painted {ToPrettyString(args.Args.Target.Value):target}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnActivate(EntityUid uid, SprayPainterComponent component, ActivateInWorldEvent args)
|
private void OnPipeInteract(Entity<AtmosPipeColorComponent> ent, ref InteractUsingEvent args)
|
||||||
{
|
{
|
||||||
if (!EntityManager.TryGetComponent(args.User, out ActorComponent? actor))
|
if (args.Handled)
|
||||||
return;
|
|
||||||
DirtyUI(uid, component);
|
|
||||||
|
|
||||||
_userInterfaceSystem.TryOpen(uid, SprayPainterUiKey.Key, actor.PlayerSession);
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AfterInteractOn(EntityUid uid, SprayPainterComponent component, AfterInteractEvent args)
|
|
||||||
{
|
|
||||||
if (component.IsSpraying || args.Target is not { Valid: true } target || !args.CanReach)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (EntityManager.TryGetComponent<PaintableAirlockComponent>(target, out var airlock))
|
if (!TryComp<SprayPainterComponent>(args.Used, out var painter) || painter.PickedColor is not {} colorName)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!painter.ColorPalette.TryGetValue(colorName, out var color))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var doAfterEventArgs = new DoAfterArgs(EntityManager, args.User, painter.PipeSprayTime, new SprayPainterPipeDoAfterEvent(color), args.Used, target: ent, used: args.Used)
|
||||||
{
|
{
|
||||||
if (!_prototypeManager.TryIndex<AirlockGroupPrototype>(airlock.Group, out var grp))
|
BreakOnTargetMove = true,
|
||||||
{
|
BreakOnUserMove = true,
|
||||||
Log.Error("Group not defined: %s", airlock.Group);
|
BreakOnDamage = true,
|
||||||
return;
|
CancelDuplicate = true,
|
||||||
}
|
// multiple pipes can be sprayed at once just not the same one
|
||||||
|
DuplicateCondition = DuplicateConditions.SameTarget,
|
||||||
|
NeedHand = true
|
||||||
|
};
|
||||||
|
|
||||||
string style = Styles[component.Index];
|
args.Handled = DoAfter.TryStartDoAfter(doAfterEventArgs);
|
||||||
if (!grp.StylePaths.TryGetValue(style, out var sprite))
|
|
||||||
{
|
|
||||||
string msg = Loc.GetString("spray-painter-style-not-available");
|
|
||||||
_popupSystem.PopupEntity(msg, args.User, args.User);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
component.IsSpraying = true;
|
|
||||||
|
|
||||||
var doAfterEventArgs = new DoAfterArgs(EntityManager, args.User, component.AirlockSprayTime, new SprayPainterDoAfterEvent(sprite, null), uid, target: target, used: uid)
|
|
||||||
{
|
|
||||||
BreakOnTargetMove = true,
|
|
||||||
BreakOnUserMove = true,
|
|
||||||
BreakOnDamage = true,
|
|
||||||
NeedHand = true,
|
|
||||||
};
|
|
||||||
_doAfterSystem.TryStartDoAfter(doAfterEventArgs);
|
|
||||||
|
|
||||||
// Log attempt
|
|
||||||
_adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(args.User):user} is painting {ToPrettyString(uid):target} to '{style}' at {Transform(uid).Coordinates:targetlocation}");
|
|
||||||
} else { // Painting pipes
|
|
||||||
if(component.PickedColor is null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!EntityManager.HasComponent<AtmosPipeColorComponent>(target))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(!component.ColorPalette.TryGetValue(component.PickedColor, out var color))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var doAfterEventArgs = new DoAfterArgs(EntityManager, args.User, component.PipeSprayTime, new SprayPainterDoAfterEvent(null, color), uid, target, uid)
|
|
||||||
{
|
|
||||||
BreakOnTargetMove = true,
|
|
||||||
BreakOnUserMove = true,
|
|
||||||
BreakOnDamage = true,
|
|
||||||
CancelDuplicate = true,
|
|
||||||
DuplicateCondition = DuplicateConditions.SameTarget,
|
|
||||||
NeedHand = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
_doAfterSystem.TryStartDoAfter(doAfterEventArgs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnColorPicked(EntityUid uid, SprayPainterComponent component, SprayPainterColorPickedMessage args)
|
|
||||||
{
|
|
||||||
SetColor(uid, component, args.Key);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSpritePicked(EntityUid uid, SprayPainterComponent component, SprayPainterSpritePickedMessage args)
|
|
||||||
{
|
|
||||||
component.Index = args.Index;
|
|
||||||
DirtyUI(uid, component);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetColor(EntityUid uid, SprayPainterComponent component, string? paletteKey)
|
|
||||||
{
|
|
||||||
if (paletteKey == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!component.ColorPalette.ContainsKey(paletteKey) || paletteKey == component.PickedColor)
|
|
||||||
return;
|
|
||||||
|
|
||||||
component.PickedColor = paletteKey;
|
|
||||||
DirtyUI(uid, component);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DirtyUI(EntityUid uid, SprayPainterComponent? component = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(uid, ref component))
|
|
||||||
return;
|
|
||||||
|
|
||||||
_userInterfaceSystem.TrySetUiState(
|
|
||||||
uid,
|
|
||||||
SprayPainterUiKey.Key,
|
|
||||||
new SprayPainterBoundUserInterfaceState(
|
|
||||||
component.Index,
|
|
||||||
component.PickedColor,
|
|
||||||
component.ColorPalette));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,24 @@
|
|||||||
|
using Content.Shared.Roles;
|
||||||
using Content.Shared.SprayPainter.Prototypes;
|
using Content.Shared.SprayPainter.Prototypes;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Server.SprayPainter;
|
namespace Content.Shared.SprayPainter.Components;
|
||||||
|
|
||||||
[RegisterComponent]
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||||
public sealed partial class PaintableAirlockComponent : Component
|
public sealed partial class PaintableAirlockComponent : Component
|
||||||
{
|
{
|
||||||
[DataField("group", customTypeSerializer:typeof(PrototypeIdSerializer<AirlockGroupPrototype>))]
|
/// <summary>
|
||||||
public string Group = default!;
|
/// Group of styles this airlock can be painted with, e.g. glass, standard or external.
|
||||||
|
/// </summary>
|
||||||
|
[DataField(required: true), AutoNetworkedField]
|
||||||
|
public ProtoId<AirlockGroupPrototype> Group = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Department this airlock is painted as, or none.
|
||||||
|
/// Must be specified in prototypes for turf war to work.
|
||||||
|
/// To better catch any mistakes, you need to explicitly state a non-styled airlock has a null department.
|
||||||
|
/// </summary>
|
||||||
|
[DataField(required: true), AutoNetworkedField]
|
||||||
|
public ProtoId<DepartmentPrototype>? Department;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,44 @@
|
|||||||
|
using Content.Shared.DoAfter;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
namespace Content.Shared.SprayPainter.Components;
|
namespace Content.Shared.SprayPainter.Components;
|
||||||
|
|
||||||
[RegisterComponent, NetworkedComponent]
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||||
public sealed partial class SprayPainterComponent : Component
|
public sealed partial class SprayPainterComponent : Component
|
||||||
{
|
{
|
||||||
[DataField("spraySound")]
|
[DataField]
|
||||||
public SoundSpecifier SpraySound = new SoundPathSpecifier("/Audio/Effects/spray2.ogg");
|
public SoundSpecifier SpraySound = new SoundPathSpecifier("/Audio/Effects/spray2.ogg");
|
||||||
|
|
||||||
[DataField("airlockSprayTime")]
|
[DataField]
|
||||||
public float AirlockSprayTime = 3.0f;
|
public TimeSpan AirlockSprayTime = TimeSpan.FromSeconds(3);
|
||||||
|
|
||||||
[DataField("pipeSprayTime")]
|
[DataField]
|
||||||
public float PipeSprayTime = 1.0f;
|
public TimeSpan PipeSprayTime = TimeSpan.FromSeconds(1);
|
||||||
|
|
||||||
[DataField("isSpraying")]
|
/// <summary>
|
||||||
public bool IsSpraying = false;
|
/// DoAfterId for airlock spraying.
|
||||||
|
/// Pipes do not track doafters so you can spray multiple at once.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public DoAfterId? AirlockDoAfter;
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
/// <summary>
|
||||||
|
/// Pipe color chosen to spray with.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
public string? PickedColor;
|
public string? PickedColor;
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
/// <summary>
|
||||||
[DataField("colorPalette")]
|
/// Pipe colors that can be selected.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
public Dictionary<string, Color> ColorPalette = new();
|
public Dictionary<string, Color> ColorPalette = new();
|
||||||
|
|
||||||
public int Index = default!;
|
/// <summary>
|
||||||
|
/// Airlock style index selected.
|
||||||
|
/// After prototype reload this might not be the same style but it will never be out of bounds.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public int Index;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using Content.Shared.Roles;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Shared.SprayPainter.Prototypes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maps airlock style names to department ids.
|
||||||
|
/// </summary>
|
||||||
|
[Prototype("airlockDepartments")]
|
||||||
|
public sealed class AirlockDepartmentsPrototype : IPrototype
|
||||||
|
{
|
||||||
|
[IdDataField]
|
||||||
|
public string ID { get; private set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dictionary of style names to department ids.
|
||||||
|
/// If a style does not have a department (e.g. external) it is set to null.
|
||||||
|
/// </summary>
|
||||||
|
[DataField(required: true)]
|
||||||
|
public Dictionary<string, ProtoId<DepartmentPrototype>> Departments = new();
|
||||||
|
}
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
using Content.Shared.SprayPainter.Prototypes;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.Shared.SprayPainter;
|
|
||||||
|
|
||||||
public abstract class SharedSprayPainterSystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] protected readonly IPrototypeManager _prototypeManager = default!;
|
|
||||||
|
|
||||||
public List<string> Styles { get; private set; } = new();
|
|
||||||
public List<AirlockGroupPrototype> Groups { get; private set; } = new();
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
SortedSet<string> styles = new();
|
|
||||||
foreach (AirlockGroupPrototype grp in _prototypeManager.EnumeratePrototypes<AirlockGroupPrototype>())
|
|
||||||
{
|
|
||||||
Groups.Add(grp);
|
|
||||||
foreach (string style in grp.StylePaths.Keys)
|
|
||||||
{
|
|
||||||
styles.Add(style);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Styles = styles.ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
202
Content.Shared/SprayPainter/SharedSprayPainterSystem.cs
Normal file
202
Content.Shared/SprayPainter/SharedSprayPainterSystem.cs
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
using Content.Shared.Administration.Logs;
|
||||||
|
using Content.Shared.Database;
|
||||||
|
using Content.Shared.DoAfter;
|
||||||
|
using Content.Shared.Doors.Components;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
|
using Content.Shared.Popups;
|
||||||
|
using Content.Shared.SprayPainter.Components;
|
||||||
|
using Content.Shared.SprayPainter.Prototypes;
|
||||||
|
using Robust.Shared.Audio.Systems;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Content.Shared.SprayPainter;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// System for painting airlocks using a spray painter.
|
||||||
|
/// Pipes are handled serverside since AtmosPipeColorSystem is server only.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class SharedSprayPainterSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] protected readonly IPrototypeManager Proto = default!;
|
||||||
|
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||||
|
[Dependency] protected readonly SharedAppearanceSystem Appearance = default!;
|
||||||
|
[Dependency] protected readonly SharedAudioSystem Audio = default!;
|
||||||
|
[Dependency] protected readonly SharedDoAfterSystem DoAfter = default!;
|
||||||
|
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||||
|
[Dependency] private readonly SharedUserInterfaceSystem _ui = default!;
|
||||||
|
|
||||||
|
public List<AirlockStyle> Styles { get; private set; } = new();
|
||||||
|
public List<AirlockGroupPrototype> Groups { get; private set; } = new();
|
||||||
|
|
||||||
|
[ValidatePrototypeId<AirlockDepartmentsPrototype>]
|
||||||
|
private const string Departments = "Departments";
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
CacheStyles();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<SprayPainterComponent, MapInitEvent>(OnMapInit);
|
||||||
|
SubscribeLocalEvent<SprayPainterComponent, SprayPainterDoorDoAfterEvent>(OnDoorDoAfter);
|
||||||
|
Subs.BuiEvents<SprayPainterComponent>(SprayPainterUiKey.Key, subs =>
|
||||||
|
{
|
||||||
|
subs.Event<SprayPainterSpritePickedMessage>(OnSpritePicked);
|
||||||
|
subs.Event<SprayPainterColorPickedMessage>(OnColorPicked);
|
||||||
|
});
|
||||||
|
|
||||||
|
SubscribeLocalEvent<PaintableAirlockComponent, InteractUsingEvent>(OnAirlockInteract);
|
||||||
|
|
||||||
|
SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnPrototypesReloaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMapInit(Entity<SprayPainterComponent> ent, ref MapInitEvent args)
|
||||||
|
{
|
||||||
|
if (ent.Comp.ColorPalette.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SetColor(ent, ent.Comp.ColorPalette.First().Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDoorDoAfter(Entity<SprayPainterComponent> ent, ref SprayPainterDoorDoAfterEvent args)
|
||||||
|
{
|
||||||
|
ent.Comp.AirlockDoAfter = null;
|
||||||
|
|
||||||
|
if (args.Handled || args.Cancelled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (args.Args.Target is not {} target)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryComp<PaintableAirlockComponent>(target, out var airlock))
|
||||||
|
return;
|
||||||
|
|
||||||
|
airlock.Department = args.Department;
|
||||||
|
Dirty(target, airlock);
|
||||||
|
|
||||||
|
Audio.PlayPredicted(ent.Comp.SpraySound, ent, args.Args.User);
|
||||||
|
Appearance.SetData(target, DoorVisuals.BaseRSI, args.Sprite);
|
||||||
|
_adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(args.Args.User):user} painted {ToPrettyString(args.Args.Target.Value):target}");
|
||||||
|
|
||||||
|
args.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region UI messages
|
||||||
|
|
||||||
|
private void OnColorPicked(Entity<SprayPainterComponent> ent, ref SprayPainterColorPickedMessage args)
|
||||||
|
{
|
||||||
|
SetColor(ent, args.Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSpritePicked(Entity<SprayPainterComponent> ent, ref SprayPainterSpritePickedMessage args)
|
||||||
|
{
|
||||||
|
if (args.Index >= Styles.Count)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ent.Comp.Index = args.Index;
|
||||||
|
Dirty(ent, ent.Comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetColor(Entity<SprayPainterComponent> ent, string? paletteKey)
|
||||||
|
{
|
||||||
|
if (paletteKey == null || paletteKey == ent.Comp.PickedColor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!ent.Comp.ColorPalette.ContainsKey(paletteKey))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ent.Comp.PickedColor = paletteKey;
|
||||||
|
Dirty(ent, ent.Comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private void OnAirlockInteract(Entity<PaintableAirlockComponent> ent, ref InteractUsingEvent args)
|
||||||
|
{
|
||||||
|
if (args.Handled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryComp<SprayPainterComponent>(args.Used, out var painter) || painter.AirlockDoAfter != null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var group = Proto.Index<AirlockGroupPrototype>(ent.Comp.Group);
|
||||||
|
|
||||||
|
var style = Styles[painter.Index];
|
||||||
|
if (!group.StylePaths.TryGetValue(style.Name, out var sprite))
|
||||||
|
{
|
||||||
|
string msg = Loc.GetString("spray-painter-style-not-available");
|
||||||
|
_popup.PopupEntity(msg, args.User, args.User);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var doAfterEventArgs = new DoAfterArgs(EntityManager, args.User, painter.AirlockSprayTime, new SprayPainterDoorDoAfterEvent(sprite, style.Department), args.Used, target: ent, used: args.Used)
|
||||||
|
{
|
||||||
|
BreakOnTargetMove = true,
|
||||||
|
BreakOnUserMove = true,
|
||||||
|
BreakOnDamage = true,
|
||||||
|
NeedHand = true
|
||||||
|
};
|
||||||
|
if (!DoAfter.TryStartDoAfter(doAfterEventArgs, out var id))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// since we are now spraying an airlock prevent spraying more at the same time
|
||||||
|
// pipes ignore this
|
||||||
|
painter.AirlockDoAfter = id;
|
||||||
|
args.Handled = true;
|
||||||
|
|
||||||
|
// Log the attempt
|
||||||
|
_adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(args.User):user} is painting {ToPrettyString(ent):target} to '{style.Name}' at {Transform(ent).Coordinates:targetlocation}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Style caching
|
||||||
|
|
||||||
|
private void OnPrototypesReloaded(PrototypesReloadedEventArgs args)
|
||||||
|
{
|
||||||
|
if (!args.WasModified<AirlockGroupPrototype>() && !args.WasModified<AirlockDepartmentsPrototype>())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Styles.Clear();
|
||||||
|
Groups.Clear();
|
||||||
|
CacheStyles();
|
||||||
|
|
||||||
|
// style index might be invalid now so check them all
|
||||||
|
var max = Styles.Count - 1;
|
||||||
|
var query = AllEntityQuery<SprayPainterComponent>();
|
||||||
|
while (query.MoveNext(out var uid, out var comp))
|
||||||
|
{
|
||||||
|
if (comp.Index > max)
|
||||||
|
{
|
||||||
|
comp.Index = max;
|
||||||
|
Dirty(uid, comp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void CacheStyles()
|
||||||
|
{
|
||||||
|
// collect every style's name
|
||||||
|
var names = new SortedSet<string>();
|
||||||
|
foreach (var group in Proto.EnumeratePrototypes<AirlockGroupPrototype>())
|
||||||
|
{
|
||||||
|
Groups.Add(group);
|
||||||
|
foreach (var style in group.StylePaths.Keys)
|
||||||
|
{
|
||||||
|
names.Add(style);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get their department ids too for the final style list
|
||||||
|
var departments = Proto.Index<AirlockDepartmentsPrototype>(Departments);
|
||||||
|
Styles.Capacity = names.Count;
|
||||||
|
foreach (var name in names)
|
||||||
|
{
|
||||||
|
departments.Departments.TryGetValue(name, out var department);
|
||||||
|
Styles.Add(new AirlockStyle(name, department));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
public record struct AirlockStyle(string Name, string? Department);
|
||||||
@@ -12,7 +12,7 @@ public enum SprayPainterUiKey
|
|||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public sealed class SprayPainterSpritePickedMessage : BoundUserInterfaceMessage
|
public sealed class SprayPainterSpritePickedMessage : BoundUserInterfaceMessage
|
||||||
{
|
{
|
||||||
public int Index { get; }
|
public readonly int Index;
|
||||||
|
|
||||||
public SprayPainterSpritePickedMessage(int index)
|
public SprayPainterSpritePickedMessage(int index)
|
||||||
{
|
{
|
||||||
@@ -23,7 +23,7 @@ public sealed class SprayPainterSpritePickedMessage : BoundUserInterfaceMessage
|
|||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public sealed class SprayPainterColorPickedMessage : BoundUserInterfaceMessage
|
public sealed class SprayPainterColorPickedMessage : BoundUserInterfaceMessage
|
||||||
{
|
{
|
||||||
public string? Key { get; }
|
public readonly string? Key;
|
||||||
|
|
||||||
public SprayPainterColorPickedMessage(string? key)
|
public SprayPainterColorPickedMessage(string? key)
|
||||||
{
|
{
|
||||||
@@ -32,36 +32,40 @@ public sealed class SprayPainterColorPickedMessage : BoundUserInterfaceMessage
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public sealed class SprayPainterBoundUserInterfaceState : BoundUserInterfaceState
|
public sealed partial class SprayPainterDoorDoAfterEvent : DoAfterEvent
|
||||||
{
|
{
|
||||||
public int SelectedStyle { get; }
|
/// <summary>
|
||||||
public string? SelectedColorKey { get; }
|
/// Base RSI path to set for the door sprite.
|
||||||
public Dictionary<string, Color> Palette { get; }
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public string Sprite;
|
||||||
|
|
||||||
public SprayPainterBoundUserInterfaceState(int selectedStyle, string? selectedColorKey, Dictionary<string, Color> palette)
|
/// <summary>
|
||||||
|
/// Department id to set for the door, if the style has one.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public string? Department;
|
||||||
|
|
||||||
|
public SprayPainterDoorDoAfterEvent(string sprite, string? department)
|
||||||
{
|
{
|
||||||
SelectedStyle = selectedStyle;
|
Sprite = sprite;
|
||||||
SelectedColorKey = selectedColorKey;
|
Department = department;
|
||||||
Palette = palette;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override DoAfterEvent Clone() => this;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public sealed partial class SprayPainterDoAfterEvent : DoAfterEvent
|
public sealed partial class SprayPainterPipeDoAfterEvent : DoAfterEvent
|
||||||
{
|
{
|
||||||
[DataField("sprite")]
|
/// <summary>
|
||||||
public string? Sprite = null;
|
/// Color of the pipe to set.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public Color Color;
|
||||||
|
|
||||||
[DataField("color")]
|
public SprayPainterPipeDoAfterEvent(Color color)
|
||||||
public Color? Color = null;
|
|
||||||
|
|
||||||
private SprayPainterDoAfterEvent()
|
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
public SprayPainterDoAfterEvent(string? sprite, Color? color)
|
|
||||||
{
|
|
||||||
Sprite = sprite;
|
|
||||||
Color = color;
|
Color = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,24 +4,31 @@
|
|||||||
name: spray painter
|
name: spray painter
|
||||||
description: A spray painter for painting airlocks and pipes.
|
description: A spray painter for painting airlocks and pipes.
|
||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Tools/spray_painter.rsi
|
sprite: Objects/Tools/spray_painter.rsi
|
||||||
state: spray_painter
|
state: spray_painter
|
||||||
- type: Item
|
- type: Item
|
||||||
sprite: Objects/Tools/spray_painter.rsi
|
sprite: Objects/Tools/spray_painter.rsi
|
||||||
- type: UserInterface
|
- type: ActivatableUI
|
||||||
interfaces:
|
key: enum.SprayPainterUiKey.Key
|
||||||
- key: enum.SprayPainterUiKey.Key
|
- type: UserInterface
|
||||||
type: SprayPainterBoundUserInterface
|
interfaces:
|
||||||
- type: SprayPainter
|
- key: enum.SprayPainterUiKey.Key
|
||||||
colorPalette:
|
type: SprayPainterBoundUserInterface
|
||||||
red: '#FF1212FF'
|
- type: SprayPainter
|
||||||
yellow: '#B3A234FF'
|
colorPalette:
|
||||||
brown: '#947507FF'
|
red: '#FF1212FF'
|
||||||
green: '#3AB334FF'
|
yellow: '#B3A234FF'
|
||||||
cyan: '#03FCD3FF'
|
brown: '#947507FF'
|
||||||
blue: '#0335FCFF'
|
green: '#3AB334FF'
|
||||||
white: '#FFFFFFFF'
|
cyan: '#03FCD3FF'
|
||||||
black: '#333333FF'
|
blue: '#0335FCFF'
|
||||||
- type: StaticPrice
|
white: '#FFFFFFFF'
|
||||||
price: 40
|
black: '#333333FF'
|
||||||
|
# standard atmos pipes
|
||||||
|
waste: '#990000'
|
||||||
|
distro: '#0055cc'
|
||||||
|
air: '#03fcd3'
|
||||||
|
mix: '#947507'
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 40
|
||||||
|
|||||||
@@ -13,9 +13,11 @@
|
|||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Structures/Doors/Airlocks/Standard/engineering.rsi
|
sprite: Structures/Doors/Airlocks/Standard/engineering.rsi
|
||||||
|
- type: PaintableAirlock
|
||||||
|
department: Engineering
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: Airlock
|
parent: AirlockEngineering
|
||||||
id: AirlockAtmospherics
|
id: AirlockAtmospherics
|
||||||
suffix: Atmospherics
|
suffix: Atmospherics
|
||||||
components:
|
components:
|
||||||
@@ -29,6 +31,8 @@
|
|||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Structures/Doors/Airlocks/Standard/cargo.rsi
|
sprite: Structures/Doors/Airlocks/Standard/cargo.rsi
|
||||||
|
- type: PaintableAirlock
|
||||||
|
department: Cargo
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: Airlock
|
parent: Airlock
|
||||||
@@ -37,9 +41,11 @@
|
|||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Structures/Doors/Airlocks/Standard/medical.rsi
|
sprite: Structures/Doors/Airlocks/Standard/medical.rsi
|
||||||
|
- type: PaintableAirlock
|
||||||
|
department: Medical
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: Airlock
|
parent: AirlockMedical
|
||||||
id: AirlockVirology
|
id: AirlockVirology
|
||||||
suffix: Virology
|
suffix: Virology
|
||||||
components:
|
components:
|
||||||
@@ -47,12 +53,9 @@
|
|||||||
sprite: Structures/Doors/Airlocks/Standard/virology.rsi
|
sprite: Structures/Doors/Airlocks/Standard/virology.rsi
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: Airlock
|
parent: AirlockMedical
|
||||||
id: AirlockChemistry
|
id: AirlockChemistry
|
||||||
suffix: Chemistry
|
suffix: Chemistry
|
||||||
components:
|
|
||||||
- type: Sprite
|
|
||||||
sprite: Structures/Doors/Airlocks/Standard/medical.rsi
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: Airlock
|
parent: Airlock
|
||||||
@@ -61,6 +64,8 @@
|
|||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Structures/Doors/Airlocks/Standard/science.rsi
|
sprite: Structures/Doors/Airlocks/Standard/science.rsi
|
||||||
|
- type: PaintableAirlock
|
||||||
|
department: Science
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: Airlock
|
parent: Airlock
|
||||||
@@ -71,6 +76,8 @@
|
|||||||
sprite: Structures/Doors/Airlocks/Standard/command.rsi
|
sprite: Structures/Doors/Airlocks/Standard/command.rsi
|
||||||
- type: WiresPanelSecurity
|
- type: WiresPanelSecurity
|
||||||
securityLevel: medSecurity
|
securityLevel: medSecurity
|
||||||
|
- type: PaintableAirlock
|
||||||
|
department: Command
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: Airlock
|
parent: Airlock
|
||||||
@@ -79,6 +86,8 @@
|
|||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Structures/Doors/Airlocks/Standard/security.rsi
|
sprite: Structures/Doors/Airlocks/Standard/security.rsi
|
||||||
|
- type: PaintableAirlock
|
||||||
|
department: Security
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: Airlock
|
parent: Airlock
|
||||||
@@ -89,7 +98,7 @@
|
|||||||
sprite: Structures/Doors/Airlocks/Standard/maint.rsi
|
sprite: Structures/Doors/Airlocks/Standard/maint.rsi
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: Airlock
|
parent: AirlockSecurity # if you get syndie door somehow it counts as sec
|
||||||
id: AirlockSyndicate
|
id: AirlockSyndicate
|
||||||
suffix: Syndicate
|
suffix: Syndicate
|
||||||
components:
|
components:
|
||||||
@@ -97,7 +106,7 @@
|
|||||||
sprite: Structures/Doors/Airlocks/Standard/syndicate.rsi
|
sprite: Structures/Doors/Airlocks/Standard/syndicate.rsi
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: Airlock
|
parent: AirlockCargo
|
||||||
id: AirlockMining
|
id: AirlockMining
|
||||||
suffix: Mining(Salvage)
|
suffix: Mining(Salvage)
|
||||||
components:
|
components:
|
||||||
@@ -105,14 +114,12 @@
|
|||||||
sprite: Structures/Doors/Airlocks/Standard/mining.rsi
|
sprite: Structures/Doors/Airlocks/Standard/mining.rsi
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: Airlock
|
parent: AirlockCommand # if you get centcom door somehow it counts as command, also inherit panel
|
||||||
id: AirlockCentralCommand
|
id: AirlockCentralCommand
|
||||||
suffix: Central Command
|
suffix: Central Command
|
||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Structures/Doors/Airlocks/Standard/centcomm.rsi
|
sprite: Structures/Doors/Airlocks/Standard/centcomm.rsi
|
||||||
- type: WiresPanelSecurity
|
|
||||||
securityLevel: medSecurity
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: Airlock
|
parent: Airlock
|
||||||
@@ -181,7 +188,7 @@
|
|||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Structures/Doors/Airlocks/Glass/engineering.rsi
|
sprite: Structures/Doors/Airlocks/Glass/engineering.rsi
|
||||||
- type: PaintableAirlock
|
- type: PaintableAirlock
|
||||||
group: Glass
|
department: Engineering
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: AirlockGlass
|
parent: AirlockGlass
|
||||||
@@ -190,18 +197,14 @@
|
|||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Structures/Doors/Airlocks/Glass/maint.rsi
|
sprite: Structures/Doors/Airlocks/Glass/maint.rsi
|
||||||
- type: PaintableAirlock
|
|
||||||
group: Glass
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: AirlockGlass
|
parent: AirlockEngineeringGlass
|
||||||
id: AirlockAtmosphericsGlass
|
id: AirlockAtmosphericsGlass
|
||||||
suffix: Atmospherics
|
suffix: Atmospherics
|
||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Structures/Doors/Airlocks/Glass/atmospherics.rsi
|
sprite: Structures/Doors/Airlocks/Glass/atmospherics.rsi
|
||||||
- type: PaintableAirlock
|
|
||||||
group: Glass
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: AirlockGlass
|
parent: AirlockGlass
|
||||||
@@ -211,17 +214,7 @@
|
|||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Structures/Doors/Airlocks/Glass/cargo.rsi
|
sprite: Structures/Doors/Airlocks/Glass/cargo.rsi
|
||||||
- type: PaintableAirlock
|
- type: PaintableAirlock
|
||||||
group: Glass
|
department: Cargo
|
||||||
|
|
||||||
- type: entity
|
|
||||||
parent: AirlockGlass
|
|
||||||
id: AirlockChemistryGlass
|
|
||||||
suffix: Chemistry
|
|
||||||
components:
|
|
||||||
- type: Sprite
|
|
||||||
sprite: Structures/Doors/Airlocks/Glass/medical.rsi
|
|
||||||
- type: PaintableAirlock
|
|
||||||
group: Glass
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: AirlockGlass
|
parent: AirlockGlass
|
||||||
@@ -231,17 +224,20 @@
|
|||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Structures/Doors/Airlocks/Glass/medical.rsi
|
sprite: Structures/Doors/Airlocks/Glass/medical.rsi
|
||||||
- type: PaintableAirlock
|
- type: PaintableAirlock
|
||||||
group: Glass
|
department: Medical
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: AirlockGlass
|
parent: AirlockMedicalGlass
|
||||||
|
id: AirlockChemistryGlass
|
||||||
|
suffix: Chemistry
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: AirlockMedicalGlass
|
||||||
id: AirlockVirologyGlass
|
id: AirlockVirologyGlass
|
||||||
suffix: Virology
|
suffix: Virology
|
||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Structures/Doors/Airlocks/Glass/virology.rsi
|
sprite: Structures/Doors/Airlocks/Glass/virology.rsi
|
||||||
- type: PaintableAirlock
|
|
||||||
group: Glass
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: AirlockGlass
|
parent: AirlockGlass
|
||||||
@@ -251,7 +247,7 @@
|
|||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Structures/Doors/Airlocks/Glass/science.rsi
|
sprite: Structures/Doors/Airlocks/Glass/science.rsi
|
||||||
- type: PaintableAirlock
|
- type: PaintableAirlock
|
||||||
group: Glass
|
department: Science
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: AirlockGlass
|
parent: AirlockGlass
|
||||||
@@ -261,7 +257,7 @@
|
|||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Structures/Doors/Airlocks/Glass/command.rsi
|
sprite: Structures/Doors/Airlocks/Glass/command.rsi
|
||||||
- type: PaintableAirlock
|
- type: PaintableAirlock
|
||||||
group: Glass
|
department: Command
|
||||||
- type: WiresPanelSecurity
|
- type: WiresPanelSecurity
|
||||||
securityLevel: medSecurity
|
securityLevel: medSecurity
|
||||||
|
|
||||||
@@ -273,20 +269,18 @@
|
|||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Structures/Doors/Airlocks/Glass/security.rsi
|
sprite: Structures/Doors/Airlocks/Glass/security.rsi
|
||||||
- type: PaintableAirlock
|
- type: PaintableAirlock
|
||||||
group: Glass
|
department: Security
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: AirlockGlass
|
parent: AirlockSecurityGlass # see standard
|
||||||
id: AirlockSyndicateGlass
|
id: AirlockSyndicateGlass
|
||||||
suffix: Syndicate
|
suffix: Syndicate
|
||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Structures/Doors/Airlocks/Glass/syndicate.rsi
|
sprite: Structures/Doors/Airlocks/Glass/syndicate.rsi
|
||||||
- type: PaintableAirlock
|
|
||||||
group: Glass
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: AirlockGlass
|
parent: AirlockCargoGlass
|
||||||
id: AirlockMiningGlass
|
id: AirlockMiningGlass
|
||||||
suffix: Mining(Salvage)
|
suffix: Mining(Salvage)
|
||||||
components:
|
components:
|
||||||
@@ -294,7 +288,7 @@
|
|||||||
sprite: Structures/Doors/Airlocks/Glass/mining.rsi
|
sprite: Structures/Doors/Airlocks/Glass/mining.rsi
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: AirlockGlass
|
parent: AirlockCommandGlass # see standard
|
||||||
id: AirlockCentralCommandGlass
|
id: AirlockCentralCommandGlass
|
||||||
suffix: Central Command
|
suffix: Central Command
|
||||||
components:
|
components:
|
||||||
@@ -302,4 +296,3 @@
|
|||||||
sprite: Structures/Doors/Airlocks/Glass/centcomm.rsi
|
sprite: Structures/Doors/Airlocks/Glass/centcomm.rsi
|
||||||
- type: WiresPanelSecurity
|
- type: WiresPanelSecurity
|
||||||
securityLevel: medSecurity
|
securityLevel: medSecurity
|
||||||
|
|
||||||
|
|||||||
@@ -134,6 +134,7 @@
|
|||||||
mode: NoSprite
|
mode: NoSprite
|
||||||
- type: PaintableAirlock
|
- type: PaintableAirlock
|
||||||
group: Standard
|
group: Standard
|
||||||
|
department: Civilian
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
- type: StaticPrice
|
- type: StaticPrice
|
||||||
price: 150
|
price: 150
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
sprite: Structures/Doors/Airlocks/Standard/external.rsi
|
sprite: Structures/Doors/Airlocks/Standard/external.rsi
|
||||||
- type: PaintableAirlock
|
- type: PaintableAirlock
|
||||||
group: External
|
group: External
|
||||||
|
department: null
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: AirlockExternal
|
parent: AirlockExternal
|
||||||
|
|||||||
@@ -64,6 +64,7 @@
|
|||||||
- ForceNoFixRotations
|
- ForceNoFixRotations
|
||||||
- type: PaintableAirlock
|
- type: PaintableAirlock
|
||||||
group: Shuttle
|
group: Shuttle
|
||||||
|
department: null
|
||||||
- type: Construction
|
- type: Construction
|
||||||
graph: AirlockShuttle
|
graph: AirlockShuttle
|
||||||
node: airlock
|
node: airlock
|
||||||
|
|||||||
@@ -58,3 +58,19 @@
|
|||||||
iconPriority: 40
|
iconPriority: 40
|
||||||
stylePaths:
|
stylePaths:
|
||||||
shuttle: Structures/Doors/Airlocks/Glass/shuttle.rsi
|
shuttle: Structures/Doors/Airlocks/Glass/shuttle.rsi
|
||||||
|
|
||||||
|
# fun
|
||||||
|
- type: airlockDepartments
|
||||||
|
id: Departments
|
||||||
|
departments:
|
||||||
|
atmospherics: Engineering
|
||||||
|
basic: Civilian
|
||||||
|
cargo: Cargo
|
||||||
|
command: Command
|
||||||
|
engineering: Engineering
|
||||||
|
freezer: Civilian
|
||||||
|
maintenance: Civilian
|
||||||
|
medical: Medical
|
||||||
|
science: Science
|
||||||
|
security: Security
|
||||||
|
virology: Medical
|
||||||
|
|||||||
Reference in New Issue
Block a user