00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <set>
00022 #include <server/ServerNewGameState.h>
00023 #include <server/ServerState.h>
00024 #include <server/ScorchedServer.h>
00025 #include <server/ServerMessageHandler.h>
00026 #include <server/ServerChannelManager.h>
00027 #include <server/TurnController.h>
00028 #include <server/ServerCommon.h>
00029 #ifndef S3D_SERVER
00030 #include <client/ClientSave.h>
00031 #endif
00032 #include <tankai/TankAIAdder.h>
00033 #include <tank/TankContainer.h>
00034 #include <tank/TankSort.h>
00035 #include <tank/TankTeamScore.h>
00036 #include <tank/TankDeadContainer.h>
00037 #include <tank/TankModelStore.h>
00038 #include <tank/TankState.h>
00039 #include <tank/TankScore.h>
00040 #include <tank/TankPosition.h>
00041 #include <tank/TankAccessories.h>
00042 #include <tank/TankModelContainer.h>
00043 #include <target/TargetLife.h>
00044 #include <tankai/TankAI.h>
00045 #include <weapons/EconomyStore.h>
00046 #include <coms/ComsNewGameMessage.h>
00047 #include <coms/ComsMessageSender.h>
00048 #include <landscapemap/LandscapeMaps.h>
00049 #include <landscapedef/LandscapeDefn.h>
00050 #include <landscapedef/LandscapeDefinitions.h>
00051 #include <placement/PlacementTankPosition.h>
00052 #include <lua/LUAScriptHook.h>
00053 #include <common/RandomGenerator.h>
00054 #include <common/OptionsTransient.h>
00055 #include <common/OptionsScorched.h>
00056 #include <common/Clock.h>
00057 #include <common/StatsLogger.h>
00058 #include <common/Logger.h>
00059 #include <common/Defines.h>
00060 #include <algorithm>
00061
00062 extern Clock serverTimer;
00063
00064 ServerNewGameState::ServerNewGameState() :
00065 GameStateI("ServerNewGameState")
00066 {
00067 ScorchedServer::instance()->getLUAScriptHook().addHookProvider("server_newgame");
00068 }
00069
00070 ServerNewGameState::~ServerNewGameState()
00071 {
00072 }
00073
00074 void ServerNewGameState::enterState(const unsigned state)
00075 {
00076 std::list<Tank *> currentTanks;
00077 std::map<unsigned int, Tank *> &playingTanks =
00078 ScorchedServer::instance()->getTankContainer().getPlayingTanks();
00079 std::map<unsigned int, Tank *>::iterator playingTanksItor;
00080 for (playingTanksItor = playingTanks.begin();
00081 playingTanksItor != playingTanks.end();
00082 playingTanksItor++)
00083 {
00084 Tank *tank = (*playingTanksItor).second;
00085 currentTanks.push_back(tank);
00086 }
00087 StatsLogger::instance()->gameStart(currentTanks);
00088
00089
00090 ServerChannelManager::instance()->sendText(
00091 ChannelText("info", "NEXT_ROUND", "Next Round"),
00092 true);
00093
00094
00095 EconomyStore::instance()->getEconomy()->calculatePrices();
00096 EconomyStore::instance()->getEconomy()->savePrices();
00097
00098
00099
00100
00101 bool sendGameState = false;
00102 if (ScorchedServer::instance()->getOptionsGame().commitChanges())
00103 {
00104 sendGameState = true;
00105 ServerChannelManager::instance()->sendText(
00106 ChannelText("info",
00107 "GAME_OPTIONS_CHANGED",
00108 "Game options have been changed!"),
00109 true);
00110 }
00111
00112
00113 LandscapeDefinition defn = ScorchedServer::instance()->getLandscapes().getRandomLandscapeDefn(
00114 ScorchedServer::instance()->getContext().getOptionsGame(),
00115 ScorchedServer::instance()->getContext().getTankContainer());
00116
00117
00118 ScorchedServer::instance()->getOptionsGame().updateLevelOptions(
00119 ScorchedServer::instance()->getContext(), defn);
00120
00121
00122 ScorchedServer::instance()->getContext().getOptionsTransient().newGame();
00123 ScorchedServer::instance()->getContext().getTankTeamScore().newGame();
00124
00125
00126 #ifndef S3D_SERVER
00127
00128 {
00129 if (ScorchedServer::instance()->getTankContainer().getNoOfTanks() == 0 ||
00130 ScorchedServer::instance()->getTankContainer().getNoOfTanks() -
00131 ScorchedServer::instance()->getTankContainer().getNoOfNonSpectatorTanks() > 1)
00132 {
00133
00134
00135 }
00136 else
00137 {
00138
00139 if (ClientSave::stateRestored())
00140 {
00141 ClientSave::restoreClient(false, true);
00142 ClientSave::setStateNotRestored();
00143 }
00144 else
00145 {
00146 ClientSave::storeClient();
00147 }
00148 }
00149 }
00150 #endif
00151
00152
00153 ServerCommon::serverLog( "Generating landscape");
00154
00155
00156 removeTargets();
00157
00158
00159 checkBots(true);
00160
00161
00162 checkTeams();
00163
00164
00165 resetTankStates(state);
00166
00167
00168 ScorchedServer::instance()->getLandscapeMaps().generateMaps(
00169 ScorchedServer::instance()->getContext(), defn);
00170
00171
00172 addTanksToGame(state, sendGameState);
00173
00174
00175 TurnController::instance()->newGame();
00176
00177
00178 ScorchedServer::instance()->getLUAScriptHook().callHook("server_newgame");
00179
00180
00181
00182
00183 serverTimer.getTimeDifference();
00184
00185
00186 ScorchedServer::instance()->getTankContainer().setAllNotReady();
00187 ScorchedServer::instance()->getGameState().stimulate(ServerState::ServerStimulusNewGameReady);
00188 }
00189
00190 int ServerNewGameState::addTanksToGame(const unsigned state,
00191 bool addState)
00192 {
00193 std::list<Tank *> tanks = resetTankStates(state);
00194 if (tanks.empty()) return 0;
00195
00196
00197 ComsNewGameMessage newGameMessage;
00198 if (addState)
00199 {
00200
00201 newGameMessage.addGameState();
00202 }
00203
00204
00205 std::map<unsigned int, Target *> &targets =
00206 ScorchedServer::instance()->getTargetContainer().getTargets();
00207 std::map<unsigned int, Target *>::iterator targetItor;
00208 for (targetItor = targets.begin();
00209 targetItor != targets.end();
00210 targetItor++)
00211 {
00212 Target *target = targetItor->second;
00213 if (target->getPlayerId() >= TargetID::MIN_TARGET_ID &&
00214 target->getPlayerId() < TargetID::MIN_TARGET_TRANSIENT_ID)
00215 {
00216
00217 newGameMessage.getLevelMessage().getTargetIds().insert(
00218 target->getPlayerId());
00219 if (state != ServerState::ServerStateNewGame &&
00220 target->isTarget())
00221 {
00222 newGameMessage.getLevelMessage().getOldTargets().addToBuffer(target->getPlayerId());
00223 target->writeMessage(newGameMessage.getLevelMessage().getOldTargets());
00224 }
00225 }
00226 else if (target->getPlayerId() >= TargetID::MIN_TARGET_TRANSIENT_ID &&
00227 target->getPlayerId() < TargetID::MAX_TARGET_ID)
00228 {
00229
00230 newGameMessage.getLevelMessage().getNewTargets().addToBuffer(target->getPlayerId());
00231 target->writeMessage(newGameMessage.getLevelMessage().getNewTargets());
00232 }
00233 }
00234
00235
00236 newGameMessage.getLevelMessage().createMessage(
00237 ScorchedServer::instance()->getLandscapeMaps().getDefinitions().getDefinition());
00238 newGameMessage.getLevelMessage().getDeformInfos() =
00239 DeformLandscape::getInfos();
00240 LandscapeDefinitionCache &definitions =
00241 ScorchedServer::instance()->getLandscapeMaps().getDefinitions();
00242 ServerCommon::serverLog(
00243 S3D::formatStringBuffer("Finished generating landscape (%u, %s, %s)",
00244 definitions.getSeed(),
00245 definitions.getDefinition().getDefn(),
00246 definitions.getDefinition().getTex()));
00247
00248
00249 int sendSize = int(newGameMessage.getLevelMessage().getDeformInfos().size()) *
00250 sizeof(DeformLandscape::DeformInfo);
00251 if (sendSize > ScorchedServer::instance()->getOptionsGame().getMaxLandscapeSize())
00252 {
00253 ServerChannelManager::instance()->sendText(
00254 ChannelText("info",
00255 "LANDSCAPE_TOO_LARGE",
00256 "Landscape too large to send to waiting clients ({0} bytes).",
00257 sendSize),
00258 true);
00259 return 0;
00260 }
00261
00262
00263
00264 std::list<unsigned int> sendDestinations;
00265 std::set<unsigned int> destinations;
00266 std::set<unsigned int>::iterator findItor;
00267
00268 std::list<Tank *>::iterator itor;
00269 for (itor = tanks.begin();
00270 itor != tanks.end();
00271 itor++)
00272 {
00273 Tank *tank = *itor;
00274
00275
00276 tank->getState().setNotReady();
00277
00278
00279
00280 unsigned int destination = tank->getDestinationId();
00281 findItor = destinations.find(destination);
00282 if (findItor == destinations.end())
00283 {
00284 destinations.insert(destination);
00285 sendDestinations.push_back(destination);
00286 }
00287 }
00288
00289
00290
00291 ComsMessageSender::sendToMultipleClients(newGameMessage, sendDestinations);
00292
00293 return (int) tanks.size();
00294 }
00295
00296 std::list<Tank *> ServerNewGameState::resetTankStates(unsigned int state)
00297 {
00298 std::list<Tank *> resultingTanks;
00299
00300
00301 std::map<unsigned int, Tank *> &tanks =
00302 ScorchedServer::instance()->getTankContainer().getPlayingTanks();
00303 std::map<unsigned int, Tank *>::iterator itor;
00304 for (itor = tanks.begin();
00305 itor != tanks.end();
00306 itor++)
00307 {
00308 Tank *tank = (*itor).second;
00309
00310 if (tank->getState().getState() == TankState::sPending ||
00311 (state == ServerState::ServerStateNewGame && (
00312 tank->getState().getState() == TankState::sDead ||
00313 tank->getState().getState() == TankState::sNormal)))
00314 {
00315 resultingTanks.push_back(tank);
00316
00317
00318
00319
00320 if (tank->getState().getState() == TankState::sPending)
00321 {
00322 tank->newMatch();
00323
00324
00325
00326
00327
00328 if (ScorchedServer::instance()->getTankDeadContainer().getTank(tank))
00329 {
00330 Logger::log( "Found residual player info");
00331 }
00332 }
00333
00334 if (tank->getState().getSpectator())
00335 {
00336
00337 tank->getState().setState(TankState::sDead);
00338 }
00339 else if (state == ServerState::ServerStateNewGame)
00340 {
00341
00342 tank->newGame();
00343 }
00344 else
00345 {
00346
00347 tank->getState().setState(TankState::sDead);
00348 }
00349 }
00350 }
00351
00352 return resultingTanks;
00353 }
00354
00355 void ServerNewGameState::checkTeams()
00356 {
00357
00358 std::map<unsigned int, Tank *> &playingTanks =
00359 ScorchedServer::instance()->getTankContainer().getPlayingTanks();
00360 std::map<unsigned int, Tank *>::iterator mainitor;
00361 for (mainitor = playingTanks.begin();
00362 mainitor != playingTanks.end();
00363 mainitor++)
00364 {
00365 Tank *current = (*mainitor).second;
00366 if (!current->getState().getSpectator())
00367 {
00368 if (ScorchedServer::instance()->getOptionsGame().getTeams() > 1 &&
00369 current->getTeam() == 0) current->setTeam(1);
00370 if (ScorchedServer::instance()->getOptionsGame().getTeams() == 1 &&
00371 current->getTeam() > 0) current->setTeam(0);
00372 }
00373 }
00374
00375
00376 if (ScorchedServer::instance()->getOptionsGame().getTeams() != 1)
00377 {
00378
00379 switch (ScorchedServer::instance()->getOptionsGame().getTeamBallance())
00380 {
00381 case OptionsGame::TeamBallanceAuto:
00382 case OptionsGame::TeamBallanceAutoByScore:
00383 case OptionsGame::TeamBallanceAutoByBots:
00384 checkTeamsAuto();
00385 break;
00386 case OptionsGame::TeamBallanceBotsVs:
00387 checkTeamsBotsVs();
00388 break;
00389 default:
00390 break;
00391 }
00392 }
00393
00394
00395 for (mainitor = playingTanks.begin();
00396 mainitor != playingTanks.end();
00397 mainitor++)
00398 {
00399 Tank *current = (*mainitor).second;
00400 if (!current->getState().getSpectator())
00401 {
00402 TankModel *model =
00403 ScorchedServer::instance()->getTankModels().getModelByName(
00404 current->getModelContainer().getTankModelName(),
00405 current->getTeam(),
00406 current->isTemp());
00407 if (0 != strcmp(model->getName(),
00408 current->getModelContainer().getTankModelName()))
00409 {
00410
00411
00412 current->getModelContainer().setTankModelName(
00413 model->getName(),
00414 model->getName(),
00415 model->getTypeName());
00416 }
00417 }
00418 }
00419 }
00420
00421 static inline bool lt_score(const Tank *o1, const Tank *o2)
00422 {
00423 return ((Tank*)o1)->getScore().getScore() > ((Tank *)o2)->getScore().getScore();
00424 }
00425
00426 static inline bool lt_bots(const Tank *o1, const Tank *o2)
00427 {
00428 return ((Tank*)o1)->getTankAI() < ((Tank *)o2)->getTankAI();
00429 }
00430
00431 void ServerNewGameState::checkTeamsAuto()
00432 {
00433
00434 std::vector<Tank *> teamPlayers[4];
00435 std::map<unsigned int, Tank *> &playingTanks =
00436 ScorchedServer::instance()->getTankContainer().getPlayingTanks();
00437 std::map<unsigned int, Tank *>::iterator mainitor;
00438 for (mainitor = playingTanks.begin();
00439 mainitor != playingTanks.end();
00440 mainitor++)
00441 {
00442 Tank *current = (*mainitor).second;
00443 if (!current->getState().getSpectator())
00444 {
00445 if (current->getTeam() > 0)
00446 {
00447 teamPlayers[current->getTeam() - 1].push_back(current);
00448 }
00449 }
00450 }
00451
00452 bool ballanced = false;
00453 bool check = true;
00454 while (check)
00455 {
00456 check = false;
00457
00458
00459 std::vector<Tank *> *minPlayers = &teamPlayers[0];
00460 std::vector<Tank *> *maxPlayers = &teamPlayers[0];
00461 for (int i=0; i<ScorchedServer::instance()->getOptionsGame().getTeams(); i++)
00462 {
00463 if (teamPlayers[i].size() < minPlayers->size()) minPlayers = &teamPlayers[i];
00464 if (teamPlayers[i].size() > maxPlayers->size()) maxPlayers = &teamPlayers[i];
00465 }
00466
00467
00468 if (maxPlayers->size() - minPlayers->size() >= 2)
00469 {
00470 check = true;
00471 ballanced = true;
00472
00473
00474 if (ScorchedServer::instance()->getOptionsGame().getTeamBallance() ==
00475 OptionsGame::TeamBallanceAutoByScore)
00476 {
00477 std::sort(minPlayers->begin(), minPlayers->end(), lt_score);
00478 std::sort(maxPlayers->begin(), maxPlayers->end(), lt_score);
00479 }
00480 else if (ScorchedServer::instance()->getOptionsGame().getTeamBallance() ==
00481 OptionsGame::TeamBallanceAutoByBots)
00482 {
00483 std::sort(minPlayers->begin(), minPlayers->end(), lt_bots);
00484 std::sort(maxPlayers->begin(), maxPlayers->end(), lt_bots);
00485 }
00486
00487
00488 for (int i=0; i<ScorchedServer::instance()->getOptionsGame().getTeams(); i++)
00489 {
00490 if (minPlayers == &teamPlayers[i])
00491 {
00492
00493 Tank *tank = maxPlayers->back();
00494 maxPlayers->pop_back();
00495 minPlayers->push_back(tank);
00496 tank->setTeam(i+1);
00497 }
00498 }
00499 }
00500 }
00501
00502
00503 if (ballanced)
00504 {
00505 if (ScorchedServer::instance()->getOptionsGame().getTeamBallance() ==
00506 OptionsGame::TeamBallanceAutoByScore)
00507 {
00508 ServerChannelManager::instance()->sendText(
00509 ChannelText("info",
00510 "SCORE_AUTO_BALLANCE",
00511 "Auto ballancing teams, by score"),
00512 true);
00513 }
00514 else if (ScorchedServer::instance()->getOptionsGame().getTeamBallance() ==
00515 OptionsGame::TeamBallanceAutoByBots)
00516 {
00517 ServerChannelManager::instance()->sendText(
00518 ChannelText("info",
00519 "BOTS_AUTO_BALLANCE",
00520 "Auto ballancing teams, by bots"),
00521 true);
00522 }
00523 else
00524 {
00525 ServerChannelManager::instance()->sendText(
00526 ChannelText("info",
00527 "NORMAL_AUTO_BALLANCE",
00528 "Auto ballancing teams"),
00529 true);
00530 }
00531 }
00532 }
00533
00534 void ServerNewGameState::checkTeamsBotsVs()
00535 {
00536 std::map<unsigned int, Tank *> &playingTanks =
00537 ScorchedServer::instance()->getTankContainer().getPlayingTanks();
00538 std::map<unsigned int, Tank *>::iterator mainitor;
00539 for (mainitor = playingTanks.begin();
00540 mainitor != playingTanks.end();
00541 mainitor++)
00542 {
00543 Tank *current = (*mainitor).second;
00544 if (!current->getState().getSpectator())
00545 {
00546 if (current->getDestinationId() == 0) current->setTeam(1);
00547 else current->setTeam(2);
00548 }
00549 }
00550 }
00551
00552 void ServerNewGameState::checkBots(bool removeBots)
00553 {
00554 int requiredPlayers =
00555 ScorchedServer::instance()->getOptionsGame().
00556 getRemoveBotsAtPlayers();
00557 if (requiredPlayers == 0)
00558 {
00559
00560 return;
00561 }
00562
00563
00564
00565
00566 int noPlayers = 0;
00567 std::map<unsigned int, Tank *> &playingTanks =
00568 ScorchedServer::instance()->getTankContainer().getPlayingTanks();
00569 std::map<unsigned int, Tank *>::iterator mainitor;
00570 for (mainitor = playingTanks.begin();
00571 mainitor != playingTanks.end();
00572 mainitor++)
00573 {
00574 Tank *current = (*mainitor).second;
00575 if (!current->getState().getSpectator() ||
00576 current->getDestinationId() == 0)
00577 {
00578 noPlayers++;
00579 }
00580 }
00581
00582 if (noPlayers > requiredPlayers &&
00583 removeBots)
00584 {
00585 std::multimap<unsigned int, unsigned int> ais_;
00586
00587
00588
00589 for (mainitor = playingTanks.begin();
00590 mainitor != playingTanks.end();
00591 mainitor++)
00592 {
00593 Tank *current = (*mainitor).second;
00594 if (current->getDestinationId() == 0)
00595 {
00596 unsigned int startTime = (unsigned int)
00597 current->getScore().getStartTime();
00598 ais_.insert(std::pair<unsigned int, unsigned int>
00599 (startTime, current->getPlayerId()));
00600 }
00601 }
00602
00603
00604 std::multimap<unsigned int, unsigned int>::reverse_iterator
00605 aiItor = ais_.rbegin();
00606 while (noPlayers > requiredPlayers)
00607 {
00608 if (aiItor != ais_.rend())
00609 {
00610 std::pair<unsigned int, unsigned int> item = *aiItor;
00611 ServerMessageHandler::instance()->destroyPlayer(
00612 item.second, "Auto-kick");
00613 aiItor++;
00614 }
00615 noPlayers--;
00616 }
00617 }
00618 if (noPlayers < requiredPlayers)
00619 {
00620 std::multimap<std::string, unsigned int> ais_;
00621
00622
00623
00624 for (mainitor = playingTanks.begin();
00625 mainitor != playingTanks.end();
00626 mainitor++)
00627 {
00628 Tank *current = (*mainitor).second;
00629 if (current->getDestinationId() == 0)
00630 {
00631 ais_.insert(std::pair<std::string, unsigned int>
00632 (current->getTankAI()->getName(),
00633 current->getPlayerId()));
00634 }
00635 }
00636
00637
00638
00639 int maxComputerAIs =
00640 ScorchedServer::instance()->getOptionsGame().getNoMaxPlayers();
00641 for (int i=0; i<maxComputerAIs; i++)
00642 {
00643 const char *playerType =
00644 ScorchedServer::instance()->getOptionsGame().getPlayerType(i);
00645 if (0 != stricmp(playerType, "Human") &&
00646 0 != stricmp(playerType, "Random"))
00647 {
00648 std::multimap<std::string, unsigned int>::iterator findItor =
00649 ais_.find(playerType);
00650 if (findItor == ais_.end())
00651 {
00652 if (noPlayers < requiredPlayers)
00653 {
00654
00655 TankAIAdder::addTankAI(*ScorchedServer::instance(), playerType);
00656 noPlayers++;
00657 }
00658 }
00659 else
00660 {
00661
00662 ais_.erase(findItor);
00663 }
00664 }
00665 }
00666 for (int i=0; i<maxComputerAIs; i++)
00667 {
00668 const char *playerType =
00669 ScorchedServer::instance()->getOptionsGame().getPlayerType(i);
00670 if (0 != stricmp(playerType, "Human") &&
00671 0 == stricmp(playerType, "Random"))
00672 {
00673 if (ais_.empty())
00674 {
00675 if (noPlayers < requiredPlayers)
00676 {
00677
00678 TankAIAdder::addTankAI(*ScorchedServer::instance(), playerType);
00679 noPlayers++;
00680 }
00681 }
00682 else
00683 {
00684
00685 ais_.erase(ais_.begin());
00686 }
00687 }
00688 }
00689 }
00690 }
00691
00692 void ServerNewGameState::removeTargets()
00693 {
00694 std::map<unsigned int, Target *> targets =
00695 ScorchedServer::instance()->getTargetContainer().getTargets();
00696 std::map<unsigned int, Target *>::iterator itor;
00697 for (itor = targets.begin();
00698 itor != targets.end();
00699 itor++)
00700 {
00701 unsigned int playerId = (*itor).first;
00702 Target *target = (*itor).second;
00703 if (target->isTemp())
00704 {
00705 if (target->isTarget())
00706 {
00707 Target *removedTarget =
00708 ScorchedServer::instance()->getTargetContainer().removeTarget(playerId);
00709 delete removedTarget;
00710 }
00711 else
00712 {
00713 Tank *removedTank =
00714 ScorchedServer::instance()->getTankContainer().removeTank(playerId);
00715 delete removedTank;
00716 }
00717 }
00718 }
00719 }