using System.Linq; using Content.Shared.Hands.Components; using Content.Shared.Interaction.Components; using Content.Shared.Silicons.Borgs.Components; using Content.Shared.Whitelist; using Robust.Shared.Containers; namespace Content.Server.Silicons.Borgs; /// public sealed partial class BorgSystem { public void InitializeModules() { SubscribeLocalEvent(OnModuleGotInserted); SubscribeLocalEvent(OnModuleGotRemoved); SubscribeLocalEvent(OnSelectableInstalled); SubscribeLocalEvent(OnSelectableUninstalled); SubscribeLocalEvent(OnSelectableAction); SubscribeLocalEvent(OnProvideItemStartup); SubscribeLocalEvent(OnItemModuleSelected); SubscribeLocalEvent(OnItemModuleUnselected); } private void OnModuleGotInserted(EntityUid uid, BorgModuleComponent component, EntGotInsertedIntoContainerMessage args) { var chassis = args.Container.Owner; if (!TryComp(chassis, out var chassisComp) || args.Container != chassisComp.ModuleContainer || !Toggle.IsActivated(chassis)) return; if (!_powerCell.HasDrawCharge(uid)) return; InstallModule(chassis, uid, chassisComp, component); } private void OnModuleGotRemoved(EntityUid uid, BorgModuleComponent component, EntGotRemovedFromContainerMessage args) { var chassis = args.Container.Owner; if (!TryComp(chassis, out var chassisComp) || args.Container != chassisComp.ModuleContainer) return; UninstallModule(chassis, uid, chassisComp, component); } private void OnProvideItemStartup(EntityUid uid, ItemBorgModuleComponent component, ComponentStartup args) { component.ProvidedContainer = Container.EnsureContainer(uid, component.ProvidedContainerId); } private void OnSelectableInstalled(EntityUid uid, SelectableBorgModuleComponent component, ref BorgModuleInstalledEvent args) { var chassis = args.ChassisEnt; if (_actions.AddAction(chassis, ref component.ModuleSwapActionEntity, out var action, component.ModuleSwapActionId, uid)) { if(TryComp(uid, out var moduleIconComp)) { action.Icon = moduleIconComp.Icon; }; action.EntityIcon = uid; Dirty(component.ModuleSwapActionEntity.Value, action); } if (!TryComp(chassis, out BorgChassisComponent? chassisComp)) return; if (chassisComp.SelectedModule == null) SelectModule(chassis, uid, chassisComp, component); } private void OnSelectableUninstalled(EntityUid uid, SelectableBorgModuleComponent component, ref BorgModuleUninstalledEvent args) { var chassis = args.ChassisEnt; _actions.RemoveProvidedActions(chassis, uid); if (!TryComp(chassis, out BorgChassisComponent? chassisComp)) return; if (chassisComp.SelectedModule == uid) UnselectModule(chassis, chassisComp); } private void OnSelectableAction(EntityUid uid, SelectableBorgModuleComponent component, BorgModuleActionSelectedEvent args) { var chassis = args.Performer; if (!TryComp(chassis, out var chassisComp)) return; var selected = chassisComp.SelectedModule; args.Handled = true; UnselectModule(chassis, chassisComp); if (selected != uid) { SelectModule(chassis, uid, chassisComp, component); } } /// /// Selects a module, enabling the borg to use its provided abilities. /// public void SelectModule(EntityUid chassis, EntityUid moduleUid, BorgChassisComponent? chassisComp = null, SelectableBorgModuleComponent? selectable = null, BorgModuleComponent? moduleComp = null) { if (LifeStage(chassis) >= EntityLifeStage.Terminating) return; if (!Resolve(chassis, ref chassisComp)) return; if (!Resolve(moduleUid, ref moduleComp) || !moduleComp.Installed || moduleComp.InstalledEntity != chassis) { Log.Error($"{ToPrettyString(chassis)} attempted to select uninstalled module {ToPrettyString(moduleUid)}"); return; } if (selectable == null && !HasComp(moduleUid)) { Log.Error($"{ToPrettyString(chassis)} attempted to select invalid module {ToPrettyString(moduleUid)}"); return; } if (!chassisComp.ModuleContainer.Contains(moduleUid)) { Log.Error($"{ToPrettyString(chassis)} does not contain the installed module {ToPrettyString(moduleUid)}"); return; } if (chassisComp.SelectedModule != null) return; if (chassisComp.SelectedModule == moduleUid) return; UnselectModule(chassis, chassisComp); var ev = new BorgModuleSelectedEvent(chassis); RaiseLocalEvent(moduleUid, ref ev); chassisComp.SelectedModule = moduleUid; Dirty(chassis, chassisComp); } /// /// Unselects a module, removing its provided abilities /// public void UnselectModule(EntityUid chassis, BorgChassisComponent? chassisComp = null) { if (LifeStage(chassis) >= EntityLifeStage.Terminating) return; if (!Resolve(chassis, ref chassisComp)) return; if (chassisComp.SelectedModule == null) return; var ev = new BorgModuleUnselectedEvent(chassis); RaiseLocalEvent(chassisComp.SelectedModule.Value, ref ev); chassisComp.SelectedModule = null; Dirty(chassis, chassisComp); } private void OnItemModuleSelected(EntityUid uid, ItemBorgModuleComponent component, ref BorgModuleSelectedEvent args) { ProvideItems(args.Chassis, uid, component: component); } private void OnItemModuleUnselected(EntityUid uid, ItemBorgModuleComponent component, ref BorgModuleUnselectedEvent args) { RemoveProvidedItems(args.Chassis, uid, component: component); } private void ProvideItems(EntityUid chassis, EntityUid uid, BorgChassisComponent? chassisComponent = null, ItemBorgModuleComponent? component = null) { if (!Resolve(chassis, ref chassisComponent) || !Resolve(uid, ref component)) return; if (!TryComp(chassis, out var hands)) return; var xform = Transform(chassis); foreach (var itemProto in component.Items) { EntityUid item; if (!component.ItemsCreated) { item = Spawn(itemProto, xform.Coordinates); } else { item = component.ProvidedContainer.ContainedEntities .FirstOrDefault(ent => Prototype(ent)?.ID == itemProto); if (!item.IsValid()) { Log.Debug($"no items found: {component.ProvidedContainer.ContainedEntities.Count}"); continue; } _container.Remove(item, component.ProvidedContainer, force: true); } if (!item.IsValid()) { Log.Debug("no valid item"); continue; } var handId = $"{uid}-item{component.HandCounter}"; component.HandCounter++; _hands.AddHand(chassis, handId, HandLocation.Middle, hands); _hands.DoPickup(chassis, hands.Hands[handId], item, hands); EnsureComp(item); component.ProvidedItems.Add(handId, item); } component.ItemsCreated = true; } private void RemoveProvidedItems(EntityUid chassis, EntityUid uid, BorgChassisComponent? chassisComponent = null, ItemBorgModuleComponent? component = null) { if (!Resolve(chassis, ref chassisComponent) || !Resolve(uid, ref component)) return; if (!TryComp(chassis, out var hands)) return; if (TerminatingOrDeleted(uid)) { foreach (var (hand, item) in component.ProvidedItems) { QueueDel(item); _hands.RemoveHand(chassis, hand, hands); } component.ProvidedItems.Clear(); return; } foreach (var (handId, item) in component.ProvidedItems) { if (LifeStage(item) <= EntityLifeStage.MapInitialized) { RemComp(item); _container.Insert(item, component.ProvidedContainer); } _hands.RemoveHand(chassis, handId, hands); } component.ProvidedItems.Clear(); } /// /// Checks if a given module can be inserted into a borg /// public bool CanInsertModule(EntityUid uid, EntityUid module, BorgChassisComponent? component = null, BorgModuleComponent? moduleComponent = null, EntityUid? user = null) { if (!Resolve(uid, ref component) || !Resolve(module, ref moduleComponent)) return false; if (component.ModuleContainer.ContainedEntities.Count >= component.MaxModules) { if (user != null) Popup.PopupEntity(Loc.GetString("borg-module-too-many"), uid, user.Value); return false; } if (_whitelistSystem.IsWhitelistFail(component.ModuleWhitelist, module)) { if (user != null) Popup.PopupEntity(Loc.GetString("borg-module-whitelist-deny"), uid, user.Value); return false; } if (TryComp(module, out var itemModuleComp)) { foreach (var containedModuleUid in component.ModuleContainer.ContainedEntities) { if (!TryComp(containedModuleUid, out var containedItemModuleComp)) continue; if (containedItemModuleComp.Items.Count == itemModuleComp.Items.Count && containedItemModuleComp.Items.All(itemModuleComp.Items.Contains)) { if (user != null) Popup.PopupEntity(Loc.GetString("borg-module-duplicate"), uid, user.Value); return false; } } } return true; } /// /// Check if a module can be removed from a borg. /// /// The borg that the module is being removed from. /// The module to remove from the borg. /// The user attempting to remove the module. /// True if the module can be removed. public bool CanRemoveModule( Entity borg, Entity module, EntityUid? user = null) { if (module.Comp.DefaultModule) return false; return true; } /// /// Installs and activates all modules currently inside the borg's module container /// public void InstallAllModules(EntityUid uid, BorgChassisComponent? component = null) { if (!Resolve(uid, ref component)) return; var query = GetEntityQuery(); foreach (var moduleEnt in new List(component.ModuleContainer.ContainedEntities)) { if (!query.TryGetComponent(moduleEnt, out var moduleComp)) continue; InstallModule(uid, moduleEnt, component, moduleComp); } } /// /// Deactivates all modules currently inside the borg's module container /// /// /// public void DisableAllModules(EntityUid uid, BorgChassisComponent? component = null) { if (!Resolve(uid, ref component)) return; var query = GetEntityQuery(); foreach (var moduleEnt in new List(component.ModuleContainer.ContainedEntities)) { if (!query.TryGetComponent(moduleEnt, out var moduleComp)) continue; UninstallModule(uid, moduleEnt, component, moduleComp); } } /// /// Installs a single module into a borg. /// public void InstallModule(EntityUid uid, EntityUid module, BorgChassisComponent? component, BorgModuleComponent? moduleComponent = null) { if (!Resolve(uid, ref component) || !Resolve(module, ref moduleComponent)) return; if (moduleComponent.Installed) return; moduleComponent.InstalledEntity = uid; var ev = new BorgModuleInstalledEvent(uid); RaiseLocalEvent(module, ref ev); } /// /// Uninstalls a single module from a borg. /// public void UninstallModule(EntityUid uid, EntityUid module, BorgChassisComponent? component, BorgModuleComponent? moduleComponent = null) { if (!Resolve(uid, ref component) || !Resolve(module, ref moduleComponent)) return; if (!moduleComponent.Installed) return; moduleComponent.InstalledEntity = null; var ev = new BorgModuleUninstalledEvent(uid); RaiseLocalEvent(module, ref ev); } /// /// Sets . /// /// The borg to modify. /// The new max module count. public void SetMaxModules(Entity ent, int maxModules) { ent.Comp.MaxModules = maxModules; } /// /// Sets . /// /// The borg to modify. /// The new module whitelist. public void SetModuleWhitelist(Entity ent, EntityWhitelist? whitelist) { ent.Comp.ModuleWhitelist = whitelist; } }