config.add_route("top_maps_index", "/topmaps")
config.add_view(top_maps_index, route_name="top_maps_index", renderer="top_maps_index.mako")
+ config.add_route("player_versus", "/versus")
+ config.add_view(player_versus, route_name="player_versus", renderer="player_versus.mako")
+
# GAME ROUTES
config.add_route("game_info", "/game/{id:\d+}")
config.add_view(game_info, route_name="game_info", renderer="game_info.mako")
--- /dev/null
+<%inherit file="base.mako"/>
+<%namespace name="nav" file="nav.mako" />
+<%namespace file="navlinks.mako" import="navlinks" />
+
+<%block name="navigation">
+ ${nav.nav('players')}
+</%block>
+
+<div class="row">
+ <div class="small-5 columns text-right">
+ <h3>${p1.nick_html_colors()|n}</h3>
+ </div>
+
+ <div class="small-2 columns text-center">
+ <h3>vs</h3>
+ </div>
+
+ <div class="small-5 columns text-left">
+ <h3>${p2.nick_html_colors()|n}</h3>
+ </div>
+</div>
+
+<div class="row">
+ <div class="small-5 columns text-right">
+ <h3>${p1_wins}</h3>
+ </div>
+
+ <div class="small-2 columns text-center">
+ <h3>wins</h3>
+ </div>
+
+ <div class="small-5 columns text-left">
+ <h3>${p2_wins}</h3>
+ </div>
+</div>
+
+% if len(recent_games) > 0:
+<div class="row">
+ <div class="small-12 columns">
+ <h5>Recent Games</h5>
+ <table class="table table-hover table-condensed">
+ <thead>
+ <tr>
+ <th class="small-1 text-center"></th>
+ <th class="small-1">Type</th>
+ <th class="show-for-medium-up small-3">Server</th>
+ <th class="show-for-medium-up small-2">Map</th>
+ <th class="show-for-large-up small-2">Time</th>
+ <th class="small-3">Winner</th>
+ </tr>
+ </thead>
+ <tbody>
+ % for rg in recent_games:
+ <tr>
+ <td class="text-center"><a class="button tiny" href="${request.route_url('game_info', id=rg.game_id)}" title="View detailed information about this game">view</a></td>
+ <td class="text-center"><span class="sprite sprite-${rg.game_type_cd}" alt="${rg.game_type_cd}" title="${rg.game_type_descr}"></span></td>
+ <td class="show-for-medium-up no-stretch"><a href="${request.route_url('server_info', id=rg.server_id)}" title="Go to the detail page for this server">${rg.server_name}</a></td>
+ <td class="show-for-medium-up"><a href="${request.route_url('map_info', id=rg.map_id)}" title="Go to the map detail page for this map">${rg.map_name}</a></td>
+ <td class="show-for-large-up"><span class="abstime" data-epoch="${rg.epoch}" title="${rg.start_dt.strftime('%a, %d %b %Y %H:%M:%S UTC')}">${rg.fuzzy_date}</span></td>
+ <td class="no-stretch">
+ % if rg.player_id > 2:
+ <a href="${request.route_url('player_info', id=rg.player_id)}" title="Go to the player info page for this player">${rg.nick_html_colors|n}</a></td>
+ % else:
+ ${rg.nick_html_colors|n}</td>
+ % endif
+ </tr>
+ % endfor
+ </tbody>
+ </table>
+ </div>
+</div>
+% endif
from xonstat.views.player import player_elo_info_text, player_elo_info_json
from xonstat.views.player import player_hashkey_info_text, player_hashkey_info_json
from xonstat.views.player import player_captimes, player_captimes_json
-from xonstat.views.player import player_weaponstats_data_json
+from xonstat.views.player import player_weaponstats_data_json, player_versus
from xonstat.views.game import game_info, rank_index
from xonstat.views.game import game_info_json, rank_index_json
def recent_games_q(server_id=None, map_id=None, player_id=None,
game_type_cd=None, cutoff=None, force_player_id=False,
- start_game_id=None, end_game_id=None):
+ start_game_id=None, end_game_id=None, player_id_2=None):
'''
Returns a SQLA query of recent game data. Parameters filter
the results returned if they are provided. If not, it is
filter(Game.game_id==pgstat_alias.game_id).\
filter(Game.players.contains([player_id])).\
filter(pgstat_alias.player_id==player_id)
+
+ # supports versus queries
+ if player_id_2 is not None:
+ recent_games_q = recent_games_q.\
+ filter(Game.players.contains([player_id, player_id_2]))
+
else:
recent_games_q = recent_games_q.\
filter(PlayerGameStat.scoreboardpos==1)
"averages": avgs,
}
+
+def player_versus_data(request):
+ try:
+ p1_id = int(request.params.get("p1", None))
+ p2_id = int(request.params.get("p2", None))
+
+ p1_wins = 0
+ p2_wins = 0
+
+ players = DBSession.query(Player).filter(sa.or_(Player.player_id ==
+ p1_id, Player.player_id == p2_id)).order_by(Player.player_id).all()
+
+
+ if len(players) < 2:
+ raise Exception("Not enough players found.")
+
+ # assign the players from the array retrieved above
+ if players[0].player_id == p1_id:
+ p1 = players[0]
+ p2 = players[1]
+ else:
+ p1 = players[1]
+ p2 = players[0]
+
+ # note that wins and losses are from p1's perspective
+ win_loss_sql = """select win_loss, count(1)
+ from (
+ select case
+ when pgsp1.score >= pgsp2.score then 'win'
+ else 'loss'
+ end win_loss
+ from games g join player_game_stats pgsp1
+ on g.game_id = pgsp1.game_id and pgsp1.player_id = :p1
+ join player_game_stats pgsp2
+ on g.game_id = pgsp2.game_id and pgsp2.player_id = :p2
+ where g.players @> ARRAY[:p1,:p2]
+ and g.game_type_cd = 'duel'
+ and pgsp1.create_dt between g.create_dt - interval '1 hour'
+ and g.create_dt + interval '1 hour'
+ and pgsp2.create_dt between g.create_dt - interval '1 hour'
+ and g.create_dt + interval '1 hour'
+ ) wl
+ group by win_loss
+ """
+
+ wins_losses = DBSession.query("win_loss", "count").\
+ from_statement(win_loss_sql).\
+ params(p1=p1_id, p2=p2_id).all()
+
+ for row in wins_losses:
+ if row.win_loss == "win":
+ p1_wins = row.count
+ elif row.win_loss == "loss":
+ p2_wins = row.count
+
+ # grab the 20 most recent games between the two
+ rgs_raw = recent_games_q(player_id=p1_id, player_id_2=p2_id,
+ game_type_cd="duel").limit(20).all()
+
+ rgs = [RecentGame(row) for row in rgs_raw]
+
+ except Exception as e:
+ log.debug(e)
+ raise pyramid.httpexceptions.HTTPNotFound
+
+ return {
+ "p1" : p1,
+ "p2" : p2,
+ "p1_wins" : p1_wins,
+ "p2_wins" : p2_wins,
+ "recent_games" : rgs,
+ }
+
+
+def player_versus(request):
+ return player_versus_data(request)