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
|