Module:PlayerStats

local p = {}

local function tprint (tbl, indent) if not indent then indent = 0 end for k, v in pairs(tbl) do   formatting = string.rep("  ", indent) .. k .. ": "   if type(v) == "table" then mw.log(formatting) tprint(v, indent+1) elseif type(v) == 'boolean' then mw.log(formatting .. tostring(v)) else mw.log(formatting .. v)   end end end

p.games = { BlOps3 = { modes = {HP=1, SD=2, UL=3, CTF=4} },	IW = { modes = {HP=1, SD=2, UL=3} },	WWII = { modes = {HP=1, SD=2, CTF=3} } }

p.playerStats = function(frame) -- for player pages frame = mw.getCurrentFrame args = require( 'Module:ProcessArgs').merge -- merge because args are both passed to template and hardcoded in template local game = args.game local playerName = args[1]

local tbl = mw.html.create('table') tbl:addClass("wikitable sortable"):css("text-align","center") :tag("tr"):tag("th"):attr("colspan","25"):wikitext('Player Statistics'):done local firstHeader = tbl:tag("tr") :tag("th"):attr('colspan','8'):wikitext('Overall'):done -- table-specific headers p:printFirstHeader(frame, game, firstHeader) -- add game headers local secondHeader = tbl:tag("tr") -- table-specific subheaders :tag("th"):wikitext('Date'):done :tag("th"):wikitext('Tournament'):done :tag("th"):wikitext('Team'):done :tag("th"):wikitext(frame:expandTemplate{ title = 'Abbr', args = {'G','Games'}}):done :tag("th"):wikitext(frame:expandTemplate{ title = 'Abbr', args = {'W','Wins'}}):done :tag("th"):wikitext(frame:expandTemplate{ title = 'Abbr', args = {'L','Losses'}}):done :tag("th"):wikitext(frame:expandTemplate{ title = 'Abbr', args = {'WR','Winrate'}}):done :tag("th"):wikitext(frame:expandTemplate{ title = 'Abbr', args = {'K/D','Kill/Death Ratio'}}):done p:printSecondHeader(frame, game, secondHeader) -- add game-specific subheaders local data, order = p:groupResults(p:queryByPlayer(game, playerName), "Tournament") p:printTablePlayer(frame, game, tbl, data, order) return tbl end

p.tournamentStats = function(frame) -- for tournament pages frame = mw.getCurrentFrame args = require( 'Module:ProcessArgs').merge -- merge because args are both passed to template and hardcoded in template local game = args.game local tournament = args[1]

local data, order = p:groupResults(p:queryByTournament(game, tournament), "PlayerName") local tbl = mw.html.create('table') tbl:addClass("wikitable sortable"):css("text-align","center") :tag("tr"):tag("th"):attr("colspan","22"):wikitext('Player Statistics - ') :tag("span"):css('color','red'):wikitext(data._totalGames):done :wikitext(' Total Games Played (All Scoreboards Included)'):done local firstHeader = tbl:tag("tr") :tag("th"):attr('colspan','8'):wikitext('Overall'):done -- table-specific headers p:printFirstHeader(frame, game, firstHeader) -- add game headers local secondHeader = tbl:tag("tr") -- table-specific subheaders :tag("th"):wikitext('Date'):done :tag("th"):wikitext('Tournament'):done :tag("th"):wikitext('Team'):done :tag("th"):wikitext(frame:expandTemplate{ title = 'Abbr', args = {'G','Games'}}):done :tag("th"):wikitext(frame:expandTemplate{ title = 'Abbr', args = {'W','Wins'}}):done :tag("th"):wikitext(frame:expandTemplate{ title = 'Abbr', args = {'L','Losses'}}):done :tag("th"):wikitext(frame:expandTemplate{ title = 'Abbr', args = {'WR','Winrate'}}):done :tag("th"):wikitext(frame:expandTemplate{ title = 'Abbr', args = {'K/D','Kill/Death Ratio'}}):done p:printSecondHeader(frame, game, secondHeader) -- add game-specific subheaders p:printTableTournament(frame, game, tbl, data, order) return tbl end p.printFirstHeader = function(self, frame, game, tr, options) if not options then options = {} end local colsPerGame = 3 if options.killsPerGame then colsPerGame = colsPerGame +1 end if self.games[game].modes['HP'] then tr:tag("th"):attr('colspan',colsPerGame):wikitext('Hardpoint'):done end if self.games[game].modes['SD'] then tr:tag("th"):attr('colspan',colsPerGame):wikitext('Search & Destroy'):done end if self.games[game].modes['UL'] then tr:tag("th"):attr('colspan',colsPerGame):wikitext('Uplink'):done end if self.games[game].modes['CTF'] then tr:tag("th"):attr('colspan',colsPerGame):wikitext('Capture the Flag'):done end end

p.printSecondHeader = function(self, frame, game, tr, options) if not options then options = {} end if self.games[game].modes['HP'] then tr:tag("th"):wikitext(frame:expandTemplate{ title = 'Abbr', args = {'K/D','Kill/Death Ratio'}}):done :tag("th"):wikitext(frame:expandTemplate{ title = 'Abbr', args = {'HPT','Hardpoint Time per Game'}}):done :tag("th"):wikitext(frame:expandTemplate{ title = 'Abbr', args = {'DFND','Defends per Game'}}):done end if self.games[game].modes['SD'] then tr:tag("th"):wikitext(frame:expandTemplate{ title = 'Abbr', args = {'K/D','Kill/Death Ratio'}}):done :tag("th"):wikitext(frame:expandTemplate{ title = 'Abbr', args = {'PLNT','Plants per Game'}}):done :tag("th"):wikitext(frame:expandTemplate{ title = 'Abbr', args = {'DFSE','Defuse per Game'}}):done end if self.games[game].modes['UL'] then tr:tag("th"):wikitext(frame:expandTemplate{ title = 'Abbr', args = {'K/D','Kill/Death Ratio'}}):done :tag("th"):wikitext(frame:expandTemplate{ title = 'Abbr', args = {'THR','Throws per Game'}}):done :tag("th"):wikitext(frame:expandTemplate{ title = 'Abbr', args = {'CAR','Carries per Game'}}):done end if self.games[game].modes['CTF'] then tr:tag("th"):wikitext(frame:expandTemplate{ title = 'Abbr', args = {'K/D','Kill/Death Ratio'}}):done :tag("th"):wikitext(frame:expandTemplate{ title = 'Abbr', args = {'CAP','Captures per Game'}}):done :tag("th"):wikitext(frame:expandTemplate{ title = 'Abbr', args = {'RET','Returns per Game'}}):done end end

p.printTablePlayer = function(self, frame, game, tbl, data, order) for _,t in ipairs(order) do		local v = data[t] local tr = tbl:tag('tr') tr:tag('td'):wikitext(frame:callParserFunction('#time','Y-m-d', v.date )):done :tag('td'):wikitext(..v.tournament..):done :tag('td'):wikitext(frame:expandTemplate{title='Team/Onlyimagelinked', args= {v.team}}):done :tag('td'):wikitext(v.games):done :tag('td'):wikitext(v.wins):done :tag('td'):wikitext(v.games-v.wins):done :tag('td'):wikitext(math.floor((v.wins*1000 / v.games)/10)..'%'):done :tag('td'):wikitext(v.deaths < 1 and N/A or math.floor(v.kills*100/v.deaths)/100):done if self.games[game].modes['HP'] then if v.hpGames < 1 then tr:tag('td'):wikitext('--'):done :tag('td'):wikitext('--'):done :tag('td'):wikitext('--'):done else tr:tag('td'):wikitext(v.hpDeaths < 1 and 'N/A' or math.floor(v.hpKills*100/v.hpDeaths)/100):done :tag('td'):wikitext(math.floor(v.hpTime/v.hpGames/60)..':'..string.sub('0'..v.hpTime/v.hpGames%60, -2)):done :tag('td'):wikitext(math.floor(v.hpDefends*100/v.hpGames)/100):done end end if self.games[game].modes['SD'] then if v.sdGames < 1 then tr:tag('td'):wikitext('--'):done :tag('td'):wikitext('--'):done :tag('td'):wikitext('--'):done else tr:tag('td'):wikitext(v.sdDeaths < 1 and 'N/A' or math.floor(v.sdKills*100/v.sdDeaths)/100):done :tag('td'):wikitext(math.floor(v.sdPlants*100/v.sdGames)/100):done :tag('td'):wikitext(math.floor(v.sdDefuses*100/v.sdGames)/100):done end end if self.games[game].modes['UL'] then if v.ulGames < 1 then tr:tag('td'):wikitext('--'):done :tag('td'):wikitext('--'):done :tag('td'):wikitext('--'):done else tr:tag('td'):wikitext(v.ulDeaths < 1 and 'N/A' or math.floor(v.ulKills*100/v.ulDeaths)/100):done :tag('td'):wikitext(math.floor(v.ulThrows*100/v.ulGames)/100):done :tag('td'):wikitext(math.floor(v.ulCarries*100/v.ulGames)/100):done end end if self.games[game].modes['CTF'] then if v.ctfGames < 1 then tr:tag('td'):wikitext('--'):done :tag('td'):wikitext('--'):done :tag('td'):wikitext('--'):done else tr:tag('td'):wikitext(v.ctfDeaths < 1 and 'N/A' or math.floor(v.ctfKills*100/v.ctfDeaths)/100):done :tag('td'):wikitext(math.floor(v.ctfCaptures*100/v.ctfGames)/100):done :tag('td'):wikitext(math.floor(v.ctfReturns*100/v.ctfGames)/100):done end end end end

p.printTableTournament = function(self, frame, game, tbl, data, order) for _,t in ipairs(order) do		local v = data[t] local tr = tbl:tag('tr') tr:tag('td'):wikitext(frame:expandTemplate{title='Team/Onlyimagelinked', args= {v.team}}):done :tag('td'):wikitext(v.games):done :tag('td'):wikitext(v.wins):done :tag('td'):wikitext(v.games-v.wins):done :tag('td'):wikitext(math.floor((v.wins*1000 / v.games)/10)..'%'):done :tag('td'):wikitext(v.deaths < 1 and N/A or math.floor(v.kills*100/v.deaths)/100):done if self.games[game].modes['HP'] then if v.hpGames < 1 then tr:tag('td'):wikitext('--'):done :tag('td'):wikitext('--'):done :tag('td'):wikitext('--'):done else tr:tag('td'):wikitext(v.hpDeaths < 1 and 'N/A' or math.floor(v.hpKills*100/v.hpDeaths)/100):done :tag('td'):wikitext(math.floor(v.hpTime/v.hpGames/60)..':'..string.sub('0'..v.hpTime/v.hpGames%60, -2)):done :tag('td'):wikitext(math.floor(v.hpDefends*100/v.hpGames)/100):done end end if self.games[game].modes['SD'] then if v.sdGames < 1 then tr:tag('td'):wikitext('--'):done :tag('td'):wikitext('--'):done :tag('td'):wikitext('--'):done else tr:tag('td'):wikitext(v.sdDeaths < 1 and 'N/A' or math.floor(v.sdKills*100/v.sdDeaths)/100):done :tag('td'):wikitext(math.floor(v.sdPlants*100/v.sdGames)/100):done :tag('td'):wikitext(math.floor(v.sdDefuses*100/v.sdGames)/100):done end end if self.games[game].modes['UL'] then if v.ulGames < 1 then tr:tag('td'):wikitext('--'):done :tag('td'):wikitext('--'):done :tag('td'):wikitext('--'):done else tr:tag('td'):wikitext(v.ulDeaths < 1 and 'N/A' or math.floor(v.ulKills*100/v.ulDeaths)/100):done :tag('td'):wikitext(math.floor(v.ulThrows*100/v.ulGames)/100):done :tag('td'):wikitext(math.floor(v.ulCarries*100/v.ulGames)/100):done end end if self.games[game].modes['CTF'] then if v.ctfGames < 1 then tr:tag('td'):wikitext('--'):done :tag('td'):wikitext('--'):done :tag('td'):wikitext('--'):done else tr:tag('td'):wikitext(v.ctfDeaths < 1 and 'N/A' or math.floor(v.ctfKills*100/v.ctfDeaths)/100):done :tag('td'):wikitext(math.floor(v.ctfCaptures*100/v.ctfGames)/100):done :tag('td'):wikitext(math.floor(v.ctfReturns*100/v.ctfGames)/100):done end end end end p.groupResults = function(self, result, groupBy) local groupedResults = {_totalGames=0} local order = {} for _,row in ipairs(result) do

if #order == 0 or row[groupBy] ~= order[#order] then order[#order+1] = row[groupBy] end local tnData if groupedResults[row[groupBy]] then tnData = groupedResults[row[groupBy]] else tnData = {date=row.Date, tournament=row.Tournament, tournamentLink=row.TournamentLink, team=row.Team, games=0, wins=0, kills=0, deaths=0, hpGames=0, hpKills=0, hpDeaths=0, hpTime=0, hpDefends=0, sdGames=0, sdKills=0, sdDeaths=0, sdPlants=0, sdDefuses=0, ulGames=0, ulKills=0, ulDeaths=0, ulCarries=0, ulThrows=0, ctfGames=0, ctfKills=0, ctfDeaths=0, ctfCaptures=0, ctfReturns=0 }		end groupedResults._totalGames = groupedResults._totalGames+1; tnData.games = tnData.games+1 tnData.wins = tnData.wins + row.Win tnData.kills = tnData.kills + row.Kills tnData.deaths = tnData.deaths + row.Deaths if row.Gamemode == 'Hardpoint' then tnData.hpGames = tnData.hpGames+1 tnData.hpKills = tnData.hpKills + row.Kills tnData.hpDeaths = tnData.hpDeaths + row.Deaths tnData.hpTime = tnData.hpTime + row.HPTime tnData.hpDefends = tnData.hpDefends + (tonumber(row.Defends) or 0) elseif row.Gamemode == 'Search and Destroy' then tnData.sdGames = tnData.sdGames+1 tnData.sdKills = tnData.sdKills + row.Kills tnData.sdDeaths = tnData.sdDeaths + row.Deaths tnData.sdPlants = tnData.sdPlants + (tonumber(row.Plants) or 0) tnData.sdDefuses = tnData.sdDefuses + (tonumber(row.Defuses) or 0) elseif row.Gamemode == 'Uplink' then tnData.ulGames = tnData.ulGames+1 tnData.ulKills = tnData.ulKills + row.Kills tnData.ulDeaths = tnData.ulDeaths + row.Deaths tnData.ulCarries = tnData.ulCarries + row.Carries tnData.ulThrows = tnData.ulThrows + (tonumber(row.Throws) or 0) elseif row.Gamemode == 'Capture the Flag' then tnData.ctfGames = tnData.ctfGames+1 tnData.ctfKills = tnData.ctfKills + row.Kills tnData.ctfDeaths = tnData.ctfDeaths + row.Deaths tnData.ctfCaptures = tnData.ctfCaptures + row.Captures tnData.ctfReturns = tnData.ctfReturns + (tonumber(row.Returns) or 0) end groupedResults[row[groupBy]]=tnData end tprint(groupedResults) return groupedResults, order end p.queryByPlayer = function(self, game, playerName) local fieldstable = { "coalesce(StartDate, Date)=Date", "Name=Tournament", "Concat(TournamentPage)=TournamentLink", "Gamemode", "Team", "Win", "Kills", "Deaths" }	fieldstable = self:createFieldsTable(fieldstable, game) local cargoTables = 'PlayerStats'..game..', Tournaments' local cargoFields = table.concat(fieldstable, ',') local result = mw.ext.cargo.query(cargoTables, cargoFields, 		{			join='PlayerStats'..game..'.TournamentPage=Tournaments._pagename' ,			where='PlayerName="'..playerName..'"',			orderBy='StartDate desc, Date desc',			groupBy='UniqueLine',			limit=5000		}) return result end

p.queryByTournament = function(self, game, tournament) local fieldstable = { "Team", "PlayerName", "Team", "Win", "Kills", "Deaths" }	fieldstable = self:createFieldsTable(fieldstable, game) local cargoFields = table.concat(fieldstable, ',') local result = mw.ext.cargo.query('PlayerStats'..game, cargoFields, 		{			where='TournamentPage="'..tournament..'"',			orderBy='Team asc, PlayerName asc',			groupBy='UniqueLine',			limit=5000		}) return result end

p.createFieldsTable = function(self, fieldstable, game) if self.games[game].modes['HP'] then fieldstable[#fieldstable+1]="HPTime" fieldstable[#fieldstable+1]="Defends" end if self.games[game].modes['SD'] then fieldstable[#fieldstable+1]="Plants" fieldstable[#fieldstable+1]="Defuses" end if self.games[game].modes['UL'] then fieldstable[#fieldstable+1]="Carries" fieldstable[#fieldstable+1]="Throws" end if self.games[game].modes['CTF'] then fieldstable[#fieldstable+1]="Captures" fieldstable[#fieldstable+1]="Returns" end return fieldstable end

return p