commit ab380d11
Add kill matrix for each game
Changed files
| M | src/pages/game.cpp before |
| M | src/pages/pages.hpp before |
| M | static_content/css/oastat.css before |
| M | templates/game.tpl before |
diff --git a/src/pages/game.cpp b/src/pages/game.cpp
index 69bc622..acb5955 100644
--- a/src/pages/game.cpp
+++ b/src/pages/game.cpp
@@ -76,6 +76,39 @@ void write_html_game(cppdb::session& database, const OastatGame& game, const std
json_file << json_data.str();
json_file.close();
+ // Get kill matrix
+ std::map<std::pair<int,int>, int> kill_matrix;
+ std::vector<int> matrix_players;
+ getGameKillMatrix(database, game.gamenumber, kill_matrix, matrix_players);
+
+ // Add kill matrix to template
+ if (!matrix_players.empty()) {
+ game_tpl.ShowSection("HAS_KILL_MATRIX");
+
+ // Add header row with player names
+ for (int playerid : matrix_players) {
+ ctemplate::TemplateDictionary* header_dict = game_tpl.AddSectionDictionary("MATRIX_HEADER");
+ const OastatPlayer& p = getPlayer(database, playerid);
+ header_dict->SetValue("PLAYER_NICKNAME", p.nickname);
+ }
+
+ // Add data rows
+ for (int killer : matrix_players) {
+ ctemplate::TemplateDictionary* row_dict = game_tpl.AddSectionDictionary("MATRIX_ROWS");
+ const OastatPlayer& killer_player = getPlayer(database, killer);
+ row_dict->SetValue("KILLER_NICKNAME", killer_player.nickname);
+ for (int victim : matrix_players) {
+ ctemplate::TemplateDictionary* cell_dict = row_dict->AddSectionDictionary("MATRIX_CELLS");
+ auto key = std::make_pair(killer, victim);
+ int kills = kill_matrix.count(key) ? kill_matrix[key] : 0;
+ cell_dict->SetValue("KILL_COUNT", std::to_string(kills));
+ if (kills > 0) {
+ cell_dict->ShowSection("HAS_KILLS");
+ }
+ }
+ }
+ }
+
std::string output;
ctemplate::ExpandTemplate("templates/game.tpl", ctemplate::DO_NOT_STRIP, &game_tpl, &output);
std::ofstream myfile;
@@ -121,3 +154,31 @@ void getGameScoreProgression(cppdb::session& database, int gamenumber, std::vect
}
}
+void getGameKillMatrix(cppdb::session& database, int gamenumber, std::map<std::pair<int,int>, int>& matrix, std::vector<int>& players) {
+ // Get all players in the game
+ std::set<int> player_set;
+ std::string sql_players = "SELECT DISTINCT player FROM oastat.oastat_points WHERE gamenumber = ?";
+ cppdb::statement st_players = database.prepare(sql_players);
+ st_players.bind(1, gamenumber);
+ cppdb::result res_players = st_players.query();
+ while(res_players.next()) {
+ int playerid;
+ res_players >> playerid;
+ player_set.insert(playerid);
+ }
+
+ // Convert to vector for ordered iteration
+ players.assign(player_set.begin(), player_set.end());
+
+ // Get kill data
+ std::string sql = "SELECT attacker, target, COUNT(0) as kills FROM oastat.oastat_kills WHERE gamenumber = ? AND attacker <> target GROUP BY attacker, target";
+ cppdb::statement st = database.prepare(sql);
+ st.bind(1, gamenumber);
+ cppdb::result res = st.query();
+ while(res.next()) {
+ int attacker, target, kills;
+ res >> attacker >> target >> kills;
+ matrix[std::make_pair(attacker, target)] = kills;
+ }
+}
+
diff --git a/src/pages/pages.hpp b/src/pages/pages.hpp
index 9c73a1e..6cd9733 100644
--- a/src/pages/pages.hpp
+++ b/src/pages/pages.hpp
@@ -42,6 +42,7 @@ void getMapRecentGames(cppdb::session& database, const std::string& mapname, std
void getRecentGames(cppdb::session& database, std::vector<OastatGame>& games);
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);
// Page generation functions
void write_html_index(cppdb::session& database, const std::string& output_dir);
diff --git a/static_content/css/oastat.css b/static_content/css/oastat.css
index 9669e37..0cc09df 100644
--- a/static_content/css/oastat.css
+++ b/static_content/css/oastat.css
@@ -107,3 +107,20 @@ td {
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
+
+/* Kill matrix styling */
+.kill-matrix {
+ font-size: 0.9em;
+}
+
+.kill-matrix th:first-child,
+.kill-matrix td:first-child {
+ text-align: left;
+ font-weight: 600;
+}
+
+.kill-matrix td.has-kills {
+ background: #e8f5e9;
+ font-weight: 600;
+ color: #2e7d32;
+}
diff --git a/templates/game.tpl b/templates/game.tpl
index 5f024c4..263684a 100644
--- a/templates/game.tpl
+++ b/templates/game.tpl
@@ -44,11 +44,11 @@
<div class="levelshot">
<img src="../static/images/oa640x400/{{GAME_MAP}}.jpg" alt="{{GAME_MAP}}">
</div>
-
+
<h2>Score Progression Over Time</h2>
<div id="score-chart" style="margin: 20px 0;"></div>
<div id="score-legend" class="legend"></div>
-
+
<h2>Final Scores</h2>
<table>
<tr>
@@ -62,7 +62,27 @@
</tr>
{{/SCORES_LIST}}
</table>
-
+
+ {{#HAS_KILL_MATRIX}}
+ <h2>Kill Matrix</h2>
+ <table class="kill-matrix">
+ <tr>
+ <th>Killer \ Victim</th>
+ {{#MATRIX_HEADER}}
+ <th>{{PLAYER_NICKNAME}}</th>
+ {{/MATRIX_HEADER}}
+ </tr>
+ {{#MATRIX_ROWS}}
+ <tr>
+ <td><strong>{{KILLER_NICKNAME}}</strong></td>
+ {{#MATRIX_CELLS}}
+ <td{{#HAS_KILLS}} class="has-kills"{{/HAS_KILLS}}>{{KILL_COUNT}}</td>
+ {{/MATRIX_CELLS}}
+ </tr>
+ {{/MATRIX_ROWS}}
+ </table>
+ {{/HAS_KILL_MATRIX}}
+
<script>
// Render score chart with game data
renderScoreChart("{{GAME_NUMBER}}.json");