From 72fd83f0972f10546a475b428ddd8e0af9cb554c Mon Sep 17 00:00:00 2001 From: PvrG <143443369+PvrG@users.noreply.github.com> Date: Mon, 2 Dec 2024 16:52:58 +1000 Subject: [PATCH] 2 --- .../ExperimentalTeleporterSystem.cs | 4 +- .../Standing/SharedLayingDownSystem.cs | 216 ++++++++++++++++++ 2 files changed, 218 insertions(+), 2 deletions(-) create mode 100644 Content.Shared/Standing/SharedLayingDownSystem.cs diff --git a/Content.Server/Backmen/Teleporter/ExperimentalTeleporterSystem.cs b/Content.Server/Backmen/Teleporter/ExperimentalTeleporterSystem.cs index b4522cd593e..186ad19e123 100644 --- a/Content.Server/Backmen/Teleporter/ExperimentalTeleporterSystem.cs +++ b/Content.Server/Backmen/Teleporter/ExperimentalTeleporterSystem.cs @@ -1,7 +1,7 @@ using System.Linq; using System.Numerics; using Content.Server.Body.Systems; -using Content.Server.Backmen.Standing; +using Content.Server.Standing; using Content.Shared.Charges.Systems; using Content.Shared.Coordinates.Helpers; using Content.Shared.Interaction.Events; @@ -25,7 +25,7 @@ public sealed class ExperimentalTeleporterSystem : EntitySystem [Dependency] private readonly AudioSystem _audio = default!; [Dependency] private readonly ContainerSystem _containerSystem = default!; [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] private readonly LayingDownSystem _layingDown = default!; + [Dependency] private readonly SharedLayingDownSystem _layingDown = default!; [Dependency] private readonly SharedChargesSystem _charges = default!; [Dependency] private readonly TagSystem _tag = default!; diff --git a/Content.Shared/Standing/SharedLayingDownSystem.cs b/Content.Shared/Standing/SharedLayingDownSystem.cs new file mode 100644 index 00000000000..dda62517f7e --- /dev/null +++ b/Content.Shared/Standing/SharedLayingDownSystem.cs @@ -0,0 +1,216 @@ +using System.Linq; +using Content.Shared.ActionBlocker; +using Content.Shared.CCVar; +using Content.Shared.DoAfter; +using Content.Shared.Gravity; +using Content.Shared.Input; +using Content.Shared.Mobs.Systems; +using Content.Shared.Movement.Systems; +using Content.Shared.Body.Components; +using Content.Shared.Standing; +using Content.Shared.Popups; +using Content.Shared.Stunnable; +using Robust.Shared.Configuration; +using Robust.Shared.Input.Binding; +using Robust.Shared.Map; +using Robust.Shared.Player; +using Robust.Shared.Serialization; + +namespace Content.Shared.Standing; + +public abstract class SharedLayingDownSystem : EntitySystem +{ + [Dependency] private readonly IConfigurationManager _config = default!; + + [Dependency] private readonly ActionBlockerSystem _actionBlocker = default!; + [Dependency] private readonly EntityLookupSystem _lookup = default!; // WWDP + [Dependency] private readonly MobStateSystem _mobState = default!; + [Dependency] private readonly MovementSpeedModifierSystem _speed = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; + [Dependency] private readonly SharedGravitySystem _gravity = default!; + [Dependency] private readonly SharedPopupSystem _popups = default!; + [Dependency] private readonly StandingStateSystem _standing = default!; + + public override void Initialize() + { + CommandBinds.Builder + .Bind(ContentKeyFunctions.ToggleStanding, InputCmdHandler.FromDelegate(ToggleStanding)) + .Bind(ContentKeyFunctions.ToggleCrawlingUnder, + InputCmdHandler.FromDelegate(HandleCrawlUnderRequest, handle: false)) + .Register(); + + SubscribeNetworkEvent(OnChangeState); + + SubscribeLocalEvent(OnStandingUpDoAfter); + SubscribeLocalEvent(OnRefreshMovementSpeed); + SubscribeLocalEvent(OnParentChanged); + } + + public override void Shutdown() + { + base.Shutdown(); + + CommandBinds.Unregister(); + } + + private void ToggleStanding(ICommonSession? session) + { + if (session is not { AttachedEntity: { Valid: true } uid } _ + || !Exists(uid) + || !HasComp(session.AttachedEntity) + || _gravity.IsWeightless(session.AttachedEntity.Value)) + return; + + RaiseNetworkEvent(new ChangeLayingDownEvent()); + } + + private void HandleCrawlUnderRequest(ICommonSession? session) + { + if (session == null + || session.AttachedEntity is not { } uid + || !TryComp(uid, out var standingState) + || !TryComp(uid, out var layingDown) + || !_actionBlocker.CanInteract(uid, null)) + return; + + var newState = !layingDown.IsCrawlingUnder; + if (standingState.CurrentState is StandingState.Standing) + newState = false; // If the entity is already standing, this function only serves a fallback method to fix its draw depth + + // Do not allow to begin crawling under if it's disabled in config. We still, however, allow to stop it, as a failsafe. + if (newState && !_config.GetCVar(CCVars.CrawlUnderTables)) + { + _popups.PopupEntity(Loc.GetString("crawling-under-tables-disabled-popup"), uid, session); + return; + } + + layingDown.IsCrawlingUnder = newState; + _speed.RefreshMovementSpeedModifiers(uid); + Dirty(uid, layingDown); + } + + private void OnChangeState(ChangeLayingDownEvent ev, EntitySessionEventArgs args) + { + if (!args.SenderSession.AttachedEntity.HasValue) + return; + + var uid = args.SenderSession.AttachedEntity.Value; + if (!TryComp(uid, out StandingStateComponent? standing) + || !TryComp(uid, out LayingDownComponent? layingDown)) + return; + + RaiseNetworkEvent(new CheckAutoGetUpEvent(GetNetEntity(uid))); + + if (HasComp(uid) + || !_mobState.IsAlive(uid)) + return; + + if (_standing.IsDown(uid, standing)) + TryStandUp(uid, layingDown, standing); + else + TryLieDown(uid, layingDown, standing); + } + + private void OnStandingUpDoAfter(EntityUid uid, StandingStateComponent component, StandingUpDoAfterEvent args) + { + if (args.Handled || args.Cancelled + || HasComp(uid) + || _mobState.IsIncapacitated(uid) + || !_standing.Stand(uid)) + component.CurrentState = StandingState.Lying; + + component.CurrentState = StandingState.Standing; + } + + private void OnRefreshMovementSpeed(EntityUid uid, + LayingDownComponent component, + RefreshMovementSpeedModifiersEvent args) + { + if (!_standing.IsDown(uid)) + return; + + var modifier = component.LyingSpeedModifier * + (component.IsCrawlingUnder ? component.CrawlingUnderSpeedModifier : 1); + args.ModifySpeed(modifier, modifier); + } + + private void OnParentChanged(EntityUid uid, LayingDownComponent component, EntParentChangedMessage args) + { + // If the entity is not on a grid, try to make it stand up to avoid issues + if (!TryComp(uid, out var standingState) + || standingState.CurrentState is StandingState.Standing + || Transform(uid).GridUid != null) + return; + + _standing.Stand(uid, standingState); + } + + public bool TryStandUp(EntityUid uid, + LayingDownComponent? layingDown = null, + StandingStateComponent? standingState = null) + { + if (!Resolve(uid, ref standingState, false) + || !Resolve(uid, ref layingDown, false) + || standingState.CurrentState is not StandingState.Lying + || !_mobState.IsAlive(uid) + || TerminatingOrDeleted(uid) + || !TryComp(uid, out var body) + || body.LegEntities.Count == 0) + return false; + + var args = new DoAfterArgs(EntityManager, uid, layingDown.StandingUpTime, new StandingUpDoAfterEvent(), uid) + { + BreakOnHandChange = false, + RequireCanInteract = false + }; + + if (!_doAfter.TryStartDoAfter(args)) + return false; + + standingState.CurrentState = StandingState.GettingUp; + layingDown.IsCrawlingUnder = false; + return true; + } + + public bool TryLieDown(EntityUid uid, + LayingDownComponent? layingDown = null, + StandingStateComponent? standingState = null, + DropHeldItemsBehavior behavior = DropHeldItemsBehavior.NoDrop) + { + if (!Resolve(uid, ref standingState, false) + || !Resolve(uid, ref layingDown, false) + || standingState.CurrentState is not StandingState.Standing) + { + if (behavior == DropHeldItemsBehavior.AlwaysDrop) + RaiseLocalEvent(uid, new DropHandItemsEvent()); + + return false; + } + + _standing.Down(uid, true, behavior != DropHeldItemsBehavior.NoDrop, standingState); + return true; + } + + // WWDP + public void LieDownInRange(EntityUid uid, EntityCoordinates coords, float range = 0.4f) + { + var ents = new HashSet>(); + _lookup.GetEntitiesInRange(coords, range, ents); + + foreach (var ent in ents.Where(ent => ent.Owner != uid)) + { + TryLieDown(ent, behavior: DropHeldItemsBehavior.DropIfStanding); + } + } +} + +[Serializable, NetSerializable] +public sealed partial class StandingUpDoAfterEvent : SimpleDoAfterEvent; + +[Serializable, NetSerializable] +public enum DropHeldItemsBehavior : byte +{ + NoDrop, + DropIfStanding, + AlwaysDrop +} \ No newline at end of file