using Content.Shared.Antag; using Content.Shared.Changeling.Components; using Content.Shared.Changeling.Systems; using Content.Shared.DoAfter; using Content.Shared.Humanoid; using Content.Shared.IdentityManagement; using Content.Shared.Mind; using Content.Shared.Mobs.Systems; using Content.Shared.Popups; using Content.Shared.Zombies; using Robust.Shared.Prototypes; namespace Content.Server.Changeling.Systems; public sealed partial class ServerChangelingLastResortSystem : ChangelingLastResortSystem { private static readonly ProtoId ChangelingAntag = "Changeling"; [Dependency] private SharedMindSystem _mind = default!; [Dependency] private MobStateSystem _mobState = default!; [Dependency] private SharedPopupSystem _popup = default!; [Dependency] private SharedDoAfterSystem _doAfter = default!; [Dependency] private AntagSelectionSystem _antag = default!; [SubscribeLocalEvent] private void OnTakeOverCorpseAction(Entity ent, ref ChangelingTakeOverCorpseActionEvent args) { // CanTakeOver checks for the existence of ChangelingIdentityComponent on the target. // As such it cannot be predicted as that component is not networked to sessions other than the owner // Unless we do fucky networking magic if (args.Handled || !CanTakeOver(ent.Owner, args.Target)) return; args.Handled = true; Audio.PlayPvs(ent.Comp.Sound, ent.Owner); _popup.PopupEntity(Loc.GetString("changeling-takeover-start-others", ("user", Identity.Entity(ent.Owner, EntityManager))), ent.Owner, PopupType.MediumCaution); var examine = Loc.GetString("changeling-takeover-doafter", ("user", Identity.Entity(ent, EntityManager)), ("target", Identity.Entity(args.Target, EntityManager))); var doAfter = new DoAfterArgs(EntityManager, ent.Owner, ent.Comp.TakeOverDuration, new ChangelingTakeOverCorpseDoAfterEvent(), ent, target: args.Target) { BreakOnDamage = true, BreakOnMove = true, DuplicateCondition = DuplicateConditions.None, RequireCanInteract = false, ExamineText = examine }; _doAfter.TryStartDoAfter(doAfter); } /// /// Checks whether a changeling slug can take over the body. /// private bool CanTakeOver(EntityUid user, EntityUid target, bool showPopups = true) { if (!HasComp(target)) return false; if (HasComp(target) || HasComp(target)) { if (showPopups) _popup.PopupEntity(Loc.GetString("changeling-takeover-is-changeling"), user, user); return false; } if (_mobState.IsDead(target)) return true; if (showPopups) _popup.PopupEntity(Loc.GetString("changeling-takeover-not-dead"), user, user); return false; } [SubscribeLocalEvent] private void OnTakeOverCorpseDoAfter(Entity ent, ref ChangelingTakeOverCorpseDoAfterEvent args) { args.Handled = true; if (args.Cancelled || args.Target is not { } target || !CanTakeOver(args.User, target, showPopups: false)) return; if (!_mind.TryGetMind(args.User, out var mindId, out var mind)) return; TakeOverCorpse(ent, target, mindId, mind); } private void TakeOverCorpse(Entity ent, EntityUid target, EntityUid mindId, MindComponent mind) { _mind.TransferTo(mindId, target, mind: mind); _antag.AssignAntagComponents(target, ChangelingAntag); var ev = new BodyTakenByHeadslugEvent(target, ent.Comp.AutoStasis, ent.Comp.AutoStasisDurationMultiplier); RaiseLocalEvent(target, ref ev); QueueDel(ent); } }