Module:Armor

local p = {} local h = {}

local DataTable = require("Module:Data Table") local TermList = require("Module:Term List") local utilsArg = require("Module:UtilsArg") local utilsCargo = require("Module:UtilsCargo") local utilsString = require("Module:UtilsString") local utilsTable = require("Module:UtilsTable")

local CATEGORY_INVALID_ARGS = require("Module:Constants/category/invalidArgs") local ARMOR_COLUMNS = {"Set", "Body Part", "Armor", "Defense", "Effect(s)", "Sell Price", "Inventory Description"} local UPGRADE_COLUMNS = {"Armor", "Level", "Materials", "Defense", "Sell Price"}

local function warn(msg, ...) local utilsError = require("Module:UtilsError") msg = string.format(msg, ...) utilsError.warn(msg) end

function p.ArmorData(frame) return h.armorData(frame) end

function p.ArmorTable(frame) return DataTable.Main(frame, h.storeArmor, {		requiredColumns = ARMOR_COLUMNS	}) end

function p.UpgradeTable(frame) return DataTable.Main(frame, h.storeUpgrades, {		requiredColumns = UPGRADE_COLUMNS	}) end

function h.armorData(frame) local args, err = utilsArg.parse(frame:getParent.args, p.Templates["Armor Data"]) if err then return "", err.categoryText end local armor = args.armor or mw.title.getCurrentTitle.subpageText local armorRows = utilsCargo.query("Armor", "armor, armorSet, bodyPart, level, defense, materials, sellPrice", {		where = utilsCargo.anyOf({ armor = armor, armorSet = armor, })	})	local armorCount = #(utilsTable.uniqueBy(armorRows, "armor")) if #armorRows == 1 then warn("Non-upgradeable Armor does not have enough data to show in a table. The template should be removed from the page.") return "" elseif armorCount == 0 then warn("No data exists for Armor or Armor Set  on the Armor page.", armor) return "" elseif #armorRows == armorCount then return h.armorPieces(armorRows, args.game) -- simply list Armor pieces for non-upgradeable armor sets elseif armorCount > 1 then return h.setLevels(armorRows, args.game) else return h.armorLevels(armorRows, args.game) end end function h.armorLevels(armorRows, game) local rows = {} for i, armor in ipairs(armorRows) do		local row = {} row.cells = { armor.level or " ", armor.defense, armor.materials or "N/A", armor.sellPrice or "N/A" }		table.insert(rows, row) end local tableArgs = DataTable.formatTable(rows, {		game = game,		sortable = false,		columns = {"Level", string.format("Defense [Defense:%s:-]", game), "Materials [Amounts]", "Sell Price [Rupees]"}	}) local dataTable = DataTable.printTable(tableArgs) return dataTable end function h.setLevels(armorRows, game) armorRows = utilsTable.groupBy(armorRows, "bodyPart") armorRows = utilsTable.concat(armorRows["Head"] or {}, armorRows["Chest"] or {}, armorRows["Legs"] or {}) local rows = {} for i, armor in ipairs(armorRows) do		local row = {} row.cells = { armor.armor, armor.level or " ", armor.defense, armor.materials or "N/A", armor.sellPrice or "N/A" }		table.insert(rows, row) end local tableArgs = DataTable.formatTable(rows, {		game = game,		sortable = false,		columns = {"Armor [Rowspan:5][Term]", "Level", string.format("Defense [Defense:%s:-]", game), "Materials [Amounts]", "Sell Price [Rupees]"}	}) local dataTable = DataTable.printTable(tableArgs) return dataTable end function h.armorPieces(armorRows, game) local rows = {} for i, armor in ipairs(armorRows) do		local row = {} row.cells = { armor.armor, armor.defense, armor.sellPrice or "N/A" }		table.insert(rows, row) end local tableArgs = DataTable.formatTable(rows, {		game = game,		sortable = false,		columns = {"Armor [Term]", string.format("Defense [Defense:%s:-]", game), "Sell Price [Rupees]"}	}) local dataTable = DataTable.printTable(tableArgs) return dataTable end

function h.storeArmor(args) local categories = "" for i, row in ipairs(args.rows) do		local data, rowCategories = h.parseRow(ARMOR_COLUMNS, row.cells, i)		categories = categories..rowCategories mw.getCurrentFrame:expandTemplate({			title = "Armor/Store",			args = {				game = args.game,				armorSet = data["Set"],				armor = data["Armor"],				bodyPart = data["Body Part"],				level = nil,				defense = data["Defense"],				sellPrice = data["Sell Price"],				effects = data["Effect(s)"],				materials = nil,				description = data["Inventory Description"]			}		}) end return categories end

function h.storeUpgrades(args) local categories = "" local armorByName, armorBySet = h.getBaseArmorData(args.game) for i, row in ipairs(args.rows) do		local data, errCategories = h.parseRow(UPGRADE_COLUMNS, row.cells, i)		categories = categories..errCategories local armors, errCategories = h.addBaseData(data, armorBySet, armorByName, args.game) categories = categories..errCategories for i, armor in ipairs(armors) do			mw.getCurrentFrame:expandTemplate({				title = "Armor/Store",				args = armor,			}) end end return categories end function h.addBaseData(data, armorBySet, armorByName, game) local categories = "" local armors = {} local armorName = data["Armor"] local armorPieces = armorBySet[armorName] if armorPieces then for i, armorPiece in ipairs(armorPieces) do			local armor = h.mergeBaseData(data, armorByName[armorPiece]) armor.game = game table.insert(armors, armor) end elseif armorByName[armorName] then local armor = h.mergeBaseData(data, armorByName[armorName]) armor.game = game table.insert(armors, armor) else warn("Unknown Armor or Set '%s'", armorName) categories = categories.."" end return armors, categories end function h.mergeBaseData(upgrade, base) local description = base.description return { armor = base.armor, armorSet = base.armorSet, bodyPart = base.bodyPart, effects = base.effects, level = upgrade["Level"], defense = upgrade["Defense"], sellPrice = upgrade["Sell Price"], materials = upgrade["Materials"], description = upgrade["Description"], } end

function h.parseRow(columns, cells, rowIndex) local categories = "" local row = {} local cellsByColumn = utilsTable.keyBy(cells, "columnHeader") for i, column in ipairs(columns) do		local cell = cellsByColumn[column] or {} if cell.raw == "" or cell.raw == nil then warn("The value for column  in row %d should not be empty.", column, rowIndex) categories = categories.."" cell = nil elseif string.find(cell.raw, "^N/A") then cell = nil else cell = TermList.separateAdditionalInfo(cell.raw) end row[column] = cell end return row, categories end

function h.getBaseArmorData local armors = utilsCargo.query("Armor", "armor, armorSet, bodyPart, effects", {		limit = 400	}) local armorByName = utilsTable.keyBy(armors, "armor") local armorBySet = utilsTable.groupBy(armors, "armorSet") armorBySet = utilsTable.mapValues(armorBySet, utilsTable._map("armor")) return armorByName, armorBySet end

p.Templates = { ["Armor Data"] = { wip = true, description = "Displays Armor data", purpose = "Displays Armor data retrieved from the Armor list and Armor upgrade list stored in the Armor Cargo table. For use on individual Armor and Armor Set articles.", params = { [1] = {				name = "game", required = true, type = "string", enum = {"BotW"}, desc = "A game code.", },			[2] = {				name = "armor", type = "wiki-page-name", desc = "An article name referring to a particular piece of Armor. Defaults to the current page.", },		},		examples = { vertical= true, {"BotW", "Rubber Armor"}, {"BotW", "Rubber Armor (Set)"}, {"BotW", "Well-Worn Outfit"}, {				desc = "Displays nothing for non-upgradeable individual armor pieces, as there is not enough information to display in a table.", args = {"BotW", "Thunder Helm"}, },			{				desc = "Error: Non-existent Armor", args = {"BotW", "Not an Armor"}, },		},	},	["Armor/Store"] = { purpose = "Used by Template:Data Table/Armor to store armor data.", format = "block", storesData = true, paramOrder = {"game", "armorSet", "armor", "bodyPart", "level", "defense", "sellPrice", "effects", "materials", "description"}, boilerplate = { separateRequiredParams = false, },		params = { game = { type = "string", desc = "A game code from Data:Franchise", trim = true, nilIfEmpty = true, },			armorSet = { type = "wiki-page-name", desc = "If applicable, a wiki page name on the Armor Set that this Armor belongs to.", trim = true, },			armor = { required = true, type = "wiki-page-name", desc = "A wiki article name on a particular piece of Armor.", trim = true, nilIfEmpty = true, },			bodyPart = { required = true, type = "string", enum = {"Head", "Chest", "Legs"}, desc = "The slot that this Armor occupies on Link's body.", trim = true, nilIfEmpty = true, },			level = { type = "number", desc = "The level of the Armor upgrade, as an integer. Blank for base items.", trim = true, nilIfEmpty = true, },			defense = { required = true, type = "number", desc = "The defensive value for the Armor at the specified level.", trim = true, nilIfEmpty = true, },			sellPrice = { type = "number", desc = "An integer – the amount of Rupees that Link can sell the Armor for at the specified level.", trim = true, nilIfEmpty = true, },			effects = { type = "string", desc = "A comma-separated list of the Armor's Effects, if any.", trim = true, nilIfEmpty = true, },			materials = { required = true, type = "string", desc = "A list of the materials required to obtain specified upgrade level.", trim = true, nilIfEmpty = true, },			description = { required = true, type = "content", desc = "A transcript of the item's description on the Inventory screen.", trim = true, nilIfEmpty = true, },		},	},	["Data Table/Armor"] = {}, ["Data Table/Armor Upgrades"] = {}, }

return p