Files
wwdpublic/Content.Shared/Standing/SharedLayingDownSystem.cs
vanx 7e2cd40a2c [Add] Minimal Movement Speed (#593)
* crawling in my sleeeeeeeeeep

* fix

---------

Co-authored-by: vanx <discord@vanxxxx>
2025-06-18 09:22:18 +03:00

222 lines
8.0 KiB
C#

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._Shitmed.Body.Organ;
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;
using Content.Shared.Movement.Components;
using Content.Shared.Traits.Assorted.Components;
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<SharedLayingDownSystem>();
SubscribeNetworkEvent<ChangeLayingDownEvent>(OnChangeState);
SubscribeLocalEvent<StandingStateComponent, StandingUpDoAfterEvent>(OnStandingUpDoAfter);
SubscribeLocalEvent<LayingDownComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovementSpeed);
SubscribeLocalEvent<LayingDownComponent, EntParentChangedMessage>(OnParentChanged);
}
public override void Shutdown()
{
base.Shutdown();
CommandBinds.Unregister<SharedLayingDownSystem>();
}
private void ToggleStanding(ICommonSession? session)
{
if (session is not { AttachedEntity: { Valid: true } uid } _
|| !Exists(uid)
|| !HasComp<LayingDownComponent>(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<StandingStateComponent>(uid, out var standingState)
|| !TryComp<LayingDownComponent>(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<KnockedDownComponent>(uid)
|| !_mobState.IsAlive(uid))
return;
if (_standing.IsDown(uid, standing))
TryStandUp(uid, layingDown, standing);
else
TryLieDown(uid, standing);
}
private void OnStandingUpDoAfter(EntityUid uid, StandingStateComponent component, StandingUpDoAfterEvent args)
{
if (args.Handled || args.Cancelled
|| HasComp<KnockedDownComponent>(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<StandingStateComponent>(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<BodyComponent>(uid, out var body)
|| body.LegEntities.Count < body.RequiredLegs
|| HasComp<DebrainedComponent>(uid)
|| HasComp<LegsParalyzedComponent>(uid) // WWDP
|| TryComp<MovementSpeedModifierComponent>(uid, out var movement) && movement.CurrentWalkSpeed == 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,
StandingStateComponent? standingState = null,
DropHeldItemsBehavior behavior = DropHeldItemsBehavior.NoDrop)
{
if (!Resolve(uid, ref standingState, 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<Entity<LayingDownComponent>>();
_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
}