2025-09-17 10:12:15 +02:00
|
|
|
|
using System;
|
2025-09-16 01:16:02 +02:00
|
|
|
|
using System.Collections.Generic;
|
2025-09-16 10:45:09 +02:00
|
|
|
|
using System.Dynamic;
|
2025-09-16 19:49:18 +02:00
|
|
|
|
using System.Linq;
|
2025-09-18 20:05:01 +02:00
|
|
|
|
using TMPro;
|
2025-09-16 01:16:02 +02:00
|
|
|
|
using Unity.VisualScripting;
|
|
|
|
|
|
using UnityEditor;
|
|
|
|
|
|
using UnityEngine;
|
2025-09-18 20:05:01 +02:00
|
|
|
|
using UnityEngine.UI;
|
2025-09-16 01:16:02 +02:00
|
|
|
|
|
2025-09-18 17:37:35 +02:00
|
|
|
|
|
2025-09-16 01:16:02 +02:00
|
|
|
|
[ExecuteAlways]
|
|
|
|
|
|
public class GameManager : MonoBehaviour
|
|
|
|
|
|
{
|
2025-09-16 16:50:21 +02:00
|
|
|
|
public Transform ConnectionParent;
|
2025-09-17 23:38:11 +02:00
|
|
|
|
public GameObject ConnectionPrefab;
|
2025-09-16 10:45:09 +02:00
|
|
|
|
public Transform NodeParent;
|
|
|
|
|
|
public GameObject NodePrefab;
|
2025-09-16 01:16:02 +02:00
|
|
|
|
|
2025-09-18 20:05:01 +02:00
|
|
|
|
public TMP_Text hoverText;
|
|
|
|
|
|
public TMP_Text energyText;
|
|
|
|
|
|
public TMP_Text currentPlayerText;
|
|
|
|
|
|
public GameObject actionListItemPrefab;
|
|
|
|
|
|
public Transform actionListParent;
|
|
|
|
|
|
public Button finishTurnBtn;
|
|
|
|
|
|
|
|
|
|
|
|
[SerializeField]
|
2025-09-18 17:37:35 +02:00
|
|
|
|
public List<Player> players;
|
2025-09-18 20:05:01 +02:00
|
|
|
|
|
2025-09-17 21:48:38 +02:00
|
|
|
|
public int currentPlayer = -1;
|
2025-09-18 03:24:40 +02:00
|
|
|
|
public Node pressedNode = null;
|
2025-09-18 20:05:01 +02:00
|
|
|
|
public Connection pressedCon = null;
|
|
|
|
|
|
public KeyCode altActionKey = KeyCode.LeftShift;
|
|
|
|
|
|
|
|
|
|
|
|
public float zoomSpeed = 20f;
|
|
|
|
|
|
public float minFOV = 20f;
|
|
|
|
|
|
public float maxFOV = 80f;
|
2025-09-17 21:48:38 +02:00
|
|
|
|
|
2025-09-16 18:19:40 +02:00
|
|
|
|
public static GameManager Instance { get; private set; }
|
2025-09-16 01:16:02 +02:00
|
|
|
|
|
2025-09-16 19:49:18 +02:00
|
|
|
|
public bool regenerateOnChange = false;
|
|
|
|
|
|
|
2025-09-18 20:05:01 +02:00
|
|
|
|
[SerializeField]
|
|
|
|
|
|
public List<Action> actions;
|
|
|
|
|
|
|
2025-09-17 17:05:48 +02:00
|
|
|
|
[HideInInspector] public float minConnectionLength = 6;
|
2025-09-16 16:50:21 +02:00
|
|
|
|
[HideInInspector] public float maxConnectionLength = 6;
|
|
|
|
|
|
[HideInInspector] public int nodeCount = 100;
|
2025-09-16 17:40:34 +02:00
|
|
|
|
[HideInInspector] public int hoverRadiusCon = 50;
|
|
|
|
|
|
[HideInInspector] public int hoverRadiusNode = 50;
|
2025-09-17 10:12:15 +02:00
|
|
|
|
[HideInInspector] public int selectedLevel = -1;
|
2025-09-16 00:08:50 +02:00
|
|
|
|
|
2025-09-17 10:12:15 +02:00
|
|
|
|
[SerializeField] [HideInInspector] public List<LevelData> levels = new List<LevelData>();
|
2025-09-16 10:45:09 +02:00
|
|
|
|
|
2025-09-18 20:05:01 +02:00
|
|
|
|
public enum ActionType { NONE, MOVE_HALF_UNITS, MOVE_ALL_UNITS, ATTACK_NODE_WITH_HALF, ATTACK_NODE_WITH_ALL, ATTACK_CON_WITH_HALF, ATTACK_CON_WITH_ALL, CONSTRUCT_CON, DESTRUCT_CON, EXPLODE_CON };
|
2025-09-18 03:24:40 +02:00
|
|
|
|
|
2025-09-18 20:05:01 +02:00
|
|
|
|
public Dictionary<ActionType, string> ActionTypeText = new Dictionary<ActionType, string>
|
|
|
|
|
|
{
|
|
|
|
|
|
{ ActionType.NONE, "" },
|
|
|
|
|
|
{ ActionType.MOVE_HALF_UNITS, "Move troops (1/2)" },
|
|
|
|
|
|
{ ActionType.MOVE_ALL_UNITS, "Move troops" },
|
|
|
|
|
|
{ ActionType.ATTACK_NODE_WITH_HALF, "Attack (1/2)" },
|
|
|
|
|
|
{ ActionType.ATTACK_NODE_WITH_ALL, "Attack" },
|
|
|
|
|
|
{ ActionType.ATTACK_CON_WITH_HALF, "Interrupt Construction (1/2)" },
|
|
|
|
|
|
{ ActionType.ATTACK_CON_WITH_ALL, "Interrupt Construction" },
|
|
|
|
|
|
{ ActionType.CONSTRUCT_CON, "Construct" },
|
|
|
|
|
|
{ ActionType.DESTRUCT_CON, "Destruct" },
|
|
|
|
|
|
{ ActionType.EXPLODE_CON, "Explode (immediately)" }
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
public Dictionary<ActionType, int> ActionTypeEnergyUsage = new Dictionary<ActionType, int>
|
|
|
|
|
|
{
|
|
|
|
|
|
{ ActionType.NONE, 0},
|
|
|
|
|
|
{ ActionType.MOVE_HALF_UNITS, 1},
|
|
|
|
|
|
{ ActionType.MOVE_ALL_UNITS, 1},
|
|
|
|
|
|
{ ActionType.ATTACK_NODE_WITH_HALF, 1},
|
|
|
|
|
|
{ ActionType.ATTACK_NODE_WITH_ALL, 1},
|
|
|
|
|
|
{ ActionType.ATTACK_CON_WITH_HALF, 1},
|
|
|
|
|
|
{ ActionType.ATTACK_CON_WITH_ALL, 1},
|
|
|
|
|
|
{ ActionType.CONSTRUCT_CON, 1},
|
|
|
|
|
|
{ ActionType.DESTRUCT_CON, 1},
|
|
|
|
|
|
{ ActionType.EXPLODE_CON, 2 }
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
[Serializable]
|
2025-09-18 03:24:40 +02:00
|
|
|
|
public struct Action
|
|
|
|
|
|
{
|
2025-09-18 20:05:01 +02:00
|
|
|
|
public ActionType intendedAction;
|
|
|
|
|
|
|
|
|
|
|
|
public bool onConnection;
|
|
|
|
|
|
public bool altAction;
|
2025-09-18 03:24:40 +02:00
|
|
|
|
public int nodeFromId;
|
|
|
|
|
|
public int nodeToId;
|
2025-09-18 17:37:35 +02:00
|
|
|
|
public int amount;
|
2025-09-18 03:24:40 +02:00
|
|
|
|
public int player;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-17 15:43:26 +02:00
|
|
|
|
[Serializable]
|
|
|
|
|
|
public class LevelData
|
|
|
|
|
|
{
|
|
|
|
|
|
[Serializable]
|
|
|
|
|
|
public class NodeData
|
|
|
|
|
|
{
|
|
|
|
|
|
public Vector3 position;
|
|
|
|
|
|
public int owner;
|
2025-09-18 20:05:01 +02:00
|
|
|
|
public int units;
|
2025-09-17 15:43:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[Serializable]
|
|
|
|
|
|
public class ConnectionData
|
|
|
|
|
|
{
|
|
|
|
|
|
public int nodeAIndex;
|
|
|
|
|
|
public int nodeBIndex;
|
|
|
|
|
|
public bool allowed = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-17 17:05:48 +02:00
|
|
|
|
public float minConnectionLength = 0;
|
2025-09-17 15:43:26 +02:00
|
|
|
|
public float maxConnectionLength = 0;
|
|
|
|
|
|
public List<NodeData> nodes = new List<NodeData>();
|
|
|
|
|
|
public List<ConnectionData> connections = new List<ConnectionData>();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-16 18:19:40 +02:00
|
|
|
|
void Awake()
|
2025-09-16 17:40:34 +02:00
|
|
|
|
{
|
|
|
|
|
|
if (Instance != null && Instance != this)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Application.isPlaying)
|
|
|
|
|
|
Destroy(gameObject);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Instance = this;
|
|
|
|
|
|
if (Application.isPlaying)
|
|
|
|
|
|
DontDestroyOnLoad(gameObject);
|
|
|
|
|
|
|
2025-09-17 17:26:16 +02:00
|
|
|
|
|
2025-09-17 23:38:11 +02:00
|
|
|
|
GetConnections().ForEach(obj => obj.DelConnect());
|
|
|
|
|
|
GetConnections().ForEach(obj => obj.SetConnect());
|
2025-09-17 17:26:16 +02:00
|
|
|
|
|
2025-09-16 17:40:34 +02:00
|
|
|
|
}
|
2025-09-16 16:50:21 +02:00
|
|
|
|
|
2025-09-18 20:05:01 +02:00
|
|
|
|
private void Start()
|
|
|
|
|
|
{
|
|
|
|
|
|
LoadLevelData(selectedLevel);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-17 21:48:38 +02:00
|
|
|
|
private void Update()
|
|
|
|
|
|
{
|
2025-09-18 20:05:01 +02:00
|
|
|
|
hoverText.enabled = false;
|
|
|
|
|
|
|
|
|
|
|
|
Player player = players.Find(p => p.id == currentPlayer);
|
|
|
|
|
|
|
|
|
|
|
|
int totalEnergyCost = 0;
|
|
|
|
|
|
actions.ForEach(a => totalEnergyCost += ActionTypeEnergyUsage[a.intendedAction]);
|
|
|
|
|
|
|
|
|
|
|
|
if (player != null && Application.isPlaying)
|
|
|
|
|
|
{
|
|
|
|
|
|
energyText.text = "Energy: [" + string.Concat(Enumerable.Repeat("□", player.energy - totalEnergyCost)) + string.Concat(Enumerable.Repeat("-", totalEnergyCost)) + "]";
|
|
|
|
|
|
currentPlayerText.text = "[ Player " + currentPlayer + " ]";
|
|
|
|
|
|
|
|
|
|
|
|
foreach (TMP_Text item in actionListParent.GetComponentsInChildren<TMP_Text>())
|
|
|
|
|
|
Destroy(item.gameObject);
|
|
|
|
|
|
|
|
|
|
|
|
actions.ForEach(a => Instantiate(actionListItemPrefab, actionListParent).GetComponentInChildren<TMP_Text>().text = ActionTypeText[a.intendedAction] + " (" + a.nodeFromId + ">" + a.nodeToId + ")");
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-09-18 03:24:40 +02:00
|
|
|
|
if (Input.GetMouseButtonDown(0))
|
|
|
|
|
|
{
|
|
|
|
|
|
pressedNode = GetNodes().Find(n => n.hovered && n.Owner == currentPlayer);
|
|
|
|
|
|
}
|
2025-09-18 20:05:01 +02:00
|
|
|
|
if (Input.GetMouseButton(0))
|
|
|
|
|
|
{
|
|
|
|
|
|
if(pressedNode != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Node node = GetNodes().Find(n => n.hovered && n != pressedNode);
|
|
|
|
|
|
|
|
|
|
|
|
if (node)
|
|
|
|
|
|
{
|
|
|
|
|
|
Connection con = GetConnections().Find(c => (c.nodeA == pressedNode && c.nodeB == node) || (c.nodeB == pressedNode && c.nodeA == node)) ?? null;
|
|
|
|
|
|
ActionType possibleAction = CalcActionBetweenNodes(currentPlayer, pressedNode.id, node.id, Input.GetKey(altActionKey));
|
|
|
|
|
|
hoverText.text = ActionTypeText[possibleAction];
|
|
|
|
|
|
hoverText.enabled = true;
|
|
|
|
|
|
|
|
|
|
|
|
if (con != null && con.allowed)
|
|
|
|
|
|
con.hovered = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-18 03:24:40 +02:00
|
|
|
|
if (Input.GetMouseButtonUp(0))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (pressedNode != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Node toNode = GetNodes().Find(n => n.hovered && pressedNode != n);
|
|
|
|
|
|
|
|
|
|
|
|
if (toNode)
|
|
|
|
|
|
{
|
2025-09-18 20:05:01 +02:00
|
|
|
|
Connection con = GetConnections().Find(c => (c.nodeA == pressedNode && c.nodeB == toNode) || (c.nodeB == pressedNode && c.nodeA == toNode)) ?? null;
|
|
|
|
|
|
if (con != null && con.allowed)
|
|
|
|
|
|
PushNewAction(pressedNode.id, toNode.id);
|
2025-09-18 03:24:40 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-18 20:05:01 +02:00
|
|
|
|
if (!hoverText.enabled)
|
|
|
|
|
|
{
|
|
|
|
|
|
Connection hoveredCon = GetConnections().Find(c => c.hovered);
|
|
|
|
|
|
if (hoveredCon != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
ActionType possibleAction = CalcActionBetweenNodes(currentPlayer, hoveredCon.nodeA.id, hoveredCon.nodeB.id, Input.GetKey(altActionKey), true);
|
|
|
|
|
|
hoverText.text = ActionTypeText[possibleAction];
|
|
|
|
|
|
hoverText.enabled = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-17 23:38:11 +02:00
|
|
|
|
}
|
2025-09-17 21:48:38 +02:00
|
|
|
|
|
2025-09-18 20:05:01 +02:00
|
|
|
|
public ActionType CalcActionBetweenNodes(int player, int nodeFromId, int nodeToId, bool altAction = false, bool onConnection = false)
|
|
|
|
|
|
{
|
|
|
|
|
|
Node nodeTo = GetNodes().Find(n => n.id == nodeToId);
|
|
|
|
|
|
Node nodeFrom = GetNodes().Find(n => n.id == nodeFromId);
|
|
|
|
|
|
Connection con = GetConnections().Find(c => (c.nodeA == nodeTo && c.nodeB == nodeFrom) || (c.nodeA == nodeFrom && c.nodeB == nodeTo));
|
|
|
|
|
|
|
|
|
|
|
|
if (con == null || con.allowed == false)
|
|
|
|
|
|
return ActionType.NONE;
|
|
|
|
|
|
|
|
|
|
|
|
// Clicked on connection
|
|
|
|
|
|
if (onConnection)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (con.state == Connection.BuildState.BUILT && nodeFrom.Owner == player && nodeTo.Owner == player)
|
|
|
|
|
|
{
|
|
|
|
|
|
return altAction ? ActionType.EXPLODE_CON : ActionType.DESTRUCT_CON;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (con.state == Connection.BuildState.EMPTY && (nodeFrom.Owner == player || nodeTo.Owner == player))
|
|
|
|
|
|
{
|
|
|
|
|
|
return ActionType.CONSTRUCT_CON;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// Dragged owned nodeFrom to nodeTo
|
|
|
|
|
|
else if (nodeFrom.Owner == player)
|
|
|
|
|
|
{
|
|
|
|
|
|
// To Owned
|
|
|
|
|
|
if (nodeTo.Owner == player)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (con.state)
|
|
|
|
|
|
{
|
|
|
|
|
|
case Connection.BuildState.EMPTY:
|
|
|
|
|
|
return ActionType.CONSTRUCT_CON;
|
|
|
|
|
|
|
|
|
|
|
|
case Connection.BuildState.CONSTRUCTING:
|
|
|
|
|
|
case Connection.BuildState.DECONSTRUCTING:
|
|
|
|
|
|
return ActionType.NONE;
|
|
|
|
|
|
|
|
|
|
|
|
case Connection.BuildState.BUILT:
|
|
|
|
|
|
return altAction ? ActionType.MOVE_HALF_UNITS : ActionType.MOVE_ALL_UNITS;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// To Hostile
|
|
|
|
|
|
else if (nodeTo.Owner >= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (con.state)
|
|
|
|
|
|
{
|
|
|
|
|
|
case Connection.BuildState.EMPTY:
|
|
|
|
|
|
return ActionType.CONSTRUCT_CON;
|
|
|
|
|
|
|
|
|
|
|
|
case Connection.BuildState.CONSTRUCTING:
|
|
|
|
|
|
return altAction ? ActionType.ATTACK_CON_WITH_HALF : ActionType.ATTACK_CON_WITH_ALL;
|
|
|
|
|
|
|
|
|
|
|
|
case Connection.BuildState.DECONSTRUCTING:
|
|
|
|
|
|
return ActionType.NONE;
|
|
|
|
|
|
|
|
|
|
|
|
case Connection.BuildState.BUILT:
|
|
|
|
|
|
return altAction ? ActionType.ATTACK_NODE_WITH_HALF : ActionType.ATTACK_NODE_WITH_ALL;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// To Unclaimed
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (con.state)
|
|
|
|
|
|
{
|
|
|
|
|
|
case Connection.BuildState.EMPTY:
|
|
|
|
|
|
return ActionType.CONSTRUCT_CON;
|
|
|
|
|
|
|
|
|
|
|
|
case Connection.BuildState.CONSTRUCTING:
|
|
|
|
|
|
case Connection.BuildState.DECONSTRUCTING:
|
|
|
|
|
|
return ActionType.NONE;
|
|
|
|
|
|
|
|
|
|
|
|
case Connection.BuildState.BUILT:
|
|
|
|
|
|
return altAction ? ActionType.MOVE_HALF_UNITS : ActionType.MOVE_ALL_UNITS;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return ActionType.NONE;
|
|
|
|
|
|
}
|
2025-09-17 23:38:11 +02:00
|
|
|
|
public List<Node> GetNodes() => NodeParent.GetComponentsInChildren<Node>().ToList();
|
2025-09-18 17:37:35 +02:00
|
|
|
|
public List<Connection> GetConnections() => ConnectionParent != null ? ConnectionParent.GetComponentsInChildren<Connection>()?.ToList() ?? new() : new();
|
2025-09-17 21:48:38 +02:00
|
|
|
|
|
2025-09-18 20:05:01 +02:00
|
|
|
|
public void UpdateConstructions()
|
2025-09-17 23:38:11 +02:00
|
|
|
|
{
|
2025-09-18 03:24:40 +02:00
|
|
|
|
foreach(Connection con in GetConnections())
|
|
|
|
|
|
{
|
2025-09-18 20:05:01 +02:00
|
|
|
|
if (con.constructingPlayerId == currentPlayer)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (con.state == Connection.BuildState.CONSTRUCTING)
|
|
|
|
|
|
con.state = Connection.BuildState.BUILT;
|
|
|
|
|
|
else if (con.state == Connection.BuildState.DECONSTRUCTING)
|
|
|
|
|
|
con.state = Connection.BuildState.EMPTY;
|
|
|
|
|
|
|
|
|
|
|
|
con.constructingPlayerId = -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void ExecuteTurn()
|
|
|
|
|
|
{
|
|
|
|
|
|
Player player = players.Find(p => p.id == currentPlayer);
|
|
|
|
|
|
|
|
|
|
|
|
if (player == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogWarning("Player " + currentPlayer + " not found!");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int totalEnergyCost = 0;
|
|
|
|
|
|
actions.ForEach(a => totalEnergyCost += ActionTypeEnergyUsage[a.intendedAction]);
|
|
|
|
|
|
|
|
|
|
|
|
if (totalEnergyCost > player.energy)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Log("Insuficcient Energy for Turn! (needs " + totalEnergyCost + " has " + player.energy + ")");
|
|
|
|
|
|
return;
|
2025-09-18 03:24:40 +02:00
|
|
|
|
}
|
2025-09-18 20:05:01 +02:00
|
|
|
|
|
|
|
|
|
|
actions.ForEach(a => ExecuteAction(a));
|
|
|
|
|
|
actions.Clear();
|
|
|
|
|
|
|
|
|
|
|
|
// Select next player
|
|
|
|
|
|
currentPlayer++;
|
|
|
|
|
|
Player nextPlayer = players.Find(p => p.id == currentPlayer);
|
|
|
|
|
|
|
|
|
|
|
|
// Executed turn of last Player => Round ended
|
|
|
|
|
|
if(nextPlayer == null)
|
|
|
|
|
|
currentPlayer = 0;
|
|
|
|
|
|
|
|
|
|
|
|
UpdateConstructions();
|
|
|
|
|
|
|
|
|
|
|
|
// Refill energy
|
|
|
|
|
|
players.Find(p => p.id == currentPlayer).energy = 3;
|
2025-09-17 21:48:38 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-18 20:05:01 +02:00
|
|
|
|
public void PushAction(Action action) => actions.Add(action);
|
|
|
|
|
|
public Action PushNewAction(int nodeFromId, int nodeToId, bool onConnection = false, int? player = null, bool ? altAction = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
int _player = player != null ? (int)player : currentPlayer;
|
|
|
|
|
|
bool _altAction = altAction != null ? (bool)altAction : Input.GetKey(altActionKey);
|
|
|
|
|
|
|
|
|
|
|
|
ActionType type = CalcActionBetweenNodes(_player, nodeFromId, nodeToId, _altAction, onConnection);
|
|
|
|
|
|
Action action = new Action
|
|
|
|
|
|
{
|
|
|
|
|
|
intendedAction = type,
|
|
|
|
|
|
nodeFromId = nodeFromId,
|
|
|
|
|
|
nodeToId = nodeToId,
|
|
|
|
|
|
player = _player,
|
|
|
|
|
|
altAction = _altAction,
|
|
|
|
|
|
onConnection = onConnection
|
|
|
|
|
|
};
|
|
|
|
|
|
if(type != ActionType.NONE)
|
|
|
|
|
|
PushAction(action);
|
|
|
|
|
|
|
|
|
|
|
|
return action;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-09-18 03:24:40 +02:00
|
|
|
|
public void ExecuteAction(Action action)
|
|
|
|
|
|
{
|
|
|
|
|
|
Node nodeTo = GetNodes().Find(n => n.id == action.nodeToId);
|
|
|
|
|
|
Node nodeFrom = GetNodes().Find(n => n.id == action.nodeFromId);
|
|
|
|
|
|
Connection con = GetConnections().Find(c => (c.nodeA == nodeTo && c.nodeB == nodeFrom) || (c.nodeA == nodeFrom && c.nodeB == nodeTo));
|
2025-09-18 17:37:35 +02:00
|
|
|
|
Player p = players.Find(p => (p.id == action.player));
|
2025-09-18 03:24:40 +02:00
|
|
|
|
|
2025-09-18 20:05:01 +02:00
|
|
|
|
if (p == null)
|
2025-09-18 03:24:40 +02:00
|
|
|
|
{
|
2025-09-18 20:05:01 +02:00
|
|
|
|
Debug.LogWarning("Player " + action.player + " not found!");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-09-18 17:37:35 +02:00
|
|
|
|
|
2025-09-18 20:05:01 +02:00
|
|
|
|
ActionType possibleAction = CalcActionBetweenNodes(action.player, action.nodeFromId, action.nodeToId, action.altAction, action.onConnection);
|
2025-09-18 03:24:40 +02:00
|
|
|
|
|
2025-09-18 20:05:01 +02:00
|
|
|
|
if (possibleAction != action.intendedAction)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogWarning("Intended action not possible (TODO: execute counter action)");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-09-18 03:24:40 +02:00
|
|
|
|
|
2025-09-18 20:05:01 +02:00
|
|
|
|
if (p.energy < ActionTypeEnergyUsage[action.intendedAction])
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Log("Insuficcient Energy! (needs " + ActionTypeEnergyUsage[action.intendedAction] + " has " + p.energy + ")");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-09-18 03:24:40 +02:00
|
|
|
|
|
2025-09-18 20:05:01 +02:00
|
|
|
|
switch (action.intendedAction)
|
|
|
|
|
|
{
|
|
|
|
|
|
case ActionType.NONE:
|
|
|
|
|
|
break;
|
2025-09-18 03:24:40 +02:00
|
|
|
|
|
2025-09-18 20:05:01 +02:00
|
|
|
|
case ActionType.MOVE_HALF_UNITS:
|
|
|
|
|
|
case ActionType.MOVE_ALL_UNITS:
|
|
|
|
|
|
Debug.Log("Moving units from " + nodeTo.id + " to " + nodeFrom.id);
|
|
|
|
|
|
|
|
|
|
|
|
if (action.intendedAction == ActionType.MOVE_ALL_UNITS)
|
2025-09-18 03:24:40 +02:00
|
|
|
|
{
|
2025-09-18 20:05:01 +02:00
|
|
|
|
nodeTo.Units += nodeFrom.Units;
|
|
|
|
|
|
nodeFrom.Units = 0;
|
2025-09-18 03:24:40 +02:00
|
|
|
|
}
|
2025-09-18 20:05:01 +02:00
|
|
|
|
else if (action.intendedAction == ActionType.MOVE_HALF_UNITS)
|
2025-09-18 03:24:40 +02:00
|
|
|
|
{
|
2025-09-18 20:05:01 +02:00
|
|
|
|
int diff = Mathf.CeilToInt(nodeFrom.Units / 2);
|
|
|
|
|
|
nodeTo.Units += diff;
|
|
|
|
|
|
nodeFrom.Units -= diff;
|
2025-09-18 03:24:40 +02:00
|
|
|
|
}
|
2025-09-18 20:05:01 +02:00
|
|
|
|
if (nodeFrom.Units <= 0)
|
|
|
|
|
|
nodeFrom.Owner = -1;
|
|
|
|
|
|
if (nodeTo.Units > 0)
|
|
|
|
|
|
nodeTo.Owner = currentPlayer;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case ActionType.ATTACK_NODE_WITH_HALF:
|
|
|
|
|
|
Debug.Log("Attacking hostile units with half from " + nodeTo.id + " to " + nodeFrom.id);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case ActionType.ATTACK_NODE_WITH_ALL:
|
|
|
|
|
|
Debug.Log("Attacking hostile units with all from " + nodeTo.id + " to " + nodeFrom.id);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case ActionType.ATTACK_CON_WITH_HALF:
|
|
|
|
|
|
Debug.Log("Attacking hostile construction with half from " + nodeTo.id + " to " + nodeFrom.id);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case ActionType.ATTACK_CON_WITH_ALL:
|
|
|
|
|
|
Debug.Log("Attacking hostile construction with all from " + nodeTo.id + " to " + nodeFrom.id);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case ActionType.CONSTRUCT_CON:
|
|
|
|
|
|
Debug.Log("Starting construction from " + nodeTo.id + " to " + nodeFrom.id);
|
|
|
|
|
|
con.state = Connection.BuildState.CONSTRUCTING;
|
|
|
|
|
|
con.constructingPlayerId = action.player;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case ActionType.DESTRUCT_CON:
|
|
|
|
|
|
Debug.Log("Starten deconstruction from " + nodeTo.id + " to " + nodeFrom.id);
|
|
|
|
|
|
con.state = Connection.BuildState.DECONSTRUCTING;
|
|
|
|
|
|
con.constructingPlayerId = action.player;
|
|
|
|
|
|
break;
|
2025-09-18 03:24:40 +02:00
|
|
|
|
|
|
|
|
|
|
case ActionType.EXPLODE_CON:
|
2025-09-18 17:37:35 +02:00
|
|
|
|
if (p.energy < 2)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Log("Not enough energy");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
p.energy -= 2;
|
2025-09-18 03:24:40 +02:00
|
|
|
|
Debug.Log("Exploding connection from " + nodeTo.id + " to " + nodeFrom.id);
|
|
|
|
|
|
con.state = Connection.BuildState.EMPTY;
|
2025-09-18 20:05:01 +02:00
|
|
|
|
break;
|
2025-09-18 03:24:40 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-16 01:16:02 +02:00
|
|
|
|
public void GenerateAlongSphere()
|
2025-09-16 00:08:50 +02:00
|
|
|
|
{
|
2025-09-16 01:16:02 +02:00
|
|
|
|
for (int i = NodeParent.childCount - 1; i >= 0; i--)
|
|
|
|
|
|
DestroyImmediate(NodeParent.GetChild(i).gameObject);
|
2025-09-16 00:08:50 +02:00
|
|
|
|
|
|
|
|
|
|
float radius = 20f;
|
|
|
|
|
|
float goldenRatio = (1f + Mathf.Sqrt(5f)) / 2f;
|
|
|
|
|
|
float angleIncrement = 2f * Mathf.PI * goldenRatio;
|
|
|
|
|
|
|
2025-09-16 01:16:02 +02:00
|
|
|
|
for (int i = 0; i < nodeCount; i++)
|
2025-09-16 00:08:50 +02:00
|
|
|
|
{
|
2025-09-16 01:16:02 +02:00
|
|
|
|
float t = (float)i / nodeCount; // von 0 bis 1
|
2025-09-16 00:08:50 +02:00
|
|
|
|
float inclination = Mathf.Acos(1f - 2f * t);
|
|
|
|
|
|
float azimuth = angleIncrement * i;
|
|
|
|
|
|
|
|
|
|
|
|
float x = Mathf.Sin(inclination) * Mathf.Cos(azimuth);
|
|
|
|
|
|
float y = Mathf.Sin(inclination) * Mathf.Sin(azimuth);
|
|
|
|
|
|
float z = Mathf.Cos(inclination);
|
|
|
|
|
|
|
|
|
|
|
|
Vector3 pos = new Vector3(x, y, z) * radius;
|
|
|
|
|
|
|
2025-09-16 14:20:19 +02:00
|
|
|
|
var auto = PrefabUtility.InstantiatePrefab(NodePrefab, NodeParent) as GameObject;
|
2025-09-17 23:38:11 +02:00
|
|
|
|
auto.GetComponent<Node>().id = i;
|
2025-09-16 00:08:50 +02:00
|
|
|
|
auto.transform.localPosition = pos;
|
|
|
|
|
|
}
|
2025-09-16 01:16:02 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void GenerateConnections()
|
2025-09-16 00:08:50 +02:00
|
|
|
|
{
|
2025-09-17 23:38:11 +02:00
|
|
|
|
for (int i = ConnectionParent.childCount - 1; i >= 0; i--)
|
|
|
|
|
|
DestroyImmediate(ConnectionParent.GetChild(i).gameObject);
|
2025-09-16 16:50:21 +02:00
|
|
|
|
|
2025-09-17 23:38:11 +02:00
|
|
|
|
var nodes = GetNodes();
|
2025-09-16 16:50:21 +02:00
|
|
|
|
|
2025-09-16 01:16:02 +02:00
|
|
|
|
foreach (Node nodeA in nodes)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (nodeA == null) continue;
|
|
|
|
|
|
foreach (Node nodeB in nodes)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (nodeB == null) continue;
|
|
|
|
|
|
bool conExists = false;
|
2025-09-17 17:05:48 +02:00
|
|
|
|
float dist = Vector3.Distance(nodeA.transform.position, nodeB.transform.position);
|
|
|
|
|
|
if (nodeA == nodeB || dist > maxConnectionLength)
|
2025-09-16 01:16:02 +02:00
|
|
|
|
continue;
|
|
|
|
|
|
|
2025-09-17 23:38:11 +02:00
|
|
|
|
foreach (Connection con in GetConnections())
|
2025-09-16 01:16:02 +02:00
|
|
|
|
{
|
|
|
|
|
|
if ((con.nodeA == nodeA && con.nodeB == nodeB) || (con.nodeA == nodeB && con.nodeB == nodeA))
|
|
|
|
|
|
{
|
|
|
|
|
|
conExists = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!conExists)
|
2025-09-16 14:20:19 +02:00
|
|
|
|
{
|
2025-09-17 17:05:48 +02:00
|
|
|
|
AddConnection(nodeA, nodeB, dist < minConnectionLength);
|
2025-09-16 14:20:19 +02:00
|
|
|
|
}
|
2025-09-16 01:16:02 +02:00
|
|
|
|
}
|
2025-09-16 14:20:19 +02:00
|
|
|
|
|
2025-09-16 00:08:50 +02:00
|
|
|
|
}
|
2025-09-16 01:16:02 +02:00
|
|
|
|
}
|
2025-09-16 13:04:05 +02:00
|
|
|
|
|
2025-09-17 15:43:26 +02:00
|
|
|
|
public void AddConnection(Node nodeA, Node nodeB, bool allowed = true)
|
|
|
|
|
|
{
|
2025-09-17 23:38:11 +02:00
|
|
|
|
var newCon = PrefabUtility.InstantiatePrefab(ConnectionPrefab, ConnectionParent).GetComponent<Connection>();
|
|
|
|
|
|
newCon.nodeA = nodeA;
|
|
|
|
|
|
newCon.nodeB = nodeB;
|
|
|
|
|
|
newCon.allowed = allowed;
|
2025-09-17 15:43:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-17 10:12:15 +02:00
|
|
|
|
public void LoadLevelData(int index)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(index >= levels.Count)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogWarning("LevelIndex out of range");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = NodeParent.childCount - 1; i >= 0; i--)
|
|
|
|
|
|
DestroyImmediate(NodeParent.GetChild(i).gameObject);
|
|
|
|
|
|
|
|
|
|
|
|
foreach (LineRenderer line in ConnectionParent.GetComponentsInChildren<LineRenderer>())
|
|
|
|
|
|
DestroyImmediate(line.gameObject);
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-09-17 23:38:11 +02:00
|
|
|
|
for(int i = 0; i < levels[index].nodes.Count; i++)
|
2025-09-17 10:12:15 +02:00
|
|
|
|
{
|
2025-09-17 23:38:11 +02:00
|
|
|
|
var nodeData = levels[index].nodes[i];
|
2025-09-17 10:12:15 +02:00
|
|
|
|
var auto = PrefabUtility.InstantiatePrefab(NodePrefab, NodeParent) as GameObject;
|
|
|
|
|
|
auto.transform.localPosition = nodeData.position;
|
2025-09-18 20:05:01 +02:00
|
|
|
|
|
|
|
|
|
|
Node node = auto.GetComponent<Node>();
|
|
|
|
|
|
node.Owner = nodeData.owner;
|
|
|
|
|
|
node.Units = nodeData.units;
|
|
|
|
|
|
node.id = i;
|
2025-09-17 10:12:15 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-17 23:38:11 +02:00
|
|
|
|
var currentNodes = GetNodes();
|
|
|
|
|
|
|
|
|
|
|
|
int idx = 0;
|
|
|
|
|
|
foreach (Node node in currentNodes)
|
|
|
|
|
|
node.id = idx++;
|
|
|
|
|
|
|
|
|
|
|
|
currentNodes = GetNodes();
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-09-18 20:05:01 +02:00
|
|
|
|
foreach (LevelData.ConnectionData conData in levels[index].connections)
|
2025-09-17 23:38:11 +02:00
|
|
|
|
AddConnection(currentNodes[conData.nodeAIndex], currentNodes[conData.nodeBIndex], conData.allowed);
|
2025-09-18 20:05:01 +02:00
|
|
|
|
|
2025-09-17 10:12:15 +02:00
|
|
|
|
selectedLevel = index;
|
2025-09-17 17:05:48 +02:00
|
|
|
|
minConnectionLength = levels[index].minConnectionLength;
|
2025-09-17 10:12:15 +02:00
|
|
|
|
maxConnectionLength = levels[index].maxConnectionLength;
|
2025-09-17 23:38:11 +02:00
|
|
|
|
nodeCount = currentNodes.Count;
|
2025-09-17 10:12:15 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void SaveLevelData(int index = -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
LevelData data = new LevelData();
|
|
|
|
|
|
|
2025-09-17 17:05:48 +02:00
|
|
|
|
data.minConnectionLength = minConnectionLength;
|
2025-09-17 10:12:15 +02:00
|
|
|
|
data.maxConnectionLength = maxConnectionLength;
|
|
|
|
|
|
|
|
|
|
|
|
// Nodes speichern
|
2025-09-17 23:38:11 +02:00
|
|
|
|
foreach (var node in GetNodes())
|
2025-09-17 10:12:15 +02:00
|
|
|
|
{
|
|
|
|
|
|
data.nodes.Add(new LevelData.NodeData
|
|
|
|
|
|
{
|
|
|
|
|
|
position = node.transform.localPosition,
|
2025-09-18 20:05:01 +02:00
|
|
|
|
owner = node.Owner,
|
|
|
|
|
|
units = node.Units
|
2025-09-17 10:12:15 +02:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Connections speichern
|
2025-09-17 23:38:11 +02:00
|
|
|
|
foreach (var con in GetConnections())
|
2025-09-17 10:12:15 +02:00
|
|
|
|
{
|
2025-09-17 23:38:11 +02:00
|
|
|
|
if (con.nodeA.id >= 0 && con.nodeB.id >= 0)
|
2025-09-17 10:12:15 +02:00
|
|
|
|
{
|
|
|
|
|
|
data.connections.Add(new LevelData.ConnectionData
|
|
|
|
|
|
{
|
2025-09-17 23:38:11 +02:00
|
|
|
|
nodeAIndex = con.nodeA.id,
|
|
|
|
|
|
nodeBIndex = con.nodeB.id,
|
2025-09-17 10:12:15 +02:00
|
|
|
|
allowed = con.allowed
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (index == -1 || index >= levels.Count)
|
|
|
|
|
|
levels.Add(data);
|
|
|
|
|
|
else
|
|
|
|
|
|
levels[index] = data;
|
|
|
|
|
|
|
|
|
|
|
|
int newIndex = index < 0 ? levels.Count - 1 : index;
|
|
|
|
|
|
selectedLevel = newIndex;
|
|
|
|
|
|
}
|
2025-09-16 14:20:19 +02:00
|
|
|
|
}
|