]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
scram implant (#23122)
authorIlya246 <57039557+Ilya246@users.noreply.github.com>
Thu, 4 Jan 2024 12:38:02 +0000 (16:38 +0400)
committerGitHub <noreply@github.com>
Thu, 4 Jan 2024 12:38:02 +0000 (05:38 -0700)
* implement

* fix charges

* add listing

* fixes

* fix locale, probably all done

* fix

* fix of fix

* move query init

* cleanup

* unbrokey rt

Content.Server/Implants/Components/ScramImplantComponent.cs [new file with mode: 0644]
Content.Server/Implants/SubdermalImplantSystem.cs
Content.Shared/Implants/Components/SubdermalImplantComponent.cs
Resources/Locale/en-US/store/uplink-catalog.ftl
Resources/Prototypes/Actions/types.yml
Resources/Prototypes/Catalog/uplink_catalog.yml
Resources/Prototypes/Entities/Objects/Misc/implanters.yml
Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml

diff --git a/Content.Server/Implants/Components/ScramImplantComponent.cs b/Content.Server/Implants/Components/ScramImplantComponent.cs
new file mode 100644 (file)
index 0000000..88c433a
--- /dev/null
@@ -0,0 +1,26 @@
+using Content.Server.Implants;
+using Robust.Shared.Audio;
+
+namespace Content.Server.Implants.Components;
+
+/// <summary>
+/// Randomly teleports entity when triggered.
+/// </summary>
+[RegisterComponent]
+public sealed partial class ScramImplantComponent : Component
+{
+    /// <summary>
+    /// Up to how far to teleport the user
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float TeleportRadius = 100f;
+
+    /// <summary>
+    /// How many times to check for a valid tile to teleport to
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadOnly)]
+    public int TeleportAttempts = 20;
+
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public SoundSpecifier TeleportSound = new SoundPathSpecifier("/Audio/Effects/teleport_arrival.ogg");
+}
index 0b1e9d46b1050af5ec94d901044fb72e9c211fb6..7f6f6fd04593a13091bb08c78dda40abd475fa5c 100644 (file)
@@ -1,6 +1,7 @@
 using Content.Server.Cuffs;
 using Content.Server.Forensics;
 using Content.Server.Humanoid;
+using Content.Server.Implants.Components;
 using Content.Server.Store.Components;
 using Content.Server.Store.Systems;
 using Content.Shared.Cuffs.Components;
@@ -8,8 +9,16 @@ using Content.Shared.Humanoid;
 using Content.Shared.Implants;
 using Content.Shared.Implants.Components;
 using Content.Shared.Interaction;
+using Content.Shared.Physics;
 using Content.Shared.Popups;
 using Content.Shared.Preferences;
+using Robust.Shared.Audio.Systems;
+using Robust.Shared.Map;
+using Robust.Shared.Maths;
+using Robust.Shared.Physics;
+using Robust.Shared.Physics.Components;
+using Robust.Shared.Random;
+using System.Numerics;
 
 namespace Content.Server.Implants;
 
@@ -17,18 +26,27 @@ public sealed class SubdermalImplantSystem : SharedSubdermalImplantSystem
 {
     [Dependency] private readonly CuffableSystem _cuffable = default!;
     [Dependency] private readonly HumanoidAppearanceSystem _humanoidAppearance = default!;
+    [Dependency] private readonly IMapManager _mapManager = default!;
+    [Dependency] private readonly IRobustRandom _random = default!;
     [Dependency] private readonly MetaDataSystem _metaData = default!;
     [Dependency] private readonly StoreSystem _store = default!;
+    [Dependency] private readonly SharedAudioSystem _audio = default!;
     [Dependency] private readonly SharedPopupSystem _popup = default!;
+    [Dependency] private readonly SharedTransformSystem _xform = default!;
     [Dependency] private readonly ForensicsSystem _forensicsSystem = default!;
 
+    private EntityQuery<PhysicsComponent> _physicsQuery;
+
     public override void Initialize()
     {
         base.Initialize();
 
+        _physicsQuery = GetEntityQuery<PhysicsComponent>();
+
         SubscribeLocalEvent<SubdermalImplantComponent, UseFreedomImplantEvent>(OnFreedomImplant);
         SubscribeLocalEvent<StoreComponent, ImplantRelayEvent<AfterInteractUsingEvent>>(OnStoreRelay);
         SubscribeLocalEvent<SubdermalImplantComponent, ActivateImplantEvent>(OnActivateImplantEvent);
+        SubscribeLocalEvent<SubdermalImplantComponent, UseScramImplantEvent>(OnScramImplant);
         SubscribeLocalEvent<SubdermalImplantComponent, UseDnaScramblerImplantEvent>(OnDnaScramblerImplant);
 
     }
@@ -72,6 +90,52 @@ public sealed class SubdermalImplantSystem : SharedSubdermalImplantSystem
         args.Handled = true;
     }
 
+    private void OnScramImplant(EntityUid uid, SubdermalImplantComponent component, UseScramImplantEvent args)
+    {
+        if (component.ImplantedEntity is not { } ent)
+            return;
+
+        if (!TryComp<ScramImplantComponent>(uid, out var implant))
+            return;
+
+        var xform = Transform(ent);
+        var entityCoords = xform.Coordinates.ToMap(EntityManager);
+
+        // try to find a valid position to teleport to, teleport to whatever works if we can't
+        var targetCoords = new MapCoordinates();
+        for (var i = 0; i < implant.TeleportAttempts; i++)
+        {
+            var distance = implant.TeleportRadius * MathF.Sqrt(_random.NextFloat()); // to get an uniform distribution
+            targetCoords = entityCoords.Offset(_random.NextAngle().ToVec() * distance);
+
+            // prefer teleporting to grids
+            if (!_mapManager.TryFindGridAt(targetCoords, out var gridUid, out var grid))
+                continue;
+
+            // the implant user probably does not want to be in your walls
+            var valid = true;
+            foreach (var entity in grid.GetAnchoredEntities(targetCoords))
+            {
+                if (!_physicsQuery.TryGetComponent(entity, out var body))
+                    continue;
+
+                if (body.BodyType != BodyType.Static ||
+                    !body.Hard ||
+                    (body.CollisionLayer & (int) CollisionGroup.Impassable) == 0)
+                    continue;
+
+                valid = false;
+                break;
+            }
+            if (valid)
+                break;
+        }
+        _xform.SetWorldPosition(ent, targetCoords.Position);
+        _audio.PlayPvs(implant.TeleportSound, ent);
+
+        args.Handled = true;
+    }
+
     private void OnDnaScramblerImplant(EntityUid uid, SubdermalImplantComponent component, UseDnaScramblerImplantEvent args)
     {
         if (component.ImplantedEntity is not { } ent)
index 5edc26ead32c472495b3436bbea8861035951d54..09ef05e48a8f2198144b5655ade28eacdc73cfd8 100644 (file)
@@ -80,6 +80,11 @@ public sealed partial class OpenUplinkImplantEvent : InstantActionEvent
 
 }
 
+public sealed partial class UseScramImplantEvent : InstantActionEvent
+{
+
+}
+
 public sealed partial class UseDnaScramblerImplantEvent : InstantActionEvent
 {
 
index ac97c0d1a3a10f294c6486119dec26376fd2d03c..50823a58973be8c6a002e62872a83e269ab34390 100644 (file)
@@ -149,6 +149,9 @@ uplink-storage-implanter-desc = Hide goodies inside of yourself with new bluespa
 uplink-freedom-implanter-name = Freedom Implanter
 uplink-freedom-implanter-desc = Get away from those nasty sec officers with this three use implant!
 
+uplink-scram-implanter-name = Scram Implanter
+uplink-scram-implanter-desc = A 3-use implant which teleports you within a large radius. Attempts to teleport you onto an unobstructed tile. May sometimes fail to do so. Life insurance not included.
+
 uplink-dna-scrambler-implanter-name = DNA Scrambler Implanter
 uplink-dna-scrambler-implanter-desc = A single use implant that can be activated to modify your DNA and give you a completely new look.
 
index 6200d8b3812a5f648914733d475a55200cd6c6bc..8151cf422e8bb36f50ed889a8151ba984dbb8c15 100644 (file)
       state: icon
     event: !type:ActivateImplantEvent
 
+- type: entity
+  id: ActionActivateScramImplant
+  name: SCRAM!
+  description: Randomly teleports you within a large distance.
+  noSpawn: true
+  components:
+  - type: InstantAction
+    charges: 2
+    useDelay: 5
+    itemIconStyle: BigAction
+    priority: -20
+    icon:
+      sprite: Structures/Specific/anomaly.rsi
+      state: anom4
+    event: !type:UseScramImplantEvent
+
 - type: entity
   id: ActionActivateDnaScramblerImplant
   name: Scramble DNA
index 5c1bc63de1cfbcaf329616a7174170dfd5dfa33c..36c3c1435f40ba8ad0aaf987a3e18e821bc31a7c 100644 (file)
   categories:
     - UplinkImplants
 
+- type: listing
+  id: UplinkScramImplanter
+  name: uplink-scram-implanter-name
+  description: uplink-scram-implanter-desc
+  icon: { sprite: /Textures/Structures/Specific/anomaly.rsi, state: anom4 }
+  productEntity: ScramImplanter
+  cost:
+    Telecrystal: 6 # it's a gamble that may kill you easily so 6 TC per 2 uses, second one more of a backup
+  categories:
+    - UplinkImplants
+
 - type: listing
   id: UplinkDnaScramblerImplant
   name: uplink-dna-scrambler-implanter-name
index f35e72de8cdd26293fad4ec06e60f05f63864a8c..400bfc5c0f8478043294fc88cebfb7a838d4fda1 100644 (file)
     - type: Implanter
       implant: EmpImplant
 
+- type: entity
+  id: ScramImplanter
+  name: scram implanter
+  parent: BaseImplantOnlyImplanterSyndi
+  components:
+    - type: Implanter
+      implant: ScramImplant
+
 - type: entity
   id: DnaScramblerImplanter
   name: DNA scrambler implanter
index 6caa5322af8b52a510f3f192507b9a64f2ef9c14..d369d03996844a872a846fa6032a1615eb2908c7 100644 (file)
       range: 1.75
       energyConsumption: 50000
       disableDuration: 10
+      
+- type: entity
+  parent: BaseSubdermalImplant
+  id: ScramImplant
+  name: scram implant
+  description: This implant randomly teleports the user within a large radius when activated.
+  noSpawn: true
+  components:
+    - type: SubdermalImplant
+      implantAction: ActionActivateScramImplant
+    - type: TriggerImplantAction
+    - type: ScramImplant
+      teleportAttempts: 10 # small amount of risk of being teleported into space and lets you teleport off shuttles
 
 - type: entity
   parent: BaseSubdermalImplant