428 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			428 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| --- Recipe class
 | |
| -- @classmod Data.Recipe
 | |
| 
 | |
| local Data = require('__stdlib__/stdlib/data/data')
 | |
| local Table = require('__stdlib__/stdlib/utils/table')
 | |
| 
 | |
| local Recipe = {
 | |
|     __class = 'Recipe',
 | |
|     __index = Data,
 | |
| }
 | |
| 
 | |
| function Recipe:__call(recipe)
 | |
|     local new = self:get(recipe, 'recipe')
 | |
|     -- rawset(new, 'Ingredients', {})
 | |
|     -- rawset(new, 'Results', {})
 | |
|     return new
 | |
| end
 | |
| setmetatable(Recipe, Recipe)
 | |
| 
 | |
| -- Returns a formated ingredient or prodcut table
 | |
| local function format(ingredient, result_count)
 | |
|     local Item = require('__stdlib__/stdlib/data/item')
 | |
|     local object
 | |
|     if type(ingredient) == 'table' then
 | |
|         if ingredient.valid and ingredient:is_valid() then
 | |
|             return ingredient
 | |
|         elseif ingredient.name then
 | |
|             if Item(ingredient.name, ingredient.type):is_valid() then
 | |
|                 object = Table.deepcopy(ingredient)
 | |
|                 if not object.amount and not (object.amount_min and object.amount_max and object.probability) then
 | |
|                     error('Result table requires amount or probabilities')
 | |
|                 end
 | |
|             end
 | |
|         elseif #ingredient > 0 then
 | |
|             -- Can only be item types not fluid
 | |
|             local item = Item(ingredient[1])
 | |
|             if item:is_valid() and item.type ~= 'fluid' then
 | |
|                 object = {
 | |
|                     type = 'item',
 | |
|                     name = ingredient[1],
 | |
|                     amount = ingredient[2] or 1
 | |
|                 }
 | |
|             end
 | |
|         end
 | |
|     elseif type(ingredient) == 'string' then
 | |
|         -- Our shortcut so we need to check it
 | |
|         local item = Item(ingredient)
 | |
|         if item:is_valid() then
 | |
|             object = {
 | |
|                 type = item.type == 'fluid' and 'fluid' or 'item',
 | |
|                 name = ingredient,
 | |
|                 amount = result_count or 1
 | |
|             }
 | |
|         end
 | |
|     end
 | |
|     return object
 | |
| end
 | |
| 
 | |
| -- Format items for difficulties
 | |
| -- If expensive is a boolean then return a copy of normal for expensive
 | |
| local function get_difficulties(normal, expensive)
 | |
|     return format(normal), format((expensive == true and Table.deepcopy(normal)) or expensive)
 | |
| end
 | |
| 
 | |
| --- Remove an ingredient from an ingredients table.
 | |
| -- @tparam table ingredients
 | |
| -- @tparam string name Name of the ingredient to remove
 | |
| local function remove_ingredient(ingredients, name)
 | |
|     name = name.name
 | |
|     for i, ingredient in pairs(ingredients or {}) do
 | |
|         if ingredient[1] == name or ingredient.name == name then
 | |
|             ingredients[i] = nil
 | |
|             return true
 | |
|         end
 | |
|     end
 | |
| end
 | |
| 
 | |
| --- Replace an ingredient.
 | |
| -- @tparam table ingredients Ingredients table
 | |
| -- @tparam string find ingredient to replace
 | |
| -- @tparam concepts.ingredient replace
 | |
| -- @tparam boolean replace_name_only Don't replace amounts
 | |
| local function replace_ingredient(ingredients, find, replace, replace_name_only)
 | |
|     for i, ingredient in pairs(ingredients or {}) do
 | |
|         if ingredient[1] == find or ingredient.name == find then
 | |
|             if replace_name_only then
 | |
|                 local amount = ingredient[2] or ingredient.amount
 | |
|                 replace.amount = amount
 | |
|             end
 | |
|             ingredients[i] = replace
 | |
|             return true
 | |
|         end
 | |
|     end
 | |
| end
 | |
| 
 | |
| --- Add an ingredient to a recipe.
 | |
| -- @tparam string|Concepts.ingredient normal
 | |
| -- @tparam[opt] string|Concepts.ingredient|boolean expensive
 | |
| -- @treturn Recipe
 | |
| function Recipe:add_ingredient(normal, expensive)
 | |
|     if self:is_valid() then
 | |
|         normal, expensive = get_difficulties(normal, expensive)
 | |
| 
 | |
|         if self.normal then
 | |
|             if normal then
 | |
|                 self.normal.ingredients = self.normal.ingredients or {}
 | |
|                 self.normal.ingredients[#self.normal.ingredients + 1] = normal
 | |
|             end
 | |
|             if expensive then
 | |
|                 self.expensive.ingredients = self.expensive.ingredients or {}
 | |
|                 self.expensive.ingredients[#self.expensive.ingredients + 1] = expensive
 | |
|             end
 | |
|         elseif normal then
 | |
|             self.ingredients = self.ingredients or {}
 | |
|             self.ingredients[#self.ingredients + 1] = normal
 | |
|         end
 | |
|     end
 | |
|     return self
 | |
| end
 | |
| Recipe.add_ing = Recipe.add_ingredient
 | |
| 
 | |
| --- Remove one ingredient completely.
 | |
| -- @tparam string normal
 | |
| -- @tparam string|boolean expensive expensive recipe to remove, or if true remove normal recipe from both
 | |
| -- @treturn Recipe
 | |
| function Recipe:remove_ingredient(normal, expensive)
 | |
|     if self:is_valid() then
 | |
|         normal, expensive = get_difficulties(normal, expensive)
 | |
|         if self.normal then
 | |
|             if normal then
 | |
|                 remove_ingredient(self.normal.ingredients, normal)
 | |
|             end
 | |
|             if expensive then
 | |
|                 remove_ingredient(self.expensive.ingredients, expensive)
 | |
|             end
 | |
|         elseif normal then
 | |
|             remove_ingredient(self.ingredients, normal)
 | |
|         end
 | |
|     end
 | |
|     return self
 | |
| end
 | |
| Recipe.rem_ing = Recipe.remove_ingredient
 | |
| 
 | |
| --- Replace one ingredient with another.
 | |
| -- @tparam string replace
 | |
| -- @tparam string|ingredient normal
 | |
| -- @tparam[opt] string|ingredient|boolean expensive
 | |
| function Recipe:replace_ingredient(replace, normal, expensive)
 | |
|     assert(replace, 'Missing recipe to replace')
 | |
|     if self:is_valid() then
 | |
|         local n_string = type(normal) == 'string'
 | |
|         local e_string = type(expensive == true and normal or expensive) == 'string'
 | |
|         normal, expensive = get_difficulties(normal, expensive)
 | |
|         if self.normal then
 | |
|             if normal then
 | |
|                 replace_ingredient(self.normal.ingredients, replace, normal, n_string)
 | |
|             end
 | |
|             if expensive then
 | |
|                 replace_ingredient(self.expensive.ingredients, replace, expensive, e_string)
 | |
|             end
 | |
|         elseif normal then
 | |
|             replace_ingredient(self.ingredients, replace, normal, n_string)
 | |
|         end
 | |
|     end
 | |
|     return self
 | |
| end
 | |
| Recipe.rep_ing = Recipe.replace_ingredient
 | |
| 
 | |
| -- Currently does no checking
 | |
| function Recipe:clear_ingredients()
 | |
|     if self:is_valid() then
 | |
|         if self.normal then
 | |
|             if self.normal.ingredients then
 | |
|                 self.normal.ingredients = {}
 | |
|             end
 | |
|             if self.expensive.ingredients then
 | |
|                 self.expensive.ingredients = {}
 | |
|             end
 | |
|         elseif self.ingredients then
 | |
|             self.ingredients = {}
 | |
|         end
 | |
|     end
 | |
|     return self
 | |
| end
 | |
| 
 | |
| --- Converts a recipe to the difficulty recipe format.
 | |
| -- @tparam[opt] number expensive_energy crafting energy_required for the expensive recipe
 | |
| -- @treturn self
 | |
| function Recipe:make_difficult(expensive_energy)
 | |
|     if self:is_valid('recipe') and not self.normal then
 | |
|         --convert all ingredients
 | |
|         local normal, expensive = {}, {}
 | |
|         for _, ingredient in ipairs(self.ingredients) do
 | |
|             local this = format(ingredient)
 | |
|             normal[#normal + 1] = this
 | |
|             expensive[#expensive + 1] = Table.deepcopy(this)
 | |
|         end
 | |
| 
 | |
|         local r_normal, r_expensive = {}, {}
 | |
|         for _, ingredient in ipairs(self.results or { self.result }) do
 | |
|             local this = format(ingredient)
 | |
|             r_normal[#r_normal + 1] = this
 | |
|             r_expensive[#r_expensive + 1] = Table.deepcopy(this)
 | |
|         end
 | |
| 
 | |
|         self.normal = {
 | |
|             enabled = self.enabled,
 | |
|             energy_required = self.energy_required,
 | |
|             ingredients = normal,
 | |
|             results = r_normal,
 | |
|             main_product = self.main_product
 | |
|         }
 | |
|         self.expensive = {
 | |
|             enabled = self.enabled,
 | |
|             energy_required = expensive_energy or self.energy_required,
 | |
|             ingredients = expensive,
 | |
|             results = r_expensive,
 | |
|             main_product = self.main_product
 | |
|         }
 | |
| 
 | |
|         self.ingredients = nil
 | |
|         self.result = nil
 | |
|         self.results = nil
 | |
|         self.result_count = nil
 | |
|         self.energy_required = nil
 | |
|         self.enabled = nil
 | |
|         self.main_product = nil
 | |
|     end
 | |
|     return self
 | |
| end
 | |
| 
 | |
| --- Change the recipe category.
 | |
| -- @tparam string category_name The new crafting category
 | |
| -- @treturn self
 | |
| function Recipe:change_category(category_name)
 | |
|     if self:is_valid() then
 | |
|         local Category = require('__stdlib__/stdlib/data/category')
 | |
|         self.category = Category(category_name, 'recipe-category'):is_valid() and category_name or self.category
 | |
|     end
 | |
|     return self
 | |
| end
 | |
| Recipe.set_category = Recipe.change_category
 | |
| 
 | |
| --- Add to technology as a recipe unlock.
 | |
| -- @tparam string tech_name Name of the technology to add the unlock too
 | |
| -- @treturn self
 | |
| function Recipe:add_unlock(tech_name)
 | |
|     if self:is_valid() then
 | |
|         local Tech = require('__stdlib__/stdlib/data/technology')
 | |
|         Tech.add_effect(self, tech_name) --self is passed as a valid recipe
 | |
|     end
 | |
|     return self
 | |
| end
 | |
| 
 | |
| --- Remove the recipe unlock from the technology.
 | |
| -- @tparam string tech_name Name of the technology to remove the unlock from
 | |
| -- @treturn self
 | |
| function Recipe:remove_unlock(tech_name)
 | |
|     if self:is_valid('recipe') then
 | |
|         local Tech = require('__stdlib__/stdlib/data/technology')
 | |
|         Tech.remove_effect(self, tech_name, 'unlock-recipe')
 | |
|     end
 | |
|     return self
 | |
| end
 | |
| 
 | |
| --- Set the enabled status of the recipe.
 | |
| -- @tparam boolean enabled Enable or disable the recipe
 | |
| -- @treturn self
 | |
| function Recipe:set_enabled(enabled)
 | |
|     if self:is_valid() then
 | |
|         if self.normal then
 | |
|             self.normal.enabled = enabled
 | |
|             self.expensive.enabled = enabled
 | |
|         else
 | |
|             self.enabled = enabled
 | |
|         end
 | |
|     end
 | |
|     return self
 | |
| end
 | |
| 
 | |
| --- Convert result type to results type.
 | |
| -- @treturn self
 | |
| function Recipe:convert_results()
 | |
|     if self:is_valid('recipe') then
 | |
|         if self.normal then
 | |
|             if self.normal.result then
 | |
|                 self.normal.results = {
 | |
|                     format(self.normal.result, self.normal.result_count or 1)
 | |
|                 }
 | |
|                 self.normal.result = nil
 | |
|                 self.normal.result_count = nil
 | |
|             end
 | |
|             if self.expensive.result then
 | |
|                 self.expensive.results = {
 | |
|                     format(self.expensive.result, self.expensive.result_count or 1)
 | |
|                 }
 | |
|                 self.expensive.result = nil
 | |
|                 self.expensive.result_count = nil
 | |
|             end
 | |
|         elseif self.result then
 | |
|             self.results = {
 | |
|                 format(self.result, self.result_count or 1)
 | |
|             }
 | |
|             self.result = nil
 | |
|             self.result_count = nil
 | |
|         end
 | |
|     end
 | |
|     return self
 | |
| end
 | |
| 
 | |
| --- Set the main product of the recipe.
 | |
| -- @tparam string|boolean main_product if boolean then use normal/expensive recipes passed as main product
 | |
| -- @tparam[opt] Concepts.Product|string normal recipe
 | |
| -- @tparam[opt] Concepts.Product|string expensive recipe
 | |
| -- @treturn self
 | |
| function Recipe:set_main_product(main_product, normal, expensive)
 | |
|     if self:is_valid('recipe') then
 | |
|         normal, expensive = get_difficulties(normal, expensive)
 | |
|         local normal_main, expensive_main
 | |
|         if main_product then
 | |
|             local Item = require('__stdlib__/stdlib/data/item')
 | |
|             if type(main_product) == 'string' and Item(main_product):is_valid() then
 | |
|                 normal_main = normal and main_product
 | |
|                 expensive_main = expensive and main_product
 | |
|             elseif type(main_product) == 'boolean' then
 | |
|                 normal_main = normal and Item(normal.name):is_valid() and normal.name
 | |
|                 expensive_main = expensive and Item(expensive.name):is_valid() and expensive.name
 | |
|             end
 | |
|             if self.normal then
 | |
|                 self.normal.main_product = normal_main
 | |
|                 self.expensive.main_product = expensive_main
 | |
|             else
 | |
|                 self.main_product = normal_main
 | |
|             end
 | |
|         end
 | |
|     end
 | |
|     return self
 | |
| end
 | |
| 
 | |
| --- Remove the main product of the recipe.
 | |
| -- @tparam[opt=false] boolean for_normal
 | |
| -- @tparam[opt=false] boolean for_expensive
 | |
| function Recipe:remove_main_product(for_normal, for_expensive)
 | |
|     if self:is_valid('recipe') then
 | |
|         if self.normal then
 | |
|             if for_normal or (for_normal == nil and for_expensive == nil) then
 | |
|                 self.normal.main_product = nil
 | |
|             end
 | |
|             if for_expensive or (for_normal == nil and for_expensive == nil) then
 | |
|                 self.expensive.main_product = nil
 | |
|             end
 | |
|         elseif for_normal or (for_normal == nil and for_expensive == nil) then
 | |
|             self.main_product = nil
 | |
|         end
 | |
|     end
 | |
|     return self
 | |
| end
 | |
| 
 | |
| --- Add a new product to results, converts if needed.
 | |
| -- @tparam string|Concepts.product normal
 | |
| -- @tparam[opt] string|Concepts.product|boolean expensive
 | |
| -- @tparam[opt] string main_product
 | |
| function Recipe:add_result(normal, expensive, main_product)
 | |
|     if self:is_valid() then
 | |
|         normal, expensive = get_difficulties(normal, expensive)
 | |
|         self:convert_results()
 | |
|         self:set_main_product(main_product, normal, expensive)
 | |
| 
 | |
|         -- if self.normal then
 | |
|         --     if normal then
 | |
|         --     end
 | |
|         --     if expensive then
 | |
|         --     end
 | |
|         -- elseif normal then
 | |
|         -- end
 | |
|     end
 | |
|     return self
 | |
| end
 | |
| 
 | |
| --- Remove a product from results, converts if needed.
 | |
| -- @tparam[opt] string|Concepts.product normal
 | |
| -- @tparam[opt] string|Concepts.product|boolean expensive
 | |
| -- @tparam[opt] string main_product new main_product to use
 | |
| function Recipe:remove_result(normal, expensive, main_product)
 | |
|     if self:is_valid() then
 | |
|         normal, expensive = get_difficulties(normal, expensive)
 | |
|         self:convert_results()
 | |
|         self:set_main_product(main_product, normal, expensive)
 | |
| 
 | |
|         -- if self.normal then
 | |
|         --     if normal then
 | |
|         --     end
 | |
|         --     if expensive then
 | |
|         --     end
 | |
|         -- elseif normal then
 | |
|         -- end
 | |
|     end
 | |
|     return self
 | |
| end
 | |
| 
 | |
| --- Remove a product from results, converts if needed.
 | |
| -- @tparam string|Concepts.product result_name
 | |
| -- @tparam[opt] string|Concepts.product normal
 | |
| -- @tparam[opt] string|Concepts.product|boolean expensive
 | |
| -- @tparam[opt] string main_product
 | |
| function Recipe:replace_result(result_name, normal, expensive, main_product)
 | |
|     if self:is_valid() and normal or expensive then
 | |
|         result_name = format(result_name)
 | |
|         if result_name then
 | |
|             normal, expensive = get_difficulties(normal, expensive)
 | |
|             self:convert_results()
 | |
|             self:remove_result(result_name, expensive and result_name)
 | |
|             self:set_main_product(main_product, normal, expensive)
 | |
| 
 | |
|             -- if self.normal then
 | |
|             --     if normal then
 | |
|             --     end
 | |
|             --     if expensive then
 | |
|             --     end
 | |
|             -- elseif normal then
 | |
|             -- end
 | |
|         end
 | |
|     end
 | |
|     return self
 | |
| end
 | |
| 
 | |
| return Recipe
 |