StatsLoggerDatabase.cpp

Go to the documentation of this file.
00001 ////////////////////////////////////////////////////////////////////////////////
00002 //    Scorched3D (c) 2000-2009
00003 //
00004 //    This file is part of Scorched3D.
00005 //
00006 //    Scorched3D is free software; you can redistribute it and/or modify
00007 //    it under the terms of the GNU General Public License as published by
00008 //    the Free Software Foundation; either version 2 of the License, or
00009 //    (at your option) any later version.
00010 //
00011 //    Scorched3D is distributed in the hope that it will be useful,
00012 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //    GNU General Public License for more details.
00015 //
00016 //    You should have received a copy of the GNU General Public License
00017 //    along with Scorched3D; if not, write to the Free Software
00018 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 ////////////////////////////////////////////////////////////////////////////////
00020 
00021 #include <common/StatsLoggerDatabase.h>
00022 #include <common/OptionsScorched.h>
00023 #include <common/Defines.h>
00024 #include <common/Logger.h>
00025 #include <net/NetInterface.h>
00026 #include <server/ServerCommon.h>
00027 #include <weapons/AccessoryStore.h>
00028 #include <server/ScorchedServer.h>
00029 #include <tank/TankState.h>
00030 #include <tank/TankScore.h>
00031 #include <tank/TankAvatar.h>
00032 #include <XML/XMLFile.h>
00033 #include <stdlib.h>
00034 #include <time.h>
00035 #include <math.h>
00036 
00037 enum EventType
00038 {
00039         EventKill = 1,
00040         EventTeamKill = 2,
00041         EventSelfKill = 3,
00042         EventResigned = 4,
00043         EventWon = 5,
00044         EventOverallWinner = 6,
00045         EventConnected = 7,
00046         EventDisconnected = 8,
00047         EventJoined = 9
00048 };
00049 
00050 const char *StatsLoggerDatabase::RowResult::getValue(const char *name)
00051 {
00052         std::map<std::string, unsigned int>::iterator findItor =
00053                 names.find(name);
00054         if (findItor == names.end()) return 0;
00055         unsigned int pos = findItor->second;
00056         return columns[pos].c_str();
00057 }
00058 
00059 StatsLoggerDatabase::StatsLoggerDatabase() : 
00060         success_(false),
00061         serverid_(0), seriesid_(0), prefixid_(0),
00062         updateTime_(0)
00063 {
00064 }
00065 
00066 StatsLoggerDatabase::~StatsLoggerDatabase()
00067 {
00068 }
00069 
00070 void StatsLoggerDatabase::createLogger()
00071 {
00072         if (success_) return;
00073 
00074         XMLFile file;
00075         std::string fileName = S3D::getSettingsFile(S3D::formatStringBuffer("mysql-%i.xml",
00076                 ScorchedServer::instance()->getOptionsGame().getPortNo()));
00077 
00078         std::string host, port, user, passwd, db, prefix;
00079         if (!file.readFile(fileName) ||
00080                 !file.getRootNode())
00081         {
00082                 S3D::dialogExit("Stats Logging",
00083                         S3D::formatStringBuffer(
00084                         "Failed to parse %s settings file. Error: %s", 
00085                         fileName.c_str(),
00086                         file.getParserError()));
00087                 return;
00088         }
00089 
00090         if (!file.getRootNode()->getNamedChild("host", host) ||
00091                 !file.getRootNode()->getNamedChild("port", port) ||
00092                 !file.getRootNode()->getNamedChild("user", user) ||
00093                 !file.getRootNode()->getNamedChild("passwd", passwd) ||
00094                 !file.getRootNode()->getNamedChild("db", db) ||
00095                 !file.getRootNode()->getNamedChild("prefix", prefix)) 
00096         {
00097                 S3D::dialogExit("Stats Logging", 
00098                         S3D::formatStringBuffer(
00099                         "Failed to parse %s settings file.", fileName.c_str()));
00100                 return;
00101         }
00102 
00103         // Create the database connection
00104         success_ = false;
00105         if (!connectDatabase(host.c_str(), port.c_str(), 
00106                 user.c_str(), passwd.c_str(), 
00107                 db.c_str()))
00108         {
00109                 S3D::dialogExit("Stats Logging",
00110                         "Failed to connect to stats database");
00111                 return;
00112         }
00113         success_ = true;
00114 
00115         // Add event types
00116         runQuery("INSERT INTO scorched3d_eventtypes "
00117                 "(eventtype, name) VALUES "
00118                 "(%i, \"KILL\"), "
00119                 "(%i, \"TEAMKILL\"), "
00120                 "(%i, \"SELFKILL\"), "
00121                 "(%i, \"WON\"), "
00122                 "(%i, \"OVERALLWINNER\"), "
00123                 "(%i, \"CONNECTED\"), "
00124                 "(%i, \"DISCONNECTED\"), "
00125                 "(%i, \"JOINED\"), "
00126                 "(%i, \"RESIGNED\"); ",
00127                 EventKill, EventTeamKill, EventSelfKill,
00128                 EventWon, EventOverallWinner, 
00129                 EventConnected, EventDisconnected, 
00130                 EventJoined, EventResigned);
00131 
00132         // Get/allocate the prefixid
00133         std::list<StatsLoggerDatabase::RowResult> prefixRows =
00134                 runSelectQuery("SELECT prefixid FROM scorched3d_prefixs "
00135                 "WHERE prefix = \"%s\";",
00136                 prefix.c_str());
00137         if (!prefixRows.empty())
00138         {
00139                 std::list<StatsLoggerDatabase::RowResult>::iterator itor;
00140                 for (itor = prefixRows.begin();
00141                         itor != prefixRows.end();
00142                         itor++)
00143                 {
00144                         StatsLoggerDatabase::RowResult &rowResult = (*itor);
00145                         prefixid_ = atoi(rowResult.columns[0].c_str());
00146                 }
00147         }
00148         if (prefixid_ == 0)
00149         {
00150                 if (runQuery("INSERT INTO scorched3d_prefixs "
00151                         "(prefix) VALUES(\"%s\");",
00152                         prefix.c_str()))
00153                 {
00154                         prefixid_ = getLastInsertId();
00155                 }
00156         }
00157 
00158         // Get/allocate the server id
00159         std::list<StatsLoggerDatabase::RowResult> serverIdRows =
00160                 runSelectQuery("SELECT serverid, displaystats FROM scorched3d_servers "
00161                 "WHERE name = \"%s\";",
00162                 ScorchedServer::instance()->getOptionsGame().getServerName());
00163         if (!serverIdRows.empty())
00164         {
00165                 std::list<StatsLoggerDatabase::RowResult>::iterator itor;
00166                 for (itor = serverIdRows.begin();
00167                         itor != serverIdRows.end();
00168                         itor++)
00169                 {
00170                         StatsLoggerDatabase::RowResult &rowResult = (*itor);
00171                         serverid_ = atoi(rowResult.columns[0].c_str());
00172                         displayStats_ = (atoi(rowResult.columns[1].c_str()) != 0);
00173                 }
00174         }
00175         if (serverid_ == 0)
00176         {
00177                 if (runQuery("INSERT INTO scorched3d_servers "
00178                         "(name, published) VALUES(\"%s\", \"%s\");",
00179                         ScorchedServer::instance()->getOptionsGame().getServerName(),
00180                         ScorchedServer::instance()->getOptionsGame().getPublishAddress()))
00181                 {
00182                         serverid_ = getLastInsertId();
00183                         displayStats_ = true;
00184                 }
00185         }
00186 
00187         // Get/allocate the series id
00188         std::list<StatsLoggerDatabase::RowResult> seriesIdRows =
00189                 runSelectQuery("SELECT seriesid FROM scorched3d_series "
00190                 "WHERE type = 0;");
00191         if (!seriesIdRows.empty())
00192         {
00193                 std::list<StatsLoggerDatabase::RowResult>::iterator itor;
00194                 for (itor = seriesIdRows.begin();
00195                         itor != seriesIdRows.end();
00196                         itor++)
00197                 {
00198                         StatsLoggerDatabase::RowResult &rowResult = (*itor);
00199                         seriesid_ = atoi(rowResult.columns[0].c_str());
00200                 }
00201         }
00202         if (seriesid_ == 0)
00203         {
00204                 if (runQuery("INSERT INTO scorched3d_series "
00205                         "(started, ended) VALUES(NOW(), NOW());"))
00206                 {
00207                         seriesid_ = getLastInsertId();
00208                 }
00209         }
00210 
00211         // Add this server in this series
00212         runQuery("INSERT INTO scorched3d_statssource "
00213                 "(serverid, prefixid, seriesid) VALUES "
00214                 "(%i, %i, %i);", 
00215                 serverid_, prefixid_, seriesid_);
00216 
00217 
00218         // Add all the weapons
00219         std::list<Accessory *> weapons = 
00220                 ScorchedServer::instance()->getAccessoryStore().getAllAccessories();
00221         std::list<Accessory *>::iterator itor;  
00222         for (itor = weapons.begin();
00223                 itor != weapons.end();
00224                 itor++)
00225         {
00226                 Accessory *accessory = *itor;
00227 
00228                 int weaponId = 0;
00229                 std::list<StatsLoggerDatabase::RowResult> weaponIdRows =
00230                         runSelectQuery("SELECT weaponid FROM scorched3d_weapons "
00231                                 "WHERE name = \"%s\" AND seriesid = %i AND prefixid = %i;", 
00232                                 accessory->getName(),
00233                                 seriesid_,
00234                                 prefixid_);
00235                 if (!weaponIdRows.empty())
00236                 {
00237                         std::list<StatsLoggerDatabase::RowResult>::iterator itor;
00238                         for (itor = weaponIdRows.begin();
00239                                 itor != weaponIdRows.end();
00240                                 itor++)
00241                         {
00242                                 StatsLoggerDatabase::RowResult &rowResult = (*itor);
00243                                 weaponId = atoi(rowResult.columns[0].c_str());
00244                         }
00245                 }
00246 
00247                 if (weaponId == 0)
00248                 {
00249                         if (runQuery("INSERT INTO scorched3d_weapons "
00250                                 "(seriesid, prefixid, name, description, armslevel, cost, bundlesize, icon) "
00251                                 "VALUES(%i, %i, \"%s\", \"%s\", %i, %i, %i, \"%s\");", 
00252                                 seriesid_,
00253                                 prefixid_,
00254                                 accessory->getName(), 
00255                                 accessory->getDescription(),
00256                                 accessory->getArmsLevel(),
00257                                 accessory->getOriginalPrice(),
00258                                 accessory->getBundle(),
00259                                 accessory->getIconName()))
00260                         {
00261                                 weaponId = getLastInsertId();
00262                         }
00263                 }
00264                 else
00265                 {
00266                         runQuery("UPDATE scorched3d_weapons SET "
00267                                 "description = \"%s\", "
00268                                 "armslevel = %i, "
00269                                 "cost = %i, "
00270                                 "bundlesize = %i, "
00271                                 "icon = \"%s\" "
00272                                 "WHERE name = \"%s\" AND seriesid = %i AND prefixid = %i;", 
00273                                 accessory->getDescription(),
00274                                 accessory->getArmsLevel(),
00275                                 accessory->getOriginalPrice(),
00276                                 accessory->getBundle(),
00277                                 accessory->getIconName(),
00278                                 accessory->getName(),
00279                                 seriesid_,
00280                                 prefixid_);
00281                 }
00282 
00283                 weaponId_[accessory->getName()] = weaponId;
00284         }
00285 
00286         Logger::log(S3D::formatStringBuffer("database stats logger started, prefix=%i, server=%i, series=%i",
00287                 prefixid_, serverid_, seriesid_));
00288         periodicUpdate();
00289 }
00290 
00291 void StatsLoggerDatabase::addIpAliases(int playerId, 
00292         std::set<int> &currentPlayers, std::list<std::string> &results)
00293 {
00294         currentPlayers.insert(playerId);
00295         addAliases(playerId, results);
00296 
00297         std::list<std::string> ipaddresses;
00298         std::list<StatsLoggerDatabase::RowResult> ipaddressesRows =
00299                 runSelectQuery("SELECT ipaddress FROM scorched3d_ipaddress "
00300                         "WHERE playerid = %i;", playerId);
00301         if (!ipaddresses.empty())
00302         {
00303                 std::list<StatsLoggerDatabase::RowResult>::iterator itor;
00304                 for (itor = ipaddressesRows.begin();
00305                         itor != ipaddressesRows.end();
00306                         itor++)
00307                 {
00308                         StatsLoggerDatabase::RowResult &rowResult = (*itor);
00309                         ipaddresses.push_back(rowResult.columns[0]);
00310                 }
00311         }
00312 
00313         std::list<std::string>::iterator itor;
00314         for (itor = ipaddresses.begin();
00315                 itor != ipaddresses.end();
00316                 itor++)
00317         {
00318                 const char *ipaddress = (*itor).c_str();
00319                 std::list<int> newplayers;
00320 
00321                 std::list<StatsLoggerDatabase::RowResult> ipaddressRows =
00322                         runSelectQuery("SELECT playerid FROM scorched3d_ipaddress "
00323                                 "WHERE ipaddress = \"%s\";", ipaddress);
00324                 if (!ipaddressRows.empty())
00325                 {
00326                         std::list<StatsLoggerDatabase::RowResult>::iterator itor;
00327                         for (itor = ipaddressRows.begin();
00328                                 itor != ipaddressRows.end();
00329                                 itor++)
00330                         {
00331                                 StatsLoggerDatabase::RowResult &rowResult = (*itor);
00332                                 int newplayerid = atoi(rowResult.columns[0].c_str());
00333                                 if (currentPlayers.find(newplayerid) == currentPlayers.end())
00334                                 {
00335                                         newplayers.push_back(newplayerid);
00336                                 }
00337                         }
00338                 }
00339 
00340                 std::list<int>::iterator itor2;
00341                 for (itor2 = newplayers.begin();
00342                         itor2 != newplayers.end();
00343                         itor2++)
00344                 {
00345                         addIpAliases((*itor2), currentPlayers, results);
00346                 }
00347         }
00348 }
00349 
00350 std::string StatsLoggerDatabase::getTopRanks()
00351 {
00352         createLogger();
00353         if (!success_) return "";
00354 
00355         const char *columns = 
00356                 "rank, kills, deaths, selfkills, teamkills, shots, wins, "
00357                 "overallwinner, resigns, gamesplayed, timeplayed, roundsplayed, "
00358                 "moneyearned, skill, name";
00359 
00360         std::string stringResult;
00361         std::list<StatsLoggerDatabase::RowResult> rankRows =
00362                 runSelectQuery(
00363                         "select %s from scorched3d_stats "
00364                         "left join scorched3d_players on scorched3d_stats.playerid = "
00365                         "scorched3d_players.playerid where seriesid=%i and prefixid=%i "
00366                         "order by skill desc limit 0,50",
00367                         columns, seriesid_, prefixid_);
00368 
00369         stringResult.append("<table>");
00370 
00371         std::string cols(columns);
00372         char *token = strtok((char *) cols.c_str(), " ");
00373         stringResult.append("<tr>");
00374         while(token != 0)
00375         {
00376                 stringResult.append("<td><b>").append(token).append("</b></td>");
00377                 token = strtok(0, " ");
00378         }
00379         stringResult.append("</tr>");
00380 
00381         if (!rankRows.empty())
00382         {
00383                 std::list<StatsLoggerDatabase::RowResult>::iterator itor;
00384                 for (itor = rankRows.begin();
00385                         itor != rankRows.end();
00386                         itor++)
00387                 {
00388                         StatsLoggerDatabase::RowResult &result = (*itor);
00389                         stringResult.append("<tr>");
00390                         for (unsigned int i=0; i<result.columns.size(); i++)
00391                         {
00392                                 stringResult.append("<td>").append(result.columns[i]).append("</td>");
00393                         }
00394                         stringResult.append("</tr>");
00395                 }
00396         }
00397         stringResult.append("</table>");
00398         return S3D::formatStringBuffer("%s", stringResult.c_str());
00399 }
00400 
00401 std::string StatsLoggerDatabase::getPlayerInfo(const char *player)
00402 {
00403         createLogger();
00404         if (!success_) return "";
00405 
00406         std::string stringResult;
00407         std::list<StatsLoggerDatabase::RowResult> playerRows =
00408                 runSelectQuery("select "
00409                         "scorched3d_names.playerid as playerid, "
00410                         "scorched3d_names.name as name, "
00411                         "uniqueid from "
00412                         "scorched3d_names left join "
00413                         "scorched3d_players on scorched3d_players.playerid = scorched3d_names.playerid "
00414                         "where LOCATE(LOWER(\"%s\"), LOWER(scorched3d_names.name)) != 0 limit 0,50",
00415                         player);
00416         if (!playerRows.empty())
00417         {
00418                 std::list<StatsLoggerDatabase::RowResult>::iterator itor;
00419                 for (itor = playerRows.begin();
00420                         itor != playerRows.end();
00421                         itor++)
00422                 {
00423                         StatsLoggerDatabase::RowResult &result = (*itor);
00424                         for (unsigned int i=0; i<result.columns.size(); i++)
00425                         {
00426                                 stringResult.append(result.columns[i]);
00427                                 if (i < result.columns.size() - 1) stringResult.append(",");
00428                                 else stringResult.append("\n");
00429                         }
00430                 }
00431         }
00432         
00433         return S3D::formatStringBuffer("%s", stringResult.c_str());
00434 }
00435 
00436 void StatsLoggerDatabase::combinePlayers(unsigned int player1, unsigned int player2)
00437 {
00438         createLogger();
00439         if (!success_) return;
00440 
00441         // Check these players exist
00442         std::list<StatsLoggerDatabase::RowResult> player1Rows =
00443                 runSelectQuery("select name, uniqueid from "
00444                 "scorched3d_players where playerid=%i", 
00445                 player1);
00446         std::list<StatsLoggerDatabase::RowResult> player2Rows =
00447                 runSelectQuery("select name, uniqueid from "
00448                 "scorched3d_players where playerid=%i", 
00449                 player2);
00450         if (player1Rows.empty()) return;
00451         if (player2Rows.empty()) return;
00452 
00453         // Find all results from player2
00454         std::list<StatsLoggerDatabase::RowResult> player2Results =
00455                 runSelectQuery("select * from scorched3d_stats where playerid=%i", 
00456                 player2);
00457         std::list<StatsLoggerDatabase::RowResult>::iterator itor;
00458         for (itor = player2Results.begin();
00459                 itor != player2Results.end();
00460                 itor++)
00461         {
00462                 StatsLoggerDatabase::RowResult &player2Result = *itor;
00463                 const char *prefixId = player2Result.getValue("prefixid");
00464                 const char *seriesId = player2Result.getValue("seriesid");
00465                 if (prefixId && seriesId)
00466                 {
00467                         // Find all results from player1 in the same prefix and series
00468                         std::list<StatsLoggerDatabase::RowResult> player1Results =
00469                                 runSelectQuery("select * from scorched3d_stats where playerid=%i AND "
00470                                 "prefixid=%s and seriesid=%s", 
00471                                 player1, prefixId, seriesId);
00472                         if (player1Results.empty())
00473                         {
00474                                 // There are no results for player1, just move the results
00475                                 runQuery("update scorched3d_stats set playerid=%i where "
00476                                         "playerid=%i and prefixid=%s and seriesid=%s", 
00477                                         player1, player2,
00478                                         prefixId, seriesId);
00479                         }
00480                         else
00481                         {
00482                                 // There are results for player1, combine the results
00483                                 StatsLoggerDatabase::RowResult &player1Result = player1Results.front();
00484                                 std::map<std::string, unsigned int>::iterator itor;
00485                                 for (itor = player1Result.names.begin();
00486                                         itor != player1Result.names.end();
00487                                         itor++)
00488                                 {
00489                                         std::string name = itor->first;
00490                                         std::string value1 = player1Result.getValue(name.c_str());
00491                                         std::string value2 = player2Result.getValue(name.c_str());
00492                                         
00493                                         std::string query = "update scorched3d_stats ";
00494                                         if (name == "playerid" ||
00495                                                 name == "prefixid" ||
00496                                                 name == "seriesid" ||
00497                                                 name == "lastconnected" ||
00498                                                 name == "rank" ||
00499                                                 name == "skill")
00500                                         {
00501                                                 // Ignore
00502                                         }
00503                                         else
00504                                         {
00505                                                 int v1 = atoi(value1.c_str());
00506                                                 int v2 = atoi(value2.c_str());
00507                                                 int value = v1 + v2;
00508                                                 query.append(S3D::formatStringBuffer("set %s=%i ", name.c_str(), value));
00509                                         }
00510                                         query.append(
00511                                                 S3D::formatStringBuffer("where playerid=%i and prefixid=%s and seriesid=%s", 
00512                                                         player1, prefixId, seriesId));
00513                                         runQuery(query.c_str());
00514                                 }
00515                         }
00516                 }
00517         }
00518 
00519         // Remove player2
00520         runQuery("delete from scorched3d_players where playerid=%i", player2);
00521         runQuery("delete from scorched3d_stats where playerid=%i", player2);
00522         runQuery("delete from scorched3d_names where playerid=%i", player2);
00523         runQuery("delete from scorched3d_ipaddresses where playerid=%i", player2);
00524 }
00525 
00526 std::list<std::string> StatsLoggerDatabase::getIpAliases(const char *unqiueId)
00527 {
00528         std::list<std::string> results;
00529         createLogger();
00530         if (!success_) return results;
00531         
00532         int playerId = getPlayerId(unqiueId);
00533         if (playerId == 0) return results;
00534 
00535         std::set<int> currentPlayers;
00536         addIpAliases(playerId, currentPlayers, results);
00537         
00538         return results;
00539 }
00540 
00541 static bool findInList(std::list<std::string> &results, 
00542         const char *name)
00543 {
00544         std::list<std::string>::iterator itor;
00545         for (itor = results.begin();
00546                 itor != results.end();
00547                 itor++)
00548         {
00549                 if (0 == strcmp(name, (*itor).c_str())) return true;
00550         }
00551         return false;
00552 }
00553 
00554 void StatsLoggerDatabase::addAliases(int playerId, 
00555         std::list<std::string> &results)
00556 {
00557         // Make sure the last used name is in the list and
00558         // it is always first
00559         {
00560                 std::list<StatsLoggerDatabase::RowResult> nameRows =
00561                         runSelectQuery("SELECT name FROM scorched3d_players "
00562                                 "WHERE playerid = %i;", playerId);
00563                 if (!nameRows.empty())
00564                 {
00565                         std::list<StatsLoggerDatabase::RowResult>::iterator itor;
00566                         for (itor = nameRows.begin();
00567                                 itor != nameRows.end();
00568                                 itor++)
00569                         {
00570                                 StatsLoggerDatabase::RowResult &rowResult = (*itor);
00571                                 if (!findInList(results, rowResult.columns[0].c_str()))
00572                                 {
00573                                         results.push_back(rowResult.columns[0].c_str());
00574                                 }
00575                         }
00576                 }
00577         }
00578 
00579         // Add all other UNIQUE aliases
00580         {
00581                 std::list<StatsLoggerDatabase::RowResult> nameRows =
00582                         runSelectQuery("SELECT name FROM scorched3d_names "
00583                                 "WHERE playerid = %i;", playerId);
00584                 if (!nameRows.empty())
00585                 {
00586                         std::list<StatsLoggerDatabase::RowResult>::iterator itor;
00587                         for (itor = nameRows.begin();
00588                                 itor != nameRows.end();
00589                                 itor++)
00590                         {
00591                                 StatsLoggerDatabase::RowResult &rowResult = (*itor);
00592                                 if (!findInList(results, rowResult.columns[0].c_str()))
00593                                 {
00594                                         results.push_back(rowResult.columns[0].c_str());
00595                                 }
00596                         }
00597                 }
00598         }
00599 }
00600 
00601 std::list<std::string> StatsLoggerDatabase::getAliases(const char *unqiueId)
00602 {
00603         std::list<std::string> results;
00604         createLogger();
00605         if (!success_) return results;
00606         
00607         int playerId = getPlayerId(unqiueId);
00608         if (playerId == 0) return results;
00609         addAliases(playerId, results);
00610 
00611         return results;
00612 }
00613 
00614 void StatsLoggerDatabase::gameStart(std::list<Tank *> &tanks)
00615 {
00616         createLogger();
00617         if (!success_) return;
00618 
00619         runQuery("UPDATE scorched3d_series SET games = games + 1, "
00620                 "ended = NOW() WHERE seriesid = %i;",
00621                 seriesid_);
00622 
00623         std::list<Tank *>::iterator itor;
00624         for (itor = tanks.begin();
00625                 itor != tanks.end();
00626                 itor++)
00627         {
00628                 Tank *tank = *itor;
00629                 if (!tank->getState().getSpectator())
00630                 {
00631                         runQuery("UPDATE scorched3d_stats SET gamesplayed=gamesplayed+1 "
00632                                 "WHERE playerid = %i AND prefixid = %i AND seriesid = %i;", 
00633                                 playerId_[tank->getUniqueId()],
00634                                 prefixid_,
00635                                 seriesid_);
00636                 }
00637         }
00638 }
00639 
00640 void StatsLoggerDatabase::roundStart(std::list<Tank *> &tanks)
00641 {
00642         createLogger();
00643         if (!success_) return;
00644 
00645         runQuery("UPDATE scorched3d_series SET rounds = rounds + 1, "
00646                 "ended = NOW() WHERE seriesid = %i;",
00647                 seriesid_);
00648 
00649         std::list<Tank *>::iterator itor;
00650         for (itor = tanks.begin();
00651                 itor != tanks.end();
00652                 itor++)
00653         {
00654                 Tank *tank = *itor;
00655                 if (!tank->getState().getSpectator())
00656                 {
00657                         runQuery("UPDATE scorched3d_stats SET roundsplayed=roundsplayed+1 "
00658                                 "WHERE playerid = %i AND prefixid = %i AND seriesid = %i;", 
00659                                 playerId_[tank->getUniqueId()],
00660                                 prefixid_,
00661                                 seriesid_);
00662                 }
00663         }
00664 }
00665 
00666 void StatsLoggerDatabase::tankFired(Tank *firedTank, Weapon *weapon)
00667 {
00668         createLogger();
00669         if (!success_) return;
00670 
00671         runQuery("UPDATE scorched3d_stats SET shots=shots+1 "
00672                 "WHERE playerid = %i AND prefixid = %i AND seriesid = %i;", 
00673                 playerId_[firedTank->getUniqueId()],
00674                 prefixid_,
00675                 seriesid_);
00676 }
00677 
00678 void StatsLoggerDatabase::tankResigned(Tank *tank)
00679 {
00680         createLogger();
00681         if (!success_) return;
00682 
00683     runQuery("INSERT INTO scorched3d_events "
00684                 "(prefixid, seriesid, eventtype, playerid, otherplayerid, weaponid, eventtime) "
00685                 "VALUES(%i, %i, %i, %i, 0, 0, NOW());",
00686                 prefixid_, seriesid_,
00687                 EventResigned,
00688                 playerId_[tank->getUniqueId()]);
00689 
00690         runQuery("UPDATE scorched3d_stats SET resigns=resigns+1 "
00691                 "WHERE playerid = %i AND prefixid = %i AND seriesid = %i;", 
00692                 playerId_[tank->getUniqueId()],
00693                 prefixid_,
00694                 seriesid_);
00695 }
00696 
00697 void StatsLoggerDatabase::updateStats(Tank *tank)
00698 {
00699         createLogger();
00700         if (!success_) return;
00701 
00702         if (!tank->getState().getSpectator())
00703         {
00704                 unsigned int playerId = playerId_[tank->getUniqueId()];
00705 
00706                 runQuery("UPDATE scorched3d_stats SET "
00707                         "timeplayed=timeplayed+%i, moneyearned=moneyearned+%i, scoreearned=scoreearned+%i "
00708                         "WHERE playerid = %i AND prefixid = %i AND seriesid = %i;", 
00709                         ((unsigned int) tank->getScore().getTimePlayedStat()),
00710                         tank->getScore().getTotalMoneyEarnedStat(), 
00711                         tank->getScore().getTotalScoreEarnedStat(),
00712                         playerId,
00713                         prefixid_,
00714                         seriesid_);
00715         }
00716 }
00717 
00718 void StatsLoggerDatabase::periodicUpdate()
00719 {
00720         time_t currentTime = time(0);
00721         if (currentTime - updateTime_ > 60 * 60 * 12) // 12 hrs
00722         {
00723                 updateTime_ = currentTime;
00724                 Logger::log(S3D::formatStringBuffer("statslogger database starting periodics"));
00725 
00726                 // Cleanup orphaned avatars
00727                 std::list<StatsLoggerDatabase::RowResult> binaryRows =
00728                         runSelectQuery("select binaryid, count(binaryid) "
00729                                 "from scorched3d_binary left join "
00730                                 "scorched3d_players on binaryid = avatarid group by avatarid");
00731                 if (!binaryRows.empty())
00732                 {
00733                         std::list<StatsLoggerDatabase::RowResult>::iterator itor;
00734                         for (itor = binaryRows.begin();
00735                                 itor != binaryRows.end();
00736                                 itor++)
00737                         {
00738                                 StatsLoggerDatabase::RowResult &rowResult = (*itor);
00739                                 if (rowResult.columns[1] == "0")
00740                                 {
00741                                         runQuery("delete from scorched3d_binary where binaryid = %s",
00742                                                 rowResult.columns[0].c_str());
00743                                 }
00744                         }
00745                 }
00746 
00747                 // Generate ranks
00748                 std::list<StatsLoggerDatabase::RowResult>::iterator playerItor;
00749                 std::list<StatsLoggerDatabase::RowResult> playerRows =
00750                         runSelectQuery(
00751                                 "SELECT playerid, skill from scorched3d_stats "
00752                                 "WHERE seriesid=%u and prefixid=%u order by skill desc",
00753                                 seriesid_,
00754                                 prefixid_);
00755 
00756                 int rank = 1;
00757                 for (playerItor = playerRows.begin();
00758                         playerItor != playerRows.end();
00759                         playerItor++, rank++)
00760                 {
00761                         StatsLoggerDatabase::RowResult &playerRow = *playerItor;
00762                         runQuery("UPDATE scorched3d_stats SET rank=%i "
00763                                 "WHERE seriesid=%u and prefixid=%u and playerid=%s",
00764                                 rank, 
00765                                 seriesid_,
00766                                 prefixid_,
00767                                 playerRow.columns[0].c_str());
00768                 }
00769 
00770                 Logger::log(S3D::formatStringBuffer("statslogger database finished periodics"));
00771         }
00772 }
00773 
00774 StatsLogger::TankRank StatsLoggerDatabase::tankRank(Tank *tank)
00775 {
00776         TankRank result;
00777 
00778         createLogger();
00779         if (!success_ || !displayStats_) return result;
00780 
00781         // Try to determine this players sql playerid
00782         std::list<StatsLoggerDatabase::RowResult> skillRows =
00783                 runSelectQuery("SELECT skill FROM scorched3d_stats "
00784                 "WHERE playerid = %i AND prefixid = %i AND seriesid = %i;", 
00785                 playerId_[tank->getUniqueId()],
00786                 prefixid_,
00787                 seriesid_);
00788         if (!skillRows.empty())
00789         {
00790                 std::list<StatsLoggerDatabase::RowResult>::iterator itor;
00791                 for (itor = skillRows.begin();
00792                         itor != skillRows.end();
00793                         itor++)
00794                 {
00795                         StatsLoggerDatabase::RowResult &rowResult = (*itor);
00796                         result.skill = atoi(rowResult.columns[0].c_str());
00797                 }
00798 
00799                 std::list<StatsLoggerDatabase::RowResult> countRows =
00800                         runSelectQuery("SELECT count(*) FROM scorched3d_stats "
00801                         "WHERE skill > \"%i\" AND prefixid = %i AND seriesid = %i;", 
00802                         result.skill,
00803                         prefixid_,
00804                         seriesid_);
00805                 if (!countRows.empty())
00806                 {
00807                         std::list<StatsLoggerDatabase::RowResult>::iterator itor;
00808                         for (itor = countRows.begin();
00809                                 itor != countRows.end();
00810                                 itor++)
00811                         {
00812                                 StatsLoggerDatabase::RowResult &rowResult = (*itor);
00813                                 result.rank = atoi(rowResult.columns[0].c_str()) + 1;
00814                         }
00815                 }
00816         }
00817 
00818         return result;
00819 }
00820 
00821 int StatsLoggerDatabase::getPlayerId(const char *uniqueId)
00822 {
00823         createLogger();
00824         if (!success_) return 0;
00825 
00826         // Try to determine this players sql playerid
00827         int playerId = 0;
00828         std::list<StatsLoggerDatabase::RowResult> playerIdRows =
00829                 runSelectQuery("SELECT playerid FROM scorched3d_players "
00830                         "WHERE uniqueid = \"%s\";", uniqueId);
00831         if (!playerIdRows.empty())
00832         {
00833                 std::list<StatsLoggerDatabase::RowResult>::iterator itor;
00834                 for (itor = playerIdRows.begin();
00835                         itor != playerIdRows.end();
00836                         itor++)
00837                 {
00838                         StatsLoggerDatabase::RowResult &rowResult = (*itor);
00839                         playerId = atoi(rowResult.columns[0].c_str());
00840                 }
00841         }
00842 
00843         return playerId;
00844 }
00845 
00846 unsigned int StatsLoggerDatabase::getStatsId(const char *uniqueId)
00847 {
00848         createLogger();
00849         if (!success_) return 0;
00850         int id = getPlayerId(uniqueId);
00851         return id;
00852 }
00853 
00854 std::string StatsLoggerDatabase::allocateId() 
00855 { 
00856         const char possibleChars [] = {
00857                 '1', '2', '3', '4', '5', '6', '7', '8', '9',
00858                 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
00859                 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S',
00860                 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
00861         char buffer[128];
00862 
00863         do
00864         {
00865                 int pos = 0;
00866                 for (int j=0; j<3; j++)
00867                 {
00868                         for (int i=0; i<8; i++)
00869                         {
00870                                 buffer[pos++] = possibleChars[rand() % 33];
00871                         }
00872                         buffer[pos++] = '-';
00873                 }
00874                 buffer[pos - 1] = '\0';
00875 
00876         } while (getPlayerId(buffer) != 0);
00877         return buffer;
00878 }
00879 
00880 void StatsLoggerDatabase::addInfo(Tank *tank)
00881 {
00882         char playerName[1024];
00883         escapeString(playerName, 
00884                 tank->getCStrName().c_str(),
00885                 tank->getCStrName().size());
00886 
00887         // Add the players name (may fail if duplicates)
00888         runQuery("INSERT INTO scorched3d_names (playerid, name, count) VALUES "
00889                 "(%i, \"%s\", 0);", 
00890                 playerId_[tank->getUniqueId()], 
00891                 playerName);
00892         runQuery("UPDATE scorched3d_names SET count=count+1 WHERE "
00893                 "playerid=%i AND name=\"%s\";", 
00894                 playerId_[tank->getUniqueId()], 
00895                 playerName);
00896 
00897         // Add the ipaddress (may fail if duplicates)
00898         runQuery("INSERT INTO scorched3d_ipaddress (playerid, ipaddress, count) VALUES "
00899                 "(%i, \"%s\", 0);",
00900                 playerId_[tank->getUniqueId()], 
00901                 NetInterface::getIpName(tank->getIpAddress()));
00902         runQuery("UPDATE scorched3d_ipaddress SET count=count+1 WHERE "
00903                 "playerid=%i AND ipaddress=\"%s\";",
00904                 playerId_[tank->getUniqueId()], 
00905                 NetInterface::getIpName(tank->getIpAddress()));
00906 
00907         // Update last username etc
00908         runQuery("UPDATE scorched3d_players SET "
00909                 "name=\"%s\", ipaddress=\"%s\" "
00910                 "WHERE playerid = %i;",
00911                 playerName, 
00912                 NetInterface::getIpName(tank->getIpAddress()),
00913                 playerId_[tank->getUniqueId()]);
00914 }
00915 
00916 void StatsLoggerDatabase::tankConnected(Tank *tank)
00917 {
00918         createLogger();
00919         if (!success_) return;
00920 
00921         // We don't have a player id, create one
00922         int playerId = getPlayerId(tank->getUniqueId());
00923         if (playerId == 0)
00924         {
00925                 if (runQuery("INSERT INTO scorched3d_players (uniqueid) "
00926                         "VALUES(\"%s\");",
00927                         tank->getUniqueId()))
00928                 {
00929                         playerId = getLastInsertId();
00930                         Logger::log(S3D::formatStringBuffer("Add new stats user \"%i\"", playerId));
00931                 }
00932         }
00933         else
00934         {
00935                 Logger::log(S3D::formatStringBuffer("Found stats user \"%i\"", playerId));
00936         }
00937 
00938         // Create the players stats entry if it does not exist
00939         std::list<StatsLoggerDatabase::RowResult> playerIdRows =
00940                 runSelectQuery("SELECT playerid FROM scorched3d_stats "
00941                 "WHERE playerid = %i AND prefixid = %i AND seriesid = %i;", 
00942                 playerId,
00943                 prefixid_,
00944                 seriesid_);
00945         if (playerIdRows.empty())
00946         {
00947                 runQuery("INSERT INTO scorched3d_stats (playerid, prefixid, seriesid) "
00948                         "VALUES(%i, %i, %i);",
00949                         playerId,
00950                         prefixid_,
00951                         seriesid_);
00952         }
00953 
00954         // Store this new player id
00955         playerId_[tank->getUniqueId()] = playerId;
00956 
00957         // Add name and ip address
00958         addInfo(tank);
00959 
00960         // Connecting events
00961         runQuery("INSERT INTO scorched3d_events "
00962                 "(prefixid, seriesid, eventtype, playerid, otherplayerid, weaponid, eventtime) "
00963                 "VALUES(%i, %i, %i, %i, 0, 0, NOW());",
00964                 prefixid_, seriesid_,
00965                 EventConnected,
00966                 playerId_[tank->getUniqueId()]);
00967 
00968         // Connecting stats
00969         runQuery("UPDATE scorched3d_players SET osdesc=\"%s\" "
00970                 "WHERE playerid = %i;", 
00971                 tank->getHostDesc(),
00972                 playerId);
00973         runQuery("UPDATE scorched3d_stats SET connects=connects+1, "
00974                 "lastconnected=NOW() "
00975                 "WHERE playerid = %i AND prefixid = %i AND seriesid = %i;", 
00976                 playerId,
00977                 prefixid_,
00978                 seriesid_);
00979 
00980         TankRank rank = StatsLogger::instance()->tankRank(tank);
00981     tank->getScore().setRank(rank.rank);
00982     tank->getScore().setSkill(rank.skill);
00983 }
00984 
00985 void StatsLoggerDatabase::tankJoined(Tank *tank)
00986 {
00987         createLogger();
00988         if (!success_) return;
00989 
00990         // Joined events
00991         runQuery("INSERT INTO scorched3d_events "
00992                 "(prefixid, seriesid, eventtype, playerid, otherplayerid, weaponid, eventtime) "
00993                 "VALUES(%i, %i, %i, %i, 0, 0, NOW());",
00994                 prefixid_, seriesid_,
00995                 EventJoined,
00996                 playerId_[tank->getUniqueId()]);
00997 
00998         // add new info
00999         addInfo(tank);
01000 
01001         // Add the avatar
01002         if (tank->getAvatar().getName()[0])
01003         {
01004                 char buffer[32];
01005                 for (int i=0; i<30; i++)
01006                 {
01007                         buffer[i] = tank->getAvatar().getName()[i];
01008                         if (!buffer[i]) break;
01009                 }
01010                 buffer[30] = '\0';
01011 
01012                 int binaryid = 0;
01013                 unsigned int crc = tank->getAvatar().getCrc();
01014                 std::list<StatsLoggerDatabase::RowResult> binaryIdRows =
01015                         runSelectQuery("SELECT binaryid FROM scorched3d_binary "
01016                         "WHERE name = \"%s\" AND crc = %u;", 
01017                         buffer,
01018                         crc);
01019                 if (!binaryIdRows.empty())
01020                 {
01021                         std::list<StatsLoggerDatabase::RowResult>::iterator itor;
01022                         for (itor = binaryIdRows.begin();
01023                                 itor != binaryIdRows.end();
01024                                 itor++)
01025                         {
01026                                 StatsLoggerDatabase::RowResult &rowResult = (*itor);
01027                                 binaryid = atoi(rowResult.columns[0].c_str());
01028                         }
01029                 }
01030 
01031                 if (binaryid == 0)
01032                 {
01033                         char *to = new char[tank->getAvatar().getFile().getBufferUsed() * 2];
01034             escapeString(to, 
01035                                 tank->getAvatar().getFile().getBuffer(),
01036                                 tank->getAvatar().getFile().getBufferUsed());
01037                         if (runQuery("INSERT INTO scorched3d_binary "
01038                                 "(name, crc, length, data) "
01039                                 "VALUES(\"%s\", %u, %u, \"%s\");", 
01040                                 buffer,
01041                                 crc,
01042                                 tank->getAvatar().getFile().getBufferUsed(),
01043                                 to))
01044                         {
01045                                 binaryid = getLastInsertId();
01046                         }
01047 
01048                         delete [] to;
01049                 }
01050 
01051                 // Set the avatar id
01052                 runQuery("UPDATE scorched3d_players SET avatarid = %i "
01053                         "WHERE playerid = %i;", 
01054                         binaryid,
01055                         playerId_[tank->getUniqueId()]);
01056         }
01057 }
01058 
01059 int StatsLoggerDatabase::getKillCount(const char *uniqueId)
01060 {
01061         createLogger();
01062         if (!success_) return 0;
01063 
01064         int kills = 0;
01065         int playerId = getPlayerId(uniqueId);
01066         if (playerId != 0) 
01067         {
01068                 std::list<StatsLoggerDatabase::RowResult> killsRows =
01069                         runSelectQuery("SELECT kills FROM scorched3d_stats "
01070                         "WHERE playerid = %i;",
01071                         playerId);
01072                 if (!killsRows.empty())
01073                 {
01074                         std::list<StatsLoggerDatabase::RowResult>::iterator itor;
01075                         for (itor = killsRows.begin();
01076                                 itor != killsRows.end();
01077                                 itor++)
01078                         {
01079                                 StatsLoggerDatabase::RowResult &rowResult = (*itor);
01080                                 kills += atoi(rowResult.columns[0].c_str());
01081                         }
01082                 }
01083         }
01084 
01085         return kills;
01086 }
01087 
01088 void StatsLoggerDatabase::tankDisconnected(Tank *tank)
01089 {
01090         createLogger();
01091         if (!success_) return;
01092 
01093         // Leaving events
01094         runQuery("INSERT INTO scorched3d_events "
01095                 "(prefixid, seriesid, eventtype, playerid, otherplayerid, weaponid, eventtime) "
01096                 "VALUES(%i, %i, %i, %i, 0, 0, NOW());",
01097                 prefixid_, seriesid_,
01098                 EventDisconnected,
01099                 playerId_[tank->getUniqueId()]);
01100 
01101         updateStats(tank);
01102 }
01103 
01104 void StatsLoggerDatabase::tankKilled(Tank *firedTank, Tank *deadTank, Weapon *weapon)
01105 {
01106         createLogger();
01107         if (!success_) return;
01108 
01109         runQuery("INSERT INTO scorched3d_events "
01110                 "(prefixid, seriesid, eventtype, playerid, otherplayerid, weaponid, eventtime) "
01111                 "VALUES(%i, %i, %i, %i, %i, %i, NOW());",
01112                 prefixid_, seriesid_,
01113                 EventKill,
01114                 playerId_[firedTank->getUniqueId()], 
01115                 playerId_[deadTank->getUniqueId()], 
01116                 weaponId_[weapon->getParent()->getName()]);
01117 
01118         runQuery("UPDATE scorched3d_stats SET kills=kills+1, skill=%i "
01119                 "WHERE playerid = %i AND prefixid = %i AND seriesid = %i;", 
01120                 firedTank->getScore().getSkill(),
01121                 playerId_[firedTank->getUniqueId()],
01122                 prefixid_,
01123                 seriesid_);
01124                 
01125         runQuery("UPDATE scorched3d_stats SET deaths=deaths+1, skill=%i "
01126                 "WHERE playerid = %i AND prefixid = %i AND seriesid = %i;", 
01127                 deadTank->getScore().getSkill(),
01128                 playerId_[deadTank->getUniqueId()],
01129                 prefixid_,
01130                 seriesid_);
01131 }
01132 
01133 void StatsLoggerDatabase::tankTeamKilled(Tank *firedTank, Tank *deadTank, Weapon *weapon)
01134 {
01135         createLogger();
01136         if (!success_) return;
01137 
01138         runQuery("INSERT INTO scorched3d_events "
01139                 "(prefixid, seriesid, eventtype, playerid, otherplayerid, weaponid, eventtime) "
01140                 "VALUES(%i, %i, %i, %i, %i, %i, NOW());",
01141                 prefixid_, seriesid_,
01142                 EventTeamKill,
01143                 playerId_[firedTank->getUniqueId()],
01144                 playerId_[deadTank->getUniqueId()], 
01145                 weaponId_[weapon->getParent()->getName()]);
01146 
01147         runQuery("UPDATE scorched3d_stats SET teamkills=teamkills+1, skill=%i  "
01148                 "WHERE playerid = %i AND prefixid = %i AND seriesid = %i;", 
01149                 firedTank->getScore().getSkill(),
01150                 playerId_[firedTank->getUniqueId()],
01151                 prefixid_,
01152                 seriesid_);
01153                 
01154         runQuery("UPDATE scorched3d_stats SET deaths=deaths+1 "
01155                 "WHERE playerid = %i AND prefixid = %i AND seriesid = %i;", 
01156                 playerId_[deadTank->getUniqueId()],
01157                 prefixid_,
01158                 seriesid_);
01159 }
01160 
01161 void StatsLoggerDatabase::tankSelfKilled(Tank *firedTank, Weapon *weapon)
01162 {
01163         createLogger();
01164         if (!success_) return;
01165 
01166         runQuery("INSERT INTO scorched3d_events "
01167                 "(prefixid, seriesid, eventtype, playerid, otherplayerid, weaponid, eventtime) "
01168                 "VALUES(%i, %i, %i, %i, 0, %i, NOW());",
01169                 prefixid_, seriesid_, 
01170                 EventSelfKill,
01171                 playerId_[firedTank->getUniqueId()],
01172                 weaponId_[weapon->getParent()->getName()]);
01173 
01174         runQuery("UPDATE scorched3d_stats SET selfkills=selfkills+1, deaths=deaths+1, skill=%i "
01175                 "WHERE playerid = %i AND prefixid = %i AND seriesid = %i;", 
01176                 firedTank->getScore().getSkill(),
01177                 playerId_[firedTank->getUniqueId()],
01178                 prefixid_,
01179                 seriesid_);
01180 }
01181 
01182 void StatsLoggerDatabase::tankWon(Tank *tank)
01183 {
01184         createLogger();
01185         if (!success_) return;
01186 
01187         runQuery("INSERT INTO scorched3d_events "
01188                 "(prefixid, seriesid, eventtype, playerid, otherplayerid, weaponid, eventtime) "
01189                 "VALUES(%i, %i, %i, %i, 0, 0, NOW());",
01190                 prefixid_, seriesid_,
01191                 EventWon,
01192                 playerId_[tank->getUniqueId()]);
01193 
01194         runQuery("UPDATE scorched3d_stats SET wins=wins+1, skill=%i  "
01195                 "WHERE playerid = %i AND prefixid = %i AND seriesid = %i;", 
01196                 tank->getScore().getSkill(),
01197                 playerId_[tank->getUniqueId()],
01198                 prefixid_,
01199                 seriesid_);
01200 }
01201 
01202 void StatsLoggerDatabase::tankOverallWinner(Tank *tank)
01203 {
01204         createLogger();
01205         if (!success_) return;
01206 
01207         runQuery("INSERT INTO scorched3d_events "
01208                 "(prefixid, seriesid, eventtype, playerid, otherplayerid, weaponid, eventtime) "
01209                 "VALUES(%i, %i, %i, %i, 0, 0, NOW());",
01210                 prefixid_, seriesid_,
01211                 EventOverallWinner,
01212                 playerId_[tank->getUniqueId()]);
01213 
01214         runQuery("UPDATE scorched3d_stats SET overallwinner=overallwinner+1, skill=%i "
01215                 "WHERE playerid = %i AND prefixid = %i AND seriesid = %i;",
01216                 tank->getScore().getSkill(),
01217                 playerId_[tank->getUniqueId()],
01218                 prefixid_,
01219                 seriesid_);
01220 }
01221 
01222 void StatsLoggerDatabase::weaponFired(Weapon *weapon, bool deathAni)
01223 {
01224         createLogger();
01225         if (!success_) return;
01226 
01227         if (deathAni)
01228         {
01229                 runQuery("UPDATE scorched3d_weapons SET deathshots=deathshots+1 "
01230                         "WHERE weaponid = \"%i\" AND prefixid = %i AND seriesid = %i;",
01231                         weaponId_[weapon->getParent()->getName()],
01232                         prefixid_,
01233                         seriesid_);
01234         }
01235         else
01236         {
01237                 runQuery("UPDATE scorched3d_weapons SET shots=shots+1 "
01238                         "WHERE weaponid = \"%i\" AND prefixid = %i AND seriesid = %i;", 
01239                         weaponId_[weapon->getParent()->getName()],
01240                         prefixid_,
01241                         seriesid_);
01242         }
01243 }
01244 
01245 void StatsLoggerDatabase::weaponKilled(Weapon *weapon, bool deathAni)
01246 {
01247         createLogger();
01248         if (!success_) return;
01249 
01250         if (deathAni)
01251         {
01252                 runQuery("UPDATE scorched3d_weapons SET deathkills=deathkills+1 "
01253                         "WHERE weaponid = \"%i\" AND prefixid = %i AND seriesid = %i;", 
01254                         weaponId_[weapon->getParent()->getName()],
01255                         prefixid_,
01256                         seriesid_);
01257         }
01258         else
01259         {
01260                 runQuery("UPDATE scorched3d_weapons SET kills=kills+1 "
01261                         "WHERE weaponid = \"%i\" AND prefixid = %i AND seriesid = %i;", 
01262                         weaponId_[weapon->getParent()->getName()],
01263                         prefixid_,
01264                         seriesid_);
01265         }
01266 }
01267 

Generated on Mon Feb 16 15:14:49 2009 for Scorched3D by  doxygen 1.5.3