diff --git a/lib/metas/entity.lua b/lib/metas/entity.lua
index bb6d0a6..32e4681 100644
--- a/lib/metas/entity.lua
+++ b/lib/metas/entity.lua
@@ -1,12 +1,12 @@
local collision_mask_util = require "__core__/lualib/collision-mask-util"
+local entity_types = defines.prototypes.entity
+
---@class data.EntityPrototype
----@field public standardize fun(self: data.EntityPrototype): data.EntityPrototype
----@field public add_flag fun(self: data.EntityPrototype, flag: string): data.EntityPrototype
----@field public remove_flag fun(self: data.EntityPrototype, flag: string): data.EntityPrototype
+---@field public standardize fun(self: data.EntityPrototype): data.EntityPrototype, boolean
+---@field public add_flag fun(self: data.EntityPrototype, flag: string): data.EntityPrototype, boolean
+---@field public remove_flag fun(self: data.EntityPrototype, flag: string): data.EntityPrototype, boolean
---@field public has_flag fun(self: data.EntityPrototype, flag: string): boolean
-
-local entity_types = defines.prototypes.entity
ENTITY = setmetatable({}, {
---@param entity data.EntityPrototype
__call = function(self, entity)
@@ -57,20 +57,39 @@ metas.standardize = function(self)
return self
end
+---@param self data.EntityPrototype
+---@param flag string
+---@return data.EntityPrototype self
+---@return boolean success
metas.add_flag = function(self, flag)
- if not self.flags then self.flags = {} end
+ self.flags = self.flags or {}
+ for _, f in pairs(self.flags) do
+ if f == flag then
+ return self, false -- flag already exists
+ end
+ end
table.insert(self.flags, flag)
- return self
+ return self, true -- flag added
end
+---@param self data.EntityPrototype
+---@param flag string
+---@return data.EntityPrototype self
+---@return boolean success
metas.remove_flag = function(self, flag)
- if not self.flags then return self end
+ if not self.flags then return self, false end
for i, f in pairs(self.flags) do
- if f == flag then table.remove(self.flags, i) end
+ if f == flag then
+ table.remove(self.flags, i)
+ return self, true -- flag found and removed
+ end
end
- return self
+ return self, false -- could not find flag
end
+---@param self data.EntityPrototype
+---@param flag string
+---@return boolean has_flag
metas.has_flag = function(self, flag)
if not self.flags then return false end
for _, f in pairs(self.flags) do
diff --git a/lib/metas/fluid.lua b/lib/metas/fluid.lua
index 186d03b..84452d3 100644
--- a/lib/metas/fluid.lua
+++ b/lib/metas/fluid.lua
@@ -1,3 +1,4 @@
+---@class data.FluidPrototype
FLUID = setmetatable(data.raw.fluid, {
---@param fluid data.FluidPrototype
__call = function(self, fluid)
diff --git a/lib/metas/item.lua b/lib/metas/item.lua
index 4f9a1fc..ef12629 100644
--- a/lib/metas/item.lua
+++ b/lib/metas/item.lua
@@ -1,10 +1,10 @@
+local item_prototypes = defines.prototypes.item
+
---@class data.ItemPrototype
----@field public add_flag fun(self: data.ItemPrototype, flag: string): data.ItemPrototype
----@field public remove_flag fun(self: data.ItemPrototype, flag: string): data.ItemPrototype
+---@field public add_flag fun(self: data.ItemPrototype, flag: string): data.ItemPrototype, boolean
+---@field public remove_flag fun(self: data.ItemPrototype, flag: string): data.ItemPrototype, boolean
---@field public has_flag fun(self: data.ItemPrototype, flag: string): boolean
----@field public spoil fun(self: data.ItemPrototype, spoil_result: (string | table), spoil_ticks: number): data.ItemPrototype
-
-local item_prototypes = defines.prototypes.item
+---@field public spoil fun(self: data.ItemPrototype, spoil_result: (string | table), spoil_ticks: number): data.ItemPrototype, boolean
ITEM = setmetatable({}, {
---@param item data.ItemPrototype
__call = function(self, item)
@@ -36,20 +36,39 @@ ITEM = setmetatable({}, {
local metas = {}
+---@param self data.ItemPrototype
+---@param flag string
+---@return data.ItemPrototype self
+---@return boolean success
metas.add_flag = function(self, flag)
- if not self.flags then self.flags = {} end
+ self.flags = self.flags or {}
+ for _, f in pairs(self.flags) do
+ if f == flag then
+ return self, false -- flag already exists
+ end
+ end
table.insert(self.flags, flag)
- return self
+ return self, true -- flag added
end
+---@param self data.ItemPrototype
+---@param flag string
+---@return data.ItemPrototype self
+---@return boolean success
metas.remove_flag = function(self, flag)
- if not self.flags then return self end
+ if not self.flags then return self, false end
for i, f in pairs(self.flags) do
- if f == flag then table.remove(self.flags, i) end
+ if f == flag then
+ table.remove(self.flags, i)
+ return self, true -- flag found and removed
+ end
end
- return self
+ return self, false -- could not find flag
end
+---@param self data.ItemPrototype
+---@param flag string
+---@return boolean has_flag
metas.has_flag = function(self, flag)
if not self.flags then return false end
for _, f in pairs(self.flags) do
@@ -82,8 +101,13 @@ py.spoil_triggers = {
end
}
+---@param self data.ItemPrototype
+---@param spoil_result string|data.SpoilToTriggerResult
+---@param spoil_ticks int
+---@return table self
+---@return boolean success
metas.spoil = function(self, spoil_result, spoil_ticks)
- if not feature_flags.spoiling then return end
+ if not feature_flags.spoiling then return self, false end -- spoilage is off
if not spoil_ticks then error("No spoil ticks provided for item " .. self.name) end
if type(spoil_result) == "string" then
@@ -96,7 +120,7 @@ metas.spoil = function(self, spoil_result, spoil_ticks)
self.spoil_ticks = spoil_ticks
- return self
+ return self, true
end
return metas
diff --git a/lib/metas/recipe.lua b/lib/metas/recipe.lua
index 86ada2e..c6f9cd9 100644
--- a/lib/metas/recipe.lua
+++ b/lib/metas/recipe.lua
@@ -2,32 +2,31 @@ local table_insert = table.insert
--unsafe functions overrides protections for ingredient/result existence
+local metas = {}
+
---@class data.RecipePrototype
---@field public standardize fun(self: data.RecipePrototype): data.RecipePrototype
----@field public add_unlock fun(self: data.RecipePrototype, technology_name: string | string[]): data.RecipePrototype
----@field public remove_unlock fun(self: data.RecipePrototype, technology_name: string | string[]): data.RecipePrototype
----@field public replace_unlock fun(self: data.RecipePrototype, technology_old: string | string[], technology_new: string | string[]): data.RecipePrototype
----@field public replace_ingredient fun(self: data.RecipePrototype, old_ingredient: string, new_ingredient: string | data.IngredientPrototype, new_amount: integer?): data.RecipePrototype
----@field public replace_ingredient_unsafe fun(self: data.RecipePrototype, old_ingredient: string, new_ingredient: string | data.IngredientPrototype, new_amount: integer?): data.RecipePrototype
----@field public add_ingredient fun(self: data.RecipePrototype, ingredient: data.IngredientPrototype): data.RecipePrototype
----@field public add_ingredient_unsafe fun(self: data.RecipePrototype, ingredient: data.IngredientPrototype): data.RecipePrototype
+---@field public add_unlock fun(self: data.RecipePrototype, technology_name: string | string[]): data.RecipePrototype, boolean
+---@field public remove_unlock fun(self: data.RecipePrototype, technology_name: string | string[]): data.RecipePrototype, boolean
+---@field public replace_unlock fun(self: data.RecipePrototype, technology_old: string | string[], technology_new: string | string[]): data.RecipePrototype, boolean
+---@field public replace_ingredient fun(self: data.RecipePrototype, old_ingredient: string, new_ingredient: string | data.IngredientPrototype, new_amount: integer?): data.RecipePrototype, boolean
+---@field public replace_ingredient_unsafe fun(self: data.RecipePrototype, old_ingredient: string, new_ingredient: string | data.IngredientPrototype, new_amount: integer?): data.RecipePrototype, boolean
+---@field public add_ingredient fun(self: data.RecipePrototype, ingredient: data.IngredientPrototype): data.RecipePrototype, boolean
+---@field public add_ingredient_unsafe fun(self: data.RecipePrototype, ingredient: data.IngredientPrototype): data.RecipePrototype, boolean
---@field public remove_ingredient fun(self: data.RecipePrototype, ingredient_name: string): data.RecipePrototype, integer
----@field public replace_result fun(self: data.RecipePrototype, old_result: string, new_result: string | data.ProductPrototype, new_amount: integer?): data.RecipePrototype
----@field public replace_result_unsafe fun(self: data.RecipePrototype, old_result: string, new_result: string | data.ProductPrototype, new_amount: integer?): data.RecipePrototype
----@field public add_result fun(self: data.RecipePrototype, result: data.ProductPrototype): data.RecipePrototype
----@field public remove_result fun(self: data.RecipePrototype, result_name: string): data.RecipePrototype
----@field public clear_ingredients fun(self: data.RecipePrototype): data.RecipePrototype
----@field public multiply_result_amount fun(self: data.RecipePrototype, result_name: string, percent: number): data.RecipePrototype
----@field public multiply_ingredient_amount fun(self: data.RecipePrototype, ingredient_name: string, percent: number): data.RecipePrototype
----@field public add_result_amount fun(self: data.RecipePrototype, result_name: string, increase: number): data.RecipePrototype
----@field public add_ingredient_amount fun(self: data.RecipePrototype, ingredient_name: string, increase: number): data.RecipePrototype
----@field public set_result_amount fun(self: data.RecipePrototype, result_name: string, amount: number): data.RecipePrototype
----@field public set_ingredient_amount fun(self: data.RecipePrototype, ingredient_name: string, amount: number): data.RecipePrototype
+---@field public replace_result fun(self: data.RecipePrototype, old_result: string, new_result: string | data.ProductPrototype, new_amount: integer?): data.RecipePrototype, boolean
+---@field public replace_result_unsafe fun(self: data.RecipePrototype, old_result: string, new_result: string | data.ProductPrototype, new_amount: integer?): data.RecipePrototype, boolean
+---@field public add_result fun(self: data.RecipePrototype, result: data.ProductPrototype): data.RecipePrototype, boolean
+---@field public remove_result fun(self: data.RecipePrototype, result_name: string): data.RecipePrototype, integer
+---@field public clear_ingredients fun(self: data.RecipePrototype): data.RecipePrototype, boolean
+---@field public multiply_result_amount fun(self: data.RecipePrototype, result_name: string, percent: number): data.RecipePrototype, boolean
+---@field public multiply_ingredient_amount fun(self: data.RecipePrototype, ingredient_name: string, percent: number): data.RecipePrototype, boolean
+---@field public add_result_amount fun(self: data.RecipePrototype, result_name: string, increase: number): data.RecipePrototype, boolean
+---@field public add_ingredient_amount fun(self: data.RecipePrototype, ingredient_name: string, increase: number): data.RecipePrototype, boolean
+---@field public set_result_amount fun(self: data.RecipePrototype, result_name: string, amount: number): data.RecipePrototype, boolean
+---@field public set_ingredient_amount fun(self: data.RecipePrototype, ingredient_name: string, amount: number): data.RecipePrototype, boolean
---@field public get_main_product fun(self: data.RecipePrototype, allow_multi_product: boolean?): LuaItemPrototype?|LuaFluidPrototype?
----@field public get_icons fun(self: data.RecipePrototype): data.IconData
-
-local metas = {}
-
+---@field public get_icons fun(self: data.RecipePrototype): data.IconData[]
RECIPE = setmetatable(data.raw.recipe, {
---@param recipe data.RecipePrototype
__call = function(self, recipe)
@@ -81,60 +80,84 @@ py.allow_productivity = function(recipe_names)
end
end
+---@param self data.RecipePrototype
+---@param technology_name string|string[]
+---@return data.RecipePrototype self
+---@return boolean success
metas.add_unlock = function(self, technology_name)
if type(technology_name) == "table" then
+ local success = true
for _, tech in pairs(technology_name) do
- self:add_unlock(tech)
+ local _, this_success = self:add_unlock(tech)
+ success = success and this_success -- if any addition fails, the whole check fails
end
- return self
+ return self, success
end
local technology = data.raw.technology[technology_name]
if not technology then
log("WARNING @ \'" .. self.name .. "\':add_unlock(): Technology " .. technology_name .. " does not exist")
- return self
+ return self, false -- fails, tech does not exist
end
- if not technology.effects then
- technology.effects = {}
+ technology.effects = technology.effects or {}
+
+ -- skip adding unlocks twice
+ for _, effect in pairs(technology.effects) do
+ if effect.type == "unlock-recipe" and effect.recipe == self.name then
+ return self, false -- fails, already in tech
+ end
end
table_insert(technology.effects, {type = "unlock-recipe", recipe = self.name})
self.enabled = false
- return self
+ return self, true
end
+---@param self data.RecipePrototype
+---@param technology_name string|string[]
+---@return data.RecipePrototype self
+---@return boolean success
metas.remove_unlock = function(self, technology_name)
if type(technology_name) == "table" then
+ local success = true
for _, tech in pairs(technology_name) do
- self:remove_unlock(tech)
+ local _, this_success = self:remove_unlock(tech)
+ success = success and this_success
end
- return self
+ return self, success -- if any removal fails, the whole check fails
end
local technology = data.raw.technology[technology_name]
if not technology then
log("WARNING @ \'" .. self.name .. "\':remove_unlock(): Technology " .. technology_name .. " does not exist")
- return self
+ return self, false -- fails, tech does not exist
+ elseif not technology.effects then
+ return self, false -- tech effects do not exist
end
- if not technology.effects then
- return self
+ for i, effect in pairs(technology.effects) do
+ if effect.recipe == self.name then
+ table.remove(technology.effects, i)
+ return self, true -- successfully removed recipe from tech
+ end
end
- technology.effects = table.filter(technology.effects, function(effect)
- return effect.recipe ~= self.name
- end)
-
- return self
+ return self, false -- recipe not part of tech
end
+---@param self data.RecipePrototype
+---@param technology_old string|string[]
+---@param technology_new string|string[]
+---@return data.RecipePrototype self
+---@return boolean success
metas.replace_unlock = function(self, technology_old, technology_new)
- self:remove_unlock(technology_old):add_unlock(technology_new)
+ local _, success_remove = self:remove_unlock(technology_old)
+ local _, success_add = self:add_unlock(technology_new)
- return self
+ return self, success_remove and success_add -- fails if either fails
end
do
@@ -144,7 +167,7 @@ do
if type == "string" then
if not FLUID[new] and not ITEM[new] and not unsafe then
log("WARNING @ \'" .. recipe.name .. "\':replace_ingredient(): Ingredient " .. new .. " does not exist")
- return
+ return false
end
for _, ingredient in pairs(ingredients_or_results) do
if ingredient.name == old then
@@ -164,7 +187,7 @@ do
new = table.deepcopy(new)
if not FLUID[new.name] and not ITEM[new.name] and not unsafe then
log("WARNING @ \'" .. recipe.name .. "\':replace_ingredient(): Ingredient " .. new.name .. " does not exist")
- return
+ return false
end
for k, ingredient in pairs(ingredients_or_results) do
if ingredient.name == old then
@@ -172,39 +195,68 @@ do
end
end
end
+ return true -- must have been a success! cant early return on success because of possible repeated results
end
+ ---@param self data.RecipePrototype
+ ---@param old_ingredient string
+ ---@param new_ingredient string|data.IngredientPrototype
+ ---@param new_amount? int
+ ---@return data.RecipePrototype self
+ ---@return boolean success
metas.replace_ingredient = function(self, old_ingredient, new_ingredient, new_amount)
self:standardize()
- replacement_helper(self, self.ingredients, old_ingredient, new_ingredient, new_amount, false)
- return self
+ local success = replacement_helper(self, self.ingredients, old_ingredient, new_ingredient, new_amount, false)
+ return self, success
end
+ ---@param self data.RecipePrototype
+ ---@param old_ingredient string
+ ---@param new_ingredient string|data.IngredientPrototype
+ ---@param new_amount? int
+ ---@return data.RecipePrototype self
+ ---@return boolean success
metas.replace_ingredient_unsafe = function(self, old_ingredient, new_ingredient, new_amount)
self:standardize()
- replacement_helper(self, self.ingredients, old_ingredient, new_ingredient, new_amount, true)
- return self
+ local success = replacement_helper(self, self.ingredients, old_ingredient, new_ingredient, new_amount, true)
+ return self, success
end
+ ---@param self data.RecipePrototype
+ ---@param old_result string
+ ---@param new_result string|data.ProductPrototype
+ ---@param new_amount? int
+ ---@return data.RecipePrototype self
+ ---@return boolean success
metas.replace_result = function(self, old_result, new_result, new_amount)
self:standardize()
- replacement_helper(self, self.results, old_result, new_result, new_amount, false)
+ local success = replacement_helper(self, self.results, old_result, new_result, new_amount, false)
if self.main_product == old_result then
self.main_product = type(new_result) == "string" and new_result or new_result[1] or new_result.name
end
- return self
+ return self, success
end
+ ---@param self data.RecipePrototype
+ ---@param old_result string
+ ---@param new_result string|data.ProductPrototype
+ ---@param new_amount? int
+ ---@return data.RecipePrototype self
+ ---@return boolean success
metas.replace_result_unsafe = function(self, old_result, new_result, new_amount)
self:standardize()
- replacement_helper(self, self.results, old_result, new_result, new_amount, true)
+ local success = replacement_helper(self, self.results, old_result, new_result, new_amount, true)
if self.main_product == old_result then
self.main_product = type(new_result) == "string" and new_result or new_result[1] or new_result.name
end
- return self
+ return self, success
end
end
+---@param self data.RecipePrototype
+---@param ingredient data.IngredientPrototype
+---@return data.RecipePrototype self
+---@return boolean success
metas.add_ingredient_unsafe = function(self, ingredient)
self:standardize()
-- Ensure that this ingredient does not already exist in this recipe.
@@ -213,8 +265,8 @@ metas.add_ingredient_unsafe = function(self, ingredient)
if existing.name == ingredient.name and existing.type == ingredient.type then
if existing.amount and ingredient.amount then
existing.amount = existing.amount + ingredient.amount
- existing.ignored_by_productivity = (existing.ignored_by_productivity or 0) + (ingredient.ignored_by_productivity or 0)
- return self
+ existing.ignored_by_stats = (existing.ignored_by_stats or 0) + (ingredient.ignored_by_stats or 0)
+ return self, true
end
end
end
@@ -224,25 +276,37 @@ metas.add_ingredient_unsafe = function(self, ingredient)
end
table_insert(self.ingredients, ingredient)
- return self
+ return self, true
end
+---@param self data.RecipePrototype
+---@param ingredient data.IngredientPrototype
+---@return data.RecipePrototype self
+---@return boolean success
metas.add_ingredient = function(self, ingredient)
self:standardize()
if not FLUID[ingredient.name] and not ITEM[ingredient.name] then
log("WARNING @ \'" .. self.name .. "\':add_ingredient(): Ingredient " .. ingredient.name .. " does not exist")
- return self
+ return self, false
end
return metas.add_ingredient_unsafe(self, ingredient)
end
+---@param self data.RecipePrototype
+---@param result data.ProductPrototype
+---@return data.RecipePrototype self
+---@return boolean success
metas.add_result = function(self, result)
self:standardize()
table_insert(self.results, result)
- return self
+ return self, true
end
+---@param self data.RecipePrototype
+---@param ingredient_name string
+---@return data.RecipePrototype self
+---@return int amount_removed
metas.remove_ingredient = function(self, ingredient_name)
self:standardize()
local amount_removed = 0
@@ -256,6 +320,10 @@ metas.remove_ingredient = function(self, ingredient_name)
return self, amount_removed
end
+---@param self data.RecipePrototype
+---@param result_name string
+---@return data.RecipePrototype self
+---@return int amount_removed
metas.remove_result = function(self, result_name)
self:standardize()
local amount_removed = 0
@@ -272,9 +340,19 @@ end
metas.clear_ingredients = function(self)
self.ingredients = {}
- return self
+ return self, true -- impossible to fail
+end
+
+metas.clear_results = function(self)
+ self.ingredients = {}
+ return self, true -- impossible to fail
end
+---@param self data.RecipePrototype
+---@param result_name string
+---@param percent float
+---@return data.RecipePrototype self
+---@return boolean success
metas.multiply_result_amount = function(self, result_name, percent)
self:standardize()
@@ -284,18 +362,23 @@ metas.multiply_result_amount = function(self, result_name, percent)
result.amount = math.ceil(amount * percent)
if result.amount == 0 then
self:remove_result(result_name)
- return
+ return self, true -- successful multiply
end
result.amount_min = nil
result.amount_max = nil
- return self
+ return self, true -- successful multiply
end
end
log("WARNING @ \'" .. self.name .. "\':multiply_result_amount(): Result " .. result_name .. " not found")
- return self
+ return self, false -- could not find result
end
+---@param self data.RecipePrototype
+---@param ingredient_name string
+---@param percent float
+---@return data.RecipePrototype self
+---@return boolean success
metas.multiply_ingredient_amount = function(self, ingredient_name, percent)
self:standardize()
@@ -304,77 +387,102 @@ metas.multiply_ingredient_amount = function(self, ingredient_name, percent)
ingredient.amount = math.ceil(ingredient.amount * percent)
if ingredient.amount == 0 then
self:remove_ingredient(ingredient_name)
- return
+ return self, true -- successful multiply
end
- return self
+ return self, true -- successful multiply
end
end
log("WARNING @ \'" .. self.name .. "\':multiply_ingredient_amount(): Ingredient " .. ingredient_name .. " not found")
- return self
+ return self, false -- could not find ingredient
end
+---@param self data.RecipePrototype
+---@param result_name string
+---@param increase int
+---@return data.RecipePrototype self
+---@return boolean success
metas.add_result_amount = function(self, result_name, increase)
self:standardize()
for _, result in pairs(self.results) do
if result.name == result_name then
result.amount = result.amount + increase
- if result.amount == 0 then
+ if result.amount <= 0 then
self:remove_result(result_name)
- return
+ return self, true -- successful addition
end
- return self
+ return self, true -- successful addition
end
end
log("WARNING @ \'" .. self.name .. "\':add_result_amount(): Result " .. result_name .. " not found")
- return self
+ return self, false -- could not find result
end
+---@param self data.RecipePrototype
+---@param ingredient_name string
+---@param increase int
+---@return data.RecipePrototype self
+---@return boolean success
metas.add_ingredient_amount = function(self, ingredient_name, increase)
self:standardize()
for _, ingredient in pairs(self.ingredients) do
if ingredient.name == ingredient_name then
ingredient.amount = ingredient.amount + increase
- if ingredient.amount == 0 then
+ if ingredient.amount <= 0 then
self:remove_ingredient(ingredient_name)
- return
+ return self, true -- successful addition
end
- return self
+ return self, true -- successful addition
end
end
log("WARNING @ \'" .. self.name .. "\':add_ingredient_amount(): Ingredient " .. ingredient_name .. " not found")
- return self
+ return self, false -- could not find ingredient
end
+---@param self data.RecipePrototype
+---@param result_name string
+---@param amount int
+---@return data.RecipePrototype self
+---@return boolean success
metas.set_result_amount = function(self, result_name, amount)
- self:replace_result(result_name, result_name, amount)
- return self
+ return self:replace_result(result_name, result_name, amount)
end
+---@param self data.RecipePrototype
+---@param ingredient_name string
+---@param amount int
+---@return data.RecipePrototype self
+---@return boolean success
metas.set_ingredient_amount = function(self, ingredient_name, amount)
- self:replace_ingredient(ingredient_name, ingredient_name, amount)
- return self
+ return self:replace_ingredient(ingredient_name, ingredient_name, amount)
end
+---@param self data.RecipePrototype
+---@param category_name string
+---@return data.RecipePrototype self
+---@return boolean success
metas.change_category = function(self, category_name)
self:standardize()
if data.raw["recipe-category"][category_name] then
self.category = category_name
+ return self, true -- successful set
else
log("WARNING @ \'" .. self.name .. "\':change_category(): Category " .. category_name .. " not found")
+ return self, false -- category does not exist
end
-
- return self
end
--- Get the prototype for the main_product using the same logic the game uses.
--- Set allow_multi_product to take the *first* result (not game behavior) instead of failing when a recipe has no main_product set but has multiple results.
---
Check https://lua-api.factorio.com/latest/prototypes/RecipePrototype.html#main_product for more details
+---@param self data.RecipePrototype
+---@param allow_multi_product boolean
+---@return data.ItemPrototype|data.FluidPrototype
metas.get_main_product = function(self, allow_multi_product)
self:standardize()
local target, target_type = self.main_product, "item"
@@ -430,6 +538,8 @@ end
--- Returns the icons table a recipe would use (i.e. using the item icon if the recipe prototype has no .icons/.icon set).
--- May error on malformed prototypes.
---
Check https://lua-api.factorio.com/latest/prototypes/RecipePrototype.html#icon for more details.
+---@param self data.RecipePrototype
+---@return data.IconData[]
metas.get_icons = function(self)
local icon = icons(self)
if icon then return icon end
diff --git a/lib/metas/technology.lua b/lib/metas/technology.lua
index 8961856..e6f26d0 100644
--- a/lib/metas/technology.lua
+++ b/lib/metas/technology.lua
@@ -4,8 +4,6 @@
---@field public remove_prereq fun(self, prereq_technology_name: string): data.TechnologyPrototype
---@field public remove_pack fun(self, science_pack_name: string): data.TechnologyPrototype
---@field public add_pack fun(self, science_pack_name: string): data.TechnologyPrototype
----@field dependencies string[]
-
TECHNOLOGY = setmetatable(data.raw.technology, {
---@param technology data.TechnologyPrototype
__call = function(self, technology)
@@ -29,66 +27,94 @@ metas.standardize = function(self)
if not self.unit and not self.research_trigger then self.unit = {ingredients = {}} end
self.prerequisites = self.prerequisites or {}
- self.dependencies = self.dependencies or {}
self.effects = self.effects or {}
return self
end
+---@param self data.TechnologyPrototype
+---@param prereq_technology_name string
+---@return data.TechnologyPrototype self
+---@return boolean success
metas.add_prereq = function(self, prereq_technology_name)
local prereq_technology = data.raw.technology[prereq_technology_name]
if not prereq_technology then
log("WARNING @ \'" .. self.name .. "\':add_prereq(): Technology " .. prereq_technology_name .. " does not exist")
- return self
+ return self, false -- add prereq failed
end
- if not self.prerequisites then
- self.prerequisites = {}
- end
+ self.prerequisites = self.prerequisites or {}
for _, prereq in pairs(self.prerequisites) do
if prereq == prereq_technology_name then
- return
+ return self, true -- should it be true? false? its already in the tech
end
end
self.prerequisites[#self.prerequisites + 1] = prereq_technology_name
- return self
+ return self, true -- add prereq succeeds
end
+---@param self data.TechnologyPrototype
+---@param prereq_technology_name string
+---@return data.TechnologyPrototype self
+---@return boolean success
metas.remove_prereq = function(self, prereq_technology_name)
if not self.prerequisites then
- return self
+ return self, true -- should it be true? false?
end
- self.prerequisites = table.filter(self.prerequisites, function(prereq) return prereq ~= prereq_technology_name end)
+ for i, prereq in pairs(self.prerequisites) do
+ if prereq == prereq_technology_name then
+ table.remove(self.prerequisites, i)
+ return self, true -- remove prereq succeeds
+ end
+ end
- return self
+ return self, false -- remove prereq fails
end
+---@param self data.TechnologyPrototype
+---@param science_pack_name string
+---@return data.TechnologyPrototype self
+---@return boolean success
metas.remove_pack = function(self, science_pack_name)
if not self.unit then
- return self
+ return self, true -- should it be true? false?
end
- self.unit.ingredients = table.filter(self.unit.ingredients, function(ingredient) return ingredient[1] ~= science_pack_name end)
+ for i, ingredient in pairs(self.unit.ingredients) do
+ if ingredient[1] == science_pack_name then
+ table.remove(self.unit.ingredients, i)
+ return self, true -- remove pack succeeds
+ end
+ end
- return self
+ return self, false -- remove pack fails
end
+-- possible to add the same pack twice, should probably check for that
+---@param self data.TechnologyPrototype
+---@param science_pack_name string
+---@return data.TechnologyPrototype self
+---@return boolean success
metas.add_pack = function(self, science_pack_name)
if self.research_trigger then
error("WARNING @ \'" .. self.name .. "\':add_pack(): Attempted to add science packs to technology with research_trigger.")
end
- if not self.unit then
- self.unit = {ingredients = {}}
+ self.unit = self.unit or {ingredients = {}}
+
+ for _, ingredient in pairs(self.unit.ingredients) do
+ if ingredient[1] == science_pack_name then
+ return self, true -- add pack fails, it already exists
+ end
end
table.insert(self.unit.ingredients, {science_pack_name, 1})
- return self
+ return self, true -- add pack succeeds
end
return metas
diff --git a/lib/metas/tile.lua b/lib/metas/tile.lua
index 78be897..6a9d935 100644
--- a/lib/metas/tile.lua
+++ b/lib/metas/tile.lua
@@ -1,3 +1,4 @@
+---@class data.TilePrototype
TILE = setmetatable(data.raw.tile, {
---@param tile data.TilePrototype
__call = function(self, tile)