00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "FSServer.h"
00027
00028 #include "Hull.h"
00029 #include "RacialTrait.h"
00030 #include "Packet.h"
00031
00032 #include "Creation.h"
00033
00034 #include <stdlib.h>
00035 #include <time.h>
00036
00037 #ifdef _DEBUG
00038 #define new DEBUG_NEW
00039 #endif
00040
00041 Game * TheGame;
00042
00043 Game::Game()
00044 {
00045 TurnPhase = 0;
00046 mCreation = NULL;
00047 mNumberOfPlayers = 0;
00048 mWHMin = 0;
00049 mWHMax = 0;
00050 mWHMinDistance = 0;
00051
00052 VCWorlds = 0;
00053 VCTechLevel = 0;
00054 VCTechCount = 0;
00055 VCScore = 0;
00056 VCTimes2nd = 0.0;
00057 VCResources = 0;
00058 VCCapShips = 0;
00059 VCHighScoreAt = 0;
00060 VCCount = 0;
00061 VCStart = 0;
00062 mGameID = 0;
00063 }
00064
00065 Game::~Game()
00066 {
00067 delete mCreation;
00068
00069 deque<Component *>::iterator i1;
00070 for (i1 = mComponents.begin(); i1 != mComponents.end(); ++i1)
00071 delete *i1;
00072 mComponents.clear();
00073
00074 deque<Player *>::iterator i3;
00075 for (i3 = mPlayers.begin(); i3 != mPlayers.end(); ++i3)
00076 delete *i3;
00077 mPlayers.clear();
00078
00079 deque<RacialTrait *>::iterator i2;
00080 for (i2 = mPRTs.begin(); i2 != mPRTs.end(); ++i2)
00081 delete *i2;
00082 mPRTs.clear();
00083
00084 for (i2 = mLRTs.begin(); i2 != mLRTs.end(); ++i2)
00085 delete *i2;
00086 mLRTs.clear();
00087
00088 int i;
00089 for (i = 0; i < mMessages.size(); ++i)
00090 delete mMessages[i];
00091
00092 for (i = 0; i < mTopObjects.size(); ++i)
00093 delete mTopObjects[i];
00094
00095 mOrders.clear();
00096 }
00097
00098 Message * Game::AddMessage(string type)
00099 {
00100 Message * mess = new Message(type);
00101 mMessages.push_back(mess);
00102 return mess;
00103 }
00104
00105 void Game::StoreMessageLocation(const Location * loc)
00106 {
00107 int i;
00108 for (i = 0; i < mMessages.size(); ++i)
00109 mMessages[i]->StoreMessageLocation(loc, NULL);
00110
00111 for (i = 0; i < mNumberOfPlayers; ++i)
00112 mPlayers[i]->StoreMessageLocation(loc);
00113 }
00114
00115 bool Game::LoadCreation(const TiXmlNode * options)
00116 {
00117 const char * ptr;
00118 if (!options)
00119 return false;
00120
00121
00122 ptr = GetString(options->FirstChild("TechAdvances"));
00123 if (ptr == NULL || strcmp(ptr, "Normal") == 0)
00124 TechFactor = 1.0;
00125 else if (strcmp(ptr, "Slow") == 0)
00126 TechFactor = 2.0;
00127 else {
00128 double tmp = atof(ptr);
00129 if (tmp > 0 && tmp <= 100)
00130 TechFactor = tmp;
00131 else
00132 TechFactor = 1.0;
00133 }
00134
00135
00136 const TiXmlNode * child1;
00137 const TiXmlNode * child2;
00138 const TiXmlNode * child3;
00139 const TiXmlText * text;
00140
00141 if (!TheGalaxy->ParseSize(options->FirstChild("Size")))
00142 return false;
00143
00144 RandomEventsStart = 0;
00145 child1 = options->FirstChild("RandomEvents");
00146 if (!child1)
00147 mRandomEvents = RE_NONE;
00148 else {
00149 child2 = child1->FirstChild("Start");
00150 if (child2)
00151 RandomEventsStart = GetLong(child2);
00152
00153 mRandomEvents = RE_NONE;
00154 for (child2 = child1->FirstChild("Event"); child2; child2 = child2->NextSibling("Event")) {
00155 child3 = child2->FirstChild();
00156 if (!child3)
00157 continue;
00158
00159 if (child3->Type() != TiXmlNode::TEXT)
00160 continue;
00161
00162 text = child3->ToText();
00163 if (strcmp(text->Value(), "Mystery Trader") == 0)
00164 mRandomEvents |= RE_MT;
00165 else if (strcmp(text->Value(), "Artifacts") == 0)
00166 mRandomEvents |= RE_ARTIFACT;
00167 else if (strcmp(text->Value(), "Comets") == 0)
00168 mRandomEvents |= RE_COMET;
00169 else if (strcmp(text->Value(), "Wormholes") == 0) {
00170 mRandomEvents |= RE_WORMHOLE;
00171 child3 = child1->FirstChild("Wormholes");
00172 mWHMin = GetLong(child3->FirstChild("MinimumPairs"));
00173 mWHMax = GetLong(child3->FirstChild("MaximumPairs"));
00174 mWHMinDistance = GetLong(child3->FirstChild("MinDistance"));
00175 mWHMinDistance = max(mWHMinDistance, 10L);
00176 } else if (strcmp(text->Value(), "All") == 0) {
00177 mRandomEvents = RE_ALL;
00178 break;
00179 }
00180 }
00181 }
00182
00183 PublicScoreStart = 0;
00184 child1 = options->FirstChild("PublicScores");
00185 if (!child1)
00186 PublicScore = PPS_RANK;
00187 else {
00188 PublicScore = PPS_NONE;
00189 PublicScoreStart = 20;
00190 child2 = child1->FirstChild("Start");
00191 if (child2)
00192 PublicScoreStart = GetLong(child2);
00193
00194 for (child2 = child1->FirstChild("Category"); child2; child2 = child2->NextSibling("Category")) {
00195 child3 = child2->FirstChild();
00196 if (!child3)
00197 continue;
00198
00199 if (child3->Type() != TiXmlNode::TEXT)
00200 continue;
00201
00202 text = child3->ToText();
00203 if (strcmp(text->Value(), "Planets") == 0)
00204 PublicScore |= PPS_PLANET;
00205 else if (strcmp(text->Value(), "Bases") == 0)
00206 PublicScore |= PPS_BASES;
00207 else if (strcmp(text->Value(), "Unarmed Ships") == 0)
00208 PublicScore |= PPS_UNARM;
00209 else if (strcmp(text->Value(), "Escort Ships") == 0)
00210 PublicScore |= PPS_ESCORT;
00211 else if (strcmp(text->Value(), "Capital Ships") == 0)
00212 PublicScore |= PPS_CAPSHIP;
00213 else if (strcmp(text->Value(), "Tech Levels") == 0)
00214 PublicScore |= PPS_TECH;
00215 else if (strcmp(text->Value(), "Resources") == 0)
00216 PublicScore |= PPS_RESOURCE;
00217 else if (strcmp(text->Value(), "Score") == 0)
00218 PublicScore |= PPS_SCORE;
00219 else if (strcmp(text->Value(), "Rank") == 0)
00220 PublicScore |= PPS_RANK;
00221 else if (strcmp(text->Value(), "All") == 0) {
00222 PublicScore = PPS_ALL;
00223 break;
00224 }
00225 }
00226 }
00227
00228 child1 = options->FirstChild("VictoryConditions");
00229 if (child1) {
00230 VCCount = GetLong(child1->FirstChild("WinnerConditions"));
00231 VCStart = GetLong(child1->FirstChild("MinimumYears"));
00232 VCWorlds = GetLong(child1->FirstChild("ControledWorlds"));
00233 child2 = child1->FirstChild("TechLevels");
00234 if (child2) {
00235 VCTechLevel = GetLong(child2->FirstChild("Level"));
00236 VCTechCount = GetLong(child2->FirstChild("Number"));
00237 }
00238 VCScore = GetLong(child1->FirstChild("Score"));
00239 VCTimes2nd = GetDouble(child1->FirstChild("OverSecond"));
00240 VCResources = GetLong(child1->FirstChild("Resources"));
00241 VCCapShips = GetLong(child1->FirstChild("CapShips"));
00242 VCHighScoreAt = GetLong(child1->FirstChild("HighestScoreAt"));
00243 }
00244
00245 child1 = options->FirstChild("MineralSettings");
00246 if (!child1) {
00247 Message * mess = TheGame->AddMessage("Error: Missing section");
00248 mess->AddItem("Section", "MineralSettings");
00249 return false;
00250 }
00251
00252 Rules::ParseMinSettings(child1);
00253
00254 return true;
00255 }
00256
00257 bool Game::LoadRacialTraits(const TiXmlNode * node)
00258 {
00259 if (!node)
00260 return false;
00261
00262 const TiXmlNode * child;
00263 for (child = node->FirstChild("PrimaryRacialTrait"); child != NULL; child = child->NextSibling("PrimaryRacialTrait")) {
00264 mPRTs.insert(mPRTs.end(), RacialTrait::ParseNode(child));
00265 }
00266
00267 for (child = node->FirstChild("LesserRacialTrait"); child != NULL; child = child->NextSibling("LesserRacialTrait")) {
00268 mLRTs.insert(mLRTs.end(), RacialTrait::ParseNode(child));
00269 }
00270
00271 return true;
00272 }
00273
00274 bool Game::LoadStartShips(const TiXmlNode * node)
00275 {
00276 if (!node)
00277 return false;
00278
00279 const TiXmlNode * child;
00280 RacialTrait * rt;
00281 for (child = node->FirstChild("PrimaryRacialTrait"); child != NULL; child = child->NextSibling("PrimaryRacialTrait")) {
00282 rt = const_cast<RacialTrait *>(ParsePRT(GetString(child->FirstChild("Name"))));
00283 if (rt == NULL) {
00284 return false;
00285 }
00286 rt->ParseStartShips(child);
00287 }
00288
00289 for (child = node->FirstChild("LesserRacialTrait"); child != NULL; child = child->NextSibling("LesserRacialTrait")) {
00290 rt = const_cast<RacialTrait *>(ParseLRT(GetString(child->FirstChild("Name"))));
00291 if (rt == NULL) {
00292 return false;
00293 }
00294 rt->ParseStartShips(child);
00295 }
00296
00297 return true;
00298 }
00299
00300 bool Game::LoadComponents(const TiXmlNode * node)
00301 {
00302 if (!node)
00303 return false;
00304
00305 if (!Component::LoadComponents(node, mComponents))
00306 return false;
00307
00308 #ifdef DEBUG
00309 deque<Component *>::const_iterator iter;
00310 Component * temp;
00311 Hull * thull;
00312
00313 for (iter = mComponents.begin(); iter != mComponents.end(); ++iter) {
00314 temp = *iter;
00315 thull = dynamic_cast<Hull *>(temp);
00316 if (thull)
00317 thull->CheckSlots();
00318 }
00319 #endif // DEBUG
00320
00321 return true;
00322 }
00323
00324 unsigned long GetRandomSeed()
00325 {
00326 return (unsigned)time(NULL);
00327 }
00328
00329 void Game::SetFileLocation(const char * hostfile)
00330 {
00331 mFileLoc = hostfile;
00332 int pos = max(int(mFileLoc.find_last_of('/')), int(mFileLoc.find_last_of('\\')));
00333 mFileName = mFileLoc.substr(pos+1);
00334 mFileName.erase(mFileName.find_last_of('.'));
00335 mFileLoc.erase(pos+1);
00336 }
00337
00338 bool Game::LoadHostFile(const char * hostfile)
00339 {
00340 SetFileLocation(hostfile);
00341
00342 TiXmlDocument doc(hostfile);
00343 doc.SetCondenseWhiteSpace(false);
00344 if (!doc.LoadFile()) {
00345 Message * mess = TheGame->AddMessage("Error: Cannot open file");
00346 mess->AddItem("File name", hostfile);
00347 mess->AddItem("TinyXML error description", doc.ErrorDesc());
00348 mess->AddLong("TinyXML error row", doc.ErrorRow());
00349 mess->AddLong("TinyXML error column", doc.ErrorCol());
00350 return false;
00351 }
00352
00353 const TiXmlNode * hf;
00354 const TiXmlNode * node;
00355
00356 hf = doc.FirstChild("HostFile");
00357 if (!hf) {
00358 Message * mess = TheGame->AddMessage("Error: Missing section");
00359 mess->AddItem("File name", hostfile);
00360 mess->AddItem("Section", "HostFile");
00361 return false;
00362 }
00363
00364 if (!Game::CheckMetaInfo(hf, hostfile, HOSTFILEVERSION))
00365 return false;
00366
00367 mGameID = GetLong(hf->FirstChild("GameID"));
00368 if (mGameID == 0) {
00369 Message * mess = TheGame->AddMessage("Error: Invalid Game ID");
00370 mess->AddLong("Game ID", mGameID);
00371 return false;
00372 }
00373
00374 node = hf->FirstChild("Turn");
00375 Turn = GetLong(node);
00376 if (Turn < 1) {
00377 Message * mess = TheGame->AddMessage("Error: Turn too low");
00378 mess->AddLong("Turn", Turn);
00379 return false;
00380 }
00381
00382 ++Turn;
00383 mNumberOfPlayers = GetLong(hf->FirstChild("NumberOfPlayers"));
00384 if (mNumberOfPlayers < 1) {
00385 TheGame->AddMessage("Error: Less then 1 player");
00386 return false;
00387 }
00388
00389 unsigned long seed;
00390 seed = GetLong(hf->FirstChild("Seed"));
00391 if (seed == 0)
00392 seed = GetRandomSeed();
00393
00394 init_genrand(seed);
00395
00396 if (!LoadXYFile())
00397 return false;
00398
00399 for (node = hf->FirstChild("Player"); node; node = node->NextSibling("Player")) {
00400 const TiXmlNode * child2 = node->FirstChild("PlayerNumber");
00401 unsigned int p = GetLong(child2);
00402 if (p < 1 || p > NumberPlayers() || p != mPlayers.size()+1) {
00403 Message * mess = TheGame->AddMessage("Error: Invalid player number");
00404 mess->AddLong("", p);
00405 return false;
00406 }
00407
00408 deque<Player *>::iterator pi;
00409 pi = mPlayers.insert(mPlayers.end(), new Player(p));
00410 if (!(*pi)->ParseNode(node, false))
00411 return false;
00412 }
00413
00414 if (mNumberOfPlayers != mPlayers.size())
00415 return false;
00416
00417
00418 node = hf->FirstChild("Galaxy");
00419 if (!node) {
00420 Message * mess = TheGame->AddMessage("Error: Missing section");
00421 mess->AddItem("File name", hostfile);
00422 mess->AddItem("Section", "Galaxy");
00423 return false;
00424 }
00425 if (!TheGalaxy->ParseNode(node))
00426 return false;
00427
00428 return true;
00429 }
00430
00431 bool Game::LoadPlayerFile(const char * playerfile)
00432 {
00433 SetFileLocation(playerfile);
00434
00435 string file = playerfile;
00436 int pos = file.find_last_of('.');
00437 mCurrentPlayer = atol(file.substr(pos+2).c_str());
00438
00439 TiXmlDocument doc(playerfile);
00440 doc.SetCondenseWhiteSpace(false);
00441 if (!doc.LoadFile()) {
00442 Message * mess = TheGame->AddMessage("Error: Cannot open file");
00443 mess->AddItem("File name", playerfile);
00444 mess->AddItem("TinyXML error description", doc.ErrorDesc());
00445 mess->AddLong("TinyXML error row", doc.ErrorRow());
00446 mess->AddLong("TinyXML error column", doc.ErrorCol());
00447 return false;
00448 }
00449
00450 const TiXmlNode * ptf;
00451 const TiXmlNode * node;
00452
00453 ptf = doc.FirstChild("PlayerTurnFile");
00454 if (!ptf) {
00455 Message * mess = TheGame->AddMessage("Error: Missing section");
00456 mess->AddItem("File name", playerfile);
00457 mess->AddItem("Section", "PlayerTurnFile");
00458 return false;
00459 }
00460
00461 if (!Game::CheckMetaInfo(ptf, playerfile, TURNFILEVERSION))
00462 return false;
00463
00464 mGameID = GetLong(ptf->FirstChild("GameID"));
00465 if (mGameID == 0) {
00466 Message * mess = TheGame->AddMessage("Error: Invalid Game ID");
00467 mess->AddLong("Game ID", mGameID);
00468 return false;
00469 }
00470
00471 node = ptf->FirstChild("Turn");
00472 Turn = GetLong(node);
00473 if (Turn < 1) {
00474 Message * mess = TheGame->AddMessage("Error: Turn too low");
00475 mess->AddLong("Turn", Turn);
00476 return false;
00477 }
00478
00479 mNumberOfPlayers = GetLong(ptf->FirstChild("NumberOfPlayers"));
00480 if (mNumberOfPlayers < 1) {
00481 TheGame->AddMessage("Error: Less then 1 player");
00482 return false;
00483 }
00484
00485 if (!LoadXYFile())
00486 return false;
00487
00488 mPlayers.insert(mPlayers.begin(), mNumberOfPlayers, NULL);
00489 for (node = ptf->FirstChild("Player"); node; node = node->NextSibling("Player")) {
00490 const TiXmlNode * child2 = node->FirstChild("PlayerNumber");
00491 unsigned int p = GetLong(child2);
00492 if (p < 1 || p > NumberPlayers()) {
00493 Message * mess = TheGame->AddMessage("Error: Invalid player number");
00494 mess->AddLong("", p);
00495 return false;
00496 }
00497
00498 mPlayers[p-1] = new Player(p);
00499 if (!mPlayers[p-1]->ParseNode(node, p != mCurrentPlayer))
00500 return false;
00501 }
00502
00503 if (mNumberOfPlayers != mPlayers.size())
00504 return false;
00505
00506 if (mPlayers[mCurrentPlayer-1] == NULL)
00507 return false;
00508
00509
00510 node = ptf->FirstChild("Galaxy");
00511 if (!node) {
00512 Message * mess = TheGame->AddMessage("Error: Missing section");
00513 mess->AddItem("File name", playerfile);
00514 mess->AddItem("Section", "Galaxy");
00515 return false;
00516 }
00517 if (!TheGalaxy->ParseNode(node))
00518 return false;
00519
00520 mPlayers[mCurrentPlayer-1]->ParseMessages(ptf->FirstChild("Messages"));
00521
00522 file[pos+1] = 'x';
00523 mPlayers[mCurrentPlayer-1]->SetWriteXFile();
00524 mPlayers[mCurrentPlayer-1]->OpenOrdersFile(file.c_str());
00525
00526 return true;
00527 }
00528
00529 bool Game::CheckMetaInfo(const TiXmlNode * node, const char * file, double fileversion)
00530 {
00531 const TiXmlNode * mn = node->FirstChild("MetaInfo");
00532 if (!mn) {
00533 Message * mess = TheGame->AddMessage("Error: Missing section");
00534 mess->AddItem("File name", file);
00535 mess->AddItem("Section", "MetaInfo");
00536 return false;
00537 }
00538
00539 double meta = GetDouble(mn->FirstChild("FileVersion"));
00540 if (meta > fileversion + epsilon || meta < fileversion - epsilon) {
00541 Message * mess = TheGame->AddMessage("Error: Invalid FileVersion");
00542 mess->AddItem("File name", file);
00543 mess->AddItem("FileVersion", GetString(node->FirstChild("FileVersion")));
00544 return false;
00545 }
00546
00547 meta = GetDouble(mn->FirstChild("FreeStarsVersion"));
00548 if (meta > FREESTARSVERSION + epsilon || meta < FREESTARSVERSION - epsilon) {
00549 Message * mess = TheGame->AddMessage("Error: Invalid FreeStarsVersion");
00550 mess->AddItem("File name", file);
00551 mess->AddItem("FreeStarsVersion", GetString(node->FirstChild("FreeStarsVersion")));
00552 return false;
00553 }
00554
00555 return true;
00556 }
00557
00558 bool Game::LoadDefFile(const char * deffile)
00559 {
00560 SetFileLocation(deffile);
00561
00562
00563 init_genrand(GetRandomSeed());
00564 do mGameID = genrand_int32();
00565 while (mGameID == 0);
00566
00567 TiXmlDocument doc(deffile);
00568 doc.SetCondenseWhiteSpace(false);
00569 if (!doc.LoadFile()) {
00570 Message * mess = TheGame->AddMessage("Error: Cannot open file");
00571 mess->AddItem("File name", deffile);
00572 return false;
00573 }
00574
00575 const TiXmlNode * df;
00576 const TiXmlNode * node;
00577
00578 mCreation = new Creation;
00579
00580 df = doc.FirstChild("DefFile");
00581 if (!df) {
00582 Message * mess = TheGame->AddMessage("Error: Missing section");
00583 mess->AddItem("File name", deffile);
00584 mess->AddItem("Section", "DefFile");
00585 return false;
00586 }
00587
00588 if (!CheckMetaInfo(df, deffile, HOSTFILEVERSION))
00589 return false;
00590
00591 int seedc = 0;
00592 int seeds = GetLong(df->FirstChild("Seeds"));
00593 if (seeds <= 18)
00594 seeds = 18;
00595 else if (seeds > 600)
00596 seeds = 600;
00597
00598 unsigned long * seed = new unsigned long[seeds];
00599 node = df->FirstChild("Seed");
00600 if (node == NULL)
00601 seed[seedc++] = GetRandomSeed();
00602 else {
00603 for (; node != NULL; node = node->NextSibling("Seed")) {
00604 seed[seedc] = GetLong(node);
00605 if (seed[seedc] == 0)
00606 seed[seedc] = GetRandomSeed();
00607
00608 ++seedc;
00609 }
00610 }
00611
00612 node = df->FirstChild("Turn");
00613 Turn = GetLong(node);
00614 if (Turn < 1) {
00615 Message * mess = TheGame->AddMessage("Error: Turn too low");
00616 mess->AddLong("Turn", Turn);
00617 delete [] seed;
00618 return false;
00619 }
00620
00621 node = df->FirstChild("Rules");
00622 if (!node) {
00623 Message * mess = TheGame->AddMessage("Error: Missing section");
00624 mess->AddItem("File name", deffile);
00625 mess->AddItem("Section", "Rules");
00626 delete [] seed;
00627 return false;
00628 }
00629
00630 if (!LoadRules(GetString(node->FirstChild("File")), "", 0.0, false)) {
00631 delete [] seed;
00632 return false;
00633 }
00634
00635 unsigned long randomize;
00636 for (node = df->FirstChild("RaceFile"); node != NULL; node = node->NextSibling("RaceFile")) {
00637 Player * p = new Player(mPlayers.size() + 1);
00638 mPlayers.insert(mPlayers.end(), p);
00639 string file;
00640 file = mFileLoc;
00641 file += GetString(node);
00642 randomize = p->CreateFromFile(file.c_str());
00643 if (randomize < 0) {
00644 delete [] seed;
00645 return false;
00646 } else if (seedc < seeds)
00647 seed[seedc++] = randomize;
00648 }
00649
00650 mNumberOfPlayers = mPlayers.size();
00651 int i;
00652 for (i = 0; i < mNumberOfPlayers; ++i)
00653 mPlayers[i]->SetupRelations();
00654
00655
00656
00657 init_by_array(seed, seedc);
00658 delete [] seed;
00659
00660 const TiXmlNode * cre;
00661 cre = df->FirstChild("Creation");
00662 if (!LoadCreation(cre))
00663 return false;
00664
00665 if (cre == NULL || !mCreation->LoadCreation(cre->FirstChild("UniverseSetup")))
00666 return false;
00667
00668 string NameFile;
00669 NameFile = mFileLoc;
00670 NameFile += GetString(df->FirstChild("PlanetNames"));
00671 if (!mCreation->LoadNames(NameFile.c_str()))
00672 return false;
00673
00674
00675 if (df->FirstChild("Galaxy") != NULL) {
00676 if (!TheGalaxy->ParseNode(df->FirstChild("Galaxy")))
00677 return false;
00678 }
00679
00680 if (mCreation->mWorlds > TheGalaxy->GetPlanetCount()) {
00681
00682 TheGalaxy->Build(mCreation);
00683 }
00684
00685 PlacePlayers();
00686
00687 return true;
00688 }
00689
00690 void Game::PlacePlayers()
00691 {
00692 deque<long> PNums(NumberPlayers());
00693 unsigned int i;
00694
00695 for (i = 0; i < NumberPlayers(); ++i)
00696 PNums[i] = i+1;
00697
00698
00699 Random_Shuffle(PNums.begin(), PNums.end());
00700
00701 for (i = 0; i < NumberPlayers(); ++i) {
00702 TheGalaxy->PlacePlayer(NCGetPlayer(PNums[i]));
00703 }
00704
00705
00706 Planet * hw;
00707 while ((hw = TheGame->GetCreation()->GetNextHW()) != NULL) {
00708 hw->SetBaseNumber(-1);
00709 }
00710 }
00711
00712 bool Game::LoadRules(const char * file, const char * verify, double version, bool checkver)
00713 {
00714 string File;
00715 File = "rules/";
00716 File += file;
00717
00718 if (checkver) {
00719
00720
00721 } else {
00722
00723 }
00724
00725 TiXmlDocument doc(File);
00726 doc.SetCondenseWhiteSpace(false);
00727 if (!doc.LoadFile()) {
00728 Message * mess = TheGame->AddMessage("Error: Cannot open file");
00729 mess->AddItem("File name", File);
00730 return false;
00731 }
00732
00733 const TiXmlNode * rd;
00734 const TiXmlNode * node;
00735
00736 rd = doc.FirstChild("RulesDefination");
00737 if (!rd) {
00738 Message * mess = TheGame->AddMessage("Error: Missing section");
00739 mess->AddItem("File name", File);
00740 mess->AddItem("Section", "RulesDefination");
00741 return false;
00742 }
00743
00744 node = rd->FirstChild("MetaInfo");
00745 if (!node) {
00746 Message * mess = TheGame->AddMessage("Error: Missing section");
00747 mess->AddItem("File name", File);
00748 mess->AddItem("Section", "MetaInfo");
00749 return false;
00750 }
00751
00752 double meta = GetDouble(node->FirstChild("FileVersion"));
00753 if (meta > RULESFILEVERSION + epsilon || meta < RULESFILEVERSION - epsilon) {
00754 Message * mess = TheGame->AddMessage("Warning: Incorrect FileVersion");
00755 mess->AddItem("File name", File);
00756 mess->AddItem("FileVersion", GetString(node->FirstChild("FileVersion")));
00757 return false;
00758 }
00759
00760 meta = GetDouble(node->FirstChild("RulesVersion"));
00761 if (checkver) {
00762 if (meta > version + epsilon || meta < version - epsilon) {
00763 Message * mess = TheGame->AddMessage("Warning: Incorrect RulesVersion");
00764 mess->AddItem("File name", File);
00765 mess->AddItem("RulesVersion", GetString(node->FirstChild("RulesVersion")));
00766 return false;
00767 }
00768 } else {
00769 version = meta;
00770 }
00771
00772 if (!Rules::LoadRules(rd->FirstChild("Rules"), file, verify, version))
00773 return false;
00774
00775 if (!LoadRacialTraits(rd->FirstChild("RacialTraits")))
00776 return false;
00777
00778 if (!LoadComponents(rd->FirstChild("Components")))
00779 return false;
00780
00781 if (mCreation) {
00782 if (!LoadStartShips(rd->FirstChild("RacialTraits")))
00783 return false;
00784 }
00785
00786 return true;
00787 }
00788
00789 bool Game::LoadXYFile()
00790 {
00791 string File;
00792 File = mFileLoc;
00793 File += mFileName;
00794 File += ".xy";
00795
00796 TiXmlDocument doc(File);
00797 doc.SetCondenseWhiteSpace(false);
00798 if (!doc.LoadFile()) {
00799 Message * mess = TheGame->AddMessage("Error: Cannot open file");
00800 mess->AddItem("File name", File);
00801 return false;
00802 }
00803
00804 const TiXmlNode * xy;
00805 const TiXmlNode * node;
00806
00807 xy = doc.FirstChild("XYFile");
00808 if (!xy) {
00809 Message * mess = TheGame->AddMessage("Error: Missing section");
00810 mess->AddItem("File name", File);
00811 mess->AddItem("Section", "XYFile");
00812 return false;
00813 }
00814
00815 if (!Game::CheckMetaInfo(xy, File.c_str(), XYFILEVERSION))
00816 return false;
00817
00818 long id = GetLong(xy->FirstChild("GameID"));
00819 if (id != TheGame->GetGameID()) {
00820 Message * mess = TheGame->AddMessage("Error: Missmatched Game IDs");
00821 mess->AddLong("Host file GameID", mGameID);
00822 mess->AddLong("XY file GameID", id);
00823 return false;
00824 }
00825
00826 node = xy->FirstChild("Rules");
00827 if (!node) {
00828 Message * mess = TheGame->AddMessage("Error: Missing section");
00829 mess->AddItem("File name", File);
00830 mess->AddItem("Section", "Rules");
00831 return false;
00832 }
00833
00834 if (!LoadRules( GetString(node->FirstChild("File")),
00835 GetString(node->FirstChild("Verification")),
00836 GetDouble(node->FirstChild("Version")), true))
00837 {
00838 return false;
00839 }
00840
00841 if (!LoadCreation(xy->FirstChild("Creation")))
00842 return false;
00843
00844 if (!TheGalaxy->ParseNode(xy->FirstChild("Galaxy")))
00845 return false;
00846
00847 return true;
00848 }
00849
00850 void Game::WriteXYFile()
00851 {
00852 cout << "Writing XYfile File" << endl;
00853
00854 TiXmlDocument doc;
00855 doc.SetCondenseWhiteSpace(false);
00856
00857 TiXmlDeclaration decl("1.0", "", "yes");
00858 doc.InsertEndChild(decl);
00859
00860 TiXmlElement * XYFile = new TiXmlElement("XYFile");
00861 TiXmlElement * MetaInfo = new TiXmlElement("MetaInfo");
00862 AddDouble(MetaInfo, "FreeStarsVersion", FREESTARSVERSION);
00863 AddDouble(MetaInfo, "FileVersion", HOSTFILEVERSION);
00864 XYFile->LinkEndChild(MetaInfo);
00865 AddLong(XYFile, "GameID", TheGame->GetGameID());
00866 Rules::WriteRulesFile(XYFile);
00867
00868 TiXmlElement * cre = new TiXmlElement("Creation");
00869 AddString(cre, "GameName", Name.c_str());
00870 AddDouble(cre, "TechAdvances", TechFactor);
00871
00872 TiXmlElement * size = new TiXmlElement("Size");
00873 AddLong(size, "MinX", TheGalaxy->MinX());
00874 AddLong(size, "MaxX", TheGalaxy->MaxX());
00875 AddLong(size, "MinY", TheGalaxy->MinY());
00876 AddLong(size, "MaxY", TheGalaxy->MaxY());
00877 cre->LinkEndChild(size);
00878
00879 TiXmlElement * re = new TiXmlElement("RandomEvents");
00880 AddLong(re, "Start", RandomEventsStart);
00881 if (mRandomEvents == RE_ALL)
00882 AddString(re, "Event", "All");
00883 else {
00884 if (mRandomEvents & RE_MT)
00885 AddString(re, "Event", "Mystery Trader");
00886 if (mRandomEvents & RE_ARTIFACT)
00887 AddString(re, "Event", "Artifacts");
00888 if (mRandomEvents & RE_COMET)
00889 AddString(re, "Event", "Comets");
00890 if (mRandomEvents & RE_WORMHOLE) {
00891 AddString(re, "Event", "Wormholes");
00892 TiXmlElement * wh = new TiXmlElement("Wormholes");
00893 AddLong(wh, "MinimumPairs", mWHMin);
00894 AddLong(wh, "MaximumPairs", mWHMax);
00895 AddLong(wh, "MinDistance", mWHMinDistance);
00896 re->LinkEndChild(wh);
00897 }
00898 }
00899 cre->LinkEndChild(re);
00900
00901 TiXmlElement * ps = new TiXmlElement("PublicScores");
00902 AddLong(ps, "Start", PublicScoreStart);
00903 if (PublicScore == PPS_ALL)
00904 AddString(ps, "Category", "All");
00905 else {
00906 if (mRandomEvents & PPS_PLANET)
00907 AddString(ps, "Category", "Planets");
00908 if (mRandomEvents & PPS_BASES)
00909 AddString(ps, "Category", "Bases");
00910 if (mRandomEvents & PPS_UNARM)
00911 AddString(ps, "Category", "Unarmed Ships");
00912 if (mRandomEvents & PPS_ESCORT)
00913 AddString(ps, "Category", "Escort Ships");
00914 if (mRandomEvents & PPS_CAPSHIP)
00915 AddString(ps, "Category", "Capital Ships");
00916 if (mRandomEvents & PPS_TECH)
00917 AddString(ps, "Category", "Tech Levels");
00918 if (mRandomEvents & PPS_RESOURCE)
00919 AddString(ps, "Category", "Resources");
00920 if (mRandomEvents & PPS_SCORE)
00921 AddString(ps, "Category", "Score");
00922 if (mRandomEvents & PPS_RANK)
00923 AddString(ps, "Category", "Rank");
00924 }
00925 cre->LinkEndChild(ps);
00926
00927 TiXmlElement * vc = new TiXmlElement("VictoryConditions");
00928 AddLong(vc, "WinnerConditions", VCCount);
00929 AddLong(vc, "MinimumYears", VCStart);
00930 if (VCWorlds > 0)
00931 AddLong(vc, "ControledWorlds", VCWorlds);
00932 if (VCTechLevel > 0) {
00933 TiXmlElement * tl = new TiXmlElement("TechLevels");
00934 AddLong(tl, "Level", VCTechLevel);
00935 AddLong(tl, "Number", VCTechCount);
00936 vc->LinkEndChild(tl);
00937 }
00938 if (VCScore > 0)
00939 AddLong(vc, "Score", VCScore);
00940 if (VCTimes2nd > 0.0)
00941 AddDouble(vc, "OverSecond", VCTimes2nd);
00942 if (VCResources > 0)
00943 AddLong(vc, "Resources", VCResources);
00944 if (VCCapShips > 0)
00945 AddLong(vc, "CapShips", VCCapShips);
00946 if (VCHighScoreAt > 0)
00947 AddLong(vc, "HighestScoreAt", VCHighScoreAt);
00948 cre->LinkEndChild(vc);
00949
00950 Rules::WriteMinSettings(cre);
00951 XYFile->LinkEndChild(cre);
00952
00953 TiXmlElement * galaxy = new TiXmlElement("Galaxy");
00954 TheGalaxy->WriteXYFile(galaxy);
00955 XYFile->LinkEndChild(galaxy);
00956 doc.LinkEndChild(XYFile);
00957
00958
00959 string File;
00960
00961 File = mFileLoc;
00962 File += mFileName;
00963 File += ".xy";
00964 doc.SaveFile(File);
00965 }
00966
00967 bool Game::WriteHostFile()
00968 {
00969 cout << "Writing Host File" << endl;
00970
00971 deque<Player *>::const_iterator pi;
00972
00973 TiXmlDocument doc;
00974 doc.SetCondenseWhiteSpace(false);
00975
00976 TiXmlDeclaration decl("1.0", "", "yes");
00977 doc.InsertEndChild(decl);
00978
00979 TiXmlElement HostFile("HostFile");
00980 TiXmlElement MetaInfo("MetaInfo");
00981 AddDouble(&MetaInfo, "FreeStarsVersion", FREESTARSVERSION);
00982 AddDouble(&MetaInfo, "FileVersion", HOSTFILEVERSION);
00983 HostFile.InsertEndChild(MetaInfo);
00984
00985 AddLong(&HostFile, "GameID", TheGame->GetGameID());
00986 AddLong(&HostFile, "Turn", Turn);
00987 AddLong(&HostFile, "NumberOfPlayers", mNumberOfPlayers);
00988
00989 for (pi = mPlayers.begin(); pi != mPlayers.end(); ++pi) {
00990 TiXmlElement player("Player");
00991 (*pi)->WriteNode(&player, NULL);
00992
00993 HostFile.InsertEndChild(player);
00994 }
00995
00996 TiXmlElement galaxy("Galaxy");
00997 TheGalaxy->WriteNode(&galaxy, NULL);
00998 HostFile.InsertEndChild(galaxy);
00999
01000 TiXmlElement eMess("ErrorMessages");
01001 for (unsigned int i = 0; i < mMessages.size(); ++i)
01002 mMessages[i]->WriteNode(&eMess);
01003
01004 for (pi = mPlayers.begin(); pi != mPlayers.end(); ++pi) {
01005 TiXmlElement player("Player");
01006 AddLong(&player, "PlayerNumber", (*pi)->GetID());
01007 (*pi)->WriteMessages(&player, "Error");
01008 eMess.InsertEndChild(player);
01009 }
01010 HostFile.InsertEndChild(eMess);
01011
01012 doc.InsertEndChild(HostFile);
01013
01014
01015 string File;
01016
01017 File = mFileLoc;
01018 File += mFileName;
01019 File += ".hstnew";
01020 doc.SaveFile(File);
01021
01022
01023
01024
01025 return true;
01026 }
01027
01028 void Game::UpdateLoadBy()
01029 {
01030 int i, j, l;
01031 CargoHolder * other;
01032 bool pickpocket;
01033
01034
01035 for (i = 0; i < mTopObjects.size(); ++i) for (j = 0; j < mTopObjects[i]->size(); ++j) {
01036 Fleet * fleet = dynamic_cast<Fleet *>(mTopObjects[i]->at(j));
01037 if (fleet == NULL)
01038 continue;
01039
01040 pickpocket = fleet->CanStealShip();
01041
01042
01043 for (l = 0; l < mTopObjects[i]->size(); ++l) {
01044 other = mTopObjects[i]->at(l);
01045 if (fleet->GetOwner() != other->GetOwner()) {
01046 if (l == 0 && dynamic_cast<Planet *>(other) != NULL) {
01047 if (fleet->CanStealPlanet() || (fleet->GetFirstOrder()->GetType() == OT_REMOTEMINE && other->GetOwner() == NULL))
01048 other->SetCanLoadBy(fleet->GetOwner());
01049 } else if (pickpocket)
01050 other->SetCanLoadBy(fleet->GetOwner());
01051 }
01052 }
01053 }
01054 }
01055
01056 void Game::UpdateSeen()
01057 {
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078 int i, j, k, l;
01079 long pen;
01080 long space;
01081 double mradius;
01082 CargoHolder * viewer;
01083 CargoHolder * other;
01084 long inorbit;
01085 Planet * planet = NULL;
01086 MineField * mine;
01087 double dist, cloakdist;
01088
01089
01090 for (i = 0; i < mTopObjects.size(); ++i) for (j = 0; j < mTopObjects[i]->size(); ++j) {
01091
01092 viewer = mTopObjects[i]->at(j);
01093 mine = dynamic_cast<MineField *>(viewer);
01094 if (mine != NULL)
01095 mradius = mine->GetRadius();
01096 else
01097 mradius = -1;
01098
01099 pen = viewer->GetScanPen();
01100 space = viewer->GetScanSpace();
01101
01102 if (pen < 0 && space < 0 && mradius < 0)
01103 continue;
01104
01105 if (space >= 0) {
01106
01107 for (l = 0; l < mTopObjects[i]->size(); ++l) if (j != l) {
01108 other = mTopObjects[i]->at(l);
01109 if (viewer->GetOwner() != other->GetOwner())
01110 other->SetSeenBy(viewer->GetOwner()->GetID()-1, pen >= 0 ? SEEN_PENSCAN : SEEN_SCANNER);
01111 }
01112 }
01113
01114 if (pen <= 0 && space <= 0 && mradius < epsilon)
01115 continue;
01116
01117
01118 for (k = 0; k < mTopObjects.size(); ++k) if (k != i) {
01119
01120 dist = viewer->Distance(*mTopObjects[k]->at(0));
01121 if (dist > pen && dist > space)
01122 continue;
01123
01124 inorbit = -1;
01125 planet = NULL;
01126
01127
01128
01129 for (l = 0; l < mTopObjects[k]->size(); ++l) {
01130 other = mTopObjects[k]->at(l);
01131 if (l == 0) {
01132 planet = dynamic_cast<Planet *>(other);
01133 inorbit = planet != NULL;
01134 }
01135
01136 if (dist < mradius) {
01137 if (space >= 0 || pen >= 0)
01138 viewer->SetSeenBy(other->GetOwner()->GetID()-1, SEEN_SCANNER);
01139
01140 if (!planet && viewer->GetOwner()->MineFieldScanning() && Random(100) > other->GetCloak(viewer->GetOwner(), false))
01141 other->SetSeenBy(viewer->GetOwner()->GetID()-1, SEEN_SCANNER);
01142 }
01143
01144 cloakdist = dist / (1.0 - other->GetCloak(viewer->GetOwner(), true) * viewer->GetMaxTachyon());
01145 if (cloakdist < pen) {
01146
01147 if (planet != NULL && planet->GetOwner() && planet->GetBaseNumber() >= 0) {
01148 cloakdist = dist/ (1.0 - Rules::CloakValue(planet->GetBaseDesign()->GetCloaking(), planet->GetBaseDesign()->GetMass()) * viewer->GetMaxTachyon());
01149 if (cloakdist < pen)
01150 planet->SetSeenBy(viewer->GetOwner()->GetID()-1, SEEN_PENSCAN | SEEN_HULL);
01151 }
01152
01153 other->SetSeenBy(viewer->GetOwner()->GetID()-1, (l == 0 && planet) ? SEEN_PENSCAN : (SEEN_PENSCAN | SEEN_HULL));
01154 } else {
01155 cloakdist = dist / (1.0 - other->GetCloak(viewer->GetOwner(), false) * viewer->GetMaxTachyon());
01156 if (cloakdist < space) {
01157 if (inorbit == -1)
01158 inorbit = dynamic_cast<Planet *>(mTopObjects[k]->at(0)) != NULL ? 1 : 0;
01159
01160 if (inorbit == 0 ||
01161 dynamic_cast<MineField *>(other) != NULL ||
01162 dynamic_cast<Packet *>(other) != NULL)
01163 {
01164
01165 other->SetSeenBy(viewer->GetOwner()->GetID()-1, SEEN_SCANNER);
01166 }
01167 }
01168 }
01169 }
01170 }
01171 }
01172 }
01173
01174 void Game::ResetSeen()
01175 {
01176 int i, j;
01177
01178 for (i = 0; i < mTopObjects.size(); ++i) for (j = 0; j < mTopObjects[i]->size(); ++j)
01179 mTopObjects[i]->at(j)->ResetSeen();
01180
01181 for (i = 0; i < mPlayers.size(); ++i)
01182 mPlayers[i]->ResetSeen();
01183 }
01184
01185 bool Game::WritePlayerFiles()
01186 {
01187 cout << "Writing Player Files" << endl;
01188
01189 deque<Player *>::const_iterator pi;
01190 for (pi = mPlayers.begin(); pi != mPlayers.end(); ++pi) {
01191 TiXmlDocument doc;
01192 doc.SetCondenseWhiteSpace(false);
01193
01194 TiXmlDeclaration decl("1.0", "", "yes");
01195 doc.InsertEndChild(decl);
01196
01197 TiXmlElement TurnFile("PlayerTurnFile");
01198
01199 TiXmlElement MetaInfo("MetaInfo");
01200 AddDouble(&MetaInfo, "FreeStarsVersion", FREESTARSVERSION);
01201 AddDouble(&MetaInfo, "FileVersion", TURNFILEVERSION);
01202 TurnFile.InsertEndChild(MetaInfo);
01203
01204 AddLong(&TurnFile, "GameID", TheGame->GetGameID());
01205 AddLong(&TurnFile, "Turn", Turn);
01206 AddLong(&TurnFile, "NumberOfPlayers", mNumberOfPlayers);
01207
01208 TiXmlElement player("Player");
01209 (*pi)->WriteNode(&player, *pi);
01210 TurnFile.InsertEndChild(player);
01211
01212 TiXmlElement galaxy("Galaxy");
01213 TheGalaxy->WriteNode(&galaxy, *pi);
01214 TurnFile.InsertEndChild(galaxy);
01215
01216 deque<Player *>::const_iterator pi2;
01217 for (pi2 = mPlayers.begin(); pi2 != mPlayers.end(); ++pi2) {
01218 if (*pi != *pi2) {
01219 TiXmlElement player("Player");
01220 if ((*pi2)->WriteNode(&player, *pi))
01221 TurnFile.InsertEndChild(player);
01222 }
01223 }
01224
01225 TiXmlElement eMess("Messages");
01226 (*pi)->WriteMessages(&eMess, "");
01227 TurnFile.InsertEndChild(eMess);
01228
01229 doc.InsertEndChild(TurnFile);
01230
01231 char buf[1024];
01232 sprintf(buf, "%s%s.m%ldnew", mFileLoc.c_str(), mFileName.c_str(), long(pi - mPlayers.begin() + 1));
01233 doc.SaveFile(buf);
01234 }
01235
01236
01237
01238
01239 return true;
01240 }
01241
01242 bool Game::LoadTurns()
01243 {
01244 deque<long> PNums(NumberPlayers());
01245 unsigned int i;
01246
01247 for (i = 0; i < NumberPlayers(); ++i)
01248 PNums[i] = i;
01249
01250
01251 Random_Shuffle(PNums.begin(), PNums.end());
01252
01253 for (i = 0; i < NumberPlayers(); ++i) {
01254 if (!ProcessWaypoints(i))
01255 return false;
01256 }
01257
01258 for (i = 0; i < NumberPlayers(); ++i) {
01259 if (!ProcessOrders(PNums[i]))
01260 return false;
01261 }
01262
01263 if (!AssignWaypoints())
01264 return false;
01265
01266 return true;
01267 }
01268
01269 bool Game::ProcessWaypoints(long pnumber)
01270 {
01271 string File;
01272 File = mFileLoc;
01273 File += mFileName;
01274 File += ".x" + Long2String(pnumber+1);
01275
01276 Player * player = mPlayers[pnumber];
01277
01278 TiXmlDocument doc(File.c_str());
01279 doc.SetCondenseWhiteSpace(false);
01280 if (!doc.LoadFile()) {
01281 Message * mess = TheGame->AddMessage("Error: Cannot open file");
01282 mess->AddItem("File name", File);
01283 return false;
01284 }
01285
01286 const TiXmlNode * orders;
01287 const TiXmlNode * node;
01288 orders = doc.FirstChild("OrdersFile");
01289 if (!orders) {
01290 Message * mess = TheGame->AddMessage("Error: Missing section");
01291 mess->AddItem("File name", File);
01292 mess->AddItem("Section", "OrdersFile");
01293 return false;
01294 }
01295
01296 if (!Game::CheckMetaInfo(orders, File.c_str(), ORDERSFILEVERSION))
01297 return false;
01298
01299 long id = GetLong(orders->FirstChild("GameID"));
01300 if (id != TheGame->GetGameID()) {
01301 Message * mess = TheGame->AddMessage("Error: Missmatched Game IDs");
01302 mess->AddLong("Host file GameID", mGameID);
01303 mess->AddLong("Orders file GameID", id);
01304 return false;
01305 }
01306
01307 node = orders->FirstChild("PlayerNo");
01308 if (GetLong(node) != pnumber+1) {
01309 Message * mess = player->AddMessage("Error: Invalid player number");
01310 mess->AddLong("", GetLong(node));
01311 mess->AddItem("File name", File);
01312 return false;
01313 }
01314
01315 node = orders->FirstChild("Turn");
01316 if (GetLong(node) != Turn-1) {
01317 Message * mess = player->AddMessage("Error: Wrong year number in turn file");
01318 mess->AddLong("Turn specified", GetLong(node));
01319 mess->AddLong("Actual turn", Turn);
01320 return false;
01321 }
01322
01323
01324 for (node = orders->FirstChild("Waypoints"); node; node = node->NextSibling("Waypoints")) {
01325 WayOrderList & wol = *mOrders.insert(mOrders.end(),WayOrderList());
01326 wol.SetFleet(GetLong(node->FirstChild("Fleet")));
01327 wol.ParseNode(node, player);
01328 }
01329
01330 return true;
01331 }
01332
01333 bool Game::AssignWaypoints()
01334 {
01335 Player * p;
01336 Fleet * f;
01337 for (int i = 0; i < mOrders.size(); ++i) {
01338 p = NCGetPlayer(mOrders[i].GetPlayer());
01339 if (p == NULL)
01340 return false;
01341
01342 f = p->NCGetFleet(mOrders[i].GetFleet());
01343 if (f == NULL)
01344 return false;
01345
01346 f->ChangeWaypoints(mOrders[i]);
01347 }
01348
01349 return true;
01350 }
01351
01352 bool Game::ProcessOrders(long pnumber)
01353 {
01354 const TiXmlNode * node;
01355
01356 string File;
01357 File = mFileLoc;
01358 File += mFileName;
01359 File += ".x" + Long2String(pnumber+1);
01360
01361 TiXmlDocument doc(File.c_str());
01362 doc.SetCondenseWhiteSpace(false);
01363 if (!doc.LoadFile()) {
01364 Message * mess = mPlayers[pnumber]->AddMessage("Error: Cannot open file");
01365 mess->AddItem("File name", File);
01366 return false;
01367 }
01368
01369 const TiXmlNode * orders;
01370 orders = doc.FirstChild("OrdersFile");
01371 if (!orders) {
01372 Message * mess = mPlayers[pnumber]->AddMessage("Error: Missing section");
01373 mess->AddItem("File name", File);
01374 mess->AddItem("Section", "OrdersFile");
01375 return false;
01376 }
01377
01378 long id = GetLong(orders->FirstChild("GameID"));
01379 if (id != TheGame->GetGameID()) {
01380 Message * mess = TheGame->AddMessage("Error: Missmatched Game IDs");
01381 mess->AddLong("Host file GameID", mGameID);
01382 mess->AddLong("Orders file GameID", id);
01383 return false;
01384 }
01385
01386 node = orders->FirstChild("PlayerNo");
01387 if (GetLong(node) != pnumber+1) {
01388 Message * mess = mPlayers[pnumber]->AddMessage("Error: Invalid player number");
01389 mess->AddLong("", GetLong(node));
01390 mess->AddItem("File name", File);
01391 return false;
01392 }
01393
01394 node = orders->FirstChild("Turn");
01395 if (GetLong(node) != Turn-1) {
01396 Message * mess = mPlayers[pnumber]->AddMessage("Error: Wrong year number in turn file");
01397 mess->AddLong("Turn specified", GetLong(node));
01398 mess->AddLong("Actual turn", Turn);
01399 return false;
01400 }
01401
01402 mPlayers[pnumber]->ParseOrders(orders);
01403
01404 return true;
01405 }
01406
01407 Player * Game::NCGetPlayer(unsigned int n)
01408 {
01409 if (n < 1 || n > mPlayers.size())
01410 return NULL;
01411
01412 return mPlayers[n-1];
01413 }
01414
01415 const RacialTrait * Game::ParsePRT(const char * str) const
01416 {
01417 if (str != NULL && *str != '\0') {
01418 deque<RacialTrait *>::const_iterator iter;
01419 for (iter = mPRTs.begin(); iter != mPRTs.end(); ++iter) {
01420 if (stricmp((*iter)->Name().c_str(), str) == 0)
01421 return *iter;
01422 }
01423 }
01424
01425 return NULL;
01426 }
01427
01428 const RacialTrait * Game::ParseLRT(const char * str) const
01429 {
01430 if (str != NULL && *str != '\0') {
01431 deque<RacialTrait *>::const_iterator iter;
01432 for (iter = mLRTs.begin(); iter != mLRTs.end(); ++iter) {
01433 if (stricmp((*iter)->Name().c_str(), str) == 0)
01434 return *iter;
01435 }
01436 }
01437
01438 return NULL;
01439 }
01440
01441 const Component * Game::ParseComponent(const char * name) const
01442 {
01443 if (name != NULL && *name != '\0') {
01444 deque<Component *>::const_iterator iter;
01445 for (iter = mComponents.begin(); iter != mComponents.end(); ++iter) {
01446 if (stricmp((*iter)->GetName().c_str(), name) == 0)
01447 return *iter;
01448 }
01449 }
01450
01451 return NULL;
01452 }
01453
01454 const Component * Game::GetBestComp(const Player * player, const char * ValueType, bool CheckRad) const
01455 {
01456 long vt = Component::ParseSubType(ValueType, false);
01457 if (vt < 0)
01458 return NULL;
01459 else
01460 return GetBestComp(player, vt, CheckRad);
01461 }
01462
01463 const Component * Game::GetBestComp(const Player * player, long vt, bool CheckRad) const
01464 {
01465 long temp;
01466 long Score = 0;
01467 const Component * Result = NULL;
01468
01469 deque<Component *>::const_iterator iter;
01470 for (iter = mComponents.begin(); iter != mComponents.end(); ++iter) {
01471
01472 if (!(*iter)->IsBuildable(player))
01473 continue;
01474
01475 if (CheckRad && player->RadDamage((*iter)->GetRadiation()) > 0.0)
01476 continue;
01477
01478 temp = Component::GetScore(*iter, vt);
01479 if (temp > Score) {
01480 Result = *iter;
01481 Score = temp;
01482 }
01483 }
01484
01485 return Result;
01486 }
01487
01488 bool Game::ProcessTurn()
01489 {
01490 deque<long> PNums(NumberPlayers());
01491 unsigned int i;
01492
01493 for (i = 0; i < NumberPlayers(); ++i)
01494 PNums[i] = i;
01495
01496
01497 Random_Shuffle(PNums.begin(), PNums.end());
01498
01499
01500 TurnPhase = TP_SCRAPFLEET;
01501 for (i = 0; i < NumberPlayers(); ++i)
01502 mPlayers[i]->ForEachFleet(Fleet::FTScrap, true);
01503
01504
01505 TurnPhase = TP_WAY0_UNLOAD;
01506 for (i = 0; i < NumberPlayers(); ++i)
01507 mPlayers[PNums[i]]->ForEachFleet(Fleet::FTUnload0, true);
01508
01509 TurnPhase = TP_WAY0_COLONIZE;
01510 for (i = 0; i < NumberPlayers(); ++i)
01511 mPlayers[PNums[i]]->ForEachFleet(Fleet::FTColonize0, true);
01512
01513 TurnPhase = TP_WAY0_INVADE;
01514 TheGalaxy->ResolveInvasions();
01515
01516 TurnPhase = TP_WAY0_LOAD;
01517 for (i = 0; i < NumberPlayers(); ++i) {
01518 mPlayers[PNums[i]]->ForEachFleet(Fleet::FTLoad0, false);
01519 mPlayers[PNums[i]]->ForEachFleet(Fleet::FTLoad0, true);
01520 }
01521
01522
01523 TurnPhase = TP_TECH_CHECK1;
01524 for (i = 0; i < NumberPlayers(); ++i)
01525 mPlayers[i]->CheckTechGain();
01526
01527
01528 TurnPhase = TP_MT_MOVE;
01529
01530
01531 TurnPhase = TP_PACKETS1;
01532 TheGalaxy->MovePackets(false);
01533
01534
01535 TurnPhase = TP_DEADCHECK1;
01536 TheGalaxy->DeadCheck();
01537
01538
01539 TurnPhase = TP_MOVEMENT;
01540 long Left = 0;
01541 long Last = -1;
01542
01543
01544 while (Left != Last) {
01545 for (i = 0; i < NumberPlayers(); ++i) {
01546 Last = Left;
01547
01548
01549 Left = mPlayers[i]->ForEachFleet(Fleet::FTMove, true);
01550 }
01551 }
01552
01553
01554 TurnPhase = TP_MOVEMENT_CYCLE;
01555
01556
01557 TurnPhase = TP_FREIGHTER_GROW;
01558 for (i = 0; i < NumberPlayers(); ++i) {
01559 if (mPlayers[i]->FreighterReproduction() > epsilon)
01560 mPlayers[i]->ForEachFleet(Fleet::FTFreighterReproduction, true);
01561 }
01562
01563
01564 TurnPhase = TP_SALVAGEDECAY;
01565 TheGalaxy->DecaySalvage();
01566
01567
01568 TurnPhase = TP_WORMHOLES;
01569 TheGalaxy->JiggleWormholes();
01570
01571
01572 ResetSeen();
01573
01574
01575 TurnPhase = TP_MINES_DETONATE;
01576
01577
01578 this->TurnPhase = TP_MINING;
01579 if (!TheGalaxy->Mine())
01580 return false;
01581
01582 deque<Player *>::iterator pi;
01583
01584 for (i = 0; i < NumberPlayers(); ++i) {
01585 if (mPlayers[i]->ARTechType() >= 0)
01586 mPlayers[i]->ForEachFleet(Fleet::FTRemoteMine, true);
01587 }
01588
01589
01590 this->TurnPhase = TP_PRODUCTION;
01591 TheGalaxy->DoProduction();
01592
01593
01594 TurnPhase = TP_TECH_CHECK2;
01595 for (i = 0; i < NumberPlayers(); ++i)
01596 mPlayers[i]->AddProductionTech();
01597
01598
01599 TurnPhase = TP_SPYBONUS;
01600 for (i = 0; i < NumberPlayers(); ++i) {
01601 if (mPlayers[i]->SpyTechBonus() > epsilon)
01602 TheGalaxy->GainSpyTech(mPlayers[i]);
01603 }
01604
01605
01606 for (i = 0; i < NumberPlayers(); ++i)
01607 mPlayers[i]->ForEachFleet(Fleet::FTRefuel, true);
01608
01609
01610 this->TurnPhase = TP_POPULATION;
01611 TheGalaxy->GrowPop();
01612
01613
01614 TurnPhase = TP_INSTA_PACKETS;
01615 TheGalaxy->MovePackets(true);
01616
01617
01618 TurnPhase = TP_RANDOM_EVENTS;
01619
01620
01621 TurnPhase = TP_DEADCHECK2;
01622 TheGalaxy->DeadCheck();
01623
01624
01625 TurnPhase = TP_BATTLES;
01626 for (i = 0; i < NumberPlayers(); ++i) {
01627 mPlayers[i]->DoBattles();
01628 }
01629
01630
01631 TurnPhase = TP_REMOTE_MINE;
01632 for (i = 0; i < NumberPlayers(); ++i)
01633 mPlayers[PNums[i]]->ForEachFleet(Fleet::FTRemoteMine, false);
01634
01635
01636 TurnPhase = TP_MEET_MT;
01637
01638
01639 TurnPhase = TP_BOMBING;
01640 TheGalaxy->DoBombing();
01641
01642
01643 TurnPhase = TP_REPAIR;
01644 TheGalaxy->RepairBases();
01645 for (i = 0; i < NumberPlayers(); ++i)
01646 mPlayers[i]->ForEachFleet(Fleet::FTRepair, false);
01647
01648
01649 TurnPhase = TP_WAY1_UNLOAD;
01650 for (i = 0; i < NumberPlayers(); ++i)
01651 mPlayers[i]->ForEachFleet(Fleet::FTCheckWaypoint, true);
01652
01653 for (i = 0; i < NumberPlayers(); ++i)
01654 mPlayers[PNums[i]]->ForEachFleet(Fleet::FTUnload1, true);
01655
01656 TurnPhase = TP_WAY1_COLONIZE;
01657 for (i = 0; i < NumberPlayers(); ++i)
01658 mPlayers[PNums[i]]->ForEachFleet(Fleet::FTColonize1, true);
01659
01660 TurnPhase = TP_WAY1_INVADE;
01661 TheGalaxy->ResolveInvasions();
01662
01663
01664
01665 UpdateLoadBy();
01666
01667 TurnPhase = TP_WAY1_LOAD;
01668 for (i = 0; i < NumberPlayers(); ++i) {
01669 mPlayers[PNums[i]]->ForEachFleet(Fleet::FTLoad1, false);
01670 mPlayers[PNums[i]]->ForEachFleet(Fleet::FTLoad1, true);
01671 }
01672
01673
01674 TurnPhase = TP_TECH_CHECK3;
01675 for (i = 0; i < NumberPlayers(); ++i)
01676 mPlayers[i]->CheckTechGain();
01677
01678
01679 TurnPhase = TP_DEADCHECK3;
01680 TheGalaxy->DeadCheck();
01681
01682
01683 TurnPhase = TP_MINELAYING;
01684
01685
01686 TurnPhase = TP_MINEDECAY;
01687
01688
01689 TurnPhase = TP_MINESWEEP;
01690
01691
01692 TurnPhase = TP_TRANSFER;
01693
01694
01695 TurnPhase = TP_MERGE;
01696 for (i = 0; i < NumberPlayers(); ++i)
01697 mPlayers[i]->ForEachFleet(Fleet::FTMerge, true);
01698
01699
01700 TurnPhase = TP_INSTA_TERRAFORM;
01701 TheGalaxy->Instaform();
01702
01703
01704 TurnPhase = TP_REMOTE_TERRAFORM;
01705 for (i = 0; i < NumberPlayers(); ++i)
01706 mPlayers[i]->ForEachFleet(Fleet::FTRemoteTerraform, true);
01707
01708
01709 for (i = 0; i < NumberPlayers(); ++i)
01710 mPlayers[i]->ForEachFleet(Fleet::FTClearWaypoint, true);
01711
01712
01713 UpdateSeen();
01714 TheGalaxy->AdjustWormholeTraverse();
01715
01716
01717 TurnPhase = TP_PATROL;
01718
01719
01720
01721 return true;
01722 }
01723
01724 void Game::InitialSeen()
01725 {
01726 ResetSeen();
01727 UpdateSeen();
01728 }
01729
01730 long Game::GetTerraLimit(const Player * player, HabType ht)
01731 {
01732 long temp;
01733 long Score = 0;
01734
01735 deque<Component *>::const_iterator iter;
01736 for (iter = mComponents.begin(); iter != mComponents.end(); ++iter) {
01737 if ((*iter)->GetType() != CT_TERRAFORM)
01738 continue;
01739
01740 if (!(*iter)->IsBuildable(player))
01741 continue;
01742
01743 if ((*iter)->GetTerraType() == ht || (*iter)->GetTerraType() == -1) {
01744 temp = (*iter)->GetTerraLimit();
01745 if (temp > Score)
01746 Score = temp;
01747 }
01748 }
01749
01750 return Score;
01751 }
01752
01753 double Game::ClosestMinefield(deque<MineField *> *pm, const Location * loc, long dist)
01754 {
01755 double Result = TheGalaxy->MaxX() + TheGalaxy->MaxY();
01756
01757 return Result;
01758 }
01759
01760 double Game::ClosestMinefield(deque<MineField *> *pm, const Location * loc, double px, double py, deque<MineField *> *inmine)
01761 {
01762 double Result = TheGalaxy->MaxX() + TheGalaxy->MaxY();
01763
01764 return Result;
01765 }
01766
01767 deque<CargoHolder *> * Game::GetClosestTop(int x, int y, long max)
01768 {
01769 if (mTopObjects.size() <= 0)
01770 return NULL;
01771
01772 double lowestdist = mTopObjects[0]->at(0)->Distance(x, y);
01773 double dist;
01774 int closest = 0;
01775 int j;
01776 for (j = 1; j < mTopObjects.size(); ++j) {
01777 dist = mTopObjects[j]->at(0)->Distance(x, y);
01778 if (dist < lowestdist) {
01779 lowestdist = dist;
01780 closest = j;
01781 }
01782
01783 if (dist < epsilon)
01784 break;
01785 }
01786
01787 if (max <= 0 || lowestdist < max)
01788 return mTopObjects[closest];
01789 else
01790 return NULL;
01791 }
01792
01793 void Game::AddAlsoHere(CargoHolder * loc)
01794 {
01795 int j;
01796 for (j = 0; j < mTopObjects.size(); ++j) {
01797 if (loc->IsWith(*mTopObjects[j]->at(0)))
01798 break;
01799 }
01800
01801 if (j < mTopObjects.size()) {
01802 assert(find(mTopObjects[j]->begin(), mTopObjects[j]->end(), loc) == mTopObjects[j]->end());
01803 mTopObjects[j]->push_back(loc);
01804 loc->SetAlsoHere(mTopObjects[j]);
01805 } else {
01806 mTopObjects.push_back(new deque<CargoHolder *>(1, loc));
01807 loc->SetAlsoHere(mTopObjects[mTopObjects.size()-1]);
01808 }
01809 }
01810
01811 void Game::RemoveAlsoHere(CargoHolder * loc)
01812 {
01813 deque<CargoHolder *>::iterator i;
01814 deque<CargoHolder *> * deq = loc->GetAlsoHere();
01815
01816 i = find(deq->begin(), deq->end(), loc);
01817 deq->erase(i);
01818
01819 if (deq->size() == 0) {
01820 deque<deque<CargoHolder *> *>::iterator i2;
01821 i2 = find(mTopObjects.begin(), mTopObjects.end(), deq);
01822 mTopObjects.erase(i2);
01823 }
01824 }
01825
01826 void Game::MoveAlsoHere(CargoHolder * loc)
01827 {
01828 deque<CargoHolder *> * deq = loc->GetAlsoHere();
01829
01830 if (loc->IsWith(*deq->at(0)))
01831 return;
01832
01833 RemoveAlsoHere(loc);
01834 AddAlsoHere(loc);
01835 }