From: Ant Zucaro Date: Fri, 15 Jun 2012 13:39:25 +0000 (-0400) Subject: Add a damage efficiency view structure. X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonstat.git;a=commitdiff_plain;h=fbe02f385740039b3f15608488949d3d2c0207d1 Add a damage efficiency view structure. Allow tracking of damage efficiency as well. Damage efficiency I'll define as the amount of damage you do per hit. The higher, the better! This is appropriate for all splash-damage weapons. Spam shots are not included on purpose (unless they hit, of course) after conversations with the competitive community; spam shots usually miss and are intended for blocking routes or catching your opponent while they are out of your direct line of sight. --- diff --git a/xonstat/__init__.py b/xonstat/__init__.py index 5a164ef..79f7f52 100755 --- a/xonstat/__init__.py +++ b/xonstat/__init__.py @@ -45,6 +45,10 @@ def main(global_config, **settings): config.add_view(player_accuracy_json, route_name="player_accuracy", renderer="json") + config.add_route("player_damage", "/player/{id:\d+}/damage") + config.add_view(player_damage_json, route_name="player_damage", + renderer="json") + # GAME ROUTES config.add_route("game_index", "/games") config.add_view(game_index, route_name="game_index", diff --git a/xonstat/views/__init__.py b/xonstat/views/__init__.py index 7f1de44..45a91b5 100755 --- a/xonstat/views/__init__.py +++ b/xonstat/views/__init__.py @@ -1,6 +1,6 @@ from xonstat.views.submission import stats_submit from xonstat.views.player import player_index, player_info, player_game_index -from xonstat.views.player import player_accuracy_json +from xonstat.views.player import player_accuracy_json, player_damage_json from xonstat.views.game import game_index, game_info, rank_index from xonstat.views.map import map_info, map_index, map_index_json from xonstat.views.server import server_info, server_game_index, server_index diff --git a/xonstat/views/player.py b/xonstat/views/player.py index af1337d..82acf16 100755 --- a/xonstat/views/player.py +++ b/xonstat/views/player.py @@ -147,6 +147,48 @@ def get_accuracy_stats(player_id, weapon_cd, games): return (avg, accs) +def get_damage_stats(player_id, weapon_cd, games): + """ + Provides damage info for weapon_cd by player_id for the past N games. + """ + try: + raw_avg = DBSession.query(func.sum(PlayerWeaponStat.actual), + func.sum(PlayerWeaponStat.hit)).\ + filter(PlayerWeaponStat.player_id == player_id).\ + filter(PlayerWeaponStat.weapon_cd == weapon_cd).\ + one() + + avg = round(float(raw_avg[0])/raw_avg[1], 2) + + # Determine the damage efficiency (hit, fired) numbers for $games games + # This is then enumerated to create parameters for a flot graph + raw_dmgs = DBSession.query(PlayerWeaponStat.game_id, + PlayerWeaponStat.actual, PlayerWeaponStat.hit).\ + filter(PlayerWeaponStat.player_id == player_id).\ + filter(PlayerWeaponStat.weapon_cd == weapon_cd).\ + order_by(PlayerWeaponStat.game_id.desc()).\ + limit(games).\ + all() + + # they come out in opposite order, so flip them in the right direction + raw_dmgs.reverse() + + dmgs = [] + for i in range(len(raw_dmgs)): + # try to derive, unless we've hit nothing then set to 0! + try: + dmg = round(float(raw_dmgs[i][1])/raw_dmgs[i][2], 2) + except: + dmg = 0.0 + + dmgs.append((raw_dmgs[i][0], dmg)) + except Exception as e: + dmgs = [] + avg = 0.0 + + return (avg, dmgs) + + def _player_info_data(request): player_id = int(request.matchdict['id']) if player_id <= 2: @@ -314,3 +356,54 @@ def player_accuracy_json(request): games = over how many games to display accuracy. Can be up to 50. """ return _player_accuracy_data(request) + + +def _player_damage_data(request): + player_id = request.matchdict['id'] + allowed_weapons = ['grenadelauncher', 'electro', 'crylink', 'hagar', + 'rocketlauncher', 'laser'] + weapon_cd = 'laser' + games = 20 + + if request.params.has_key('weapon'): + if request.params['weapon'] in allowed_weapons: + weapon_cd = request.params['weapon'] + + if request.params.has_key('games'): + try: + games = request.params['games'] + + if games < 0: + games = 20 + if games > 50: + games = 50 + except: + games = 20 + + (avg, dmgs) = get_damage_stats(player_id, weapon_cd, games) + + # if we don't have enough data for the given weapon + if len(dmgs) < games: + games = len(dmgs) + + return { + 'player_id':player_id, + 'player_url':request.route_url('player_info', id=player_id), + 'weapon':weapon_cd, + 'games':games, + 'avg':avg, + 'dmgs':dmgs + } + + +def player_damage_json(request): + """ + Provides a JSON response representing the damage for the given weapon. + + Parameters: + weapon = which weapon to display damage for. Valid values are + 'grenadelauncher', 'electro', 'crylink', 'hagar', 'rocketlauncher', + 'laser'. + games = over how many games to display damage. Can be up to 50. + """ + return _player_damage_data(request)