using Content.Shared.Containers.ItemSlots; using Robust.Shared.Containers; using Robust.Shared.Timing; namespace Content.Shared.CartridgeLoader; public sealed partial class CartridgeLoaderSystem : EntitySystem { [Dependency] private IGameTiming _timing = default!; [Dependency] private ItemSlotsSystem _itemSlotsSystem = default!; [Dependency] private SharedAppearanceSystem _appearanceSystem = default!; [Dependency] private SharedContainerSystem _container = default!; [Dependency] private SharedUserInterfaceSystem _userInterface = default!; public override void Initialize() { base.Initialize(); InitializeRelay(); SubscribeLocalEvent(OnComponentInit); SubscribeLocalEvent(OnComponentRemove); SubscribeLocalEvent(OnItemInserted); SubscribeLocalEvent(OnItemRemoved); SubscribeLocalEvent(OnLoaderUiMessage); SubscribeLocalEvent(OnUiMessage); SubscribeLocalEvent(OnCartridgeState); } private void OnComponentInit(Entity ent, ref ComponentInit args) { _itemSlotsSystem.AddItemSlot(ent.Owner, CartridgeLoaderComponent.CartridgeSlotId, ent.Comp.CartridgeSlot); _container.EnsureContainer(ent, CartridgeLoaderComponent.RemovableContainerId); _container.EnsureContainer(ent, CartridgeLoaderComponent.UnremovableContainerId); } /// /// Marks installed program entities for deletion when the component gets removed /// private void OnComponentRemove(Entity ent, ref ComponentRemove args) { _itemSlotsSystem.RemoveItemSlot(ent.Owner, ent.Comp.CartridgeSlot); if (_container.TryGetContainer(ent, CartridgeLoaderComponent.RemovableContainerId, out var removable)) _container.ShutdownContainer(removable); if (_container.TryGetContainer(ent, CartridgeLoaderComponent.UnremovableContainerId, out var unremovable)) _container.ShutdownContainer(unremovable); } private void OnItemInserted(Entity ent, ref EntInsertedIntoContainerMessage args) { if (_timing.ApplyingState) return; if (args.Container.ID != CartridgeLoaderComponent.RemovableContainerId && args.Container.ID != CartridgeLoaderComponent.UnremovableContainerId && args.Container.ID != CartridgeLoaderComponent.CartridgeSlotId ) return; if (TryComp(args.Entity, out var cartridge)) { cartridge.LoaderUid = ent; Dirty(args.Entity, cartridge); if (args.Container.ID == CartridgeLoaderComponent.RemovableContainerId) UpdateCartridgeInstallationStatus((args.Entity, cartridge), InstallationStatus.Installed); else if (args.Container.ID == CartridgeLoaderComponent.UnremovableContainerId) UpdateCartridgeInstallationStatus((args.Entity, cartridge), InstallationStatus.Readonly); else UpdateCartridgeInstallationStatus((args.Entity, cartridge), InstallationStatus.Cartridge); } var evt = new CartridgeAddedEvent(ent); RaiseLocalEvent(args.Entity, ref evt); UpdateUiState(ent.AsNullable()); UpdateAppearanceData(ent); } private void OnItemRemoved(Entity ent, ref EntRemovedFromContainerMessage args) { if (_timing.ApplyingState) return; if (args.Container.ID != CartridgeLoaderComponent.RemovableContainerId && args.Container.ID != CartridgeLoaderComponent.UnremovableContainerId && args.Container.ID != CartridgeLoaderComponent.CartridgeSlotId ) return; if (ent.Comp.ActiveProgram == args.Entity) { ent.Comp.ActiveProgram = null; Dirty(ent); var deactivated = new CartridgeDeactivatedEvent(ent); RaiseLocalEvent(args.Entity, ref deactivated); } if (TryComp(args.Entity, out var cartridge)) { cartridge.LoaderUid = null; Dirty(args.Entity, cartridge); } var removed = new CartridgeRemovedEvent(ent); RaiseLocalEvent(args.Entity, ref removed); UpdateUiState(ent.AsNullable()); UpdateAppearanceData(ent); } private void UpdateAppearanceData(Entity ent) { _appearanceSystem.SetData(ent.Owner, CartridgeLoaderVisuals.CartridgeInserted, ent.Comp.CartridgeSlot.HasItem); } public void SendNotification(EntityUid loaderUid, string header, string message, CartridgeLoaderComponent? loader = default) { if (!Resolve(loaderUid, ref loader)) return; if (!loader.NotificationsEnabled) return; var args = new CartridgeLoaderNotificationSentEvent(header, message); RaiseLocalEvent(loaderUid, ref args); } private void OnCartridgeState(Entity ent, ref AfterAutoHandleStateEvent args) { if (ent.Comp.LoaderUid is not { } loader) return; UpdateUiState(loader); } } /// /// Gets sent to program / cartridge entities when they get inserted or installed. /// [ByRefEvent] public record struct CartridgeAddedEvent(Entity Loader); /// /// Gets sent to cartridge entities when they get ejected. /// [ByRefEvent] public record struct CartridgeRemovedEvent(Entity Loader); /// /// Gets sent to program / cartridge entities when they get activated. /// /// /// Don't update the programs ui state in this events listener. /// [ByRefEvent] public record struct CartridgeActivatedEvent(Entity Loader); /// /// Gets sent to program / cartridge entities when they get deactivated. /// [ByRefEvent] public record struct CartridgeDeactivatedEvent(Entity Loader); /// /// Gets sent to program / cartridge entities when the ui is ready to be updated by the cartridge. /// /// /// This is used for the initial ui state update because updating the ui in the activate event doesn't work. /// [ByRefEvent] public record struct CartridgeUiReadyEvent(Entity Loader); /// /// Gets sent by the cartridge loader system to the cartridge loader entity so another system. /// can handle displaying the notification /// /// The message to be displayed. [ByRefEvent] public record struct CartridgeLoaderNotificationSentEvent(string Header, string Message); /// /// Raised on an attempt of program installation. /// [ByRefEvent] public record struct ProgramInstallationAttempt(EntityUid LoaderUid, string Prototype, bool Cancelled = false);