using System.Linq;
using Content.Shared.Silicons.Borgs.Components;
using Content.Shared.Whitelist;
using Robust.Shared.Player;
namespace Content.Shared.Silicons.Borgs;
public abstract partial class SharedBorgSystem
{
///
/// Can this borg currently activate it's ?
/// The requirements for this are
/// - Having enough power in its power cell
/// - Having a player mind attached
/// - The borg is alive (not crit or dead).
///
public bool CanActivate(Entity chassis)
{
if (!_powerCell.HasDrawCharge(chassis.Owner))
return false;
// TODO: Replace this with something else, only the client's own mind is networked to them,
// so this will always be false for the minds of other clients.
if (!_mind.TryGetMind(chassis.Owner, out _, out _))
return false;
if (_mobState.IsIncapacitated(chassis.Owner))
return false;
return true;
}
///
/// Activates the borg if the conditions are met.
/// Returns true if the borg was activated.
///
public bool TryActivate(Entity chassis, EntityUid? user = null)
{
if (chassis.Comp.Active)
return false; // Already active.
if (!CanActivate(chassis))
return false;
SetActive(chassis, true, user);
return true;
}
///
/// Activates or deactivates a borg.
/// If active the borg
/// - can use modules and
/// - has full movement speed.
///
public void SetActive(Entity chassis, bool active, EntityUid? user = null)
{
if (chassis.Comp.Active == active)
return;
chassis.Comp.Active = active;
Dirty(chassis);
if (active)
InstallAllModules(chassis.AsNullable());
else
DisableAllModules(chassis.AsNullable());
_powerCell.SetDrawEnabled(chassis.Owner, active);
_movementSpeedModifier.RefreshMovementSpeedModifiers(chassis);
var sound = active ? chassis.Comp.ActivateSound : chassis.Comp.DeactivateSound;
// If a user is given predict the audio for them, if not keep it unpredicted.
if (user != null)
_audio.PlayPredicted(sound, chassis.Owner, user);
else if (_net.IsServer)
_audio.PlayPvs(sound, chassis.Owner);
}
///
/// Inserts a new module into a borg, the same as if a player inserted it manually.
/// This does not run checks to see if the borg is actually allowed to be inserted, such as whitelists.
///
/// The borg to insert into.
/// The module to insert.
public void InsertModule(Entity ent, EntityUid module)
{
_container.Insert(module, ent.Comp.ModuleContainer);
}
///
/// Sets .
///
/// The borg to modify.
/// The new module whitelist.
public void SetModuleWhitelist(Entity ent, EntityWhitelist? whitelist)
{
ent.Comp.ModuleWhitelist = whitelist;
Dirty(ent);
}
///
/// Sets .
///
/// The borg to modify.
/// The new max module count.
public void SetMaxModules(Entity ent, int maxModules)
{
ent.Comp.MaxModules = maxModules;
Dirty(ent);
}
///
/// Checks that a player has fulfilled the requirements for the borg job, i.e. they are not banned from that role.
/// Always true on the client.
///
///
/// TODO: This currently causes mispredicts, but we have no way of knowing on the client if a player is banned.
/// Maybe solve this by giving banned players an unborgable trait instead?
///
public virtual bool CanPlayerBeBorged(ICommonSession session)
{
return true;
}
///
/// Installs a single module into a borg.
///
public void InstallModule(Entity borg, Entity module)
{
if (!Resolve(borg, ref borg.Comp) || !Resolve(module, ref module.Comp))
return;
if (module.Comp.Installed)
return;
module.Comp.InstalledEntity = borg.Owner;
Dirty(module);
var ev = new BorgModuleInstalledEvent(borg.Owner);
RaiseLocalEvent(module, ref ev);
}
///
/// Uninstalls a single module from a borg.
///
public void UninstallModule(Entity borg, Entity module)
{
if (!Resolve(borg, ref borg.Comp) || !Resolve(module, ref module.Comp))
return;
if (!module.Comp.Installed)
return;
module.Comp.InstalledEntity = null;
Dirty(module);
var ev = new BorgModuleUninstalledEvent(borg.Owner);
RaiseLocalEvent(module, ref ev);
}
///
/// Installs and activates all modules currently inside the borg's module container.
///
public void InstallAllModules(Entity borg)
{
if (!Resolve(borg, ref borg.Comp))
return;
foreach (var moduleEnt in new List(borg.Comp.ModuleContainer.ContainedEntities))
{
if (!_moduleQuery.TryGetComponent(moduleEnt, out var moduleComp))
continue;
InstallModule(borg, (moduleEnt, moduleComp));
}
}
///
/// Deactivates all modules currently inside the borg's module container.
///
public void DisableAllModules(Entity borg)
{
if (!Resolve(borg, ref borg.Comp))
return;
foreach (var moduleEnt in new List(borg.Comp.ModuleContainer.ContainedEntities))
{
if (!_moduleQuery.TryGetComponent(moduleEnt, out var moduleComp))
continue;
UninstallModule(borg, (moduleEnt, moduleComp));
}
}
///
/// Sets .
///
public void SetBorgModuleDefault(Entity ent, bool newDefault)
{
ent.Comp.DefaultModule = newDefault;
Dirty(ent);
}
///
/// Checks if a given module can be inserted into a borg.
///
public bool CanInsertModule(Entity chassis, Entity module, EntityUid? user = null)
{
if (!Resolve(chassis, ref chassis.Comp) || !Resolve(module, ref module.Comp))
return false;
if (chassis.Comp.ModuleContainer.ContainedEntities.Count >= chassis.Comp.MaxModules)
{
_popup.PopupClient(Loc.GetString("borg-module-too-many"), chassis.Owner, user);
return false;
}
if (_whitelist.IsWhitelistFail(chassis.Comp.ModuleWhitelist, module))
{
_popup.PopupClient(Loc.GetString("borg-module-whitelist-deny"), chassis.Owner, user);
return false;
}
if (TryComp(module, out var itemModuleComp))
{
foreach (var containedModuleUid in chassis.Comp.ModuleContainer.ContainedEntities)
{
if (!TryComp(containedModuleUid, out var containedItemModuleComp))
continue;
if (containedItemModuleComp.Hands.Count == itemModuleComp.Hands.Count &&
containedItemModuleComp.Hands.All(itemModuleComp.Hands.Contains))
{
_popup.PopupClient(Loc.GetString("borg-module-duplicate"), chassis.Owner, user);
return false;
}
}
}
return true;
}
///
/// Check if a module can be removed from a borg.
///
/// The module to remove from the borg.
/// True if the module can be removed.
public bool CanRemoveModule(Entity module)
{
if (module.Comp.DefaultModule)
return false;
return true;
}
///
/// Selects a module, enabling the borg to use its provided abilities.
///
public void SelectModule(Entity chassis,
Entity module)
{
if (LifeStage(chassis) >= EntityLifeStage.Terminating)
return;
if (!Resolve(chassis, ref chassis.Comp))
return;
if (!Resolve(module, ref module.Comp) || !module.Comp.Installed || module.Comp.InstalledEntity != chassis.Owner)
{
Log.Error($"{ToPrettyString(chassis)} attempted to select uninstalled module {ToPrettyString(module)}");
return;
}
if (!HasComp(module))
{
Log.Error($"{ToPrettyString(chassis)} attempted to select invalid module {ToPrettyString(module)}");
return;
}
if (!chassis.Comp.ModuleContainer.Contains(module))
{
Log.Error($"{ToPrettyString(chassis)} does not contain the installed module {ToPrettyString(module)}");
return;
}
if (chassis.Comp.SelectedModule == module.Owner)
return;
UnselectModule(chassis);
var ev = new BorgModuleSelectedEvent(chassis);
RaiseLocalEvent(module, ref ev);
chassis.Comp.SelectedModule = module.Owner;
Dirty(chassis);
}
///
/// Unselects a module, removing its provided abilities.
///
public void UnselectModule(Entity chassis)
{
if (LifeStage(chassis) >= EntityLifeStage.Terminating)
return;
if (!Resolve(chassis, ref chassis.Comp))
return;
if (chassis.Comp.SelectedModule == null)
return;
var ev = new BorgModuleUnselectedEvent(chassis);
RaiseLocalEvent(chassis.Comp.SelectedModule.Value, ref ev);
chassis.Comp.SelectedModule = null;
Dirty(chassis);
}
}