Big project cleanup with overhaul of file responsibilities (KISS) and code (DRY, YAGNI)
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public static class GateRequirementGenerator
|
||||
{
|
||||
public static void ApplyGateRequirements(Layer[] layers)
|
||||
{
|
||||
List<string> availableResources = new List<string>();
|
||||
|
||||
foreach (Layer layer in layers)
|
||||
{
|
||||
GateRequirementOptions options = BuildRequirementOptions(layer, availableResources);
|
||||
ApplyLayerRequirements(layer, options);
|
||||
}
|
||||
}
|
||||
|
||||
private static GateRequirementOptions BuildRequirementOptions(Layer layer, List<string> availableResources)
|
||||
{
|
||||
GateRequirementOptions options = new GateRequirementOptions();
|
||||
|
||||
foreach (string resource in layer.currentResources)
|
||||
{
|
||||
if (availableResources.Contains(resource)) continue;
|
||||
|
||||
availableResources.Add(resource);
|
||||
}
|
||||
|
||||
bool addedNewItem;
|
||||
do
|
||||
{
|
||||
addedNewItem = false;
|
||||
|
||||
foreach (ItemData item in GameData.availableItems.Values)
|
||||
{
|
||||
if (options.PossibleIngredients.Any(existing => existing.Id == item.Id)) continue;
|
||||
if (!CanCraftItem(item, availableResources)) continue;
|
||||
|
||||
options.PossibleIngredients.Add(item);
|
||||
availableResources.Add(item.Id);
|
||||
options.LowestCraftTime = Mathf.Min(options.LowestCraftTime, item.CraftTime);
|
||||
options.HighestCraftTime = Mathf.Max(options.HighestCraftTime, item.CraftTime);
|
||||
|
||||
addedNewItem = true;
|
||||
}
|
||||
} while (addedNewItem);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
private static bool CanCraftItem(ItemData item, List<string> availableResources)
|
||||
{
|
||||
return item.Inputs.All(input => availableResources.Contains(input.Item));
|
||||
}
|
||||
|
||||
private static void ApplyLayerRequirements(Layer layer, GateRequirementOptions options)
|
||||
{
|
||||
double goalCraftTime = GetGoalCraftTime(layer, options);
|
||||
int ingredientAmount = Mathf.Clamp(1 + layer.level / 3, 1, 4);
|
||||
float craftTimeModifier = 0f;
|
||||
|
||||
for (int i = 0; i < ingredientAmount; i++)
|
||||
{
|
||||
List<ItemData> validIngredients = GetValidIngredients(layer, options, goalCraftTime, craftTimeModifier);
|
||||
if (validIngredients.Count == 0)
|
||||
{
|
||||
i--;
|
||||
craftTimeModifier += 0.05f;
|
||||
continue;
|
||||
}
|
||||
|
||||
AddGateIngredient(layer, validIngredients);
|
||||
craftTimeModifier = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
private static double GetGoalCraftTime(Layer layer, GateRequirementOptions options)
|
||||
{
|
||||
return Mathf.Lerp(
|
||||
options.LowestCraftTime,
|
||||
options.HighestCraftTime,
|
||||
Mathf.Clamp(layer.level / (float)GameData.ruinSize, 0, 1)
|
||||
);
|
||||
}
|
||||
|
||||
private static List<ItemData> GetValidIngredients(
|
||||
Layer layer,
|
||||
GateRequirementOptions options,
|
||||
double goalCraftTime,
|
||||
float craftTimeModifier
|
||||
)
|
||||
{
|
||||
double craftTimeLower = goalCraftTime - goalCraftTime * craftTimeModifier;
|
||||
double craftTimeUpper = goalCraftTime + goalCraftTime * craftTimeModifier;
|
||||
|
||||
return options.PossibleIngredients
|
||||
.Where(item =>
|
||||
item.CraftTime >= craftTimeLower &&
|
||||
item.CraftTime <= craftTimeUpper &&
|
||||
!layer.gateIngredients.Any(ingredient => ingredient.Item == item.Id))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private static void AddGateIngredient(Layer layer, List<ItemData> validIngredients)
|
||||
{
|
||||
ItemData item = validIngredients[GameData.rand.Next(validIngredients.Count)];
|
||||
|
||||
layer.gateIngredients.Add(new Ingredient
|
||||
{
|
||||
Item = item.Id,
|
||||
Amount = GameData.rand.Next(3 + layer.level * 2, 9 + layer.level * 4)
|
||||
});
|
||||
}
|
||||
|
||||
private class GateRequirementOptions
|
||||
{
|
||||
public List<ItemData> PossibleIngredients = new List<ItemData>();
|
||||
public double HighestCraftTime = 0;
|
||||
public double LowestCraftTime = double.MaxValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://bct2we4yxah6v
|
||||
@@ -16,7 +16,7 @@ public partial class Layer : Node3D
|
||||
public Vector2I gateCoordinate;
|
||||
public List<string> currentResources;
|
||||
public bool isGateOpen = false;
|
||||
public List<Ingredient> gateIngredients = new();
|
||||
public List<Ingredient> gateIngredients = new List<Ingredient>();
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
@@ -125,14 +125,12 @@ public partial class Layer : Node3D
|
||||
for (int z = 0; z < layerSize; z++)
|
||||
{
|
||||
if (x == 0 && z == 0 && level == 0) continue;
|
||||
if (!IsBorder(x, z))
|
||||
continue;
|
||||
if (!IsBorder(x, z)) continue;
|
||||
|
||||
Tile tile = tiles[x, z];
|
||||
List<string> possibilities = GetBorderPossibilities(x, z);
|
||||
|
||||
if (possibilities.Count == 0)
|
||||
continue;
|
||||
if (possibilities.Count == 0) continue;
|
||||
|
||||
tile.Collapse(possibilities[GameData.rand.Next(possibilities.Count)]);
|
||||
Propagate(new Vector2I(x, z));
|
||||
@@ -147,7 +145,6 @@ public partial class Layer : Node3D
|
||||
|
||||
private void GenerateNecessaryTiles()
|
||||
{
|
||||
//Generate spawn only in the first layer
|
||||
if (level == 0)
|
||||
{
|
||||
tiles[0, 0].Collapse("spawn");
|
||||
@@ -197,9 +194,7 @@ public partial class Layer : Node3D
|
||||
safetyCounter++;
|
||||
if (safetyCounter == layerSize * layerSize) return false;
|
||||
}
|
||||
if (updateFailed) return false;
|
||||
if (!WFC.IsMapConnected(tiles, 1f)) return false;
|
||||
return true;
|
||||
return !updateFailed && WFC.IsMapConnected(tiles, 1f);
|
||||
}
|
||||
|
||||
private void Propagate(Vector2I startPos)
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class LightHandler
|
||||
public static class LightHandler
|
||||
{
|
||||
public static List<OmniLight3D> lights = new List<OmniLight3D>();
|
||||
public static List<OmniLight3D> lights = new List<OmniLight3D>();
|
||||
|
||||
public static void RedrawLights(Color color)
|
||||
{
|
||||
List<OmniLight3D> availableLights = new List<OmniLight3D>();
|
||||
public static void RedrawLights(Color color)
|
||||
{
|
||||
List<OmniLight3D> availableLights = new List<OmniLight3D>();
|
||||
|
||||
foreach (OmniLight3D light in lights)
|
||||
{
|
||||
if (GodotObject.IsInstanceValid(light))
|
||||
{
|
||||
light.LightColor = color;
|
||||
availableLights.Add(light);
|
||||
}
|
||||
}
|
||||
foreach (OmniLight3D light in lights)
|
||||
{
|
||||
if (!GodotObject.IsInstanceValid(light)) continue;
|
||||
|
||||
lights = availableLights;
|
||||
}
|
||||
light.LightColor = color;
|
||||
availableLights.Add(light);
|
||||
}
|
||||
|
||||
lights = availableLights;
|
||||
}
|
||||
}
|
||||
|
||||
+108
-103
@@ -1,131 +1,136 @@
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
|
||||
public class Pathfinding
|
||||
public static class Pathfinding
|
||||
{
|
||||
private static AStar3D aStar = new AStar3D();
|
||||
private static Dictionary<Vector3I, long> coordToId = new Dictionary<Vector3I, long>();
|
||||
private static Dictionary<long, Vector3I> idToCoord = new Dictionary<long, Vector3I>();
|
||||
private static long nextId = 1;
|
||||
private static Dictionary<int, (long fromId, long toId)> verticalConnections = new Dictionary<int, (long fromId, long toId)>();
|
||||
private static AStar3D aStar = new AStar3D();
|
||||
private static Dictionary<Vector3I, long> coordToId = new Dictionary<Vector3I, long>();
|
||||
private static Dictionary<long, Vector3I> idToCoord = new Dictionary<long, Vector3I>();
|
||||
private static long nextId = 1;
|
||||
private static Dictionary<int, (long fromId, long toId)> verticalConnections = new Dictionary<int, (long fromId, long toId)>();
|
||||
|
||||
private static long GetOrCreateId(Vector3I coord)
|
||||
{
|
||||
if (coordToId.TryGetValue(coord, out long id))
|
||||
return id;
|
||||
private static long GetOrCreateId(Vector3I coord)
|
||||
{
|
||||
if (coordToId.TryGetValue(coord, out long id)) return id;
|
||||
|
||||
id = nextId++;
|
||||
coordToId[coord] = id;
|
||||
idToCoord[id] = coord;
|
||||
id = nextId++;
|
||||
coordToId[coord] = id;
|
||||
idToCoord[id] = coord;
|
||||
|
||||
return id;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public static void BuildAStarGraph()
|
||||
{
|
||||
aStar.Clear();
|
||||
coordToId.Clear();
|
||||
idToCoord.Clear();
|
||||
verticalConnections.Clear();
|
||||
nextId = 1;
|
||||
public static void BuildAStarGraph()
|
||||
{
|
||||
aStar.Clear();
|
||||
coordToId.Clear();
|
||||
idToCoord.Clear();
|
||||
verticalConnections.Clear();
|
||||
nextId = 1;
|
||||
|
||||
for (int y = 0; y < GameData.ruinSize; y++)
|
||||
{
|
||||
for (int x = 0; x < GameData.layerSize; x++)
|
||||
{
|
||||
for (int z = 0; z < GameData.layerSize; z++)
|
||||
{
|
||||
Vector3I coord = new Vector3I(x, y, z);
|
||||
Tile tile = GameData.map[y].tiles[x, z];
|
||||
for (int y = 0; y < GameData.ruinSize; y++)
|
||||
{
|
||||
for (int x = 0; x < GameData.layerSize; x++)
|
||||
{
|
||||
for (int z = 0; z < GameData.layerSize; z++)
|
||||
{
|
||||
AddPointIfValid(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tile == null || tile.collapsedMesh == null) continue;
|
||||
foreach (KeyValuePair<Vector3I, long> kvp in coordToId)
|
||||
{
|
||||
ConnectPoint(kvp.Key, kvp.Value);
|
||||
}
|
||||
|
||||
long id = GetOrCreateId(coord);
|
||||
for (int y = 0; y < GameData.ruinSize; y++)
|
||||
{
|
||||
UpdateGatePoint(y, false);
|
||||
}
|
||||
}
|
||||
|
||||
aStar.AddPoint(id, tile.Position);
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void AddPointIfValid(int x, int y, int z)
|
||||
{
|
||||
Vector3I coord = new Vector3I(x, y, z);
|
||||
Tile tile = GameData.map[y].tiles[x, z];
|
||||
if (tile == null || tile.collapsedMesh == null) return;
|
||||
|
||||
foreach (KeyValuePair<Vector3I, long> kvp in coordToId)
|
||||
{
|
||||
Vector3I from = kvp.Key;
|
||||
long fromId = kvp.Value;
|
||||
long id = GetOrCreateId(coord);
|
||||
aStar.AddPoint(id, tile.Position);
|
||||
}
|
||||
|
||||
foreach (Vector3I offset in WFC.offsets3D)
|
||||
{
|
||||
Vector3I to = new Vector3I(
|
||||
from.X + offset.X,
|
||||
from.Y + offset.Y,
|
||||
from.Z + offset.Z
|
||||
);
|
||||
private static void ConnectPoint(Vector3I from, long fromId)
|
||||
{
|
||||
foreach (Vector3I offset in WFC.offsets3D)
|
||||
{
|
||||
Vector3I to = new Vector3I(
|
||||
from.X + offset.X,
|
||||
from.Y + offset.Y,
|
||||
from.Z + offset.Z
|
||||
);
|
||||
|
||||
if (!coordToId.ContainsKey(to)) continue;
|
||||
if (!coordToId.ContainsKey(to)) continue;
|
||||
if (!WFC.CanWalk3D(from, to)) continue;
|
||||
|
||||
if (!WFC.CanWalk3D(from, to)) continue;
|
||||
long toId = coordToId[to];
|
||||
if (TryRegisterGateConnection(from, to, fromId, toId)) continue;
|
||||
|
||||
long toId = coordToId[to];
|
||||
ConnectPointsIfNeeded(fromId, toId);
|
||||
}
|
||||
}
|
||||
|
||||
if (from.Y != to.Y && GameData.map[from.Y].tiles[from.X, from.Z].collapsedMesh == "gate")
|
||||
{
|
||||
verticalConnections[from.Y] = (fromId, toId);
|
||||
if (GameData.map[from.Y].isGateOpen)
|
||||
{
|
||||
if (!aStar.ArePointsConnected(fromId, toId))
|
||||
{
|
||||
aStar.ConnectPoints(fromId, toId, true);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
private static bool TryRegisterGateConnection(Vector3I from, Vector3I to, long fromId, long toId)
|
||||
{
|
||||
if (from.Y == to.Y) return false;
|
||||
if (GameData.map[from.Y].tiles[from.X, from.Z].collapsedMesh != "gate") return false;
|
||||
|
||||
if (!aStar.ArePointsConnected(fromId, toId))
|
||||
{
|
||||
aStar.ConnectPoints(fromId, toId, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
verticalConnections[from.Y] = (fromId, toId);
|
||||
if (GameData.map[from.Y].isGateOpen)
|
||||
{
|
||||
ConnectPointsIfNeeded(fromId, toId);
|
||||
}
|
||||
|
||||
for (int y = 0; y < GameData.ruinSize; y++)
|
||||
{
|
||||
UpdateGatePoint(y, false);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void UpdateGatePoint(int layer, bool isOpen)
|
||||
{
|
||||
if (!verticalConnections.ContainsKey(layer)) return;
|
||||
private static void ConnectPointsIfNeeded(long fromId, long toId)
|
||||
{
|
||||
if (aStar.ArePointsConnected(fromId, toId)) return;
|
||||
|
||||
(long fromId, long toId) = verticalConnections[layer];
|
||||
aStar.ConnectPoints(fromId, toId, true);
|
||||
}
|
||||
|
||||
if (isOpen)
|
||||
{
|
||||
if (!aStar.ArePointsConnected(fromId, toId))
|
||||
{
|
||||
aStar.ConnectPoints(fromId, toId, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (aStar.ArePointsConnected(fromId, toId))
|
||||
{
|
||||
aStar.DisconnectPoints(fromId, toId);
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void UpdateGatePoint(int layer, bool isOpen)
|
||||
{
|
||||
if (!verticalConnections.ContainsKey(layer)) return;
|
||||
|
||||
public static List<Vector3> GetPath(Vector3I start, Vector3I end)
|
||||
{
|
||||
if (!coordToId.ContainsKey(start) || !coordToId.ContainsKey(end)) return new List<Vector3>();
|
||||
(long fromId, long toId) = verticalConnections[layer];
|
||||
|
||||
long startId = coordToId[start];
|
||||
long endId = coordToId[end];
|
||||
if (isOpen)
|
||||
{
|
||||
ConnectPointsIfNeeded(fromId, toId);
|
||||
return;
|
||||
}
|
||||
|
||||
return new List<Vector3>(aStar.GetPointPath(startId, endId));
|
||||
}
|
||||
if (aStar.ArePointsConnected(fromId, toId))
|
||||
{
|
||||
aStar.DisconnectPoints(fromId, toId);
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector3I GetClosestStartPoint(Vector3 robotPosition)
|
||||
{
|
||||
return idToCoord[aStar.GetClosestPoint(robotPosition)];
|
||||
}
|
||||
public static List<Vector3> GetPath(Vector3I start, Vector3I end)
|
||||
{
|
||||
if (!coordToId.ContainsKey(start) || !coordToId.ContainsKey(end)) return new List<Vector3>();
|
||||
|
||||
long startId = coordToId[start];
|
||||
long endId = coordToId[end];
|
||||
|
||||
return new List<Vector3>(aStar.GetPointPath(startId, endId));
|
||||
}
|
||||
|
||||
public static Vector3I GetClosestStartPoint(Vector3 robotPosition)
|
||||
{
|
||||
return idToCoord[aStar.GetClosestPoint(robotPosition)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
|
||||
public class ResourceDistributor
|
||||
public static class ResourceDistributor
|
||||
{
|
||||
public static Dictionary<string, Texture2D> resources = ResourceLoader.LoadResourceSymbols();
|
||||
public static Dictionary<string, float[]> weights = ResourceLoader.LoadResourceWeights();
|
||||
public static Dictionary<string, Texture2D> resources = ResourceLoader.LoadResourceSymbols();
|
||||
public static Dictionary<string, float[]> weights = ResourceLoader.LoadResourceWeights();
|
||||
|
||||
public static string GetResource(int layer)
|
||||
{
|
||||
return ChooseWeighted(layer);
|
||||
}
|
||||
public static string GetResource(int layer)
|
||||
{
|
||||
return ChooseWeighted(layer);
|
||||
}
|
||||
|
||||
private static string ChooseWeighted(int layer)
|
||||
private static string ChooseWeighted(int layer)
|
||||
{
|
||||
float totalWeight = 0f;
|
||||
float weightLerp;
|
||||
|
||||
foreach (string resource in resources.Keys)
|
||||
{
|
||||
weightLerp = Mathf.Lerp(weights[resource][0], weights[resource][1], layer);
|
||||
totalWeight += weightLerp;
|
||||
totalWeight += GetWeight(resource, layer);
|
||||
}
|
||||
|
||||
float r = (float)(GameData.rand.NextDouble() * totalWeight);
|
||||
|
||||
float randomWeight = (float)(GameData.rand.NextDouble() * totalWeight);
|
||||
float cumulative = 0f;
|
||||
|
||||
foreach (string resource in resources.Keys)
|
||||
{
|
||||
weightLerp = Mathf.Lerp(weights[resource][0], weights[resource][1], layer);
|
||||
cumulative += weightLerp;
|
||||
cumulative += GetWeight(resource, layer);
|
||||
|
||||
if (r <= cumulative)
|
||||
return resource;
|
||||
if (randomWeight <= cumulative) return resource;
|
||||
}
|
||||
|
||||
return "stone";
|
||||
}
|
||||
|
||||
private static float GetWeight(string resource, int layer)
|
||||
{
|
||||
return Mathf.Lerp(weights[resource][0], weights[resource][1], layer);
|
||||
}
|
||||
}
|
||||
|
||||
+31
-41
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Godot;
|
||||
|
||||
public class WFC
|
||||
public static class WFC
|
||||
{
|
||||
public static Dictionary<string, Dictionary<Direction, List<string>>> adjacency = new Dictionary<string, Dictionary<Direction, List<string>>>();
|
||||
public enum Direction
|
||||
@@ -122,8 +122,6 @@ public class WFC
|
||||
return aOpen == bOpen;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void FillAdjacencies()
|
||||
{
|
||||
foreach (string tile in tileConnections.Keys)
|
||||
@@ -136,8 +134,7 @@ public class WFC
|
||||
|
||||
foreach (string other in tileConnections.Keys)
|
||||
{
|
||||
if (CanConnect(tile, other, dir, false))
|
||||
valid.Add(other);
|
||||
if (CanConnect(tile, other, dir, false)) valid.Add(other);
|
||||
}
|
||||
|
||||
adjacency[tile][dir] = valid;
|
||||
@@ -156,8 +153,7 @@ public class WFC
|
||||
Tile fromTile = layer[from.X, from.Y];
|
||||
Tile toTile = layer[to.X, to.Y];
|
||||
|
||||
if (!IsWalkable(toTile))
|
||||
return false;
|
||||
if (!IsWalkable(toTile)) return false;
|
||||
|
||||
return CanConnect(fromTile.collapsedMesh, toTile.collapsedMesh, dir, true);
|
||||
}
|
||||
@@ -167,29 +163,21 @@ public class WFC
|
||||
Tile fromTile = GameData.map[from.Y].tiles[from.X, from.Z];
|
||||
Tile toTile = GameData.map[to.Y].tiles[to.X, to.Z];
|
||||
|
||||
if (fromTile == null || toTile == null)
|
||||
return false;
|
||||
if (fromTile == null || toTile == null) return false;
|
||||
|
||||
if (from.Y != to.Y)
|
||||
{
|
||||
if (Math.Abs(from.Y - to.Y) != 1)
|
||||
return false;
|
||||
if (Math.Abs(from.Y - to.Y) != 1) return false;
|
||||
|
||||
if (from.Y > to.Y)
|
||||
{
|
||||
return toTile.collapsedMesh == "gate";
|
||||
}
|
||||
else
|
||||
{
|
||||
return fromTile.collapsedMesh == "gate";
|
||||
}
|
||||
return from.Y > to.Y
|
||||
? toTile.collapsedMesh == "gate"
|
||||
: fromTile.collapsedMesh == "gate";
|
||||
}
|
||||
|
||||
int dx = to.X - from.X;
|
||||
int dz = to.Z - from.Z;
|
||||
|
||||
if (Math.Abs(dx) + Math.Abs(dz) != 1)
|
||||
return false;
|
||||
if (Math.Abs(dx) + Math.Abs(dz) != 1) return false;
|
||||
|
||||
Direction dir;
|
||||
|
||||
@@ -207,29 +195,23 @@ public class WFC
|
||||
);
|
||||
}
|
||||
|
||||
public static bool IsMapConnected(Tile[,] layer, float accessibilityThreshhold)
|
||||
public static bool IsMapConnected(Tile[,] layer, float accessibilityThreshold)
|
||||
{
|
||||
bool result = false;
|
||||
HashSet<Vector2I> visited = new HashSet<Vector2I>();
|
||||
List<Vector2I> toCheck = new List<Vector2I>();
|
||||
Vector2I position;
|
||||
toCheck.Add(new Vector2I(1, 1));
|
||||
|
||||
int safetyCounter = 0;
|
||||
while (true)
|
||||
while (toCheck.Count > 0)
|
||||
{
|
||||
if (toCheck.Count <= 0) break;
|
||||
int index = GameData.rand.Next(toCheck.Count);
|
||||
position = toCheck[index];
|
||||
toCheck[index] = toCheck[^1];
|
||||
toCheck.RemoveAt(toCheck.Count - 1);
|
||||
Vector2I position = TakeRandomPosition(toCheck);
|
||||
if (!visited.Add(position)) continue;
|
||||
|
||||
for (int i = 0; i < offsets2D.Length; i++)
|
||||
{
|
||||
Vector2I next = position + offsets2D[i];
|
||||
|
||||
if (!InBounds(next, layer.GetLength(0)))
|
||||
continue;
|
||||
if (!InBounds(next, layer.GetLength(0))) continue;
|
||||
|
||||
if (CanWalk(layer, position, next, dirs[i]))
|
||||
{
|
||||
@@ -238,22 +220,30 @@ public class WFC
|
||||
}
|
||||
safetyCounter++;
|
||||
if (safetyCounter > layer.Length * 2) break;
|
||||
if (visited.Count >= Math.Pow(layer.GetLength(0) - 1, 2) * accessibilityThreshhold)
|
||||
if (visited.Count >= Math.Pow(layer.GetLength(0) - 1, 2) * accessibilityThreshold)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
return result;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Vector2I TakeRandomPosition(List<Vector2I> positions)
|
||||
{
|
||||
int index = GameData.rand.Next(positions.Count);
|
||||
Vector2I position = positions[index];
|
||||
positions[index] = positions[positions.Count - 1];
|
||||
positions.RemoveAt(positions.Count - 1);
|
||||
return position;
|
||||
}
|
||||
|
||||
public static bool InBounds(Vector2I pos, int layerSize)
|
||||
{
|
||||
return pos.X > 0 &&
|
||||
pos.Y > 0 &&
|
||||
pos.X < layerSize &&
|
||||
pos.Y < layerSize;
|
||||
return pos.X > 0
|
||||
&& pos.Y > 0
|
||||
&& pos.X < layerSize
|
||||
&& pos.Y < layerSize;
|
||||
}
|
||||
|
||||
public static List<string> GetBorderPossibilities(int x, int z)
|
||||
|
||||
+1
-81
@@ -1,6 +1,5 @@
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using static GameData;
|
||||
|
||||
public partial class World : Node3D
|
||||
@@ -48,7 +47,7 @@ public partial class World : Node3D
|
||||
|
||||
map = new Layer[ruinSize];
|
||||
GenerateWorld();
|
||||
SetGateRequirements();
|
||||
GateRequirementGenerator.ApplyGateRequirements(map);
|
||||
|
||||
if (shouldLoadSave && saveGame != null)
|
||||
{
|
||||
@@ -288,83 +287,4 @@ public partial class World : Node3D
|
||||
}
|
||||
}
|
||||
|
||||
private void SetGateRequirements()
|
||||
{
|
||||
List<string> availableResources = new List<string>();
|
||||
List<ItemData> possibleIngredients;
|
||||
bool canCraft;
|
||||
double highestCraftTime;
|
||||
double lowestCraftTime;
|
||||
foreach (Layer layer in map)
|
||||
{
|
||||
highestCraftTime = 0;
|
||||
lowestCraftTime = double.MaxValue;
|
||||
possibleIngredients = new List<ItemData>();
|
||||
//Step 1: Determine all possible resources for this and all previous layers combined
|
||||
foreach (string resource in layer.currentResources)
|
||||
{
|
||||
if (availableResources.Contains(resource)) continue;
|
||||
availableResources.Add(resource);
|
||||
}
|
||||
//Step 2: Check which items can be crafted with those items, repeat until no further items are added to the list
|
||||
bool addedNewItem;
|
||||
do
|
||||
{
|
||||
addedNewItem = false;
|
||||
|
||||
foreach (ItemData item in availableItems.Values)
|
||||
{
|
||||
if (possibleIngredients.Any(existing => existing.Id == item.Id))
|
||||
continue;
|
||||
|
||||
canCraft = item.Inputs.All(input => availableResources.Contains(input.Item));
|
||||
|
||||
if (!canCraft)
|
||||
continue;
|
||||
|
||||
possibleIngredients.Add(item);
|
||||
availableResources.Add(item.Id);
|
||||
|
||||
lowestCraftTime = Mathf.Min(lowestCraftTime, item.CraftTime);
|
||||
highestCraftTime = Mathf.Max(highestCraftTime, item.CraftTime);
|
||||
|
||||
addedNewItem = true;
|
||||
}
|
||||
|
||||
} while (addedNewItem);
|
||||
//Step 3: Choose gate items needed based on crafting time and layer it is for (Lower layers -> More advanced items -> More crafting time)
|
||||
double goalCraftTime = Mathf.Lerp(lowestCraftTime, highestCraftTime, Mathf.Clamp(layer.level/(float)ruinSize, 0, 1));
|
||||
int ingredientAmount = Mathf.Clamp(1 + layer.level / 3, 1, 4);
|
||||
float craftTimeModifier = 0f;
|
||||
double craftTimeLower, craftTimeUpper;
|
||||
for (int i = 0; i < ingredientAmount; i++)
|
||||
{
|
||||
craftTimeLower = goalCraftTime - goalCraftTime * craftTimeModifier;
|
||||
craftTimeUpper = goalCraftTime + goalCraftTime * craftTimeModifier;
|
||||
|
||||
List<ItemData> validIngredients = possibleIngredients
|
||||
.Where(item =>
|
||||
item.CraftTime >= craftTimeLower &&
|
||||
item.CraftTime <= craftTimeUpper &&
|
||||
!layer.gateIngredients.Any(ingredient => ingredient.Item == item.Id))
|
||||
.ToList();
|
||||
|
||||
if (validIngredients.Count == 0)
|
||||
{
|
||||
i--;
|
||||
craftTimeModifier += 0.05f;
|
||||
continue;
|
||||
}
|
||||
|
||||
ItemData item = validIngredients[rand.Next(validIngredients.Count)];
|
||||
|
||||
layer.gateIngredients.Add(new Ingredient
|
||||
{
|
||||
Item = item.Id,
|
||||
Amount = rand.Next(3 + layer.level * 2, 9 + layer.level * 4)
|
||||
});
|
||||
craftTimeModifier = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user