Module:MatchHistoryGame

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 SETTINGS = require('Module:MatchHistoryGame/Settings') local PRELOAD local DEFAULT_LIMIT = 50

local h = {} local p = {} function p.main(frame) local args = util_args.merge i18n.init('MatchHistoryGame') h.setPreloadAndValidate(args) local data = h.getData(args) h.countData(data, args) if util_args.castAsBool(args.textonly) then h.formatDataText(data, args) else h.formatDataPretty(data, args) end return h.makeOutput(data, args) 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.Team2Gold=Team2Gold', 'SG.Team2Kills=Team2Kills', 'SG.Team2Towers=Team2Towers', 'SG.Team2Barons=Team2Barons', 'SG.Team2Inhibitors=Team2Inhibitors', 'SG.Team2Dragons=Team2Dragons', 'SG.Team2RiftHeralds=Team2RiftHeralds', 'SG.Team1Players__full=Team1Links', 'SG.Team2Players__full=Team2Links', 'IT._pageName=TournamentPage', 'SG._pageName=ScoreboardPage', 'SG.ScoreboardID_Wiki', },		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), }	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 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')) 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', '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')) end end

-- output function h.makeOutput(data, args) local output = mw.html.create local headings = h.getHeadings local tbl = output:tag('div'):addClass('wide-content-scroll'):tag('table') :addClass('wikitable hoverable-multirows mhgame sortable plainlinks') :addClass(PRELOAD.class) 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) 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) 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(args)) util_form.printLog(output) end

return p