Module:Armor/Query

local p = {} local h = {}

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

local CATEGORY_INVALID_ARGS = ""

function h.err(errMsg, warnMsg) local utilsError = require("Module:UtilsError") return utilsError.error(errMsg, warnMsg) end

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

function p.ArmorList(frame) local args, err = utilsArg.parse(frame:getParent.args, p.Templates["Armor List"]) local categories = err and err.categoryText or ""

if not args.game then return err.categoryText end

local armorData = utilsCargo.query("Armor2=Sets, ArmorLevels=Levels", "Sets.armorSet=armorSet, Sets.bodyPart=bodyPart, Levels.armor=armor, Levels.level=level, Levels.defense=defense, Levels.materials=materials, Levels.sellable=sellable, Levels.sellPrice=sellPrice, Levels.description=description", {		join = "Levels.armor = Sets.armor, Levels.game = Sets.game",		where = utilsCargo.allOf({ ["Levels.game"] = args.game, }),		limit = 1000,	}) categories = categories..utilsCargo.categoryQuerying armorData = utilsTable.sortBy(armorData, function(armor)		local sortKey = armor.armor..(armor.level or "")		if armor.armorSet and armor.armorSet ~= "" then			sortKey = armor.armorSet..h.bodyPartSortKey(armor.bodyPart)..sortKey		end		return sortKey	end) local columns = {"Armor Set [Term]", "Body Part", "Armor [Nowrap][Rowspan][Term]", "Level", string.format("Defense [Defense:%s:-]", args.game), "Sell Price [Rupees]", "Description [Transcript]"} local rows = utilsTable.map(armorData, function(armor)		return {			cells = {				armor.armorSet or "N/A",				armor.bodyPart or "",				armor.armor or "",				armor.level or "",				armor.defense or "",				armor.sellable == "1" and (armor.sellPrice or "") or "N/A",				armor.description or "",			}		}	end) local categories2 = h.annotateTable(rows, columns, args.notes) categories = categories..categories2 local dataTable = DataTable.printTable(rows, {		game = args.game,		columns = columns,	}, function (tableArgs)		for i, row in ipairs(tableArgs.rows) do			row.cells[1].rowspan = row.cells[3].rowspan			row.cells[2].rowspan = row.cells[3].rowspan			row.cells[1].skip = row.cells[3].skip			row.cells[2].skip = row.cells[3].skip		end		return tableArgs	end)

return dataTable, categories end

function p.ArmorLevels(frame) local args, err = utilsArg.parse(frame:getParent.args, p.Templates["Armor Levels"]) local categories = err and err.categoryText or "" if err then return categories end local data = utilsCargo.query("ArmorLevels", "level, defense, materials, sellPrice, sellable, description", {		where = utilsCargo.allOf({ game = args.game, armor = args.armor, }),		orderBy = "level",	}) if #data == 0 then categories = categories..CATEGORY_INVALID_ARGS h.warn("No armor named  is stored at Data:Armor/%s.", args.armor, args.game) return categories end if #data == 1 then categories = categories..CATEGORY_INVALID_ARGS h.warn("This template is for upgradeable armor only —  has only one level stored at Data:Armor/%s.", args.armor, args.game) return categories end local rows = utilsTable.map(data, function(armor)		return {			cells = {				armor.level or "",				armor.defense or "",				armor.level and (armor.materials or "") or "N/A",				armor.sellable == "1" and (armor.sellPrice or "") or "N/A",				armor.description or "",			}		}	end) local dataTable = DataTable.printTable(rows, {		game = args.game,		sortable = false,		columns = {"Level", string.format("Defense [Defense:%s:-]", args.game), "Materials [Amounts]", "Sell Price [Rupees]", "Description [Transcript]"}	})

return dataTable, categories end

function p.ArmorSetPieces(frame) local args, err = utilsArg.parse(frame:getParent.args, p.Templates["Armor Set Pieces"]) local categories = err and err.categoryText or "" if err then return categories end local armorSetPieces = utilsCargo.query("ArmorLevels=Levels, Armor2=Sets", "Sets.armor=armor, Sets.armorSet=armorSet, Sets.bodyPart=bodyPart, Levels.level=level, Levels.defense=defense, Levels.materials=materials, Levels.sellable=sellable, Levels.sellPrice=sellPrice", {		join = "Levels.armor = Sets.armor, Levels.game = Sets.game",		where = utilsCargo.allOf({ ["Levels.game"] = args.game, ["Sets.armorSet"] = args.armorSet, }),	})	categories = categories..utilsCargo.categoryQuerying if #armorSetPieces == 0 then categories = categories..CATEGORY_INVALID_ARGS h.warn("No such armor set  is stored at Data:Armor/%s.", args.armorSet, args.game) return categories end local isUpgradeable = utilsTable.find(armorSetPieces, "level") -- Sort armor by slot, then by name, then by level armorSetPieces = utilsTable.sortBy(armorSetPieces, function(armor)		return h.bodyPartSortKey(armor.bodyPart)..armor.armor..(armor.level or "")	end) local rows = utilsTable.map(armorSetPieces, function(armor)		if isUpgradeable then			return {				cells = {					armor.armor or "",					armor.level or "",					armor.defense or "",					armor.level and (armor.materials or "") or "N/A",					armor.sellable == "1" and (armor.sellPrice or "") or "N/A",				}			}		else 			return {				cells = {					armor.armor or "",					armor.defense or "",					armor.sellable == "1" and (armor.sellPrice or "") or "N/A",				}			}		end	end) local columns if isUpgradeable then columns = {"Armor [Rowspan][Term]", "Level", string.format("Defense [Defense:%s:-]", args.game), "Materials [Amounts]", "Sell Price [Rupees]"} else columns = {"Armor [Term]", string.format("Defense [Defense:%s:-]", args.game), "Sell Price [Rupees]"} end local dataTable = DataTable.printTable(rows, {		game = args.game,		sortable = false,		columns = columns	})

return dataTable, categories end

function p.MaterialArmors(frame) local args, err = utilsArg.parse(frame:getParent.args, p.Templates["Material Armors"]) local categories = err and err.categoryText or "" if err then return categories end

-- Legacy code. Going forward, the material name should always be specified to avoid bugs that can occur when the same term can refer to multiple subjects local currentPage = mw.title.getCurrentTitle.subpageText -- subpageText for the benefit of sandboxes local material = args.material or Term.fetchTerm(currentPage, args.game) or currentPage local armorRows = utilsCargo.query("ArmorLevels", "armor, level, materials", {		where = "game = '"..args.game.."' AND materials LIKE '%"..utilsCargo.escape(material).."%'",		orderBy = "armor, level"	}) categories = categories .. utilsCargo.categoryQuerying

-- Do an exact match on the material name as the SQL query above will return rows containing "Giant Ancient Core" for material "Ancient Row" -- At the same time, compute the total of this material that is required to upgrade everything local totalAmountRequired = 0 armorRows = utilsTable.filter(armorRows, function(armorRow)		local materials = utilsString.split(armorRow.materials)		armorRow.materialAmounts = {}		for i, armorMaterial in ipairs(materials) do			local amount = string.match(armorMaterial, "^(%d+)%s+")			local materialName = string.gsub(armorMaterial, "^(%d+)%s+", "")			if materialName == material then				totalAmountRequired = totalAmountRequired + tonumber(amount)				return true			end		end	end)

if #armorRows == 0 then categories = categories..CATEGORY_INVALID_ARGS return h.err("Data not found", string.format("No upgrade data exists for material  on page Data:Armor/%s", material, args.game)), categories end local tableRows = utilsTable.map(armorRows, function(armorRow)		return {			cells = {				armorRow.armor,				armorRow.level,				armorRow.materials,			}		}	end) local dataTable = DataTable.printTable(tableRows, {		game = args.game,		columns = {"Armor [Rowspan][Term]", "Level", "Materials [Amounts]"},		sortable = false,	})

local plural = Term.plural(material, args.game) local totalRequired = string.format("Total %s required: %d", plural, totalAmountRequired)

local result = dataTable.." "..totalRequired.." " return result, categories end

function h.bodyPartSortKey(bodyPart) if bodyPart == "Head" then return "1" elseif bodyPart == "Chest" then return "2" elseif bodyPart == "Legs" then return "3" else return "4" end end

function h.annotateTable(rows, columns, notes) if not notes then return end

local categories = ""

local addedNotes = {} for i, row in ipairs(rows) do		columns = DataTable.extractColumnTags(columns) local categories = "" for j, note in ipairs(notes) do			local matchesRow = utilsTable.includes(row.cells, note.row) local columnIndex = utilsTable.findIndex(columns, function(column)				return column == note.column			end) if matchesRow and columnIndex then row.cells[columnIndex] = row.cells[columnIndex]..note.note end if not columnIndex then h.warn("No such column ", note.row) categories = categories..CATEGORY_INVALID_ARGS end if matchesRow then table.insert(addedNotes, j)			end end end

local unmatchedNotes = utilsTable.difference(utilsTable.keys(notes), addedNotes) for i, noteIndex in ipairs(unmatchedNotes) do		h.warn("No row  found for note %d", notes[noteIndex].row, noteIndex) categories = categories..CATEGORY_INVALID_ARGS end return categories end

p.Templates = { ["Armor List"] = { format = "block", paramOrder = {1, "note", "row", "column"}, repeatedGroup = { name = "notes", params = {"note", "row", "column"}, },		params = { [1] = {				name = "game", inline = true, required = true, trim = true, nilIfEmpty = true, type = "string", desc = "A game code from Data:Franchise.", },			note = { name = "note", type = "wikitext", desc = "An annotation to add to a table cell.", },			row = { type = "string", desc = "The name of the armor identifying the row to add the annotation to.", },			column = { type = "string", desc = "The name of the column identifying the cell to add the annotation to.", },		},	},	["Armor Levels"] = { params = { [1] = {				name = "game", required = true, type = "string", desc = "A game code from Data:Franchise.", },			[2] = {				name = "armor", required = true, type = "wiki-page-name", desc = "A wiki page name referring to a particular piece of Armor as named in .", },		},	},	["Armor Set Pieces"] = { params = { [1] = {				name = "game", required = true, type = "string", desc = "A game code from Data:Franchise.", },			[2] = {				name = "armorSet", required = true, type = "wiki-page-name", desc = "A wiki page name referring to a particular Armor Set as named in .", },		},	},	["Material Armors"] = { params = { [1] = {				name = "game", required = true, type = "string", desc = "A game code from Data:Franchise.", },			[2] = {				name = "material", required = true, type = "wiki-page-name", desc = "A wiki page name referring to a particular Material as named in .", },		},	}, }

return p