mirror of
https://github.com/WWhiteDreamProject/wwdpublic.git
synced 2026-04-24 09:08:04 +03:00
## Mirror of PR #22962: [Landmine stepoff](https://github.com/space-wizards/space-station-14/pull/22962) from <img src="https://avatars.githubusercontent.com/u/10567778?v=4" alt="space-wizards" width="22"/> [space-wizards](https://github.com/space-wizards)/[space-station-14](https://github.com/space-wizards/space-station-14) ###### `54dd273f660d6d8d523d0771bb8d8437373b082e` PR opened by <img src="https://avatars.githubusercontent.com/u/59531932?v=4" width="16"/><a href="https://github.com/YuriyKiss"> YuriyKiss</a> at 2023-12-25 12:38:55 UTC --- PR changed 13 files with 95 additions and 47 deletions. The PR had the following labels: - Status: Awaiting Changes --- <details open="true"><summary><h1>Original Body</h1></summary> > ## About the PR > Landmine will explode when player steps off it. Landmine will make a sound effect when player steps on it > Close #21658 (Issue has some other suggestions, turn them into separate issues if relevant) > > Requires https://github.com/space-wizards/RobustToolbox/pull/4883 > > ## Why / Balance > IRL some landmines will only trigger after you release the pressure put on them. > > ## Technical details > There are two landmine modes now, one will make landmine trigger immediately after player steps on them another one will only trigger after player steps off the landmine (this is the default now). > > ## Media > Landmine stepoff in action: > > https://github.com/space-wizards/space-station-14/assets/59531932/6e884619-7217-4301-bd78-6e843e0d78f1 > > - [X] I have added screenshots/videos to this PR showcasing its changes ingame, **or** this PR does not require an ingame showcase > > ## Breaking changes > > > **Changelog** > - tweak: landmines will trigger after you step off them > - add: landmine trigger sound > </details> Signed-off-by: VMSolidus <evilexecutive@gmail.com> Co-authored-by: SimpleStation14 <Unknown> Co-authored-by: VMSolidus <evilexecutive@gmail.com>
172 lines
6.5 KiB
C#
172 lines
6.5 KiB
C#
using System.Linq;
|
|
using Content.Server.Body.Systems;
|
|
using Content.Shared.Alert;
|
|
using Content.Shared.Body.Part;
|
|
using Content.Shared.CombatMode.Pacification;
|
|
using Content.Shared.Damage.Components;
|
|
using Content.Shared.Damage.Systems;
|
|
using Content.Shared.DoAfter;
|
|
using Content.Shared.Ensnaring;
|
|
using Content.Shared.Ensnaring.Components;
|
|
using Content.Shared.IdentityManagement;
|
|
using Content.Shared.StepTrigger.Systems;
|
|
using Content.Shared.Throwing;
|
|
|
|
namespace Content.Server.Ensnaring;
|
|
|
|
public sealed partial class EnsnareableSystem
|
|
{
|
|
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
|
[Dependency] private readonly AlertsSystem _alerts = default!;
|
|
[Dependency] private readonly BodySystem _body = default!;
|
|
[Dependency] private readonly StaminaSystem _stamina = default!;
|
|
|
|
public void InitializeEnsnaring()
|
|
{
|
|
SubscribeLocalEvent<EnsnaringComponent, ComponentRemove>(OnComponentRemove);
|
|
SubscribeLocalEvent<EnsnaringComponent, StepTriggerAttemptEvent>(AttemptStepTrigger);
|
|
SubscribeLocalEvent<EnsnaringComponent, StepTriggeredOffEvent>(OnStepTrigger);
|
|
SubscribeLocalEvent<EnsnaringComponent, ThrowDoHitEvent>(OnThrowHit);
|
|
SubscribeLocalEvent<EnsnaringComponent, AttemptPacifiedThrowEvent>(OnAttemptPacifiedThrow);
|
|
}
|
|
|
|
private void OnAttemptPacifiedThrow(Entity<EnsnaringComponent> ent, ref AttemptPacifiedThrowEvent args)
|
|
{
|
|
args.Cancel("pacified-cannot-throw-snare");
|
|
}
|
|
|
|
private void OnComponentRemove(EntityUid uid, EnsnaringComponent component, ComponentRemove args)
|
|
{
|
|
if (!TryComp<EnsnareableComponent>(component.Ensnared, out var ensnared))
|
|
return;
|
|
|
|
if (ensnared.IsEnsnared)
|
|
ForceFree(uid, component);
|
|
}
|
|
|
|
private void AttemptStepTrigger(EntityUid uid, EnsnaringComponent component, ref StepTriggerAttemptEvent args)
|
|
{
|
|
args.Continue = true;
|
|
}
|
|
|
|
private void OnStepTrigger(EntityUid uid, EnsnaringComponent component, ref StepTriggeredOffEvent args)
|
|
{
|
|
TryEnsnare(args.Tripper, uid, component);
|
|
}
|
|
|
|
private void OnThrowHit(EntityUid uid, EnsnaringComponent component, ThrowDoHitEvent args)
|
|
{
|
|
if (!component.CanThrowTrigger)
|
|
return;
|
|
|
|
TryEnsnare(args.Target, uid, component);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Used where you want to try to ensnare an entity with the <see cref="EnsnareableComponent"/>
|
|
/// </summary>
|
|
/// <param name="target">The entity that will be ensnared</param>
|
|
/// <paramref name="ensnare"> The entity that is used to ensnare</param>
|
|
/// <param name="component">The ensnaring component</param>
|
|
public void TryEnsnare(EntityUid target, EntityUid ensnare, EnsnaringComponent component)
|
|
{
|
|
//Don't do anything if they don't have the ensnareable component.
|
|
if (!TryComp<EnsnareableComponent>(target, out var ensnareable))
|
|
return;
|
|
|
|
var legs = _body.GetBodyChildrenOfType(target, BodyPartType.Leg).Count();
|
|
var ensnaredLegs = (2 * ensnareable.Container.ContainedEntities.Count);
|
|
var freeLegs = legs - ensnaredLegs;
|
|
|
|
if (freeLegs <= 0)
|
|
return;
|
|
|
|
// Apply stamina damage to target if they weren't ensnared before.
|
|
if (ensnareable.IsEnsnared != true)
|
|
{
|
|
if (TryComp<StaminaComponent>(target, out var stamina))
|
|
{
|
|
_stamina.TakeStaminaDamage(target, component.StaminaDamage, with: ensnare);
|
|
}
|
|
}
|
|
|
|
component.Ensnared = target;
|
|
_container.Insert(ensnare, ensnareable.Container);
|
|
ensnareable.IsEnsnared = true;
|
|
Dirty(ensnareable);
|
|
|
|
UpdateAlert(target, ensnareable);
|
|
var ev = new EnsnareEvent(component.WalkSpeed, component.SprintSpeed);
|
|
RaiseLocalEvent(target, ev);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Used where you want to try to free an entity with the <see cref="EnsnareableComponent"/>
|
|
/// </summary>
|
|
/// <param name="target">The entity that will be freed</param>
|
|
/// <param name="user">The entity that is freeing the target</param>
|
|
/// <param name="ensnare">The entity used to ensnare</param>
|
|
/// <param name="component">The ensnaring component</param>
|
|
public void TryFree(EntityUid target, EntityUid user, EntityUid ensnare, EnsnaringComponent component)
|
|
{
|
|
//Don't do anything if they don't have the ensnareable component.
|
|
if (!HasComp<EnsnareableComponent>(target))
|
|
return;
|
|
|
|
var freeTime = user == target ? component.BreakoutTime : component.FreeTime;
|
|
var breakOnMove = !component.CanMoveBreakout;
|
|
|
|
var doAfterEventArgs = new DoAfterArgs(EntityManager, user, freeTime, new EnsnareableDoAfterEvent(), target, target: target, used: ensnare)
|
|
{
|
|
BreakOnUserMove = breakOnMove,
|
|
BreakOnTargetMove = breakOnMove,
|
|
BreakOnDamage = false,
|
|
NeedHand = true,
|
|
BlockDuplicate = true,
|
|
};
|
|
|
|
if (!_doAfter.TryStartDoAfter(doAfterEventArgs))
|
|
return;
|
|
|
|
if (user == target)
|
|
_popup.PopupEntity(Loc.GetString("ensnare-component-try-free", ("ensnare", ensnare)), target, target);
|
|
else
|
|
_popup.PopupEntity(Loc.GetString("ensnare-component-try-free-other", ("ensnare", ensnare), ("user", Identity.Entity(target, EntityManager))), user, user);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Used to force free someone for things like if the <see cref="EnsnaringComponent"/> is removed
|
|
/// </summary>
|
|
public void ForceFree(EntityUid ensnare, EnsnaringComponent component)
|
|
{
|
|
if (component.Ensnared == null)
|
|
return;
|
|
|
|
if (!TryComp<EnsnareableComponent>(component.Ensnared, out var ensnareable))
|
|
return;
|
|
|
|
var target = component.Ensnared.Value;
|
|
|
|
_container.Remove(ensnare, ensnareable.Container, force: true);
|
|
ensnareable.IsEnsnared = ensnareable.Container.ContainedEntities.Count > 0;
|
|
Dirty(ensnareable);
|
|
component.Ensnared = null;
|
|
|
|
UpdateAlert(target, ensnareable);
|
|
var ev = new EnsnareRemoveEvent(component.WalkSpeed, component.SprintSpeed);
|
|
RaiseLocalEvent(ensnare, ev);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update the Ensnared alert for an entity.
|
|
/// </summary>
|
|
/// <param name="target">The entity that has been affected by a snare</param>
|
|
public void UpdateAlert(EntityUid target, EnsnareableComponent component)
|
|
{
|
|
if (!component.IsEnsnared)
|
|
_alerts.ClearAlert(target, AlertType.Ensnared);
|
|
else
|
|
_alerts.ShowAlert(target, AlertType.Ensnared);
|
|
}
|
|
}
|