]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Clumsy system refactor (#31147)
authorbeck-thompson <107373427+beck-thompson@users.noreply.github.com>
Fri, 15 Nov 2024 23:46:01 +0000 (15:46 -0800)
committerGitHub <noreply@github.com>
Fri, 15 Nov 2024 23:46:01 +0000 (00:46 +0100)
* First commit

* Fixes

* Added the noise

* Renames

* Timespan

* Fixed space

* entity -> ent

* This shouldn't work

* opps....

* Datafield name change

* Better comments

* small comment

* Personal skill issue

* Event renames and stuff

* Couple fixes

* Defib ref fixes (Silly me)

* Added clumsy back!

* no hard code clumsy!

* Identity fix

* Event name change

* Comment change

* Function name change

* opp

* Update names

* Damage stuff!

* Fixes!

* Fixes

* opps

* This was hidden away!!

* negative diff feeds me

25 files changed:
Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs
Content.Server/Administration/Systems/SuperBonkSystem.cs
Content.Server/Chemistry/EntitySystems/HypospraySystem.cs
Content.Server/Cluwne/CluwneSystem.cs
Content.Server/Medical/DefibrillatorSystem.cs
Content.Server/Weapons/Ranged/Systems/GunSystem.cs
Content.Shared/Chemistry/Components/HyposprayComponent.cs
Content.Shared/Chemistry/Events/HyposprayEvents.cs [new file with mode: 0644]
Content.Shared/Climbing/Components/BonkableComponent.cs
Content.Shared/Climbing/Events/BeforeClimbEvents.cs [new file with mode: 0644]
Content.Shared/Climbing/Systems/BonkSystem.cs [deleted file]
Content.Shared/Climbing/Systems/ClimbSystem.cs
Content.Shared/Clumsy/ClumsyComponent.cs [new file with mode: 0644]
Content.Shared/Clumsy/ClumsySystem.cs [new file with mode: 0644]
Content.Shared/Interaction/Components/ClumsyComponent.cs [deleted file]
Content.Shared/Interaction/SharedInteractionSystem.Clumsy.cs [deleted file]
Content.Shared/Inventory/InventorySystem.Relay.cs
Content.Shared/Medical/DefibrillatorEvents.cs [new file with mode: 0644]
Content.Shared/Medical/TargetDefibrillatedEvent.cs [deleted file]
Content.Shared/Weapons/Ranged/Events/BeforeGunShootEvent.cs [new file with mode: 0644]
Resources/Locale/en-US/bonk/components/bonkable-component.ftl
Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
Resources/Prototypes/Entities/Mobs/Player/guardian.yml
Resources/Prototypes/Entities/Structures/Furniture/Tables/base_structuretables.yml
Resources/Prototypes/Roles/Jobs/Civilian/clown.yml

index 2187cbd68f39c93820a1b96846b8c697ba9517bd..4cd1f95288011496e306844abf3b312a1393468e 100644 (file)
@@ -22,6 +22,7 @@ using Content.Shared.Administration;
 using Content.Shared.Administration.Components;
 using Content.Shared.Body.Components;
 using Content.Shared.Body.Part;
+using Content.Shared.Clumsy;
 using Content.Shared.Clothing.Components;
 using Content.Shared.Cluwne;
 using Content.Shared.Damage;
index 5488a8d6f46d49e99671c733d4ae5620e29bb167..5cd62d835729343b8ee5229ada657aa273b84202 100644 (file)
@@ -1,27 +1,27 @@
 using Content.Server.Administration.Components;
 using Content.Shared.Climbing.Components;
-using Content.Shared.Climbing.Events;
-using Content.Shared.Climbing.Systems;
-using Content.Shared.Interaction.Components;
+using Content.Shared.Clumsy;
 using Content.Shared.Mobs;
 using Content.Shared.Mobs.Components;
+using Robust.Shared.Audio.Systems;
 
 namespace Content.Server.Administration.Systems;
 
-public sealed class SuperBonkSystem: EntitySystem
+public sealed class SuperBonkSystem : EntitySystem
 {
     [Dependency] private readonly SharedTransformSystem _transformSystem = default!;
-    [Dependency] private readonly BonkSystem _bonkSystem = default!;
+    [Dependency] private readonly ClumsySystem _clumsySystem = default!;
+    [Dependency] private readonly SharedAudioSystem _audioSystem = default!;
 
     public override void Initialize()
     {
         base.Initialize();
 
-        SubscribeLocalEvent<SuperBonkComponent, ComponentShutdown>(OnBonkShutdown);
         SubscribeLocalEvent<SuperBonkComponent, MobStateChangedEvent>(OnMobStateChanged);
+        SubscribeLocalEvent<SuperBonkComponent, ComponentShutdown>(OnBonkShutdown);
     }
 
-    public void StartSuperBonk(EntityUid target, float delay = 0.1f, bool stopWhenDead = false )
+    public void StartSuperBonk(EntityUid target, float delay = 0.1f, bool stopWhenDead = false)
     {
 
         //The other check in the code to stop when the target dies does not work if the target is already dead.
@@ -31,7 +31,6 @@ public sealed class SuperBonkSystem: EntitySystem
                 return;
         }
 
-
         var hadClumsy = EnsureComp<ClumsyComponent>(target, out _);
 
         var tables = EntityQueryEnumerator<BonkableComponent>();
@@ -79,16 +78,17 @@ public sealed class SuperBonkSystem: EntitySystem
     private void Bonk(SuperBonkComponent comp)
     {
         var uid = comp.Tables.Current.Key;
-        var bonkComp = comp.Tables.Current.Value;
 
         // It would be very weird for something without a transform component to have a bonk component
         // but just in case because I don't want to crash the server.
-        if (!HasComp<TransformComponent>(uid))
+        if (!HasComp<TransformComponent>(uid) || !TryComp<ClumsyComponent>(comp.Target, out var clumsyComp))
             return;
 
         _transformSystem.SetCoordinates(comp.Target, Transform(uid).Coordinates);
 
-        _bonkSystem.TryBonk(comp.Target, uid, bonkComp);
+        _clumsySystem.HitHeadClumsy((comp.Target, clumsyComp), uid);
+
+        _audioSystem.PlayPvs(clumsyComp.TableBonkSound, comp.Target);
     }
 
     private void OnMobStateChanged(EntityUid uid, SuperBonkComponent comp, MobStateChangedEvent args)
index 9b78e81aa00aab96367a746f987127430356dacc..8345aa3c3ddeff7997ebb96b3fcdda7661941be3 100644 (file)
@@ -1,6 +1,7 @@
 using Content.Shared.Chemistry.EntitySystems;
 using Content.Shared.Chemistry.Components;
 using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry.Hypospray.Events;
 using Content.Shared.Chemistry;
 using Content.Shared.Database;
 using Content.Shared.FixedPoint;
@@ -85,14 +86,44 @@ public sealed class HypospraySystem : SharedHypospraySystem
 
         string? msgFormat = null;
 
-        if (target == user)
-            msgFormat = "hypospray-component-inject-self-message";
-        else if (EligibleEntity(user, EntityManager, component) && _interaction.TryRollClumsy(user, component.ClumsyFailChance))
+        // Self event
+        var selfEvent = new SelfBeforeHyposprayInjectsEvent(user, entity.Owner, target);
+        RaiseLocalEvent(user, selfEvent);
+
+        if (selfEvent.Cancelled)
+        {
+            _popup.PopupEntity(Loc.GetString(selfEvent.InjectMessageOverride ?? "hypospray-cant-inject", ("owner", Identity.Entity(target, EntityManager))), target, user);
+            return false;
+        }
+
+        target = selfEvent.TargetGettingInjected;
+
+        if (!EligibleEntity(target, EntityManager, component))
+            return false;
+
+        // Target event
+        var targetEvent = new TargetBeforeHyposprayInjectsEvent(user, entity.Owner, target);
+        RaiseLocalEvent(target, targetEvent);
+
+        if (targetEvent.Cancelled)
         {
-            msgFormat = "hypospray-component-inject-self-clumsy-message";
-            target = user;
+            _popup.PopupEntity(Loc.GetString(targetEvent.InjectMessageOverride ?? "hypospray-cant-inject", ("owner", Identity.Entity(target, EntityManager))), target, user);
+            return false;
         }
 
+        target = targetEvent.TargetGettingInjected;
+
+        if (!EligibleEntity(target, EntityManager, component))
+            return false;
+
+        // The target event gets priority for the overriden message.
+        if (targetEvent.InjectMessageOverride != null)
+            msgFormat = targetEvent.InjectMessageOverride;
+        else if (selfEvent.InjectMessageOverride != null)
+            msgFormat = selfEvent.InjectMessageOverride;
+        else if (target == user)
+            msgFormat = "hypospray-component-inject-self-message";
+
         if (!_solutionContainers.TryGetSolution(uid, component.SolutionName, out var hypoSpraySoln, out var hypoSpraySolution) || hypoSpraySolution.Volume == 0)
         {
             _popup.PopupEntity(Loc.GetString("hypospray-component-empty-message"), target, user);
index f24f0143f3164bc6482a6a36b6d633c4b37e6123..1fbb0c72690fb6b1b31f3ab5f798fdcb2d12c7cc 100644 (file)
@@ -16,6 +16,7 @@ using Content.Shared.Cluwne;
 using Content.Shared.Interaction.Components;
 using Robust.Shared.Audio.Systems;
 using Content.Shared.NameModifier.EntitySystems;
+using Content.Shared.Clumsy;
 
 namespace Content.Server.Cluwne;
 
index c9cb6cc58dc2e8db7605a97b4d044b449eb33eb8..fa0ea26385d09760e9895749f5232544d3d537c1 100644 (file)
@@ -77,7 +77,20 @@ public sealed class DefibrillatorSystem : EntitySystem
         Zap(uid, target, args.User, component);
     }
 
-    public bool CanZap(EntityUid uid, EntityUid target, EntityUid? user = null, DefibrillatorComponent? component = null)
+    /// <summary>
+    ///     Checks if you can actually defib a target.
+    /// </summary>
+    /// <param name="uid">Uid of the defib</param>
+    /// <param name="target">Uid of the target getting defibbed</param>
+    /// <param name="user">Uid of the entity using the defibrillator</param>
+    /// <param name="component">Defib component</param>
+    /// <param name="targetCanBeAlive">
+    ///     If true, the target can be alive. If false, the function will check if the target is alive and will return false if they are.
+    /// </param>
+    /// <returns>
+    ///     Returns true if the target is valid to be defibed, false otherwise.
+    /// </returns>
+    public bool CanZap(EntityUid uid, EntityUid target, EntityUid? user = null, DefibrillatorComponent? component = null, bool targetCanBeAlive = false)
     {
         if (!Resolve(uid, ref component))
             return false;
@@ -98,15 +111,25 @@ public sealed class DefibrillatorSystem : EntitySystem
         if (!_powerCell.HasActivatableCharge(uid, user: user))
             return false;
 
-        if (_mobState.IsAlive(target, mobState))
+        if (!targetCanBeAlive && _mobState.IsAlive(target, mobState))
             return false;
 
-        if (!component.CanDefibCrit && _mobState.IsCritical(target, mobState))
+        if (!targetCanBeAlive && !component.CanDefibCrit && _mobState.IsCritical(target, mobState))
             return false;
 
         return true;
     }
 
+    /// <summary>
+    ///     Tries to start defibrillating the target. If the target is valid, will start the defib do-after.
+    /// </summary>
+    /// <param name="uid">Uid of the defib</param>
+    /// <param name="target">Uid of the target getting defibbed</param>
+    /// <param name="user">Uid of the entity using the defibrillator</param>
+    /// <param name="component">Defib component</param>
+    /// <returns>
+    ///     Returns true if the defibrillation do-after started, otherwise false.
+    /// </returns>
     public bool TryStartZap(EntityUid uid, EntityUid target, EntityUid user, DefibrillatorComponent? component = null)
     {
         if (!Resolve(uid, ref component))
@@ -118,25 +141,42 @@ public sealed class DefibrillatorSystem : EntitySystem
         _audio.PlayPvs(component.ChargeSound, uid);
         return _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, user, component.DoAfterDuration, new DefibrillatorZapDoAfterEvent(),
             uid, target, uid)
-            {
-                NeedHand = true,
-                BreakOnMove = !component.AllowDoAfterMovement
-            });
+        {
+            NeedHand = true,
+            BreakOnMove = !component.AllowDoAfterMovement
+        });
     }
 
-    public void Zap(EntityUid uid, EntityUid target, EntityUid user, DefibrillatorComponent? component = null, MobStateComponent? mob = null, MobThresholdsComponent? thresholds = null)
+    /// <summary>
+    ///     Tries to defibrillate the target with the given defibrillator.
+    /// </summary>
+    public void Zap(EntityUid uid, EntityUid target, EntityUid user, DefibrillatorComponent? component = null)
     {
-        if (!Resolve(uid, ref component) || !Resolve(target, ref mob, ref thresholds, false))
+        if (!Resolve(uid, ref component))
             return;
 
-        // clowns zap themselves
-        if (HasComp<ClumsyComponent>(user) && user != target)
-        {
-            Zap(uid, user, user, component);
+        if (!_powerCell.TryUseActivatableCharge(uid, user: user))
             return;
-        }
 
-        if (!_powerCell.TryUseActivatableCharge(uid, user: user))
+        var selfEvent = new SelfBeforeDefibrillatorZapsEvent(user, uid, target);
+        RaiseLocalEvent(user, selfEvent);
+
+        target = selfEvent.DefibTarget;
+
+        // Ensure thet new target is still valid.
+        if (selfEvent.Cancelled || !CanZap(uid, target, user, component, true))
+            return;
+
+        var targetEvent = new TargetBeforeDefibrillatorZapsEvent(user, uid, target);
+        RaiseLocalEvent(target, targetEvent);
+
+        target = targetEvent.DefibTarget;
+
+        if (targetEvent.Cancelled || !CanZap(uid, target, user, component, true))
+            return;
+
+        if (!TryComp<MobStateComponent>(target, out var mob) ||
+            !TryComp<MobThresholdsComponent>(target, out var thresholds))
             return;
 
         _audio.PlayPvs(component.ZapSound, uid);
index 701753a8ce235dfebae3223b6bcb8b0c4210730f..d22b5ec2af7b4a93b8171449cc769a39ba979eff 100644 (file)
@@ -1,15 +1,12 @@
 using System.Linq;
 using System.Numerics;
 using Content.Server.Cargo.Systems;
-using Content.Server.Interaction;
 using Content.Server.Power.EntitySystems;
-using Content.Server.Stunnable;
 using Content.Server.Weapons.Ranged.Components;
 using Content.Shared.Damage;
 using Content.Shared.Damage.Systems;
 using Content.Shared.Database;
 using Content.Shared.Effects;
-using Content.Shared.Interaction.Components;
 using Content.Shared.Projectiles;
 using Content.Shared.Weapons.Melee;
 using Content.Shared.Weapons.Ranged;
@@ -33,16 +30,13 @@ public sealed partial class GunSystem : SharedGunSystem
     [Dependency] private readonly IComponentFactory _factory = default!;
     [Dependency] private readonly BatterySystem _battery = default!;
     [Dependency] private readonly DamageExamineSystem _damageExamine = default!;
-    [Dependency] private readonly InteractionSystem _interaction = default!;
     [Dependency] private readonly PricingSystem _pricing = default!;
     [Dependency] private readonly SharedColorFlashEffectSystem _color = default!;
     [Dependency] private readonly SharedTransformSystem _transform = default!;
     [Dependency] private readonly StaminaSystem _stamina = default!;
-    [Dependency] private readonly StunSystem _stun = default!;
     [Dependency] private readonly SharedContainerSystem _container = default!;
 
     private const float DamagePitchVariation = 0.05f;
-    public const float GunClumsyChance = 0.5f;
 
     public override void Initialize()
     {
@@ -71,26 +65,14 @@ public sealed partial class GunSystem : SharedGunSystem
     {
         userImpulse = true;
 
-        // Try a clumsy roll
-        // TODO: Who put this here
-        if (TryComp<ClumsyComponent>(user, out var clumsy) && gun.ClumsyProof == false)
+        if (user != null)
         {
-            for (var i = 0; i < ammo.Count; i++)
+            var selfEvent = new SelfBeforeGunShotEvent(user.Value, (gunUid, gun), ammo);
+            RaiseLocalEvent(user.Value, selfEvent);
+            if (selfEvent.Cancelled)
             {
-                if (_interaction.TryRollClumsy(user.Value, GunClumsyChance, clumsy))
-                {
-                    // Wound them
-                    Damageable.TryChangeDamage(user, clumsy.ClumsyDamage, origin: user);
-                    _stun.TryParalyze(user.Value, TimeSpan.FromSeconds(3f), true);
-
-                    // Apply salt to the wound ("Honk!")
-                    Audio.PlayPvs(new SoundPathSpecifier("/Audio/Weapons/Guns/Gunshots/bang.ogg"), gunUid);
-                    Audio.PlayPvs(clumsy.ClumsySound, gunUid);
-
-                    PopupSystem.PopupEntity(Loc.GetString("gun-clumsy"), user.Value);
-                    userImpulse = false;
-                    return;
-                }
+                userImpulse = false;
+                return;
             }
         }
 
index 05ef84bbaf757932326a0c200b0b8cdd963d5e9c..17d52f0ad9333d19a052c4c3db921eb99f94705e 100644 (file)
@@ -11,11 +11,6 @@ public sealed partial class HyposprayComponent : Component
     [DataField]
     public string SolutionName = "hypospray";
 
-    // TODO: This should be on clumsycomponent.
-    [DataField]
-    [ViewVariables(VVAccess.ReadWrite)]
-    public float ClumsyFailChance = 0.5f;
-
     [DataField]
     [ViewVariables(VVAccess.ReadWrite)]
     public FixedPoint2 TransferAmount = FixedPoint2.New(5);
diff --git a/Content.Shared/Chemistry/Events/HyposprayEvents.cs b/Content.Shared/Chemistry/Events/HyposprayEvents.cs
new file mode 100644 (file)
index 0000000..e8ed081
--- /dev/null
@@ -0,0 +1,38 @@
+using Content.Shared.Inventory;
+
+namespace Content.Shared.Chemistry.Hypospray.Events;
+
+public abstract partial class BeforeHyposprayInjectsTargetEvent : CancellableEntityEventArgs, IInventoryRelayEvent
+{
+    public SlotFlags TargetSlots { get; } = SlotFlags.WITHOUT_POCKET;
+    public EntityUid EntityUsingHypospray;
+    public readonly EntityUid Hypospray;
+    public EntityUid TargetGettingInjected;
+    public string? InjectMessageOverride;
+
+    public BeforeHyposprayInjectsTargetEvent(EntityUid user, EntityUid hypospray, EntityUid target)
+    {
+        EntityUsingHypospray = user;
+        Hypospray = hypospray;
+        TargetGettingInjected = target;
+        InjectMessageOverride = null;
+    }
+}
+
+/// <summary>
+///     This event is raised on the user using the hypospray before the hypospray is injected.
+///     The event is triggered on the user and all their clothing.
+/// </summary>
+public sealed class SelfBeforeHyposprayInjectsEvent : BeforeHyposprayInjectsTargetEvent
+{
+    public SelfBeforeHyposprayInjectsEvent(EntityUid user, EntityUid hypospray, EntityUid target) : base(user, hypospray, target) { }
+}
+
+/// <summary>
+///     This event is raised on the target before the hypospray is injected.
+///     The event is triggered on the target itself and all its clothing.
+/// </summary>
+public sealed class TargetBeforeHyposprayInjectsEvent  : BeforeHyposprayInjectsTargetEvent
+{
+    public TargetBeforeHyposprayInjectsEvent (EntityUid user, EntityUid hypospray, EntityUid target) : base(user, hypospray, target) { }
+}
index 5e97396fbad04a7f771435654cc9b7ad89bea70b..cb4839cae7136ce9e25953f74301d15b287172d7 100644 (file)
@@ -1,5 +1,4 @@
 using Content.Shared.Damage;
-using Robust.Shared.Audio;
 using Robust.Shared.GameStates;
 
 namespace Content.Shared.Climbing.Components;
@@ -8,39 +7,18 @@ namespace Content.Shared.Climbing.Components;
 ///     Makes entity do damage and stun entities with ClumsyComponent
 ///     upon DragDrop or Climb interactions.
 /// </summary>
-[RegisterComponent, NetworkedComponent, Access(typeof(Systems.BonkSystem))]
+[RegisterComponent, NetworkedComponent]
 public sealed partial class BonkableComponent : Component
 {
     /// <summary>
-    /// Chance of bonk triggering if the user is clumsy.
+    ///     How long to stun players on bonk, in seconds.
     /// </summary>
-    [DataField("bonkClumsyChance")]
-    public float BonkClumsyChance = 0.5f;
+    [DataField]
+    public TimeSpan BonkTime = TimeSpan.FromSeconds(2);
 
     /// <summary>
-    /// Sound to play when bonking.
+    ///     How much damage to apply on bonk.
     /// </summary>
-    /// <seealso cref="Bonk"/>
-    [DataField("bonkSound")]
-    public SoundSpecifier? BonkSound;
-
-    /// <summary>
-    /// How long to stun players on bonk, in seconds.
-    /// </summary>
-    /// <seealso cref="Bonk"/>
-    [DataField("bonkTime")]
-    public float BonkTime = 2;
-
-    /// <summary>
-    /// How much damage to apply on bonk.
-    /// </summary>
-    /// <seealso cref="Bonk"/>
-    [DataField("bonkDamage")]
+    [DataField]
     public DamageSpecifier? BonkDamage;
-
-    /// <summary>
-    /// How long it takes to bonk.
-    /// </summary>
-    [DataField("bonkDelay")]
-    public float BonkDelay = 1.5f;
 }
diff --git a/Content.Shared/Climbing/Events/BeforeClimbEvents.cs b/Content.Shared/Climbing/Events/BeforeClimbEvents.cs
new file mode 100644 (file)
index 0000000..85c40f9
--- /dev/null
@@ -0,0 +1,36 @@
+using Content.Shared.Inventory;
+using Content.Shared.Climbing.Components;
+
+namespace Content.Shared.Climbing.Events;
+
+public abstract partial class BeforeClimbEvent : CancellableEntityEventArgs
+{
+    public readonly EntityUid GettingPutOnTable;
+    public readonly EntityUid PuttingOnTable;
+    public readonly Entity<ClimbableComponent> BeingClimbedOn;
+
+    public BeforeClimbEvent(EntityUid gettingPutOntable, EntityUid puttingOnTable, Entity<ClimbableComponent> beingClimbedOn)
+    {
+        GettingPutOnTable = gettingPutOntable;
+        PuttingOnTable = puttingOnTable;
+        BeingClimbedOn = beingClimbedOn;
+    }
+}
+
+/// <summary>
+///     This event is raised on the the person either getting put on or going on the table.
+///     The event is also called on their clothing as well.
+/// </summary>
+public sealed class SelfBeforeClimbEvent : BeforeClimbEvent, IInventoryRelayEvent
+{
+    public SlotFlags TargetSlots { get; } = SlotFlags.WITHOUT_POCKET;
+    public SelfBeforeClimbEvent(EntityUid gettingPutOntable, EntityUid puttingOnTable, Entity<ClimbableComponent> beingClimbedOn) : base(gettingPutOntable, puttingOnTable, beingClimbedOn) { }
+}
+
+/// <summary>
+///     This event is raised on the thing being climbed on.
+/// </summary>
+public sealed class TargetBeforeClimbEvent : BeforeClimbEvent
+{
+    public TargetBeforeClimbEvent(EntityUid gettingPutOntable, EntityUid puttingOnTable, Entity<ClimbableComponent> beingClimbedOn) : base(gettingPutOntable, puttingOnTable, beingClimbedOn) { }
+}
diff --git a/Content.Shared/Climbing/Systems/BonkSystem.cs b/Content.Shared/Climbing/Systems/BonkSystem.cs
deleted file mode 100644 (file)
index f59fe92..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-using Content.Shared.CCVar;
-using Content.Shared.Climbing.Components;
-using Content.Shared.Climbing.Events;
-using Content.Shared.Damage;
-using Content.Shared.DoAfter;
-using Content.Shared.DragDrop;
-using Content.Shared.Hands.Components;
-using Content.Shared.IdentityManagement;
-using Content.Shared.Interaction;
-using Content.Shared.Interaction.Components;
-using Content.Shared.Popups;
-using Content.Shared.Stunnable;
-using Robust.Shared.Audio.Systems;
-using Robust.Shared.Configuration;
-using Robust.Shared.Player;
-using Robust.Shared.Serialization;
-
-namespace Content.Shared.Climbing.Systems;
-
-public sealed partial class BonkSystem : EntitySystem
-{
-    [Dependency] private readonly IConfigurationManager _cfg = default!;
-    [Dependency] private readonly DamageableSystem _damageableSystem = default!;
-    [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
-    [Dependency] private readonly SharedStunSystem _stunSystem = default!;
-    [Dependency] private readonly SharedAudioSystem _audioSystem = default!;
-    [Dependency] private readonly SharedPopupSystem _popupSystem = default!;
-    [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
-
-    public override void Initialize()
-    {
-        base.Initialize();
-        SubscribeLocalEvent<BonkableComponent, BonkDoAfterEvent>(OnBonkDoAfter);
-        SubscribeLocalEvent<BonkableComponent, AttemptClimbEvent>(OnAttemptClimb);
-    }
-
-    private void OnBonkDoAfter(EntityUid uid, BonkableComponent component, BonkDoAfterEvent args)
-    {
-        if (args.Handled || args.Cancelled || args.Args.Used == null)
-            return;
-
-        TryBonk(args.Args.Used.Value, uid, component, source: args.Args.User);
-
-        args.Handled = true;
-    }
-
-
-    public bool TryBonk(EntityUid user, EntityUid bonkableUid, BonkableComponent? bonkableComponent = null, EntityUid? source = null)
-    {
-        if (!Resolve(bonkableUid, ref bonkableComponent, false))
-            return false;
-
-        // BONK!
-        var userName = Identity.Entity(user, EntityManager);
-        var bonkableName = Identity.Entity(bonkableUid, EntityManager);
-
-        if (user == source)
-        {
-            // Non-local, non-bonking players
-            var othersMessage = Loc.GetString("bonkable-success-message-others", ("user", userName), ("bonkable", bonkableName));
-            // Local, bonking player
-            var selfMessage = Loc.GetString("bonkable-success-message-user", ("user", userName), ("bonkable", bonkableName));
-
-            _popupSystem.PopupPredicted(selfMessage, othersMessage, user, user);
-        }
-        else if (source != null)
-        {
-            // Local, non-bonking player (dragger)
-            _popupSystem.PopupClient(Loc.GetString("bonkable-success-message-others", ("user", userName), ("bonkable", bonkableName)), user, source.Value);
-            // Non-local, non-bonking players
-            _popupSystem.PopupEntity(Loc.GetString("bonkable-success-message-others", ("user", userName), ("bonkable", bonkableName)), user, Filter.Pvs(user).RemoveWhereAttachedEntity(e => e == user || e == source.Value), true);
-            // Non-local, bonking player
-            _popupSystem.PopupEntity(Loc.GetString("bonkable-success-message-user", ("user", userName), ("bonkable", bonkableName)), user, user);
-        }
-
-
-
-        if (source != null)
-            _audioSystem.PlayPredicted(bonkableComponent.BonkSound, bonkableUid, source);
-        else
-            _audioSystem.PlayPvs(bonkableComponent.BonkSound, bonkableUid);
-
-        _stunSystem.TryParalyze(user, TimeSpan.FromSeconds(bonkableComponent.BonkTime), true);
-
-        if (bonkableComponent.BonkDamage is { } bonkDmg)
-            _damageableSystem.TryChangeDamage(user, bonkDmg, true, origin: user);
-
-        return true;
-
-    }
-
-    private bool TryStartBonk(EntityUid uid, EntityUid user, EntityUid climber, BonkableComponent? bonkableComponent = null)
-    {
-        if (!Resolve(uid, ref bonkableComponent, false))
-            return false;
-
-        if (!HasComp<ClumsyComponent>(climber) || !HasComp<HandsComponent>(user))
-            return false;
-
-        if (!_cfg.GetCVar(CCVars.GameTableBonk))
-        {
-            // Not set to always bonk, try clumsy roll.
-            if (!_interactionSystem.TryRollClumsy(climber, bonkableComponent.BonkClumsyChance))
-                return false;
-        }
-
-        var doAfterArgs = new DoAfterArgs(EntityManager, user, bonkableComponent.BonkDelay, new BonkDoAfterEvent(), uid, target: uid, used: climber)
-        {
-            BreakOnMove = true,
-            BreakOnDamage = true,
-            DuplicateCondition = DuplicateConditions.SameTool | DuplicateConditions.SameTarget
-        };
-
-        return _doAfter.TryStartDoAfter(doAfterArgs);
-    }
-
-    private void OnAttemptClimb(EntityUid uid, BonkableComponent component, ref AttemptClimbEvent args)
-    {
-        if (args.Cancelled)
-            return;
-
-        if (TryStartBonk(uid, args.User, args.Climber, component))
-            args.Cancelled = true;
-    }
-
-    [Serializable, NetSerializable]
-    private sealed partial class BonkDoAfterEvent : SimpleDoAfterEvent
-    {
-    }
-}
index da194706f8f0a6fcb3f63a7b69c6714f31255ec0..9bf481002a9b61ba4736ef1484b30dd380396825 100644 (file)
@@ -251,6 +251,18 @@ public sealed partial class ClimbSystem : VirtualController
         if (!Resolve(climbable, ref comp, false))
             return;
 
+        var selfEvent = new SelfBeforeClimbEvent(uid, user, (climbable, comp));
+        RaiseLocalEvent(uid, selfEvent);
+
+        if (selfEvent.Cancelled)
+            return;
+
+        var targetEvent = new TargetBeforeClimbEvent(uid, user, (climbable, comp));
+        RaiseLocalEvent(climbable, targetEvent);
+
+        if (targetEvent.Cancelled)
+            return;
+
         if (!ReplaceFixtures(uid, climbing, fixtures))
             return;
 
diff --git a/Content.Shared/Clumsy/ClumsyComponent.cs b/Content.Shared/Clumsy/ClumsyComponent.cs
new file mode 100644 (file)
index 0000000..c71f5d0
--- /dev/null
@@ -0,0 +1,61 @@
+using Content.Shared.Damage;
+using Robust.Shared.Audio;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Clumsy;
+
+/// <summary>
+/// A simple clumsy tag-component.
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class ClumsyComponent : Component
+{
+
+    // Standard options. Try to fit these in if you can!
+
+    /// <summary>
+    ///     Sound to play when clumsy interactions fail.
+    /// </summary>
+    [DataField]
+    public SoundSpecifier ClumsySound = new SoundPathSpecifier("/Audio/Items/bikehorn.ogg");
+
+    /// <summary>
+    ///     Default chance to fail a clumsy interaction.
+    ///     If a system needs to use something else, add a new variable in the component, do not modify this percentage.
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public float ClumsyDefaultCheck = 0.5f;
+
+    /// <summary>
+    ///     Default stun time.
+    ///     If a system needs to use something else, add a new variable in the component, do not modify this number.
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public TimeSpan ClumsyDefaultStunTime = TimeSpan.FromSeconds(2.5);
+
+    // Specific options
+
+    /// <summary>
+    ///     Sound to play after hitting your head on a table. Ouch!
+    /// </summary>
+    [DataField]
+    public SoundCollectionSpecifier TableBonkSound = new SoundCollectionSpecifier("TrayHit");
+
+    /// <summary>
+    ///     Stun time after failing to shoot a gun.
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public TimeSpan GunShootFailStunTime = TimeSpan.FromSeconds(3);
+
+    /// <summary>
+    ///     Stun time after failing to shoot a gun.
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public DamageSpecifier? GunShootFailDamage;
+
+    /// <summary>
+    ///     Noise to play after failing to shoot a gun. Boom!
+    /// </summary>
+    [DataField]
+    public SoundSpecifier GunShootFailSound = new SoundPathSpecifier("/Audio/Weapons/Guns/Gunshots/bang.ogg");
+}
diff --git a/Content.Shared/Clumsy/ClumsySystem.cs b/Content.Shared/Clumsy/ClumsySystem.cs
new file mode 100644 (file)
index 0000000..e034458
--- /dev/null
@@ -0,0 +1,146 @@
+using Content.Shared.CCVar;
+using Content.Shared.Chemistry.Hypospray.Events;
+using Content.Shared.Climbing.Components;
+using Content.Shared.Climbing.Events;
+using Content.Shared.Damage;
+using Content.Shared.IdentityManagement;
+using Content.Shared.Medical;
+using Content.Shared.Popups;
+using Content.Shared.Stunnable;
+using Content.Shared.Weapons.Ranged.Events;
+using Robust.Shared.Audio.Systems;
+using Robust.Shared.Configuration;
+using Robust.Shared.Random;
+using Robust.Shared.Timing;
+
+namespace Content.Shared.Clumsy;
+
+public sealed class ClumsySystem : EntitySystem
+{
+    [Dependency] private readonly IRobustRandom _random = default!;
+    [Dependency] private readonly SharedStunSystem _stun = default!;
+    [Dependency] private readonly SharedAudioSystem _audio = default!;
+    [Dependency] private readonly SharedPopupSystem _popup = default!;
+    [Dependency] private readonly DamageableSystem _damageable = default!;
+    [Dependency] private readonly IGameTiming _timing = default!;
+    [Dependency] private readonly IConfigurationManager _cfg = default!;
+
+    public override void Initialize()
+    {
+        SubscribeLocalEvent<ClumsyComponent, SelfBeforeHyposprayInjectsEvent>(BeforeHyposprayEvent);
+        SubscribeLocalEvent<ClumsyComponent, SelfBeforeDefibrillatorZapsEvent>(BeforeDefibrillatorZapsEvent);
+        SubscribeLocalEvent<ClumsyComponent, SelfBeforeGunShotEvent>(BeforeGunShotEvent);
+        SubscribeLocalEvent<ClumsyComponent, SelfBeforeClimbEvent>(OnBeforeClimbEvent);
+    }
+
+    // If you add more clumsy interactions add them in this section!
+    #region Clumsy interaction events
+    private void BeforeHyposprayEvent(Entity<ClumsyComponent> ent, ref SelfBeforeHyposprayInjectsEvent args)
+    {
+        // Clumsy people sometimes inject themselves! Apparently syringes are clumsy proof...
+        if (!_random.Prob(ent.Comp.ClumsyDefaultCheck))
+            return;
+
+        args.TargetGettingInjected = args.EntityUsingHypospray;
+        args.InjectMessageOverride = "hypospray-component-inject-self-clumsy-message";
+        _audio.PlayPvs(ent.Comp.ClumsySound, ent);
+    }
+
+    private void BeforeDefibrillatorZapsEvent(Entity<ClumsyComponent> ent, ref SelfBeforeDefibrillatorZapsEvent args)
+    {
+        // Clumsy people sometimes defib themselves!
+        if (!_random.Prob(ent.Comp.ClumsyDefaultCheck))
+            return;
+
+        args.DefibTarget = args.EntityUsingDefib;
+        _audio.PlayPvs(ent.Comp.ClumsySound, ent);
+
+    }
+
+    private void BeforeGunShotEvent(Entity<ClumsyComponent> ent, ref SelfBeforeGunShotEvent args)
+    {
+        // Clumsy people sometimes can't shoot :(
+
+        if (args.Gun.Comp.ClumsyProof)
+            return;
+
+        if (!_random.Prob(ent.Comp.ClumsyDefaultCheck))
+            return;
+
+        if (ent.Comp.GunShootFailDamage != null)
+            _damageable.TryChangeDamage(ent, ent.Comp.GunShootFailDamage, origin: ent);
+
+        _stun.TryParalyze(ent, ent.Comp.GunShootFailStunTime, true);
+
+        // Apply salt to the wound ("Honk!") (No idea what this comment means)
+        _audio.PlayPvs(ent.Comp.GunShootFailSound, ent);
+        _audio.PlayPvs(ent.Comp.ClumsySound, ent);
+
+        _popup.PopupEntity(Loc.GetString("gun-clumsy"), ent, ent);
+        args.Cancel();
+    }
+
+    private void OnBeforeClimbEvent(Entity<ClumsyComponent> ent, ref SelfBeforeClimbEvent args)
+    {
+        // This event is called in shared, thats why it has all the extra prediction stuff.
+        var rand = new System.Random((int)_timing.CurTick.Value);
+
+        // If someone is putting you on the table, always get past the guard.
+        if (!_cfg.GetCVar(CCVars.GameTableBonk) && args.PuttingOnTable == ent.Owner && !rand.Prob(ent.Comp.ClumsyDefaultCheck))
+            return;
+
+        HitHeadClumsy(ent, args.BeingClimbedOn);
+
+        _audio.PlayPredicted(ent.Comp.ClumsySound, ent, ent);
+
+        _audio.PlayPredicted(ent.Comp.TableBonkSound, ent, ent);
+
+        var gettingPutOnTableName = Identity.Entity(args.GettingPutOnTable, EntityManager);
+        var puttingOnTableName = Identity.Entity(args.PuttingOnTable, EntityManager);
+
+        if (args.PuttingOnTable == ent.Owner)
+        {
+            // You are slamming yourself onto the table.
+            _popup.PopupPredicted(
+                Loc.GetString("bonkable-success-message-user", ("bonkable", args.BeingClimbedOn)),
+                Loc.GetString("bonkable-success-message-others", ("victim", gettingPutOnTableName), ("bonkable", args.BeingClimbedOn)),
+                ent,
+                ent);
+        }
+        else
+        {
+            // Someone else slamed you onto the table.
+            // This is only run in server so you need to use popup entity.
+            _popup.PopupPredicted(
+                Loc.GetString("forced-bonkable-success-message",
+                    ("bonker", puttingOnTableName),
+                    ("victim", gettingPutOnTableName),
+                    ("bonkable", args.BeingClimbedOn)),
+                ent,
+                null);
+        }
+
+        args.Cancel();
+    }
+    #endregion
+
+    #region Helper functions
+    /// <summary>
+    ///     "Hits" an entites head against the given table.
+    /// </summary>
+    // Oh this fucntion is public le- NO!! This is only public for the one admin command if you use this anywhere else I will cry.
+    public void HitHeadClumsy(Entity<ClumsyComponent> target, EntityUid table)
+    {
+        var stunTime = target.Comp.ClumsyDefaultStunTime;
+
+        if (TryComp<BonkableComponent>(table, out var bonkComp))
+        {
+            stunTime = bonkComp.BonkTime;
+            if (bonkComp.BonkDamage != null)
+                _damageable.TryChangeDamage(target, bonkComp.BonkDamage, true);
+        }
+
+        _stun.TryParalyze(target, stunTime, true);
+    }
+    #endregion
+}
diff --git a/Content.Shared/Interaction/Components/ClumsyComponent.cs b/Content.Shared/Interaction/Components/ClumsyComponent.cs
deleted file mode 100644 (file)
index 824696c..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-using Content.Shared.Damage;
-using Robust.Shared.Audio;
-using Robust.Shared.GameStates;
-
-namespace Content.Shared.Interaction.Components;
-
-/// <summary>
-/// A simple clumsy tag-component.
-/// </summary>
-[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
-public sealed partial class ClumsyComponent : Component
-{
-    /// <summary>
-    /// Damage dealt to a clumsy character when they try to fire a gun.
-    /// </summary>
-    [DataField(required: true), AutoNetworkedField]
-    public DamageSpecifier ClumsyDamage = default!;
-
-    /// <summary>
-    /// Sound to play when clumsy interactions fail.
-    /// </summary>
-    [DataField]
-    public SoundSpecifier ClumsySound = new SoundPathSpecifier("/Audio/Items/bikehorn.ogg");
-}
diff --git a/Content.Shared/Interaction/SharedInteractionSystem.Clumsy.cs b/Content.Shared/Interaction/SharedInteractionSystem.Clumsy.cs
deleted file mode 100644 (file)
index 9e45847..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-using Content.Shared.Interaction.Components;
-using Robust.Shared.Random;
-
-namespace Content.Shared.Interaction
-{
-    public partial class SharedInteractionSystem
-    {
-        public bool RollClumsy(ClumsyComponent component, float chance)
-        {
-            return component.Running && _random.Prob(chance);
-        }
-
-        /// <summary>
-        ///     Rolls a probability chance for a "bad action" if the target entity is clumsy.
-        /// </summary>
-        /// <param name="entity">The entity that the clumsy check is happening for.</param>
-        /// <param name="chance">
-        /// The chance that a "bad action" happens if the user is clumsy, between 0 and 1 inclusive.
-        /// </param>
-        /// <returns>True if a "bad action" happened, false if the normal action should happen.</returns>
-        public bool TryRollClumsy(EntityUid entity, float chance, ClumsyComponent? component = null)
-        {
-            return Resolve(entity, ref component, false) && RollClumsy(component, chance);
-        }
-    }
-}
index c910a9ae772195081274d316aff31bb9cf9ffc50..9573f9b43d9df6dbfb54e23206666d09946df4c1 100644 (file)
@@ -1,4 +1,7 @@
+using Content.Shared.Chat;
 using Content.Shared.Chemistry;
+using Content.Shared.Chemistry.Hypospray.Events;
+using Content.Shared.Climbing.Events;
 using Content.Shared.Damage;
 using Content.Shared.Electrocution;
 using Content.Shared.Explosion;
@@ -15,7 +18,7 @@ using Content.Shared.Slippery;
 using Content.Shared.Strip.Components;
 using Content.Shared.Temperature;
 using Content.Shared.Verbs;
-using Content.Shared.Chat;
+using Content.Shared.Weapons.Ranged.Events;
 
 namespace Content.Shared.Inventory;
 
@@ -33,6 +36,10 @@ public partial class InventorySystem
         SubscribeLocalEvent<InventoryComponent, GetDefaultRadioChannelEvent>(RelayInventoryEvent);
         SubscribeLocalEvent<InventoryComponent, RefreshNameModifiersEvent>(RelayInventoryEvent);
         SubscribeLocalEvent<InventoryComponent, TransformSpeakerNameEvent>(RelayInventoryEvent);
+        SubscribeLocalEvent<InventoryComponent, SelfBeforeHyposprayInjectsEvent>(RelayInventoryEvent);
+        SubscribeLocalEvent<InventoryComponent, TargetBeforeHyposprayInjectsEvent>(RelayInventoryEvent);
+        SubscribeLocalEvent<InventoryComponent, SelfBeforeGunShotEvent>(RelayInventoryEvent);
+        SubscribeLocalEvent<InventoryComponent, SelfBeforeClimbEvent>(RelayInventoryEvent);
 
         // by-ref events
         SubscribeLocalEvent<InventoryComponent, GetExplosionResistanceEvent>(RefRelayInventoryEvent);
diff --git a/Content.Shared/Medical/DefibrillatorEvents.cs b/Content.Shared/Medical/DefibrillatorEvents.cs
new file mode 100644 (file)
index 0000000..54a21a4
--- /dev/null
@@ -0,0 +1,39 @@
+using Content.Shared.Inventory;
+
+namespace Content.Shared.Medical;
+
+[ByRefEvent]
+public readonly record struct TargetDefibrillatedEvent(EntityUid User, Entity<DefibrillatorComponent> Defibrillator);
+
+public abstract class BeforeDefibrillatorZapsEvent : CancellableEntityEventArgs, IInventoryRelayEvent
+{
+    public SlotFlags TargetSlots { get; } = SlotFlags.WITHOUT_POCKET;
+    public EntityUid EntityUsingDefib;
+    public readonly EntityUid Defib;
+    public EntityUid DefibTarget;
+
+    public BeforeDefibrillatorZapsEvent(EntityUid entityUsingDefib, EntityUid defib, EntityUid defibTarget)
+    {
+        EntityUsingDefib = entityUsingDefib;
+        Defib = defib;
+        DefibTarget = defibTarget;
+    }
+}
+
+/// <summary>
+///     This event is raised on the user using the defibrillator before is actually zaps someone.
+///     The event is triggered on the user and all their clothing.
+/// </summary>
+public sealed class SelfBeforeDefibrillatorZapsEvent : BeforeDefibrillatorZapsEvent
+{
+    public SelfBeforeDefibrillatorZapsEvent(EntityUid entityUsingDefib, EntityUid defib, EntityUid defibtarget) : base(entityUsingDefib, defib, defibtarget) { }
+}
+
+/// <summary>
+///     This event is raised on the target before it gets zapped with the defibrillator.
+///     The event is triggered on the target itself and all its clothing.
+/// </summary>
+public sealed class TargetBeforeDefibrillatorZapsEvent : BeforeDefibrillatorZapsEvent
+{
+    public TargetBeforeDefibrillatorZapsEvent(EntityUid entityUsingDefib, EntityUid defib, EntityUid defibtarget) : base(entityUsingDefib, defib, defibtarget) { }
+}
diff --git a/Content.Shared/Medical/TargetDefibrillatedEvent.cs b/Content.Shared/Medical/TargetDefibrillatedEvent.cs
deleted file mode 100644 (file)
index 60d1a21..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-namespace Content.Shared.Medical;
-
-[ByRefEvent]
-public readonly record struct TargetDefibrillatedEvent(EntityUid User, Entity<DefibrillatorComponent> Defibrillator);
diff --git a/Content.Shared/Weapons/Ranged/Events/BeforeGunShootEvent.cs b/Content.Shared/Weapons/Ranged/Events/BeforeGunShootEvent.cs
new file mode 100644 (file)
index 0000000..1d3317c
--- /dev/null
@@ -0,0 +1,20 @@
+using Content.Shared.Inventory;
+using Content.Shared.Weapons.Ranged.Components;
+
+namespace Content.Shared.Weapons.Ranged.Events;
+/// <summary>
+///     This event is triggered on an entity right before they shoot a gun.
+/// </summary>
+public sealed partial class SelfBeforeGunShotEvent : CancellableEntityEventArgs, IInventoryRelayEvent
+{
+    public SlotFlags TargetSlots { get; } = SlotFlags.WITHOUT_POCKET;
+    public readonly EntityUid Shooter;
+    public readonly Entity<GunComponent> Gun;
+    public readonly List<(EntityUid? Entity, IShootable Shootable)> Ammo;
+    public SelfBeforeGunShotEvent(EntityUid shooter, Entity<GunComponent> gun, List<(EntityUid? Entity, IShootable Shootable)> ammo)
+    {
+        Shooter = shooter;
+        Gun = gun;
+        Ammo = ammo;
+    }
+}
index 560b10c46ec61c1f781f23b49f9529362e69b4a2..1a79da3509fe374ab8b6e1849994efd949d3c59a 100644 (file)
@@ -1,2 +1,4 @@
-bonkable-success-message-others = { CAPITALIZE(THE($user)) } bonks { POSS-ADJ($user) } head against { THE($bonkable) }
-bonkable-success-message-user = You bonk your head against { THE($bonkable) }
+forced-bonkable-success-message = { CAPITALIZE($bonker) } bonks {$victim}s head against { THE($bonkable) }!
+
+bonkable-success-message-user = You bonk your head against { THE($bonkable) }!
+bonkable-success-message-others = {$victim} bonks their head against { THE($bonkable) }!
index 2280c3fecb8b545786378fab4a69c83a658b22af..48c83c8d1e8707d970d20583b5ac0a03fce1f7b9 100644 (file)
     rules: ghost-role-information-nonantagonist-rules
   - type: GhostTakeoverAvailable
   - type: Clumsy
-    clumsyDamage:
+    gunShootFailDamage:
       types:
         Blunt: 5
         Piercing: 4
   description: Cousins to the sentient race of lizard people, kobolds blend in with their natural habitat and are as nasty as monkeys; ready to pull out your hair and stab you to death.
   components:
   - type: Clumsy
-    clumsyDamage:
+    gunShootFailDamage:
       types:
         Blunt: 2
         Piercing: 7
index b21f19edd3c12cea466e41a189d2f760ee8abdf4..dca47e1c83708dd2adeb2841345ea68910a32ad6 100644 (file)
     - type: Hands
     - type: ComplexInteraction
     - type: Clumsy
-      clumsyDamage:
+      gunShootFailDamage:
         types:
           Blunt: 5
           Piercing: 4
index 2862980dad33413ae897f505cfb13f6f41e01b31..4b3b4c18743ec3ea10b5b62b737be859f9e4109f 100644 (file)
@@ -32,8 +32,6 @@
     bonkDamage:
       types:
         Blunt: 4
-    bonkSound: !type:SoundCollectionSpecifier
-      collection: TrayHit
   - type: Clickable
   - type: FootstepModifier
     footstepSoundCollection:
index 29232d9dbb5d948398784121ac9557c22c201e6e..b8f289e70eb18330bcde075bafc982de6ac93fc6 100644 (file)
@@ -13,7 +13,7 @@
   - !type:AddComponentSpecial
     components:
     - type: Clumsy
-      clumsyDamage:
+      gunShootFailDamage:
         types: #literally just picked semi random valus. i tested this once and tweaked it.
           Blunt: 5
           Piercing: 4