Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Module:Rankings: Difference between revisions

From eSportsAmaze
Created page with "local p = {} local cargo = mw.ext.cargo local html = mw.html local function sqlEscape(s) if not s then return "" end return s:gsub("\\", "\\\\"):gsub("'", "\\'") end -- Gets difference between today and the tournament end date local function getDaysDiff(dateStr) if not dateStr or dateStr == "" then return 0 end local y, m, d = dateStr:match("(%d+)-(%d+)-(%d+)") if not y then return 0 end local endTs = os.time({year=y, month=m, day=d}) local nowTs =..."
 
No edit summary
Line 5: Line 5:
local function sqlEscape(s) if not s then return "" end return s:gsub("\\", "\\\\"):gsub("'", "\\'") end
local function sqlEscape(s) if not s then return "" end return s:gsub("\\", "\\\\"):gsub("'", "\\'") end


-- Gets difference between today and the tournament end date
local function getDaysDiff(dateStr)
local function getDaysDiff(dateStr)
     if not dateStr or dateStr == "" then return 0 end
     if not dateStr or dateStr == "" then return 0 end
Line 11: Line 10:
     if not y then return 0 end
     if not y then return 0 end
     local endTs = os.time({year=y, month=m, day=d})
     local endTs = os.time({year=y, month=m, day=d})
     local nowTs = os.time() -- Fetches the live current date
     local nowTs = os.time()  
     local diff = os.difftime(nowTs, endTs)
     local diff = os.difftime(nowTs, endTs)
     local days = math.floor(diff / 86400)
     local days = math.floor(diff / 86400)
Line 18: Line 17:
end
end


-- Team Matrix Points
local function getTeamBasePts(tier, rank)
local function getTeamBasePts(tier, rank)
     local t = tier:lower()
     local t = tier:lower()
Line 40: Line 38:
end
end


-- Decay Multipliers
local function getTeamDecay(days)
local function getTeamDecay(days)
     if days <= 180 then return 1
     if days <= 180 then return 1
Line 59: Line 56:


local function buildLogo(teamName)
local function buildLogo(teamName)
     local lightFile = teamName:gsub("'", "") .. '.png'
     local lightFile = "Shield_team.png"
    local darkFile = teamName:gsub("'", "") .. '_dark.png'
    local darkFile = "Shield_team_dark.png"
   
    if teamName and teamName ~= "" then
        lightFile = teamName:gsub("'", "") .. '.png'
        darkFile = teamName:gsub("'", "") .. '_dark.png'
    end
   
     local container = html.create('span'):addClass('team-logo-wrapper')
     local container = html.create('span'):addClass('team-logo-wrapper')
     container:tag('span'):addClass('logo-lightmode'):wikitext('[[File:' .. lightFile .. '|24px|link=|class=team-logo]]')
     container:tag('span'):addClass('logo-lightmode'):wikitext('[[File:' .. lightFile .. '|24px|link=|class=team-logo]]')
Line 77: Line 80:


     if statType == "team" then
     if statType == "team" then
         local results = cargo.query("RankingData_Team", "tournament, tier, end_date, team, rank", { limit = 5000 })
         local results = cargo.query("RankingData_Team", "tournament, tier, end_date, team, rank", { orderBy = "end_date DESC", limit = 5000 })
         if not results or #results == 0 then return 'No data.' end
         if not results or #results == 0 then return 'No data.' end
          
          
Line 83: Line 86:
         for _, r in ipairs(results) do
         for _, r in ipairs(results) do
             local t = r.team
             local t = r.team
             if not tData[t] then tData[t] = { team = t, points = 0, events = 0 } end
             if t and t ~= "" then
           
                if not tData[t] then tData[t] = { team = t, points = 0, events = 0 } end
            local days = getDaysDiff(r.end_date)
               
            local base = getTeamBasePts(r.tier, tonumber(r.rank) or 99)
                local days = getDaysDiff(r.end_date)
            local decay = getTeamDecay(days)
                local base = getTeamBasePts(r.tier, tonumber(r.rank) or 99)
            local finalPts = base * decay
                local decay = getTeamDecay(days)
           
                local finalPts = base * decay
            if finalPts > 0 then
               
                tData[t].points = tData[t].points + finalPts
                if finalPts > 0 then
                tData[t].events = tData[t].events + 1
                    tData[t].points = tData[t].points + finalPts
                    tData[t].events = tData[t].events + 1
                end
             end
             end
         end
         end
Line 120: Line 125:


     elseif statType == "player" then
     elseif statType == "player" then
         local results = cargo.query("RankingData_Player", "tournament, tier, end_date, player, team, finishes, mvp_tourney, igl, survivor, mvp_finals, emerging", { limit = 5000 })
         local results = cargo.query("RankingData_Player", "tournament, tier, end_date, player, team, finishes, mvp_tourney, igl, survivor, mvp_finals, emerging", { orderBy = "end_date DESC", limit = 5000 })
         if not results or #results == 0 then return 'No data.' end
         if not results or #results == 0 then return 'No data.' end
          
          
Line 126: Line 131:
         for _, r in ipairs(results) do
         for _, r in ipairs(results) do
             local p = r.player
             local p = r.player
             if not pData[p] then pData[p] = { player = p, team = r.team, points = 0, events = 0 } end
             if p and p ~= "" then
           
                -- Create player entry if it doesn't exist
            local days = getDaysDiff(r.end_date)
                if not pData[p] then  
            local decay = getPlayerDecay(days)
                    pData[p] = { player = p, team = r.team, points = 0, events = 0 }  
           
                else
            local t = (r.tier or ""):lower()
                    -- Smart fallback: If their current team is blank, but an older event has a team, use it!
            local mult = 1
                    if (not pData[p].team or pData[p].team == "") and r.team and r.team ~= "" then
            if t:find("publisher") then mult = 2 elseif t:find("tier 1") then mult = 1.5 end
                        pData[p].team = r.team
           
                    end
            local base = (tonumber(r.finishes) or 0) * mult
                end
            if tonumber(r.mvp_tourney) == 1 then base = base + 20 end
               
            if tonumber(r.igl) == 1 then base = base + 10 end
                local days = getDaysDiff(r.end_date)
            if tonumber(r.survivor) == 1 then base = base + 10 end
                local decay = getPlayerDecay(days)
            if tonumber(r.mvp_finals) == 1 then base = base + 10 end
               
            if tonumber(r.emerging) == 1 then base = base + 5 end
                local t = (r.tier or ""):lower()
           
                local mult = 1
            local finalPts = base * decay
                if t:find("publisher") then mult = 2 elseif t:find("tier 1") then mult = 1.5 end
            if finalPts > 0 then
               
                pData[p].points = pData[p].points + finalPts
                local base = (tonumber(r.finishes) or 0) * mult
                pData[p].events = pData[p].events + 1
                if tonumber(r.mvp_tourney) == 1 then base = base + 20 end
                if tonumber(r.igl) == 1 then base = base + 10 end
                if tonumber(r.survivor) == 1 then base = base + 10 end
                if tonumber(r.mvp_finals) == 1 then base = base + 10 end
                if tonumber(r.emerging) == 1 then base = base + 5 end
               
                local finalPts = base * decay
                if finalPts > 0 then
                    pData[p].points = pData[p].points + finalPts
                    pData[p].events = pData[p].events + 1
                end
             end
             end
         end
         end
Line 171: Line 186:
             local infoDiv = pCell:tag('div'):css('line-height','1.1')
             local infoDiv = pCell:tag('div'):css('line-height','1.1')
             infoDiv:tag('div'):addClass('player-name-txt'):wikitext('[[' .. d.player .. ']]')
             infoDiv:tag('div'):addClass('player-name-txt'):wikitext('[[' .. d.player .. ']]')
             infoDiv:tag('div'):css('font-size','0.7em'):css('color','var(--text-muted)'):css('text-transform','uppercase'):css('font-weight','700'):wikitext('[[' .. d.team .. ']]')
              
            -- Display "Free Agent" if team is completely blank across all their events
            if d.team and d.team ~= "" then
                infoDiv:tag('div'):css('font-size','0.7em'):css('color','var(--text-muted)'):css('text-transform','uppercase'):css('font-weight','700'):wikitext('[[' .. d.team .. ']]')
            else
                infoDiv:tag('div'):css('font-size','0.7em'):css('color','var(--text-muted)'):css('text-transform','uppercase'):css('font-weight','700'):css('opacity','0.5'):wikitext('Free Agent')
            end
              
              
             tr:tag('td'):addClass('stat-col'):wikitext(d.events)
             tr:tag('td'):addClass('stat-col'):wikitext(d.events)

Revision as of 13:02, 22 May 2026

Documentation for this module may be created at Module:Rankings/doc

local p = {}
local cargo = mw.ext.cargo
local html = mw.html

local function sqlEscape(s) if not s then return "" end return s:gsub("\\", "\\\\"):gsub("'", "\\'") end

local function getDaysDiff(dateStr)
    if not dateStr or dateStr == "" then return 0 end
    local y, m, d = dateStr:match("(%d+)-(%d+)-(%d+)")
    if not y then return 0 end
    local endTs = os.time({year=y, month=m, day=d})
    local nowTs = os.time() 
    local diff = os.difftime(nowTs, endTs)
    local days = math.floor(diff / 86400)
    if days < 0 then days = 0 end
    return days
end

local function getTeamBasePts(tier, rank)
    local t = tier:lower()
    local col = 0
    if t:find("publisher") then col = 1
    elseif t:find("tier 1") then col = 2
    elseif t:find("tier 2") then col = 3
    elseif t:find("tier 3") then col = 4
    else return 0 end

    if rank == 1 then return ({1000, 800, 600, 400})[col]
    elseif rank == 2 then return ({800, 700, 500, 350})[col]
    elseif rank == 3 then return ({700, 600, 400, 300})[col]
    elseif rank == 4 then return ({600, 500, 300, 250})[col]
    elseif rank == 5 then return ({500, 400, 250, 200})[col]
    elseif rank >= 6 and rank <= 10 then return ({400, 300, 200, 150})[col]
    elseif rank >= 11 and rank <= 20 then return ({300, 200, 150, 100})[col]
    elseif rank >= 21 and rank <= 30 then return ({200, 100, 75, 50})[col]
    elseif rank >= 31 and rank <= 48 then return ({100, 50, 35, 25})[col]
    end return 0
end

local function getTeamDecay(days)
    if days <= 180 then return 1
    elseif days <= 270 then return 0.75
    elseif days <= 365 then return 0.5
    elseif days <= 1095 then return 0.1
    else return 0 end
end

local function getPlayerDecay(days)
    if days <= 180 then return 1
    elseif days <= 240 then return 0.75
    elseif days <= 300 then return 0.5
    elseif days <= 365 then return 0.25
    elseif days <= 1095 then return 0.1
    else return 0 end
end

local function buildLogo(teamName)
    local lightFile = "Shield_team.png"
    local darkFile = "Shield_team_dark.png"
    
    if teamName and teamName ~= "" then
        lightFile = teamName:gsub("'", "") .. '.png'
        darkFile = teamName:gsub("'", "") .. '_dark.png'
    end
    
    local container = html.create('span'):addClass('team-logo-wrapper')
    container:tag('span'):addClass('logo-lightmode'):wikitext('[[File:' .. lightFile .. '|24px|link=|class=team-logo]]')
    container:tag('span'):addClass('logo-darkmode'):wikitext('[[File:' .. darkFile .. '|24px|link=|class=team-logo]]')
    return tostring(container)
end

function p.main(frame)
    local args = frame:getParent().args
    if not args.type then args = frame.args end
    local statType = (args.type or "team"):lower()
    local limit = tonumber(args.limit) or 100
    
    local root = html.create('div'):addClass('standings-wrapper')
    local tbl = root:tag('table'):addClass('standings-card-table stats-card-table')

    if statType == "team" then
        local results = cargo.query("RankingData_Team", "tournament, tier, end_date, team, rank", { orderBy = "end_date DESC", limit = 5000 })
        if not results or #results == 0 then return 'No data.' end
        
        local tData = {}
        for _, r in ipairs(results) do
            local t = r.team
            if t and t ~= "" then
                if not tData[t] then tData[t] = { team = t, points = 0, events = 0 } end
                
                local days = getDaysDiff(r.end_date)
                local base = getTeamBasePts(r.tier, tonumber(r.rank) or 99)
                local decay = getTeamDecay(days)
                local finalPts = base * decay
                
                if finalPts > 0 then
                    tData[t].points = tData[t].points + finalPts
                    tData[t].events = tData[t].events + 1
                end
            end
        end
        
        local list = {}
        for _, d in pairs(tData) do if d.points > 0 then table.insert(list, d) end end
        table.sort(list, function(a, b) return a.points > b.points end)
        
        local th = tbl:tag('tr')
        th:tag('th'):addClass('sticky-col sticky-1'):wikitext('Rank')
        th:tag('th'):addClass('sticky-col sticky-2 stat-team'):wikitext('Team')
        th:tag('th'):addClass('stat-col'):wikitext('Events Counted')
        th:tag('th'):addClass('stat-col'):wikitext('Total Points')
        
        for i = 1, math.min(#list, limit) do
            local d = list[i]
            local tr = tbl:tag('tr'):addClass('standings-row')
            tr:tag('td'):addClass('sticky-col sticky-1 dyn-rank'):css('text-align','center'):css('font-weight','800')
            
            local teamCell = tr:tag('td'):addClass('sticky-col sticky-2 stat-team team-name-cell')
            teamCell:wikitext(buildLogo(d.team))
            teamCell:tag('span'):css('font-size','0.95em'):css('font-weight','700'):wikitext('[[' .. d.team .. ']]')
            
            tr:tag('td'):addClass('stat-col'):wikitext(d.events)
            tr:tag('td'):addClass('stat-col'):css('font-weight','800'):css('color','#00509d'):css('font-size','1.1em'):wikitext(string.format("%.2f", d.points))
        end

    elseif statType == "player" then
        local results = cargo.query("RankingData_Player", "tournament, tier, end_date, player, team, finishes, mvp_tourney, igl, survivor, mvp_finals, emerging", { orderBy = "end_date DESC", limit = 5000 })
        if not results or #results == 0 then return 'No data.' end
        
        local pData = {}
        for _, r in ipairs(results) do
            local p = r.player
            if p and p ~= "" then
                -- Create player entry if it doesn't exist
                if not pData[p] then 
                    pData[p] = { player = p, team = r.team, points = 0, events = 0 } 
                else
                    -- Smart fallback: If their current team is blank, but an older event has a team, use it!
                    if (not pData[p].team or pData[p].team == "") and r.team and r.team ~= "" then
                        pData[p].team = r.team
                    end
                end
                
                local days = getDaysDiff(r.end_date)
                local decay = getPlayerDecay(days)
                
                local t = (r.tier or ""):lower()
                local mult = 1
                if t:find("publisher") then mult = 2 elseif t:find("tier 1") then mult = 1.5 end
                
                local base = (tonumber(r.finishes) or 0) * mult
                if tonumber(r.mvp_tourney) == 1 then base = base + 20 end
                if tonumber(r.igl) == 1 then base = base + 10 end
                if tonumber(r.survivor) == 1 then base = base + 10 end
                if tonumber(r.mvp_finals) == 1 then base = base + 10 end
                if tonumber(r.emerging) == 1 then base = base + 5 end
                
                local finalPts = base * decay
                if finalPts > 0 then
                    pData[p].points = pData[p].points + finalPts
                    pData[p].events = pData[p].events + 1
                end
            end
        end
        
        local list = {}
        for _, d in pairs(pData) do if d.points > 0 then table.insert(list, d) end end
        table.sort(list, function(a, b) return a.points > b.points end)
        
        local th = tbl:tag('tr')
        th:tag('th'):addClass('sticky-col sticky-1'):wikitext('Rank')
        th:tag('th'):addClass('sticky-col sticky-logo'):wikitext('Team')
        th:tag('th'):addClass('sticky-col sticky-player stat-team'):wikitext('Player')
        th:tag('th'):addClass('stat-col'):wikitext('Events Counted')
        th:tag('th'):addClass('stat-col'):wikitext('Total Points')
        
        for i = 1, math.min(#list, limit) do
            local d = list[i]
            local tr = tbl:tag('tr'):addClass('standings-row')
            tr:tag('td'):addClass('sticky-col sticky-1 dyn-rank'):css('text-align','center'):css('font-weight','800')
            
            local logoCell = tr:tag('td'):addClass('sticky-col sticky-logo')
            logoCell:wikitext(buildLogo(d.team))
            
            local pCell = tr:tag('td'):addClass('sticky-col sticky-player stat-team team-name-cell')
            local infoDiv = pCell:tag('div'):css('line-height','1.1')
            infoDiv:tag('div'):addClass('player-name-txt'):wikitext('[[' .. d.player .. ']]')
            
            -- Display "Free Agent" if team is completely blank across all their events
            if d.team and d.team ~= "" then
                infoDiv:tag('div'):css('font-size','0.7em'):css('color','var(--text-muted)'):css('text-transform','uppercase'):css('font-weight','700'):wikitext('[[' .. d.team .. ']]')
            else
                infoDiv:tag('div'):css('font-size','0.7em'):css('color','var(--text-muted)'):css('text-transform','uppercase'):css('font-weight','700'):css('opacity','0.5'):wikitext('Free Agent')
            end
            
            tr:tag('td'):addClass('stat-col'):wikitext(d.events)
            tr:tag('td'):addClass('stat-col'):css('font-weight','800'):css('color','#00509d'):css('font-size','1.1em'):wikitext(string.format("%.2f", d.points))
        end
    end
    
    return tostring(root)
end

return p