Documentation for this module may be created at Module:ScoreboardAbstract/doc
local util_args = require('Module:ArgsUtil')
local util_cargo = require('Module:CargoUtil')
local util_esports = require('Module:EsportsUtil')
local util_footnote = require('Module:FootnoteUtil')
local util_map = require('Module:MapUtil')
local util_html = require('Module:HtmlUtil')
local util_math = require('Module:MathUtil')
local util_riot = require("Module:RiotUtil")
local util_scoreboard = require("Module:ScoreboardUtil")
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_toggle = require('Module:ToggleUtil')
local util_vars = require('Module:VarsUtil')
local Role = require('Module:Role')
local m_team = require('Module:Team')
local Item = require('Module:Item')
local ItemList = require('Module:ItemList')
local Champion = require('Module:Champion')
local ChampionList = require('Module:ChampionList')
local Keystone = require('Module:Keystone')
local LCS = require('Module:LuaClassSystem')
local i18n = require('Module:i18nUtil')
local Sprite = require('Module:Sprite').sprite
local RunesReforged = require('Module:Scoreboard/RunesReforged')
local TabVariables = require('Module:TabVariables')
local SEASON
local PLAYER_NUMBER = 5
local PLAYER_SIDES = { 'blue', 'red' } -- this is whatever the args in the template want
local TEAMS = { 'blue', 'red' } -- this is absolute for CSS classes
local TEAMS_DISPLAY = { 'Blue', 'Red' } -- this is for Cargo
local PRINT_ITEMS = true
local PLAYERS = {}
local PLAYER_ARGS = { 'Champion', 'Link', 'Name', 'SummonerSpells', 'Items', 'Trinket', 'Kills', 'Deaths', 'Assists', 'Gold', 'CS', 'Keystone', 'PrimaryTree', 'SecondaryTree', 'Pentakills', 'PentakillVod', 'nocargo', 'SkillLetter', 'SkillImage', 'AllRunes', 'IngameRole', 'DamageToChampions', 'VisionScore', }
local GAME_ARGS_TEAMS = {
score = 'Score',
d = 'Dragons',
b = 'Barons',
t = 'Towers',
rh = 'RiftHeralds',
i = 'Inhibitors',
g = 'Gold',
k = 'Kills',
vg = 'VoidGrubs',
at = 'Atakhans'
}
local GAME_ARGS = {
gamename = 'Gamename',
gamelength = 'Gamelength',
dst = 'DST',
statslink = 'MatchHistory',
vodlink = 'VOD',
lolvod = 'VOD2',
patch = 'LegacyPatch'
}
local FOOTER_ITEMS = { 'Towers', 'Inhibitors', 'Barons', 'Dragons', 'RiftHeralds', 'VoidGrubs', 'Atakhans' }
local TIMEZONES = { 'PST', 'KST', 'CET' }
local summonerspell_sep = ','
local item_sep = ';'
local arg_sep = ';;;'
local lang = mw.getLanguage('en')
local h = {}
local p = LCS.class.abstract()
local s = {}
function p:init(args)
i18n.init('Scoreboard')
if util_args.castAsBool(args.notplayed) then
util_scoreboard.storeCounterCargo()
return self:_noGamePlayed(args)
end
SEASON = mw.loadData('Module:Scoreboard/SeasonData')[tonumber(args.season)]
h.setSeasonVariables(args)
h.initializePlayerN(args) -- in case it's not 5 players per team
h.initializeItems(args)
local player_data = self:getPlayerDisplayData(args)
local game_data = h.getGameDisplayData(args)
self:cargo(args, player_data, game_data)
return self:makeOutput(game_data, player_data)
end
function p:_noGamePlayed(args)
i18n.init('Scoreboard')
local game_data = h.getNotPlayedGameData(args)
h.prepToggles(game_data)
local tbl = mw.html.create('table')
:addClass('sb')
h.printTeamLine(tbl, game_data)
h.setScores(game_data, args)
h.printScoreLine(tbl, game_data)
h.printNotPlayedTitle(tbl, args)
h.printNotPlayedReason(tbl, args)
util_scoreboard.storeCounterCargo(args)
return tbl
end
function s.SummonerSprite(id)
return Sprite{
id,
size = 30,
type = 'Summoner',
notext = true,
nolink = true
}
end
function s.InfoSprite(id)
return Sprite{
id,
size = 15,
type = 'ScoreboardIcon',
notext = true,
nolink = true
}
end
function h.setSeasonVariables(args)
if not SEASON.rh then
-- could use keyOf but meh
util_table.removeValue(FOOTER_ITEMS, "RiftHeralds")
end
if not args.team1vg and not args.team2vg then
util_table.removeValue(FOOTER_ITEMS, "VoidGrubs")
end
if not args.team1at and not args.team2at then
util_table.removeValue(FOOTER_ITEMS, "Atakhans")
end
end
function h.initializePlayerN(args)
PLAYER_NUMBER = args.teamsize or PLAYER_NUMBER
end
function h.initializeItems(args)
PRINT_ITEMS = not util_args.castAsBool(args.noitems)
end
function p:getPlayerDisplayData(args)
local data = {}
for i, side in ipairs(PLAYER_SIDES) do
data[i] = {}
for j = 1, PLAYER_NUMBER do
local row = h.splitPlayerDataAndErrorcheck(args, side, i, j)
data[i][j] = self:parsePlayerData(row, i, j, args)
end
data[i].rolemap = h.getRolemap(data[i])
data[i].rolemapHash = util_table.hash(data[i].rolemap)
end
return data
end
function h.splitPlayerDataAndErrorcheck(args, side, i, j)
if not args[side .. j] then
error(i18n.print('no_player_data', i, j))
end
local row = util_args.splitArgs(args[side .. j], PLAYER_ARGS, arg_sep)
return row
end
function p:parsePlayerData(row, i, j, args)
row.Name = util_esports.playerDisplay(row.Link or row.Name or '')
row.Link = row.Link or row.Name
row.Side = i
row.Role_Number = j
-- ill substitute all ",,," by ";" because we want to store to cargo using that delimiter
-- i cant use the ; delimiter in the Scoreboard/Player template
row.Items = ItemList(row.Items:gsub(",,,", ";"), {patch = args.patch_sort or args.patch, sep = item_sep})
row.Trinket = Item(row.Trinket)
row.SummonerSpells = util_text.split(row.SummonerSpells)
row.Champion = Champion(row.Champion)
row.AllRunes = RunesReforged.cast(row.AllRunes)
row.IngameRole = Role(row.IngameRole or tostring(row.Role_Number))
row.IngameRoleNumber = row.IngameRole:get('sortnumber')
return row
end
function h.getRolemap(players)
local ret = {}
for i, row in ipairs(players) do
-- the ingame role number is the proper final position of this row
-- so when we look up, what row to use at this final position? we want to get this row
ret[row.IngameRoleNumber] = i
end
return ret
end
function h.getGameDisplayData(args)
local game_data = {}
h.setVariables(game_data, args)
h.getWinnerAndLoser(game_data, args)
h.getGameDataByRenamingArgs(game_data, args)
h.getGamelengthNumber(game_data)
h.getTeamDisplayData(game_data, args)
h.getDateAndTime(game_data, args)
h.getGameFootnotes(game_data, args)
h.setScores(game_data, args)
game_data.version = util_math.tonumber(args.version)
game_data.Patch = util_esports.getPatchFromLegacyPatch(args.patch)
return game_data
end
function h.setVariables(game_data, args)
game_data.N_MatchInTab = util_vars.getGlobalIndex('sb_N_MatchInTab')
game_data.N_MatchInPage = util_vars.getGlobalIndex('sb_N_MatchInPage')
game_data.N_GameInMatch = util_vars.setGlobalIndex('sb_N_GameInMatch')
util_vars.setGlobalIndex('sb_N_GameInTab')
game_data.Tournament = args.tournament
end
function h.getWinnerAndLoser(game_data, args)
if args.winner and not tonumber(args.winner) then
error('Invalid winner')
elseif not args.winner then
return
end
local winner = tonumber(args.winner)
local loser = util_esports.otherTeamN(winner)
game_data.Winner = winner
game_data.WinTeam = m_team.teamlinkname(args['team' .. winner])
game_data.LossTeam = m_team.teamlinkname(args['team' .. loser])
end
function h.getGameDataByRenamingArgs(game_data, args)
for k, v in pairs(GAME_ARGS) do
game_data[v] = args[k]
end
game_data.VOD = game_data.VOD or game_data.VOD2
end
function h.getGamelengthNumber(game_data)
if not game_data.Gamelength then return end
local m, s = game_data.Gamelength:match('(%d+):(%d+)')
m = tonumber(m)
s = tonumber(s)
if not m then
error("Can't find minutes in game length")
elseif not s then
error("Can't find seconds in game length")
end
game_data.Gamelength_Number = m + s / 60
end
function h.getTeamDisplayData(game_data, args)
for i, s in ipairs(PLAYER_SIDES) do
local key = 'Team' .. i
local arg = 'team' .. i
game_data[key] = m_team.teamlinkname(args[arg])
game_data[key .. 'Bans'] = h.getBans(args, arg)
h.getTeamDataByRenamingArgs(game_data, args, key, arg)
end
end
function h.getBans(args, arg)
local bans = util_args.numberedArgsToTable(args, arg .. 'ban', true, SEASON.max_bans) or {}
util_table.padFalseEntries(bans, SEASON.max_bans, 'None')
bans = ChampionList(bans)
return bans
end
function h.getTeamDataByRenamingArgs(game_data, args, key, arg)
for k, v in pairs(GAME_ARGS_TEAMS) do
game_data[key .. v] = args[arg .. k]
end
end
function h.getDateAndTime(game_data, args)
game_data.tz = h.parseTimeData(args)
end
function h.parseTimeData(args)
local dst = util_args.norm(args.dst)
if args.time then
return util_time.getTimezones(args.date .. ' ' .. args.time, args.timezone, dst)
end
return h.getTZDataFromOldParamStyle(args, dst) or { UTC = 'Undefined' }
end
function h.getTZDataFromOldParamStyle(args, dst)
for _, tz in ipairs(TIMEZONES) do
if args[tz] then
return util_time.getTimezones(args.date .. ' ' .. args[tz], tz, dst)
end
end
return nil
end
function h.getGameFootnotes(game_data, args)
game_data.footnote = args.footnote
end
function h.setScores(game_data, args)
if args.team1score and args.team2score then return end
if not game_data.WinTeam then return end
util_scoreboard.incrementScore(game_data.WinTeam)
game_data.Team1Score = util_scoreboard.getScore(game_data.Team1)
game_data.Team2Score = util_scoreboard.getScore(game_data.Team2)
end
-- cargo data
function p:cargo(args, player_data, game_data)
util_scoreboard.storeCounterCargo()
if not h.doWeStoreCargo(args) then return end
self:processCargoData(args, player_data, game_data)
self:storeCargo(args, player_data, game_data)
end
function h.doWeStoreCargo(args)
if util_args.castAsBool(args.nocargo) then
return false
end
return mw.title.getCurrentTitle().nsText == ''
end
function p:processCargoData(args, player_data, game_data)
game_data.cargo = h.initGameCargoFromData(game_data)
game_data.cargo.OverviewPage = util_esports.getOverviewPage(args.page)
game_data.cargo.N_Page = TabVariables.getIndex()
game_data.cargo.N_MatchInTab = nil
game_data.cargo.UniqueGame = util_cargo.getUniqueLine(game_data.N_MatchInPage, game_data.N_GameInMatch)
game_data.cargo.UniqueLine = util_cargo.getUniqueLine(game_data.N_MatchInPage, game_data.N_GameInMatch)
game_data.cargo.GameId = h.getIdWiki(game_data)
game_data.cargo.MatchId = h.getMatchId(game_data)
game_data.cargo.DateTime_UTC = game_data.tz.UTC
game_data.cargo.RiotPlatformGameId = args.rpgid
game_data.cargo.Version = args.version
util_riot.setMhIdFields(game_data.cargo, game_data.cargo.MatchHistory)
game_data.cargo.Gamename = game_data.cargo.Gamename or i18n.default('gamename', game_data.N_GameInMatch)
-- TODO: Add list of picks to game maybe?
-- add actual values to what's nil above
h.gatherPlayerCargoForGameFields(game_data.cargo, player_data)
game_data.team_cargo = {}
for t, team in ipairs(player_data) do
game_data.team_cargo[t] = h.getTeamCargo(game_data, player_data, t)
for playerN, player_data in ipairs(team) do
player_data.cargo = h.initPlayerCargoFromData(player_data)
h.addPlayerCargoDataFromGame(player_data.cargo, game_data.cargo, t)
h.addPlayerCargoRoleData(player_data.cargo, playerN)
h.addPlayerCargoKeystoneData(player_data.cargo, player_data)
player_data.cargo.GameTeamId = game_data.team_cargo[t].GameTeamId
player_data.cargo.Runes = RunesReforged.store(player_data.AllRunes)
player_data.cargo.Side = t
player_data.cargo.Name = util_esports.playerDisplay(player_data.Link, player_data.Name)
-- primary key as well as a self-foreign key for joining
player_data.cargo.UniqueLine = util_cargo.getUniqueLine(game_data.N_MatchInPage, game_data.N_GameInMatch, t, playerN)
player_data.cargo.UniqueLineVs = util_cargo.getUniqueLine(game_data.N_MatchInPage, game_data.N_GameInMatch, util_esports.otherTeamN(t), playerN)
-- for ingame roles we will want to join on the ingame role, not the position
-- within the scoreboard. let's keep the position within the scoreboard as the
-- primary key, but for stats calculations we'll just use UniqueRole and
-- UniqueRoleVs.
local ingameRoleNumber = player_data.IngameRole:get('sortnumber') or playerN
player_data.cargo.UniqueRole = util_cargo.getUniqueLine(game_data.N_MatchInPage, game_data.N_GameInMatch, t, ingameRoleNumber)
player_data.cargo.UniqueRoleVs = util_cargo.getUniqueLine(game_data.N_MatchInPage, game_data.N_GameInMatch, util_esports.otherTeamN(t), ingameRoleNumber)
player_data.cargo.GameRoleId = util_cargo.getUniqueLine(game_data.N_MatchInPage, game_data.N_GameInMatch, t, ingameRoleNumber)
player_data.cargo.GameRoleIdVs = util_cargo.getUniqueLine(game_data.N_MatchInPage, game_data.N_GameInMatch, util_esports.otherTeamN(t), ingameRoleNumber)
player_data.cargoPentakills = h.getPlayerPentakillCargo(player_data.cargo, player_data)
-- this field is just for an external python script
player_data.cargo.StatsPage = util_title.concatSubpageParts(player_data.Link, 'Statistics', util_vars.getVar('sbYear'))
end
end
end
-- get for entire game
function h.initGameCargoFromData(game_data)
local fields = { 'Tournament', 'Team1', 'Team2', 'WinTeam', 'LossTeam', 'DST', 'Team1Score', 'Team2Score', 'Winner', 'Gamelength', 'Gamelength_Number', 'Team1Bans', 'Team2Bans', 'Team1Dragons', 'Team2Dragons', 'Team1Barons', 'Team2Barons', 'Team1Towers', 'Team2Towers', 'Team1Gold', 'Team2Gold', 'Team1Kills', 'Team2Kills', 'Team1RiftHeralds', 'Team2RiftHeralds', 'Team1VoidGrubs', 'Team2VoidGrubs', 'Team1Atakhans', 'Team2Atakhans', 'Team1Inhibitors', 'Team2Inhibitors', 'Patch', 'LegacyPatch', 'MatchHistory', 'Gamename', 'N_GameInMatch', 'N_MatchInPage', 'VOD' }
local ret = {
_table = 'ScoreboardGames',
}
for _, v in ipairs(fields) do
ret[v] = game_data[v]
end
return ret
end
function h.getIdWiki(game_data)
return ('%s_%s_%s_%s'):format(
game_data.cargo.OverviewPage,
util_scoreboard.getTabName(),
util_vars.getGlobalIndex('sb_N_MatchInTab'),
game_data.N_GameInMatch
)
end
function h.getMatchId(game_data)
return ('%s_%s_%s'):format(
game_data.cargo.OverviewPage,
util_scoreboard.getTabName(),
util_vars.getGlobalIndex('sb_N_MatchInTab')
)
end
function h.gatherPlayerCargoForGameFields(cargo, player_data)
cargo.Team1Picks = h.gatherOnePlayerDatapointForGameFields(player_data[1], 'Champion')
cargo.Team2Picks = h.gatherOnePlayerDatapointForGameFields(player_data[2], 'Champion')
cargo.Team1Players = h.gatherOnePlayerDatapointForGameFields(player_data[1], 'Link')
cargo.Team2Players = h.gatherOnePlayerDatapointForGameFields(player_data[2], 'Link')
end
function h.gatherOnePlayerDatapointForGameFields(team, datapoint)
local tbl = {}
for i, player in ipairs(team) do
tbl[team.rolemapHash[i]] = tostring(player[datapoint])
end
return util_table.concat(tbl, ',')
end
-- get for one team
function h.getTeamCargo(game_data, player_data, teamIndex)
-- table with each row a team
-- this is a way better data structure than having Team1... etc
-- and all queries should be updated to use this, then the game table have
-- team specific stuff removed from it
local ret = {
_table = 'ScoreboardTeams',
OverviewPage = game_data.cargo.OverviewPage,
Side = TEAMS_DISPLAY[teamIndex],
Number = teamIndex,
UniqueGame = game_data.cargo.UniqueGame,
MatchId = game_data.cargo.MatchId,
GameId = game_data.cargo.GameId,
UniqueTeam = game_data.cargo.UniqueGame .. '_Team' .. teamIndex,
GameTeamId = game_data.cargo.UniqueGame .. '_Team' .. teamIndex,
}
util_table.merge(ret, h.getOneTeamFieldsFromGame(game_data.cargo, teamIndex))
ret.IsWinner = game_data.WinTeam == ret.Team
ret.StatsPage = util_title.concatSubpageParts(ret.Team, 'Statistics', util_vars.getVar('sbYear'))
return ret
end
function h.getOneTeamFieldsFromGame(gameCargo, teamIndex)
-- copy paste from the game data to one specific team
-- this will need to be rewritten if we stop storing team-specific stuff in the game table
-- but for now this was a quick way to implement this
local ret = {}
local fields = { '', 'Score', 'Bans', 'Picks', 'Players', 'Dragons', 'Barons', 'Towers', 'Gold', 'Kills', 'RiftHeralds', 'VoidGrubs', 'Atakhans', 'Inhibitors' }
local field_aliases = {
[''] = 'Team',
Players = 'Roster',
}
for _, field in ipairs(fields) do
ret[field_aliases[field] or field] = gameCargo['Team' .. teamIndex .. field]
end
return ret
end
-- get for individual player
function h.initPlayerCargoFromData(player_data)
local fields = {
'Link',
'Kills',
'Deaths',
'Assists',
'SummonerSpells',
'Gold',
'CS',
'DamageToChampions',
'VisionScore',
'Champion',
'Items',
'Trinket',
'IngameRole',
'PrimaryTree',
'SecondaryTree',
}
local ret = { _table = 'ScoreboardPlayers' }
for _, v in ipairs(fields) do
ret[v] = player_data[v]
end
ret.SummonerSpells = util_table.concat(player_data.SummonerSpells)
return ret
end
function h.addPlayerCargoDataFromGame(player, game, team)
player.Team = game['Team' .. team]
player.TeamVs = game['Team' .. util_esports.otherTeamN(team)]
player.TeamGold = game['Team' .. team .. 'Gold']
player.TeamKills = game['Team' .. team .. 'Kills']
player.DateTime_UTC = game.DateTime_UTC
player.OverviewPage = game.OverviewPage
player.UniqueGame = game.UniqueGame
player.GameId = game.GameId
player.MatchId = game.MatchId
player.PlayerWin = game.Winner == team
end
function h.addPlayerCargoRoleData(cargo, playerN)
cargo.Role = Role(playerN)
cargo.Role_Number = playerN
end
function h.addPlayerCargoKeystoneData(cargo, player_data)
if not SEASON.keystone then return end
if SEASON.keystone == 'Mastery' then
cargo.KeystoneMastery = player_data.Keystone
elseif SEASON.keystone == 'Rune' then
cargo.KeystoneRune = player_data.Keystone
end
end
function h.getPlayerPentakillCargo(playerCargo, player_data)
if tonumber(player_data.Pentakills or 0) < 1 then return {} end
if not player_data.PentakillVod then
return { h.getOnePlayerPentakillCargo(nil, playerCargo) }
end
return util_map.split(player_data.PentakillVod, nil, h.getOnePlayerPentakillCargo, playerCargo)
end
function h.getOnePlayerPentakillCargo(vod, playerCargo)
local pentakill = {
_table = 'Pentakills',
DateDisplay = util_time.strToDateStr(playerCargo.DateTime_UTC),
DateSort = playerCargo.DateTime_UTC,
OverviewPage = util_esports.getOverviewPage(),
Team = playerCargo.Team,
TeamVs = playerCargo.TeamVs,
Name = playerCargo.Name,
Link = playerCargo.Link,
Champion = playerCargo.Champion,
Role = playerCargo.Role,
Win = playerCargo.PlayerWin,
Kills = playerCargo.Kills,
Deaths = playerCargo.Deaths,
Assists = playerCargo.Assists,
ScoreboardLink = mw.title.getCurrentTitle().text,
Vod = vod
}
return pentakill
end
-- cargo
function p:storeCargo(args, player_data, game_data)
util_cargo.store(game_data.cargo)
for i, team in ipairs(player_data) do
util_cargo.store(game_data.team_cargo[i])
for _, player in ipairs(team) do
util_cargo.store(player.cargo)
util_map.rowsInPlace(player.cargoPentakills, util_cargo.storeAndAttach)
end
end
end
-- output
function p:makeOutput(game_data, player_data)
h.prepToggles()
local tbl = mw.html.create('table')
:addClass('sb')
h.printTeamLine(tbl, game_data)
h.printScoreLine(tbl, game_data)
h.printHeaderLine(tbl, game_data)
self:printLine(tbl, game_data, 'th', self.printKey)
self:printLine(tbl, player_data, 'td', self.printPlayers)
h.printDateTimeAndLinks(tbl, game_data)
self:printLine(tbl, game_data, 'td', self.printFooter)
return tbl
end
function h.prepToggles()
local n = util_vars.getGlobalIndex('sb_N_GameInTab')
local section = util_vars.getGlobalIndex('sb_N_TabInPage_display')
util_toggle.prepDataByWeekAndGame(util_scoreboard.TOGGLES.one, section, n)
util_scoreboard.TOGGLES.row = util_scoreboard.TOGGLES.row:format(section, section, n)
end
function h.printTeamLine(tbl, game_data)
local tr = tbl:tag('tr')
local th1 = tr:tag('th')
:addClass('sb-teamname')
:wikitext(m_team.rightmediumlinked(game_data.Team1))
h.printVs(tr, game_data)
local th2 = tr:tag('th')
:addClass('sb-teamname')
:wikitext(m_team.leftmediumlinked(game_data.Team2))
end
function h.printVs(tr, game_data)
local thVs = tr:tag('th')
:addClass('sb-teamname-vs')
:attr('colspan',2)
:wikitext('vs')
util_footnote.tagFootnotePlain(thVs, game_data.footnote)
end
function h.printScoreLine(tbl, game_data)
local tr = tbl:tag('tr')
h.printScore(tr, game_data.Team1Score, 'blue', game_data.Winner == 1)
local th = tr:tag('th'):attr('colspan','2')
util_toggle.printToggleButton(th, util_scoreboard.TOGGLES.one)
h.printScore(tr, game_data.Team2Score, 'red', game_data.Winner == 2)
end
function h.printScore(tr, score, side, isWinner)
local th = tr:tag('th')
:addClass('side-' .. side)
:wikitext(score)
if isWinner then
th:addClass('sb-score-winner')
end
end
function h.printHeaderLine(tbl, game_data)
local tr = tbl:tag('tr')
:addClass(util_scoreboard.TOGGLES.row)
h.printHeaderCell(tr, game_data, 1)
h.printGameLength(tr, game_data)
h.printHeaderCell(tr, game_data, 2)
end
function h.printHeaderCell(tr, game_data, i)
local td = tr:tag('th')
if i == 2 then
td:addClass('side-red')
end
local div = td:tag('div')
:addClass('sb-header')
local verdict
if game_data.Winner == i then
verdict = 'Victory'
elseif game_data.Winner == util_esports.otherTeamN(i) then
verdict = 'Defeat'
end
util_scoreboard.div(div, 'header-vertict', verdict)
h.printHeaderInfo(div, 'Gold', util_esports.roundedGold(game_data['Team' .. i .. 'Gold']))
h.printHeaderInfo(div, 'Kills', game_data['Team' .. i .. 'Kills'])
end
function h.printHeaderInfo(parent, name, wikitext)
local class = ('%s'):format(lang:lc(name))
parent:tag('div')
:addClass('sb-header-' .. name)
:attr('title', i18n.print(name))
:wikitext(s.InfoSprite(name), ' ', wikitext)
end
function h.printGameLength(tr, game_data)
local th = tr:tag('th')
:attr('colspan', 2)
th:wikitext(game_data.Gamelength)
end
function p:printLine(tbl, data, celltype, f)
local tr = tbl:tag('tr')
:addClass(util_scoreboard.TOGGLES.row)
for i, side in ipairs(TEAMS) do
local td = tr:tag(celltype)
:attr('colspan',2)
:addClass('side-' .. side)
f(self, td, data, i)
end
end
function p:printKey(td)
-- honestly it's just not worth it to write any kind of loop for this
local outer = td:tag('div'):addClass('sb-key')
util_scoreboard.div(outer, 'key-champion', 'Champ')
util_scoreboard.div(outer, 'key-summoners', 'SS')
if SEASON.runes then
util_scoreboard.div(outer, 'key-runes', 'R')
end
local info = outer:tag('div'):addClass('sb-key-info')
local stats = info:tag('div'):addClass('sb-key-stats')
self:printStatsHeaders(stats)
if SEASON.trinket then
util_scoreboard.div(stats, 'key-trinket', 'T')
end
if PRINT_ITEMS then
util_scoreboard.div(outer, 'key-items', 'Items')
end
end
function p:printStatsHeaders(stats)
util_scoreboard.div(stats, 'key-stat', 'KDA', 'kda')
util_scoreboard.div(stats, 'key-stat', 'CS', 'cs')
util_scoreboard.div(stats, 'key-stat', 'Gold', 'gold')
end
function p:printPlayers(td, player_data, i)
local data = player_data[i]
for _, row in ipairs(data) do
self:printPlayer(td, row)
end
end
function p:printPlayer(td, row)
local outer = td:tag('div'):addClass('sb-p')
util_scoreboard.div(outer, 'p-champion', row.Champion:image{size=60, nosize=true})
h.printPlayerSummoners(outer, row.SummonerSpells)
if SEASON.runes then
h.printPlayerRunes(outer, row)
end
local info = outer:tag('div'):addClass('sb-p-info')
h.printPlayerName(info, row)
self:printPlayerStats(info, row)
if SEASON.mastery then
h.printTrinketAndMastery(outer, row)
end
if PRINT_ITEMS then
h.printPlayerItems(outer, row.Items)
end
end
function h.printPlayerSummoners(outer, spells)
local ss = outer:tag('div'):addClass('sb-p-summoners')
util_scoreboard.div(ss, 'p-sum', s.SummonerSprite(spells[1]))
util_scoreboard.div(ss, 'p-sum', s.SummonerSprite(spells[2]))
end
function h.printPlayerRunes(outer, row)
local runes = outer:tag('div'):addClass('sb-p-runes')
h.printPlayerKeystone(runes, row.Keystone or 'EmptySummoner')
RunesReforged.display(runes, row.AllRunes)
h.printPlayerRune(runes, row.SecondaryTree or 'EmptySummoner')
end
function h.printPlayerKeystone(runes_div, rune)
util_scoreboard.div(
runes_div,
'p-rune',
Keystone(rune):image({ size = 30 })
)
end
function h.printPlayerRune(runes_div, rune)
util_scoreboard.div(
runes_div,
'p-rune',
('[[File:Rune %s.png|30px|link=]]'):format(rune)
)
end
function h.printPlayerName(info, row)
util_scoreboard.div(info, 'p-name', util_esports.playerLinked(row.Link, row.Name))
end
function h.printTrinketAndMastery(outer, row)
local inner = outer:tag('div'):addClass('sb-p-masteryandtrinket')
util_scoreboard.div(inner, 'p-trinket', ('[[File:Mastery %s.png|30px|link=]]'):format(row.Keystone or 'None'))
h.printTrinket(inner, row.Trinket)
end
function h.printTrinket(div, trinket)
util_scoreboard.div(div, 'p-trinket', trinket:image({ size=30, nosize=true }))
end
function p:printPlayerStats(info, row)
local stats = info:tag('div'):addClass('sb-p-stats')
self:printPlayerKDA(stats, row)
self:printPlayerCS(stats, row)
self:printPlayerGold(stats, row)
if SEASON.trinket and not SEASON.mastery then
h.printTrinket(stats, row.Trinket)
end
end
function p:printPlayerKDA(stats, row)
util_scoreboard.div(stats, 'p-stat', util_esports.KDA(row.Kills or '', row.Deaths or '', row.Assists or ''), 'kda')
end
function p:printPlayerCS(stats, row)
util_scoreboard.div(stats, 'p-stat', row.CS, 'cs')
end
function p:printPlayerGold(stats, row)
util_scoreboard.div(stats, 'p-stat', util_esports.roundedGold(row.Gold), 'gold')
end
function h.printPlayerItems(outer, items)
util_scoreboard.div(outer, 'p-items', items:images({ size=30, nosize=true }))
end
function h.printDateTimeAndLinks(tbl, game_data)
local tr = tbl:tag('tr')
:addClass(util_scoreboard.TOGGLES.row)
local td = tr:tag('td')
:attr('colspan',4)
:addClass('sb-datetime-outer')
:addClass('plainlinks')
local div = td:tag('div')
:addClass('sb-datetime')
h.printDateAndTime(div, game_data.tz.UTC)
h.printPatch(div, game_data.Patch)
if game_data.version ~= 5 then
h.printMH(div, game_data.MatchHistory)
end
h.printVOD(div, game_data.VOD)
h.printStatsPopup(div, game_data)
end
function h.printDateAndTime(div, utc)
local date = util_time.dateInLocal(utc)
local time = util_time.timeInLocal(utc)
local display = date .. ' ' .. time
h.printDateTimeItem(div, 'date', display, 'Date & Time of the match in your local time zone')
end
function h.printPatch(div, patch)
local display = patch and util_text.intLinkOrText('Patch ' .. patch) or ''
h.printDateTimeItem(div, 'patch', display, 'Patch')
end
function h.printMH(div, mh)
local display = i18n.print('match_history') .. (util_text.extLink(mh, 'Link') or 'N/A')
h.printDateTimeItem(div, 'mh', display)
end
function h.printVOD(div, vod)
local display = i18n.print('vod') .. (util_text.extLink(vod, 'Link') or 'N/A')
h.printDateTimeItem(div, 'vod', display)
end
function h.printStatsPopup(div, game_data)
if game_data.cargo == nil then return end
local popupWrapper = div:tag("div")
:addClass("sbes-popup-wrapper")
:wikitext("Stat Graphs ")
local popup = util_toggle.popupButtonLazy(popupWrapper, "sbes-lazyloaded")
popup.button:attr("data-parse-text", "ScoreboardExtraStats|id=" .. game_data.cargo.GameId)
popup.tbl:addClass('sb-runes-popup-container')
popup.wrapper:addClass('sbes-wrapper')
popup.inner:addClass('sbes-inner')
return popup.tbl
end
function h.printDateTimeItem(div, class, str, title)
div:tag('div')
:addClass('sb-datetime-' .. class)
:wikitext(str)
:attr('title', title)
end
function p:printFooter(td, game_data, i)
local key = 'Team' .. i
local div = td:tag('div'):addClass('sb-footer')
local bans = div:tag('div'):addClass('sb-footer-bans')
util_scoreboard.div(bans, 'footer-ban-header', nil)
util_scoreboard.div(bans, 'footer-bans', game_data[key .. 'Bans']:images{size=30, nosize=true})
local stats = div:tag('div'):addClass('sb-footer-stats')
for _, v in ipairs(FOOTER_ITEMS) do
h.printFooterInfo(stats, game_data, key, v, 'footer-item')
end
end
function h.printFooterInfo(parent, data, key, datapoint, parentclass)
local fullkey = key .. datapoint
local class2 = ('%s'):format(lang:lc(datapoint))
parent:tag('div')
:addClass('sb-' .. parentclass)
:addClass('sb-' .. parentclass .. '-' .. class2)
:wikitext(s.InfoSprite(fullkey), ' ', data[fullkey])
:attr('title', i18n.print(datapoint))
end
-- if game wasn't played
function h.getNotPlayedGameData(args)
local game_data = {}
h.setVariables(game_data, args)
h.getWinnerAndLoser(game_data, args)
h.getGameDataByRenamingArgs(game_data, args)
h.getNotPlayedTeamDisplayData(game_data, args)
h.getDateAndTime(game_data, args)
h.getGameFootnotes(game_data, args)
return game_data
end
function h.getNotPlayedTeamDisplayData(game_data, args)
for i, s in ipairs(PLAYER_SIDES) do
local key = 'Team' .. i
local arg = 'team' .. i
game_data[key] = m_team.teamlinkname(args[arg])
h.getTeamDataByRenamingArgs(game_data, args, key, arg)
end
end
function h.printNotPlayedTitle(tbl, args)
local tr = tbl:tag('tr')
tr:tag('td')
:addClass('sb-notplayed-header')
:addClass(util_scoreboard.TOGGLES.row)
:attr('colspan', 4)
:wikitext(args.notplayed)
end
function h.printNotPlayedReason(tbl, args)
local tr = tbl:tag('tr')
tr:tag('td')
:addClass('sb-notplayed')
:addClass(util_scoreboard.TOGGLES.row)
:attr('colspan', 4)
:wikitext(args.reason or i18n.print('no_reason'))
end
return p