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 doAfter = new DoAfterArgs(EntityManager, ent.Owner, ent.Comp.TakeOverDuration, new ChangelingTakeOverCorpseDoAfterEvent(), ent, target: args.Target) { BreakOnDamage = true, BreakOnMove = true, DuplicateCondition = DuplicateConditions.None, RequireCanInteract = false, }; _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(args.User, target, mindId, mind); _popup.PopupEntity(Loc.GetString("changeling-takeover-success-self"), target, target, PopupType.Large); } private void TakeOverCorpse(EntityUid user, EntityUid target, EntityUid mindId, MindComponent mind) { _mind.TransferTo(mindId, target, mind: mind); _antag.AssignAntagComponents(target, ChangelingAntag); QueueDel(user); } }