private void ReassembleComplete(EntityUid uid, BodyReassembleComponent component, ReassembleCompleteEvent args)
        {
            component.CancelToken = null;

            if (component.DNA == null || component.BodyParts == null)
            {
                return;
            }

            // Creates the new entity and transfers the mind component
            var speciesProto = _prototype.Index <SpeciesPrototype>(component.DNA.Value.Profile.Species).Prototype;
            var mob          = EntityManager.SpawnEntity(speciesProto, EntityManager.GetComponent <TransformComponent>(component.Owner).MapPosition);

            _humanoidAppearance.UpdateFromProfile(mob, component.DNA.Value.Profile);
            MetaData(mob).EntityName = component.DNA.Value.Profile.Name;

            if (TryComp <MindComponent>(uid, out var mindcomp) && mindcomp.Mind != null)
            {
                mindcomp.Mind.TransferTo(mob);
            }

            // Cleans up all the body part pieces
            foreach (var entity in component.BodyParts)
            {
                EntityManager.DeleteEntity(entity);
            }

            _popupSystem.PopupEntity(Loc.GetString("reassemble-success", ("user", Identity.Entity(mob, EntityManager))), mob, Filter.Entities(mob));
        }
        private void StartReassembly(EntityUid uid, BodyReassembleComponent component, float multiplier = 1f)
        {
            if (component.CancelToken != null)
            {
                return;
            }

            if (!GetNearbyParts(uid, component, out var partList))
            {
                return;
            }

            if (partList == null)
            {
                return;
            }

            var doAfterTime = component.DoAfterTime * multiplier;
            var cancelToken = new CancellationTokenSource();

            component.CancelToken = cancelToken;

            var doAfterEventArgs = new DoAfterEventArgs(component.Owner, doAfterTime, cancelToken.Token, component.Owner)
            {
                BreakOnTargetMove    = true,
                BreakOnUserMove      = true,
                BreakOnDamage        = true,
                BreakOnStun          = true,
                NeedHand             = false,
                TargetCancelledEvent = new ReassembleCancelledEvent(),
                TargetFinishedEvent  = new ReassembleCompleteEvent(uid, uid, partList),
            };

            _doAfterSystem.DoAfter(doAfterEventArgs);
        }
        private bool GetNearbyParts(EntityUid uid, BodyReassembleComponent component, out HashSet <EntityUid>?partList)
        {
            partList = new HashSet <EntityUid>();

            if (component.BodyParts == null)
            {
                return(false);
            }

            // Ensures all of the old body part pieces are there
            var xformQuery = GetEntityQuery <TransformComponent>();
            var bodyXform  = xformQuery.GetComponent(uid);

            foreach (var part in component.BodyParts)
            {
                if (!xformQuery.TryGetComponent(part, out var xform) ||
                    !bodyXform.Coordinates.InRange(EntityManager, xform.Coordinates, 2f))
                {
                    _popupSystem.PopupEntity(Loc.GetString("reassemble-fail"), uid, Filter.Entities(uid));
                    return(false);
                }
                partList.Add(part);
            }
            return(true);
        }
        /// <summary>
        /// Adds the custom verb for reassembling body parts
        /// </summary>
        private void AddReassembleVerbs(EntityUid uid, BodyReassembleComponent component, GetVerbsEvent <AlternativeVerb> args)
        {
            if (!args.CanAccess || !args.CanInteract)
            {
                return;
            }

            if (!TryComp <MindComponent>(uid, out var mind) ||
                !mind.HasMind ||
                component.CancelToken != null)
            {
                return;
            }

            // doubles the time if you reconstruct yourself
            var multiplier = args.User == uid ? SelfReassembleMultiplier : 1f;

            // Custom verb
            AlternativeVerb custom = new()
            {
                Text = Loc.GetString("reassemble-action"),
                Act  = () =>
                {
                    StartReassembly(uid, component, multiplier);
                },
                IconEntity = uid,
                Priority   = 1
            };

            args.Verbs.Add(custom);
        }
        private void OnPartGibbed(EntityUid uid, BodyReassembleComponent component, PartGibbedEvent args)
        {
            if (!TryComp <MindComponent>(args.EntityToGib, out var mindComp) || mindComp?.Mind == null)
            {
                return;
            }

            component.BodyParts = args.GibbedParts;
            UpdateDNAEntry(uid, args.EntityToGib);
            mindComp.Mind.TransferTo(uid);

            if (component.ReassembleAction == null)
            {
                return;
            }

            _actions.AddAction(uid, component.ReassembleAction, null);
        }
 private void ReassembleCancelled(EntityUid uid, BodyReassembleComponent component, ReassembleCancelledEvent args)
 {
     component.CancelToken = null;
 }
 private void StartReassemblyAction(EntityUid uid, BodyReassembleComponent component, ReassembleActionEvent args)
 {
     args.Handled = true;
     StartReassembly(uid, component, SelfReassembleMultiplier);
 }