Module:DataTableParser
From Dune Awakening DB
Documentation for this module may be created at Module:DataTableParser/doc
-- Module:DataTableParser
-- Handles display and formatting of building data for Templates
-- Updated to parse wiki tables directly instead of using Cargo
local p = {}
-- Function to generate icon file reference for a resource
local function getResourceIcon(resourceName)
if not resourceName or resourceName == "" then
return ""
end
-- Convert spaces to underscores for file name
local fileName = resourceName:gsub("%s+", "_") .. "_-_Icon.png"
-- Check if the file actually exists in the wiki
local fileTitle = mw.title.new("File:" .. fileName)
if fileTitle and fileTitle.exists then
-- Return file reference with appropriate size only if it exists
return "[[File:" .. fileName .. "|20px]]"
else
-- If file doesn't exist, return empty string
return ""
end
end
-- Function to add icons to resource links in text
function p.iconize(frame)
local text = frame.args[1] or ""
-- Find all resource links [[Resource Name]] and add appropriate icons
text = text:gsub("%[%[([^%]]+)%]%]", function(resourceName)
local icon = getResourceIcon(resourceName)
if icon ~= "" then
return icon .. " [[" .. resourceName .. "]]"
else
-- If no icon exists, just return the original link
return "[[" .. resourceName .. "]]"
end
end)
return text
end
----------------------------------------------------------------------
-- Helper function to load/parse the wiki table page for buildings
----------------------------------------------------------------------
local function loadBuildingWikiTable()
local title = "Data:Building" -- The page containing your building table
local content = mw.title.new(title):getContent()
if not content then
return nil, "Error: Building wiki table page not found!"
end
local lines = mw.text.split(content, "\n")
-- Filter out magic words, noindex tags, or blank lines
local filtered = {}
for _, line in ipairs(lines) do
line = mw.text.trim(line)
if line ~= "" and not line:match("^__") and not line:match("<noindex>") and not line:match("</noindex>") then
table.insert(filtered, line)
end
end
if #filtered < 2 then
return nil, "Error: No valid wiki table content found!"
end
local inTable = false
local headers = {} -- store the table headers
local colMap = {} -- map header name to column index
local data = {} -- array of row arrays
local currentRow = {}
local readingHeader = true -- before the first row separator ("|-"), treat cells as headers
for _, line in ipairs(filtered) do
if line:match("^{|") then
-- Start of table (line starts with "{|")
inTable = true
elseif line:match("^|%-") then
-- Row separator ("|-")
if not readingHeader and #currentRow > 0 then
table.insert(data, currentRow)
end
currentRow = {}
readingHeader = false -- after the first row separator, subsequent cells are row cells
elseif line:match("^!") then
-- Header cell (starts with "!")
local header = line:gsub("^!+%s*", "") -- Remove leading ! and whitespace
header = mw.text.trim(header)
table.insert(headers, header)
elseif line:match("^|%+") then
-- Table caption line ("|+"), skip it
elseif line:match("^|}") then
-- End of table ("|}")
if not readingHeader and #currentRow > 0 then
table.insert(data, currentRow)
end
inTable = false
elseif inTable and line:match("^|[^%-+}]") then
-- Process table cell lines (lines that start with "|" but not "|+", "|-", or "|}")
local cell = line:gsub("^|+%s*", "") -- Remove leading | and whitespace
cell = mw.text.trim(cell)
if not readingHeader then
table.insert(currentRow, cell)
end
end
end
-- Build colMap from headers (map header name to its column index)
for i, h in ipairs(headers) do
colMap[mw.text.trim(h)] = i
end
return { rows = data, colMap = colMap }, nil
end
----------------------------------------------------------------------
-- Helper function to load/parse the wiki table page for refining data
----------------------------------------------------------------------
local function loadRefiningWikiTable()
local title = "Data:Refining" -- The page containing your refining table
local content = mw.title.new(title):getContent()
if not content then
return nil, "Error: Refining wiki table page not found!"
end
local lines = mw.text.split(content, "\n")
-- Filter out magic words, noindex tags, or blank lines
local filtered = {}
for _, line in ipairs(lines) do
line = mw.text.trim(line)
if line ~= "" and not line:match("^__") and not line:match("<noindex>") and not line:match("</noindex>") then
table.insert(filtered, line)
end
end
if #filtered < 2 then
return nil, "Error: No valid wiki table content found!"
end
local inTable = false
local headers = {} -- store the table headers
local colMap = {} -- map header name to column index
local data = {} -- array of row arrays
local currentRow = {}
local readingHeader = true -- before the first row separator ("|-"), treat cells as headers
for _, line in ipairs(filtered) do
if line:match("^{|") then
-- Start of table (line starts with "{|")
inTable = true
elseif line:match("^|%-") then
-- Row separator ("|-")
if not readingHeader and #currentRow > 0 then
table.insert(data, currentRow)
end
currentRow = {}
readingHeader = false -- after the first row separator, subsequent cells are row cells
elseif line:match("^!") then
-- Header cell (starts with "!")
local header = line:gsub("^!+%s*", "") -- Remove leading ! and whitespace
header = mw.text.trim(header)
table.insert(headers, header)
elseif line:match("^|%+") then
-- Table caption line ("|+"), skip it
elseif line:match("^|}") then
-- End of table ("|}")
if not readingHeader and #currentRow > 0 then
table.insert(data, currentRow)
end
inTable = false
elseif inTable and line:match("^|[^%-+}]") then
-- Process table cell lines (lines that start with "|" but not "|+", "|-", or "|}")
local cell = line:gsub("^|+%s*", "") -- Remove leading | and whitespace
cell = mw.text.trim(cell)
if not readingHeader then
table.insert(currentRow, cell)
end
end
end
-- Build colMap from headers (map header name to its column index)
for i, h in ipairs(headers) do
colMap[mw.text.trim(h)] = i
end
return { rows = data, colMap = colMap }, nil
end
-- Function to add icons to resource links in text
function p.iconize(frame)
local text = frame.args[1] or ""
-- Find all resource links [[Resource Name]] and add appropriate icons
text = text:gsub("%[%[([^%]]+)%]%]", function(resourceName)
local icon = getResourceIcon(resourceName)
return icon .. " [[" .. resourceName .. "]]"
end)
return text
end
-- Function to format a recipe component
function p.formatComponent(text)
if not text or text == "" then
return ""
end
-- Split recipe into components (in case there are multiple)
local components = mw.text.split(text, ";")
local formatted = {}
for i, component in ipairs(components) do
component = mw.text.trim(component)
-- Extract item name and quantity (e.g., "[[Salvaged Metal]] x 25")
local itemName, quantity = component:match("%[%[([^%]]+)%]%] x (%d+)")
if itemName and quantity then
local icon = getResourceIcon(itemName)
table.insert(formatted, icon .. " [[" .. itemName .. "]] x " .. quantity)
else
-- If pattern doesn't match, use as is
table.insert(formatted, component)
end
end
return table.concat(formatted, "<br>")
end
-- Function to get building data by name
function p.getBuildingData(buildingName)
local buildingData, err = loadBuildingWikiTable()
if not buildingData then
return nil, err
end
local colMap = buildingData.colMap
local rows = buildingData.rows
local nameCol = colMap["Name"]
if not nameCol then
return nil, "Error: 'Name' column not found in Building table"
end
for _, fields in ipairs(rows) do
local name = fields[nameCol]
if name == buildingName then
return fields, colMap
end
end
return nil, "Building '" .. buildingName .. "' not found"
end
----------------------------------------------------------------------
-- Helper function to load/parse the refining data wiki table
----------------------------------------------------------------------
local function loadRefiningWikiTable()
local title = "Data:Refining" -- Make sure this matches your wiki page path exactly
local content = mw.title.new(title):getContent()
if not content then
return nil, "Error: Refining wiki table page not found at " .. title
end
local lines = mw.text.split(content, "\n")
-- Filter out magic words, noindex tags, or blank lines
local filtered = {}
for _, line in ipairs(lines) do
line = mw.text.trim(line)
if line ~= "" and not line:match("^__") and not line:match("<noindex>") and not line:match("</noindex>") then
table.insert(filtered, line)
end
end
if #filtered < 2 then
return nil, "Error: No valid wiki table content found in " .. title
end
local inTable = false
local headers = {} -- store the table headers
local colMap = {} -- map header name to column index
local data = {} -- array of row arrays
local currentRow = {}
local readingHeader = true -- before the first row separator ("|-"), treat cells as headers
for _, line in ipairs(filtered) do
if line:match("^{|") then
-- Start of table (line starts with "{|")
inTable = true
elseif line:match("^|%-") then
-- Row separator ("|-")
if not readingHeader and #currentRow > 0 then
table.insert(data, currentRow)
end
currentRow = {}
readingHeader = false -- after the first row separator, subsequent cells are row cells
elseif line:match("^!") then
-- Header cell (starts with "!")
local header = line:gsub("^!+%s*", "") -- Remove leading ! and whitespace
header = mw.text.trim(header)
table.insert(headers, header)
elseif line:match("^|%+") then
-- Table caption line ("|+"), skip it
elseif line:match("^|}") then
-- End of table ("|}")
if not readingHeader and #currentRow > 0 then
table.insert(data, currentRow)
end
inTable = false
elseif inTable and line:match("^|[^%-+}]") then
-- Process table cell lines (lines that start with "|" but not "|+", "|-", or "|}")
local cell = line:gsub("^|+%s*", "") -- Remove leading | and whitespace
cell = mw.text.trim(cell)
if not readingHeader then
table.insert(currentRow, cell)
end
end
end
-- Build colMap from headers (map header name to its column index)
for i, h in ipairs(headers) do
colMap[mw.text.trim(h)] = i
end
-- Add debug logging
if #data == 0 then
return nil, "Error: No data rows found in " .. title
end
return { rows = data, colMap = colMap }, nil
end
----------------------------------------------------------------------
-- Function to display refining recipes for a building
----------------------------------------------------------------------
-- Function to display refining recipes for a building
function p.getRefiningRecipes(frame)
local buildingName = frame.args[1] or mw.title.getCurrentTitle().text
-- Get refining data
local refiningData, err = loadRefiningWikiTable()
if not refiningData then
return "Error loading refining data: " .. (err or "Unknown error")
end
local rows = refiningData.rows
-- Fixed indices for the required columns
local resourceClassCol = 1 -- Resource Class
local nameCol = 2 -- Name
local timeCol = 3 -- Time to Smelt
local ingredientsCol = 4 -- Ingredients to Smelt
local recipeCol = 5 -- Recipe to Smelt
-- Helper function to find refiner name in a row
local function getRefinerFromRow(row)
-- Check potential positions for Refiner Needed column
-- Try column 8 first (matches original table structure)
if row[8] and row[8] ~= "" then
return row[8]
-- Try column 6 next (as seen in debug output)
elseif row[6] and row[6] ~= "" then
return row[6]
-- As a fallback, try each column from the end
else
for i = #row, 1, -1 do
if row[i] and row[i] ~= "" then
return row[i]
end
end
end
return ""
end
-- Helper function to normalize text for comparison
local function normalizeText(text)
if not text then return "" end
-- Remove quotes
text = text:gsub('["\']', '')
-- Remove wiki link brackets and extract the name
text = text:gsub("%[%[([^%]]+)%]%]", "%1")
-- Trim whitespace
text = mw.text.trim(text)
return text
end
-- Find recipes matching the building name
local matchingRecipes = {}
for _, row in ipairs(rows) do
-- Get the refiner name from the row
local refinerNeeded = getRefinerFromRow(row)
-- Normalize both texts for comparison
local normalizedRefiner = normalizeText(refinerNeeded)
local normalizedBuilding = normalizeText(buildingName)
if normalizedRefiner == normalizedBuilding then
table.insert(matchingRecipes, row)
end
end
-- If no recipes found, return a message
if #matchingRecipes == 0 then
return '<tr><td colspan="3" style="text-align:center;">No refining recipes found for this building.</td></tr>'
end
-- Start with the updated table headers
local output = "<tr>\n" ..
"<th style=\"text-align:left;\">Output</th>\n" ..
"<th style=\"text-align:left;\">Ingredients</th>\n" ..
"<th style=\"text-align:left;\">Craft Time</th>\n" ..
"</tr>\n"
-- Generate table rows for each recipe
for _, recipe in ipairs(matchingRecipes) do
local outputItem = recipe[nameCol] or ""
local ingredients = recipe[ingredientsCol] or ""
local time = recipe[timeCol] or ""
local recipeQty = recipe[recipeCol] or ""
-- Extract quantity from recipe text (e.g., "[[Copper Ore]] x 4" → "4")
local qty = "1"
if recipeQty ~= "" then
local extractQty = recipeQty:match("x%s*(%d+)")
if extractQty then
qty = extractQty
end
end
-- Format the output item with icon, including quantity
local formattedOutput = p.iconize({args = {[1] = outputItem}})
if qty ~= "1" then
formattedOutput = formattedOutput .. " × " .. qty
end
-- Split ingredients by semicolon and format each with icon
local formattedIngredients = ""
if ingredients ~= "" then
local ingredientsList = mw.text.split(ingredients, ";")
for i, ingredient in ipairs(ingredientsList) do
local trimmedIngredient = mw.text.trim(ingredient)
if trimmedIngredient ~= "" then
local formattedIngredient = p.iconize({args = {[1] = trimmedIngredient}})
if i > 1 then
formattedIngredients = formattedIngredients .. "<br>"
end
formattedIngredients = formattedIngredients .. formattedIngredient
end
end
end
-- Add table row
output = output .. "<tr>\n" ..
"<td style=\"text-align:left;\">" .. formattedOutput .. "</td>\n" ..
"<td style=\"text-align:left;\">" .. formattedIngredients .. "</td>\n" ..
"<td style=\"text-align:left;\">" .. time .. "</td>\n" ..
"</tr>\n"
end
return output
end
----------------------------------------------------------------------
-- Debug function to show raw refining data
----------------------------------------------------------------------
function p.debugRefiningData(frame)
local refiningData, err = loadRefiningWikiTable()
if not refiningData then
return "Error loading refining data: " .. (err or "Unknown error")
end
local output = "Refining data loaded successfully!\n\n"
output = output .. "Number of rows: " .. #refiningData.rows .. "\n\n"
output = output .. "Column mappings:\n"
for name, index in pairs(refiningData.colMap) do
output = output .. name .. " -> " .. index .. "\n"
end
output = output .. "\nFirst 3 rows:\n"
for i = 1, math.min(3, #refiningData.rows) do
output = output .. "Row " .. i .. ":\n"
for j, cell in ipairs(refiningData.rows[i]) do
output = output .. " Column " .. j .. ": " .. cell .. "\n"
end
end
return output
end
-- Main function to format building data for the template
function p.formatBuilding(frame)
local buildingName = frame.args[1] or frame.args.name
if not buildingName then
return "Error: No building name provided"
end
-- Get building data
local building, colMap = p.getBuildingData(buildingName)
if not building then
return "Error: Building '" .. buildingName .. "' not found"
end
-- Map building data to template parameters
local params = {
Name = building[colMap["Name"]] or "",
Description = p.iconize({args = {[1] = building[colMap["Description"]] or ""}}),
JourneyRequirement = p.iconize({args = {[1] = building[colMap["Journey Requirement"]] or ""}}),
ImageFile = building[colMap["Image File"]] or "",
Health = building[colMap["Health"]] or "",
EnergyConsumption = building[colMap["Power Cost"]] or "",
GeneratesPower = building[colMap["Generates Power"]] or "",
StorageSlots = building[colMap["Storage Slots"]] or "",
StorageVolume = building[colMap["Storage Capacity"]] or "",
Components = p.formatComponent(building[colMap["Recipe to Build"]] or ""),
PlacedWith = p.iconize({args = {[1] = building[colMap["Placed With"]] or ""}}),
AdditionalNotes = p.iconize({args = {[1] = building[colMap["Additional Notes"]] or ""}}),
PrimarySource = "Crafting" -- Default value, adjust as needed
}
-- Generate formatted output for template
local output = ""
for param, value in pairs(params) do
if value and value ~= "" then
output = output .. "|" .. param .. "=" .. value .. "\n"
end
end
return output
end
-- Function to format all refining recipes for a building
function p.formatRefiningRecipes(frame)
local buildingName = frame.args[1] or frame.args.name
if not buildingName then
return "Error: No building name provided"
end
-- Get refining recipes
local recipes, colMap = p.getRefiningRecipes(buildingName)
if not recipes or #recipes == 0 then
return "<tr><td colspan=\"4\" style=\"text-align:center;\">No recipes found.</td></tr>"
end
local output = ""
for _, recipe in ipairs(recipes) do
output = output .. p.formatRecipeRow(recipe, colMap)
end
return output
end
-- Helper function to display building with the template
function p.displayBuilding(frame)
local buildingName = frame.args[1] or frame.args.name
local customNotes = frame.args[2] or ""
if not buildingName then
return "Error: No building name provided"
end
-- Get building data directly
local buildingData, err = loadBuildingWikiTable()
if not buildingData then
return err
end
local rows = buildingData.rows
-- Find the building by name (column 2)
local building = nil
for _, row in ipairs(rows) do
if row[2] == buildingName then
building = row
break
end
end
if not building then
return "Error: Building '" .. buildingName .. "' not found"
end
-- Map building data to template parameters
local args = {}
-- Direct mapping with explicit indices based on the wiki table
args["Name"] = building[2] or "" -- Column 2: Name
args["Tier"] = building[3] or "" -- Column 3: Tier
args["Description"] = building[4] or "" -- Column 4: Description
args["JourneyRequirement"] = building[5] or "" -- Column 5: JourneyRequirement
args["Health"] = building[6] or "" -- Column 6: Health
args["EnergyConsumption"] = building[7] or "" -- Column 7: PowerCost
args["GeneratesPower"] = building[8] or "" -- Column 8: GeneratesPower
args["StorageSlots"] = building[9] or "" -- Column 9: StorageSlots
args["StorageVolume"] = building[10] or "" -- Column 10: StorageCapacity
args["Components"] = building[11] or "" -- Column 11: RecipeToBuild
args["PlacedWith"] = building[12] or "" -- Column 12: PlacedWith
args["ImageFile"] = building[15] or "" -- Column 15: ImageFile
args["PrimarySource"] = "Crafting" -- Default value
-- Use custom notes if provided, otherwise use notes from data
if customNotes and customNotes ~= "" then
args["AdditionalNotes"] = customNotes
else
args["AdditionalNotes"] = building[13] or "" -- Column 13: AdditionalNotes
end
-- Handle YouTube video (Column 20)
if building[20] and building[20] ~= "-" and building[20] ~= "" then
-- Set video title
args["VideoTitle"] = "Building Guide"
local youtubeUrl = building[20]
-- Extract video ID from the URL
local videoId = youtubeUrl:match("v=([%w-_]+)")
if videoId then
-- We'll store just the ID
args["VideoID"] = videoId
end
end
-- Replace "-" placeholders with empty strings
for key, value in pairs(args) do
if value == "-" then
args[key] = ""
end
end
-- Process recipe components
if args["Components"] and args["Components"] ~= "" then
args["Components"] = p.formatComponent(args["Components"])
end
-- Process descriptions and journey requirements with iconize
if args["Description"] and args["Description"] ~= "" then
args["Description"] = p.iconize({args = {[1] = args["Description"]}})
end
if args["JourneyRequirement"] and args["JourneyRequirement"] ~= "" then
args["JourneyRequirement"] = p.iconize({args = {[1] = args["JourneyRequirement"]}})
end
if args["PlacedWith"] and args["PlacedWith"] ~= "" then
args["PlacedWith"] = p.iconize({args = {[1] = args["PlacedWith"]}})
end
if args["AdditionalNotes"] and args["AdditionalNotes"] ~= "" then
args["AdditionalNotes"] = p.iconize({args = {[1] = args["AdditionalNotes"]}})
end
-- Generate formatted template call
local templateCall = "{{BuildingRefinerDisplay"
for param, value in pairs(args) do
if value and value ~= "" then
templateCall = templateCall .. "\n|" .. param .. "=" .. value
end
end
templateCall = templateCall .. "\n}}"
-- Expand the template with our parameters
return frame:preprocess(templateCall)
end
-- Debug function to show raw building data
function p.debugBuildingData(frame)
local buildingName = frame.args[1] or mw.title.getCurrentTitle().text
-- Get building data
local buildingData, err = loadBuildingWikiTable()
if not buildingData then
return "Error loading building data: " .. (err or "Unknown error")
end
local rows = buildingData.rows
-- Find the building by name
local building = nil
for _, row in ipairs(rows) do
if row[2] == buildingName then
building = row
break
end
end
if not building then
return "Building '" .. buildingName .. "' not found."
end
-- Output all column data
local output = "Data for building: " .. buildingName .. "\n\n"
for i, value in ipairs(building) do
output = output .. "Column " .. i .. ": " .. tostring(value or "nil") .. "\n"
end
return output
end
-- Debug function to show raw table data
function p.debugRawData(frame)
local buildingData, err = loadBuildingWikiTable()
if not buildingData then
return err
end
local colMap = buildingData.colMap
-- Show all column mappings
local output = "Column mappings:\n"
for name, index in pairs(colMap) do
output = output .. name .. " -> " .. index .. "\n"
end
output = output .. "\n\nFirst row raw data:\n"
local row = buildingData.rows[1]
for i = 1, #row do
output = output .. "Column " .. i .. ": " .. tostring(row[i]) .. "\n"
end
return output
end
-- Debug function to show template parameters
function p.debugTemplateParams(frame)
local buildingName = frame.args[1] or frame.args.name
if not buildingName then
return "Error: No building name provided"
end
-- Get building data directly
local buildingData, err = loadBuildingWikiTable()
if not buildingData then
return err
end
local colMap = buildingData.colMap
local rows = buildingData.rows
-- Find the building
local building = nil
for _, row in ipairs(rows) do
if row[colMap["Name"]] == buildingName then
building = row
break
end
end
if not building then
return "Error: Building '" .. buildingName .. "' not found"
end
-- Map building data to template parameters
local args = {
["Name"] = building[colMap["Name"]] or "",
["Description"] = building[colMap["Description"]] or "",
["JourneyRequirement"] = building[colMap["Journey Requirement"]] or "",
["ImageFile"] = building[colMap["Image File"]] or "",
["Health"] = building[colMap["Health"]] or "",
["EnergyConsumption"] = building[colMap["Power Cost"]] or "",
["GeneratesPower"] = building[colMap["Generates Power"]] or "",
["StorageSlots"] = building[colMap["Storage Slots"]] or "",
["StorageVolume"] = building[colMap["Storage Capacity"]] or "",
["Components"] = building[colMap["Recipe to Build"]] or "",
["PlacedWith"] = building[colMap["Placed With"]] or "",
["AdditionalNotes"] = building[colMap["Additional Notes"]] or "",
["PrimarySource"] = "Crafting" -- Default value, adjust as needed
}
-- Output the template parameters
local result = "Template Parameters:\n"
for param, value in pairs(args) do
result = result .. param .. " = " .. tostring(value) .. "\n"
end
return result
end
-- Function to generate a YouTube embed with customizable dimensions
function p.getYoutubeEmbed(frame)
local buildingName = frame.args[1] or mw.title.getCurrentTitle().text
-- Get optional dimensions parameters
local width = frame.args.width or 400
local height = frame.args.height or 300
local dimensions = width .. "x" .. height
-- Get building data
local buildingData, err = loadBuildingWikiTable()
if not buildingData then
return "Error loading data"
end
local rows = buildingData.rows
-- Find the building
local building = nil
for _, row in ipairs(rows) do
if row[2] == buildingName then
building = row
break
end
end
-- Changed from column 19 to column 20 to account for the new Tier column
if not building or not building[20] or building[20] == "-" or building[20] == "" then
return "Coming Soon"
end
-- Get YouTube URL and extract video ID (now from column 20)
local youtubeUrl = building[20]
local videoId = youtubeUrl:match("v=([%w-_]+)")
if not videoId then
return "Coming Soon"
end
-- Create YouTube tag with specified dimensions and centered alignment
local ytMarkup = string.format('<youtube dimensions="%s" alignment="center">%s</youtube>', dimensions, videoId)
-- Process the markup so MediaWiki parses it as wikitext
return frame:preprocess(ytMarkup)
end
-- Breadcrumb trail function
function p.breadcrumb(frame)
local buildingData, err = loadBuildingWikiTable()
if not buildingData then
return err
end
local rows = buildingData.rows
-- Use the passed parameter 'name' or the current page title
local buildingName = frame.args[1] or mw.title.getCurrentTitle().text
for _, row in ipairs(rows) do
if row[2] == buildingName then
-- Get categories (using hardcoded indices based on your table)
local cat1 = row[17] or "" -- Category1 (column 17)
local cat2 = row[18] or "" -- Category2 (column 18)
local cat3 = row[19] or "" -- Category3 (column 19)
-- Clean up categories (remove brackets and Category: prefix)
local function cleanCategory(cat)
if not cat or cat == "-" then return "" end
if cat:find("%[%[Category:") then
cat = cat:match("%[%[Category:%s*(.-)%s*%]%]")
elseif cat:find("%[%[") then
cat = cat:match("%[%[(.-)%]%]")
end
return mw.text.trim(cat)
end
cat1 = cleanCategory(cat1)
cat2 = cleanCategory(cat2)
cat3 = cleanCategory(cat3)
-- Build breadcrumb parts
local breadcrumbParts = {}
if cat1 ~= "" then
table.insert(breadcrumbParts, "[[" .. cat1 .. "]]")
end
if cat2 ~= "" then
table.insert(breadcrumbParts, "[[" .. cat2 .. "]]")
end
if cat3 ~= "" then
table.insert(breadcrumbParts, "[[" .. cat3 .. "]]")
end
-- Add current building name in bold
table.insert(breadcrumbParts, "'''" .. buildingName .. "'''")
return table.concat(breadcrumbParts, " > ")
end
end
return "Breadcrumb not available"
end
-- Get Category 3 for "Other X" title
function p.getCategory3(frame)
local buildingName = frame.args[1] or mw.title.getCurrentTitle().text
-- Get building data
local buildingData, err = loadBuildingWikiTable()
if not buildingData then
return "Buildings"
end
local rows = buildingData.rows
-- Find the building
for _, row in ipairs(rows) do
if row[2] == buildingName then
-- Get Category3 (column 19)
local cat3 = row[19] or ""
-- Clean up category
if cat3 == "-" or cat3 == "" then
return "Buildings"
end
-- Remove brackets if present
if cat3:find("%[%[") then
cat3 = cat3:match("%[%[(.-)%]%]")
end
return mw.text.trim(cat3)
end
end
return "Buildings" -- Default if building not found
end
-- Find related buildings based on Category 3
function p.relatedBuildings(frame)
local buildingName = frame.args[1] or mw.title.getCurrentTitle().text
-- Get building data
local buildingData, err = loadBuildingWikiTable()
if not buildingData then
return "Error loading building data"
end
local rows = buildingData.rows
-- Find current building and its Category3
local targetCategory = nil
for _, row in ipairs(rows) do
if row[2] == buildingName then
-- Get Category3 (column 19)
targetCategory = row[19] or ""
-- Clean up category
if targetCategory == "-" or targetCategory == "" then
return "No related buildings found"
end
-- Remove brackets if present
if targetCategory:find("%[%[") then
targetCategory = targetCategory:match("%[%[(.-)%]%]")
end
targetCategory = mw.text.trim(targetCategory)
break
end
end
if not targetCategory then
return "Building not found"
end
-- Find related buildings with the same Category3
local relatedBuildings = {}
for _, row in ipairs(rows) do
if row[2] ~= buildingName then -- Skip current building
local category = row[19] or ""
-- Clean up category
if category ~= "-" and category ~= "" then
-- Remove brackets if present
if category:find("%[%[") then
category = category:match("%[%[(.-)%]%]")
end
category = mw.text.trim(category)
if category == targetCategory then
table.insert(relatedBuildings, row)
end
end
end
end
if #relatedBuildings == 0 then
return "No other " .. targetCategory .. " found"
end
-- Format as a table
local output = '<table class="infobox-dune" style="width:100%">\n'
output = output .. "<tr>\n"
output = output .. "<th style=\"text-align:left;\">Name</th>\n"
output = output .. "<th style=\"text-align:left;\">Tier</th>\n"
output = output .. "<th style=\"text-align:left;\">Description</th>\n"
output = output .. "</tr>\n"
for _, building in ipairs(relatedBuildings) do
local name = building[2] or ""
local tier = building[3] or ""
local description = building[4] or ""
-- Clean up values
if tier == "-" then tier = "" end
if description == "-" then description = "" end
-- Format name with icon
local nameWithIcon = name
local iconFile = building[16] or "" -- IconFile (column 16)
if iconFile ~= "-" and iconFile ~= "" then
nameWithIcon = "[[File:" .. iconFile .. "|20px]] [[" .. name .. "]]"
else
nameWithIcon = "[[" .. name .. "]]"
end
-- Add table row
output = output .. "<tr>\n"
output = output .. "<td>" .. nameWithIcon .. "</td>\n"
output = output .. "<td>" .. tier .. "</td>\n"
output = output .. "<td>" .. description .. "</td>\n"
output = output .. "</tr>\n"
end
output = output .. "</table>"
return output
end
return p
