diff --git a/Content.Server/Shipyard/Systems/ShipyardSystem.Consoles.cs b/Content.Server/Shipyard/Systems/ShipyardSystem.Consoles.cs
index b740900b66d..629d2e12ed4 100644
--- a/Content.Server/Shipyard/Systems/ShipyardSystem.Consoles.cs
+++ b/Content.Server/Shipyard/Systems/ShipyardSystem.Consoles.cs
@@ -36,6 +36,7 @@
using Content.Server.Shuttles.Components;
using Content.Server.Station.Components;
using System.Text.RegularExpressions;
+using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
namespace Content.Server.Shipyard.Systems;
@@ -438,12 +439,12 @@ private void SendSellMessage(EntityUid uid, EntityUid? player, string name, stri
private void PlayDenySound(EntityUid uid, ShipyardConsoleComponent component)
{
- _audio.PlayPvs(_audio.GetSound(component.ErrorSound), uid);
+ _audio.PlayPvs(_audio.GetSound(component.ErrorSound), uid, AudioParams.Default.WithMaxDistance(0.01f));
}
private void PlayConfirmSound(EntityUid uid, ShipyardConsoleComponent component)
{
- _audio.PlayPvs(_audio.GetSound(component.ConfirmSound), uid);
+ _audio.PlayPvs(_audio.GetSound(component.ConfirmSound), uid, AudioParams.Default.WithMaxDistance(0.01f));
}
private void OnItemSlotChanged(EntityUid uid, ShipyardConsoleComponent component, ContainerModifiedMessage args)
diff --git a/Content.Shared/Access/Components/IdCardComponent.cs b/Content.Shared/Access/Components/IdCardComponent.cs
index 26e83c5586e..9459f6c1910 100644
--- a/Content.Shared/Access/Components/IdCardComponent.cs
+++ b/Content.Shared/Access/Components/IdCardComponent.cs
@@ -1,6 +1,7 @@
using Content.Shared.Access.Systems;
using Content.Shared.PDA;
using Content.Shared.StatusIcon;
+using Robust.Shared.Audio;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
@@ -40,4 +41,21 @@ public sealed partial class IdCardComponent : Component
///
[DataField, ViewVariables(VVAccess.ReadWrite)]
public bool BypassLogging;
+
+
+ // Frontier
+ [DataField("soundError")]
+ public SoundSpecifier ErrorSound =
+ new SoundPathSpecifier("/Audio/Effects/Cargo/buzz_sigh.ogg");
+
+ // Frontier
+ [DataField("soundSwipe")]
+ public SoundSpecifier SwipeSound =
+ new SoundPathSpecifier("/Audio/Machines/id_swipe.ogg");
+
+ // Frontier
+ [DataField("soundInsert")]
+ public SoundSpecifier InsertSound =
+ new SoundPathSpecifier("/Audio/Machines/id_insert.ogg");
+
}
diff --git a/Content.Shared/RCD/Components/RCDAmmoComponent.cs b/Content.Shared/RCD/Components/RCDAmmoComponent.cs
index 7b1fc001d4d..16a92b6aa25 100644
--- a/Content.Shared/RCD/Components/RCDAmmoComponent.cs
+++ b/Content.Shared/RCD/Components/RCDAmmoComponent.cs
@@ -13,6 +13,13 @@ public sealed partial class RCDAmmoComponent : Component
///
[DataField("charges"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
public int Charges = 5;
+
+ ///
+ /// ~~~ Frontier ~~~
+ /// A flag that limits RCD to the authorized ships.
+ ///
+ [DataField("isShipyardRCDAmmo"), AutoNetworkedField]
+ public bool IsShipyardRCDAmmo;
}
// TODO: state??? check if it desyncs
diff --git a/Content.Shared/RCD/Components/RCDComponent.cs b/Content.Shared/RCD/Components/RCDComponent.cs
index 8e1032884aa..68271b1a102 100644
--- a/Content.Shared/RCD/Components/RCDComponent.cs
+++ b/Content.Shared/RCD/Components/RCDComponent.cs
@@ -48,4 +48,18 @@ public sealed partial class RCDComponent : Component
[DataField("floor", customTypeSerializer: typeof(PrototypeIdSerializer))]
[ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
public string Floor = "FloorSteel";
+
+ ///
+ /// ~~~ Frontier ~~~
+ /// A flag that limits RCD to the authorized ships.
+ ///
+ [DataField("isShipyardRCD"), AutoNetworkedField]
+ public bool IsShipyardRCD;
+
+ ///
+ /// ~~~ Frontier ~~~
+ /// The uid to which this RCD is limited to be used on.
+ ///
+ [DataField("linkedShuttleUid"), AutoNetworkedField]
+ public EntityUid? LinkedShuttleUid = null;
}
diff --git a/Content.Shared/RCD/Systems/RCDAmmoSystem.cs b/Content.Shared/RCD/Systems/RCDAmmoSystem.cs
index 9481d299aaa..9136e337e28 100644
--- a/Content.Shared/RCD/Systems/RCDAmmoSystem.cs
+++ b/Content.Shared/RCD/Systems/RCDAmmoSystem.cs
@@ -42,6 +42,16 @@ private void OnAfterInteract(EntityUid uid, RCDAmmoComponent comp, AfterInteract
return;
var user = args.User;
+
+ // ## Frontier - Shipyard RCD ammo only fits in shipyard RCD.
+ // At this point RCDComponent is guaranteed
+ EnsureComp(target, out var rcdComponent);
+ if (rcdComponent.IsShipyardRCD && !comp.IsShipyardRCDAmmo || !rcdComponent.IsShipyardRCD && comp.IsShipyardRCDAmmo)
+ {
+ _popup.PopupClient(Loc.GetString("rcd-component-wrong-ammo-type"), target, user);
+ return;
+ }
+
args.Handled = true;
var count = Math.Min(charges.MaxCharges - charges.Charges, comp.Charges);
if (count <= 0)
diff --git a/Content.Shared/RCD/Systems/RCDSystem.cs b/Content.Shared/RCD/Systems/RCDSystem.cs
index 2b9852a6945..f93ecb12fd2 100644
--- a/Content.Shared/RCD/Systems/RCDSystem.cs
+++ b/Content.Shared/RCD/Systems/RCDSystem.cs
@@ -1,3 +1,4 @@
+using Content.Shared.Access.Components;
using Content.Shared.Administration.Logs;
using Content.Shared.Charges.Components;
using Content.Shared.Charges.Systems;
@@ -10,6 +11,7 @@
using Content.Shared.Physics;
using Content.Shared.Popups;
using Content.Shared.RCD.Components;
+using Content.Shared.Shipyard.Components;
using Content.Shared.Tag;
using Content.Shared.Tiles;
using Robust.Shared.Audio;
@@ -50,6 +52,7 @@ public override void Initialize()
SubscribeLocalEvent(OnAfterInteract);
SubscribeLocalEvent(OnDoAfter);
SubscribeLocalEvent>(OnDoAfterAttempt);
+ SubscribeLocalEvent(OnIdCardSwipeHappened); // Frontier
}
private void OnExamine(EntityUid uid, RCDComponent comp, ExaminedEvent args)
@@ -70,6 +73,56 @@ private void OnUseInHand(EntityUid uid, RCDComponent comp, UseInHandEvent args)
args.Handled = true;
}
+ /**
+ * Frontier - ability to swipe rcd for authorizations to build on specific grids
+ */
+ private void OnIdCardSwipeHappened(EntityUid uid, IdCardComponent comp, ref AfterInteractEvent args)
+ {
+ if (args.Handled)
+ return;
+
+ if (args.Target is not { Valid: true } target || !args.CanReach)
+ return;
+
+ var rcdEntityUid = target;
+
+ // Is this id card interacting with a shipyard RCD ? if not, ignore it.
+ if (!TryComp(rcdEntityUid, out var rcdComponent) || !rcdComponent.IsShipyardRCD)
+ {
+ args.Handled = true;
+ return;
+ }
+
+ // If the id card has no registered ship we cant continue.
+ if (!TryComp(comp.Owner, out var shuttleDeedComponent))
+ {
+ _popup.PopupClient(Loc.GetString("rcd-component-missing-id-deed"),
+ uid, args.User, PopupType.Medium);
+ _audio.PlayPredicted(comp.ErrorSound, rcdEntityUid, args.User, AudioParams.Default.WithMaxDistance(0.01f));
+ args.Handled = true;
+ return;
+ }
+
+ // Swiping it again removes the authorization on it.
+ if (rcdComponent.LinkedShuttleUid != null)
+ {
+ _popup.PopupClient(Loc.GetString("rcd-component-id-card-removed"),
+ uid, args.User, PopupType.Medium);
+ _audio.PlayPredicted(comp.SwipeSound, rcdEntityUid, args.User, AudioParams.Default.WithMaxDistance(0.01f));
+ rcdComponent.LinkedShuttleUid = null;
+ }
+ else
+ {
+ _popup.PopupClient(Loc.GetString("rcd-component-id-card-accepted"),
+ uid, args.User, PopupType.Medium);
+ _audio.PlayPredicted(comp.InsertSound, rcdEntityUid, args.User, AudioParams.Default.WithMaxDistance(0.01f));
+ rcdComponent.LinkedShuttleUid = shuttleDeedComponent.ShuttleUid;
+ }
+
+ Dirty(rcdComponent.Owner, rcdComponent);
+ args.Handled = true;
+ }
+
private void OnAfterInteract(EntityUid uid, RCDComponent comp, AfterInteractEvent args)
{
if (args.Handled || !args.CanReach)
@@ -111,10 +164,48 @@ private void OnAfterInteract(EntityUid uid, RCDComponent comp, AfterInteractEven
args.Handled = true;
- if (_doAfter.TryStartDoAfter(doAfterArgs) && _gameTiming.IsFirstTimePredicted)
+ // IsAuthorized is part of frontier
+ if (IsAuthorized(gridId, uid, comp, args) && _doAfter.TryStartDoAfter(doAfterArgs) && _gameTiming.IsFirstTimePredicted)
Spawn("EffectRCDConstruction", location);
}
+ /**
+ * Frontier - Stops RCD functions if there is a protected grid component on it, and adds shipyard rcd limitations.
+ */
+ private bool IsAuthorized(EntityUid? gridId, EntityUid uid, RCDComponent comp, AfterInteractEvent args)
+ {
+ if (gridId == null)
+ {
+ return true;
+ }
+ var mapGrid = _mapMan.GetGrid(gridId.Value);
+ var gridUid = mapGrid.Owner;
+
+ // Frontier - Remove all RCD use on outpost.
+ if (HasComp(gridUid))
+ {
+ _popup.PopupClient(Loc.GetString("rcd-component-use-blocked"), uid, args.User);
+ return false;
+ }
+
+ // Frontier - LinkedShuttleUid requirements to use Shipyard RCD.
+ if (comp.IsShipyardRCD)
+ {
+ if (comp.LinkedShuttleUid == null)
+ {
+ _popup.PopupClient(Loc.GetString("rcd-component-no-id-swiped"), uid, args.User);
+ return false;
+ }
+ if (comp.LinkedShuttleUid != gridUid)
+ {
+ _popup.PopupClient(Loc.GetString("rcd-component-can-only-build-authorized-ship"), uid, args.User);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
private void OnDoAfterAttempt(EntityUid uid, RCDComponent comp, DoAfterAttemptEvent args)
{
// sus client crash why
@@ -162,14 +253,6 @@ private void OnDoAfter(EntityUid uid, RCDComponent comp, RCDDoAfterEvent args)
var tile = mapGrid.GetTileRef(location);
var snapPos = mapGrid.TileIndicesFor(location);
- // I love that this uses entirely separate code to construction and tile placement!!!
-
- var gridUid = mapGrid.Owner;
- var ev = new FloorTileAttemptEvent();
-
- if (HasComp(gridUid) || ev.Cancelled) // Frontier - Remove all RCD use on outpost.
- return;
-
switch (comp.Mode)
{
//Floor mode just needs the tile to be a space tile (subFloor)
diff --git a/Content.Shared/Shipyard/Components/ShuttleDeedComponent.cs b/Content.Shared/Shipyard/Components/ShuttleDeedComponent.cs
index ef66b5ff989..1ff534afbcb 100644
--- a/Content.Shared/Shipyard/Components/ShuttleDeedComponent.cs
+++ b/Content.Shared/Shipyard/Components/ShuttleDeedComponent.cs
@@ -1,9 +1,11 @@
+using Robust.Shared.GameStates;
+
namespace Content.Shared.Shipyard.Components;
///
/// Tied to an ID card when a ship is purchased. 1 ship per captain.
///
-[RegisterComponent, Access(typeof(SharedShipyardSystem))]
+[RegisterComponent, NetworkedComponent, Access(typeof(SharedShipyardSystem))]
public sealed partial class ShuttleDeedComponent : Component
{
public const int MaxNameLength = 30;
diff --git a/Resources/Locale/en-US/_NF/research/technologies.ftl b/Resources/Locale/en-US/_NF/research/technologies.ftl
index b706785d5fe..450e9a9d736 100644
--- a/Resources/Locale/en-US/_NF/research/technologies.ftl
+++ b/Resources/Locale/en-US/_NF/research/technologies.ftl
@@ -1,4 +1,5 @@
research-techology-advanced-personal-propulsion = Advanced Personal Propulsion
+research-technology-rapid-construction = Rapid Construction
research-technology-hardsuits-basic = Basic Hardsuits
research-technology-hardsuits-specialized = Specialized Hardsuits
research-technology-hardsuits-advanced = Advanced Hardsuits
diff --git a/Resources/Locale/en-US/_NF/shipyard/shipyard-rcd-component.ftl b/Resources/Locale/en-US/_NF/shipyard/shipyard-rcd-component.ftl
new file mode 100644
index 00000000000..ee6dac465c4
--- /dev/null
+++ b/Resources/Locale/en-US/_NF/shipyard/shipyard-rcd-component.ftl
@@ -0,0 +1,8 @@
+## UI
+rcd-component-missing-id-deed = No ship registered to this ID
+rcd-component-can-only-build-authorized-ship = Can only build on authorized ships!
+rcd-component-no-id-swiped = Swipe id card on RCD to authorize.
+rcd-component-use-blocked = The RCD whirrs, but nothing happens.
+rcd-component-id-card-accepted = You swipe the id card and the RCD makes a accepting noise.
+rcd-component-id-card-removed = The RCD powers down, unauthorizing it.
+rcd-component-wrong-ammo-type = Wrong type of RCD ammo.
diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/engivend.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/engivend.yml
index 292d93ab452..0c11ae10c2e 100644
--- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/engivend.yml
+++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/engivend.yml
@@ -11,3 +11,5 @@
GeigerCounter: 10 # Frontier
PowerCellMedium: 15
# NetworkConfigurator: 15
+ ShipyardRCD: 10
+ ShipyardRCDAmmo: 20
diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
index e4e23c8ddc8..cfa378dec6f 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
@@ -283,6 +283,8 @@
- AnomalyLocatorWide
- RCD
- RCDAmmo
+ - ShipyardRCD # Frontier
+ - ShipyardRCDAmmo # Frontier
- Scalpel
- Retractor
- Cautery
diff --git a/Resources/Prototypes/Research/industrial.yml b/Resources/Prototypes/Research/industrial.yml
index 37beffccbbc..eafa72a0b21 100644
--- a/Resources/Prototypes/Research/industrial.yml
+++ b/Resources/Prototypes/Research/industrial.yml
@@ -198,3 +198,16 @@
- PowerCellMicroreactor
technologyPrerequisites:
- AdvancedPowercells
+
+- type: technology
+ id: RapidConstruction
+ name: research-technology-rapid-construction
+ icon:
+ sprite: Objects/Tools/rcd.rsi
+ state: icon
+ discipline: Industrial
+ tier: 2
+ cost: 10000
+ recipeUnlocks:
+ - ShipyardRCD
+ - ShipyardRCDAmmo
diff --git a/Resources/Prototypes/_NF/Entities/Objects/Tools/shipyard_rcd.yml b/Resources/Prototypes/_NF/Entities/Objects/Tools/shipyard_rcd.yml
new file mode 100644
index 00000000000..a2ef2214564
--- /dev/null
+++ b/Resources/Prototypes/_NF/Entities/Objects/Tools/shipyard_rcd.yml
@@ -0,0 +1,37 @@
+- type: entity
+ name: Shipyard RCD
+ parent: BaseItem
+ id: ShipyardRCD
+ description: An advanced construction device which can place/remove walls, floors, and airlocks quickly. It has a slot to swipe ID cards.
+ components:
+ - type: RCD
+ isShipyardRCD: true
+ - type: LimitedCharges
+ maxCharges: 5
+ charges: 5
+ - type: UseDelay
+ - type: Sprite
+ sprite: Objects/Tools/rcd.rsi
+ state: icon-shipyard
+ - type: Item
+ size: Normal
+ - type: Clothing
+ sprite: Objects/Tools/rcd.rsi
+ quickEquip: false
+ slots:
+ - Belt
+ - type: PhysicalComposition
+ materialComposition:
+ Steel: 5000
+ Plastic: 1000
+ - type: StaticPrice
+ price: 500
+
+- type: entity
+ id: ShipyardRCDEmpty
+ parent: ShipyardRCD
+ suffix: Empty
+ components:
+ - type: LimitedCharges
+ maxCharges: 5
+ charges: 0
diff --git a/Resources/Prototypes/_NF/Recipes/Lathes/devices.yml b/Resources/Prototypes/_NF/Recipes/Lathes/devices.yml
index 68f30ba047f..6565ac3cba6 100644
--- a/Resources/Prototypes/_NF/Recipes/Lathes/devices.yml
+++ b/Resources/Prototypes/_NF/Recipes/Lathes/devices.yml
@@ -35,3 +35,21 @@
Glass: 500
Plastic: 50
Gold: 100
+
+- type: latheRecipe
+ id: ShipyardRCD
+ result: ShipyardRCDEmpty
+ category: Tools
+ completetime: 4
+ materials:
+ Steel: 1000
+ Plastic: 300
+
+- type: latheRecipe
+ id: ShipyardRCDAmmo
+ result: ShipyardRCDAmmo
+ category: Tools
+ completetime: 2.4
+ materials:
+ Steel: 500
+ Plastic: 250
diff --git a/Resources/Prototypes/_NF/Recipes/Lathes/tools.yml b/Resources/Prototypes/_NF/Recipes/Lathes/tools.yml
new file mode 100644
index 00000000000..48ae087fd7a
--- /dev/null
+++ b/Resources/Prototypes/_NF/Recipes/Lathes/tools.yml
@@ -0,0 +1,20 @@
+- type: entity
+ name: Shipyard RCD Ammo
+ parent: BaseItem
+ id: ShipyardRCDAmmo
+ description: Ammo cartridge for a Shipyard RCD.
+ components:
+ - type: RCDAmmo
+ isShipyardRCDAmmo: true
+ - type: Sprite
+ sprite: Objects/Tools/rcd.rsi
+ state: ammo-shipyard
+ - type: Item
+ sprite: Objects/Tools/rcd.rsi
+ heldPrefix: ammo-shipyard
+ - type: PhysicalComposition
+ materialComposition:
+ Steel: 1000
+ Plastic: 1000
+ - type: StaticPrice
+ price: 100
diff --git a/Resources/Textures/Objects/Tools/rcd.rsi/ammo-shipyard.png b/Resources/Textures/Objects/Tools/rcd.rsi/ammo-shipyard.png
new file mode 100644
index 00000000000..e7ecb309989
Binary files /dev/null and b/Resources/Textures/Objects/Tools/rcd.rsi/ammo-shipyard.png differ
diff --git a/Resources/Textures/Objects/Tools/rcd.rsi/icon-shipyard.png b/Resources/Textures/Objects/Tools/rcd.rsi/icon-shipyard.png
new file mode 100644
index 00000000000..7e038d4bb5b
Binary files /dev/null and b/Resources/Textures/Objects/Tools/rcd.rsi/icon-shipyard.png differ
diff --git a/Resources/Textures/Objects/Tools/rcd.rsi/meta.json b/Resources/Textures/Objects/Tools/rcd.rsi/meta.json
index 4b9b1914006..d9dde9dcfa3 100644
--- a/Resources/Textures/Objects/Tools/rcd.rsi/meta.json
+++ b/Resources/Textures/Objects/Tools/rcd.rsi/meta.json
@@ -10,6 +10,9 @@
{
"name": "icon"
},
+ {
+ "name": "icon-shipyard"
+ },
{
"name": "icon-experimental"
},
@@ -18,6 +21,9 @@
},
{
"name": "ammo"
+ },
+ {
+ "name": "ammo-shipyard"
},
{
"name": "ammo-inhand-left",