commit 9641d231
Add chart with weapon kills to the gamge page
Changed files
| M | src/pages/game.cpp before |
| M | src/pages/pages.hpp before |
| M | templates/game.tpl before |
diff --git a/src/pages/game.cpp b/src/pages/game.cpp
index 98a4438..922d5fb 100644
--- a/src/pages/game.cpp
+++ b/src/pages/game.cpp
@@ -4,6 +4,11 @@
#include <fstream>
#include <sstream>
#include <set>
+#include <algorithm>
+
+static bool compareWeaponKillsDesc(const std::pair<std::string, int>& a, const std::pair<std::string, int>& b) {
+ return a.second > b.second;
+}
static void addPlayerToTemplateDict(ctemplate::TemplateDictionary* dict, const OastatPlayer& player) {
dict->SetValue("PLAYER_ID", std::to_string(player.playerid));
@@ -112,6 +117,44 @@ void write_html_game(cppdb::session& database, const OastatGame& game, const std
}
}
+ // Get weapon kills for this game
+ std::map<int, int> weapon_kills;
+ getGameWeaponKills(database, game.gamenumber, weapon_kills);
+
+ // Combine splash damage with base weapon damage
+ std::map<std::string, int> combined_weapon_kills;
+ combined_weapon_kills["Shotgun"] = weapon_kills[MOD_SHOTGUN];
+ combined_weapon_kills["Gauntlet"] = weapon_kills[MOD_GAUNTLET];
+ combined_weapon_kills["Machinegun"] = weapon_kills[MOD_MACHINEGUN];
+ combined_weapon_kills["Grenade"] = weapon_kills[MOD_GRENADE] + weapon_kills[MOD_GRENADE_SPLASH];
+ combined_weapon_kills["Rocket"] = weapon_kills[MOD_ROCKET] + weapon_kills[MOD_ROCKET_SPLASH];
+ combined_weapon_kills["Plasma"] = weapon_kills[MOD_PLASMA] + weapon_kills[MOD_PLASMA_SPLASH];
+ combined_weapon_kills["Railgun"] = weapon_kills[MOD_RAILGUN];
+ combined_weapon_kills["Lightning"] = weapon_kills[MOD_LIGHTNING];
+ combined_weapon_kills["Nailgun"] = weapon_kills[MOD_NAIL];
+ combined_weapon_kills["Chaingun"] = weapon_kills[MOD_CHAINGUN];
+ combined_weapon_kills["BFG"] = weapon_kills[MOD_BFG] + weapon_kills[MOD_BFG_SPLASH];
+ combined_weapon_kills["Telefrag"] = weapon_kills[MOD_TELEFRAG];
+ combined_weapon_kills["Falling"] = weapon_kills[MOD_FALLING];
+
+ // Sort weapons by kill count (descending)
+ std::vector<std::pair<std::string, int>> sorted_weapons;
+ for (const auto& wk : combined_weapon_kills) {
+ if (wk.second > 0) {
+ sorted_weapons.push_back(wk);
+ }
+ }
+ std::stable_sort(sorted_weapons.begin(), sorted_weapons.end(), compareWeaponKillsDesc);
+
+ if (!sorted_weapons.empty()) {
+ game_tpl.ShowSection("HAS_WEAPON_KILLS");
+ for (const auto& wk : sorted_weapons) {
+ ctemplate::TemplateDictionary* sub_dict = game_tpl.AddSectionDictionary("WEAPON_KILLS");
+ sub_dict->SetValue("WEAPON_NAME", wk.first);
+ sub_dict->SetValue("KILL_COUNT", std::to_string(wk.second));
+ }
+ }
+
std::string output;
ctemplate::ExpandTemplate("templates/game.tpl", ctemplate::DO_NOT_STRIP, &game_tpl, &output);
std::ofstream myfile;
@@ -185,3 +228,17 @@ void getGameKillMatrix(cppdb::session& database, int gamenumber, std::map<std::p
}
}
+void getGameWeaponKills(cppdb::session& database, int gamenumber, std::map<int, int>& weapon_kills) {
+ std::string sql = "SELECT modtype, COUNT(0) as count FROM oastat.oastat_kills "
+ "WHERE gamenumber = ? AND attacker <> target "
+ "GROUP BY modtype ORDER BY count DESC";
+ cppdb::statement st = database.prepare(sql);
+ st.bind(1, gamenumber);
+ cppdb::result res = st.query();
+ while(res.next()) {
+ int modtype;
+ int count;
+ res >> modtype >> count;
+ weapon_kills[modtype] = count;
+ }
+}
diff --git a/src/pages/pages.hpp b/src/pages/pages.hpp
index 6cd9733..ac8a1ce 100644
--- a/src/pages/pages.hpp
+++ b/src/pages/pages.hpp
@@ -40,6 +40,7 @@ void getMapRecentGames(cppdb::session& database, const std::string& mapname, std
// Game management
void getRecentGames(cppdb::session& database, std::vector<OastatGame>& games);
+void getGameWeaponKills(cppdb::session& database, int gamenumber, std::map<int, int>& weapon_kills);
void getGameScoreTotal(cppdb::session& database, int gamenumber, std::vector<std::pair<int,int>>& scores);
void getGameScoreProgression(cppdb::session& database, int gamenumber, std::vector<ScorePoint>& progression);
void getGameKillMatrix(cppdb::session& database, int gamenumber, std::map<std::pair<int,int>, int>& matrix, std::vector<int>& players);
diff --git a/templates/game.tpl b/templates/game.tpl
index 926baae..886ea1c 100644
--- a/templates/game.tpl
+++ b/templates/game.tpl
@@ -35,6 +35,7 @@
<link rel="stylesheet" href="../static/css/oastat_d3.css" type="text/css">
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="../static/js/score-chart.js"></script>
+ <script src="../static/js/weapon-pie-chart.js"></script>
<title>OpenArena Stats - Game {{GAME_NUMBER}}</title>
</head>
<body>
@@ -87,9 +88,43 @@
</table>
{{/HAS_KILL_MATRIX}}
+ {{#HAS_WEAPON_KILLS}}
+ <h2>Weapon Kills in this Game</h2>
+
+ <div class="pie-chart">
+ <div id="weapon-pie-chart"></div>
+ </div>
+ <div class="legend" id="weapon-legend"></div>
+
+ <table>
+ <tr>
+ <th>Weapon</th>
+ <th>Kills</th>
+ </tr>
+ {{#WEAPON_KILLS}}
+ <tr>
+ <td>{{WEAPON_NAME}}</td>
+ <td>{{KILL_COUNT}}</td>
+ </tr>
+ {{/WEAPON_KILLS}}
+ </table>
+ {{/HAS_WEAPON_KILLS}}
+
<script>
// Render score chart with game data
renderScoreChart("{{GAME_NUMBER}}.json");
+
+ {{#HAS_WEAPON_KILLS}}
+ // Weapon kills data
+ const weaponData = [
+ {{#WEAPON_KILLS}}
+ {name: "{{WEAPON_NAME}}", value: {{KILL_COUNT}}},
+ {{/WEAPON_KILLS}}
+ ];
+
+ // Render weapon pie chart with data
+ renderWeaponPieChart(weaponData);
+ {{/HAS_WEAPON_KILLS}}
</script>
</div>
</body>