Merge remote-tracking branch 'upstream/stable' into ed-311-03-2025-upstream-2
# Conflicts: # Content.Client/Administration/AdminNameOverlay.cs # Content.Client/Administration/UI/Bwoink/BwoinkControl.xaml # Content.Client/Guidebook/Controls/GuideReagentReaction.xaml # Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs # Content.Client/SubFloor/SubFloorHideSystem.cs # Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs # Content.Server/Antag/AntagSelectionSystem.cs # Content.Server/Cloning/CloningSystem.cs # Content.Server/GameTicking/Rules/Components/ParadoxCloneRuleComponent.cs # Content.Server/GameTicking/Rules/ParadoxCloneRuleSystem.cs # Content.Server/Roles/ParadoxCloneRoleComponent.cs # Content.Shared.Database/LogType.cs # Content.Shared/CCVar/CCVars.Interface.cs # Content.Shared/Cloning/CloningEvents.cs # Content.Shared/Cloning/CloningSettingsPrototype.cs # Content.Shared/Humanoid/NamingSystem.cs # Content.Shared/Humanoid/Prototypes/SpeciesPrototype.cs # Content.Shared/Light/Components/SunShadowCycleComponent.cs # Content.Shared/Storage/StorageComponent.cs # Resources/Changelog/Admin.yml # Resources/Changelog/Changelog.yml # Resources/Credits/GitHub.txt # Resources/Locale/en-US/paradox-clone/role.ftl # Resources/Maps/bagel.yml # Resources/Maps/loop.yml # Resources/Prototypes/Chemistry/mixing_types.yml # Resources/Prototypes/Datasets/Names/last.yml # Resources/Prototypes/Entities/Effects/puddle.yml # Resources/Prototypes/Entities/Mobs/Player/clone.yml # Resources/Prototypes/Entities/Mobs/Species/base.yml # Resources/Prototypes/Entities/Objects/Deliveries/deliveries_tables.yml # Resources/Prototypes/Entities/Objects/Devices/pda.yml # Resources/Prototypes/Entities/Objects/Tools/handheld_mass_scanner.yml # Resources/Prototypes/GameRules/events.yml # Resources/Prototypes/Maps/Pools/default.yml # Resources/Prototypes/Objectives/paradoxClone.yml # Resources/Prototypes/Reagents/Consumable/Drink/alcohol.yml # Resources/Textures/Clothing/Eyes/Glasses/jensen.rsi/equipped-EYES-arachnid.png
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Client.Administration.Systems;
|
||||
using Content.Client.Stylesheets;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Ghost;
|
||||
using Content.Shared.Mind;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.ResourceManagement;
|
||||
@@ -14,32 +17,54 @@ namespace Content.Client.Administration;
|
||||
|
||||
internal sealed class AdminNameOverlay : Overlay
|
||||
{
|
||||
[Dependency] private readonly IConfigurationManager _config = default!;
|
||||
|
||||
private readonly AdminSystem _system;
|
||||
private readonly IEntityManager _entityManager;
|
||||
private readonly IEyeManager _eyeManager;
|
||||
private readonly EntityLookupSystem _entityLookup;
|
||||
private readonly IUserInterfaceManager _userInterfaceManager;
|
||||
private readonly Font _font;
|
||||
private readonly Font _fontBold;
|
||||
private bool _overlayClassic;
|
||||
private bool _overlaySymbols;
|
||||
private bool _overlayPlaytime;
|
||||
private bool _overlayStartingJob;
|
||||
private float _ghostFadeDistance;
|
||||
private float _ghostHideDistance;
|
||||
private int _overlayStackMax;
|
||||
private float _overlayMergeDistance;
|
||||
|
||||
//TODO make this adjustable via GUI
|
||||
private readonly ProtoId<RoleTypePrototype>[] _filter =
|
||||
["SoloAntagonist", "TeamAntagonist", "SiliconAntagonist", "FreeAgent"];
|
||||
private readonly string _antagLabelClassic = Loc.GetString("admin-overlay-antag-classic");
|
||||
private readonly Color _antagColorClassic = Color.OrangeRed;
|
||||
|
||||
public AdminNameOverlay(AdminSystem system, IEntityManager entityManager, IEyeManager eyeManager, IResourceCache resourceCache, EntityLookupSystem entityLookup, IUserInterfaceManager userInterfaceManager)
|
||||
public AdminNameOverlay(
|
||||
AdminSystem system,
|
||||
IEntityManager entityManager,
|
||||
IEyeManager eyeManager,
|
||||
IResourceCache resourceCache,
|
||||
EntityLookupSystem entityLookup,
|
||||
IUserInterfaceManager userInterfaceManager,
|
||||
IConfigurationManager config)
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
_system = system;
|
||||
_entityManager = entityManager;
|
||||
_eyeManager = eyeManager;
|
||||
_entityLookup = entityLookup;
|
||||
_userInterfaceManager = userInterfaceManager;
|
||||
ZIndex = 200;
|
||||
_font = new VectorFont(resourceCache.GetResource<FontResource>("/Fonts/NotoSans/NotoSans-Regular.ttf"), 10);
|
||||
// Setting these to a specific ttf would break the antag symbols
|
||||
_font = resourceCache.NotoStack();
|
||||
_fontBold = resourceCache.NotoStack(variation: "Bold");
|
||||
|
||||
config.OnValueChanged(CCVars.AdminOverlayClassic, (show) => { _overlayClassic = show; }, true);
|
||||
config.OnValueChanged(CCVars.AdminOverlaySymbols, (show) => { _overlaySymbols = show; }, true);
|
||||
config.OnValueChanged(CCVars.AdminOverlayPlaytime, (show) => { _overlayPlaytime = show; }, true);
|
||||
config.OnValueChanged(CCVars.AdminOverlayStartingJob, (show) => { _overlayStartingJob = show; }, true);
|
||||
config.OnValueChanged(CCVars.AdminOverlayGhostHideDistance, (f) => { _ghostHideDistance = f; }, true);
|
||||
config.OnValueChanged(CCVars.AdminOverlayGhostFadeDistance, (f) => { _ghostFadeDistance = f; }, true);
|
||||
config.OnValueChanged(CCVars.AdminOverlayStackMax, (i) => { _overlayStackMax = i; }, true);
|
||||
config.OnValueChanged(CCVars.AdminOverlayMergeDistance, (f) => { _overlayMergeDistance = f; }, true);
|
||||
}
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.ScreenSpace;
|
||||
@@ -47,75 +72,147 @@ internal sealed class AdminNameOverlay : Overlay
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
{
|
||||
var viewport = args.WorldAABB;
|
||||
var colorDisconnected = Color.White;
|
||||
var uiScale = _userInterfaceManager.RootControl.UIScale;
|
||||
var lineoffset = new Vector2(0f, 14f) * uiScale;
|
||||
var drawnOverlays = new List<(Vector2,Vector2)>() ; // A saved list of the overlays already drawn
|
||||
|
||||
//TODO make this adjustable via GUI
|
||||
var classic = _config.GetCVar(CCVars.AdminOverlayClassic);
|
||||
var playTime = _config.GetCVar(CCVars.AdminOverlayPlaytime);
|
||||
var startingJob = _config.GetCVar(CCVars.AdminOverlayStartingJob);
|
||||
|
||||
foreach (var playerInfo in _system.PlayerList)
|
||||
// Get all player positions before drawing overlays, so they can be sorted before iteration
|
||||
var sortable = new List<(PlayerInfo, Box2, EntityUid, Vector2)>();
|
||||
foreach (var info in _system.PlayerList)
|
||||
{
|
||||
var entity = _entityManager.GetEntity(playerInfo.NetEntity);
|
||||
var entity = _entityManager.GetEntity(info.NetEntity);
|
||||
|
||||
// Otherwise the entity can not exist yet
|
||||
if (entity == null || !_entityManager.EntityExists(entity))
|
||||
{
|
||||
// If entity does not exist or is on a different map, skip
|
||||
if (entity == null
|
||||
|| !_entityManager.EntityExists(entity)
|
||||
|| _entityManager.GetComponent<TransformComponent>(entity.Value).MapID != args.MapId)
|
||||
continue;
|
||||
}
|
||||
|
||||
// if not on the same map, continue
|
||||
if (_entityManager.GetComponent<TransformComponent>(entity.Value).MapID != args.MapId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var aabb = _entityLookup.GetWorldAABB(entity.Value);
|
||||
|
||||
// if not on screen, continue
|
||||
// if not on screen, skip
|
||||
if (!aabb.Intersects(in viewport))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var uiScale = _userInterfaceManager.RootControl.UIScale;
|
||||
var lineoffset = new Vector2(0f, 14f) * uiScale;
|
||||
var screenCoordinates = _eyeManager.WorldToScreen(aabb.Center +
|
||||
new Angle(-_eyeManager.CurrentEye.Rotation).RotateVec(
|
||||
aabb.TopRight - aabb.Center)) + new Vector2(1f, 7f);
|
||||
// Get on-screen coordinates of player
|
||||
var screenCoordinates = _eyeManager.WorldToScreen(aabb.Center).Rounded();
|
||||
|
||||
sortable.Add((info, aabb, entity.Value, screenCoordinates));
|
||||
}
|
||||
|
||||
// Draw overlays for visible players, starting from the top of the screen
|
||||
foreach (var info in sortable.OrderBy(s => s.Item4.Y).ToList())
|
||||
{
|
||||
var playerInfo = info.Item1;
|
||||
var aabb = info.Item2;
|
||||
var entity = info.Item3;
|
||||
var screenCoordinatesCenter = info.Item4;
|
||||
//the center position is kept separately, for simpler position comparison later
|
||||
var centerOffset = new Vector2(28f, -18f) * uiScale;
|
||||
var screenCoordinates = screenCoordinatesCenter + centerOffset;
|
||||
var alpha = 1f;
|
||||
|
||||
//TODO make a smarter system where the starting offset can be modified by the predicted position and size of already-drawn overlays/stacks?
|
||||
var currentOffset = Vector2.Zero;
|
||||
|
||||
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, playerInfo.CharacterName, uiScale, playerInfo.Connected ? Color.Aquamarine : Color.White);
|
||||
// Ghosts near the cursor are made transparent/invisible
|
||||
// TODO would be "cheaper" if playerinfo already contained a ghost bool, this gets called every frame for every onscreen player!
|
||||
if (_entityManager.HasComponent<GhostComponent>(entity))
|
||||
{
|
||||
// We want the map positions here, so we don't have to worry about resolution and such shenanigans
|
||||
var mobPosition = aabb.Center;
|
||||
var mousePosition = _eyeManager
|
||||
.ScreenToMap(_userInterfaceManager.MousePositionScaled.Position * uiScale)
|
||||
.Position;
|
||||
var dist = Vector2.Distance(mobPosition, mousePosition);
|
||||
if (dist < _ghostHideDistance)
|
||||
continue;
|
||||
|
||||
alpha = Math.Clamp((dist - _ghostHideDistance) / (_ghostFadeDistance - _ghostHideDistance), 0f, 1f);
|
||||
colorDisconnected.A = alpha;
|
||||
}
|
||||
|
||||
// If the new overlay text block is within merge distance of any previous ones
|
||||
// merge them into a stack so they don't hide each other
|
||||
var stack = drawnOverlays.FindAll(x =>
|
||||
Vector2.Distance(_eyeManager.ScreenToMap(x.Item1).Position, aabb.Center) <= _overlayMergeDistance);
|
||||
if (stack.Count > 0)
|
||||
{
|
||||
screenCoordinates = stack.First().Item1 + centerOffset;
|
||||
// Replacing this overlay's coordinates for the later save with the stack root's coordinates
|
||||
// so that other overlays don't try to stack to these coordinates
|
||||
screenCoordinatesCenter = stack.First().Item1;
|
||||
|
||||
var i = 1;
|
||||
foreach (var s in stack)
|
||||
{
|
||||
// additional entries after maximum stack size is reached will be drawn over the last entry
|
||||
if (i <= _overlayStackMax - 1)
|
||||
currentOffset = lineoffset + s.Item2 ;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// Character name
|
||||
var color = Color.Aquamarine;
|
||||
color.A = alpha;
|
||||
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, playerInfo.CharacterName, uiScale, playerInfo.Connected ? color : colorDisconnected);
|
||||
currentOffset += lineoffset;
|
||||
|
||||
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, playerInfo.Username, uiScale, playerInfo.Connected ? Color.Yellow : Color.White);
|
||||
// Username
|
||||
color = Color.Yellow;
|
||||
color.A = alpha;
|
||||
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, playerInfo.Username, uiScale, playerInfo.Connected ? color : colorDisconnected);
|
||||
currentOffset += lineoffset;
|
||||
|
||||
if (!string.IsNullOrEmpty(playerInfo.PlaytimeString) && playTime)
|
||||
// Playtime
|
||||
if (!string.IsNullOrEmpty(playerInfo.PlaytimeString) && _overlayPlaytime)
|
||||
{
|
||||
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, playerInfo.PlaytimeString, uiScale, playerInfo.Connected ? Color.Orange : Color.White);
|
||||
color = Color.Orange;
|
||||
color.A = alpha;
|
||||
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, playerInfo.PlaytimeString, uiScale, playerInfo.Connected ? color : colorDisconnected);
|
||||
currentOffset += lineoffset;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(playerInfo.StartingJob) && startingJob)
|
||||
// Job
|
||||
if (!string.IsNullOrEmpty(playerInfo.StartingJob) && _overlayStartingJob)
|
||||
{
|
||||
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, Loc.GetString(playerInfo.StartingJob), uiScale, playerInfo.Connected ? Color.GreenYellow : Color.White);
|
||||
color = Color.GreenYellow;
|
||||
color.A = alpha;
|
||||
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, Loc.GetString(playerInfo.StartingJob), uiScale, playerInfo.Connected ? color : colorDisconnected);
|
||||
currentOffset += lineoffset;
|
||||
}
|
||||
|
||||
if (classic && playerInfo.Antag)
|
||||
// Classic Antag Label
|
||||
if (_overlayClassic && playerInfo.Antag)
|
||||
{
|
||||
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, _antagLabelClassic, uiScale, Color.OrangeRed);
|
||||
var symbol = _overlaySymbols ? Loc.GetString("player-tab-antag-prefix") : string.Empty;
|
||||
var label = _overlaySymbols
|
||||
? Loc.GetString("player-tab-character-name-antag-symbol",
|
||||
("symbol", symbol),
|
||||
("name", _antagLabelClassic))
|
||||
: _antagLabelClassic;
|
||||
color = Color.OrangeRed;
|
||||
color.A = alpha;
|
||||
args.ScreenHandle.DrawString(_fontBold, screenCoordinates + currentOffset, label, uiScale, color);
|
||||
currentOffset += lineoffset;
|
||||
}
|
||||
else if (!classic && _filter.Contains(playerInfo.RoleProto))
|
||||
// Role Type
|
||||
else if (!_overlayClassic && _filter.Contains(playerInfo.RoleProto))
|
||||
{
|
||||
var label = Loc.GetString(playerInfo.RoleProto.Name).ToUpper();
|
||||
var color = playerInfo.RoleProto.Color;
|
||||
var symbol = _overlaySymbols && playerInfo.Antag ? playerInfo.RoleProto.Symbol : string.Empty;
|
||||
var role = Loc.GetString(playerInfo.RoleProto.Name).ToUpper();
|
||||
var label = _overlaySymbols
|
||||
? Loc.GetString("player-tab-character-name-antag-symbol", ("symbol", symbol), ("name", role))
|
||||
: role;
|
||||
color = playerInfo.RoleProto.Color;
|
||||
color.A = alpha;
|
||||
args.ScreenHandle.DrawString(_fontBold, screenCoordinates + currentOffset, label, uiScale, color);
|
||||
currentOffset += lineoffset;
|
||||
}
|
||||
|
||||
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, label, uiScale, color);
|
||||
currentOffset += lineoffset;
|
||||
}
|
||||
//Save the coordinates and size of the text block, for stack merge check
|
||||
drawnOverlays.Add((screenCoordinatesCenter, currentOffset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Content.Client.Administration.Systems
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _entityLookup = default!;
|
||||
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
|
||||
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
||||
|
||||
private AdminNameOverlay _adminNameOverlay = default!;
|
||||
|
||||
@@ -22,7 +23,14 @@ namespace Content.Client.Administration.Systems
|
||||
|
||||
private void InitializeOverlay()
|
||||
{
|
||||
_adminNameOverlay = new AdminNameOverlay(this, EntityManager, _eyeManager, _resourceCache, _entityLookup, _userInterfaceManager);
|
||||
_adminNameOverlay = new AdminNameOverlay(
|
||||
this,
|
||||
EntityManager,
|
||||
_eyeManager,
|
||||
_resourceCache,
|
||||
_entityLookup,
|
||||
_userInterfaceManager,
|
||||
_configurationManager);
|
||||
_adminManager.AdminStatusUpdated += OnAdminStatusUpdated;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls">
|
||||
<PanelContainer StyleClasses="BackgroundDark">
|
||||
<SplitContainer Orientation="Vertical">
|
||||
<SplitContainer Orientation="Vertical" ResizeMode="NotResizable">
|
||||
<SplitContainer Orientation="Horizontal" VerticalExpand="True">
|
||||
<cc:PlayerListControl Access="Public" Name="ChannelSelector" HorizontalExpand="True" SizeFlagsStretchRatio="2" />
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" SizeFlagsStretchRatio="2">
|
||||
<BoxContainer Access="Public" Name="BwoinkArea" VerticalExpand="True" />
|
||||
</BoxContainer>
|
||||
</SplitContainer>
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||
<BoxContainer Orientation="Horizontal" SetHeight="30" >
|
||||
<CheckBox Name="AdminOnly" Access="Public" Text="{Loc 'admin-ahelp-admin-only'}" ToolTip="{Loc 'admin-ahelp-admin-only-tooltip'}" />
|
||||
<Control HorizontalExpand="True" MinWidth="5" />
|
||||
<CheckBox Name="PlaySound" Access="Public" Text="{Loc 'admin-bwoink-play-sound'}" Pressed="True" />
|
||||
|
||||
@@ -2,11 +2,13 @@ using System.Linq;
|
||||
using Content.Client.Administration.Systems;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.CCVar;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Configuration;
|
||||
using static Content.Client.Administration.UI.Tabs.PlayerTab.PlayerTabHeader;
|
||||
using static Robust.Client.UserInterface.Controls.BaseButton;
|
||||
|
||||
@@ -16,6 +18,7 @@ namespace Content.Client.Administration.UI.Tabs.PlayerTab;
|
||||
public sealed partial class PlayerTab : Control
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
[Dependency] private readonly IConfigurationManager _config = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerMan = default!;
|
||||
|
||||
private const string ArrowUp = "↑";
|
||||
@@ -41,6 +44,10 @@ public sealed partial class PlayerTab : Control
|
||||
_adminSystem.OverlayEnabled += OverlayEnabled;
|
||||
_adminSystem.OverlayDisabled += OverlayDisabled;
|
||||
|
||||
_config.OnValueChanged(CCVars.AdminPlayerlistSeparateSymbols, PlayerListSettingsChanged);
|
||||
_config.OnValueChanged(CCVars.AdminPlayerlistHighlightedCharacterColor, PlayerListSettingsChanged);
|
||||
_config.OnValueChanged(CCVars.AdminPlayerlistRoleTypeColor, PlayerListSettingsChanged);
|
||||
|
||||
OverlayButton.OnPressed += OverlayButtonPressed;
|
||||
ShowDisconnectedButton.OnPressed += ShowDisconnectedPressed;
|
||||
|
||||
@@ -106,6 +113,11 @@ public sealed partial class PlayerTab : Control
|
||||
|
||||
#region ListContainer
|
||||
|
||||
private void PlayerListSettingsChanged(bool _)
|
||||
{
|
||||
RefreshPlayerList(_adminSystem.PlayerList);
|
||||
}
|
||||
|
||||
private void RefreshPlayerList(IReadOnlyList<PlayerInfo> players)
|
||||
{
|
||||
_players = players;
|
||||
@@ -196,8 +208,7 @@ public sealed partial class PlayerTab : Control
|
||||
Header.Username => Compare(x.Username, y.Username),
|
||||
Header.Character => Compare(x.CharacterName, y.CharacterName),
|
||||
Header.Job => Compare(x.StartingJob, y.StartingJob),
|
||||
Header.Antagonist => x.Antag.CompareTo(y.Antag),
|
||||
Header.RoleType => Compare(x.RoleProto.Name , y.RoleProto.Name),
|
||||
Header.RoleType => y.SortWeight - x.SortWeight,
|
||||
Header.Playtime => TimeSpan.Compare(x.OverallPlaytime ?? default, y.OverallPlaytime ?? default),
|
||||
_ => 1
|
||||
};
|
||||
|
||||
@@ -19,11 +19,6 @@
|
||||
HorizontalExpand="True"
|
||||
ClipText="True"/>
|
||||
<customControls:VSeparator/>
|
||||
<Label Name="AntagonistLabel"
|
||||
SizeFlagsStretchRatio="1"
|
||||
HorizontalExpand="True"
|
||||
ClipText="True"/>
|
||||
<customControls:VSeparator/>
|
||||
<Label Name="RoleTypeLabel"
|
||||
SizeFlagsStretchRatio="2"
|
||||
HorizontalExpand="True"
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.CCVar;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Configuration;
|
||||
|
||||
namespace Content.Client.Administration.UI.Tabs.PlayerTab;
|
||||
|
||||
@@ -14,17 +16,25 @@ public sealed partial class PlayerTabEntry : PanelContainer
|
||||
public PlayerTabEntry(PlayerInfo player, StyleBoxFlat styleBoxFlat)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
var config = IoCManager.Resolve<IConfigurationManager>();
|
||||
|
||||
UsernameLabel.Text = player.Username;
|
||||
if (!player.Connected)
|
||||
UsernameLabel.StyleClasses.Add("Disabled");
|
||||
JobLabel.Text = player.StartingJob;
|
||||
CharacterLabel.Text = player.CharacterName;
|
||||
var separateAntagSymbols = config.GetCVar(CCVars.AdminPlayerlistSeparateSymbols);
|
||||
var genericAntagSymbol = player.Antag ? Loc.GetString("player-tab-antag-prefix") : string.Empty;
|
||||
var roleSymbol = player.Antag ? player.RoleProto.Symbol : string.Empty;
|
||||
var symbol = separateAntagSymbols ? roleSymbol : genericAntagSymbol;
|
||||
CharacterLabel.Text = Loc.GetString("player-tab-character-name-antag-symbol", ("symbol", symbol), ("name", player.CharacterName));
|
||||
|
||||
if (player.Antag && config.GetCVar(CCVars.AdminPlayerlistHighlightedCharacterColor))
|
||||
CharacterLabel.FontColorOverride = player.RoleProto.Color;
|
||||
if (player.IdentityName != player.CharacterName)
|
||||
CharacterLabel.Text += $" [{player.IdentityName}]";
|
||||
AntagonistLabel.Text = Loc.GetString(player.Antag ? "player-tab-is-antag-yes" : "player-tab-is-antag-no");
|
||||
RoleTypeLabel.Text = Loc.GetString(player.RoleProto.Name);
|
||||
RoleTypeLabel.FontColorOverride = player.RoleProto.Color;
|
||||
if (config.GetCVar(CCVars.AdminPlayerlistRoleTypeColor))
|
||||
RoleTypeLabel.FontColorOverride = player.RoleProto.Color;
|
||||
BackgroundColorPanel.PanelOverride = styleBoxFlat;
|
||||
OverallPlaytimeLabel.Text = player.PlaytimeString;
|
||||
PlayerEntity = player.NetEntity;
|
||||
|
||||
@@ -25,13 +25,6 @@
|
||||
Text="{Loc player-tab-job}"
|
||||
MouseFilter="Pass"/>
|
||||
<cc:VSeparator/>
|
||||
<Label Name="AntagonistLabel"
|
||||
SizeFlagsStretchRatio="1"
|
||||
HorizontalExpand="True"
|
||||
ClipText="True"
|
||||
Text="{Loc player-tab-antagonist}"
|
||||
MouseFilter="Pass"/>
|
||||
<cc:VSeparator/>
|
||||
<Label Name="RoleTypeLabel"
|
||||
SizeFlagsStretchRatio="2"
|
||||
HorizontalExpand="True"
|
||||
|
||||
@@ -18,7 +18,6 @@ public sealed partial class PlayerTabHeader : Control
|
||||
UsernameLabel.OnKeyBindDown += UsernameClicked;
|
||||
CharacterLabel.OnKeyBindDown += CharacterClicked;
|
||||
JobLabel.OnKeyBindDown += JobClicked;
|
||||
AntagonistLabel.OnKeyBindDown += AntagonistClicked;
|
||||
RoleTypeLabel.OnKeyBindDown += RoleTypeClicked;
|
||||
PlaytimeLabel.OnKeyBindDown += PlaytimeClicked;
|
||||
}
|
||||
@@ -30,7 +29,6 @@ public sealed partial class PlayerTabHeader : Control
|
||||
Header.Username => UsernameLabel,
|
||||
Header.Character => CharacterLabel,
|
||||
Header.Job => JobLabel,
|
||||
Header.Antagonist => AntagonistLabel,
|
||||
Header.RoleType => RoleTypeLabel,
|
||||
Header.Playtime => PlaytimeLabel,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(header), header, null)
|
||||
@@ -42,7 +40,6 @@ public sealed partial class PlayerTabHeader : Control
|
||||
UsernameLabel.Text = Loc.GetString("player-tab-username");
|
||||
CharacterLabel.Text = Loc.GetString("player-tab-character");
|
||||
JobLabel.Text = Loc.GetString("player-tab-job");
|
||||
AntagonistLabel.Text = Loc.GetString("player-tab-antagonist");
|
||||
RoleTypeLabel.Text = Loc.GetString("player-tab-roletype");
|
||||
PlaytimeLabel.Text = Loc.GetString("player-tab-playtime");
|
||||
}
|
||||
@@ -73,11 +70,6 @@ public sealed partial class PlayerTabHeader : Control
|
||||
HeaderClicked(args, Header.Job);
|
||||
}
|
||||
|
||||
private void AntagonistClicked(GUIBoundKeyEventArgs args)
|
||||
{
|
||||
HeaderClicked(args, Header.Antagonist);
|
||||
}
|
||||
|
||||
private void RoleTypeClicked(GUIBoundKeyEventArgs args)
|
||||
{
|
||||
HeaderClicked(args, Header.RoleType);
|
||||
@@ -97,7 +89,6 @@ public sealed partial class PlayerTabHeader : Control
|
||||
UsernameLabel.OnKeyBindDown -= UsernameClicked;
|
||||
CharacterLabel.OnKeyBindDown -= CharacterClicked;
|
||||
JobLabel.OnKeyBindDown -= JobClicked;
|
||||
AntagonistLabel.OnKeyBindDown -= AntagonistClicked;
|
||||
RoleTypeLabel.OnKeyBindDown -= RoleTypeClicked;
|
||||
PlaytimeLabel.OnKeyBindDown -= PlaytimeClicked;
|
||||
}
|
||||
@@ -108,7 +99,6 @@ public sealed partial class PlayerTabHeader : Control
|
||||
Username,
|
||||
Character,
|
||||
Job,
|
||||
Antagonist,
|
||||
RoleType,
|
||||
Playtime
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public sealed class ClientAlertsSystem : AlertsSystem
|
||||
if (args.Current is not AlertComponentState cast)
|
||||
return;
|
||||
|
||||
alerts.Comp.Alerts = cast.Alerts;
|
||||
alerts.Comp.Alerts = new(cast.Alerts);
|
||||
|
||||
UpdateHud(alerts);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
using Content.Shared.CartridgeLoader.Cartridges;
|
||||
|
||||
namespace Content.Client.CartridgeLoader.Cartridges;
|
||||
|
||||
public sealed class NanoTaskCartridgeSystem : SharedNanoTaskCartridgeSystem;
|
||||
@@ -0,0 +1,32 @@
|
||||
<Control xmlns="https://spacestation14.io" xmlns:system="clr-namespace:System;assembly=System.Runtime">
|
||||
<BoxContainer Name="MainContainer"
|
||||
Orientation="Horizontal"
|
||||
SetWidth="250">
|
||||
<Button Name="MainButton"
|
||||
HorizontalExpand="True"
|
||||
VerticalExpand="True"
|
||||
StyleClasses="ButtonSquare"
|
||||
Margin="-1 0 0 0">
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||
<BoxContainer Orientation="Vertical"
|
||||
VerticalExpand="True"
|
||||
HorizontalExpand="True"
|
||||
Margin="-5 0 0 0">
|
||||
<Label Name="TaskLabel"
|
||||
StyleClasses="LabelSubText" />
|
||||
<Label Name="TaskForLabel"
|
||||
StyleClasses="LabelSubText"
|
||||
Margin="0 -5 0 0" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</Button>
|
||||
<Button Name="DoneButton"
|
||||
VerticalExpand="True"
|
||||
Text="{Loc 'nano-task-ui-done'}">
|
||||
<Button.StyleClasses>
|
||||
<system:String>ButtonSmall</system:String>
|
||||
<system:String>OpenLeft</system:String>
|
||||
</Button.StyleClasses>
|
||||
</Button>
|
||||
</BoxContainer>
|
||||
</Control>
|
||||
@@ -0,0 +1,33 @@
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Maths;
|
||||
using Content.Shared.CartridgeLoader.Cartridges;
|
||||
|
||||
namespace Content.Client.CartridgeLoader.Cartridges;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a single control for a single NanoTask item
|
||||
/// </summary>
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class NanoTaskItemControl : Control
|
||||
{
|
||||
public Action<int>? OnMainPressed;
|
||||
public Action<int>? OnDonePressed;
|
||||
|
||||
public NanoTaskItemControl(NanoTaskItemAndId item)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
TaskLabel.Text = item.Data.Description;
|
||||
TaskLabel.FontColorOverride = Color.White;
|
||||
TaskForLabel.Text = item.Data.TaskIsFor;
|
||||
|
||||
MainButton.OnPressed += _ => OnMainPressed?.Invoke(item.Id);
|
||||
DoneButton.OnPressed += _ => OnDonePressed?.Invoke(item.Id);
|
||||
|
||||
MainButton.Disabled = item.Data.IsTaskDone;
|
||||
DoneButton.Text = item.Data.IsTaskDone ? Loc.GetString("nano-task-ui-revert-done") : Loc.GetString("nano-task-ui-done");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<DefaultWindow xmlns="https://spacestation14.io"
|
||||
Title="{Loc nano-task-ui-item-title}"
|
||||
MinSize="300 300">
|
||||
<PanelContainer StyleClasses="AngleRect">
|
||||
<BoxContainer Orientation="Vertical" Margin="4">
|
||||
<!-- Task Description Input -->
|
||||
<BoxContainer Orientation="Vertical" Margin="0 4">
|
||||
<Label Text="{Loc nano-task-ui-description-label}"
|
||||
StyleClasses="LabelHeading" />
|
||||
<PanelContainer StyleClasses="ButtonSquare">
|
||||
<LineEdit Name="DescriptionInput"
|
||||
PlaceHolder="{Loc nano-task-ui-description-placeholder}" />
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
|
||||
<!-- Task Requester Input -->
|
||||
<BoxContainer Orientation="Vertical" Margin="0 4">
|
||||
<Label Text="{Loc nano-task-ui-requester-label}"
|
||||
StyleClasses="LabelHeading" />
|
||||
<PanelContainer StyleClasses="ButtonSquare">
|
||||
<LineEdit Name="RequesterInput"
|
||||
PlaceHolder="{Loc nano-task-ui-requester-placeholder}" />
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
|
||||
<!-- Severity Buttons -->
|
||||
<BoxContainer Orientation="Horizontal"
|
||||
HorizontalAlignment="Center"
|
||||
Margin="0 8 0 0">
|
||||
<Button Name="LowButton"
|
||||
Text="{Loc nano-task-ui-priority-low}"
|
||||
StyleClasses="OpenRight"
|
||||
MinSize="60 0" />
|
||||
<Button Name="MediumButton"
|
||||
Text="{Loc nano-task-ui-priority-medium}"
|
||||
StyleClasses="ButtonSquare"
|
||||
MinSize="60 0" />
|
||||
<Button Name="HighButton"
|
||||
Text="{Loc nano-task-ui-priority-high}"
|
||||
StyleClasses="OpenLeft"
|
||||
MinSize="60 0" />
|
||||
</BoxContainer>
|
||||
|
||||
<!-- Verb Buttons -->
|
||||
<BoxContainer Orientation="Horizontal"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0 8 0 0">
|
||||
<Button Name="CancelButton"
|
||||
Text="{Loc nano-task-ui-cancel}"
|
||||
StyleClasses="OpenRight"
|
||||
MinSize="60 0" />
|
||||
<Button Name="DeleteButton"
|
||||
Text="{Loc nano-task-ui-delete}"
|
||||
StyleClasses="ButtonSquare"
|
||||
MinSize="60 0" />
|
||||
<Button Name="PrintButton"
|
||||
Text="{Loc nano-task-ui-print}"
|
||||
StyleClasses="ButtonSquare"
|
||||
MinSize="60 0" />
|
||||
<Button Name="SaveButton"
|
||||
Text="{Loc nano-task-ui-save}"
|
||||
StyleClasses="OpenLeft"
|
||||
MinSize="60 0" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</DefaultWindow>
|
||||
@@ -0,0 +1,109 @@
|
||||
using System.Linq;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Content.Shared.CartridgeLoader.Cartridges;
|
||||
|
||||
namespace Content.Client.CartridgeLoader.Cartridges;
|
||||
|
||||
/// <summary>
|
||||
/// Popup displayed to edit a NanoTask item
|
||||
/// </summary>
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class NanoTaskItemPopup : DefaultWindow
|
||||
{
|
||||
private readonly ButtonGroup _priorityGroup = new();
|
||||
private int? _editingTaskId = null;
|
||||
|
||||
public Action<int, NanoTaskItem>? TaskSaved;
|
||||
public Action<int>? TaskDeleted;
|
||||
public Action<NanoTaskItem>? TaskCreated;
|
||||
public Action<NanoTaskItem>? TaskPrinted;
|
||||
|
||||
private NanoTaskItem MakeItem()
|
||||
{
|
||||
return new(
|
||||
description: DescriptionInput.Text,
|
||||
taskIsFor: RequesterInput.Text,
|
||||
isTaskDone: false,
|
||||
priority: _priorityGroup.Pressed switch {
|
||||
var item when item == LowButton => NanoTaskPriority.Low,
|
||||
var item when item == MediumButton => NanoTaskPriority.Medium,
|
||||
var item when item == HighButton => NanoTaskPriority.High,
|
||||
_ => NanoTaskPriority.Medium,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public NanoTaskItemPopup()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
LowButton.Group = _priorityGroup;
|
||||
MediumButton.Group = _priorityGroup;
|
||||
HighButton.Group = _priorityGroup;
|
||||
|
||||
CancelButton.OnPressed += _ => Close();
|
||||
DeleteButton.OnPressed += _ =>
|
||||
{
|
||||
if (_editingTaskId is int id)
|
||||
{
|
||||
TaskDeleted?.Invoke(id);
|
||||
}
|
||||
};
|
||||
PrintButton.OnPressed += _ =>
|
||||
{
|
||||
TaskPrinted?.Invoke(MakeItem());
|
||||
};
|
||||
SaveButton.OnPressed += _ =>
|
||||
{
|
||||
if (_editingTaskId is int id)
|
||||
{
|
||||
TaskSaved?.Invoke(id, MakeItem());
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskCreated?.Invoke(MakeItem());
|
||||
}
|
||||
};
|
||||
|
||||
DescriptionInput.OnTextChanged += args =>
|
||||
{
|
||||
if (args.Text.Length > NanoTaskItem.MaximumStringLength)
|
||||
DescriptionInput.Text = args.Text[..NanoTaskItem.MaximumStringLength];
|
||||
};
|
||||
RequesterInput.OnTextChanged += args =>
|
||||
{
|
||||
if (args.Text.Length > NanoTaskItem.MaximumStringLength)
|
||||
RequesterInput.Text = args.Text[..NanoTaskItem.MaximumStringLength];
|
||||
};
|
||||
}
|
||||
|
||||
public void SetEditingTaskId(int? id)
|
||||
{
|
||||
_editingTaskId = id;
|
||||
DeleteButton.Visible = id is not null;
|
||||
}
|
||||
|
||||
public void ResetInputs(NanoTaskItem? item)
|
||||
{
|
||||
if (item is NanoTaskItem task)
|
||||
{
|
||||
var button = task.Priority switch {
|
||||
NanoTaskPriority.High => HighButton,
|
||||
NanoTaskPriority.Medium => MediumButton,
|
||||
NanoTaskPriority.Low => LowButton,
|
||||
};
|
||||
button.Pressed = true;
|
||||
DescriptionInput.Text = task.Description;
|
||||
RequesterInput.Text = task.TaskIsFor;
|
||||
}
|
||||
else
|
||||
{
|
||||
MediumButton.Pressed = true;
|
||||
DescriptionInput.Text = "";
|
||||
RequesterInput.Text = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
82
Content.Client/CartridgeLoader/Cartridges/NanoTaskUi.cs
Normal file
82
Content.Client/CartridgeLoader/Cartridges/NanoTaskUi.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using System.Linq;
|
||||
using Content.Client.UserInterface.Fragments;
|
||||
using Content.Shared.CartridgeLoader;
|
||||
using Content.Shared.CartridgeLoader.Cartridges;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
namespace Content.Client.CartridgeLoader.Cartridges;
|
||||
|
||||
/// <summary>
|
||||
/// UI fragment responsible for displaying NanoTask controls in a PDA and coordinating with the NanoTaskCartridgeSystem for state
|
||||
/// </summary>
|
||||
public sealed partial class NanoTaskUi : UIFragment
|
||||
{
|
||||
private NanoTaskUiFragment? _fragment;
|
||||
private NanoTaskItemPopup? _popup;
|
||||
|
||||
public override Control GetUIFragmentRoot()
|
||||
{
|
||||
return _fragment!;
|
||||
}
|
||||
|
||||
public override void Setup(BoundUserInterface userInterface, EntityUid? fragmentOwner)
|
||||
{
|
||||
_fragment = new NanoTaskUiFragment();
|
||||
_popup = new NanoTaskItemPopup();
|
||||
_fragment.NewTask += () =>
|
||||
{
|
||||
_popup.ResetInputs(null);
|
||||
_popup.SetEditingTaskId(null);
|
||||
_popup.OpenCentered();
|
||||
};
|
||||
_fragment.OpenTask += id =>
|
||||
{
|
||||
if (_fragment.Tasks.Find(task => task.Id == id) is not NanoTaskItemAndId task)
|
||||
return;
|
||||
|
||||
_popup.ResetInputs(task.Data);
|
||||
_popup.SetEditingTaskId(task.Id);
|
||||
_popup.OpenCentered();
|
||||
};
|
||||
_fragment.ToggleTaskCompletion += id =>
|
||||
{
|
||||
if (_fragment.Tasks.Find(task => task.Id == id) is not NanoTaskItemAndId task)
|
||||
return;
|
||||
|
||||
userInterface.SendMessage(new CartridgeUiMessage(new NanoTaskUiMessageEvent(new NanoTaskUpdateTask(new(id, new(
|
||||
description: task.Data.Description,
|
||||
taskIsFor: task.Data.TaskIsFor,
|
||||
isTaskDone: !task.Data.IsTaskDone,
|
||||
priority: task.Data.Priority
|
||||
))))));
|
||||
};
|
||||
_popup.TaskSaved += (id, data) =>
|
||||
{
|
||||
userInterface.SendMessage(new CartridgeUiMessage(new NanoTaskUiMessageEvent(new NanoTaskUpdateTask(new(id, data)))));
|
||||
_popup.Close();
|
||||
};
|
||||
_popup.TaskDeleted += id =>
|
||||
{
|
||||
userInterface.SendMessage(new CartridgeUiMessage(new NanoTaskUiMessageEvent(new NanoTaskDeleteTask(id))));
|
||||
_popup.Close();
|
||||
};
|
||||
_popup.TaskCreated += data =>
|
||||
{
|
||||
userInterface.SendMessage(new CartridgeUiMessage(new NanoTaskUiMessageEvent(new NanoTaskAddTask(data))));
|
||||
_popup.Close();
|
||||
};
|
||||
_popup.TaskPrinted += data =>
|
||||
{
|
||||
userInterface.SendMessage(new CartridgeUiMessage(new NanoTaskUiMessageEvent(new NanoTaskPrintTask(data))));
|
||||
};
|
||||
}
|
||||
|
||||
public override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
if (state is not NanoTaskUiState nanoTaskState)
|
||||
return;
|
||||
|
||||
_fragment?.UpdateState(nanoTaskState.Tasks);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<cartridges:NanoTaskUiFragment xmlns:cartridges="clr-namespace:Content.Client.CartridgeLoader.Cartridges"
|
||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
xmlns="https://spacestation14.io" Margin="1 0 2 0">
|
||||
|
||||
<PanelContainer StyleClasses="BackgroundDark"></PanelContainer>
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
|
||||
<ScrollContainer HorizontalExpand="True" VerticalExpand="True">
|
||||
<BoxContainer HorizontalExpand="True" VerticalExpand="True" Orientation="Vertical" Margin="8" SeparationOverride="8">
|
||||
<!-- Heading for High Priority Items -->
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<PanelContainer SetWidth="7" Margin="0 0 8 0">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BackgroundColor="#e93d58"/>
|
||||
</PanelContainer.PanelOverride>
|
||||
</PanelContainer>
|
||||
<Label Name="HighPriority" StyleClasses="LabelHeading"/>
|
||||
</BoxContainer>
|
||||
<!-- Location for High Priority Items -->
|
||||
<GridContainer Name="HighContainer"
|
||||
HorizontalExpand="True"
|
||||
Access="Public"
|
||||
Columns="2" />
|
||||
|
||||
<!-- Heading for Medium Priority Items -->
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<PanelContainer SetWidth="7" Margin="0 0 8 0">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BackgroundColor="#ef973c"/>
|
||||
</PanelContainer.PanelOverride>
|
||||
</PanelContainer>
|
||||
<Label Name="MediumPriority" StyleClasses="LabelHeading"/>
|
||||
</BoxContainer>
|
||||
<!-- Location for Medium Priority Items -->
|
||||
<GridContainer Name="MediumContainer"
|
||||
HorizontalExpand="True"
|
||||
Access="Public"
|
||||
Columns="2" />
|
||||
|
||||
<!-- Location for Low Priority Items -->
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<PanelContainer SetWidth="7" Margin="0 0 8 0">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BackgroundColor="#3dd425"/>
|
||||
</PanelContainer.PanelOverride>
|
||||
</PanelContainer>
|
||||
<Label Name="LowPriority" StyleClasses="LabelHeading"/>
|
||||
</BoxContainer>
|
||||
<!-- Location for Low Priority Items -->
|
||||
<GridContainer Name="LowContainer"
|
||||
HorizontalExpand="True"
|
||||
Access="Public"
|
||||
Columns="2" />
|
||||
|
||||
<Button Name="NewTaskButton" Text="{Loc 'nano-task-ui-new-task'}" HorizontalAlignment="Right"/>
|
||||
</BoxContainer>
|
||||
</ScrollContainer>
|
||||
</BoxContainer>
|
||||
</cartridges:NanoTaskUiFragment>
|
||||
@@ -0,0 +1,52 @@
|
||||
using System.Linq;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Content.Shared.CartridgeLoader.Cartridges;
|
||||
|
||||
namespace Content.Client.CartridgeLoader.Cartridges;
|
||||
|
||||
/// <summary>
|
||||
/// Class displaying the main UI of NanoTask
|
||||
/// </summary>
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class NanoTaskUiFragment : BoxContainer
|
||||
{
|
||||
public Action<int>? OpenTask;
|
||||
public Action<int>? ToggleTaskCompletion;
|
||||
public Action? NewTask;
|
||||
public List<NanoTaskItemAndId> Tasks = new();
|
||||
|
||||
public NanoTaskUiFragment()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
Orientation = LayoutOrientation.Vertical;
|
||||
HorizontalExpand = true;
|
||||
VerticalExpand = true;
|
||||
NewTaskButton.OnPressed += _ => NewTask?.Invoke();
|
||||
}
|
||||
public void UpdateState(List<NanoTaskItemAndId> tasks)
|
||||
{
|
||||
Tasks = tasks;
|
||||
HighContainer.RemoveAllChildren();
|
||||
MediumContainer.RemoveAllChildren();
|
||||
LowContainer.RemoveAllChildren();
|
||||
|
||||
HighPriority.Text = Loc.GetString("nano-task-ui-heading-high-priority-tasks", ("amount", tasks.Count(task => task.Data.Priority == NanoTaskPriority.High)));
|
||||
MediumPriority.Text = Loc.GetString("nano-task-ui-heading-medium-priority-tasks", ("amount", tasks.Count(task => task.Data.Priority == NanoTaskPriority.Medium)));
|
||||
LowPriority.Text = Loc.GetString("nano-task-ui-heading-low-priority-tasks", ("amount", tasks.Count(task => task.Data.Priority == NanoTaskPriority.Low)));
|
||||
|
||||
foreach (var task in tasks)
|
||||
{
|
||||
var container = task.Data.Priority switch {
|
||||
NanoTaskPriority.High => HighContainer,
|
||||
NanoTaskPriority.Medium => MediumContainer,
|
||||
NanoTaskPriority.Low => LowContainer,
|
||||
};
|
||||
var control = new NanoTaskItemControl(task);
|
||||
container.AddChild(control);
|
||||
control.OnMainPressed += id => OpenTask?.Invoke(id);
|
||||
control.OnDonePressed += id => ToggleTaskCompletion?.Invoke(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -131,13 +131,13 @@ public sealed partial class ChangelogTab : Control
|
||||
Margin = new Thickness(6, 0, 0, 0),
|
||||
};
|
||||
authorLabel.SetMessage(
|
||||
FormattedMessage.FromMarkupOrThrow(Loc.GetString("changelog-author-changed", ("author", author))));
|
||||
FormattedMessage.FromMarkupOrThrow(Loc.GetString("changelog-author-changed", ("author", FormattedMessage.EscapeText(author)))));
|
||||
ChangelogBody.AddChild(authorLabel);
|
||||
|
||||
foreach (var change in groupedEntry.SelectMany(c => c.Changes))
|
||||
{
|
||||
var text = new RichTextLabel();
|
||||
text.SetMessage(FormattedMessage.FromMarkupOrThrow(change.Message));
|
||||
text.SetMessage(FormattedMessage.FromUnformatted(change.Message));
|
||||
ChangelogBody.AddChild(new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
|
||||
@@ -169,7 +169,7 @@ public sealed class ClientClothingSystem : ClothingSystem
|
||||
|
||||
var state = $"equipped-{correctedSlot}";
|
||||
|
||||
if (clothing.EquippedPrefix != null)
|
||||
if (!string.IsNullOrEmpty(clothing.EquippedPrefix))
|
||||
state = $"{clothing.EquippedPrefix}-equipped-{correctedSlot}";
|
||||
|
||||
if (clothing.EquippedState != null)
|
||||
|
||||
@@ -3,6 +3,7 @@ using Content.Shared.Access.Systems;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.CriminalRecords;
|
||||
using Content.Shared.Dataset;
|
||||
using Content.Shared.Random.Helpers;
|
||||
using Content.Shared.Security;
|
||||
using Content.Shared.StationRecords;
|
||||
using Robust.Client.AutoGenerated;
|
||||
@@ -32,7 +33,7 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
|
||||
|
||||
public readonly EntityUid Console;
|
||||
|
||||
[ValidatePrototypeId<DatasetPrototype>]
|
||||
[ValidatePrototypeId<LocalizedDatasetPrototype>]
|
||||
private const string ReasonPlaceholders = "CriminalRecordsWantedReasonPlaceholders";
|
||||
|
||||
public Action<uint?>? OnKeySelected;
|
||||
@@ -333,8 +334,8 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
|
||||
|
||||
var field = "reason";
|
||||
var title = Loc.GetString("criminal-records-status-" + status.ToString().ToLower());
|
||||
var placeholders = _proto.Index<DatasetPrototype>(ReasonPlaceholders);
|
||||
var placeholder = Loc.GetString("criminal-records-console-reason-placeholder", ("placeholder", _random.Pick(placeholders.Values))); // just funny it doesn't actually get used
|
||||
var placeholders = _proto.Index<LocalizedDatasetPrototype>(ReasonPlaceholders);
|
||||
var placeholder = Loc.GetString("criminal-records-console-reason-placeholder", ("placeholder", _random.Pick(placeholders))); // just funny it doesn't actually get used
|
||||
var prompt = Loc.GetString("criminal-records-console-reason");
|
||||
var entry = new QuickDialogEntry(field, QuickDialogEntryType.LongText, prompt, placeholder);
|
||||
var entries = new List<QuickDialogEntry>() { entry };
|
||||
|
||||
@@ -4,6 +4,7 @@ using Content.Shared.Verbs;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -40,7 +41,17 @@ public sealed class ExamineButton : ContainerButton
|
||||
Disabled = true;
|
||||
}
|
||||
|
||||
ToolTip = verb.Message ?? verb.Text;
|
||||
TooltipSupplier = sender =>
|
||||
{
|
||||
var label = new RichTextLabel();
|
||||
label.SetMessage(FormattedMessage.FromMarkupOrThrow(verb.Message ?? verb.Text));
|
||||
|
||||
var tooltip = new Tooltip();
|
||||
tooltip.GetChild(0).Children.Clear();
|
||||
tooltip.GetChild(0).Children.Add(label);
|
||||
|
||||
return tooltip;
|
||||
};
|
||||
|
||||
Icon = new TextureRect
|
||||
{
|
||||
|
||||
@@ -298,10 +298,28 @@ namespace Content.Client.Examine
|
||||
{
|
||||
Name = "ExamineButtonsHBox",
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
HorizontalAlignment = Control.HAlignment.Right,
|
||||
HorizontalAlignment = Control.HAlignment.Stretch,
|
||||
VerticalAlignment = Control.VAlignment.Bottom,
|
||||
};
|
||||
|
||||
var hoverExamineBox = new BoxContainer
|
||||
{
|
||||
Name = "HoverExamineHBox",
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
HorizontalAlignment = Control.HAlignment.Left,
|
||||
VerticalAlignment = Control.VAlignment.Center,
|
||||
HorizontalExpand = true
|
||||
};
|
||||
|
||||
var clickExamineBox = new BoxContainer
|
||||
{
|
||||
Name = "ClickExamineHBox",
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
HorizontalAlignment = Control.HAlignment.Right,
|
||||
VerticalAlignment = Control.VAlignment.Center,
|
||||
HorizontalExpand = true
|
||||
};
|
||||
|
||||
// Examine button time
|
||||
foreach (var verb in verbs)
|
||||
{
|
||||
@@ -316,8 +334,15 @@ namespace Content.Client.Examine
|
||||
|
||||
var button = new ExamineButton(examine);
|
||||
|
||||
button.OnPressed += VerbButtonPressed;
|
||||
buttonsHBox.AddChild(button);
|
||||
if (examine.HoverVerb)
|
||||
{
|
||||
hoverExamineBox.AddChild(button);
|
||||
}
|
||||
else
|
||||
{
|
||||
button.OnPressed += VerbButtonPressed;
|
||||
clickExamineBox.AddChild(button);
|
||||
}
|
||||
}
|
||||
|
||||
var vbox = _examineTooltipOpen?.GetChild(0).GetChild(0);
|
||||
@@ -334,6 +359,8 @@ namespace Content.Client.Examine
|
||||
{
|
||||
vbox.Children.Remove(hbox.First());
|
||||
}
|
||||
buttonsHBox.AddChild(hoverExamineBox);
|
||||
buttonsHBox.AddChild(clickExamineBox);
|
||||
vbox.AddChild(buttonsHBox);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,24 +29,25 @@
|
||||
VerticalAlignment="Center"
|
||||
Access="Public"
|
||||
Visible="False" />
|
||||
<!-- CP14 random reactions begin -->
|
||||
<BoxContainer Name="RandomVariations"
|
||||
Orientation="Vertical"
|
||||
VerticalExpand="True"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center">
|
||||
<controls:SplitBar MinHeight="10">
|
||||
</controls:SplitBar>
|
||||
<Label Name="RandomVariationsLabel"
|
||||
Text="{Loc 'cp14-guidebook-random-variations-title'}"
|
||||
Visible="False"
|
||||
HorizontalAlignment="Center"
|
||||
FontColorOverride="#1e6651" />
|
||||
<controls:SplitBar MinHeight="10">
|
||||
</controls:SplitBar>
|
||||
</BoxContainer>
|
||||
<!-- CP14 random reactions end -->
|
||||
</BoxContainer>
|
||||
<!-- CP14 random reactions begin -->
|
||||
<BoxContainer Name="RandomVariations"
|
||||
Orientation="Vertical"
|
||||
VerticalExpand="True"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center">
|
||||
<controls:SplitBar MinHeight="10">
|
||||
</controls:SplitBar>
|
||||
<Label Name="RandomVariationsLabel"
|
||||
Text="{Loc 'cp14-guidebook-random-variations-title'}"
|
||||
Visible="False"
|
||||
HorizontalAlignment="Center"
|
||||
FontColorOverride="#1e6651" />
|
||||
<controls:SplitBar MinHeight="10">
|
||||
</controls:SplitBar>
|
||||
</BoxContainer>
|
||||
<!-- CP14 random reactions end -->
|
||||
|
||||
</BoxContainer>
|
||||
<PanelContainer StyleClasses="LowDivider" Margin="0 5 0 5" />
|
||||
</BoxContainer>
|
||||
|
||||
@@ -2,6 +2,7 @@ using Content.Shared.CCVar;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Humanoid.Markings;
|
||||
using Content.Shared.Humanoid.Prototypes;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Preferences;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.Configuration;
|
||||
@@ -48,7 +49,7 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
|
||||
}
|
||||
|
||||
private static bool IsHidden(HumanoidAppearanceComponent humanoid, HumanoidVisualLayers layer)
|
||||
=> humanoid.HiddenLayers.Contains(layer) || humanoid.PermanentlyHidden.Contains(layer);
|
||||
=> humanoid.HiddenLayers.ContainsKey(layer) || humanoid.PermanentlyHidden.Contains(layer);
|
||||
|
||||
private void UpdateLayers(HumanoidAppearanceComponent component, SpriteComponent sprite)
|
||||
{
|
||||
@@ -57,7 +58,7 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
|
||||
|
||||
// add default species layers
|
||||
var speciesProto = _prototypeManager.Index(component.Species);
|
||||
var baseSprites = _prototypeManager.Index<HumanoidSpeciesBaseSpritesPrototype>(speciesProto.SpriteSet);
|
||||
var baseSprites = _prototypeManager.Index(speciesProto.SpriteSet);
|
||||
foreach (var (key, id) in baseSprites.Sprites)
|
||||
{
|
||||
oldLayers.Remove(key);
|
||||
@@ -214,7 +215,7 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
|
||||
|
||||
humanoid.MarkingSet = markings;
|
||||
humanoid.PermanentlyHidden = new HashSet<HumanoidVisualLayers>();
|
||||
humanoid.HiddenLayers = new HashSet<HumanoidVisualLayers>();
|
||||
humanoid.HiddenLayers = new Dictionary<HumanoidVisualLayers, SlotFlags>();
|
||||
humanoid.CustomBaseLayers = customBaseLayers;
|
||||
humanoid.Sex = profile.Sex;
|
||||
humanoid.Gender = profile.Gender;
|
||||
@@ -402,23 +403,21 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SetLayerVisibility(
|
||||
EntityUid uid,
|
||||
HumanoidAppearanceComponent humanoid,
|
||||
public override void SetLayerVisibility(
|
||||
Entity<HumanoidAppearanceComponent> ent,
|
||||
HumanoidVisualLayers layer,
|
||||
bool visible,
|
||||
bool permanent,
|
||||
SlotFlags? slot,
|
||||
ref bool dirty)
|
||||
{
|
||||
base.SetLayerVisibility(uid, humanoid, layer, visible, permanent, ref dirty);
|
||||
base.SetLayerVisibility(ent, layer, visible, slot, ref dirty);
|
||||
|
||||
var sprite = Comp<SpriteComponent>(uid);
|
||||
var sprite = Comp<SpriteComponent>(ent);
|
||||
if (!sprite.LayerMapTryGet(layer, out var index))
|
||||
{
|
||||
if (!visible)
|
||||
return;
|
||||
else
|
||||
index = sprite.LayerMapReserveBlank(layer);
|
||||
index = sprite.LayerMapReserveBlank(layer);
|
||||
}
|
||||
|
||||
var spriteLayer = sprite[index];
|
||||
@@ -428,13 +427,14 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
|
||||
spriteLayer.Visible = visible;
|
||||
|
||||
// I fucking hate this. I'll get around to refactoring sprite layers eventually I swear
|
||||
// Just a week away...
|
||||
|
||||
foreach (var markingList in humanoid.MarkingSet.Markings.Values)
|
||||
foreach (var markingList in ent.Comp.MarkingSet.Markings.Values)
|
||||
{
|
||||
foreach (var marking in markingList)
|
||||
{
|
||||
if (_markingManager.TryGetMarking(marking, out var markingPrototype) && markingPrototype.BodyPart == layer)
|
||||
ApplyMarking(markingPrototype, marking.MarkingColors, marking.Visible, humanoid, sprite);
|
||||
ApplyMarking(markingPrototype, marking.MarkingColors, marking.Visible, ent, sprite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,21 +68,13 @@ public sealed partial class LatheMenu : DefaultWindow
|
||||
{
|
||||
ServerListButton.Visible = false;
|
||||
}
|
||||
|
||||
AmountLineEdit.SetText(latheComponent.DefaultProductionAmount.ToString());
|
||||
}
|
||||
|
||||
MaterialsList.SetOwner(Entity);
|
||||
}
|
||||
|
||||
protected override void Opened()
|
||||
{
|
||||
base.Opened();
|
||||
|
||||
if (_entityManager.TryGetComponent<LatheComponent>(Entity, out var latheComp))
|
||||
{
|
||||
AmountLineEdit.SetText(latheComp.DefaultProductionAmount.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populates the list of all the recipes
|
||||
/// </summary>
|
||||
|
||||
@@ -4,7 +4,20 @@
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<ScrollContainer VerticalExpand="True" HScrollEnabled="False">
|
||||
<BoxContainer Orientation="Vertical" Margin="8">
|
||||
<Label Text="{Loc 'ui-options-admin-player-panel'}"
|
||||
StyleClasses="LabelKeyText"/>
|
||||
<CheckBox Name="PlayerlistSeparateSymbolsCheckBox" Text="{Loc 'ui-options-admin-playerlist-separate-symbols'}" />
|
||||
<CheckBox Name="PlayerlistCharacterColorCheckBox" Text="{Loc 'ui-options-admin-playerlist-character-color'}" />
|
||||
<CheckBox Name="PlayerlistRoleTypeColorCheckBox" Text="{Loc 'ui-options-admin-playerlist-roletype-color'}" />
|
||||
<Label Text="{Loc 'ui-options-admin-overlay-title'}"
|
||||
StyleClasses="LabelKeyText"/>
|
||||
<CheckBox Name="EnableClassicOverlayCheckBox" Text="{Loc 'ui-options-enable-classic-overlay'}" />
|
||||
<CheckBox Name="EnableOverlaySymbolsCheckBox" Text="{Loc 'ui-options-enable-overlay-symbols'}" />
|
||||
<CheckBox Name="EnableOverlayPlaytimeCheckBox" Text="{Loc 'ui-options-enable-overlay-playtime'}" />
|
||||
<CheckBox Name="EnableOverlayStartingJobCheckBox" Text="{Loc 'ui-options-enable-overlay-starting-job'}" />
|
||||
<ui:OptionSlider Name="OverlayMergeDistanceSlider" Title="{Loc 'ui-options-overlay-merge-distance'}"/>
|
||||
<ui:OptionSlider Name="OverlayGhostFadeSlider" Title="{Loc 'ui-options-overlay-ghost-fade-distance'}"/>
|
||||
<ui:OptionSlider Name="OverlayGhostHideSlider" Title="{Loc 'ui-options-overlay-ghost-hide-distance'}"/>
|
||||
</BoxContainer>
|
||||
</ScrollContainer>
|
||||
<ui:OptionsTabControlRow Name="Control" Access="Public" />
|
||||
|
||||
@@ -8,13 +8,45 @@ namespace Content.Client.Options.UI.Tabs;
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class AdminOptionsTab : Control
|
||||
{
|
||||
private const float OverlayMergeMin = 0.05f;
|
||||
private const float OverlayMergeMax = 0.95f;
|
||||
private const int OverlayGhostFadeMin = 0;
|
||||
private const int OverlayGhostFadeMax = 10;
|
||||
private const int OverlayGhostHideMin = 0;
|
||||
private const int OverlayGhostHideMax = 5;
|
||||
|
||||
public AdminOptionsTab()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
Control.AddOptionCheckBox(CCVars.AdminPlayerlistSeparateSymbols, PlayerlistSeparateSymbolsCheckBox);
|
||||
Control.AddOptionCheckBox(CCVars.AdminPlayerlistHighlightedCharacterColor, PlayerlistCharacterColorCheckBox);
|
||||
Control.AddOptionCheckBox(CCVars.AdminPlayerlistRoleTypeColor, PlayerlistRoleTypeColorCheckBox);
|
||||
|
||||
Control.AddOptionCheckBox(CCVars.AdminOverlayClassic, EnableClassicOverlayCheckBox);
|
||||
Control.AddOptionCheckBox(CCVars.AdminOverlaySymbols, EnableOverlaySymbolsCheckBox);
|
||||
Control.AddOptionCheckBox(CCVars.AdminOverlayPlaytime, EnableOverlayPlaytimeCheckBox);
|
||||
Control.AddOptionCheckBox(CCVars.AdminOverlayStartingJob, EnableOverlayStartingJobCheckBox);
|
||||
|
||||
Control.Initialize();
|
||||
|
||||
Control.AddOptionPercentSlider(
|
||||
CCVars.AdminOverlayMergeDistance,
|
||||
OverlayMergeDistanceSlider,
|
||||
OverlayMergeMin,
|
||||
OverlayMergeMax);
|
||||
|
||||
Control.AddOptionSlider(
|
||||
CCVars.AdminOverlayGhostFadeDistance,
|
||||
OverlayGhostFadeSlider,
|
||||
OverlayGhostFadeMin,
|
||||
OverlayGhostFadeMax);
|
||||
|
||||
Control.AddOptionSlider(
|
||||
CCVars.AdminOverlayGhostHideDistance,
|
||||
OverlayGhostHideSlider,
|
||||
OverlayGhostHideMin,
|
||||
OverlayGhostHideMax);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -314,6 +314,7 @@ namespace Content.Client.Options.UI.Tabs
|
||||
AddHeader("ui-options-header-cp14");
|
||||
AddButton(ContentKeyFunctions.CP14OpenSkillMenu);
|
||||
//CP14 end
|
||||
|
||||
foreach (var control in _keyControls.Values)
|
||||
{
|
||||
UpdateKeyControl(control);
|
||||
|
||||
@@ -11,13 +11,21 @@ public sealed class PaperVisualizerSystem : VisualizerSystem<PaperVisualsCompone
|
||||
if (args.Sprite == null)
|
||||
return;
|
||||
|
||||
if (AppearanceSystem.TryGetData<PaperStatus>(uid, PaperVisuals.Status , out var writingStatus, args.Component))
|
||||
if (AppearanceSystem.TryGetData<PaperStatus>(uid, PaperVisuals.Status, out var writingStatus, args.Component))
|
||||
args.Sprite.LayerSetVisible(PaperVisualLayers.Writing, writingStatus == PaperStatus.Written);
|
||||
|
||||
if (AppearanceSystem.TryGetData<string>(uid, PaperVisuals.Stamp, out var stampState, args.Component))
|
||||
{
|
||||
args.Sprite.LayerSetState(PaperVisualLayers.Stamp, stampState);
|
||||
args.Sprite.LayerSetVisible(PaperVisualLayers.Stamp, true);
|
||||
if (stampState != string.Empty)
|
||||
{
|
||||
args.Sprite.LayerSetState(PaperVisualLayers.Stamp, stampState);
|
||||
args.Sprite.LayerSetVisible(PaperVisualLayers.Stamp, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
args.Sprite.LayerSetVisible(PaperVisualLayers.Stamp, false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Content.Client.Parallax.Data;
|
||||
/// <summary>
|
||||
/// Prototype data for a parallax.
|
||||
/// </summary>
|
||||
[Prototype("parallax")]
|
||||
[Prototype]
|
||||
public sealed partial class ParallaxPrototype : IPrototype
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -237,6 +237,12 @@ namespace Content.Client.Popups
|
||||
PopupEntity(message, uid, recipient.Value, type);
|
||||
}
|
||||
|
||||
public override void PopupPredicted(string? message, EntityUid uid, EntityUid? recipient, Filter filter, bool recordReplay, PopupType type = PopupType.Small)
|
||||
{
|
||||
if (recipient != null && _timing.IsFirstTimePredicted)
|
||||
PopupEntity(message, uid, recipient.Value, type);
|
||||
}
|
||||
|
||||
public override void PopupPredicted(string? recipientMessage, string? othersMessage, EntityUid uid, EntityUid? recipient, PopupType type = PopupType.Small)
|
||||
{
|
||||
if (recipient != null && _timing.IsFirstTimePredicted)
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
using Content.Shared.DrawDepth;
|
||||
using Content.Client.UserInterface.Systems.Sandbox;
|
||||
using Content.Shared.SubFloor;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Client.SubFloor;
|
||||
|
||||
public sealed class SubFloorHideSystem : SharedSubFloorHideSystem
|
||||
{
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly IUserInterfaceManager _ui = default!;
|
||||
|
||||
private bool _showAll;
|
||||
|
||||
@@ -18,8 +21,13 @@ public sealed class SubFloorHideSystem : SharedSubFloorHideSystem
|
||||
{
|
||||
if (_showAll == value) return;
|
||||
_showAll = value;
|
||||
_ui.GetUIController<SandboxUIController>().SetToggleSubfloors(value);
|
||||
|
||||
UpdateAll();
|
||||
var ev = new ShowSubfloorRequestEvent()
|
||||
{
|
||||
Value = value,
|
||||
};
|
||||
RaiseNetworkEvent(ev);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +36,20 @@ public sealed class SubFloorHideSystem : SharedSubFloorHideSystem
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<SubFloorHideComponent, AppearanceChangeEvent>(OnAppearanceChanged);
|
||||
SubscribeNetworkEvent<ShowSubfloorRequestEvent>(OnRequestReceived);
|
||||
SubscribeLocalEvent<LocalPlayerDetachedEvent>(OnPlayerDetached);
|
||||
}
|
||||
|
||||
private void OnPlayerDetached(LocalPlayerDetachedEvent ev)
|
||||
{
|
||||
// Vismask resets so need to reset this.
|
||||
ShowAll = false;
|
||||
}
|
||||
|
||||
private void OnRequestReceived(ShowSubfloorRequestEvent ev)
|
||||
{
|
||||
// When client receives request Queue an update on all vis.
|
||||
UpdateAll();
|
||||
}
|
||||
|
||||
private void OnAppearanceChanged(EntityUid uid, SubFloorHideComponent component, ref AppearanceChangeEvent args)
|
||||
|
||||
@@ -14,6 +14,7 @@ public sealed partial class GhostGui : UIWidget
|
||||
public event Action? RequestWarpsPressed;
|
||||
public event Action? ReturnToBodyPressed;
|
||||
public event Action? GhostRolesPressed;
|
||||
private int _prevNumberRoles;
|
||||
|
||||
public GhostGui()
|
||||
{
|
||||
@@ -26,6 +27,7 @@ public sealed partial class GhostGui : UIWidget
|
||||
GhostWarpButton.OnPressed += _ => RequestWarpsPressed?.Invoke();
|
||||
ReturnToBodyButton.OnPressed += _ => ReturnToBodyPressed?.Invoke();
|
||||
GhostRolesButton.OnPressed += _ => GhostRolesPressed?.Invoke();
|
||||
GhostRolesButton.OnPressed += _ => GhostRolesButton.StyleClasses.Remove(StyleBase.ButtonCaution);
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
@@ -41,14 +43,13 @@ public sealed partial class GhostGui : UIWidget
|
||||
if (roles != null)
|
||||
{
|
||||
GhostRolesButton.Text = Loc.GetString("ghost-gui-ghost-roles-button", ("count", roles));
|
||||
if (roles > 0)
|
||||
|
||||
if (roles > _prevNumberRoles)
|
||||
{
|
||||
GhostRolesButton.StyleClasses.Add(StyleBase.ButtonCaution);
|
||||
}
|
||||
else
|
||||
{
|
||||
GhostRolesButton.StyleClasses.Remove(StyleBase.ButtonCaution);
|
||||
}
|
||||
|
||||
_prevNumberRoles = (int)roles;
|
||||
}
|
||||
|
||||
TargetWindow.Populate();
|
||||
|
||||
@@ -39,7 +39,6 @@ public sealed class SandboxUIController : UIController, IOnStateChanged<Gameplay
|
||||
[UISystemDependency] private readonly DebugPhysicsSystem _debugPhysics = default!;
|
||||
[UISystemDependency] private readonly MarkerSystem _marker = default!;
|
||||
[UISystemDependency] private readonly SandboxSystem _sandbox = default!;
|
||||
[UISystemDependency] private readonly SubFloorHideSystem _subfloorHide = default!;
|
||||
|
||||
private SandboxWindow? _window;
|
||||
|
||||
@@ -117,10 +116,11 @@ public sealed class SandboxUIController : UIController, IOnStateChanged<Gameplay
|
||||
|
||||
_window.OnOpen += () => { SandboxButton!.Pressed = true; };
|
||||
_window.OnClose += () => { SandboxButton!.Pressed = false; };
|
||||
|
||||
// TODO: These need moving to opened so at least if they're not synced properly on open they work.
|
||||
_window.ToggleLightButton.Pressed = !_light.Enabled;
|
||||
_window.ToggleFovButton.Pressed = !_eye.CurrentEye.DrawFov;
|
||||
_window.ToggleShadowsButton.Pressed = !_light.DrawShadows;
|
||||
_window.ToggleSubfloorButton.Pressed = _subfloorHide.ShowAll;
|
||||
_window.ShowMarkersButton.Pressed = _marker.MarkersVisible;
|
||||
_window.ShowBbButton.Pressed = (_debugPhysics.Flags & PhysicsDebugFlags.Shapes) != 0x0;
|
||||
|
||||
@@ -219,4 +219,16 @@ public sealed class SandboxUIController : UIController, IOnStateChanged<Gameplay
|
||||
_window.Close();
|
||||
}
|
||||
}
|
||||
|
||||
#region Buttons
|
||||
|
||||
public void SetToggleSubfloors(bool value)
|
||||
{
|
||||
if (_window == null)
|
||||
return;
|
||||
|
||||
_window.ToggleSubfloorButton.Pressed = value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Content.Client.SubFloor;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
@@ -7,8 +8,18 @@ namespace Content.Client.UserInterface.Systems.Sandbox.Windows;
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class SandboxWindow : DefaultWindow
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entManager = null!;
|
||||
|
||||
public SandboxWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
}
|
||||
|
||||
protected override void Opened()
|
||||
{
|
||||
base.Opened();
|
||||
// Make sure state is up to date.
|
||||
ToggleSubfloorButton.Pressed = _entManager.System<SubFloorHideSystem>().ShowAll;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,9 @@ public sealed class StorageWindow : BaseWindow
|
||||
private ValueList<EntityUid> _contained = new();
|
||||
private ValueList<EntityUid> _toRemove = new();
|
||||
|
||||
// Manually store this because you can't have a 0x0 GridContainer but we still need to add child controls for 1x1 containers.
|
||||
private Vector2i _pieceGridSize;
|
||||
|
||||
private TextureButton? _backButton;
|
||||
|
||||
private bool _isDirty;
|
||||
@@ -408,11 +411,14 @@ public sealed class StorageWindow : BaseWindow
|
||||
_contained.Clear();
|
||||
_contained.AddRange(storageComp.Container.ContainedEntities.Reverse());
|
||||
|
||||
var width = boundingGrid.Width + 1;
|
||||
var height = boundingGrid.Height + 1;
|
||||
|
||||
// Build the grid representation
|
||||
if (_pieceGrid.Rows - 1 != boundingGrid.Height || _pieceGrid.Columns - 1 != boundingGrid.Width)
|
||||
if (_pieceGrid.Rows != _pieceGridSize.Y || _pieceGrid.Columns != _pieceGridSize.X)
|
||||
{
|
||||
_pieceGrid.Rows = boundingGrid.Height + 1;
|
||||
_pieceGrid.Columns = boundingGrid.Width + 1;
|
||||
_pieceGrid.Rows = height;
|
||||
_pieceGrid.Columns = width;
|
||||
_controlGrid.Clear();
|
||||
|
||||
for (var y = boundingGrid.Bottom; y <= boundingGrid.Top; y++)
|
||||
@@ -430,6 +436,7 @@ public sealed class StorageWindow : BaseWindow
|
||||
}
|
||||
}
|
||||
|
||||
_pieceGridSize = new(width, height);
|
||||
_toRemove.Clear();
|
||||
|
||||
// Remove entities no longer relevant / Update existing ones
|
||||
|
||||
@@ -3,10 +3,12 @@ using Content.Client.ContextMenu.UI;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Verbs.UI
|
||||
{
|
||||
@@ -27,7 +29,17 @@ namespace Content.Client.Verbs.UI
|
||||
|
||||
public VerbMenuElement(Verb verb) : base(verb.Text)
|
||||
{
|
||||
ToolTip = verb.Message;
|
||||
TooltipSupplier = sender =>
|
||||
{
|
||||
var label = new RichTextLabel();
|
||||
label.SetMessage(FormattedMessage.FromMarkupOrThrow(verb.Message ?? verb.Text));
|
||||
|
||||
var tooltip = new Tooltip();
|
||||
tooltip.GetChild(0).Children.Clear();
|
||||
tooltip.GetChild(0).Children.Add(label);
|
||||
|
||||
return tooltip;
|
||||
};
|
||||
Disabled = verb.Disabled;
|
||||
Verb = verb;
|
||||
|
||||
|
||||
@@ -213,7 +213,7 @@ namespace Content.Client.Verbs
|
||||
{
|
||||
// maybe send an informative pop-up message.
|
||||
if (!string.IsNullOrWhiteSpace(verb.Message))
|
||||
_popupSystem.PopupEntity(verb.Message, user);
|
||||
_popupSystem.PopupEntity(FormattedMessage.RemoveMarkupOrThrow(verb.Message), user);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user