239 lines
9.7 KiB
Lua

local table = require("__flib__.table")
local constants = require("constants")
local util = require("scripts.util")
local fluid_proc = {}
function fluid_proc.build(database, metadata)
local localised_fluids = {}
for name, prototype in pairs(global.prototypes.fluid) do
-- Group
local group = prototype.group
local group_data = database.group[group.name]
group_data.fluids[#group_data.fluids + 1] = { class = "fluid", name = name }
-- Fake fuel category
local fuel_category
if prototype.fuel_value > 0 then
fuel_category = { class = "fuel_category", name = constants.fake_fluid_fuel_category }
local fluids = database.fuel_category[constants.fake_fluid_fuel_category].fluids
fluids[#fluids + 1] = { class = "fluid", name = name }
end
-- Save to recipe book
database.fluid[name] = {
burned_in = {},
class = "fluid",
default_temperature = prototype.default_temperature,
fuel_category = fuel_category,
fuel_pollution = prototype.fuel_value > 0
and prototype.emissions_multiplier ~= 1
and prototype.emissions_multiplier
or nil,
fuel_value = prototype.fuel_value > 0 and prototype.fuel_value or nil,
group = { class = "group", name = group.name },
hidden = prototype.hidden,
ingredient_in = {},
mined_from = {},
product_of = {},
prototype_name = name,
pumped_by = {},
recipe_categories = util.unique_obj_array(),
science_packs = {},
subgroup = { class = "group", name = prototype.subgroup.name },
temperatures = {},
unlocked_by = util.unique_obj_array(),
}
-- Don't add strings yet - they will be added in process_temperatures() to improve the ordering
localised_fluids[name] = { name = prototype.localised_name, description = prototype.localised_description }
end
metadata.localised_fluids = localised_fluids
end
-- Adds a fluid temperature definition if one doesn't exist yet
function fluid_proc.add_temperature(fluid_data, temperature_ident)
local temperature_string = temperature_ident.string
local temperatures = fluid_data.temperatures
if not temperatures[temperature_string] then
temperatures[temperature_string] = {
base_fluid = { class = "fluid", name = fluid_data.prototype_name },
class = "fluid",
default_temperature = fluid_data.default_temperature,
fuel_pollution = fluid_data.fuel_pollution,
fuel_value = fluid_data.fuel_value,
group = fluid_data.group,
hidden = fluid_data.hidden,
ingredient_in = {},
mined_from = {},
name = fluid_data.prototype_name .. "." .. temperature_string,
product_of = {},
prototype_name = fluid_data.prototype_name,
recipe_categories = util.unique_obj_array(),
science_packs = {},
subgroup = fluid_data.subgroup,
temperature_ident = temperature_ident,
unlocked_by = util.unique_obj_array(),
}
end
end
-- Returns true if `comp` is within `base`
function fluid_proc.is_within_range(base, comp, flip)
if flip then
return base.min >= comp.min and base.max <= comp.max
else
return base.min <= comp.min and base.max >= comp.max
end
end
function fluid_proc.process_temperatures(database, metadata)
-- Create a new fluids table so insertion order will neatly organize the temperature variants
local new_fluid_table = {}
for fluid_name, fluid_data in pairs(database.fluid) do
new_fluid_table[fluid_name] = fluid_data
local localised = metadata.localised_fluids[fluid_name]
util.add_to_dictionary("fluid", fluid_name, localised.name)
util.add_to_dictionary("fluid_description", fluid_name, localised.description)
local temperatures = fluid_data.temperatures
if temperatures and next(temperatures) then
-- Step 1: Add a variant for the default temperature if one does not exist
local default_temperature = fluid_data.default_temperature
local default_temperature_ident = util.build_temperature_ident({ temperature = default_temperature })
if not temperatures[default_temperature_ident.string] then
fluid_proc.add_temperature(fluid_data, default_temperature_ident)
end
-- Step 2: Sort the temperature variants
local temp = {}
for _, temperature_data in pairs(temperatures) do
table.insert(temp, temperature_data)
end
table.sort(temp, function(temp_a, temp_b)
return util.get_sorting_number(temp_a.temperature_ident) < util.get_sorting_number(temp_b.temperature_ident)
end)
-- Create a new table and insert in order
temperatures = {}
for _, temperature_data in pairs(temp) do
temperatures[temperature_data.name] = temperature_data
-- Add to database and add translation
new_fluid_table[temperature_data.name] = temperature_data
util.add_to_dictionary("fluid", temperature_data.name, {
"",
localised.name,
" (",
{ "format-degrees-c-compact", temperature_data.temperature_ident.string },
")",
})
end
fluid_data.temperatures = temperatures
-- Step 3: Add researched properties to temperature variants
for _, temperature_data in pairs(temperatures) do
temperature_data.enabled_at_start = fluid_data.enabled_at_start
if fluid_data.researched_forces then
temperature_data.researched_forces = {}
end
end
-- Step 4: Add properties from base fluid to temperature variants
-- TODO: This is an idiotic way to do this
for fluid_tbl_name, obj_table_name in pairs({
ingredient_in = "ingredients",
product_of = "products",
mined_from = "products",
}) do
for _, obj_ident in pairs(fluid_data[fluid_tbl_name]) do
local obj_data = database[obj_ident.class][obj_ident.name]
-- Get the matching fluid
local fluid_ident
-- This is kind of a slow way to do it, but I don't really care
for _, material_ident in pairs(obj_data[obj_table_name]) do
if material_ident.name == fluid_name then
fluid_ident = material_ident
break
end
end
-- Get the temperature identifier from the material table
local temperature_ident = fluid_ident.temperature_ident
if temperature_ident then
-- Change the name of the material and remove the identifier
fluid_ident.name = fluid_ident.name .. "." .. temperature_ident.string
fluid_ident.temperature_ident = nil
elseif obj_table_name == "products" then
-- Change the name of the material to the default temperature
fluid_ident.name = fluid_ident.name .. "." .. default_temperature_ident.string
fluid_ident.temperature_ident = nil
-- Use the default temperature for matching
temperature_ident = default_temperature_ident
end
-- Iterate over all temperature variants and compare their constraints
for _, temperature_data in pairs(temperatures) do
if
not temperature_ident
or fluid_proc.is_within_range(
temperature_data.temperature_ident,
temperature_ident,
fluid_tbl_name == "ingredient_in"
)
then
-- Add to recipes table
temperature_data[fluid_tbl_name][#temperature_data[fluid_tbl_name] + 1] = obj_ident
-- Recipe-specific logic
if obj_ident.class == "recipe" then
-- Add recipe category
local recipe_categories = temperature_data.recipe_categories
recipe_categories[#recipe_categories + 1] = table.shallow_copy(obj_data.recipe_category)
-- If in product_of, append to unlocked_by
-- Also add this fluid to that tech's `unlocks fluids` table
-- This is to avoid variants being "unlocked" when you can't actually get them
-- If this is an "empty X barrel" recipe, ignore it
if fluid_tbl_name == "product_of" and not string.find(obj_ident.name, "^empty%-.+%-barrel$") then
local temp_unlocked_by = temperature_data.unlocked_by
for _, technology_ident in pairs(obj_data.unlocked_by) do
temp_unlocked_by[#temp_unlocked_by + 1] = technology_ident
local technology_data = database.technology[technology_ident.name]
-- Don't use fluid_ident becuase it has an amount
technology_data.unlocks_fluids[#technology_data.unlocks_fluids + 1] = {
class = "fluid",
name = temperature_data.name,
}
end
end
end
end
end
end
end
-- Step 5: If this variant is not produced by anything, unlock with the base fluid
for _, temperature_data in pairs(temperatures) do
if #temperature_data.product_of == 0 and #temperature_data.unlocked_by == 0 then
temperature_data.unlocked_by = table.deep_copy(fluid_data.unlocked_by)
for _, technology_ident in pairs(fluid_data.unlocked_by) do
local technology_data = database.technology[technology_ident.name]
-- Don't use fluid_ident becuase it has an amount
technology_data.unlocks_fluids[#technology_data.unlocks_fluids + 1] = {
class = "fluid",
name = temperature_data.name,
}
end
end
end
end
end
database.fluid = new_fluid_table
end
-- When calling the module directly, call fluid_proc.build
setmetatable(fluid_proc, {
__call = function(_, ...)
return fluid_proc.build(...)
end,
})
return fluid_proc