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",