Module:Recipe

local recipe = {}

-- Load modules local iter = require("Module:Functional").iter

local data = require("Module:Data") local item = require("Module:Item")

local CargoUtils = require("Module:CargoUtils") local DurationConverter = require("Module:DurationConverter")

-- Recipe-related constants local RARITIES = table.concat(iter(data.RARITY_COLORS):keys:totable, ',')

-- Mixin that enables storage of an entity's material costs -- This uses the property _materials local EntityMaterialsMixin = {} recipe.EntityMaterialsMixin = EntityMaterialsMixin

-- Gets all of the entity's material costs. -- The result is a table { { ["item"] = item, ["amount"] = amount } }, which may be empty. function EntityMaterialsMixin:getMaterials local materials_table = recipe.getMaterialsTableFor(self.class.name) local materials = materials_table:query{ where = string.format("_pageName = %s", self._pageName) } -- Cache query result if not self._materials then self._materials = totable(iter(contains):map(function (v) return { item = v.item, amount = v.amount, }		end)) end return mw.clone(self._materials) end

-- Creates a table that stores material cost information of an entity. -- There should be at most one instance of said entity per page. function recipe.getMaterialsTableFor(entity_type) return CargoUtils.CargoTable(string.format("%sMaterials", entity_type),		{			["item"] = { "String", { mandatory = true }, { "NOT NULL" } },			["amount"] = { "List of Integer" },		},		nil,		{			["_pageName"] = { entity_type, "_pageName" },		}) end

-- Represents a recipe in the game. local Recipe = data.Entity:subclass("Recipe"):include(EntityMaterialsMixin) recipe.Recipe = Recipe

Recipe.static.ATTRIBUTE_TABLE = CargoUtils.CargoTable("Recipe",	{		["name"] = { "String", { mandatory = true }, { "NOT NULL" } },		["image"] = { "File", { mandatory = true }, { "NOT NULL" } },		["rarity"] = { "String", { mandatory = true, ["allowed values"] = RARITIES }, { "NOT NULL" } },		["prereq_items"] = { "List of Page" },		["prereq_researches"] = { "List  of Page" },		["prereq_blueprints"] = { "List  of Page" },		["craft_helium_3"] = { "Integer" },		["craft_mineral_ore"] = { "Integer" },		["craft_antimatter"] = { "Integer" },		["craft_seconds"] = { "Integer" },	},	{ "_pageName" },	{		["prereq_items"] = { "Item", "_pageName" },		["prereq_researches"] = { "Research", "_pageName" },		["prereq_blueprints"] = { "Blueprint", "_pageName" },	})

-- Relationship-related tables Recipe.static.RELATIONAL_TABLES = { ["RecipeMaterials"] = recipe.getMaterialsTableFor("Recipe"), }

-- Static methods -- -- Returns a new Recipe instance with properties according to the record stored in the given page. function Recipe.static:fromPageName(fullpagename) assert(type(fullpagename) == type(""), "`fullpagename` must be a string") local query_args = {where = string.format("_pageName = '%s'", fullpagename)} return Recipe(self.ATTRIBUTE_TABLE:query(query_args, true)[1]) end

-- Module call from Template:Recipe Definition -- Takes in one parameter - the name of the Cargo table. If not given, declares -- `ATTRIBUTE_TABLE`. function recipe.declareTable( frame ) local args = require("Module:Args").getCleanArgs local name = args[1] local cargo_table if name then cargo_table = assert(Recipe.RELATIONAL_TABLES[name], string.format("The Cargo table '%s' is not registered in this module", name)) else cargo_table = Recipe.ATTRIBUTE_TABLE end return cargo_table:declare(frame) end

-- Module call from Template:Recipe Definition function recipe.define( frame ) local args = require("Module:Args").getCleanArgs if (args.prereq_items) then args.prereq_items = table.concat(iter(mw.text.split(args.prereq_items, '%s*,%s*')):map(function (e) return "Item:" .. e end):totable, ',') end if (args.prereq_researches) then args.prereq_researches = table.concat(iter(mw.text.split(args.prereq_researches, '%s*,%s*')):map(function (e) return "Research:" .. e end):totable, ',') end if (args.prereq_blueprints) then args.prereq_blueprints = table.concat(iter(mw.text.split(args.prereq_blueprints, '%s*,%s*')):map(function (e) return "Blueprint:" .. e end):totable, ',') end assert(args.materials == nil, "The argument `materials` is not allowed in the item definition. Use Template:Recipe Definition/materials instead.") if (args.craft_time) then args.craft_seconds = tostring(DurationConverter.durationToSeconds(args.craft_time)) args.craft_time = nil end

local recipe_to_store = Recipe(args) local store = recipe_to_store:storeToTable(Recipe.ATTRIBUTE_TABLE) return store .. tostring(recipe_to_store:generateInfobox) end

-- Module call from Template:Recipe Definition/materials function recipe.appendMaterials( frame ) local args = require("Module:Args").getCleanArgs local RecipeMaterialsCargoTable = Recipe.RELATIONAL_TABLES["RecipeMaterials"] local stores = iter(args):map(function (item, amount)		return RecipeMaterialsCargoTable:store{			["item"] = "Item:" .. item,			["amount"] = amount,		}	end):totable return table.concat(stores, '') end

-- Module call from Template:Recipe Infobox function recipe.generateInfobox( frame ) local args = require("Module:Args").getCleanArgs local fullpagename = "Recipe:" .. assert(args.full_name, "Missing argument `full_name`") local general_only = args.general_only local no_categories = args.no_categories return Recipe:fromPageName(fullpagename):generateInfobox(general_only, no_categories) end

return recipe