Module:Team
From eSportsAmaze
More actions
Documentation for this module may be created at Module:Team/doc
local p = {}
local cargo = mw.ext.cargo
local html = mw.html
local currentTitle = mw.title.getCurrentTitle()
-- ============================================================
-- HELPER: Argument Fetcher
-- ============================================================
local function getArgs(frame)
local args = {}
if frame:getParent() then
for k, v in pairs(frame:getParent().args) do args[k] = v end
end
for k, v in pairs(frame.args) do args[k] = v end
return args
end
-- ============================================================
-- HELPER: Sanitize Strings
-- ============================================================
local function clean(s)
if not s then return nil end
local cleaned = s:gsub("[\r\n]", ""):gsub("^%s*(.-)%s*$", "%1")
if cleaned == "" then return nil end
return cleaned
end
-- ============================================================
-- HELPER: Tier Class (MATCHES TOURNAMENT MODULE EXACTLY)
-- ============================================================
local function getTierClass(tier)
if not tier then return "tier-def" end
local t = tier:lower()
-- Loose matching to catch "A Tier", "A-Tier", "Tier A"
if string.find(t, "s") and string.find(t, "tier") then return "tier-s" end
if string.find(t, "a") and string.find(t, "tier") then return "tier-a" end
if string.find(t, "b") and string.find(t, "tier") then return "tier-b" end
if string.find(t, "c") and string.find(t, "tier") then return "tier-c" end
return "tier-def"
end
local function formatCurrency(amount)
if not amount then return "0" end
local n = tonumber(amount) or 0
local formatted = tostring(n):reverse():gsub("(%d%d%d)(%d%d%d)","%1,%2"):reverse()
return '<span class="indian-currency">₹ ' .. formatted .. '</span>'
end
local function getSocials(args)
local container = html.create('div'):addClass('fib-socials')
local hasSocials = false
local platforms = {
{arg='instagram', file='Icon_instagram.png'},
{arg='twitter', file='Icon_twitter.png'},
{arg='youtube', file='Icon_youtube.png'},
{arg='discord', file='Icon_discord.png'},
{arg='facebook', file='Icon_facebook.png'},
{arg='website', file='Icon_website.png'}
}
for _, p in ipairs(platforms) do
if args[p.arg] and args[p.arg] ~= "" then
hasSocials = true
container:wikitext('[[File:' .. p.file .. '|24px|link=' .. args[p.arg] .. '|class=social-img]]')
end
end
if hasSocials then return tostring(container) else return "" end
end
local function getInfoboxLogo(teamName, image, imageDark)
local lightFile = (image ~= "" and image) or (teamName .. '.png')
local darkFile = (imageDark ~= "" and imageDark) or (teamName .. '_dark.png')
local hasLight = mw.title.new('File:' .. lightFile).exists
local hasDark = mw.title.new('File:' .. darkFile).exists
local container = html.create('div'):addClass('fib-image')
local lSpan = container:tag('span'):addClass('logo-lightmode')
if hasLight then lSpan:wikitext('[[File:' .. lightFile .. '|220px]]') else lSpan:wikitext('[[File:Shield_team.png|180px]]') end
local dSpan = container:tag('span'):addClass('logo-darkmode')
if hasDark then dSpan:wikitext('[[File:' .. darkFile .. '|220px]]') elseif hasLight then dSpan:wikitext('[[File:' .. lightFile .. '|220px]]') else dSpan:wikitext('[[File:Shield_team_dark.png|180px]]') end
return tostring(container)
end
-- ============================================================
-- MAIN 1: TEAM INFOBOX
-- ============================================================
function p.infobox(frame)
local args = getArgs(frame)
local team = clean(args.name) or currentTitle.subpageText
local root = html.create('div'):addClass('flat-infobox')
root:tag('div'):addClass('fib-header'):tag('div'):addClass('fib-title'):wikitext(team)
root:wikitext(getInfoboxLogo(team, clean(args.image), clean(args.image_dark)))
local earnings = "0"
if cargo and cargo.query then
local results = cargo.query("PrizeMoney", "SUM(prize)=total", { where = "team = '" .. team:gsub("'", "\\'") .. "' AND (player='' OR player IS NULL)" })
if results and #results > 0 and results[1].total then earnings = results[1].total end
end
local rankVal = "Unranked"
if cargo and cargo.query then
local rResults = cargo.query("Krafton_Rankings", "rank", { where = "name = '" .. team:gsub("'", "\\'") .. "' AND type='Team'", limit = 1 })
if rResults and #rResults > 0 then rankVal = "#" .. rResults[1].rank end
end
local statusColor = "#333"
local statusText = clean(args.status) or "Active"
if args.status then
local s = args.status:lower()
if s == "active" then statusColor = "#16a34a" elseif s == "inactive" or s == "disbanded" then statusColor = "#dc2626" end
end
local grid1 = root:tag('div'):addClass('fib-grid')
grid1:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Status'):done():tag('div'):addClass('fib-value-sm'):css('color', statusColor):wikitext(statusText):done()
grid1:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Krafton Rank'):done():tag('div'):addClass('fib-value-sm'):wikitext(rankVal):done()
local grid2 = root:tag('div'):addClass('fib-grid')
grid2:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Country'):done():tag('div'):addClass('fib-value-sm'):wikitext(clean(args.country) or 'TBD'):done()
grid2:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Tag'):done():tag('div'):addClass('fib-value-sm'):wikitext(clean(args.short_code) or '-'):done()
if earnings and tonumber(earnings) and tonumber(earnings) > 0 then
root:tag('div'):addClass('fib-prize'):tag('div'):addClass('fib-label-sm'):wikitext('Total Earnings'):done():tag('div'):addClass('fib-prize-val'):wikitext(formatCurrency(earnings)):done()
end
local list = root:tag('div'):addClass('fib-list')
local function addRow(label, value)
if value and value ~= "" then list:tag('div'):addClass('fib-row'):tag('div'):addClass('fib-label'):wikitext(label):done():tag('div'):addClass('fib-data'):wikitext(value):done() end
end
addRow('Display Name', clean(args.other_team))
if args.sponsors then addRow('Sponsors', args.sponsors:gsub(",", "<br>")) end
root:wikitext(getSocials(args))
return tostring(root)
end
-- ============================================================
-- MAIN 2: HYBRID ROSTER (SORTED BY ROLE)
-- ============================================================
function p.roster(frame)
local args = getArgs(frame)
local team = clean(args.team) or currentTitle.subpageText
-- 1. Fetch Database Players
local dbPlayers = {}
if cargo and cargo.query then
local tables = "Players"
local fields = "id, real_name, role, nationality, image, _pageName"
local where = "current_team = '" .. team:gsub("'", "\\'") .. "' AND status='Active'"
local results = cargo.query(tables, fields, { where = where })
for _, row in ipairs(results) do
dbPlayers[row.id] = {
id = row.id,
name = row.real_name,
role = row.role,
flag = clean(row.nationality),
image = clean(row.image),
link = row._pageName,
source = "auto"
}
end
end
-- 2. Process Manual Inputs
local finalRoster = {}
for _, pData in pairs(dbPlayers) do table.insert(finalRoster, pData) end
for i = 1, 10 do
local mid = clean(args['player' .. i])
if mid and mid ~= "" then
if not dbPlayers[mid] then
table.insert(finalRoster, {
id = mid,
name = clean(args['name' .. i]) or "",
role = clean(args['role' .. i]) or "Player",
flag = clean(args['flag' .. i]) or "India",
image = clean(args['image' .. i]) or "",
link = mid,
source = "manual"
})
end
end
end
-- 3. Define Role Hierarchy & Colors
local roleConfig = {
{ key = "igl", sort = 1, color = "#eab308" },
{ key = "entry", sort = 2, color = "#f97316" },
{ key = "assault", sort = 3, color = "#3b82f6" },
{ key = "fragger", sort = 3, color = "#3b82f6" },
{ key = "support", sort = 4, color = "#22c55e" },
{ key = "medic", sort = 4, color = "#22c55e" },
{ key = "scout", sort = 5, color = "#14b8a6" },
{ key = "sniper", sort = 6, color = "#ef4444" },
{ key = "coach", sort = 7, color = "#a855f7" },
{ key = "analyst", sort = 8, color = "#a855f7" },
{ key = "manager", sort = 9, color = "#1f2937" }
}
-- 4. Assign Sort Priority & Color
for _, player in ipairs(finalRoster) do
local r = (player.role or ""):lower()
player.sortOrder = 99
player.color = "#64748b" -- Gray
for _, config in ipairs(roleConfig) do
if r:find(config.key) then
player.sortOrder = config.sort
player.color = config.color
break
end
end
end
-- 5. Sort
table.sort(finalRoster, function(a, b)
if a.sortOrder ~= b.sortOrder then
return a.sortOrder < b.sortOrder
else
return (a.id or ""):lower() < (b.id or ""):lower()
end
end)
-- 6. Render
local grid = html.create('div'):addClass('hero-roster-grid')
for _, player in ipairs(finalRoster) do
local card = grid:tag('div'):addClass('hero-player-card')
-- Header
local header = card:tag('div'):addClass('hero-card-image')
if player.image and player.image ~= "" then
header:wikitext('[[File:' .. player.image .. '|link=' .. player.link .. ']]')
else
header:wikitext('[[File:Player_Placeholder.png|link=' .. player.link .. ']]')
end
-- Body
local body = card:tag('div'):addClass('hero-card-body')
body:tag('div'):addClass('hero-role-pill')
:css('background-color', player.color)
:wikitext(player.role or "Player")
body:tag('div'):addClass('hero-player-id'):wikitext('[[' .. player.link .. '|' .. player.id .. ']]')
if player.name and player.name ~= "" then
body:tag('div'):addClass('hero-player-name'):wikitext(player.name)
end
if player.flag then
local safeFlag = player.flag:gsub(" ", "_")
local flagFile = "Flag_" .. safeFlag .. ".png"
body:tag('div'):addClass('hero-player-flag'):wikitext('[[File:' .. flagFile .. '|link=]] ' .. player.flag)
end
end
return tostring(grid)
end
-- ============================================================
-- MAIN 3: FORMER PLAYERS LIST (NO JOIN + FLAT UI DESIGN)
-- ============================================================
function p.formerPlayers(frame)
local args = getArgs(frame)
local team = clean(args.team) or currentTitle.subpageText
-- STEP 1: Get History
local history = cargo.query(
"Player_Former_Teams",
"player_id, role, join_date, leave_date",
{
where = "team = '" .. team:gsub("'", "\\'") .. "' AND leave_date != ''",
orderBy = "leave_date DESC",
limit = 100
}
)
if not history or #history == 0 then
return '<div style="font-style:italic; color:#64748b; padding:10px;">No former players recorded.</div>'
end
-- STEP 2: Get Page Names
local pageNames = {}
for i, row in ipairs(history) do
local pName = row.player_id
if pName and pName ~= "" then table.insert(pageNames, "'" .. pName:gsub("'", "\\'") .. "'") end
end
-- STEP 3: Get Details
local playerDetails = {}
if #pageNames > 0 then
local details = cargo.query("Players", "_pageName, real_name, id", { where = "_pageName IN (" .. table.concat(pageNames, ",") .. ")" })
if details then
for _, d in ipairs(details) do
playerDetails[d._pageName] = { realName = d.real_name, shortID = d.id }
end
end
end
-- STEP 4: Render
local tbl = html.create('table'):addClass('flat-data-table sortable')
local h = tbl:tag('tr')
h:tag('th'):wikitext('ID'); h:tag('th'):wikitext('Name'); h:tag('th'):wikitext('Role'); h:tag('th'):wikitext('Join Date'); h:tag('th'):wikitext('Leave Date')
for _, row in ipairs(history) do
local pName = row.player_id
local details = playerDetails[pName] or {}
local displayID = details.shortID
if not displayID or displayID == "" then displayID = pName:gsub("^.*/", "") end
local tr = tbl:tag('tr')
tr:tag('td'):addClass('t-id'):wikitext('[[' .. pName .. '|' .. displayID .. ']]')
tr:tag('td'):wikitext(details.realName or "-")
local rCell = tr:tag('td')
if row.role and row.role ~= "" then rCell:tag('span'):addClass('t-role'):wikitext(row.role) else rCell:wikitext("-") end
tr:tag('td'):addClass('t-date'):wikitext(row.join_date or "?")
tr:tag('td'):addClass('t-date'):wikitext(row.leave_date or "?")
end
return tostring(tbl)
end
-- ============================================================
-- MAIN 4: HISTORY
-- ============================================================
function p.history(frame)
local args = getArgs(frame)
local team = clean(args.team) or mw.title.getCurrentTitle().subpageText
local results = cargo.query("StageStandings", "tournament, stage, totalpts, matchesplayed, wwcd, elimpts, lastmatchrank, result", {
where = "team = '" .. team:gsub("'", "\\'") .. "'",
orderBy = "tournament DESC",
limit = 50
})
local root = html.create('div')
root:wikitext('== Tournament Statistics ==')
if #results > 0 then
local tbl = root:tag('table'):addClass('modern-history-table')
local thead = tbl:tag('thead'):tag('tr')
thead:tag('th'):wikitext('Tournament'); thead:tag('th'):wikitext('Stage'); thead:tag('th'):wikitext('Rank')
thead:tag('th'):wikitext('MP'); thead:tag('th'):wikitext('WWCD'); thead:tag('th'):wikitext('Elims'); thead:tag('th'):wikitext('Pts')
for _, row in ipairs(results) do
local tr = tbl:tag('tr')
local res = (row.result or ""):lower()
if res == "q" or res == "qualified" then tr:css('background-color', '#E9FFF0')
elseif res == "e" or res == "eliminated" then tr:css('background-color', '#FFE9E9') end
tr:tag('td'):css('font-weight','bold'):wikitext('[[' .. row.tournament .. ']]')
tr:tag('td'):wikitext(row.stage)
tr:tag('td'):css('font-weight','bold'):css('text-align','center'):wikitext('#' .. (row.lastmatchrank or '?'))
tr:tag('td'):css('text-align','center'):wikitext(row.matchesplayed)
tr:tag('td'):css('text-align','center'):wikitext(row.wwcd)
tr:tag('td'):css('text-align','center'):wikitext(row.elimpts)
tr:tag('td'):css('text-align','center'):css('font-weight','800'):wikitext(row.totalpts)
end
else root:wikitext("''No tournament data found for this team.''") end
return tostring(root)
end
-- ============================================================
-- MAIN 5: TEAM ACHIEVEMENTS (Matches CSS & Logic)
-- ============================================================
function p.achievements(frame)
local args = getArgs(frame)
local team = clean(args.team) or currentTitle.subpageText
-- STEP 1: Get Placements & Prizes
local results = cargo.query(
"PrizeMoney",
"tournament, placement, prize, award",
{
where = "team = '" .. team:gsub("'", "\\'") .. "' AND (player='' OR player IS NULL)",
orderBy = "prize DESC",
limit = 50
}
)
local root = html.create('div')
if not results or #results == 0 then
root:wikitext('<div style="font-style:italic; color:#64748b; padding:10px;">No achievements recorded.</div>')
return tostring(root)
end
-- STEP 2: Collect Tournament Names
local tourneyNames = {}
for _, row in ipairs(results) do
if row.tournament and row.tournament ~= "" then
table.insert(tourneyNames, "'" .. row.tournament:gsub("'", "\\'") .. "'")
end
end
-- STEP 3: Fetch Date & Tier
local tDetails = {}
if #tourneyNames > 0 then
local tResults = cargo.query("Tournaments", "name, end_date, tier", { where = "name IN (" .. table.concat(tourneyNames, ",") .. ")" })
if tResults then
for _, t in ipairs(tResults) do tDetails[t.name] = { date = t.end_date, tier = t.tier } end
end
end
-- STEP 4: Render Table
local tbl = root:tag('table'):addClass('achievements-table sortable')
local h = tbl:tag('tr')
h:tag('th'):wikitext('Date')
h:tag('th'):wikitext('Tier')
h:tag('th'):wikitext('Tournament')
h:tag('th'):wikitext('Place')
h:tag('th'):css('text-align', 'right'):wikitext('Prize')
for _, row in ipairs(results) do
local tr = tbl:tag('tr')
local info = tDetails[row.tournament] or {}
tr:tag('td'):addClass('ac-date'):wikitext(info.date or "-")
-- UPDATED TIER CELL LOGIC (Using unified helper)
local tierCell = tr:tag('td'):addClass('ac-tier')
local tierClass = getTierClass(info.tier) -- Uses the new helper
if info.tier and info.tier ~= "" then
tierCell:tag('span'):addClass('tier-badge ' .. tierClass):wikitext(info.tier)
else
tierCell:wikitext("-")
end
tr:tag('td'):css('font-weight', '600'):wikitext('[[' .. row.tournament .. ']]')
local pCell = tr:tag('td'):addClass('ac-place')
local rank = tonumber(row.placement) or 99
local badgeClass = "place-def"
local placeText = row.placement or "-"
if rank == 1 then badgeClass = "place-1"; placeText = "1st"
elseif rank == 2 then badgeClass = "place-2"; placeText = "2nd"
elseif rank == 3 then badgeClass = "place-3"; placeText = "3rd"
elseif placeText:match("^%d+$") then placeText = placeText .. "th"
end
pCell:tag('span'):addClass('place-badge ' .. badgeClass):wikitext(placeText)
tr:tag('td'):addClass('ac-prize'):wikitext(formatCurrency(row.prize))
end
return tostring(root)
end
return p