Initial commit
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
*.pyc
|
||||
163
glicko2.py
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
"""
|
||||
Copyright (c) 2009 Ryan Kirkman
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
"""
|
||||
|
||||
import math
|
||||
|
||||
class Player:
|
||||
# Class attribute
|
||||
# The system constant, which constrains
|
||||
# the change in volatility over time.
|
||||
_tau = 0.5
|
||||
|
||||
def getRating(self):
|
||||
return (self.__rating * 173.7178) + 1500
|
||||
|
||||
def setRating(self, rating):
|
||||
self.__rating = (rating - 1500) / 173.7178
|
||||
|
||||
rating = property(getRating, setRating)
|
||||
|
||||
def getRd(self):
|
||||
return self.__rd * 173.7178
|
||||
|
||||
def setRd(self, rd):
|
||||
self.__rd = rd / 173.7178
|
||||
|
||||
rd = property(getRd, setRd)
|
||||
|
||||
def __init__(self, rating = 1500, rd = 350, vol = 0.06):
|
||||
# For testing purposes, preload the values
|
||||
# assigned to an unrated player.
|
||||
self.setRating(rating)
|
||||
self.setRd(rd)
|
||||
self.vol = vol
|
||||
|
||||
def _preRatingRD(self):
|
||||
""" Calculates and updates the player's rating deviation for the
|
||||
beginning of a rating period.
|
||||
|
||||
preRatingRD() -> None
|
||||
|
||||
"""
|
||||
self.__rd = math.sqrt(math.pow(self.__rd, 2) + math.pow(self.vol, 2))
|
||||
|
||||
def update_player(self, rating_list, RD_list, outcome_list):
|
||||
""" Calculates the new rating and rating deviation of the player.
|
||||
|
||||
update_player(list[int], list[int], list[bool]) -> None
|
||||
|
||||
"""
|
||||
# Convert the rating and rating deviation values for internal use.
|
||||
rating_list = [(x - 1500) / 173.7178 for x in rating_list]
|
||||
RD_list = [x / 173.7178 for x in RD_list]
|
||||
|
||||
v = self._v(rating_list, RD_list)
|
||||
self.vol = self._newVol(rating_list, RD_list, outcome_list, v)
|
||||
self._preRatingRD()
|
||||
|
||||
self.__rd = 1 / math.sqrt((1 / math.pow(self.__rd, 2)) + (1 / v))
|
||||
|
||||
tempSum = 0
|
||||
for i in range(len(rating_list)):
|
||||
tempSum += self._g(RD_list[i]) * \
|
||||
(outcome_list[i] - self._E(rating_list[i], RD_list[i]))
|
||||
self.__rating += math.pow(self.__rd, 2) * tempSum
|
||||
|
||||
|
||||
def _newVol(self, rating_list, RD_list, outcome_list, v):
|
||||
""" Calculating the new volatility as per the Glicko2 system.
|
||||
|
||||
_newVol(list, list, list) -> float
|
||||
|
||||
"""
|
||||
i = 0
|
||||
delta = self._delta(rating_list, RD_list, outcome_list, v)
|
||||
a = math.log(math.pow(self.vol, 2))
|
||||
tau = self._tau
|
||||
x0 = a
|
||||
x1 = 0
|
||||
|
||||
while x0 != x1:
|
||||
# New iteration, so x(i) becomes x(i-1)
|
||||
x0 = x1
|
||||
d = math.pow(self.__rating, 2) + v + math.exp(x0)
|
||||
h1 = -(x0 - a) / math.pow(tau, 2) - 0.5 * math.exp(x0) \
|
||||
/ d + 0.5 * math.exp(x0) * math.pow(delta / d, 2)
|
||||
h2 = -1 / math.pow(tau, 2) - 0.5 * math.exp(x0) * \
|
||||
(math.pow(self.__rating, 2) + v) \
|
||||
/ math.pow(d, 2) + 0.5 * math.pow(delta, 2) * math.exp(x0) \
|
||||
* (math.pow(self.__rating, 2) + v - math.exp(x0)) / math.pow(d, 3)
|
||||
x1 = x0 - (h1 / h2)
|
||||
|
||||
return math.exp(x1 / 2)
|
||||
|
||||
def _delta(self, rating_list, RD_list, outcome_list, v):
|
||||
""" The delta function of the Glicko2 system.
|
||||
|
||||
_delta(list, list, list) -> float
|
||||
|
||||
"""
|
||||
tempSum = 0
|
||||
for i in range(len(rating_list)):
|
||||
tempSum += self._g(RD_list[i]) * (outcome_list[i] - self._E(rating_list[i], RD_list[i]))
|
||||
return v * tempSum
|
||||
|
||||
def _v(self, rating_list, RD_list):
|
||||
""" The v function of the Glicko2 system.
|
||||
|
||||
_v(list[int], list[int]) -> float
|
||||
|
||||
"""
|
||||
tempSum = 0
|
||||
for i in range(len(rating_list)):
|
||||
tempE = self._E(rating_list[i], RD_list[i])
|
||||
tempSum += math.pow(self._g(RD_list[i]), 2) * tempE * (1 - tempE)
|
||||
return 1 / tempSum
|
||||
|
||||
def _E(self, p2rating, p2RD):
|
||||
""" The Glicko E function.
|
||||
|
||||
_E(int) -> float
|
||||
|
||||
"""
|
||||
return 1 / (1 + math.exp(-1 * self._g(p2RD) * \
|
||||
(self.__rating - p2rating)))
|
||||
|
||||
def _g(self, RD):
|
||||
""" The Glicko2 g(RD) function.
|
||||
|
||||
_g() -> float
|
||||
|
||||
"""
|
||||
return 1 / math.sqrt(1 + 3 * math.pow(RD, 2) / math.pow(math.pi, 2))
|
||||
|
||||
def did_not_compete(self):
|
||||
""" Applies Step 6 of the algorithm. Use this for
|
||||
players who did not compete in the rating period.
|
||||
|
||||
did_not_compete() -> None
|
||||
|
||||
"""
|
||||
self._preRatingRD()
|
||||
1526
pubresults.yaml
Normal file
284
pubstatcruncher.py
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
# from yaml import safe_load, dump
|
||||
import yaml
|
||||
from operator import itemgetter
|
||||
import glicko2
|
||||
# from itertools import pairwise
|
||||
from more_itertools import pairwise
|
||||
|
||||
# load file
|
||||
with open('pubresults.yaml', 'r') as file:
|
||||
file_contents = yaml.full_load(file)
|
||||
|
||||
# print(yaml.dump(file_contents))
|
||||
# print(len([key for key in file_contents]))
|
||||
# print(len(file_contents))
|
||||
# print(file_contents[0]['mission']) # zero'th match, missionname
|
||||
# print(file_contents[0]['date'])
|
||||
# print(file_contents[0]['results'])
|
||||
|
||||
# create player dictionary
|
||||
# playerdata = dict()
|
||||
|
||||
# Point Whore Glickos
|
||||
pwglickos = dict()
|
||||
# Single Team Whore Glickos
|
||||
stpwglickos = dict()
|
||||
# Team Player Glickos
|
||||
tpglickos = dict()
|
||||
|
||||
players_to_roles = {
|
||||
'stormcrow':['ld','lof'],
|
||||
'jacob':['ld','lo','cap'],
|
||||
'bizzy':['ld','lo'],
|
||||
'slush':['cap'],
|
||||
'astralis':['cap','flex'],
|
||||
'domestic':['ld','chase'],
|
||||
'danno':['ho','ho'],
|
||||
'hybrid':['lof','ho'],
|
||||
'vaxity':['ho','shrike'],
|
||||
'mistcane':['ld','cap'],
|
||||
'nevares':['cap'],
|
||||
'haggis':['ho'],
|
||||
'devil':['cap','ho'],
|
||||
'efx':['ld','lof'],
|
||||
'hexy':['ld','shrike'],
|
||||
'halo2':['ho'],
|
||||
'blake':['lof'],
|
||||
'future':['flex'],
|
||||
'thaen':['offense'],
|
||||
'strazz':['hof'],
|
||||
'history':['cap','shrike','ho'],
|
||||
'sliderzero':['shrike','flex'],
|
||||
'jerry':['ld'],
|
||||
'wingedwarrior':['ld','snipe'],
|
||||
'sylock':['ho'],
|
||||
'darrell':['ld'],
|
||||
'pedro':['ld'],
|
||||
'coorslightman':['ld'],
|
||||
'hautsoss':['flex'],
|
||||
'sajent':['ld','ho'],
|
||||
'turtle':['ld'],
|
||||
'irvin':['cap'],
|
||||
'redeye':['lo','ho','flex'],
|
||||
'mlgru':['shrike','ho','cap'],
|
||||
'actionswanson':['flex'],
|
||||
'bendover':['ho'],
|
||||
'warchilde':['ho'],
|
||||
'johnwayne':['flex'],
|
||||
'lsecannon':['farm'],
|
||||
'hp':['ld','lof'],
|
||||
'sake':['ld'],
|
||||
'anthem':['ho'],
|
||||
'taco':['ho'],
|
||||
'exogen':['cap'],
|
||||
'mp40':['hd'],
|
||||
'gunther':['ho'],
|
||||
'ipkiss':['snipe'],
|
||||
'alterego':['hd'],
|
||||
'homer':['ho'],
|
||||
'spartanonyx':['ld'],
|
||||
'bish':['ho'],
|
||||
'flyersfan':['ld'],
|
||||
'geekofwires':['ho'],
|
||||
'aromatomato':['ho'],
|
||||
'heat':['ho','hd','farm'],
|
||||
'daddyroids':['ld'],
|
||||
'pupecki':['ld'],
|
||||
'yuanz':['farm','hd','ho'],
|
||||
'm80':['lof'],
|
||||
'andycap':['hof'],
|
||||
'tetchy':['cap','shrike'],
|
||||
'systeme':['hd','farm','ho'],
|
||||
'friendo':['hof','farm','ld','ho'],
|
||||
'coastal':['shrike','ld'],
|
||||
'caution':['ho','cap'],
|
||||
'jx':['ld'],
|
||||
'nightwear':['flex'],
|
||||
'piata':['ho'],
|
||||
'foxox':['snipe','farm'],
|
||||
'elliebackwards':['ld'],
|
||||
'nutty':['ld'],
|
||||
'sweetcheeks':['farm'],
|
||||
'carpenter':['hd','ld'],
|
||||
'eeor':['ld'],
|
||||
'cooter':['cap'],
|
||||
'flakpyro':['flex','d'],
|
||||
'doug':['ld','ho','snipe'],
|
||||
'raynian':['ho','mo'],
|
||||
'legelos':['ld'],
|
||||
'7thbishop':['cap','hd'],
|
||||
'dirkdiggler':['ho'],
|
||||
'lazer':['ld'],
|
||||
'iroc':['ld'],
|
||||
'ember':['ld'],
|
||||
'2short':['hd','ho','cap'],
|
||||
'earth':['tank','hd','hof'],
|
||||
'lolcaps':['cap'],
|
||||
'aftermath':['ld'],
|
||||
'fnatic':['ld'],
|
||||
}
|
||||
|
||||
first_roles_to_players = dict()
|
||||
any_roles_to_players = dict()
|
||||
for player,roles in players_to_roles.items():
|
||||
if roles[0] is None:
|
||||
# print('')
|
||||
continue
|
||||
# first_role_players = first_roles_to_players[roles[0]]
|
||||
if not roles[0] in first_roles_to_players:
|
||||
first_roles_to_players[roles[0]] = list()
|
||||
# print('adding', player,'to role',roles[0])
|
||||
first_roles_to_players[roles[0]].append(player)
|
||||
|
||||
for role in roles:
|
||||
if not role in any_roles_to_players:
|
||||
any_roles_to_players[role] = list()
|
||||
any_roles_to_players[role].append(player)
|
||||
|
||||
print(first_roles_to_players)
|
||||
print(any_roles_to_players)
|
||||
|
||||
|
||||
# quit()
|
||||
|
||||
|
||||
# loop over all matches
|
||||
for match in file_contents:
|
||||
print()
|
||||
print(match['date'], match['mission'])
|
||||
winning_team_score = 0
|
||||
winning_team_name = None
|
||||
results = match['results']
|
||||
# match
|
||||
merged_match_player_results = list()
|
||||
for team in results:
|
||||
print('team:', team)
|
||||
# if results[team]['score'] > winning_team_score:
|
||||
# winning_team_score = results[team]['score']
|
||||
# winning_team_name = team
|
||||
# print('input unsorted')
|
||||
# for player in results[team]['players']:
|
||||
# print('player:', player)
|
||||
|
||||
# results[team]['players'].sort(key=itemgetter(2), reverse=True)
|
||||
|
||||
# print('input sorted')
|
||||
# print('appending to list this thing',results[team]['players'],type(results[team]['players']), type(results[team]['players'][0]))
|
||||
|
||||
team_player_results = list()
|
||||
|
||||
# parse the string as a tuple
|
||||
for player in results[team]['players']:
|
||||
player_split = player.split(", ")
|
||||
# print('player_split:',player_split)
|
||||
player_tuple = (player_split[0], int(player_split[1]))
|
||||
# print('xx:"',player,'"')
|
||||
# print('xx:',player_tuple)
|
||||
|
||||
# todo consider removing the bottom 20% or something, to filter out people who had connection problems
|
||||
|
||||
merged_match_player_results.append(player_tuple)
|
||||
team_player_results.append(player_tuple)
|
||||
|
||||
# initialize glicko objects for each player, if not already initialized
|
||||
if player_tuple[0] not in pwglickos:
|
||||
pwglickos[player_tuple[0]] = glicko2.Player()
|
||||
if player_tuple[0] not in stpwglickos:
|
||||
stpwglickos[player_tuple[0]] = glicko2.Player()
|
||||
if player_tuple[0] not in tpglickos:
|
||||
tpglickos[player_tuple[0]] = glicko2.Player()
|
||||
|
||||
# per team point whore glicko updates
|
||||
team_player_results.sort(key=itemgetter(1), reverse=True)
|
||||
for better_player, worse_player in pairwise(team_player_results):
|
||||
# score ties
|
||||
lose = 0
|
||||
win = 1
|
||||
if better_player[1] == worse_player[1]:
|
||||
lose = 0.5
|
||||
win = 0.5
|
||||
# print('bp:', better_player)
|
||||
# print('wp:', worse_player)
|
||||
worse_player_glicko = stpwglickos[worse_player[0]]
|
||||
stpwglickos[better_player[0]].update_player([worse_player_glicko.rating], [worse_player_glicko.rd], [win])
|
||||
better_player_glicko = stpwglickos[better_player[0]]
|
||||
stpwglickos[worse_player[0]].update_player([better_player_glicko.rating], [better_player_glicko.rd], [lose])
|
||||
|
||||
|
||||
# for player in merged_match_player_results:
|
||||
# print('inplayer:', player)
|
||||
|
||||
# Sort all of the players in the match by their scores
|
||||
merged_match_player_results.sort(key=itemgetter(1), reverse=True)
|
||||
|
||||
for better_player, worse_player in pairwise(merged_match_player_results):
|
||||
# score ties
|
||||
lose = 0
|
||||
win = 1
|
||||
if better_player[1] == worse_player[1]:
|
||||
lose = 0.5
|
||||
win = 0.5
|
||||
|
||||
# print('bp:', better_player)
|
||||
# print('wp:', worse_player)
|
||||
worse_player_glicko = pwglickos[worse_player[0]]
|
||||
pwglickos[better_player[0]].update_player([worse_player_glicko.rating], [worse_player_glicko.rd], [win])
|
||||
better_player_glicko = pwglickos[better_player[0]]
|
||||
pwglickos[worse_player[0]].update_player([better_player_glicko.rating], [better_player_glicko.rd], [lose])
|
||||
|
||||
# for player in merged_match_player_results:
|
||||
# print(player[0], pwglickos[player[0]].rating, pwglickos[player[0]].rd)
|
||||
|
||||
# Count a team win as an individual win for each winning team player against all losing team players (and vice versa for losses)
|
||||
# todo: maybe it should only count as a personal win if your personal score is higher than the other team's player
|
||||
assert(len(results) == 2)
|
||||
winning_team_name = 0
|
||||
losing_team_name = 0
|
||||
lose = 0
|
||||
win = 1
|
||||
team_names = list(results.keys())
|
||||
if results[team_names[0]]['score'] > results[team_names[1]]['score']:
|
||||
winning_team_name = team_names[0]
|
||||
losing_team_name = team_names[1]
|
||||
elif results[team_names[0]]['score'] < results[team_names[1]]['score']:
|
||||
winning_team_name = team_names[1]
|
||||
losing_team_name = team_names[0]
|
||||
else:
|
||||
lose = 0.5
|
||||
win = 0.5
|
||||
|
||||
for losing_team_player in results[losing_team_name]['players']:
|
||||
losing_player_split = losing_team_player.split(", ")
|
||||
losing_player_tuple = (losing_player_split[0], int(losing_player_split[1]))
|
||||
# print('losing_team_player:',losing_player_tuple[0])
|
||||
for winning_team_player in results[winning_team_name]['players']:
|
||||
winning_player_split = winning_team_player.split(", ")
|
||||
winning_player_tuple = (winning_player_split[0], int(winning_player_split[1]))
|
||||
# print('winning_team_player:',winning_player_tuple[0])
|
||||
# if winning_player_split[1] > losing_player_split[1]:
|
||||
tpglickos[losing_player_tuple[0]].update_player([tpglickos[winning_player_tuple[0]].rating],[tpglickos[winning_player_tuple[0]].rd],[lose])
|
||||
tpglickos[winning_player_tuple[0]].update_player([tpglickos[losing_player_tuple[0]].rating],[tpglickos[losing_player_tuple[0]].rd],[win])
|
||||
|
||||
|
||||
# Sort by glicko ratings and print them out
|
||||
pwglickolist = list(pwglickos.items())
|
||||
pwglickolist.sort(key=lambda rating: rating[1].rating, reverse=True)
|
||||
print('Point Whore Ratings, sorted:\n', [(x[0], str(round(x[1].rating))) for x in pwglickolist])
|
||||
|
||||
# Sort by glicko ratings and print them out
|
||||
stpwglickolist = list(stpwglickos.items())
|
||||
stpwglickolist.sort(key=lambda rating: rating[1].rating, reverse=True)
|
||||
# print('Single Team Point Whore Ratings, sorted:\n', [(x[0], str(round(x[1].rating))) for x in stpwglickolist])
|
||||
print('\nSingle Team Point Whore Ratings',"\n".join([ str((x[0], str(round(x[1].rating)), str(round(x[1].rd)))) for x in stpwglickolist]))
|
||||
|
||||
# Sort by glicko ratings and print them out
|
||||
tpglickolist = list(tpglickos.items())
|
||||
tpglickolist.sort(key=lambda rating: rating[1].rating, reverse=True)
|
||||
print('\nTeam Player Ratings, sorted:')
|
||||
print("\n".join([ str((x[0], str(round(x[1].rating)), str(round(x[1].rd)))) for x in tpglickolist]))
|
||||
|
||||
print('\nPer role single team point whore ratings:\n')
|
||||
for role, players in first_roles_to_players.items():
|
||||
# print('unsorted:',role,players)
|
||||
players.sort(key=lambda p: stpwglickos[p].rating if p in stpwglickos else 1400, reverse=True)
|
||||
print('sorted:',role,players)
|
||||
BIN
pugstatspics/20251108 pug/CTF-Icedance-Nov8.png
Normal file
|
After Width: | Height: | Size: 217 KiB |
BIN
pugstatspics/20251108 pug/CTF-Opus-Nopv8.png
Normal file
|
After Width: | Height: | Size: 204 KiB |
BIN
pugstatspics/20251108 pug/CTF-Puli-Nov8.png
Normal file
|
After Width: | Height: | Size: 210 KiB |
BIN
pugstatspics/20251108 pug/CTF-Sangria-Nov8.png
Normal file
|
After Width: | Height: | Size: 208 KiB |
BIN
pugstatspics/20251108 pug/CTF-Sklight-Nov8.png
Normal file
|
After Width: | Height: | Size: 204 KiB |
BIN
pugstatspics/20251108 pug/CTF-Stats-Nov8.png
Normal file
|
After Width: | Height: | Size: 314 KiB |
BIN
pugstatspics/3280.png
Normal file
|
After Width: | Height: | Size: 2.2 MiB |
BIN
pugstatspics/3283.png
Normal file
|
After Width: | Height: | Size: 980 KiB |
BIN
pugstatspics/3284.png
Normal file
|
After Width: | Height: | Size: 984 KiB |
BIN
pugstatspics/328aa.png
Normal file
|
After Width: | Height: | Size: 1 MiB |
BIN
pugstatspics/4110.png
Normal file
|
After Width: | Height: | Size: 2 MiB |
BIN
pugstatspics/4111.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
pugstatspics/4113.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
pugstatspics/4114.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
pugstatspics/4115.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
pugstatspics/4180.png
Normal file
|
After Width: | Height: | Size: 2.1 MiB |
BIN
pugstatspics/4181.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
pugstatspics/4182.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
pugstatspics/4183.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
pugstatspics/4184.png
Normal file
|
After Width: | Height: | Size: 1 MiB |
BIN
pugstatspics/4240.png
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
pugstatspics/4241.png
Normal file
|
After Width: | Height: | Size: 178 KiB |
BIN
pugstatspics/4242.png
Normal file
|
After Width: | Height: | Size: 176 KiB |
BIN
pugstatspics/4243.png
Normal file
|
After Width: | Height: | Size: 184 KiB |
BIN
pugstatspics/4244.png
Normal file
|
After Width: | Height: | Size: 222 KiB |
BIN
pugstatspics/4245.png
Normal file
|
After Width: | Height: | Size: 216 KiB |
BIN
pugstatspics/4246.png
Normal file
|
After Width: | Height: | Size: 318 KiB |
BIN
pugstatspics/4247.png
Normal file
|
After Width: | Height: | Size: 204 KiB |
BIN
pugstatspics/4250.png
Normal file
|
After Width: | Height: | Size: 966 KiB |
BIN
pugstatspics/4251.png
Normal file
|
After Width: | Height: | Size: 532 KiB |
BIN
pugstatspics/4252.png
Normal file
|
After Width: | Height: | Size: 519 KiB |
BIN
pugstatspics/4253.png
Normal file
|
After Width: | Height: | Size: 521 KiB |
BIN
pugstatspics/4254.png
Normal file
|
After Width: | Height: | Size: 522 KiB |
BIN
pugstatspics/4255.png
Normal file
|
After Width: | Height: | Size: 488 KiB |
BIN
pugstatspics/441.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
pugstatspics/442.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
pugstatspics/443.png
Normal file
|
After Width: | Height: | Size: 1 MiB |
BIN
pugstatspics/445.png
Normal file
|
After Width: | Height: | Size: 2.6 MiB |
BIN
pugstatspics/615a.png
Normal file
|
After Width: | Height: | Size: 346 KiB |
BIN
pugstatspics/615b.png
Normal file
|
After Width: | Height: | Size: 213 KiB |
BIN
pugstatspics/615c.png
Normal file
|
After Width: | Height: | Size: 225 KiB |
BIN
pugstatspics/615d.png
Normal file
|
After Width: | Height: | Size: 231 KiB |
BIN
pugstatspics/615e.png
Normal file
|
After Width: | Height: | Size: 235 KiB |
BIN
pugstatspics/615f.png
Normal file
|
After Width: | Height: | Size: 228 KiB |
BIN
pugstatspics/72025/0.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
pugstatspics/72025/1.png
Normal file
|
After Width: | Height: | Size: 579 KiB |
BIN
pugstatspics/72025/2.png
Normal file
|
After Width: | Height: | Size: 594 KiB |
BIN
pugstatspics/72025/3.png
Normal file
|
After Width: | Height: | Size: 607 KiB |
BIN
pugstatspics/72025/4.png
Normal file
|
After Width: | Height: | Size: 601 KiB |
BIN
pugstatspics/7625/0.png
Normal file
|
After Width: | Height: | Size: 892 KiB |
BIN
pugstatspics/7625/1.png
Normal file
|
After Width: | Height: | Size: 592 KiB |
BIN
pugstatspics/7625/2.png
Normal file
|
After Width: | Height: | Size: 602 KiB |
BIN
pugstatspics/7625/3.png
Normal file
|
After Width: | Height: | Size: 579 KiB |
BIN
pugstatspics/7625/4.png
Normal file
|
After Width: | Height: | Size: 598 KiB |
BIN
pugstatspics/81725/0.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
pugstatspics/81725/1.png
Normal file
|
After Width: | Height: | Size: 508 KiB |
BIN
pugstatspics/81725/2.png
Normal file
|
After Width: | Height: | Size: 570 KiB |
BIN
pugstatspics/81725/3.png
Normal file
|
After Width: | Height: | Size: 594 KiB |
BIN
pugstatspics/81725/4.png
Normal file
|
After Width: | Height: | Size: 598 KiB |
BIN
pugstatspics/81725/5.png
Normal file
|
After Width: | Height: | Size: 606 KiB |
BIN
pugstatspics/81725/6.png
Normal file
|
After Width: | Height: | Size: 603 KiB |
BIN
pugstatspics/824a.png
Normal file
|
After Width: | Height: | Size: 341 KiB |
BIN
pugstatspics/824b.png
Normal file
|
After Width: | Height: | Size: 217 KiB |
BIN
pugstatspics/824c.png
Normal file
|
After Width: | Height: | Size: 219 KiB |
BIN
pugstatspics/824d.png
Normal file
|
After Width: | Height: | Size: 233 KiB |
BIN
pugstatspics/824e.png
Normal file
|
After Width: | Height: | Size: 234 KiB |
BIN
pugstatspics/824f.png
Normal file
|
After Width: | Height: | Size: 227 KiB |
BIN
pugstatspics/83125.png
Normal file
|
After Width: | Height: | Size: 898 KiB |
BIN
pugstatspics/83125banshee.png
Normal file
|
After Width: | Height: | Size: 558 KiB |
BIN
pugstatspics/83125crossfire.png
Normal file
|
After Width: | Height: | Size: 592 KiB |
BIN
pugstatspics/83125damnation.png
Normal file
|
After Width: | Height: | Size: 612 KiB |
BIN
pugstatspics/83125katabatic.png
Normal file
|
After Width: | Height: | Size: 578 KiB |
BIN
pugstatspics/83125sandstorm.png
Normal file
|
After Width: | Height: | Size: 568 KiB |
BIN
pugstatspics/8325/0.png
Normal file
|
After Width: | Height: | Size: 905 KiB |
BIN
pugstatspics/8325/1.png
Normal file
|
After Width: | Height: | Size: 567 KiB |
BIN
pugstatspics/8325/2.png
Normal file
|
After Width: | Height: | Size: 585 KiB |
BIN
pugstatspics/8325/3.png
Normal file
|
After Width: | Height: | Size: 583 KiB |
BIN
pugstatspics/8325/4.png
Normal file
|
After Width: | Height: | Size: 600 KiB |
BIN
pugstatspics/8325/5.png
Normal file
|
After Width: | Height: | Size: 578 KiB |
BIN
pugstatspics/CTF-Ocular-Nov1.png
Normal file
|
After Width: | Height: | Size: 199 KiB |
BIN
pugstatspics/CTF-Shockridge-Nov1.png
Normal file
|
After Width: | Height: | Size: 208 KiB |
BIN
pugstatspics/CTF-Stats-Nov1.png
Normal file
|
After Width: | Height: | Size: 315 KiB |
BIN
pugstatspics/CTF-Stonehenge-Nov1.png
Normal file
|
After Width: | Height: | Size: 222 KiB |
BIN
pugstatspics/partially digitized/112.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
pugstatspics/partially digitized/2Sangria.png
Normal file
|
After Width: | Height: | Size: 211 KiB |
BIN
pugstatspics/partially digitized/2image.png
Normal file
|
After Width: | Height: | Size: 218 KiB |
BIN
pugstatspics/partially digitized/3.png
Normal file
|
After Width: | Height: | Size: 210 KiB |
BIN
pugstatspics/partially digitized/328a.png
Normal file
|
After Width: | Height: | Size: 1 MiB |
BIN
pugstatspics/partially digitized/4.png
Normal file
|
After Width: | Height: | Size: 213 KiB |
BIN
pugstatspics/partially digitized/5.png
Normal file
|
After Width: | Height: | Size: 198 KiB |
BIN
pugstatspics/partially digitized/Banshee.png
Normal file
|
After Width: | Height: | Size: 201 KiB |
BIN
pugstatspics/partially digitized/BleedOct18.png
Normal file
|
After Width: | Height: | Size: 200 KiB |
BIN
pugstatspics/partially digitized/CTF-Crossfire-Nov1.png
Normal file
|
After Width: | Height: | Size: 209 KiB |
BIN
pugstatspics/partially digitized/CTF-Massive-Nov1.png
Normal file
|
After Width: | Height: | Size: 214 KiB |
BIN
pugstatspics/partially digitized/CloakofNightOct18.png
Normal file
|
After Width: | Height: | Size: 209 KiB |
BIN
pugstatspics/partially digitized/Damnation.png
Normal file
|
After Width: | Height: | Size: 211 KiB |