503 lines
19 KiB
Lua
503 lines
19 KiB
Lua
local common = require("common")
|
|
|
|
local permutationsThreshold = settings.startup[common.PERMUTATION_THRESHOLD_SETTING].value
|
|
local simpleMode = settings.startup[common.SIMPLE_MODE_SETTING].value
|
|
|
|
local factorial = common.functions.factorial;
|
|
|
|
local function fluidCount(items)
|
|
if items == nil then
|
|
return 0
|
|
end
|
|
local count = 0
|
|
for i = 1, #items do
|
|
if items[i] ~= nil
|
|
and items[i].type ~= nil
|
|
and items[i].type == "fluid" then
|
|
count = count + 1
|
|
end
|
|
end
|
|
return count
|
|
end
|
|
|
|
local function separateFluids(items)
|
|
local fluids = {}
|
|
local solids = {}
|
|
for _, i in pairs(items) do
|
|
if i ~= nil then
|
|
if i.type ~= nil
|
|
and i.type == "fluid" then
|
|
fluids[#fluids + 1] = i
|
|
else
|
|
solids[#solids + 1] = i
|
|
end
|
|
end
|
|
end
|
|
return fluids, solids
|
|
end
|
|
|
|
local function permutations(ttable, n, out)
|
|
if n == 0 then
|
|
out[#out + 1] = table.deepcopy(ttable)
|
|
return
|
|
end
|
|
|
|
for i = 1, n do
|
|
ttable[n], ttable[i] = ttable[i], ttable[n]
|
|
permutations(ttable, n - 1, out)
|
|
ttable[n], ttable[i] = ttable[i], ttable[n]
|
|
end
|
|
end
|
|
|
|
local function concatTables(t1, t2)
|
|
local result = {}
|
|
for i = 1, #t1 do
|
|
if type(t1[i]) == "table" then
|
|
result[#result + 1] = table.deepcopy(t1[i])
|
|
else
|
|
result[#result + 1] = t1[i]
|
|
end
|
|
end
|
|
for i = 1, #t2 do
|
|
if type(t2[i]) == "table" then
|
|
result[#result + 1] = table.deepcopy(t2[i])
|
|
else
|
|
result[#result + 1] = t2[i]
|
|
end
|
|
end
|
|
return result
|
|
end
|
|
|
|
local function getFluidPermutations(tableOfItems)
|
|
local fluids, solids = separateFluids(tableOfItems)
|
|
local fluidPermutations = {}
|
|
if simpleMode then
|
|
local reversedFluids = {}
|
|
for i = 1, #fluids do
|
|
reversedFluids[i] = fluids[#fluids + 1 - i]
|
|
end
|
|
fluidPermutations[1] = reversedFluids
|
|
fluidPermutations[2] = fluids
|
|
else
|
|
permutations(fluids, #fluids, fluidPermutations)
|
|
end
|
|
|
|
local result = {}
|
|
|
|
for i = 1, #fluidPermutations do
|
|
local temp = concatTables(fluidPermutations[i], solids)
|
|
result[#result + 1] = temp
|
|
end
|
|
return result;
|
|
end
|
|
|
|
local function checkSameItems(tab1, tab2)
|
|
if #tab1 ~= #tab2 then
|
|
return false
|
|
end
|
|
|
|
for i = 1, #tab1 do
|
|
if tab1[i] ~= nil and tab2[i] ~= nil then
|
|
if tab1[i].name ~= tab2[i].name then
|
|
return false
|
|
end
|
|
if tab1[i].type ~= tab2[i].type then
|
|
return false
|
|
end
|
|
else
|
|
if tab1[i] ~= nil or tab2[i] ~= nil then
|
|
return false;
|
|
end
|
|
end
|
|
end
|
|
return true
|
|
end
|
|
|
|
local accessors = {
|
|
ingredientsSetter = function(t, difficulty, ingredients)
|
|
t.ingredients = ingredients
|
|
end,
|
|
difficultyIngredientsSetter = function(t, difficulty, ingredients)
|
|
if difficulty == "a" then
|
|
t.normal.ingredients = ingredients["n"]
|
|
t.expensive.ingredients = ingredients["e"]
|
|
elseif difficulty == "n" then
|
|
t.normal.ingredients = ingredients
|
|
elseif difficulty == "e" then
|
|
t.expensive.ingredients = ingredients
|
|
end
|
|
end,
|
|
resultsSetter = function(t, difficulty, results)
|
|
t.results = results
|
|
end,
|
|
difficultyResultsSetter = function(t, difficulty, results)
|
|
if difficulty == "a" then
|
|
t.normal.results = results["n"]
|
|
t.expensive.results = results["e"]
|
|
elseif difficulty == "n" then
|
|
t.normal.results = results
|
|
elseif difficulty == "e" then
|
|
t.expensive.results = results
|
|
end
|
|
end
|
|
}
|
|
|
|
local function inspectRecipe(recipe)
|
|
local permutations = {a = {}, n = {}, e = {}}
|
|
local ingredientsSetter, resultsSetter
|
|
local difficultyTags = {}
|
|
local maxPermutations = {}
|
|
if recipe.normal then
|
|
local normalIngredientsPermutations
|
|
local expensiveIngredientsPermutations
|
|
local normalResultsPermutations
|
|
local expensiveResultsPermutations
|
|
|
|
local permutationCount = 1
|
|
|
|
local normalSameAsExpensive = false
|
|
if recipe.expensive then
|
|
normalSameAsExpensive = true
|
|
|
|
normalSameAsExpensive = normalSameAsExpensive
|
|
and ((recipe.normal.ingredients == nil and recipe.expensive.ingredients == nil)
|
|
or checkSameItems(recipe.normal.ingredients, recipe.expensive.ingredients))
|
|
|
|
normalSameAsExpensive = normalSameAsExpensive
|
|
and ((recipe.normal.results == nil and recipe.expensive.results == nil)
|
|
or (recipe.normal.results ~= nil and recipe.expensive.results ~= nil
|
|
and checkSameItems(recipe.normal.results, recipe.expensive.results)))
|
|
|
|
if normalSameAsExpensive then
|
|
difficultyTags["a"] = 1
|
|
else
|
|
difficultyTags["n"] = 1
|
|
difficultyTags["e"] = 1
|
|
end
|
|
|
|
local expensiveIngredientsFluidCount = fluidCount(recipe.expensive.ingredients)
|
|
local expensiveResultsFluidCount = fluidCount(recipe.expensive.results)
|
|
local expensiveIngredientsPermutationsMaxCount = math.max(1, factorial(expensiveIngredientsFluidCount))
|
|
local expensiveResultsPermutationsMaxCount = math.max(1, factorial(expensiveResultsFluidCount))
|
|
if simpleMode then
|
|
permutationCount = math.max(1, expensiveIngredientsFluidCount) * math.max(1, expensiveResultsFluidCount)
|
|
else
|
|
permutationCount = expensiveIngredientsPermutationsMaxCount * expensiveResultsPermutationsMaxCount
|
|
end
|
|
if permutationCount > permutationsThreshold then
|
|
return {}, nil, nil, {}, {}
|
|
end
|
|
|
|
if expensiveIngredientsFluidCount > 1 then
|
|
expensiveIngredientsPermutations = getFluidPermutations(recipe.expensive.ingredients)
|
|
end
|
|
if expensiveResultsFluidCount > 1 then
|
|
expensiveResultsPermutations = getFluidPermutations(recipe.expensive.results)
|
|
end
|
|
|
|
if normalSameAsExpensive then
|
|
maxPermutations["a"] = {expensiveIngredientsPermutationsMaxCount, expensiveResultsPermutationsMaxCount}
|
|
else
|
|
maxPermutations["e"] = {expensiveIngredientsPermutationsMaxCount, expensiveResultsPermutationsMaxCount}
|
|
end
|
|
else
|
|
difficultyTags["n"] = 1
|
|
end
|
|
|
|
local normalIngredientsFluidCount = fluidCount(recipe.normal.ingredients)
|
|
local normalResultsFluidCount = fluidCount(recipe.normal.results)
|
|
local normalIngredientsPermutationsMaxCount = math.max(1, factorial(normalIngredientsFluidCount))
|
|
local normalResultsPermutationsMaxCount = math.max(1, factorial(normalResultsFluidCount))
|
|
|
|
if not normalSameAsExpensive then
|
|
if simpleMode then
|
|
permutationCount = permutationCount + math.max(1, normalIngredientsFluidCount) * math.max(1, normalResultsFluidCount)
|
|
else
|
|
permutationCount = permutationCount + normalIngredientsPermutationsMaxCount * normalResultsPermutationsMaxCount
|
|
end
|
|
if permutationCount > permutationsThreshold then
|
|
return {}, nil, nil, {}, {}
|
|
end
|
|
end
|
|
|
|
if normalIngredientsFluidCount > 1 then
|
|
normalIngredientsPermutations = getFluidPermutations(recipe.normal.ingredients)
|
|
end
|
|
if normalResultsFluidCount > 1 then
|
|
normalResultsPermutations = getFluidPermutations(recipe.normal.results)
|
|
end
|
|
if normalIngredientsPermutations or expensiveIngredientsPermutations then
|
|
ingredientsSetter = accessors.difficultyIngredientsSetter
|
|
end
|
|
if normalResultsPermutations or expensiveResultsPermutations then
|
|
resultsSetter = accessors.difficultyResultsSetter
|
|
end
|
|
|
|
if normalIngredientsPermutations and expensiveIngredientsPermutations then
|
|
if normalSameAsExpensive then
|
|
local combinedIngredientsPermutations = {}
|
|
for i = 1, #normalIngredientsPermutations do
|
|
combinedIngredientsPermutations[#combinedIngredientsPermutations + 1] = {
|
|
n = normalIngredientsPermutations[i],
|
|
e = expensiveIngredientsPermutations[i]
|
|
}
|
|
end
|
|
permutations["a"].ingredients = combinedIngredientsPermutations
|
|
else
|
|
permutations["n"].ingredients = normalIngredientsPermutations
|
|
permutations["e"].ingredients = expensiveIngredientsPermutations
|
|
end
|
|
elseif normalIngredientsPermutations then
|
|
permutations["n"].ingredients = normalIngredientsPermutations
|
|
elseif expensiveIngredientsPermutations then
|
|
permutations["e"].ingredients = expensiveIngredientsPermutations
|
|
end
|
|
if normalResultsPermutations and expensiveResultsPermutations then
|
|
if normalSameAsExpensive then
|
|
local combinedResultPermutations = {}
|
|
for i = 1, #normalResultsPermutations do
|
|
combinedResultPermutations[#combinedResultPermutations + 1] = {
|
|
n = normalResultsPermutations[i],
|
|
e = expensiveResultsPermutations[i]
|
|
}
|
|
end
|
|
permutations["a"].results = combinedResultPermutations
|
|
else
|
|
permutations["n"].results = normalResultsPermutations
|
|
permutations["e"].results = expensiveResultsPermutations
|
|
end
|
|
elseif normalResultsPermutations then
|
|
permutations["n"].results = normalResultsPermutations
|
|
elseif expensiveResultsPermutations then
|
|
permutations["e"].results = expensiveResultsPermutations
|
|
end
|
|
if permutations["n"] then
|
|
maxPermutations["n"] = {normalIngredientsPermutationsMaxCount, normalResultsPermutationsMaxCount}
|
|
end
|
|
else
|
|
local ingredientsFluidCount = fluidCount(recipe.ingredients)
|
|
local resultsFluidCount = fluidCount(recipe.results)
|
|
local ingredientsPermutationsMaxCount;
|
|
local resultsPermutationsMaxCount = 0;
|
|
local permutationCount = 0
|
|
|
|
ingredientsPermutationsMaxCount = math.max(1, factorial(ingredientsFluidCount))
|
|
resultsPermutationsMaxCount = math.max(1, factorial(resultsFluidCount))
|
|
|
|
if simpleMode then
|
|
permutationCount = math.max(1, ingredientsFluidCount) * math.max(1, resultsFluidCount)
|
|
else
|
|
permutationCount = ingredientsPermutationsMaxCount * resultsPermutationsMaxCount
|
|
end
|
|
|
|
if permutationCount > permutationsThreshold then
|
|
return {}, nil, nil, {}, {}
|
|
end
|
|
|
|
difficultyTags["a"] = 1
|
|
if ingredientsFluidCount > 1 then
|
|
permutations["a"].ingredients = getFluidPermutations(recipe.ingredients)
|
|
ingredientsSetter = accessors.ingredientsSetter
|
|
end
|
|
|
|
if resultsFluidCount > 1 then
|
|
permutations["a"].results = getFluidPermutations(recipe.results)
|
|
resultsSetter = accessors.resultsSetter
|
|
end
|
|
|
|
maxPermutations["a"] = {ingredientsPermutationsMaxCount, resultsPermutationsMaxCount}
|
|
end
|
|
return permutations, ingredientsSetter, resultsSetter, difficultyTags, maxPermutations
|
|
end
|
|
|
|
local function generateRecipePermutations(recipe)
|
|
local permutations, ingredientsSetter, resultsSetter, difficultyTags, maxCounts = inspectRecipe(recipe)
|
|
local newRecipies = {}
|
|
local generateRecipeName = common.functions.generateRecipeName
|
|
for difficultyTag, _ in pairs(difficultyTags) do
|
|
local ingredientsPermutations = permutations[difficultyTag].ingredients
|
|
local resultsPermutations = permutations[difficultyTag].results
|
|
local maxI = 0
|
|
local maxJ = 0
|
|
local minI = 0
|
|
local minJ = 0
|
|
if ingredientsPermutations then
|
|
maxI = #ingredientsPermutations
|
|
minI = 1
|
|
end
|
|
if resultsPermutations then
|
|
maxJ = #resultsPermutations
|
|
minJ = 1
|
|
end
|
|
for i = minI, maxI do -- for difficulty
|
|
for j = minJ, maxJ do -- for difficulty
|
|
if i < maxI or j < maxJ then
|
|
local newRecipe = table.deepcopy(recipe)
|
|
if ingredientsSetter then
|
|
ingredientsSetter(newRecipe, difficultyTag, ingredientsPermutations[i])
|
|
end
|
|
if resultsSetter then
|
|
resultsSetter(newRecipe, difficultyTag, resultsPermutations[j])
|
|
end
|
|
if simpleMode and (i > 1 or j > 1) then
|
|
if i > 1 then
|
|
newRecipe.name = generateRecipeName(recipe.name, common.FP_RECIPE_AFFIX, difficultyTag, maxCounts[difficultyTag][1], j)
|
|
else
|
|
newRecipe.name = generateRecipeName(recipe.name, common.FP_RECIPE_AFFIX, difficultyTag, i, maxCounts[difficultyTag][2])
|
|
end
|
|
else
|
|
newRecipe.name = generateRecipeName(recipe.name,common.FP_RECIPE_AFFIX, difficultyTag, i, j)
|
|
end
|
|
newRecipies[#newRecipies + 1] = newRecipe
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return newRecipies
|
|
end
|
|
|
|
local function generateLocalisation(recipe)
|
|
local newRecipeLocalisedName
|
|
if recipe.localised_name then
|
|
newRecipeLocalisedName = recipe.localised_name
|
|
else
|
|
if recipe.normal then
|
|
if recipe.normal.results then
|
|
if #recipe.normal.results == 1 then
|
|
if recipe.normal.results[1].type == "fluid" then
|
|
newRecipeLocalisedName = {"fluid-name."..recipe.normal.results[1].name}
|
|
else
|
|
local result = recipe.normal.results[1]
|
|
newRecipeLocalisedName = {"item-name."..(result[1] or result.name)}
|
|
end
|
|
elseif recipe.normal.main_product or recipe.main_product then
|
|
local resultType
|
|
local lookingFor = recipe.normal.main_product or recipe.main_product
|
|
for i = 1, #recipe.normal.results do
|
|
if recipe.normal.results[i].name == lookingFor then
|
|
resultType = recipe.normal.results[i].type
|
|
break
|
|
end
|
|
end
|
|
if resultType then
|
|
newRecipeLocalisedName = {resultType.."-name."..lookingFor}
|
|
end
|
|
end
|
|
end
|
|
else
|
|
if recipe.results then
|
|
if #recipe.results == 1 then
|
|
if recipe.results[1].type == "fluid" then
|
|
newRecipeLocalisedName = {"fluid-name."..recipe.results[1].name}
|
|
else
|
|
local result = recipe.results[1]
|
|
newRecipeLocalisedName = {"item-name."..(result[1] or result.name)}
|
|
end
|
|
elseif recipe.main_product then
|
|
local resultType
|
|
for i = 1, #recipe.results do
|
|
local result = recipe.results[i]
|
|
if (result[1] or result.name) == recipe.main_product then
|
|
resultType = result.type or "item"
|
|
break
|
|
end
|
|
end
|
|
if resultType then
|
|
newRecipeLocalisedName = {resultType.."-name."..recipe.main_product}
|
|
end
|
|
end
|
|
elseif recipe.result then
|
|
newRecipeLocalisedName = {"item-name."..recipe.result}
|
|
end
|
|
end
|
|
if newRecipeLocalisedName == nil then
|
|
newRecipeLocalisedName = {"recipe-name."..recipe.name}
|
|
end
|
|
end
|
|
return newRecipeLocalisedName
|
|
end
|
|
|
|
local function generateRecipies()
|
|
local affectedRecipies = 0
|
|
local newRecipiesCount = 0
|
|
|
|
local newSubgroups = {}
|
|
local newRecipies = {}
|
|
local newRecipeNames = {}
|
|
for _,recipe in pairs(data.raw.recipe) do
|
|
local status, permutations = pcall(generateRecipePermutations, recipe)
|
|
if not status then
|
|
log("Error while generating permutations for recipe: "..serpent.block(recipe))
|
|
error(permutations)
|
|
end
|
|
|
|
if #permutations > 0 then
|
|
local subgroupName
|
|
local subgroupOrder
|
|
if recipe.subgroup then
|
|
subgroupName = recipe.category.."-"..recipe.subgroup.."-"..recipe.name.."-perm";
|
|
subgroupOrder = data.raw["item-subgroup"][recipe.subgroup].order
|
|
else
|
|
subgroupName = recipe.category.."-"..recipe.name.."-perm";
|
|
subgroupOrder = nil
|
|
end
|
|
|
|
newSubgroups[#newSubgroups + 1] = {
|
|
type = "item-subgroup",
|
|
name = subgroupName,
|
|
group = common.FP_ITEM_GROUP_NAME,
|
|
order = subgroupOrder,
|
|
}
|
|
local newRecipeLocalisedName = generateLocalisation(recipe)
|
|
|
|
newRecipeNames[recipe.name] = {}
|
|
for i = 1, #permutations do
|
|
permutations[i].subgroup = subgroupName
|
|
permutations[i].localised_name = newRecipeLocalisedName
|
|
permutations[i].hidden = true
|
|
if permutations[i].normal then
|
|
permutations[i].normal.hidden = true
|
|
end
|
|
if permutations[i].expensive then
|
|
permutations[i].expensive.hidden = true
|
|
end
|
|
|
|
newRecipeNames[recipe.name][#newRecipeNames[recipe.name] + 1] = permutations[i].name
|
|
end
|
|
|
|
newRecipies[#newRecipies + 1] = permutations
|
|
|
|
affectedRecipies = affectedRecipies + 1
|
|
newRecipiesCount = newRecipiesCount + #permutations
|
|
end
|
|
end
|
|
|
|
log("Affected recipes count: "..affectedRecipies)
|
|
log("New recipes count: "..newRecipiesCount)
|
|
|
|
if #newSubgroups > 0 then
|
|
data:extend(newSubgroups)
|
|
end
|
|
if #newRecipies > 0 then
|
|
for i = 1, #newRecipies do
|
|
data:extend(newRecipies[i])
|
|
end
|
|
end
|
|
|
|
for _, moduleItem in pairs(data.raw.module) do
|
|
if moduleItem.limitation then
|
|
local newRestrictions = {}
|
|
for j = #moduleItem.limitation, 1, -1 do
|
|
local restriction = moduleItem.limitation[j]
|
|
if newRecipeNames[restriction] then
|
|
for i = 1, #newRecipeNames[restriction] do
|
|
moduleItem.limitation[#moduleItem.limitation + 1] = newRecipeNames[restriction][i]
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
generateRecipies()
|