diff --git a/Content.Server/Explosion/Components/ClusterGrenadeComponent.cs b/Content.Server/Explosion/Components/ClusterGrenadeComponent.cs
index e2e3ca2733..fe1b8caede 100644
--- a/Content.Server/Explosion/Components/ClusterGrenadeComponent.cs
+++ b/Content.Server/Explosion/Components/ClusterGrenadeComponent.cs
@@ -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
///
/// What we fill our prototype with if we want to pre-spawn with grenades.
///
- [DataField("fillPrototype", customTypeSerializer:typeof(PrototypeIdSerializer))]
- public string? FillPrototype;
+ [DataField("fillPrototype")]
+ public EntProtoId? FillPrototype;
///
/// 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;
///
- /// How long until our grenades are shot out and armed.
+ /// Maximum delay in seconds between individual grenade triggers
///
- [ViewVariables(VVAccess.ReadWrite)] [DataField("delay")]
- public float Delay = 1;
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("grenadeTriggerIntervalMax")]
+ public float GrenadeTriggerIntervalMax = 0f;
///
- /// Max distance grenades can be thrown.
+ /// Minimum delay in seconds between individual grenade triggers
///
- [ViewVariables(VVAccess.ReadWrite)] [DataField("distance")]
- public float ThrowDistance = 50;
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("grenadeTriggerIntervalMin")]
+ public float GrenadeTriggerIntervalMin = 0f;
+
+ ///
+ /// Minimum delay in seconds before any grenades start to be triggered.
+ ///
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("baseTriggerDelay")]
+ public float BaseTriggerDelay = 1.0f;
+
+ ///
+ /// Decides if grenades trigger after getting launched
+ ///
+ [DataField("triggerGrenades")]
+ public bool TriggerGrenades = true;
+
+ ///
+ /// Does the cluster grenade shoot or throw
+ ///
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("grenadeType")]
+ public Enum GrenadeType = Components.GrenadeType.Throw;
+
+ ///
+ /// The speed at which grenades get thrown
+ ///
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("velocity")]
+ public float Velocity = 5;
+
+ ///
+ /// Should the spread be random
+ ///
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("randomSpread")]
+ public bool RandomSpread = false;
+
+ ///
+ /// Should the angle be random
+ ///
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("randomAngle")]
+ public bool RandomAngle = false;
+
+ ///
+ /// Static distance grenades will be thrown to.
+ ///
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("distance")]
+ public float Distance = 1f;
+
+ ///
+ /// Max distance grenades should randomly be thrown to.
+ ///
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("maxSpreadDistance")]
+ public float MaxSpreadDistance = 2.5f;
+
+ ///
+ /// Minimal distance grenades should randomly be thrown to.
+ ///
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("minSpreadDistance")]
+ public float MinSpreadDistance = 0f;
///
/// This is the end.
///
public bool CountDown;
}
+
+ public enum GrenadeType
+ {
+ Throw,
+ Shoot
+ }
+
}
diff --git a/Content.Server/Explosion/EntitySystems/ClusterGrenadeSystem.cs b/Content.Server/Explosion/EntitySystems/ClusterGrenadeSystem.cs
index 9467966cb6..2674a8d61b 100644
--- a/Content.Server/Explosion/EntitySystems/ClusterGrenadeSystem.cs
+++ b/Content.Server/Explosion/EntitySystems/ClusterGrenadeSystem.cs
@@ -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(OnClugInit);
SubscribeLocalEvent(OnClugStartup);
SubscribeLocalEvent(OnClugUsing);
- SubscribeLocalEvent(OnClugUse);
+ SubscribeLocalEvent(OnClugTrigger);
}
private void OnClugInit(EntityUid uid, ClusterGrenadeComponent component, ComponentInit args)
{
- component.GrenadesContainer = _container.EnsureContainer(uid, "cluster-flash");
+ component.GrenadesContainer = _container.EnsureContainer(uid, "cluster-payload");
}
private void OnClugStartup(Entity clug, ref ComponentStartup args)
@@ -53,64 +59,97 @@ public sealed class ClusterGrenadeSystem : EntitySystem
!HasComp(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 clug, ref TriggerEvent args)
{
- if (component.CountDown || (component.GrenadesContainer.ContainedEntities.Count + component.UnspawnedCount) <= 0)
- return;
-
- // TODO: Should be an Update loop
- uid.SpawnTimer((int) (component.Delay * 1000), () =>
- {
- 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))
- {
- var angleMin = segmentAngle * thrownCount;
- var angleMax = segmentAngle * (thrownCount + 1);
- var angle = Angle.FromDegrees(_random.Next(angleMin, angleMax));
- // var distance = random.NextFloat() * _throwDistance;
-
- delay += _random.Next(550, 900);
- thrownCount++;
-
- // TODO: Suss out throw strength
- _throwingSystem.TryThrow(grenade, angle.ToVec().Normalized() * component.ThrowDistance);
-
- grenade.SpawnTimer(delay, () =>
- {
- if ((!EntityManager.EntityExists(grenade) ? EntityLifeStage.Deleted : MetaData(grenade).EntityLifeStage) >= EntityLifeStage.Deleted)
- return;
-
- _trigger.Trigger(grenade, args.User);
- });
- }
-
- EntityManager.DeleteEntity(uid);
- });
-
+ var component = clug.Comp;
+ component.CountDown = true;
args.Handled = true;
}
- private bool TryGetGrenade(Entity ent, out EntityUid grenade)
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+ var query = EntityQueryEnumerator();
+
+ while (query.MoveNext(out var uid, out var clug))
+ {
+ if (clug.CountDown && clug.UnspawnedCount > 0)
+ {
+ var grenadesInserted = clug.GrenadesContainer.ContainedEntities.Count + clug.UnspawnedCount;
+ var thrownCount = 0;
+ var segmentAngle = 360 / grenadesInserted;
+ var grenadeDelay = 0f;
+
+ 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(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);
+ }
+ }
+ }
+
+ private void ShootProjectile(EntityUid grenade, Angle angle, ClusterGrenadeComponent clug, EntityUid clugUid)
+ {
+ var direction = angle.ToVec().Normalized();
+
+ if (clug.RandomSpread)
+ direction = _random.NextVector2().Normalized();
+
+ _gun.ShootProjectile(grenade, direction, Vector2.One.Normalized(), clugUid);
+
+ }
+
+ 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(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 ent)
+ private void UpdateAppearance(Entity clug)
{
- var component = ent.Comp;
- if (!TryComp(ent, out var appearance))
+ var component = clug.Comp;
+ if (!TryComp(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);
}
}
diff --git a/Content.Server/Projectiles/ProjectileSystem.cs b/Content.Server/Projectiles/ProjectileSystem.cs
index b8a6b8c5b2..1d256071d6 100644
--- a/Content.Server/Projectiles/ProjectileSystem.cs
+++ b/Content.Server/Projectiles/ProjectileSystem.cs
@@ -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(target, out var mobState))
+ QueueDel(uid);
+ }
+ else if (component.DeleteOnCollide && !component.CanPenetrate)
{
QueueDel(uid);
}
diff --git a/Content.Shared/Projectiles/ProjectileComponent.cs b/Content.Shared/Projectiles/ProjectileComponent.cs
index 276e0943e0..3b5cd33c79 100644
--- a/Content.Shared/Projectiles/ProjectileComponent.cs
+++ b/Content.Shared/Projectiles/ProjectileComponent.cs
@@ -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;
diff --git a/Resources/Locale/en-US/store/uplink-catalog.ftl b/Resources/Locale/en-US/store/uplink-catalog.ftl
index 55bcb94c57..3ad5fb5de3 100644
--- a/Resources/Locale/en-US/store/uplink-catalog.ftl
+++ b/Resources/Locale/en-US/store/uplink-catalog.ftl
@@ -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.
diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml
index 658a955b88..cd319c3b42 100644
--- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml
+++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml
@@ -3,6 +3,8 @@
startingInventory:
Handcuffs: 8
GrenadeFlashBang: 4
+ ClusterBangFull: 2
+ GrenadeStinger: 4
Flash: 5
FlashlightSeclite: 5
ClothingEyesGlassesSunglasses: 2
diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml
index 344bd6a081..cce9897256 100644
--- a/Resources/Prototypes/Catalog/uplink_catalog.yml
+++ b/Resources/Prototypes/Catalog/uplink_catalog.yml
@@ -250,6 +250,36 @@
- 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
@@ -956,6 +986,20 @@
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
@@ -1186,6 +1230,16 @@
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
diff --git a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/soap.yml b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/soap.yml
index 09f48b258e..ca267a308c 100644
--- a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/soap.yml
+++ b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/soap.yml
@@ -128,6 +128,46 @@
- 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
diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml
index 84883c975d..7d95e7481e 100644
--- a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml
+++ b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml
@@ -83,11 +83,23 @@
- 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
index 0000000000..511cf76df9
--- /dev/null
+++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/grenade.yml
@@ -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
diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml
index b94191ef02..d5bca926b9 100644
--- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml
+++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml
@@ -641,6 +641,11 @@
- 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
diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/clusterbang.yml b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/clusterbang.yml
index f7d0a0e5df..43ed06a3ea 100644
--- a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/clusterbang.yml
+++ b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/clusterbang.yml
@@ -11,16 +11,233 @@
- 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
diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml
index ece4ec4ef4..7f5124a5eb 100644
--- a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml
+++ b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml
@@ -29,7 +29,12 @@
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
diff --git a/Resources/Textures/Objects/Specific/Janitorial/soap.rsi/meta.json b/Resources/Textures/Objects/Specific/Janitorial/soap.rsi/meta.json
index 1b0c2eb436..ce6de2f88f 100644
--- a/Resources/Textures/Objects/Specific/Janitorial/soap.rsi/meta.json
+++ b/Resources/Textures/Objects/Specific/Janitorial/soap.rsi/meta.json
@@ -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
index 0000000000..b071219781
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
index 0000000000..18a1d3042c
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Grenades/clusterbang.rsi/icon.png differ
diff --git a/Resources/Textures/Objects/Weapons/Grenades/clusterbang.rsi/meta.json b/Resources/Textures/Objects/Weapons/Grenades/clusterbang.rsi/meta.json
index 01b494cc95..c017ee2117 100644
--- a/Resources/Textures/Objects/Weapons/Grenades/clusterbang.rsi/meta.json
+++ b/Resources/Textures/Objects/Weapons/Grenades/clusterbang.rsi/meta.json
@@ -22,6 +22,19 @@
{
"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
index 0000000000..7ce992cde8
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
index 0000000000..d28cae5a6b
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
index 0000000000..392d6981b4
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
index 0000000000..7b4ccd1c0f
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
index 0000000000..a4d1e8aeb9
--- /dev/null
+++ b/Resources/Textures/Objects/Weapons/Grenades/clusterbomb.rsi/meta.json
@@ -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
index 0000000000..b3383c172d
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
index 0000000000..20d341ef8c
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
index 0000000000..50421bf708
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
index 0000000000..28d3e6969a
--- /dev/null
+++ b/Resources/Textures/Objects/Weapons/Grenades/pyrogrenade.rsi/meta.json
@@ -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
index 0000000000..fbe975391a
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
index 0000000000..3b76c4e57f
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
index 0000000000..5bb1563118
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
index 0000000000..28d3e6969a
--- /dev/null
+++ b/Resources/Textures/Objects/Weapons/Grenades/shrapnelgrenade.rsi/meta.json
@@ -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
index 0000000000..2369617cd3
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
index 0000000000..85a06f2d4d
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
index 0000000000..1fae857453
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
index 0000000000..28d3e6969a
--- /dev/null
+++ b/Resources/Textures/Objects/Weapons/Grenades/stingergrenade.rsi/meta.json
@@ -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
index 0000000000..32d39cb89f
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Grenades/stingergrenade.rsi/primed.png differ
diff --git a/Resources/Textures/Objects/Weapons/Guns/Ammunition/Explosives/explosives.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Ammunition/Explosives/explosives.rsi/meta.json
index 5a58b6b608..bfdf73fe57 100644
--- a/Resources/Textures/Objects/Weapons/Guns/Ammunition/Explosives/explosives.rsi/meta.json
+++ b/Resources/Textures/Objects/Weapons/Guns/Ammunition/Explosives/explosives.rsi/meta.json
@@ -29,4 +29,4 @@
"name": "spent"
}
]
-}
\ No newline at end of file
+}