Clumsy system refactor (#31147)
* 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
This commit is contained in:
@@ -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);
|
||||
|
||||
38
Content.Shared/Chemistry/Events/HyposprayEvents.cs
Normal file
38
Content.Shared/Chemistry/Events/HyposprayEvents.cs
Normal file
@@ -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) { }
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
36
Content.Shared/Climbing/Events/BeforeClimbEvents.cs
Normal file
36
Content.Shared/Climbing/Events/BeforeClimbEvents.cs
Normal file
@@ -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) { }
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
61
Content.Shared/Clumsy/ClumsyComponent.cs
Normal file
61
Content.Shared/Clumsy/ClumsyComponent.cs
Normal file
@@ -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");
|
||||
}
|
||||
146
Content.Shared/Clumsy/ClumsySystem.cs
Normal file
146
Content.Shared/Clumsy/ClumsySystem.cs
Normal file
@@ -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
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
39
Content.Shared/Medical/DefibrillatorEvents.cs
Normal file
39
Content.Shared/Medical/DefibrillatorEvents.cs
Normal file
@@ -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) { }
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
namespace Content.Shared.Medical;
|
||||
|
||||
[ByRefEvent]
|
||||
public readonly record struct TargetDefibrillatedEvent(EntityUid User, Entity<DefibrillatorComponent> Defibrillator);
|
||||
20
Content.Shared/Weapons/Ranged/Events/BeforeGunShootEvent.cs
Normal file
20
Content.Shared/Weapons/Ranged/Events/BeforeGunShootEvent.cs
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user