Admin playerlist antag presentation rework (#35538)

* refactor(src): Minor refactor of Draw in "AdminNameOverlay. And new info about playtime player

* fix(src): Add configure classic admin owerlay

* fix

* antag status indication rework

* the cvars are free, you can just take them

* update playerlist on cvar change

* more overlay options

* tweak(src): Use _antagLabelClassic and tweak style

* tweak(src): Add config display overlay for startingJob and playTime

* tweak(src): Vector2 is replaced by var

* tweak(src): return to the end of the list

* add new option checkboxes

* passing ConfigurationManager through constructor, some format changes

* made sorting values more futureproof

* comments

* labels

* no point commenting this out when the overlay stack PR will uncomment it again anyway

* sorting prototype

* localize symbols because why not

* symmetry

* Revert "localize symbols because why not"

This reverts commit 922d4030300285a45777d62fcfd9c74b25fe7a60.

* layout and formatting stuff

* fix errant space

---------

Co-authored-by: Schrödinger <132720404+Schrodinger71@users.noreply.github.com>
This commit is contained in:
Errant
2025-03-25 17:03:59 +01:00
committed by GitHub
parent 1b74de6dbb
commit 72141abf8a
19 changed files with 199 additions and 58 deletions

View File

@@ -1,6 +1,7 @@
using System.Linq;
using System.Numerics;
using Content.Client.Administration.Systems;
using Content.Client.Stylesheets;
using Content.Shared.CCVar;
using Content.Shared.Mind;
using Robust.Client.Graphics;
@@ -14,14 +15,17 @@ 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;
//TODO make this adjustable via GUI
private readonly ProtoId<RoleTypePrototype>[] _filter =
@@ -29,17 +33,29 @@ internal sealed class AdminNameOverlay : Overlay
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 this to a specific font 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);
}
public override OverlaySpace Space => OverlaySpace.ScreenSpace;
@@ -48,11 +64,6 @@ internal sealed class AdminNameOverlay : Overlay
{
var viewport = args.WorldAABB;
//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)
{
var entity = _entityManager.GetEntity(playerInfo.NetEntity);
@@ -85,35 +96,51 @@ internal sealed class AdminNameOverlay : Overlay
var currentOffset = Vector2.Zero;
// Character name
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, playerInfo.CharacterName, uiScale, playerInfo.Connected ? Color.Aquamarine : Color.White);
currentOffset += lineoffset;
// Username
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, playerInfo.Username, uiScale, playerInfo.Connected ? Color.Yellow : Color.White);
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);
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);
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;
args.ScreenHandle.DrawString(_fontBold, screenCoordinates + currentOffset, label, uiScale, _antagColorClassic);
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 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;
var color = playerInfo.RoleProto.Color;
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, label, uiScale, color);
args.ScreenHandle.DrawString(_fontBold, screenCoordinates + currentOffset, label, uiScale, color);
currentOffset += lineoffset;
}
}

View File

@@ -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;
}

View File

@@ -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
};

View File

@@ -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"

View File

@@ -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;

View File

@@ -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"

View File

@@ -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
}

View File

@@ -3,8 +3,19 @@
xmlns:ui="clr-namespace:Content.Client.Options.UI">
<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'}" />
</BoxContainer>
</ScrollContainer>
<ui:OptionsTabControlRow Name="Control" Access="Public" />

View File

@@ -12,7 +12,14 @@ public sealed partial class AdminOptionsTab : Control
{
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();
}

View File

@@ -221,6 +221,7 @@ public sealed class AdminSystem : EntitySystem
var name = data.UserName;
var entityName = string.Empty;
var identityName = string.Empty;
var sortWeight = 0;
// Visible (identity) name can be different from real name
if (session?.AttachedEntity != null)
@@ -234,8 +235,10 @@ public sealed class AdminSystem : EntitySystem
// Starting role, antagonist status and role type
RoleTypePrototype roleType = new();
var startingRole = string.Empty;
if (_minds.TryGetMind(session, out var mindId, out var mindComp))
if (_minds.TryGetMind(session, out var mindId, out var mindComp) && mindComp is not null)
{
sortWeight = _role.GetRoleCompByTime(mindComp)?.Comp.SortWeight ?? 0;
if (_proto.TryIndex(mindComp.RoleType, out var role))
roleType = role;
else
@@ -259,8 +262,19 @@ public sealed class AdminSystem : EntitySystem
overallPlaytime = playTime;
}
return new PlayerInfo(name, entityName, identityName, startingRole, antag, roleType, GetNetEntity(session?.AttachedEntity), data.UserId,
connected, _roundActivePlayers.Contains(data.UserId), overallPlaytime);
return new PlayerInfo(
name,
entityName,
identityName,
startingRole,
antag,
roleType,
sortWeight,
GetNetEntity(session?.AttachedEntity),
data.UserId,
connected,
_roundActivePlayers.Contains(data.UserId),
overallPlaytime);
}
private void OnPanicBunkerChanged(bool enabled)

View File

@@ -12,6 +12,7 @@ public sealed record PlayerInfo(
string StartingJob,
bool Antag,
RoleTypePrototype RoleProto,
int SortWeight,
NetEntity? NetEntity,
NetUserId SessionId,
bool Connected,

View File

@@ -47,11 +47,35 @@ public sealed partial class CCVars
/// If true, the admin overlay will display the total time of the players
/// </summary>
public static readonly CVarDef<bool> AdminOverlayPlaytime =
CVarDef.Create("ui.admin_overlay_playtime", false, CVar.CLIENTONLY | CVar.ARCHIVE);
CVarDef.Create("ui.admin_overlay_playtime", true, CVar.CLIENTONLY | CVar.ARCHIVE);
/// <summary>
/// If true, the admin overlay will display the players starting position.
/// </summary>
public static readonly CVarDef<bool> AdminOverlayStartingJob =
CVarDef.Create("ui.admin_overlay_starting_job", false, CVar.CLIENTONLY | CVar.ARCHIVE);
CVarDef.Create("ui.admin_overlay_starting_job", true, CVar.CLIENTONLY | CVar.ARCHIVE);
/// <summary>
/// If true, the admin window player tab will show different antag symbols for each role type
/// </summary>
public static readonly CVarDef<bool> AdminPlayerlistSeparateSymbols =
CVarDef.Create("ui.admin_playerlist_separate_symbols", false, CVar.CLIENTONLY | CVar.ARCHIVE);
/// <summary>
/// If true, characters with antag role types will have their names colored by their role type
/// </summary>
public static readonly CVarDef<bool> AdminPlayerlistHighlightedCharacterColor =
CVarDef.Create("ui.admin_playerlist_highlighted_character_color", true, CVar.CLIENTONLY | CVar.ARCHIVE);
/// <summary>
/// If true, the Role Types column will be colored
/// </summary>
public static readonly CVarDef<bool> AdminPlayerlistRoleTypeColor =
CVarDef.Create("ui.admin_playerlist_role_type_color", true, CVar.CLIENTONLY | CVar.ARCHIVE);
/// <summary>
/// If true, the admin overlay will show antag symbols
/// </summary>
public static readonly CVarDef<bool> AdminOverlaySymbols =
CVarDef.Create("ui.admin_overlay_symbols", true, CVar.CLIENTONLY | CVar.ARCHIVE);
}

View File

@@ -22,4 +22,10 @@ public sealed partial class RoleTypePrototype : IPrototype
/// </summary>
[DataField]
public Color Color { get; private set; } = Color.FromHex("#eeeeee");
/// <summary>
/// A symbol used to represent the role type.
/// </summary>
[DataField]
public string Symbol = string.Empty;
}

View File

@@ -45,6 +45,12 @@ public sealed partial class MindRoleComponent : BaseMindRoleComponent
/// </summary>
[DataField]
public ProtoId<JobPrototype>? JobPrototype { get; set; }
/// <summary>
/// Used to order the characters on by role/antag status. Highest numbers are shown first.
/// </summary>
[DataField]
public int SortWeight;
}
// Why does this base component actually exist? It does make auto-categorization easy, but before that it was useless?

View File

@@ -211,20 +211,30 @@ public abstract class SharedRoleSystem : EntitySystem
return true;
}
/// <summary>
/// Return the most recently specified role type, or Neutral
/// </summary>
private ProtoId<RoleTypePrototype> GetRoleTypeByTime(MindComponent mind)
{
// If any Mind Roles specify a Role Type, return the most recent. Otherwise return Neutral
var role = GetRoleCompByTime(mind);
return role?.Comp?.RoleType ?? "Neutral";
}
var roles = new List<ProtoId<RoleTypePrototype>>();
/// <summary>
/// Return the most recently specified role type's mind role entity, or null
/// </summary>
public Entity<MindRoleComponent>? GetRoleCompByTime(MindComponent mind)
{
var roles = new List<Entity<MindRoleComponent>>();
foreach (var role in mind.MindRoles)
{
var comp = Comp<MindRoleComponent>(role);
if (comp.RoleType is not null)
roles.Add(comp.RoleType.Value);
roles.Add((role, comp));
}
ProtoId<RoleTypePrototype> result = (roles.Count > 0) ? roles.LastOrDefault() : "Neutral";
Entity<MindRoleComponent>? result = roles.Count > 0 ? roles.LastOrDefault() : null;
return (result);
}

View File

@@ -2,7 +2,6 @@
player-tab-username = Username
player-tab-character = Character
player-tab-job = Job
player-tab-antagonist = Antagonist
player-tab-roletype = Role Type
player-tab-playtime = Playtime
player-tab-show-disconnected = Show Disconnected
@@ -11,3 +10,7 @@ player-tab-entry-tooltip = Playtime is displayed in days:hours:minutes.
player-tab-filter-line-edit-placeholder = Filter
player-tab-is-antag-yes = YES
player-tab-is-antag-no = NO
player-tab-character-name-antag-symbol = {$symbol} {$name}
player-tab-antag-prefix = 🗡

View File

@@ -337,4 +337,14 @@ ui-options-censor-nudity = Censor character nudity
## Admin menu
ui-options-enable-classic-overlay = Revert antag overlay to classic mode
ui-options-admin-player-panel = Admin Menu Players List
ui-options-admin-playerlist-separate-symbols = Show separate symbols for each antag role type
ui-options-admin-playerlist-character-color = Color names of antagonist characters
ui-options-admin-playerlist-roletype-color = Color role types
ui-options-admin-overlay-title = Admin Overlay
ui-options-enable-classic-overlay = Revert overlay to classic mode
ui-options-enable-overlay-symbols = Add antag symbol to text
ui-options-enable-overlay-playtime = Show playtime
ui-options-enable-overlay-starting-job = Show starting job

View File

@@ -15,6 +15,7 @@
antag: true
antagPrototype: GenericAntagonist
roleType: SoloAntagonist
sortWeight: 50
#Observer
- type: entity
@@ -23,6 +24,8 @@
name: Observer Role
components:
- type: ObserverRole
- type: MindRole
sortWeight: -10
#Ghost Roles
- type: entity
@@ -48,6 +51,7 @@
- type: MindRole
roleType: FreeAgent
antagPrototype: GenericFreeAgent
sortWeight: 30
- type: entity
parent: MindRoleGhostRoleNeutral
@@ -56,6 +60,7 @@
components:
- type: MindRole
roleType: FreeAgent
sortWeight: 0 # Maybe 10?
- type: entity
parent: MindRoleGhostRoleNeutral
@@ -73,6 +78,7 @@
- type: MindRole
roleType: SiliconAntagonist
antagPrototype: GenericSiliconAntagonist
sortWeight: 30
- type: entity
parent: [ BaseMindRoleAntag, MindRoleGhostRoleNeutral ]
@@ -94,6 +100,9 @@
parent: MindRoleGhostRoleTeamAntagonist
id: MindRoleGhostRoleTeamAntagonistFlock
name: Ghost Role (Team Antagonist)
components:
- type: MindRole
sortWeight: 40
# The Job MindRole holds the mob's Job prototype
- type: entity

View File

@@ -5,34 +5,40 @@
id: Neutral
name: role-type-crew-aligned-name
color: '#eeeeee'
symbol: "🗡" # Should never be antag, but just in case.
- type: roleType
id: SoloAntagonist
name: role-type-solo-antagonist-name
color: '#d82000'
symbol: "🗡"
- type: roleType
id: TeamAntagonist
name: role-type-team-antagonist-name
color: '#d82000'
symbol: "⚔"
- type: roleType
id: FreeAgent
name: role-type-free-agent-name
color: '#ffff00'
symbol: "☯"
- type: roleType
id: Familiar
name: role-type-familiar-name
color: '#6495ed'
symbol: "🗡" # Should never be antag, but just in case.
- type: roleType
id: Silicon
name: role-type-silicon-name
color: '#6495ed'
symbol: "🗡" # Should never be antag, but just in case.
- type: roleType
id: SiliconAntagonist
name: role-type-silicon-antagonist-name
color: '#c832e6'
symbol: "⛞"