diff --git a/Content.Server/_CorvaxNext/Silicons/Borgs/AiRemoteControlSystem.cs b/Content.Server/_CorvaxNext/Silicons/Borgs/AiRemoteControlSystem.cs index 9c28cbc3cff..c1b9d8e7207 100644 --- a/Content.Server/_CorvaxNext/Silicons/Borgs/AiRemoteControlSystem.cs +++ b/Content.Server/_CorvaxNext/Silicons/Borgs/AiRemoteControlSystem.cs @@ -19,6 +19,9 @@ using Content.Shared.Body.Part; using Robust.Shared.Containers; using Robust.Shared.Player; +using Content.Shared._HL.Silicons.Components; +using Content.Shared.Interaction.Events; +using Content.Server.Popups; namespace Content.Server._CorvaxNext.Silicons.Borgs; @@ -35,6 +38,7 @@ public sealed class AiRemoteControlSystem : SharedAiRemoteControlSystem [Dependency] private readonly SharedTransformSystem _xformSystem = default!; [Dependency] private readonly PositronicJumpSystem _positronicJumpSystem = default!; //Hardlight: Incorporates positronic jump system into transfer [Dependency] private readonly TransformSystem _transformSystem = default!; //Used to prevent AI from selecting borgs from list that aren't on same grid + [Dependency] private readonly PopupSystem _popupSystem = default!; public override void Initialize() { @@ -49,7 +53,26 @@ public override void Initialize() SubscribeLocalEvent(OnBrainInserted); SubscribeLocalEvent(OnBrainRemoved); + + SubscribeLocalEvent(OnShuntRadioUsed); //Hardlight: For setting the AIShuntRadioComponent grid + } + + //Hardlight: + /// + /// Sets the receiver's assigned grid so an AI on that grid can access it. + /// + /// + /// + private void OnShuntRadioUsed(Entity ent, ref UseInHandEvent args) + { + if (!TryComp(ent, out var radioComponent)) + return; + + radioComponent.AssignedGrid = _transformSystem.GetGrid(args.User); + + _popupSystem.PopupEntity("Radio linked to local grid", args.User, args.User); } + //Hardlight End private void OnBrainInserted(EntityUid uid, AiRemoteBrainComponent component, EntGotInsertedIntoContainerMessage args) { @@ -204,7 +227,15 @@ private void OnToggleRemoteDevicesScreen(EntityUid uid, StationAiHeldComponent c var targetEntity = GetEntity(GetNetEntity(queryUid)); var targetGrid = _transformSystem.GetGrid(targetEntity); - if (targetGrid == null || targetGrid != aiGrid) + //Checks to make sure the borg entity has the AIShuntReceiver component + if (!TryComp(targetEntity, out var chassis)) + continue; + + if (!TryComp(chassis.BrainContainer.ContainedEntity, out var radioComponent)) + continue; + + //Checks to make sure AIShuntReceiver is set to proper grid + if (radioComponent.AssignedGrid == null || radioComponent?.AssignedGrid != aiGrid) continue; //Only lists borgs that pass the valid candidate check @@ -212,6 +243,7 @@ private void OnToggleRemoteDevicesScreen(EntityUid uid, StationAiHeldComponent c if (!_positronicJumpSystem.IsTargetValidControlCandidate(uid, targetEntity)) continue; //Hardlight end + var data = new RemoteDevicesData { NetEntityUid = GetNetEntity(queryUid), diff --git a/Content.Server/_CorvaxNext/Silicons/Borgs/PositronicJumpSystem.cs b/Content.Server/_CorvaxNext/Silicons/Borgs/PositronicJumpSystem.cs index a443e1b1d38..d0cb8eeeccf 100644 --- a/Content.Server/_CorvaxNext/Silicons/Borgs/PositronicJumpSystem.cs +++ b/Content.Server/_CorvaxNext/Silicons/Borgs/PositronicJumpSystem.cs @@ -1,25 +1,28 @@ -using System.Linq; +using Content.Server._CorvaxNext.Silicons.Borgs.Components; +using Content.Server._Mono.SpaceArtillery.Components; +using Content.Server._NF.Roles.Systems; // VRS: move JobTrackingComponent across shunt (HL #1354) using Content.Server.Mech.Systems; using Content.Server.Silicons.Borgs; using Content.Server.Silicons.Laws; using Content.Server.SurveillanceCamera; -using Content.Server._CorvaxNext.Silicons.Borgs.Components; -using Content.Server._Mono.SpaceArtillery.Components; -using Content.Server._NF.Roles.Systems; // VRS: move JobTrackingComponent across shunt (HL #1354) +using Content.Shared._CorvaxNext.Silicons.Borgs; +using Content.Shared._HL.Silicons.Components; using Content.Shared._NF.Roles.Components; // VRS: move JobTrackingComponent across shunt (HL #1354) -using Content.Shared.Mech.Components; using Content.Shared.Actions; +using Content.Shared.Mech.Components; using Content.Shared.Mind; using Content.Shared.PAI; using Content.Shared.Popups; -using Content.Shared._CorvaxNext.Silicons.Borgs; +using Content.Shared.Roles.Jobs; using Content.Shared.Silicons.Borgs.Components; using Content.Shared.Silicons.Laws.Components; using Content.Shared.Silicons.StationAi; using Content.Shared.Turrets; using Content.Shared.Verbs; -using Robust.Shared.GameStates; +using Robust.Server.GameObjects; using Robust.Shared.Containers; +using Robust.Shared.GameStates; +using System.Linq; namespace Content.Server._CorvaxNext.Silicons.Borgs; @@ -33,6 +36,7 @@ public sealed class PositronicJumpSystem : EntitySystem [Dependency] private readonly MechSystem _mech = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly JobTrackingSystem _jobTracking = default!; // VRS: HL #1354 + [Dependency] private readonly TransformSystem _transformSystem = default!; private const string ReturnToAiAction = "ActionBackToAi"; @@ -118,6 +122,10 @@ private void OnBorgChassisGetVerbs(EntityUid uid, BorgChassisComponent component if (_mind.TryGetMind(uid, out _, out _)) return; + //Hardlight: If the user is an AI, then make sure target isn't invalid borg + if (HasComp(args.User) && !AITargetingValidBorg(args.User, uid)) + return; + //Hardlight End var user = args.User; var target = uid; @@ -329,6 +337,11 @@ public bool TryTakeControl(EntityUid user, EntityUid target) if (mind.OwnedEntity == target) return false; + //Hardlight: If user is AI make sure they're not taking over an invalid borg + if (HasComp(user) && !AITargetingValidBorg(user, target)) + return false; + //Hardlight end + if (mind.OwnedEntity != null) TransferReturnState(mind.OwnedEntity.Value, target); @@ -362,6 +375,28 @@ public bool IsTargetValidControlCandidate(EntityUid user, EntityUid target) return true; } + //Hardlight: + /// + /// Checks if the target is a borg and if so, make sure it has the proper receiver + /// installed to restrict AI takeovers. + /// + /// + /// + /// + public bool AITargetingValidBorg(EntityUid user, EntityUid target) + { + if (!TryComp(target, out var chassis)) + return true; + + if (!TryComp(chassis.BrainContainer.ContainedEntity, out var radioComponent)) + return false; + + if (radioComponent.AssignedGrid == null || radioComponent?.AssignedGrid != _transformSystem.GetGrid(user)) + return false; + + return true; + } + //Hardlight End public bool TryReturnControl(EntityUid target) { if (TryComp(target, out var remoteMechPilot)) diff --git a/Content.Shared/_HL/Silicons/Components/AIShuntReceiverComponent.cs b/Content.Shared/_HL/Silicons/Components/AIShuntReceiverComponent.cs new file mode 100644 index 00000000000..956162c6e02 --- /dev/null +++ b/Content.Shared/_HL/Silicons/Components/AIShuntReceiverComponent.cs @@ -0,0 +1,15 @@ +using Robust.Shared.GameStates; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Content.Shared._HL.Silicons.Components +{ + [RegisterComponent, NetworkedComponent] + public sealed partial class AIShuntReceiverComponent : Component + { + [ViewVariables] + [DataField] + public EntityUid? AssignedGrid = null; + } +} diff --git a/Resources/Prototypes/Recipes/Lathes/Packs/robotics.yml b/Resources/Prototypes/Recipes/Lathes/Packs/robotics.yml index 72261e21d76..937a9cf64f2 100644 --- a/Resources/Prototypes/Recipes/Lathes/Packs/robotics.yml +++ b/Resources/Prototypes/Recipes/Lathes/Packs/robotics.yml @@ -5,6 +5,7 @@ recipes: - MMI - PositronicBrain + - AIShuntReceiver # Hardlight - SciFlash - CyborgEndoskeleton - Quadborgendoskeleton diff --git a/Resources/Prototypes/Recipes/Lathes/robotics.yml b/Resources/Prototypes/Recipes/Lathes/robotics.yml index fe75756551e..7e78227c859 100644 --- a/Resources/Prototypes/Recipes/Lathes/robotics.yml +++ b/Resources/Prototypes/Recipes/Lathes/robotics.yml @@ -246,6 +246,20 @@ Silver: 100 Plasma: 1000 +# Hardlight +- type: latheRecipe + parent: BaseRoboticsRecipe + id: AIShuntReceiver + result: AIShuntReceiver + completetime: 3 + materials: + Steel: 500 + Plastic: 500 + Gold: 100 + Silver: 100 + Plasma: 1000 +# Hardlight End + # Modules - type: latheRecipe diff --git a/Resources/Prototypes/_HL/Entities/Objects/Specific/Robotics/mmi.yml b/Resources/Prototypes/_HL/Entities/Objects/Specific/Robotics/mmi.yml new file mode 100644 index 00000000000..caa159542ab --- /dev/null +++ b/Resources/Prototypes/_HL/Entities/Objects/Specific/Robotics/mmi.yml @@ -0,0 +1,54 @@ +- type: entity + parent: [ BaseItem, BaseSiliconBrainLanguages ] + id: AIShuntReceiver + name: AI Shunt Receiver + description: A long range receiver for an AI to shunt into. Works off-grid at any distance. Must be linked to AI's grid first. + components: + - type: Sprite + sprite: _HL/Objects/Specific/Robotics/mmi.rsi + layers: + - state: aishuntreceiver + - state: aishuntreceiver_overlay + - type: Input + context: human + - type: Organ + slotId: brain + - type: Brain + - type: BlockMovement + - type: Examiner + - type: BorgBrain + - type: IntrinsicRadioReceiver + - type: IntrinsicRadioTransmitter + channels: + - Binary + - type: ActiveRadio + channels: + - Binary + - Common + - type: NameIdentifier + group: PositronicBrain + - type: DoAfter + - type: Actions + - type: TypingIndicator + proto: robot + - type: Speech + speechSounds: Pai + - type: Alerts + - type: MobState + allowedStates: + - Alive + - Dead + - type: Appearance + - type: Tag + tags: + - CannotSuicide + - type: GuideHelp + guides: + - Cyborgs + - Robotics + - type: ChangeVoiceInContainer + whitelist: + components: + - SecretStash + - type: RetroMonitorView # Mono - #3902 + - type: AIShuntReceiver diff --git a/Resources/Textures/_HL/Objects/Specific/Robotics/mmi.rsi/aishuntreceiver.png b/Resources/Textures/_HL/Objects/Specific/Robotics/mmi.rsi/aishuntreceiver.png new file mode 100644 index 00000000000..1539f14d517 Binary files /dev/null and b/Resources/Textures/_HL/Objects/Specific/Robotics/mmi.rsi/aishuntreceiver.png differ diff --git a/Resources/Textures/_HL/Objects/Specific/Robotics/mmi.rsi/aishuntreceiver_overlay.png b/Resources/Textures/_HL/Objects/Specific/Robotics/mmi.rsi/aishuntreceiver_overlay.png new file mode 100644 index 00000000000..82dd4c64f6f Binary files /dev/null and b/Resources/Textures/_HL/Objects/Specific/Robotics/mmi.rsi/aishuntreceiver_overlay.png differ diff --git a/Resources/Textures/_HL/Objects/Specific/Robotics/mmi.rsi/meta.json b/Resources/Textures/_HL/Objects/Specific/Robotics/mmi.rsi/meta.json new file mode 100644 index 00000000000..11686c561df --- /dev/null +++ b/Resources/Textures/_HL/Objects/Specific/Robotics/mmi.rsi/meta.json @@ -0,0 +1,23 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "PAI overlay sprite taken from tgstation at commit https://github.com/tgstation/tgstation/commit/9ddb8cf084e292571d4e9c79745db25befbd82fe and edited by Typheus", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "aishuntreceiver" + }, + { + "name": "aishuntreceiver_overlay", + "delays": [ + [ + 0.8, + 0.8 + ] + ] + } + ] +}