Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List

Planet.cpp

00001 /*
00002 Copyright 2003 - 2005 Elliott Kleinrock, Dan Neely, Kurt W. Over, Damon Domjan
00003 
00004 This file is part of FreeStars, a free clone of the Stars! game.
00005 
00006 FreeStars is free software; you can redistribute it and/or modify
00007 it under the terms of the GNU General Public License as published by
00008 the Free Software Foundation; either version 2 of the License, or
00009 (at your option) any later version.
00010 
00011 FreeStars is distributed in the hope that it will be useful,
00012 but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 GNU General Public License for more details.
00015 
00016 You should have received a copy of the GNU General Public License
00017 along with FreeStars; if not, write to the Free Software
00018 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 
00020 The full GPL Copyright notice should be in the file COPYING.txt
00021 
00022 Contact:
00023 Email Elliott at 9jm0tjj02@sneakemail.com
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)  // leave immunes random
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;       // special value to allow placement later
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         // if we are creating a game, and it has an owner, add starting ships
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);      // HW isn't used if owner is already set.
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                 // change this once so the same value gets returned for every call
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                 // int((x-1.5)/6)*6+9
00421                 // int((x-150)/600)*600+900
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                 // find biggest and 2nd biggest attackers
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         // add everyones troop count to everyones message
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                 // attackers win
00489                 // First take losses from fight with defenders
00490                 MaxAttack->Strength = long(MaxAttack->Strength * (1.0-ratio));
00491                 if (MaxAttack2) {
00492                         MaxAttack2->Strength = long(MaxAttack2->Strength * (1.0-ratio));
00493                         // Max now fights Max2
00494                         MaxAttack->Strength -= MaxAttack2->Strength;
00495                 }
00496 
00497                 // calculate survivors
00498                 MaxAttack->amount = long(MaxAttack->amount * double(MaxAttack->Strength) / double(MaxAttack->InitStr));
00499 
00500                 // Send message to everyone
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 {        // if (ration > 1.0)
00516                 // defenders win
00517                 // calculate survivors
00518                 int survivors = long(GetPopulation() * (1.0 - double(AttackStr)/DefenseValue));
00519                 mPopulation = survivors;
00520                 // Send message to everyone
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();     // Done, delete everything about invasions on this planet
00542 }
00543 
00544 void Planet::TakePlanet(Player * invader, long amount)
00545 {
00546         if (invader != NULL) {
00547                 // get tech
00548                 if (GetOwner() == NULL) {       // colonized
00549                         if (amount < 1000)      // small colonizations don't get full benifit from artifacts
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 {        // invaded
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 {  // comp->GetTerraType() == -1
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         // sanity check, should never happen
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         // Check terra limits
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                 // OK we know which direction to move it, and know that it's valid
00758         long before = GetOwner()->HabFactor(this);
00759         const_cast<Planet *>(this)->mHabTerra[ht] += direction;         // move it temporarily
00760         long after = GetOwner()->HabFactor(this);
00761         const_cast<Planet *>(this)->mHabTerra[ht] -= direction;         // move it back
00762 
00763         return after - before;
00764 }
00765 
00766 bool Planet::Terraform(const Player * player, bool positive)    // Terraforms a world 1 tick, and returns true if any change was made
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)    // immune
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                 // OK we know which direction to move it, and know that it's valid
00797                 mHabTerra[ht] += direction;             // move it temporarily
00798                 long temp = player->HabFactor(this);
00799                 mHabTerra[ht] -= direction;             // move it back
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)        // cannot terraform this world
00813                 return false;
00814 
00815         // OK, now we know which to move, so do it
00816         mHabTerra[htMax] += dMax;
00817 
00818 //      assert(player->HabFactor(this) == ValMax);
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;       // pop up to max pop, then pop /2 up to 3x max, then 0
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                 // 10000 pop on a -10% world will lose 100 pop, so 10000 * -10 = 100000, +500 and /1000 gives 100
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                         // 10000 pop on a 100% world with 10% gr will grow by 1000
00928                         double Growth = GetPopulation() * currentHab / 100.0 * GetOwner()->GrowthRate();
00929                         if (PopFactor > 0.25) {
00930                                 // 250000 pop on a 100% world with 10% gr will grow by 25000:  2500 * 100 * 1000 / 10000 = 25000
00931                                 Growth *= 16.0 / 9.0;
00932                                 Growth *= (1.0-PopFactor) * (1.0-PopFactor);    // at 25% this works out to (3/4)^2 which is 9/16
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         // Add UR resources
00953         resources += (mScrapRes * resources) / (mScrapRes + resources);
00954 
00955         // first pay research tax
00956         if (mPayTax && owner->GetResearchField() != RESEARCH_ALCHEMY) {
00957                 long tax = long(resources * owner->GetResearchTax() + .5);
00958                 tax -= owner->GainTech(tax);    // returns unused portion
00959                 resources -= tax;
00960         }
00961 
00962         // TODO packet launch
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         // Left over resources
00975         if (resources > 0) {
00976                 // make minerals or research
00977                 if (!AutoAlchemy && owner->GetResearchField() != RESEARCH_ALCHEMY)
00978                         resources = owner->GainTech(resources); // returns unused portion
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         // Sum built messages
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         // preplant artifacts
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;       // allow this world to have a base
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)  // leave immunes random
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;  // 38 for 50 points
01120                         else
01121                                 mMinConc[i] += (player->GetStartConcentrations() + 2) / 4;      // 13 for 50 points
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;       // allow this world to have a base
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    // between min and max, set to ideal
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         // At some point, perhaps this should be changed to be the sum of positive and
01280         // negative terraforming, if there are is competing remote terraforming.
01281         // Or apply lowest terra tech first if cooperating ones.
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    // between min and max, set to ideal
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 }

Generated on Mon Aug 8 21:33:44 2005 for Freestars by  doxygen 1.4.2-20050421