using Content.Shared.Actions; using Content.Shared.Implants.Components; using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Content.Shared.Mobs; using Content.Shared.Tag; using JetBrains.Annotations; using Robust.Shared.Containers; using Robust.Shared.Network; using System.Linq; namespace Content.Shared.Implants; public abstract class SharedSubdermalImplantSystem : EntitySystem { [Dependency] private readonly INetManager _net = default!; [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly TagSystem _tag = default!; [Dependency] private readonly SharedTransformSystem _transformSystem = default!; public const string BaseStorageId = "storagebase"; public override void Initialize() { SubscribeLocalEvent(OnInsert); SubscribeLocalEvent(OnRemoveAttempt); SubscribeLocalEvent(OnRemove); SubscribeLocalEvent(RelayToImplantEvent); SubscribeLocalEvent(RelayToImplantEvent); SubscribeLocalEvent(RelayToImplantEvent); } private void OnInsert(EntityUid uid, SubdermalImplantComponent component, EntGotInsertedIntoContainerMessage args) { if (component.ImplantedEntity == null || _net.IsClient) return; if (!string.IsNullOrWhiteSpace(component.ImplantAction)) { _actionsSystem.AddAction(component.ImplantedEntity.Value, ref component.Action, component.ImplantAction, uid); } //replace micro bomb with macro bomb if (_container.TryGetContainer(component.ImplantedEntity.Value, ImplanterComponent.ImplantSlotId, out var implantContainer) && _tag.HasTag(uid, "MacroBomb")) { foreach (var implant in implantContainer.ContainedEntities) { if (_tag.HasTag(implant, "MicroBomb")) { _container.Remove(implant, implantContainer); QueueDel(implant); } } } var ev = new ImplantImplantedEvent(uid, component.ImplantedEntity.Value); RaiseLocalEvent(uid, ref ev); } private void OnRemoveAttempt(EntityUid uid, SubdermalImplantComponent component, ContainerGettingRemovedAttemptEvent args) { if (component.Permanent && component.ImplantedEntity != null) args.Cancel(); } private void OnRemove(EntityUid uid, SubdermalImplantComponent component, EntGotRemovedFromContainerMessage args) { if (component.ImplantedEntity == null || Terminating(component.ImplantedEntity.Value)) return; if (component.ImplantAction != null) _actionsSystem.RemoveProvidedActions(component.ImplantedEntity.Value, uid); if (!_container.TryGetContainer(uid, BaseStorageId, out var storageImplant)) return; var containedEntites = storageImplant.ContainedEntities.ToArray(); foreach (var entity in containedEntites) { _transformSystem.DropNextTo(entity, uid); } } /// /// Add a list of implants to a person. /// Logs any implant ids that don't have . /// public void AddImplants(EntityUid uid, IEnumerable implants) { foreach (var id in implants) { AddImplant(uid, id); } } /// /// Adds a single implant to a person, and returns the implant. /// Logs any implant ids that don't have . /// /// /// The implant, if it was successfully created. Otherwise, null. /// > public EntityUid? AddImplant(EntityUid uid, String implantId) { var coords = Transform(uid).Coordinates; var ent = Spawn(implantId, coords); if (TryComp(ent, out var implant)) { ForceImplant(uid, ent, implant); } else { Log.Warning($"Found invalid starting implant '{implantId}' on {uid} {ToPrettyString(uid):implanted}"); Del(ent); return null; } return ent; } /// /// Forces an implant into a person /// Good for on spawn related code or admin additions /// /// The entity to be implanted /// The implant /// The implant component public void ForceImplant(EntityUid target, EntityUid implant, SubdermalImplantComponent component) { //If the target doesn't have the implanted component, add it. var implantedComp = EnsureComp(target); var implantContainer = implantedComp.ImplantContainer; component.ImplantedEntity = target; _container.Insert(implant, implantContainer); } /// /// Force remove a singular implant /// /// the implanted entity /// the implant [PublicAPI] public void ForceRemove(EntityUid target, EntityUid implant) { if (!TryComp(target, out var implanted)) return; var implantContainer = implanted.ImplantContainer; _container.Remove(implant, implantContainer); QueueDel(implant); } /// /// Removes and deletes implants by force /// /// The entity to have implants removed [PublicAPI] public void WipeImplants(EntityUid target) { if (!TryComp(target, out var implanted)) return; var implantContainer = implanted.ImplantContainer; _container.CleanContainer(implantContainer); } //Relays from the implanted to the implant private void RelayToImplantEvent(EntityUid uid, ImplantedComponent component, T args) where T : notnull { if (!_container.TryGetContainer(uid, ImplanterComponent.ImplantSlotId, out var implantContainer)) return; var relayEv = new ImplantRelayEvent(args); foreach (var implant in implantContainer.ContainedEntities) { if (args is HandledEntityEventArgs { Handled : true }) return; RaiseLocalEvent(implant, relayEv); } } } public sealed class ImplantRelayEvent where T : notnull { public readonly T Event; public ImplantRelayEvent(T ev) { Event = ev; } } /// /// Event that is raised whenever someone is implanted with any given implant. /// Raised on the the implant entity. /// /// /// implant implant implant implant /// [ByRefEvent] public readonly struct ImplantImplantedEvent { public readonly EntityUid Implant; public readonly EntityUid? Implanted; public ImplantImplantedEvent(EntityUid implant, EntityUid? implanted) { Implant = implant; Implanted = implanted; } }