Module:Recipe: Difference between revisions

From Against the Storm Official Wiki
debugging; maybe solved? # operator doesn't work on arrays loaded from mw.loadData!
m fixed more uses of # operator
Line 99: Line 99:
end
end


-- Gets the number of ingredient slots in the recipe.
-- Gets the number of ingredient slots in the recipe.<br>
-- This *must* loop over the array due to MediaWiki's metatables on data loaded with `mw.loadData` messing with `#` operator.
---@param recipe Recipe
---@param recipe Recipe
---@return integer
---@return integer
Line 113: Line 114:
end
end


-- Gets the number of options for the given ingredient slot.
-- Gets the number of options for the given ingredient slot.<br>
-- This *must* loop over the array due to MediaWiki's metatables on data loaded with `mw.loadData` messing with `#` operator.
---@param recipe Recipe
---@param recipe Recipe
---@param slotIndex integer
---@param slotIndex integer
Line 133: Line 135:
function Recipe.getBuildings(recipe)
function Recipe.getBuildings(recipe)
return recipe._buildings
return recipe._buildings
end
-- Gets the number of buildings that can make the recipe.<br>
-- This *must* loop over the array due to MediaWiki's metatables on data loaded with `mw.loadData` messing with `#` operator.
---@param recipe Recipe
---@return integer
function Recipe.getNumBuildings(recipe)
if not recipe._buildings then
error("Recipe.getNumBuildings cannot work with nil array.")
end
local count = 0
for _ in ipairs(recipe._buildings) do
count = count + 1
end
return count
end
end



Revision as of 16:52, 3 November 2025

Documentation for this module may be created at Module:Recipe/doc

-- Provides a standard way of interacting with recipe data.
local Recipe = {}

-- A single recipe with one product, one grade, and one stack; possibly in more than one building.
---@class Recipe
---@field package _buildings BuildingID[] The ID codes of buildings that can make this recipe.
---@field package _grade Grade How many efficiency stars (0-3) the recipe has.
---@field package _time number Seconds to produce one product.
---@field package _productPair ProductPair The product and amount of it produced.
---@field package _isService boolean `true` if this recipe offers a service instead of a product.
---@field package _extraProductChances? ExtraProductChance[] Possible extra products for each cycle, if any, before any upgrades.
---@field package _ingredients IngredientSlot[] Ingredient slots (0-3, usually 1-2), each with multiple option choices.

-- Array of (usually 1-6, can be 8) interchangeable options for one ingredient slot in a recipe.
---@alias IngredientSlot IngredientOption[]
-- One acceptable option of good to use in the recipe.
---@alias IngredientOption ResourcePair

-- Recipes sorted by [productID][grade][stackSize].
---@alias RecipeBook table<ProductID, RecipeListByGrade>
-- Subset of recipes sorted by [grade][stackSize] (sparse: only existing grades present).<br>
-- Use `pairs()` to iterate, not `ipairs()`.<br>
-- For sorting, extract keys, then sort, then iterate.
---@alias RecipeListByGrade table<Grade, RecipeSublistByStacksize>
-- Subsubset of recipes sorted by [stackSize] (sparse: only existing stack sizes present).<br>
-- Use `pairs()` to iterate, not `ipairs()`.<br>
-- For sorting, extract keys, then sort, then iterate.
---@alias RecipeSublistByStacksize table<integer, Recipe>

-- The ID and amount of a good or service made.
---@alias ProductPair ResourcePair

-- The ID, amount, and probability of an extra product.
---@alias ExtraProductChance {_id: ProductID, _amount: integer, _chance: number}

-- The ID of a good or service produced.
---@alias ProductID ResourceID

-- A number 0, 1, 2, or 3 (worst to best) of a recipe indicating its efficiency, effectiveness, or capability.
---@alias Grade 0|1|2|3



--#region Public Methods

-- Adds the given building ID to the recipe's list of buildings that can make it.
---@param recipe Recipe
---@param buildingID BuildingID
---@return BuildingID[] buildings
function Recipe.addBuilding(recipe, buildingID)
	table.insert(recipe._buildings, buildingID)
	return recipe._buildings
end

-- Checks if the given ingredient is anywhere in the recipe's ingredient options.
---@param recipe Recipe
---@param ingredientID ResourceID
---@return boolean
---@return integer|nil slotIndex
---@return integer|nil optionIndex
function Recipe.isIngredientInOptions(recipe, ingredientID)
	if not recipe then error("Cannot find ingredient in nil recipe") end
	if not ingredientID then error("Cannot find ingredient using nil ingredientID") end
	for slotIndex, slot in ipairs(recipe._ingredients) do
		for optionIndex, option in ipairs(slot) do
			if option._id == ingredientID then
				return true, slotIndex, optionIndex
			end
		end
	end
	return false, nil, nil
end

-- Gets the array of ingredient options for the given slot.
---@param recipe Recipe
---@param slotIndex integer
---@return IngredientOption[]
function Recipe.getIngredientOptions(recipe, slotIndex)
	return recipe._ingredients[slotIndex]
end

-- Gets the ingredient at the given slot and option index, both the ID and amount.
---@param recipe Recipe
---@param slotIndex integer
---@param optionIndex integer
---@return ResourceID
---@return integer # amount
function Recipe.getIngredient(recipe, slotIndex, optionIndex)
	local ingredientPair = recipe._ingredients[slotIndex][optionIndex]
	return ingredientPair._id, ingredientPair._amount
end

-- Gets the product of the recipe, both the ID and amount.
---@param recipe Recipe
---@return ProductID
---@return integer # amount
function Recipe.getProduct(recipe)
	return recipe._productPair._id, recipe._productPair._amount
end

-- Gets the number of ingredient slots in the recipe.<br>
-- This *must* loop over the array due to MediaWiki's metatables on data loaded with `mw.loadData` messing with `#` operator.
---@param recipe Recipe
---@return integer
function Recipe.getNumIngredients(recipe)
	if not recipe._ingredients then
		error("Recipe.getNumIngredients cannot work with nil array.")
	end
	local count = 0
	for _ in ipairs(recipe._ingredients) do
		count = count + 1
	end
	return count
end

-- Gets the number of options for the given ingredient slot.<br>
-- This *must* loop over the array due to MediaWiki's metatables on data loaded with `mw.loadData` messing with `#` operator.
---@param recipe Recipe
---@param slotIndex integer
---@return integer
function Recipe.getNumOptions(recipe, slotIndex)
	if not recipe._ingredients then
		error("Recipe.getNumOptions cannot work with nil array.")
	end
	local count = 0
	for _ in ipairs(recipe._ingredients[slotIndex]) do
		count = count + 1
	end
	return count
end

-- Gets the array of buildings that can make the recipe.
---@param recipe Recipe
---@return BuildingID[]
function Recipe.getBuildings(recipe)
	return recipe._buildings
end

-- Gets the number of buildings that can make the recipe.<br>
-- This *must* loop over the array due to MediaWiki's metatables on data loaded with `mw.loadData` messing with `#` operator.
---@param recipe Recipe
---@return integer
function Recipe.getNumBuildings(recipe)
	if not recipe._buildings then
		error("Recipe.getNumBuildings cannot work with nil array.")
	end
	local count = 0
	for _ in ipairs(recipe._buildings) do
		count = count + 1
	end
	return count
end

-- Gets the production time of the recipe.
---@param recipe Recipe
---@return number
function Recipe.getTime(recipe)
	return recipe._time
end

-- Gets the production time of the recipe in a clock format.
---@param recipe Recipe
---@return string # formatted as "M:SS"
function Recipe.getTimeClock(recipe)
	local minutes = math.floor((recipe._time or 0) / 60)
	local seconds = (recipe._time or 0) % 60
	return string.format("%d:%02d", minutes, seconds)
end

--#endregion Public Methods



return Recipe