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:
beck-thompson
2024-11-15 15:46:01 -08:00
committed by GitHub
parent 09d0565413
commit da4fa9bea9
25 changed files with 485 additions and 282 deletions

View 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;

View 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)

View 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)
{
msgFormat = "hypospray-component-inject-self-clumsy-message";
target = user;
_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)
{
_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);

View 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;

View 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,27 +141,44 @@ 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);
return;
}
if (!_powerCell.TryUseActivatableCharge(uid, user: user))
return;
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);
_electrocution.TryDoElectrocution(target, null, component.ZapDamage, component.WritheDuration, true, ignoreInsulation: true);
component.NextZapTime = _timing.CurTime + component.ZapDelay;

View 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;
}
}