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 #include "Order.h"
00030
00031 #ifdef _DEBUG
00032 #define new DEBUG_NEW
00033 #endif
00034
00035
00036 Planet::Planet()
00037 {
00038 Init();
00039 }
00040
00041 void Planet::Init()
00042 {
00043 mMinConc.insert(mMinConc.begin(), Rules::MaxMinType, 1);
00044 mMinMined.insert(mMinMined.begin(), Rules::MaxMinType, 0);
00045 mCanLoadBy.clear();
00046 mCanLoadBy.insert(mCanLoadBy.begin(), TheGame->NumberPlayers(), false);
00047 mHabTerra.insert(mHabTerra.begin(), Rules::MaxHabType, 50);
00048 mHabStart.insert(mHabStart.begin(), Rules::MaxHabType, 50);
00049 mHomeWorld = false;
00050 mScanner = false;
00051 mArtifactType = ARTI_NONE;
00052 mArtifactAmount = 0;
00053 mScrapRes = 0;
00054 mBaseDesign = -1;
00055 mFactories = 0;
00056 mMines = 0;
00057 mDefenses = 0;
00058 mPayTax = false;
00059 mBaseDamage = 0;
00060 mPacketSpeed = 0;
00061 mPacketDest = NULL;
00062 mRouteTo = NULL;
00063 mDisplayPop = 0;
00064 mName.erase();
00065 mHadBattle = false;
00066 }
00067
00068 Planet::~Planet()
00069 {
00070 deque<ProdOrder *>::iterator iter;
00071 for (iter = mProductionQ.begin(); iter != mProductionQ.end(); ++iter)
00072 delete *iter;
00073 }
00074
00075 bool Planet::ParseNode(const TiXmlNode * node)
00076 {
00077 if (!CargoHolder::ParseNode(node))
00078 return false;
00079
00080 const TiXmlNode * child1;
00081 const char * ptr;
00082 int i;
00083
00084 ptr = GetString(node->FirstChild("Name"));
00085 if (ptr != NULL)
00086 mName = ptr;
00087 if (mName.empty() && TheGame->GetCreation())
00088 mName = TheGame->GetCreation()->GetNextName();
00089 if (mName.empty()) {
00090 Message * mess = TheGame->AddMessage("Error: Invalid value on Planet");
00091 mess->AddItem("", "Missing Name");
00092 return false;
00093 }
00094 if (TheGame->GetCreation() && TheGalaxy->GetPlanet(mName.c_str()) != NULL) {
00095 Message * mess = TheGame->AddMessage("Error: Invalid value on Planet");
00096 mess->AddItem("Duplicate Name", mName);
00097 return false;
00098 }
00099
00100 mHomeWorld = GetBool(node->FirstChild("HomeWorld"));
00101
00102 bool bSecond = GetBool(node->FirstChild("SecondWorld"));
00103 if (bSecond && GetOwner() != NULL)
00104 TheGame->GetCreation()->AddSecond(NCGetOwner(), this);
00105
00106 if (mHomeWorld && bSecond) {
00107 return false;
00108 }
00109
00110 child1 = node->FirstChild("StartingHab");
00111 if (child1 != NULL)
00112 Rules::ParseArray(child1, mHabStart, HABS);
00113 else if (TheGame->GetCreation()) {
00114 for (i = 0; i < Rules::MaxHabType; ++i) {
00115 if (mHomeWorld && GetOwner() != NULL && GetOwner()->HabCenter(i) >= 0)
00116 mHabStart[i] = GetOwner()->HabCenter(i);
00117 else if (bSecond && GetOwner() != NULL)
00118 mHabStart[i] = Rules::GetSecondHab(i, GetOwner());
00119 else
00120 mHabStart[i] = Rules::RandomHab(i);
00121 }
00122 }
00123
00124 Rules::ParseArrayBool(node->FirstChild("CanLoadBy"), "Race", "Number", mCanLoadBy);
00125
00126 child1 = node->FirstChild("Concentrations");
00127 if (child1 != NULL)
00128 Rules::ParseArray(child1, mMinConc, MINERALS);
00129 else if (TheGame->GetCreation()) {
00130 if (mHomeWorld) {
00131 for (i = 0; i < Rules::MaxMinType; ++i) {
00132 mMinConc[i] = Rules::GetHWMC(i);
00133 mContains[i] = Rules::GetHWStartMinerals(i);
00134 }
00135 } else {
00136 for (i = 0; i < Rules::MaxHabType; ++i)
00137 mMinConc[i] = Random(Rules::MinMC(i), Rules::MaxMC(i));
00138 }
00139 }
00140
00141 Rules::ParseArray(node->FirstChild("MineProgress"), mMinMined, MINERALS);
00142
00143 child1 = node->FirstChild("Factories");
00144 mFactories = GetLong(child1);
00145 if (mFactories < 0) {
00146 Message * mess = TheGame->AddMessage("Error: Invalid value on Planet");
00147 mess->AddItem("", this);
00148 mess->AddLong("Factories", mFactories);
00149 return false;
00150 } else if (child1 == NULL && mHomeWorld && TheGame->GetCreation())
00151 mFactories = TheGame->GetCreation()->mHWFactories;
00152 else if (child1 == NULL && bSecond && TheGame->GetCreation())
00153 mFactories = TheGame->GetCreation()->mSWFactories;
00154
00155 child1 = node->FirstChild("Mines");
00156 mMines = GetLong(child1);
00157 if (mMines < 0) {
00158 Message * mess = TheGame->AddMessage("Error: Invalid value on Planet");
00159 mess->AddItem("", this);
00160 mess->AddLong("Mines", mMines);
00161 return false;
00162 } else if (child1 == NULL && mHomeWorld && TheGame->GetCreation())
00163 mMines = TheGame->GetCreation()->mHWMines;
00164 else if (child1 == NULL && bSecond && TheGame->GetCreation())
00165 mMines = TheGame->GetCreation()->mSWMines;
00166
00167 child1 = node->FirstChild("CurrentHab");
00168 if (child1 != NULL)
00169 Rules::ParseArray(child1, mHabTerra, HABS);
00170 else if (TheGame->GetCreation()) {
00171 for (i = 0; i < Rules::MaxMinType; ++i)
00172 mHabTerra[i] = mHabStart[i];
00173 }
00174
00175 if (GetOwner() != NULL) {
00176 child1 = node->FirstChild("BaseDesign");
00177 if (child1) {
00178 mBaseDesign = GetLong(child1) - 1;
00179 if (mBaseDesign < -1 || mBaseDesign > Rules::GetConstant("MaxBaseDesigns")) {
00180 Message * mess = TheGame->AddMessage("Error: Invalid value on Planet");
00181 mess->AddItem("", this);
00182 mess->AddLong("BaseDesign", mBaseDesign);
00183 return false;
00184 }
00185 } else if ((mHomeWorld || bSecond) && TheGame->GetCreation()) {
00186 mBaseDesign = -2;
00187 } else
00188 mBaseDesign = -1;
00189
00190 mBaseDamage = GetLong(node->FirstChild("BaseDamage"));
00191 if ( mBaseDamage < 0 ||
00192 (mBaseDesign == -1 && mBaseDamage != 0) ||
00193 (mBaseDamage > 0 && mBaseDamage > GetBaseDesign()->GetArmor(GetOwner()))
00194 )
00195 {
00196 Message * mess = TheGame->AddMessage("Error: Invalid value on Planet");
00197 mess->AddItem("", this);
00198 mess->AddLong("BaseDamage", mBaseDamage);
00199 return false;
00200 }
00201
00202 child1 = node->FirstChild("Scanner");
00203 if (child1)
00204 mScanner = GetBool(child1);
00205 else if (TheGame->GetCreation() && (mHomeWorld || bSecond) && GetOwner())
00206 mScanner = GetOwner()->GetScanSpace() > 0;
00207
00208 child1 = node->FirstChild("Defenses");
00209 if (child1)
00210 mDefenses = GetLong(node->FirstChild("Defenses"));
00211 else if (mHomeWorld && TheGame->GetCreation())
00212 mDefenses = TheGame->GetCreation()->mHWDefenses;
00213
00214 if (mDefenses < 0 || mDefenses > Rules::GetConstant("MaxDefenses")) {
00215 Message * mess = TheGame->AddMessage("Error: Invalid value on Planet");
00216 mess->AddItem("", this);
00217 mess->AddLong("Defenses", mDefenses);
00218 return false;
00219 }
00220
00221 Planet * pdest;
00222 child1 = node->FirstChild("PacketDestination");
00223 if (child1) {
00224 pdest = TheGalaxy->GetPlanet(GetString(child1));
00225 if (!pdest) {
00226 Message * mess = NCGetOwner()->AddMessage("Error: Invalid planet");
00227 mess->AddItem("", GetString(child1));
00228 mess->AddItem("Where", "driver destination to");
00229 return false;
00230 }
00231 SetPacketDest(pdest);
00232 }
00233 child1 = node->FirstChild("PacketDestination");
00234 if (child1) {
00235 pdest = TheGalaxy->GetPlanet(GetString(child1));
00236 if (!pdest) {
00237 Message * mess = NCGetOwner()->AddMessage("Error: Invalid planet");
00238 mess->AddItem("", GetString(child1));
00239 mess->AddItem("Where", "route destination to");
00240 return false;
00241 }
00242 SetRoute(pdest);
00243 }
00244 SetPacketSpeed(GetLong(node->FirstChild("PacketSpeed")));
00245 ParseProduction(node->FirstChild("ProductionQueue"));
00246 mPayTax = GetBool(node->FirstChild("PayTax"));
00247 mArtifactType = ARTI_NONE;
00248 mArtifactAmount = 0;
00249 } else {
00250 mBaseDesign = -1;
00251 mBaseDamage = 0;
00252 mScanner = false;
00253 mDefenses = 0;
00254 mRouteName = "";
00255 mPacketName = "";
00256 mPacketSpeed = 0;
00257 mPayTax = false;
00258 DeleteProdQ();
00259 mArtifactType = GetLong(node->FirstChild("ArtifactType"), ARTI_NONE);
00260 mArtifactAmount = GetLong(node->FirstChild("ArtifactAmount"));
00261 }
00262
00263
00264 if (TheGame->GetCreation() && mHomeWorld) {
00265 if (GetOwner())
00266 NCGetOwner()->PlaceHW(this);
00267 else
00268 TheGame->GetCreation()->AddHW(this);
00269 }
00270 if (TheGame->GetCreation() && bSecond) {
00271 if (GetOwner())
00272 NCGetOwner()->PlaceSW(this, NULL);
00273 }
00274
00275 return true;
00276 }
00277
00278 TiXmlNode * Planet::WriteNode(TiXmlNode * node, const Player * viewer) const
00279 {
00280 if (viewer != NULL && !SeenBy(viewer))
00281 return NULL;
00282
00283 AddString(node, "Name", mName.c_str());
00284 CargoHolder::WriteNode(node, viewer);
00285
00286 if (viewer == NULL)
00287 node->LinkEndChild(Rules::WriteArrayBool("CanLoadBy", "Race", "Number", mCanLoadBy));
00288
00289 if (SeenBy(viewer) & SEEN_PLANETMC) {
00290 AddString(node, "HomeWorld", mHomeWorld ? "true" : "false");
00291 node->LinkEndChild(Rules::WriteArray("Concentrations", mMinConc, MINERALS));
00292 if (viewer == NULL)
00293 node->LinkEndChild(Rules::WriteArray("MineProgress", mMinMined, MINERALS));
00294 }
00295
00296 if (SeenBy(viewer) & SEEN_PLANETHAB) {
00297 node->LinkEndChild(Rules::WriteArray("StartingHab", mHabStart, HABS));
00298 node->LinkEndChild(Rules::WriteArray("CurrentHab", mHabTerra, HABS));
00299 if (viewer && viewer != GetOwner() && viewer->CanSeeHabSettings())
00300 NCGetOwner()->SetSeenHab(viewer);
00301 }
00302
00303 if (SeenBy(viewer) & SEEN_INSTALLATIONS) {
00304 AddLong(node, "Factories", mFactories);
00305 AddLong(node, "Mines", mMines);
00306 }
00307
00308 if (GetOwner() != NULL) {
00309 if (SeenBy(viewer) & SEEN_INSTALLATIONS) {
00310 AddString(node, "Scanner", mScanner ? "true" : "false");
00311 AddLong(node, "Defenses", mDefenses);
00312 }
00313
00314 if (SeenBy(viewer) & SEEN_HULL)
00315 AddLong(node, "BaseDesign", mBaseDesign+1);
00316
00317 if (SeenBy(viewer) & SEEN_ORDERS) {
00318 AddLong(node, "BaseDamage", mBaseDamage);
00319 if (mRouteTo != NULL)
00320 AddString(node, "RouteDestination", mRouteTo->GetName().c_str());
00321
00322 if (mPacketDest != NULL)
00323 AddString(node, "PacketDestination", mPacketDest->GetName().c_str());
00324
00325 AddLong(node, "PacketSpeed", mPacketSpeed);
00326 ProdOrder::WriteNode(node, mProductionQ);
00327 AddBool(node, "PayTax", mPayTax);
00328 }
00329
00330 if (viewer != NULL && viewer != GetOwner() && (SeenBy(viewer) & SEEN_PLANETPOP)) {
00331 AddDouble(node, "DefenseCoverage", GetDisplayDef());
00332 TiXmlNode * cargo = node->FirstChild("Contains");
00333 if (cargo == NULL) {
00334 cargo = new TiXmlElement("Contains");
00335 node->LinkEndChild(cargo);
00336 }
00337
00338 TiXmlNode * pop = cargo->FirstChild("Population");
00339 if (pop != NULL)
00340 cargo->RemoveChild(pop);
00341
00342 AddLong(cargo, "Population", GetDisplayPop());
00343 }
00344 }
00345
00346 if (viewer == NULL) {
00347 AddLong(node, "ArtifactType", mArtifactType);
00348 AddLong(node, "ArtifactAmount", mArtifactAmount);
00349 }
00350
00351 return node;
00352 }
00353
00354 long Planet::GetDisplayPop() const
00355 {
00356 if (mDisplayPop == 0 && mPopulation > 0) {
00357
00358 long lmin, lmax;
00359 lmin = long(mPopulation * 0.8 / Rules::PopEQ1kT);
00360 if (lmin < 4)
00361 lmin = 4;
00362 lmax = long(mPopulation * 1.2 / Rules::PopEQ1kT);
00363 if (lmax < lmin)
00364 lmax = lmin;
00365
00366 const_cast<Planet *>(this)->mDisplayPop = Random(lmin, lmax) * Rules::PopEQ1kT;
00367 }
00368
00369 return mDisplayPop;
00370 }
00371
00372 void Planet::SetDestinations()
00373 {
00374 mRouteTo = TheGalaxy->GetPlanet(mRouteName.c_str());
00375 mRouteName.erase();
00376 mPacketDest = TheGalaxy->GetPlanet(mPacketName.c_str());
00377 mPacketName.erase();
00378 }
00379
00380 void Planet::Invade(Player * invader, long amount)
00381 {
00382 deque<Invasion>::iterator iter;
00383 for (iter = mInvasions.begin(); iter != mInvasions.end(); ++iter) {
00384 if (invader == iter->player) {
00385 iter->amount += amount;
00386 return;
00387 }
00388 }
00389
00390 mInvasions.insert(mInvasions.end(), Invasion(invader, amount));
00391 TheGalaxy->AddInvasion(this);
00392 }
00393
00394 double Planet::GetDefenseValue() const
00395 {
00396 if (GetOwner() == NULL)
00397 return 0L;
00398
00399 if (GetDefenses() == 0)
00400 return 0L;
00401
00402 return 1.0 - pow(double(1.0) - GetOwner()->GetDefenseValue(), int(GetDefenses()));
00403 }
00404
00405 double Planet::GetSmartDefenseValue() const
00406 {
00407 if (GetOwner() == NULL)
00408 return 0L;
00409
00410 if (GetDefenses() == 0)
00411 return 0L;
00412
00413 return 1.0 - pow(double(1.0) - GetOwner()->GetDefenseValue() / 2, int(GetDefenses()));
00414 }
00415
00416 double Planet::GetDisplayDef() const
00417 {
00418 double Result = 0;
00419 if (GetOwner() != NULL) {
00420
00421
00422 Result = GetDefenseValue();
00423 if (Result > 0) {
00424 Result = double(int((Result*100 - 1.5) / 6) * 6 + 9) / 100.0;
00425 Result = min(Result, 0.93);
00426 }
00427 }
00428
00429 return Result;
00430 }
00431
00432 void Planet::ResolveInvasion()
00433 {
00434 if (mInvasions.empty())
00435 return;
00436
00437 long AttackStr = 0;
00438 Invasion * MaxAttack = NULL;
00439 Invasion * MaxAttack2 = NULL;
00440 long DefenseValue = 0;
00441 if (GetOwner()) {
00442 DefenseValue = long(GetPopulation() * GetOwner()->GroundDefenseFactor());
00443 DefenseValue = long(DefenseValue / (1.0 - GetDefenseValue() * 3.0 / 4.0));
00444 }
00445
00446 Message * omess = NULL;
00447 if (GetOwner() != NULL) {
00448 omess = NCGetOwner()->AddMessage("World invasion", this);
00449 omess->AddLong("Starting population", GetPopulation());
00450 }
00451
00452 deque<Invasion>::iterator iter;
00453 for (iter = mInvasions.begin(); iter != mInvasions.end(); ++iter) {
00454 long str = long(iter->amount * (1.0 + Rules::GetFloat("GCAttackerBonus")) * iter->player->GroundAttackFactor());
00455 iter->Strength = str;
00456 iter->InitStr = str;
00457 AttackStr += str;
00458
00459
00460 if (MaxAttack == NULL) {
00461 MaxAttack = &*iter;
00462 } else if (MaxAttack->Strength < str) {
00463 MaxAttack2 = MaxAttack;
00464 MaxAttack = &*iter;
00465 } else if (MaxAttack2 && MaxAttack2->Strength < str) {
00466 MaxAttack2 = &*iter;
00467 }
00468
00469 iter->mess = iter->player->AddMessage("World invasion", this);
00470 iter->mess->AddLong("Starting population", GetPopulation());
00471 if (omess) {
00472 omess->AddItem("Invader", iter->player);
00473 omess->AddLong("Invasion amount", iter->amount);
00474 }
00475 }
00476
00477
00478 deque<Invasion>::iterator i2;
00479 for (iter = mInvasions.begin(); iter != mInvasions.end(); ++iter) {
00480 for (i2 = mInvasions.begin(); i2 != mInvasions.end(); ++i2) {
00481 iter->mess->AddItem("Other invader", i2->player);
00482 iter->mess->AddLong("Invasion Amount", i2->amount);
00483 }
00484 }
00485
00486 double ratio = double(DefenseValue) / double(AttackStr);
00487 if (ratio <= 1.00) {
00488
00489
00490 MaxAttack->Strength = long(MaxAttack->Strength * (1.0-ratio));
00491 if (MaxAttack2) {
00492 MaxAttack2->Strength = long(MaxAttack2->Strength * (1.0-ratio));
00493
00494 MaxAttack->Strength -= MaxAttack2->Strength;
00495 }
00496
00497
00498 MaxAttack->amount = long(MaxAttack->amount * double(MaxAttack->Strength) / double(MaxAttack->InitStr));
00499
00500
00501 for (iter = mInvasions.begin(); iter != mInvasions.end(); ++iter) {
00502 if (MaxAttack->amount > 100) {
00503 iter->mess->AddItem("Captured by", MaxAttack->player);
00504 iter->mess->AddLong("Survivors", MaxAttack->amount);
00505 } else
00506 iter->mess->AddItem("No survivors", (const Player *)NULL);
00507 }
00508 if (GetOwner() != NULL) {
00509 if (MaxAttack->amount > 100) {
00510 omess->AddItem("Captured by", MaxAttack->player);
00511 omess->AddLong("Survivors", MaxAttack->amount);
00512 } else
00513 omess->AddItem("No survivors", (const Player *)NULL);
00514 }
00515 } else {
00516
00517
00518 int survivors = long(GetPopulation() * (1.0 - double(AttackStr)/DefenseValue));
00519 mPopulation = survivors;
00520
00521 for (iter = mInvasions.begin(); iter != mInvasions.end(); ++iter) {
00522 if (survivors > Rules::PopEQ1kT) {
00523 iter->mess->AddItem("Defender holds", GetOwner());
00524 iter->mess->AddLong("Survivors", survivors);
00525 } else
00526 iter->mess->AddItem("No survivors", (const Player *)NULL);
00527 }
00528 if (survivors > Rules::PopEQ1kT) {
00529 omess->AddItem("Defender holds", GetOwner());
00530 omess->AddLong("Survivors", survivors);
00531 } else if (omess)
00532 omess->AddItem("No survivors", (const Player *)NULL);
00533 }
00534
00535 if (MaxAttack->amount > Rules::PopEQ1kT)
00536 TakePlanet(const_cast<Player *>(MaxAttack->player), MaxAttack->amount);
00537 else {
00538 TakePlanet(NULL, 0);
00539 }
00540
00541 mInvasions.clear();
00542 }
00543
00544 void Planet::TakePlanet(Player * invader, long amount)
00545 {
00546 if (invader != NULL) {
00547
00548 if (GetOwner() == NULL) {
00549 if (amount < 1000)
00550 mArtifactAmount = mArtifactAmount * amount / 1000;
00551
00552 TechType tt;
00553 int i;
00554 switch (mArtifactType) {
00555 case ARTI_NONE:
00556 break;
00557 case ARTI_ALL:
00558 for (tt = 0; tt < Rules::MaxTechType; ++tt)
00559 invader->GainTech(mArtifactAmount, tt);
00560 break;
00561 case ARTI_RANDTYPE:
00562 invader->GainTech(mArtifactAmount, Random(Rules::MaxTechType));
00563 break;
00564 case ARTI_RANDSPLIT:
00565 for (i = 0; i < Rules::MaxTechType * 2; ++i)
00566 invader->GainTech(mArtifactAmount / Rules::MaxTechType / 2, Random(Rules::MaxTechType));
00567 default:
00568 invader->GainTech(mArtifactAmount, mArtifactType);
00569 break;
00570 }
00571
00572 mArtifactType = ARTI_NONE;
00573 mArtifactAmount = 0;
00574 } else {
00575 if (GetContain(POPULATION) > 0) {
00576 TechType TechGot = Rules::TechInvasion(invader, GetOwner());
00577 if (TechGot > TECH_NONE) {
00578 NCGetOwner()->SetGotTech(true);
00579 NCGetOwner()->GainTech(TechGot, GetOwner()->TechCost(TechGot));
00580 }
00581 }
00582 }
00583 }
00584
00585 Kill();
00586 mOwner = invader;
00587 mPopulation = amount;
00588 if (invader != NULL) {
00589 CopyProdQ(invader->GetDefaultQ());
00590 mPayTax = invader->GetDefaultPayTax();
00591 }
00592 }
00593
00594 void Planet::DeadCheck()
00595 {
00596 if (GetOwner() != NULL && GetContain(POPULATION) < Rules::PopEQ1kT) {
00597 Kill();
00598 }
00599 }
00600
00601 void Planet::Kill()
00602 {
00603 DeleteProdQ();
00604 mPopulation = 0;
00605 mScrapRes = 0;
00606 mBaseDesign = -1;
00607 mScanner = false;
00608 mDefenses = 0;
00609 mRouteTo = NULL;
00610 mPacketDest = NULL;
00611 mPacketSpeed = 0;
00612 mBaseDamage = 0;
00613 if (mOwner != NULL && mOwner->TemporaryTerraform())
00614 mHabTerra = mHabStart;
00615
00616 mPayTax = false;
00617 mDisplayPop = 0;
00618 mOwner = NULL;
00619 }
00620
00621 long Planet::GetScanPen() const
00622 {
00623 long Scan = 0;
00624 if (GetOwner()) {
00625 if (mScanner)
00626 Scan = GetOwner()->GetScanPen();
00627
00628 const Ship * base = GetBaseDesign();
00629 if (base)
00630 Scan = max(Scan, base->GetScanPen(GetOwner(), GetContain(POPULATION)));
00631 }
00632
00633 return Scan;
00634 }
00635
00636 long Planet::GetScanSpace() const
00637 {
00638 long Scan = 0;
00639 if (GetOwner()) {
00640 if (mScanner)
00641 Scan = GetOwner()->GetScanSpace();
00642
00643 const Ship * base = GetBaseDesign();
00644 if (base)
00645 Scan = max(Scan, base->GetScanSpace(GetOwner(), GetContain(POPULATION)));
00646
00647 Scan = long(Scan * GetOwner()->SpaceScanFactor());
00648 }
00649
00650 return Scan;
00651 }
00652
00653 double Planet::GetMaxTachyon() const
00654 {
00655 if (GetOwner()) {
00656 const Ship * base = GetBaseDesign();
00657 if (base)
00658 return base->GetTachyon();
00659 }
00660
00661 return 0.0;
00662 }
00663
00664 void Planet::SetBaseNumber(long n)
00665 {
00666 mBaseDesign = n;
00667 if (mBaseDesign >= 0) {
00668 mBaseDamage = min(mBaseDamage, GetBaseDesign()->GetArmor(GetOwner()) - 1L);
00669 NCGetOwner()->IncrementBaseBuilt(n);
00670 }
00671 }
00672
00673 void Planet::DeleteProdQ()
00674 {
00675 deque<ProdOrder *>::iterator iter;
00676 for (iter = mProductionQ.begin(); iter != mProductionQ.end(); ++iter)
00677 delete *iter;
00678
00679 mProductionQ.erase(mProductionQ.begin(), mProductionQ.end());
00680 }
00681
00682 void Planet::CopyProdQ(const deque<ProdOrder *> &prod)
00683 {
00684 deque<ProdOrder *>::iterator iter;
00685 for (iter = mProductionQ.begin(); iter != mProductionQ.end(); ++iter)
00686 delete *iter;
00687
00688 deque<ProdOrder *>::const_iterator it2;
00689 for (it2 = prod.begin(); it2 != prod.end(); ++it2) {
00690 mProductionQ.insert(mProductionQ.end(), (*it2)->Copy());
00691 }
00692 }
00693
00694 void Planet::AdjustDefenses(long amount)
00695 {
00696 mDefenses += amount;
00697 if (mDefenses < 0)
00698 mDefenses = 0;
00699 if (mDefenses > Rules::GetConstant("MaxDefenses"))
00700 mDefenses = Rules::GetConstant("MaxDefenses");
00701 }
00702
00703 void Planet::AdjustMines(long amount)
00704 {
00705 mMines += amount;
00706 if (mMines < 0)
00707 mMines = 0;
00708 }
00709
00710 void Planet::AdjustFactories(long amount)
00711 {
00712 mDefenses += amount;
00713 if (mMines < 0)
00714 mMines = 0;
00715
00716 }
00717
00718 long Planet::CanTerraform(const Component * comp) const
00719 {
00720 if (comp->GetTerraType() != -1)
00721 return CanTerraform(comp->GetTerraType(), comp->GetTerraLimit());
00722 else {
00723 long maxT = 0;
00724 for (long i = 0; i < Rules::MaxHabType; ++i) {
00725 maxT = max(maxT, CanTerraform(i, comp->GetTerraLimit()));
00726 }
00727
00728 return maxT;
00729 }
00730 }
00731
00732 long Planet::CanTerraform(HabType ht, long max) const
00733 {
00734 if (GetOwner()->HabCenter(ht) == -1)
00735 return 0;
00736
00737 long direction = 0;
00738 if (mHabTerra[ht] < GetOwner()->HabCenter(ht))
00739 direction = 1;
00740 else if (mHabTerra[ht] > GetOwner()->HabCenter(ht))
00741 direction = -1;
00742 else
00743 return 0;
00744
00745
00746 if (direction > 0 && mHabTerra[ht] + direction > Rules::GetConstant("MaxHabValue"))
00747 return 0;
00748 else if (direction < 0 && mHabTerra[ht] + direction < Rules::GetConstant("MinHabValue"))
00749 return 0;
00750
00751
00752 if (direction > 0 && mHabTerra[ht] + direction > mHabStart[ht] + max)
00753 return 0;
00754 else if (direction < 0 && mHabTerra[ht] + direction < mHabStart[ht] - max)
00755 return 0;
00756
00757
00758 long before = GetOwner()->HabFactor(this);
00759 const_cast<Planet *>(this)->mHabTerra[ht] += direction;
00760 long after = GetOwner()->HabFactor(this);
00761 const_cast<Planet *>(this)->mHabTerra[ht] -= direction;
00762
00763 return after - before;
00764 }
00765
00766 bool Planet::Terraform(const Player * player, bool positive)
00767 {
00768 HabType ht, htMax = -1;
00769 long ValMax = positive ? -100 : 100;
00770 long direction = 0;
00771 long dMax = 0;
00772 for (ht = 0; ht < Rules::MaxHabType; ++ht) {
00773 if (GetOwner()->HabCenter(ht) == -1)
00774 continue;
00775 else if (mHabTerra[ht] < GetOwner()->HabCenter(ht) && positive)
00776 direction = 1;
00777 else if (mHabTerra[ht] < GetOwner()->HabCenter(ht) && !positive)
00778 direction = -1;
00779 else if (mHabTerra[ht] > GetOwner()->HabCenter(ht) && positive)
00780 direction = -1;
00781 else if (mHabTerra[ht] > GetOwner()->HabCenter(ht) && !positive)
00782 direction = 1;
00783 else
00784 continue;
00785
00786 if (direction > 0 && mHabTerra[ht] + direction > Rules::GetConstant("MaxHabValue"))
00787 continue;
00788 else if (direction < 0 && mHabTerra[ht] + direction < Rules::GetConstant("MinHabValue"))
00789 continue;
00790
00791 if (direction > 0 && mHabTerra[ht] + direction > mHabStart[ht] + (player == NULL) ? player->TerraLimit(ht) : 0)
00792 continue;
00793 else if (direction < 0 && mHabTerra[ht] + direction < mHabStart[ht] - (player == NULL) ? player->TerraLimit(ht) : 0)
00794 continue;
00795
00796
00797 mHabTerra[ht] += direction;
00798 long temp = player->HabFactor(this);
00799 mHabTerra[ht] -= direction;
00800 if (direction > 0 && temp > ValMax) {
00801 ValMax = temp;
00802 htMax = ht;
00803 dMax = direction;
00804 }
00805 if (direction < 0 && temp < ValMax) {
00806 ValMax = temp;
00807 htMax = ht;
00808 dMax = direction;
00809 }
00810 }
00811
00812 if (htMax == -1)
00813 return false;
00814
00815
00816 mHabTerra[htMax] += dMax;
00817
00818
00819 return true;
00820 }
00821
00822 long Planet::GetMaxPop() const
00823 {
00824 if (GetOwner() == NULL)
00825 return 0L;
00826
00827 if (GetOwner()->ARTechType() >= 0) {
00828 if (GetBaseDesign() == NULL)
00829 return 0L;
00830 else
00831 return long(GetBaseDesign()->GetARMaxPop() * GetOwner()->PopulationFactor());
00832 } else {
00833 long hab = max(GetOwner()->HabFactor(this), 5L);
00834 return long(Rules::GetConstant("MaxPlanetPop") * hab / 100L * GetOwner()->PopulationFactor());
00835 }
00836 }
00837
00838 void Planet::Mine()
00839 {
00840 if (GetOwner() == NULL)
00841 return;
00842
00843 long mines;
00844 if (GetOwner()->ARTechType() >= 0) {
00845 mines = long(sqrt((double)min(GetMaxPop(), GetContain(POPULATION)) * GetOwner()->MinesRun()));
00846 } else {
00847 mines = min(GetMaxPop(), GetContain(POPULATION)) * GetOwner()->MinesRun() / 100;
00848 mines = min(mines, mMines);
00849 }
00850
00851 Mine(mines, GetOwner());
00852 }
00853
00854
00855 void Planet::Mine(long mines, const Player * miner)
00856 {
00857 if (mines == 0)
00858 return;
00859
00860 long rate;
00861 if (GetOwner() == NULL)
00862 rate = 10;
00863 else
00864 rate = GetOwner()->MineRate();
00865
00866 for (long mineral = 0; mineral < Rules::MaxMinType; ++mineral) {
00867 long conc;
00868 if (mHomeWorld && miner == GetOwner())
00869 conc = max(mMinConc[mineral], Rules::GetConstant("MineralHWMinimum"));
00870 else
00871 conc = mMinConc[mineral];
00872
00873 mContains[mineral] += (conc * mines * rate + 500) / 10 / 100;
00874 mMinMined[mineral] += mines;
00875 long minesper = Rules::GetConstant("MineralDecayFactor") / mMinConc[mineral] / mMinConc[mineral];
00876 if (mMinMined[mineral] > minesper) {
00877 mMinConc[mineral] -= mMinMined[mineral] / minesper;
00878 if (mMinConc[mineral] < Rules::GetConstant("MineralMinimum"))
00879 mMinConc[mineral] = Rules::GetConstant("MineralMinimum");
00880
00881 mMinMined[mineral] %= minesper;
00882 }
00883 }
00884 }
00885
00886 long Planet::GetResources() const
00887 {
00888 if (GetOwner() == NULL)
00889 return 0;
00890
00891 long Res = 0;
00892 long maxpop = GetMaxPop();
00893 long pop;
00894 pop = min(maxpop, GetContain(POPULATION));
00895 if (GetContain(POPULATION) > maxpop)
00896 pop = (min(maxpop * 3L, GetContain(POPULATION)) - maxpop) / 2 + maxpop;
00897
00898 if (GetOwner()->ARTechType() >= 0) {
00899 long hab = max(GetOwner()->HabFactor(this), 25L);
00900 Res = long(sqrt(double(pop * GetOwner()->GetTechLevel(GetOwner()->ARTechType()) / 10) * hab / 100));
00901 } else {
00902 long facts;
00903 facts = min(maxpop, GetContain(POPULATION)) * GetOwner()->FactoriesRun() / 10000;
00904 facts = min(facts, mFactories);
00905
00906 Res = facts * GetOwner()->FactoryRate() / 10;
00907 Res += pop / GetOwner()->PopEfficiency();
00908 }
00909
00910 return Res;
00911 }
00912
00913 long Planet::PopGrowth() const
00914 {
00915 if (GetOwner() == NULL)
00916 return 0L;
00917
00918 long currentHab = GetOwner()->HabFactor(this);
00919 if (currentHab < 0) {
00920
00921 return (GetPopulation() * currentHab + 500) / 1000;
00922 } else {
00923 double PopFactor = double(GetPopulation()) / double(GetMaxPop());
00924 if (PopFactor > 1.0) {
00925 return long(GetPopulation() * PopFactor * -4 + 0.5);
00926 } else {
00927
00928 double Growth = GetPopulation() * currentHab / 100.0 * GetOwner()->GrowthRate();
00929 if (PopFactor > 0.25) {
00930
00931 Growth *= 16.0 / 9.0;
00932 Growth *= (1.0-PopFactor) * (1.0-PopFactor);
00933 }
00934 return long(Growth + .5);
00935 }
00936 }
00937 }
00938
00939 void Planet::DoProduction()
00940 {
00941 Player * owner = NCGetOwner();
00942 if (owner == NULL)
00943 return;
00944
00945 long resources = GetResources();
00946 bool AutoAlchemy = false;
00947 mBuiltFactories = 0;
00948 mBuiltMines = 0;
00949 mBuiltDefenses = 0;
00950 mBuiltAlchemy = 0;
00951
00952
00953 resources += (mScrapRes * resources) / (mScrapRes + resources);
00954
00955
00956 if (mPayTax && owner->GetResearchField() != RESEARCH_ALCHEMY) {
00957 long tax = long(resources * owner->GetResearchTax() + .5);
00958 tax -= owner->GainTech(tax);
00959 resources -= tax;
00960 }
00961
00962
00963 for (unsigned int i = 0; i < mProductionQ.size(); ++i) {
00964 if (mProductionQ[i]->Produce(this, &resources, &AutoAlchemy)) {
00965 delete mProductionQ[i];
00966 mProductionQ.erase(mProductionQ.begin() + i);
00967 --i;
00968 }
00969
00970 if (resources <= 0)
00971 break;
00972 }
00973
00974
00975 if (resources > 0) {
00976
00977 if (!AutoAlchemy && owner->GetResearchField() != RESEARCH_ALCHEMY)
00978 resources = owner->GainTech(resources);
00979
00980 if (resources > 0) {
00981 double BuildAlchem = 0;
00982 BuildAlchem = resources / (Rules::GetConstant("AlchemyCost") * owner->ComponentCostFactor(CT_ALCHEMY));
00983
00984 POPlanetary * alchem = new POPlanetary(POP_ALCHEMY, long(BuildAlchem + 1.0 - epsilon));
00985 if (!alchem->Produce(this, &resources, &AutoAlchemy)) {
00986 mProductionQ.push_front(alchem);
00987 } else {
00988 delete alchem;
00989 }
00990 }
00991 }
00992
00993
00994 if (mBuiltFactories > 0) {
00995 Message * mess = owner->AddMessage("Factories built", this);
00996 mess->AddLong("Number built", mBuiltFactories);
00997 }
00998 if (mBuiltMines > 0) {
00999 Message * mess = owner->AddMessage("Mines built", this);
01000 mess->AddLong("Number built", mBuiltMines);
01001 }
01002 if (mBuiltDefenses > 0) {
01003 Message * mess = owner->AddMessage("Defenses built", this);
01004 mess->AddLong("Number built", mBuiltDefenses);
01005 }
01006 if (mBuiltAlchemy > 0) {
01007 Message * mess = owner->AddMessage("Alchemy built", this);
01008 mess->AddLong("Number built", mBuiltAlchemy);
01009 }
01010 }
01011
01012 long Planet::MaxFactories() const
01013 {
01014 return GetMaxPop() * GetOwner()->FactoriesRun() / 10;
01015 }
01016
01017 long Planet::MaxMines() const
01018 {
01019 return GetMaxPop() * GetOwner()->MinesRun() / 10;
01020 }
01021
01022 long Planet::MaxDefenses() const
01023 {
01024 if (GetOwner()->HabFactor(this) < 0)
01025 return 10;
01026 else
01027 return min(Rules::GetConstant("MaxDefenses", 100L), GetMaxPop() / 2500L);
01028 }
01029
01030 Cost Planet::GetPacketCost(long type) const
01031 {
01032 Cost c;
01033
01034 c.SetCrew(0);
01035 c.SetResources(GetOwner()->PacketCostResources());
01036 if (type == -1) {
01037 for (long i = 0; i < Rules::MaxMinType; ++i)
01038 c[i] = long(GetOwner()->PacketSizeMixed() * GetOwner()->PacketCostMinFactor());
01039 } else
01040 c[type] = long(GetOwner()->PacketSizeOneMin() * GetOwner()->PacketCostMinFactor());
01041
01042 return c;
01043 }
01044
01045 void Planet::ResetSeen()
01046 {
01047 CargoHolder::ResetSeen();
01048
01049 mCanLoadBy.clear();
01050 mCanLoadBy.insert(mCanLoadBy.begin(), TheGame->NumberPlayers(), false);
01051 }
01052
01053 void Planet::CreateRandom(Creation * c)
01054 {
01055 long i;
01056
01057 mID = TheGalaxy->GetNextPlanetID();
01058 for (i = 0; i < Rules::MaxMinType; ++i)
01059 mMinConc[i] = Random(Rules::MinMC(i), Rules::MaxMC(i));
01060
01061 mCanLoadBy.insert(mCanLoadBy.begin(), TheGame->NumberPlayers(), false);
01062 for (i = 0; i < Rules::MaxHabType; ++i)
01063 mHabTerra[i] = mHabStart[i] = Rules::RandomHab(i);
01064
01065
01066 if (TheGame->GetRandomEvents() | RE_ARTIFACT && Randodd(Rules::GetFloat("ArtifactOdds"))) {
01067 mArtifactAmount = Random(Rules::GetConstant("ArtifactMin"), Rules::GetConstant("ArtifactMax"));
01068 mArtifactType = Random(Rules::MaxTechType);
01069 }
01070
01071 mName = c->GetNextName();
01072 }
01073
01074 void Planet::CreateHW(const Player * player)
01075 {
01076 mPopulation = TheGame->GetCreation()->mHWBasePop;
01077 if (player->HasSecondPlanet() && TheGame->GetCreation()->mSecondaryWorlds)
01078 mPopulation = long(mPopulation * TheGame->GetCreation()->mPopMultiplierFor2nd + .5);
01079
01080 mDefenses = TheGame->GetCreation()->mHWDefenses;
01081 mFactories = TheGame->GetCreation()->mHWFactories;
01082 mMines = TheGame->GetCreation()->mHWMines;
01083 for (int i = 0; i < Rules::MaxMinType; ++i) {
01084 mMinConc[i] = Rules::GetHWMC(i);
01085 mContains[i] = Rules::GetHWStartMinerals(i);
01086 }
01087
01088 mBaseDesign = -2;
01089 mArtifactType = ARTI_NONE;
01090 mArtifactAmount = 0;
01091 mHomeWorld = true;
01092 }
01093
01094 void Planet::AdjustHW(Player * player)
01095 {
01096 mOwner = player;
01097 long bonusPop;
01098 bonusPop = long(TheGame->GetCreation()->mHWPopBonus * player->GrowthRate());
01099 if (player->HasSecondPlanet() && TheGame->GetCreation()->mSecondaryWorlds)
01100 bonusPop = long(bonusPop * TheGame->GetCreation()->mPopMultiplierFor2nd + .5);
01101
01102 mPopulation = long((bonusPop + mPopulation) * player->StartingPopFactor());
01103
01104 int i;
01105 for (i = 0; i < Rules::MaxHabType; ++i) {
01106 if (player->HabCenter(i) >= 0)
01107 mHabTerra[i] = mHabStart[i] = player->HabCenter(i);
01108 }
01109
01110 if (player->GetStartConcentrations() > 0) {
01111 long minMC = 0;
01112 for (i = 1; i < Rules::MaxMinType; ++i) {
01113 if (mMinConc[i] < mMinConc[minMC])
01114 minMC = i;
01115 }
01116
01117 for (i = 0; i < Rules::MaxMinType; ++i) {
01118 if (i == minMC)
01119 mMinConc[i] += (player->GetStartConcentrations() + 2) * 3 / 4;
01120 else
01121 mMinConc[i] += (player->GetStartConcentrations() + 2) / 4;
01122 }
01123 }
01124
01125 mMines += player->GetStartMines() / Rules::GetConstant("StartMineCost", 3);
01126 mFactories += player->GetStartFactories() / Rules::GetConstant("StartFactoryCost", 5);
01127 mDefenses += player->GetStartDefneses() / Rules::GetConstant("StartDefenseCost", 10);
01128
01129 if (player->GetStartMinerals() > 0) {
01130 long minSM = 0;
01131 for (i = 1; i < Rules::MaxMinType; ++i) {
01132 if (mContains[i] < mContains[minSM])
01133 minSM = i;
01134 }
01135 mContains[minSM] += player->GetStartMinerals() * 5 / 2;
01136
01137 for (i = 0; i < Rules::MaxMinType; ++i)
01138 mContains[i] += player->GetStartMinerals() * 5 / 2;
01139 }
01140
01141 CopyProdQ(player->GetDefaultQ());
01142 mPayTax = player->GetDefaultPayTax();
01143 if (player->GetScanSpace() > 0)
01144 mScanner = true;
01145 }
01146
01147 void Planet::CreateSecondWorld(const Planet * HW)
01148 {
01149 mPopulation = long(HW->GetPopulation() * TheGame->GetCreation()->mSecondaryPop);
01150
01151 mDefenses = TheGame->GetCreation()->mSWDefenses;
01152 mFactories = TheGame->GetCreation()->mSWFactories;
01153 mMines = TheGame->GetCreation()->mSWMines;
01154 int i;
01155 for (i = 0; i < Rules::MaxMinType; ++i)
01156 mContains[i] = Rules::GetSWStartMinerals(i);
01157
01158 for (i = 0; i < Rules::MaxHabType; ++i)
01159 mHabStart[i] = Rules::GetSecondHab(i, HW->GetOwner());
01160
01161 mBaseDesign = -2;
01162 mArtifactType = ARTI_NONE;
01163 mArtifactAmount = 0;
01164 }
01165
01166 void Planet::AdjustSecondWorld(Player * player)
01167 {
01168 mOwner = player;
01169 int i;
01170
01171 for (i = 0; i < Rules::MaxHabType; ++i)
01172 mHabTerra[i] = mHabStart[i] = Rules::GetSecondHab(i, player);
01173
01174 CopyProdQ(player->GetDefaultQ());
01175 mPayTax = player->GetDefaultPayTax();
01176 if (player->GetScanSpace() > 0)
01177 mScanner = true;
01178 }
01179
01180 void Planet::ParseProduction(const TiXmlNode * node)
01181 {
01182 if (node != NULL)
01183 SetProduction(ProdOrder::ParseNode(node, this));
01184 }
01185
01186 void Planet::SetProduction(const deque<ProdOrder *> & ords)
01187 {
01188 assert(GetOwner());
01189 if (GetOwner()->WriteXFile())
01190 NCGetOwner()->AddOrder(new ProductionOrder(mName.c_str(), &mProductionQ));
01191 else {
01192 for (int i = 0; i < mProductionQ.size(); ++i)
01193 delete mProductionQ[i];
01194 }
01195
01196 mProductionQ = ords;
01197 }
01198
01199 void Planet::SetPayTax(bool paytax)
01200 {
01201 assert(GetOwner());
01202 if (paytax != mPayTax && GetOwner()->WriteXFile())
01203 NCGetOwner()->AddOrder(new TypedOrder<bool>(&mPayTax, AddBool, "PayTax", "Planet", mName.c_str()));
01204
01205 mPayTax = paytax;
01206 }
01207
01208 void Planet::SetPacketSpeed(int speed)
01209 {
01210 if (speed != mPacketSpeed && GetOwner()->WriteXFile())
01211 NCGetOwner()->AddOrder(new TypedOrder<long>(&mPacketSpeed, AddLong, "PacketSpeed", "Planet", mName.c_str()));
01212
01213 mPacketSpeed = speed;
01214 }
01215
01216 void Planet::SetPacketDest(Planet * pdest)
01217 {
01218 if (pdest != mPacketDest && GetOwner()->WriteXFile())
01219 NCGetOwner()->AddOrder(new TypedOrder<Planet *>(&mPacketDest, "PacketDestination", Planet::SGetName, "Planet", mName.c_str()));
01220
01221 mPacketDest = pdest;
01222 }
01223
01224 void Planet::SetRoute(const Planet * rdest)
01225 {
01226 if (rdest != mRouteTo && GetOwner()->WriteXFile())
01227 NCGetOwner()->AddOrder(new TypedOrder<const Planet *>(&mRouteTo, "RouteDestination", Planet::SGetName, "From", mName.c_str()));
01228
01229 mRouteTo = rdest;
01230 }
01231
01232 void Planet::RepairBase()
01233 {
01234 if (mHadBattle || mOwner == NULL || mBaseDesign < 0 || mBaseDamage == 0)
01235 return;
01236
01237 assert(mBaseDamage > 0);
01238 double rate = Rules::GetFloat("StarbaseRepair", .1);
01239 rate += rate * mOwner->RepairFactor() / 2.0;
01240
01241 mBaseDamage -= min(1L, long(GetBaseDesign()->GetArmor(mOwner) * rate + .5));
01242 }
01243
01244 void Planet::Instaform()
01245 {
01246 if (mOwner == NULL || mOwner->ComponentCostFactor(CT_TERRAFORM) > epsilon)
01247 return;
01248
01249 long startHab = mOwner->HabFactor(this);
01250 HabType ht;
01251 for (ht = 0; ht < Rules::MaxHabType; ++ht) {
01252 if (GetOwner()->HabCenter(ht) == -1 || mHabTerra[ht] == mOwner->HabCenter(ht))
01253 continue;
01254
01255 long maxT, minT;
01256 maxT = min(mHabStart[ht] + mOwner->TerraLimit(ht), Rules::GetConstant("MaxHabValue"));
01257 maxT = max(maxT, mHabTerra[ht]);
01258 minT = max(mHabStart[ht] - mOwner->TerraLimit(ht), Rules::GetConstant("MinHabValue"));
01259 minT = min(minT, mHabTerra[ht]);
01260
01261 if (mOwner->HabCenter(ht) > maxT)
01262 mHabTerra[ht] = maxT;
01263 else if (mOwner->HabCenter(ht) < minT)
01264 mHabTerra[ht] = minT;
01265 else
01266 mHabTerra[ht] = mOwner->HabCenter(ht);
01267 }
01268
01269 long endHab = mOwner->HabFactor(this);
01270 if (startHab != endHab) {
01271 Message * mess = mOwner->AddMessage("Instaform", this);
01272 mess->AddLong("Start Hab", startHab);
01273 mess->AddLong("End Hab", endHab);
01274 }
01275 }
01276
01277 void Planet::RemoteTerraform(Fleet * fleet, bool bomb)
01278 {
01279
01280
01281
01282
01283 bool positive = mOwner->GetRelations(fleet->GetOwner()) > PR_NEUTRAL;
01284
01285 long totech, toinit;
01286 if (positive) {
01287 totech = fleet->GetTerraPower((bomb ? TERRA_BOMB : TERRA_REMOTE) | TERRA_POSTERRA | TERRA_TOTECH);
01288 toinit = fleet->GetTerraPower((bomb ? TERRA_BOMB : TERRA_REMOTE) | TERRA_POSTERRA | TERRA_TOINIT);
01289 } else {
01290 totech = fleet->GetTerraPower((bomb ? TERRA_BOMB : TERRA_REMOTE) | TERRA_DETERRA | TERRA_TOTECH);
01291 toinit = fleet->GetTerraPower((bomb ? TERRA_BOMB : TERRA_REMOTE) | TERRA_DETERRA | TERRA_TOINIT);
01292 }
01293
01294 if (totech == 0 && toinit == 0)
01295 return;
01296
01297 long startHab = mOwner->HabFactor(this);
01298 HabType ht;
01299 for (ht = 0; ht < Rules::MaxHabType; ++ht) {
01300 if (GetOwner()->HabCenter(ht) == -1 || (positive && mHabTerra[ht] == mOwner->HabCenter(ht)))
01301 continue;
01302
01303 long maxT, minT;
01304 maxT = min(mHabStart[ht] + fleet->GetOwner()->TerraLimit(ht), Rules::GetConstant("MaxHabValue"));
01305 if (mHabTerra[ht] >= maxT)
01306 maxT = mHabTerra[ht];
01307 else if (mHabTerra[ht] < mHabStart[ht])
01308 maxT = min(maxT, min(mHabTerra[ht] + toinit, mHabStart[ht]) + totech);
01309 else
01310 maxT = min(maxT, mHabTerra[ht] + totech);
01311
01312 minT = max(mHabStart[ht] - fleet->GetOwner()->TerraLimit(ht), Rules::GetConstant("MinHabValue"));
01313 if (mHabTerra[ht] <= minT)
01314 minT = mHabTerra[ht];
01315 else if (mHabTerra[ht] > mHabStart[ht])
01316 minT = max(minT, max(mHabTerra[ht] - toinit, mHabStart[ht]) - totech);
01317 else
01318 minT = max(minT, mHabTerra[ht] - totech);
01319
01320 if (positive) {
01321 if (mOwner->HabCenter(ht) > maxT)
01322 mHabTerra[ht] = maxT;
01323 else if (mOwner->HabCenter(ht) < minT)
01324 mHabTerra[ht] = minT;
01325 else
01326 mHabTerra[ht] = mOwner->HabCenter(ht);
01327 } else {
01328 if ((mOwner->HabCenter(ht) - minT) > (maxT - mOwner->HabCenter(ht)))
01329 mHabTerra[ht] = minT;
01330 else if ((mOwner->HabCenter(ht) - minT) < (maxT - mOwner->HabCenter(ht)))
01331 mHabTerra[ht] = maxT;
01332 else
01333 mHabTerra[ht] = Random(2) ? minT : maxT;
01334 }
01335 }
01336
01337 long endHab = mOwner->HabFactor(this);
01338 Message * mess = fleet->NCGetOwner()->AddMessage("Remote Terraform", this);
01339 mess->AddItem("Terraforming fleet", fleet);
01340 mess->AddLong("Start Hab", startHab);
01341 mess->AddLong("End Hab", endHab);
01342
01343 if (startHab != endHab && mOwner != fleet->GetOwner()) {
01344 mess = mOwner->AddMessage("Remote Terraform", this);
01345 mess->AddItem("Terraforming fleet", fleet);
01346 mess->AddLong("Start Hab", startHab);
01347 mess->AddLong("End Hab", endHab);
01348 }
01349 }