using System.Linq; using Content.Server.GameObjects.Components.Interactable; using Content.Server.GameObjects.Components.Stack; using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects.Components.Interactable; using Content.Server.Utility; using Robust.Server.Interfaces.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components.Transform; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects.Components; using Robust.Shared.IoC; using Robust.Shared.Map; using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Power { /// /// Component to transfer power to nearby components, can create powernets and connect to nodes /// [RegisterComponent] public class PowerTransferComponent : Component, IInteractUsing { public override string Name => "PowerTransfer"; /// /// The powernet this component is connected to /// [ViewVariables] public Powernet Parent { get; set; } [ViewVariables] public bool Regenerating { get; set; } = false; protected override void Startup() { base.Startup(); if (Parent == null) { SpreadPowernet(); } } public override void OnRemove() { DisconnectFromPowernet(); base.OnRemove(); } /// /// Searches for local powernets to connect to, otherwise creates its own, and spreads powernet to nearby entities /// public void SpreadPowernet() { var entMgr = IoCManager.Resolve(); var sgc = Owner.GetComponent(); var wires = sgc.GetCardinalNeighborCells() .SelectMany(x => x.GetLocal()).Distinct() .Select(x => x.TryGetComponent(out var c) ? c : null) .Where(x => x != null).Distinct() .ToArray(); //we have no parent so lets find a partner we can join his powernet if (Parent == null || Regenerating) { foreach (var wire in wires) { if (wire.CanConnectTo()) { ConnectToPowernet(wire.Parent); break; } } //we couldn't find a partner so none must have spread yet, lets make our own powernet to spread if (Parent == null || Regenerating) { ConnectToPowernet(new Powernet()); } } //Find nodes intersecting us and if not already assigned to a powernet assign them to us var nodes = entMgr.GetEntitiesIntersecting(Owner) .Select(x => x.TryGetComponent(out PowerNodeComponent pnc) ? pnc : null) .Where(x => x != null); foreach (var node in nodes) { if (node.Parent == null) { node.ConnectToPowernet(Parent); } else if (node.Parent.Dirty) { node.RegeneratePowernet(Parent); } } //spread powernet to nearby wires which haven't got one yet, and tell them to spread as well foreach (var wire in wires) { if (wire.Parent == null || Regenerating) { wire.ConnectToPowernet(Parent); wire.SpreadPowernet(); } else if (wire.Parent != Parent && !wire.Parent.Dirty) { Parent.MergePowernets(wire.Parent); } } } /// /// Called when connecting to a new powernet, either on creation or on regeneration /// /// public void ConnectToPowernet(Powernet toconnect) { Parent = toconnect; Parent.WireList.Add(this); Regenerating = false; } /// /// Called when we are removed and telling the powernet that it is now dirty and must regenerate /// public void DisconnectFromPowernet() { Parent.WireList.Remove(this); Parent.Dirty = true; Parent = null; } public bool CanConnectTo() { return Parent != null && Parent.Dirty == false && !Regenerating; } public bool InteractUsing(InteractUsingEventArgs eventArgs) { if (!eventArgs.Using.TryGetComponent(out ToolComponent tool)) return false; if (!tool.UseTool(eventArgs.User, Owner, ToolQuality.Cutting)) return false; Owner.Delete(); var droppedEnt = Owner.EntityManager.SpawnEntity("CableStack", eventArgs.ClickLocation); if (droppedEnt.TryGetComponent(out var stackComp)) stackComp.Count = 1; return true; } } }