Files
wwdpublic/Content.Shared/_Goobstation/TableSlam/TableSlamSystem.cs
Tirochora 7e306e040e Clean Up Tableslam + Strangling Bugfix (#2247)
<!--
This is a semi-strict format, you can add/remove sections as needed but
the order/format should be kept the same
Remove these comments before submitting
-->

# Description

<!--
Explain this PR in as much detail as applicable

Some example prompts to consider:
How might this affect the game? The codebase?
What might be some alternatives to this?
How/Who does this benefit/hurt [the game/codebase]?
-->

Previously, the "TryStopPull" function didn't make you drop a
virtualitem if you were strangling somebody, meaning that you could lose
use of a hand until disarmed because it would still consider you to be
holding the person. I fixed that, as well as additionally cleaned up the
table slam system, which should make it run a bit smoother and be
functionally about the same. The "tableable" and "posttabled" components
were removed, because they shouldn't have existed in the first place.
The only notable non-bugfix change that's player facing is that shoving
people who are knocked down on any climbable entity stuns them (as
opposed to just tables), but it's a rather minor change and I intend on
reworking it pretty heavily once my [other
PR](https://github.com/Simple-Station/Einstein-Engines/pull/2199) is
reviewed. On the backend, I added an optional variable to "TryClimb"
that gives you an option to skip the do-after. If it's possible to
change these actions to be predicted, I'd be interested in learning how.

---

# TODO

<!--
A list of everything you have to do before this PR is "complete"
You probably won't have to complete everything before merging but it's
good to leave future references
-->

- [ ] Task
- [x] Completed Task

---

<!--
This is default collapsed, readers click to expand it and see all your
media
The PR media section can get very large at times, so this is a good way
to keep it clean
The title is written using HTML tags
The title must be within the <summary> tags or you won't see it
-->

<details><summary><h1>Media</h1></summary>
<p>

Note that glass tables do much more damage when slammed into, and even
more if they would shatter when attempting to climb it.


https://github.com/user-attachments/assets/bc0a12e3-0b67-4d61-aa4e-785e3210c3bb

</p>
</details>

---

# Changelog

<!--
You can add an author after the `🆑` to change the name that appears
in the changelog (ex: `🆑 Death`)
Leaving it blank will default to your GitHub display name
This includes all available types for the changelog
-->

🆑
- tweak: Table slamming should be more consistent.
- fix: You should properly be able to use both hands after letting
somebody go from a stranglehold.
2025-07-12 01:48:19 +10:00

103 lines
4.7 KiB
C#

using System.Linq;
using Content.Shared.Contests;
using Content.Shared._Shitmed.Targeting;
using Content.Shared.Actions.Events;
using Content.Shared.Climbing.Components;
using Content.Shared.CombatMode;
using Content.Shared.Coordinates;
using Content.Shared.Damage;
using Content.Shared.Damage.Events;
using Content.Shared.Damage.Systems;
using Content.Shared.FixedPoint;
using Content.Shared.Interaction;
using Content.Shared.Movement.Pulling.Components;
using Content.Shared.Movement.Pulling.Systems;
using Content.Shared.Standing;
using Content.Shared.StatusEffect;
using Content.Shared.Stunnable;
using Content.Shared.Throwing;
using Content.Shared.Weapons.Melee;
using Content.Shared.Weapons.Melee.Events;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Events;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Random;
using Robust.Shared.Timing;
using Content.Shared.Climbing.Systems;
namespace Content.Shared._Goobstation.TableSlam;
/// <summary>
/// This handles...
/// </summary>
public sealed class TableSlamSystem : EntitySystem
{
[Dependency] private readonly PullingSystem _pullingSystem = default!;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
[Dependency] private readonly StandingStateSystem _standing = default!;
[Dependency] private readonly ThrowingSystem _throwingSystem = default!;
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private readonly StaminaSystem _staminaSystem = default!;
[Dependency] private readonly SharedStunSystem _stunSystem = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly ContestsSystem _contestsSystem = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ClimbSystem _climbing = default!;
/// <inheritdoc/>
public override void Initialize()
{
SubscribeLocalEvent<PullerComponent, MeleeHitEvent>(OnMeleeHit);
}
private void OnMeleeHit(Entity<PullerComponent> ent, ref MeleeHitEvent args)
{
if (ent.Comp.GrabStage < GrabStage.Suffocate
|| ent.Comp.Pulling == null || (args.HitEntities.Count is > 1 or 0))
return;
if(!TryComp<PullableComponent>(ent.Comp.Pulling, out var pullableComponent))
return;
var massContest = _contestsSystem.MassContest(ent, ent.Comp.Pulling.Value);
var attemptChance = Math.Clamp(1 * massContest, 0, 1);
var attemptRoundedToNearestQuarter = Math.Round(attemptChance * 4, MidpointRounding.ToEven) / 4;
if(_random.Prob((float) attemptRoundedToNearestQuarter)) // base chance to table slam someone is 1 if your mass ratio is less than 1 then you're going to have a harder time slamming somebody.
TryTableSlam((ent.Comp.Pulling.Value, pullableComponent), ent, args.HitEntities.ElementAt(0));
}
public void TryTableSlam(Entity<PullableComponent> ent, Entity<PullerComponent> pullerEnt, EntityUid tableUid)
{
if (!_transformSystem.InRange(ent.Owner.ToCoordinates(), tableUid.ToCoordinates(), 2f)
|| !TryComp<ClimbableComponent>(tableUid, out var component)
|| !HasComp<BonkableComponent>(tableUid))
return;
_stunSystem.TryKnockdown(ent, TimeSpan.FromSeconds(3), false);
_climbing.TryClimb(pullerEnt, ent, tableUid, out _, component, null, true);
_pullingSystem.TryStopPull(ent, ent.Comp, pullerEnt, ignoreGrab: true);
if (TryComp<GlassTableComponent>(tableUid, out var glassTableComponent))
{
_damageableSystem.TryChangeDamage(tableUid, glassTableComponent.TableDamage, origin: ent);
_damageableSystem.TryChangeDamage(ent, glassTableComponent.ClimberDamage, origin: ent, targetPart: TargetBodyPart.Torso);
_stunSystem.TryParalyze(ent, TimeSpan.FromSeconds(3), false);
}
else
{
_damageableSystem.TryChangeDamage(ent,
new DamageSpecifier()
{
DamageDict = new Dictionary<string, FixedPoint2> { { "Blunt", ent.Comp.TabledDamage } },
},
targetPart: TargetBodyPart.Torso);
_damageableSystem.TryChangeDamage(ent,
new DamageSpecifier()
{
DamageDict = new Dictionary<string, FixedPoint2> { { "Blunt", ent.Comp.TabledDamage } },
});
}
_staminaSystem.TakeStaminaDamage(ent, ent.Comp.TabledStaminaDamage);
pullerEnt.Comp.NextStageChange = _gameTiming.CurTime + pullerEnt.Comp.StageChangeCooldown * 2;
//_audioSystem.PlayPvs("/Audio/Effects/thudswoosh.ogg", uid);
}
}