Add a damage efficiency view structure.
authorAnt Zucaro <azucaro@gmail.com>
Fri, 15 Jun 2012 13:39:25 +0000 (09:39 -0400)
committerAnt Zucaro <azucaro@gmail.com>
Fri, 15 Jun 2012 13:39:25 +0000 (09:39 -0400)
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.

xonstat/__init__.py
xonstat/views/__init__.py
xonstat/views/player.py

index 5a164ef4c7dbcefbf0847ca1cd7ef26e2a412a23..79f7f527bc64c066cc77d75b766725ab4f0176f2 100755 (executable)
@@ -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",
index 7f1de44581d1ff7e771bc48003f49006d6abefa4..45a91b58c860e0b200c6fdbf967e1e0fcd01d378 100755 (executable)
@@ -1,6 +1,6 @@
 from xonstat.views.submission import stats_submit\r
 from xonstat.views.player import player_index, player_info, player_game_index\r
-from xonstat.views.player import player_accuracy_json\r
+from xonstat.views.player import player_accuracy_json, player_damage_json\r
 from xonstat.views.game import game_index, game_info, rank_index\r
 from xonstat.views.map import map_info, map_index, map_index_json\r
 from xonstat.views.server import server_info, server_game_index, server_index\r
index af1337d3fc44a64b3eb796472437268b30703784..82acf169d437a4c19b81dfe88fa2eed85599dd08 100755 (executable)
@@ -147,6 +147,48 @@ def get_accuracy_stats(player_id, weapon_cd, games):
     return (avg, accs)\r
 \r
 \r
+def get_damage_stats(player_id, weapon_cd, games):\r
+    """\r
+    Provides damage info for weapon_cd by player_id for the past N games.\r
+    """\r
+    try:\r
+        raw_avg = DBSession.query(func.sum(PlayerWeaponStat.actual),\r
+                func.sum(PlayerWeaponStat.hit)).\\r
+                filter(PlayerWeaponStat.player_id == player_id).\\r
+                filter(PlayerWeaponStat.weapon_cd == weapon_cd).\\r
+                one()\r
+\r
+        avg = round(float(raw_avg[0])/raw_avg[1], 2)\r
+\r
+        # Determine the damage efficiency (hit, fired) numbers for $games games\r
+        # This is then enumerated to create parameters for a flot graph\r
+        raw_dmgs = DBSession.query(PlayerWeaponStat.game_id, \r
+            PlayerWeaponStat.actual, PlayerWeaponStat.hit).\\r
+                filter(PlayerWeaponStat.player_id == player_id).\\r
+                filter(PlayerWeaponStat.weapon_cd == weapon_cd).\\r
+                order_by(PlayerWeaponStat.game_id.desc()).\\r
+                limit(games).\\r
+                all()\r
+\r
+        # they come out in opposite order, so flip them in the right direction\r
+        raw_dmgs.reverse()\r
+\r
+        dmgs = []\r
+        for i in range(len(raw_dmgs)):\r
+            # try to derive, unless we've hit nothing then set to 0!\r
+            try:\r
+                dmg = round(float(raw_dmgs[i][1])/raw_dmgs[i][2], 2)\r
+            except:\r
+                dmg = 0.0\r
+\r
+            dmgs.append((raw_dmgs[i][0], dmg))\r
+    except Exception as e:\r
+        dmgs = []\r
+        avg = 0.0\r
+\r
+    return (avg, dmgs)\r
+\r
+\r
 def _player_info_data(request):\r
     player_id = int(request.matchdict['id'])\r
     if player_id <= 2:\r
@@ -314,3 +356,54 @@ def player_accuracy_json(request):
        games = over how many games to display accuracy. Can be up to 50.\r
     """\r
     return _player_accuracy_data(request)\r
+\r
+\r
+def _player_damage_data(request):\r
+    player_id = request.matchdict['id']\r
+    allowed_weapons = ['grenadelauncher', 'electro', 'crylink', 'hagar',\r
+            'rocketlauncher', 'laser']\r
+    weapon_cd = 'laser'\r
+    games = 20\r
+\r
+    if request.params.has_key('weapon'):\r
+        if request.params['weapon'] in allowed_weapons:\r
+            weapon_cd = request.params['weapon']\r
+\r
+    if request.params.has_key('games'):\r
+        try:\r
+            games = request.params['games']\r
+\r
+            if games < 0:\r
+                games = 20\r
+            if games > 50:\r
+                games = 50\r
+        except:\r
+            games = 20\r
+\r
+    (avg, dmgs) = get_damage_stats(player_id, weapon_cd, games)\r
+\r
+    # if we don't have enough data for the given weapon\r
+    if len(dmgs) < games:\r
+        games = len(dmgs)\r
+\r
+    return {\r
+            'player_id':player_id, \r
+            'player_url':request.route_url('player_info', id=player_id), \r
+            'weapon':weapon_cd, \r
+            'games':games, \r
+            'avg':avg, \r
+            'dmgs':dmgs\r
+            }\r
+\r
+\r
+def player_damage_json(request):\r
+    """\r
+    Provides a JSON response representing the damage for the given weapon.\r
+\r
+    Parameters:\r
+       weapon = which weapon to display damage for. Valid values are\r
+         'grenadelauncher', 'electro', 'crylink', 'hagar', 'rocketlauncher',\r
+         'laser'.\r
+       games = over how many games to display damage. Can be up to 50.\r
+    """\r
+    return _player_damage_data(request)\r