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 "Creation.h"
00029
00030 #include <stdlib.h>
00031
00032 #ifdef _DEBUG
00033 #define new DEBUG_NEW
00034 #endif
00035
00036 long Rules::MaxTechType = 0;
00037 unsigned long Rules::MaxTechLevel = 0;
00038 long Rules::MaxHabType = 0;
00039 long Rules::MaxMinType = 0;
00040 long Rules::MaxMineType = 0;
00041 unsigned long Rules::MaxFleets = 512;
00042 long Rules::PopEQ1kT = 100;
00043
00044
00045 map<string, long, less<string> > Rules::Consts;
00046 map<string, double, less<string> > Rules::Floats;
00047 map<string, Array<long> *, less<string> > Rules::Arrays;
00048 map<string, Array<double> *, less<string> > Rules::FloatArrays;
00049
00050 deque<unsigned long> Rules::TechCost;
00051 deque<string> Rules::TechName;
00052 deque<string> Rules::HabName;
00053 deque<string> Rules::MinName;
00054 deque<string> Rules::MineName;
00055
00056 string * Rules::ModFileName = NULL;
00057 double Rules::ModFileVersion = 0.0;
00058 string * Rules::ModFileCRC = NULL;
00059
00060 deque<deque<long> *> Rules::mHabOdds;
00061 deque<long> Rules::mMinMC;
00062 deque<long> Rules::mMaxMC;
00063 deque<long> Rules::mHWMinMC;
00064 deque<long> Rules::mHWMaxMC;
00065 deque<long> Rules::mHWFloorMC;
00066 deque<long> Rules::mHWSetupMC;
00067 deque<long> Rules::mHWSetupSM;
00068
00069
00070 void Rules::Init()
00071 {
00072 }
00073
00074 void Rules::Cleanup()
00075 {
00076 int i;
00077 for (i = 0; i < mHabOdds.size(); ++i)
00078 delete mHabOdds[i];
00079 mHabOdds.clear();
00080
00081 TechCost.clear();
00082 TechName.clear();
00083 HabName.clear();
00084 MinName.clear();
00085 MineName.clear();
00086
00087 Consts.clear();
00088 Floats.clear();
00089 map<string, Array<long> *, less<string> >::iterator iml;
00090 for (iml = Arrays.begin(); iml != Arrays.end(); ++iml)
00091 delete iml->second;
00092 Arrays.clear();
00093
00094 map<string, Array<double> *, less<string> >::iterator imd;
00095 for (imd = FloatArrays.begin(); imd != FloatArrays.end(); ++imd)
00096 delete imd->second;
00097 FloatArrays.clear();
00098
00099 delete ModFileName;
00100 delete ModFileCRC;
00101 mMinMC.clear();
00102 mMaxMC.clear();
00103 mHWMinMC.clear();
00104 mHWMaxMC.clear();
00105 mHWFloorMC.clear();
00106 mHWSetupMC.clear();
00107 mHWSetupSM.clear();
00108 }
00109
00110 bool Rules::TechScrap(const Planet * planet)
00111 {
00112 if (planet &&
00113 planet->GetOwner() &&
00114 planet->GetBaseNumber() >= 0 &&
00115 !planet->GetOwner()->HasGotTech() &&
00116 Randodd(GetFloat("TechEventChance")))
00117 {
00118 return true;
00119 } else
00120 return false;
00121 }
00122
00123 TechType Rules::TechFleet(const Player * player, const Fleet * fleet)
00124 {
00125 TechType TechGot = TECH_NONE;
00126
00127
00128 if (!player->HasGotTech() && Randodd(GetFloat("TechEventChance")))
00129 {
00130 long Count = 0;
00131 for (long i = 0; i < Rules::MaxTechType; ++i) {
00132
00133 if (player->GetTechLevel(i) < fleet->TechLevel(i) && Randodd(GetFloat("TechFieldChance")))
00134 if (Random(++Count) == 0)
00135 TechGot = i;
00136 }
00137
00138 if (!TechGot) {
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152 }
00153 }
00154
00155 return TechGot;
00156 }
00157
00158 double Rules::ScrapRecover(const Planet * planet, bool colonize)
00159 {
00160 if (planet == NULL)
00161 return 1.0 / 3.0;
00162
00163 double percent;
00164 if (colonize)
00165 percent = .75;
00166 else if (planet->GetBaseNumber() >= 0) {
00167 if (planet->GetOwner()->UltimateRecycle())
00168 percent = .9;
00169 else
00170 percent = .8;
00171 } else {
00172 if (planet->GetOwner() && planet->GetOwner()->UltimateRecycle())
00173 percent = .45;
00174 else
00175 percent = 1.0 / 3.0;
00176 }
00177
00178 return percent;
00179 }
00180
00181 long Rules::ScrapResource(const Planet * planet)
00182 {
00183 long percent;
00184 if (!planet || !planet->GetOwner()->UltimateRecycle())
00185 percent = 0;
00186 else if (planet->GetBaseNumber() >= 0)
00187 percent = 7000;
00188 else
00189 percent = 3500;
00190
00191 return percent;
00192 }
00193
00194 TechType Rules::TechInvasion(Player * invader, const Player * owner)
00195 {
00196 TechType TechGot = TECH_NONE;
00197
00198
00199 if (!invader->HasGotTech() && Randodd(GetFloat("TechEventChance")))
00200 {
00201 long Count = 0;
00202 for (long i = 0; i < Rules::MaxTechType; ++i) {
00203
00204 if (invader->GetTechLevel(i) < owner->GetTechLevel(i) && Randodd(GetFloat("TechFieldChance")))
00205 if (Random(++Count) == 0)
00206 TechGot = i;
00207 }
00208 }
00209
00210 return TechGot;
00211 }
00212
00213 bool Rules::Stealable(CargoType ct)
00214 {
00215 return ct != POPULATION;
00216 }
00217
00218 long Rules::CloakValue(long Cloaking, long Mass)
00219 {
00220 long Cloak = Cloaking / Mass;
00221 long percent;
00222 if (Cloak <= 100)
00223 percent = Cloak / 2;
00224 else {
00225 Cloak -= 100;
00226 if (Cloak <= 200)
00227 percent = 50 + Cloak / 8;
00228 else {
00229 Cloak -= 200;
00230 if (Cloak <= 312)
00231 percent = 75 + Cloak / 24;
00232 else {
00233 Cloak -= 312;
00234 if (Cloak <= 512)
00235 percent = 88 + Cloak/64;
00236 else if (Cloak < 768)
00237 percent = 96;
00238 else if (Cloak < 1000)
00239 percent = 97;
00240 else
00241 percent = 98;
00242 }
00243 }
00244 }
00245
00246 return percent;
00247 }
00248
00249 double Rules::CalcScanning(double base, long newscan, long count)
00250 {
00251 double Result = base;
00252 if (newscan > 0)
00253 Result = pow(pow(Result, 4) + pow((double)newscan, 4) * count, 0.25);
00254 else if (newscan == 0 && Result < 0)
00255 Result = 0;
00256
00257 return Result;
00258 }
00259
00260 void Rules::WriteRulesFile(TiXmlNode * node)
00261 {
00262 TiXmlElement rulefile("Rules");
00263 AddString(&rulefile, "File", ModFileName ? ModFileName->c_str() : "");
00264 AddDouble(&rulefile, "Version", ModFileVersion);
00265 AddString(&rulefile, "Verification", ModFileCRC ? ModFileCRC->c_str() : "");
00266 node->InsertEndChild(rulefile);
00267 }
00268
00269 bool Rules::LoadRules(const TiXmlNode * node, const char * file, const char * verify, double version)
00270 {
00271 if (!node)
00272 return false;
00273
00274 ModFileName = new string(file);
00275 ModFileVersion = version;
00276 if (verify)
00277 ModFileCRC = new string(verify);
00278
00279 const TiXmlNode * child1;
00280 const TiXmlElement * el;
00281 const char * ptr;
00282
00283 long val;
00284 double dval;
00285 for (child1 = node->FirstChild(); child1; child1 = child1->NextSibling()) {
00286 if (child1->Type() == TiXmlNode::COMMENT)
00287 continue;
00288
00289 el = child1->ToElement();
00290 if (el == NULL)
00291 continue;
00292
00293 if (stricmp(child1->Value(), "Constant") == 0) {
00294
00295 ptr = el->Attribute("Name");
00296 val = GetLong(child1);
00297 Consts.insert(pair<string, long>(ptr, val));
00298 if (stricmp(ptr, "MaxFleets") == 0)
00299 MaxFleets = val;
00300 else if (stricmp(ptr, "PopEQ1kT") == 0)
00301 PopEQ1kT = val;
00302 } else if (stricmp(child1->Value(), "Float") == 0) {
00303
00304 ptr = el->Attribute("Name");
00305 dval = GetDouble(child1);
00306 Floats.insert(pair<string, double>(ptr, dval));
00307 } else if (stricmp(child1->Value(), "Array") == 0) {
00308
00309 const char * ptr = el->Attribute("Name");
00310 if (ptr == NULL)
00311 continue;
00312
00313 int start;
00314 el->Attribute("Start", &start);
00315 Array<long> * arr = new Array<long>(start);
00316 const TiXmlNode * child2;
00317 for (child2 = child1->FirstChild("Item"); child2; child2 = child2->NextSibling("Item")) {
00318 if (child2->Type() == TiXmlNode::COMMENT)
00319 continue;
00320
00321 arr->AddItem(GetLong(child2));
00322 }
00323 Arrays.insert(pair<string, Array<long> *>(ptr, arr));
00324 } else if (stricmp(child1->Value(), "FloatArray") == 0) {
00325
00326 const char * ptr = el->Attribute("Name");
00327 if (ptr == NULL)
00328 continue;
00329
00330 int start;
00331 el->Attribute("Start", &start);
00332 Array<double> * arr = new Array<double>(start);
00333 const TiXmlNode * child2;
00334 for (child2 = child1->FirstChild("Item"); child2; child2 = child2->NextSibling("Item")) {
00335 if (child2->Type() == TiXmlNode::COMMENT)
00336 continue;
00337
00338 arr->AddItem(GetDouble(child2));
00339 }
00340 FloatArrays.insert(pair<string, Array<double> *>(ptr, arr));
00341 } else if (stricmp(child1->Value(), "TechCost") == 0) {
00342
00343 int level = 0;
00344 el->Attribute("Level", &level);
00345 val = GetLong(child1);
00346 if (static_cast<int>(TechCost.size()) < level)
00347 TechCost.insert(TechCost.end(), level - TechCost.size(), 0);
00348
00349 TechCost[level-1] = val;
00350 MaxTechLevel = max(MaxTechLevel, static_cast<unsigned long>(level));
00351 } else if (stricmp(child1->Value(), "TechName") == 0) {
00352
00353 TechName.insert(TechName.end(), GetString(child1));
00354 ++MaxTechType;
00355 } else if (stricmp(child1->Value(), "Habitat") == 0) {
00356 HabName.insert(HabName.end(), GetString(child1->FirstChild("Name")));
00357 deque<long> * hoa;
00358 hoa = Rules::GetHabOddArray(MaxHabType, true);
00359 ParseArray(child1->FirstChild("Array"), "TickOdds", "TickNumber", *hoa);
00360 long sum = 0;
00361 for (long i = 0; i < hoa->size(); ++i) {
00362 sum += (*hoa)[i];
00363 (*hoa)[i] = sum;
00364 }
00365
00366 ++MaxHabType;
00367 } else if (stricmp(child1->Value(), "MinName") == 0) {
00368 MinName.insert(MinName.end(), GetString(child1));
00369 ++MaxMinType;
00370 } else if (stricmp(child1->Value(), "MineName") == 0) {
00371 MineName.insert(MineName.end(), GetString(child1));
00372 ++MaxMineType;
00373 }
00374 }
00375 return true;
00376 }
00377
00378 long Rules::GetConstant(const string name, long Default )
00379 {
00380 map<string, long, less<string> >::const_iterator im;
00381 im = Consts.find(name);
00382 if (im == Consts.end())
00383 return Default;
00384
00385 return im->second;
00386 }
00387
00388 double Rules::GetFloat(const string name, double Default )
00389 {
00390 map<string, double, less<string> >::const_iterator im;
00391 im = Floats.find(name);
00392 if (im == Floats.end())
00393 return Default;
00394
00395 return im->second;
00396 }
00397
00398 long Rules::GetArrayValue(const string name, int position)
00399 {
00400 map<string, Array<long> *, less<string> >::const_iterator im;
00401 im = Arrays.find(name);
00402 if (im == Arrays.end())
00403 return 0;
00404
00405 return (*im->second)[position];
00406 }
00407
00408 double Rules::GetArrayFloat(const string name, int position)
00409 {
00410 map<string, Array<double> *, less<string> >::const_iterator im;
00411 im = FloatArrays.find(name);
00412 if (im == FloatArrays.end())
00413 return 0;
00414
00415 return (*im->second)[position];
00416 }
00417
00418 long Rules::TechID(const char * name)
00419 {
00420 if (name == NULL || *name == '\0')
00421 return -1;
00422
00423 if (stricmp(name, "Alchemy instead of research") == 0)
00424 return RESEARCH_ALCHEMY;
00425 else if (stricmp(name, "Same field") == 0)
00426 return NEXT_SAME;
00427 else if (stricmp(name, "Lowest field") == 0)
00428 return NEXT_LOW;
00429 else if (stricmp(name, "Cheapest field") == 0)
00430 return NEXT_CHEAP;
00431
00432 deque<string>::const_iterator it;
00433 it = find(TechName.begin(), TechName.end(), name);
00434 if (it == TechName.end())
00435 return TECH_NONE;
00436
00437 return it - TechName.begin();
00438 }
00439
00440 const string Rules::GetTechName(long type)
00441 {
00442 if (type == RESEARCH_ALCHEMY)
00443 return "Alchemy instead of research";
00444 else if (type == NEXT_SAME)
00445 return "Same field";
00446 else if (type == NEXT_LOW)
00447 return "Lowest field";
00448 else if (type == NEXT_CHEAP)
00449 return "Cheapest field";
00450 else if (type >= 0 && type < MaxTechType)
00451 return TechName[type];
00452 else
00453 return "BadName";
00454 }
00455
00456 long Rules::MineralID(const char * name)
00457 {
00458 if (name == NULL || *name == '\0')
00459 return -1;
00460
00461 deque<string>::const_iterator it;
00462 it = find(MinName.begin(), MinName.end(), name);
00463 if (it == MinName.end())
00464 return -1;
00465
00466 return it - MinName.begin();
00467 }
00468
00469 long Rules::HabID(const char * name)
00470 {
00471 if (name == NULL || *name == '\0')
00472 return -1;
00473
00474 deque<string>::const_iterator it;
00475 it = find(HabName.begin(), HabName.end(), name);
00476 if (it == HabName.end())
00477 return -1;
00478
00479 return it - HabName.begin();
00480 }
00481
00482 long Rules::MineID(const char * name)
00483 {
00484 if (name == NULL || *name == '\0')
00485 return -1;
00486
00487 deque<string>::const_iterator it;
00488 it = find(MineName.begin(), MineName.end(), name);
00489 if (it == MineName.end())
00490 return -1;
00491
00492 return it - MineName.begin();
00493 }
00494
00495 void Rules::ReadCargo(const TiXmlNode * node, deque<long> & q, long * pop)
00496 {
00497 deque<long>::iterator li;
00498 if (node == NULL) {
00499 if (pop) *pop = 0;
00500 for (li = q.begin(); li != q.end(); ++li)
00501 *li = 0;
00502 } else {
00503 if (pop) *pop = GetLong(node->FirstChild("Population"));
00504 ParseArray(node, q, MINERALS);
00505 }
00506 }
00507
00508 TiXmlElement * Rules::WriteCargo(TiXmlNode * node, const char * name, const deque<long> &q, long pop)
00509 {
00510 deque<long>::const_iterator lmax, lmin;
00511
00512 lmax = max_element(q.begin(), q.end());
00513 lmin = min_element(q.begin(), q.end());
00514 if (*lmax > 0 || *lmin < 0 || pop != 0 ) {
00515 TiXmlElement * child;
00516 child = WriteArray(name, q, MINERALS);
00517 if (pop != 0)
00518 AddLong(child, "Population", pop);
00519
00520 node->LinkEndChild(child);
00521 return child;
00522 } else
00523 return NULL;
00524 }
00525
00526 long Rules::GetCargoType(const char * name)
00527 {
00528 if (stricmp(name, "Population") == 0 || stricmp(name, "Crew") == 0)
00529 return POPULATION;
00530 else if (stricmp(name, "Fuel") == 0)
00531 return FUEL;
00532 else if (stricmp(name, "Resources") == 0)
00533 return RESOURCES;
00534 else {
00535 long result = MineralID(name);
00536 if (result < 0) {
00537 Message * mess = TheGame->AddMessage("Error: Bad cargo type");
00538 mess->AddItem("", name);
00539 }
00540
00541 return result;
00542 }
00543 }
00544
00545 const string Rules::GetCargoName(long type)
00546 {
00547 if (type == POPULATION)
00548 return "Population";
00549 else if (type == FUEL)
00550 return "Fuel";
00551 else {
00552 if (type >= 0 && type < MaxMinType)
00553 return MinName[type];
00554 else
00555 return "BadName";
00556 }
00557 }
00558
00559 TiXmlElement * Rules::WriteArray(const char * node, const deque<long> & q, long Type)
00560 {
00561 if (Type == MINERALS)
00562 return WriteArray(node, "Mineral", "Name", q, &MinName);
00563 else if (Type == TECHS)
00564 return WriteArray(node, "Tech", "Name", q, &TechName);
00565 else if (Type == HABS)
00566 return WriteArray(node, "Hab", "Name", q, &HabName);
00567 else if (Type == MINES)
00568 return WriteArray(node, "Mine", "Type", q, &MineName);
00569 else {
00570 assert(false);
00571 return NULL;
00572 }
00573 }
00574
00575 TiXmlElement * Rules::WriteArrayFloat(const char * node, const deque<double> & q, long Type)
00576 {
00577 if (Type == MINERALS)
00578 return WriteArrayFloat(node, "Mineral", "Name", q, &MinName);
00579 else if (Type == TECHS)
00580 return WriteArrayFloat(node, "Tech", "Name", q, &TechName);
00581 else if (Type == HABS)
00582 return WriteArrayFloat(node, "Hab", "Name", q, &HabName);
00583 else if (Type == MINES)
00584 return WriteArrayFloat(node, "Mine", "Type", q, &MineName);
00585 else {
00586 assert(false);
00587 return NULL;
00588 }
00589 }
00590
00591 TiXmlElement * Rules::WriteArrayBool(const char * node, const char * name, const char * Attrib, const deque<bool> & arr, const deque<string> * desc )
00592 {
00593 TiXmlElement * result;
00594 result = new TiXmlElement(node);
00595 for (unsigned int i = 0; i < arr.size(); ++i) {
00596 TiXmlElement txe(name);
00597 if (desc == NULL)
00598 txe.SetAttribute(Attrib, i+1);
00599 else
00600 txe.SetAttribute(Attrib, (*desc)[i]);
00601
00602 TiXmlText txt(arr[i] ? "True" : "False");
00603 txe.InsertEndChild(txt);
00604 result->InsertEndChild(txe);
00605 }
00606 return result;
00607 }
00608
00609 TiXmlElement * Rules::WriteArray(const char * node, const char * name, const char * Attrib, const deque<long> & arr, const deque<string> * desc )
00610 {
00611 TiXmlElement * result;
00612 result = new TiXmlElement(node);
00613 for (unsigned int i = 0; i < arr.size(); ++i) {
00614 TiXmlElement txe(name);
00615 if (desc == NULL)
00616 txe.SetAttribute(Attrib, i+1);
00617 else
00618 txe.SetAttribute(Attrib, (*desc)[i]);
00619
00620 TiXmlText txt(Long2String(arr[i]));
00621 txe.InsertEndChild(txt);
00622 result->InsertEndChild(txe);
00623 }
00624 return result;
00625 }
00626
00627 TiXmlElement * Rules::WriteArrayFloat(const char * node, const char * name, const char * Attrib, const deque<double> & arr, const deque<string> * desc )
00628 {
00629 TiXmlElement * result;
00630 result = new TiXmlElement(node);
00631 for (unsigned int i = 0; i < arr.size(); ++i) {
00632 TiXmlElement txe(name);
00633 if (desc == NULL)
00634 txe.SetAttribute(Attrib, i+1);
00635 else
00636 txe.SetAttribute(Attrib, (*desc)[i]);
00637
00638 TiXmlText txt(Float2String(arr[i]));
00639 txe.InsertEndChild(txt);
00640 result->InsertEndChild(txe);
00641 }
00642 return result;
00643 }
00644
00645 bool Rules::ParseArray(const TiXmlNode * node, deque<long> & q, long Type)
00646 {
00647 if (Type == MINERALS)
00648 return ParseArray(node, "Mineral", "Name", q, &MinName);
00649 else if (Type == TECHS)
00650 return ParseArray(node, "Tech", "Name", q, &TechName);
00651 else if (Type == HABS)
00652 return ParseArray(node, "Hab", "Name", q, &HabName);
00653 else if (Type == MINES)
00654 return ParseArray(node, "Mine", "Type", q, &MineName);
00655 else
00656 return false;
00657 }
00658
00659 bool Rules::ParseArrayFloat(const TiXmlNode * node, deque<double> & q, long Type)
00660 {
00661 if (Type == MINERALS)
00662 return ParseArrayFloat(node, "Mineral", "Name", q, &MinName);
00663 else if (Type == TECHS)
00664 return ParseArrayFloat(node, "Tech", "Name", q, &TechName);
00665 else if (Type == HABS)
00666 return ParseArrayFloat(node, "Hab", "Name", q, &HabName);
00667 else if (Type == MINES)
00668 return ParseArrayFloat(node, "Mine", "Type", q, &MineName);
00669 else
00670 return false;
00671 }
00672
00673 bool Rules::ParseArrayBool(const TiXmlNode * node, const char * name, const char * Attrib, deque<bool> & arr, const deque<string> * desc )
00674 {
00675 if (!node)
00676 return false;
00677
00678 bool IsOK = true;
00679 const TiXmlNode * child;
00680 for (child = node->FirstChild(name); child; child = child->NextSibling(name)) {
00681 const TiXmlElement * el = child->ToElement();
00682 if (el == NULL) {
00683 Message * mess = TheGame->AddMessage("Error: Invalid element in ParseArrayBool");
00684 mess->AddItem("", name);
00685 IsOK = false;
00686 continue;
00687 }
00688
00689 unsigned int index;
00690 if (desc == NULL) {
00691 el->Attribute(Attrib, (int*)(&index));
00692 } else {
00693 const char * type;
00694 type = el->Attribute(Attrib);
00695 if (type == NULL) {
00696 Message * mess = TheGame->AddMessage("Error: Invalid attribute in ParseArrayBool");
00697 mess->AddItem(name, Attrib);
00698 IsOK = false;
00699 continue;
00700 }
00701
00702 deque<string>::const_iterator in;
00703 in = find(desc->begin(), desc->end(), type);
00704 if (in == desc->end()) {
00705 Message * mess = TheGame->AddMessage("Error: Invalid attribute in ParseArrayBool");
00706 mess->AddItem(name, Attrib);
00707 IsOK = false;
00708 continue;
00709 }
00710
00711 index = in - desc->begin() + 1;
00712 }
00713
00714 if (index < 1 || index > arr.size()) {
00715 Message * mess = TheGame->AddMessage("Error: Invalid index in ParseArrayBool");
00716 mess->AddLong(name, index);
00717 IsOK = false;
00718 continue;
00719 }
00720
00721 arr[index-1] = GetBool(child);
00722 }
00723
00724 return IsOK;
00725 }
00726
00727 bool Rules::ParseArray(const TiXmlNode * node, const char * name, const char * Attrib, deque<long> & arr, const deque<string> * desc )
00728 {
00729 if (!node)
00730 return false;
00731
00732 bool IsOK = true;
00733 const TiXmlNode * child;
00734 for (child = node->FirstChild(name); child; child = child->NextSibling(name)) {
00735 const TiXmlElement * el = child->ToElement();
00736 if (el == NULL) {
00737 Message * mess = TheGame->AddMessage("Error: Invalid element in ParseArray");
00738 mess->AddItem("", name);
00739 IsOK = false;
00740 continue;
00741 }
00742
00743 unsigned int index;
00744 if (desc == NULL) {
00745 el->Attribute(Attrib, (int*)(&index));
00746 } else {
00747 const char * type;
00748 type = el->Attribute(Attrib);
00749 if (type == NULL) {
00750 Message * mess = TheGame->AddMessage("Error: Invalid attribute in ParseArray");
00751 mess->AddItem(name, Attrib);
00752 IsOK = false;
00753 continue;
00754 }
00755
00756 deque<string>::const_iterator in;
00757 in = find(desc->begin(), desc->end(), type);
00758 if (in == desc->end()) {
00759 Message * mess = TheGame->AddMessage("Error: Invalid attribute in ParseArray");
00760 mess->AddItem(name, Attrib);
00761 IsOK = false;
00762 continue;
00763 }
00764
00765 index = in - desc->begin() + 1;
00766 }
00767
00768 if (index < 1 || index > arr.size()) {
00769 Message * mess = TheGame->AddMessage("Error: Invalid index in ParseArray");
00770 mess->AddLong(name, index);
00771 IsOK = false;
00772 continue;
00773 }
00774
00775 arr[index-1] = GetLong(child);
00776 }
00777
00778 return IsOK;
00779 }
00780
00781 bool Rules::ParseArrayFloat(const TiXmlNode * node, const char * name, const char * Attrib, deque<double> & arr, const deque<string> * desc )
00782 {
00783 if (!node)
00784 return false;
00785
00786 bool IsOK = true;
00787 const TiXmlNode * child;
00788 for (child = node->FirstChild(name); child; child = child->NextSibling(name)) {
00789 const TiXmlElement * el = child->ToElement();
00790 if (el == NULL) {
00791 Message * mess = TheGame->AddMessage("Error: Invalid element in ParseArray");
00792 mess->AddItem("", name);
00793 IsOK = false;
00794 continue;
00795 }
00796
00797 unsigned int index;
00798 if (desc == NULL) {
00799 el->Attribute(Attrib, (int*)(&index));
00800 } else {
00801 const char * type;
00802 type = el->Attribute(Attrib);
00803 if (type == NULL) {
00804 Message * mess = TheGame->AddMessage("Error: Invalid attribute in ParseArray");
00805 mess->AddItem(name, Attrib);
00806 IsOK = false;
00807 continue;
00808 }
00809
00810 deque<string>::const_iterator in;
00811 in = find(desc->begin(), desc->end(), type);
00812 if (in == desc->end()) {
00813 Message * mess = TheGame->AddMessage("Error: Invalid attribute in ParseArray");
00814 mess->AddItem(name, Attrib);
00815 IsOK = false;
00816 continue;
00817 }
00818
00819 index = in - desc->begin() + 1;
00820 }
00821
00822 if (index < 1 || index > arr.size()) {
00823 Message * mess = TheGame->AddMessage("Error: Invalid index in ParseArray");
00824 mess->AddLong(name, index);
00825 IsOK = false;
00826 continue;
00827 }
00828
00829 arr[index-1] = GetDouble(child);
00830 }
00831
00832 return IsOK;
00833 }
00834
00835 long Rules::RandomHab(HabType ht)
00836 {
00837 deque<long> * hoa = GetHabOddArray(ht, false);
00838
00839 if (hoa == NULL) {
00840
00841 return 50;
00842 }
00843
00844 long rnd = Random((*hoa)[hoa->size() - GetConstant("MinHabValue")]) + 1;
00845
00846
00847
00848 long hig = GetConstant("MaxHabValue") - GetConstant("MinHabValue");
00849 long log = 0;
00850 long g = (log + hig) / 2;
00851 bool done = false;
00852
00853 while (!done) {
00854 g = (log + hig) / 2;
00855
00856 if (g > 0 && rnd <= (*hoa)[g-1])
00857 hig = g - 1;
00858 else if (g < hig && rnd > (*hoa)[g])
00859 log = g + 1;
00860 else
00861 done = true;
00862 }
00863
00864 return g + GetConstant("MinHabValue");
00865 }
00866
00867
00868 long Rules::GetSecondHab(HabType ht, const Player * owner)
00869 {
00870 long Result;
00871 long count = 0;
00872 do {
00873 Result = RandomHab(ht);
00874 } while (count++ < 1000 &&
00875 owner->HabCenter(ht) >= 0 &&
00876 (Result < owner->HabCenter(ht) - owner->HabWidth(ht) ||
00877 Result > owner->HabCenter(ht) + owner->HabWidth(ht))
00878 );
00879
00880 return Result;
00881 }
00882
00883 bool Rules::ParseMinSettings(const TiXmlNode * node)
00884 {
00885 const TiXmlNode * child;
00886 mMinMC.insert(mMinMC.begin(), Rules::MaxMinType, 1);
00887 mMaxMC.insert(mMaxMC.begin(), Rules::MaxMinType, 120);
00888 mHWMinMC.insert(mHWMinMC.begin(), Rules::MaxMinType, 30);
00889 mHWMaxMC.insert(mHWMaxMC.begin(), Rules::MaxMinType, 120);
00890 mHWFloorMC.insert(mHWFloorMC.begin(), Rules::MaxMinType, 30);
00891
00892 child = node->FirstChild("AllWorlds");
00893 if (!child) {
00894 Message * mess = TheGame->AddMessage("Error: Missing section");
00895 mess->AddItem("Section", "Mineral settings - AllWorlds");
00896 return false;
00897 }
00898
00899 if (!ParseArray(child->FirstChild("Minimum"), mMinMC, MINERALS))
00900 return false;
00901
00902 if (!ParseArray(child->FirstChild("Maximum"), mMaxMC, MINERALS))
00903 return false;
00904
00905 child = node->FirstChild("HomeWorlds");
00906 if (!child) {
00907 Message * mess = TheGame->AddMessage("Error: Missing section");
00908 mess->AddItem("Section", "Mineral settings - HomeWorlds");
00909 return false;
00910 }
00911
00912 if (!ParseArray(child->FirstChild("Minimum"), mHWMinMC, MINERALS))
00913 return false;
00914
00915 if (!ParseArray(child->FirstChild("Maximum"), mHWMaxMC, MINERALS))
00916 return false;
00917
00918 if (!ParseArray(child->FirstChild("HWFloor"), mHWFloorMC, MINERALS))
00919 return false;
00920
00921 return true;
00922 }
00923
00924 void Rules::WriteMinSettings(TiXmlNode * node)
00925 {
00926 TiXmlElement minset("MineralSettings");
00927
00928 TiXmlElement All("AllWorlds");
00929 All.LinkEndChild(Rules::WriteArray("Minimum", mMinMC, MINERALS));
00930 All.LinkEndChild(Rules::WriteArray("Maximum", mMaxMC, MINERALS));
00931 minset.InsertEndChild(All);
00932
00933 TiXmlElement HWs("HomeWorlds");
00934 HWs.LinkEndChild(Rules::WriteArray("Minimum", mHWMinMC, MINERALS));
00935 HWs.LinkEndChild(Rules::WriteArray("Maximum", mHWMaxMC, MINERALS));
00936 minset.InsertEndChild(HWs);
00937
00938 minset.LinkEndChild(Rules::WriteArray("HWFloor", mHWFloorMC, MINERALS));
00939 node->InsertEndChild(minset);
00940 }
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975 deque<long> * Rules::GetHabOddArray(HabType ht, bool Create )
00976 {
00977 while (Create && ht >= mHabOdds.size()) {
00978 deque<long> * hoa;
00979 hoa = new deque<long>;
00980 hoa->insert(hoa->begin(), 99, 1);
00981 mHabOdds.push_back(hoa);
00982 }
00983
00984 if (ht >= mHabOdds.size())
00985 return NULL;
00986 else
00987 return mHabOdds[ht];
00988 }
00989
00990
00991 long Rules::GetHWMC(long mintype)
00992 {
00993 if (mHWSetupMC.size() == 0) {
00994 mHWSetupMC.insert(mHWSetupMC.begin(), Rules::MaxMinType, 1);
00995 for (int i = 0; i < Rules::MaxMinType; ++i) {
00996 if (Random(100) < Rules::HWMinMC(i))
00997 mHWSetupMC[i] = Rules::HWMinMC(i);
00998 else {
00999 long die1 = (Rules::HWMaxMC(i) - Rules::HWMinMC(i)) / 2;
01000 long die2 = (Rules::HWMaxMC(i) - Rules::HWMinMC(i) + 1) / 2;
01001 mHWSetupMC[i] = Random(die1) + Random(die2) + Rules::HWMinMC(i) + 1;
01002 }
01003
01004 if (mHWSetupMC[i] < mHWFloorMC[i])
01005 mHWSetupMC[i] = mHWFloorMC[i];
01006 }
01007 }
01008
01009 return mHWSetupMC[mintype];
01010 }
01011
01012 long Rules::GetHWStartMinerals(long mintype)
01013 {
01014 long lMax;
01015 long lMin = 165;
01016 if (TheGame->GetCreation() && mHWSetupSM.size() == 0) {
01017 mHWSetupSM.insert(mHWSetupSM.begin(), Rules::MaxMinType, 1);
01018 for (int i = 0; i < Rules::MaxMinType; ++i) {
01019 lMax = Rules::GetHWMC(i) * 11;
01020 if (lMax < 500)
01021 lMax = 500;
01022
01023 mHWSetupSM[i] = Random(lMin, lMax);
01024 }
01025 }
01026
01027
01028 #pragma unfinished(__FILE__ " : Rules::GetHWStartMinerals needs to set starting minerals correctly")
01029
01030 return mHWSetupSM[mintype];
01031 }
01032
01033 long Rules::GetSWStartMinerals(long )
01034 {
01035 if (TheGame->GetCreation())
01036 return Random(TheGame->GetCreation()->mSWMinMin, TheGame->GetCreation()->mSWMaxMin);
01037 else
01038 return 0;
01039 }
01040
01041 double Rules::OverGateRange(long range, long dist)
01042 {
01043 if (range == -1 || range >= dist)
01044 return 0;
01045 else
01046 return double(dist - range) / 4.0 * range;
01047 }
01048
01049 double Rules::OverGateMass(long cap1, long cap2, long mass)
01050 {
01051 double safe = 1.0;
01052 if (cap1 != -1 && cap1 < mass)
01053 safe = 1.0 - double(mass - cap1) / 4.0 * cap1;
01054 if (cap2 != -1 && cap2 < mass)
01055 safe *= 1.0 - double(mass - cap2) / 4.0 * cap2;
01056
01057 return 1.0 - safe;
01058 }