Module:TeamsMatchup/versus: Difference between revisions
From Liquipedia Call of Duty Wiki
mNo edit summary |
No edit summary |
||
| Line 175: | Line 175: | ||
:css('height', '100%') | :css('height', '100%') | ||
:css('width', '100%') | :css('width', '100%') | ||
:css('font-weight', 'bold') | :css('font-weight', 'bold') | ||
:css('display', 'flex') | :css('display', 'flex') | ||
Revision as of 17:40, 30 August 2025
Documentation for this module may be created at Module:TeamsMatchup/versus/doc
local p = {} -- p stands for package
local DateExt = require('Module:Date/Ext')
local getArgs = require('Module:Arguments').getArgs
local args
function p.queryMatchLPDB(frame, args)
local LPDBoutput = mw.ext.LiquipediaDB.lpdb('match', {
conditions = '[[stream_' .. args.provider .. '::' .. args.channel .. ']] AND [[finished::0]] AND [[date::!' .. DateExt.defaultDateTime .. ']] AND [[matchid::!-1]] AND [[status::!cancelled]] AND [[status::!postponed]]',
order = 'date asc',
limit = 1
})
return LPDBoutput[1]
end
function p.queryLogoLPDB(frame, args, pagename, team)
local LPDBoutput = mw.ext.LiquipediaDB.lpdb('placement', {
conditions = '[[participant::' .. team .. ']] AND [[pagename::' .. pagename .. ']]',
query = 'image, imagedark',
limit = 1
})
if LPDBoutput == {} then
return {light = 'File:Crossfire default lightmode.png', dark = 'File:Crossfire default darkmode.png'}
else
return {light = (LPDBoutput[1] or {}).image or 'File:Crossfire default lightmode.png', dark = (LPDBoutput[1] or {}).imagedark or 'File:Crossfire default darkmode.png'}
end
end
function p.queryTournamentLogo(pagename)
local LPDBoutput = mw.ext.LiquipediaDB.lpdb('tournament', {
conditions = '[[pagename::' .. pagename .. ']]',
query = 'banner, extradata',
limit = 1
})
local lightmode = (LPDBoutput[1] or {}).banner
local darkmode = (LPDBoutput[1] or {}).bannerdark
return {lightmode = lightmode, darkmode = darkmode ~= '' and darkmode or lightmode}
end
function p.printPlayerRow(frame, wrapper, player, flag)
player = player or ''
local LPDBoutput = mw.ext.LiquipediaDB.lpdb('player', {
conditions = '[[pagename::' .. mw.ext.TeamLiquidIntegration.resolve_redirect(player):gsub(' ','_') .. ']]',
limit = 1
})
local image
if (LPDBoutput[1] or {}).image and (LPDBoutput[1] or {}).image ~= '' then
image = 'File:' .. LPDBoutput[1].image
elseif (((LPDBoutput[1] or {}).extradata or {}).image) and (((LPDBoutput[1] or {}).extradata or {}).image ~= '') then
image = 'File:' .. ((LPDBoutput[1] or {}).extradata or {}).image
else
image = 'File:Blank Player Image.png'
end
if player == '' then
display = '<abbr title="To Be Determined">TBD</abbr>'
else
display = frame:expandTemplate{title = 'player', args = {player:gsub(' %((.*)%)', ''), link = player, flag = flag:lower()}}
end
tr = wrapper:tag('tr')
td = tr:tag('td')
:css('padding','0')
:css('text-align','center')
:wikitext('[[' .. image ..'|225x150px|link=' .. player .. ']]')
tr = wrapper:tag('tr')
th = tr:tag('th')
:css('position','absolute')
:css('margin-top','-32px')
:css('width','225px')
:css('opacity','95%')
:wikitext(display)
return wrapper
end
function p.create(frame)
local args = getArgs(frame)
if args.provider == nil or args.channel == nil then
return ''
end
local match = p.queryMatchLPDB(frame, args) or {}
if match.pagename == nil then
return ''
end
mw.ext.VariablesLua.vardefine('match_team1', match.opponent1)
mw.ext.VariablesLua.vardefine('match_team2', match.opponent2)
mw.ext.VariablesLua.vardefine('match_pagename', match.pagename)
mw.ext.VariablesLua.vardefine('match_staticid', match.staticid)
mw.ext.VariablesLua.vardefine('match_matchid', match.matchid)
if match.parent == '' then
match.parent = nil
end
local team1_logos = p.queryLogoLPDB(frame, args, (match.parent or match.pagename), match.opponent1)
local team2_logos = p.queryLogoLPDB(frame, args, (match.parent or match.pagename), match.opponent2)
local team1_wins
local team2_wins
local team1_losses
local team2_losses
local team1_winrate
local team2_winrate
local matchDate = args.date or os.date("%Y-%m-%d", (os.time() - 7884000))
local timezoneID
if ((match.extradata or {}).timezoneID == '') or ((match.extradata or {}).timezoneID == nil) then
timezoneID = 'UTC'
else
timezoneID = (match.extradata or {}).timezoneID
end
local formattedDate = p.formatDate(p.adjustDate(match.date,(match.extradata or {}).timezone)) .. ' ' .. frame:expandTemplate{ title='Abbr/' .. (timezoneID or 'UTC')}
local team1_h2h
local team2_h2h
local team1_h2hg
local team2_h2hg
local wrapper = mw.html.create('div')
:addClass('row')
:css('text-align','center')
:css('border','1px solid #bbbbbb !important')
:css('margin','5px 0')
:css('padding', '5px')
:css('min-height', '170px')
local colteam1 = wrapper:tag('div')
:addClass('col-sm-4')
:addClass('col-xs-6')
:addClass('col-sm-pull-4')
:css('display', 'flex')
:css('flex-direction', 'column')
colteam1:tag('div')
:css('margin', 'auto')
:addClass('logo lightmode')
:wikitext('[[' .. team1_logos.light ..'|150x150px|link=' .. match.opponent1 .. ']]')
colteam1:tag('div')
:css('margin', 'auto')
:css('display', 'none')
:addClass('logo darkmode')
:wikitext('[[' .. team1_logos.dark ..'|150x150px|link=' .. match.opponent1 .. ']]')
colteam1:tag('strong')
:css('font-size','130%')
:wikitext('[[' .. match.opponent1 .. '|' .. match.opponent1:gsub(' %((.*)%)', '') .. ']]')
local colvs = wrapper:tag('div')
:addClass('col-sm-4')
:addClass('col-xs-12')
:addClass('col-sm-push-4')
:css('min-height', '160px')
local background = colvs:tag('div')
:css('position', 'absolute')
:css('height', '100%')
:css('width', '100%')
:css('opacity', '15%')
:css('display', 'flex')
local logos = p.queryTournamentLogo(match.parent ~= '' and match.parent or match.pagename)
background:tag('div')
:css('margin', 'auto')
:wikitext('<span class="banner lightmode">[[File:' .. (logos.lightmode or 'Filler 600px.png') .. '|300x155px|link=]]</span>')
:wikitext('<span class="banner darkmode">[[File:' .. (logos.darkmode or 'Filler 600px.png') .. '|300x155px|link=]]</span>')
local infodiv = colvs:tag('div')
:css('position', 'absolute')
:css('height', '100%')
:css('width', '100%')
:css('font-weight', 'bold')
:css('display', 'flex')
:css('flex-direction', 'column')
infodiv:tag('span')
:css('font-size','125%')
:wikitext('[[' .. match.pagename .. '|' .. match.tournament .. ']]')
infodiv:tag('span')
:css('margin', 'auto')
:css('font-size','250%')
:wikitext('VS')
infodiv:tag('span')
:wikitext(frame:expandTemplate({title = 'countdown', args = {date = formattedDate, rawdatetime = 'true'}}))
local colteam2 = wrapper:tag('div')
:addClass('col-sm-4')
:addClass('col-xs-6')
:addClass('pull-right')
:css('display', 'flex')
:css('flex-direction', 'column')
colteam2:tag('div')
:css('margin', 'auto')
:addClass('logo lightmode')
:wikitext('[[' .. team2_logos.light ..'|150x150px|link=' .. match.opponent2 .. ']]')
colteam2:tag('div')
:css('margin', 'auto')
:css('display', 'none')
:addClass('logo darkmode')
:wikitext('[[' .. team2_logos.dark ..'|150x150px|link=' .. match.opponent2 .. ']]')
colteam2:tag('strong')
:css('font-size','130%')
:wikitext('[[' .. match.opponent2 .. '|' .. match.opponent2:gsub(' %((.*)%)', '') .. ']]')
local wrapper2 = mw.html.create('table')
:addClass('table')
:addClass('wikitable')
:css('float','left')
:css('margin','0')
:css('width', '227px')
tr = wrapper2:tag('tr')
:addClass('wiki-backgroundcolor-light')
:css('font-size','150%')
th = tr:tag('th')
:css('background-color','#c1dfdf !important')
:css('padding','5px')
:wikitext('Players')
p.printPlayerRow(frame, wrapper2, match.opponent1players.p1, match.opponent1players.p1flag)
p.printPlayerRow(frame, wrapper2, match.opponent1players.p2, match.opponent1players.p2flag)
p.printPlayerRow(frame, wrapper2, match.opponent1players.p3, match.opponent1players.p3flag)
p.printPlayerRow(frame, wrapper2, match.opponent1players.p4, match.opponent1players.p4flag)
p.printPlayerRow(frame, wrapper2, match.opponent1players.p5, match.opponent1players.p5flag)
local wrapper3 = mw.html.create('table')
:addClass('table')
:addClass('wikitable')
:css('float','right')
:css('margin','0')
:css('width', '227px')
tr = wrapper3:tag('tr')
:addClass('wiki-backgroundcolor-light')
:css('font-size','150%')
th = tr:tag('th')
:css('background-color','#c1dfdf !important')
:css('padding','5px')
:wikitext('Players')
p.printPlayerRow(frame, wrapper3, match.opponent2players.p1, match.opponent2players.p1flag)
p.printPlayerRow(frame, wrapper3, match.opponent2players.p2, match.opponent2players.p2flag)
p.printPlayerRow(frame, wrapper3, match.opponent2players.p3, match.opponent2players.p3flag)
p.printPlayerRow(frame, wrapper3, match.opponent2players.p4, match.opponent2players.p4flag)
p.printPlayerRow(frame, wrapper3, match.opponent2players.p5, match.opponent2players.p5flag)
local wrapper4 = mw.html.create('div')
:css('width','80%')
local div = wrapper4:tag('div')
:css('display','inline-block')
:css('vertical-align','top')
:css('width','25%')
:css('margin-right','5px')
local div = wrapper4:tag('div')
:css('display','inline-block')
:css('vertical-align','top')
:css('width','25%')
local table = div:tag('table')
:addClass('table stats')
:css('border','1px solid #bbbbbb !important')
:css('text-align','center')
:css('width','100%')
tr = table:tag('tr')
:addClass('wiki-backgroundcolor-light')
:css('font-size','130%')
th = tr:tag('th')
:attr('colspan',3)
:css('padding','5px')
:wikitext(frame:expandTemplate{title = 'Abbr', args = {'Overview Stats', 'Over the last 3 months'}})
data = mw.ext.LiquipediaDB.lpdb('match', {
limit = 5000,
offset = 0,
conditions = '(([[opponent1::' .. match.opponent1 .. ']] AND [[winner::1]]) OR ([[opponent2::' .. match.opponent1 .. ']] AND [[winner::2]])) AND [[date::>' .. matchDate .. ']] AND [[matchid::!-1]]',
query = 'count::winner',
})
team1_wins = tonumber(data[1].count_winner)
data = mw.ext.LiquipediaDB.lpdb('match', {
limit = 5000,
offset = 0,
conditions = '(([[opponent1::' .. match.opponent1 .. ']] AND [[winner::2]]) OR ([[opponent2::' .. match.opponent1 .. ']] AND [[winner::1]])) AND [[date::>' .. matchDate .. ']] AND [[matchid::!-1]]',
query = 'count::winner',
})
team1_losses = tonumber(data[1].count_winner)
team1_winrate = (team1_wins / (team1_wins + team1_losses)) * 100
tr = table:tag('tr')
:addClass('stats-row')
td = tr:tag('td')
:css('text-align','center')
:wikitext(p.round(team1_winrate, 0) .. '%')
data = mw.ext.LiquipediaDB.lpdb('match', {
limit = 5000,
offset = 0,
conditions = '(([[opponent1::' .. match.opponent2 .. ']] AND [[winner::1]]) OR ([[opponent2::' .. match.opponent2 .. ']] AND [[winner::2]])) AND [[date::>' .. matchDate .. ']] AND [[matchid::!-1]]',
query = 'count::winner',
})
team2_wins = tonumber(data[1].count_winner)
data = mw.ext.LiquipediaDB.lpdb('match', {
limit = 5000,
offset = 0,
conditions = '(([[opponent1::' .. match.opponent2 .. ']] AND [[winner::2]]) OR ([[opponent2::' .. match.opponent2 .. ']] AND [[winner::1]])) AND [[date::>' .. matchDate .. ']] AND [[matchid::!-1]]',
query = 'count::winner',
})
team2_losses = tonumber(data[1].count_winner)
team2_winrate = (team2_wins / (team2_wins + team2_losses)) * 100
td = tr:tag('td')
:css('text-align','center')
:css('font-weight','bold')
:wikitext('Winrate')
td = tr:tag('td')
:css('text-allign','center')
:wikitext(p.round(team2_winrate, 0) .. '%')
data = mw.ext.LiquipediaDB.lpdb('match', {
limit = 5000,
offset = 0,
conditions = '(([[opponent1::' .. match.opponent1 .. ']] AND [[opponent2::' .. match.opponent2 .. ']] AND [[winner::1]]) OR ([[opponent1::' .. match.opponent2 .. ']] AND [[opponent2::' .. match.opponent1.. ']] AND [[winner::2]])) AND [[date::>' .. matchDate .. ']] AND [[matchid::!-1]]',
query = 'count::winner',
})
team1_h2h = tonumber(data[1].count_winner)
data = mw.ext.LiquipediaDB.lpdb('game', {
limit = 5000,
offset = 0,
conditions = '(([[opponent1::' .. match.opponent1 .. ']] AND [[opponent2::' .. match.opponent2 .. ']] AND [[winner::1]]) OR ([[opponent1::' .. match.opponent2 .. ']] AND [[opponent2::' .. match.opponent1.. ']] AND [[winner::2]])) AND [[date::>' .. matchDate .. ']] AND [[matchid::!-1]]',
query = 'count::winner',
})
team1_h2hg = tonumber(data[1].count_winner)
data = mw.ext.LiquipediaDB.lpdb('match', {
limit = 5000,
offset = 0,
conditions = '(([[opponent1::' .. match.opponent1 .. ']] AND [[opponent2::' .. match.opponent2 .. ']] AND [[winner::2]]) OR ([[opponent1::' .. match.opponent2 .. ']] AND [[opponent2::' .. match.opponent1.. ']] AND [[winner::1]])) AND [[date::>' .. matchDate .. ']] AND [[matchid::!-1]]',
query = 'count::winner',
})
team2_h2h = tonumber(data[1].count_winner)
data = mw.ext.LiquipediaDB.lpdb('game', {
limit = 5000,
offset = 0,
conditions = '(([[opponent1::' .. match.opponent1 .. ']] AND [[opponent2::' .. match.opponent2 .. ']] AND [[winner::2]]) OR ([[opponent1::' .. match.opponent2 .. ']] AND [[opponent2::' .. match.opponent1.. ']] AND [[winner::1]])) AND [[date::>' .. matchDate .. ']] AND [[matchid::!-1]]',
query = 'count::winner',
})
team2_h2hg = tonumber(data[1].count_winner)
tr = table:tag('tr')
:addClass('stats-row')
td = tr:tag('td')
:css('text-align','center')
if team1_h2h+team2_h2h == 0 then
td:wikitext(team1_h2h)
else
td:wikitext(team1_h2h .. ' (' .. p.round(((team1_h2h / (team1_h2h + team2_h2h)) * 100), 1) .. '%)')
end
td = tr:tag('td')
:css('text-align','center')
:css('font-weight','bold')
:wikitext('Head to Head')
td = tr:tag('td')
:css('text-align','center')
if team1_h2h+team2_h2h == 0 then
td:wikitext(team2_h2h)
else
td:wikitext(team2_h2h .. ' (' .. p.round(((team2_h2h / (team1_h2h + team2_h2h)) * 100), 1) .. '%)')
end
local div = wrapper4:tag('div')
:css('display','inline-block')
:css('vertical-align','top')
:css('width','25%')
:css('margin-left','5px')
local table = div:tag('table')
:addClass('table streams-table streams')
:css('border','1px solid #bbbbbb !important')
:css('text-align','center')
:css('width','100%')
tr = table:tag('tr')
:addClass('wiki-backgroundcolor-light')
:css('font-size','130%')
th = tr:tag('th')
:attr('colspan',4)
:css('padding','5px')
:wikitext('Streams')
tr = table:tag('tr')
if (match.stream.twitch) and (match.stream.twitch ~= '') then
td = tr:tag('td')
:wikitext('[[Special:StreamPage/twitch/' .. match.stream.twitch .. '|<i class="lp-icon lp-twitch"></i>]]')
end
if (match.stream.youtube) and (match.stream.youtube ~= '') then
td = tr:tag('td')
:wikitext('[[Special:StreamPage/youtube/' .. match.stream.youtube .. '|<i class="lp-icon lp-youtube"></i>]]')
end
if (match.stream.facebook) and (match.stream.facebook ~= '') then
td = tr:tag('td')
:wikitext('[[Special:StreamPage/facebook/' .. match.stream.facebook .. '|<i class="lp-icon lp-facebook"></i>]]')
end
if (match.stream.steamtv) and (match.stream.steamtv ~= '') then
td = tr:tag('td')
:wikitext('[https://steam.tv/' .. match.stream.steamtv .. ' <i class="lp-icon lp-steam"></i>]')
end
return tostring(wrapper:done()) .. tostring(wrapper2:done()) .. tostring(wrapper3:done()) .. '<center>' .. tostring(wrapper4:done()) .. '</center>'
end
function p.round(num, numDecimalPlaces)
num = tonumber(num)
local mult = 10^(numDecimalPlaces or 0)
return math.floor(num * mult + 0.5) / mult
end
function p.formatDate(date)
return os.date( "!%B %d, %Y - %H:%M", date)
end
function p.serverTimeOffset()
local utcDate = os.date("!%Y-%m-%d %H:%M:%S")
local utcYear,utcMonth,utcDay,utcHour,utcMin,utcSec=utcDate:match('(%d+)-(%d+)-(%d+) (%d+):(%d+):(%d+)')
local utcUnixDate = os.time({day=utcDay,month=utcMonth,year=utcYear,hour=utcHour,min=utcMin,sec=utcSec})
local localDate = os.date("%Y-%m-%d %H:%M:%S")
local localYear,localMonth,localDay,localHour,localMin,localSec=localDate:match('(%d+)-(%d+)-(%d+) (%d+):(%d+):(%d+)')
local localUnixDate = os.time({day=localDay,month=localMonth,year=localYear,hour=localHour,min=localMin,sec=localSec})
return localUnixDate - utcUnixDate
end
function p.adjustDate(date, timezone)
if type(date) == 'string' then
local year, month, day, hour, min, sec = date:match('(%d+)-(%d+)-(%d+) (%d+):(%d+):(%d+)')
date = os.time({day=day, month=month, year=year, hour=hour, min=min, sec=sec})
date = date + p.serverTimeOffset() -- adjust for the fact that the server might not be set to UTC
end
if not timezone or timezone == '' then
timezone = '+00:00'
end
local timezoneSign, timezoneHour, timezoneMin = string.match(timezone, '^([+-])(%d+):(%d+)')
return date + tonumber(timezoneSign .. '1') * (timezoneHour * 3600 + timezoneMin * 60)
end
return p