diff --git a/Content.IntegrationTests/Tests/Minds/JobTests.cs b/Content.IntegrationTests/Tests/Minds/JobTests.cs new file mode 100644 index 0000000000..5172049a99 --- /dev/null +++ b/Content.IntegrationTests/Tests/Minds/JobTests.cs @@ -0,0 +1,48 @@ +using Content.Shared.Roles; +using Content.Shared.Roles.Jobs; +using Robust.Shared.Prototypes; +using System.Linq; + +namespace Content.IntegrationTests.Tests.Station; + +[TestFixture] +[TestOf(typeof(SharedJobSystem))] +public sealed class JobTest +{ + /// + /// Ensures that every job belongs to at most 1 primary department. + /// Having no primary department is ok. + /// + [Test] + public async Task PrimaryDepartmentsTest() + { + await using var pair = await PoolManager.GetServerClient(); + var server = pair.Server; + + var prototypeManager = server.ResolveDependency(); + + await server.WaitAssertion(() => + { + // only checking primary departments so don't bother with others + var departments = prototypeManager.EnumeratePrototypes() + .Where(department => department.Primary) + .ToList(); + var jobs = prototypeManager.EnumeratePrototypes(); + foreach (var job in jobs) + { + // not actually using the jobs system since that will return the first department + // and we need to test that there is never more than 1, so it not sorting them is correct + var primaries = 0; + foreach (var department in departments) + { + if (!department.Roles.Contains(job.ID)) + continue; + + primaries++; + Assert.That(primaries, Is.EqualTo(1), $"The job {job.ID} has more than 1 primary department!"); + } + } + }); + await pair.CleanReturnAsync(); + } +} diff --git a/Content.Shared/Roles/DepartmentPrototype.cs b/Content.Shared/Roles/DepartmentPrototype.cs index f91d1a43fd..b3549d9584 100644 --- a/Content.Shared/Roles/DepartmentPrototype.cs +++ b/Content.Shared/Roles/DepartmentPrototype.cs @@ -23,4 +23,11 @@ public sealed partial class DepartmentPrototype : IPrototype [ViewVariables(VVAccess.ReadWrite), DataField("roles", customTypeSerializer: typeof(PrototypeIdListSerializer))] public List Roles = new(); + + /// + /// Whether this is a primary department or not. + /// For example, CE's primary department is engineering since Command has primary: false. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public bool Primary = true; } diff --git a/Content.Shared/Roles/Jobs/SharedJobSystem.cs b/Content.Shared/Roles/Jobs/SharedJobSystem.cs index fe0f9d115b..04ac45c4c5 100644 --- a/Content.Shared/Roles/Jobs/SharedJobSystem.cs +++ b/Content.Shared/Roles/Jobs/SharedJobSystem.cs @@ -76,6 +76,30 @@ public abstract class SharedJobSystem : EntitySystem return false; } + /// + /// Like but ignores any non-primary departments. + /// For example, with CE it will return Engineering but with captain it will + /// not return anything, since Command is not a primary department. + /// + public bool TryGetPrimaryDepartment(string jobProto, [NotNullWhen(true)] out DepartmentPrototype? departmentPrototype) + { + // not sorting it since there should only be 1 primary department for a job. + // this is enforced by the job tests. + var departmentProtos = _protoManager.EnumeratePrototypes(); + + foreach (var department in departmentProtos) + { + if (department.Primary && department.Roles.Contains(jobProto)) + { + departmentPrototype = department; + return true; + } + } + + departmentPrototype = null; + return false; + } + public bool MindHasJobWithId(EntityUid? mindId, string prototypeId) { return CompOrNull(mindId)?.Prototype == prototypeId; diff --git a/Resources/Prototypes/Roles/Jobs/departments.yml b/Resources/Prototypes/Roles/Jobs/departments.yml index 5b5ee2252d..e1df397721 100644 --- a/Resources/Prototypes/Roles/Jobs/departments.yml +++ b/Resources/Prototypes/Roles/Jobs/departments.yml @@ -43,6 +43,7 @@ - HeadOfSecurity - ResearchDirector - Quartermaster + primary: false - type: department id: Engineering @@ -95,3 +96,4 @@ - Reporter - Zookeeper - Psychologist + primary: false