From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Mon, 11 Sep 2023 05:44:21 +0000 (+1000) Subject: Make role timer tooltips pretty (#19605) X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=b77265314b9608a6568350364904e471fd8e4e8a;p=space-station-14.git Make role timer tooltips pretty (#19605) Co-authored-by: ElectroJr --- diff --git a/Content.Client/LateJoin/LateJoinGui.cs b/Content.Client/LateJoin/LateJoinGui.cs index dd8281ecbf..9acfb03126 100644 --- a/Content.Client/LateJoin/LateJoinGui.cs +++ b/Content.Client/LateJoin/LateJoinGui.cs @@ -257,9 +257,11 @@ namespace Content.Client.LateJoin { jobButton.Disabled = true; - if (!string.IsNullOrEmpty(reason)) + if (!reason.IsEmpty) { - jobButton.ToolTip = reason; + var tooltip = new Tooltip(); + tooltip.SetMessage(reason); + jobButton.TooltipSupplier = _ => tooltip; } jobSelector.AddChild(new TextureRect diff --git a/Content.Client/Players/PlayTimeTracking/JobRequirementsManager.cs b/Content.Client/Players/PlayTimeTracking/JobRequirementsManager.cs index 25a0061610..9d5801b925 100644 --- a/Content.Client/Players/PlayTimeTracking/JobRequirementsManager.cs +++ b/Content.Client/Players/PlayTimeTracking/JobRequirementsManager.cs @@ -10,6 +10,7 @@ using Robust.Client.Player; using Robust.Shared.Configuration; using Robust.Shared.Network; using Robust.Shared.Prototypes; +using Robust.Shared.Utility; namespace Content.Client.Players.PlayTimeTracking; @@ -18,6 +19,7 @@ public sealed class JobRequirementsManager [Dependency] private readonly IBaseClient _client = default!; [Dependency] private readonly IClientNetManager _net = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; + [Dependency] private readonly IEntityManager _entManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IPrototypeManager _prototypes = default!; @@ -78,13 +80,13 @@ public sealed class JobRequirementsManager Updated?.Invoke(); } - public bool IsAllowed(JobPrototype job, [NotNullWhen(false)] out string? reason) + public bool IsAllowed(JobPrototype job, [NotNullWhen(false)] out FormattedMessage? reason) { reason = null; if (_roleBans.Contains($"Job:{job.ID}")) { - reason = Loc.GetString("role-ban"); + reason = FormattedMessage.FromUnformatted(Loc.GetString("role-ban")); return false; } @@ -101,20 +103,15 @@ public sealed class JobRequirementsManager var reasonBuilder = new StringBuilder(); - var first = true; foreach (var requirement in job.Requirements) { - if (JobRequirements.TryRequirementMet(requirement, _roles, out reason, _prototypes)) + if (JobRequirements.TryRequirementMet(requirement, _roles, out var jobReason, _entManager, _prototypes)) continue; - if (!first) - reasonBuilder.Append('\n'); - first = false; - - reasonBuilder.AppendLine(reason); + reasonBuilder.AppendLine(jobReason.ToMarkup()); } - reason = reasonBuilder.Length == 0 ? null : reasonBuilder.ToString(); + reason = reasonBuilder.Length == 0 ? null : FormattedMessage.FromMarkup(reasonBuilder.ToString().Trim()); return reason == null; } } diff --git a/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs b/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs index 144477199d..076e4805c8 100644 --- a/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs +++ b/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs @@ -21,6 +21,7 @@ using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; using Robust.Client.Utility; using Robust.Shared.Configuration; @@ -1272,9 +1273,11 @@ namespace Content.Client.Preferences.UI }); } - public void LockRequirements(string requirements) + public void LockRequirements(FormattedMessage requirements) { - _lockStripe.ToolTip = requirements; + var tooltip = new Tooltip(); + tooltip.SetMessage(requirements); + _lockStripe.TooltipSupplier = _ => tooltip; _lockStripe.Visible = true; _optionButton.Visible = false; } diff --git a/Content.Client/Roles/JobSystem.cs b/Content.Client/Roles/JobSystem.cs new file mode 100644 index 0000000000..f49bb7de55 --- /dev/null +++ b/Content.Client/Roles/JobSystem.cs @@ -0,0 +1,9 @@ +using Content.Shared.Roles; +using Content.Shared.Roles.Jobs; + +namespace Content.Client.Roles; + +public sealed class JobSystem : SharedJobSystem +{ + +} diff --git a/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs b/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs index 3902b8e1b9..6442ef2c67 100644 --- a/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs +++ b/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs @@ -165,7 +165,7 @@ public sealed class PlayTimeTrackingSystem : EntitySystem var playTimes = _tracking.GetTrackerTimes(player); - return JobRequirements.TryRequirementsMet(job, playTimes, out _, _prototypes); + return JobRequirements.TryRequirementsMet(job, playTimes, out _, EntityManager, _prototypes); } public HashSet GetDisallowedJobs(IPlayerSession player) @@ -182,7 +182,7 @@ public sealed class PlayTimeTrackingSystem : EntitySystem { foreach (var requirement in job.Requirements) { - if (JobRequirements.TryRequirementMet(requirement, playTimes, out _, _prototypes)) + if (JobRequirements.TryRequirementMet(requirement, playTimes, out _, EntityManager, _prototypes)) continue; goto NoRole; @@ -220,7 +220,7 @@ public sealed class PlayTimeTrackingSystem : EntitySystem foreach (var requirement in jobber.Requirements) { - if (JobRequirements.TryRequirementMet(requirement, playTimes, out _, _prototypes)) + if (JobRequirements.TryRequirementMet(requirement, playTimes, out _, EntityManager, _prototypes)) continue; jobs.RemoveSwap(i); diff --git a/Content.Server/Roles/Jobs/JobSystem.cs b/Content.Server/Roles/Jobs/JobSystem.cs index 22d6286215..66224d1aba 100644 --- a/Content.Server/Roles/Jobs/JobSystem.cs +++ b/Content.Server/Roles/Jobs/JobSystem.cs @@ -4,14 +4,18 @@ using Content.Server.Mind; using Content.Shared.Mind; using Content.Shared.Roles; using Content.Shared.Roles.Jobs; +using Robust.Shared.Prototypes; namespace Content.Server.Roles.Jobs; +/// +/// Handles the job data on mind entities. +/// public sealed class JobSystem : SharedJobSystem { [Dependency] private readonly IChatManager _chat = default!; - [Dependency] private readonly MindSystem _minds = default!; - [Dependency] private readonly SharedRoleSystem _roles = default!; + [Dependency] private readonly MindSystem _mind = default!; + [Dependency] private readonly RoleSystem _roles = default!; public override void Initialize() { @@ -23,7 +27,7 @@ public sealed class JobSystem : SharedJobSystem if (args.Silent) return; - if (!_minds.TryGetSession(mindId, out var session)) + if (!_mind.TryGetSession(mindId, out var session)) return; if (!MindTryGetJob(mindId, out _, out var prototype)) diff --git a/Content.Shared/Roles/JobRequirements.cs b/Content.Shared/Roles/JobRequirements.cs index 7e0c1a98aa..dd54ca60cf 100644 --- a/Content.Shared/Roles/JobRequirements.cs +++ b/Content.Shared/Roles/JobRequirements.cs @@ -1,8 +1,10 @@ using System.Diagnostics.CodeAnalysis; using Content.Shared.Players.PlayTimeTracking; +using Content.Shared.Roles.Jobs; using JetBrains.Annotations; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Robust.Shared.Utility; namespace Content.Shared.Roles { @@ -67,7 +69,8 @@ namespace Content.Shared.Roles public static bool TryRequirementsMet( JobPrototype job, Dictionary playTimes, - [NotNullWhen(false)] out string? reason, + [NotNullWhen(false)] out FormattedMessage? reason, + IEntityManager entManager, IPrototypeManager prototypes) { reason = null; @@ -76,7 +79,7 @@ namespace Content.Shared.Roles foreach (var requirement in job.Requirements) { - if (!TryRequirementMet(requirement, playTimes, out reason, prototypes)) + if (!TryRequirementMet(requirement, playTimes, out reason, entManager, prototypes)) return false; } @@ -89,9 +92,9 @@ namespace Content.Shared.Roles public static bool TryRequirementMet( JobRequirement requirement, Dictionary playTimes, - [NotNullWhen(false)] out string? reason, + [NotNullWhen(false)] out FormattedMessage? reason, + IEntityManager entManager, IPrototypeManager prototypes) - { reason = null; @@ -101,7 +104,8 @@ namespace Content.Shared.Roles var playtime = TimeSpan.Zero; // Check all jobs' departments - var jobs = prototypes.Index(deptRequirement.Department).Roles; + var department = prototypes.Index(deptRequirement.Department); + var jobs = department.Roles; string proto; // Check all jobs' playtime @@ -121,20 +125,22 @@ namespace Content.Shared.Roles if (deptDiff <= 0) return true; - reason = Loc.GetString( + reason = FormattedMessage.FromMarkup(Loc.GetString( "role-timer-department-insufficient", ("time", deptDiff), - ("department", Loc.GetString(deptRequirement.Department))); + ("department", Loc.GetString(deptRequirement.Department)), + ("departmentColor", department.Color.ToHex()))); return false; } else { if (deptDiff <= 0) { - reason = Loc.GetString( + reason = FormattedMessage.FromMarkup(Loc.GetString( "role-timer-department-too-high", ("time", -deptDiff), - ("department", Loc.GetString(deptRequirement.Department))); + ("department", Loc.GetString(deptRequirement.Department)), + ("departmentColor", department.Color.ToHex()))); return false; } @@ -150,14 +156,14 @@ namespace Content.Shared.Roles if (overallDiff <= 0 || overallTime >= overallRequirement.Time) return true; - reason = Loc.GetString("role-timer-overall-insufficient", ("time", overallDiff)); + reason = FormattedMessage.FromMarkup(Loc.GetString("role-timer-overall-insufficient", ("time", overallDiff))); return false; } else { if (overallDiff <= 0 || overallTime >= overallRequirement.Time) { - reason = Loc.GetString("role-timer-overall-too-high", ("time", -overallDiff)); + reason = FormattedMessage.FromMarkup(Loc.GetString("role-timer-overall-too-high", ("time", -overallDiff))); return false; } @@ -169,26 +175,37 @@ namespace Content.Shared.Roles playTimes.TryGetValue(proto, out var roleTime); var roleDiff = roleRequirement.Time.TotalMinutes - roleTime.TotalMinutes; + var departmentColor = Color.Yellow; + + if (entManager.EntitySysManager.TryGetEntitySystem(out SharedJobSystem? jobSystem)) + { + var jobProto = jobSystem.GetJobPrototype(proto); + + if (jobSystem.TryGetDepartment(jobProto, out var departmentProto)) + departmentColor = departmentProto.Color; + } if (!roleRequirement.Inverted) { if (roleDiff <= 0) return true; - reason = Loc.GetString( + reason = FormattedMessage.FromMarkup(Loc.GetString( "role-timer-role-insufficient", ("time", roleDiff), - ("job", Loc.GetString(proto))); + ("job", Loc.GetString(proto)), + ("departmentColor", departmentColor.ToHex()))); return false; } else { if (roleDiff <= 0) { - reason = Loc.GetString( + reason = FormattedMessage.FromMarkup(Loc.GetString( "role-timer-role-too-high", ("time", -roleDiff), - ("job", Loc.GetString(proto))); + ("job", Loc.GetString(proto)), + ("departmentColor", departmentColor.ToHex()))); return false; } diff --git a/Content.Shared/Roles/Jobs/SharedJobSystem.cs b/Content.Shared/Roles/Jobs/SharedJobSystem.cs index f172b3d310..6ab5776a77 100644 --- a/Content.Shared/Roles/Jobs/SharedJobSystem.cs +++ b/Content.Shared/Roles/Jobs/SharedJobSystem.cs @@ -1,7 +1,10 @@ using System.Diagnostics.CodeAnalysis; +using System.Linq; using Content.Shared.Players; +using Content.Shared.Players.PlayTimeTracking; using Robust.Shared.Players; using Robust.Shared.Prototypes; +using Robust.Shared.Utility; namespace Content.Shared.Roles.Jobs; @@ -13,6 +16,71 @@ public abstract class SharedJobSystem : EntitySystem [Dependency] private readonly IPrototypeManager _prototypes = default!; [Dependency] private readonly SharedPlayerSystem _playerSystem = default!; + [Dependency] private readonly IPrototypeManager _protoManager = default!; + private readonly Dictionary _inverseTrackerLookup = new(); + + public override void Initialize() + { + base.Initialize(); + _protoManager.PrototypesReloaded += OnProtoReload; + SetupTrackerLookup(); + } + + public override void Shutdown() + { + base.Shutdown(); + _protoManager.PrototypesReloaded -= OnProtoReload; + _inverseTrackerLookup.Clear(); + } + + private void OnProtoReload(PrototypesReloadedEventArgs obj) + { + _inverseTrackerLookup.Clear(); + SetupTrackerLookup(); + } + + private void SetupTrackerLookup() + { + // This breaks if you have N trackers to 1 JobId but future concern. + foreach (var job in _protoManager.EnumeratePrototypes()) + { + _inverseTrackerLookup.Add(job.PlayTimeTracker, job.ID); + } + } + + /// + /// Gets the corresponding Job Prototype to a + /// + /// + /// + public string GetJobPrototype(string trackerProto) + { + DebugTools.Assert(_protoManager.HasIndex(trackerProto)); + return _inverseTrackerLookup[trackerProto]; + } + + /// + /// Tries to get the first corresponding department for this job prototype. + /// + public bool TryGetDepartment(string jobProto, [NotNullWhen(true)] out DepartmentPrototype? departmentPrototype) + { + // Not that many departments so we can just eat the cost instead of storing the inverse lookup. + var departmentProtos = _protoManager.EnumeratePrototypes().ToList(); + departmentProtos.Sort((x, y) => string.Compare(x.ID, y.ID, StringComparison.Ordinal)); + + foreach (var department in departmentProtos) + { + if (department.Roles.Contains(jobProto)) + { + departmentPrototype = department; + return true; + } + } + + departmentPrototype = null; + return false; + } + public bool MindHasJobWithId(EntityUid? mindId, string prototypeId) { return CompOrNull(mindId)?.PrototypeId == prototypeId; diff --git a/Resources/Locale/en-US/job/role-timers.ftl b/Resources/Locale/en-US/job/role-timers.ftl index 8e70e234d3..1981f5e795 100644 --- a/Resources/Locale/en-US/job/role-timers.ftl +++ b/Resources/Locale/en-US/job/role-timers.ftl @@ -1,9 +1,9 @@ -role-timer-department-insufficient = You require {TOSTRING($time, "0")} more minutes in {$department} department to play this role. -role-timer-department-too-high = You require {TOSTRING($time, "0")} fewer minutes in {$department} department to play this role. (Are you trying to play a trainee role?) -role-timer-overall-insufficient = You require {TOSTRING($time, "0")} more minutes of playtime to play this role. -role-timer-overall-too-high = You require {TOSTRING($time, "0")} fewer minutes of playtime to play this role. (Are you trying to play a trainee role?) -role-timer-role-insufficient = You require {TOSTRING($time, "0")} more minutes with {$job} to play this role. -role-timer-role-too-high = You require {TOSTRING($time, "0")} fewer minutes with {$job} to play this role. (Are you trying to play a trainee role?) +role-timer-department-insufficient = You require [color=yellow]{TOSTRING($time, "0")}[/color] more minutes of [color={$departmentColor}]{$department}[/color] department playtime to play this role. +role-timer-department-too-high = You require [color=yellow]{TOSTRING($time, "0")}[/color] fewer minutes in [color={$departmentColor}]{$department}[/color] department to play this role. (Are you trying to play a trainee role?) +role-timer-overall-insufficient = You require [color=yellow]{TOSTRING($time, "0")}[/color] more minutes of playtime to play this role. +role-timer-overall-too-high = You require [color=yellow]{TOSTRING($time, "0")}[/color] fewer minutes of playtime to play this role. (Are you trying to play a trainee role?) +role-timer-role-insufficient = You require [color=yellow]{TOSTRING($time, "0")}[/color] more minutes with [color={$departmentColor}]{$job}[/color] to play this role. +role-timer-role-too-high = You require[color=yellow] {TOSTRING($time, "0")}[/color] fewer minutes with [color={$departmentColor}]{$job}[/color] to play this role. (Are you trying to play a trainee role?) role-timer-locked = Locked (hover for details)