using System.Diagnostics.CodeAnalysis; using Content.Shared.Implants.Components; using Content.Shared.Inventory; using Content.Shared.StatusEffectNew.Components; using Content.Shared.Storage; using Content.Shared.Whitelist; using Robust.Shared.Map; using Robust.Shared.Prototypes; namespace Content.Shared.Cloning; public abstract partial class SharedCloningSystem : EntitySystem { [Dependency] private StatusEffectNew.StatusEffectsSystem _statusEffects = default!; //TODO: This system has to support both the old and new status effect systems, until the old is able to be fully removed. [Dependency] private EntityQuery _cloneableEffectQuery = default!; [Dependency] private EntityWhitelistSystem _whitelist = default!; /// /// Spawns a clone of the given humanoid mob at the specified location or in nullspace. /// public virtual bool TryCloning( EntityUid original, MapCoordinates? coords, ProtoId settingsId, [NotNullWhen(true)] out EntityUid? clone) { clone = null; return false; } /// /// Copy components from one entity to another based on a CloningSettingsPrototype. /// /// The orignal Entity to clone components from. /// The target Entity to clone components to. /// The clone settings prototype id containing the list of components to clone. public virtual void CloneComponents( EntityUid original, EntityUid clone, ProtoId settings) { } /// /// Copy components from one entity to another based on a CloningSettingsPrototype. /// /// The orignal Entity to clone components from. /// The target Entity to clone components to. /// The clone settings prototype containing the list of components to clone. public virtual void CloneComponents( EntityUid original, EntityUid clone, CloningSettingsPrototype settings) { } /// /// Copies the equipment the original has to the clone. /// This uses the original prototype of the items, so any changes to components that are done after spawning are lost! /// public virtual void CopyEquipment( Entity original, Entity clone, SlotFlags slotFlags, EntityWhitelist? whitelist = null, EntityWhitelist? blacklist = null) { } /// /// Copies an item and its storage recursively, placing all items at the same position in grid storage. /// This uses the original prototype of the items, so any changes to components that are done after spawning are lost! /// /// /// This is not perfect and only considers item in storage containers. /// Some components have their own additional spawn logic on map init, so we cannot just copy all containers. /// public virtual EntityUid? CopyItem( EntityUid original, EntityCoordinates coords, EntityWhitelist? whitelist = null, EntityWhitelist? blacklist = null) { return null; } /// /// Copies an item's storage recursively to another storage. /// The storage grids should have the same shape or it will drop on the floor. /// Basically the same as CopyItem, but we don't copy the outermost container. /// public virtual void CopyStorage( Entity original, Entity target, EntityWhitelist? whitelist = null, EntityWhitelist? blacklist = null) { } /// /// Copies all implants from one mob to another. /// Might result in duplicates if the target already has them. /// Can copy the storage inside a storage implant according to a whitelist and blacklist. /// /// Entity to copy implants from. /// Entity to copy implants to. /// If true will copy storage of the implants (E.g storage implant) /// Whitelist for the storage copy (If copyStorage is true) /// Blacklist for the storage copy (If copyStorage is true) public virtual void CopyImplants( Entity original, EntityUid target, bool copyStorage = false, EntityWhitelist? whitelist = null, EntityWhitelist? blacklist = null) { } /// /// Scans all permanent status effects applied to the original entity and transfers them to the clone. /// /// The entity to take status effects from /// The entity to copy the status effects to. /// The whitelist the status effects need to be in to get copied. /// The blacklist the status effects cannot be in to get copied. /// Whether to remove clonable status effects from the target before applying new ones. public void CopyStatusEffects( Entity original, Entity target, EntityWhitelist? whitelist = null, EntityWhitelist? blacklist = null, bool removeMissing = true) { if (removeMissing) { foreach (var effect in _statusEffects.EnumerateStatusEffects(target, _cloneableEffectQuery)) { if (effect.Comp1.EndEffectTime is not null) continue; // Don't delete status effects that were never in the whitelist. if (!_whitelist.CheckBoth(effect.Owner, blacklist, whitelist)) continue; var effectProto = Prototype(effect); if (effectProto is null) continue; // Remove all status effects we do not need anymore. // We clone permanent ones, so we assume we replace them with a new set of permanent ones. _statusEffects.TryRemoveStatusEffect(target, effectProto); } } foreach (var effect in _statusEffects.EnumerateStatusEffects(original, _cloneableEffectQuery)) { // We are not interested in temporary effects, only permanent ones. if (effect.Comp1.EndEffectTime is not null) continue; if (!_whitelist.CheckBoth(effect.Owner, blacklist, whitelist)) continue; var effectProto = Prototype(effect); if (effectProto is null) continue; _statusEffects.TrySetStatusEffectDuration(target, effectProto); } } }