]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Add JobRequirementOverride prototypes (#28607)
authorLeon Friedrich <60421075+ElectroJr@users.noreply.github.com>
Fri, 7 Jun 2024 16:43:02 +0000 (04:43 +1200)
committerGitHub <noreply@github.com>
Fri, 7 Jun 2024 16:43:02 +0000 (09:43 -0700)
* Add JobRequirementOverride prototypes

* a

* invert if

* Add override that takes in prototypes directly

14 files changed:
Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs
Content.Client/Players/PlayTimeTracking/JobRequirementsManager.cs
Content.Server/Antag/AntagSelectionSystem.cs
Content.Server/Ghost/Roles/Components/GhostRoleComponent.cs
Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs
Content.Shared/CCVar/CCVars.cs
Content.Shared/Ghost/Roles/GhostRolePrototype.cs
Content.Shared/Ghost/Roles/GhostRolesEuiMessages.cs
Content.Shared/Roles/AntagPrototype.cs
Content.Shared/Roles/JobPrototype.cs
Content.Shared/Roles/JobRequirementOverridePrototype.cs [new file with mode: 0644]
Content.Shared/Roles/JobRequirements.cs
Content.Shared/Roles/SharedRoleSystem.cs
Resources/Prototypes/Roles/requirement_overrides.yml [new file with mode: 0644]

index 1681cd93bd2bb0c0737badb29274f92edd114dec..8ee25d6880b2143a8968b57b18f801072292de1a 100644 (file)
@@ -623,7 +623,8 @@ namespace Content.Client.Lobby.UI
                 selector.Setup(items, title, 250, description, guides: antag.Guides);
                 selector.Select(Profile?.AntagPreferences.Contains(antag.ID) == true ? 0 : 1);
 
-                if (!_requirements.CheckRoleTime(antag.Requirements, out var reason))
+                var requirements = _entManager.System<SharedRoleSystem>().GetAntagRequirement(antag);
+                if (!_requirements.CheckRoleTime(requirements, out var reason))
                 {
                     selector.LockRequirements(reason);
                     Profile = Profile?.WithAntagPreference(antag.ID, false);
index cb155cadbf43932b6c56b46d298b37b726786163..bd4ac877dbbf6f3ae9f7af78ad8a608efda116b5 100644 (file)
@@ -106,7 +106,13 @@ public sealed class JobRequirementsManager : ISharedPlaytimeManager
         if (player == null)
             return true;
 
-        return CheckRoleTime(job.Requirements, out reason);
+        return CheckRoleTime(job, out reason);
+    }
+
+    public bool CheckRoleTime(JobPrototype job, [NotNullWhen(false)] out FormattedMessage? reason)
+    {
+        var reqs = _entManager.System<SharedRoleSystem>().GetJobRequirement(job);
+        return CheckRoleTime(reqs, out reason);
     }
 
     public bool CheckRoleTime(HashSet<JobRequirement>? requirements, [NotNullWhen(false)] out FormattedMessage? reason)
index 52ccb1bd708d312a63ddaf7fdb00d61c35cb7d35..55c66e8933419e8147cd6ca9114609b0d86b5586 100644 (file)
@@ -374,6 +374,9 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
     /// </summary>
     public bool IsSessionValid(Entity<AntagSelectionComponent> ent, ICommonSession? session, AntagSelectionDefinition def, EntityUid? mind = null)
     {
+        // TODO ROLE TIMERS
+        // Check if antag role requirements are met
+
         if (session == null)
             return true;
 
index 86026b230baf54436992083aba531976d8dd51a3..14007edcbf9ca0ce3fbdad40d97f3e33b0ae1158 100644 (file)
@@ -14,6 +14,10 @@ namespace Content.Server.Ghost.Roles.Components
 
         [DataField("rules")] private string _roleRules = "ghost-role-component-default-rules";
 
+        // TODO ROLE TIMERS
+        // Actually make use of / enforce this requirement?
+        // Why is this even here.
+        // Move to ghost role prototype & respect CCvars.GameRoleTimerOverride
         [DataField("requirements")]
         public HashSet<JobRequirement>? Requirements;
 
index c3142a709a76da6cc627ba7db901ed14dabeb728..09956e313f34be01870dcb757b0127b71ab3a7b6 100644 (file)
@@ -35,6 +35,7 @@ public sealed class PlayTimeTrackingSystem : EntitySystem
     [Dependency] private readonly MindSystem _minds = default!;
     [Dependency] private readonly PlayTimeTrackingManager _tracking = default!;
     [Dependency] private readonly IAdminManager _adminManager = default!;
+    [Dependency] private readonly SharedRoleSystem _role = default!;
 
     public override void Initialize()
     {
@@ -197,7 +198,6 @@ public sealed class PlayTimeTrackingSystem : EntitySystem
     public bool IsAllowed(ICommonSession player, string role)
     {
         if (!_prototypes.TryIndex<JobPrototype>(role, out var job) ||
-            job.Requirements == null ||
             !_cfg.GetCVar(CCVars.GameRoleTimers))
             return true;
 
@@ -224,19 +224,8 @@ public sealed class PlayTimeTrackingSystem : EntitySystem
 
         foreach (var job in _prototypes.EnumeratePrototypes<JobPrototype>())
         {
-            if (job.Requirements != null)
-            {
-                foreach (var requirement in job.Requirements)
-                {
-                    if (JobRequirements.TryRequirementMet(requirement, playTimes, out _, EntityManager, _prototypes))
-                        continue;
-
-                    goto NoRole;
-                }
-            }
-
-            roles.Add(job.ID);
-            NoRole:;
+            if (JobRequirements.TryRequirementsMet(job, playTimes, out _, EntityManager, _prototypes))
+                roles.Add(job.ID);
         }
 
         return roles;
@@ -257,22 +246,14 @@ public sealed class PlayTimeTrackingSystem : EntitySystem
 
         for (var i = 0; i < jobs.Count; i++)
         {
-            var job = jobs[i];
-
-            if (!_prototypes.TryIndex(job, out var jobber) ||
-                jobber.Requirements == null ||
-                jobber.Requirements.Count == 0)
-                continue;
-
-            foreach (var requirement in jobber.Requirements)
+            if (_prototypes.TryIndex(jobs[i], out var job)
+                && JobRequirements.TryRequirementsMet(job, playTimes, out _, EntityManager, _prototypes))
             {
-                if (JobRequirements.TryRequirementMet(requirement, playTimes, out _, EntityManager, _prototypes))
-                    continue;
-
-                jobs.RemoveSwap(i);
-                i--;
-                break;
+                continue;
             }
+
+            jobs.RemoveSwap(i);
+            i--;
         }
     }
 
index c74a3c2363692a2963897075125c0fbf55ed990e..0f3e62d33f585ec16d85ca7d84f8786ecf131d43 100644 (file)
@@ -1,4 +1,5 @@
 using Content.Shared.Maps;
+using Content.Shared.Roles;
 using Robust.Shared;
 using Robust.Shared.Configuration;
 using Robust.Shared.Physics.Components;
@@ -219,6 +220,12 @@ namespace Content.Shared.CCVar
         public static readonly CVarDef<bool>
             GameRoleTimers = CVarDef.Create("game.role_timers", true, CVar.SERVER | CVar.REPLICATED);
 
+        /// <summary>
+        /// Override default role requirements using a <see cref="JobRequirementOverridePrototype"/>
+        /// </summary>
+        public static readonly CVarDef<string>
+            GameRoleTimerOverride = CVarDef.Create("game.role_timer_override", "", CVar.SERVER | CVar.REPLICATED);
+
         /// <summary>
         /// If roles should be restricted based on whether or not they are whitelisted.
         /// </summary>
index 43d64322504de194fd50d69a8d120b249fcb27cf..bc36774ea8baca445867f91091e4a3f494e1daf1 100644 (file)
@@ -15,24 +15,24 @@ public sealed partial class GhostRolePrototype : IPrototype
     /// <summary>
     ///     The name of the ghostrole.
     /// </summary>
-    [DataField]
+    [DataField(required: true)]
     public string Name { get; set; } = default!;
 
     /// <summary>
     ///     The description of the ghostrole.
     /// </summary>
-    [DataField]
+    [DataField(required: true)]
     public string Description { get; set; } = default!;
 
     /// <summary>
     ///     The entity prototype of the ghostrole
     /// </summary>
-    [DataField]
-    public string EntityPrototype = default!;
+    [DataField(required: true)]
+    public EntProtoId EntityPrototype;
 
     /// <summary>
     ///     Rules of the ghostrole
     /// </summary>
-    [DataField]
+    [DataField(required: true)]
     public string Rules = default!;
-}
\ No newline at end of file
+}
index b7457538ebe0dc96388dc950db261a71ad786620..b5d8fedbd92129b3da88d993b8463230c4a37d1b 100644 (file)
@@ -11,6 +11,11 @@ namespace Content.Shared.Ghost.Roles
         public string Name { get; set; }
         public string Description { get; set; }
         public string Rules { get; set; }
+
+        // TODO ROLE TIMERS
+        // Actually make use of / enforce this requirement?
+        // Why is this even here.
+        // Move to ghost role prototype & respect CCvars.GameRoleTimerOverride
         public HashSet<JobRequirement>? Requirements { get; set; }
 
         /// <inheritdoc cref="GhostRoleKind"/>
index 05c0c535049cf15c49d0abed663430ba69cf02dd..3cb81d4f9c564d72303968cd466094ea551e824b 100644 (file)
@@ -42,7 +42,9 @@ public sealed partial class AntagPrototype : IPrototype
     /// <summary>
     ///     Requirements that must be met to opt in to this antag role.
     /// </summary>
-    [DataField("requirements")]
+    // TODO ROLE TIMERS
+    // Actually check if the requirements are met. Because apparently this is actually unused.
+    [DataField, Access(typeof(SharedRoleSystem), Other = AccessPermissions.None)]
     public HashSet<JobRequirement>? Requirements;
 
     /// <summary>
index 2a8e9d4b0333f02580b52e3305f99b7556714458..c2549e3925f1e9f882b13d2433c0d4544e000ab2 100644 (file)
@@ -41,7 +41,7 @@ namespace Content.Shared.Roles
         [ViewVariables(VVAccess.ReadOnly)]
         public string? LocalizedDescription => Description is null ? null : Loc.GetString(Description);
 
-        [DataField("requirements")]
+        [DataField, Access(typeof(SharedRoleSystem), Other = AccessPermissions.None)]
         public HashSet<JobRequirement>? Requirements;
 
         [DataField("joinNotifyCrew")]
diff --git a/Content.Shared/Roles/JobRequirementOverridePrototype.cs b/Content.Shared/Roles/JobRequirementOverridePrototype.cs
new file mode 100644 (file)
index 0000000..d0ce649
--- /dev/null
@@ -0,0 +1,20 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Roles;
+
+/// <summary>
+/// Collection of job, antag, and ghost-role job requirements for per-server requirement overrides.
+/// </summary>
+[Prototype]
+public sealed partial class JobRequirementOverridePrototype : IPrototype
+{
+    [ViewVariables]
+    [IdDataField]
+    public string ID { get; private set; } = default!;
+
+    [DataField]
+    public Dictionary<ProtoId<JobPrototype>, HashSet<JobRequirement>> Jobs = new ();
+
+    [DataField]
+    public Dictionary<ProtoId<AntagPrototype>, HashSet<JobRequirement>> Antags = new ();
+}
index ba559fadd5cd9aa399893c6b418e34d1d0dc3594..c9d66fcf9186a89b640917f4b66bbb4f19e7de54 100644 (file)
@@ -73,16 +73,18 @@ namespace Content.Shared.Roles
     {
         public static bool TryRequirementsMet(
             JobPrototype job,
-            Dictionary<string, TimeSpan> playTimes,
+            IReadOnlyDictionary<string, TimeSpan> playTimes,
             [NotNullWhen(false)] out FormattedMessage? reason,
             IEntityManager entManager,
             IPrototypeManager prototypes)
         {
+            var sys = entManager.System<SharedRoleSystem>();
+            var requirements = sys.GetJobRequirement(job);
             reason = null;
-            if (job.Requirements == null)
+            if (requirements == null)
                 return true;
 
-            foreach (var requirement in job.Requirements)
+            foreach (var requirement in requirements)
             {
                 if (!TryRequirementMet(requirement, playTimes, out reason, entManager, prototypes))
                     return false;
@@ -130,7 +132,7 @@ namespace Content.Shared.Roles
                         if (deptDiff <= 0)
                             return true;
 
-                        reason = FormattedMessage.FromMarkup(Loc.GetString(
+                        reason = FormattedMessage.FromMarkupPermissive(Loc.GetString(
                             "role-timer-department-insufficient",
                             ("time", Math.Ceiling(deptDiff)),
                             ("department", Loc.GetString(deptRequirement.Department)),
@@ -141,7 +143,7 @@ namespace Content.Shared.Roles
                     {
                         if (deptDiff <= 0)
                         {
-                            reason = FormattedMessage.FromMarkup(Loc.GetString(
+                            reason = FormattedMessage.FromMarkupPermissive(Loc.GetString(
                                 "role-timer-department-too-high",
                                 ("time", -deptDiff),
                                 ("department", Loc.GetString(deptRequirement.Department)),
@@ -161,7 +163,7 @@ namespace Content.Shared.Roles
                         if (overallDiff <= 0 || overallTime >= overallRequirement.Time)
                             return true;
 
-                        reason = FormattedMessage.FromMarkup(Loc.GetString(
+                        reason = FormattedMessage.FromMarkupPermissive(Loc.GetString(
                               "role-timer-overall-insufficient",
                               ("time", Math.Ceiling(overallDiff))));
                         return false;
@@ -170,7 +172,7 @@ namespace Content.Shared.Roles
                     {
                         if (overallDiff <= 0 || overallTime >= overallRequirement.Time)
                         {
-                            reason = FormattedMessage.FromMarkup(Loc.GetString("role-timer-overall-too-high", ("time", -overallDiff)));
+                            reason = FormattedMessage.FromMarkupPermissive(Loc.GetString("role-timer-overall-too-high", ("time", -overallDiff)));
                             return false;
                         }
 
@@ -197,7 +199,7 @@ namespace Content.Shared.Roles
                         if (roleDiff <= 0)
                             return true;
 
-                        reason = FormattedMessage.FromMarkup(Loc.GetString(
+                        reason = FormattedMessage.FromMarkupPermissive(Loc.GetString(
                             "role-timer-role-insufficient",
                             ("time", Math.Ceiling(roleDiff)),
                             ("job", Loc.GetString(proto)),
@@ -208,7 +210,7 @@ namespace Content.Shared.Roles
                     {
                         if (roleDiff <= 0)
                         {
-                            reason = FormattedMessage.FromMarkup(Loc.GetString(
+                            reason = FormattedMessage.FromMarkupPermissive(Loc.GetString(
                                 "role-timer-role-too-high",
                                 ("time", -roleDiff),
                                 ("job", Loc.GetString(proto)),
index d5ac2e5923ae9dcf091384362a014faf72a73222..81a360ebb7f77822ff82ae0049277f22c918c64e 100644 (file)
@@ -1,10 +1,12 @@
-using System.Linq;
 using Content.Shared.Administration.Logs;
+using Content.Shared.CCVar;
 using Content.Shared.Database;
+using Content.Shared.Ghost.Roles;
 using Content.Shared.Mind;
 using Content.Shared.Roles.Jobs;
 using Robust.Shared.Audio;
 using Robust.Shared.Audio.Systems;
+using Robust.Shared.Configuration;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Utility;
 
@@ -16,14 +18,30 @@ public abstract class SharedRoleSystem : EntitySystem
     [Dependency] private readonly IPrototypeManager _prototypes = default!;
     [Dependency] private readonly SharedAudioSystem _audio = default!;
     [Dependency] private readonly SharedMindSystem _minds = default!;
+    [Dependency] private readonly IConfigurationManager _cfg = default!;
 
     // TODO please lord make role entities
     private readonly HashSet<Type> _antagTypes = new();
 
+    private JobRequirementOverridePrototype? _requirementOverride;
+
     public override void Initialize()
     {
         // TODO make roles entities
         SubscribeLocalEvent<JobComponent, MindGetAllRolesEvent>(OnJobGetAllRoles);
+        Subs.CVar(_cfg, CCVars.GameRoleTimerOverride, SetRequirementOverride, true);
+    }
+
+    private void SetRequirementOverride(string value)
+    {
+        if (string.IsNullOrEmpty(value))
+        {
+            _requirementOverride = null;
+            return;
+        }
+
+        if (!_prototypes.TryIndex(value, out _requirementOverride ))
+            Log.Error($"Unknown JobRequirementOverridePrototype: {value}");
     }
 
     private void OnJobGetAllRoles(EntityUid uid, JobComponent component, ref MindGetAllRolesEvent args)
@@ -253,4 +271,36 @@ public abstract class SharedRoleSystem : EntitySystem
         if (Resolve(mindId, ref mind) && mind.Session != null)
             _audio.PlayGlobal(sound, mind.Session);
     }
+
+    public HashSet<JobRequirement>? GetJobRequirement(JobPrototype job)
+    {
+        if (_requirementOverride != null && _requirementOverride.Jobs.TryGetValue(job.ID, out var req))
+            return req;
+
+        return job.Requirements;
+    }
+
+    public HashSet<JobRequirement>? GetJobRequirement(ProtoId<JobPrototype> job)
+    {
+        if (_requirementOverride != null && _requirementOverride.Jobs.TryGetValue(job, out var req))
+            return req;
+
+        return _prototypes.Index(job).Requirements;
+    }
+
+    public HashSet<JobRequirement>? GetAntagRequirement(ProtoId<AntagPrototype> antag)
+    {
+        if (_requirementOverride != null && _requirementOverride.Antags.TryGetValue(antag, out var req))
+            return req;
+
+        return _prototypes.Index(antag).Requirements;
+    }
+
+    public HashSet<JobRequirement>? GetAntagRequirement(AntagPrototype antag)
+    {
+        if (_requirementOverride != null && _requirementOverride.Antags.TryGetValue(antag.ID, out var req))
+            return req;
+
+        return antag.Requirements;
+    }
 }
diff --git a/Resources/Prototypes/Roles/requirement_overrides.yml b/Resources/Prototypes/Roles/requirement_overrides.yml
new file mode 100644 (file)
index 0000000..62041f4
--- /dev/null
@@ -0,0 +1,16 @@
+- type: jobRequirementOverride
+  id: Reduced
+  jobs:
+    Captain:
+    - !type:DepartmentTimeRequirement
+      department: Engineering
+      time: 3600 # 1 hours
+    - !type:DepartmentTimeRequirement
+      department: Medical
+      time: 3600 # 1 hours
+    - !type:DepartmentTimeRequirement
+      department: Security
+      time: 3600 # 1 hours
+    - !type:DepartmentTimeRequirement
+      department: Command
+      time: 3600 # 1 hour