diff --git a/Content.Client/Lathe/UI/LatheMenu.xaml.cs b/Content.Client/Lathe/UI/LatheMenu.xaml.cs
index d4f1f81c62d..1ad41fd7e5e 100644
--- a/Content.Client/Lathe/UI/LatheMenu.xaml.cs
+++ b/Content.Client/Lathe/UI/LatheMenu.xaml.cs
@@ -42,6 +42,11 @@ public sealed partial class LatheMenu : FancyWindow
public EntityUid Entity;
+ // LuaM-start
+ private readonly List<(string Id, RecipeControl Control)> _recipeControls = new();
+ private readonly List<(int Index, Label Label)> _queueRows = new();
+ // LuaM-end
+
public LatheMenu()
{
RobustXamlLoader.Load(this);
@@ -132,10 +137,25 @@ public void PopulateRecipes()
if (!int.TryParse(AmountLineEdit.Text, out var quantity) || quantity <= 0)
quantity = 1;
- var sortedRecipesToShow = recipesToShow.OrderBy(_lathe.GetRecipeName);
- RecipeList.Children.Clear();
+ var sortedRecipesToShow = recipesToShow.OrderBy(_lathe.GetRecipeName).ToList(); // LuaM: added ToList
_entityManager.TryGetComponent(Entity, out LatheComponent? lathe);
+ // LuaM-start
+ if (sortedRecipesToShow.Count == _recipeControls.Count &&
+ sortedRecipesToShow.Select(p => p.ID).SequenceEqual(_recipeControls.Select(c => c.Id)))
+ {
+ for (var i = 0; i < sortedRecipesToShow.Count; i++)
+ {
+ _recipeControls[i].Control.SetCanProduce(_lathe.CanProduce(Entity, sortedRecipesToShow[i], quantity, component: lathe));
+ }
+
+ return;
+ }
+
+ _recipeControls.Clear();
+ // LuaM-end
+ RecipeList.Children.Clear();
+
foreach (var prototype in sortedRecipesToShow)
{
var canProduce = _lathe.CanProduce(Entity, prototype, quantity, component: lathe);
@@ -148,6 +168,7 @@ public void PopulateRecipes()
RecipeQueueAction?.Invoke(s, amount);
};
RecipeList.AddChild(control);
+ _recipeControls.Add((prototype.ID, control)); // LuaM
}
}
@@ -243,6 +264,20 @@ public void UpdateCategories()
///
public void PopulateQueueList(List queue) // Frontier: LatheRecipePrototype b.Index).SequenceEqual(_queueRows.Select(r => r.Index)))
+ {
+ for (var i = 0; i < queue.Count; i++)
+ {
+ _queueRows[i].Label.Text = GetQueueLabelText(i + 1, queue[i]);
+ }
+
+ return;
+ }
+
+ _queueRows.Clear();
+ // LuaM-end
QueueList.DisposeAllChildren();
var idx = 1;
@@ -255,10 +290,8 @@ public void PopulateQueueList(List queue) // Frontier: LatheRe
queuedRecipeBox.AddChild(GetRecipeDisplayControl(batch.Recipe));
var queuedRecipeLabel = new Label();
- if (batch.ItemsRequested > 1)
- queuedRecipeLabel.Text = $"{idx}. {_lathe.GetRecipeName(batch.Recipe)} ({batch.ItemsPrinted}/{batch.ItemsRequested})";
- else
- queuedRecipeLabel.Text = $"{idx}. {_lathe.GetRecipeName(batch.Recipe)}";
+ queuedRecipeLabel.Text = GetQueueLabelText(idx, batch); // LuaM: inline text > GetQueueLabelText
+ _queueRows.Add((batch.Index, queuedRecipeLabel)); // LuaM
// End Frontier
queuedRecipeBox.AddChild(queuedRecipeLabel);
//
@@ -273,6 +306,16 @@ public void PopulateQueueList(List queue) // Frontier: LatheRe
}
}
+ // LuaM-start
+ private string GetQueueLabelText(int idx, LatheRecipeBatch batch)
+ {
+ if (batch.ItemsRequested > 1)
+ return $"{idx}. {_lathe.GetRecipeName(batch.Recipe)} ({batch.ItemsPrinted}/{batch.ItemsRequested})";
+
+ return $"{idx}. {_lathe.GetRecipeName(batch.Recipe)}";
+ }
+ // LuaM-end
+
public void SetQueueInfo(LatheRecipePrototype? recipe)
{
FabricatingContainer.Visible = recipe != null;
diff --git a/Content.Client/Lathe/UI/RecipeControl.xaml.cs b/Content.Client/Lathe/UI/RecipeControl.xaml.cs
index 4f438c8a8e5..756d213c7e9 100644
--- a/Content.Client/Lathe/UI/RecipeControl.xaml.cs
+++ b/Content.Client/Lathe/UI/RecipeControl.xaml.cs
@@ -27,6 +27,11 @@ public RecipeControl(LatheSystem latheSystem, LatheRecipePrototype recipe, Func<
};
}
+ public void SetCanProduce(bool canProduce) // LuaM
+ {
+ Button.Disabled = !canProduce;
+ }
+
private Control? SupplyTooltip(Control sender)
{
return new RecipeTooltip(TooltipTextSupplier());
diff --git a/Content.Client/_Mono/Movement/Systems/FocusToggleSystem.cs b/Content.Client/_Mono/Movement/Systems/FocusToggleSystem.cs
index 31b69badddd..ec81b1c3249 100644
--- a/Content.Client/_Mono/Movement/Systems/FocusToggleSystem.cs
+++ b/Content.Client/_Mono/Movement/Systems/FocusToggleSystem.cs
@@ -1,23 +1,125 @@
-using Content.Client.Movement.Components;
-using Content.Shared._Mono.Movement.Systems;
+using System.Numerics;
+using Content.Client.UserInterface.Controls;
+using Content.Shared.Camera;
+using Content.Shared.Input;
+using Content.Shared.Movement.Components;
+using Content.Shared.Shuttles.Components;
+using Robust.Client.Graphics;
+using Robust.Client.Input;
+using Robust.Client.Player;
+using Robust.Client.UserInterface;
+using Robust.Shared.Input.Binding;
+using Robust.Shared.Map;
+using Robust.Shared.Player;
namespace Content.Client._Mono.Movement.Systems;
-public sealed class FocusToggleSystem : SharedFocusToggleSystem
+public sealed class FocusToggleSystem : EntitySystem
{
- protected override bool HasCompEyeCursorOffset(EntityUid uid)
+ [Dependency] private IEyeManager _eyeManager = default!;
+ [Dependency] private IInputManager _inputManager = default!;
+ [Dependency] private IUserInterfaceManager _uiManager = default!;
+ [Dependency] private IPlayerManager _player = default!;
+
+ private const float MaxOffset = 3f;
+ private const float EdgeOffset = 0.9f;
+ private const float Sharpness = 8f;
+
+ private EntityUid? _owner;
+ private bool _active;
+ private Vector2 _target;
+ private Vector2 _current;
+
+ public override void Initialize()
{
- return HasComp(uid);
+ base.Initialize();
+
+ SubscribeLocalEvent(OnGetEyeOffset);
+
+ CommandBinds.Builder
+ .Bind(ContentKeyFunctions.ToggleFocus, InputCmdHandler.FromDelegate(OnToggleFocus))
+ .Register();
}
- protected override void AddCompEyeCursorOffset(EntityUid uid)
+ public override void Shutdown()
{
- EnsureComp(uid);
+ base.Shutdown();
+
+ CommandBinds.Unregister();
}
- protected override void RemCompEyeCursorOffset(EntityUid uid)
+ private void OnToggleFocus(ICommonSession? session)
{
- RemComp(uid);
+ if (session?.AttachedEntity is not { } uid || uid != _player.LocalEntity)
+ return;
+
+ if (TryComp(uid, out var pilot) && pilot.Console != null)
+ return;
+
+ _active = !_active;
}
-}
+ private void OnGetEyeOffset(Entity ent, ref GetEyeOffsetEvent args)
+ {
+ if (ent.Owner != _owner)
+ return;
+
+ args.Offset += _current;
+ }
+
+ public override void FrameUpdate(float frameTime)
+ {
+ base.FrameUpdate(frameTime);
+
+ var player = _player.LocalEntity;
+ if (player != _owner)
+ {
+ _owner = player;
+ _active = false;
+ _target = Vector2.Zero;
+ _current = Vector2.Zero;
+ }
+
+ if (player == null)
+ return;
+
+ if (_active && TryComp(player.Value, out var pilot) && pilot.Console != null)
+ _active = false;
+
+ if (!_active)
+ _target = Vector2.Zero;
+ else if (TryGetMouseOffset(out var offset))
+ _target = offset;
+
+ _current = Vector2.Lerp(_current, _target, 1f - MathF.Exp(-Sharpness * frameTime));
+ if (!_active && _current.LengthSquared() < 0.0001f)
+ _current = Vector2.Zero;
+ }
+
+ private bool TryGetMouseOffset(out Vector2 offset)
+ {
+ offset = Vector2.Zero;
+
+ var mousePos = _inputManager.MouseScreenPosition;
+ if (mousePos.Window == WindowId.Invalid)
+ return false;
+
+ if (_uiManager.ActiveScreen == null || !_uiManager.ActiveScreen.TryGetWidget(out var mainViewport))
+ return false;
+
+ var screenSize = mainViewport.Size;
+ var minValue = MathF.Min(screenSize.X / 2, screenSize.Y / 2) * EdgeOffset;
+ if (minValue <= 0f)
+ return false;
+
+ var normalized = new Vector2(-(mousePos.X - screenSize.X / 2) / minValue, (mousePos.Y - screenSize.Y / 2) / minValue);
+ var eyeRotation = _eyeManager.CurrentEye.Rotation;
+ offset = Vector2.Transform(normalized, Quaternion.CreateFromAxisAngle(-Vector3.UnitZ, (float) eyeRotation.Opposite().Theta));
+
+ offset *= MaxOffset;
+ if (offset.Length() > MaxOffset)
+ offset = offset.Normalized() * MaxOffset;
+
+ return true;
+ }
+}
diff --git a/Content.Client/_Mono/PersonalShield/PersonalShieldOverlay.cs b/Content.Client/_Mono/PersonalShield/PersonalShieldOverlay.cs
index a80c9413b2e..a4cfdd17b23 100644
--- a/Content.Client/_Mono/PersonalShield/PersonalShieldOverlay.cs
+++ b/Content.Client/_Mono/PersonalShield/PersonalShieldOverlay.cs
@@ -34,6 +34,7 @@ public PersonalShieldOverlay()
_inventory = _entManager.System();
var protoMan = IoCManager.Resolve();
_shader = protoMan.Index(ShaderId).InstanceUnique();
+ ZIndex = -2; // LuaM
}
protected override void Draw(in OverlayDrawArgs args)
diff --git a/Content.Server/Research/Systems/ResearchSystem.cs b/Content.Server/Research/Systems/ResearchSystem.cs
index b859f224a1a..ffbd608e245 100644
--- a/Content.Server/Research/Systems/ResearchSystem.cs
+++ b/Content.Server/Research/Systems/ResearchSystem.cs
@@ -103,15 +103,11 @@ public string[] GetNFServerNames(EntityUid gridUid)
{
var allServers = EntityQueryEnumerator();
var list = new List();
- var station = _station.GetOwningStation(gridUid);
- if (station is { } stationUid)
+ while (allServers.MoveNext(out var uid, out var comp)) // LuaM: station-only > IsSameResearchNetwork
{
- while (allServers.MoveNext(out var uid, out var comp))
- {
- if (_station.GetOwningStation(uid) == stationUid)
- list.Add(comp.ServerName);
- }
+ if (IsSameResearchNetwork(gridUid, uid))
+ list.Add(comp.ServerName);
}
var serverList = list.ToArray();
@@ -122,21 +118,27 @@ public int[] GetNFServerIds(EntityUid gridUid)
{
var allServers = EntityQueryEnumerator();
var list = new List();
- var station = _station.GetOwningStation(gridUid);
- if (station is { } stationUid)
+ while (allServers.MoveNext(out var uid, out var comp)) // LuaM: station-only > IsSameResearchNetwork
{
- while (allServers.MoveNext(out var uid, out var comp))
- {
- if (_station.GetOwningStation(uid) == stationUid)
- list.Add(comp.Id);
- }
+ if (IsSameResearchNetwork(gridUid, uid))
+ list.Add(comp.Id);
}
var serverList = list.ToArray();
return serverList;
}
+ // LuaM-start
+ private bool IsSameResearchNetwork(EntityUid client, EntityUid server)
+ {
+ if (_station.GetOwningStation(client) is { } station)
+ return _station.GetOwningStation(server) == station;
+
+ return Transform(client).GridUid is { } grid && Transform(server).GridUid == grid;
+ }
+ // LuaM-end
+
public override void Update(float frameTime)
{
var query = EntityQueryEnumerator();
diff --git a/Content.Server/_Mono/Movement/Systems/FocusToggleSystem.cs b/Content.Server/_Mono/Movement/Systems/FocusToggleSystem.cs
index 86ae74accff..e285407b6d8 100644
--- a/Content.Server/_Mono/Movement/Systems/FocusToggleSystem.cs
+++ b/Content.Server/_Mono/Movement/Systems/FocusToggleSystem.cs
@@ -1,23 +1,24 @@
-using Content.Server.Movement.Components;
-using Content.Shared._Mono.Movement.Systems;
-
-namespace Content.Server._Mono.Movement.Systems;
-
-public sealed class FocusToggleSystem : SharedFocusToggleSystem
-{
- protected override bool HasCompEyeCursorOffset(EntityUid uid)
- {
- return HasComp(uid);
- }
-
- protected override void AddCompEyeCursorOffset(EntityUid uid)
- {
- EnsureComp(uid);
- }
-
- protected override void RemCompEyeCursorOffset(EntityUid uid)
- {
- RemComp(uid);
- }
-}
-
+// LuaM-start: Закомменчено из-за ненадобности
+// using Content.Server.Movement.Components;
+// using Content.Shared._Mono.Movement.Systems;
+//
+// namespace Content.Server._Mono.Movement.Systems;
+//
+// public sealed class FocusToggleSystem : SharedFocusToggleSystem
+// {
+// protected override bool HasCompEyeCursorOffset(EntityUid uid)
+// {
+// return HasComp(uid);
+// }
+//
+// protected override void AddCompEyeCursorOffset(EntityUid uid)
+// {
+// EnsureComp(uid);
+// }
+//
+// protected override void RemCompEyeCursorOffset(EntityUid uid)
+// {
+// RemComp(uid);
+// }
+// }
+// LuaM-end
diff --git a/Content.Shared/NightVision/SharedNightVisionSystem.cs b/Content.Shared/NightVision/SharedNightVisionSystem.cs
index fff2ced3f00..5c08e64e372 100644
--- a/Content.Shared/NightVision/SharedNightVisionSystem.cs
+++ b/Content.Shared/NightVision/SharedNightVisionSystem.cs
@@ -54,8 +54,7 @@ private void OnCompUnequip(Entity ent, ref GotUnequippedEv
if (!ent.Comp.RelayOverlay)
return;
- ent.Comp.Enabled = false; // mono
- RefreshOverlay(ent);
+ SetEnabled((ent, ent.Comp), false, args.Equipee); // LuaM: Enabled = false, RefreshOverlay(ent) > SetEnabled
}
protected virtual void OnRefreshEquipmentHud(Entity ent, ref InventoryRelayedEvent args)
{
diff --git a/Content.Shared/Preferences/HumanoidCharacterProfile.cs b/Content.Shared/Preferences/HumanoidCharacterProfile.cs
index 74e0a2482eb..e77e1b91336 100644
--- a/Content.Shared/Preferences/HumanoidCharacterProfile.cs
+++ b/Content.Shared/Preferences/HumanoidCharacterProfile.cs
@@ -772,10 +772,18 @@ public List> GetValidTraits(IEnumerable();
var result = new List>();
- foreach (var trait in traits)
+ var ordered = new List(); // LuaM
+ foreach (var trait in traits) // LuaM
{
- if (!protoManager.TryIndex(trait, out var traitProto))
- continue;
+ if (protoManager.TryIndex(trait, out var indexed)) // LuaM
+ ordered.Add(indexed); // LuaM
+ }
+
+ ordered.Sort((a, b) => a.Cost != b.Cost ? a.Cost.CompareTo(b.Cost) : string.CompareOrdinal(a.ID, b.ID)); // LuaM
+
+ foreach (var traitProto in ordered) // LuaM: traits > ordered
+ {
+ ProtoId trait = traitProto.ID; // LuaM
// Always valid.
if (traitProto.Category == null)
diff --git a/Content.Shared/_Mono/Movement/Systems/SharedFocusToggleSystem.cs b/Content.Shared/_Mono/Movement/Systems/SharedFocusToggleSystem.cs
index b0845378b83..90b63fdbc08 100644
--- a/Content.Shared/_Mono/Movement/Systems/SharedFocusToggleSystem.cs
+++ b/Content.Shared/_Mono/Movement/Systems/SharedFocusToggleSystem.cs
@@ -1,59 +1,61 @@
-using Content.Shared.Input;
-using Content.Shared.Shuttles.Components;
-using Robust.Shared.Input.Binding;
-using Robust.Shared.Player;
-using Robust.Shared.Serialization;
-
-namespace Content.Shared._Mono.Movement.Systems;
-
-public abstract class SharedFocusToggleSystem : EntitySystem
-{
- public override void Initialize()
- {
- base.Initialize();
-
- CommandBinds.Builder
- .Bind(ContentKeyFunctions.ToggleFocus, InputCmdHandler.FromDelegate(ToggleEyeCursorOffset))
- .Register();
-
- SubscribeNetworkEvent(OnToggleEyeCursorOffset);
- }
-
- public override void Shutdown()
- {
- base.Shutdown();
-
- CommandBinds.Unregister();
- }
-
- private void ToggleEyeCursorOffset(ICommonSession? session)
- {
- if (session?.AttachedEntity == null)
- return;
-
- RaiseNetworkEvent(new ToggleEyeCursorOffsetEvent());
- }
-
- protected virtual void OnToggleEyeCursorOffset(ToggleEyeCursorOffsetEvent ev, EntitySessionEventArgs args)
- {
- if (!args.SenderSession.AttachedEntity.HasValue)
- return;
-
- var uid = args.SenderSession.AttachedEntity.Value;
-
- if (TryComp(uid, out var pilot) && pilot.Console != null)
- return;
-
- if (HasCompEyeCursorOffset(uid))
- RemCompEyeCursorOffset(uid);
- else
- AddCompEyeCursorOffset(uid);
- }
-
- protected abstract bool HasCompEyeCursorOffset(EntityUid uid);
- protected abstract void AddCompEyeCursorOffset(EntityUid uid);
- protected abstract void RemCompEyeCursorOffset(EntityUid uid);
-}
-
-[Serializable, NetSerializable]
-public sealed class ToggleEyeCursorOffsetEvent : EntityEventArgs;
+// LuaM-start: Закомменчено из-за ненадобности
+// using Content.Shared.Input;
+// using Content.Shared.Shuttles.Components;
+// using Robust.Shared.Input.Binding;
+// using Robust.Shared.Player;
+// using Robust.Shared.Serialization;
+//
+// namespace Content.Shared._Mono.Movement.Systems;
+//
+// public abstract class SharedFocusToggleSystem : EntitySystem
+// {
+// public override void Initialize()
+// {
+// base.Initialize();
+//
+// CommandBinds.Builder
+// .Bind(ContentKeyFunctions.ToggleFocus, InputCmdHandler.FromDelegate(ToggleEyeCursorOffset))
+// .Register();
+//
+// SubscribeNetworkEvent(OnToggleEyeCursorOffset);
+// }
+//
+// public override void Shutdown()
+// {
+// base.Shutdown();
+//
+// CommandBinds.Unregister();
+// }
+//
+// private void ToggleEyeCursorOffset(ICommonSession? session)
+// {
+// if (session?.AttachedEntity == null)
+// return;
+//
+// RaiseNetworkEvent(new ToggleEyeCursorOffsetEvent());
+// }
+//
+// protected virtual void OnToggleEyeCursorOffset(ToggleEyeCursorOffsetEvent ev, EntitySessionEventArgs args)
+// {
+// if (!args.SenderSession.AttachedEntity.HasValue)
+// return;
+//
+// var uid = args.SenderSession.AttachedEntity.Value;
+//
+// if (TryComp(uid, out var pilot) && pilot.Console != null)
+// return;
+//
+// if (HasCompEyeCursorOffset(uid))
+// RemCompEyeCursorOffset(uid);
+// else
+// AddCompEyeCursorOffset(uid);
+// }
+//
+// protected abstract bool HasCompEyeCursorOffset(EntityUid uid);
+// protected abstract void AddCompEyeCursorOffset(EntityUid uid);
+// protected abstract void RemCompEyeCursorOffset(EntityUid uid);
+// }
+//
+// [Serializable, NetSerializable]
+// public sealed class ToggleEyeCursorOffsetEvent : EntityEventArgs;
+// LuaM-end
diff --git a/Resources/Prototypes/_Mono/Entities/Clothing/Eyes/glasses.yml b/Resources/Prototypes/_Mono/Entities/Clothing/Eyes/glasses.yml
index 37f636b2e40..3416ba13b1b 100644
--- a/Resources/Prototypes/_Mono/Entities/Clothing/Eyes/glasses.yml
+++ b/Resources/Prototypes/_Mono/Entities/Clothing/Eyes/glasses.yml
@@ -172,4 +172,15 @@
- type: ThermalVision
isEquipment: true
color: "#FFFFFFFF"
- lightRadius: 45
+ lightRadius: 0 # LuaM: 45 > 0
+ drawOverlay: false # LuaM
+ - type: NightVision # LuaM
+ relayOverlay: true
+ goggleEffect: true
+ viewCircleRadius: 1000
+ viewCircleCount: 3
+ viewCircleSpacing: 280
+ action: ActionToggleNightVision
+ phosphorColor: "#337a98"
+ lightingColor: "#0EFFFFFF"
+ amplification: 1.0