using System.Diagnostics; using System.Linq; using Content.Server.Objectives.Components; using Content.Server.Shuttles.Systems; using Content.Shared.Access.Systems; using Content.Shared.Changeling.Systems; using Content.Shared.Cuffs; using Content.Shared.Mind; using Content.Shared.Objectives.Components; using Content.Shared.Roles.Jobs; using Robust.Shared.Random; namespace Content.Server.Objectives.Systems; /// /// Makes it so that works. /// public sealed partial class ChangelingEscapeDepartmentConditionSystem : EntitySystem { [Dependency] private EmergencyShuttleSystem _emergencyShuttle = default!; [Dependency] private SharedChangelingIdentitySystem _changelingIdentity = default!; [Dependency] private SharedCuffableSystem _cuffable = default!; [Dependency] private SharedIdCardSystem _idCard = default!; [Dependency] private SharedMindSystem _mind = default!; [Dependency] private TargetObjectiveSystem _target = default!; [Dependency] private SharedJobSystem _job = default!; [Dependency] private IRobustRandom _random = default!; [SubscribeLocalEvent] private void OnAfterAssign(Entity ent, ref ObjectiveAfterAssignEvent args) { if (!_target.GetTarget(ent, out var target)) return; // Does our target have a valid job? if (!_job.MindTryGetJobId(target.Value, out var jobPrototype) || !jobPrototype.HasValue) return; // We get the department of the job for our target, prioritizing the secondary departments (such as Command) // We do this to allow the objective to roll Command. // Otherwise RD/HoS/QM would return Science/Security/Cargo instead of Command. if (!_job.TryGetSecondaryDepartmentsOrFallback(jobPrototype.Value, out var departmentPrototypes)) return; Debug.Assert(departmentPrototypes.Count > 0, $"Attempted to assign a job without departments to objective {MetaData(ent).EntityPrototype}!"); // Get a random department. // This is all done on the server, so no need to worry about mispredictions. ent.Comp.Department = _random.Pick(departmentPrototypes); } [SubscribeLocalEvent] private void OnGetProgress(Entity ent, ref ObjectiveGetProgressEvent args) { args.Progress = GetProgress(ent, (args.MindId, args.Mind)); } private float GetProgress(Entity ent, Entity mind) { var ownedEntity = mind.Comp.OwnedEntity; if (ownedEntity == null || _mind.IsCharacterDeadIc(mind)) return 0f; // Check 1: Must have transformed into a target with a job that is in the department if (!_changelingIdentity.TryGetCurrentIdentityData(ownedEntity.Value, out var identityData)) return 0f; // this should not happen // Our identity must have a job. var job = identityData.OriginalJob; if (!job.HasValue) return 0f; if (ent.Comp.Department == null || !_job.JobIsInDepartment(job.Value, ent.Comp.Department.Value)) return 0f; // The job of our identity is not in the target department or the department doesn't exist. // Check 2: Must escape alive. if (!_emergencyShuttle.IsTargetEscaping(ownedEntity.Value)) return 0.5f; if (_cuffable.IsCuffed(ownedEntity.Value)) return 0.5f; // Check 3: Must wear an ID card with the target's name on it. if (!_idCard.TryFindIdCard(ownedEntity.Value, out var idCard)) return 0.75f; // is not wearing an id if (idCard.Comp.JobDepartments.All(idDept => idDept.Id != ent.Comp.Department)) return 0.75f; // found ID is not of the correct department. return 1f; } }