155 lines
3.9 KiB
C
155 lines
3.9 KiB
C
#pragma once
|
|
#include "SkillTreeState.Generated.h"
|
|
|
|
USTRUCT(BlueprintType)
|
|
struct FSkillTreeStateObject
|
|
{
|
|
GENERATED_BODY();
|
|
UPROPERTY()
|
|
FVector2D gridIndex;
|
|
UPROPERTY()
|
|
float rotation;
|
|
UPROPERTY()
|
|
TArray<FIntPoint> placedPoints;
|
|
UPROPERTY()
|
|
UClass* skillObject;
|
|
UPROPERTY()
|
|
int32 selectedEffect;
|
|
|
|
bool ContainsRoot(FIntPoint root)
|
|
{
|
|
for (int32 i = 0; i < placedPoints.Num(); i++)
|
|
{
|
|
if (placedPoints[i] == root) return true;
|
|
}
|
|
return false;
|
|
}
|
|
TArray<FSkillTreeStateObject*> ConnectedSkills( TMap<FIntPoint, FSkillTreeStateObject*>& skillsMap )
|
|
{
|
|
TArray<FSkillTreeStateObject*> result;
|
|
const FIntPoint offsets[2][6]{
|
|
{ FIntPoint(0, -1), FIntPoint(1, -1), FIntPoint(1, 0), FIntPoint(0, 1), FIntPoint(-1, 0), FIntPoint(-1, -1) },
|
|
{ FIntPoint(0, -1), FIntPoint(1, 0), FIntPoint(1, 1), FIntPoint(0, 1), FIntPoint(-1, 1), FIntPoint(-1, 0) } };
|
|
for (int32 i = 0; i < placedPoints.Num(); i++)
|
|
{
|
|
int32 k = placedPoints[i].X & 1;
|
|
for (int32 j = 0; j < 6; j++)
|
|
{
|
|
FIntPoint checkPoint = placedPoints[i] + offsets[k][j];
|
|
if (placedPoints.Contains(checkPoint)) continue;
|
|
if (skillsMap.Contains(checkPoint))
|
|
{
|
|
FSkillTreeStateObject* skill = *skillsMap.Find(checkPoint);
|
|
if (result.Contains(skill)) continue;
|
|
result.Push(skill);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
|
|
USTRUCT(BlueprintType)
|
|
struct FSkillTreeState
|
|
{
|
|
GENERATED_BODY();
|
|
|
|
UPROPERTY(BlueprintReadOnly)
|
|
TArray<FSkillTreeStateObject> objects;
|
|
|
|
private:
|
|
void WalkTree(TMap<FSkillTreeStateObject*, TArray<FSkillTreeStateObject*>>* a_map, TArray<FSkillTreeStateObject*>* a_checked, TArray<FSkillTreeStateObject*> a_nodes)
|
|
{
|
|
for (int32 i = 0; i < a_nodes.Num(); i++)
|
|
{
|
|
if (a_checked->Contains(a_nodes[i])) continue;
|
|
a_checked->Push(a_nodes[i]);
|
|
TArray<FSkillTreeStateObject*>* connected = a_map->Find(a_nodes[i]);
|
|
if (!connected)
|
|
{
|
|
YERROR("Could not find the connected skills.");
|
|
continue;
|
|
}
|
|
WalkTree(a_map, a_checked, *connected);
|
|
}
|
|
}
|
|
|
|
public:
|
|
bool ValidateSkillTree()
|
|
{
|
|
bool rootResult = false;
|
|
bool connectResult = true;
|
|
|
|
if (objects.Num() == 0) return true;
|
|
|
|
|
|
TMap<FSkillTreeStateObject*, TArray<FSkillTreeStateObject*>> connectedSkillsMap;
|
|
TMap<FIntPoint, FSkillTreeStateObject*> skillsMap;
|
|
FSkillTreeStateObject* rootSkill = NULL;
|
|
for (int32 i = 0; i < objects.Num(); i++)
|
|
{
|
|
TArray<FIntPoint> points = objects[i].placedPoints;
|
|
for (int32 j = 0; j < points.Num(); j++)
|
|
{
|
|
skillsMap.Add(points[j], &objects[i]);
|
|
}
|
|
}
|
|
|
|
for (int32 i = 0; i < objects.Num(); i++)
|
|
{
|
|
TArray<FIntPoint> points = objects[i].placedPoints;
|
|
if (!rootResult)
|
|
{
|
|
bool rootTest = objects[i].ContainsRoot(FIntPoint(6,15));
|
|
if (rootTest)
|
|
{
|
|
rootResult = true;
|
|
rootSkill = &objects[i];
|
|
}
|
|
}
|
|
TArray<FSkillTreeStateObject*> connectedSkills = objects[i].ConnectedSkills(skillsMap);
|
|
connectedSkillsMap.Add(&objects[i], connectedSkills);
|
|
if (connectedSkills.Num() == 0)
|
|
{
|
|
connectResult = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (connectResult && rootResult)
|
|
{
|
|
if (!rootSkill)
|
|
{
|
|
YERROR("Root Skill is NULL!");
|
|
return false;
|
|
}
|
|
TArray<FSkillTreeStateObject*> checkedSkills;
|
|
checkedSkills.Push(rootSkill);
|
|
TArray<FSkillTreeStateObject*>* connected = connectedSkillsMap.Find(rootSkill);
|
|
if (!connected)
|
|
{
|
|
YPRINT("Root Skill is not attached to any skills!");
|
|
return false;
|
|
}
|
|
WalkTree(&connectedSkillsMap, &checkedSkills, *connected);
|
|
if (objects.Num() != checkedSkills.Num())
|
|
connectResult = false;
|
|
else
|
|
{
|
|
for (int32 i = 0; i < objects.Num(); i++)
|
|
{
|
|
if (!checkedSkills.Contains(&objects[i]))
|
|
{
|
|
connectResult = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
bool isValid = false;
|
|
if (objects.Num() == 1 && rootResult)
|
|
isValid = true;
|
|
else
|
|
isValid = (rootResult && connectResult);
|
|
return isValid;
|
|
}
|
|
}; |