ServerShotFinishedState.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 <server/ServerShotFinishedState.h>
00022 #include <server/ScorchedServer.h>
00023 #include <server/ServerState.h>
00024 #include <server/ServerTooFewPlayersStimulus.h>
00025 #include <server/ServerMessageHandler.h>
00026 #include <server/ServerNextShotState.h>
00027 #include <server/ServerChannelManager.h>
00028 #include <server/ServerShotState.h>
00029 #include <server/ServerCommon.h>
00030 #include <common/Logger.h>
00031 #include <common/StatsLogger.h>
00032 #include <common/OptionsScorched.h>
00033 #include <common/OptionsTransient.h>
00034 #include <coms/ComsScoreMessage.h>
00035 #include <coms/ComsPlayerStateMessage.h>
00036 #include <coms/ComsMessageSender.h>
00037 #include <coms/ComsSyncCheckMessage.h>
00038 #include <tank/TankColorGenerator.h>
00039 #include <tank/TankContainer.h>
00040 #include <tank/TankTeamScore.h>
00041 #include <tank/TankSort.h>
00042 #include <tank/TankState.h>
00043 #include <tank/TankScore.h>
00044 #include <lua/LUAScriptHook.h>
00045 
00046 float ServerShotFinishedState::speed_(1.0f);
00047 
00048 ServerShotFinishedState::ServerShotFinishedState(ServerShotState *shotState) :
00049         GameStateI("ServerShotFinishedState"),
00050         shotState_(shotState)
00051 {
00052         ScorchedServer::instance()->getLUAScriptHook().addHookProvider("server_score");
00053 }
00054 
00055 ServerShotFinishedState::~ServerShotFinishedState()
00056 {
00057 }
00058 
00059 void ServerShotFinishedState::enterState(const unsigned state)
00060 {
00061         // Send sync check
00062         if (ScorchedServer::instance()->getOptionsGame().getAutoSendSyncCheck())
00063         {
00064                 ServerCommon::serverLog("Sending auto synccheck");
00065 
00066                 std::list<unsigned int> destinations;
00067                 std::set<unsigned int> &playing = shotState_->getPlaying();
00068                 std::set<unsigned int>::iterator itor;
00069                 for (itor = playing.begin();
00070                         itor != playing.end();
00071                         itor++)
00072                 {
00073                         destinations.push_back(*itor);
00074                 }
00075                 ComsSyncCheckMessage syncCheck;
00076                 ComsMessageSender::sendToMultipleClients(syncCheck, destinations);
00077         }
00078 
00079         // Remove any tanks that have disconected during the shot state
00080         ServerMessageHandler::instance()->destroyTaggedPlayers();
00081 
00082         totalTime_ = 0.0f;
00083         waitTime_ = 0.0f;
00084 
00085         // Check if any player or team has won the round
00086         if (ServerNextShotState::getRoundFinished() ||
00087                 ((ScorchedServer::instance()->getOptionsTransient().getCurrentGameNo() >
00088                 ScorchedServer::instance()->getOptionsGame().getNoMaxRoundTurns()) &&
00089                 ScorchedServer::instance()->getOptionsGame().getNoMaxRoundTurns() > 0))
00090         {
00091                 // The actual state transition for no tanks left is done
00092                 // in the next round state however
00093                 // score the last remaining tanks here
00094                 bool finalScore = scoreWinners();
00095                 if (finalScore)
00096                 {
00097                         waitTime_ = (float) ScorchedServer::instance()->
00098                                 getOptionsGame().getScoreTime();
00099                 }
00100                 else
00101                 {
00102                         waitTime_ = (float) ScorchedServer::instance()->
00103                                 getOptionsGame().getRoundScoreTime();
00104                 }
00105 
00106                 ComsPlayerStateMessage playerMessage(true, true);
00107                 ComsMessageSender::sendToAllPlayingClients(playerMessage);
00108                 ComsScoreMessage message(finalScore);
00109                 ComsMessageSender::sendToAllPlayingClients(message);
00110 
00111                 if (finalScore)
00112                 {
00113                         ServerCommon::serverLog("Final scores -------");
00114                         std::map<unsigned int, Tank *> &tanks =
00115                                 ScorchedServer::instance()->getTankContainer().getPlayingTanks();
00116                         std::map<unsigned int, Tank *>::iterator itor;
00117                         for (itor = tanks.begin();
00118                                 itor != tanks.end();
00119                                 itor++)
00120                         {
00121                                 Tank *tank = (*itor).second;
00122                                 ServerCommon::serverLog(S3D::formatStringBuffer("%s - %s",
00123                                         tank->getCStrName().c_str(),
00124                                         tank->getScore().getScoreString()));
00125                         }
00126                         ServerCommon::serverLog("--------------------");
00127                 }
00128         }
00129 }
00130 
00131 bool ServerShotFinishedState::acceptStateChange(const unsigned state, 
00132         const unsigned nextState,
00133         float frameTime)
00134 {
00135         totalTime_ += frameTime * speed_;
00136         if (totalTime_ > waitTime_)
00137         {
00138                 if (ServerTooFewPlayersStimulus::instance()->acceptStateChange(state, 
00139                         ServerState::ServerStateTooFewPlayers, 0.0f))
00140                 {
00141                         ScorchedServer::instance()->getGameState().stimulate(
00142                                 ServerState::ServerStimulusTooFewPlayers);
00143                 }
00144                 else return true;
00145         }
00146         return false;
00147 }
00148 
00149 bool ServerShotFinishedState::scoreWinners()
00150 {
00151         // Calculate all the tanks interest
00152         float interest = float(ScorchedServer::instance()->
00153                 getOptionsGame().getInterest()) / 100.0f;
00154         std::map<unsigned int, Tank *> &playingTank = 
00155                 ScorchedServer::instance()->getTankContainer().getPlayingTanks();
00156 
00157         int moneyWonForRound = 
00158                 ScorchedServer::instance()->getOptionsGame().getMoneyWonForRound();
00159         int moneyWonForLives =
00160                 ScorchedServer::instance()->getOptionsGame().getMoneyWonForLives();
00161         int scoreWonForRound = 
00162                 ScorchedServer::instance()->getOptionsGame().getScoreWonForRound();
00163         int scoreWonForLives = 
00164                 ScorchedServer::instance()->getOptionsGame().getScoreWonForLives();
00165 
00166         // Add score for each life left
00167         std::map<unsigned int, Tank *>::iterator itor;
00168         for (itor = playingTank.begin();
00169                 itor != playingTank.end();
00170                 itor++)
00171         {
00172                 Tank *tank = (*itor).second;
00173                 if (tank->getState().getSpectator()) continue;
00174                 if (tank->getAlive())
00175                         tank->getScore().setScore(
00176                                 tank->getScore().getScore() + (scoreWonForLives * tank->getState().getLives()));
00177         }
00178                                 
00179         // Is it a team game?
00180         if (ScorchedServer::instance()->getOptionsGame().getTeams() > 1)
00181         {
00182                 // Yes, check which team has won and give points accordingly
00183                 // Add score for round wins
00184                 std::map<unsigned int, Tank *>::iterator itor;
00185                 for (itor = playingTank.begin();
00186                         itor != playingTank.end();
00187                         itor++)
00188                 {
00189                         Tank *tank = (*itor).second;
00190                         if (tank->getState().getSpectator()) continue;
00191 
00192                         if (tank->getAlive())
00193                         {
00194                                 ScorchedServer::instance()->getContext().getTankTeamScore().addScore(
00195                                         scoreWonForLives * tank->getState().getLives(), tank->getTeam());
00196                         }
00197                 }
00198 
00199                 std::set<int> winningTeams;
00200                 int winningTeam = 
00201                         ScorchedServer::instance()->getContext().getTankTeamScore().getWonGame();
00202                 if (winningTeam != 0)
00203                 {
00204                         winningTeams.insert(winningTeam);
00205                         ScorchedServer::instance()->getContext().getTankTeamScore().addScore(
00206                                 scoreWonForRound, winningTeam);
00207                 }
00208                 else
00209                 {
00210                         for (itor = playingTank.begin();
00211                                 itor != playingTank.end();
00212                                 itor++)
00213                         {
00214                                 Tank *tank = (*itor).second;
00215                                 if (tank->getState().getSpectator()) continue;
00216 
00217                                 if (tank->getAlive())
00218                                 {
00219                                         if (winningTeams.find(tank->getTeam()) == winningTeams.end())
00220                                         {
00221                                                 ScorchedServer::instance()->getContext().getTankTeamScore().addScore(
00222                                                         scoreWonForRound, tank->getTeam());
00223                                                 winningTeams.insert(tank->getTeam());
00224 
00225                                         }
00226                                 }
00227                         }
00228                 }
00229 
00230                 for (itor = playingTank.begin();
00231                         itor != playingTank.end();
00232                         itor++)
00233                 {
00234                         Tank *tank = (*itor).second;
00235                         if (tank->getState().getSpectator()) continue;
00236 
00237                         if (winningTeams.find(tank->getTeam()) != winningTeams.end())
00238                         {
00239                                 StatsLogger::instance()->tankWon(tank);
00240                                 tank->getScore().setMoney(
00241                                         tank->getScore().getMoney() + moneyWonForRound);
00242                                 tank->getScore().setMoney(
00243                                         tank->getScore().getMoney() + (moneyWonForLives * tank->getState().getLives()));
00244                                 tank->getScore().setWins(
00245                                         tank->getScore().getWins() + 1);
00246                         }
00247                 }
00248         }
00249         else
00250         {
00251                 // Check which player has won and give points accordingly
00252                 bool tankWon = false;
00253                 std::map<unsigned int, Tank *>::iterator itor;
00254                 for (itor = playingTank.begin();
00255                         itor != playingTank.end();
00256                         itor++)
00257                 {
00258                         Tank *tank = (*itor).second;
00259                         if (tank->getState().getSpectator()) continue;
00260 
00261                         if (tank->getScore().getWonGame())
00262                         {
00263                                 StatsLogger::instance()->tankWon(tank);
00264                                 tank->getScore().setMoney(
00265                                         tank->getScore().getMoney() + moneyWonForRound);
00266                                 tank->getScore().setMoney(
00267                                         tank->getScore().getMoney() + (moneyWonForLives * tank->getState().getLives()));
00268                                 tank->getScore().setWins(
00269                                         tank->getScore().getWins() + 1);
00270                                 tank->getScore().setScore(
00271                                         tank->getScore().getScore() + scoreWonForRound);
00272 
00273                                 tankWon = true;
00274                         }
00275                 }
00276 
00277                 if (!tankWon)
00278                 {
00279                         for (itor = playingTank.begin();
00280                                 itor != playingTank.end();
00281                                 itor++)
00282                         {
00283                                 Tank *tank = (*itor).second;
00284                                 if (tank->getState().getSpectator()) continue;
00285 
00286                                 if (tank->getAlive())
00287                                 {
00288                                         StatsLogger::instance()->tankWon(tank);
00289                                         tank->getScore().setMoney(
00290                                                 tank->getScore().getMoney() + moneyWonForRound);
00291                                         tank->getScore().setMoney(
00292                                                 tank->getScore().getMoney() + (moneyWonForLives * tank->getState().getLives()));
00293                                         tank->getScore().setWins(
00294                                                 tank->getScore().getWins() + 1);        
00295                                         tank->getScore().setScore(
00296                                                 tank->getScore().getScore() + scoreWonForRound);
00297                                 }
00298                         }
00299                 }
00300         }
00301 
00302         // Give interest and round played money to all tanks
00303         {
00304                 std::map<unsigned int, Tank *>::iterator itor;
00305                 for (itor = playingTank.begin();
00306                         itor != playingTank.end();
00307                         itor++)
00308                 {
00309                         Tank *tank = (*itor).second;
00310                         if (tank->getState().getSpectator()) continue;
00311 
00312                         int addMoney = int(float(tank->getScore().getMoney()) * interest) +
00313                                 ScorchedServer::instance()->getOptionsGame().getMoneyPerRound();
00314                         tank->getScore().setMoney(tank->getScore().getMoney() + addMoney);
00315 
00316                         // Make sure this tank is dead
00317                         if (tank->getState().getState() == TankState::sNormal)
00318                         {
00319                                 tank->getState().setState(TankState::sDead);
00320                         }
00321                 }
00322         }
00323 
00324         // Check if this is the last round that will be played
00325         bool overAllWinner = false;
00326         if (ScorchedServer::instance()->getOptionsTransient().getCurrentRoundNo() >=
00327                 ScorchedServer::instance()->getOptionsGame().getNoRounds())
00328         {
00329                 overAllWinner = true;
00330         }
00331         else
00332         {
00333                 if (ServerTooFewPlayersStimulus::instance()->acceptStateChange(0, 
00334                         ServerState::ServerStateTooFewPlayers, 0.0f))
00335                 {
00336                         if (ScorchedServer::instance()->getOptionsTransient().getCurrentRoundNo() >
00337                                 ScorchedServer::instance()->getOptionsGame().getNoRounds() / 2 && 
00338                                 ScorchedServer::instance()->getOptionsTransient().getCurrentRoundNo() > 2)
00339                         {
00340                                 overAllWinner = true;
00341                         }
00342                 }
00343         }
00344 
00345         // Tell scripts to score 
00346         ScorchedServer::instance()->getLUAScriptHook().callHook("server_score", 
00347                 overAllWinner);
00348 
00349         // Update the stats for the players before sending out the
00350         // stats message
00351         std::map<unsigned int, Tank *> &tanks = 
00352                 ScorchedServer::instance()->getTankContainer().getPlayingTanks();
00353         for (itor = tanks.begin();
00354                 itor != tanks.end();
00355                 itor++)
00356         {
00357                 Tank *tank = (*itor).second;
00358 
00359                 // Money earned
00360                 int newMoney = tank->getScore().getTotalMoneyEarnedStat();
00361                 int scoreAdded = (newMoney * 
00362                         ScorchedServer::instance()->getOptionsGame().getScorePerMoney())
00363                         / 1000;
00364                 tank->getScore().setScore(tank->getScore().getScore() + scoreAdded);
00365 
00366                 // Ensure stats are uptodate
00367                 StatsLogger::instance()->updateStats(tank);
00368 
00369                 // Reset the totaled stats
00370                 tank->getScore().resetTotalEarnedStats();
00371 
00372                 // Get the new tanks rank
00373                 StatsLogger::TankRank rank = StatsLogger::instance()->tankRank(tank);
00374                 tank->getScore().setRank(rank.rank);
00375         }
00376 
00377         // Its the very last round, score the overall winner
00378         if (overAllWinner)
00379         {
00380                 scoreOverallWinner();
00381         }
00382         return overAllWinner;
00383 }
00384 
00385 void ServerShotFinishedState::scoreOverallWinner()
00386 {
00387         StatsLogger::instance()->periodicUpdate();
00388 
00389         if (ScorchedServer::instance()->getOptionsGame().getTeams() == 1)
00390         {
00391                 std::list<Tank *> sortedTanks;
00392                 std::map<unsigned int, Tank *> &tanks = 
00393                         ScorchedServer::instance()->getTankContainer().getPlayingTanks();
00394                 std::map<unsigned int, Tank *>::iterator itor;
00395                 for (itor = tanks.begin();
00396                         itor != tanks.end();
00397                         itor++)
00398                 {
00399                         Tank *current = (*itor).second;
00400                         if (!current->getState().getSpectator() &&
00401                                 current->getState().getState() != TankState::sPending &&
00402                                 current->getState().getState() != TankState::sInitializing &&
00403                                 current->getState().getState() != TankState::sLoading)
00404                         {
00405                                 sortedTanks.push_back(current);
00406                         }
00407                 }
00408                 
00409                 TankSort::getSortedTanks(sortedTanks, ScorchedServer::instance()->getContext());
00410                 if (!sortedTanks.empty())
00411                 {
00412                         Tank *topScore = *(sortedTanks.begin());
00413 
00414                         LangString names;
00415                         std::list<Tank *> winners;
00416             std::list<Tank *>::iterator scoreitor;
00417                         for (scoreitor = sortedTanks.begin();
00418                                 scoreitor != sortedTanks.end();
00419                                 scoreitor++)
00420                         {
00421                                 Tank *current = *scoreitor;
00422                                 if (topScore->getScore().getScore() == 
00423                                         current->getScore().getScore())
00424                                 {
00425                                         winners.push_back(current);
00426                                         if (!names.empty()) names.append(LANG_STRING(","));
00427                                         names.append(current->getTargetName());
00428 
00429                                         // Score the winning tank as the overall winner
00430                                         StatsLogger::instance()->tankOverallWinner(current);
00431                                 }
00432                         }
00433 
00434                         if (winners.size() == 1)
00435                         {
00436                                 ServerChannelManager::instance()->sendText(
00437                                         ChannelText("banner",
00438                                                 "PLAYER_OVERALL_WINNER",
00439                                                 "{0} is the overall winner!", 
00440                                                 names),
00441                                         true);
00442                         }
00443                         else
00444                         {
00445                                 ServerChannelManager::instance()->sendText(
00446                                         ChannelText("banner",
00447                                                 "PLAYERS_OVERALL_WINNERS",
00448                                                 "{0} are the overall winners!", 
00449                                                 names),
00450                                         true);
00451                         }
00452                 }
00453         }
00454         else
00455         {
00456                 int winningTeam = TankSort::getWinningTeam(
00457                         ScorchedServer::instance()->getContext());
00458                 if (winningTeam == 0)
00459                 {
00460                         ServerChannelManager::instance()->sendText(
00461                                 ChannelText("banner", 
00462                                         "GAME_DRAWN",
00463                                         "The game is a draw!"),
00464                                 true);
00465                 }
00466                 else
00467                 {
00468                         ServerChannelManager::instance()->sendText(
00469                                 ChannelText("banner",
00470                                         "TEAM_OVERALL_WINNER",
00471                                         "{0} team is the overall winner!",
00472                                         TankColorGenerator::getTeamName(winningTeam)),
00473                                 true);
00474                 }
00475                 
00476                 // Score all the winning tanks as overall winners
00477                 if (winningTeam != 0)
00478                 {
00479                         std::map<unsigned int, Tank *> &tanks = 
00480                                 ScorchedServer::instance()->getTankContainer().getPlayingTanks();
00481                         std::map<unsigned int, Tank *>::iterator itor;
00482                         for (itor = tanks.begin();
00483                                 itor != tanks.end();
00484                                 itor++)
00485                         {
00486                                 Tank *tank = (*itor).second;
00487                                 if (tank->getTeam() == winningTeam)
00488                                 {
00489                                         if (!tank->getState().getSpectator() &&
00490                                                 tank->getState().getState() != TankState::sPending &&
00491                                                 tank->getState().getState() != TankState::sInitializing &&
00492                                                 tank->getState().getState() != TankState::sLoading)
00493                                         {
00494                                                 StatsLogger::instance()->tankOverallWinner(tank);
00495                                         }
00496                                 }
00497                         }
00498                 }
00499         }
00500 }

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