]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Cluster grenades for uplink and security (#22029)
authorArendian <137322659+Arendian@users.noreply.github.com>
Thu, 14 Dec 2023 03:30:42 +0000 (04:30 +0100)
committerGitHub <noreply@github.com>
Thu, 14 Dec 2023 03:30:42 +0000 (22:30 -0500)
* clustergrenades go boom

* Small tweaks

* Some tweaks and soaplet

* clustergrenadesystem changes and launcher types

* small tweaks

* typo

* whitespace

* rsi edit

* another typo

* add containers

* Some changes related to merge

* Forgot to change name

* Made changes based on review

* Removed new china lake ammo based on feedback in other PR

* Unneeded nested loop moment

* Nested loop needed after all moment

36 files changed:
Content.Server/Explosion/Components/ClusterGrenadeComponent.cs
Content.Server/Explosion/EntitySystems/ClusterGrenadeSystem.cs
Content.Server/Projectiles/ProjectileSystem.cs
Content.Shared/Projectiles/ProjectileComponent.cs
Resources/Locale/en-US/store/uplink-catalog.ftl
Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml
Resources/Prototypes/Catalog/uplink_catalog.yml
Resources/Prototypes/Entities/Objects/Specific/Janitorial/soap.yml
Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml
Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/grenade.yml [new file with mode: 0644]
Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml
Resources/Prototypes/Entities/Objects/Weapons/Throwable/clusterbang.yml
Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml
Resources/Textures/Objects/Specific/Janitorial/soap.rsi/meta.json
Resources/Textures/Objects/Specific/Janitorial/soap.rsi/syndie-soaplet.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/clusterbang.rsi/icon.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/clusterbang.rsi/meta.json
Resources/Textures/Objects/Weapons/Grenades/clusterbang.rsi/primed.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/clusterbomb.rsi/base-1.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/clusterbomb.rsi/base-2.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/clusterbomb.rsi/icon.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/clusterbomb.rsi/meta.json [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/clusterbomb.rsi/primed.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/pyrogrenade.rsi/equipped-BELT.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/pyrogrenade.rsi/icon.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/pyrogrenade.rsi/meta.json [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/pyrogrenade.rsi/primed.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/shrapnelgrenade.rsi/equipped-BELT.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/shrapnelgrenade.rsi/icon.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/shrapnelgrenade.rsi/meta.json [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/shrapnelgrenade.rsi/primed.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/stingergrenade.rsi/equipped-BELT.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/stingergrenade.rsi/icon.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/stingergrenade.rsi/meta.json [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/stingergrenade.rsi/primed.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Guns/Ammunition/Explosives/explosives.rsi/meta.json

index e2e3ca27333e77052e2ffe10aac98df3d5d63ab4..fe1b8caede7fd2e48f64fb6fa73af056be2c0d0e 100644 (file)
@@ -1,7 +1,6 @@
 using Content.Server.Explosion.EntitySystems;
 using Robust.Shared.Containers;
 using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
 
 namespace Content.Server.Explosion.Components
 {
@@ -13,8 +12,8 @@ namespace Content.Server.Explosion.Components
         /// <summary>
         ///     What we fill our prototype with if we want to pre-spawn with grenades.
         /// </summary>
-        [DataField("fillPrototype", customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
-        public string? FillPrototype;
+        [DataField("fillPrototype")]
+        public EntProtoId? FillPrototype;
 
         /// <summary>
         ///     If we have a pre-fill how many more can we spawn.
@@ -28,20 +27,91 @@ namespace Content.Server.Explosion.Components
         public int MaxGrenades = 3;
 
         /// <summary>
-        ///     How long until our grenades are shot out and armed.
+        ///     Maximum delay in seconds between individual grenade triggers
         /// </summary>
-        [ViewVariables(VVAccess.ReadWrite)] [DataField("delay")]
-        public float Delay = 1;
+        [ViewVariables(VVAccess.ReadWrite)]
+        [DataField("grenadeTriggerIntervalMax")]
+        public float GrenadeTriggerIntervalMax = 0f;
 
         /// <summary>
-        ///     Max distance grenades can be thrown.
+        ///     Minimum delay in seconds between individual grenade triggers
         /// </summary>
-        [ViewVariables(VVAccess.ReadWrite)] [DataField("distance")]
-        public float ThrowDistance = 50;
+        [ViewVariables(VVAccess.ReadWrite)]
+        [DataField("grenadeTriggerIntervalMin")]
+        public float GrenadeTriggerIntervalMin = 0f;
+
+        /// <summary>
+        ///     Minimum delay in seconds before any grenades start to be triggered.
+        /// </summary>
+        [ViewVariables(VVAccess.ReadWrite)]
+        [DataField("baseTriggerDelay")]
+        public float BaseTriggerDelay = 1.0f;
+
+        /// <summary>
+        ///     Decides if grenades trigger after getting launched
+        /// </summary>
+        [DataField("triggerGrenades")]
+        public bool TriggerGrenades = true;
+
+        /// <summary>
+        ///     Does the cluster grenade shoot or throw
+        /// </summary>
+        [ViewVariables(VVAccess.ReadWrite)]
+        [DataField("grenadeType")]
+        public Enum GrenadeType = Components.GrenadeType.Throw;
+
+        /// <summary>
+        ///     The speed at which grenades get thrown
+        /// </summary>
+        [ViewVariables(VVAccess.ReadWrite)]
+        [DataField("velocity")]
+        public float Velocity = 5;
+
+        /// <summary>
+        ///     Should the spread be random
+        /// </summary>
+        [ViewVariables(VVAccess.ReadWrite)]
+        [DataField("randomSpread")]
+        public bool RandomSpread = false;
+
+        /// <summary>
+        ///     Should the angle be random
+        /// </summary>
+        [ViewVariables(VVAccess.ReadWrite)]
+        [DataField("randomAngle")]
+        public bool RandomAngle = false;
+
+        /// <summary>
+        ///     Static distance grenades will be thrown to.
+        /// </summary>
+        [ViewVariables(VVAccess.ReadWrite)]
+        [DataField("distance")]
+        public float Distance = 1f;
+
+        /// <summary>
+        ///     Max distance grenades should randomly be thrown to.
+        /// </summary>
+        [ViewVariables(VVAccess.ReadWrite)]
+        [DataField("maxSpreadDistance")]
+        public float MaxSpreadDistance = 2.5f;
+
+        /// <summary>
+        ///     Minimal distance grenades should randomly be thrown to.
+        /// </summary>
+        [ViewVariables(VVAccess.ReadWrite)]
+        [DataField("minSpreadDistance")]
+        public float MinSpreadDistance = 0f;
 
         /// <summary>
         ///     This is the end.
         /// </summary>
         public bool CountDown;
     }
+
+    public enum GrenadeType
+    {
+        Throw,
+        Shoot
+    }
+
 }
index 9467966cb6c9f91153334039278bab81d37d8083..2674a8d61bc17788d4b9165bbf626771af1e50f8 100644 (file)
@@ -6,6 +6,10 @@ using Content.Shared.Interaction.Events;
 using Content.Shared.Throwing;
 using Robust.Shared.Containers;
 using Robust.Shared.Random;
+using Content.Server.Weapons.Ranged.Systems;
+using System.Numerics;
+using Robust.Server.Containers;
+using Robust.Server.GameObjects;
 
 namespace Content.Server.Explosion.EntitySystems;
 
@@ -13,9 +17,11 @@ public sealed class ClusterGrenadeSystem : EntitySystem
 {
     [Dependency] private readonly IRobustRandom _random = default!;
     [Dependency] private readonly SharedContainerSystem _container = default!;
-    [Dependency] private readonly TriggerSystem _trigger = default!;
     [Dependency] private readonly ThrowingSystem _throwingSystem = default!;
     [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
+    [Dependency] private readonly GunSystem _gun = default!;
+    [Dependency] private readonly TransformSystem _transformSystem = default!;
+    [Dependency] private readonly ContainerSystem _containerSystem = default!;
 
     public override void Initialize()
     {
@@ -23,12 +29,12 @@ public sealed class ClusterGrenadeSystem : EntitySystem
         SubscribeLocalEvent<ClusterGrenadeComponent, ComponentInit>(OnClugInit);
         SubscribeLocalEvent<ClusterGrenadeComponent, ComponentStartup>(OnClugStartup);
         SubscribeLocalEvent<ClusterGrenadeComponent, InteractUsingEvent>(OnClugUsing);
-        SubscribeLocalEvent<ClusterGrenadeComponent, UseInHandEvent>(OnClugUse);
+        SubscribeLocalEvent<ClusterGrenadeComponent, TriggerEvent>(OnClugTrigger);
     }
 
     private void OnClugInit(EntityUid uid, ClusterGrenadeComponent component, ComponentInit args)
     {
-        component.GrenadesContainer = _container.EnsureContainer<Container>(uid, "cluster-flash");
+        component.GrenadesContainer = _container.EnsureContainer<Container>(uid, "cluster-payload");
     }
 
     private void OnClugStartup(Entity<ClusterGrenadeComponent> clug, ref ComponentStartup args)
@@ -53,64 +59,97 @@ public sealed class ClusterGrenadeSystem : EntitySystem
             !HasComp<FlashOnTriggerComponent>(args.Used))
             return;
 
-        component.GrenadesContainer.Insert(args.Used);
+        _containerSystem.Insert(args.Used, component.GrenadesContainer);
         UpdateAppearance(clug);
         args.Handled = true;
     }
 
-    private void OnClugUse(EntityUid uid, ClusterGrenadeComponent component, UseInHandEvent args)
+    private void OnClugTrigger(Entity<ClusterGrenadeComponent> clug, ref TriggerEvent args)
     {
-        if (component.CountDown || (component.GrenadesContainer.ContainedEntities.Count + component.UnspawnedCount) <= 0)
-            return;
+        var component = clug.Comp;
+        component.CountDown = true;
+        args.Handled = true;
+    }
+
+    public override void Update(float frameTime)
+    {
+        base.Update(frameTime);
+        var query = EntityQueryEnumerator<ClusterGrenadeComponent>();
 
-        // TODO: Should be an Update loop
-        uid.SpawnTimer((int) (component.Delay * 1000), () =>
+        while (query.MoveNext(out var uid, out var clug))
         {
-            if (Deleted(uid))
-                return;
-
-            component.CountDown = true;
-            var delay = 20;
-            var grenadesInserted = component.GrenadesContainer.ContainedEntities.Count + component.UnspawnedCount;
-            var thrownCount = 0;
-            var segmentAngle = 360 / grenadesInserted;
-            while (TryGetGrenade((uid, component), out var grenade))
+            if (clug.CountDown && clug.UnspawnedCount > 0)
             {
-                var angleMin = segmentAngle * thrownCount;
-                var angleMax = segmentAngle * (thrownCount + 1);
-                var angle = Angle.FromDegrees(_random.Next(angleMin, angleMax));
-                // var distance = random.NextFloat() * _throwDistance;
+                var grenadesInserted = clug.GrenadesContainer.ContainedEntities.Count + clug.UnspawnedCount;
+                var thrownCount = 0;
+                var segmentAngle = 360 / grenadesInserted;
+                var grenadeDelay = 0f;
 
-                delay += _random.Next(550, 900);
-                thrownCount++;
+                while (TryGetGrenade(uid, clug, out var grenade))
+                {
+                    // var distance = random.NextFloat() * _throwDistance;
+                    var angleMin = segmentAngle * thrownCount;
+                    var angleMax = segmentAngle * (thrownCount + 1);
+                    var angle = Angle.FromDegrees(_random.Next(angleMin, angleMax));
+                    if (clug.RandomAngle)
+                        angle = _random.NextAngle();
+                    thrownCount++;
+
+                    switch (clug.GrenadeType)
+                    {
+                        case GrenadeType.Shoot:
+                            ShootProjectile(grenade, angle, clug, uid);
+                            break;
+                        case GrenadeType.Throw:
+                            ThrowGrenade(grenade, angle, clug);
+                            break;
+                    }
+
+                    // give an active timer trigger to the contained grenades when they get launched
+                    if (clug.TriggerGrenades)
+                    {
+                        grenadeDelay += _random.NextFloat(clug.GrenadeTriggerIntervalMin, clug.GrenadeTriggerIntervalMax);
+                        var grenadeTimer = EnsureComp<ActiveTimerTriggerComponent>(grenade);
+                        grenadeTimer.TimeRemaining = (clug.BaseTriggerDelay + grenadeDelay);
+                        var ev = new ActiveTimerTriggerEvent(grenade, uid);
+                        RaiseLocalEvent(uid, ref ev);
+                    }
+                }
+                // delete the empty shell of the clusterbomb
+                Del(uid);
+            }
+        }
+    }
 
-                // TODO: Suss out throw strength
-                _throwingSystem.TryThrow(grenade, angle.ToVec().Normalized() * component.ThrowDistance);
+    private void ShootProjectile(EntityUid grenade, Angle angle, ClusterGrenadeComponent clug, EntityUid clugUid)
+    {
+        var direction = angle.ToVec().Normalized();
 
-                grenade.SpawnTimer(delay, () =>
-                {
-                    if ((!EntityManager.EntityExists(grenade) ? EntityLifeStage.Deleted : MetaData(grenade).EntityLifeStage) >= EntityLifeStage.Deleted)
-                        return;
+        if (clug.RandomSpread)
+            direction = _random.NextVector2().Normalized();
 
-                    _trigger.Trigger(grenade, args.User);
-                });
-            }
+        _gun.ShootProjectile(grenade, direction, Vector2.One.Normalized(), clugUid);
 
-            EntityManager.DeleteEntity(uid);
-        });
+    }
 
-        args.Handled = true;
+    private void ThrowGrenade(EntityUid grenade, Angle angle, ClusterGrenadeComponent clug)
+    {
+        var direction = angle.ToVec().Normalized() * clug.Distance;
+
+        if (clug.RandomSpread)
+            direction = angle.ToVec().Normalized() * _random.NextFloat(clug.MinSpreadDistance, clug.MaxSpreadDistance);
+
+        _throwingSystem.TryThrow(grenade, direction, clug.Velocity);
     }
 
-    private bool TryGetGrenade(Entity<ClusterGrenadeComponent> ent, out EntityUid grenade)
+    private bool TryGetGrenade(EntityUid clugUid, ClusterGrenadeComponent component, out EntityUid grenade)
     {
         grenade = default;
-        var component = ent.Comp;
 
         if (component.UnspawnedCount > 0)
         {
             component.UnspawnedCount--;
-            grenade = EntityManager.SpawnEntity(component.FillPrototype, Transform(ent).MapPosition);
+            grenade = Spawn(component.FillPrototype, _transformSystem.GetMapCoordinates(clugUid));
             return true;
         }
 
@@ -128,12 +167,12 @@ public sealed class ClusterGrenadeSystem : EntitySystem
         return false;
     }
 
-    private void UpdateAppearance(Entity<ClusterGrenadeComponent> ent)
+    private void UpdateAppearance(Entity<ClusterGrenadeComponent> clug)
     {
-        var component = ent.Comp;
-        if (!TryComp<AppearanceComponent>(ent, out var appearance))
+        var component = clug.Comp;
+        if (!TryComp<AppearanceComponent>(clug, out var appearance))
             return;
 
-        _appearance.SetData(ent, ClusterGrenadeVisuals.GrenadesCounter, component.GrenadesContainer.ContainedEntities.Count + component.UnspawnedCount, appearance);
+        _appearance.SetData(clug, ClusterGrenadeVisuals.GrenadesCounter, component.GrenadesContainer.ContainedEntities.Count + component.UnspawnedCount, appearance);
     }
 }
index b8a6b8c5b262e2edea00d1151aa6debecb3737f7..1d256071d622828d1e9d18380ccfbad8996b9a54 100644 (file)
@@ -7,6 +7,7 @@ using Content.Shared.Database;
 using Content.Shared.Projectiles;
 using Robust.Server.GameObjects;
 using Robust.Shared.Physics.Events;
+using Content.Shared.Mobs.Components;
 using Robust.Shared.Player;
 
 namespace Content.Server.Projectiles;
@@ -70,7 +71,18 @@ public sealed class ProjectileSystem : SharedProjectileSystem
 
         component.DamagedEntity = true;
 
-        if (component.DeleteOnCollide)
+        if (component.DeleteOnCollide )
+        {
+            QueueDel(uid);
+        }
+        if (component.CanPenetrate)
+        {
+            component.DamagedEntity = false;
+
+            if (!TryComp<MobStateComponent>(target, out var mobState))
+                QueueDel(uid);
+        }
+        else if (component.DeleteOnCollide && !component.CanPenetrate)
         {
             QueueDel(uid);
         }
index 276e0943e0213adef93a068524e776335faf53df..3b5cd33c791b57f4361a358d462054035602f0ea 100644 (file)
@@ -33,6 +33,9 @@ public sealed partial class ProjectileComponent : Component
     [DataField("deleteOnCollide")]
     public bool DeleteOnCollide = true;
 
+    [DataField("canPenetrate")]
+    public bool CanPenetrate = false;
+
     [DataField("ignoreResistances")]
     public bool IgnoreResistances = false;
 
index 55bcb94c57360f0e2bdcaf2356458b30395a211e..3ad5fb5de38464a19c40956a44ef84881bce24ca 100644 (file)
@@ -28,7 +28,7 @@ uplink-gloves-north-star-desc = A pair of gloves that reduce your punching coold
 
 # Explosives
 uplink-explosive-grenade-name = Explosive Grenade
-uplink-explosive-grenade-desc = A simplistic grenade with a ten-second fuse that is geared towards injuring personnel. Causes minimal hull damage.
+uplink-explosive-grenade-desc = A simplistic grenade with a three-and-a-half-second long fuse that is geared towards injuring personnel. Causes minimal hull damage.
 
 uplink-flash-grenade-name = Flashbang
 uplink-flash-grenade-desc = A standard-issue flashbang, capable of blinding and slowing down anyone without proper protection. This, of course, includes you; make sure you're properly equipped before using it.
@@ -63,6 +63,15 @@ uplink-exploding-pen-desc = A class IV explosive device contained within a stand
 uplink-exploding-syndicate-bomb-name = Syndicate Bomb
 uplink-exploding-syndicate-bomb-desc = A big, anchored bomb that can create a huge explosion if not defused in time. Useful as a distraction. Has an adjustable timer with a minimum setting of 120 seconds.
 
+uplink-cluster-grenade-name = Cluster Grenade
+uplink-cluster-grenade-desc = Three explosive grenades bundled together, the grenades get launched after the 3.5 second timer runs out.
+
+uplink-incendiary-grenade-name = Incendiary Grenade
+uplink-incendiary-grenade-desc = Releases a spray of incendiary fragments, igniting anyone near the detonation area.
+
+uplink-shrapnel-grenade-name = Shrapnel Grenade
+uplink-shrapnel-grenade-desc = Launches a spray of sharp fragments dealing great damage against unarmored targets.
+
 # Ammo
 uplink-pistol-magazine-name = Pistol Magazine (.35 auto)
 uplink-pistol-magazine-desc = Pistol magazine with 10 catridges. Compatible with the Viper.
@@ -240,6 +249,9 @@ uplink-proximity-mine-desc = A mine disguised as a wet floor sign.
 uplink-disposable-turret-name = Disposable Ballistic Turret
 uplink-disposable-turret-desc = Looks and functions like a normal electrical toolbox. Upon hitting the toolbox it will transform into a ballistic turret, theoretically shooting at anyone except members of the syndicate. Can be turned back into a toolbox using a screwdriver and repaired using a wrench.
 
+uplink-cluster-banana-peel-name = Cluster Banana
+uplink-cluster-banana-peel-desc = Splits into 6 explosive banana peels after being thrown, the peels detonate automatically after 20 seconds if nobody slips on them.
+
 # Armor
 uplink-chameleon-name = Chameleon Kit
 uplink-chameleon-desc = A backpack full of items that contain chameleon technology allowing you to disguise as pretty much anything on the station, and more!
@@ -308,6 +320,9 @@ uplink-syndicate-segway-crate-desc = Be an enemy of the corporation, in style!
 uplink-syndicate-sponge-box-name = Syndicate Sponge Box
 uplink-syndicate-sponge-box-desc = A box containing 6 syndicate sponges disguised as monkey cubes, these cubes turn into a variety of angry wildlife after coming into contact with water.
 
+uplink-slipocalypse-clustersoap-name = Slipocalypse Clustersoap
+uplink-slipocalypse-clustersoap-desc = Scatters arounds small pieces of syndicate-brand soap after being thrown, these pieces of soap evaporate after 60 seconds.
+
 # Pointless
 uplink-revolver-cap-gun-name = Cap Gun
 uplink-revolver-cap-gun-desc = Looks almost like the real thing! Ages 8 and up.
index 658a955b88a08528abe23b2f067f49d1dd9cb135..cd319c3b427936411ac2e81be03fb5bd2493332e 100644 (file)
@@ -3,6 +3,8 @@
   startingInventory:
     Handcuffs: 8
     GrenadeFlashBang: 4
+    ClusterBangFull: 2
+    GrenadeStinger: 4
     Flash: 5
     FlashlightSeclite: 5
     ClothingEyesGlassesSunglasses: 2
index 344bd6a08140b3303f7a40d635c43c7d3b5bc5a4..cce9897256e1f6925f69ed89a0ab4212f4847080 100644 (file)
     - UplinkExplosives
   restockTime: 30
 
+- type: listing
+  id: UplinkClusterGrenade
+  name: uplink-cluster-grenade-name
+  description: uplink-cluster-grenade-desc
+  productEntity: ClusterGrenade
+  cost:
+    Telecrystal: 8
+  categories:
+  - UplinkExplosives
+
+- type: listing
+  id: UplinkGrenadeShrapnel
+  name: uplink-shrapnel-grenade-name
+  description: uplink-shrapnel-grenade-desc
+  productEntity: GrenadeShrapnel
+  cost:
+    Telecrystal: 4
+  categories:
+  - UplinkExplosives
+
+- type: listing
+  id: UplinkGrenadeIncendiary
+  name: uplink-incendiary-grenade-name
+  description: uplink-incendiary-grenade-desc
+  productEntity: GrenadeIncendiary
+  cost:
+    Telecrystal: 4
+  categories:
+  - UplinkExplosives
+
 # Ammo
 
 - type: listing
     whitelist:
     - Clown
 
+- type: listing
+  id: UplinkClusterBananaPeel
+  name: uplink-cluster-banana-peel-name
+  description: uplink-cluster-banana-peel-desc
+  productEntity: ClusterBananaPeel
+  cost:
+    Telecrystal: 6
+  categories:
+  - UplinkJob
+  conditions:
+  - !type:BuyerJobCondition
+    whitelist:
+    - Clown
+
 - type: listing
   id: UplinkHoloclownKit
   name: uplink-holoclown-kit-name
   categories:
   - UplinkMisc
 
+- type: listing
+  id: UplinkSlipocalypseClusterSoap
+  name: uplink-slipocalypse-clustersoap-name
+  description: uplink-slipocalypse-clustersoap-desc
+  productEntity: SlipocalypseClusterSoap
+  cost:
+    Telecrystal: 3
+  categories:
+  - UplinkMisc
+
 - type: listing
   id: UplinkUltrabrightLantern
   name: uplink-ultrabright-lantern-name
index 09f48b258e90ecea133acbb169351b5da12a7faa..ca267a308ca9b3e004f90f0da9ac21f0c7441aa1 100644 (file)
       - clean
       - punishment
 
+- type: entity
+  name: soaplet
+  id: SoapletSyndie
+  noSpawn: true
+  parent: Soap
+  description: A tiny piece of syndicate soap.
+  components:
+  - type: Sprite
+    layers:
+    - state: syndie-soaplet
+  - type: Slippery
+    paralyzeTime: 5
+    launchForwardsMultiplier: 2.5
+  - type: StepTrigger
+    intersectRatio: 0.04
+  - type: Item
+    heldPrefix: syndie
+  - type: Fixtures
+    fixtures:
+      slips:
+        shape:
+          !type:PhysShapeAabb
+          bounds: "-0.08,-0.06,0.08,0.06"
+        layer:
+        - SlipLayer
+        hard: false
+      fix1:
+        shape:
+          !type:PhysShapeAabb
+          bounds: "-0.08,-0.06,0.08,0.06"
+        density: 1
+        mask:
+        - ItemMask
+  - type: DeleteOnTrigger
+  - type: EmitSoundOnTrigger
+    sound:
+      path: "/Audio/Effects/Fluids/splat.ogg"
+      params:
+        volume: -20
+
 - type: entity
   name: soap
   id: SoapHomemade
index 84883c975d04dd226181e6912ba9147c73d5ad37..7d95e7481e3b2125e55b8a630def031edebccc9a 100644 (file)
   - type: ExplodeOnTrigger
   - type: Explosive
     explosionType: Default
-    maxIntensity: 2
-    totalIntensity: 10
+    maxIntensity: 3.4
+    intensitySlope: 3
+    totalIntensity: 20
     canCreateVacuum: false
   - type: DeleteOnTrigger
   - type: AnimationPlayer
+  - type: Damageable
+    damageContainer: Inorganic
+  - type: Destructible
+    thresholds:
+    - trigger:
+        !type:DamageTrigger
+        damage: 10
+      behaviors:
+      - !type:TriggerBehavior
+      - !type:DoActsBehavior
+        acts: ["Destruction"]
 
 - type: entity
   parent: BaseItem
diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/grenade.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/grenade.yml
new file mode 100644 (file)
index 0000000..511cf76
--- /dev/null
@@ -0,0 +1,58 @@
+- type: entity
+  id: PelletClusterRubber
+  name: pellet (ball, Rubber)
+  noSpawn: true
+  parent: BaseBullet
+  components:
+  - type: Sprite
+    sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi
+    state: buckshot
+  - type: Projectile
+    deleteOnCollide: false
+    canPenetrate: true
+    damage:
+      types:
+        Blunt: 4
+  - type: StaminaDamageOnCollide
+    damage: 55
+  - type: TimedDespawn
+    lifetime: 0.25
+
+- type: entity
+  id: PelletClusterLethal
+  name: pellet (ball, Lethal)
+  noSpawn: true
+  parent: BaseBullet
+  components:
+  - type: Sprite
+    sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi
+    state: buckshot
+  - type: Projectile
+    deleteOnCollide: false
+    canPenetrate: true
+    damage:
+      types:
+        Piercing: 45
+  - type: TimedDespawn
+    lifetime: 0.25
+
+- type: entity
+  id: PelletClusterIncendiary
+  name: pellet (ball, incendiary)
+  noSpawn: true
+  parent: BaseBulletIncendiary
+  components:
+  - type: Sprite
+    sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi
+    state: buckshot-flare
+  - type: Projectile
+    deleteOnCollide: false
+    canPenetrate: true
+    damage:
+      groups:
+        Burn: 4
+  - type: IgniteOnCollide
+    fireStacks: 3
+    count: 10
+  - type: TimedDespawn
+    lifetime: 0.25
index b94191ef0278fa16e09ea6a040c285c482712287..d5bca926b9995e39c15dc8aa91d42c7dee34a1dd 100644 (file)
       - state: grenade
   - type: FlashOnTrigger
     range: 7
+  - type: SpawnOnTrigger
+    proto: GrenadeFlashEffect
+  - type: ActiveTimerTrigger
+    timeRemaining: 0.3
+  - type: DeleteOnTrigger
 
 # This is supposed to spawn shrapnel and stuff so uhh... TODO?
 - type: entity
index f7d0a0e5df92f38895c48601b4ce3d19d67df23c..43ed06a3ea020f1490feb39563ec817fe63fbfd4 100644 (file)
   - type: ClusterGrenadeVisuals
     state: base
   - type: ClusterGrenade
+  - type: OnUseTimerTrigger
+    delay: 3.5
   - type: ContainerContainer
     containers:
-      cluster-flash: !type:Container
+      cluster-payload: !type:Container
 
 - type: entity
-  parent: ClusterBang
+  parent: GrenadeBase
   id: ClusterBangFull
+  name: ClusterBang
+  description: Launches three flashbangs after the timer runs out.
   suffix: Full
   components:
   - type: Sprite
-    state: base-3
+    sprite: Objects/Weapons/Grenades/clusterbang.rsi
+    layers:
+    - state: icon
+      map: ["enum.TriggerVisualLayers.Base"]
   - type: ClusterGrenade
     fillPrototype: GrenadeFlashBang
+    distance: 7
+    velocity: 7
+  - type: TimerTriggerVisuals
+    primingSound:
+      path: /Audio/Effects/countdown.ogg
+  - type: GenericVisualizer
+    visuals:
+      enum.Trigger.TriggerVisuals.VisualState:
+        enum.ConstructionVisuals.Layer:
+          Primed: { state: primed }
+          Unprimed: { state: icon }
+  - type: EmitSoundOnTrigger
+    sound:
+      path: "/Audio/Machines/door_lock_off.ogg"
+  - type: ContainerContainer
+    containers:
+      cluster-payload: !type:Container
+
+- type: entity
+  parent: GrenadeBase
+  id: ClusterGrenade
+  name: clustergrenade
+  description: Why use one grenade when you can use three at once!
+  components:
+  - type: Sprite
+    sprite: Objects/Weapons/Grenades/clusterbomb.rsi
+    layers:
+    - state: icon
+      map: ["enum.TriggerVisualLayers.Base"]
+  - type: ClusterGrenade
+    fillPrototype: ExGrenade
+    velocity: 3.5
+    distance: 5
+  - type: OnUseTimerTrigger
+    beepSound:
+      path: "/Audio/Effects/beep1.ogg"
+      params:
+        volume: 5
+    initialBeepDelay: 0
+    beepInterval: 0.5
+  - type: EmitSoundOnTrigger
+    sound:
+      path: "/Audio/Machines/door_lock_off.ogg"
+  - type: ContainerContainer
+    containers:
+      cluster-payload: !type:Container
+
+- type: entity
+  parent: BaseItem
+  id: ClusterBananaPeel
+  name: cluster banana peel
+  description: Splits into 6 explosive banana peels after throwing, guaranteed fun!
+  components:
+  - type: Sprite
+    sprite: Objects/Specific/Hydroponics/banana.rsi
+    state: produce
+  - type: Appearance
+  - type: ClusterGrenade
+    fillPrototype: TrashBananaPeelExplosive
+    maxGrenadesCount: 6
+    baseTriggerDelay: 20
+  - type: DamageOnLand
+    damage:
+      types:
+        Blunt: 10
+  - type: Damageable
+    damageContainer: Inorganic
+  - type: EmitSoundOnTrigger
+    sound:
+      path: "/Audio/Items/bikehorn.ogg"
+  - type: Destructible
+    thresholds:
+    - trigger:
+        !type:DamageTrigger
+        damage: 10
+      behaviors:
+      - !type:TriggerBehavior
+      - !type:DoActsBehavior
+        acts: ["Destruction"]
+  - type: ContainerContainer
+    containers:
+      cluster-payload: !type:Container
+
+- type: entity
+  parent: GrenadeBase
+  id: GrenadeStinger
+  name: stinger grenade
+  description: Nothing to see here, please disperse.
+  components:
+  - type: Sprite
+    sprite: Objects/Weapons/Grenades/stingergrenade.rsi
+    layers:
+    - state: icon
+      map: ["enum.TriggerVisualLayers.Base"]
+  - type: ClusterGrenade
+    fillPrototype: PelletClusterRubber
+    maxGrenadesCount: 30
+    grenadeType: enum.GrenadeType.Shoot
+  - type: FlashOnTrigger
+    range: 7
+  - type: EmitSoundOnTrigger
+    sound:
+      path: "/Audio/Effects/flash_bang.ogg"
+  - type: SpawnOnTrigger
+    proto: GrenadeFlashEffect
+  - type: TimerTriggerVisuals
+    primingSound:
+      path: /Audio/Effects/countdown.ogg
+  - type: ContainerContainer
+    containers:
+      cluster-payload: !type:Container
+
+- type: entity
+  parent: GrenadeBase
+  id: GrenadeIncendiary
+  name: incendiary grenade
+  description: Guaranteed to light up the mood.
+  components:
+  - type: Sprite
+    sprite: Objects/Weapons/Grenades/pyrogrenade.rsi
+    layers:
+    - state: icon
+      map: ["enum.TriggerVisualLayers.Base"]
+  - type: ClusterGrenade
+    fillPrototype: PelletClusterIncendiary
+    maxGrenadesCount: 15
+    grenadeType: enum.GrenadeType.Shoot
+  - type: OnUseTimerTrigger
+    beepSound:
+      path: "/Audio/Effects/beep1.ogg"
+      params:
+        volume: 5
+    initialBeepDelay: 0
+    beepInterval: 2
+  - type: EmitSoundOnTrigger
+    sound:
+      path: "/Audio/Weapons/Guns/Gunshots/batrifle.ogg"
+  - type: ContainerContainer
+    containers:
+      cluster-payload: !type:Container
+
+- type: entity
+  parent: GrenadeBase
+  id: GrenadeShrapnel
+  name: shrapnel grenade
+  description: Releases a deadly spray of shrapnel that causes severe bleeding.
+  components:
+  - type: Sprite
+    sprite: Objects/Weapons/Grenades/shrapnelgrenade.rsi
+    layers:
+    - state: icon
+      map: ["enum.TriggerVisualLayers.Base"]
+  - type: ClusterGrenade
+    fillPrototype: PelletClusterLethal
+    maxGrenadesCount: 30
+    grenadeType: enum.GrenadeType.Shoot
+  - type: OnUseTimerTrigger
+    beepSound:
+      path: "/Audio/Effects/beep1.ogg"
+      params:
+        volume: 5
+    initialBeepDelay: 0
+    beepInterval: 2
+  - type: EmitSoundOnTrigger
+    sound:
+      path: "/Audio/Weapons/Guns/Gunshots/batrifle.ogg"
+  - type: ContainerContainer
+    containers:
+      cluster-payload: !type:Container
+
+- type: entity
+  parent: SoapSyndie
+  id: SlipocalypseClusterSoap
+  name: slipocalypse clustersoap
+  description: Spreads small pieces of syndicate soap over an area upon landing on the floor.
+  components:
+  - type: Sprite
+    sprite: Objects/Specific/Janitorial/soap.rsi
+    layers:
+    - state: syndie-4
+  - type: Appearance
+  - type: ClusterGrenade
+    fillPrototype: SoapletSyndie
+    maxGrenadesCount: 30
+    grenadeTriggerIntervalMax: 0
+    grenadeTriggerIntervalMin: 0
+    baseTriggerDelay: 60
+    randomSpread: true
+    velocity: 3
+  - type: DamageOnLand
+    damage:
+      types:
+        Blunt: 10
+  - type: EmitSoundOnTrigger
+    sound:
+      path: "/Audio/Effects/flash_bang.ogg"
+  - type: Damageable
+    damageContainer: Inorganic
+  - type: Destructible
+    thresholds:
+    - trigger:
+        !type:DamageTrigger
+        damage: 10
+      behaviors:
+      - !type:TriggerBehavior
+      - !type:DoActsBehavior
+        acts: ["Destruction"]
+  - type: ContainerContainer
+    containers:
+      cluster-payload: !type:Container
index ece4ec4ef486235d3cf89d1ac4b08004b9fe5ad4..7f5124a5ebca690b9825ae1747654bc4f7f7d88b 100644 (file)
         acts: ["Destruction"]
   - type: Appearance
   - type: AnimationPlayer
-  - type: TimerTriggerVisuals
+  - type: GenericVisualizer
+    visuals:
+      enum.Trigger.TriggerVisuals.VisualState:
+        enum.ConstructionVisuals.Layer:
+          Primed: { state: primed }
+          Unprimed: { state: icon }
 
 - type: entity
   name: explosive grenade
index 1b0c2eb4364f8afd2cb9f02e6c69c5dbba9042d4..ce6de2f88f2f72f20c8e707ff9df345dcd1e360c 100644 (file)
@@ -79,6 +79,9 @@
     {
       "name": "syndie-4"
     },
+    {
+      "name": "syndie-soaplet"
+    },
     {
       "name": "inhand-left",
       "directions": 4
diff --git a/Resources/Textures/Objects/Specific/Janitorial/soap.rsi/syndie-soaplet.png b/Resources/Textures/Objects/Specific/Janitorial/soap.rsi/syndie-soaplet.png
new file mode 100644 (file)
index 0000000..b071219
Binary files /dev/null and b/Resources/Textures/Objects/Specific/Janitorial/soap.rsi/syndie-soaplet.png differ
diff --git a/Resources/Textures/Objects/Weapons/Grenades/clusterbang.rsi/icon.png b/Resources/Textures/Objects/Weapons/Grenades/clusterbang.rsi/icon.png
new file mode 100644 (file)
index 0000000..18a1d30
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Grenades/clusterbang.rsi/icon.png differ
index 01b494cc954f88d029e5fefea3e706a303ad066d..c017ee2117d49d442ddec065a9f5c15a8a007d7f 100644 (file)
     {
       "name": "base-3",
       "directions": 1
+    },
+    {
+      "name": "icon",
+      "directions": 1
+    },
+    {
+      "name": "primed",
+      "delays": [
+        [
+          0.1,
+          0.1
+        ]
+      ]
     }
   ]
 }
diff --git a/Resources/Textures/Objects/Weapons/Grenades/clusterbang.rsi/primed.png b/Resources/Textures/Objects/Weapons/Grenades/clusterbang.rsi/primed.png
new file mode 100644 (file)
index 0000000..7ce992c
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Grenades/clusterbang.rsi/primed.png differ
diff --git a/Resources/Textures/Objects/Weapons/Grenades/clusterbomb.rsi/base-1.png b/Resources/Textures/Objects/Weapons/Grenades/clusterbomb.rsi/base-1.png
new file mode 100644 (file)
index 0000000..d28cae5
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Grenades/clusterbomb.rsi/base-1.png differ
diff --git a/Resources/Textures/Objects/Weapons/Grenades/clusterbomb.rsi/base-2.png b/Resources/Textures/Objects/Weapons/Grenades/clusterbomb.rsi/base-2.png
new file mode 100644 (file)
index 0000000..392d698
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Grenades/clusterbomb.rsi/base-2.png differ
diff --git a/Resources/Textures/Objects/Weapons/Grenades/clusterbomb.rsi/icon.png b/Resources/Textures/Objects/Weapons/Grenades/clusterbomb.rsi/icon.png
new file mode 100644 (file)
index 0000000..7b4ccd1
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Grenades/clusterbomb.rsi/icon.png differ
diff --git a/Resources/Textures/Objects/Weapons/Grenades/clusterbomb.rsi/meta.json b/Resources/Textures/Objects/Weapons/Grenades/clusterbomb.rsi/meta.json
new file mode 100644 (file)
index 0000000..a4d1e8a
--- /dev/null
@@ -0,0 +1,29 @@
+{
+  "version": 1,
+  "license": "CC-BY-SA-3.0",
+  "copyright": "Taken from tgstation and modified by Swept at https://github.com/tgstation/tgstation/commit/29c0ed1b000619cb5398ef921000a8d4502ba0b6 and modified by Swept",
+  "size": {
+    "x": 32,
+    "y": 32
+  },
+  "states": [
+    {
+      "name": "icon"
+    },
+    {
+      "name": "base-1"
+    },
+    {
+      "name": "base-2"
+    },
+    {
+      "name": "primed",
+      "delays": [
+        [
+          0.1,
+          0.1
+        ]
+      ]
+    }
+  ]
+}
diff --git a/Resources/Textures/Objects/Weapons/Grenades/clusterbomb.rsi/primed.png b/Resources/Textures/Objects/Weapons/Grenades/clusterbomb.rsi/primed.png
new file mode 100644 (file)
index 0000000..b3383c1
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Grenades/clusterbomb.rsi/primed.png differ
diff --git a/Resources/Textures/Objects/Weapons/Grenades/pyrogrenade.rsi/equipped-BELT.png b/Resources/Textures/Objects/Weapons/Grenades/pyrogrenade.rsi/equipped-BELT.png
new file mode 100644 (file)
index 0000000..20d341e
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Grenades/pyrogrenade.rsi/equipped-BELT.png differ
diff --git a/Resources/Textures/Objects/Weapons/Grenades/pyrogrenade.rsi/icon.png b/Resources/Textures/Objects/Weapons/Grenades/pyrogrenade.rsi/icon.png
new file mode 100644 (file)
index 0000000..50421bf
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Grenades/pyrogrenade.rsi/icon.png differ
diff --git a/Resources/Textures/Objects/Weapons/Grenades/pyrogrenade.rsi/meta.json b/Resources/Textures/Objects/Weapons/Grenades/pyrogrenade.rsi/meta.json
new file mode 100644 (file)
index 0000000..28d3e69
--- /dev/null
@@ -0,0 +1,27 @@
+{
+  "version": 1,
+  "license": "CC-BY-SA-3.0",
+  "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/b13d244d761a07e200a9a41730bd446e776020d5",
+  "size": {
+    "x": 32,
+    "y": 32
+  },
+  "states": [
+    {
+      "name": "icon"
+    },
+    {
+      "name": "primed",
+      "delays": [
+        [
+          0.1,
+          0.1
+        ]
+      ]
+    },
+    {
+      "name": "equipped-BELT",
+      "directions": 4
+    }
+  ]
+}
diff --git a/Resources/Textures/Objects/Weapons/Grenades/pyrogrenade.rsi/primed.png b/Resources/Textures/Objects/Weapons/Grenades/pyrogrenade.rsi/primed.png
new file mode 100644 (file)
index 0000000..fbe9753
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Grenades/pyrogrenade.rsi/primed.png differ
diff --git a/Resources/Textures/Objects/Weapons/Grenades/shrapnelgrenade.rsi/equipped-BELT.png b/Resources/Textures/Objects/Weapons/Grenades/shrapnelgrenade.rsi/equipped-BELT.png
new file mode 100644 (file)
index 0000000..3b76c4e
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Grenades/shrapnelgrenade.rsi/equipped-BELT.png differ
diff --git a/Resources/Textures/Objects/Weapons/Grenades/shrapnelgrenade.rsi/icon.png b/Resources/Textures/Objects/Weapons/Grenades/shrapnelgrenade.rsi/icon.png
new file mode 100644 (file)
index 0000000..5bb1563
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Grenades/shrapnelgrenade.rsi/icon.png differ
diff --git a/Resources/Textures/Objects/Weapons/Grenades/shrapnelgrenade.rsi/meta.json b/Resources/Textures/Objects/Weapons/Grenades/shrapnelgrenade.rsi/meta.json
new file mode 100644 (file)
index 0000000..28d3e69
--- /dev/null
@@ -0,0 +1,27 @@
+{
+  "version": 1,
+  "license": "CC-BY-SA-3.0",
+  "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/b13d244d761a07e200a9a41730bd446e776020d5",
+  "size": {
+    "x": 32,
+    "y": 32
+  },
+  "states": [
+    {
+      "name": "icon"
+    },
+    {
+      "name": "primed",
+      "delays": [
+        [
+          0.1,
+          0.1
+        ]
+      ]
+    },
+    {
+      "name": "equipped-BELT",
+      "directions": 4
+    }
+  ]
+}
diff --git a/Resources/Textures/Objects/Weapons/Grenades/shrapnelgrenade.rsi/primed.png b/Resources/Textures/Objects/Weapons/Grenades/shrapnelgrenade.rsi/primed.png
new file mode 100644 (file)
index 0000000..2369617
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Grenades/shrapnelgrenade.rsi/primed.png differ
diff --git a/Resources/Textures/Objects/Weapons/Grenades/stingergrenade.rsi/equipped-BELT.png b/Resources/Textures/Objects/Weapons/Grenades/stingergrenade.rsi/equipped-BELT.png
new file mode 100644 (file)
index 0000000..85a06f2
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Grenades/stingergrenade.rsi/equipped-BELT.png differ
diff --git a/Resources/Textures/Objects/Weapons/Grenades/stingergrenade.rsi/icon.png b/Resources/Textures/Objects/Weapons/Grenades/stingergrenade.rsi/icon.png
new file mode 100644 (file)
index 0000000..1fae857
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Grenades/stingergrenade.rsi/icon.png differ
diff --git a/Resources/Textures/Objects/Weapons/Grenades/stingergrenade.rsi/meta.json b/Resources/Textures/Objects/Weapons/Grenades/stingergrenade.rsi/meta.json
new file mode 100644 (file)
index 0000000..28d3e69
--- /dev/null
@@ -0,0 +1,27 @@
+{
+  "version": 1,
+  "license": "CC-BY-SA-3.0",
+  "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/b13d244d761a07e200a9a41730bd446e776020d5",
+  "size": {
+    "x": 32,
+    "y": 32
+  },
+  "states": [
+    {
+      "name": "icon"
+    },
+    {
+      "name": "primed",
+      "delays": [
+        [
+          0.1,
+          0.1
+        ]
+      ]
+    },
+    {
+      "name": "equipped-BELT",
+      "directions": 4
+    }
+  ]
+}
diff --git a/Resources/Textures/Objects/Weapons/Grenades/stingergrenade.rsi/primed.png b/Resources/Textures/Objects/Weapons/Grenades/stingergrenade.rsi/primed.png
new file mode 100644 (file)
index 0000000..32d39cb
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Grenades/stingergrenade.rsi/primed.png differ
index 5a58b6b60891663669def55471649ecb88fbdb32..bfdf73fe57ff68a440612d5f913cc394eda45f89 100644 (file)
@@ -29,4 +29,4 @@
             "name": "spent"
         }
     ]
-}
\ No newline at end of file
+}