Edit the documentation or categories for this module. This module has an i18n file.
local util_args = require('Module:ArgsUtil')
local util_cargo = require('Module:CargoUtil')
local util_esports = require('Module:EsportsUtil')
local util_form = require('Module:FormUtil')
local util_game = require('Module:GameUtil')
local util_html = require('Module:HtmlUtil')
local util_map = require('Module:MapUtil')
local util_math = require('Module:MathUtil')
local util_sort = require('Module:SortUtil')
local util_stats = require('Module:StatsUtil')
local util_table = require('Module:TableUtil')
local util_text = require('Module:TextUtil')
local util_time = require('Module:TimeUtil')
local util_title = require('Module:TitleUtil')
local util_vars = require('Module:VarsUtil')
local i18n = require('Module:i18nUtil')
local m_team = require('Module:Team')
local RegionList = require('Module:RegionList')
local ColumnShowHide = require('Module:ColumnShowHide')
local ReplaceRedirects = require('Module:ReplaceRedirects')
local SETTINGS = require('Module:MatchHistoryGame/Settings')
local PRELOAD
local DEFAULT_LIMIT = 50
local h = {}
local p = {}
function p.main(frame)
local args = util_args.merge()
local args2 = h.castArgs(args)
i18n.init('MatchHistoryGame')
h.setPreloadAndValidate(args)
local data = h.getData(args2)
h.countData(data, args)
if util_args.castAsBool(args.textonly) then
h.formatDataText(data, args)
else
h.formatDataPretty(data, args)
end
return ReplaceRedirects.main(h.makeOutput(data, args, args2), args)
end
function h.castArgs(args)
local args2 = mw.clone(args)
args2.region = RegionList(args2.region)
return args2
end
function h.setPreloadAndValidate(args)
local preload = h.getPreload(args.preload .. (util_args.castAsBool(args.textonly) and 'text' or ''))
PRELOAD = preload or h.getPreload(args.preload)
util_stats.validatePreload(args, PRELOAD)
end
function h.getPreload(str)
return SETTINGS.preloads[str:lower()]
end
-- cargo
function h.getData(args)
local query = {
tables = {
'ScoreboardGames=SG',
'Tournaments=IT'
},
join = {
'SG.OverviewPage=IT.OverviewPage'
},
fields = {
'SG.DateTime_UTC=Date',
'IT.Region=Region [region]',
'IT.StandardName=Tournament',
'SG.Patch=Patch',
'SG.Team1=Team1',
'SG.Team2=Team2',
'SG.WinTeam=WinTeam',
'SG.Team1Bans__full=Team1Bans [ChampionList]',
'SG.Team2Bans__full=Team2Bans [ChampionList]',
'SG.Team1Picks__full=Team1Picks [ChampionList]',
'SG.Team2Picks__full=Team2Picks [ChampionList]',
'SG._pageName=_pageName',
'SG.MatchHistory=MatchHistory',
'SG.VOD=VOD',
'SG.Gamelength=Gamelength',
'SG.Team1Gold=Team1Gold',
'SG.Team1Kills=Team1Kills',
'SG.Team1Towers=Team1Towers',
'SG.Team1Barons=Team1Barons',
'SG.Team1Inhibitors=Team1Inhibitors',
'SG.Team1Dragons=Team1Dragons',
'SG.Team1RiftHeralds=Team1RiftHeralds',
'SG.Team1VoidGrubs=Team1VoidGrubs',
'SG.Team2Gold=Team2Gold',
'SG.Team2Kills=Team2Kills',
'SG.Team2Towers=Team2Towers',
'SG.Team2Barons=Team2Barons',
'SG.Team2Inhibitors=Team2Inhibitors',
'SG.Team2Dragons=Team2Dragons',
'SG.Team2RiftHeralds=Team2RiftHeralds',
'SG.Team2VoidGrubs=Team2VoidGrubs',
'SG.Team1Players__full=Team1Links',
'SG.Team2Players__full=Team2Links',
'IT._pageName=TournamentPage',
'SG._pageName=ScoreboardPage',
'SG.GameId',
},
where = h.getWhere(args),
limit = h.getLimit(args),
orderBy = h.getOrderBy(args),
offset = args.offset,
}
local data = util_cargo.queryAndCast(query)
return data
end
function h.getWhere(args)
local tbl = {
util_cargo.whereFromArg('(%s)', args.where),
h.getEitherTeamWhereArg('', args.team and m_team.teamlinkname(args.team)),
util_cargo.whereFromArgList('SG.OverviewPage="%s"', args.tournament, nil, util_title.target),
h.getBanWhere(args.ban),
h.getTeamHeadToHeadWhereArg(args.team1, args.team2),
util_cargo.whereFromArgList('IT.TournamentLevel="%s"', args.tournamentlevel),
util_cargo.whereFromCompoundEntity('IT.Region="%s"', args.region),
util_cargo.whereFromArgList('IT.Year="%s"', args.year),
util_cargo.whereFromArg('SG.DateTime_UTC >= "%s"', args.startdate),
util_cargo.whereFromArg('SG.DateTime_UTC <= "%s"', args.enddate),
}
if args.record then
tbl[#tbl+1] = ('%s IS NOT NULL'):format(args.record)
end
return util_cargo.concatWhere(tbl)
end
function h.getLimit(args)
return args.limit or PRELOAD.limit or DEFAULT_LIMIT
end
function h.getEitherTeamWhereArg(str, value)
if not value then return nil end
return ('(SG.Team1%s="%s" OR SG.Team2%s="%s")'):format(str, value, str, value)
end
function h.getBanWhere(ban)
if not ban then return nil end
local tbl = {
util_cargo.fakeHolds('SG.Team1Bans', ban),
util_cargo.fakeHolds('SG.Team2Bans', ban)
}
return util_cargo.concatWhereOr(tbl)
end
function h.getTeamHeadToHeadWhereArg(team1, team2)
if not (team1 and team2) then return nil end
team1 = m_team.teamlinkname(team1)
team2 = m_team.teamlinkname(team2)
return ('((SG.Team1="%s" AND SG.Team2="%s") OR (SG.Team1="%s" AND SG.Team2="%s"))'):format(
team1,
team2,
team2,
team1
)
end
function h.getOrderBy(args)
if args.orderBy then return args.orderBy end
if not args.record then
return PRELOAD.orderBy or 'SG.DateTime_UTC DESC'
end
local order = util_args.castAsBool(args.ascending) and 'ASC' or 'DESC'
return ('SG.%s %s'):format(args.record, order)
end
-- count
function h.countData(data, args)
data.wins = {}
for _, row in ipairs(data) do
data.wins[row.WinTeam] = (data.wins[row.WinTeam] or 0) + 1
end
end
-- format
function h.formatDataPretty(data, args)
for n, row in ipairs(data) do
h.formatRowPretty(row, args, n)
end
end
function h.formatRowPretty(row, args, n)
row.N = n
row.UsN = h.getUsN(row, args)
row.TournamentDisplay = util_stats.tournamentAndRegion(row)
util_stats.infoLinks(row)
row.Date = util_time.strToDateStr(row.Date)
row.Patch = row.Patch and util_text.intLink('Patch ' .. row.Patch, row.Patch)
row.Team1Display = m_team.onlyimagelinked(row.Team1)
row.Team2Display = m_team.onlyimagelinked(row.Team2)
row.WinTeamDisplay = m_team.onlyimagelinked(row.WinTeam)
row.Side = row.UsN and util_game.side_names[row.UsN]
row.BannedBy = row.Side
row.class = row.Team1 == row.WinTeam and 'blue' or 'red'
row.TournamentLink = util_text.intLinkOrText(row.Tournament)
row.RegionDisplay = row.Region:flair()
row.Team1BansDisplay = row.Team1Bans:images()
row.Team2BansDisplay = row.Team2Bans:images()
row.Team1PicksDisplay = row.Team1Picks:images()
row.Team2PicksDisplay = row.Team2Picks:images()
h.linkedRosters(row)
h.addUsThemFields(row, args)
h.setClassTHTH(row, args)
h.checkIfTruePerfect(row)
end
function h.getUsN(row, args)
if not PRELOAD.bias then
return
elseif PRELOAD.bias == 'Team' and m_team.teamlinkname(args.team) == row.Team1 then
return 1
elseif PRELOAD.bias == 'Team' and m_team.teamlinkname(args.team) == row.Team2 then
return 2
elseif PRELOAD.bias == 'Ban' and row.Team2Bans:has(nil, args.ban) then
return 2
elseif PRELOAD.bias == 'Ban' and row.Team1Bans:has(nil, args.ban) then
return 1
elseif PRELOAD.bias == 'Perfect' and row.Team2Kills == '0' and row.Team2Towers == '0' then
return 1
elseif PRELOAD.bias == 'Perfect' and row.Team1Kills == '0' and row.Team1Towers == '0' then
return 2
elseif PRELOAD.bias == 'AlmostPerfect' and row.Team2Kills <= args.maxkills and row.Team2Towers <= args.maxtowers then
return 1
elseif PRELOAD.bias == 'AlmostPerfect' and row.Team1Kills <= args.maxkills and row.Team1Towers <= args.maxtowers then
return 2
end
error(i18n.print('invalidUsThem', row.GameId, row.ScoreboardPage, row.Team1, row.Team2))
end
function h.addUsThemFields(row, args)
if not row.UsN then return end
h.addSetOfUsThemFields(row, row.UsN, '')
h.addSetOfUsThemFields(row, util_esports.otherTeamN(row.UsN), 'Vs')
row.ResultBiased = m_team.teamlinkname(row.WinTeam) == row.Team and 'Win' or 'Loss'
row.class = m_team.teamlinkname(row.WinTeam) == row.Team and 'winner' or 'loser'
end
function h.addSetOfUsThemFields(row, us, suffix)
for _, v in ipairs({ 'BansDisplay', 'PicksDisplay', 'Roster', 'Gold', 'Kills', 'Towers', 'Dragons', 'Barons', 'Inhibitors', 'RiftHeralds', 'VoidGrubs', 'Bans', 'Picks', 'Display', }) do
row[v .. suffix] = row['Team' .. us .. v]
end
row['Team' .. suffix] = row['Team' .. us]
end
function h.linkedRosters(row)
row.Team1Roster = h.oneLinkedRoster(row, 1)
row.Team2Roster = h.oneLinkedRoster(row, 2)
end
function h.oneLinkedRoster(row, n)
local ret = {}
local links = util_text.split(row['Team' .. n .. 'Links'])
for i, v in ipairs(links) do
ret[#ret+1] = util_esports.playerLinked(v)
end
return util_table.concat(ret, ', ')
end
function h.setClassTHTH(row, args)
if not PRELOAD.thth then return end
if row.WinTeam == m_team.teamlinkname(args.team1) then
row.class = 'thth-team1'
else
row.class = 'thth-team2'
end
end
function h.formatDataText(data, args)
for n, row in ipairs(data) do
h.formatRowText(row, args, n)
end
end
function h.formatRowText(row, args, n)
row.N = n
row.TournamentDisplay = row.Region:name() .. ',' .. row.Tournament
row.Team1Roster = row.Team1Links
row.Team2Roster = row.Team2Links
row.UsN = h.getUsN(row, args)
row.Team1BansDisplay = row.Team1Bans:names()
row.Team2BansDisplay = row.Team2Bans:names()
row.Team1PicksDisplay = row.Team1Picks:names()
row.Team2PicksDisplay = row.Team2Picks:names()
h.addUsThemFields(row, args)
row.Side = row.UsN and util_game.side_names[row.UsN]
row.BannedBy = row.Side
row.Scoreboard = util_text.intLink(row._pageName, 'SB')
end
function h.checkIfTruePerfect(row)
if row.BaronsVs == '0' and row.DragonsVs == '0' then
row.TruePerfect = tostring(mw.html.create('div'):addClass('greencheck'))
-- Only if one of them is null we can still apply the criteria using
-- only the other one
if (
(row.RiftHeraldsVs == '0' and row.VoidGrubsVs == '0') or
(row.RiftHeraldsVs == '0' and row.VoidGrubsVs == nil) or
(row.RiftHeraldsVs == nil and row.VoidGrubsVs == '0')
) then
row.TruePerfect = row.TruePerfect .. tostring(mw.html.create('div'):addClass('greencheck'))
end
end
end
-- output
function h.makeOutput(data, args, args2)
local output = mw.html.create()
local headings = h.getHeadings()
ColumnShowHide.printToggles(output, headings)
local tbl = output:tag('div'):addClass('wide-content-scroll'):tag('table')
:addClass('wikitable hoverable-multirows mhgame sortable plainlinks')
:addClass(PRELOAD.class)
ColumnShowHide.printTableClass(tbl)
h.printColspanHeader(tbl, args, #headings)
h.printHeaderTHTH(tbl, args, data.wins, #headings)
h.printUpperHeadings(tbl)
h.printLowerHeadings(tbl, headings.headerCells or headings)
util_html.printEmptySortRow(tbl, #headings)
h.printRows(tbl, data, headings)
h.printPermalink(output, args, args2)
return output
end
function h.printColspanHeader(tbl, args, colspan)
if PRELOAD.noheading then return end
local displayTbl = {
util_stats.heading(args, 'MatchHistoryGame', h.getLimit(args)),
util_stats.openAsQueryLink(SETTINGS.form_info, args)
}
util_html.printColspanHeader(tbl, util_table.concat(displayTbl, ' - '), colspan)
end
function h.printHeaderTHTH(tbl, args, winData, colspan)
if not PRELOAD.thth then return end
local div = tbl:tag('tr'):tag('th'):attr('colspan', colspan):tag('div'):addClass(h.getClassName('thth-outer'))
for n = 1, 2 do
h.printHeaderTHTHTeam(div, args, winData, n)
end
end
function h.printHeaderTHTHTeam(div, args, winData, n)
div:tag('div')
:addClass(h.getClassName('thth-team' .. n))
:wikitext(h.getHeaderTHTHTeamText(args, winData, n))
end
function h.getHeaderTHTHTeamText(args, winData, n)
local team = m_team.teamlinkname(args['team' .. n])
return ('%s: %s %s'):format(m_team.rightmedium(team), winData[team] or 0, i18n.print('ththWins'))
end
function h.getHeadings()
if PRELOAD.upper then
return h.getHeadingsWhenTwoRowsOfHeadings()
elseif PRELOAD.multiline then
return h.getHeadingsWhenTwoRowsPerDataLine()
else
return PRELOAD.headings
end
end
function h.getHeadingsWhenTwoRowsOfHeadings()
local ret = { headerCells = {} }
for _, group in ipairs(PRELOAD.headings) do
for _, col in ipairs(PRELOAD.headings[group]) do
ret[#ret+1] = col
if #PRELOAD.headings[group] > 1 then
ret.headerCells[#ret.headerCells+1] = col
end
end
end
return ret
end
function h.getHeadingsWhenTwoRowsPerDataLine()
local ret = { row2 = {} }
for _, row in ipairs(PRELOAD.headings) do
for _, col in ipairs(row) do
ret[#ret+1] = col
ret[col] = row.rowspan
if row.rowspan == 1 then
ret.row2[#ret.row2+1] = col
end
end
end
return ret
end
function h.printUpperHeadings(tbl)
if not PRELOAD.upper then return end
local tr = tbl:tag('tr')
for _, col in ipairs(PRELOAD.headings) do
local th = tr:tag('th')
:wikitext(i18n.print(col))
:attr('colspan', #PRELOAD.headings[col])
if #PRELOAD.headings[col] == 1 then
th:attr('rowspan', 2)
end
end
end
function h.printLowerHeadings(tbl, headings)
local tr = tbl:tag('tr')
for _, col in ipairs(headings) do
tr:tag('th')
:wikitext(i18n.print(col))
end
end
function h.printRows(tbl, data, headings)
for i, row in ipairs(data) do
h.printOneRow(tbl, row, headings, i)
h.printOneSecondRow(tbl, row, headings.row2, i)
end
end
function h.printOneRow(tbl, row, headings, i)
local tr = tbl:tag('tr')
tr:addClass(h.getClassName(row.class))
tr:attr('data-highlight-row', i)
tr:addClass('multirow-highlighter')
for _, col in ipairs(headings) do
local td = tr:tag('td')
:addClass(h.getClassFromCol(col))
:wikitext(row[col:gsub('TeamN', 'Team' .. 1)])
if headings[col] then
td:attr('rowspan', headings[col])
end
end
end
function h.printOneSecondRow(tbl, row, headingsRow2, i)
if not headingsRow2 then return end
local tr = tbl:tag('tr')
tr:addClass(h.getClassName(row.class))
tr:attr('data-highlight-row', i)
tr:addClass('multirow-highlighter')
for _, col in ipairs(headingsRow2) do
tr:tag('td')
:addClass(h.getClassFromCol(col))
:wikitext(row[col:gsub('TeamN', 'Team' .. 2)])
end
end
function h.getClassFromCol(col)
return h.getClassName(SETTINGS.classes[col])
end
function h.getClassName(str)
if not str then return nil end
return 'mhgame-' .. str
end
function h.printPermalink(output, args, args2)
if not util_args.castAsBool(args.spl) then return end
util_form.permalink(output, args, SETTINGS.form_info)
output:tag('hr')
output:wikitext(i18n.print('debugInfo'))
output:wikitext(h.getWhere(args2))
util_form.printLog(output)
end
return p