using System.Linq; using Robust.Shared.Prototypes; namespace Content.Shared.CartridgeLoader; public sealed partial class CartridgeLoaderSystem { public Entity? TryGetProgram(Entity ent) where T : IComponent { if (!Resolve(ent, ref ent.Comp)) return null; foreach (var prog in GetAllPrograms(ent)) { if (!TryComp(prog, out var program)) continue; return (prog, program); } return null; } public bool HasProgram(Entity ent) where T : IComponent { return TryGetProgram(ent).HasValue; } public IEnumerable GetAllPrograms(EntityUid uid) { if (_itemSlotsSystem.GetItemOrNull(uid, CartridgeLoaderComponent.CartridgeSlotId) is { } cartridge) return GetDiskPrograms(uid).Append(cartridge); return GetDiskPrograms(uid); } public IEnumerable GetDiskPrograms(EntityUid uid) { return GetPreinstalledPrograms(uid).Concat(GetRemovablePrograms(uid)); } public IReadOnlyList GetRemovablePrograms(EntityUid uid) { if (_container.TryGetContainer(uid, CartridgeLoaderComponent.RemovableContainerId, out var container)) return container.ContainedEntities; return []; } public IReadOnlyList GetPreinstalledPrograms(EntityUid uid) { if (_container.TryGetContainer(uid, CartridgeLoaderComponent.UnremovableContainerId, out var container)) return container.ContainedEntities; return []; } public int UsedDiskSpace(EntityUid uid) { var ret = 0; if (_container.TryGetContainer(uid, CartridgeLoaderComponent.RemovableContainerId, out var removable)) ret += removable.Count; if (_container.TryGetContainer(uid, CartridgeLoaderComponent.UnremovableContainerId, out var unremovable)) ret += unremovable.Count; return ret; } private bool HasProgram(EntityUid uid, EntityUid program) { return GetAllPrograms(uid).Contains(program); } public void ActivateProgram(Entity ent, EntityUid program) { if (!HasProgram(ent, program)) return; if (ent.Comp.ActiveProgram is { } active) DeactivateProgram(ent, active); var evt = new CartridgeActivatedEvent(ent); RaiseLocalEvent(program, ref evt); ent.Comp.ActiveProgram = program; Dirty(ent); UpdateUiState(ent.AsNullable()); } public void DeactivateProgram(Entity ent, EntityUid program) { if (!HasProgram(ent, program) || ent.Comp.ActiveProgram != program) return; var evt = new CartridgeDeactivatedEvent(ent); RaiseLocalEvent(program, ref evt); ent.Comp.ActiveProgram = null; Dirty(ent); UpdateUiState(ent.AsNullable()); } /// /// Installs a program by its prototype. /// /// The cartridge loader. /// The prototype. /// Whether the program can be deinstalled or not. /// Whether installing the cartridge was successful. public bool InstallProgram(Entity ent, EntProtoId prototype, bool deinstallable = true) { if (UsedDiskSpace(ent) >= ent.Comp.DiskSpace) return false; var ev = new ProgramInstallationAttempt(ent, prototype); RaiseLocalEvent(ref ev); if (ev.Cancelled) return false; return PredictedTrySpawnInContainer(prototype, ent, deinstallable ? CartridgeLoaderComponent.RemovableContainerId : CartridgeLoaderComponent.UnremovableContainerId, out _); } /// /// Uninstalls a program using its uid. /// /// The cartridge loader uid. /// The uid of the program to be uninstalled. /// Whether uninstalling the program was successful. public bool UninstallProgram(Entity ent, EntityUid program) { if (!GetDiskPrograms(ent).Contains(program)) return false; PredictedQueueDel(program); return true; } /// /// Installs a cartridge by spawning an invisible version of the cartridges prototype into the cartridge loaders program container. /// /// The cartridge loader. /// The uid of the cartridge to be installed. /// Whether installing the cartridge was successful. public bool InstallCartridge(Entity ent, EntityUid cartridge) { if (!HasComp(cartridge)) return false; if (MetaData(cartridge).EntityPrototype is not { } cartridgeProto) return false; foreach (var program in GetDiskPrograms(ent)) { if (MetaData(program).EntityPrototype is { } programProto && programProto == cartridgeProto) return false; } return InstallProgram(ent, cartridgeProto); } private void UpdateCartridgeInstallationStatus(Entity ent, InstallationStatus installationStatus) { ent.Comp.InstallationStatus = installationStatus; Dirty(ent); } }