|
|
| (22 intermediate revisions by the same user not shown) |
| Line 1: |
Line 1: |
| -- Provides a standard way of interacting with data about goods, resources, and metaresources.
| | local Export = {} |
| local Resource = {} | | local resourceData = require("Module:ResourceData") |
|
| |
|
| -- A single resource with attributes like ID, name, category, etc.
| | local function recipeToText(recipe) |
| ---@class Resource
| | if not recipe or next(recipe) == nil then |
| ---@field _id ResourceID Unique ID code of the resource.
| | return "''None''" |
| ---@field _displayName ResourceName The display name in-game.
| | end |
| ---@field _description string The in-game descriptive text, including sprite icons, newlines, and escape characters.
| |
| ---@field _iconFilename Filename The file name of the icon for this resource.
| |
| ---@field _category CategoryResource Resource type from the info bar.
| |
| ---@field _tradingSellValue Coins Base value when selling to tradeposts.
| |
| ---@field _tradingBuyValue Coins Base cost when buying from Grand Market.
| |
| | |
| -- The ID code of a good or resource.
| |
| ---@alias ResourceID string
| |
| | |
| -- The display name of a resource.
| |
| ---@alias ResourceName string
| |
| | |
| -- Currency in-game.
| |
| ---@alias Coins number
| |
| | |
| -- The ID and amount of a good or service.
| |
| ---@alias ResourcePair {_id: ResourceID, _amount: Amount}
| |
| | |
| -- The resource category based on the info bar.<br>
| |
| -- Metaresources are categorized with trade goods.
| |
| ---@enum CategoryResource
| |
| local CATEGORY_RESOURCE = {
| |
| Materials = "Materials",
| |
| Food = "Food",
| |
| Drink = "Drink",
| |
| Ships = "Ships",
| |
| Equipment = "Equipment",
| |
| Weapons = "Weapons"
| |
| }
| |
| | |
| | |
| | |
| --#region Dependencies
| |
| | |
| local RESOURCES_DATA_FILE = "Module:Resources/resources_data"
| |
|
| |
|
| local Wiki_Utility = require("Module:Wiki_Utility") | | local parts = {} |
| local icon = Wiki_Utility.renderIcon
| |
| local nowrap = Wiki_Utility.surroundWithNoWrap
| |
| local wrapClasses = Wiki_Utility.surroundWithClasses
| |
| local link = Wiki_Utility.renderWikiLink
| |
| local NBSP = Wiki_Utility.NBSP
| |
| local standards = Wiki_Utility.StandardizedSizes
| |
| local isValidIconSize = Wiki_Utility.isValidIconSize
| |
|
| |
|
| --#endregion Dependencies
| | local i = 1 |
| | | while recipe["ingredient"..i] do |
| | | local ingredient = recipe["ingredient"..i] |
| | | local icon = resourceData[ingredient] and resourceData[ingredient].icon_file or "" |
| --#region Constants
| | |
| | | table.insert(parts, |
| local MIN_ICON_SIZE = 16 | | string.format( |
| | | "%d [[File:%s|16px]] [[%s]]", |
| --#endregion Constants
| | recipe["ingredient"..i.."_qty"], |
| | | icon, |
| | | ingredient |
| | | ) |
| --#region Private Members
| | ) |
| | | i = i + 1 |
| ---@type table<ResourceID, Resource>
| |
| local resourceData
| |
| ---@type table<ResourceName, ResourceID>
| |
| local mapNamesToIDs
| |
| | |
| local function data()
| |
| if not resourceData then
| |
| mapNamesToIDs = {}
| |
| resourceData = mw.loadData(RESOURCES_DATA_FILE)
| |
| for id, resource in pairs(resourceData) do
| |
| mapNamesToIDs[resource._displayName] = id
| |
| end | | end |
| end
| |
| return resourceData
| |
| end
| |
|
| |
|
| -- Finds a resource by its display name.
| | if #parts == 0 then |
| ---@param resourceName ResourceName display name
| | return "''None''" |
| ---@return Resource|nil foundResource or nil if not found
| |
| local function findName(resourceName)
| |
| local foundResource = nil
| |
| for _, resource in pairs(data()) do
| |
| if resource._displayName == resourceName then | |
| foundResource = resource
| |
| break
| |
| end | | end |
| end
| |
| return foundResource
| |
| end
| |
|
| |
|
| -- Renders a link to the given resource's wiki page.<br>
| | return table.concat(parts, "<br/>") |
| -- If the specified iconSize is too small, the icon will be ommitted instead of drawn so small as to be unrecognizable.
| |
| ---@param resource Resource must not be nil
| |
| ---@param iconSize string|nil size of the icon including units, e.g., "x16px", or nil for default
| |
| ---@param needsIcon boolean|nil or nil for default
| |
| ---@param needsText boolean|nil or nil for default
| |
| ---@param targetElementID string|nil #name or #id of the DOM element to link directly to, if any
| |
| ---@return Wikitext wikitext
| |
| local function resourceLink(resource, iconSize, needsIcon, needsText, targetElementID)
| |
| iconSize = iconSize or standards.small
| |
| needsIcon = needsIcon or (needsIcon == nil and true)
| |
| needsText = needsText or (needsText == nil and true)
| |
| local wikitext = ""
| |
| local isValidSize, sizeN = isValidIconSize(iconSize)
| |
| if needsIcon and isValidSize and sizeN >= MIN_ICON_SIZE then
| |
| -- Make it a height if it's not already.
| |
| if not iconSize:match("^x") then
| |
| iconSize = "x" .. iconSize
| |
| end
| |
| local directLink = resource._displayName .. (targetElementID and ("" .. targetElementID) or "")
| |
| wikitext = wikitext .. wrapClasses(icon(resource._iconFilename, iconSize, directLink, resource._displayName), "ats-link-resource", sizeN and sizeN < 23 and "ats-flag-small" or nil)
| |
| end
| |
| if (needsIcon and isValidSize and sizeN >= MIN_ICON_SIZE) and needsText then
| |
| wikitext = wikitext .. NBSP
| |
| end
| |
| if needsText then
| |
| wikitext = wikitext .. link(resource._displayName, resource._displayName, targetElementID)
| |
| end
| |
| return nowrap(wikitext)
| |
| end | | end |
|
| |
|
| --#endregion Private Methods
| | function Export.resourceToWiki(resource) |
| | local sourceText = {} |
| | local quantityText = {} |
| | local recipeText = {} |
| | local prodSellText = {} |
|
| |
|
| | for i = 1, 3 do |
| | local src = resource.production["source"..i] |
|
| |
|
| | if src and src ~= "" then |
| | table.insert(sourceText, "[[" .. src .. "]]") |
|
| |
|
| --#region Public Methods
| | local qty = resource.production["quantity"..i] or 0 |
| | local qty_str = tostring(qty) .. " [[File:" .. resource.icon_file .. "|16px]] [[" .. resource.name .. "]]" |
| | table.insert(quantityText, qty_str) |
|
| |
|
| -- Checks if the given ID is a valid resource ID.
| | local recipe = recipeToText(resource.production["recipe"..i]) |
| ---@param id ResourceID
| | table.insert(recipeText, recipe) |
| ---@return boolean
| | |
| function Resource.isGood(id)
| | local prod_sell = string.format("%.1f", resource.stack_value * (qty / resource.stack_size)) |
| return data()[id] ~= nil
| | table.insert(prodSellText, prod_sell) |
| end | | end |
| | end |
|
| |
|
| -- Finds a resource's ID by its display name.
| | local recipes = table.concat(recipeText, "<hr/>") |
| ---@param displayName ResourceName
| |
| ---@return ResourceID|nil
| |
| function Resource.getID(displayName)
| |
| data()
| |
| return mapNamesToIDs[displayName]
| |
| end
| |
|
| |
|
| -- Gets the specified resource's display name.
| | return table.concat({ |
| ---@param id ResourceID
| | "| [[File: " .. resource.icon_file .. " |x96px]]", |
| ---@return ResourceName
| | "[[" .. resource.name .. "]]", |
| function Resource.getName(id)
| | resource.category, |
| return data()[id]._displayName
| | table.concat(sourceText, "<hr/>"), |
| | recipes, |
| | table.concat(quantityText, "<hr/>"), |
| | tostring(resource.stack_size), |
| | string.format("%.0f", resource.stack_value * 0.3), |
| | tostring(resource.stack_value), |
| | table.concat(prodSellText, " <hr/> ") |
| | }, " || ") |
| end | | end |
|
| |
|
| -- Renders a table of pairs of resource IDs and amounts.
| | function Export.wikiResourceTable() |
| ---@param pairsList ResourcePair[] array of pairs of resource IDs and amounts
| |
| ---@param iconSize string |nil size of the icon including any units, e.g., `20em` or `x16px` or assumes `px` if no units, or nil if not relevant
| |
| ---@vararg string|nil additional classes to add to the table, if any
| |
| ---@return Wikitext wikitext
| |
| function Resource.tableStack(pairsList, iconSize, ...) | |
| local classes = {...}
| |
| -- quick check to see if amount column needed
| |
| local needsAmountColumn = false
| |
| for _, pair in ipairs(pairsList) do
| |
| if pair._amount and pair._amount ~= "" then
| |
| needsAmountColumn = true
| |
| end
| |
| end
| |
| local wikitext = "{|" .. ((#classes > 0) and ("class=" .. table.concat(classes, " ")) or "") .. "\n"
| |
| for _, pair in ipairs(pairsList) do
| |
| local resource = data()[pair._id]
| |
| if not resource then return "[Resource table stack ID not found: " .. pair._id .. "]" end
| |
| wikitext = wikitext .. "|-\n"
| |
| wikitext = wikitext .. (needsAmountColumn and ("|style=text-align:right| " .. (pair._amount or "") .. "\n") or "")
| |
| wikitext = wikitext .. "| " .. resourceLink(resource, iconSize or standards.medium, true, true, "#Product") .. "\n"
| |
| end
| |
| return wikitext .. "|}"
| |
| end
| |
|
| |
|
| -- Renders a link to the given resource's wiki page by its ID.
| | local rows = {} |
| ---@param resourceID ResourceID
| |
| ---@param iconSize string|nil size of the icon including units, e.g., "x16px" or nil for default
| |
| ---@param needsIcon boolean|nil or nil for default
| |
| ---@param needsText boolean|nil or nil for default
| |
| ---@param targetElementID string|nil #name or #id of the DOM element to link directly to, if any
| |
| ---@return Wikitext wikitext
| |
| function Resource.resourceLinkByID(resourceID, iconSize, needsIcon, needsText, targetElementID)
| |
| return resourceLink(data()[resourceID], iconSize, needsIcon, needsText, targetElementID)
| |
| end
| |
|
| |
|
| -- Resource_link template invokes this method from MediaWiki.
| | for _, resource in pairs(resourceData) do |
| ---@param frame Frame MediaWiki template context
| | table.insert(rows, Export.resourceToWiki(resource)) |
| ---@return Wikitext wikitext wikitext markup to link to the resource's wiki page
| | end |
| function Resource.link(frame)
| |
| local name = frame.args.name or ""
| |
| if name == "" then
| |
| return "[Resource Link needs resource name]" | |
| end
| |
| local iconSize = standards[frame.args.icon] or frame.args.icon or ""
| |
| local needsIcon = iconSize ~= "none"
| |
| -- Check if the size string is valid and doesn't represent a negative or too-large number.
| |
| if needsIcon and not isValidIconSize(iconSize) then
| |
| return "[Resource Link size not valid: " .. iconSize .. "]"
| |
| end
| |
| local display = frame.args.display or ""
| |
| if display ~= "" and display ~= "notext" then
| |
| return "[Resource Link display override not supported: " .. display .. "]"
| |
| end
| |
| local needsText = display ~= "notext"
| |
| local resource = findName(name)
| |
| if not resource then
| |
| return "[Resource not found: " .. name .. "]"
| |
| end
| |
| return resourceLink(resource, iconSize, needsIcon, needsText)
| |
| end | |
|
| |
|
| function Resource.stack(frame)
| | return table.concat({ |
| local parent = frame:getParent()
| | '{| class="wikitable sortable"', |
| local args = parent and parent.args or frame.args
| | '! class="unsortable" | Icon !! Name !! Category !!Production<br/>Building !! Ingredients<br/>per min. !! Production<br/>per min. !! Stack Size !! [[Quartermaster|Cohesion Value]] !! [[Trade Post|Stack Selling Value]] !! [[Trade Post|Production Sale]]<br/>per min.', |
| local iconSize = args.icon and (args.icon ~= "" and standards[args.icon] or standards.medium)
| | '|-', |
| local classes = args.classes or ""
| | table.concat(rows, '\n|-\n'), |
| --@type ResourcePair[]
| | '|}', |
| local pairsList = {}
| | '' |
| -- handle the indeterminate number of unnamed parameters passed to the template, but skip empty ones
| | }, '\n') |
| for _, pair in ipairs(args) do
| |
| if pair ~= "" then
| |
| -- Remove leading/trailing whitespace from the argument
| |
| pair = pair:match("^%s*(.-)%s*$")
| |
| local amount, name = pair:match("^(%d*)%s*(.+)$")
| |
| -- Remove leading/trailing whitespace from the resource name
| |
| if name then
| |
| name = name:match("^%s*(.-)%s*$") | |
| end
| |
| local resource = findName(name)
| |
| if not resource then
| |
| return "[Resource not found: " .. name .. "]" | |
| end
| |
| pairsList[#pairsList + 1] = {_id = resource._id, _amount = amount}
| |
| end
| |
| end
| |
| if #pairsList == 0 then
| |
| return "[Resource stack needs at least one resource]" | |
| end
| |
| return Resource.tableStack(pairsList, iconSize, classes)
| |
| end | | end |
|
| |
|
| --#endregion Public Methods
| | return Export |
| | |
| | |
| | |
| return Resource | |
This module arranges resource data into a table, providing detailed stats as well as useful cost calculations.
It uses data from Module:ResourceData.
local Export = {}
local resourceData = require("Module:ResourceData")
local function recipeToText(recipe)
if not recipe or next(recipe) == nil then
return "''None''"
end
local parts = {}
local i = 1
while recipe["ingredient"..i] do
local ingredient = recipe["ingredient"..i]
local icon = resourceData[ingredient] and resourceData[ingredient].icon_file or ""
table.insert(parts,
string.format(
"%d [[File:%s|16px]] [[%s]]",
recipe["ingredient"..i.."_qty"],
icon,
ingredient
)
)
i = i + 1
end
if #parts == 0 then
return "''None''"
end
return table.concat(parts, "<br/>")
end
function Export.resourceToWiki(resource)
local sourceText = {}
local quantityText = {}
local recipeText = {}
local prodSellText = {}
for i = 1, 3 do
local src = resource.production["source"..i]
if src and src ~= "" then
table.insert(sourceText, "[[" .. src .. "]]")
local qty = resource.production["quantity"..i] or 0
local qty_str = tostring(qty) .. " [[File:" .. resource.icon_file .. "|16px]] [[" .. resource.name .. "]]"
table.insert(quantityText, qty_str)
local recipe = recipeToText(resource.production["recipe"..i])
table.insert(recipeText, recipe)
local prod_sell = string.format("%.1f", resource.stack_value * (qty / resource.stack_size))
table.insert(prodSellText, prod_sell)
end
end
local recipes = table.concat(recipeText, "<hr/>")
return table.concat({
"| [[File: " .. resource.icon_file .. " |x96px]]",
"[[" .. resource.name .. "]]",
resource.category,
table.concat(sourceText, "<hr/>"),
recipes,
table.concat(quantityText, "<hr/>"),
tostring(resource.stack_size),
string.format("%.0f", resource.stack_value * 0.3),
tostring(resource.stack_value),
table.concat(prodSellText, " <hr/> ")
}, " || ")
end
function Export.wikiResourceTable()
local rows = {}
for _, resource in pairs(resourceData) do
table.insert(rows, Export.resourceToWiki(resource))
end
return table.concat({
'{| class="wikitable sortable"',
'! class="unsortable" | Icon !! Name !! Category !!Production<br/>Building !! Ingredients<br/>per min. !! Production<br/>per min. !! Stack Size !! [[Quartermaster|Cohesion Value]] !! [[Trade Post|Stack Selling Value]] !! [[Trade Post|Production Sale]]<br/>per min.',
'|-',
table.concat(rows, '\n|-\n'),
'|}',
''
}, '\n')
end
return Export