771 lines
32 KiB
Lua
771 lines
32 KiB
Lua
require "math.Matrix"
|
|
require "math.SolverMatrix"
|
|
require "math.SolverMatrixAlgebra"
|
|
require "math.SolverMatrixSimplex"
|
|
|
|
require "math.Solver"
|
|
require "math.SolverAlgebra"
|
|
require "math.SolverSimplex"
|
|
|
|
------------------------------------------------------------------------------
|
|
---Description of the module.
|
|
---@class ModelCompute
|
|
local ModelCompute = {
|
|
classname = "HMModelCompute",
|
|
capEnergy = -0.8,
|
|
capSpeed = -0.8,
|
|
capPollution = -0.8,
|
|
waste_value = 0.00001,
|
|
new_solver = false,
|
|
cap_reason = {
|
|
speed = {
|
|
cycle = 1,
|
|
module_low = 2,
|
|
module_high = 4
|
|
},
|
|
productivity = {
|
|
module_low = 1
|
|
},
|
|
consumption = {
|
|
module_low = 1
|
|
},
|
|
pollution = {
|
|
module_low = 1
|
|
}
|
|
}
|
|
}
|
|
|
|
-------------------------------------------------------------------------------
|
|
---Check and valid unlinked all blocks
|
|
---@param model table
|
|
function ModelCompute.checkUnlinkedBlocks(model)
|
|
if model.blocks ~= nil then
|
|
for _, block in spairs(model.blocks, function(t, a, b) return t[b].index > t[a].index end) do
|
|
ModelCompute.checkUnlinkedBlock(model, block)
|
|
end
|
|
end
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
---Check and valid unlinked block
|
|
---@param model table
|
|
---@param block table
|
|
function ModelCompute.checkUnlinkedBlock(model, block)
|
|
local unlinked = true
|
|
local recipe = Player.getPlayerRecipe(block.name)
|
|
if recipe ~= nil then
|
|
if model.blocks ~= nil then
|
|
for _, current_block in spairs(model.blocks, function(t, a, b) return t[b].index > t[a].index end) do
|
|
if current_block.id == block.id then
|
|
break
|
|
end
|
|
for _, ingredient in pairs(current_block.ingredients) do
|
|
for _, product in pairs(recipe.products) do
|
|
if product.name == ingredient.name then
|
|
unlinked = false
|
|
end
|
|
end
|
|
end
|
|
if current_block.id ~= block.id and current_block.name == block.name then
|
|
unlinked = true
|
|
end
|
|
end
|
|
end
|
|
block.unlinked = unlinked
|
|
else
|
|
---not a recipe
|
|
block.unlinked = true
|
|
end
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
---Update model
|
|
---@param model table
|
|
function ModelCompute.try_update(model)
|
|
local ok , err = pcall(function()
|
|
ModelCompute.update(model)
|
|
end)
|
|
if not(ok) then
|
|
log(err)
|
|
end
|
|
end
|
|
-------------------------------------------------------------------------------
|
|
---Update model
|
|
---@param model table
|
|
function ModelCompute.update(model)
|
|
if model ~= nil and model.blocks ~= nil then
|
|
Model.appendParameters(model)
|
|
---calcul les blocks
|
|
local input = {}
|
|
for _, block in spairs(model.blocks, function(t, a, b) return t[b].index > t[a].index end) do
|
|
block.time = model.time
|
|
---premiere recette
|
|
local _, recipe = next(block.recipes)
|
|
if recipe == nil then
|
|
block.ingredients = {}
|
|
block.products = {}
|
|
else
|
|
|
|
---prepare bloc
|
|
ModelCompute.prepareBlock(block)
|
|
|
|
---state = 0 => produit
|
|
---state = 1 => produit pilotant
|
|
---state = 2 => produit restant
|
|
---prepare input
|
|
if not (block.unlinked) then
|
|
if block.products == nil then
|
|
ModelCompute.computeBlock(block)
|
|
end
|
|
|
|
---prepare les inputs
|
|
local factor = -1
|
|
local block_elements = block.products
|
|
if block.by_product == false then
|
|
block_elements = block.ingredients
|
|
factor = 1
|
|
end
|
|
if block_elements ~= nil then
|
|
for _, element in pairs(block_elements) do
|
|
local element_key = Product(element):getTableKey()
|
|
if (element.state ~= nil and element.state == 1) or (block.products_linked ~= nil and block.products_linked[element_key] == true) then
|
|
if input[element_key] ~= nil then
|
|
element.input = (input[element_key] or 0) * factor
|
|
--element.state = 0
|
|
end
|
|
else
|
|
element.input = 0
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
ModelCompute.computeBlockCleanInput(block)
|
|
|
|
|
|
ModelCompute.computeBlock(block, model.parameters)
|
|
|
|
---consomme les ingredients
|
|
for _, product in pairs(block.products) do
|
|
local element_key = Product(product):getTableKey()
|
|
if input[element_key] == nil then
|
|
input[element_key] = product.count
|
|
elseif input[element_key] ~= nil then
|
|
input[element_key] = input[element_key] + product.count
|
|
end
|
|
end
|
|
---compte les ingredients
|
|
for _, ingredient in pairs(block.ingredients) do
|
|
local element_key = Product(ingredient):getTableKey()
|
|
if input[element_key] == nil then
|
|
input[element_key] = -ingredient.count
|
|
else
|
|
input[element_key] = input[element_key] - ingredient.count
|
|
end
|
|
end
|
|
---consume energy
|
|
local element_key = "energy"
|
|
if input[element_key] == nil then
|
|
input[element_key] = -block.power
|
|
else
|
|
input[element_key] = input[element_key] - block.power
|
|
end
|
|
end
|
|
end
|
|
|
|
ModelCompute.computeInputOutput(model)
|
|
ModelCompute.computeResources(model)
|
|
|
|
---genere un bilan
|
|
ModelCompute.createSummary(model)
|
|
model.version = Model.version
|
|
end
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
---Compute production block
|
|
---@param block table
|
|
function ModelCompute.computeBlockCleanInput(block)
|
|
local recipes = block.recipes
|
|
if recipes ~= nil then
|
|
if block.input ~= nil then
|
|
---state = 0 => produit
|
|
---state = 1 => produit pilotant
|
|
---state = 2 => produit restant
|
|
for product_name, quantity in pairs(block.input) do
|
|
if block.products[product_name] == nil or not (bit32.band(block.products[product_name].state, 1)) then
|
|
block.input[product_name] = nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
---Prepare production block
|
|
---@param block table
|
|
function ModelCompute.prepareBlock(block)
|
|
local recipes = block.recipes
|
|
if recipes ~= nil then
|
|
local block_products = {}
|
|
local block_ingredients = {}
|
|
---preparation
|
|
for _, recipe in spairs(recipes, function(t, a, b) return t[b].index > t[a].index end) do
|
|
local recipe_prototype = RecipePrototype(recipe)
|
|
|
|
for i, lua_product in pairs(recipe_prototype:getProducts(recipe.factory)) do
|
|
local product_key = Product(lua_product):getTableKey()
|
|
block_products[product_key] = {
|
|
name = lua_product.name,
|
|
type = lua_product.type,
|
|
count = 0,
|
|
temperature = lua_product.temperature,
|
|
minimum_temperature = lua_product.minimum_temperature,
|
|
maximum_temperature = lua_product.maximum_temperature
|
|
}
|
|
end
|
|
for i, lua_ingredient in pairs(recipe_prototype:getIngredients(recipe.factory)) do
|
|
local ingredient_key = Product(lua_ingredient):getTableKey()
|
|
block_ingredients[ingredient_key] = {
|
|
name = lua_ingredient.name,
|
|
type = lua_ingredient.type,
|
|
count = 0,
|
|
temperature = lua_ingredient.temperature,
|
|
minimum_temperature = lua_ingredient.minimum_temperature,
|
|
maximum_temperature = lua_ingredient.maximum_temperature
|
|
}
|
|
end
|
|
end
|
|
---preparation state
|
|
---state = 0 => produit
|
|
---state = 1 => produit pilotant
|
|
---state = 2 => produit restant
|
|
for i, block_product in pairs(block_products) do
|
|
local product_key = Product(block_product):getTableKey()
|
|
---recopie la valeur input
|
|
if block.by_factory ~= true and block.products ~= nil and block.products[product_key] ~= nil then
|
|
block_product.input = block.products[product_key].input
|
|
end
|
|
---pose le status
|
|
if block_ingredients[product_key] == nil then
|
|
block_product.state = 1
|
|
else
|
|
block_product.state = 0
|
|
end
|
|
end
|
|
|
|
for i, block_ingredient in pairs(block_ingredients) do
|
|
local ingredient_key = Product(block_ingredient):getTableKey()
|
|
---recopie la valeur input
|
|
if block.by_factory ~= true and block.ingredients ~= nil and block.ingredients[ingredient_key] ~= nil then
|
|
block_ingredient.input = block.ingredients[ingredient_key].input
|
|
end
|
|
---pose le status
|
|
if block_products[ingredient_key] == nil then
|
|
block_ingredient.state = 1
|
|
else
|
|
block_ingredient.state = 0
|
|
end
|
|
end
|
|
block.products = block_products
|
|
block.ingredients = block_ingredients
|
|
end
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
---Compute production block
|
|
---@param block table
|
|
function ModelCompute.computeBlock(block, parameters)
|
|
local recipes = block.recipes
|
|
block.power = 0
|
|
block.count = 1
|
|
block.pollution_total = 0
|
|
|
|
if recipes ~= nil then
|
|
local my_solver
|
|
|
|
local debug = User.getModGlobalSetting("debug_solver")
|
|
local selected_solvers = { algebra = SolverAlgebra, simplex = SolverSimplex }
|
|
|
|
local solver_selected = User.getParameter("solver_selected") or defines.constant.default_solver
|
|
if solver_selected ~= defines.constant.solvers.normal then
|
|
selected_solvers = { algebra = SolverMatrixAlgebra, simplex = SolverMatrixSimplex }
|
|
end
|
|
if block.solver == true and block.by_factory ~= true then
|
|
my_solver = selected_solvers.simplex()
|
|
else
|
|
my_solver = selected_solvers.algebra()
|
|
end
|
|
|
|
my_solver:solve(block, parameters, debug)
|
|
|
|
end
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
---Compute module effects of factory
|
|
---@param recipe table
|
|
---@param parameters ParametersData
|
|
---@return table
|
|
function ModelCompute.computeModuleEffects(recipe, parameters)
|
|
local factory = recipe.factory
|
|
factory.effects = { speed = 0, productivity = 0, consumption = 0, pollution = 0 }
|
|
if parameters ~= nil then
|
|
factory.effects.speed = parameters.effects.speed
|
|
factory.effects.productivity = parameters.effects.productivity
|
|
factory.effects.consumption = parameters.effects.consumption
|
|
factory.effects.pollution = parameters.effects.pollution
|
|
end
|
|
factory.cap = { speed = 0, productivity = 0, consumption = 0, pollution = 0 }
|
|
local factory_prototype = EntityPrototype(factory)
|
|
factory.effects.productivity = factory.effects.productivity + factory_prototype:getBaseProductivity()
|
|
---effet module factory
|
|
if factory.modules ~= nil then
|
|
for module, value in pairs(factory.modules) do
|
|
local speed_bonus = Player.getModuleBonus(module, "speed")
|
|
local productivity_bonus = Player.getModuleBonus(module, "productivity")
|
|
local consumption_bonus = Player.getModuleBonus(module, "consumption")
|
|
local pollution_bonus = Player.getModuleBonus(module, "pollution")
|
|
factory.effects.speed = factory.effects.speed + value * speed_bonus
|
|
factory.effects.productivity = factory.effects.productivity + value * productivity_bonus
|
|
factory.effects.consumption = factory.effects.consumption + value * consumption_bonus
|
|
factory.effects.pollution = factory.effects.pollution + value * pollution_bonus
|
|
end
|
|
end
|
|
---effet module beacon
|
|
if recipe.beacons ~= nil then
|
|
for _, beacon in pairs(recipe.beacons) do
|
|
if beacon.modules ~= nil then
|
|
for module, value in pairs(beacon.modules) do
|
|
local speed_bonus = Player.getModuleBonus(module, "speed")
|
|
local productivity_bonus = Player.getModuleBonus(module, "productivity")
|
|
local consumption_bonus = Player.getModuleBonus(module, "consumption")
|
|
local pollution_bonus = Player.getModuleBonus(module, "pollution")
|
|
local distribution_effectivity = EntityPrototype(beacon):getDistributionEffectivity()
|
|
factory.effects.speed = factory.effects.speed + value * speed_bonus * distribution_effectivity * beacon
|
|
.combo
|
|
factory.effects.productivity = factory.effects.productivity +
|
|
value * productivity_bonus * distribution_effectivity * beacon.combo
|
|
factory.effects.consumption = factory.effects.consumption +
|
|
value * consumption_bonus * distribution_effectivity * beacon.combo
|
|
factory.effects.pollution = factory.effects.pollution +
|
|
value * pollution_bonus * distribution_effectivity * beacon.combo
|
|
end
|
|
end
|
|
end
|
|
end
|
|
if recipe.type == "resource" then
|
|
local bonus = Player.getForce().mining_drill_productivity_bonus
|
|
factory.effects.productivity = factory.effects.productivity + bonus
|
|
end
|
|
if recipe.type == "technology" then
|
|
local bonus = Player.getForce().laboratory_speed_modifier or 0
|
|
factory.effects.speed = factory.effects.speed + bonus * (1 + factory.effects.speed)
|
|
end
|
|
---nuclear reactor
|
|
if factory_prototype:getType() == "reactor" then
|
|
local bonus = factory_prototype:getNeighbourBonus()
|
|
factory.effects.consumption = factory.effects.consumption + bonus
|
|
end
|
|
|
|
---cap la productivite
|
|
if factory.effects.productivity < 0 then
|
|
factory.effects.productivity = 0
|
|
factory.cap.productivity = bit32.bor(factory.cap.productivity, ModelCompute.cap_reason.productivity.module_low)
|
|
end
|
|
|
|
---cap la vitesse a self.capSpeed
|
|
if factory.effects.speed < ModelCompute.capSpeed then
|
|
factory.effects.speed = ModelCompute.capSpeed
|
|
factory.cap.speed = bit32.bor(factory.cap.speed, ModelCompute.cap_reason.speed.module_low)
|
|
end
|
|
---cap short integer max for %
|
|
---@see https://fr.wikipedia.org/wiki/Entier_court
|
|
if factory.effects.speed * 100 > 32767 then
|
|
factory.effects.speed = 32767 / 100
|
|
factory.cap.speed = bit32.bor(factory.cap.speed, ModelCompute.cap_reason.speed.module_high)
|
|
end
|
|
|
|
---cap l'energy a self.capEnergy
|
|
if factory.effects.consumption < ModelCompute.capEnergy then
|
|
factory.effects.consumption = ModelCompute.capEnergy
|
|
factory.cap.consumption = bit32.bor(factory.cap.consumption, ModelCompute.cap_reason.consumption.module_low)
|
|
end
|
|
|
|
---cap la pollution a self.capPollution
|
|
if factory.effects.pollution < ModelCompute.capPollution then
|
|
factory.effects.pollution = ModelCompute.capPollution
|
|
factory.cap.pollution = bit32.bor(factory.cap.pollution, ModelCompute.cap_reason.pollution.module_low)
|
|
end
|
|
return recipe
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
---Compute energy, speed, number of factory for recipes
|
|
---@param recipe table
|
|
function ModelCompute.computeFactory(recipe)
|
|
local recipe_prototype = RecipePrototype(recipe)
|
|
local factory_prototype = EntityPrototype(recipe.factory)
|
|
recipe.time = recipe_prototype:getEnergy(recipe.factory)
|
|
|
|
---effet speed
|
|
recipe.factory.speed_total = factory_prototype:speedFactory(recipe) * (1 + recipe.factory.effects.speed)
|
|
if recipe.type == "rocket" then
|
|
local speed_penalty = recipe_prototype:getRocketPenalty(recipe.factory)
|
|
recipe.factory.speed_total = recipe.factory.speed_total * speed_penalty
|
|
end
|
|
recipe.factory.speed = recipe.factory.speed_total
|
|
---cap speed creation maximum de 1 cycle par tick
|
|
---seulement sur les recipes normaux
|
|
if recipe.type == "recipe" and recipe.time / recipe.factory.speed < 1 / 60 then
|
|
recipe.factory.speed = 60 * recipe.time
|
|
recipe.factory.cap.speed = bit32.bor(recipe.factory.cap.speed, ModelCompute.cap_reason.speed.cycle)
|
|
end
|
|
|
|
---effet consumption
|
|
local energy_type = factory_prototype:getEnergyType()
|
|
recipe.factory.energy = factory_prototype:getEnergyConsumption() * (1 + recipe.factory.effects.consumption)
|
|
|
|
---effet pollution
|
|
recipe.factory.pollution = factory_prototype:getPollution() * (1 + recipe.factory.effects.pollution) *
|
|
(1 + recipe.factory.effects.consumption)
|
|
|
|
---compte le nombre de machines necessaires
|
|
---[ratio recipe] * [effort necessaire du recipe] / ([la vitesse de la factory] * [le temps en second])
|
|
local count = recipe.count * recipe.time / (recipe.factory.speed * recipe.base_time)
|
|
if recipe.factory.speed == 0 then count = 0 end
|
|
recipe.factory.count = count
|
|
|
|
if energy_type ~= "electric" then
|
|
recipe.factory.energy_total = 0
|
|
else
|
|
recipe.factory.energy_total = recipe.factory.count * recipe.factory.energy
|
|
local drain = factory_prototype:getMinEnergyUsage()
|
|
recipe.factory.energy_total = math.ceil(recipe.factory.energy_total + (math.ceil(recipe.factory.count) * drain))
|
|
recipe.factory.energy = recipe.factory.energy + drain
|
|
end
|
|
---arrondi des valeurs
|
|
recipe.factory.speed = recipe.factory.speed
|
|
recipe.factory.energy = math.ceil(recipe.factory.energy)
|
|
|
|
local beacons_energy_total = 0
|
|
if recipe.beacons ~= nil then
|
|
for _, beacon in pairs(recipe.beacons) do
|
|
if Model.countModulesModel(beacon) > 0 then
|
|
local variant = beacon.per_factory or 0
|
|
local constant = beacon.per_factory_constant or 0
|
|
beacon.count = count * variant + constant
|
|
else
|
|
beacon.count = 0
|
|
end
|
|
local beacon_prototype = EntityPrototype(beacon)
|
|
beacon.energy = beacon_prototype:getEnergyUsage()
|
|
beacon.energy_total = math.ceil(beacon.count * beacon.energy)
|
|
beacon.energy = math.ceil(beacon.energy)
|
|
beacons_energy_total = beacons_energy_total + beacon.energy_total
|
|
end
|
|
end
|
|
|
|
--- totaux
|
|
recipe.factory.pollution_total = recipe.factory.pollution * recipe.factory.count * recipe.base_time
|
|
recipe.pollution_total = recipe.factory.pollution_total * recipe_prototype:getEmissionsMultiplier()
|
|
recipe.energy_total = recipe.factory.energy_total + beacons_energy_total
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
---Compute energy factory for recipes
|
|
---@param recipe table
|
|
function ModelCompute.computeEnergyFactory(recipe)
|
|
local recipe_prototype = RecipePrototype(recipe)
|
|
local factory_prototype = EntityPrototype(recipe.factory)
|
|
local recipe_energy = recipe_prototype:getEnergy(recipe.factory)
|
|
---effet speed
|
|
recipe.factory.speed = factory_prototype:speedFactory(recipe) * (1 + recipe.factory.effects.speed)
|
|
---cap speed creation maximum de 1 cycle par tick
|
|
---seulement sur les recipes normaux
|
|
if recipe.type == "recipe" and recipe_energy / recipe.factory.speed < 1 / 60 then
|
|
recipe.factory.speed = 60 * recipe_energy
|
|
end
|
|
|
|
---effet consumption
|
|
local energy_prototype = factory_prototype:getEnergySource()
|
|
|
|
local energy_type = factory_prototype:getEnergyType()
|
|
local gameDay = { day = 12500, dusk = 5000, night = 2500, dawn = 2500 }
|
|
if factory_prototype:getType() == "accumulator" then
|
|
local dark_time = (gameDay.dusk / 2 + gameDay.night + gameDay.dawn / 2)
|
|
--recipe_energy = dark_time
|
|
end
|
|
recipe.factory.energy = factory_prototype:getEnergyConsumption() * (1 + recipe.factory.effects.consumption)
|
|
|
|
---effet pollution
|
|
recipe.factory.pollution = factory_prototype:getPollution() * (1 + recipe.factory.effects.pollution)
|
|
|
|
---compte le nombre de machines necessaires
|
|
---[ratio recipe] * [effort necessaire du recipe] / ([la vitesse de la factory]
|
|
local count = recipe.count * recipe_energy / (recipe.factory.speed * recipe.base_time)
|
|
if recipe.factory.speed == 0 then count = 0 end
|
|
recipe.factory.count = count
|
|
---calcul des totaux
|
|
if energy_type == "electric" then
|
|
recipe.factory.energy_total = 0
|
|
else
|
|
recipe.factory.energy_total = 0
|
|
end
|
|
recipe.factory.pollution_total = recipe.factory.pollution * recipe.factory.count * recipe.base_time
|
|
|
|
recipe.energy_total = recipe.factory.energy_total
|
|
recipe.pollution_total = recipe.factory.pollution_total * recipe_prototype:getEmissionsMultiplier()
|
|
---arrondi des valeurs
|
|
recipe.factory.speed = recipe.factory.speed
|
|
recipe.factory.energy = math.ceil(recipe.factory.energy)
|
|
|
|
if recipe.beacons then
|
|
for _, beacon in pairs(recipe.beacons) do
|
|
beacon.energy_total = 0
|
|
beacon.energy = 0
|
|
end
|
|
end
|
|
|
|
recipe.time = 1
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
---Compute input and output
|
|
---@param model table
|
|
function ModelCompute.computeInputOutput(model)
|
|
model.products = {}
|
|
model.ingredients = {}
|
|
|
|
local index = 1
|
|
for _, element in spairs(model.blocks, function(t, a, b) return t[b].index > t[a].index end) do
|
|
---count product
|
|
if element.products ~= nil and table.size(element.products) then
|
|
for key, product in pairs(element.products) do
|
|
if model.products[key] == nil then
|
|
model.products[key] = Model.newIngredient(product.name, product.type)
|
|
model.products[key].temperature = product.temperature
|
|
model.products[key].minimum_temperature = product.minimum_temperature
|
|
model.products[key].maximum_temperature = product.maximum_temperature
|
|
model.products[key].index = index
|
|
index = index + 1
|
|
end
|
|
model.products[key].count = model.products[key].count + product.count
|
|
end
|
|
end
|
|
---count ingredient
|
|
if element.ingredients ~= nil and table.size(element.ingredients) then
|
|
for key, ingredient in pairs(element.ingredients) do
|
|
if model.ingredients[key] == nil then
|
|
model.ingredients[key] = Model.newIngredient(ingredient.name, ingredient.type)
|
|
model.ingredients[key].temperature = ingredient.temperature
|
|
model.ingredients[key].minimum_temperature = ingredient.minimum_temperature
|
|
model.ingredients[key].maximum_temperature = ingredient.maximum_temperature
|
|
model.ingredients[key].index = index
|
|
index = index + 1
|
|
end
|
|
model.ingredients[key].count = model.ingredients[key].count + ingredient.count
|
|
end
|
|
end
|
|
end
|
|
|
|
for _, element in spairs(model.blocks, function(t, a, b) return t[b].index > t[a].index end) do
|
|
---consomme les produits
|
|
if element.ingredients ~= nil and table.size(element.ingredients) then
|
|
for key, ingredient in pairs(element.ingredients) do
|
|
if element.mining_ingredient ~= ingredient.name then
|
|
if model.products[key] ~= nil then
|
|
model.products[key].count = model.products[key].count - ingredient.count
|
|
end
|
|
end
|
|
end
|
|
end
|
|
---consomme les ingredients
|
|
if element.products ~= nil and table.size(element.products) then
|
|
for key, product in pairs(element.products) do
|
|
if model.ingredients[key] ~= nil then
|
|
model.ingredients[key].count = model.ingredients[key].count - product.count
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
for key, ingredient in pairs(model.ingredients) do
|
|
if ingredient.count < 0.01 then
|
|
model.ingredients[key] = nil
|
|
end
|
|
end
|
|
|
|
for key, product in pairs(model.products) do
|
|
if product.count < 0.01 then
|
|
model.products[key] = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
---Compute resources
|
|
---@param model table
|
|
function ModelCompute.computeResources(model)
|
|
local resources = {}
|
|
|
|
---calcul resource
|
|
for k, ingredient in pairs(model.ingredients) do
|
|
if ingredient.resource_category ~= nil or ingredient.name == "water" then
|
|
local resource = model.resources[ingredient.name]
|
|
if resource ~= nil then
|
|
resource.count = ingredient.count
|
|
else
|
|
resource = Model.newResource(model, ingredient.name, ingredient.type, ingredient.count)
|
|
end
|
|
|
|
if ingredient.resource_category == "basic-solid" then
|
|
resource.category = "basic-solid"
|
|
end
|
|
if ingredient.name == "water" then
|
|
resource.category = "basic-fluid"
|
|
end
|
|
if ingredient.name == "crude-oil" then
|
|
resource.category = "basic-fluid"
|
|
end
|
|
|
|
resource.blocks = 1
|
|
resource.wagon = nil
|
|
resource.storage = nil
|
|
local ratio = 1
|
|
|
|
---compute storage
|
|
if resource.category == "basic-solid" then
|
|
resource.wagon = { type = "item", name = "cargo-wagon" }
|
|
resource.wagon.count = math.ceil(resource.count / 2000)
|
|
resource.wagon.limit_count = math.ceil(resource.wagon.count * ratio)
|
|
|
|
resource.storage = { type = "item", name = "steel-chest" }
|
|
resource.storage.count = math.ceil(resource.count / (48 * 50))
|
|
resource.storage.limit_count = math.ceil(resource.storage.count * ratio)
|
|
elseif resource.category == "basic-fluid" then
|
|
--resource.wagon = {type="item", name="cargo-wagon"}
|
|
--resource.wagon.count = math.ceil(resource.count/2000)
|
|
|
|
resource.storage = { type = "item", name = "storage-tank" }
|
|
resource.storage.count = math.ceil(resource.count / 2400)
|
|
resource.storage.limit_count = math.ceil(resource.storage.count * ratio)
|
|
end
|
|
resources[resource.name] = resource
|
|
end
|
|
end
|
|
model.resources = resources
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
---Compute energy, speed, number total
|
|
---@param model table
|
|
function ModelCompute.createSummary(model)
|
|
model.summary = {}
|
|
model.summary.factories = {}
|
|
model.summary.beacons = {}
|
|
model.summary.modules = {}
|
|
model.summary.building = 0
|
|
local energy = 0
|
|
local pollution = 0
|
|
local building = 0
|
|
|
|
for _, block in pairs(model.blocks) do
|
|
energy = energy + block.power
|
|
pollution = pollution + (block.pollution_total or 0)
|
|
ModelCompute.computeSummaryFactory(block)
|
|
building = building + block.summary.building
|
|
for _, type in pairs({ "factories", "beacons", "modules" }) do
|
|
for _, element in pairs(block.summary[type]) do
|
|
if model.summary[type][element.name] == nil then
|
|
model.summary[type][element.name] = {
|
|
name = element.name,
|
|
type = "item",
|
|
count = 0
|
|
}
|
|
end
|
|
model.summary[type][element.name].count = model.summary[type][element.name].count + element.count
|
|
end
|
|
end
|
|
end
|
|
model.summary.energy = energy
|
|
model.summary.pollution = pollution
|
|
model.summary.building = building
|
|
|
|
model.generators = {}
|
|
---formule 20 accumulateur /24 panneau solaire/1 MW
|
|
model.generators["accumulator"] = { name = "accumulator", type = "item",
|
|
count = 20 * math.ceil(energy / (1000 * 1000)) }
|
|
model.generators["solar-panel"] = { name = "solar-panel", type = "item",
|
|
count = 24 * math.ceil(energy / (1000 * 1000)) }
|
|
model.generators["steam-engine"] = { name = "steam-engine", type = "item", count = math.ceil(energy / (510 * 1000)) }
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
---Compute summary factory
|
|
---@param block table
|
|
function ModelCompute.computeSummaryFactory(block)
|
|
if block ~= nil then
|
|
block.summary = { building = 0, factories = {}, beacons = {}, modules = {} }
|
|
for _, recipe in pairs(block.recipes) do
|
|
---calcul nombre factory
|
|
local factory = recipe.factory
|
|
if block.summary.factories[factory.name] == nil then
|
|
block.summary.factories[factory.name] = {
|
|
name = factory.name,
|
|
type = factory.type or "entity",
|
|
count = 0
|
|
}
|
|
end
|
|
block.summary.factories[factory.name].count = block.summary.factories[factory.name].count +
|
|
math.ceil(factory.count)
|
|
block.summary.building = block.summary.building + math.ceil(factory.count)
|
|
---calcul nombre de module factory
|
|
if factory.modules ~= nil then
|
|
for module, value in pairs(factory.modules) do
|
|
if block.summary.modules[module] == nil then
|
|
block.summary.modules[module] = {
|
|
name = module,
|
|
type = "item",
|
|
count = 0
|
|
}
|
|
end
|
|
block.summary.modules[module].count = block.summary.modules[module].count +
|
|
value * math.ceil(factory.count)
|
|
end
|
|
end
|
|
---calcul nombre beacon
|
|
local beacons = recipe.beacons
|
|
if beacons ~= nil then
|
|
for _, beacon in pairs(beacons) do
|
|
if block.summary.beacons[beacon.name] == nil then
|
|
block.summary.beacons[beacon.name] = {
|
|
name = beacon.name,
|
|
type = beacon.type or "entity",
|
|
count = 0
|
|
}
|
|
end
|
|
block.summary.beacons[beacon.name].count = block.summary.beacons[beacon.name].count + math.ceil(beacon.count)
|
|
block.summary.building = block.summary.building + math.ceil(beacon.count)
|
|
---calcul nombre de module beacon
|
|
if beacon.modules ~= nil then
|
|
for module, value in pairs(beacon.modules) do
|
|
if block.summary.modules[module] == nil then
|
|
block.summary.modules[module] = {
|
|
name = module,
|
|
type = "item",
|
|
count = 0
|
|
}
|
|
end
|
|
block.summary.modules[module].count = block.summary.modules[module].count +
|
|
value * math.ceil(beacon.count)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return ModelCompute
|