using System.Collections.Generic;
using UnityEngine;
namespace Colosseum.Passives
{
///
/// 패시브 트리 전체 데이터를 정의합니다.
///
[CreateAssetMenu(fileName = "PassiveTree", menuName = "Colosseum/Passives/Passive Tree")]
public class PassiveTreeData : ScriptableObject
{
[Header("기본 정보")]
[SerializeField] private string treeId;
[SerializeField] private string treeName;
[TextArea(2, 4)]
[SerializeField] private string description;
[Min(0)] [SerializeField] private int initialPoints = 0;
[Header("노드")]
[SerializeField] private List nodes = new List();
public string TreeId => treeId;
public string TreeName => treeName;
public string Description => description;
public int InitialPoints => initialPoints;
public IReadOnlyList Nodes => nodes;
public PassiveNodeData GetNodeById(string nodeId)
{
if (string.IsNullOrWhiteSpace(nodeId))
return null;
for (int i = 0; i < nodes.Count; i++)
{
PassiveNodeData node = nodes[i];
if (node != null && string.Equals(node.NodeId, nodeId, System.StringComparison.Ordinal))
return node;
}
return null;
}
///
/// 선택된 노드 구성이 유효한지 검사합니다.
///
public bool TryResolveSelection(IReadOnlyList selectedNodeIds, out List resolvedNodes, out string reason)
{
resolvedNodes = new List();
reason = string.Empty;
HashSet uniqueIds = new HashSet();
int totalCost = 0;
if (selectedNodeIds == null)
return true;
for (int i = 0; i < selectedNodeIds.Count; i++)
{
string nodeId = selectedNodeIds[i];
if (string.IsNullOrWhiteSpace(nodeId))
continue;
if (!uniqueIds.Add(nodeId))
{
reason = $"중복 노드가 포함되어 있습니다: {nodeId}";
return false;
}
PassiveNodeData node = GetNodeById(nodeId);
if (node == null)
{
reason = $"트리에 없는 노드입니다: {nodeId}";
return false;
}
resolvedNodes.Add(node);
totalCost += node.Cost;
}
for (int i = 0; i < resolvedNodes.Count; i++)
{
PassiveNodeData node = resolvedNodes[i];
IReadOnlyList prerequisiteNodes = node.PrerequisiteNodes;
if (prerequisiteNodes == null)
continue;
for (int j = 0; j < prerequisiteNodes.Count; j++)
{
PassiveNodeData prerequisiteNode = prerequisiteNodes[j];
if (prerequisiteNode == null)
continue;
if (!uniqueIds.Contains(prerequisiteNode.NodeId))
{
reason = $"{node.DisplayName} 선택에는 선행 노드 {prerequisiteNode.DisplayName} 이(가) 필요합니다.";
return false;
}
}
}
if (totalCost > initialPoints)
{
reason = $"선택한 노드 비용이 보유 포인트를 초과합니다. Used={totalCost}, Max={initialPoints}";
return false;
}
return true;
}
public int CalculateUsedPoints(IReadOnlyList selectedNodes)
{
if (selectedNodes == null)
return 0;
int totalCost = 0;
for (int i = 0; i < selectedNodes.Count; i++)
{
PassiveNodeData node = selectedNodes[i];
if (node == null)
continue;
totalCost += Mathf.Max(0, node.Cost);
}
return totalCost;
}
}
}