]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Fake mindshield componentry and Implanter (#34079)
authorZachary Higgs <compgeek223@gmail.com>
Tue, 28 Jan 2025 02:37:46 +0000 (22:37 -0400)
committerGitHub <noreply@github.com>
Tue, 28 Jan 2025 02:37:46 +0000 (18:37 -0800)
* Fake Mindshield (With some bad sprites)

- Add FakeMindshield System and Component

- Add FakeMindsheildImplantSystem and Component

- modify ShowMindShieldIconsSystem to check for FakeMindshields

- add all supporting yaml for the Implants, action and uplink

- add loc file stuff

- add unfinished sprites

* Cleanup, add to thief toolbox, remove metagame

- Move Implant sameness check to AFTER the implant DoAfter
to prevent instant identification of Deception Implants

- cleanup the systems and components

- add the fake mindshield to the Thief toolbox

* part 1 of fixing the folder problem

* Make the fakemindshield sprite folder lowercase

* CR - Move ImplantCheck into shared, cleanup

- Moved ImplantCheck and eventsubscription into Shared

- Remove Client/Server extensions of FakeMindshieldImplantSystem and
FakeMindShieldSystem and make shared Sealed

- make OnToggleMindshield Private, use the event!

* CR - Cleanup extra lines, fix some Prototype

- cleaned up extra liens in ImplanterSystem and
SharedFakeMindshieldSystem from when i was developing

- Uplink catalog no longer lists the implant in 2 spots,
only implants now, also uses the On state action icon

- added a comment about why it's reraising the action event
rather than directly interacting with the FakeMindshield Component

* Fake Mindshield CR:

- Added a comment about IsEnabled

- moved OnFakeMindShieldToggle to Entity<> from Uid, Comp

- fixed some formatting in uplink_catalog

* CR - Add a bit more comment

17 files changed:
Content.Client/Overlays/ShowMindShieldIconsSystem.cs
Content.Server/Implants/ImplanterSystem.cs
Content.Shared/Implants/SharedImplanterSystem.cs
Content.Shared/Mindshield/Components/FakeMindShieldImplantComponent.cs [new file with mode: 0644]
Content.Shared/Mindshield/Components/FakeMindshieldComponent.cs [new file with mode: 0644]
Content.Shared/Mindshield/FakeMindShield/SharedFakeMindShieldImplantSystem.cs [new file with mode: 0644]
Content.Shared/Mindshield/FakeMindShield/SharedFakeMindshieldSystem.cs [new file with mode: 0644]
Resources/Locale/en-US/implant/implant.ftl
Resources/Locale/en-US/store/uplink-catalog.ftl
Resources/Prototypes/Actions/types.yml
Resources/Prototypes/Catalog/thief_toolbox_sets.yml
Resources/Prototypes/Catalog/uplink_catalog.yml
Resources/Prototypes/Entities/Objects/Misc/implanters.yml
Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml
Resources/Textures/Interface/Actions/actions_fakemindshield.rsi/icon-on.png [new file with mode: 0644]
Resources/Textures/Interface/Actions/actions_fakemindshield.rsi/icon.png [new file with mode: 0644]
Resources/Textures/Interface/Actions/actions_fakemindshield.rsi/meta.json [new file with mode: 0644]

index cdb9c54fdfa41a56c35c4c4b45952d641c079617..8f8b8e6407754e598a46b9bdf3197ffc9e7b6b6a 100644 (file)
@@ -15,6 +15,16 @@ public sealed class ShowMindShieldIconsSystem : EquipmentHudSystem<ShowMindShiel
         base.Initialize();
 
         SubscribeLocalEvent<MindShieldComponent, GetStatusIconsEvent>(OnGetStatusIconsEvent);
+        SubscribeLocalEvent<FakeMindShieldComponent, GetStatusIconsEvent>(OnGetStatusIconsEventFake);
+    }
+    // TODO: Probably need to get this OFF of client since this can be read by bad actors rather easily
+    //  ...imagine cheating in a game about silly paper dolls
+    private void OnGetStatusIconsEventFake(EntityUid uid, FakeMindShieldComponent component, ref GetStatusIconsEvent ev)
+    {
+        if(!IsActive)
+            return;
+        if (component.IsEnabled && _prototype.TryIndex(component.MindShieldStatusIcon, out var fakeStatusIconPrototype))
+            ev.StatusIcons.Add(fakeStatusIconPrototype);
     }
 
     private void OnGetStatusIconsEvent(EntityUid uid, MindShieldComponent component, ref GetStatusIconsEvent ev)
index e441574213e93451e6856700dc5e9e14ad4ac8ac..5efd5dc6fb32bfe3e056c5a3cdec974dc9645851 100644 (file)
@@ -58,17 +58,6 @@ public sealed partial class ImplanterSystem : SharedImplanterSystem
                 return;
             }
 
-            // Check if we are trying to implant a implant which is already implanted
-            if (implant.HasValue && !component.AllowMultipleImplants && CheckSameImplant(target, implant.Value))
-            {
-                var name = Identity.Name(target, EntityManager, args.User);
-                var msg = Loc.GetString("implanter-component-implant-already", ("implant", implant), ("target", name));
-                _popup.PopupEntity(msg, target, args.User);
-                args.Handled = true;
-                return;
-            }
-
-
             //Implant self instantly, otherwise try to inject the target.
             if (args.User == target)
                 Implant(target, target, uid, component);
@@ -79,14 +68,7 @@ public sealed partial class ImplanterSystem : SharedImplanterSystem
         args.Handled = true;
     }
 
-    public bool CheckSameImplant(EntityUid target, EntityUid implant)
-    {
-        if (!TryComp<ImplantedComponent>(target, out var implanted))
-            return false;
 
-        var implantPrototype = Prototype(implant);
-        return implanted.ImplantContainer.ContainedEntities.Any(entity => Prototype(entity) == implantPrototype);
-    }
 
     /// <summary>
     /// Attempt to implant someone else.
index 44803e721c0db7a303e965fcdf7bf71b23175d70..6f394fb932a41f0986d9ce1ff4e2429fc45a1d00 100644 (file)
@@ -52,7 +52,14 @@ public abstract class SharedImplanterSystem : EntitySystem
 
         args.PushMarkup(Loc.GetString("implanter-contained-implant-text", ("desc", component.ImplantData.Item2)));
     }
+    public bool CheckSameImplant(EntityUid target, EntityUid implant)
+    {
+        if (!TryComp<ImplantedComponent>(target, out var implanted))
+            return false;
 
+        var implantPrototype = Prototype(implant);
+        return implanted.ImplantContainer.ContainedEntities.Any(entity => Prototype(entity) == implantPrototype);
+    }
     //Instantly implant something and add all necessary components and containers.
     //Set to draw mode if not implant only
     public void Implant(EntityUid user, EntityUid target, EntityUid implanter, ImplanterComponent component)
@@ -60,6 +67,16 @@ public abstract class SharedImplanterSystem : EntitySystem
         if (!CanImplant(user, target, implanter, component, out var implant, out var implantComp))
             return;
 
+        // Check if we are trying to implant a implant which is already implanted
+        // Check AFTER the doafter to prevent "is it a fake?" metagaming against deceptive implants
+        if (!component.AllowMultipleImplants && CheckSameImplant(target, implant.Value))
+        {
+            var name = Identity.Name(target, EntityManager, user);
+            var msg = Loc.GetString("implanter-component-implant-already", ("implant", implant), ("target", name));
+            _popup.PopupEntity(msg, target, user);
+            return;
+        }
+
         //If the target doesn't have the implanted component, add it.
         var implantedComp = EnsureComp<ImplantedComponent>(target);
         var implantContainer = implantedComp.ImplantContainer;
diff --git a/Content.Shared/Mindshield/Components/FakeMindShieldImplantComponent.cs b/Content.Shared/Mindshield/Components/FakeMindShieldImplantComponent.cs
new file mode 100644 (file)
index 0000000..788de80
--- /dev/null
@@ -0,0 +1,8 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Mindshield.Components;
+
+[RegisterComponent, NetworkedComponent]
+public sealed partial class FakeMindShieldImplantComponent : Component
+{
+}
diff --git a/Content.Shared/Mindshield/Components/FakeMindshieldComponent.cs b/Content.Shared/Mindshield/Components/FakeMindshieldComponent.cs
new file mode 100644 (file)
index 0000000..106f433
--- /dev/null
@@ -0,0 +1,22 @@
+using Content.Shared.StatusIcon;
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Mindshield.Components;
+
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class FakeMindShieldComponent : Component
+{
+
+    /// <summary>
+    /// The state of the Fake mindshield, if true the owning entity will display a mindshield effect on their job icon
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public bool IsEnabled { get; set; } = false;
+
+    /// <summary>
+    /// The Security status icon displayed to the security officer. Should be a duplicate of the one the mindshield uses since it's spoofing that
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public ProtoId<SecurityIconPrototype> MindShieldStatusIcon = "MindShieldIcon";
+}
diff --git a/Content.Shared/Mindshield/FakeMindShield/SharedFakeMindShieldImplantSystem.cs b/Content.Shared/Mindshield/FakeMindShield/SharedFakeMindShieldImplantSystem.cs
new file mode 100644 (file)
index 0000000..8887025
--- /dev/null
@@ -0,0 +1,36 @@
+using Content.Shared.Actions;
+using Content.Shared.Implants;
+using Content.Shared.Implants.Components;
+using Content.Shared.Mindshield.Components;
+
+namespace Content.Shared.Mindshield.FakeMindShield;
+
+public sealed class SharedFakeMindShieldImplantSystem : EntitySystem
+{
+    [Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
+    public override void Initialize()
+    {
+        base.Initialize();
+        SubscribeLocalEvent<SubdermalImplantComponent, FakeMindShieldToggleEvent>(OnFakeMindShieldToggle);
+        SubscribeLocalEvent<FakeMindShieldImplantComponent, ImplantImplantedEvent>(ImplantCheck);
+    }
+    /// <summary>
+    /// Raise the Action of a Implanted user toggling their implant to the FakeMindshieldComponent on their entity
+    /// </summary>
+    private void OnFakeMindShieldToggle(Entity<SubdermalImplantComponent> entity, ref FakeMindShieldToggleEvent ev)
+    {
+        ev.Handled = true;
+        if (entity.Comp.ImplantedEntity is not { } ent)
+            return;
+
+        if (!TryComp<FakeMindShieldComponent>(ent, out var comp))
+            return;
+        _actionsSystem.SetToggled(ev.Action, !comp.IsEnabled); // Set it to what the Mindshield component WILL be after this
+        RaiseLocalEvent(ent, ev); //this reraises the action event to support an eventual future Changeling Antag which will also be using this component for it's "mindshield" ability
+    }
+    private void ImplantCheck(EntityUid uid, FakeMindShieldImplantComponent component ,ref ImplantImplantedEvent ev)
+    {
+        if (ev.Implanted != null)
+            EnsureComp<FakeMindShieldComponent>(ev.Implanted.Value);
+    }
+}
diff --git a/Content.Shared/Mindshield/FakeMindShield/SharedFakeMindshieldSystem.cs b/Content.Shared/Mindshield/FakeMindShield/SharedFakeMindshieldSystem.cs
new file mode 100644 (file)
index 0000000..0a7c974
--- /dev/null
@@ -0,0 +1,21 @@
+using Content.Shared.Actions;
+using Content.Shared.Mindshield.Components;
+
+namespace Content.Shared.Mindshield.FakeMindShield;
+
+public sealed class SharedFakeMindShieldSystem : EntitySystem
+{
+    public override void Initialize()
+    {
+        base.Initialize();
+        SubscribeLocalEvent<FakeMindShieldComponent, FakeMindShieldToggleEvent>(OnToggleMindshield);
+    }
+
+    private void OnToggleMindshield(EntityUid uid, FakeMindShieldComponent comp, FakeMindShieldToggleEvent toggleEvent)
+    {
+        comp.IsEnabled = !comp.IsEnabled;
+        Dirty(uid, comp);
+    }
+}
+
+public sealed partial class FakeMindShieldToggleEvent : InstantActionEvent;
index 073757f53c7858e0f46db91fc2fa77b3aaee07d7..813ed3e7a9867b4332fa077988596d7adbaf90ec 100644 (file)
@@ -17,6 +17,9 @@ implanter-label = [color=green]{$implantName}[/color]
 
 implanter-contained-implant-text = [color=green]{$desc}[/color]
 
+action-name-toggle-fake-mindshield = [color=green]Toggle Fake Mindshield[/color]
+action-description-toggle-fake-mindshield = Turn the Fake Mindshield implants transmission on/off
+
 ## Implant Popups
 
 scramble-implant-activated-popup = Your appearance shifts and changes!
index 82c80dab1f46383d0dd545c60fb3f81ba8ced411..655c620e3073df08dc35a11b67a977c5a41cc3e7 100644 (file)
@@ -451,3 +451,6 @@ uplink-combat-bakery-desc = A kit of clandestine baked weapons. Contains a bague
 
 uplink-business-card-name = Syndicate Business Card
 uplink-business-card-desc = A business card that you can give to someone to demonstrate your involvement in the syndicate or leave at the crime scene in order to make fun of the detective. You can buy no more than three of them.
+
+uplink-fake-mindshield-name = Fake Mindshield
+uplink-fake-mindshield-desc = A togglable implant capable of mimicking the same transmissions a real mindshield puts out when on, tricking capable Heads-up displays into thinking you have a mindshield (Nanotrasen brand implanter not provided.)
index a9ac169d3cdf76fd3ee63aa65f36f1fe326bf8cb..89c8e56b78ada95c3b07c1194a50f37915b648d8 100644 (file)
       itemIconStyle: NoItem
       useDelay: 1 # emote spam
       event: !type:ToggleActionEvent
+
+- type: entity
+  id: FakeMindShieldToggleAction
+  name: action-name-toggle-fake-mindshield
+  description: action-description-toggle-fake-mindshield
+  components:
+  - type: InstantAction
+    icon: { sprite: Interface/Actions/actions_fakemindshield.rsi, state: icon }
+    iconOn: { sprite: Interface/Actions/actions_fakemindshield.rsi, state: icon-on }
+    itemIconStyle: NoItem
+    useDelay: 1
+    event: !type:FakeMindShieldToggleEvent
index f9ea34b3899353576e4e0842ab243375f561cab5..06328870fc8aef4d71ddd88bdce20076aaaad42b 100644 (file)
@@ -17,6 +17,7 @@
   - ClothingShoesChameleon
   - BarberScissors
   - ChameleonProjector
+  - FakeMindShieldImplanter
   - AgentIDCard
 
 - type: thiefBackpackSet
index f31d85414d47f106c531fa84c51be93fc2804104..f3ace5b0bb2bf7891cae73d7758817d73452dccc 100644 (file)
         components:
           - SurplusBundle
 
+- type: listing
+  id: UplinkFakeMindshield
+  name: uplink-fake-mindshield-name
+  description: uplink-fake-mindshield-desc
+  icon: { sprite: Interface/Actions/actions_fakemindshield.rsi, state: icon-on }
+  productEntity: FakeMindShieldImplanter
+  discountDownTo:
+    Telecrystal: 2
+  cost:
+    Telecrystal: 4
+  categories:
+  - UplinkImplants
+
+
 # Wearables
 
 - type: listing
index beffe8959a60945f52293e25894795fdc239c94d..b8ab92e5e9981ebeb18ff13c5dcf325d8f25a976 100644 (file)
   - type: Implanter
     implant: DeathAcidifierImplant
 
+- type: entity
+  id: FakeMindShieldImplanter
+  suffix: fake mindshield
+  parent: BaseImplantOnlyImplanterSyndi
+  components:
+  - type: Implanter
+    implant: FakeMindShieldImplant
+
 # Security and Command implanters
 
 - type: entity
index 28788e9a1376f208fc7468e69ad7bd94b0acc9c2..5d93cefd5dd7124758125e1da5d6e242636bee1a 100644 (file)
       - Dead
     - type: Rattle
 
+- type: entity
+  parent: BaseSubdermalImplant
+  id: FakeMindShieldImplant
+  name: fake mindshield implant
+  description: This implant allows the implanter to produce a fake signal that NT security huds use to identify individuals implanted with a mindshield.
+  categories: [ HideSpawnMenu ]
+  components:
+      - type: SubdermalImplant
+        implantAction: FakeMindShieldToggleAction
+      - type: FakeMindShieldImplant
+
 # Sec and Command implants
 
 - type: entity
diff --git a/Resources/Textures/Interface/Actions/actions_fakemindshield.rsi/icon-on.png b/Resources/Textures/Interface/Actions/actions_fakemindshield.rsi/icon-on.png
new file mode 100644 (file)
index 0000000..19b4e13
Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_fakemindshield.rsi/icon-on.png differ
diff --git a/Resources/Textures/Interface/Actions/actions_fakemindshield.rsi/icon.png b/Resources/Textures/Interface/Actions/actions_fakemindshield.rsi/icon.png
new file mode 100644 (file)
index 0000000..9eb33d5
Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_fakemindshield.rsi/icon.png differ
diff --git a/Resources/Textures/Interface/Actions/actions_fakemindshield.rsi/meta.json b/Resources/Textures/Interface/Actions/actions_fakemindshield.rsi/meta.json
new file mode 100644 (file)
index 0000000..31f2881
--- /dev/null
@@ -0,0 +1,17 @@
+{
+    "version": 1,
+    "license": "CC-BY-SA-3.0",
+    "copyright": "Created by Ubaser (Discord) for SS14, Modified for purpose by brassicaprime69 (Discord)",
+    "size": {
+        "x": 32,
+        "y": 32
+    },
+    "states": [
+        {
+            "name": "icon"
+        },
+        {
+            "name": "icon-on"
+        }
+    ]
+}