Add conditional camera offset based on cursor - Hristov Rework, Part 1 (#31626)

(cherry picked from commit 5c782d30283d5e3661e1ce6ebc6d972f12671c41)
This commit is contained in:
SlamBamActionman
2025-01-28 02:20:45 +03:00
committed by Spatison
parent 06c2a16480
commit bd28f7f0dd
39 changed files with 473 additions and 315 deletions

View File

@@ -89,7 +89,7 @@ namespace Content.Client.Input
human.AddFunction(ContentKeyFunctions.Arcade1);
human.AddFunction(ContentKeyFunctions.Arcade2);
human.AddFunction(ContentKeyFunctions.Arcade3);
human.AddFunction(ContentKeyFunctions.LookUp);
human.AddFunction(ContentKeyFunctions.LookUp); // WD EDIT
// Shitmed Change Start - TODO: Add groin targeting.
human.AddFunction(ContentKeyFunctions.TargetHead);
human.AddFunction(ContentKeyFunctions.TargetTorso);

View File

@@ -0,0 +1,19 @@
using System.Numerics;
using Content.Client.Movement.Systems;
using Content.Shared.Movement.Components;
namespace Content.Client.Movement.Components;
[RegisterComponent]
public sealed partial class EyeCursorOffsetComponent : SharedEyeCursorOffsetComponent
{
/// <summary>
/// The location the offset will attempt to pan towards; based on the cursor's position in the game window.
/// </summary>
public Vector2 TargetPosition = Vector2.Zero;
/// <summary>
/// The current positional offset being applied. Used to enable gradual panning.
/// </summary>
public Vector2 CurrentPosition = Vector2.Zero;
}

View File

@@ -1,6 +1,7 @@
using System.Numerics;
using Content.Shared.Movement.Components;
using Content.Shared.Movement.Systems;
using Robust.Client.GameObjects;
using Robust.Client.Player;
namespace Content.Client.Movement.Systems;
@@ -52,4 +53,14 @@ public sealed class ContentEyeSystem : SharedContentEyeSystem
{
RaisePredictiveEvent(new RequestEyeEvent(drawFov, drawLight));
}
public override void FrameUpdate(float frameTime)
{
base.FrameUpdate(frameTime);
var eyeEntities = AllEntityQuery<ContentEyeComponent, EyeComponent>();
while (eyeEntities.MoveNext(out var entity, out ContentEyeComponent? contentComponent, out EyeComponent? eyeComponent))
{
UpdateEyeOffset((entity, eyeComponent));
}
}
}

View File

@@ -0,0 +1,127 @@
using System.Numerics;
using Content.Client.Movement.Components;
using Content.Shared.Camera;
using Content.Shared.Input;
using Content.Shared.Inventory;
using Content.Shared.Movement.Systems;
using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Shared.Map;
using Robust.Client.Player;
using Robust.Shared.Input;
using Robust.Shared.Input.Binding;
using Robust.Shared.Player;
namespace Content.Client.Movement.Systems;
public partial class EyeCursorOffsetSystem : EntitySystem
{
[Dependency] private readonly IEyeManager _eyeManager = default!;
[Dependency] private readonly IInputManager _inputManager = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedContentEyeSystem _contentEye = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IClyde _clyde = default!;
// This value is here to make sure the user doesn't have to move their mouse
// all the way out to the edge of the screen to get the full offset.
static private float _edgeOffset = 0.9f;
private static bool _toggled; // WD EDIT
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<EyeCursorOffsetComponent, GetEyeOffsetEvent>(OnGetEyeOffsetEvent);
// WD EDIT START
CommandBinds.Builder
.Bind(ContentKeyFunctions.LookUp, new EyeOffsetInputCmdHandler())
.Register<EyeCursorOffsetSystem>();
// WD EDIT END
}
private void OnGetEyeOffsetEvent(EntityUid uid, EyeCursorOffsetComponent component, ref GetEyeOffsetEvent args)
{
var offset = OffsetAfterMouse(uid, component);
if (offset == null)
return;
args.Offset += offset.Value;
}
public Vector2? OffsetAfterMouse(EntityUid uid, EyeCursorOffsetComponent? component)
{
// WD EDIT START
if (!_toggled)
return null;
// WD EDIT END
var localPlayer = _player.LocalPlayer?.ControlledEntity;
var mousePos = _inputManager.MouseScreenPosition;
var screenSize = _clyde.MainWindow.Size;
var minValue = MathF.Min(screenSize.X / 2, screenSize.Y / 2) * _edgeOffset;
var mouseNormalizedPos = new Vector2(-(mousePos.X - screenSize.X / 2) / minValue, (mousePos.Y - screenSize.Y / 2) / minValue); // X needs to be inverted here for some reason, otherwise it ends up flipped.
if (localPlayer == null)
return null;
var playerPos = _transform.GetWorldPosition(localPlayer.Value);
if (component == null)
{
component = EnsureComp<EyeCursorOffsetComponent>(uid);
}
// Doesn't move the offset if the mouse has left the game window!
if (mousePos.Window != WindowId.Invalid)
{
// The offset must account for the in-world rotation.
var eyeRotation = _eyeManager.CurrentEye.Rotation;
var mouseActualRelativePos = Vector2.Transform(mouseNormalizedPos, System.Numerics.Quaternion.CreateFromAxisAngle(-System.Numerics.Vector3.UnitZ, (float)(eyeRotation.Opposite().Theta))); // I don't know, it just works.
// Caps the offset into a circle around the player.
mouseActualRelativePos *= component.MaxOffset;
if (mouseActualRelativePos.Length() > component.MaxOffset)
{
mouseActualRelativePos = mouseActualRelativePos.Normalized() * component.MaxOffset;
}
component.TargetPosition = mouseActualRelativePos;
//Makes the view not jump immediately when moving the cursor fast.
if (component.CurrentPosition != component.TargetPosition)
{
Vector2 vectorOffset = component.TargetPosition - component.CurrentPosition;
if (vectorOffset.Length() > component.OffsetSpeed)
{
vectorOffset = vectorOffset.Normalized() * component.OffsetSpeed;
}
component.CurrentPosition += vectorOffset;
}
}
return component.CurrentPosition;
}
// WD EDIT START
private sealed class EyeOffsetInputCmdHandler : InputCmdHandler
{
public override bool HandleCmdMessage(
IEntityManager entManager,
ICommonSession? session,
IFullInputCmdMessage message
)
{
if (session?.AttachedEntity == null)
return false;
_toggled = message.State == BoundKeyState.Down;
return false;
}
}
// WD EDIT END
}

View File

@@ -1,6 +1,6 @@
using System.Numerics;
using Content.Client.Stylesheets;
using Content.Shared._White;
using Content.Shared._White.CCVar;
using Content.Shared.CCVar;
using Content.Shared.Input;
using Robust.Client.AutoGenerated;
@@ -57,6 +57,16 @@ namespace Content.Client.Options.UI.Tabs
}
}
// WD EDIT START
private void InitToggleLookUp()
{
if (_cfg.GetCVar(WhiteCVars.ToggleLookUp))
ToggleFunctions.Add(ContentKeyFunctions.LookUp);
else
ToggleFunctions.Remove(ContentKeyFunctions.LookUp);
}
// WD EDIT END
private void HandleToggleWalk(BaseButton.ButtonToggledEventArgs args)
{
_cfg.SetCVar(CCVars.ToggleWalk, args.Pressed);
@@ -100,16 +110,51 @@ namespace Content.Client.Options.UI.Tabs
_deferCommands.Add(_inputManager.SaveToUserData);
}
private void HandleHoldLookUp(BaseButton.ButtonToggledEventArgs args)
// WD EDIT START
private void HandleToggleLookUp(BaseButton.ButtonToggledEventArgs args)
{
_cfg.SetCVar(CCVars.HoldLookUp, args.Pressed);
_cfg.SetCVar(WhiteCVars.ToggleLookUp, args.Pressed);
_cfg.SaveToFile();
InitToggleLookUp();
if (!_keyControls.TryGetValue(ContentKeyFunctions.LookUp, out var keyControl))
return;
var bindingType = args.Pressed ? KeyBindingType.Toggle : KeyBindingType.State;
for (var i = 0; i <= 1; i++)
{
var binding = (i == 0 ? keyControl.BindButton1 : keyControl.BindButton2).Binding;
if (binding == null)
continue;
var registration = new KeyBindingRegistration
{
Function = ContentKeyFunctions.LookUp,
BaseKey = binding.BaseKey,
Mod1 = binding.Mod1,
Mod2 = binding.Mod2,
Mod3 = binding.Mod3,
Priority = binding.Priority,
Type = bindingType,
CanFocus = binding.CanFocus,
CanRepeat = binding.CanRepeat,
};
_deferCommands.Add(() =>
{
_inputManager.RemoveBinding(binding);
_inputManager.RegisterBinding(registration);
});
}
_deferCommands.Add(_inputManager.SaveToUserData);
}
// WD EDIT END
private void HandleDefaultWalk(BaseButton.ButtonToggledEventArgs args)
{
_cfg.SetCVar(CCVars.DefaultWalk, args.Pressed);
_cfg.SaveToFile();
_cfg.SaveToFile();
}
private void HandleStaticStorageUI(BaseButton.ButtonToggledEventArgs args)
@@ -252,7 +297,7 @@ namespace Content.Client.Options.UI.Tabs
AddButton(ContentKeyFunctions.ToggleCombatMode); // WD EDIT
AddButton(ContentKeyFunctions.LookUp);
AddCheckBox("ui-options-function-auto-get-up", _cfg.GetCVar(CCVars.AutoGetUp), HandleToggleAutoGetUp);
AddCheckBox("ui-options-function-hold-look-up", _cfg.GetCVar(CCVars.HoldLookUp), HandleHoldLookUp);
AddCheckBox("ui-options-function-toggle-look-up", _cfg.GetCVar(WhiteCVars.ToggleLookUp), HandleToggleLookUp); // WD EDIT
AddHeader("ui-options-header-interaction-adv");
AddButton(ContentKeyFunctions.SmartEquipBackpack);

View File

@@ -1,128 +0,0 @@
using System.Numerics;
using Content.Client.Viewport;
using Content.Shared.CCVar;
using Content.Shared.Telescope;
using Content.Shared.Input;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Shared.Configuration;
using Robust.Shared.Input;
using Robust.Shared.Input.Binding;
using Robust.Shared.Timing;
namespace Content.Client.Telescope;
public sealed class TelescopeSystem : SharedTelescopeSystem
{
[Dependency] private readonly InputSystem _inputSystem = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IInputManager _input = default!;
[Dependency] private readonly IEyeManager _eyeManager = default!;
[Dependency] private readonly IUserInterfaceManager _uiManager = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
private ScalingViewport? _viewport;
private bool _holdLookUp;
private bool _toggled;
public override void Initialize()
{
base.Initialize();
_cfg.OnValueChanged(CCVars.HoldLookUp,
val =>
{
var input = val ? null : InputCmdHandler.FromDelegate(_ => _toggled = !_toggled);
_input.SetInputCommand(ContentKeyFunctions.LookUp, input);
_holdLookUp = val;
_toggled = false;
},
true);
}
public override void FrameUpdate(float frameTime)
{
base.FrameUpdate(frameTime);
if (_timing.ApplyingState
|| !_timing.IsFirstTimePredicted
|| !_input.MouseScreenPosition.IsValid)
return;
var player = _player.LocalEntity;
var telescope = GetRightTelescope(player);
if (telescope == null)
{
_toggled = false;
return;
}
if (!TryComp<EyeComponent>(player, out var eye))
return;
var offset = Vector2.Zero;
if (_holdLookUp)
{
if (_inputSystem.CmdStates.GetState(ContentKeyFunctions.LookUp) != BoundKeyState.Down)
{
RaiseEvent(offset);
return;
}
}
else if (!_toggled)
{
RaiseEvent(offset);
return;
}
var mousePos = _input.MouseScreenPosition;
if (_uiManager.MouseGetControl(mousePos) as ScalingViewport is { } viewport)
_viewport = viewport;
if (_viewport == null)
return;
var centerPos = _eyeManager.WorldToScreen(eye.Eye.Position.Position + eye.Offset);
var diff = mousePos.Position - centerPos;
var len = diff.Length();
var size = _viewport.PixelSize;
var maxLength = Math.Min(size.X, size.Y) * 0.4f;
var minLength = maxLength * 0.2f;
if (len > maxLength)
{
diff *= maxLength / len;
len = maxLength;
}
var divisor = maxLength * telescope.Divisor;
if (len > minLength)
{
diff -= diff * minLength / len;
offset = new Vector2(diff.X / divisor, -diff.Y / divisor);
offset = new Angle(-eye.Rotation.Theta).RotateVec(offset);
}
RaiseEvent(offset);
}
private void RaiseEvent(Vector2 offset)
{
RaisePredictiveEvent(new EyeOffsetChangedEvent
{
Offset = offset
});
}
}

View File

@@ -0,0 +1,49 @@
using System.Numerics;
using Content.Client.Movement.Components;
using Content.Client.Movement.Systems;
using Content.Shared.Camera;
using Content.Shared.Hands;
using Content.Shared.Movement.Components;
using Content.Shared.Wieldable;
using Content.Shared.Wieldable.Components;
using Robust.Client.Timing;
namespace Content.Client.Wieldable;
public sealed class WieldableSystem : SharedWieldableSystem
{
[Dependency] private readonly EyeCursorOffsetSystem _eyeOffset = default!;
[Dependency] private readonly IClientGameTiming _gameTiming = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CursorOffsetRequiresWieldComponent, ItemUnwieldedEvent>(OnEyeOffsetUnwielded);
SubscribeLocalEvent<CursorOffsetRequiresWieldComponent, HeldRelayedEvent<GetEyeOffsetRelayedEvent>>(OnGetEyeOffset);
}
public void OnEyeOffsetUnwielded(Entity<CursorOffsetRequiresWieldComponent> entity, ref ItemUnwieldedEvent args)
{
if (!TryComp(entity.Owner, out EyeCursorOffsetComponent? cursorOffsetComp))
return;
if (_gameTiming.IsFirstTimePredicted)
cursorOffsetComp.CurrentPosition = Vector2.Zero;
}
public void OnGetEyeOffset(Entity<CursorOffsetRequiresWieldComponent> entity, ref HeldRelayedEvent<GetEyeOffsetRelayedEvent> args)
{
if (!TryComp(entity.Owner, out WieldableComponent? wieldableComp))
return;
if (!wieldableComp.Wielded)
return;
var offset = _eyeOffset.OffsetAfterMouse(entity.Owner, null);
if (offset == null)
return;
args.Args.Offset += offset.Value;
}
}

View File

@@ -0,0 +1,12 @@
using System.Numerics;
using Content.Shared.Movement.Components;
using Content.Shared.Movement.Systems;
using Robust.Shared.GameStates;
namespace Content.Server.Movement.Components;
[RegisterComponent]
public sealed partial class EyeCursorOffsetComponent : SharedEyeCursorOffsetComponent
{
}

View File

@@ -1,5 +0,0 @@
using Content.Shared.Telescope;
namespace Content.Server.Telescope;
public sealed class TelescopeSystem : SharedTelescopeSystem;

View File

@@ -0,0 +1,45 @@
using Content.Server.Movement.Components;
using Content.Server.Movement.Systems;
using Content.Shared.Camera;
using Content.Shared.Hands;
using Content.Shared.Movement.Components;
using Content.Shared.Wieldable;
using Content.Shared.Wieldable.Components;
namespace Content.Server.Wieldable;
public sealed class WieldableSystem : SharedWieldableSystem
{
[Dependency] private readonly ContentEyeSystem _eye = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CursorOffsetRequiresWieldComponent, ItemUnwieldedEvent>(OnEyeOffsetUnwielded);
SubscribeLocalEvent<CursorOffsetRequiresWieldComponent, ItemWieldedEvent>(OnEyeOffsetWielded);
SubscribeLocalEvent<CursorOffsetRequiresWieldComponent, HeldRelayedEvent<GetEyePvsScaleRelayedEvent>>(OnGetEyePvsScale);
}
private void OnEyeOffsetUnwielded(Entity<CursorOffsetRequiresWieldComponent> entity, ref ItemUnwieldedEvent args)
{
_eye.UpdatePvsScale(args.User);
}
private void OnEyeOffsetWielded(Entity<CursorOffsetRequiresWieldComponent> entity, ref ItemWieldedEvent args)
{
_eye.UpdatePvsScale(args.User);
}
private void OnGetEyePvsScale(Entity<CursorOffsetRequiresWieldComponent> entity,
ref HeldRelayedEvent<GetEyePvsScaleRelayedEvent> args)
{
if (!TryComp(entity, out EyeCursorOffsetComponent? eyeCursorOffset) || !TryComp(entity.Owner, out WieldableComponent? wieldableComp))
return;
if (!wieldableComp.Wielded)
return;
args.Args.Scale += eyeCursorOffset.PvsIncrease;
}
}

View File

@@ -5,10 +5,4 @@ public sealed partial class ImmersiveAspectComponent : Component
{
[DataField]
public float EyeModifier = 0.6f;
[DataField]
public float TelescopeDivisor = 0.15f;
[DataField]
public float TelescopeLerpAmount = 0.07f;
}

View File

@@ -1,17 +1,16 @@
using System.Numerics;
using Content.Server._White.GameTicking.Aspects.Components;
using Content.Server.Movement.Components;
using Content.Shared.GameTicking;
using Content.Shared.GameTicking.Components;
using Content.Shared.Movement.Components;
using Content.Shared.Movement.Systems;
using Content.Shared.Telescope;
namespace Content.Server._White.GameTicking.Aspects;
public sealed class ImmersiveAspect : AspectSystem<ImmersiveAspectComponent>
{
[Dependency] private readonly SharedContentEyeSystem _eye = default!;
[Dependency] private readonly SharedTelescopeSystem _telescope = default!;
public override void Initialize()
{
@@ -39,7 +38,7 @@ public sealed class ImmersiveAspect : AspectSystem<ImmersiveAspectComponent>
while (query.MoveNext(out var entity, out _))
{
SetEyeZoom(entity, component.EyeModifier);
AddTelescope(entity, component.TelescopeDivisor, component.TelescopeLerpAmount);
EnsureComp<EyeCursorOffsetComponent>(entity);
}
}
@@ -49,13 +48,6 @@ public sealed class ImmersiveAspect : AspectSystem<ImmersiveAspectComponent>
_eye.SetZoom(human, new Vector2(modifier));
}
private void AddTelescope(EntityUid human, float divisor, float lerpAmount)
{
var telescope = EnsureComp<TelescopeComponent>(human);
_telescope.SetParameters((human, telescope), divisor, lerpAmount);
}
private void OnPlayerSpawn(PlayerSpawnCompleteEvent ev)
{
if (!HasComp<ContentEyeComponent>(ev.Mob))
@@ -68,7 +60,7 @@ public sealed class ImmersiveAspect : AspectSystem<ImmersiveAspectComponent>
continue;
SetEyeZoom(ev.Mob, immersiveAspect.EyeModifier);
AddTelescope(ev.Mob, immersiveAspect.TelescopeDivisor, immersiveAspect.TelescopeLerpAmount);
EnsureComp<EyeCursorOffsetComponent>(ev.Mob);
}
}
@@ -87,7 +79,7 @@ public sealed class ImmersiveAspect : AspectSystem<ImmersiveAspectComponent>
{
SetEyeZoom(entity, 1f);
RemComp<TelescopeComponent>(entity);
RemComp<EyeCursorOffsetComponent>(entity);
}
}
}

View File

@@ -7,9 +7,6 @@ public sealed partial class CCVars
public static readonly CVarDef<bool> AutoGetUp =
CVarDef.Create("rest.auto_get_up", true, CVar.CLIENT | CVar.ARCHIVE | CVar.REPLICATED);
public static readonly CVarDef<bool> HoldLookUp =
CVarDef.Create("rest.hold_look_up", false, CVar.CLIENT | CVar.ARCHIVE);
/// <summary>
/// When true, players can choose to crawl under tables while laying down, using the designated keybind.
/// </summary>

View File

@@ -1,4 +1,5 @@
using System.Numerics;
using Content.Shared.Inventory;
using Content.Shared.Movement.Systems;
namespace Content.Shared.Camera;
@@ -17,3 +18,15 @@ namespace Content.Shared.Camera;
/// </remarks>
[ByRefEvent]
public record struct GetEyeOffsetEvent(Vector2 Offset);
/// <summary>
/// Raised on any equipped and in-hand items that may modify the eye offset.
/// Pockets and suitstorage are excluded.
/// </summary>
[ByRefEvent]
public sealed class GetEyeOffsetRelayedEvent : EntityEventArgs, IInventoryRelayEvent
{
public SlotFlags TargetSlots { get; } = ~(SlotFlags.POCKET & SlotFlags.SUITSTORAGE);
public Vector2 Offset;
}

View File

@@ -0,0 +1,33 @@
using System.Numerics;
using Content.Shared.Inventory;
using Content.Shared.Movement.Systems;
namespace Content.Shared.Camera;
/// <summary>
/// Raised directed by-ref when <see cref="SharedContentEyeSystem.UpdatePvsScale"/> is called.
/// Should be subscribed to by any systems that want to modify an entity's eye PVS scale,
/// so that they do not override each other. Keep in mind that this should be done serverside;
/// the client may set a new PVS scale, but the server won't provide the data if it isn't done on the server.
/// </summary>
/// <param name="Scale">
/// The total scale to apply.
/// </param>
/// <remarks>
/// Note that in most cases <see cref="Scale"/> should be incremented or decremented by subscribers, not set.
/// Otherwise, any offsets applied by previous subscribing systems will be overridden.
/// </remarks>
[ByRefEvent]
public record struct GetEyePvsScaleEvent(float Scale);
/// <summary>
/// Raised on any equipped and in-hand items that may modify the eye offset.
/// Pockets and suitstorage are excluded.
/// </summary>
[ByRefEvent]
public sealed class GetEyePvsScaleRelayedEvent : EntityEventArgs, IInventoryRelayEvent
{
public SlotFlags TargetSlots { get; } = ~(SlotFlags.POCKET & SlotFlags.SUITSTORAGE);
public float Scale;
}

View File

@@ -1,4 +1,6 @@
using System.Numerics;
using Content.Shared.Movement.Components;
using Content.Shared.Movement.Systems;
using JetBrains.Annotations;
using Robust.Shared.Network;
using Robust.Shared.Serialization;
@@ -28,7 +30,7 @@ public abstract class SharedCameraRecoilSystem : EntitySystem
/// </summary>
protected const float KickMagnitudeMax = 1f;
[Dependency] private readonly SharedEyeSystem _eye = default!;
[Dependency] private readonly SharedContentEyeSystem _eye = default!;
[Dependency] private readonly INetManager _net = default!;
public override void Initialize()
@@ -81,9 +83,7 @@ public abstract class SharedCameraRecoilSystem : EntitySystem
continue;
recoil.LastKick = recoil.CurrentKick;
var ev = new GetEyeOffsetEvent();
RaiseLocalEvent(uid, ref ev);
_eye.SetOffset(uid, ev.Offset, eye);
_eye.UpdateEyeOffset((uid, eye));
}
}

View File

@@ -1,4 +1,5 @@
using Content.Shared._White.Move;
using Content.Shared.Camera;
using Content.Shared.Hands.Components;
using Content.Shared.Movement.Systems;
@@ -8,6 +9,8 @@ public abstract partial class SharedHandsSystem
{
private void InitializeRelay()
{
SubscribeLocalEvent<HandsComponent, GetEyeOffsetRelayedEvent>(RelayEvent);
SubscribeLocalEvent<HandsComponent, GetEyePvsScaleRelayedEvent>(RelayEvent);
SubscribeLocalEvent<HandsComponent, RefreshMovementSpeedModifiersEvent>(RelayEvent);
SubscribeLocalEvent<HandsComponent, MoveEventProxy>(RelayEvent);
}

View File

@@ -64,7 +64,7 @@ namespace Content.Shared.Input
public static readonly BoundKeyFunction ToggleStanding = "ToggleStanding";
public static readonly BoundKeyFunction ToggleCrawlingUnder = "ToggleCrawlingUnder";
public static readonly BoundKeyFunction ToggleCombatMode = "ToggleCombatMode"; // WD EDIT
public static readonly BoundKeyFunction LookUp = "LookUp";
public static readonly BoundKeyFunction LookUp = "LookUp"; // WD EDIT
public static readonly BoundKeyFunction TargetHead = "TargetHead";
public static readonly BoundKeyFunction TargetTorso = "TargetTorso";
public static readonly BoundKeyFunction TargetLeftArm = "TargetLeftArm";

View File

@@ -0,0 +1,13 @@
using Content.Shared.Wieldable;
using Robust.Shared.GameStates;
namespace Content.Shared.Movement.Components;
/// <summary>
/// Indicates that this item requires wielding for the cursor offset effect to be active.
/// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(SharedWieldableSystem))]
public sealed partial class CursorOffsetRequiresWieldComponent : Component
{
}

View File

@@ -0,0 +1,32 @@
using System.Numerics;
using Content.Shared.Movement.Systems;
using Robust.Shared.GameStates;
namespace Content.Shared.Movement.Components;
/// <summary>
/// Displaces SS14 eye data when given to an entity.
/// </summary>
[ComponentProtoName("EyeCursorOffset"), NetworkedComponent]
public abstract partial class SharedEyeCursorOffsetComponent : Component
{
/// <summary>
/// The amount the view will be displaced when the cursor is positioned at/beyond the max offset distance.
/// Measured in tiles.
/// </summary>
[DataField]
public float MaxOffset = 3f;
/// <summary>
/// The speed which the camera adjusts to new positions. 0.5f seems like a good value, but can be changed if you want very slow/instant adjustments.
/// </summary>
[DataField]
public float OffsetSpeed = 0.5f;
/// <summary>
/// The amount the PVS should increase to account for the max offset.
/// Should be 1/10 of MaxOffset most of the time.
/// </summary>
[DataField]
public float PvsIncrease = 0.3f;
}

View File

@@ -161,11 +161,29 @@ public abstract class SharedContentEyeSystem : EntitySystem
Dirty(uid, component);
}
public void UpdateEyeOffset(Entity<EyeComponent?> eye)
public void UpdateEyeOffset(Entity<EyeComponent> eye)
{
var ev = new GetEyeOffsetEvent();
RaiseLocalEvent(eye, ref ev);
_eye.SetOffset(eye, ev.Offset, eye);
var evRelayed = new GetEyeOffsetRelayedEvent();
RaiseLocalEvent(eye, ref evRelayed);
_eye.SetOffset(eye, ev.Offset + evRelayed.Offset, eye);
}
public void UpdatePvsScale(EntityUid uid, ContentEyeComponent? contentEye = null, EyeComponent? eye = null)
{
if (!Resolve(uid, ref contentEye) || !Resolve(uid, ref eye))
return;
var ev = new GetEyePvsScaleEvent();
RaiseLocalEvent(uid, ref ev);
var evRelayed = new GetEyePvsScaleRelayedEvent();
RaiseLocalEvent(uid, ref evRelayed);
_eye.SetPvsScale((uid, eye), 1 + ev.Scale + evRelayed.Scale);
}
/// <summary>

View File

@@ -1,110 +0,0 @@
using System.Numerics;
using Content.Shared.Camera;
using Content.Shared.Hands;
using Content.Shared.Hands.Components;
using Content.Shared.Item;
using Robust.Shared.Serialization;
namespace Content.Shared.Telescope;
public abstract class SharedTelescopeSystem : EntitySystem
{
[Dependency] private readonly SharedEyeSystem _eye = default!;
public override void Initialize()
{
base.Initialize();
SubscribeAllEvent<EyeOffsetChangedEvent>(OnEyeOffsetChanged);
SubscribeLocalEvent<TelescopeComponent, GotUnequippedHandEvent>(OnUnequip);
SubscribeLocalEvent<TelescopeComponent, HandDeselectedEvent>(OnHandDeselected);
SubscribeLocalEvent<TelescopeComponent, ComponentShutdown>(OnShutdown);
}
private void OnShutdown(Entity<TelescopeComponent> ent, ref ComponentShutdown args)
{
if (!TryComp(ent.Comp.LastEntity, out EyeComponent? eye)
|| ent.Comp.LastEntity == ent && TerminatingOrDeleted(ent))
return;
SetOffset((ent.Comp.LastEntity.Value, eye), Vector2.Zero, ent);
}
private void OnHandDeselected(Entity<TelescopeComponent> ent, ref HandDeselectedEvent args)
{
if (!TryComp(args.User, out EyeComponent? eye))
return;
SetOffset((args.User, eye), Vector2.Zero, ent);
}
private void OnUnequip(Entity<TelescopeComponent> ent, ref GotUnequippedHandEvent args)
{
if (!TryComp(args.User, out EyeComponent? eye)
|| !HasComp<ItemComponent>(ent.Owner))
return;
SetOffset((args.User, eye), Vector2.Zero, ent);
}
public TelescopeComponent? GetRightTelescope(EntityUid? ent)
{
TelescopeComponent? telescope = null;
if (TryComp<HandsComponent>(ent, out var hands)
&& hands.ActiveHandEntity.HasValue
&& TryComp<TelescopeComponent>(hands.ActiveHandEntity, out var handTelescope))
telescope = handTelescope;
else if (TryComp<TelescopeComponent>(ent, out var entityTelescope))
telescope = entityTelescope;
return telescope;
}
private void OnEyeOffsetChanged(EyeOffsetChangedEvent msg, EntitySessionEventArgs args)
{
if (args.SenderSession.AttachedEntity is not { } ent
|| !TryComp<EyeComponent>(ent, out var eye))
return;
var telescope = GetRightTelescope(ent);
if (telescope == null)
return;
var offset = Vector2.Lerp(eye.Offset, msg.Offset, telescope.LerpAmount);
SetOffset((ent, eye), offset, telescope);
}
private void SetOffset(Entity<EyeComponent> ent, Vector2 offset, TelescopeComponent telescope)
{
telescope.LastEntity = ent;
if (TryComp(ent, out CameraRecoilComponent? recoil))
{
recoil.BaseOffset = offset;
_eye.SetOffset(ent, offset + recoil.CurrentKick, ent);
}
else
{
_eye.SetOffset(ent, offset, ent);
}
}
public void SetParameters(Entity<TelescopeComponent> ent, float? divisor = null, float? lerpAmount = null)
{
var telescope = ent.Comp;
telescope.Divisor = divisor ?? telescope.Divisor;
telescope.LerpAmount = lerpAmount ?? telescope.LerpAmount;
Dirty(ent.Owner, telescope);
}
}
[Serializable, NetSerializable]
public sealed class EyeOffsetChangedEvent : EntityEventArgs
{
public Vector2 Offset;
}

View File

@@ -1,16 +0,0 @@
using Robust.Shared.GameStates;
namespace Content.Shared.Telescope;
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class TelescopeComponent : Component
{
[DataField, AutoNetworkedField]
public float Divisor = 0.1f;
[DataField, AutoNetworkedField]
public float LerpAmount = 0.1f;
[ViewVariables]
public EntityUid? LastEntity;
}

View File

@@ -6,7 +6,7 @@ namespace Content.Shared.Weapons.Melee.Components;
/// <summary>
/// Indicates that this meleeweapon requires wielding to be useable.
/// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(WieldableSystem))]
[RegisterComponent, NetworkedComponent, Access(typeof(SharedWieldableSystem))]
public sealed partial class MeleeRequiresWieldComponent : Component
{
// Lavaland Change: The player will slip if they try to use the weapon without wielding it.

View File

@@ -7,7 +7,7 @@ namespace Content.Shared.Weapons.Ranged.Components;
/// Indicates that this gun requires wielding to be useable.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
[Access(typeof(WieldableSystem))]
[Access(typeof(SharedWieldableSystem))]
public sealed partial class GunRequiresWieldComponent : Component
{
[DataField, AutoNetworkedField]

View File

@@ -6,7 +6,7 @@ namespace Content.Shared.Weapons.Ranged.Components;
/// <summary>
/// Applies an accuracy bonus upon wielding.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(WieldableSystem))]
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SharedWieldableSystem))]
public sealed partial class GunWieldBonusComponent : Component
{
[ViewVariables(VVAccess.ReadWrite), DataField("minAngle"), AutoNetworkedField]

View File

@@ -2,7 +2,7 @@ using Content.Shared.Damage;
namespace Content.Shared.Wieldable.Components;
[RegisterComponent, Access(typeof(WieldableSystem))]
[RegisterComponent, Access(typeof(SharedWieldableSystem))]
public sealed partial class IncreaseDamageOnWieldComponent : Component
{
[DataField("damage", required: true)]

View File

@@ -7,7 +7,7 @@ namespace Content.Shared.Wieldable.Components;
/// <summary>
/// Used for objects that can be wielded in two or more hands,
/// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(WieldableSystem)), AutoGenerateComponentState]
[RegisterComponent, NetworkedComponent, Access(typeof(SharedWieldableSystem)), AutoGenerateComponentState]
public sealed partial class WieldableComponent : Component
{
[DataField("wieldSound")]

View File

@@ -1,5 +1,5 @@
using System.Linq;
using Content.Shared._White.Resomi.Abilities;
using Content.Shared.Camera;
using Content.Shared.Examine;
using Content.Shared.Hands;
using Content.Shared.Hands.Components;
@@ -8,6 +8,7 @@ using Content.Shared.IdentityManagement;
using Content.Shared.Interaction.Events;
using Content.Shared.Inventory.VirtualItem;
using Content.Shared.Item;
using Content.Shared.Movement.Components;
using Content.Shared.Popups;
using Content.Shared.StatusEffect;
using Content.Shared.Stunnable;
@@ -27,7 +28,7 @@ using Robust.Shared.Timing;
namespace Content.Shared.Wieldable;
public sealed class WieldableSystem : EntitySystem
public abstract class SharedWieldableSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly INetManager _netManager = default!;

View File

@@ -9,7 +9,7 @@ namespace Content.Shared._Goobstation.Weapons.FoldingWeapon;
public sealed class FoldingWeaponSystem : EntitySystem
{
[Dependency] private readonly WieldableSystem _wieldable = default!;
[Dependency] private readonly SharedWieldableSystem _wieldable = default!;
[Dependency] private readonly ClothingSystem _clothing = default!;
[Dependency] private readonly SharedItemSystem _item = default!;

View File

@@ -6,7 +6,7 @@ namespace Content.Shared._Goobstation.Weapons.Wielding;
public sealed class UnwieldOnShootSystem : EntitySystem
{
[Dependency] private readonly WieldableSystem _wieldable = default!;
[Dependency] private readonly SharedWieldableSystem _wieldable = default!;
public override void Initialize()
{

View File

@@ -0,0 +1,9 @@
using Robust.Shared.Configuration;
namespace Content.Shared._White.CCVar;
public sealed partial class WhiteCVars
{
public static readonly CVarDef<bool> ToggleLookUp =
CVarDef.Create("eye.toggle_look_up", false, CVar.CLIENT | CVar.ARCHIVE);
}

View File

@@ -0,0 +1,2 @@
ui-options-function-look-up = Look up/Take aim
ui-options-function-toggle-look-up = Hold down the key to aim

View File

@@ -297,6 +297,4 @@ cmd-options-desc = Opens options menu, optionally with a specific tab selected.
cmd-options-help = Usage: options [tab]
## Combat Options
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

View File

@@ -0,0 +1,2 @@
ui-options-function-look-up = Присмотреться/Прицелиться
ui-options-function-toggle-look-up = Удерживать клавишу для прицеливания

View File

@@ -308,12 +308,10 @@ ui-options-net-pvs-leave-tooltip =
привести к неправильным предугадываниям и другим проблемам.
## Toggle window console command
## Toggle window console command
cmd-options-desc = Открывает меню опций, опционально с конкретно выбранной вкладкой.
cmd-options-help = Использование: options [tab]
## Combat Options
## Combat Options
ui-options-function-look-up = Присмотреться/Прицелиться
ui-options-function-auto-get-up = Автоматически вставать при падении
ui-options-function-hold-look-up = Удерживать клавишу для прицеливания

View File

@@ -183,12 +183,15 @@
capacity: 5
proto: CartridgeAntiMateriel
- type: Gun
angleDecay: 1 # WWDP
bonusAngleDecay: 10 # WWDP
bonusAngleIncreaseTurn: 1 # wwdp
fireRate: 0.6
angleDecay: 1
bonusAngleDecay: 10
bonusAngleIncreaseTurn: 1
fireRate: 0.5
- type: Wieldable
- type: Telescope
- type: CursorOffsetRequiresWield
- type: EyeCursorOffset
maxOffset: 3
pvsIncrease: 0.3
- type: MagazineVisuals
magState: mag
steps: 1

View File

@@ -118,8 +118,7 @@
powerLoad: 5
- type: ExtensionCableReceiver
- type: Alerts
- type: Telescope
lerpAmount: 0.25
- type: EyeCursorOffset
- type: Silicon
entityType: enum.SiliconType.Player
batteryPowered: true

View File

@@ -561,9 +561,11 @@ binds:
- function: Hotbar9
type: State
key: Num9
# WD EDIT START
- function: LookUp
type: State
key: Space
# WD EDIT END
- function: MappingUnselect
type: State
key: MouseRight