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)
{
Container.EnsureContainer(uid, component.HoldingContainer);
}
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))
{
var actEnt = (component.ModuleSwapActionEntity.Value, action);
_actions.SetEntityIcon(actEnt, uid);
if (TryComp(uid, out var moduleIconComp))
_actions.SetIcon(actEnt, moduleIconComp.Icon);
/// Set a custom name and description on the action. The borg module action prototypes are shared across
/// all modules. Extract localized names, then populate variables with the info from the module itself.
var moduleName = Name(uid);
var actionMetaData = MetaData(component.ModuleSwapActionEntity.Value);
var instanceName = Loc.GetString("borg-module-action-name", ("moduleName", moduleName));
_metaData.SetEntityName(component.ModuleSwapActionEntity.Value, instanceName, actionMetaData);
var instanceDesc = Loc.GetString("borg-module-action-description", ("moduleName", moduleName));
_metaData.SetEntityDescription(component.ModuleSwapActionEntity.Value, instanceDesc, actionMetaData);
}
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;
if (!_container.TryGetContainer(uid, component.HoldingContainer, out var container))
return;
var xform = Transform(chassis);
for (var i = 0; i < component.Hands.Count; i++)
{
var hand = component.Hands[i];
var handId = $"{uid}-hand-{i}";
_hands.AddHand((chassis, hands), handId, hand.Hand);
EntityUid? item = null;
if (component.StoredItems is not null)
{
if (component.StoredItems.TryGetValue(handId, out var storedItem))
{
item = storedItem;
_container.Remove(storedItem, container, force: true);
}
}
else if (hand.Item is { } itemProto)
{
item = Spawn(itemProto, xform.Coordinates);
}
if (item is { } pickUp)
{
_hands.DoPickup(chassis, handId, pickUp, hands);
if (!hand.ForceRemovable && hand.Hand.Whitelist == null && hand.Hand.Blacklist == null)
{
EnsureComp(pickUp);
}
}
}
Dirty(uid, component);
}
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 (!_container.TryGetContainer(uid, component.HoldingContainer, out var container))
return;
if (TerminatingOrDeleted(uid))
return;
component.StoredItems ??= new();
for (var i = 0; i < component.Hands.Count; i++)
{
var handId = $"{uid}-hand-{i}";
if (_hands.TryGetHeldItem(chassis, handId, out var held))
{
RemComp(held.Value);
_container.Insert(held.Value, container);
component.StoredItems[handId] = held.Value;
}
else
{
component.StoredItems.Remove(handId);
}
_hands.RemoveHand(chassis, handId);
}
Dirty(uid, component);
}
///
/// 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.Hands.Count == itemModuleComp.Hands.Count &&
containedItemModuleComp.Hands.All(itemModuleComp.Hands.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;
}
}