diff --git a/Content.Client/LateJoin/LateJoinGui.cs b/Content.Client/LateJoin/LateJoinGui.cs index ba9351d6746..c9737e09b13 100644 --- a/Content.Client/LateJoin/LateJoinGui.cs +++ b/Content.Client/LateJoin/LateJoinGui.cs @@ -4,9 +4,13 @@ using Content.Client.GameTicking.Managers; using Content.Client.UserInterface.Controls; using Content.Client.Players.PlayTimeTracking; +using Content.Client.Preferences; using Content.Shared.CCVar; +using Content.Shared.Customization.Systems; +using Content.Shared.Preferences; using Content.Shared.Roles; using Content.Shared.StatusIcon; +using Microsoft.Win32.SafeHandles; using Robust.Client.Console; using Robust.Client.GameObjects; using Robust.Client.UserInterface; @@ -26,6 +30,9 @@ public sealed class LateJoinGui : DefaultWindow [Dependency] private readonly IConfigurationManager _configManager = default!; [Dependency] private readonly IEntitySystemManager _entitySystem = default!; [Dependency] private readonly JobRequirementsManager _jobRequirements = default!; + [Dependency] private readonly CharacterRequirementsSystem _characterRequirements = default!; + [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly IClientPreferencesManager _prefs = default!; public event Action<(NetEntity, string)> SelectedId; @@ -254,14 +261,24 @@ private void RebuildUI() jobButton.OnPressed += _ => SelectedId.Invoke((id, jobButton.JobId)); - if (!_jobRequirements.IsAllowed(prototype, out var reason)) + if (!_characterRequirements.CheckRequirementsValid( + prototype.Requirements ?? new(), + prototype, + (HumanoidCharacterProfile) (_prefs.Preferences?.SelectedCharacter + ?? HumanoidCharacterProfile.DefaultWithSpecies()), + _jobRequirements.GetPlayTimes(), + _jobRequirements.IsWhitelisted(), + _entityManager, + _prototypeManager, + _configManager, + out var reasons)) { jobButton.Disabled = true; - if (!reason.IsEmpty) + if (reasons.Count > 0) { var tooltip = new Tooltip(); - tooltip.SetMessage(reason); + tooltip.SetMessage(_characterRequirements.GetRequirementsText(reasons)); jobButton.TooltipSupplier = _ => tooltip; } diff --git a/Content.Client/Lobby/LobbyUIController.cs b/Content.Client/Lobby/LobbyUIController.cs index 36f43d6f4aa..3e7eb84b998 100644 --- a/Content.Client/Lobby/LobbyUIController.cs +++ b/Content.Client/Lobby/LobbyUIController.cs @@ -2,6 +2,7 @@ using Content.Client.Humanoid; using Content.Client.Inventory; using Content.Client.Lobby.UI; +using Content.Client.Players.PlayTimeTracking; using Content.Client.Preferences; using Content.Client.Preferences.UI; using Content.Shared.Clothing.Loadouts.Systems; @@ -23,6 +24,7 @@ public sealed class LobbyUIController : UIController, IOnStateEntered diff --git a/Content.Client/Players/PlayTimeTracking/JobRequirementsManager.cs b/Content.Client/Players/PlayTimeTracking/JobRequirementsManager.cs index df73f5ff3f4..a38d4e2f308 100644 --- a/Content.Client/Players/PlayTimeTracking/JobRequirementsManager.cs +++ b/Content.Client/Players/PlayTimeTracking/JobRequirementsManager.cs @@ -1,5 +1,6 @@ using System.Diagnostics.CodeAnalysis; using Content.Shared.CCVar; +using Content.Shared.Customization.Systems; using Content.Shared.Players; using Content.Shared.Players.PlayTimeTracking; using Content.Shared.Roles; @@ -17,9 +18,6 @@ public sealed partial class JobRequirementsManager : ISharedPlaytimeManager { [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!; private readonly Dictionary _roles = new(); @@ -80,43 +78,6 @@ private void RxPlayTime(MsgPlayTime message) Updated?.Invoke(); } - public bool IsAllowed(JobPrototype job, [NotNullWhen(false)] out FormattedMessage? reason) - { - reason = null; - - if (_roleBans.Contains($"Job:{job.ID}")) - { - reason = FormattedMessage.FromUnformatted(Loc.GetString("role-ban")); - return false; - } - - var player = _playerManager.LocalSession; - if (player == null) - return true; - - return CheckRoleTime(job.Requirements, out reason); - } - - public bool CheckRoleTime(HashSet? requirements, [NotNullWhen(false)] out FormattedMessage? reason, string? localePrefix = "role-timer-") - { - reason = null; - - if (requirements == null || !_cfg.GetCVar(CCVars.GameRoleTimers)) - return true; - - var reasons = new List(); - foreach (var requirement in requirements) - { - if (JobRequirements.TryRequirementMet(requirement, _roles, out var jobReason, _entManager, _prototypes, _whitelisted, localePrefix)) - continue; - - reasons.Add(jobReason.ToMarkup()); - } - - reason = reasons.Count == 0 ? null : FormattedMessage.FromMarkup(string.Join('\n', reasons)); - return reason == null; - } - public TimeSpan FetchOverallPlaytime() { return _roles.TryGetValue("Overall", out var overallPlaytime) ? overallPlaytime : TimeSpan.Zero; @@ -137,12 +98,8 @@ public Dictionary FetchPlaytimeByRoles() public Dictionary GetPlayTimes() { - var dict = new Dictionary(); - + var dict = FetchPlaytimeByRoles(); dict.Add(PlayTimeTrackingShared.TrackerOverall, FetchOverallPlaytime()); - foreach (var role in FetchPlaytimeByRoles()) - dict.Add(role.Key, role.Value); - return dict; } } diff --git a/Content.Client/Preferences/UI/AntagPreferenceSelector.cs b/Content.Client/Preferences/UI/AntagPreferenceSelector.cs index 06694f51168..872b783c2f9 100644 --- a/Content.Client/Preferences/UI/AntagPreferenceSelector.cs +++ b/Content.Client/Preferences/UI/AntagPreferenceSelector.cs @@ -1,5 +1,9 @@ using Content.Client.Players.PlayTimeTracking; +using Content.Shared.Customization.Systems; +using Content.Shared.Preferences; using Content.Shared.Roles; +using Robust.Shared.Configuration; +using Robust.Shared.Prototypes; namespace Content.Client.Preferences.UI; @@ -14,7 +18,7 @@ public bool Preference public event Action? PreferenceChanged; - public AntagPreferenceSelector(AntagPrototype proto) : base(proto) + public AntagPreferenceSelector(AntagPrototype proto, JobPrototype highJob) : base(proto, highJob) { Options.OnItemSelected += _ => PreferenceChanged?.Invoke(Preference); @@ -30,7 +34,23 @@ public AntagPreferenceSelector(AntagPrototype proto) : base(proto) // Immediately lock requirements if they aren't met. // Another function checks Disabled after creating the selector so this has to be done now var requirements = IoCManager.Resolve(); - if (proto.Requirements != null && !requirements.CheckRoleTime(proto.Requirements, out var reason)) - LockRequirements(reason); + var prefs = IoCManager.Resolve(); + var entMan = IoCManager.Resolve(); + var characterReqs = entMan.System(); + var protoMan = IoCManager.Resolve(); + var configMan = IoCManager.Resolve(); + + if (proto.Requirements != null + && !characterReqs.CheckRequirementsValid( + proto.Requirements, + highJob, + (HumanoidCharacterProfile) (prefs.Preferences?.SelectedCharacter ?? HumanoidCharacterProfile.DefaultWithSpecies()), + requirements.GetPlayTimes(), + requirements.IsWhitelisted(), + entMan, + protoMan, + configMan, + out var reasons)) + LockRequirements(characterReqs.GetRequirementsText(reasons)); } } diff --git a/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs b/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs index 771d928ebf9..8d31ea92280 100644 --- a/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs +++ b/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs @@ -115,7 +115,7 @@ public HumanoidProfileEditor(IClientPreferencesManager preferencesManager, IProt _preferencesManager = preferencesManager; _configurationManager = configurationManager; _markingManager = IoCManager.Resolve(); - _characterRequirementsSystem = EntitySystem.Get(); + _characterRequirementsSystem = _entityManager.System(); _controller = UserInterfaceManager.GetUIController(); _controller.SetProfileEditor(this); @@ -642,7 +642,9 @@ private void UpdateAntagRequirements() if (!antag.SetPreference) continue; - var selector = new AntagPreferenceSelector(antag) + var selector = new AntagPreferenceSelector(antag, + _jobPriorities.FirstOrDefault(j => j.Priority == JobPriority.High)?.HighJob + ?? new()) { Margin = new Thickness(3f, 3f, 3f, 0f) }; _antagList.AddChild(selector); _antagPreferences.Add(selector); @@ -723,10 +725,17 @@ private void UpdateRoleRequirements() { var selector = new JobPrioritySelector(job, _prototypeManager); - if (!_requirements.IsAllowed(job, out var reason)) - { - selector.LockRequirements(reason); - } + if (!_characterRequirementsSystem.CheckRequirementsValid( + job.Requirements ?? new(), + job, + Profile ?? HumanoidCharacterProfile.DefaultWithSpecies(), + _requirements.GetPlayTimes(), + _requirements.IsWhitelisted(), + _entityManager, + _prototypeManager, + _configurationManager, + out var reasons)) + selector.LockRequirements(_characterRequirementsSystem.GetRequirementsText(reasons)); category.AddChild(selector); _jobPriorities.Add(selector); @@ -770,7 +779,17 @@ private void EnsureJobRequirementsValid() var changed = false; foreach (var selector in _jobPriorities) { - if (_requirements.IsAllowed(selector.Proto, out var _) || selector.Priority == JobPriority.Never) + if (selector.Priority == JobPriority.Never + || _characterRequirementsSystem.CheckRequirementsValid( + selector.Proto.Requirements ?? new(), + selector.Proto, + Profile ?? HumanoidCharacterProfile.DefaultWithSpecies(), + _requirements.GetPlayTimes(), + _requirements.IsWhitelisted(), + _entityManager, + _prototypeManager, + _configurationManager, + out _)) continue; selector.Priority = JobPriority.Never; @@ -1412,11 +1431,11 @@ private void UpdateTraits(bool showUnusable) var traits = enumeratedTraits.Where(trait => showUnusable || // Ignore everything if this is true _characterRequirementsSystem.CheckRequirementsValid( - trait, trait.Requirements, highJob?.Proto ?? new JobPrototype(), Profile ?? HumanoidCharacterProfile.DefaultWithSpecies(), _requirements.GetPlayTimes(), + _requirements.IsWhitelisted(), _entityManager, _prototypeManager, _configurationManager, @@ -1427,11 +1446,11 @@ out _ // Traits to highlight red when showUnusable is true var traitsUnusable = enumeratedTraits.Where(trait => _characterRequirementsSystem.CheckRequirementsValid( - trait, trait.Requirements, highJob?.Proto ?? new JobPrototype(), Profile ?? HumanoidCharacterProfile.DefaultWithSpecies(), _requirements.GetPlayTimes(), + _requirements.IsWhitelisted(), _entityManager, _prototypeManager, _configurationManager, @@ -1538,7 +1557,8 @@ out _ var selector = new TraitPreferenceSelector(trait, highJob?.Proto ?? new JobPrototype(), Profile ?? HumanoidCharacterProfile.DefaultWithSpecies(), traitsUnusable.Contains(trait) ? "" : "ButtonColorRed", - _entityManager, _prototypeManager, _configurationManager, _characterRequirementsSystem); + _entityManager, _prototypeManager, _configurationManager, _characterRequirementsSystem, + _requirements); // Look for an existing trait category BoxContainer? match = null; @@ -1570,7 +1590,8 @@ out _ { var selector = new TraitPreferenceSelector(trait, highJob?.Proto ?? new JobPrototype(), Profile ?? HumanoidCharacterProfile.DefaultWithSpecies(), "", - _entityManager, _prototypeManager, _configurationManager, _characterRequirementsSystem); + _entityManager, _prototypeManager, _configurationManager, _characterRequirementsSystem, + _requirements); AddSelector(selector, trait.Points, trait.ID); @@ -1671,11 +1692,11 @@ private void UpdateLoadouts(bool showUnusable) var loadouts = enumeratedLoadouts.Where(loadout => showUnusable || // Ignore everything if this is true _characterRequirementsSystem.CheckRequirementsValid( - loadout, loadout.Requirements, highJob?.Proto ?? new JobPrototype(), Profile ?? HumanoidCharacterProfile.DefaultWithSpecies(), _requirements.GetPlayTimes(), + _requirements.IsWhitelisted(), _entityManager, _prototypeManager, _configurationManager, @@ -1686,11 +1707,11 @@ out _ // Loadouts to highlight red when showUnusable is true var loadoutsUnusable = enumeratedLoadouts.Where(loadout => _characterRequirementsSystem.CheckRequirementsValid( - loadout, loadout.Requirements, highJob?.Proto ?? new JobPrototype(), Profile ?? HumanoidCharacterProfile.DefaultWithSpecies(), _requirements.GetPlayTimes(), + _requirements.IsWhitelisted(), _entityManager, _prototypeManager, _configurationManager, @@ -1800,7 +1821,8 @@ out _ var selector = new LoadoutPreferenceSelector(loadout, highJob?.Proto ?? new JobPrototype(), Profile ?? HumanoidCharacterProfile.DefaultWithSpecies(), loadoutsUnusable.Contains(loadout) ? "" : "ButtonColorRed", - _entityManager, _prototypeManager, _configurationManager, _characterRequirementsSystem); + _entityManager, _prototypeManager, _configurationManager, _characterRequirementsSystem, + _requirements); // Look for an existing loadout category BoxContainer? match = null; @@ -1829,7 +1851,8 @@ out _ { var selector = new LoadoutPreferenceSelector(loadout, highJob?.Proto ?? new JobPrototype(), Profile ?? HumanoidCharacterProfile.DefaultWithSpecies(), "", - _entityManager, _prototypeManager, _configurationManager, _characterRequirementsSystem); + _entityManager, _prototypeManager, _configurationManager, _characterRequirementsSystem, + _requirements); AddSelector(selector, loadout.Cost, loadout.ID); diff --git a/Content.Client/Preferences/UI/JobPrioritySelector.cs b/Content.Client/Preferences/UI/JobPrioritySelector.cs index 2e2c699c3ad..f66102d644f 100644 --- a/Content.Client/Preferences/UI/JobPrioritySelector.cs +++ b/Content.Client/Preferences/UI/JobPrioritySelector.cs @@ -4,6 +4,7 @@ using Content.Shared.StatusIcon; using Robust.Client.UserInterface.Controls; using Robust.Client.Utility; +using Robust.Shared.CPUJob.JobQueues; using Robust.Shared.Prototypes; namespace Content.Client.Preferences.UI; @@ -18,7 +19,7 @@ public JobPriority Priority public event Action? PriorityChanged; - public JobPrioritySelector(JobPrototype proto, IPrototypeManager protoMan) : base(proto) + public JobPrioritySelector(JobPrototype proto, IPrototypeManager protoMan) : base(proto, proto) { Options.OnItemSelected += _ => PriorityChanged?.Invoke(Priority); diff --git a/Content.Client/Preferences/UI/LoadoutPreferenceSelector.cs b/Content.Client/Preferences/UI/LoadoutPreferenceSelector.cs index a6839dee65f..82d8fd65b33 100644 --- a/Content.Client/Preferences/UI/LoadoutPreferenceSelector.cs +++ b/Content.Client/Preferences/UI/LoadoutPreferenceSelector.cs @@ -1,6 +1,7 @@ using System.Linq; using System.Numerics; using System.Text; +using Content.Client.Players.PlayTimeTracking; using Content.Client.Stylesheets; using Content.Shared.Clothing.Loadouts.Prototypes; using Content.Shared.Customization.Systems; @@ -32,7 +33,8 @@ public bool Preference public LoadoutPreferenceSelector(LoadoutPrototype loadout, JobPrototype highJob, HumanoidCharacterProfile profile, string style, IEntityManager entityManager, IPrototypeManager prototypeManager, - IConfigurationManager configManager, CharacterRequirementsSystem characterRequirementsSystem) + IConfigurationManager configManager, CharacterRequirementsSystem characterRequirementsSystem, + JobRequirementsManager jobRequirementsManager) { Loadout = loadout; @@ -94,8 +96,9 @@ public LoadoutPreferenceSelector(LoadoutPrototype loadout, JobPrototype highJob, // Get requirement reasons - characterRequirementsSystem.CheckRequirementsValid(loadout, loadout.Requirements, highJob, profile, - new Dictionary(), + characterRequirementsSystem.CheckRequirementsValid( + loadout.Requirements, highJob, profile, new Dictionary(), + jobRequirementsManager.IsWhitelisted(), entityManager, prototypeManager, configManager, out var reasons); diff --git a/Content.Client/Preferences/UI/RequirementsSelector.cs b/Content.Client/Preferences/UI/RequirementsSelector.cs index a4a25536d09..83b96952886 100644 --- a/Content.Client/Preferences/UI/RequirementsSelector.cs +++ b/Content.Client/Preferences/UI/RequirementsSelector.cs @@ -1,6 +1,7 @@ using System.Numerics; using Content.Client.Stylesheets; using Content.Client.UserInterface.Controls; +using Content.Shared.Roles; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Shared.Prototypes; @@ -11,14 +12,16 @@ namespace Content.Client.Preferences.UI; public abstract class RequirementsSelector : BoxContainer where T : IPrototype { public T Proto { get; } + public JobPrototype HighJob { get; } public bool Disabled => _lockStripe.Visible; protected readonly RadioOptions Options; private readonly StripeBack _lockStripe; - protected RequirementsSelector(T proto) + protected RequirementsSelector(T proto, JobPrototype highJob) { Proto = proto; + HighJob = highJob; Options = new RadioOptions(RadioOptionsLayout.Horizontal) { diff --git a/Content.Client/Preferences/UI/TraitPreferenceSelector.cs b/Content.Client/Preferences/UI/TraitPreferenceSelector.cs index 0f843ca3a58..e9ce1a5e9be 100644 --- a/Content.Client/Preferences/UI/TraitPreferenceSelector.cs +++ b/Content.Client/Preferences/UI/TraitPreferenceSelector.cs @@ -1,4 +1,5 @@ using System.Text; +using Content.Client.Players.PlayTimeTracking; using Content.Client.Stylesheets; using Content.Shared.Customization.Systems; using Content.Shared.Preferences; @@ -30,7 +31,8 @@ public bool Preference public TraitPreferenceSelector(TraitPrototype trait, JobPrototype highJob, HumanoidCharacterProfile profile, string style, IEntityManager entityManager, IPrototypeManager prototypeManager, - IConfigurationManager configManager, CharacterRequirementsSystem characterRequirementsSystem) + IConfigurationManager configManager, CharacterRequirementsSystem characterRequirementsSystem, + JobRequirementsManager jobRequirementsManager) { Trait = trait; @@ -71,8 +73,9 @@ public TraitPreferenceSelector(TraitPrototype trait, JobPrototype highJob, // Get requirement reasons - characterRequirementsSystem.CheckRequirementsValid(trait, trait.Requirements, highJob, profile, - new Dictionary(), + characterRequirementsSystem.CheckRequirementsValid( + trait.Requirements, highJob, profile, new Dictionary(), + jobRequirementsManager.IsWhitelisted(), entityManager, prototypeManager, configManager, out var reasons); diff --git a/Content.Client/UserInterface/Systems/Ghost/Controls/Roles/GhostRolesEui.cs b/Content.Client/UserInterface/Systems/Ghost/Controls/Roles/GhostRolesEui.cs index 8e72eafd97c..d0fd3a80c3b 100644 --- a/Content.Client/UserInterface/Systems/Ghost/Controls/Roles/GhostRolesEui.cs +++ b/Content.Client/UserInterface/Systems/Ghost/Controls/Roles/GhostRolesEui.cs @@ -1,10 +1,15 @@ using System.Linq; using Content.Client.Eui; using Content.Client.Players.PlayTimeTracking; +using Content.Client.Preferences; +using Content.Shared.Customization.Systems; using Content.Shared.Eui; using Content.Shared.Ghost.Roles; +using Content.Shared.Preferences; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Shared.Configuration; +using Robust.Shared.Prototypes; using Robust.Shared.Utility; namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles @@ -71,6 +76,10 @@ public override void HandleState(EuiStateBase state) var sysManager = entityManager.EntitySysManager; var spriteSystem = sysManager.GetEntitySystem(); var requirementsManager = IoCManager.Resolve(); + var characterReqs = entityManager.System(); + var prefs = IoCManager.Resolve(); + var protoMan = IoCManager.Resolve(); + var configManager = IoCManager.Resolve(); var groupedRoles = ghostState.GhostRoles.GroupBy( role => (role.Name, role.Description, role.Requirements)); @@ -78,15 +87,22 @@ public override void HandleState(EuiStateBase state) { var name = group.Key.Name; var description = group.Key.Description; - bool hasAccess = true; - FormattedMessage? reason; + // ReSharper disable once ReplaceWithSingleAssignment.True + var hasAccess = true; - if (!requirementsManager.CheckRoleTime(group.Key.Requirements, out reason)) - { + if (!characterReqs.CheckRequirementsValid( + group.Key.Requirements ?? new(), + new(), + (HumanoidCharacterProfile) (prefs.Preferences?.SelectedCharacter ?? HumanoidCharacterProfile.DefaultWithSpecies()), + requirementsManager.GetPlayTimes(), + requirementsManager.IsWhitelisted(), + entityManager, + protoMan, + configManager, + out var reasons)) hasAccess = false; - } - _window.AddEntry(name, description, hasAccess, reason, group, spriteSystem); + _window.AddEntry(name, description, hasAccess, characterReqs.GetRequirementsText(reasons), group, spriteSystem); } var closeRulesWindow = ghostState.GhostRoles.All(role => role.Identifier != _windowRulesId); diff --git a/Content.Server/Clothing/Systems/LoadoutSystem.cs b/Content.Server/Clothing/Systems/LoadoutSystem.cs index c22f7afb598..73d5ae387ab 100644 --- a/Content.Server/Clothing/Systems/LoadoutSystem.cs +++ b/Content.Server/Clothing/Systems/LoadoutSystem.cs @@ -3,6 +3,7 @@ using Content.Shared.CCVar; using Content.Shared.Inventory; using Content.Shared.Item; +using Content.Shared.Players; using Content.Shared.Storage; using Content.Shared.Storage.EntitySystems; using Robust.Shared.Configuration; @@ -31,7 +32,8 @@ private void OnPlayerSpawnComplete(PlayerSpawnCompleteEvent ev) return; // Spawn the loadout, get a list of items that failed to equip - var failedLoadouts = _loadout.ApplyCharacterLoadout(ev.Mob, ev.JobId, ev.Profile, _playTimeTracking.GetTrackerTimes(ev.Player)); + var failedLoadouts = _loadout.ApplyCharacterLoadout(ev.Mob, ev.JobId, ev.Profile, + _playTimeTracking.GetTrackerTimes(ev.Player), ev.Player.ContentData()?.Whitelisted ?? false); // Try to find back-mounted storage apparatus if (!_inventory.TryGetSlotEntity(ev.Mob, "back", out var item) || diff --git a/Content.Server/Ghost/Roles/Components/GhostRoleComponent.cs b/Content.Server/Ghost/Roles/Components/GhostRoleComponent.cs index abb26a8c8bc..997961ae675 100644 --- a/Content.Server/Ghost/Roles/Components/GhostRoleComponent.cs +++ b/Content.Server/Ghost/Roles/Components/GhostRoleComponent.cs @@ -1,4 +1,5 @@ using Content.Server.Mind.Commands; +using Content.Shared.Customization.Systems; using Content.Shared.Roles; namespace Content.Server.Ghost.Roles.Components @@ -14,7 +15,7 @@ public sealed partial class GhostRoleComponent : Component [DataField("rules")] private string _roleRules = "ghost-role-component-default-rules"; [DataField("requirements")] - public HashSet? Requirements; + public List? Requirements; /// /// Whether the should run on the mob. diff --git a/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs b/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs index 57c6466ebbb..8368388d81e 100644 --- a/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs +++ b/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs @@ -3,12 +3,15 @@ using Content.Server.Afk.Events; using Content.Server.GameTicking; using Content.Server.Mind; +using Content.Server.Preferences.Managers; using Content.Shared.CCVar; +using Content.Shared.Customization.Systems; using Content.Shared.GameTicking; using Content.Shared.Mobs; using Content.Shared.Mobs.Components; using Content.Shared.Players; using Content.Shared.Players.PlayTimeTracking; +using Content.Shared.Preferences; using Content.Shared.Roles; using Robust.Server.GameObjects; using Robust.Server.Player; @@ -31,6 +34,10 @@ public sealed class PlayTimeTrackingSystem : EntitySystem [Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly MindSystem _minds = default!; [Dependency] private readonly PlayTimeTrackingManager _tracking = default!; + [Dependency] private readonly CharacterRequirementsSystem _characterRequirements = default!; + [Dependency] private readonly IServerPreferencesManager _prefs = default!; + [Dependency] private readonly IConfigurationManager _config = default!; + public override void Initialize() { @@ -173,7 +180,16 @@ public bool IsAllowed(ICommonSession player, string role) var isWhitelisted = player.ContentData()?.Whitelisted ?? false; // DeltaV - Whitelist requirement - return JobRequirements.TryRequirementsMet(job, playTimes, out _, EntityManager, _prototypes, isWhitelisted); + return _characterRequirements.CheckRequirementsValid( + job.Requirements, + job, + (HumanoidCharacterProfile) _prefs.GetPreferences(player.UserId).SelectedCharacter, + playTimes, + isWhitelisted, + EntityManager, + _prototypes, + _config, + out _); } public HashSet GetDisallowedJobs(ICommonSession player) @@ -194,13 +210,19 @@ public HashSet GetDisallowedJobs(ICommonSession player) { if (job.Requirements != null) { - foreach (var requirement in job.Requirements) - { - if (JobRequirements.TryRequirementMet(requirement, playTimes, out _, EntityManager, _prototypes, isWhitelisted)) - continue; + if (_characterRequirements.CheckRequirementsValid( + job.Requirements, + job, + (HumanoidCharacterProfile) _prefs.GetPreferences(player.UserId).SelectedCharacter, + playTimes, + isWhitelisted, + EntityManager, + _prototypes, + _config, + out _)) + continue; - goto NoRole; - } + goto NoRole; } roles.Add(job.ID); @@ -234,14 +256,19 @@ public void RemoveDisallowedJobs(NetUserId userId, ref List jobs) jobber.Requirements.Count == 0) continue; - foreach (var requirement in jobber.Requirements) + if (!_characterRequirements.CheckRequirementsValid( + jobber.Requirements, + jobber, + (HumanoidCharacterProfile) _prefs.GetPreferences(userId).SelectedCharacter, + _tracking.GetPlayTimes(_playerManager.GetSessionById(userId)), + _playerManager.GetSessionById(userId).ContentData()?.Whitelisted ?? false, + EntityManager, + _prototypes, + _config, + out _)) { - if (JobRequirements.TryRequirementMet(requirement, playTimes, out _, EntityManager, _prototypes, isWhitelisted)) - continue; - jobs.RemoveSwap(i); i--; - break; } } } diff --git a/Content.Server/Traits/TraitSystem.cs b/Content.Server/Traits/TraitSystem.cs index be2c3c05039..628cb43b8d2 100644 --- a/Content.Server/Traits/TraitSystem.cs +++ b/Content.Server/Traits/TraitSystem.cs @@ -4,6 +4,7 @@ using Content.Shared.Customization.Systems; using Content.Shared.Hands.Components; using Content.Shared.Hands.EntitySystems; +using Content.Shared.Players; using Content.Shared.Roles; using Content.Shared.Traits; using Pidgin.Configuration; @@ -40,9 +41,10 @@ private void OnPlayerSpawnComplete(PlayerSpawnCompleteEvent args) return; } - if (!_characterRequirements.CheckRequirementsValid(traitPrototype, traitPrototype.Requirements, + if (!_characterRequirements.CheckRequirementsValid( + traitPrototype.Requirements, _prototype.Index(args.JobId ?? _prototype.EnumeratePrototypes().First().ID), - args.Profile, _playTimeTracking.GetTrackerTimes(args.Player), + args.Profile, _playTimeTracking.GetTrackerTimes(args.Player), args.Player.ContentData()?.Whitelisted ?? false, EntityManager, _prototype, _configuration, out _)) continue; diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs index 04e680390ce..3c3bfa8862d 100644 --- a/Content.Shared/CCVar/CCVars.cs +++ b/Content.Shared/CCVar/CCVars.cs @@ -1432,7 +1432,7 @@ public static readonly CVarDef /// Controls whether the server will deny any players that are not whitelisted in the DB. /// public static readonly CVarDef WhitelistEnabled = - CVarDef.Create("whitelist.enabled", false, CVar.SERVERONLY); + CVarDef.Create("whitelist.enabled", false, CVar.REPLICATED); /// /// The loc string to display as a disconnect reason when someone is not whitelisted. diff --git a/Content.Shared/Clothing/Loadouts/Systems/LoadoutSystem.cs b/Content.Shared/Clothing/Loadouts/Systems/LoadoutSystem.cs index 09e3db3793f..e7a0eef80ee 100644 --- a/Content.Shared/Clothing/Loadouts/Systems/LoadoutSystem.cs +++ b/Content.Shared/Clothing/Loadouts/Systems/LoadoutSystem.cs @@ -38,12 +38,11 @@ private void OnMapInit(EntityUid uid, LoadoutComponent component, MapInitEvent a } - /// - public List ApplyCharacterLoadout(EntityUid uid, string job, HumanoidCharacterProfile profile, - Dictionary? playTimes = null) + public List ApplyCharacterLoadout(EntityUid uid, ProtoId job, HumanoidCharacterProfile profile, + Dictionary playTimes, bool whitelisted) { - var jobPrototype = _prototype.Index(job); - return ApplyCharacterLoadout(uid, jobPrototype, profile, playTimes); + var jobPrototype = _prototype.Index(job); + return ApplyCharacterLoadout(uid, jobPrototype, profile, playTimes, whitelisted); } /// @@ -53,9 +52,10 @@ public List ApplyCharacterLoadout(EntityUid uid, string job, Humanoid /// The job to use for loadout whitelist/blacklist (should be the job of the entity) /// The profile to get loadout items from (should be the entity's, or at least have the same species as the entity) /// Playtime for the player for use with playtime requirements + /// If the player is whitelisted /// A list of loadout items that couldn't be equipped but passed checks public List ApplyCharacterLoadout(EntityUid uid, JobPrototype job, HumanoidCharacterProfile profile, - Dictionary? playTimes = null) + Dictionary playTimes, bool whitelisted) { var failedLoadouts = new List(); @@ -68,8 +68,8 @@ public List ApplyCharacterLoadout(EntityUid uid, JobPrototype job, Hu continue; - if (!_characterRequirements.CheckRequirementsValid(loadoutProto, loadoutProto.Requirements, job, profile, - playTimes ?? new Dictionary(), + if (!_characterRequirements.CheckRequirementsValid( + loadoutProto.Requirements, job, profile, playTimes, whitelisted, EntityManager, _prototype, _configuration, out _)) continue; diff --git a/Content.Shared/Customization/Systems/CharacterRequirements.Job.cs b/Content.Shared/Customization/Systems/CharacterRequirements.Job.cs new file mode 100644 index 00000000000..fe44f2ccc06 --- /dev/null +++ b/Content.Shared/Customization/Systems/CharacterRequirements.Job.cs @@ -0,0 +1,299 @@ +using System.Linq; +using Content.Shared.CCVar; +using Content.Shared.Players.PlayTimeTracking; +using Content.Shared.Preferences; +using Content.Shared.Roles; +using Content.Shared.Roles.Jobs; +using JetBrains.Annotations; +using Robust.Shared.Configuration; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +using Robust.Shared.Utility; + +namespace Content.Shared.Customization.Systems; + + +/// +/// Requires the selected job to be one of the specified jobs +/// +[UsedImplicitly] +[Serializable, NetSerializable] +public sealed partial class CharacterJobRequirement : CharacterRequirement +{ + [DataField(required: true)] + public List> Jobs; + + public override bool IsValid(JobPrototype job, HumanoidCharacterProfile profile, + Dictionary playTimes, bool whitelisted, + IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, + out FormattedMessage? reason) + { + var jobs = new List(); + + // Get the job names and department colors + foreach (var j in Jobs) + { + var jobProto = prototypeManager.Index(j); + var color = Color.LightBlue; + + foreach (var dept in prototypeManager.EnumeratePrototypes() + .OrderBy(d => Loc.GetString($"department-{d.ID}"))) + { + if (!dept.Roles.Contains(j)) + continue; + + color = dept.Color; + break; + } + + jobs.Add(FormattedMessage.FromMarkup($"[color={color.ToHex()}]{Loc.GetString(jobProto.Name)}[/color]")); + } + + // Join the job names + var jobsList = string.Join(", ", jobs.Select(j => j.ToMarkup())); + var jobsString = Loc.GetString("character-job-requirement", + ("inverted", Inverted), ("jobs", jobsList)); + + reason = FormattedMessage.FromMarkup(jobsString); + return Jobs.Contains(job.ID); + } +} + +/// +/// Requires the selected job to be in one of the specified departments +/// +[UsedImplicitly] +[Serializable, NetSerializable] +public sealed partial class CharacterDepartmentRequirement : CharacterRequirement +{ + [DataField(required: true)] + public List> Departments; + + public override bool IsValid(JobPrototype job, HumanoidCharacterProfile profile, + Dictionary playTimes, bool whitelisted, + IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, + out FormattedMessage? reason) + { + var departments = new List(); + + // Get the department names and colors + foreach (var d in Departments) + { + var deptProto = prototypeManager.Index(d); + var color = deptProto.Color; + + departments.Add(FormattedMessage.FromMarkup($"[color={color.ToHex()}]{Loc.GetString($"department-{deptProto.ID}")}[/color]")); + } + + // Join the department names + var departmentsList = string.Join(", ", departments.Select(d => d.ToMarkup())); + var departmentsString = Loc.GetString("character-department-requirement", + ("inverted", Inverted), ("departments", departmentsList)); + + reason = FormattedMessage.FromMarkup(departmentsString); + return Departments.Any(d => prototypeManager.Index(d).Roles.Contains(job.ID)); + } +} + +/// +/// Requires the playtime for a department to be within a certain range +/// +[UsedImplicitly] +[Serializable, NetSerializable] +public sealed partial class CharacterDepartmentTimeRequirement : CharacterRequirement +{ + [DataField] + public TimeSpan Min = TimeSpan.MinValue; + + [DataField] + public TimeSpan Max = TimeSpan.MaxValue; + + [DataField(required: true)] + public ProtoId Department; + + public override bool IsValid(JobPrototype job, HumanoidCharacterProfile profile, + Dictionary playTimes, bool whitelisted, + IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, + out FormattedMessage? reason) + { + // Disable the requirement if the role timers are disabled + if (!configManager.GetCVar(CCVars.GameRoleTimers)) + { + reason = null; + return !Inverted; + } + + var department = prototypeManager.Index(Department); + + // Combine all of this department's job playtimes + var playtime = TimeSpan.Zero; + foreach (var other in department.Roles) + { + var proto = prototypeManager.Index(other).PlayTimeTracker; + + playTimes.TryGetValue(proto, out var otherTime); + playtime += otherTime; + } + + if (playtime > Max) + { + // Show the reason if invalid + reason = Inverted + ? null + : FormattedMessage.FromMarkup(Loc.GetString("character-timer-department-too-high", + ("time", playtime.TotalMinutes - Max.TotalMinutes), + ("department", Loc.GetString($"department-{department.ID}")), + ("departmentColor", department.Color))); + return false; + } + + if (playtime < Min) + { + // Show the reason if invalid + reason = Inverted + ? null + : FormattedMessage.FromMarkup(Loc.GetString("character-timer-department-insufficient", + ("time", Min.TotalMinutes - playtime.TotalMinutes), + ("department", Loc.GetString($"department-{department.ID}")), + ("departmentColor", department.Color))); + return false; + } + + reason = null; + return true; + } +} + +/// +/// Requires the player to have a certain amount of overall job time +/// +[UsedImplicitly] +[Serializable, NetSerializable] +public sealed partial class CharacterOverallTimeRequirement : CharacterRequirement +{ + [DataField] + public TimeSpan Min = TimeSpan.MinValue; + + [DataField] + public TimeSpan Max = TimeSpan.MaxValue; + + public override bool IsValid(JobPrototype job, HumanoidCharacterProfile profile, + Dictionary playTimes, bool whitelisted, + IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, + out FormattedMessage? reason) + { + // Disable the requirement if the role timers are disabled + if (!configManager.GetCVar(CCVars.GameRoleTimers)) + { + reason = null; + return !Inverted; + } + + // Get the overall time + var overallTime = playTimes.GetValueOrDefault(PlayTimeTrackingShared.TrackerOverall); + + if (overallTime > Max) + { + // Show the reason if invalid + reason = Inverted + ? null + : FormattedMessage.FromMarkup(Loc.GetString("character-timer-overall-too-high", + ("time", overallTime.TotalMinutes - Max.TotalMinutes))); + return false; + } + + if (overallTime < Min) + { + // Show the reason if invalid + reason = Inverted + ? null + : FormattedMessage.FromMarkup(Loc.GetString("character-timer-overall-insufficient", + ("time", Min.TotalMinutes - overallTime.TotalMinutes))); + return false; + } + + reason = null; + return true; + } +} + +/// +/// Requires the playtime for a tracker to be within a certain range +/// +[UsedImplicitly] +[Serializable, NetSerializable] +public sealed partial class CharacterPlaytimeRequirement : CharacterRequirement +{ + [DataField] + public TimeSpan Min = TimeSpan.MinValue; + + [DataField] + public TimeSpan Max = TimeSpan.MaxValue; + + [DataField(required: true)] + public ProtoId Tracker; + + public override bool IsValid(JobPrototype job, HumanoidCharacterProfile profile, + Dictionary playTimes, bool whitelisted, + IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, + out FormattedMessage? reason) + { + // Disable the requirement if the role timers are disabled + if (!configManager.GetCVar(CCVars.GameRoleTimers)) + { + reason = null; + return !Inverted; + } + + // Get SharedJobSystem + if (!entityManager.EntitySysManager.TryGetEntitySystem(out SharedJobSystem? jobSystem)) + { + DebugTools.Assert("CharacterRequirements: SharedJobSystem not found"); + reason = null; + return false; + } + + // Get the JobPrototype of the Tracker + var trackerJob = jobSystem.GetJobPrototype(Tracker); + var jobStr = prototypeManager.Index(trackerJob).LocalizedName; + + // Get the primary department of the Tracker + if (!jobSystem.TryGetPrimaryDepartment(trackerJob, out var department) && + !jobSystem.TryGetDepartment(trackerJob, out department)) + { + DebugTools.Assert($"CharacterRequirements: Department not found for job {trackerJob}"); + reason = null; + return false; + } + + // Get the time for the tracker + var time = playTimes.GetValueOrDefault(Tracker); + reason = null; + + if (time > Max) + { + // Show the reason if invalid + reason = Inverted + ? null + : FormattedMessage.FromMarkup(Loc.GetString("character-timer-role-too-high", + ("time", time.TotalMinutes - Max.TotalMinutes), + ("job", jobStr), + ("departmentColor", department.Color))); + return false; + } + + if (time < Min) + { + // Show the reason if invalid + reason = Inverted + ? null + : FormattedMessage.FromMarkup(Loc.GetString("character-timer-role-insufficient", + ("time", Min.TotalMinutes - time.TotalMinutes), + ("job", jobStr), + ("departmentColor", department.Color))); + return false; + } + + return true; + } +} diff --git a/Content.Shared/Customization/Systems/CharacterRequirements.Profile.cs b/Content.Shared/Customization/Systems/CharacterRequirements.Profile.cs new file mode 100644 index 00000000000..aaeae107b9e --- /dev/null +++ b/Content.Shared/Customization/Systems/CharacterRequirements.Profile.cs @@ -0,0 +1,157 @@ +using System.Linq; +using Content.Shared.Clothing.Loadouts.Prototypes; +using Content.Shared.Humanoid.Prototypes; +using Content.Shared.Preferences; +using Content.Shared.Roles; +using Content.Shared.Traits; +using JetBrains.Annotations; +using Robust.Shared.Configuration; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +using Robust.Shared.Utility; + +namespace Content.Shared.Customization.Systems; + + +/// +/// Requires the profile to be within an age range +/// +[UsedImplicitly] +[Serializable, NetSerializable] +public sealed partial class CharacterAgeRequirement : CharacterRequirement +{ + [DataField(required: true)] + public int Min; + + [DataField(required: true)] + public int Max; + + public override bool IsValid(JobPrototype job, HumanoidCharacterProfile profile, + Dictionary playTimes, bool whitelisted, + IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, + out FormattedMessage? reason) + { + reason = FormattedMessage.FromMarkup(Loc.GetString("character-age-requirement", + ("inverted", Inverted), ("min", Min), ("max", Max))); + return profile.Age >= Min && profile.Age <= Max; + } +} + +/// +/// Requires the profile to use either a Backpack, Satchel, or Duffelbag +/// +[UsedImplicitly] +[Serializable, NetSerializable] +public sealed partial class CharacterBackpackTypeRequirement : CharacterRequirement +{ + [DataField(required: true)] + public BackpackPreference Preference; + + public override bool IsValid(JobPrototype job, HumanoidCharacterProfile profile, + Dictionary playTimes, bool whitelisted, + IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, + out FormattedMessage? reason) + { + reason = FormattedMessage.FromMarkup(Loc.GetString("character-backpack-type-requirement", + ("inverted", Inverted), + ("type", Loc.GetString($"humanoid-profile-editor-preference-{Preference.ToString().ToLower()}")))); + return profile.Backpack == Preference; + } +} + +/// +/// Requires the profile to use either Jumpsuits or Jumpskirts +/// +[UsedImplicitly] +[Serializable, NetSerializable] +public sealed partial class CharacterClothingPreferenceRequirement : CharacterRequirement +{ + [DataField(required: true)] + public ClothingPreference Preference; + + public override bool IsValid(JobPrototype job, HumanoidCharacterProfile profile, + Dictionary playTimes, bool whitelisted, + IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, + out FormattedMessage? reason) + { + reason = FormattedMessage.FromMarkup(Loc.GetString("character-clothing-preference-requirement", + ("inverted", Inverted), + ("preference", Loc.GetString($"humanoid-profile-editor-preference-{Preference.ToString().ToLower()}")))); + return profile.Clothing == Preference; + } +} + +/// +/// Requires the profile to be a certain species +/// +[UsedImplicitly] +[Serializable, NetSerializable] +public sealed partial class CharacterSpeciesRequirement : CharacterRequirement +{ + [DataField(required: true)] + public List> Species; + + public override bool IsValid(JobPrototype job, HumanoidCharacterProfile profile, + Dictionary playTimes, bool whitelisted, + IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, + out FormattedMessage? reason) + { + const string color = "green"; + reason = FormattedMessage.FromMarkup(Loc.GetString("character-species-requirement", + ("inverted", Inverted), + ("species", $"[color={color}]{string.Join($"[/color], [color={color}]", + Species.Select(s => Loc.GetString(prototypeManager.Index(s).Name)))}[/color]"))); + + return Species.Contains(profile.Species); + } +} + +/// +/// Requires the profile to have one of the specified traits +/// +[UsedImplicitly] +[Serializable, NetSerializable] +public sealed partial class CharacterTraitRequirement : CharacterRequirement +{ + [DataField(required: true)] + public List> Traits; + + public override bool IsValid(JobPrototype job, HumanoidCharacterProfile profile, + Dictionary playTimes, bool whitelisted, + IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, + out FormattedMessage? reason) + { + const string color = "lightblue"; + reason = FormattedMessage.FromMarkup(Loc.GetString("character-trait-requirement", + ("inverted", Inverted), + ("traits", $"[color={color}]{string.Join($"[/color], [color={color}]", + Traits.Select(t => Loc.GetString($"trait-name-{t}")))}[/color]"))); + + return Traits.Any(t => profile.TraitPreferences.Contains(t.ToString())); + } +} + +/// +/// Requires the profile to have one of the specified loadouts +/// +[UsedImplicitly] +[Serializable, NetSerializable] +public sealed partial class CharacterLoadoutRequirement : CharacterRequirement +{ + [DataField(required: true)] + public List> Loadouts; + + public override bool IsValid(JobPrototype job, HumanoidCharacterProfile profile, + Dictionary playTimes, bool whitelisted, + IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, + out FormattedMessage? reason) + { + const string color = "lightblue"; + reason = FormattedMessage.FromMarkup(Loc.GetString("character-loadout-requirement", + ("inverted", Inverted), + ("loadouts", $"[color={color}]{string.Join($"[/color], [color={color}]", + Loadouts.Select(l => Loc.GetString($"loadout-name-{l}")))}[/color]"))); + + return Loadouts.Any(l => profile.LoadoutPreferences.Contains(l.ToString())); + } +} diff --git a/Content.Shared/Customization/Systems/CharacterRequirements.Whitelist.cs b/Content.Shared/Customization/Systems/CharacterRequirements.Whitelist.cs new file mode 100644 index 00000000000..56465251cdd --- /dev/null +++ b/Content.Shared/Customization/Systems/CharacterRequirements.Whitelist.cs @@ -0,0 +1,28 @@ +using Content.Shared.CCVar; +using Content.Shared.Preferences; +using Content.Shared.Roles; +using JetBrains.Annotations; +using Robust.Shared.Configuration; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +using Robust.Shared.Utility; + +namespace Content.Shared.Customization.Systems; + + +/// +/// Requires the player to be whitelisted if whitelists are enabled +/// +[UsedImplicitly] +[Serializable, NetSerializable] +public sealed partial class CharacterWhitelistRequirement : CharacterRequirement +{ + public override bool IsValid(JobPrototype job, HumanoidCharacterProfile profile, + Dictionary playTimes, bool whitelisted, + IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, + out FormattedMessage? reason) + { + reason = FormattedMessage.FromMarkup(Loc.GetString("character-whitelist-requirement", ("inverted", Inverted))); + return !configManager.GetCVar(CCVars.WhitelistEnabled) || whitelisted; + } +} diff --git a/Content.Shared/Customization/Systems/CharacterRequirements.cs b/Content.Shared/Customization/Systems/CharacterRequirements.cs index 4e862aa69e3..b347c9787af 100644 --- a/Content.Shared/Customization/Systems/CharacterRequirements.cs +++ b/Content.Shared/Customization/Systems/CharacterRequirements.cs @@ -1,12 +1,5 @@ -using System.Linq; -using Content.Shared.CCVar; -using Content.Shared.Clothing.Loadouts.Prototypes; -using Content.Shared.Humanoid.Prototypes; -using Content.Shared.Players.PlayTimeTracking; using Content.Shared.Preferences; using Content.Shared.Roles; -using Content.Shared.Roles.Jobs; -using Content.Shared.Traits; using JetBrains.Annotations; using Robust.Shared.Configuration; using Robust.Shared.Prototypes; @@ -22,459 +15,25 @@ public abstract partial class CharacterRequirement { /// /// If true valid requirements will be treated as invalid and vice versa + /// This inversion is done by other systems like , not this one /// [DataField] public bool Inverted; /// /// Checks if this character requirement is valid for the given parameters + ///
+ /// You should probably not be calling this directly, use ///
/// Description for the requirement, shown when not null public abstract bool IsValid( - IPrototype prototype, JobPrototype job, HumanoidCharacterProfile profile, Dictionary playTimes, + bool whitelisted, IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, out FormattedMessage? reason ); } - - -#region HumanoidCharacterProfile - -/// -/// Requires the profile to be within an age range -/// -[UsedImplicitly] -[Serializable, NetSerializable] -public sealed partial class CharacterAgeRequirement : CharacterRequirement -{ - [DataField(required: true)] - public int Min; - - [DataField(required: true)] - public int Max; - - public override bool IsValid(IPrototype prototype, JobPrototype job, HumanoidCharacterProfile profile, - Dictionary playTimes, - IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, - out FormattedMessage? reason) - { - reason = FormattedMessage.FromMarkup(Loc.GetString("character-age-requirement", - ("inverted", Inverted), ("min", Min), ("max", Max))); - return profile.Age >= Min && profile.Age <= Max; - } -} - -/// -/// Requires the profile to use either a Backpack, Satchel, or Duffelbag -/// -[UsedImplicitly] -[Serializable, NetSerializable] -public sealed partial class CharacterBackpackTypeRequirement : CharacterRequirement -{ - [DataField(required: true)] - public BackpackPreference Preference; - - public override bool IsValid(IPrototype prototype, JobPrototype job, HumanoidCharacterProfile profile, - Dictionary playTimes, - IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, - out FormattedMessage? reason) - { - reason = FormattedMessage.FromMarkup(Loc.GetString("character-backpack-type-requirement", - ("inverted", Inverted), - ("type", Loc.GetString($"humanoid-profile-editor-preference-{Preference.ToString().ToLower()}")))); - return profile.Backpack == Preference; - } -} - -/// -/// Requires the profile to use either Jumpsuits or Jumpskirts -/// -[UsedImplicitly] -[Serializable, NetSerializable] -public sealed partial class CharacterClothingPreferenceRequirement : CharacterRequirement -{ - [DataField(required: true)] - public ClothingPreference Preference; - - public override bool IsValid(IPrototype prototype, JobPrototype job, HumanoidCharacterProfile profile, - Dictionary playTimes, - IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, - out FormattedMessage? reason) - { - reason = FormattedMessage.FromMarkup(Loc.GetString("character-clothing-preference-requirement", - ("inverted", Inverted), - ("preference", Loc.GetString($"humanoid-profile-editor-preference-{Preference.ToString().ToLower()}")))); - return profile.Clothing == Preference; - } -} - -/// -/// Requires the profile to be a certain species -/// -[UsedImplicitly] -[Serializable, NetSerializable] -public sealed partial class CharacterSpeciesRequirement : CharacterRequirement -{ - [DataField(required: true)] - public List> Species; - - public override bool IsValid(IPrototype prototype, JobPrototype job, HumanoidCharacterProfile profile, - Dictionary playTimes, - IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, - out FormattedMessage? reason) - { - const string color = "green"; - reason = FormattedMessage.FromMarkup(Loc.GetString("character-species-requirement", - ("inverted", Inverted), - ("species", $"[color={color}]{string.Join($"[/color], [color={color}]", - Species.Select(s => Loc.GetString(prototypeManager.Index(s).Name)))}[/color]"))); - - return Species.Contains(profile.Species); - } -} - -/// -/// Requires the profile to have one of the specified traits -/// -[UsedImplicitly] -[Serializable, NetSerializable] -public sealed partial class CharacterTraitRequirement : CharacterRequirement -{ - [DataField(required: true)] - public List> Traits; - - public override bool IsValid(IPrototype prototype, JobPrototype job, HumanoidCharacterProfile profile, - Dictionary playTimes, - IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, - out FormattedMessage? reason) - { - const string color = "lightblue"; - reason = FormattedMessage.FromMarkup(Loc.GetString("character-trait-requirement", - ("inverted", Inverted), - ("traits", $"[color={color}]{string.Join($"[/color], [color={color}]", - Traits.Select(t => Loc.GetString($"trait-name-{t}")))}[/color]"))); - - return Traits.Any(t => profile.TraitPreferences.Contains(t.ToString())); - } -} - -/// -/// Requires the profile to have one of the specified loadouts -/// -[UsedImplicitly] -[Serializable, NetSerializable] -public sealed partial class CharacterLoadoutRequirement : CharacterRequirement -{ - [DataField(required: true)] - public List> Loadouts; - - public override bool IsValid(IPrototype prototype, JobPrototype job, HumanoidCharacterProfile profile, - Dictionary playTimes, - IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, - out FormattedMessage? reason) - { - const string color = "lightblue"; - reason = FormattedMessage.FromMarkup(Loc.GetString("character-loadout-requirement", - ("inverted", Inverted), - ("loadouts", $"[color={color}]{string.Join($"[/color], [color={color}]", - Loadouts.Select(l => Loc.GetString($"loadout-name-{l}")))}[/color]"))); - - return Loadouts.Any(l => profile.LoadoutPreferences.Contains(l.ToString())); - } -} - -#endregion - -#region Jobs - -/// -/// Requires the selected job to be one of the specified jobs -/// -[UsedImplicitly] -[Serializable, NetSerializable] -public sealed partial class CharacterJobRequirement : CharacterRequirement -{ - [DataField(required: true)] - public List> Jobs; - - public override bool IsValid(IPrototype prototype, JobPrototype job, HumanoidCharacterProfile profile, - Dictionary playTimes, - IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, - out FormattedMessage? reason) - { - var jobs = new List(); - - // Get the job names and department colors - foreach (var j in Jobs) - { - var jobProto = prototypeManager.Index(j); - var color = Color.LightBlue; - - foreach (var dept in prototypeManager.EnumeratePrototypes() - .OrderBy(d => Loc.GetString($"department-{d.ID}"))) - { - if (!dept.Roles.Contains(j)) - continue; - - color = dept.Color; - break; - } - - jobs.Add(FormattedMessage.FromMarkup($"[color={color.ToHex()}]{Loc.GetString(jobProto.Name)}[/color]")); - } - - // Join the job names - var jobsList = string.Join(", ", jobs.Select(j => j.ToMarkup())); - var jobsString = Loc.GetString("character-job-requirement", - ("inverted", Inverted), ("jobs", jobsList)); - - reason = FormattedMessage.FromMarkup(jobsString); - return Jobs.Contains(job.ID); - } -} - -/// -/// Requires the selected job to be in one of the specified departments -/// -[UsedImplicitly] -[Serializable, NetSerializable] -public sealed partial class CharacterDepartmentRequirement : CharacterRequirement -{ - [DataField(required: true)] - public List> Departments; - - public override bool IsValid(IPrototype prototype, JobPrototype job, HumanoidCharacterProfile profile, - Dictionary playTimes, - IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, - out FormattedMessage? reason) - { - var departments = new List(); - - // Get the department names and colors - foreach (var d in Departments) - { - var deptProto = prototypeManager.Index(d); - var color = deptProto.Color; - - departments.Add(FormattedMessage.FromMarkup($"[color={color.ToHex()}]{Loc.GetString($"department-{deptProto.ID}")}[/color]")); - } - - // Join the department names - var departmentsList = string.Join(", ", departments.Select(d => d.ToMarkup())); - var departmentsString = Loc.GetString("character-department-requirement", - ("inverted", Inverted), ("departments", departmentsList)); - - reason = FormattedMessage.FromMarkup(departmentsString); - return Departments.Any(d => prototypeManager.Index(d).Roles.Contains(job.ID)); - } -} - -/// -/// Requires the playtime for a department to be within a certain range -/// -[UsedImplicitly] -[Serializable, NetSerializable] -public sealed partial class CharacterDepartmentTimeRequirement : CharacterRequirement -{ - [DataField] - public TimeSpan Min = TimeSpan.MinValue; - - [DataField] - public TimeSpan Max = TimeSpan.MaxValue; - - [DataField(required: true)] - public ProtoId Department; - - public override bool IsValid(IPrototype prototype, JobPrototype job, HumanoidCharacterProfile profile, - Dictionary playTimes, - IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, - out FormattedMessage? reason) - { - // Disable the requirement if the role timers are disabled - if (!configManager.GetCVar(CCVars.GameRoleTimers)) - { - reason = null; - return !Inverted; - } - - var department = prototypeManager.Index(Department); - - // Combine all of this department's job playtimes - var playtime = TimeSpan.Zero; - foreach (var other in department.Roles) - { - var proto = prototypeManager.Index(other).PlayTimeTracker; - - playTimes.TryGetValue(proto, out var otherTime); - playtime += otherTime; - } - - if (playtime > Max) - { - // Show the reason if invalid - reason = Inverted - ? null - : FormattedMessage.FromMarkup(Loc.GetString("character-timer-department-too-high", - ("time", playtime.TotalMinutes - Max.TotalMinutes), - ("department", Loc.GetString($"department-{department.ID}")), - ("departmentColor", department.Color))); - return false; - } - - if (playtime < Min) - { - // Show the reason if invalid - reason = Inverted - ? null - : FormattedMessage.FromMarkup(Loc.GetString("character-timer-department-insufficient", - ("time", Min.TotalMinutes - playtime.TotalMinutes), - ("department", Loc.GetString($"department-{department.ID}")), - ("departmentColor", department.Color))); - return false; - } - - reason = null; - return true; - } -} - -/// -/// Requires the player to have a certain amount of overall job time -/// -[UsedImplicitly] -[Serializable, NetSerializable] -public sealed partial class CharacterOverallTimeRequirement : CharacterRequirement -{ - [DataField] - public TimeSpan Min = TimeSpan.MinValue; - - [DataField] - public TimeSpan Max = TimeSpan.MaxValue; - - public override bool IsValid(IPrototype prototype, JobPrototype job, HumanoidCharacterProfile profile, - Dictionary playTimes, - IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, - out FormattedMessage? reason) - { - // Disable the requirement if the role timers are disabled - if (!configManager.GetCVar(CCVars.GameRoleTimers)) - { - reason = null; - return !Inverted; - } - - // Get the overall time - var overallTime = playTimes.GetValueOrDefault(PlayTimeTrackingShared.TrackerOverall); - - if (overallTime > Max) - { - // Show the reason if invalid - reason = Inverted - ? null - : FormattedMessage.FromMarkup(Loc.GetString("character-timer-overall-too-high", - ("time", overallTime.TotalMinutes - Max.TotalMinutes))); - return false; - } - - if (overallTime < Min) - { - // Show the reason if invalid - reason = Inverted - ? null - : FormattedMessage.FromMarkup(Loc.GetString("character-timer-overall-insufficient", - ("time", Min.TotalMinutes - overallTime.TotalMinutes))); - return false; - } - - reason = null; - return true; - } -} - -/// -/// Requires the playtime for a tracker to be within a certain range -/// -[UsedImplicitly] -[Serializable, NetSerializable] -public sealed partial class CharacterPlaytimeRequirement : CharacterRequirement -{ - [DataField] - public TimeSpan Min = TimeSpan.MinValue; - - [DataField] - public TimeSpan Max = TimeSpan.MaxValue; - - [DataField(required: true)] - public ProtoId Tracker; - - public override bool IsValid(IPrototype prototype, JobPrototype job, HumanoidCharacterProfile profile, - Dictionary playTimes, - IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, - out FormattedMessage? reason) - { - // Disable the requirement if the role timers are disabled - if (!configManager.GetCVar(CCVars.GameRoleTimers)) - { - reason = null; - return !Inverted; - } - - // Get SharedJobSystem - if (!entityManager.EntitySysManager.TryGetEntitySystem(out SharedJobSystem? jobSystem)) - { - DebugTools.Assert("CharacterRequirements: SharedJobSystem not found"); - reason = null; - return false; - } - - // Get the JobPrototype of the Tracker - var trackerJob = jobSystem.GetJobPrototype(Tracker); - var jobStr = prototypeManager.Index(trackerJob).LocalizedName; - - // Get the primary department of the Tracker - if (!jobSystem.TryGetPrimaryDepartment(trackerJob, out var department) && - !jobSystem.TryGetDepartment(trackerJob, out department)) - { - DebugTools.Assert($"CharacterRequirements: Department not found for job {trackerJob}"); - reason = null; - return false; - } - - // Get the time for the tracker - var time = playTimes.GetValueOrDefault(Tracker); - reason = null; - - if (time > Max) - { - // Show the reason if invalid - reason = Inverted - ? null - : FormattedMessage.FromMarkup(Loc.GetString("character-timer-role-too-high", - ("time", time.TotalMinutes - Max.TotalMinutes), - ("job", jobStr), - ("departmentColor", department.Color))); - return false; - } - - if (time < Min) - { - // Show the reason if invalid - reason = Inverted - ? null - : FormattedMessage.FromMarkup(Loc.GetString("character-timer-role-insufficient", - ("time", Min.TotalMinutes - time.TotalMinutes), - ("job", jobStr), - ("departmentColor", department.Color))); - return false; - } - - return true; - } -} - -#endregion diff --git a/Content.Shared/Customization/Systems/CharacterRequirementsSystem.cs b/Content.Shared/Customization/Systems/CharacterRequirementsSystem.cs index f21971b5e68..521c4f186a2 100644 --- a/Content.Shared/Customization/Systems/CharacterRequirementsSystem.cs +++ b/Content.Shared/Customization/Systems/CharacterRequirementsSystem.cs @@ -1,3 +1,4 @@ +using System.Text; using Content.Shared.Preferences; using Content.Shared.Roles; using Robust.Shared.Configuration; @@ -9,8 +10,8 @@ namespace Content.Shared.Customization.Systems; public sealed class CharacterRequirementsSystem : EntitySystem { - public bool CheckRequirementsValid(IPrototype prototype, List requirements, JobPrototype job, - HumanoidCharacterProfile profile, Dictionary playTimes, + public bool CheckRequirementsValid(List requirements, JobPrototype job, + HumanoidCharacterProfile profile, Dictionary playTimes, bool whitelisted, IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager, out List reasons) { @@ -21,7 +22,7 @@ public bool CheckRequirementsValid(IPrototype prototype, List + /// Gets the reason text from as a . + ///
+ public FormattedMessage GetRequirementsText(List reasons) + { + var text = new StringBuilder(); + foreach (var reason in reasons) + text.Append($"\n{reason.ToMarkup()}"); + + return FormattedMessage.FromMarkup(text.ToString().Trim()); + } + + /// + /// Gets the reason text from as a markup string. + /// + public string GetRequirementsMarkup(List reasons) + { + var text = new StringBuilder(); + foreach (var reason in reasons) + text.Append($"\n{reason.ToMarkup()}"); + + return text.ToString().Trim(); + } } diff --git a/Content.Shared/DeltaV/Roles/JobRequirements.Whitelist.cs b/Content.Shared/DeltaV/Roles/JobRequirements.Whitelist.cs deleted file mode 100644 index a6e352991e9..00000000000 --- a/Content.Shared/DeltaV/Roles/JobRequirements.Whitelist.cs +++ /dev/null @@ -1,11 +0,0 @@ -using JetBrains.Annotations; -using Robust.Shared.Serialization; - -namespace Content.Shared.Roles -{ - [UsedImplicitly] - [Serializable, NetSerializable] - public sealed partial class WhitelistRequirement : JobRequirement - { - } -} diff --git a/Content.Shared/Ghost/Roles/GhostRolesEuiMessages.cs b/Content.Shared/Ghost/Roles/GhostRolesEuiMessages.cs index 8fbb931ca95..74af1e89ecc 100644 --- a/Content.Shared/Ghost/Roles/GhostRolesEuiMessages.cs +++ b/Content.Shared/Ghost/Roles/GhostRolesEuiMessages.cs @@ -1,3 +1,4 @@ +using Content.Shared.Customization.Systems; using Content.Shared.Eui; using Content.Shared.Roles; using Robust.Shared.Serialization; @@ -11,7 +12,7 @@ public struct GhostRoleInfo public string Name { get; set; } public string Description { get; set; } public string Rules { get; set; } - public HashSet? Requirements { get; set; } + public List? Requirements { get; set; } } [NetSerializable, Serializable] diff --git a/Content.Shared/Roles/AntagPrototype.cs b/Content.Shared/Roles/AntagPrototype.cs index c6acb9b7575..824ea4be4e5 100644 --- a/Content.Shared/Roles/AntagPrototype.cs +++ b/Content.Shared/Roles/AntagPrototype.cs @@ -1,3 +1,4 @@ +using Content.Shared.Customization.Systems; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; @@ -42,5 +43,5 @@ public sealed partial class AntagPrototype : IPrototype /// Requirements that must be met to opt in to this antag role. ///
[DataField("requirements")] - public HashSet? Requirements; + public List? Requirements; } diff --git a/Content.Shared/Roles/JobPrototype.cs b/Content.Shared/Roles/JobPrototype.cs index 9f158a79e08..15f8233aab8 100644 --- a/Content.Shared/Roles/JobPrototype.cs +++ b/Content.Shared/Roles/JobPrototype.cs @@ -1,4 +1,5 @@ using Content.Shared.Access; +using Content.Shared.Customization.Systems; using Content.Shared.Players.PlayTimeTracking; using Content.Shared.Roles; using Content.Shared.StatusIcon; @@ -43,7 +44,7 @@ public sealed partial class JobPrototype : IPrototype public string? LocalizedDescription => Description is null ? null : Loc.GetString(Description); [DataField("requirements")] - public HashSet? Requirements; + public List? Requirements; [DataField("joinNotifyCrew")] public bool JoinNotifyCrew { get; private set; } = false; diff --git a/Content.Shared/Roles/JobRequirements.cs b/Content.Shared/Roles/JobRequirements.cs deleted file mode 100644 index 44607fc44d9..00000000000 --- a/Content.Shared/Roles/JobRequirements.cs +++ /dev/null @@ -1,232 +0,0 @@ -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; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Utility; - -namespace Content.Shared.Roles -{ - /// - /// Abstract class for playtime and other requirements for role gates. - /// - [ImplicitDataDefinitionForInheritors] - [Serializable, NetSerializable] - public abstract partial class JobRequirement{} - - [UsedImplicitly] - [Serializable, NetSerializable] - public sealed partial class DepartmentTimeRequirement : JobRequirement - { - /// - /// Which department needs the required amount of time. - /// - [DataField("department", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string Department = default!; - - /// - /// How long (in seconds) this requirement is. - /// - [DataField("time")] public TimeSpan Time; - - /// - /// If true, requirement will return false if playtime above the specified time. - /// - /// - /// False by default.
- /// True for invert general requirement - ///
- [DataField("inverted")] public bool Inverted; - } - - [UsedImplicitly] - [Serializable, NetSerializable] - public sealed partial class RoleTimeRequirement : JobRequirement - { - /// - /// What particular role they need the time requirement with. - /// - [DataField("role", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string Role = default!; - - /// - [DataField("time")] public TimeSpan Time; - - /// - [DataField("inverted")] public bool Inverted; - } - - [UsedImplicitly] - [Serializable, NetSerializable] - public sealed partial class OverallPlaytimeRequirement : JobRequirement - { - /// - [DataField("time")] public TimeSpan Time; - - /// - [DataField("inverted")] public bool Inverted; - } - - public static class JobRequirements - { - public static bool TryRequirementsMet( - JobPrototype job, - IReadOnlyDictionary playTimes, - [NotNullWhen(false)] out FormattedMessage? reason, - IEntityManager entManager, - IPrototypeManager prototypes, - bool isWhitelisted) - { - reason = null; - if (job.Requirements == null) - return true; - - foreach (var requirement in job.Requirements) - { - if (!TryRequirementMet(requirement, playTimes, out reason, entManager, prototypes, isWhitelisted)) - return false; - } - - return true; - } - - /// - /// Returns a string with the reason why a particular requirement may not be met. - /// - public static bool TryRequirementMet( - JobRequirement requirement, - IReadOnlyDictionary playTimes, - [NotNullWhen(false)] out FormattedMessage? reason, - IEntityManager entManager, - IPrototypeManager prototypes, - bool isWhitelisted, - string? localePrefix = "role-timer-") - { - reason = null; - - switch (requirement) - { - case DepartmentTimeRequirement deptRequirement: - var playtime = TimeSpan.Zero; - - // Check all jobs' departments - var department = prototypes.Index(deptRequirement.Department); - var jobs = department.Roles; - string proto; - - // Check all jobs' playtime - foreach (var other in jobs) - { - // The schema is stored on the Job role but we want to explode if the timer isn't found anyway. - proto = prototypes.Index(other).PlayTimeTracker; - - playTimes.TryGetValue(proto, out var otherTime); - playtime += otherTime; - } - - var deptDiff = deptRequirement.Time.TotalMinutes - playtime.TotalMinutes; - - if (!deptRequirement.Inverted) - { - if (deptDiff <= 0) - return true; - - reason = FormattedMessage.FromMarkup(Loc.GetString( - $"{localePrefix}department-insufficient", - ("time", Math.Ceiling(deptDiff)), - ("department", Loc.GetString(deptRequirement.Department)), - ("departmentColor", department.Color.ToHex()))); - return false; - } - - if (deptDiff <= 0) - { - reason = FormattedMessage.FromMarkup(Loc.GetString( - $"{localePrefix}department-too-high", - ("time", -deptDiff), - ("department", Loc.GetString(deptRequirement.Department)), - ("departmentColor", department.Color.ToHex()))); - return false; - } - - return true; - - case OverallPlaytimeRequirement overallRequirement: - var overallTime = playTimes.GetValueOrDefault(PlayTimeTrackingShared.TrackerOverall); - var overallDiff = overallRequirement.Time.TotalMinutes - overallTime.TotalMinutes; - - if (!overallRequirement.Inverted) - { - if (overallDiff <= 0 || overallTime >= overallRequirement.Time) - return true; - - reason = FormattedMessage.FromMarkup(Loc.GetString( - $"{localePrefix}overall-insufficient", - ("time", Math.Ceiling(overallDiff)))); - return false; - } - - if (overallDiff <= 0 || overallTime >= overallRequirement.Time) - { - reason = FormattedMessage.FromMarkup(Loc.GetString($"{localePrefix}overall-too-high", ("time", -overallDiff))); - return false; - } - - return true; - - case RoleTimeRequirement roleRequirement: - proto = roleRequirement.Role; - - 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 = FormattedMessage.FromMarkup(Loc.GetString( - $"{localePrefix}role-insufficient", - ("time", Math.Ceiling(roleDiff)), - ("job", Loc.GetString(proto)), - ("departmentColor", departmentColor.ToHex()))); - return false; - } - - if (roleDiff <= 0) - { - reason = FormattedMessage.FromMarkup(Loc.GetString( - $"{localePrefix}role-too-high", - ("time", -roleDiff), - ("job", Loc.GetString(proto)), - ("departmentColor", departmentColor.ToHex()))); - return false; - } - - return true; - case WhitelistRequirement _: // DeltaV - Whitelist requirement - if (isWhitelisted == null) - throw new ArgumentNullException(nameof(isWhitelisted), "isWhitelisted cannot be null."); - - if (isWhitelisted) - return true; - - reason = FormattedMessage.FromMarkup(Loc.GetString("playtime-deny-reason-not-whitelisted")); - return false; - default: - throw new NotImplementedException(); - } - } - } -} diff --git a/Resources/Locale/en-US/customization/character-requirements.ftl b/Resources/Locale/en-US/customization/character-requirements.ftl index d0eeb8f9c85..a3f00dea872 100644 --- a/Resources/Locale/en-US/customization/character-requirements.ftl +++ b/Resources/Locale/en-US/customization/character-requirements.ftl @@ -1,3 +1,22 @@ +# Job +character-job-requirement = You must {$inverted -> + [true] not be + *[other] be +} one of these jobs: {$jobs} +character-department-requirement = You must {$inverted -> + [true] not be + *[other] be +} in one of these departments: {$departments} + +character-timer-department-insufficient = You require [color=yellow]{TOSTRING($time, "0")}[/color] more minutes of [color={$departmentColor}]{$department}[/color] department playtime +character-timer-department-too-high = You require [color=yellow]{TOSTRING($time, "0")}[/color] fewer minutes in [color={$departmentColor}]{$department}[/color] department +character-timer-overall-insufficient = You require [color=yellow]{TOSTRING($time, "0")}[/color] more minutes of playtime +character-timer-overall-too-high = You require [color=yellow]{TOSTRING($time, "0")}[/color] fewer minutes of playtime +character-timer-role-insufficient = You require [color=yellow]{TOSTRING($time, "0")}[/color] more minutes with [color={$departmentColor}]{$job}[/color] +character-timer-role-too-high = You require[color=yellow] {TOSTRING($time, "0")}[/color] fewer minutes with [color={$departmentColor}]{$job}[/color] + + +# Profile character-age-requirement = You must {$inverted -> [true] not be *[other] be @@ -23,18 +42,9 @@ character-clothing-preference-requirement = You must {$inverted -> *[other] wear } a [color=white]{$type}[/color] -character-job-requirement = You must {$inverted -> - [true] not be - *[other] be -} one of these jobs: {$jobs} -character-department-requirement = You must {$inverted -> + +# Whitelist +character-whitelist-requirement = You must {$inverted -> [true] not be *[other] be -} in one of these departments: {$departments} - -character-timer-department-insufficient = You require [color=yellow]{TOSTRING($time, "0")}[/color] more minutes of [color={$departmentColor}]{$department}[/color] department playtime -character-timer-department-too-high = You require [color=yellow]{TOSTRING($time, "0")}[/color] fewer minutes in [color={$departmentColor}]{$department}[/color] department -character-timer-overall-insufficient = You require [color=yellow]{TOSTRING($time, "0")}[/color] more minutes of playtime -character-timer-overall-too-high = You require [color=yellow]{TOSTRING($time, "0")}[/color] fewer minutes of playtime -character-timer-role-insufficient = You require [color=yellow]{TOSTRING($time, "0")}[/color] more minutes with [color={$departmentColor}]{$job}[/color] -character-timer-role-too-high = You require[color=yellow] {TOSTRING($time, "0")}[/color] fewer minutes with [color={$departmentColor}]{$job}[/color] +} whitelisted diff --git a/Resources/Prototypes/DeltaV/Entities/Markers/Spawners/ghost_roles.yml b/Resources/Prototypes/DeltaV/Entities/Markers/Spawners/ghost_roles.yml index 1e014aab734..8534b737888 100644 --- a/Resources/Prototypes/DeltaV/Entities/Markers/Spawners/ghost_roles.yml +++ b/Resources/Prototypes/DeltaV/Entities/Markers/Spawners/ghost_roles.yml @@ -32,8 +32,8 @@ description: ghost-role-information-listeningop-description rules: ghost-role-information-listeningop-rules requirements: # Worth considering these numbers for the goal of making sure someone willing to MRP takes this. - - !type:OverallPlaytimeRequirement - time: 259200 # 72 hours + - !type:CharacterOverallTimeRequirement + min: 259200 # 72 hours - !type:DepartmentTimeRequirement department: Security time: 40000 # 11.1 hours diff --git a/Resources/Prototypes/DeltaV/Roles/Jobs/Medical/medical_borg.yml b/Resources/Prototypes/DeltaV/Roles/Jobs/Medical/medical_borg.yml index e2047d3c200..18a4bbf3152 100644 --- a/Resources/Prototypes/DeltaV/Roles/Jobs/Medical/medical_borg.yml +++ b/Resources/Prototypes/DeltaV/Roles/Jobs/Medical/medical_borg.yml @@ -5,11 +5,11 @@ description: job-description-medical-borg playTimeTracker: JobMedicalBorg requirements: - - !type:OverallPlaytimeRequirement - time: 216000 #60 hrs + - !type:CharacterOverallTimeRequirement + min: 216000 #60 hrs - !type:DepartmentTimeRequirement department: Medical - time: 21600 #6 hrs + min: 21600 #6 hrs canBeAntag: false icon: JobIconMedicalBorg supervisors: job-supervisors-cmo diff --git a/Resources/Prototypes/DeltaV/Roles/Jobs/Security/brigmedic.yml b/Resources/Prototypes/DeltaV/Roles/Jobs/Security/brigmedic.yml index adc6f95dfd4..daf7f1195c0 100644 --- a/Resources/Prototypes/DeltaV/Roles/Jobs/Security/brigmedic.yml +++ b/Resources/Prototypes/DeltaV/Roles/Jobs/Security/brigmedic.yml @@ -6,10 +6,10 @@ requirements: - !type:DepartmentTimeRequirement department: Medical - time: 21600 # 6 hrs + min: 21600 # 6 hrs - !type:DepartmentTimeRequirement department: Security - time: 18000 # 4 hrs + min: 18000 # 4 hrs startingGear: CorpsmanGear icon: "JobIconBrigmedic" supervisors: job-supervisors-hos diff --git a/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml b/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml index 3da346cdd65..712dfcf3a06 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml @@ -85,8 +85,8 @@ description: ghost-role-information-loneop-description rules: ghost-role-information-loneop-rules requirements: - - !type:OverallPlaytimeRequirement - time: 172800 # DeltaV - 48 hours + - !type:CharacterOverallTimeRequirement + min: 172800 # DeltaV - 48 hours - !type:DepartmentTimeRequirement # DeltaV - Security dept time requirement department: Security time: 36000 # DeltaV - 10 hours diff --git a/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml b/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml index c3e682e02a9..31c08140ac7 100644 --- a/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml +++ b/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml @@ -4,11 +4,11 @@ description: job-description-mantis playTimeTracker: JobForensicMantis requirements: - - !type:OverallPlaytimeRequirement - time: 18000 + - !type:CharacterOverallTimeRequirement + min: 18000 - !type:DepartmentTimeRequirement department: Epistemics # DeltaV - Epistemics Department replacing Science - time: 3600 + min: 3600 startingGear: ForensicMantisGear icon: "JobIconForensicMantis" supervisors: job-supervisors-rd diff --git a/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Security/prisonguard.yml b/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Security/prisonguard.yml index 55d86d343dc..12c859b7d8c 100644 --- a/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Security/prisonguard.yml +++ b/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Security/prisonguard.yml @@ -4,11 +4,11 @@ description: job-description-guard playTimeTracker: JobPrisonGuard requirements: - - !type:OverallPlaytimeRequirement - time: 18000 + - !type:CharacterOverallTimeRequirement + min: 18000 - !type:DepartmentTimeRequirement department: Security - time: 14400 + min: 14400 startingGear: PrisonGuardGear alwaysUseSpawner: true canBeAntag: false diff --git a/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Wildcards/gladiator.yml b/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Wildcards/gladiator.yml index 498477eb229..3651d223d77 100644 --- a/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Wildcards/gladiator.yml +++ b/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Wildcards/gladiator.yml @@ -13,7 +13,7 @@ requirements: - !type:DepartmentTimeRequirement department: Security - time: 21600 + min: 21600 special: - !type:AddComponentSpecial components: diff --git a/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Wildcards/martialartist.yml b/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Wildcards/martialartist.yml index 14c277ff7e5..8c3c80c72fd 100644 --- a/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Wildcards/martialartist.yml +++ b/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Wildcards/martialartist.yml @@ -4,8 +4,8 @@ description: job-description-martialartist playTimeTracker: JobMartialArtist requirements: - - !type:OverallPlaytimeRequirement - time: 7200 #2 hours + - !type:CharacterOverallTimeRequirement + min: 7200 #2 hours startingGear: MartialArtistGear icon: "JobIconMartialArtist" supervisors: job-supervisors-hop diff --git a/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Wildcards/prisoner.yml b/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Wildcards/prisoner.yml index 9df4832a584..00ffdde666f 100644 --- a/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Wildcards/prisoner.yml +++ b/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Wildcards/prisoner.yml @@ -12,7 +12,7 @@ requirements: - !type:DepartmentTimeRequirement department: Security - time: 21600 + min: 21600 - type: startingGear id: PrisonerGear diff --git a/Resources/Prototypes/Roles/Antags/ninja.yml b/Resources/Prototypes/Roles/Antags/ninja.yml index 23027805a1c..fd8a79ad254 100644 --- a/Resources/Prototypes/Roles/Antags/ninja.yml +++ b/Resources/Prototypes/Roles/Antags/ninja.yml @@ -5,5 +5,5 @@ setPreference: false objective: roles-antag-space-ninja-objective requirements: - - !type:OverallPlaytimeRequirement # DeltaV - Playtime requirement - time: 259200 # DeltaV - 72 hours + - !type:CharacterOverallTimeRequirement # DeltaV - Playtime requirement + min: 259200 # DeltaV - 72 hours diff --git a/Resources/Prototypes/Roles/Antags/nukeops.yml b/Resources/Prototypes/Roles/Antags/nukeops.yml index 7375c02639c..fe05393b9ca 100644 --- a/Resources/Prototypes/Roles/Antags/nukeops.yml +++ b/Resources/Prototypes/Roles/Antags/nukeops.yml @@ -5,11 +5,11 @@ setPreference: true objective: roles-antag-nuclear-operative-objective requirements: - - !type:OverallPlaytimeRequirement - time: 108000 # DeltaV - 30 hours - - !type:DepartmentTimeRequirement # DeltaV - Security dept time requirement + - !type:CharacterOverallTimeRequirement + min: 108000 # DeltaV - 30 hours + - !type:CharacterDepartmentTimeRequirement # DeltaV - Security dept time requirement department: Security - time: 36000 # DeltaV - 10 hours + min: 36000 # DeltaV - 10 hours - type: antag id: NukeopsMedic @@ -18,11 +18,11 @@ setPreference: true objective: roles-antag-nuclear-operative-agent-objective requirements: - - !type:OverallPlaytimeRequirement - time: 108000 # DeltaV - 30 hours - - !type:DepartmentTimeRequirement # DeltaV - Medical dept time requirement + - !type:CharacterOverallTimeRequirement + min: 108000 # DeltaV - 30 hours + - !type:CharacterDepartmentTimeRequirement # DeltaV - Medical dept time requirement department: Medical - time: 36000 # DeltaV - 10 hours + min: 36000 # DeltaV - 10 hours - type: antag id: NukeopsCommander @@ -31,12 +31,12 @@ setPreference: true objective: roles-antag-nuclear-operative-commander-objective requirements: - - !type:OverallPlaytimeRequirement - time: 216000 # DeltaV - 60 hours - - !type:DepartmentTimeRequirement # DeltaV - Security dept time requirement + - !type:CharacterOverallTimeRequirement + min: 216000 # DeltaV - 60 hours + - !type:CharacterDepartmentTimeRequirement # DeltaV - Security dept time requirement department: Security - time: 36000 # DeltaV - 10 hours - - !type:DepartmentTimeRequirement # DeltaV - Command dept time requirement + min: 36000 # DeltaV - 10 hours + - !type:CharacterDepartmentTimeRequirement # DeltaV - Command dept time requirement department: Command - time: 36000 # DeltaV - 10 hours + min: 36000 # DeltaV - 10 hours - !type:WhitelistRequirement # DeltaV - Whitelist requirement diff --git a/Resources/Prototypes/Roles/Antags/revolutionary.yml b/Resources/Prototypes/Roles/Antags/revolutionary.yml index 6f22bd1d58a..cc551fc4679 100644 --- a/Resources/Prototypes/Roles/Antags/revolutionary.yml +++ b/Resources/Prototypes/Roles/Antags/revolutionary.yml @@ -5,11 +5,11 @@ setPreference: true objective: roles-antag-rev-head-objective requirements: - - !type:OverallPlaytimeRequirement # DeltaV - Playtime requirement - time: 172800 # DeltaV - 48 hours - - !type:DepartmentTimeRequirement # DeltaV - Command dept time requirement + - !type:CharacterOverallTimeRequirement # DeltaV - Playtime requirement + min: 172800 # DeltaV - 48 hours + - !type:CharacterDepartmentTimeRequirement # DeltaV - Command dept time requirement department: Command - time: 36000 # DeltaV - 10 hours + min: 36000 # DeltaV - 10 hours - type: antag id: Rev diff --git a/Resources/Prototypes/Roles/Antags/traitor.yml b/Resources/Prototypes/Roles/Antags/traitor.yml index 98fdb0ee47d..fec2280ddc8 100644 --- a/Resources/Prototypes/Roles/Antags/traitor.yml +++ b/Resources/Prototypes/Roles/Antags/traitor.yml @@ -5,5 +5,5 @@ setPreference: true objective: roles-antag-syndicate-agent-objective requirements: - - !type:OverallPlaytimeRequirement # DeltaV - Playtime requirement - time: 86400 # DeltaV - 24 hours + - !type:CharacterOverallTimeRequirement # DeltaV - Playtime requirement + min: 86400 # DeltaV - 24 hours diff --git a/Resources/Prototypes/Roles/Antags/zombie.yml b/Resources/Prototypes/Roles/Antags/zombie.yml index 6ff0f17edc7..5ec90f68162 100644 --- a/Resources/Prototypes/Roles/Antags/zombie.yml +++ b/Resources/Prototypes/Roles/Antags/zombie.yml @@ -5,8 +5,8 @@ setPreference: true objective: roles-antag-initial-infected-objective requirements: - - !type:OverallPlaytimeRequirement # DeltaV - Playtime requirement - time: 43200 # DeltaV - 12 hours + - !type:CharacterOverallTimeRequirement # DeltaV - Playtime requirement + min: 43200 # DeltaV - 12 hours - type: antag id: Zombie diff --git a/Resources/Prototypes/Roles/Jobs/Cargo/quartermaster.yml b/Resources/Prototypes/Roles/Jobs/Cargo/quartermaster.yml index b7e8744c6ad..ee1a101154a 100644 --- a/Resources/Prototypes/Roles/Jobs/Cargo/quartermaster.yml +++ b/Resources/Prototypes/Roles/Jobs/Cargo/quartermaster.yml @@ -8,17 +8,17 @@ # - !type:RoleTimeRequirement #DeltaV # role: JobCargoTechnician # time: 21600 #6 hrs - - !type:RoleTimeRequirement - role: JobSalvageSpecialist - time: 10800 #3 hrs - - !type:RoleTimeRequirement # DeltaV - Courier role time requirement - role: JobMailCarrier - time: 7200 # 2 hours - - !type:DepartmentTimeRequirement + - !type:CharacterPlaytimeRequirement + tracker: JobSalvageSpecialist + min: 10800 #3 hrs + - !type:CharacterPlaytimeRequirement # DeltaV - Courier role time requirement + tracker: JobMailCarrier + min: 7200 # 2 hours + - !type:CharacterDepartmentTimeRequirement department: Logistics # DeltaV - Logistics Department replacing Cargo - time: 43200 #DeltaV 12 hours - - !type:OverallPlaytimeRequirement - time: 144000 #40 hrs + min: 43200 #DeltaV 12 hours + - !type:CharacterOverallTimeRequirement + min: 144000 #40 hrs weight: 10 startingGear: QuartermasterGear icon: "JobIconQuarterMaster" diff --git a/Resources/Prototypes/Roles/Jobs/Cargo/salvage_specialist.yml b/Resources/Prototypes/Roles/Jobs/Cargo/salvage_specialist.yml index f2f7c016412..8b806009ef8 100644 --- a/Resources/Prototypes/Roles/Jobs/Cargo/salvage_specialist.yml +++ b/Resources/Prototypes/Roles/Jobs/Cargo/salvage_specialist.yml @@ -5,9 +5,9 @@ playTimeTracker: JobSalvageSpecialist antagAdvantage: 3 # DeltaV - Reduced TC: External Access + Free hardsuit and weapons requirements: - - !type:DepartmentTimeRequirement + - !type:CharacterDepartmentTimeRequirement department: Logistics # DeltaV - Logistics Department replacing Cargo - time: 21600 #DeltaV 6 hrs + min: 21600 #DeltaV 6 hrs # - !type:OverallPlaytimeRequirement #DeltaV # time: 36000 #10 hrs icon: "JobIconShaftMiner" diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/bartender.yml b/Resources/Prototypes/Roles/Jobs/Civilian/bartender.yml index 8f6f9fc7de2..85a86dabce3 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/bartender.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/bartender.yml @@ -4,9 +4,9 @@ description: job-description-bartender playTimeTracker: JobBartender requirements: - - !type:DepartmentTimeRequirement + - !type:CharacterDepartmentTimeRequirement department: Civilian - time: 3600 #DeltaV + min: 3600 #DeltaV startingGear: BartenderGear icon: "JobIconBartender" supervisors: job-supervisors-hop diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/chaplain.yml b/Resources/Prototypes/Roles/Jobs/Civilian/chaplain.yml index 7f16cf16447..9b4f5ea1487 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/chaplain.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/chaplain.yml @@ -4,9 +4,9 @@ description: job-description-chaplain playTimeTracker: JobChaplain requirements: - - !type:DepartmentTimeRequirement + - !type:CharacterDepartmentTimeRequirement department: Epistemics # DeltaV - Epistemics Department replacing Science - time: 14400 #DeltaV 4 hours + min: 14400 #DeltaV 4 hours startingGear: ChaplainGear icon: "JobIconChaplain" supervisors: job-supervisors-rd diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/chef.yml b/Resources/Prototypes/Roles/Jobs/Civilian/chef.yml index 6ae2310474d..0837f1f3907 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/chef.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/chef.yml @@ -4,9 +4,9 @@ description: job-description-chef playTimeTracker: JobChef requirements: - - !type:DepartmentTimeRequirement + - !type:CharacterDepartmentTimeRequirement department: Civilian - time: 3600 #DeltaV 1 hour + min: 3600 #DeltaV 1 hour startingGear: ChefGear icon: "JobIconChef" supervisors: job-supervisors-hop @@ -17,10 +17,10 @@ extendedAccess: - Hydroponics - Bar #Nyano - Summary: After this line, Professional Che is a component to be added. Very important. - special: + special: - !type:AddComponentSpecial components: - - type: ProfessionalChef #Nyano - End Summary. + - type: ProfessionalChef #Nyano - End Summary. - type: startingGear id: ChefGear diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/clown.yml b/Resources/Prototypes/Roles/Jobs/Civilian/clown.yml index 43e07d0637c..141f4d39b76 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/clown.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/clown.yml @@ -4,8 +4,8 @@ description: job-description-clown playTimeTracker: JobClown requirements: - - !type:OverallPlaytimeRequirement # DeltaV - Playtime requirement - time: 7200 #2 hrs + - !type:CharacterOverallTimeRequirement # DeltaV - Playtime requirement + min: 7200 #2 hrs startingGear: ClownGear icon: "JobIconClown" supervisors: job-supervisors-hop diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/lawyer.yml b/Resources/Prototypes/Roles/Jobs/Civilian/lawyer.yml index b67275c9930..838a18d5e5d 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/lawyer.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/lawyer.yml @@ -5,11 +5,11 @@ playTimeTracker: JobLawyer antagAdvantage: 2 # DeltaV - Reduced TC: Security Radio and Access requirements: - - !type:OverallPlaytimeRequirement - time: 36000 # 10 hrs - - !type:DepartmentTimeRequirement # DeltaV - Security dept time requirement + - !type:CharacterOverallTimeRequirement + min: 36000 # 10 hrs + - !type:CharacterDepartmentTimeRequirement # DeltaV - Security dept time requirement department: Security - time: 14400 # 4 hours + min: 14400 # 4 hours startingGear: LawyerGear icon: "JobIconLawyer" supervisors: job-supervisors-hop diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/librarian.yml b/Resources/Prototypes/Roles/Jobs/Civilian/librarian.yml index 536c8635d1b..7f138c6d7d1 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/librarian.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/librarian.yml @@ -4,8 +4,8 @@ description: job-description-librarian playTimeTracker: JobLibrarian requirements: - - !type:OverallPlaytimeRequirement #DeltaV - time: 3600 # 1 hr + - !type:CharacterOverallTimeRequirement #DeltaV + min: 3600 # 1 hr startingGear: LibrarianGear icon: "JobIconLibrarian" supervisors: job-supervisors-hop diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml b/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml index 8da2c34231b..3e04285d601 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml @@ -4,8 +4,8 @@ description: job-description-mime playTimeTracker: JobMime requirements: - - !type:OverallPlaytimeRequirement - time: 7200 # DeltaV - 2 hours + - !type:CharacterOverallTimeRequirement + min: 7200 # DeltaV - 2 hours startingGear: MimeGear icon: "JobIconMime" supervisors: job-supervisors-hop diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/musician.yml b/Resources/Prototypes/Roles/Jobs/Civilian/musician.yml index f873ec5fe8c..28f9c597e58 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/musician.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/musician.yml @@ -4,8 +4,8 @@ description: job-description-musician playTimeTracker: JobMusician requirements: - - !type:OverallPlaytimeRequirement - time: 7200 # DeltaV - 2 hours + - !type:CharacterOverallTimeRequirement + min: 7200 # DeltaV - 2 hours startingGear: MusicianGear icon: "JobIconMusician" supervisors: job-supervisors-hire diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/service_worker.yml b/Resources/Prototypes/Roles/Jobs/Civilian/service_worker.yml index c21fafbdaa9..8bfd05ad014 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/service_worker.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/service_worker.yml @@ -4,8 +4,8 @@ description: job-description-serviceworker playTimeTracker: JobServiceWorker requirements: - - !type:OverallPlaytimeRequirement - time: 7200 # DeltaV - 2 hours + - !type:CharacterOverallTimeRequirement + min: 7200 # DeltaV - 2 hours startingGear: ServiceWorkerGear icon: "JobIconServiceWorker" supervisors: job-supervisors-service diff --git a/Resources/Prototypes/Roles/Jobs/Command/captain.yml b/Resources/Prototypes/Roles/Jobs/Command/captain.yml index 905121dbf8e..12ad83e6e5c 100644 --- a/Resources/Prototypes/Roles/Jobs/Command/captain.yml +++ b/Resources/Prototypes/Roles/Jobs/Command/captain.yml @@ -4,26 +4,26 @@ description: job-description-captain playTimeTracker: JobCaptain requirements: - - !type:DepartmentTimeRequirement + - !type:CharacterDepartmentTimeRequirement department: Logistics # DeltaV - Logistics Department replacing Cargo - time: 18000 # DeltaV - 5 hours - - !type:DepartmentTimeRequirement + min: 18000 # DeltaV - 5 hours + - !type:CharacterDepartmentTimeRequirement department: Engineering - time: 18000 # DeltaV - 5 hours - - !type:DepartmentTimeRequirement + min: 18000 # DeltaV - 5 hours + - !type:CharacterDepartmentTimeRequirement department: Medical - time: 18000 # DeltaV - 5 hours - - !type:DepartmentTimeRequirement + min: 18000 # DeltaV - 5 hours + - !type:CharacterDepartmentTimeRequirement department: Security - time: 18000 # DeltaV - 5 hours - - !type:DepartmentTimeRequirement # DeltaV - Epistemics dept time requirement + min: 18000 # DeltaV - 5 hours + - !type:CharacterDepartmentTimeRequirement # DeltaV - Epistemics dept time requirement department: Epistemics # DeltaV - Epistemics Department replacing Science - time: 18000 # 5 hours - - !type:DepartmentTimeRequirement + min: 18000 # 5 hours + - !type:CharacterDepartmentTimeRequirement department: Command - time: 108000 # DeltaV - 30 hours - - !type:OverallPlaytimeRequirement # DeltaV - Playtime requirement - time: 108000 # 30 hours + min: 108000 # DeltaV - 30 hours + - !type:CharacterOverallTimeRequirement # DeltaV - Playtime requirement + min: 108000 # 30 hours - !type:WhitelistRequirement # DeltaV - Whitelist requirement weight: 20 startingGear: CaptainGear diff --git a/Resources/Prototypes/Roles/Jobs/Command/head_of_personnel.yml b/Resources/Prototypes/Roles/Jobs/Command/head_of_personnel.yml index f999a4b6c70..6311eb9fee6 100644 --- a/Resources/Prototypes/Roles/Jobs/Command/head_of_personnel.yml +++ b/Resources/Prototypes/Roles/Jobs/Command/head_of_personnel.yml @@ -5,20 +5,20 @@ playTimeTracker: JobHeadOfPersonnel antagAdvantage: 6 # DeltaV - Reduced TC: Head of Staff requirements: - - !type:RoleTimeRequirement - role: JobChef - time: 14400 # DeltaV - 4 hours - - !type:RoleTimeRequirement - role: JobBartender - time: 14400 # DeltaV - 4 hours - - !type:RoleTimeRequirement - role: JobJanitor - time: 14400 # DeltaV - 4 hours - - !type:DepartmentTimeRequirement # DeltaV - Civilian dept time requirement + - !type:CharacterPlaytimeRequirement + tracker: JobChef + min: 14400 # DeltaV - 4 hours + - !type:CharacterPlaytimeRequirement + tracker: JobBartender + min: 14400 # DeltaV - 4 hours + - !type:CharacterPlaytimeRequirement + tracker: JobJanitor + min: 14400 # DeltaV - 4 hours + - !type:CharacterDepartmentTimeRequirement # DeltaV - Civilian dept time requirement department: Civilian - time: 72000 # 20 hours - - !type:OverallPlaytimeRequirement # DeltaV - Playtime requirement - time: 90000 # 25 hours + min: 72000 # 20 hours + - !type:CharacterOverallTimeRequirement # DeltaV - Playtime requirement + min: 90000 # 25 hours weight: 10 # DeltaV - Changed HoP weight from 20 to 10 due to them not being more important than other Heads startingGear: HoPGear icon: "JobIconHeadOfPersonnel" diff --git a/Resources/Prototypes/Roles/Jobs/Engineering/atmospheric_technician.yml b/Resources/Prototypes/Roles/Jobs/Engineering/atmospheric_technician.yml index a188e93388d..834a85e7a08 100644 --- a/Resources/Prototypes/Roles/Jobs/Engineering/atmospheric_technician.yml +++ b/Resources/Prototypes/Roles/Jobs/Engineering/atmospheric_technician.yml @@ -5,9 +5,9 @@ playTimeTracker: JobAtmosphericTechnician antagAdvantage: 10 # DeltaV - Reduced TC: External Access + Fireaxe + Free Hardsuit requirements: - - !type:DepartmentTimeRequirement + - !type:CharacterDepartmentTimeRequirement department: Engineering - time: 36000 # DeltaV - 10 hours + min: 36000 # DeltaV - 10 hours startingGear: AtmosphericTechnicianGear icon: "JobIconAtmosphericTechnician" supervisors: job-supervisors-ce diff --git a/Resources/Prototypes/Roles/Jobs/Engineering/chief_engineer.yml b/Resources/Prototypes/Roles/Jobs/Engineering/chief_engineer.yml index 644754750a7..eaa66d6f0cc 100644 --- a/Resources/Prototypes/Roles/Jobs/Engineering/chief_engineer.yml +++ b/Resources/Prototypes/Roles/Jobs/Engineering/chief_engineer.yml @@ -4,15 +4,15 @@ description: job-description-ce playTimeTracker: JobChiefEngineer requirements: - - !type:RoleTimeRequirement - role: JobAtmosphericTechnician - time: 36000 # DeltaV - 10 hours + - !type:CharacterPlaytimeRequirement + tracker: JobAtmosphericTechnician + min: 36000 # DeltaV - 10 hours # - !type:RoleTimeRequirement # DeltaV - No Station Engineer time requirement # role: JobStationEngineer # time: 21600 #6 hrs - - !type:DepartmentTimeRequirement + - !type:CharacterDepartmentTimeRequirement department: Engineering - time: 90000 # DeltaV - 25 hours + min: 90000 # DeltaV - 25 hours # - !type:OverallPlaytimeRequirement # time: 72000 # DeltaV - 20 hours weight: 10 diff --git a/Resources/Prototypes/Roles/Jobs/Engineering/senior_engineer.yml b/Resources/Prototypes/Roles/Jobs/Engineering/senior_engineer.yml index ba8a8f6acc8..5106f1129c4 100644 --- a/Resources/Prototypes/Roles/Jobs/Engineering/senior_engineer.yml +++ b/Resources/Prototypes/Roles/Jobs/Engineering/senior_engineer.yml @@ -5,15 +5,15 @@ playTimeTracker: JobSeniorEngineer setPreference: false # DeltaV - Disable Senior Roles round start selection requirements: - - !type:RoleTimeRequirement - role: JobAtmosphericTechnician - time: 21600 #6 hrs - - !type:RoleTimeRequirement - role: JobStationEngineer - time: 21600 #6 hrs - - !type:DepartmentTimeRequirement + - !type:CharacterPlaytimeRequirement + tracker: JobAtmosphericTechnician + min: 21600 #6 hrs + - !type:CharacterPlaytimeRequirement + tracker: JobStationEngineer + min: 21600 #6 hrs + - !type:CharacterDepartmentTimeRequirement department: Engineering - time: 216000 # 60 hrs + min: 216000 # 60 hrs startingGear: SeniorEngineerGear icon: "JobIconSeniorEngineer" supervisors: job-supervisors-ce diff --git a/Resources/Prototypes/Roles/Jobs/Engineering/station_engineer.yml b/Resources/Prototypes/Roles/Jobs/Engineering/station_engineer.yml index ab62d69d501..dc590045191 100644 --- a/Resources/Prototypes/Roles/Jobs/Engineering/station_engineer.yml +++ b/Resources/Prototypes/Roles/Jobs/Engineering/station_engineer.yml @@ -5,9 +5,9 @@ playTimeTracker: JobStationEngineer antagAdvantage: 3 # DeltaV - Reduced TC: External Access + Engineering requirements: - - !type:DepartmentTimeRequirement + - !type:CharacterDepartmentTimeRequirement department: Engineering - time: 14400 #4 hrs + min: 14400 #4 hrs startingGear: StationEngineerGear icon: "JobIconStationEngineer" supervisors: job-supervisors-ce diff --git a/Resources/Prototypes/Roles/Jobs/Engineering/technical_assistant.yml b/Resources/Prototypes/Roles/Jobs/Engineering/technical_assistant.yml index e0b5a268ca2..668af727519 100644 --- a/Resources/Prototypes/Roles/Jobs/Engineering/technical_assistant.yml +++ b/Resources/Prototypes/Roles/Jobs/Engineering/technical_assistant.yml @@ -5,8 +5,8 @@ playTimeTracker: JobTechnicalAssistant antagAdvantage: 3 # DeltaV - Reduced TC: External Access + Engineering requirements: - - !type:OverallPlaytimeRequirement # DeltaV - to prevent griefers from taking the role. - time: 14400 # 4 hours + - !type:CharacterOverallTimeRequirement # DeltaV - to prevent griefers from taking the role. + min: 14400 # 4 hours # - !type:DepartmentTimeRequirement # DeltaV - Removes time limit # department: Engineering # time: 54000 #15 hrs diff --git a/Resources/Prototypes/Roles/Jobs/Medical/chemist.yml b/Resources/Prototypes/Roles/Jobs/Medical/chemist.yml index d57fe982c57..3fe22792092 100644 --- a/Resources/Prototypes/Roles/Jobs/Medical/chemist.yml +++ b/Resources/Prototypes/Roles/Jobs/Medical/chemist.yml @@ -4,9 +4,9 @@ description: job-description-chemist playTimeTracker: JobChemist requirements: - - !type:DepartmentTimeRequirement + - !type:CharacterDepartmentTimeRequirement department: Medical - time: 28800 # DeltaV - 8 hours + min: 28800 # DeltaV - 8 hours startingGear: ChemistGear icon: "JobIconChemist" supervisors: job-supervisors-cmo diff --git a/Resources/Prototypes/Roles/Jobs/Medical/chief_medical_officer.yml b/Resources/Prototypes/Roles/Jobs/Medical/chief_medical_officer.yml index aac50c526c9..4a65b791283 100644 --- a/Resources/Prototypes/Roles/Jobs/Medical/chief_medical_officer.yml +++ b/Resources/Prototypes/Roles/Jobs/Medical/chief_medical_officer.yml @@ -7,17 +7,17 @@ playTimeTracker: JobChiefMedicalOfficer antagAdvantage: 6 # DeltaV - Reduced TC: Head of Staff requirements: - - !type:RoleTimeRequirement - role: JobChemist - time: 14400 #DeltaV 4 hrs + - !type:CharacterPlaytimeRequirement + tracker: JobChemist + min: 14400 #DeltaV 4 hrs # - !type:RoleTimeRequirement # DeltaV - No Medical Doctor time requirement # role: JobMedicalDoctor # time: 21600 #6 hrs - - !type:DepartmentTimeRequirement + - !type:CharacterDepartmentTimeRequirement department: Medical - time: 43200 # DeltaV - 12 hours - - !type:OverallPlaytimeRequirement - time: 72000 # DeltaV - 20 hours + min: 43200 # DeltaV - 12 hours + - !type:CharacterOverallTimeRequirement + min: 72000 # DeltaV - 20 hours weight: 10 startingGear: CMOGear icon: "JobIconChiefMedicalOfficer" diff --git a/Resources/Prototypes/Roles/Jobs/Medical/medical_doctor.yml b/Resources/Prototypes/Roles/Jobs/Medical/medical_doctor.yml index fbc6116f46b..cc048470f0c 100644 --- a/Resources/Prototypes/Roles/Jobs/Medical/medical_doctor.yml +++ b/Resources/Prototypes/Roles/Jobs/Medical/medical_doctor.yml @@ -4,9 +4,9 @@ description: job-description-doctor playTimeTracker: JobMedicalDoctor requirements: - - !type:DepartmentTimeRequirement + - !type:CharacterDepartmentTimeRequirement department: Medical - time: 14400 #4 hrs + min: 14400 #4 hrs startingGear: DoctorGear icon: "JobIconMedicalDoctor" supervisors: job-supervisors-cmo diff --git a/Resources/Prototypes/Roles/Jobs/Medical/paramedic.yml b/Resources/Prototypes/Roles/Jobs/Medical/paramedic.yml index e4ae7a7dd50..9e3484a8dcf 100644 --- a/Resources/Prototypes/Roles/Jobs/Medical/paramedic.yml +++ b/Resources/Prototypes/Roles/Jobs/Medical/paramedic.yml @@ -8,9 +8,9 @@ # - !type:RoleTimeRequirement # DeltaV - No Medical Doctor time requirement # role: JobMedicalDoctor # time: 14400 #4 hrs - - !type:DepartmentTimeRequirement # DeltaV - Medical dept time requirement + - !type:CharacterDepartmentTimeRequirement # DeltaV - Medical dept time requirement department: Medical - time: 28800 # DeltaV - 8 hours + min: 28800 # DeltaV - 8 hours # - !type:OverallPlaytimeRequirement # DeltaV - No playtime requirement # time: 54000 # 15 hrs startingGear: ParamedicGear diff --git a/Resources/Prototypes/Roles/Jobs/Medical/senior_physician.yml b/Resources/Prototypes/Roles/Jobs/Medical/senior_physician.yml index 03473cc7cbc..ac6e0620f5a 100644 --- a/Resources/Prototypes/Roles/Jobs/Medical/senior_physician.yml +++ b/Resources/Prototypes/Roles/Jobs/Medical/senior_physician.yml @@ -5,15 +5,15 @@ playTimeTracker: JobSeniorPhysician setPreference: false # DeltaV - Disable Senior Roles round start selection requirements: - - !type:RoleTimeRequirement - role: JobChemist - time: 21600 #6 hrs - - !type:RoleTimeRequirement - role: JobMedicalDoctor - time: 21600 #6 hrs - - !type:DepartmentTimeRequirement + - !type:CharacterPlaytimeRequirement + tracker: JobChemist + min: 21600 #6 hrs + - !type:CharacterPlaytimeRequirement + tracker: JobMedicalDoctor + min: 21600 #6 hrs + - !type:CharacterDepartmentTimeRequirement department: Medical - time: 216000 # 60 hrs + min: 216000 # 60 hrs startingGear: SeniorPhysicianGear icon: "JobIconSeniorPhysician" supervisors: job-supervisors-cmo diff --git a/Resources/Prototypes/Roles/Jobs/Science/borg.yml b/Resources/Prototypes/Roles/Jobs/Science/borg.yml index fe829110051..456a761dba7 100644 --- a/Resources/Prototypes/Roles/Jobs/Science/borg.yml +++ b/Resources/Prototypes/Roles/Jobs/Science/borg.yml @@ -4,8 +4,8 @@ description: job-description-borg playTimeTracker: JobBorg requirements: - - !type:OverallPlaytimeRequirement - time: 216000 #60 hrs + - !type:CharacterOverallTimeRequirement + min: 216000 #60 hrs canBeAntag: false icon: JobIconBorg supervisors: job-supervisors-rd diff --git a/Resources/Prototypes/Roles/Jobs/Science/research_director.yml b/Resources/Prototypes/Roles/Jobs/Science/research_director.yml index 19cf1419111..6f965b31b49 100644 --- a/Resources/Prototypes/Roles/Jobs/Science/research_director.yml +++ b/Resources/Prototypes/Roles/Jobs/Science/research_director.yml @@ -5,11 +5,11 @@ playTimeTracker: JobResearchDirector antagAdvantage: 6 # DeltaV - Reduced TC: Head of Staff requirements: - - !type:DepartmentTimeRequirement + - !type:CharacterDepartmentTimeRequirement department: Epistemics # DeltaV - Epistemics Department replacing Science - time: 54000 # DeltaV - 15 hours - - !type:OverallPlaytimeRequirement - time: 72000 # DeltaV - 20 hours + min: 54000 # DeltaV - 15 hours + - !type:CharacterOverallTimeRequirement + min: 72000 # DeltaV - 20 hours weight: 10 startingGear: ResearchDirectorGear icon: "JobIconResearchDirector" diff --git a/Resources/Prototypes/Roles/Jobs/Science/scientist.yml b/Resources/Prototypes/Roles/Jobs/Science/scientist.yml index fe00a72abb1..2d91e0e6ef9 100644 --- a/Resources/Prototypes/Roles/Jobs/Science/scientist.yml +++ b/Resources/Prototypes/Roles/Jobs/Science/scientist.yml @@ -4,9 +4,9 @@ description: job-description-scientist playTimeTracker: JobScientist requirements: - - !type:DepartmentTimeRequirement + - !type:CharacterDepartmentTimeRequirement department: Epistemics # DeltaV - Epistemics Department replacing Science - time: 14400 #4 hrs + min: 14400 #4 hrs startingGear: ScientistGear icon: "JobIconScientist" supervisors: job-supervisors-rd diff --git a/Resources/Prototypes/Roles/Jobs/Science/senior_researcher.yml b/Resources/Prototypes/Roles/Jobs/Science/senior_researcher.yml index 5010c7fb26f..90234250302 100644 --- a/Resources/Prototypes/Roles/Jobs/Science/senior_researcher.yml +++ b/Resources/Prototypes/Roles/Jobs/Science/senior_researcher.yml @@ -5,9 +5,9 @@ playTimeTracker: JobSeniorResearcher setPreference: false # DeltaV - Disable Senior Roles round start selection requirements: - - !type:DepartmentTimeRequirement + - !type:CharacterDepartmentTimeRequirement department: Epistemics # DeltaV - Epistemics Department replacing Science - time: 216000 #60 hrs + min: 216000 #60 hrs startingGear: SeniorResearcherGear icon: "JobIconSeniorResearcher" supervisors: job-supervisors-rd diff --git a/Resources/Prototypes/Roles/Jobs/Security/detective.yml b/Resources/Prototypes/Roles/Jobs/Security/detective.yml index feef023b450..0ed2eba9556 100644 --- a/Resources/Prototypes/Roles/Jobs/Security/detective.yml +++ b/Resources/Prototypes/Roles/Jobs/Security/detective.yml @@ -4,9 +4,9 @@ description: job-description-detective playTimeTracker: JobDetective requirements: - - !type:DepartmentTimeRequirement + - !type:CharacterDepartmentTimeRequirement department: Security - time: 36000 # DeltaV - 10 hours + min: 36000 # DeltaV - 10 hours startingGear: DetectiveGear icon: "JobIconDetective" supervisors: job-supervisors-hos diff --git a/Resources/Prototypes/Roles/Jobs/Security/head_of_security.yml b/Resources/Prototypes/Roles/Jobs/Security/head_of_security.yml index a8b7013004e..675e7768fa7 100644 --- a/Resources/Prototypes/Roles/Jobs/Security/head_of_security.yml +++ b/Resources/Prototypes/Roles/Jobs/Security/head_of_security.yml @@ -4,17 +4,17 @@ description: job-description-hos playTimeTracker: JobHeadOfSecurity requirements: - - !type:RoleTimeRequirement - role: JobWarden - time: 14400 #DeltaV 4 hrs + - !type:CharacterPlaytimeRequirement + tracker: JobWarden + min: 14400 #DeltaV 4 hrs # - !type:RoleTimeRequirement # DeltaV - No Security Officer time requirement - REIMPLEMENT WHEN MORE PEOPLE HAVE IT # role: JobDetective # time: 14400 #DeltaV 4 hrs - - !type:DepartmentTimeRequirement # DeltaV - Command dept time requirement + - !type:CharacterDepartmentTimeRequirement # DeltaV - Command dept time requirement department: Command - time: 36000 # 10 hours - - !type:OverallPlaytimeRequirement - time: 90000 # DeltaV - 25 hours + min: 36000 # 10 hours + - !type:CharacterOverallTimeRequirement + min: 90000 # DeltaV - 25 hours - !type:WhitelistRequirement # DeltaV - Whitelist requirement weight: 10 startingGear: HoSGear diff --git a/Resources/Prototypes/Roles/Jobs/Security/security_cadet.yml b/Resources/Prototypes/Roles/Jobs/Security/security_cadet.yml index 324b697baff..0b28af78502 100644 --- a/Resources/Prototypes/Roles/Jobs/Security/security_cadet.yml +++ b/Resources/Prototypes/Roles/Jobs/Security/security_cadet.yml @@ -4,8 +4,8 @@ description: job-description-cadet playTimeTracker: JobSecurityCadet requirements: - - !type:OverallPlaytimeRequirement - time: 14400 # DeltaV - 4 hours + - !type:CharacterOverallTimeRequirement + min: 14400 # DeltaV - 4 hours # - !type:DepartmentTimeRequirement # DeltaV - Removes time limit # department: Security # time: 54000 #15 hrs diff --git a/Resources/Prototypes/Roles/Jobs/Security/security_officer.yml b/Resources/Prototypes/Roles/Jobs/Security/security_officer.yml index 695464e030f..b81cef667ed 100644 --- a/Resources/Prototypes/Roles/Jobs/Security/security_officer.yml +++ b/Resources/Prototypes/Roles/Jobs/Security/security_officer.yml @@ -4,9 +4,9 @@ description: job-description-security playTimeTracker: JobSecurityOfficer requirements: - - !type:DepartmentTimeRequirement + - !type:CharacterDepartmentTimeRequirement department: Security - time: 14400 # DeltaV - 4 hours + min: 14400 # DeltaV - 4 hours startingGear: SecurityOfficerGear icon: "JobIconSecurityOfficer" supervisors: job-supervisors-hos diff --git a/Resources/Prototypes/Roles/Jobs/Security/senior_officer.yml b/Resources/Prototypes/Roles/Jobs/Security/senior_officer.yml index 99167b8cd41..2623adf1fd0 100644 --- a/Resources/Prototypes/Roles/Jobs/Security/senior_officer.yml +++ b/Resources/Prototypes/Roles/Jobs/Security/senior_officer.yml @@ -5,18 +5,18 @@ playTimeTracker: JobSeniorOfficer setPreference: false # DeltaV - Disable Senior Roles round start selection requirements: - - !type:RoleTimeRequirement - role: JobWarden - time: 21600 #6 hrs - - !type:RoleTimeRequirement - role: JobDetective - time: 7200 #2 hrs - - !type:RoleTimeRequirement - role: JobSecurityOfficer - time: 21600 #6 hrs - - !type:DepartmentTimeRequirement + - !type:CharacterPlaytimeRequirement + tracker: JobWarden + min: 21600 #6 hrs + - !type:CharacterPlaytimeRequirement + tracker: JobDetective + min: 7200 #2 hrs + - !type:CharacterPlaytimeRequirement + tracker: JobSecurityOfficer + min: 21600 #6 hrs + - !type:CharacterDepartmentTimeRequirement department: Security - time: 216000 # 60 hrs + min: 216000 # 60 hrs startingGear: SeniorOfficerGear icon: "JobIconSeniorOfficer" supervisors: job-supervisors-hos diff --git a/Resources/Prototypes/Roles/Jobs/Security/warden.yml b/Resources/Prototypes/Roles/Jobs/Security/warden.yml index 3b7697cb680..a4c5c5a8fab 100644 --- a/Resources/Prototypes/Roles/Jobs/Security/warden.yml +++ b/Resources/Prototypes/Roles/Jobs/Security/warden.yml @@ -4,12 +4,12 @@ description: job-description-warden playTimeTracker: JobWarden requirements: - - !type:RoleTimeRequirement # DeltaV - JobSecurityOfficer time requirement. Make them experienced in proper officer work. - role: JobSecurityOfficer - time: 43200 # DeltaV - 12 hrs - - !type:RoleTimeRequirement # DeltaV - JobDetective time requirement. Give them an understanding of basic forensics. - role: JobDetective - time: 14400 # DeltaV - 4 hours + - !type:CharacterPlaytimeRequirement # DeltaV - JobSecurityOfficer time requirement. Make them experienced in proper officer work. + tracker: JobSecurityOfficer + min: 43200 # DeltaV - 12 hrs + - !type:CharacterPlaytimeRequirement # DeltaV - JobDetective time requirement. Give them an understanding of basic forensics. + tracker: JobDetective + min: 14400 # DeltaV - 4 hours - !type:WhitelistRequirement # DeltaV - Whitelist requirement startingGear: WardenGear icon: "JobIconWarden" diff --git a/Resources/Prototypes/Roles/Jobs/Wildcards/boxer.yml b/Resources/Prototypes/Roles/Jobs/Wildcards/boxer.yml index ea2faf14467..33def38bb08 100644 --- a/Resources/Prototypes/Roles/Jobs/Wildcards/boxer.yml +++ b/Resources/Prototypes/Roles/Jobs/Wildcards/boxer.yml @@ -4,8 +4,8 @@ description: job-description-boxer playTimeTracker: JobBoxer requirements: - - !type:OverallPlaytimeRequirement - time: 7200 #DeltaV 2 hours + - !type:CharacterOverallTimeRequirement + min: 7200 #DeltaV 2 hours startingGear: BoxerGear icon: "JobIconBoxer" supervisors: job-supervisors-hop diff --git a/Resources/Prototypes/Roles/Jobs/Wildcards/psychologist.yml b/Resources/Prototypes/Roles/Jobs/Wildcards/psychologist.yml index 7687049b685..a2974c6eb7a 100644 --- a/Resources/Prototypes/Roles/Jobs/Wildcards/psychologist.yml +++ b/Resources/Prototypes/Roles/Jobs/Wildcards/psychologist.yml @@ -4,11 +4,11 @@ description: job-description-psychologist playTimeTracker: JobPsychologist requirements: - - !type:OverallPlaytimeRequirement - time: 36000 #DeltaV 10 hours - - !type:DepartmentTimeRequirement + - !type:CharacterOverallTimeRequirement + min: 36000 #DeltaV 10 hours + - !type:CharacterDepartmentTimeRequirement department: Medical - time: 14400 #DeltaV 4 hrs + min: 14400 #DeltaV 4 hrs startingGear: PsychologistGear icon: "JobIconPsychologist" supervisors: job-supervisors-cmo diff --git a/Resources/Prototypes/Roles/Jobs/Wildcards/reporter.yml b/Resources/Prototypes/Roles/Jobs/Wildcards/reporter.yml index 6f7093f3ae5..ad810e970e9 100644 --- a/Resources/Prototypes/Roles/Jobs/Wildcards/reporter.yml +++ b/Resources/Prototypes/Roles/Jobs/Wildcards/reporter.yml @@ -4,8 +4,8 @@ description: job-description-reporter playTimeTracker: JobReporter requirements: - - !type:OverallPlaytimeRequirement - time: 7200 #DeltaV 2 hours + - !type:CharacterOverallTimeRequirement + min: 7200 #DeltaV 2 hours startingGear: ReporterGear icon: "JobIconReporter" supervisors: job-supervisors-hop diff --git a/Resources/Prototypes/Roles/Jobs/Wildcards/zookeeper.yml b/Resources/Prototypes/Roles/Jobs/Wildcards/zookeeper.yml index 04d10513331..1686e3290fa 100644 --- a/Resources/Prototypes/Roles/Jobs/Wildcards/zookeeper.yml +++ b/Resources/Prototypes/Roles/Jobs/Wildcards/zookeeper.yml @@ -4,8 +4,8 @@ description: job-description-zookeeper playTimeTracker: JobZookeeper requirements: - - !type:OverallPlaytimeRequirement - time: 7200 #DeltaV 2 hours + - !type:CharacterOverallTimeRequirement + min: 7200 #DeltaV 2 hours startingGear: ZookeeperGear icon: "JobIconZookeeper" supervisors: job-supervisors-hop