diff --git a/.vscode/launch.json b/.vscode/launch.json index 5390b914093..1d339fc7a1c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -52,4 +52,4 @@ "preLaunchTask": "build" } ] -} \ No newline at end of file +} diff --git a/Content.Client/Atmos/AlignAtmosPipeLayers.cs b/Content.Client/Atmos/AlignAtmosPipeLayers.cs index c8e69bc17f6..ff20680e396 100644 --- a/Content.Client/Atmos/AlignAtmosPipeLayers.cs +++ b/Content.Client/Atmos/AlignAtmosPipeLayers.cs @@ -1,12 +1,15 @@ using Content.Client.Construction; +using Content.Client.Hands.Systems; // WL-Changes: RPD using Content.Shared.Atmos.Components; using Content.Shared.Atmos.EntitySystems; using Content.Shared.Construction.Prototypes; +using Content.Shared.RCD; // WL-Changes: RPD +using Content.Shared.RCD.Components; // WL-Changes: RPD using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Client.Placement; using Robust.Client.Placement.Modes; -using Robust.Client.Utility; +using Robust.Client.Player; // WL-Changes: RPD using Robust.Shared.Enums; using Robust.Shared.Map; using Robust.Shared.Map.Components; @@ -29,11 +32,13 @@ public sealed partial class AlignAtmosPipeLayers : SnapgridCenter [Dependency] private IPrototypeManager _protoManager = default!; [Dependency] private IMapManager _mapManager = default!; [Dependency] private IEyeManager _eyeManager = default!; + [Dependency] private IPlayerManager _playerManager = default!; // WL-Changes: pipe layers RPD private readonly SharedMapSystem _mapSystem; private readonly SharedTransformSystem _transformSystem; private readonly SharedAtmosPipeLayersSystem _pipeLayersSystem; private readonly SpriteSystem _spriteSystem; + private readonly HandsSystem _handsSystem; // WL-Changes: pipe layers RPD private const float SearchBoxSize = 2f; private EntityCoordinates _unalignedMouseCoords = default; @@ -51,6 +56,7 @@ public AlignAtmosPipeLayers(PlacementManager pMan) : base(pMan) _transformSystem = _entityManager.System(); _pipeLayersSystem = _entityManager.System(); _spriteSystem = _entityManager.System(); + _handsSystem = _entityManager.System(); // WL-Changes: pipe layers RPD } /// @@ -172,14 +178,39 @@ private void UpdatePlacer(AtmosPipeLayer layer) if (!currentProto.TryGetComponent(out var atmosPipeLayers, _entityManager.ComponentFactory)) return; + // WL-Changes-start: pipe layers + Entity? rcd = null; + + if (_playerManager.LocalSession?.AttachedEntity is { } player + && _handsSystem.TryGetActiveItem(player, out var item) + && _entityManager.TryGetComponent(item, out var rcdComp)) + { + rcd = (item.Value, rcdComp); + } + if (!_pipeLayersSystem.TryGetAlternativePrototype(atmosPipeLayers, layer, out var newProtoId)) + { + if (rcd is { } rcdEnt + && rcdEnt.Comp.OverrideProtoId != null) // don't dirty if it already null + _entityManager.RaisePredictiveEvent(new RCDOverrideProtoIdEvent(_entityManager.GetNetEntity(rcd.Value.Owner), null)); return; + } + // WL-Changes-end if (_protoManager.TryIndex(newProtoId, out var newProto)) { // Update the placed prototype pManager.CurrentPermission.EntityType = newProtoId; + // WL-Changes-start: RPD pipe layers + if (rcd is { } rcdEnt + && rcdEnt.Comp.OverrideProtoId != (string?)newProtoId) + { + rcdEnt.Comp.OverrideProtoId = newProtoId; + _entityManager.RaisePredictiveEvent(new RCDOverrideProtoIdEvent(_entityManager.GetNetEntity(rcdEnt.Owner), newProtoId)); + } + // WL-Changes-end + // Update the appearance of the ghost sprite if (newProto.TryGetComponent(out var sprite, _entityManager.ComponentFactory)) { diff --git a/Content.Client/RCD/AlignRCDConstruction.cs b/Content.Client/RCD/AlignRCDConstruction.cs index ee7411a6de0..03746a0b879 100644 --- a/Content.Client/RCD/AlignRCDConstruction.cs +++ b/Content.Client/RCD/AlignRCDConstruction.cs @@ -1,15 +1,19 @@ using System.Numerics; +using Content.Client.Atmos; // WL-Changes: RPD using Content.Client.Gameplay; using Content.Client.Hands.Systems; -using Content.Shared.Hands.Components; +using Content.Shared.Atmos.Components; // WL-Changes: RPD using Content.Shared.Interaction; +using Content.Shared.RCD; // WL-Changes: RPD using Content.Shared.RCD.Components; using Content.Shared.RCD.Systems; +using Robust.Client.Graphics; // WL-Changes: RPD using Robust.Client.Placement; using Robust.Client.Player; using Robust.Client.State; using Robust.Shared.Map; using Robust.Shared.Map.Components; +using Robust.Shared.Prototypes; // WL-Changes: RPD namespace Content.Client.RCD; @@ -17,12 +21,16 @@ public sealed partial class AlignRCDConstruction : PlacementMode { [Dependency] private IEntityManager _entityManager = default!; [Dependency] private IMapManager _mapManager = default!; + // WL-Changes-start: pipe layers RPD + [Dependency] private IPlayerManager _playerManager = default!; + [Dependency] private IStateManager _stateManager = default!; + [Dependency] private IPrototypeManager _protoManager = default!; + // WL-Changes-end private readonly SharedMapSystem _mapSystem; private readonly HandsSystem _handsSystem; private readonly RCDSystem _rcdSystem; private readonly SharedTransformSystem _transformSystem; - [Dependency] private IPlayerManager _playerManager = default!; - [Dependency] private IStateManager _stateManager = default!; + private AlignAtmosPipeLayers _pipeLayers; // WL-Changes: pipe layers RPD private const float SearchBoxSize = 2f; private const float PlaceColorBaseAlpha = 0.5f; @@ -39,12 +47,48 @@ public AlignRCDConstruction(PlacementManager pMan) : base(pMan) _handsSystem = _entityManager.System(); _rcdSystem = _entityManager.System(); _transformSystem = _entityManager.System(); + _pipeLayers = new AlignAtmosPipeLayers(pMan); // WL-Changes: pipe layers RPD ValidPlaceColor = ValidPlaceColor.WithAlpha(PlaceColorBaseAlpha); } + // WL-Changes-start: pipe layers + public override void Render(in OverlayDrawArgs args) + { + if (pManager.CurrentPermission?.EntityType is { } entType + && _protoManager.TryIndex(entType, out var currentProto) + && currentProto.TryGetComponent(out _, _entityManager.ComponentFactory)) + { + _pipeLayers.Render(args); + return; + } + + base.Render(args); + } + // WL-Changes-end + public override void AlignPlacementMode(ScreenCoordinates mouseScreen) { + // WL-Changes-start: RPD pipe layers + if (pManager.CurrentPermission?.EntityType is { } entType + && _protoManager.TryIndex(entType, out var curProto)) + { + if (curProto.TryGetComponent(out _, _entityManager.ComponentFactory)) + { + _pipeLayers.AlignPlacementMode(mouseScreen); + return; + } + else + { + if (_playerManager.LocalSession?.AttachedEntity is { } player + && _handsSystem.TryGetActiveItem(player, out var item) + && _entityManager.TryGetComponent(item.Value, out var rcdComp) + && rcdComp.OverrideProtoId != null) + _entityManager.RaisePredictiveEvent(new RCDOverrideProtoIdEvent(_entityManager.GetNetEntity(item.Value), null)); + } + } + // WL-Changes-end + _unalignedMouseCoords = ScreenToCursorGrid(mouseScreen); MouseCoords = _unalignedMouseCoords.AlignWithClosestGridTile(SearchBoxSize, _entityManager, _mapManager); @@ -78,7 +122,16 @@ public override bool IsValidPosition(EntityCoordinates position) if (!_entityManager.TryGetComponent(player, out var xform)) return false; - if (!_transformSystem.InRange(xform.Coordinates, position, SharedInteractionSystem.InteractionRange)) + // WL-Changes-start: rescheduled + if (!_handsSystem.TryGetActiveItem(player.Value, out var heldEntity)) + return false; + + if (!_entityManager.TryGetComponent(heldEntity, out var rcd)) + return false; + + // SharedInteractionSystem.InteractionRange -> rcd.Range > 0 ? rcd.Range : SharedInteractionSystem.MaxRaycastRange + if (!_transformSystem.InRange(xform.Coordinates, position, rcd.Range > 0 ? rcd.Range : SharedInteractionSystem.MaxRaycastRange)) + // WL-Changes-end { InvalidPlaceColor = InvalidPlaceColor.WithAlpha(0); return false; @@ -90,13 +143,6 @@ public override bool IsValidPosition(EntityCoordinates position) InvalidPlaceColor = InvalidPlaceColor.WithAlpha(PlaceColorBaseAlpha); } - // Determine if player is carrying an RCD in their active hand - if (!_handsSystem.TryGetActiveItem(player.Value, out var heldEntity)) - return false; - - if (!_entityManager.TryGetComponent(heldEntity, out var rcd)) - return false; - var gridUid = _transformSystem.GetGrid(position); if (!_entityManager.TryGetComponent(gridUid, out var mapGrid)) return false; diff --git a/Content.Client/RCD/RCDConstructionGhostSystem.cs b/Content.Client/RCD/RCDConstructionGhostSystem.cs index 2b9a31e77b0..ee40c5f5404 100644 --- a/Content.Client/RCD/RCDConstructionGhostSystem.cs +++ b/Content.Client/RCD/RCDConstructionGhostSystem.cs @@ -1,10 +1,14 @@ +using System.ComponentModel.Design; using Content.Client.Hands.Systems; +using Content.Shared.Input; // WL-Changes: RPD using Content.Shared.Interaction; using Content.Shared.RCD; using Content.Shared.RCD.Components; using Robust.Client.Placement; using Robust.Client.Player; using Robust.Shared.Enums; +using Robust.Shared.Input; // WL-Changes: RPD +using Robust.Shared.Input.Binding; // WL-Changes: RPD using Robust.Shared.Prototypes; namespace Content.Client.RCD; @@ -22,6 +26,54 @@ public sealed partial class RCDConstructionGhostSystem : EntitySystem [Dependency] private HandsSystem _hands = default!; private Direction _placementDirection = default; + // WL-Changes-start: RPD port from Goob-Station + private bool _useMirrorPrototype; + private EntityUid? _lastPlacer; // WL-Changes: fix network issue + public override void Initialize() + { + base.Initialize(); + + CommandBinds.Builder + .Bind(ContentKeyFunctions.EditorFlipObject, + new PointerInputCmdHandler(HandleFlip, outsidePrediction: true)) + .Register(); + } + + public override void Shutdown() + { + CommandBinds.Unregister(); + base.Shutdown(); + } + + private bool HandleFlip(in PointerInputCmdHandler.PointerInputCmdArgs args) + { + if (args.State == BoundKeyState.Down) + { + if (!_placementManager.IsActive || _placementManager.Eraser) + return false; + + var placerEntity = _placementManager.CurrentPermission?.MobUid; + + if (!TryComp(placerEntity, out var rcd)) + return false; + + var prototype = _protoManager.Index(rcd.ProtoId); + if (string.IsNullOrEmpty(prototype.MirrorPrototype)) + return false; + + _useMirrorPrototype = !_useMirrorPrototype; + + var useProto = _useMirrorPrototype ? prototype.MirrorPrototype : prototype.Prototype; + CreatePlacer(placerEntity.Value, rcd, useProto, prototype.Mode); + + // tell the server + + RaiseNetworkEvent(new RCDConstructionGhostFlipEvent(GetNetEntity(placerEntity.Value), _useMirrorPrototype)); + } + + return true; + } + // WL-Changes-end public override void Update(float frameTime) { @@ -57,6 +109,14 @@ public override void Update(float frameTime) } var prototype = _protoManager.Index(rcd.ProtoId); + // WL-Changes-start: fix network issue + if (_lastPlacer != heldEntity) + { + _useMirrorPrototype = rcd.UseMirrorPrototype; + _lastPlacer = heldEntity; + } + // Wl-Changes-end + // Update the direction the RCD prototype based on the placer direction if (_placementDirection != _placementManager.Direction) { @@ -64,10 +124,13 @@ public override void Update(float frameTime) RaiseNetworkEvent(new RCDConstructionGhostRotationEvent(GetNetEntity(heldEntity.Value), _placementDirection)); } - // If the placer has not changed, exit - if (heldEntity == placerEntity && prototype.Prototype == placerProto) - return; + // WL-Changes-start: RPD port from Goob-Station + // If the placer has not changed, build it + var useProto = (_useMirrorPrototype && !string.IsNullOrEmpty(prototype.MirrorPrototype)) ? prototype.MirrorPrototype : prototype.Prototype; + if (heldEntity != placerEntity || useProto != placerProto) + CreatePlacer(heldEntity.Value, rcd, useProto, prototype.Mode); + /* moved into another method // Create a new placer var newObjInfo = new PlacementInformation { @@ -75,11 +138,29 @@ public override void Update(float frameTime) PlacementOption = PlacementMode, EntityType = prototype.Prototype, Range = (int)Math.Ceiling(SharedInteractionSystem.InteractionRange), - IsTile = (prototype.Mode == RcdMode.ConstructTile), + IsTile = prototype.Mode == RcdMode.ConstructTile, UseEditorContext = false, }; + _placementManager.Clear(); + _placementManager.BeginPlacing(newObjInfo); + */ + } + + private void CreatePlacer(EntityUid uid, RCDComponent component, string? prototype, RcdMode mode) + { + var newObjInfo = new PlacementInformation + { + MobUid = uid, + PlacementOption = PlacementMode, + EntityType = component.OverrideProtoId ?? prototype, // WL-Changes: pipe layers + Range = (int)Math.Ceiling(component.Range > 0 ? component.Range : SharedInteractionSystem.MaxRaycastRange), + IsTile = mode == RcdMode.ConstructTile, + UseEditorContext = false + }; + _placementManager.Clear(); _placementManager.BeginPlacing(newObjInfo); } + // WL-Changes-end } diff --git a/Content.Client/RCD/RCDMenuBoundUserInterface.cs b/Content.Client/RCD/RCDMenuBoundUserInterface.cs index d8b60667d9e..4b7be78b31a 100644 --- a/Content.Client/RCD/RCDMenuBoundUserInterface.cs +++ b/Content.Client/RCD/RCDMenuBoundUserInterface.cs @@ -1,13 +1,15 @@ +using Content.Client.Hands.Systems; // WL-Changes: RPD using Content.Client.Popups; using Content.Client.UserInterface.Controls; +using Content.Shared.IgnitionSource; // WL-Changes: RPD using Content.Shared.RCD; using Content.Shared.RCD.Components; +using Content.Shared.RCD.Systems; // WL-Changes: RPD using JetBrains.Annotations; using Robust.Client.UserInterface; using Robust.Shared.Collections; using Robust.Shared.Player; using Robust.Shared.Prototypes; -using Robust.Shared.Utility; namespace Content.Client.RCD; @@ -16,24 +18,34 @@ public sealed partial class RCDMenuBoundUserInterface : BoundUserInterface { private const string TopLevelActionCategory = "Main"; - private static readonly Dictionary PrototypesGroupingInfo - = new Dictionary - { - ["WallsAndFlooring"] = ("rcd-component-walls-and-flooring", new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/Radial/RCD/walls_and_flooring.png"))), - ["WindowsAndGrilles"] = ("rcd-component-windows-and-grilles", new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/Radial/RCD/windows_and_grilles.png"))), - ["Airlocks"] = ("rcd-component-airlocks", new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/Radial/RCD/airlocks.png"))), - ["Electrical"] = ("rcd-component-electrical", new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/Radial/RCD/multicoil.png"))), - ["Lighting"] = ("rcd-component-lighting", new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/Radial/RCD/lighting.png"))), - }; + // WL-Change: dehardcode // commented + // private static readonly Dictionary PrototypesGroupingInfo + // = new Dictionary + // { + // ["WallsAndFlooring"] = ("rcd-component-walls-and-flooring", new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/Radial/RCD/walls_and_flooring.png"))), + // ["WindowsAndGrilles"] = ("rcd-component-windows-and-grilles", new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/Radial/RCD/windows_and_grilles.png"))), + // ["Airlocks"] = ("rcd-component-airlocks", new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/Radial/RCD/airlocks.png"))), + // ["Electrical"] = ("rcd-component-electrical", new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/Radial/RCD/multicoil.png"))), + // ["Lighting"] = ("rcd-component-lighting", new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/Radial/RCD/lighting.png"))), + // }; [Dependency] private IPrototypeManager _prototypeManager = default!; [Dependency] private ISharedPlayerManager _playerManager = default!; + // WL-Changes-start: dehardcode and RPD + [Dependency] private IEntityManager _entityManager = default!; + private RCDSystem _rcd = default!; + private HandsSystem _hands = default!; + // WL-Changes-end private SimpleRadialMenu? _menu; public RCDMenuBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { IoCManager.InjectDependencies(this); + // WL-Changes-start: dehardcode + _rcd = _entityManager.System(); + _hands = _entityManager.System(); + // WL-Changes-end } protected override void Open() @@ -55,6 +67,7 @@ private IEnumerable ConvertToButtons(HashSet> buttonsByCategory = new(); ValueList topLevelActions = new(); + var prototypesGroupingInfo = _rcd.PrototypesGroupingInfo; // WL-Changes: dehardcode foreach (var protoId in prototypes) { var prototype = _prototypeManager.Index(protoId); @@ -69,7 +82,7 @@ private IEnumerable ConvertToButtons(HashSet ConvertToButtons(HashSet(item, out var rcdComp)) + { + if (_entityManager.HasComponent(item) + && rcdComp.EnableIgnite) + _entityManager.RaisePredictiveEvent(new RCDChangeModeEvent(_entityManager.GetNetEntity(item.Value))); + if (rcdComp.OverrideProtoId != null) + _entityManager.RaisePredictiveEvent(new RCDOverrideProtoIdEvent(_entityManager.GetNetEntity(item.Value), null)); + } + // WL-Changes-end + var msg = Loc.GetString("rcd-component-change-mode", ("mode", Loc.GetString(proto.SetName))); if (proto.Mode is RcdMode.ConstructTile or RcdMode.ConstructObject) diff --git a/Content.Shared/Charges/Components/LimitedChargesComponent.cs b/Content.Shared/Charges/Components/LimitedChargesComponent.cs index a905b884c31..fd283e04d19 100644 --- a/Content.Shared/Charges/Components/LimitedChargesComponent.cs +++ b/Content.Shared/Charges/Components/LimitedChargesComponent.cs @@ -22,7 +22,7 @@ public sealed partial class LimitedChargesComponent : Component /// /// Last time charges was changed. Used to derive current charges. /// - [DataField(customTypeSerializer:typeof(TimeOffsetSerializer)), AutoNetworkedField] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] public TimeSpan LastUpdate; // WL-Changes-start diff --git a/Content.Shared/RCD/Components/RCDComponent.cs b/Content.Shared/RCD/Components/RCDComponent.cs index 1ea31665310..cc2d9be3492 100644 --- a/Content.Shared/RCD/Components/RCDComponent.cs +++ b/Content.Shared/RCD/Components/RCDComponent.cs @@ -12,7 +12,7 @@ namespace Content.Shared.RCD.Components; /// Charges can be refilled with RCD ammo /// [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] -[Access(typeof(RCDSystem))] +[Access(typeof(RCDSystem), Other = AccessPermissions.ReadWrite)] public sealed partial class RCDComponent : Component { /// @@ -33,6 +33,50 @@ public sealed partial class RCDComponent : Component [DataField, AutoNetworkedField] public ProtoId ProtoId { get; set; } = "Invalid"; + // WL-Changes-start + /// + /// WL-Changes: RPD pipe layers + /// + /// ProtoId of current prototype for AlignAtmosPipeLayers. + /// If null RCDSystem used field Prototype from RCDPrototype + /// + [DataField, AutoNetworkedField, Access(Other = AccessPermissions.ReadWrite)] + public string? OverrideProtoId; + + /// + /// Wl-Changes: RPD + /// + /// Range for interaction, if Range <= 0, range is infinity(max for interaction sistem - 100f(tiles)) + /// + [DataField, AutoNetworkedField] + public float Range = 1.5f; + + /// + /// RPD port from Goob-Station + /// + /// Indicates if a mirrored version of the construction prototype should be used (if available) + /// + [AutoNetworkedField, ViewVariables(VVAccess.ReadOnly)] + public bool UseMirrorPrototype = false; + + /// + /// RPD port from Goob-Station + /// + /// Indicates whether this is an RCD or an RPD + /// + [DataField, AutoNetworkedField] + public bool IsRpd = false; + + [DataField, AutoNetworkedField] + public bool EnableIgnite = true; + + [DataField, AutoNetworkedField] + public float IgniteChance = 0.25f; + + [DataField, AutoNetworkedField] + public TimeSpan IgnitedTime = TimeSpan.FromSeconds(0.5); + // WL-Changes-end + /// /// The direction constructed entities will face upon spawning /// diff --git a/Content.Shared/RCD/Components/RCDDeconstructableComponent.cs b/Content.Shared/RCD/Components/RCDDeconstructableComponent.cs index 0ddc6897f05..e4537ebcd0f 100644 --- a/Content.Shared/RCD/Components/RCDDeconstructableComponent.cs +++ b/Content.Shared/RCD/Components/RCDDeconstructableComponent.cs @@ -15,7 +15,7 @@ public sealed partial class RCDDeconstructableComponent : Component public int Cost = 1; /// - /// The length of the deconstruction + /// The length of the deconstruction /// [DataField, ViewVariables(VVAccess.ReadWrite)] public float Delay = 1f; @@ -31,4 +31,12 @@ public sealed partial class RCDDeconstructableComponent : Component /// [DataField, ViewVariables(VVAccess.ReadWrite)] public bool Deconstructable = true; + + /// + /// WL-Changes: RPD port from Goob-Station + /// + /// Toggles whether this entity is deconstructable by the RPD or not + /// + [DataField("rpd"), ViewVariables(VVAccess.ReadWrite)] + public bool RpdDeconstructable = false; } diff --git a/Content.Shared/RCD/RCDEvents.cs b/Content.Shared/RCD/RCDEvents.cs index 6871ec178ee..e52f888d4ba 100644 --- a/Content.Shared/RCD/RCDEvents.cs +++ b/Content.Shared/RCD/RCDEvents.cs @@ -21,3 +21,25 @@ public enum RcdUiKey : byte { Key } + +// WL-Changes-start: RPD +[Serializable, NetSerializable] // pipe layers +public sealed class RCDOverrideProtoIdEvent(NetEntity netEntity, string? proto) : EntityEventArgs +{ + public readonly NetEntity NetEntity = netEntity; + public readonly string? OverrideProtoId = proto; +} + +[Serializable, NetSerializable] +public sealed class RCDChangeModeEvent(NetEntity rcd) : EntityEventArgs +{ + public readonly NetEntity Rcd = rcd; +} + +[Serializable, NetSerializable] // RPD port from Goob-Station +public sealed class RCDConstructionGhostFlipEvent(NetEntity netEntity, bool useMirrorPrototype) : EntityEventArgs +{ + public readonly NetEntity NetEntity = netEntity; + public readonly bool UseMirrorPrototype = useMirrorPrototype; +} +// WL-Changes-end diff --git a/Content.Shared/RCD/RCDGroupPrototype.cs b/Content.Shared/RCD/RCDGroupPrototype.cs new file mode 100644 index 00000000000..1b9050e21f0 --- /dev/null +++ b/Content.Shared/RCD/RCDGroupPrototype.cs @@ -0,0 +1,18 @@ +// WL-Changes-start: dehardcode +using Robust.Shared.Prototypes; + +namespace Content.Shared.RCD; + +[Prototype("rdGroup")] +public sealed partial class RDGroupPrototype : IPrototype +{ + [IdDataField] + public string ID { get; private set; } = default!; + + [DataField] + public string Name = ""; + + [DataField] + public string Sprite = ""; +} +// WL-Changes-end diff --git a/Content.Shared/RCD/RCDPrototype.cs b/Content.Shared/RCD/RCDPrototype.cs index c4ac7148f7a..8e898437611 100644 --- a/Content.Shared/RCD/RCDPrototype.cs +++ b/Content.Shared/RCD/RCDPrototype.cs @@ -44,6 +44,22 @@ public sealed partial class RCDPrototype : IPrototype [DataField, ViewVariables(VVAccess.ReadOnly)] public string? Prototype { get; private set; } + /// + /// WL-Changes: RPD port from Goob-Station + /// + /// If the entity can be flipped, this prototype is available as an alternate (mode dependent) + /// + [DataField, ViewVariables(VVAccess.ReadOnly)] + public string? MirrorPrototype { get; private set; } + + /// + /// WL-Changes: RPD + /// + /// If true, allows placing the entity once in a crosswise direction + /// + [DataField, ViewVariables(VVAccess.ReadOnly)] + public bool AllowCrossDirection { get; private set; } + /// /// If true, allows placing the entity once per direction (North, West, South and East) /// diff --git a/Content.Shared/RCD/Systems/RCDSystem.cs b/Content.Shared/RCD/Systems/RCDSystem.cs index fa84f5719ac..69962350c5b 100644 --- a/Content.Shared/RCD/Systems/RCDSystem.cs +++ b/Content.Shared/RCD/Systems/RCDSystem.cs @@ -5,6 +5,7 @@ using Content.Shared.DoAfter; using Content.Shared.Examine; using Content.Shared.Hands.EntitySystems; +using Content.Shared.IgnitionSource; // WL-Changes: RPD using Content.Shared.Interaction; using Content.Shared.Maps; using Content.Shared.Physics; @@ -20,7 +21,11 @@ using Robust.Shared.Physics.Collision.Shapes; using Robust.Shared.Physics.Dynamics; using Robust.Shared.Prototypes; +using Robust.Shared.Random; // WL-Changes: RPD using Robust.Shared.Serialization; +using Robust.Shared.Serialization.TypeSerializers.Implementations; // WL-Changes: RPD +using Robust.Shared.Timing; // WL-Changes: RPD +using Robust.Shared.Utility; // WL-Changes: RPD using System.Linq; namespace Content.Shared.RCD.Systems; @@ -44,6 +49,11 @@ public sealed partial class RCDSystem : EntitySystem [Dependency] private SharedMapSystem _mapSystem = default!; [Dependency] private SharedTransformSystem _transform = default!; [Dependency] private TagSystem _tags = default!; + // WL-Changes-start: RPD & fire from basics RD + [Dependency] private ExamineSystemShared _examine = default!; + [Dependency] private IRobustRandom _random = default!; + [Dependency] private SharedIgnitionSourceSystem _source = default!; + // WL-Changes-end private readonly int _instantConstructionDelay = 0; private readonly EntProtoId _instantConstructionFx = "EffectRCDConstruct0"; @@ -52,7 +62,8 @@ public sealed partial class RCDSystem : EntitySystem private static readonly ProtoId CatwalkTag = "Catwalk"; private HashSet _intersectingEntities = new(); - + [Access(Other = AccessPermissions.Read)] + public Dictionary PrototypesGroupingInfo = new(); // WL-Changes: dehardcode public override void Initialize() { base.Initialize(); @@ -64,7 +75,65 @@ public override void Initialize() SubscribeLocalEvent>(OnDoAfterAttempt); SubscribeLocalEvent(OnRCDSystemMessage); SubscribeNetworkEvent(OnRCDconstructionGhostRotationEvent); + + // WL-Changes-start + SubscribeLocalEvent(OnProtoReload); // dehardcode + SubscribeNetworkEvent(OverrideChanged); // pipe layers + SubscribeNetworkEvent(OnModeChanged); + SubscribeNetworkEvent(OnRCDConstructionGhostFlipEvent); // RPD port from Goob-Station + UpdateProtoList(); + // WL-Changes-end + } + + // WL-Changes-start + private void OnProtoReload(PrototypesReloadedEventArgs args) // dehardcode + { + if (!args.WasModified()) + return; + + PrototypesGroupingInfo.Clear(); + UpdateProtoList(); + } + + private void UpdateProtoList() + { + var enume = _protoManager.EnumeratePrototypes(); + foreach (var proto in enume) + { + PrototypesGroupingInfo.Add(proto.ID, (Loc.GetString(proto.Name), new SpriteSpecifier.Texture(SpriteSpecifierSerializer.TextureRoot / proto.Sprite))); + } + } + + private void OverrideChanged(RCDOverrideProtoIdEvent args) // pipe layers + { + var rcd = GetEntity(args.NetEntity); + if (!TryComp(rcd, out var comp)) + return; + + comp.OverrideProtoId = args.OverrideProtoId; + Dirty(rcd, comp); + } + + private void OnModeChanged(RCDChangeModeEvent args, EntitySessionEventArgs session) + { + if (session.SenderSession.AttachedEntity is not { } player) + return; + + var rcd = GetEntity(args.Rcd); + + if (!_hands.TryGetActiveItem(player, out var held) || held != rcd) + return; + + if (!TryComp(rcd, out var rcdComp) || !rcdComp.EnableIgnite) + return; + + if (_random.Prob(rcdComp.IgniteChance)) + { + _source.SetIgnited((rcd, null), true); + Timer.Spawn(rcdComp.IgnitedTime, () => _source.SetIgnited((rcd, null), false)); + } } + // WL-Changes-end #region Event handling @@ -89,7 +158,7 @@ private void OnRCDSystemMessage(EntityUid uid, RCDComponent component, RCDSystem if (!component.AvailablePrototypes.Contains(args.ProtoId)) return; - if (!_protoManager.Resolve(args.ProtoId, out var prototype)) + if (!_protoManager.Resolve(args.ProtoId, out var prototype)) return; // Set the current RCD prototype to the one supplied @@ -125,8 +194,11 @@ private void OnExamine(EntityUid uid, RCDComponent component, ExaminedEvent args private void OnAfterInteract(EntityUid uid, RCDComponent component, AfterInteractEvent args) { - if (args.Handled || !args.CanReach) + // WL-Changes-start: BRPD + var distance = component.Range > 0 ? component.Range : SharedInteractionSystem.MaxRaycastRange; + if (args.Handled || !args.CanReach && !_transform.InRange(Transform(uid).Coordinates, args.ClickLocation, distance)) return; + // WL-Changes-end var user = args.User; var location = args.ClickLocation; @@ -152,7 +224,7 @@ private void OnAfterInteract(EntityUid uid, RCDComponent component, AfterInterac var tile = _mapSystem.GetTileRef(gridUid.Value, mapGrid, location); var position = _mapSystem.TileIndicesFor(gridUid.Value, mapGrid, location); - if (!IsRCDOperationStillValid(uid, component, gridUid.Value, mapGrid, tile, position, component.ConstructionDirection, args.Target, args.User)) + if (!IsRCDOperationStillValid(uid, component, gridUid.Value, mapGrid, tile, position, component.ConstructionDirection, args.Target, user)) return; if (!_net.IsServer) @@ -230,7 +302,8 @@ private void OnAfterInteract(EntityUid uid, RCDComponent component, AfterInterac BreakOnMove = true, AttemptFrequency = AttemptFrequency.EveryTick, CancelDuplicate = false, - BlockDuplicate = false + BlockDuplicate = false, + DistanceThreshold = distance // WL-Changes: BRPD }; args.Handled = true; @@ -325,6 +398,26 @@ private void OnRCDconstructionGhostRotationEvent(RCDConstructionGhostRotationEve Dirty(uid, rcd); } + // WL-Changes-start: RPD port from Goob-Station + private void OnRCDConstructionGhostFlipEvent(RCDConstructionGhostFlipEvent ev, EntitySessionEventArgs session) + { + var uid = GetEntity(ev.NetEntity); + + // Determine if player that send the message is carrying the specified RCD in their active hand + if (session.SenderSession.AttachedEntity is not { } user) + return; + + if (!_hands.TryGetActiveItem(user, out var held) || uid != held) + return; + + if (!TryComp(uid, out var rcd)) + return; + + rcd.UseMirrorPrototype = ev.UseMirrorPrototype; + Dirty(uid, rcd); + } + // WL-Changes-end + #endregion #region Entity construction/deconstruction rule checks @@ -358,13 +451,36 @@ public bool IsRCDOperationStillValid(EntityUid uid, RCDComponent component, Enti return false; } + // WL-Changes-start: BRPD + var fail = false; + // Exit if the target / target location is obstructed - var unobstructed = (target == null) - ? _interaction.InRangeUnobstructed(user, _mapSystem.GridTileToWorld(gridUid, mapGrid, position), popup: popMsgs) - : _interaction.InRangeUnobstructed(user, target.Value, popup: popMsgs); + if (component.Range > 0) + { + var unobstructedBasic = target == null + ? _interaction.InRangeUnobstructed(user, _mapSystem.GridTileToWorld(gridUid, mapGrid, position), component.Range, popup: popMsgs) + : _interaction.InRangeUnobstructed(user, target.Value, component.Range, popup: popMsgs); + fail = !unobstructedBasic; + } + else + { + var unobstructedVision = target == null + ? _examine.InRangeUnOccluded(user, _mapSystem.GridTileToWorld(gridUid, mapGrid, position), component.Range) + : _examine.InRangeUnOccluded(user, target.Value, component.Range); + var unobstructedBasic = target == null + ? _interaction.InRangeUnobstructed(user, _mapSystem.GridTileToWorld(gridUid, mapGrid, position), component.Range) + : _interaction.InRangeUnobstructed(user, target.Value, component.Range); + + fail = !unobstructedVision && !unobstructedBasic; + } - if (!unobstructed) + if (fail) + { + if (popMsgs) + _popup.PopupClient(Loc.GetString("interaction-system-user-interaction-cannot-reach"), user, user); return false; + } + // WL-Changes-end // Return whether the operation location is valid switch (prototype.Mode) @@ -373,7 +489,7 @@ public bool IsRCDOperationStillValid(EntityUid uid, RCDComponent component, Enti case RcdMode.ConstructObject: return IsConstructionLocationValid(uid, component, gridUid, mapGrid, tile, position, direction, user, popMsgs); case RcdMode.Deconstruct: - return IsDeconstructionStillValid(uid, tile, target, user, popMsgs); + return IsDeconstructionStillValid(uid, component, tile, target, user, popMsgs); // WL-Changes: RPD port from Goob-Station // added component } return false; @@ -427,7 +543,7 @@ private bool IsConstructionLocationValid(EntityUid uid, RCDComponent component, // Check rule: Respect baseTurf and baseWhitelist if (prototype.Prototype != null && _tileDefMan.TryGetDefinition(prototype.Prototype, out var replacementDef)) { - var replacementContentDef = (ContentTileDefinition) replacementDef; + var replacementContentDef = (ContentTileDefinition)replacementDef; if (replacementContentDef.BaseTurf != tileDef.ID && !replacementContentDef.BaseWhitelist.Contains(tileDef.ID)) { @@ -464,7 +580,9 @@ private bool IsConstructionLocationValid(EntityUid uid, RCDComponent component, { // If the entity is the exact same prototype as what we are trying to build, then block it. // This is to prevent spamming objects on the same tile (e.g. lights) - if (prototype.Prototype != null && MetaData(ent).EntityPrototype?.ID == prototype.Prototype) + // WL-Changes: pipe layers + var proto = (component.UseMirrorPrototype && !string.IsNullOrEmpty(prototype.MirrorPrototype)) ? prototype.MirrorPrototype : component.OverrideProtoId ?? prototype.Prototype; + if (proto != null && MetaData(ent).EntityPrototype?.ID == proto) { var isIdentical = true; @@ -475,6 +593,24 @@ private bool IsConstructionLocationValid(EntityUid uid, RCDComponent component, isIdentical = false; } + // WL-Changes-start: pipes + if (prototype.AllowCrossDirection) + { + var entDirection = Transform(ent).LocalRotation.GetCardinalDir(); + if (entDirection == Direction.South || entDirection == Direction.North) + { + if (direction == Direction.East || direction == Direction.West) + isIdentical = false; + } + else if (entDirection == Direction.East || entDirection == Direction.West) + { + if (direction == Direction.South || direction == Direction.North) + isIdentical = false; + } + } + // WL-Changes-end + + if (isIdentical) { if (popMsgs) @@ -500,7 +636,7 @@ private bool IsConstructionLocationValid(EntityUid uid, RCDComponent component, foreach (var fixture in fixtures.Fixtures.Values) { // Continue if no collision is possible - if (!fixture.Hard || fixture.CollisionLayer <= 0 || (fixture.CollisionLayer & (int) prototype.CollisionMask) == 0) + if (!fixture.Hard || fixture.CollisionLayer <= 0 || (fixture.CollisionLayer & (int)prototype.CollisionMask) == 0) continue; // Continue if our custom collision bounds are not intersected @@ -520,11 +656,23 @@ private bool IsConstructionLocationValid(EntityUid uid, RCDComponent component, return true; } - private bool IsDeconstructionStillValid(EntityUid uid, TileRef tile, EntityUid? target, EntityUid user, bool popMsgs = true) + private bool IsDeconstructionStillValid(EntityUid uid, RCDComponent component, TileRef tile, EntityUid? target, EntityUid user, bool popMsgs = true) // WL-Changes: RPD port from Goob-Station // added RCDComponent { // Attempt to deconstruct a floor tile if (target == null) { + // WL-Changes-start: RPD port from Goob-Station + /* Commented by WL, if u need - uncomment + if (component.IsRpd) + { + if (popMsgs) + _popup.PopupClient(Loc.GetString("rcd-component-deconstruct-target-not-on-whitelist-message"), uid, user); + + return false; + } + */ + // WL-Changes-end + // The tile is empty if (tile.Tile.IsEmpty) { @@ -558,8 +706,18 @@ private bool IsDeconstructionStillValid(EntityUid uid, TileRef tile, EntityUid? // Attempt to deconstruct an object else { + // WL-Changes-start: RPD port from Goob-Station + if (!TryComp(target, out var deconstructible) || !deconstructible.RpdDeconstructable && component.IsRpd) + { + if (popMsgs) + _popup.PopupClient(Loc.GetString("rcd-component-deconstruct-target-not-on-whitelist-message"), uid, user); + + return false; + } + // The object is not in the whitelist - if (!TryComp(target, out var deconstructible) || !deconstructible.Deconstructable) + if (!deconstructible.Deconstructable) + // WL-Changes-end { if (popMsgs) _popup.PopupClient(Loc.GetString("rcd-component-deconstruct-target-not-on-whitelist-message"), uid, user); @@ -581,23 +739,50 @@ private void FinalizeRCDOperation(EntityUid uid, RCDComponent component, EntityU return; var prototype = _protoManager.Index(component.ProtoId); + // WL-Changes-start: pipe layers + var protoMiddle = component.OverrideProtoId ?? prototype.Prototype; - if (prototype.Prototype == null) + if (protoMiddle == null) return; switch (prototype.Mode) { case RcdMode.ConstructTile: - if (!_tileDefMan.TryGetDefinition(prototype.Prototype, out var tileDef)) + if (!_tileDefMan.TryGetDefinition(protoMiddle, out var tileDef)) return; - _tile.ReplaceTile(tile, (ContentTileDefinition) tileDef, gridUid, mapGrid); - _adminLogger.Add(LogType.RCD, LogImpact.High, $"{ToPrettyString(user):user} used RCD to set grid: {gridUid} {position} to {prototype.Prototype}"); + _tile.ReplaceTile(tile, (ContentTileDefinition)tileDef, gridUid, mapGrid); + _adminLogger.Add(LogType.RCD, LogImpact.High, $"{ToPrettyString(user):user} used RCD to set grid: {gridUid} {position} to {protoMiddle}"); + // WL-Changes-end break; case RcdMode.ConstructObject: - var ent = Spawn(prototype.Prototype, _mapSystem.GridTileToLocal(gridUid, mapGrid, position)); + // WL-Changes-start: RPD port from Goob-Station (with Funky changes) + var proto = (component.UseMirrorPrototype && + !string.IsNullOrEmpty(prototype.MirrorPrototype)) + ? prototype.MirrorPrototype + : protoMiddle; // WL-Changes // prototype.Prototype -> protoMiddle + + // Funky - Calculate rotation and apply it before spawning + var rotation = prototype.Rotation switch + { + RcdRotation.Fixed => Angle.Zero, + RcdRotation.Camera => Transform(uid).LocalRotation, + RcdRotation.User => direction.ToAngle(), + _ => Angle.Zero // Fallback + }; + + // Convert EntityCoordinates to MapCoordinates + var entityCoords = _mapSystem.GridTileToLocal(gridUid, mapGrid, position); + var mapCoords = _transform.ToMapCoordinates(entityCoords); + + var gridRotation = _transform.GetWorldRotation(gridUid); + var worldRotation = rotation + gridRotation; + + var ent = Spawn(proto, mapCoords, rotation: worldRotation); + // End of funky changes + /* Funky - handled above switch (prototype.Rotation) { case RcdRotation.Fixed: @@ -610,6 +795,8 @@ private void FinalizeRCDOperation(EntityUid uid, RCDComponent component, EntityU Transform(ent).LocalRotation = direction.ToAngle(); break; } + */ + // WL-Changes-end _adminLogger.Add(LogType.RCD, LogImpact.High, $"{ToPrettyString(user):user} used RCD to spawn {ToPrettyString(ent)} at {position} on grid {gridUid}"); break; @@ -655,7 +842,7 @@ public sealed partial class RCDDoAfterEvent : DoAfterEvent public NetCoordinates Location { get; private set; } [DataField(required: true)] - public NetEntity TargetGridId {get ; private set; } + public NetEntity TargetGridId { get; private set; } [DataField] public Direction Direction { get; private set; } diff --git a/Resources/Audio/_WL/Items/handling/rpd_drop.ogg b/Resources/Audio/_WL/Items/handling/rpd_drop.ogg new file mode 100644 index 00000000000..e7de6cf18cf Binary files /dev/null and b/Resources/Audio/_WL/Items/handling/rpd_drop.ogg differ diff --git a/Resources/Audio/_WL/Items/handling/rpd_pickup.ogg b/Resources/Audio/_WL/Items/handling/rpd_pickup.ogg new file mode 100644 index 00000000000..5f8d34d1409 Binary files /dev/null and b/Resources/Audio/_WL/Items/handling/rpd_pickup.ogg differ diff --git a/Resources/Locale/ru-RU/_WL/entities/objects/tools/tools.ftl b/Resources/Locale/ru-RU/_WL/entities/objects/tools/tools.ftl new file mode 100644 index 00000000000..15aca6e8953 --- /dev/null +++ b/Resources/Locale/ru-RU/_WL/entities/objects/tools/tools.ftl @@ -0,0 +1,14 @@ +ent-BRPD = блюспейс РФУ + .desc = Усовершенствованное блюспейсом ручное фиксирующее устройство, позволяющее прокладывать трубы где угодно, в поле зрения пользователя. +ent-RPDRecharging = { ent-RPDExperimental } + .desc = Ручное фиксирующее устройство вмонтированное в Борга, которое на лету создаёт сжатую материю используя встроенный фабрикатор. + .suffix = Автозарядка +ent-RPDExperimental = экспериментальный РФУ + .desc = Усовершенствованное блюспейс-устройство для быстрой трубопрокладки, которое пассивно генерирует собственное сжатое вещество. + .suffix = Адмемы +ent-RPDEmpty = { ent-RPD } + .desc = { ent-RPD.desc } + .suffix = Пустой +ent-RCDRechargingCE = { ent-RCDRecharging } + .desc = { ent-RCDRecharging.desc } + .suffix = Автозарядка, СИ diff --git a/Resources/Locale/ru-RU/rcd/components/rcd-component.ftl b/Resources/Locale/ru-RU/rcd/components/rcd-component.ftl index 9d2e5736854..592407c305b 100644 --- a/Resources/Locale/ru-RU/rcd/components/rcd-component.ftl +++ b/Resources/Locale/ru-RU/rcd/components/rcd-component.ftl @@ -46,3 +46,10 @@ rcd-component-lighting = Освещение rcd-component-deconstruct = демонтаж rcd-component-floor-steel = стальной пол rcd-component-plating = корпусное покрытие + +### WL-Changes: RPD port from Goob-Station +rcd-component-piping = Трубы +rcd-component-atmosphericutility = Атмос +rcd-component-pumpsvalves = Насосы и клапаны +rcd-component-vents = Вентиляция + diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/_Goobstation/entities/objects/tools/tools.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/_Goobstation/entities/objects/tools/tools.ftl new file mode 100644 index 00000000000..61c3b86fe9d --- /dev/null +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/_Goobstation/entities/objects/tools/tools.ftl @@ -0,0 +1,2 @@ +ent-RPD = РФУ + .desc = Новейшее ручное фиксирующее устройство, которое позволяет быстро укладывать трубы. diff --git a/Resources/Prototypes/Entities/Objects/Tools/tools.yml b/Resources/Prototypes/Entities/Objects/Tools/tools.yml index 05f1abd4e05..c49f8951edb 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/tools.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/tools.yml @@ -399,6 +399,10 @@ - type: ActivatableUI inHandsOnly: true key: enum.RcdUiKey.Key + # WL-Changes-start: RD ignite + - type: IgnitionSource + temperature: 800 + # WL-Changes-end - type: entity id: RCDEmpty diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/pipes.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/pipes.yml index 36b52f02400..d0f28562b48 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/pipes.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/pipes.yml @@ -84,6 +84,11 @@ path: /Audio/_Goobstation/Items/Pipe/metal_pipe_fall.ogg params: volume: -2 + - type: RCDDeconstructable # RPD port from Goob-Station + cost: 1 + delay: 2 + fx: EffectRCDDeconstruct2 + rpd: true # WL-Changes-end # Goobstation edit end diff --git a/Resources/Prototypes/_Goobstation/Entities/Objects/Tools/tools.yml b/Resources/Prototypes/_Goobstation/Entities/Objects/Tools/tools.yml new file mode 100644 index 00000000000..93146811ba6 --- /dev/null +++ b/Resources/Prototypes/_Goobstation/Entities/Objects/Tools/tools.yml @@ -0,0 +1,45 @@ +- type: entity + parent: RCD + id: RPD + name: RPD + description: A device used to rapidly pipe things. + components: + - type: RCD + isRpd: true + availablePrototypes: + - PipeFourway + - PipeStraight + - PipeBend + - PipeTJunction + - OutletInjector + - ManualValve + - VolumetricPump + - PressurePump + - VentScrubber + - PressureValve + - DualPortVent + - VentGas + - VentPassive + - MixerGas + - Radiator + - RadiatorBend + - SignalValve + - CanisterPort + - FilterGas + - Deconstruct + - type: LimitedCharges + maxCharges: 45 + - type: Sprite + sprite: _Goobstation/Objects/Tools/rpd.rsi + # WL-Sounds-Start + - type: EmitSoundOnPickup + sound: + path: /Audio/_WL/Items/handling/rpd_pickup.ogg + params: + volume: -4 + - type: EmitSoundOnDrop + sound: + path: /Audio/_WL/Items/handling/rpd_drop.ogg + params: + volume: -4 + # WL-Sounds-End diff --git a/Resources/Prototypes/_Goobstation/RPD/rpd.yml b/Resources/Prototypes/_Goobstation/RPD/rpd.yml new file mode 100644 index 00000000000..48aa7b71658 --- /dev/null +++ b/Resources/Prototypes/_Goobstation/RPD/rpd.yml @@ -0,0 +1,232 @@ +- type: rcd + id: PipeFourway + category: Piping + sprite: /Textures/_Goobstation/Interface/Radial/RPD/fourway.png + mode: ConstructObject + prototype: GasPipeFourway + cost: 1 + delay: 0 + rotation: User + fx: EffectRCDConstruct0 + +- type: rcd + id: PipeStraight + category: Piping + sprite: /Textures/_Goobstation/Interface/Radial/RPD/straight.png + mode: ConstructObject + prototype: GasPipeStraight + cost: 1 + delay: 0 + rotation: User + fx: EffectRCDConstruct0 + allowCrossDirection: true + +- type: rcd + id: PipeBend + category: Piping + sprite: /Textures/_Goobstation/Interface/Radial/RPD/bend.png + mode: ConstructObject + prototype: GasPipeBend + cost: 1 + delay: 0 + rotation: User + fx: EffectRCDConstruct0 + +- type: rcd + id: PipeTJunction + category: Piping + sprite: /Textures/_Goobstation/Interface/Radial/RPD/tjunction.png + mode: ConstructObject + prototype: GasPipeTJunction + cost: 1 + delay: 0 + collisionMask: Impassable + rotation: User + fx: EffectRCDConstruct0 + +- type: rcd + id: PressurePump + category: PumpsValves + sprite: /Textures/_Goobstation/Interface/Radial/RPD/pump_pressure.png + mode: ConstructObject + prototype: GasPressurePump + cost: 2 + delay: 0 + collisionMask: Impassable + rotation: User + fx: EffectRCDConstruct0 + allowCrossDirection: true + +- type: rcd + id: VolumetricPump + category: PumpsValves + sprite: /Textures/_Goobstation/Interface/Radial/RPD/pump_volume.png + mode: ConstructObject + prototype: GasVolumePump + cost: 2 + delay: 0 + collisionMask: Impassable + rotation: User + fx: EffectRCDConstruct0 + allowCrossDirection: true + +- type: rcd + id: ManualValve + category: PumpsValves + sprite: /Textures/_Goobstation/Interface/Radial/RPD/pump_manual_valve.png + mode: ConstructObject + prototype: GasValve + cost: 2 + delay: 0 + collisionMask: Impassable + rotation: User + fx: EffectRCDConstruct0 + allowCrossDirection: true + +- type: rcd + id: SignalValve + category: PumpsValves + sprite: /Textures/_Goobstation/Interface/Radial/RPD/pump_signal_valve.png + mode: ConstructObject + prototype: SignalControlledValve + cost: 2 + delay: 0 + collisionMask: Impassable + rotation: User + fx: EffectRCDConstruct0 + allowCrossDirection: true + +- type: rcd + id: PressureValve + category: PumpsValves + sprite: /Textures/_Goobstation/Interface/Radial/RPD/pneumatic_valve.png + mode: ConstructObject + prototype: PressureControlledValve + cost: 2 + delay: 0 + collisionMask: Impassable + rotation: User + fx: EffectRCDConstruct0 + allowCrossDirection: true + +- type: rcd + id: OutletInjector + category: Vents + sprite: /Textures/_Goobstation/Interface/Radial/RPD/injector.png + mode: ConstructObject + prototype: GasOutletInjector + cost: 2 + delay: 0 + collisionMask: Impassable + rotation: User + fx: EffectRCDConstruct0 + +- type: rcd + id: VentScrubber + category: Vents + sprite: /Textures/_Goobstation/Interface/Radial/RPD/scrub_off.png + mode: ConstructObject + prototype: GasVentScrubber + cost: 2 + delay: 0 + collisionMask: Impassable + rotation: User + fx: EffectRCDConstruct0 + +- type: rcd + id: VentGas + category: Vents + sprite: /Textures/_Goobstation/Interface/Radial/RPD/vent_off.png + mode: ConstructObject + prototype: GasVentPump + cost: 2 + delay: 0 + collisionMask: Impassable + rotation: User + fx: EffectRCDConstruct0 + +- type: rcd + id: DualPortVent + category: Vents + sprite: /Textures/_Goobstation/Interface/Radial/RPD/dual_port.png + mode: ConstructObject + prototype: GasDualPortVentPump + cost: 2 + delay: 0 + collisionMask: Impassable + rotation: User + fx: EffectRCDConstruct0 + +- type: rcd + id: VentPassive + category: Vents + sprite: /Textures/_Goobstation/Interface/Radial/RPD/vent_passive.png + mode: ConstructObject + prototype: GasPassiveVent + cost: 2 + delay: 0 + collisionMask: Impassable + rotation: User + fx: EffectRCDConstruct0 + +- type: rcd + id: Radiator + category: AtmosphericUtility + sprite: /Textures/_Goobstation/Interface/Radial/RPD/radiator.png + mode: ConstructObject + prototype: HeatExchanger + cost: 2 + delay: 0 + collisionMask: Impassable + rotation: User + fx: EffectRCDConstruct0 + +- type: rcd + id: RadiatorBend + category: AtmosphericUtility + sprite: /Textures/_Goobstation/Interface/Radial/RPD/radiator_bend.png + mode: ConstructObject + prototype: HeatExchangerBend + cost: 2 + delay: 0 + collisionMask: Impassable + rotation: User + fx: EffectRCDConstruct0 + +- type: rcd + id: MixerGas + category: AtmosphericUtility + sprite: /Textures/_Goobstation/Interface/Radial/RPD/gas_mixer.png + mode: ConstructObject + prototype: GasMixer + mirrorPrototype: GasMixerFlipped + cost: 2 + delay: 0 + collisionMask: Impassable + rotation: User + fx: EffectRCDConstruct0 + +- type: rcd + id: FilterGas + category: AtmosphericUtility + sprite: /Textures/_Goobstation/Interface/Radial/RPD/gas_filter.png + mode: ConstructObject + prototype: GasFilter + mirrorPrototype: GasFilterFlipped + cost: 2 + delay: 0 + collisionMask: Impassable + rotation: User + fx: EffectRCDConstruct0 + +- type: rcd + id: CanisterPort + category: AtmosphericUtility + sprite: /Textures/_Goobstation/Interface/Radial/RPD/port.png + mode: ConstructObject + prototype: GasPort + cost: 2 + delay: 0 + collisionMask: Impassable + rotation: User + fx: EffectRCDConstruct0 diff --git a/Resources/Prototypes/_WL/Entities/Objects/Tools/tools.yml b/Resources/Prototypes/_WL/Entities/Objects/Tools/tools.yml new file mode 100644 index 00000000000..dab77348666 --- /dev/null +++ b/Resources/Prototypes/_WL/Entities/Objects/Tools/tools.yml @@ -0,0 +1,69 @@ +- type: entity + parent: RPD + id: BRPD + name: bluespace RPD + description: A bluespace device used to rapidly pipe things. + components: + - type: RCD + range: -1 + enableIgnite: false + - type: LimitedCharges + maxCharges: 60 + - type: Sprite + sprite: _WL/Objects/Tools/brpd.rsi + +# - type: entity +# parent: RPD +# id: RPDRechargingCE +# name: experimental RPD +# description: Rapid Piping Device which creates compressed matter on the fly using an internal fabricator. +# suffix: AutoRecharge +# components: +# - type: LimitedCharges +# maxCharges: 40 +# - type: AutoRecharge +# rechargeDuration: 10 + +- type: entity + id: RPDRecharging + parent: RPD + name: experimental RPD + description: Cyborg-mounted Rapid Piping Device which creates compressed matter on the fly using an internal fabricator. + suffix: AutoRecharge + components: + - type: LimitedCharges + maxCharges: 30 + - type: AutoRecharge + rechargeDuration: 10 + +- type: entity + id: RPDExperimental + parent: RPD + suffix: Admeme + name: experimental RPD + description: A bluespace-enhanced rapid piping device that passively generates its own compressed matter. + components: + - type: RCD + enableIgnite: false + - type: AutoRecharge + rechargeDuration: 1 + +- type: entity + id: RPDEmpty + parent: RPD + suffix: Empty + components: + - type: LimitedCharges + lastCharges: -1 + +- type: entity + id: RCDRechargingCE + parent: RCDRecharging + suffix: AutoRecharge, CE + components: + - type: RCD + enableIgnite: false + - type: LimitedCharges + maxCharges: 45 + - type: Sprite + sprite: _WL/Objects/Tools/cercd.rsi diff --git a/Resources/Prototypes/_WL/RD/rcd.yml b/Resources/Prototypes/_WL/RD/rcd.yml new file mode 100644 index 00000000000..bc206d1fb7c --- /dev/null +++ b/Resources/Prototypes/_WL/RD/rcd.yml @@ -0,0 +1,44 @@ +- type: rdGroup + id: WallsAndFlooring + name: rcd-component-walls-and-flooring + sprite: Interface/Radial/RCD/walls_and_flooring.png + +- type: rdGroup + id: WindowsAndGrilles + name: rcd-component-windows-and-grilles + sprite: Interface/Radial/RCD/windows_and_grilles.png + +- type: rdGroup + id: Airlocks + name: rcd-component-airlocks + sprite: Interface/Radial/RCD/airlocks.png + +- type: rdGroup + id: Electrical + name: rcd-component-electrical + sprite: Interface/Radial/RCD/multicoil.png + +- type: rdGroup + id: Lighting + name: rcd-component-lighting + sprite: Interface/Radial/RCD/lighting.png + +- type: rdGroup + id: Piping + name: rcd-component-piping + sprite: /Textures/_Goobstation/Interface/Radial/RPD/fourway.png + +- type: rdGroup + id: AtmosphericUtility + name: rcd-component-atmosphericutility + sprite: /Textures/_Goobstation/Interface/Radial/RPD/port.png + +- type: rdGroup + id: PumpsValves + name: rcd-component-pumpsvalves + sprite: /Textures/_Goobstation/Interface/Radial/RPD/pump_volume.png + +- type: rdGroup + id: Vents + name: rcd-component-vents + sprite: /Textures/_Goobstation/Interface/Radial/RPD/vent_passive.png diff --git a/Resources/Textures/_Goobstation/Interface/Radial/RPD/bend.png b/Resources/Textures/_Goobstation/Interface/Radial/RPD/bend.png new file mode 100644 index 00000000000..c62cf62220d Binary files /dev/null and b/Resources/Textures/_Goobstation/Interface/Radial/RPD/bend.png differ diff --git a/Resources/Textures/_Goobstation/Interface/Radial/RPD/dual_port.png b/Resources/Textures/_Goobstation/Interface/Radial/RPD/dual_port.png new file mode 100644 index 00000000000..b2e63dd51ed Binary files /dev/null and b/Resources/Textures/_Goobstation/Interface/Radial/RPD/dual_port.png differ diff --git a/Resources/Textures/_Goobstation/Interface/Radial/RPD/fourway.png b/Resources/Textures/_Goobstation/Interface/Radial/RPD/fourway.png new file mode 100644 index 00000000000..336d930022d Binary files /dev/null and b/Resources/Textures/_Goobstation/Interface/Radial/RPD/fourway.png differ diff --git a/Resources/Textures/_Goobstation/Interface/Radial/RPD/gas_filter.png b/Resources/Textures/_Goobstation/Interface/Radial/RPD/gas_filter.png new file mode 100644 index 00000000000..35096091a82 Binary files /dev/null and b/Resources/Textures/_Goobstation/Interface/Radial/RPD/gas_filter.png differ diff --git a/Resources/Textures/_Goobstation/Interface/Radial/RPD/gas_mixer.png b/Resources/Textures/_Goobstation/Interface/Radial/RPD/gas_mixer.png new file mode 100644 index 00000000000..0ef1bb69a48 Binary files /dev/null and b/Resources/Textures/_Goobstation/Interface/Radial/RPD/gas_mixer.png differ diff --git a/Resources/Textures/_Goobstation/Interface/Radial/RPD/injector.png b/Resources/Textures/_Goobstation/Interface/Radial/RPD/injector.png new file mode 100644 index 00000000000..b38c170b02c Binary files /dev/null and b/Resources/Textures/_Goobstation/Interface/Radial/RPD/injector.png differ diff --git a/Resources/Textures/_Goobstation/Interface/Radial/RPD/pneumatic_valve.png b/Resources/Textures/_Goobstation/Interface/Radial/RPD/pneumatic_valve.png new file mode 100644 index 00000000000..0ee9ddf3388 Binary files /dev/null and b/Resources/Textures/_Goobstation/Interface/Radial/RPD/pneumatic_valve.png differ diff --git a/Resources/Textures/_Goobstation/Interface/Radial/RPD/port.png b/Resources/Textures/_Goobstation/Interface/Radial/RPD/port.png new file mode 100644 index 00000000000..93a3d5fb6f2 Binary files /dev/null and b/Resources/Textures/_Goobstation/Interface/Radial/RPD/port.png differ diff --git a/Resources/Textures/_Goobstation/Interface/Radial/RPD/pump_manual_valve.png b/Resources/Textures/_Goobstation/Interface/Radial/RPD/pump_manual_valve.png new file mode 100644 index 00000000000..c2860045a33 Binary files /dev/null and b/Resources/Textures/_Goobstation/Interface/Radial/RPD/pump_manual_valve.png differ diff --git a/Resources/Textures/_Goobstation/Interface/Radial/RPD/pump_pressure.png b/Resources/Textures/_Goobstation/Interface/Radial/RPD/pump_pressure.png new file mode 100644 index 00000000000..aee0831c849 Binary files /dev/null and b/Resources/Textures/_Goobstation/Interface/Radial/RPD/pump_pressure.png differ diff --git a/Resources/Textures/_Goobstation/Interface/Radial/RPD/pump_signal_valve.png b/Resources/Textures/_Goobstation/Interface/Radial/RPD/pump_signal_valve.png new file mode 100644 index 00000000000..6f5955990f9 Binary files /dev/null and b/Resources/Textures/_Goobstation/Interface/Radial/RPD/pump_signal_valve.png differ diff --git a/Resources/Textures/_Goobstation/Interface/Radial/RPD/pump_volume.png b/Resources/Textures/_Goobstation/Interface/Radial/RPD/pump_volume.png new file mode 100644 index 00000000000..a3110ec00e3 Binary files /dev/null and b/Resources/Textures/_Goobstation/Interface/Radial/RPD/pump_volume.png differ diff --git a/Resources/Textures/_Goobstation/Interface/Radial/RPD/radiator.png b/Resources/Textures/_Goobstation/Interface/Radial/RPD/radiator.png new file mode 100644 index 00000000000..420d68bc733 Binary files /dev/null and b/Resources/Textures/_Goobstation/Interface/Radial/RPD/radiator.png differ diff --git a/Resources/Textures/_Goobstation/Interface/Radial/RPD/radiator_bend.png b/Resources/Textures/_Goobstation/Interface/Radial/RPD/radiator_bend.png new file mode 100644 index 00000000000..c8696c343fa Binary files /dev/null and b/Resources/Textures/_Goobstation/Interface/Radial/RPD/radiator_bend.png differ diff --git a/Resources/Textures/_Goobstation/Interface/Radial/RPD/scrub_off.png b/Resources/Textures/_Goobstation/Interface/Radial/RPD/scrub_off.png new file mode 100644 index 00000000000..e6da8871ac2 Binary files /dev/null and b/Resources/Textures/_Goobstation/Interface/Radial/RPD/scrub_off.png differ diff --git a/Resources/Textures/_Goobstation/Interface/Radial/RPD/straight.png b/Resources/Textures/_Goobstation/Interface/Radial/RPD/straight.png new file mode 100644 index 00000000000..46239651339 Binary files /dev/null and b/Resources/Textures/_Goobstation/Interface/Radial/RPD/straight.png differ diff --git a/Resources/Textures/_Goobstation/Interface/Radial/RPD/tjunction.png b/Resources/Textures/_Goobstation/Interface/Radial/RPD/tjunction.png new file mode 100644 index 00000000000..c537c0ab762 Binary files /dev/null and b/Resources/Textures/_Goobstation/Interface/Radial/RPD/tjunction.png differ diff --git a/Resources/Textures/_Goobstation/Interface/Radial/RPD/vent_off.png b/Resources/Textures/_Goobstation/Interface/Radial/RPD/vent_off.png new file mode 100644 index 00000000000..c54c3bb519c Binary files /dev/null and b/Resources/Textures/_Goobstation/Interface/Radial/RPD/vent_off.png differ diff --git a/Resources/Textures/_Goobstation/Interface/Radial/RPD/vent_passive.png b/Resources/Textures/_Goobstation/Interface/Radial/RPD/vent_passive.png new file mode 100644 index 00000000000..cc63ae45041 Binary files /dev/null and b/Resources/Textures/_Goobstation/Interface/Radial/RPD/vent_passive.png differ diff --git a/Resources/Textures/_Goobstation/Objects/Tools/rpd.rsi/icon.png b/Resources/Textures/_Goobstation/Objects/Tools/rpd.rsi/icon.png new file mode 100644 index 00000000000..61bc6ccf1d4 Binary files /dev/null and b/Resources/Textures/_Goobstation/Objects/Tools/rpd.rsi/icon.png differ diff --git a/Resources/Textures/_Goobstation/Objects/Tools/rpd.rsi/inhand-left.png b/Resources/Textures/_Goobstation/Objects/Tools/rpd.rsi/inhand-left.png new file mode 100644 index 00000000000..d80f8abf1f1 Binary files /dev/null and b/Resources/Textures/_Goobstation/Objects/Tools/rpd.rsi/inhand-left.png differ diff --git a/Resources/Textures/_Goobstation/Objects/Tools/rpd.rsi/inhand-right.png b/Resources/Textures/_Goobstation/Objects/Tools/rpd.rsi/inhand-right.png new file mode 100644 index 00000000000..951a323c11b Binary files /dev/null and b/Resources/Textures/_Goobstation/Objects/Tools/rpd.rsi/inhand-right.png differ diff --git a/Resources/Textures/_Goobstation/Objects/Tools/rpd.rsi/meta.json b/Resources/Textures/_Goobstation/Objects/Tools/rpd.rsi/meta.json new file mode 100644 index 00000000000..e364a670fc4 --- /dev/null +++ b/Resources/Textures/_Goobstation/Objects/Tools/rpd.rsi/meta.json @@ -0,0 +1,22 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from CEV-Eris at https://github.com/discordia-space/CEV-Eris/blob/8009c1d3db5ca5244f14899ffafaae93be0e318d/icons/obj/items.dmi,https://github.com/discordia-space/CEV-Eris/blob/df81fe2d0ba5f541bafffbb73554f3f44289dd76/icons/mob/items/righthand.dmi,https://github.com/discordia-space/CEV-Eris/blob/df81fe2d0ba5f541bafffbb73554f3f44289dd76/icons/mob/items/righthand.dmi", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/_WL/Objects/Tools/brpd.rsi/icon.png b/Resources/Textures/_WL/Objects/Tools/brpd.rsi/icon.png new file mode 100644 index 00000000000..a204bd96679 Binary files /dev/null and b/Resources/Textures/_WL/Objects/Tools/brpd.rsi/icon.png differ diff --git a/Resources/Textures/_WL/Objects/Tools/brpd.rsi/inhand-left.png b/Resources/Textures/_WL/Objects/Tools/brpd.rsi/inhand-left.png new file mode 100644 index 00000000000..16156b4be27 Binary files /dev/null and b/Resources/Textures/_WL/Objects/Tools/brpd.rsi/inhand-left.png differ diff --git a/Resources/Textures/_WL/Objects/Tools/brpd.rsi/inhand-right.png b/Resources/Textures/_WL/Objects/Tools/brpd.rsi/inhand-right.png new file mode 100644 index 00000000000..f7e2aba760f Binary files /dev/null and b/Resources/Textures/_WL/Objects/Tools/brpd.rsi/inhand-right.png differ diff --git a/Resources/Textures/_WL/Objects/Tools/brpd.rsi/meta.json b/Resources/Textures/_WL/Objects/Tools/brpd.rsi/meta.json new file mode 100644 index 00000000000..52d612974a5 --- /dev/null +++ b/Resources/Textures/_WL/Objects/Tools/brpd.rsi/meta.json @@ -0,0 +1,33 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from TG Station", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "icon", + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + } + ] +} diff --git a/Resources/Textures/_WL/Objects/Tools/cercd.rsi/icon.png b/Resources/Textures/_WL/Objects/Tools/cercd.rsi/icon.png new file mode 100644 index 00000000000..214c73b5d96 Binary files /dev/null and b/Resources/Textures/_WL/Objects/Tools/cercd.rsi/icon.png differ diff --git a/Resources/Textures/_WL/Objects/Tools/cercd.rsi/inhand-left.png b/Resources/Textures/_WL/Objects/Tools/cercd.rsi/inhand-left.png new file mode 100644 index 00000000000..e440aa76e62 Binary files /dev/null and b/Resources/Textures/_WL/Objects/Tools/cercd.rsi/inhand-left.png differ diff --git a/Resources/Textures/_WL/Objects/Tools/cercd.rsi/inhand-right.png b/Resources/Textures/_WL/Objects/Tools/cercd.rsi/inhand-right.png new file mode 100644 index 00000000000..fcdae379158 Binary files /dev/null and b/Resources/Textures/_WL/Objects/Tools/cercd.rsi/inhand-right.png differ diff --git a/Resources/Textures/_WL/Objects/Tools/cercd.rsi/meta.json b/Resources/Textures/_WL/Objects/Tools/cercd.rsi/meta.json new file mode 100644 index 00000000000..ab261a16c21 --- /dev/null +++ b/Resources/Textures/_WL/Objects/Tools/cercd.rsi/meta.json @@ -0,0 +1,22 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from TG Station", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} \ No newline at end of file