mirror of
https://github.com/WWhiteDreamProject/wwdpublic.git
synced 2026-04-17 05:27:38 +03:00
[Port] Lying Down System / Система Лежания (#2)
* add: White lay down * fix: rotation * fix * fix: rotation * fix
This commit is contained in:
@@ -57,7 +57,6 @@ internal sealed class BuckleSystem : SharedBuckleSystem
|
||||
!buckled ||
|
||||
args.Sprite == null)
|
||||
{
|
||||
_rotationVisualizerSystem.SetHorizontalAngle((uid, rotVisuals), rotVisuals.DefaultRotation);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -110,6 +110,12 @@ namespace Content.Client.Options.UI.Tabs
|
||||
_cfg.SaveToFile();
|
||||
}
|
||||
|
||||
private void HandleToggleAutoGetUp(BaseButton.ButtonToggledEventArgs args) // WD EDIT
|
||||
{
|
||||
_cfg.SetCVar(WhiteCVars.AutoGetUp, args.Pressed);
|
||||
_cfg.SaveToFile();
|
||||
}
|
||||
|
||||
public KeyRebindTab()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
@@ -194,6 +200,7 @@ namespace Content.Client.Options.UI.Tabs
|
||||
AddButton(ContentKeyFunctions.SaveItemLocation);
|
||||
AddButton(ContentKeyFunctions.ToggleStanding);
|
||||
AddButton(ContentKeyFunctions.LookUp); // WD EDIT
|
||||
AddCheckBox("ui-options-function-auto-get-up", _cfg.GetCVar(WhiteCVars.AutoGetUp), HandleToggleAutoGetUp); // WD EDIT
|
||||
AddCheckBox("ui-options-function-hold-look-up", _cfg.GetCVar(WhiteCVars.HoldLookUp), HandleHoldLookUp); // WD EDIT
|
||||
|
||||
AddHeader("ui-options-header-interaction-adv");
|
||||
|
||||
82
Content.Client/_White/Standing/LayingDownSystem.cs
Normal file
82
Content.Client/_White/Standing/LayingDownSystem.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using Content.Shared._White.Standing;
|
||||
using Content.Shared.Buckle;
|
||||
using Content.Shared.Rotation;
|
||||
using Content.Shared.Standing;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client._White.Standing;
|
||||
|
||||
public sealed class LayingDownSystem : SharedLayingDownSystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
[Dependency] private readonly StandingStateSystem _standing = default!;
|
||||
[Dependency] private readonly AnimationPlayerSystem _animation = default!;
|
||||
[Dependency] private readonly SharedBuckleSystem _buckle = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<LayingDownComponent, MoveEvent>(OnMovementInput);
|
||||
|
||||
SubscribeNetworkEvent<CheckAutoGetUpEvent>(OnCheckAutoGetUp);
|
||||
}
|
||||
|
||||
private void OnMovementInput(EntityUid uid, LayingDownComponent component, MoveEvent args)
|
||||
{
|
||||
if (!_timing.IsFirstTimePredicted)
|
||||
return;
|
||||
|
||||
if (!_standing.IsDown(uid))
|
||||
return;
|
||||
|
||||
if (_buckle.IsBuckled(uid))
|
||||
return;
|
||||
|
||||
if (_animation.HasRunningAnimation(uid, "rotate"))
|
||||
return;
|
||||
|
||||
if (!TryComp<TransformComponent>(uid, out var transform)
|
||||
|| !TryComp<SpriteComponent>(uid, out var sprite)
|
||||
|| !TryComp<RotationVisualsComponent>(uid, out var rotationVisuals))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var rotation = transform.LocalRotation + (_eyeManager.CurrentEye.Rotation - (transform.LocalRotation - transform.WorldRotation));
|
||||
|
||||
if (rotation.GetDir() is Direction.SouthEast or Direction.East or Direction.NorthEast or Direction.North)
|
||||
{
|
||||
rotationVisuals.HorizontalRotation = Angle.FromDegrees(270);
|
||||
sprite.Rotation = Angle.FromDegrees(270);
|
||||
return;
|
||||
}
|
||||
|
||||
rotationVisuals.HorizontalRotation = Angle.FromDegrees(90);
|
||||
sprite.Rotation = Angle.FromDegrees(90);
|
||||
}
|
||||
|
||||
private void OnCheckAutoGetUp(CheckAutoGetUpEvent ev, EntitySessionEventArgs args)
|
||||
{
|
||||
if (!_timing.IsFirstTimePredicted)
|
||||
return;
|
||||
|
||||
var uid = GetEntity(ev.User);
|
||||
|
||||
if (!TryComp<TransformComponent>(uid, out var transform) || !TryComp<RotationVisualsComponent>(uid, out var rotationVisuals))
|
||||
return;
|
||||
|
||||
var rotation = transform.LocalRotation + (_eyeManager.CurrentEye.Rotation - (transform.LocalRotation - transform.WorldRotation));
|
||||
|
||||
if (rotation.GetDir() is Direction.SouthEast or Direction.East or Direction.NorthEast or Direction.North)
|
||||
{
|
||||
rotationVisuals.HorizontalRotation = Angle.FromDegrees(270);
|
||||
return;
|
||||
}
|
||||
|
||||
rotationVisuals.HorizontalRotation = Angle.FromDegrees(90);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
namespace Content.Server.Standing;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class LayingDownComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public float DownedSpeedMultiplier = 0.15f;
|
||||
|
||||
[DataField]
|
||||
public TimeSpan Cooldown = TimeSpan.FromSeconds(2.5f);
|
||||
|
||||
[DataField]
|
||||
public TimeSpan NextToggleAttempt = TimeSpan.Zero;
|
||||
}
|
||||
@@ -1,101 +1,28 @@
|
||||
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;
|
||||
using Content.Shared._White;
|
||||
using Content.Shared._White.Standing;
|
||||
using Robust.Shared.Configuration;
|
||||
|
||||
namespace Content.Server.Standing;
|
||||
|
||||
/// <remarks>Unfortunately cannot be shared because some standing conditions are server-side only</remarks>
|
||||
public sealed class LayingDownSystem : EntitySystem
|
||||
public sealed class LayingDownSystem : SharedLayingDownSystem // WD EDIT
|
||||
{
|
||||
[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!;
|
||||
|
||||
[Dependency] private readonly INetConfigurationManager _cfg = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
CommandBinds.Builder
|
||||
.Bind(ContentKeyFunctions.ToggleStanding, InputCmdHandler.FromDelegate(ToggleStanding, handle: false, outsidePrediction: false))
|
||||
.Register<LayingDownSystem>();
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<LayingDownComponent, StoodEvent>(DoRefreshMovementSpeed);
|
||||
SubscribeLocalEvent<LayingDownComponent, DownedEvent>(DoRefreshMovementSpeed);
|
||||
SubscribeLocalEvent<LayingDownComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovementSpeed);
|
||||
SubscribeLocalEvent<LayingDownComponent, EntParentChangedMessage>(OnParentChanged);
|
||||
SubscribeNetworkEvent<CheckAutoGetUpEvent>(OnCheckAutoGetUp);
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
private void OnCheckAutoGetUp(CheckAutoGetUpEvent ev, EntitySessionEventArgs args)
|
||||
{
|
||||
base.Shutdown();
|
||||
var uid = GetEntity(ev.User);
|
||||
|
||||
CommandBinds.Unregister<LayingDownSystem>();
|
||||
}
|
||||
|
||||
private void DoRefreshMovementSpeed(EntityUid uid, LayingDownComponent component, object args)
|
||||
{
|
||||
_movement.RefreshMovementSpeedModifiers(uid);
|
||||
}
|
||||
|
||||
private void OnRefreshMovementSpeed(EntityUid uid, LayingDownComponent component, RefreshMovementSpeedModifiersEvent args)
|
||||
{
|
||||
if (TryComp<StandingStateComponent>(uid, out var standingState) && standingState.Standing)
|
||||
if (!TryComp(uid, out LayingDownComponent? layingDown))
|
||||
return;
|
||||
|
||||
args.ModifySpeed(component.DownedSpeedMultiplier, component.DownedSpeedMultiplier, bypassImmunity: true);
|
||||
}
|
||||
|
||||
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.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<StandingStateComponent>(uid, out var standingState)
|
||||
|| !TryComp<LayingDownComponent>(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;
|
||||
layingDown.AutoGetUp = _cfg.GetClientCVar(args.SenderSession.Channel, WhiteCVars.AutoGetUp);
|
||||
Dirty(uid, layingDown);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using Content.Server.Traits.Assorted;
|
||||
using Content.Server.Standing;
|
||||
using Content.Shared._White.Standing;
|
||||
|
||||
namespace Content.Shared.Traits.Assorted.Systems;
|
||||
|
||||
@@ -16,7 +16,7 @@ public sealed class LayingDownModifierSystem : EntitySystem
|
||||
if (!TryComp<LayingDownComponent>(uid, out var layingDown))
|
||||
return;
|
||||
|
||||
layingDown.Cooldown *= component.LayingDownCooldownMultiplier;
|
||||
layingDown.DownedSpeedMultiplier *= component.DownedSpeedMultiplierMultiplier;
|
||||
layingDown.StandingUpTime *= component.LayingDownCooldownMultiplier;
|
||||
layingDown.SpeedModify *= component.DownedSpeedMultiplierMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,35 @@
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Standing
|
||||
namespace Content.Shared.Standing;
|
||||
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class StandingStateComponent : Component
|
||||
{
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
[Access(typeof(StandingStateSystem))]
|
||||
public sealed partial class StandingStateComponent : Component
|
||||
{
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public SoundSpecifier DownSound { get; private set; } = new SoundCollectionSpecifier("BodyFall");
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public SoundSpecifier DownSound { get; private set; } = new SoundCollectionSpecifier("BodyFall");
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool Standing { get; set; } = true;
|
||||
// WD EDIT START
|
||||
[DataField, AutoNetworkedField]
|
||||
public StandingState CurrentState { get; set; } = StandingState.Standing;
|
||||
// WD EDIT END
|
||||
|
||||
/// <summary>
|
||||
/// List of fixtures that had their collision mask changed when the entity was downed.
|
||||
/// Required for re-adding the collision mask.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public List<string> ChangedFixtures = new();
|
||||
}
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool Standing { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// List of fixtures that had their collision mask changed when the entity was downed.
|
||||
/// Required for re-adding the collision mask.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public List<string> ChangedFixtures = new();
|
||||
}
|
||||
// WD EDIT START
|
||||
public enum StandingState
|
||||
{
|
||||
Lying,
|
||||
GettingUp,
|
||||
Standing,
|
||||
}
|
||||
// WD EDIT END
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using Content.Shared.Buckle;
|
||||
using Content.Shared.Buckle.Components;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.Physics;
|
||||
using Content.Shared.Rotation;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
@@ -13,6 +15,8 @@ namespace Content.Shared.Standing
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||
[Dependency] private readonly MovementSpeedModifierSystem _movement = default!; // WD EDIT
|
||||
[Dependency] private readonly SharedBuckleSystem _buckle = default!; // WD EDIT
|
||||
|
||||
// If StandingCollisionLayer value is ever changed to more than one layer, the logic needs to be edited.
|
||||
private const int StandingCollisionLayer = (int) CollisionGroup.MidImpassable;
|
||||
@@ -22,7 +26,7 @@ namespace Content.Shared.Standing
|
||||
if (!Resolve(uid, ref standingState, false))
|
||||
return false;
|
||||
|
||||
return !standingState.Standing;
|
||||
return standingState.CurrentState is StandingState.Lying or StandingState.GettingUp;
|
||||
}
|
||||
|
||||
public bool Down(EntityUid uid, bool playSound = true, bool dropHeldItems = true,
|
||||
@@ -37,7 +41,7 @@ namespace Content.Shared.Standing
|
||||
// Optional component.
|
||||
Resolve(uid, ref appearance, ref hands, false);
|
||||
|
||||
if (!standingState.Standing)
|
||||
if (standingState.CurrentState is StandingState.Lying or StandingState.GettingUp)
|
||||
return true;
|
||||
|
||||
// This is just to avoid most callers doing this manually saving boilerplate
|
||||
@@ -49,13 +53,16 @@ namespace Content.Shared.Standing
|
||||
RaiseLocalEvent(uid, new DropHandItemsEvent(), false);
|
||||
}
|
||||
|
||||
if (TryComp(uid, out BuckleComponent? buckle) && buckle.Buckled && !_buckle.TryUnbuckle(uid, uid, buckleComp: buckle)) // WD EDIT
|
||||
return false;
|
||||
|
||||
var msg = new DownAttemptEvent();
|
||||
RaiseLocalEvent(uid, msg, false);
|
||||
|
||||
if (msg.Cancelled)
|
||||
return false;
|
||||
|
||||
standingState.Standing = false;
|
||||
standingState.CurrentState = StandingState.Lying;
|
||||
Dirty(standingState);
|
||||
RaiseLocalEvent(uid, new DownedEvent(), false);
|
||||
|
||||
@@ -82,9 +89,10 @@ namespace Content.Shared.Standing
|
||||
|
||||
if (playSound)
|
||||
{
|
||||
_audio.PlayPredicted(standingState.DownSound, uid, uid);
|
||||
_audio.PlayPredicted(standingState.DownSound, uid, null);
|
||||
}
|
||||
|
||||
_movement.RefreshMovementSpeedModifiers(uid); // WD EDIT
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -100,9 +108,12 @@ namespace Content.Shared.Standing
|
||||
// Optional component.
|
||||
Resolve(uid, ref appearance, false);
|
||||
|
||||
if (standingState.Standing)
|
||||
if (standingState.CurrentState is StandingState.Standing)
|
||||
return true;
|
||||
|
||||
if (TryComp(uid, out BuckleComponent? buckle) && buckle.Buckled && !_buckle.TryUnbuckle(uid, uid, buckleComp: buckle)) // WD EDIT
|
||||
return false;
|
||||
|
||||
if (!force)
|
||||
{
|
||||
var msg = new StandAttemptEvent();
|
||||
@@ -112,7 +123,7 @@ namespace Content.Shared.Standing
|
||||
return false;
|
||||
}
|
||||
|
||||
standingState.Standing = true;
|
||||
standingState.CurrentState = StandingState.Standing;
|
||||
Dirty(uid, standingState);
|
||||
RaiseLocalEvent(uid, new StoodEvent(), false);
|
||||
|
||||
@@ -127,6 +138,7 @@ namespace Content.Shared.Standing
|
||||
}
|
||||
}
|
||||
standingState.ChangedFixtures.Clear();
|
||||
_movement.RefreshMovementSpeedModifiers(uid); // WD EDIT
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Shared._White.Standing;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Audio;
|
||||
@@ -19,6 +20,7 @@ using Content.Shared.StatusEffect;
|
||||
using Content.Shared.Throwing;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
@@ -32,6 +34,8 @@ public abstract class SharedStunSystem : EntitySystem
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly StandingStateSystem _standingState = default!;
|
||||
[Dependency] private readonly StatusEffectsSystem _statusEffect = default!;
|
||||
[Dependency] private readonly SharedLayingDownSystem _layingDown = default!; // WD EDIT
|
||||
[Dependency] private readonly SharedContainerSystem _container = default!; // WD EDIT
|
||||
|
||||
/// <summary>
|
||||
/// Friction modifier for knocked down players.
|
||||
@@ -109,12 +113,25 @@ public abstract class SharedStunSystem : EntitySystem
|
||||
|
||||
private void OnKnockInit(EntityUid uid, KnockedDownComponent component, ComponentInit args)
|
||||
{
|
||||
_standingState.Down(uid);
|
||||
RaiseNetworkEvent(new CheckAutoGetUpEvent(GetNetEntity(uid))); // WD EDIT
|
||||
_layingDown.TryLieDown(uid, null, null, DropHeldItemsBehavior.DropIfStanding); // WD EDIT
|
||||
}
|
||||
|
||||
private void OnKnockShutdown(EntityUid uid, KnockedDownComponent component, ComponentShutdown args)
|
||||
{
|
||||
_standingState.Stand(uid);
|
||||
// WD EDIT START
|
||||
if (!TryComp(uid, out StandingStateComponent? standing))
|
||||
return;
|
||||
|
||||
if (TryComp(uid, out LayingDownComponent? layingDown))
|
||||
{
|
||||
if (layingDown.AutoGetUp && !_container.IsEntityInContainer(uid))
|
||||
_layingDown.TryStandUp(uid, layingDown);
|
||||
return;
|
||||
}
|
||||
|
||||
_standingState.Stand(uid, standing);
|
||||
// WD EDIT END
|
||||
}
|
||||
|
||||
private void OnStandAttempt(EntityUid uid, KnockedDownComponent component, StandAttemptEvent args)
|
||||
|
||||
@@ -7,6 +7,9 @@ public sealed class WhiteCVars
|
||||
{
|
||||
#region Keybind
|
||||
|
||||
public static readonly CVarDef<bool> AutoGetUp =
|
||||
CVarDef.Create("white.auto_get_up", true, CVar.CLIENT | CVar.ARCHIVE | CVar.REPLICATED);
|
||||
|
||||
public static readonly CVarDef<bool> HoldLookUp =
|
||||
CVarDef.Create("white.hold_look_up", false, CVar.CLIENT | CVar.ARCHIVE);
|
||||
|
||||
|
||||
25
Content.Shared/_White/Standing/LayingDownComponent.cs
Normal file
25
Content.Shared/_White/Standing/LayingDownComponent.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._White.Standing;
|
||||
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class LayingDownComponent : Component
|
||||
{
|
||||
[DataField, AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)]
|
||||
public float StandingUpTime { get; set; } = 1f;
|
||||
|
||||
[DataField, AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)]
|
||||
public float SpeedModify { get; set; } = 0.4f;
|
||||
|
||||
[DataField, AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool AutoGetUp;
|
||||
}
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class ChangeLayingDownEvent : CancellableEntityEventArgs;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class CheckAutoGetUpEvent(NetEntity user) : CancellableEntityEventArgs
|
||||
{
|
||||
public NetEntity User = user;
|
||||
}
|
||||
162
Content.Shared/_White/Standing/SharedLayingDownSystem.cs
Normal file
162
Content.Shared/_White/Standing/SharedLayingDownSystem.cs
Normal file
@@ -0,0 +1,162 @@
|
||||
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.Standing;
|
||||
using Content.Shared.Stunnable;
|
||||
using Robust.Shared.Input.Binding;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._White.Standing;
|
||||
|
||||
public abstract class SharedLayingDownSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
[Dependency] private readonly StandingStateSystem _standing = default!;
|
||||
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
||||
[Dependency] private readonly SharedGravitySystem _gravity = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
CommandBinds.Builder
|
||||
.Bind(ContentKeyFunctions.ToggleStanding, InputCmdHandler.FromDelegate(ToggleStanding))
|
||||
.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?.AttachedEntity == null ||
|
||||
!HasComp<LayingDownComponent>(session.AttachedEntity) ||
|
||||
_gravity.IsWeightless(session.AttachedEntity.Value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RaiseNetworkEvent(new ChangeLayingDownEvent());
|
||||
}
|
||||
|
||||
private void OnChangeState(ChangeLayingDownEvent ev, EntitySessionEventArgs args)
|
||||
{
|
||||
if (!args.SenderSession.AttachedEntity.HasValue)
|
||||
return;
|
||||
|
||||
var uid = args.SenderSession.AttachedEntity.Value;
|
||||
|
||||
// TODO: Wizard
|
||||
//if (HasComp<FrozenComponent>(uid))
|
||||
// return;
|
||||
|
||||
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, layingDown, 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))
|
||||
args.ModifySpeed(component.SpeedModify, component.SpeedModify);
|
||||
else
|
||||
args.ModifySpeed(1f, 1f);
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class StandingUpDoAfterEvent : SimpleDoAfterEvent;
|
||||
|
||||
public enum DropHeldItemsBehavior : byte
|
||||
{
|
||||
NoDrop,
|
||||
DropIfStanding,
|
||||
AlwaysDrop
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
ui-options-function-look-up = Look up/Take aim
|
||||
ui-options-function-auto-get-up = Automatically get up after falling
|
||||
ui-options-function-hold-look-up = Hold down the key to aim
|
||||
@@ -1,2 +1,3 @@
|
||||
ui-options-function-look-up = Присмотреться/Прицелиться
|
||||
ui-options-function-auto-get-up = Автоматически вставать при падении
|
||||
ui-options-function-hold-look-up = Удерживать клавишу для прицеливания
|
||||
Reference in New Issue
Block a user