186 lines
5.0 KiB
Lua

--- Utilities for data stage prototype manipulation.
--- ```lua
--- local flib_data_util = require("__flib__/data-util")
--- ```
--- @class flib_data_util
local flib_data_util = {}
--- Copy a prototype, assigning a new name and minable properties.
--- @param prototype table
--- @param new_name string string
--- @param remove_icon? boolean
--- @return table
function flib_data_util.copy_prototype(prototype, new_name, remove_icon)
if not prototype.type or not prototype.name then
error("Invalid prototype: prototypes must have name and type properties.")
return --- @diagnostic disable-line
end
local p = table.deepcopy(prototype)
p.name = new_name
if p.minable and p.minable.result then
p.minable.result = new_name
end
if p.place_result then
p.place_result = new_name
end
if p.result then
p.result = new_name
end
if p.results then
for _, result in pairs(p.results) do
if result.name == prototype.name then
result.name = new_name
end
end
end
if remove_icon then
p.icon = nil
p.icon_size = nil
p.icon_mipmaps = nil
p.icons = nil
end
return p
end
--- Copy prototype.icon/icons to a new fully defined icons array, optionally adding new icon layers.
---
--- Returns `nil` if the prototype's icons are incorrectly or incompletely defined.
--- @param prototype table
--- @param new_layers? IconSpecification[]
--- @return IconSpecification[]|nil
function flib_data_util.create_icons(prototype, new_layers)
if new_layers then
for _, new_layer in pairs(new_layers) do
if not new_layer.icon or not new_layer.icon_size then
return nil
end
end
end
if prototype.icons then
local icons = {}
for _, v in pairs(prototype.icons) do
-- Over define as much as possible to minimize weirdness: https://forums.factorio.com/viewtopic.php?f=25&t=81980
icons[#icons + 1] = {
icon = v.icon,
icon_size = v.icon_size or prototype.icon_size or 32,
icon_mipmaps = v.icon_mipmaps or prototype.icon_mipmaps or 0,
tint = v.tint,
scale = v.scale or 1,
shift = v.shift,
}
end
if new_layers then
for _, new_layer in pairs(new_layers) do
icons[#icons + 1] = new_layer
end
end
return icons
elseif prototype.icon then
local icons = {
{
icon = prototype.icon,
icon_size = prototype.icon_size,
icon_mipmaps = prototype.icon_mipmaps,
tint = { r = 1, g = 1, b = 1, a = 1 },
},
}
if new_layers then
for _, new_layer in pairs(new_layers) do
icons[#icons + 1] = new_layer
end
end
return icons
else
return nil
end
end
local exponent_multipliers = {
["y"] = 0.000000000000000000000001,
["z"] = 0.000000000000000000001,
["a"] = 0.000000000000000001,
["f"] = 0.000000000000001,
["p"] = 0.000000000001,
["n"] = 0.000000001,
["u"] = 0.000001, -- μ is invalid
["m"] = 0.001,
["c"] = 0.01,
["d"] = 0.1,
[""] = 1,
["da"] = 10,
["h"] = 100,
["k"] = 1000,
["M"] = 1000000,
["G"] = 1000000000,
["T"] = 1000000000000,
["P"] = 1000000000000000,
["E"] = 1000000000000000000,
["Z"] = 1000000000000000000000,
["Y"] = 1000000000000000000000000,
}
--- Convert an energy string to base unit value + suffix.
---
--- Returns `nil` if `energy_string` is incorrectly formatted.
--- @param energy_string string
--- @return number?
--- @return string?
function flib_data_util.get_energy_value(energy_string)
if type(energy_string) == "string" then
local v, _, exp, unit = string.match(energy_string, "([%-+]?[0-9]*%.?[0-9]+)((%D*)([WJ]))")
local value = tonumber(v)
if value and exp and exponent_multipliers[exp] then
value = value * exponent_multipliers[exp]
return value, unit
end
end
return nil
end
--- Build a sprite from constituent parts.
--- @param name? string
--- @param position? MapPosition
--- @param filename? string
--- @param size? Vector
--- @param mipmap_count? number
--- @param mods? table
--- @return SpriteSpecification
function flib_data_util.build_sprite(name, position, filename, size, mipmap_count, mods)
local def = {
type = "sprite",
name = name,
filename = filename,
position = position,
size = size,
mipmap_count = mipmap_count,
flags = { "icon" },
}
if mods then
for k, v in pairs(mods) do
def[k] = v
end
end
return def
end
--- An empty image. This image is 8x8 to facilitate usage with GUI styles.
flib_data_util.empty_image = "__flib__/graphics/empty.png"
--- A black image, for use with tool backgrounds. This image is 1x1.
flib_data_util.black_image = "__flib__/graphics/black.png"
--- A desaturated planner image. Tint this sprite to easily add your own planners.
flib_data_util.planner_base_image = "__flib__/graphics/planner.png"
--- A dark red button tileset. Used for the `flib_tool_button_dark_red` style.
flib_data_util.dark_red_button_tileset = "__flib__/graphics/dark-red-button.png"
return flib_data_util
--- @class IconSpecification
--- @field icon string
--- @field icon_size int
--- @class SpriteSpecification