You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
601 lines
17 KiB
601 lines
17 KiB
using ExitGames.Client.Photon;
|
|
using Photon.Pun;
|
|
using Photon.Realtime;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
using UnityEngine.EventSystems;
|
|
|
|
public class Game : MonoBehaviourPunCallbacks {
|
|
|
|
//Singleton
|
|
public static Game Instance { get; private set; }
|
|
|
|
|
|
//General information
|
|
[Header("Game flow")]
|
|
[Tooltip("Play time of the game in minutes")]
|
|
public float playTime;
|
|
[Tooltip("Length of overtime in seconds")]
|
|
public float overtime;
|
|
[Tooltip("Tick rate in ticks/second")]
|
|
public float tickRate;
|
|
|
|
[Header("Spawn Information")]
|
|
public GameObject[] circuitSpawns;
|
|
public float circuitScale;
|
|
public float connectionScale;
|
|
|
|
[Header("Prefabs")]
|
|
public List<CircuitPrefabGroup> circuitPrefabs;
|
|
public GameObject cablePrefab;
|
|
public GameObject chargePrefab;
|
|
|
|
|
|
|
|
//Temporary dragged
|
|
[HideInInspector]
|
|
public Circuit draggedCircuit;
|
|
[HideInInspector]
|
|
public Connection draggedConnection;
|
|
[HideInInspector]
|
|
public Connection draggedCutter;
|
|
|
|
|
|
//Necessary references
|
|
private PhotonView pv;
|
|
public Camera cam;
|
|
|
|
|
|
//Objects
|
|
public List<Circuit> Circuits { get; } = new List<Circuit>();
|
|
private readonly List<Circuit> circuitsToRemove = new List<Circuit>();
|
|
|
|
public List<Connection> Connections { get; } = new List<Connection>();
|
|
private readonly List<Connection> connectionsToRemove = new List<Connection>();
|
|
|
|
|
|
//Called by Unity
|
|
void Awake() {
|
|
Instance = this;
|
|
pv = GetComponent<PhotonView>();
|
|
}
|
|
void Start() {
|
|
if (!PhotonNetwork.IsConnected) {
|
|
PhotonNetwork.OfflineMode = true;
|
|
PhotonNetwork.CreateRoom("development");
|
|
PhotonNetwork.LocalPlayer.SetCustomProperties(new Hashtable() { ["ColorIndex"] = Random.Range(1, 9) });
|
|
StartGame();
|
|
}
|
|
}
|
|
void Update() {
|
|
if (Input.GetMouseButtonDown(0) && !EventSystem.current.IsPointerOverGameObject())
|
|
OnLeftPressed();
|
|
if (Input.GetMouseButtonDown(1) && !EventSystem.current.IsPointerOverGameObject())
|
|
OnRightPressed();
|
|
else if (Input.GetMouseButtonUp(0))
|
|
OnLeftReleased();
|
|
else if (Input.GetMouseButton(0))
|
|
MoveDragged();
|
|
|
|
if (IsPlaying)
|
|
UpdateGame();
|
|
}
|
|
|
|
|
|
//Events and input controls
|
|
public void OnDragStopped() {
|
|
if (draggedCircuit != null) {
|
|
Destroy(draggedCircuit.gameObject);
|
|
draggedCircuit = null;
|
|
}
|
|
if (draggedConnection != null) {
|
|
Destroy(draggedConnection.gameObject);
|
|
draggedConnection = null;
|
|
}
|
|
if (draggedCutter != null) {
|
|
Destroy(draggedCutter.gameObject);
|
|
draggedCutter = null;
|
|
}
|
|
}
|
|
private void OnLeftPressed() {
|
|
if (!Circuits.Exists(c => c.IsMouseOver) && IsPlaying) {
|
|
if (ScreenToPlaneRayCast(Input.mousePosition, out Vector3 hitPoint))
|
|
SpawnDraggableCutter(hitPoint);
|
|
}
|
|
}
|
|
private void OnRightPressed() {
|
|
OnDragStopped();
|
|
}
|
|
private void OnLeftReleased() {
|
|
if (draggedCircuit != null) {
|
|
if (!draggedCircuit.IsNeedingReplace && !EventSystem.current.IsPointerOverGameObject()) {
|
|
Vector3 pos = draggedCircuit.transform.position;
|
|
CircuitType type = draggedCircuit.type;
|
|
if (SpawnGameCircuit(pos, type)) {
|
|
draggedCircuit.uICircuitCount.Count--;
|
|
}
|
|
}
|
|
}
|
|
if (draggedConnection != null) {
|
|
Circuit receiver = draggedConnection.Receiver;
|
|
if (receiver != null && draggedConnection.collidedCircuits.Count == 2) {
|
|
Circuit sender = draggedConnection.Sender;
|
|
Vector3 pos = draggedConnection.transform.position;
|
|
SpawnGameConnection(sender, receiver, pos);
|
|
}
|
|
}
|
|
if (draggedCutter != null) {
|
|
List<Connection> delete = new List<Connection>();
|
|
foreach (Connection connection in Connections.FindAll(c => c.IsMine)) {
|
|
if (connection.collidedConnections.Contains(draggedCutter))
|
|
delete.Add(connection);
|
|
}
|
|
foreach (Connection connection in delete)
|
|
DestroyConnection(connection);
|
|
}
|
|
OnDragStopped();
|
|
}
|
|
private void MoveDragged() {
|
|
if (ScreenToPlaneRayCast(Input.mousePosition, out Vector3 point, true)) {
|
|
if (draggedCircuit != null) {
|
|
draggedCircuit.transform.position = point;
|
|
bool isOut = !ScreenToPlaneRayCast(Input.mousePosition, out point);
|
|
draggedCircuit.IsOutOfGamePlane = isOut;
|
|
}
|
|
if (draggedConnection != null)
|
|
AdjustDraggedConnection(draggedConnection);
|
|
if (draggedCutter != null)
|
|
AdjustDraggedConnection(draggedCutter, true);
|
|
}
|
|
}
|
|
private void AdjustDraggedConnection(Connection dragged, bool cutter = false) {
|
|
Vector3 p1 = dragged.rootPosition;
|
|
if (ScreenToPlaneRayCast(Input.mousePosition, out Vector3 p2)) {
|
|
|
|
if (!cutter) {
|
|
float range = dragged.Sender.Values.range;
|
|
|
|
Circuit potencialReceiver = Circuits.Find(
|
|
c => c.IsMouseOver && c.id != dragged.Sender.id &&
|
|
Vector3.Distance(p1, c.transform.position) <= range
|
|
);
|
|
dragged.Receiver = potencialReceiver;
|
|
|
|
if (potencialReceiver != null)
|
|
p2 = potencialReceiver.transform.position;
|
|
|
|
if (Vector3.Distance(p1, p2) > range) {
|
|
Vector3 dir = (p2 - p1).normalized * range;
|
|
p2 = p1 + dir;
|
|
}
|
|
|
|
}
|
|
|
|
float scale = Vector3.Distance(p1, p2) * 4;
|
|
Vector3 pos = (p1 + p2) / 2;
|
|
Quaternion rot = Quaternion.FromToRotation(Vector3.up, p2 - p1);
|
|
|
|
dragged.LengthScale = scale;
|
|
dragged.transform.SetPositionAndRotation(pos, rot);
|
|
}
|
|
}
|
|
|
|
|
|
//Gameplay
|
|
public bool IsPlaying { get; private set; }
|
|
|
|
private bool isOvertime;
|
|
private float currentPlayTime;
|
|
private float currentOvertime;
|
|
public void StartGame() {
|
|
GameGUI.Instance.StartGUI();
|
|
SpawnCircuit();
|
|
IsPlaying = true;
|
|
Debug.Log("Game has started");
|
|
}
|
|
private void UpdateGame() {
|
|
if (PhotonNetwork.IsMasterClient) {
|
|
foreach (Circuit circuit in Circuits)
|
|
circuit.UpdateCircuit(tickRate);
|
|
foreach (Connection connection in Connections)
|
|
connection.UpdateConnection(tickRate);
|
|
}
|
|
|
|
foreach (Circuit circuit in circuitsToRemove) {
|
|
Circuits.Remove(circuit);
|
|
Destroy(circuit.gameObject);
|
|
}
|
|
circuitsToRemove.Clear();
|
|
foreach (Connection connection in connectionsToRemove) {
|
|
Connections.Remove(connection);
|
|
Destroy(connection.gameObject);
|
|
}
|
|
connectionsToRemove.Clear();
|
|
|
|
UpdateTime();
|
|
}
|
|
private void UpdateTime() {
|
|
float textTime;
|
|
|
|
if (isOvertime) {
|
|
currentOvertime += Time.deltaTime;
|
|
if (currentOvertime >= overtime) {
|
|
currentOvertime = overtime;
|
|
if (PhotonNetwork.IsMasterClient)
|
|
OnTimeRunnedOut();
|
|
}
|
|
textTime = overtime - currentOvertime;
|
|
}
|
|
else {
|
|
currentPlayTime += Time.deltaTime;
|
|
if (currentPlayTime >= playTime * 60) {
|
|
currentPlayTime = playTime * 60;
|
|
if (PhotonNetwork.IsMasterClient)
|
|
OnTimeRunnedOut();
|
|
}
|
|
textTime = playTime * 60 - currentPlayTime;
|
|
}
|
|
|
|
GameGUI.Instance.SetTimeText(textTime);
|
|
}
|
|
private void OnTimeRunnedOut() {
|
|
|
|
float[] charges = new float[5];
|
|
foreach (Circuit circuit in Circuits) {
|
|
charges[circuit.ActorNumber] += circuit.Charge;
|
|
}
|
|
int greatestIndex = 0;
|
|
for (int i = 0; i < charges.Length; i++) {
|
|
float greatest = charges[greatestIndex];
|
|
if (charges[i] > greatest)
|
|
greatestIndex = i;
|
|
}
|
|
|
|
bool isDraw(out List<int> winners) {
|
|
winners = new List<int>();
|
|
for (int i = 0; i < charges.Length; i++) {
|
|
if (charges[i] == charges[greatestIndex]) {
|
|
winners.Add(i);
|
|
}
|
|
}
|
|
if (winners.Count > 1)
|
|
return true;
|
|
return false;
|
|
}
|
|
if (isDraw(out List<int> winnerActorNumbers)) {
|
|
//Draw
|
|
pv.RPC("RpcStartNewOvertime", RpcTarget.All, winnerActorNumbers.ToArray());
|
|
|
|
} else {
|
|
//Unique winner
|
|
pv.RPC("RpcFinishGame", RpcTarget.All, greatestIndex);
|
|
}
|
|
}
|
|
[PunRPC]
|
|
private void RpcStartNewOvertime(int[] winnerActorNumbers) {
|
|
if (isOvertime)
|
|
currentOvertime = 0;
|
|
isOvertime = true;
|
|
|
|
Debug.Log("The players " + string.Join(",", winnerActorNumbers) + " triggered an overtime!");
|
|
}
|
|
[PunRPC]
|
|
private void RpcFinishGame(int winnerActorNumber) {
|
|
OnDragStopped();
|
|
GameGUI.Instance.ShowWinnerBannerPanel(winnerActorNumber);
|
|
GameGUI.Instance.CloseCircuitMenu();
|
|
IsPlaying = false;
|
|
Debug.Log("Player " + winnerActorNumber + " won the game!");
|
|
}
|
|
|
|
|
|
//Circuit Management
|
|
public void SendCircuitCharge(int circuitId, float charge) {
|
|
pv.RPC("RpcApplyCircuitCharge", RpcTarget.Others, circuitId, charge);
|
|
}
|
|
[PunRPC]
|
|
private void RpcApplyCircuitCharge(int circuitId, float charge) {
|
|
Circuit circuit = GetCircuitById(circuitId);
|
|
if (circuit == null) {
|
|
Debug.LogWarning("Circuit to be updated is null");
|
|
return;
|
|
}
|
|
circuit.Charge = charge;
|
|
}
|
|
public void SpawnDraggableCircuit(Vector3 screenPos, CircuitType type, UICircuitCount uICIrcuitCount) {
|
|
if (ScreenToPlaneRayCast(screenPos, out Vector3 hitPoint, true)) {
|
|
Circuit circuit = SpawnCircuit(hitPoint, type, 1);
|
|
circuit.ActorNumber = PhotonNetwork.LocalPlayer.ActorNumber;
|
|
circuit.isDragged = true;
|
|
circuit.uICircuitCount = uICIrcuitCount;
|
|
draggedCircuit = circuit;
|
|
}
|
|
}
|
|
public bool SpawnGameCircuit(Vector3 pos, CircuitType type, int level = 1) {
|
|
Vector3 screenPos = cam.WorldToScreenPoint(pos);
|
|
if (ScreenToPlaneRayCast(screenPos, out Vector3 hitPoint)) {
|
|
SendSpawnCircuit(hitPoint, type, level);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
private void SpawnCircuit() {
|
|
int index = PhotonNetwork.PlayerList.ToList<Player>().IndexOf(PhotonNetwork.LocalPlayer);
|
|
Vector3 pos = circuitSpawns[index].transform.position;
|
|
CircuitType type = CircuitType.Basic;
|
|
int level = 2;
|
|
float charge = GameManager.Instance.restPoints;
|
|
|
|
SendSpawnCircuit(pos, type, level, charge);
|
|
}
|
|
private void SendSpawnCircuit(Vector3 pos, CircuitType type, int level, float charge = 0) {
|
|
int actorNumber = PhotonNetwork.LocalPlayer.ActorNumber;
|
|
int id = CreateCircuitId();
|
|
|
|
pv.RPC("RpcSpawnCircuit", RpcTarget.All, pos, type, level, charge, actorNumber, id);
|
|
}
|
|
private Circuit SpawnCircuit(Vector3 pos, CircuitType type, int level) {
|
|
Quaternion rot = Quaternion.Euler(0, 90, 0);
|
|
Transform parent = GameObject.Find("Circuits").transform;
|
|
Vector3 scale = Vector3.one * circuitScale;
|
|
|
|
CircuitPrefabGroup prefabGroup = circuitPrefabs.Find(x => x.type.Equals(type));
|
|
GameObject prefab = prefabGroup.GetValuesByLevel(level);
|
|
|
|
GameObject circuitObject = Instantiate(prefab, pos, rot, parent);
|
|
circuitObject.transform.localScale = scale;
|
|
|
|
Circuit circuit = circuitObject.GetComponent<Circuit>();
|
|
circuit.type = type;
|
|
circuit.level = level;
|
|
|
|
return circuit;
|
|
}
|
|
[PunRPC]
|
|
private Circuit RpcSpawnCircuit(Vector3 pos, CircuitType type, int level, float charge, int actorNumber, int id) {
|
|
|
|
Circuit circuit = SpawnCircuit(pos, type, level);
|
|
|
|
circuit.id = id;
|
|
circuit.ActorNumber = actorNumber;
|
|
circuit.Charge = charge;
|
|
|
|
Circuits.Add(circuit);
|
|
|
|
return circuit;
|
|
}
|
|
public void DestroyCircuit(Circuit circuit) {
|
|
pv.RPC("RpcDestroyCircuit", RpcTarget.AllViaServer, circuit.id);
|
|
}
|
|
[PunRPC]
|
|
private void RpcDestroyCircuit(int circuitId) {
|
|
Circuit circuit = GetCircuitById(circuitId);
|
|
if (circuit == null)
|
|
return;
|
|
|
|
foreach (Connection connection in circuit.GoingOutConnections) {
|
|
RpcDestroyConnection(connection.id);
|
|
}
|
|
List<Connection> friendlyInConnections =
|
|
circuit.GoingInConnections.FindAll(c => c.ActorNumber == circuit.ActorNumber);
|
|
foreach (Connection connection in friendlyInConnections) {
|
|
RpcDestroyConnection(connection.id);
|
|
}
|
|
|
|
circuitsToRemove.Add(circuit);
|
|
}
|
|
public void UpgradeCircuit(Circuit circuit) {
|
|
int newId = CreateCircuitId();
|
|
pv.RPC("RpcUpgradeCircuit", RpcTarget.AllViaServer, circuit.id, newId);
|
|
}
|
|
[PunRPC]
|
|
private void RpcUpgradeCircuit(int circuitId, int newId) {
|
|
Circuit oldCircuit = GetCircuitById(circuitId);
|
|
if (oldCircuit == null)
|
|
return;
|
|
|
|
//New values
|
|
Vector3 pos = oldCircuit.transform.position;
|
|
CircuitType type = oldCircuit.type;
|
|
int level = oldCircuit.level + 1;
|
|
float charge = oldCircuit.Charge * 0.8f;
|
|
int actorNumber = oldCircuit.ActorNumber;
|
|
|
|
Circuit newCircuit = RpcSpawnCircuit(pos, type, level, charge, actorNumber, newId);
|
|
|
|
foreach (Connection connection in oldCircuit.GoingOutConnections)
|
|
connection.Sender = newCircuit;
|
|
foreach (Connection connection in oldCircuit.GoingInConnections)
|
|
connection.Receiver = newCircuit;
|
|
|
|
RpcDestroyCircuit(oldCircuit.id);
|
|
|
|
if (oldCircuit.IsSelected)
|
|
newCircuit.Select();
|
|
|
|
}
|
|
public void SendUpgradeCharge(Circuit circuit) {
|
|
pv.RPC("RpcUpgradeCharge", RpcTarget.Others, circuit.UpgradeCharge, circuit.Charge, circuit.id);
|
|
}
|
|
[PunRPC]
|
|
private void RpcUpgradeCharge(float upgradeCharge, float charge, int circuitId) {
|
|
Circuit circuit = GetCircuitById(circuitId);
|
|
if (circuit == null)
|
|
return;
|
|
|
|
circuit.Charge = charge;
|
|
circuit.UpgradeCharge = upgradeCharge;
|
|
}
|
|
|
|
//Connection Management
|
|
private void SpawnDraggableCutter(Vector3 pos) {
|
|
Quaternion rot = Quaternion.Euler(90, 0, 0);
|
|
|
|
Connection cutter = SpawnConnection(null, null, pos, rot, 0);
|
|
cutter.ActorNumber = PhotonNetwork.LocalPlayer.ActorNumber;
|
|
|
|
draggedCutter = cutter;
|
|
}
|
|
public void SpawnDraggableConnection(Vector3 pos, Circuit sender) {
|
|
Quaternion rot = Quaternion.Euler(90, 0, 0);
|
|
|
|
Connection connection = SpawnConnection(sender, null, pos, rot, 0);
|
|
|
|
draggedConnection = connection;
|
|
}
|
|
public void SpawnGameConnection(Circuit sender, Circuit receiver, Vector3 pos) {
|
|
Quaternion rot = draggedConnection.transform.rotation;
|
|
float lengthScale = draggedConnection.LengthScale;
|
|
|
|
SendSpawnConnection(sender, receiver, pos, rot, lengthScale);
|
|
}
|
|
private Connection SpawnConnection(Circuit sender, Circuit receiver, Vector3 pos, Quaternion rot, float lengthScale) {
|
|
Transform parent = GameObject.Find("Connections").transform;
|
|
|
|
GameObject connectionObject = Instantiate(cablePrefab, pos, rot, parent);
|
|
|
|
Connection connection = connectionObject.GetComponent<Connection>();
|
|
connection.Sender = sender;
|
|
connection.Receiver = receiver;
|
|
connection.LengthScale = lengthScale;
|
|
connection.rootPosition = pos;
|
|
|
|
return connection;
|
|
}
|
|
private void SendSpawnConnection(Circuit sender, Circuit receiver, Vector3 pos, Quaternion rot, float lengthScale) {
|
|
int senderId = sender.id;
|
|
int receiverId = receiver.id;
|
|
int id = CreateConnectionId();
|
|
|
|
pv.RPC("RpcSpawnConnection", RpcTarget.All, pos, rot, lengthScale, senderId, receiverId, id);
|
|
}
|
|
[PunRPC]
|
|
private void RpcSpawnConnection(Vector3 pos, Quaternion rot, float lengthScale, int senderId, int receiverId, int id) {
|
|
|
|
Circuit sender = GetCircuitById(senderId);
|
|
Circuit receiver = GetCircuitById(receiverId);
|
|
|
|
Connection connection = SpawnConnection(sender, receiver, pos, rot, lengthScale);
|
|
|
|
connection.id = id;
|
|
Connections.Add(connection);
|
|
|
|
GameGUI.Instance.UpdateMenuStats();
|
|
}
|
|
public void DestroyConnection(Connection connection) {
|
|
pv.RPC("RpcDestroyConnection", RpcTarget.AllViaServer, connection.id);
|
|
}
|
|
[PunRPC]
|
|
private void RpcDestroyConnection(int connectionId) {
|
|
Connection connection = GetConnectionById(connectionId);
|
|
if (connection == null)
|
|
return;
|
|
|
|
connectionsToRemove.Add(connection);
|
|
}
|
|
|
|
|
|
//Charge Management
|
|
public void SpawnConnectionCharge(Connection connection) {
|
|
int actorNumber = connection.ActorNumber;
|
|
int connectionId = connection.id;
|
|
int id = connection.CreateChargeId();
|
|
|
|
pv.RPC("RpcSpawnCharge", RpcTarget.All, connectionId, id, actorNumber);
|
|
}
|
|
[PunRPC]
|
|
private Charge RpcSpawnCharge(int connectionId, int id, int actorNumber) {
|
|
Connection connection = GetConnectionById(connectionId);
|
|
if (connection == null)
|
|
return null;
|
|
|
|
Charge charge = SpawnCharge(connection);
|
|
|
|
charge.id = id;
|
|
charge.ActorNumber = actorNumber;
|
|
connection.AddCharge(charge);
|
|
|
|
return charge;
|
|
}
|
|
private Charge SpawnCharge(Connection connection) {
|
|
Transform parent = connection.transform;
|
|
Vector3 pos = connection.Sender.transform.position;
|
|
Quaternion rot = parent.rotation;
|
|
Vector3 scale = new Vector3(1, 1 / parent.localScale.y * parent.localScale.x, 1);
|
|
|
|
GameObject chargeObject = Instantiate(chargePrefab, pos, rot, parent);
|
|
chargeObject.transform.localScale = scale;
|
|
|
|
Charge charge = chargeObject.GetComponent<Charge>();
|
|
charge.Speed = connection.Sender.Values.sendSpeed;
|
|
|
|
return charge;
|
|
}
|
|
public void DestroyCharge(Connection connection, Charge charge) {
|
|
int connectionId = connection.id;
|
|
int id = charge.id;
|
|
|
|
pv.RPC("RpcDestroyCharge", RpcTarget.All, connectionId, id);
|
|
}
|
|
[PunRPC]
|
|
private void RpcDestroyCharge(int connectionId, int id) {
|
|
Connection connection = GetConnectionById(connectionId);
|
|
if (connection == null)
|
|
return;
|
|
|
|
Charge charge = connection.GetChargeById(id);
|
|
|
|
connection.RemoveCharge(charge);
|
|
|
|
Destroy(charge.gameObject);
|
|
}
|
|
|
|
|
|
//Useful, logical functions
|
|
private bool ScreenToPlaneRayCast(Vector3 screenPos, out Vector3 hitPoint, bool outerPlane = false) {
|
|
Ray ray = cam.ScreenPointToRay(screenPos);
|
|
int layerMask;
|
|
if (outerPlane)
|
|
layerMask = LayerMask.GetMask("Outer Plane");
|
|
else
|
|
layerMask = LayerMask.GetMask("Game Plane");
|
|
if (Physics.Raycast(ray, out RaycastHit info, Mathf.Infinity, layerMask)) {
|
|
if (info.collider != null) {
|
|
hitPoint = info.point;
|
|
return true;
|
|
}
|
|
}
|
|
hitPoint = Vector3.zero;
|
|
return false;
|
|
}
|
|
private int CreateCircuitId() {
|
|
int id;
|
|
do
|
|
id = Random.Range(0, 10000);
|
|
while
|
|
(Circuits.Exists(c => c.id == id));
|
|
return id;
|
|
}
|
|
private int CreateConnectionId() {
|
|
int id;
|
|
do
|
|
id = Random.Range(0, 10000);
|
|
while
|
|
(Connections.Exists(c => c.id == id));
|
|
return id;
|
|
}
|
|
private Connection GetConnectionById(int id) {
|
|
Connection connection = Connections.Find(c => c.id == id);
|
|
return connection;
|
|
}
|
|
private Circuit GetCircuitById(int id) {
|
|
Circuit circuit = Circuits.Find(c => c.id == id);
|
|
return circuit;
|
|
}
|
|
public List<Circuit> CircuitsWithout(Circuit without) {
|
|
List<Circuit> copy = new List<Circuit>(Circuits);
|
|
copy.Remove(without);
|
|
return copy;
|
|
}
|
|
}
|
|
|