diff --git a/cf-lib/data/Recipe.lua b/cf-lib/data/Recipe.lua new file mode 100644 index 0000000..17ba8c0 --- /dev/null +++ b/cf-lib/data/Recipe.lua @@ -0,0 +1,153 @@ +---- Utility class for a single recipe +---- @class Recipe +local Recipe = {} + +---- Pass a recipe name or a recipe table to get a Recipe object +---- @param value string|table The name of the recipe or the recipe table +function Recipe:new(value) + local name + local recipe + + if type(value) == "string" then + name = value + recipe = data.raw.recipe[name] + elseif type(value) == "table" then + name = value.name + recipe = value + end + + if not recipe then + log("Recipe not found: " .. name) + return nil + end + + local obj = { + prototype = recipe + } + + setmetatable(obj, self) + self.__index = self + return obj +end + +---- Applies the recipe to the game +function Recipe:apply() + data:extend({ self.prototype }) +end + +---- Assigns data to the recipe +---- Shorthand for table.assign(recipe.prototype, data) +---- @param data table The data to assign +function Recipe:assign(data) + table.assign(self.prototype, data) +end + +--- Adds an ingredient to the recipe +--- @param ingredientName string The name of the ingredient +--- @param amount number The amount of the ingredient +function Recipe:addIngredient(ingredientName, amount) + local ingredientType = data.raw.item[ingredientName] and "item" + or data.raw.module[ingredientName] and "item" + or data.raw.fluid[ingredientName] and "fluid" + or nil + if not ingredientType then + log("Unknown ingredient: " .. ingredientName) + return + end + self.prototype.ingredients = self.prototype.ingredients or {} + for _, ingredient in pairs(self.prototype.ingredients) do + if ingredient.name == ingredientName then + ingredient.amount = amount + ingredient.amount_min = nil + ingredient.amount_max = nil + ingredient.probability = nil + return + end + end + table.insert(self.prototype.ingredients, { name = ingredientName, amount = amount, type = ingredientType }) +end + +--- Replaces an existing ingredient by name with a new ingredient or adjusts the amount +--- @param old string The name of the existing ingredient +--- @param new? string The name of the new ingredient +--- @param amount? number The amount of the new ingredient +function Recipe:replaceIngredient(old, new, amount) + if type(new) == "number" then + amount = new + new = old + end + if self.prototype.ingredients then + for _, result in pairs(self.prototype.ingredients) do + if result.name == old then + result.name = new + result.amount = amount or result.amount + return + end + end + end +end + +--- Removes an existing ingredient by name +--- @param ingredientName string The name of the ingredient +function Recipe:removeIngredient(ingredientName) + if self.prototype.ingredients then + for i, result in pairs(self.prototype.ingredients) do + if result.name == ingredientName then + self.prototype.ingredients[i] = nil + return + end + end + end +end + +--- Replaces an existing result by name with a new result +--- @param old string The name of the existing result +--- @param new? string The name of the new result +--- @param amount? number The amount of the new result (keeps the old value if not set) +--- @param expensiveAmount? number The amount of the new result for the expensive recipe (uses amount if not set) +function Recipe:replaceResult(old, new, amount, expensiveAmount) + if type(new) == "number" then + expensiveAmount = amount + amount = new + new = old + end + if self.prototype.results then + for _, result in pairs(self.prototype.results) do + if result.name == old then + result.name = new + result.amount = amount or result.amount + end + end + if table.main_product == old then + table.main_product = new + end + end +end + +--- Adds the recipe to a technology +--- @param technology string|table The name of the technology or the technology table +function Recipe:unlockedByTechnology(technology) + if not technology then + return + end + technology = type(technology) == "table" and technology or data.raw.technology[technology] + if (not technology.effects) then + technology.effects = {} + end + for _, effect in pairs(technology.effects) do + if effect.type == "unlock-recipe" and effect.recipe == self.prototype.name then + return + end + end + table.insert(technology.effects, { type = "unlock-recipe", recipe = self.prototype.name }) +end + +---- Clones the recipe +---- @param name string The name of the new recipe +function Recipe:clone(name) + local clone = table.deepcopy(self.prototype) + clone.name = name + return Recipe:new(clone) +end + +return Recipe \ No newline at end of file diff --git a/cf-lib/data/Technology.lua b/cf-lib/data/Technology.lua index 88b947f..2c641d5 100644 --- a/cf-lib/data/Technology.lua +++ b/cf-lib/data/Technology.lua @@ -59,6 +59,7 @@ end --- @param prerequisite string|table The name of the prerequisite or the prerequisite Technology instance function Technology:addPrerequisite(prerequisite) local _prerequisite = prerequisiteName(prerequisite) + self.prototype.prerequisites = self.prototype.prerequisites or {} if (not table.contains(self.prototype.prerequisites, _prerequisite)) then table.insert(self.prototype.prerequisites, _prerequisite) end @@ -67,6 +68,7 @@ end --- Adds multiple prerequisites to the technology --- @param prerequisites table The names of the prerequisite or the prerequisite Technology instances function Technology:addPrerequisites(prerequisites) + self.prototype.prerequisites = self.prototype.prerequisites or {} for _, prerequisite in pairs(prerequisites) do local _prerequisite = prerequisiteName(prerequisite) if (not table.contains(self.prototype.prerequisites, _prerequisite)) then