using Content.Shared.ActionBlocker;
using Content.Shared.Input;
using Content.Shared.Movement.Systems;
using Content.Shared.Popups;
using Content.Shared.Standing;
using Robust.Shared.Input.Binding;
using Robust.Shared.Player;
using Robust.Shared.Timing;
namespace Content.Server.Standing;
/// Unfortunately cannot be shared because some standing conditions are server-side only
public sealed class LayingDownSystem : EntitySystem
{
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
[Dependency] private readonly MovementSpeedModifierSystem _movement = default!;
[Dependency] private readonly SharedPopupSystem _popups = default!;
[Dependency] private readonly Shared.Standing.StandingStateSystem _standing = default!; // WHY IS THERE TWO DIFFERENT STANDING SYSTEMS?!
[Dependency] private readonly IGameTiming _timing = default!;
public override void Initialize()
{
CommandBinds.Builder
.Bind(ContentKeyFunctions.ToggleStanding, InputCmdHandler.FromDelegate(ToggleStanding, handle: false, outsidePrediction: false))
.Register();
SubscribeLocalEvent(DoRefreshMovementSpeed);
SubscribeLocalEvent(DoRefreshMovementSpeed);
SubscribeLocalEvent(OnRefreshMovementSpeed);
SubscribeLocalEvent(OnParentChanged);
}
public override void Shutdown()
{
base.Shutdown();
CommandBinds.Unregister();
}
private void DoRefreshMovementSpeed(EntityUid uid, LayingDownComponent component, object args)
{
_movement.RefreshMovementSpeedModifiers(uid);
}
private void OnRefreshMovementSpeed(EntityUid uid, LayingDownComponent component, RefreshMovementSpeedModifiersEvent args)
{
if (TryComp(uid, out var standingState) && standingState.Standing)
return;
args.ModifySpeed(component.DownedSpeedMultiplier, component.DownedSpeedMultiplier);
}
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.Standing
|| Transform(uid).GridUid != null)
return;
_standing.Stand(uid, standingState);
}
private void ToggleStanding(ICommonSession? session)
{
if (session is not { AttachedEntity: { Valid: true } uid } playerSession
|| !Exists(uid)
|| !TryComp(uid, out var standingState)
|| !TryComp(uid, out var layingDown))
return;
// If successful, show popup to self and others. Otherwise, only to self.
if (ToggleStandingImpl(uid, standingState, layingDown, out var popupBranch))
{
_popups.PopupEntity(Loc.GetString($"laying-comp-{popupBranch}-other", ("entity", uid)), uid, Filter.PvsExcept(uid), true);
layingDown.NextToggleAttempt = _timing.CurTime + layingDown.Cooldown;
}
_popups.PopupEntity(Loc.GetString($"laying-comp-{popupBranch}-self", ("entity", uid)), uid, uid);
}
private bool ToggleStandingImpl(EntityUid uid, StandingStateComponent standingState, LayingDownComponent layingDown, out string popupBranch)
{
var success = layingDown.NextToggleAttempt <= _timing.CurTime;
if (_standing.IsDown(uid, standingState))
{
success = success && _standing.Stand(uid, standingState, force: false);
popupBranch = success ? "stand-success" : "stand-fail";
}
else
{
success = success && Transform(uid).GridUid != null; // Do not allow laying down when not on a surface.
success = success && _standing.Down(uid, standingState: standingState, playSound: true, dropHeldItems: false);
popupBranch = success ? "lay-success" : "lay-fail";
}
return success;
}
}