diff --git a/Content.Omu.Server/CrewManifest/OmuCrewManifestSystem.cs b/Content.Omu.Server/CrewManifest/OmuCrewManifestSystem.cs new file mode 100644 index 00000000000..7d052d661ee --- /dev/null +++ b/Content.Omu.Server/CrewManifest/OmuCrewManifestSystem.cs @@ -0,0 +1,111 @@ +using Content.Server.CrewManifest; +using Content.Server.Roles; +using Content.Server.Roles.Jobs; +using Content.Server.Silicons.StationAi; +using Content.Server.Station.Systems; +using Content.Shared.CrewManifest; +using Content.Shared.Mind; +using Content.Shared.NPC.Prototypes; +using Content.Shared.NPC.Systems; +using Content.Shared.Roles; +using Content.Shared.Roles.Jobs; +using Content.Shared.Silicons.Borgs.Components; +using Content.Shared.Silicons.StationAi; +using Content.Shared._DV.Silicons.Laws; +using Robust.Shared.Prototypes; + +namespace Content.Omu.Server.CrewManifest; + +/// +/// Omu-specific manifest additions for silicon crew that do not create normal station records. +/// +public sealed class OmuCrewManifestSystem : EntitySystem +{ + private static readonly ProtoId BorgJobId = "Borg"; + private static readonly ProtoId StationAiJobId = "StationAi"; + private static readonly ProtoId NanoTrasenFactionId = "NanoTrasen"; + + [Dependency] private readonly StationSystem _stationSystem = default!; + [Dependency] private readonly StationAiSystem _stationAiSystem = default!; + [Dependency] private readonly SharedMindSystem _mindSystem = default!; + [Dependency] private readonly NpcFactionSystem _npcFactionSystem = default!; + [Dependency] private readonly SharedRoleSystem _roleSystem = default!; + [Dependency] private readonly JobSystem _jobSystem = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnCollectManifestEntries); + } + + private void OnCollectManifestEntries(CrewManifestEntriesCollectEvent args) + { + var borgJob = _prototypeManager.Index(BorgJobId); + var stationAiJob = _prototypeManager.Index(StationAiJobId); + + var borgQuery = EntityQueryEnumerator(); + while (borgQuery.MoveNext(out var uid, out var chassis)) + { + if (_stationSystem.GetOwningStation(uid) != args.Station) + continue; + + if (chassis.BrainEntity == null) + continue; + + if (!_npcFactionSystem.IsMember(uid, NanoTrasenFactionId)) + continue; + + if (!HasComp(uid)) + continue; + + if (!IsCrewSiliconMind(uid, BorgJobId, requireSlavedBorg: true)) + continue; + + args.Entries.Add((borgJob, BuildSiliconEntry(uid, borgJob))); + } + + var aiQuery = EntityQueryEnumerator(); + while (aiQuery.MoveNext(out var uid, out var core)) + { + if (_stationSystem.GetOwningStation(uid) != args.Station) + continue; + + if (!_stationAiSystem.TryGetHeld((uid, core), out var held)) + continue; + + if (!IsCrewSiliconMind(held, StationAiJobId)) + continue; + + args.Entries.Add((stationAiJob, BuildSiliconEntry(held, stationAiJob))); + } + } + + private bool IsCrewSiliconMind(EntityUid uid, ProtoId expectedJob, bool requireSlavedBorg = false) + { + if (!_mindSystem.TryGetMind(uid, out var mindId, out _)) + return false; + + if (!_roleSystem.MindHasRole(mindId)) + return false; + + if (_roleSystem.MindHasRole(mindId)) + return false; + + if (requireSlavedBorg && !HasComp(uid)) + return false; + + if (_jobSystem.MindHasJobWithId(mindId, expectedJob)) + return true; + + return expectedJob == BorgJobId; + } + + private CrewManifestEntry BuildSiliconEntry(EntityUid uid, JobPrototype job) + { + return new CrewManifestEntry( + MetaData(uid).EntityName, + job.LocalizedName, + job.Icon.ToString(), + job.ID); + } +} diff --git a/Content.Server/CrewManifest/CrewManifestEntriesCollectEvent.cs b/Content.Server/CrewManifest/CrewManifestEntriesCollectEvent.cs new file mode 100644 index 00000000000..a07fdcd2594 --- /dev/null +++ b/Content.Server/CrewManifest/CrewManifestEntriesCollectEvent.cs @@ -0,0 +1,11 @@ +using Content.Shared.CrewManifest; +using Content.Shared.Roles; + +namespace Content.Server.CrewManifest; + +/// +/// Allows fork modules to append extra crew manifest rows before the final sort/cache step. +/// +public readonly record struct CrewManifestEntriesCollectEvent( + EntityUid Station, + List<(JobPrototype? job, CrewManifestEntry entry)> Entries); diff --git a/Content.Server/CrewManifest/CrewManifestSystem.cs b/Content.Server/CrewManifest/CrewManifestSystem.cs index 08bf7b53f1c..86f995f0151 100644 --- a/Content.Server/CrewManifest/CrewManifestSystem.cs +++ b/Content.Server/CrewManifest/CrewManifestSystem.cs @@ -129,6 +129,8 @@ private void OnBoundUiClose(EntityUid uid, CrewManifestViewerComponent component /// The name and crew manifest entries (unordered) of the station. public (string name, CrewManifestEntries? entries) GetCrewManifest(EntityUid station) { + BuildCrewManifest(station); + var valid = _cachedEntries.TryGetValue(station, out var manifest); return (valid ? MetaData(station).EntityName : string.Empty, valid ? manifest : null); } @@ -239,7 +241,6 @@ private void BuildCrewManifest(EntityUid station) var iter = _recordsSystem.GetRecordsOfType(station); var entries = new CrewManifestEntries(); - var entriesSort = new List<(JobPrototype? job, CrewManifestEntry entry)>(); foreach (var recordObject in iter) { @@ -250,6 +251,10 @@ private void BuildCrewManifest(EntityUid station) entriesSort.Add((job, entry)); } + // Allow downstream modules to inject extra manifest rows without rewriting this system. + var ev = new CrewManifestEntriesCollectEvent(station, entriesSort); + RaiseLocalEvent(ev); + entriesSort.Sort((a, b) => { var cmp = JobUIComparer.Instance.Compare(a.job, b.job); @@ -309,4 +314,4 @@ public override CompletionResult GetCompletion(IConsoleShell shell, string[] arg return CompletionResult.FromHintOptions(stations, null); } -} \ No newline at end of file +}