]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Seperate EMAG into EMAG and Authentication Disruptor (#34337)
authorScarKy0 <106310278+ScarKy0@users.noreply.github.com>
Thu, 30 Jan 2025 04:05:47 +0000 (05:05 +0100)
committerGitHub <noreply@github.com>
Thu, 30 Jan 2025 04:05:47 +0000 (23:05 -0500)
63 files changed:
Content.Server/Access/AccessWireAction.cs
Content.Server/Access/Systems/AccessOverriderSystem.cs
Content.Server/Anomaly/Effects/TechAnomalySystem.cs
Content.Server/Atmos/Monitor/Systems/FireAlarmSystem.cs
Content.Server/Bed/BedSystem.cs
Content.Server/Cargo/Systems/CargoSystem.Orders.cs
Content.Server/Cloning/CloningSystem.cs
Content.Server/Communications/CommunicationsConsoleSystem.cs
Content.Server/Fax/FaxSystem.cs
Content.Server/Lathe/LatheSystem.cs
Content.Server/Nutrition/EntitySystems/FatExtractorSystem.cs
Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs
Content.Server/Power/EntitySystems/ApcSystem.cs
Content.Server/Research/Systems/ResearchSystem.Console.cs
Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs
Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs
Content.Server/Silicons/Laws/SiliconLawSystem.cs
Content.Server/VendingMachines/VendingMachineSystem.cs
Content.Shared/Access/Components/AccessReaderComponent.cs
Content.Shared/Access/Systems/AccessReaderSystem.cs
Content.Shared/Access/Systems/SharedAccessOverriderSystem.cs
Content.Shared/Cloning/CloningPodComponent.cs
Content.Shared/Disposal/SharedDisposalUnitSystem.cs
Content.Shared/Doors/Systems/SharedDoorSystem.cs
Content.Shared/Emag/Components/EmagComponent.cs
Content.Shared/Emag/Components/EmaggedComponent.cs
Content.Shared/Emag/Systems/EmagSystem.cs
Content.Shared/Fax/Components/FaxMachineComponent.cs
Content.Shared/Lathe/SharedLatheSystem.cs
Content.Shared/Light/EntitySystems/UnpoweredFlashlightSystem.cs
Content.Shared/Lock/LockComponent.cs
Content.Shared/Lock/LockSystem.cs
Content.Shared/Materials/SharedMaterialReclaimerSystem.cs
Content.Shared/Medical/Cryogenics/SharedCryoPodSystem.cs
Content.Shared/Ninja/Components/EmagProviderComponent.cs
Content.Shared/Ninja/Systems/EmagProviderSystem.cs
Content.Shared/Pinpointer/SharedPinpointerSystem.cs
Content.Shared/Silicons/Bots/EmaggableMedibotComponent.cs
Content.Shared/Silicons/Bots/MedibotSystem.cs
Content.Shared/Silicons/Laws/SharedSiliconLawSystem.cs
Content.Shared/Singularity/EntitySystems/SharedSingularityGeneratorSystem.cs
Content.Shared/VendingMachines/SharedVendingMachineSystem.cs
Content.Shared/Xenoarchaeology/Equipment/SharedArtifactCrusherSystem.cs
Resources/Locale/en-US/emag/emag.ftl
Resources/Locale/en-US/store/uplink-catalog.ftl
Resources/Locale/en-US/thief/backpack.ftl
Resources/Prototypes/Catalog/thief_toolbox_sets.yml
Resources/Prototypes/Catalog/uplink_catalog.yml
Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml
Resources/Prototypes/Entities/Objects/Misc/arabianlamp.yml
Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml
Resources/Prototypes/Entities/Objects/Tools/access_breaker.yml [new file with mode: 0644]
Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/magic.yml
Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml
Resources/Prototypes/Entities/Structures/Machines/fatextractor.yml
Resources/Prototypes/Entities/Structures/Machines/fax_machine.yml
Resources/Prototypes/Entities/Structures/cryogenic_sleep_unit.yml
Resources/Prototypes/tags.yml
Resources/Textures/Objects/Tools/access_breaker.rsi/equipped-BELT.png [new file with mode: 0644]
Resources/Textures/Objects/Tools/access_breaker.rsi/icon.png [new file with mode: 0644]
Resources/Textures/Objects/Tools/access_breaker.rsi/inhand-left.png [new file with mode: 0644]
Resources/Textures/Objects/Tools/access_breaker.rsi/inhand-right.png [new file with mode: 0644]
Resources/Textures/Objects/Tools/access_breaker.rsi/meta.json [new file with mode: 0644]

index 7676ce489f4316413358ee4f34ad0eb4d1fe702b..b3beb3967b9b8b3c29d1ba767375d7ba2f116eb8 100644 (file)
@@ -1,7 +1,6 @@
 using Content.Server.Wires;
 using Content.Shared.Access;
 using Content.Shared.Access.Components;
-using Content.Shared.Emag.Components;
 using Content.Shared.Wires;
 
 namespace Content.Server.Access;
@@ -31,11 +30,9 @@ public sealed partial class AccessWireAction : ComponentWireAction<AccessReaderC
 
     public override bool Mend(EntityUid user, Wire wire, AccessReaderComponent comp)
     {
-        if (!EntityManager.HasComponent<EmaggedComponent>(wire.Owner))
-        {
-            comp.Enabled = true;
-            EntityManager.Dirty(wire.Owner, comp);
-        }
+        comp.Enabled = true;
+        EntityManager.Dirty(wire.Owner, comp);
+
         return true;
     }
 
@@ -58,7 +55,7 @@ public sealed partial class AccessWireAction : ComponentWireAction<AccessReaderC
     {
         if (!wire.IsCut)
         {
-            if (EntityManager.TryGetComponent<AccessReaderComponent>(wire.Owner, out var access) && !EntityManager.HasComponent<EmaggedComponent>(wire.Owner))
+            if (EntityManager.TryGetComponent<AccessReaderComponent>(wire.Owner, out var access))
             {
                 access.Enabled = true;
                 EntityManager.Dirty(wire.Owner, access);
index a882209b2d17584586266899cb3c9024fdfcf6f8..a0dbc96677b5486dc3fde2cd9390a6acfa19c0fd 100644 (file)
@@ -245,6 +245,10 @@ public sealed class AccessOverriderSystem : SharedAccessOverriderSystem
             $"{ToPrettyString(player):player} has modified {ToPrettyString(accessReaderEnt.Value):entity} with the following allowed access level holders: [{string.Join(", ", addedTags.Union(removedTags))}] [{string.Join(", ", newAccessList)}]");
 
         accessReaderEnt.Value.Comp.AccessLists = ConvertAccessListToHashSet(newAccessList);
+
+        var ev = new OnAccessOverriderAccessUpdatedEvent(player);
+        RaiseLocalEvent(component.TargetAccessReaderId, ref ev);
+
         Dirty(accessReaderEnt.Value);
     }
 
index 9f81c64dbc10e26dff3dc3a6988dc3e6fd11ae1a..983cf2c8f465b596a8ea6bd5909c0488452cc839 100644 (file)
@@ -116,8 +116,11 @@ public sealed class TechAnomalySystem : EntitySystem
 
             if (_random.Prob(tech.Comp.EmagSupercritProbability))
             {
-                _emag.DoEmagEffect(tech, source);
-                _emag.DoEmagEffect(tech, sink);
+                var sourceEv = new GotEmaggedEvent(tech, EmagType.Access | EmagType.Interaction);
+                RaiseLocalEvent(source, ref sourceEv);
+
+                var sinkEv = new GotEmaggedEvent(tech, EmagType.Access | EmagType.Interaction);
+                RaiseLocalEvent(sink, ref sinkEv);
             }
 
             CreateNewLink(tech, source, sink);
index 0a3ee4d7f7dc76cbd1a7ad04134909e8f7a290c1..6d768c129261b4516dab13eb7563eb427347690e 100644 (file)
@@ -21,6 +21,7 @@ public sealed class FireAlarmSystem : EntitySystem
 {
     [Dependency] private readonly AtmosDeviceNetworkSystem _atmosDevNet = default!;
     [Dependency] private readonly AtmosAlarmableSystem _atmosAlarmable = default!;
+    [Dependency] private readonly EmagSystem _emag = default!;
     [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
     [Dependency] private readonly AccessReaderSystem _access = default!;
     [Dependency] private readonly IConfigurationManager _configManager = default!;
@@ -77,11 +78,18 @@ public sealed class FireAlarmSystem : EntitySystem
 
     private void OnEmagged(EntityUid uid, FireAlarmComponent component, ref GotEmaggedEvent args)
     {
-        if (TryComp<AtmosAlarmableComponent>(uid, out var alarmable))
-        {
-            // Remove the atmos alarmable component permanently from this device.
-            _atmosAlarmable.ForceAlert(uid, AtmosAlarmType.Emagged, alarmable);
-            RemCompDeferred<AtmosAlarmableComponent>(uid);
-        }
+        if (!_emag.CompareFlag(args.Type, EmagType.Interaction))
+            return;
+
+        if (_emag.CheckFlag(uid, EmagType.Interaction))
+            return;
+
+        if (!TryComp<AtmosAlarmableComponent>(uid, out var alarmable))
+            return;
+
+        // Remove the atmos alarmable component permanently from this device.
+        _atmosAlarmable.ForceAlert(uid, AtmosAlarmType.Emagged, alarmable);
+        RemCompDeferred<AtmosAlarmableComponent>(uid);
+        args.Handled = true;
     }
 }
index 2cc8085e725cd9cf5a648b92ca864ca8abf6e715..b2d688940861d206006d3820d0405adffb77992c 100644 (file)
@@ -20,6 +20,7 @@ namespace Content.Server.Bed
     {
         [Dependency] private readonly DamageableSystem _damageableSystem = default!;
         [Dependency] private readonly ActionsSystem _actionsSystem = default!;
+        [Dependency] private readonly EmagSystem _emag = default!;
         [Dependency] private readonly SleepingSystem _sleepingSystem = default!;
         [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
         [Dependency] private readonly MobStateSystem _mobStateSystem = default!;
@@ -114,7 +115,12 @@ namespace Content.Server.Bed
 
         private void OnEmagged(EntityUid uid, StasisBedComponent component, ref GotEmaggedEvent args)
         {
-            args.Repeatable = true;
+            if (!_emag.CompareFlag(args.Type, EmagType.Interaction))
+                return;
+
+            if (_emag.CheckFlag(uid, EmagType.Interaction))
+                return;
+
             // Reset any metabolisms first so they receive the multiplier correctly
             UpdateMetabolisms(uid, component, false);
             component.Multiplier = 1 / component.Multiplier;
index e4bd9515136bd861627b7797c9d1047fba009644..e05b33e975be78065bd210f092ff87c46b0f89fc 100644 (file)
@@ -8,7 +8,7 @@ using Content.Shared.Cargo.Components;
 using Content.Shared.Cargo.Events;
 using Content.Shared.Cargo.Prototypes;
 using Content.Shared.Database;
-using Content.Shared.Emag.Components;
+using Content.Shared.Emag.Systems;
 using Content.Shared.IdentityManagement;
 using Content.Shared.Interaction;
 using Content.Shared.Paper;
@@ -21,6 +21,7 @@ namespace Content.Server.Cargo.Systems
     public sealed partial class CargoSystem
     {
         [Dependency] private readonly SharedTransformSystem _transformSystem = default!;
+        [Dependency] private readonly EmagSystem _emag = default!;
 
         /// <summary>
         /// How much time to wait (in seconds) before increasing bank accounts balance.
@@ -41,6 +42,7 @@ namespace Content.Server.Cargo.Systems
             SubscribeLocalEvent<CargoOrderConsoleComponent, ComponentInit>(OnInit);
             SubscribeLocalEvent<CargoOrderConsoleComponent, InteractUsingEvent>(OnInteractUsing);
             SubscribeLocalEvent<CargoOrderConsoleComponent, BankBalanceUpdatedEvent>(OnOrderBalanceUpdated);
+            SubscribeLocalEvent<CargoOrderConsoleComponent, GotEmaggedEvent>(OnEmagged);
             Reset();
         }
 
@@ -75,6 +77,17 @@ namespace Content.Server.Cargo.Systems
             _timer = 0;
         }
 
+        private void OnEmagged(Entity<CargoOrderConsoleComponent> ent, ref GotEmaggedEvent args)
+        {
+            if (!_emag.CompareFlag(args.Type, EmagType.Interaction))
+                return;
+
+            if (_emag.CheckFlag(ent, EmagType.Interaction))
+                return;
+
+            args.Handled = true;
+        }
+
         private void UpdateConsole(float frameTime)
         {
             _timer += frameTime;
@@ -192,7 +205,7 @@ namespace Content.Server.Cargo.Systems
             order.Approved = true;
             _audio.PlayPvs(component.ConfirmSound, uid);
 
-            if (!HasComp<EmaggedComponent>(uid))
+            if (!_emag.CheckFlag(uid, EmagType.Interaction))
             {
                 var tryGetIdentityShortInfoEvent = new TryGetIdentityShortInfoEvent(uid, player);
                 RaiseLocalEvent(tryGetIdentityShortInfoEvent);
index 65f927400162976f15f78fb3832d324f6f7f62c6..d8aac565159988ac9b0cc564cdd93aa23d1f10fb 100644 (file)
@@ -60,6 +60,7 @@ namespace Content.Server.Cloning
         [Dependency] private readonly SharedMindSystem _mindSystem = default!;
         [Dependency] private readonly MetaDataSystem _metaSystem = default!;
         [Dependency] private readonly SharedJobSystem _jobs = default!;
+        [Dependency] private readonly EmagSystem _emag = default!;
 
         public readonly Dictionary<MindComponent, EntityUid> ClonesWaitingForMind = new();
         public const float EasyModeCloningCost = 0.7f;
@@ -276,10 +277,15 @@ namespace Content.Server.Cloning
         /// </summary>
         private void OnEmagged(EntityUid uid, CloningPodComponent clonePod, ref GotEmaggedEvent args)
         {
+            if (!_emag.CompareFlag(args.Type, EmagType.Interaction))
+                return;
+
+            if (_emag.CheckFlag(uid, EmagType.Interaction))
+                return;
+
             if (!this.IsPowered(uid, EntityManager))
                 return;
 
-            _audio.PlayPvs(clonePod.SparkSound, uid);
             _popupSystem.PopupEntity(Loc.GetString("cloning-pod-component-upgrade-emag-requirement"), uid);
             args.Handled = true;
         }
@@ -309,7 +315,7 @@ namespace Content.Server.Cloning
             var indices = _transformSystem.GetGridTilePositionOrDefault((uid, transform));
             var tileMix = _atmosphereSystem.GetTileMixture(transform.GridUid, null, indices, true);
 
-            if (HasComp<EmaggedComponent>(uid))
+            if (_emag.CheckFlag(uid, EmagType.Interaction))
             {
                 _audio.PlayPvs(clonePod.ScreamSound, uid);
                 Spawn(clonePod.MobSpawnId, transform.Coordinates);
@@ -327,7 +333,7 @@ namespace Content.Server.Cloning
             }
             _puddleSystem.TrySpillAt(uid, bloodSolution, out _);
 
-            if (!HasComp<EmaggedComponent>(uid))
+            if (!_emag.CheckFlag(uid, EmagType.Interaction))
             {
                 _material.SpawnMultipleFromMaterial(_robustRandom.Next(1, (int) (clonePod.UsedBiomass / 2.5)), clonePod.RequiredMaterial, Transform(uid).Coordinates);
             }
index 6c320edb23c10130e4ee1cacfd25c79280c9ad1d..abcd93f3280623eea4ab311b2a0697fb72282c61 100644 (file)
@@ -16,7 +16,6 @@ using Content.Shared.Chat;
 using Content.Shared.Communications;
 using Content.Shared.Database;
 using Content.Shared.DeviceNetwork;
-using Content.Shared.Emag.Components;
 using Content.Shared.IdentityManagement;
 using Content.Shared.Popups;
 using Robust.Server.GameObjects;
@@ -177,7 +176,7 @@ namespace Content.Server.Communications
 
         private bool CanUse(EntityUid user, EntityUid console)
         {
-            if (TryComp<AccessReaderComponent>(console, out var accessReaderComponent) && !HasComp<EmaggedComponent>(console))
+            if (TryComp<AccessReaderComponent>(console, out var accessReaderComponent))
             {
                 return _accessReaderSystem.IsAllowed(user, console, accessReaderComponent);
             }
index a43d0171e604159d2d29be6bef33460262c6bed8..b73c101e3fea8a36cac78d4addc66c9b8f34d973 100644 (file)
@@ -50,6 +50,7 @@ public sealed class FaxSystem : EntitySystem
     [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
     [Dependency] private readonly MetaDataSystem _metaData = default!;
     [Dependency] private readonly FaxecuteSystem _faxecute = default!;
+    [Dependency] private readonly EmagSystem _emag = default!;
 
     private const string PaperSlotId = "Paper";
 
@@ -227,7 +228,7 @@ public sealed class FaxSystem : EntitySystem
                 return;
             }
 
-            if (component.KnownFaxes.ContainsValue(newName) && !HasComp<EmaggedComponent>(uid)) // Allow existing names if emagged for fun
+            if (component.KnownFaxes.ContainsValue(newName) && !_emag.CheckFlag(uid, EmagType.Interaction)) // Allow existing names if emagged for fun
             {
                 _popupSystem.PopupEntity(Loc.GetString("fax-machine-popup-name-exist"), uid);
                 return;
@@ -246,7 +247,12 @@ public sealed class FaxSystem : EntitySystem
 
     private void OnEmagged(EntityUid uid, FaxMachineComponent component, ref GotEmaggedEvent args)
     {
-        _audioSystem.PlayPvs(component.EmagSound, uid);
+        if (!_emag.CompareFlag(args.Type, EmagType.Interaction))
+            return;
+
+        if (_emag.CheckFlag(uid, EmagType.Interaction))
+            return;
+
         args.Handled = true;
     }
 
@@ -260,7 +266,7 @@ public sealed class FaxSystem : EntitySystem
             switch (command)
             {
                 case FaxConstants.FaxPingCommand:
-                    var isForSyndie = HasComp<EmaggedComponent>(uid) &&
+                    var isForSyndie = _emag.CheckFlag(uid, EmagType.Interaction) &&
                                       args.Data.ContainsKey(FaxConstants.FaxSyndicateData);
                     if (!isForSyndie && !component.ResponsePings)
                         return;
@@ -405,7 +411,7 @@ public sealed class FaxSystem : EntitySystem
             { DeviceNetworkConstants.Command, FaxConstants.FaxPingCommand }
         };
 
-        if (HasComp<EmaggedComponent>(uid))
+        if (_emag.CheckFlag(uid, EmagType.Interaction))
             payload.Add(FaxConstants.FaxSyndicateData, true);
 
         _deviceNetworkSystem.QueuePacket(uid, null, payload);
index 18f246dcef491213adbe53c1cd55306b7cb16386..ba82e65aa79ac473b65119eaaa1743246e87ac28 100644 (file)
@@ -16,6 +16,7 @@ using Content.Shared.Chemistry.Reagent;
 using Content.Shared.UserInterface;
 using Content.Shared.Database;
 using Content.Shared.Emag.Components;
+using Content.Shared.Emag.Systems;
 using Content.Shared.Examine;
 using Content.Shared.Lathe;
 using Content.Shared.Materials;
@@ -42,6 +43,7 @@ namespace Content.Server.Lathe
         [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
         [Dependency] private readonly SharedAudioSystem _audio = default!;
         [Dependency] private readonly ContainerSystem _container = default!;
+        [Dependency] private readonly EmagSystem _emag = default!;
         [Dependency] private readonly UserInterfaceSystem _uiSys = default!;
         [Dependency] private readonly MaterialStorageSystem _materialStorage = default!;
         [Dependency] private readonly PopupSystem _popup = default!;
@@ -292,7 +294,7 @@ namespace Content.Server.Lathe
         {
             if (uid != args.Lathe || !TryComp<TechnologyDatabaseComponent>(uid, out var technologyDatabase))
                 return;
-            if (!args.getUnavailable && !HasComp<EmaggedComponent>(uid))
+            if (!args.getUnavailable && !_emag.CheckFlag(uid, EmagType.Interaction))
                 return;
             foreach (var recipe in component.EmagDynamicRecipes)
             {
index 6e9856a61dc0b9a3d9209ba9ef36d7ffeaa299c7..8f4c5f4150032f70bf0beb261b7bc94cca304e56 100644 (file)
@@ -21,6 +21,7 @@ namespace Content.Server.Nutrition.EntitySystems;
 public sealed class FatExtractorSystem : EntitySystem
 {
     [Dependency] private readonly IGameTiming _timing = default!;
+    [Dependency] private readonly EmagSystem _emag = default!;
     [Dependency] private readonly HungerSystem _hunger = default!;
     [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
     [Dependency] private readonly SharedAudioSystem _audio = default!;
@@ -36,8 +37,13 @@ public sealed class FatExtractorSystem : EntitySystem
 
     private void OnGotEmagged(EntityUid uid, FatExtractorComponent component, ref GotEmaggedEvent args)
     {
+        if (!_emag.CompareFlag(args.Type, EmagType.Interaction))
+            return;
+
+        if (_emag.CheckFlag(uid, EmagType.Interaction))
+            return;
+
         args.Handled = true;
-        args.Repeatable = false;
     }
 
     private void OnClosed(EntityUid uid, FatExtractorComponent component, ref StorageAfterCloseEvent args)
@@ -103,7 +109,7 @@ public sealed class FatExtractorSystem : EntitySystem
         if (_hunger.GetHunger(hunger) < component.NutritionPerSecond)
             return false;
 
-        if (hunger.CurrentThreshold < component.MinHungerThreshold && !HasComp<EmaggedComponent>(uid))
+        if (hunger.CurrentThreshold < component.MinHungerThreshold && !_emag.CheckFlag(uid, EmagType.Interaction))
             return false;
 
         return true;
index 26fa5ca3cc8f5b85b92771c2896fb011befd4c10..48fb946135e7572e4478edf85904a10f27e11a85 100644 (file)
@@ -24,6 +24,7 @@ namespace Content.Server.Nutrition.EntitySystems
     {
         [Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
         [Dependency] private readonly DamageableSystem _damageableSystem = default!;
+        [Dependency] private readonly EmagSystem _emag = default!;
         [Dependency] private readonly FoodSystem _foodSystem = default!;
         [Dependency] private readonly ExplosionSystem _explosionSystem = default!;
         [Dependency] private readonly PopupSystem _popupSystem = default!;
@@ -63,7 +64,7 @@ namespace Content.Server.Nutrition.EntitySystems
                 forced = false;
             }
 
-            if (entity.Comp.ExplodeOnUse || HasComp<EmaggedComponent>(entity.Owner))
+            if (entity.Comp.ExplodeOnUse || _emag.CheckFlag(entity, EmagType.Interaction))
             {
                 _explosionSystem.QueueExplosion(entity.Owner, "Default", entity.Comp.ExplosionIntensity, 0.5f, 3, canCreateVacuum: false);
                 EntityManager.DeleteEntity(entity);
@@ -161,8 +162,15 @@ namespace Content.Server.Nutrition.EntitySystems
                     args.Args.Target.Value);
             }
         }
+
         private void OnEmagged(Entity<VapeComponent> entity, ref GotEmaggedEvent args)
         {
+            if (!_emag.CompareFlag(args.Type, EmagType.Interaction))
+                return;
+
+            if (_emag.CheckFlag(entity, EmagType.Interaction))
+                return;
+
             args.Handled = true;
         }
     }
index 14dddbb43e329ac9a7725d791bdfeb867c4494ed..29c1431179da2309cca24892c2f9f53ecddddb7e 100644 (file)
@@ -4,7 +4,6 @@ using Content.Server.Power.Components;
 using Content.Server.Power.Pow3r;
 using Content.Shared.Access.Systems;
 using Content.Shared.APC;
-using Content.Shared.Emag.Components;
 using Content.Shared.Emag.Systems;
 using Content.Shared.Popups;
 using Content.Shared.Rounding;
@@ -19,6 +18,7 @@ public sealed class ApcSystem : EntitySystem
 {
     [Dependency] private readonly AccessReaderSystem _accessReader = default!;
     [Dependency] private readonly IGameTiming _gameTiming = default!;
+    [Dependency] private readonly EmagSystem _emag = default!;
     [Dependency] private readonly PopupSystem _popup = default!;
     [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
     [Dependency] private readonly SharedAudioSystem _audio = default!;
@@ -111,7 +111,12 @@ public sealed class ApcSystem : EntitySystem
 
     private void OnEmagged(EntityUid uid, ApcComponent comp, ref GotEmaggedEvent args)
     {
-        // no fancy conditions
+        if (!_emag.CompareFlag(args.Type, EmagType.Interaction))
+            return;
+
+        if (_emag.CheckFlag(uid, EmagType.Interaction))
+            return;
+
         args.Handled = true;
     }
 
@@ -170,7 +175,7 @@ public sealed class ApcSystem : EntitySystem
 
     private ApcChargeState CalcChargeState(EntityUid uid, PowerState.Battery battery)
     {
-        if (HasComp<EmaggedComponent>(uid))
+        if (_emag.CheckFlag(uid, EmagType.Interaction))
             return ApcChargeState.Emag;
 
         if (battery.CurrentStorage / battery.Capacity > ApcComponent.HighPowerThreshold)
index 127b80a631e634cf64e55da1c2ad51ffee745367..c227aee7f075216700041892c1529f92c3afc8d6 100644 (file)
@@ -3,6 +3,7 @@ using Content.Server.Research.Components;
 using Content.Shared.UserInterface;
 using Content.Shared.Access.Components;
 using Content.Shared.Emag.Components;
+using Content.Shared.Emag.Systems;
 using Content.Shared.IdentityManagement;
 using Content.Shared.Research.Components;
 using Content.Shared.Research.Prototypes;
@@ -11,6 +12,8 @@ namespace Content.Server.Research.Systems;
 
 public sealed partial class ResearchSystem
 {
+    [Dependency] private readonly EmagSystem _emag = default!;
+
     private void InitializeConsole()
     {
         SubscribeLocalEvent<ResearchConsoleComponent, ConsoleUnlockTechnologyMessage>(OnConsoleUnlock);
@@ -18,6 +21,7 @@ public sealed partial class ResearchSystem
         SubscribeLocalEvent<ResearchConsoleComponent, ResearchServerPointsChangedEvent>(OnPointsChanged);
         SubscribeLocalEvent<ResearchConsoleComponent, ResearchRegistrationChangedEvent>(OnConsoleRegistrationChanged);
         SubscribeLocalEvent<ResearchConsoleComponent, TechnologyDatabaseModifiedEvent>(OnConsoleDatabaseModified);
+        SubscribeLocalEvent<ResearchConsoleComponent, GotEmaggedEvent>(OnEmagged);
     }
 
     private void OnConsoleUnlock(EntityUid uid, ResearchConsoleComponent component, ConsoleUnlockTechnologyMessage args)
@@ -39,7 +43,7 @@ public sealed partial class ResearchSystem
         if (!UnlockTechnology(uid, args.Id, act))
             return;
 
-        if (!HasComp<EmaggedComponent>(uid))
+        if (!_emag.CheckFlag(uid, EmagType.Interaction))
         {
             var getIdentityEvent = new TryGetIdentityShortInfoEvent(uid, act);
             RaiseLocalEvent(getIdentityEvent);
@@ -52,7 +56,7 @@ public sealed partial class ResearchSystem
             );
             _radio.SendRadioMessage(uid, message, component.AnnouncementChannel, uid, escapeMarkup: false);
         }
-       
+
         SyncClientWithServer(uid);
         UpdateConsoleInterface(uid, component);
     }
@@ -100,4 +104,15 @@ public sealed partial class ResearchSystem
         UpdateConsoleInterface(uid, component);
     }
 
+    private void OnEmagged(Entity<ResearchConsoleComponent> ent, ref GotEmaggedEvent args)
+    {
+        if (!_emag.CompareFlag(args.Type, EmagType.Interaction))
+            return;
+
+        if (_emag.CheckFlag(ent, EmagType.Interaction))
+            return;
+
+        args.Handled = true;
+    }
+
 }
index 6b83a61d2860b2e3fa08615253461fa5564bbbe1..1eb9aabed6a1f4e7aaa940ae6ee3047e31b800ee 100644 (file)
@@ -36,7 +36,6 @@ public sealed partial class RevenantSystem
 {
     [Dependency] private readonly ThrowingSystem _throwing = default!;
     [Dependency] private readonly EntityStorageSystem _entityStorage = default!;
-    [Dependency] private readonly EmagSystem _emag = default!;
     [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
     [Dependency] private readonly MobThresholdSystem _mobThresholdSystem = default!;
     [Dependency] private readonly GhostSystem _ghost = default!;
@@ -343,7 +342,8 @@ public sealed partial class RevenantSystem
                 _whitelistSystem.IsBlacklistPass(component.MalfunctionBlacklist, ent))
                 continue;
 
-            _emag.DoEmagEffect(uid, ent); //it does not emag itself. adorable.
+            var ev = new GotEmaggedEvent(uid, EmagType.Interaction | EmagType.Access);
+            RaiseLocalEvent(ent, ref ev);
         }
     }
 }
index b4ba140044153f903aa9e05df710345b93f22b3a..4d2a8912e830c870f2aeb284b1878ce7183de847 100644 (file)
@@ -8,6 +8,7 @@ using Content.Server.DeviceNetwork;
 using Content.Server.DeviceNetwork.Components;
 using Content.Server.DeviceNetwork.Systems;
 using Content.Server.Explosion.Components;
+using Content.Shared.Emag.Systems;
 using Robust.Shared.Utility;
 
 namespace Content.Server.Silicons.Borgs;
@@ -15,6 +16,8 @@ namespace Content.Server.Silicons.Borgs;
 /// <inheritdoc/>
 public sealed partial class BorgSystem
 {
+    [Dependency] private readonly EmagSystem _emag = default!;
+
     private void InitializeTransponder()
     {
         SubscribeLocalEvent<BorgTransponderComponent, DeviceNetworkPacketEvent>(OnPacketReceived);
@@ -127,7 +130,7 @@ public sealed partial class BorgSystem
 
     private bool CheckEmagged(EntityUid uid, string name)
     {
-        if (HasComp<EmaggedComponent>(uid))
+        if (_emag.CheckFlag(uid, EmagType.Interaction))
         {
             Popup.PopupEntity(Loc.GetString($"borg-transponder-emagged-{name}-popup"), uid, uid, PopupType.LargeCaution);
             return true;
index 109c183f04011b144a87dbcb6274b3dcd1b7d4fa..f5ead80bddbf72b0afd69088bdb1c320b905da38 100644 (file)
@@ -6,7 +6,6 @@ using Content.Server.Roles;
 using Content.Server.Station.Systems;
 using Content.Shared.Administration;
 using Content.Shared.Chat;
-using Content.Shared.Emag.Components;
 using Content.Shared.Emag.Systems;
 using Content.Shared.GameTicking;
 using Content.Shared.Mind;
@@ -14,7 +13,6 @@ using Content.Shared.Mind.Components;
 using Content.Shared.Roles;
 using Content.Shared.Silicons.Laws;
 using Content.Shared.Silicons.Laws.Components;
-using Content.Shared.Stunnable;
 using Content.Shared.Wires;
 using Robust.Server.GameObjects;
 using Robust.Shared.Audio;
@@ -22,7 +20,6 @@ using Robust.Shared.Containers;
 using Robust.Shared.Player;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Toolshed;
-using Robust.Shared.Audio;
 
 namespace Content.Server.Silicons.Laws;
 
@@ -34,8 +31,8 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
     [Dependency] private readonly IPrototypeManager _prototype = default!;
     [Dependency] private readonly SharedRoleSystem _roles = default!;
     [Dependency] private readonly StationSystem _station = default!;
-    [Dependency] private readonly SharedStunSystem _stunSystem = default!;
     [Dependency] private readonly UserInterfaceSystem _userInterface = default!;
+    [Dependency] private readonly EmagSystem _emag = default!;
 
     /// <inheritdoc/>
     public override void Initialize()
@@ -52,7 +49,7 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
         SubscribeLocalEvent<SiliconLawProviderComponent, IonStormLawsEvent>(OnIonStormLaws);
         SubscribeLocalEvent<SiliconLawProviderComponent, MindAddedMessage>(OnLawProviderMindAdded);
         SubscribeLocalEvent<SiliconLawProviderComponent, MindRemovedMessage>(OnLawProviderMindRemoved);
-        SubscribeLocalEvent<SiliconLawProviderComponent, GotEmaggedEvent>(OnEmagLawsAdded);
+        SubscribeLocalEvent<SiliconLawProviderComponent, SiliconEmaggedEvent>(OnEmagLawsAdded);
     }
 
     private void OnMapInit(EntityUid uid, SiliconLawBoundComponent component, MapInitEvent args)
@@ -135,7 +132,7 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
     private void OnIonStormLaws(EntityUid uid, SiliconLawProviderComponent component, ref IonStormLawsEvent args)
     {
         // Emagged borgs are immune to ion storm
-        if (!HasComp<EmaggedComponent>(uid))
+        if (!_emag.CheckFlag(uid, EmagType.Interaction))
         {
             component.Lawset = args.Lawset;
 
@@ -152,9 +149,8 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
         }
     }
 
-    private void OnEmagLawsAdded(EntityUid uid, SiliconLawProviderComponent component, ref GotEmaggedEvent args)
+    private void OnEmagLawsAdded(EntityUid uid, SiliconLawProviderComponent component, ref SiliconEmaggedEvent args)
     {
-
         if (component.Lawset == null)
             component.Lawset = GetLawset(component.Laws);
 
@@ -164,7 +160,7 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
         // Add the first emag law before the others
         component.Lawset?.Laws.Insert(0, new SiliconLaw
         {
-            LawString = Loc.GetString("law-emag-custom", ("name", Name(args.UserUid)), ("title", Loc.GetString(component.Lawset.ObeysTo))),
+            LawString = Loc.GetString("law-emag-custom", ("name", Name(args.user)), ("title", Loc.GetString(component.Lawset.ObeysTo))),
             Order = 0
         });
 
@@ -176,20 +172,6 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
         });
     }
 
-    protected override void OnGotEmagged(EntityUid uid, EmagSiliconLawComponent component, ref GotEmaggedEvent args)
-    {
-        if (component.RequireOpenPanel && TryComp<WiresPanelComponent>(uid, out var panel) && !panel.Open)
-            return;
-
-        base.OnGotEmagged(uid, component, ref args);
-        NotifyLawsChanged(uid, component.EmaggedSound);
-        if(_mind.TryGetMind(uid, out var mindId, out _))
-            EnsureSubvertedSiliconRole(mindId);
-
-        _stunSystem.TryParalyze(uid, component.StunTime, true);
-
-    }
-
     private void EnsureSubvertedSiliconRole(EntityUid mindId)
     {
         if (!_roles.MindHasRole<SubvertedSiliconRoleComponent>(mindId))
index c20a6a46446c46329103893818bf4c01710ed320..c2ea6dd1ac0099ab728262131f6ab1afd8c7fb3b 100644 (file)
@@ -39,6 +39,7 @@ namespace Content.Server.VendingMachines
         [Dependency] private readonly IGameTiming _timing = default!;
         [Dependency] private readonly SpeakOnUIClosedSystem _speakOnUIClosed = default!;
         [Dependency] private readonly SharedPointLightSystem _light = default!;
+        [Dependency] private readonly EmagSystem _emag = default!;
 
         private const float WallVendEjectDistanceFromWall = 1f;
 
@@ -48,7 +49,6 @@ namespace Content.Server.VendingMachines
 
             SubscribeLocalEvent<VendingMachineComponent, PowerChangedEvent>(OnPowerChanged);
             SubscribeLocalEvent<VendingMachineComponent, BreakageEventArgs>(OnBreak);
-            SubscribeLocalEvent<VendingMachineComponent, GotEmaggedEvent>(OnEmagged);
             SubscribeLocalEvent<VendingMachineComponent, DamageChangedEvent>(OnDamageChanged);
             SubscribeLocalEvent<VendingMachineComponent, PriceCalculationEvent>(OnVendingPrice);
             SubscribeLocalEvent<VendingMachineComponent, EmpPulseEvent>(OnEmpPulse);
@@ -123,12 +123,6 @@ namespace Content.Server.VendingMachines
             TryUpdateVisualState(uid, vendComponent);
         }
 
-        private void OnEmagged(EntityUid uid, VendingMachineComponent component, ref GotEmaggedEvent args)
-        {
-            // only emag if there are emag-only items
-            args.Handled = component.EmaggedInventory.Count > 0;
-        }
-
         private void OnDamageChanged(EntityUid uid, VendingMachineComponent component, DamageChangedEvent args)
         {
             if (!args.DamageIncreased && component.Broken)
@@ -232,7 +226,7 @@ namespace Content.Server.VendingMachines
             if (!TryComp<AccessReaderComponent>(uid, out var accessReader))
                 return true;
 
-            if (_accessReader.IsAllowed(sender, uid, accessReader) || HasComp<EmaggedComponent>(uid))
+            if (_accessReader.IsAllowed(sender, uid, accessReader))
                 return true;
 
             Popup.PopupEntity(Loc.GetString("vending-machine-component-try-eject-access-denied"), uid);
@@ -422,7 +416,7 @@ namespace Content.Server.VendingMachines
             if (!Resolve(uid, ref component))
                 return null;
 
-            if (type == InventoryType.Emagged && HasComp<EmaggedComponent>(uid))
+            if (type == InventoryType.Emagged && _emag.CheckFlag(uid, EmagType.Interaction))
                 return component.EmaggedInventory.GetValueOrDefault(entryId);
 
             if (type == InventoryType.Contraband && component.Contraband)
index 903ceab186d1e03159dc0ca18cdb3337857a6bf3..0219fd2b1ad66f4ac12ce13b95e68263f9dacb41 100644 (file)
@@ -76,7 +76,7 @@ public sealed partial class AccessReaderComponent : Component
     /// Whether or not emag interactions have an effect on this.
     /// </summary>
     [DataField]
-    public bool BreakOnEmag = true;
+    public bool BreakOnAccessBreaker = true;
 }
 
 [DataDefinition, Serializable, NetSerializable]
index 0b1d508cc24103d6c2d19ccb32518a2dc3429d0e..84de549b663667293037e3310f58b66ae15e0c2a 100644 (file)
@@ -2,7 +2,6 @@ using System.Diagnostics.CodeAnalysis;
 using System.Linq;
 using Content.Shared.Access.Components;
 using Content.Shared.DeviceLinking.Events;
-using Content.Shared.Emag.Components;
 using Content.Shared.Emag.Systems;
 using Content.Shared.Hands.EntitySystems;
 using Content.Shared.Inventory;
@@ -24,6 +23,7 @@ public sealed class AccessReaderSystem : EntitySystem
     [Dependency] private readonly IPrototypeManager _prototype = default!;
     [Dependency] private readonly InventorySystem _inventorySystem = default!;
     [Dependency] private readonly IGameTiming _gameTiming = default!;
+    [Dependency] private readonly EmagSystem _emag = default!;
     [Dependency] private readonly SharedGameTicker _gameTicker = default!;
     [Dependency] private readonly SharedHandsSystem _handsSystem = default!;
     [Dependency] private readonly SharedContainerSystem _containerSystem = default!;
@@ -71,17 +71,28 @@ public sealed class AccessReaderSystem : EntitySystem
     {
         if (args.User == null) // AutoLink (and presumably future external linkers) have no user.
             return;
-        if (!HasComp<EmaggedComponent>(uid) && !IsAllowed(args.User.Value, uid, component))
+        if (!IsAllowed(args.User.Value, uid, component))
             args.Cancel();
     }
 
     private void OnEmagged(EntityUid uid, AccessReaderComponent reader, ref GotEmaggedEvent args)
     {
-        if (!reader.BreakOnEmag)
+        if (!_emag.CompareFlag(args.Type, EmagType.Access))
             return;
+
+        if (!reader.BreakOnAccessBreaker)
+            return;
+
+        if (!GetMainAccessReader(uid, out var accessReader))
+            return;
+
+        if (accessReader.Value.Comp.AccessLists.Count < 1)
+            return;
+
+        args.Repeatable = true;
         args.Handled = true;
-        reader.Enabled = false;
-        reader.AccessLog.Clear();
+        accessReader.Value.Comp.AccessLists.Clear();
+        accessReader.Value.Comp.AccessLog.Clear();
         Dirty(uid, reader);
     }
 
@@ -135,6 +146,7 @@ public sealed class AccessReaderSystem : EntitySystem
                 return true;
             }
         }
+
         return true;
     }
 
index 36c74ed0dd8117e21d86568007a72168744b3a38..7c6233298aeb5352ca0e073a05f74a2edcf7a541 100644 (file)
@@ -45,3 +45,6 @@ namespace Content.Shared.Access.Systems
         }
     }
 }
+
+[ByRefEvent]
+public record struct OnAccessOverriderAccessUpdatedEvent(EntityUid UserUid, bool Handled = false);
index 88d587c14577125bffd7194c9c0bfa9a29660aca..d588b62eb37f0bdf705cc8e5f50c15b43b0d8c7d 100644 (file)
@@ -46,15 +46,6 @@ public sealed partial class CloningPodComponent : Component
     [DataField("mobSpawnId"), ViewVariables(VVAccess.ReadWrite)]
     public EntProtoId MobSpawnId = "MobAbomination";
 
-    /// <summary>
-    /// Emag sound effects.
-    /// </summary>
-    [DataField("sparkSound")]
-    public SoundSpecifier SparkSound = new SoundCollectionSpecifier("sparks")
-    {
-        Params = AudioParams.Default.WithVolume(8),
-    };
-
     // TODO: Remove this from here when cloning and/or zombies are refactored
     [DataField("screamSound")]
     public SoundSpecifier ScreamSound = new SoundCollectionSpecifier("ZombieScreams")
index 9fdb4a6a804de1686513f14c55bb7e2bbfba4938..a650ef72f80371e43853491334ab98c03e755da2 100644 (file)
@@ -24,6 +24,7 @@ public sealed partial class DisposalDoAfterEvent : SimpleDoAfterEvent
 public abstract class SharedDisposalUnitSystem : EntitySystem
 {
     [Dependency] protected readonly IGameTiming GameTiming = default!;
+    [Dependency] protected readonly EmagSystem _emag = default!;
     [Dependency] protected readonly MetaDataSystem Metadata = default!;
     [Dependency] protected readonly SharedJointSystem Joints = default!;
     [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
@@ -102,6 +103,12 @@ public abstract class SharedDisposalUnitSystem : EntitySystem
 
     protected void OnEmagged(EntityUid uid, SharedDisposalUnitComponent component, ref GotEmaggedEvent args)
     {
+        if (!_emag.CompareFlag(args.Type, EmagType.Interaction))
+            return;
+
+        if (component.DisablePressure == true)
+            return;
+
         component.DisablePressure = true;
         args.Handled = true;
     }
index ef9d28e4ef7a065cd85324ea243429cf9c44b1b6..f2dcd443e918d3d74c71e3b7b16a54cbe778f7ba 100644 (file)
@@ -34,6 +34,7 @@ public abstract partial class SharedDoorSystem : EntitySystem
     [Dependency] private readonly INetManager _net = default!;
     [Dependency] protected readonly SharedPhysicsSystem PhysicsSystem = default!;
     [Dependency] private readonly DamageableSystem _damageableSystem = default!;
+    [Dependency] private readonly EmagSystem _emag = default!;
     [Dependency] private readonly SharedStunSystem _stunSystem = default!;
     [Dependency] protected readonly TagSystem Tags = default!;
     [Dependency] protected readonly SharedAudioSystem Audio = default!;
@@ -77,8 +78,6 @@ public abstract partial class SharedDoorSystem : EntitySystem
         SubscribeLocalEvent<DoorComponent, WeldableAttemptEvent>(OnWeldAttempt);
         SubscribeLocalEvent<DoorComponent, WeldableChangedEvent>(OnWeldChanged);
         SubscribeLocalEvent<DoorComponent, GetPryTimeModifierEvent>(OnPryTimeModifier);
-
-        SubscribeLocalEvent<DoorComponent, OnAttemptEmagEvent>(OnAttemptEmag);
         SubscribeLocalEvent<DoorComponent, GotEmaggedEvent>(OnEmagged);
     }
 
@@ -118,31 +117,24 @@ public abstract partial class SharedDoorSystem : EntitySystem
         _activeDoors.Remove(door);
     }
 
-    private void OnAttemptEmag(EntityUid uid, DoorComponent door, ref OnAttemptEmagEvent args)
+    private void OnEmagged(EntityUid uid, DoorComponent door, ref GotEmaggedEvent args)
     {
+        if (!_emag.CompareFlag(args.Type, EmagType.Access))
+            return;
+
         if (!TryComp<AirlockComponent>(uid, out var airlock))
-        {
-            args.Handled = true;
             return;
-        }
 
         if (IsBolted(uid) || !airlock.Powered)
-        {
-            args.Handled = true;
             return;
-        }
 
         if (door.State != DoorState.Closed)
-        {
-            args.Handled = true;
-        }
-    }
+            return;
 
-    private void OnEmagged(EntityUid uid, DoorComponent door, ref GotEmaggedEvent args)
-    {
         if (!SetState(uid, DoorState.Emagging, door))
             return;
-        Audio.PlayPredicted(door.SparkSound, uid, args.UserUid, AudioParams.Default.WithVolume(8));
+
+        args.Repeatable = true;
         args.Handled = true;
     }
 
index 235cf0c744485b7b824134256ffc8bdb465508bf..23d3b90eeda9f2ab743c8118939a6737bd9c99a6 100644 (file)
@@ -1,6 +1,8 @@
 using Content.Shared.Emag.Systems;
 using Content.Shared.Tag;
+using Robust.Shared.Audio;
 using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
 using Robust.Shared.Serialization;
 
@@ -14,7 +16,21 @@ public sealed partial class EmagComponent : Component
     /// <summary>
     /// The tag that marks an entity as immune to emags
     /// </summary>
-    [DataField("emagImmuneTag", customTypeSerializer: typeof(PrototypeIdSerializer<TagPrototype>)), ViewVariables(VVAccess.ReadWrite)]
+    [DataField]
     [AutoNetworkedField]
-    public string EmagImmuneTag = "EmagImmune";
+    public ProtoId<TagPrototype> EmagImmuneTag = "EmagImmune";
+
+    /// <summary>
+    /// What type of emag effect this device will do
+    /// </summary>
+    [DataField]
+    [AutoNetworkedField]
+    public EmagType EmagType = EmagType.Interaction;
+
+    /// <summary>
+    /// What sound should the emag play when used
+    /// </summary>
+    [DataField]
+    [AutoNetworkedField]
+    public SoundSpecifier EmagSound = new SoundCollectionSpecifier("sparks");
 }
index 337f1a8e561133003ef1f0b425f1eef5e9c6a2d7..152fdca8e368cbe6c879eda36dbb10c698edea5e 100644 (file)
@@ -1,3 +1,4 @@
+using Content.Shared.Emag.Systems;
 using Robust.Shared.GameStates;
 
 namespace Content.Shared.Emag.Components;
@@ -5,7 +6,12 @@ namespace Content.Shared.Emag.Components;
 /// <summary>
 /// Marker component for emagged entities
 /// </summary>
-[RegisterComponent, NetworkedComponent]
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
 public sealed partial class EmaggedComponent : Component
 {
+    /// <summary>
+    /// The EmagType flags that were used to emag this device
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public EmagType EmagType = EmagType.None;
 }
index 3a556b47063b75b79a572d3b8a49d0f4f18632ae..e6d0e1e653cbbd452742eeb7e1f57a9b201f2687 100644 (file)
@@ -6,8 +6,8 @@ using Content.Shared.Emag.Components;
 using Content.Shared.IdentityManagement;
 using Content.Shared.Interaction;
 using Content.Shared.Popups;
-using Content.Shared.Silicons.Laws.Components;
 using Content.Shared.Tag;
+using Robust.Shared.Audio.Systems;
 
 namespace Content.Shared.Emag.Systems;
 
@@ -23,88 +23,123 @@ public sealed class EmagSystem : EntitySystem
     [Dependency] private readonly SharedChargesSystem _charges = default!;
     [Dependency] private readonly SharedPopupSystem _popup = default!;
     [Dependency] private readonly TagSystem _tag = default!;
+    [Dependency] private readonly SharedAudioSystem _audio = default!;
 
     public override void Initialize()
     {
         base.Initialize();
 
         SubscribeLocalEvent<EmagComponent, AfterInteractEvent>(OnAfterInteract);
+        SubscribeLocalEvent<EmaggedComponent, OnAccessOverriderAccessUpdatedEvent>(OnAccessOverriderAccessUpdated);
     }
 
+    private void OnAccessOverriderAccessUpdated(Entity<EmaggedComponent> entity, ref OnAccessOverriderAccessUpdatedEvent args)
+    {
+        if (!CompareFlag(entity.Comp.EmagType, EmagType.Access))
+            return;
+
+        entity.Comp.EmagType &= ~EmagType.Access;
+        Dirty(entity);
+    }
     private void OnAfterInteract(EntityUid uid, EmagComponent comp, AfterInteractEvent args)
     {
         if (!args.CanReach || args.Target is not { } target)
             return;
 
-        args.Handled = TryUseEmag(uid, args.User, target, comp);
+        args.Handled = TryEmagEffect((uid, comp), args.User, target);
     }
 
     /// <summary>
-    /// Tries to use the emag on a target entity
+    /// Does the emag effect on a specified entity
     /// </summary>
-    public bool TryUseEmag(EntityUid uid, EntityUid user, EntityUid target, EmagComponent? comp = null)
+    public bool TryEmagEffect(Entity<EmagComponent?> ent, EntityUid user, EntityUid target)
     {
-        if (!Resolve(uid, ref comp, false))
+        if (!Resolve(ent, ref ent.Comp, false))
             return false;
 
-        if (_tag.HasTag(target, comp.EmagImmuneTag))
+        if (_tag.HasTag(target, ent.Comp.EmagImmuneTag))
             return false;
 
-        TryComp<LimitedChargesComponent>(uid, out var charges);
-        if (_charges.IsEmpty(uid, charges))
+        TryComp<LimitedChargesComponent>(ent, out var charges);
+        if (_charges.IsEmpty(ent, charges))
         {
             _popup.PopupClient(Loc.GetString("emag-no-charges"), user, user);
             return false;
         }
 
-        var handled = DoEmagEffect(user, target);
-        if (!handled)
+        var emaggedEvent = new GotEmaggedEvent(user, ent.Comp.EmagType);
+        RaiseLocalEvent(target, ref emaggedEvent);
+
+        if (!emaggedEvent.Handled)
             return false;
 
-        _popup.PopupClient(Loc.GetString("emag-success", ("target", Identity.Entity(target, EntityManager))), user,
-            user, PopupType.Medium);
+        _popup.PopupPredicted(Loc.GetString("emag-success", ("target", Identity.Entity(target, EntityManager))), user, user, PopupType.Medium);
 
-        _adminLogger.Add(LogType.Emag, LogImpact.High, $"{ToPrettyString(user):player} emagged {ToPrettyString(target):target}");
+        _audio.PlayPredicted(ent.Comp.EmagSound, ent, ent);
 
-        if (charges != null)
-            _charges.UseCharge(uid, charges);
-        return true;
+        _adminLogger.Add(LogType.Emag, LogImpact.High, $"{ToPrettyString(user):player} emagged {ToPrettyString(target):target} with flag(s): {ent.Comp.EmagType}");
+
+        if (charges != null  && emaggedEvent.Handled)
+            _charges.UseCharge(ent, charges);
+
+        if (!emaggedEvent.Repeatable)
+        {
+            EnsureComp<EmaggedComponent>(target, out var emaggedComp);
+
+            emaggedComp.EmagType |= ent.Comp.EmagType;
+            Dirty(target, emaggedComp);
+        }
+
+        return emaggedEvent.Handled;
     }
 
     /// <summary>
-    /// Does the emag effect on a specified entity
+    /// Checks whether an entity has the EmaggedComponent with a set flag.
     /// </summary>
-    public bool DoEmagEffect(EntityUid user, EntityUid target)
+    /// <param name="target">The target entity to check for the flag.</param>
+    /// <param name="flag">The EmagType flag to check for.</param>
+    /// <returns>True if entity has EmaggedComponent and the provided flag. False if the entity lacks EmaggedComponent or provided flag.</returns>
+    public bool CheckFlag(EntityUid target, EmagType flag)
     {
-        // prevent emagging twice
-        if (HasComp<EmaggedComponent>(target))
+        if (!TryComp<EmaggedComponent>(target, out var comp))
             return false;
 
-        var onAttemptEmagEvent = new OnAttemptEmagEvent(user);
-        RaiseLocalEvent(target, ref onAttemptEmagEvent);
+        if ((comp.EmagType & flag) == flag)
+            return true;
 
-        // prevent emagging if attempt fails
-        if (onAttemptEmagEvent.Handled)
-            return false;
+        return false;
+    }
 
-        var emaggedEvent = new GotEmaggedEvent(user);
-        RaiseLocalEvent(target, ref emaggedEvent);
+    /// <summary>
+    /// Compares a flag to the target.
+    /// </summary>
+    /// <param name="target">The target flag to check.</param>
+    /// <param name="flag">The flag to check for within the target.</param>
+    /// <returns>True if target contains flag. Otherwise false.</returns>
+    public bool CompareFlag(EmagType target, EmagType flag)
+    {
+        if ((target & flag) == flag)
+            return true;
 
-        if (emaggedEvent.Handled && !emaggedEvent.Repeatable)
-            EnsureComp<EmaggedComponent>(target);
-        return emaggedEvent.Handled;
+        return false;
     }
 }
 
+
+[Flags]
+public enum EmagType : byte
+{
+    None = 0,
+    Interaction = 1 << 1,
+    Access = 1 << 2
+}
 /// <summary>
 /// Shows a popup to emag user (client side only!) and adds <see cref="EmaggedComponent"/> to the entity when handled
 /// </summary>
 /// <param name="UserUid">Emag user</param>
+/// <param name="Type">The emag type to use</param>
 /// <param name="Handled">Did the emagging succeed? Causes a user-only popup to show on client side</param>
 /// <param name="Repeatable">Can the entity be emagged more than once? Prevents adding of <see cref="EmaggedComponent"/></param>
 /// <remarks>Needs to be handled in shared/client, not just the server, to actually show the emagging popup</remarks>
 [ByRefEvent]
-public record struct GotEmaggedEvent(EntityUid UserUid, bool Handled = false, bool Repeatable = false);
-
-[ByRefEvent]
-public record struct OnAttemptEmagEvent(EntityUid UserUid, bool Handled = false);
+public record struct GotEmaggedEvent(EntityUid UserUid, EmagType Type, bool Handled = false, bool Repeatable = false);
index 161c878e2752527993ead40215aa2c11061ef08e..2407ba594995d1d99adaa85049310c37921f3bca 100644 (file)
@@ -59,12 +59,6 @@ public sealed partial class FaxMachineComponent : Component
     [DataField]
     public bool ReceiveNukeCodes { get; set; } = false;
 
-    /// <summary>
-    /// Sound to play when fax has been emagged
-    /// </summary>
-    [DataField]
-    public SoundSpecifier EmagSound = new SoundCollectionSpecifier("sparks");
-
     /// <summary>
     /// Sound to play when fax printing new message
     /// </summary>
index dd251ed18b3f5114a04f094d3ad090ad151859d8..7328787f25ef71d3ef8c538dd750ffa2a4af895b 100644 (file)
@@ -18,6 +18,7 @@ public abstract class SharedLatheSystem : EntitySystem
 {
     [Dependency] private readonly IPrototypeManager _proto = default!;
     [Dependency] private readonly SharedMaterialStorageSystem _materialStorage = default!;
+    [Dependency] private readonly EmagSystem _emag = default!;
 
     public readonly Dictionary<string, List<LatheRecipePrototype>> InverseRecipes = new();
 
@@ -66,6 +67,12 @@ public abstract class SharedLatheSystem : EntitySystem
 
     private void OnEmagged(EntityUid uid, EmagLatheRecipesComponent component, ref GotEmaggedEvent args)
     {
+        if (!_emag.CompareFlag(args.Type, EmagType.Interaction))
+            return;
+
+        if (_emag.CheckFlag(uid, EmagType.Interaction))
+            return;
+
         args.Handled = true;
     }
 
index 8754de50583ed35382a155d02209c96511d573b1..6dc6cbfe0b328dbe8538aac7d1bb292d3813d447 100644 (file)
@@ -2,6 +2,7 @@ using Content.Shared.Actions;
 using Content.Shared.Emag.Systems;
 using Content.Shared.Light.Components;
 using Content.Shared.Mind.Components;
+using Content.Shared.Storage.Components;
 using Content.Shared.Toggleable;
 using Content.Shared.Verbs;
 using Robust.Shared.Audio.Systems;
@@ -22,6 +23,7 @@ public sealed class UnpoweredFlashlightSystem : EntitySystem
     [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
     [Dependency] private readonly SharedAudioSystem _audioSystem = default!;
     [Dependency] private readonly SharedPointLightSystem _light = default!;
+    [Dependency] private readonly EmagSystem _emag = default!;
 
     public override void Initialize()
     {
@@ -78,6 +80,9 @@ public sealed class UnpoweredFlashlightSystem : EntitySystem
 
     private void OnGotEmagged(EntityUid uid, UnpoweredFlashlightComponent component, ref GotEmaggedEvent args)
     {
+        if (!_emag.CompareFlag(args.Type, EmagType.Interaction))
+            return;
+
         if (!_light.TryGetLight(uid, out var light))
             return;
 
index 070d5801c1c8139caf47accd2d2d82d6c28f8a60..2689602ae8c9380eafb9f3986b46f3a89174b07d 100644 (file)
@@ -54,9 +54,9 @@ public sealed partial class LockComponent : Component
     /// <summary>
     /// Whether or not an emag disables it.
     /// </summary>
-    [DataField("breakOnEmag")]
+    [DataField]
     [AutoNetworkedField]
-    public bool BreakOnEmag = true;
+    public bool BreakOnAccessBreaker = true;
 
     /// <summary>
     /// Amount of do-after time needed to lock the entity.
index 10652800953324aa0707f39c45207aabcd0d25c8..0b24bc67221675d7fdddc769d5b193bebe2c35cd 100644 (file)
@@ -28,6 +28,7 @@ public sealed class LockSystem : EntitySystem
     [Dependency] private readonly AccessReaderSystem _accessReader = default!;
     [Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
     [Dependency] private readonly ActivatableUISystem _activatableUI = default!;
+    [Dependency] private readonly EmagSystem _emag = default!;
     [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
     [Dependency] private readonly SharedAudioSystem _audio = default!;
     [Dependency] private readonly SharedPopupSystem _sharedPopupSystem = default!;
@@ -295,7 +296,10 @@ public sealed class LockSystem : EntitySystem
 
     private void OnEmagged(EntityUid uid, LockComponent component, ref GotEmaggedEvent args)
     {
-        if (!component.Locked || !component.BreakOnEmag)
+        if (!_emag.CompareFlag(args.Type, EmagType.Access))
+            return;
+
+        if (!component.Locked || !component.BreakOnAccessBreaker)
             return;
 
         _audio.PlayPredicted(component.UnlockSound, uid, args.UserUid);
@@ -307,7 +311,7 @@ public sealed class LockSystem : EntitySystem
         var ev = new LockToggledEvent(false);
         RaiseLocalEvent(uid, ref ev, true);
 
-        RemComp<LockComponent>(uid); //Literally destroys the lock as a tell it was emagged
+        args.Repeatable = true;
         args.Handled = true;
     }
 
index d143f509485c8ec2e5463b10a7187931cb3064d6..8eb541ee5982714663481aac51cf6110475f29e3 100644 (file)
@@ -29,6 +29,7 @@ public abstract class SharedMaterialReclaimerSystem : EntitySystem
     [Dependency] private readonly SharedAudioSystem _audio = default!;
     [Dependency] protected readonly SharedContainerSystem Container = default!;
     [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
+    [Dependency] private readonly EmagSystem _emag = default!;
 
     public const string ActiveReclaimerContainerId = "active-material-reclaimer-container";
 
@@ -60,6 +61,12 @@ public abstract class SharedMaterialReclaimerSystem : EntitySystem
 
     private void OnEmagged(EntityUid uid, MaterialReclaimerComponent component, ref GotEmaggedEvent args)
     {
+        if (!_emag.CompareFlag(args.Type, EmagType.Interaction))
+            return;
+
+        if (_emag.CheckFlag(uid, EmagType.Interaction))
+            return;
+
         args.Handled = true;
     }
 
@@ -207,7 +214,7 @@ public abstract class SharedMaterialReclaimerSystem : EntitySystem
                component.Enabled &&
                !component.Broken &&
                HasComp<BodyComponent>(victim) &&
-               HasComp<EmaggedComponent>(uid);
+               _emag.CheckFlag(uid, EmagType.Interaction);
     }
 
     /// <summary>
index f6ce235ff74996cb4acf72c95ea41d6a69e416ae..891129a2ddc0b08f870802a586db9526bb28389b 100644 (file)
@@ -20,6 +20,7 @@ public abstract partial class SharedCryoPodSystem: EntitySystem
 {
     [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
     [Dependency] private readonly StandingStateSystem _standingStateSystem = default!;
+    [Dependency] private readonly EmagSystem _emag = default!;
     [Dependency] private readonly MobStateSystem _mobStateSystem = default!;
     [Dependency] private readonly SharedPopupSystem _popupSystem = default!;
     [Dependency] private readonly SharedContainerSystem _containerSystem = default!;
@@ -156,9 +157,13 @@ public abstract partial class SharedCryoPodSystem: EntitySystem
     protected void OnEmagged(EntityUid uid, CryoPodComponent? cryoPodComponent, ref GotEmaggedEvent args)
     {
         if (!Resolve(uid, ref cryoPodComponent))
-        {
             return;
-        }
+
+        if (!_emag.CompareFlag(args.Type, EmagType.Interaction))
+            return;
+
+        if (cryoPodComponent.PermaLocked && cryoPodComponent.Locked)
+            return;
 
         cryoPodComponent.PermaLocked = true;
         cryoPodComponent.Locked = true;
index ae3e85cbe42ade57097b8a3dc489e30c25272709..630ce12d53cee13b80f8d6316310f4d793bec876 100644 (file)
@@ -1,6 +1,8 @@
+using Content.Shared.Emag.Systems;
 using Content.Shared.Ninja.Systems;
 using Content.Shared.Tag;
 using Content.Shared.Whitelist;
+using Robust.Shared.Audio;
 using Robust.Shared.GameStates;
 using Robust.Shared.Prototypes;
 
@@ -17,11 +19,23 @@ public sealed partial class EmagProviderComponent : Component
     /// The tag that marks an entity as immune to emagging.
     /// </summary>
     [DataField]
-    public ProtoId<TagPrototype> EmagImmuneTag = "EmagImmune";
+    public ProtoId<TagPrototype> AccessBreakerImmuneTag = "AccessBreakerImmune";
 
     /// <summary>
     /// Whitelist that entities must be on to work.
     /// </summary>
     [DataField]
     public EntityWhitelist? Whitelist;
+
+    /// <summary>
+    /// What type of emag this will provide.
+    /// </summary>
+    [DataField]
+    public EmagType EmagType = EmagType.Access;
+
+    /// <summary>
+    /// What sound should the emag play when used
+    /// </summary>
+    [DataField]
+    public SoundSpecifier EmagSound = new SoundCollectionSpecifier("sparks");
 }
index ae0bacaf5f656b036f11b6f50d137597d4aef14d..3be2ae52e13008992dac24615a03278ccd9d8bc5 100644 (file)
@@ -5,6 +5,7 @@ using Content.Shared.Interaction;
 using Content.Shared.Ninja.Components;
 using Content.Shared.Tag;
 using Content.Shared.Whitelist;
+using Robust.Shared.Audio.Systems;
 
 namespace Content.Shared.Ninja.Systems;
 
@@ -13,6 +14,7 @@ namespace Content.Shared.Ninja.Systems;
 /// </summary>
 public sealed class EmagProviderSystem : EntitySystem
 {
+    [Dependency] private readonly SharedAudioSystem _audio = default!;
     [Dependency] private readonly EmagSystem _emag = default!;
     [Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
     [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
@@ -42,14 +44,18 @@ public sealed class EmagProviderSystem : EntitySystem
             return;
 
         // only allowed to emag non-immune entities
-        if (_tag.HasTag(target, comp.EmagImmuneTag))
+        if (_tag.HasTag(target, comp.AccessBreakerImmuneTag))
             return;
 
-        var handled = _emag.DoEmagEffect(uid, target);
-        if (!handled)
+        var emagEv = new GotEmaggedEvent(uid, EmagType.Access);
+        RaiseLocalEvent(args.Target, ref emagEv);
+
+        if (!emagEv.Handled)
             return;
 
-        _adminLogger.Add(LogType.Emag, LogImpact.High, $"{ToPrettyString(uid):player} emagged {ToPrettyString(target):target}");
+        _audio.PlayPredicted(comp.EmagSound, uid, uid);
+
+        _adminLogger.Add(LogType.Emag, LogImpact.High, $"{ToPrettyString(uid):player} emagged {ToPrettyString(target):target} with flag(s): {ent.Comp.EmagType}");
         var ev = new EmaggedSomethingEvent(target);
         RaiseLocalEvent(uid, ref ev);
         args.Handled = true;
@@ -57,7 +63,7 @@ public sealed class EmagProviderSystem : EntitySystem
 }
 
 /// <summary>
-/// Raised on the player when emagging something.
+/// Raised on the player when access breaking something.
 /// </summary>
 [ByRefEvent]
 public record struct EmaggedSomethingEvent(EntityUid Target);
index 7f6b88912559e48867492bc82c48bc1d528677ff..4710960183568fadc6e4d9a87b542218cd70ffeb 100644 (file)
@@ -10,6 +10,7 @@ namespace Content.Shared.Pinpointer;
 public abstract class SharedPinpointerSystem : EntitySystem
 {
     [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
+    [Dependency] private readonly EmagSystem _emag = default!;
 
     public override void Initialize()
     {
@@ -137,6 +138,15 @@ public abstract class SharedPinpointerSystem : EntitySystem
 
     private void OnEmagged(EntityUid uid, PinpointerComponent component, ref GotEmaggedEvent args)
     {
+        if (!_emag.CompareFlag(args.Type, EmagType.Interaction))
+            return;
+
+        if (_emag.CheckFlag(uid, EmagType.Interaction))
+            return;
+
+        if (component.CanRetarget)
+            return;
+
         args.Handled = true;
         component.CanRetarget = true;
     }
index 73775aaf91ac87cb8e3b9b422a6f8499bacd618d..0253cf12bc0641215393553f19303d61f4242e1a 100644 (file)
@@ -16,13 +16,4 @@ public sealed partial class EmaggableMedibotComponent : Component
     /// </summary>
     [DataField(required: true), ViewVariables(VVAccess.ReadWrite)]
     public Dictionary<MobState, MedibotTreatment> Replacements = new();
-
-    /// <summary>
-    /// Sound to play when the bot has been emagged
-    /// </summary>
-    [DataField]
-    public SoundSpecifier SparkSound = new SoundCollectionSpecifier("sparks")
-    {
-        Params = AudioParams.Default.WithVolume(8f)
-    };
 }
index 68f930931c2ef28d96cee7d7a2c47071b8084018..407e586eb1c8957c8cb0a90fb08dfad28c0122db 100644 (file)
@@ -20,6 +20,7 @@ namespace Content.Shared.Silicons.Bots;
 public sealed class MedibotSystem : EntitySystem
 {
     [Dependency] private readonly SharedAudioSystem _audio = default!;
+    [Dependency] private readonly EmagSystem _emag = default!;
     [Dependency] private SharedInteractionSystem _interaction = default!;
     [Dependency] private SharedSolutionContainerSystem _solutionContainer = default!;
     [Dependency] private SharedPopupSystem _popup = default!;
@@ -36,10 +37,14 @@ public sealed class MedibotSystem : EntitySystem
 
     private void OnEmagged(EntityUid uid, EmaggableMedibotComponent comp, ref GotEmaggedEvent args)
     {
-        if (!TryComp<MedibotComponent>(uid, out var medibot))
+        if (!_emag.CompareFlag(args.Type, EmagType.Interaction))
+            return;
+
+        if (_emag.CheckFlag(uid, EmagType.Interaction))
             return;
 
-        _audio.PlayPredicted(comp.SparkSound, uid, args.UserUid);
+        if (!TryComp<MedibotComponent>(uid, out var medibot))
+            return;
 
         foreach (var (state, treatment) in comp.Replacements)
         {
index a30e7c8980f98c2784aa80d0171152fa24113d8f..c3a8c228084a8d1f61946a4dd2f850bf1a9a10bb 100644 (file)
@@ -1,7 +1,10 @@
 using Content.Shared.Emag.Systems;
+using Content.Shared.Mind;
 using Content.Shared.Popups;
 using Content.Shared.Silicons.Laws.Components;
+using Content.Shared.Stunnable;
 using Content.Shared.Wires;
+using Robust.Shared.Audio;
 
 namespace Content.Shared.Silicons.Laws;
 
@@ -11,22 +14,29 @@ namespace Content.Shared.Silicons.Laws;
 public abstract partial class SharedSiliconLawSystem : EntitySystem
 {
     [Dependency] private readonly SharedPopupSystem _popup = default!;
+    [Dependency] private readonly SharedStunSystem _stunSystem = default!;
+    [Dependency] private readonly EmagSystem _emag = default!;
+    [Dependency] private readonly SharedMindSystem _mind = default!;
 
     /// <inheritdoc/>
     public override void Initialize()
     {
         InitializeUpdater();
         SubscribeLocalEvent<EmagSiliconLawComponent, GotEmaggedEvent>(OnGotEmagged);
-        SubscribeLocalEvent<EmagSiliconLawComponent, OnAttemptEmagEvent>(OnAttemptEmag);
     }
 
-    protected virtual void OnAttemptEmag(EntityUid uid, EmagSiliconLawComponent component, ref OnAttemptEmagEvent args)
+    private void OnGotEmagged(EntityUid uid, EmagSiliconLawComponent component, ref GotEmaggedEvent args)
     {
-        //prevent self emagging
+        if (!_emag.CompareFlag(args.Type, EmagType.Interaction))
+            return;
+
+        if (_emag.CheckFlag(uid, EmagType.Interaction))
+            return;
+
+        // prevent self-emagging
         if (uid == args.UserUid)
         {
             _popup.PopupClient(Loc.GetString("law-emag-cannot-emag-self"), uid, args.UserUid);
-            args.Handled = true;
             return;
         }
 
@@ -35,14 +45,33 @@ public abstract partial class SharedSiliconLawSystem : EntitySystem
             !panel.Open)
         {
             _popup.PopupClient(Loc.GetString("law-emag-require-panel"), uid, args.UserUid);
-            args.Handled = true;
+            return;
         }
 
-    }
+        var ev = new SiliconEmaggedEvent(args.UserUid);
+        RaiseLocalEvent(uid, ref ev);
 
-    protected virtual void OnGotEmagged(EntityUid uid, EmagSiliconLawComponent component, ref GotEmaggedEvent args)
-    {
         component.OwnerName = Name(args.UserUid);
+
+        NotifyLawsChanged(uid, component.EmaggedSound);
+        if(_mind.TryGetMind(uid, out var mindId, out _))
+            EnsureSubvertedSiliconRole(mindId);
+
+        _stunSystem.TryParalyze(uid, component.StunTime, true);
+
         args.Handled = true;
     }
+
+    protected virtual void NotifyLawsChanged(EntityUid uid, SoundSpecifier? cue = null)
+    {
+
+    }
+
+    protected virtual void EnsureSubvertedSiliconRole(EntityUid mindId)
+    {
+
+    }
 }
+
+[ByRefEvent]
+public record struct SiliconEmaggedEvent(EntityUid user);
index ee6dc89bb8478b5aedbe4d9348d81b928c53c104..331c1fa4ddb67026e86221cb328caa4955613389 100644 (file)
@@ -11,6 +11,7 @@ public abstract class SharedSingularityGeneratorSystem : EntitySystem
 {
     #region Dependencies
     [Dependency] protected readonly SharedPopupSystem PopupSystem = default!;
+    [Dependency] private readonly EmagSystem _emag = default!;
     #endregion Dependencies
 
     public override void Initialize()
@@ -22,7 +23,16 @@ public abstract class SharedSingularityGeneratorSystem : EntitySystem
 
     private void OnEmagged(EntityUid uid, SingularityGeneratorComponent component, ref GotEmaggedEvent args)
     {
+        if (!_emag.CompareFlag(args.Type, EmagType.Interaction))
+            return;
+
+        if (_emag.CheckFlag(uid, EmagType.Interaction))
+            return;
+
+        if (component.FailsafeDisabled)
+            return;
+
         component.FailsafeDisabled = true;
         args.Handled = true;
     }
-}
\ No newline at end of file
+}
index 94562ce8d1bf5d853a1b73250b8d29066bc9a9d9..c4f3eede2d29ba2f66d40ea773d552a2551947d6 100644 (file)
@@ -2,6 +2,7 @@ using Content.Shared.Emag.Components;
 using Robust.Shared.Prototypes;
 using System.Linq;
 using Content.Shared.DoAfter;
+using Content.Shared.Emag.Systems;
 using Content.Shared.Interaction;
 using Content.Shared.Popups;
 using Robust.Shared.Audio;
@@ -19,11 +20,14 @@ public abstract partial class SharedVendingMachineSystem : EntitySystem
     [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
     [Dependency] protected readonly SharedPopupSystem Popup = default!;
     [Dependency] protected readonly IRobustRandom Randomizer = default!;
+    [Dependency] private readonly EmagSystem _emag = default!;
 
     public override void Initialize()
     {
         base.Initialize();
         SubscribeLocalEvent<VendingMachineComponent, MapInitEvent>(OnMapInit);
+        SubscribeLocalEvent<VendingMachineComponent, GotEmaggedEvent>(OnEmagged);
+
         SubscribeLocalEvent<VendingMachineRestockComponent, AfterInteractEvent>(OnAfterInteract);
     }
 
@@ -49,9 +53,21 @@ public abstract partial class SharedVendingMachineSystem : EntitySystem
         Dirty(uid, component);
     }
 
+    private void OnEmagged(EntityUid uid, VendingMachineComponent component, ref GotEmaggedEvent args)
+    {
+        if (!_emag.CompareFlag(args.Type, EmagType.Interaction))
+            return;
+
+        if (_emag.CheckFlag(uid, EmagType.Interaction))
+            return;
+
+        // only emag if there are emag-only items
+        args.Handled = component.EmaggedInventory.Count > 0;
+    }
+
     /// <summary>
     /// Returns all of the vending machine's inventory. Only includes emagged and contraband inventories if
-    /// <see cref="EmaggedComponent"/> exists and <see cref="VendingMachineComponent.Contraband"/> is true
+    /// <see cref="EmaggedComponent"/> with the EmagType.Interaction flag exists and <see cref="VendingMachineComponent.Contraband"/> is true
     /// are <c>true</c> respectively.
     /// </summary>
     /// <param name="uid"></param>
@@ -64,7 +80,7 @@ public abstract partial class SharedVendingMachineSystem : EntitySystem
 
         var inventory = new List<VendingMachineInventoryEntry>(component.Inventory.Values);
 
-        if (HasComp<EmaggedComponent>(uid))
+        if (_emag.CheckFlag(uid, EmagType.Interaction))
             inventory.AddRange(component.EmaggedInventory.Values);
 
         if (component.Contraband)
index da253ba80afc4c1508da2a5cc5e70e9af017a4bb..2d7d86822f9ef37a896c920565dcb2ec838b3ea7 100644 (file)
@@ -14,6 +14,7 @@ public abstract class SharedArtifactCrusherSystem : EntitySystem
     [Dependency] protected readonly SharedAppearanceSystem Appearance = default!;
     [Dependency] protected readonly SharedAudioSystem AudioSystem = default!;
     [Dependency] protected readonly SharedContainerSystem ContainerSystem = default!;
+    [Dependency] private readonly EmagSystem _emag = default!;
 
     /// <inheritdoc/>
     public override void Initialize()
@@ -40,6 +41,15 @@ public abstract class SharedArtifactCrusherSystem : EntitySystem
 
     private void OnEmagged(Entity<ArtifactCrusherComponent> ent, ref GotEmaggedEvent args)
     {
+        if (!_emag.CompareFlag(args.Type, EmagType.Interaction))
+            return;
+
+        if (_emag.CheckFlag(ent, EmagType.Interaction))
+            return;
+
+        if (ent.Comp.AutoLock)
+            return;
+
         ent.Comp.AutoLock = true;
         args.Handled = true;
     }
index b4679870b522f4c03e85b40a5327704f353eb982..e91bacbc657dfe79b549cbf77c5ab3d1f92ca640 100644 (file)
@@ -1,2 +1,2 @@
-emag-success = The card zaps something in {THE($target)}.
+emag-success = The device zaps something in {THE($target)}.
 emag-no-charges = No charges left!
index 29b778b9e924210cbbf59b99802e9a6b7f108f6d..59cecca3123a94b327d42a3151f884765b7ae862 100644 (file)
@@ -113,7 +113,10 @@ uplink-chest-rig-name = Chest Rig
 uplink-chest-rig-desc = Explosion-resistant tactical webbing used for holding traitor goods.
 
 uplink-emag-name = Emag
-uplink-emag-desc = The business card of the syndicate, this sequencer is able to break open airlocks and tamper with a variety of station devices. Recharges automatically.
+uplink-emag-desc = The business card of the syndicate, this sequencer is able to tamper with a variety of station devices. Recharges automatically.
+
+uplink-access-breaker-name = Access Breaker
+uplink-access-breaker-desc = A hacked access configurator and a good friend of the emag. This device is able to force airlocks open as well as erase access requirements from station equipment. Recharges automatically.
 
 uplink-agent-id-card-name = Agent ID Card
 uplink-agent-id-card-desc = A modified ID card that can copy accesses from other cards and change its name and job title at-will.
index 6a69ab8bc6f35f7e7ac159712abefe4cdf06990f..6d3baa2c0d8a6255cfda451fa88e04454464ea80 100644 (file)
@@ -39,7 +39,7 @@ thief-backpack-category-syndie-name = syndie kit
 thief-backpack-category-syndie-description =
     Trinkets from a disavowed past, or stolen from a careless agent?
     You've made some connections. Whiskey, echo...
-    Includes: An Emag, Interdyne cigs, a Syndicate codeword,
+    Includes: An Emag, Access Breaker, Interdyne cigs, a Syndicate codeword,
     a Radio Jammer, a lighter and some strange red crystals.
 
 thief-backpack-category-sleeper-name = sleeper kit
index 06328870fc8aef4d71ddd88bdce20076aaaad42b..62e9a01edc06237a6e071552f15cf72af1579351 100644 (file)
@@ -63,6 +63,7 @@
   - RadioJammer
   - TraitorCodePaper
   - Emag
+  - AccessBreaker
   - Lighter
   - CigPackSyndicate
   - Telecrystal10 #The thief cannot use them, but it may induce communication with traitors
index 6eafed2bc8942f8c8fc6738767ddd1c9ce14397f..ee3cc773a6dd9dbf8375e0880f5ef1dd595b1583 100644 (file)
 
 # Disruption
 
+- type: listing
+  id: UplinkAccessBreaker
+  name: uplink-access-breaker-name
+  description: uplink-access-breaker-desc
+  productEntity: AccessBreaker
+  discountCategory: veryRareDiscounts
+  discountDownTo:
+    Telecrystal: 3
+  cost:
+    Telecrystal: 5
+  categories:
+  - UplinkDisruption
+
 - type: listing
   id: UplinkEmag
   name: uplink-emag-name
   description: uplink-emag-desc
   productEntity: Emag
-  discountCategory: veryRareDiscounts
+  discountCategory: rareDiscounts
   discountDownTo:
-    Telecrystal: 5
+    Telecrystal: 2
   cost:
-    Telecrystal: 8
+    Telecrystal: 4
   categories:
   - UplinkDisruption
 
index 28e4042afb4f22f8a6458a3c1982423ac2f17f3e..fdc6574c9495bb823b6332712aa7c5adad0b5af0 100644 (file)
     - cell_slot
   - type: Lock
     locked: true
-    breakOnEmag: false
     unlockOnClick: false
   - type: ActivatableUIRequiresLock
   - type: LockedWiresPanel
index 791a0d09453e5ebd79b35ed8ef58828d7d69c041..ee40316e62d80491517eb7efde1f1b30b789ac00 100644 (file)
@@ -7,10 +7,10 @@
   - type: Appearance
   - type: AccessReader
     access: [ [ "CentralCommand" ] ]
-    breakOnEmag: false
+    breakOnAccessBreaker: false
   - type: Lock
     lockOnClick: false
-    breakOnEmag: false
+    breakOnAccessBreaker: false
   - type: EntityStorage
     capacity: 1 # Its smol.
     itemCanStoreMobs: false #  just leaving this here explicitly since I know at some point someone will want to use this to hold a mob. This also prevents it from becoming His Grace.
index 5cc3adef900d248c33123863388409d062fb5e16..ff8e98339956861333edf04f04e4fb8b1ca3582b 100644 (file)
   id: BorgModuleOperative
   parent: [ BaseBorgModuleSyndicate, BaseProviderBorgModule, BaseSyndicateContraband ]
   name: operative cyborg module
-  description: A module that comes with a crowbar, an Emag and a syndicate pinpointer.
+  description: A module that comes with a crowbar, an Emag, an Access Breaker and a syndicate pinpointer.
   components:
     - type: Sprite
       layers:
       items:
       - Crowbar
       - Emag
+      - AccessBreaker
       - PinpointerSyndicateNuclear
     - type: BorgModuleIcon
       icon: { sprite: Interface/Actions/actions_borg.rsi, state: syndicate-operative-module }
diff --git a/Resources/Prototypes/Entities/Objects/Tools/access_breaker.yml b/Resources/Prototypes/Entities/Objects/Tools/access_breaker.yml
new file mode 100644 (file)
index 0000000..15c1beb
--- /dev/null
@@ -0,0 +1,22 @@
+- type: entity
+  parent: [BaseItem, BaseSyndicateContraband]
+  id: AccessBreakerUnlimited
+  suffix: Unlimited
+  name: authentication disruptor
+  description: A hacked access configurator, specialized to unlock and erase access from digital locks.
+  components:
+  - type: Emag
+    emagType: Access
+  - type: Sprite
+    sprite: Objects/Tools/access_breaker.rsi
+    state: icon
+  - type: Item
+    sprite: Objects/Tools/access_breaker.rsi
+
+- type: entity
+  parent: AccessBreakerUnlimited
+  id: AccessBreaker
+  suffix: Limited
+  components:
+  - type: LimitedCharges
+  - type: AutoRecharge
index cd736a33d082633f501fe80f1cd923bdadedcd56..4c3fd937e03fa9fe7bb2642057c9b0688cea6acd 100644 (file)
     stateLocked: cursed_door
     stateUnlocked: decursed_door
   - type: Lock
-    breakOnEmag: false
+    breakOnAccessBreaker: false
   - type: AccessReader
     access: [["Wizard"]]
-    breakOnEmag: false
+    breakOnAccessBreaker: false
   - type: Projectile
     deleteOnCollide: false
     onlyCollideWhenShot: true
index 1180b370967f828947dded85254022d930ca7b64..2e58679e7cad9fedb5af6f0eeec7e505e7b01a25 100644 (file)
     color: "#3c5eb5"
   - type: Tag
     tags:
-    - EmagImmune
+    - AccessBreakerImmune
   - type: ItemSlots
   - type: ContainerContainer
     containers:
index 96de462b79c69568f3e4446ae6b75564f054828c..770a17a8ff7c9b20bb1fcb05d13806afe4e2595f 100644 (file)
@@ -35,7 +35,7 @@
       visible: false
       map: ["enum.FatExtractorVisualLayers.Smoke"]
   - type: Lock
-    breakOnEmag: false
+    breakOnAccessBreaker: false
   - type: GenericVisualizer
     visuals:
       enum.StorageVisuals.Open:
index 402c408ed844aec7e65ba8ebe7e06aa9c52cda62..9efa7ce6f2bd6a306d8fd31532cdb87d6b9ed217 100644 (file)
     responsePings: false
     notifyAdmins: true
   - type: Emagged
+    emagType: Interaction
 
 - type: entity
   parent: FaxMachineBase
index bdb8862a8293a140ad0d7987cfc2c86083aed247..e9e9294e6364f0bd75141f7ee516d12d5d3f6f0b 100644 (file)
@@ -17,7 +17,7 @@
   - type: ActivatableUI
     key: enum.CryostorageUIKey.Key
   - type: AccessReader
-    breakOnEmag: false
+    breakOnAccessBreaker: false
     access: [["Cryogenics"]]
   - type: InteractionOutline
   - type: Cryostorage
index 478e86b8afd71cdb4009c884a62cfa455e1995b3..7847e8da0da1f9a4cb2cbdc14342595b453abf8a 100644 (file)
@@ -1,5 +1,8 @@
 # PUT YOUR TAGS IN ALPHABETICAL ORDER
 
+- type: Tag
+  id: AccessBreakerImmune
+
 - type: Tag
   id: AirAlarm
 
diff --git a/Resources/Textures/Objects/Tools/access_breaker.rsi/equipped-BELT.png b/Resources/Textures/Objects/Tools/access_breaker.rsi/equipped-BELT.png
new file mode 100644 (file)
index 0000000..b8903cc
Binary files /dev/null and b/Resources/Textures/Objects/Tools/access_breaker.rsi/equipped-BELT.png differ
diff --git a/Resources/Textures/Objects/Tools/access_breaker.rsi/icon.png b/Resources/Textures/Objects/Tools/access_breaker.rsi/icon.png
new file mode 100644 (file)
index 0000000..fab24db
Binary files /dev/null and b/Resources/Textures/Objects/Tools/access_breaker.rsi/icon.png differ
diff --git a/Resources/Textures/Objects/Tools/access_breaker.rsi/inhand-left.png b/Resources/Textures/Objects/Tools/access_breaker.rsi/inhand-left.png
new file mode 100644 (file)
index 0000000..8ea6bbb
Binary files /dev/null and b/Resources/Textures/Objects/Tools/access_breaker.rsi/inhand-left.png differ
diff --git a/Resources/Textures/Objects/Tools/access_breaker.rsi/inhand-right.png b/Resources/Textures/Objects/Tools/access_breaker.rsi/inhand-right.png
new file mode 100644 (file)
index 0000000..32070ed
Binary files /dev/null and b/Resources/Textures/Objects/Tools/access_breaker.rsi/inhand-right.png differ
diff --git a/Resources/Textures/Objects/Tools/access_breaker.rsi/meta.json b/Resources/Textures/Objects/Tools/access_breaker.rsi/meta.json
new file mode 100644 (file)
index 0000000..1e1baab
--- /dev/null
@@ -0,0 +1,44 @@
+{
+  "version": 1,
+  "license": "CC-BY-SA-3.0",
+  "copyright": "Made by 20kdc (GitHub), edited by DieselMohawk (GitHub)",
+  "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.5,
+          0.5,
+          0.5,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1
+        ]
+      ]
+    },
+    {
+      "name": "equipped-BELT"
+    }
+  ]
+}