Files
RuinAdventurer/Scripts/World/GateRequirementGenerator.cs

122 lines
3.9 KiB
C#

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;
}
}