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

Ship.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 "Hull.h"
00029 
00030 #ifdef _DEBUG
00031 #define new DEBUG_NEW
00032 #endif
00033 
00034 Cost Ship::mUpCost;
00035 
00036 Ship::Ship()
00037 {
00038         ReCost = 0;
00039         ResetSeen();
00040         ResetDefaults();
00041 
00042         mCannotBuild = NULL;    // for starting ships
00043 }
00044 
00045 Ship::~Ship()
00046 {
00047 }
00048 
00049 void Ship::Cleanup()
00050 {
00051         mUpCost.Cleanup();
00052 }
00053 
00054 void Ship::ResetDefaults()
00055 {
00056         CVFuelCapacity = -1;
00057         CVFuelGen = -1;
00058         CVMass = -1;
00059         CCalcTachyon = false;
00060         CVCargoCapacity = -1;
00061         CVArmor = -1;
00062         CVShield = -1;
00063         CVInitAdj = -1;
00064         CCalcSpeedBonus = false;
00065         CVMines = -1;
00066         CVARMaxPop = -1;
00067         CVDock = -1;
00068 
00069         CCalcCompPower = false;
00070         CCalcJamming = false;
00071         CCalcCapacitors = false;
00072         CCalcDeflection = false;
00073 
00074         CCalcDampener = false;
00075         CCalcRepairRate = false;
00076         CVSafeSpeed = -1;
00077         CVMaxSpeed = -1;
00078         CVBattleSpeed = -1;
00079         CVFreeSpeed = -1;
00080         CVEngines = -1;
00081 
00082         CVColonize = -1;
00083         CVRefuel = -1;
00084         CVDriverSpeed = -1;
00085         CVCountDrivers = -1;
00086 
00087         CVCloaking = -1;
00088         CVSweeping = -1;
00089         CVScanSpace = -1;
00090         CVScanPen = -2;
00091         CVStealShip = -1;
00092         CVStealPlanet = -1;
00093         
00094         CVShoot = -1;
00095         CVNormalBomb = CVSmartBomb = CVTerraBomb = -1;
00096         
00097         CCalcNormalKillper = false;
00098         CVMinKill = CVInstKill = -1;
00099 
00100         CVMineAmount.erase(CVMineAmount.begin(), CVMineAmount.end());
00101         CVMineAmount.insert(CVMineAmount.begin(), MT_MAXIMUM, -1);
00102 
00103         CVFuelUsage.erase(CVFuelUsage.begin(), CVFuelUsage.end());
00104         CVFuelUsage.insert(CVFuelUsage.begin(), Rules::GetConstant("MaxSpeed"), -1);
00105 
00106         CalcedFuelUsage.erase(CalcedFuelUsage.begin(), CalcedFuelUsage.end());
00107         CalcedFuelUsage.insert(CalcedFuelUsage.begin(), Rules::GetConstant("MaxSpeed"), false);
00108 
00109         CVTechLevel.erase(CVTechLevel.begin(), CVTechLevel.end());
00110         CVTechLevel.insert(CVTechLevel.begin(), Rules::MaxTechType, -1);
00111 
00112         CVRadiation.erase(CVRadiation.begin(), CVRadiation.end());
00113         CVRadiation.insert(CVRadiation.begin(), Rules::MaxHabType, -1);
00114 }
00115 
00116 void Ship::ResetSeen()
00117 {
00118         mSeenHull.clear();
00119         mSeenHull.insert(mSeenHull.begin(), TheGame->NumberPlayers(), false);
00120         mSeenDesign.clear();
00121         mSeenDesign.insert(mSeenDesign.begin(), TheGame->NumberPlayers(), false);
00122 }
00123 
00124 bool Ship::ParseNode(const TiXmlNode * node, Player * player, bool other)
00125 {
00126         const TiXmlNode * child1;
00127         const char * ptr;
00128 
00129         const Component * comp;
00130 
00131         ptr = GetString(node->FirstChild("Name"));
00132         if (ptr != NULL)
00133                 mName = ptr;
00134 
00135         Message * mess;
00136         mBuilt = GetLong(node->FirstChild("Built"));
00137         if (mBuilt < 0) {
00138                 if (player == NULL)
00139                         mess = TheGame->AddMessage("Error: Invalid data");
00140                 else
00141                         mess = player->AddMessage("Error: Invalid data");
00142                 mess->AddLong("Number ships built", mBuilt);
00143                 return false;
00144         }
00145 
00146         comp = TheGame->ParseComponent(GetString(node->FirstChild("Hull")));
00147         mHull = dynamic_cast<const Hull *>(comp);
00148         if (mHull == NULL) {
00149                 if (player == NULL)
00150                         mess = TheGame->AddMessage("Error: Invalid hull for ship design");
00151                 else
00152                         mess = player->AddMessage("Error: Invalid hull for ship design");
00153                 mess->AddItem(mName.c_str(), GetString(node->FirstChild("Hull")));
00154                 return false;
00155         }
00156 
00157         mGraphicNumber = GetLong(node->FirstChild("GraphicNumber"), -1);
00158         if (mGraphicNumber < 1) {
00159                 if (player == NULL)
00160                         mess = TheGame->AddMessage("Error: Invalid ship graphic for ship design");
00161                 else
00162                         mess = player->AddMessage("Error: Invalid ship graphic for ship design");
00163                 mess->AddItem(mName.c_str(), GetString(node->FirstChild("GraphicNumber")));
00164                 return false;
00165         }
00166 
00167         mGift = GetBool(node->FirstChild("Gift"));
00168 
00169         long amount;
00170         mSlots.erase(mSlots.begin(), mSlots.end());     // in case this is a existing design, shouldn't happen
00171         for (child1 = node->FirstChild("Slot"); child1; child1 = child1->NextSibling("Slot")) {
00172                 amount = GetLong(child1->FirstChild("Number"));
00173                 comp = TheGame->ParseComponent(GetString(child1->FirstChild("Component")));
00174 
00175                 mSlots.insert(mSlots.end(), Slot(comp, amount, mSlots.size(), mHull->GetSlot(mSlots.size())));
00176         }
00177 
00178         if (other)
00179                 return true;
00180         else
00181                 return IsValidDesign();
00182 }
00183 
00184 void Ship::WriteNode(TiXmlNode * node, bool Host, bool Owner, bool SeeDesign) const
00185 {
00186         if (Host)
00187                 Owner = SeeDesign = true;
00188         if (Owner)
00189                 SeeDesign = true;
00190 
00191         AddString(node, "Hull", mHull->GetName().c_str());
00192         AddLong(node, "GraphicNumber", mGraphicNumber);
00193         if (Owner) {
00194                 AddLong(node, "Built", mBuilt);
00195                 AddString(node, "Gift", mGift ? "true" : "false");
00196         }
00197 
00198         if (SeeDesign) {
00199                 AddString(node, "Name", mName.c_str());
00200                 deque<Slot>::const_iterator si;
00201                 for (si = mSlots.begin(); si != mSlots.end(); ++si) {
00202                         if (si->GetCount() > 0) {
00203                                 TiXmlElement slot("Slot");
00204                                 AddLong(&slot, "Number", si->GetCount());
00205                                 AddString(&slot, "Component", si->GetComp()->GetName().c_str());
00206                                 node->InsertEndChild(slot);
00207                         } else {
00208                                 AddString(node, "Slot", "");
00209                         }
00210                 }
00211         } else if (!(mHull->GetHullType() & HC_BASE))
00212                 AddLong(node, "Mass", GetMass());
00213 }
00214 
00215 bool Ship::IsValidDesign() const                                                // is this design valid (no weapons in the engine slot...)
00216 {
00217         if (mHull->GetType() != CT_HULL && mHull->GetType() != CT_BASE)
00218                 return false;
00219 
00220         if (mSlots.size() > mHull->GetNumberSlots())
00221                 return false;
00222 
00223         unsigned int i;
00224         bool ValidEngine = mHull->GetType() == CT_BASE;
00225 
00226         for (i = 0; i < mSlots.size(); ++i) {
00227                 if (mSlots[i].GetCount() == 0)
00228                         continue;
00229 
00230                 // too many things
00231                 if (mSlots[i].GetCount() > mHull->GetSlot(i).GetCount())
00232                         return false;
00233 
00234                 // is this type of component allowed in this slot?
00235                 if (!mHull->GetSlot(i).IsAllowed(mSlots[i].GetComp()->GetType()))
00236                         return false;
00237 
00238                 if (!mSlots[i].GetComp())
00239                         return false;
00240 
00241                 if (!(mSlots[i].GetComp()->GetHullType() & mHull->GetHullType()))
00242                         return false;
00243 
00244                 if (!ValidEngine && mHull->GetSlot(i).IsAllowed(CT_ENGINE) && mSlots[i].GetCount() == mHull->GetSlot(i).GetCount())
00245                         ValidEngine = true;
00246         }
00247 
00248         return ValidEngine;
00249 }
00250 
00251 bool Ship::IsValidDesign(const Player * player) const   // can this player build this ship (right PRT/LRT and tech levels)
00252 {
00253 //      assert(ValidDesign());
00254         if (!mHull->IsBuildable(player))
00255                 return false;
00256 
00257         deque<Slot>::const_iterator i;
00258         for (i = mSlots.begin(); i != mSlots.end(); ++i) {
00259                 if (i->GetComp() != NULL && !i->GetComp()->IsBuildable(player))
00260                         return false;
00261         }
00262 
00263         return true;
00264 }
00265 
00266 // Get the gate to use when sending a fleet through this base
00267 // Note that it could easily have determined the 'best' gate to use
00268 // by picking the one that gives the smallest damage.
00269 // However, that may help IT too much.
00270 // This can be changed later if the balance is looked at.
00271 const Component * Ship::GetGate() const
00272 {
00273         for (unsigned int i = 0; i < mSlots.size(); ++i) {
00274                 if (mSlots[i].GetComp()->GetGateMass() != 0)
00275                         return mSlots[i].GetComp();
00276         }
00277 
00278         return NULL;
00279 }
00280 
00281 const Cost & Ship::GetCost(const Player * owner, const Ship * from /*=NULL*/, const Planet * planet /*=NULL*/) const
00282 {
00283         bool upgrade = from != NULL;
00284         bool sameHull = false;
00285         if (planet == NULL || from == NULL)     upgrade = false;
00286         if (!(mHull->GetType() | CT_BASE))      upgrade = false;
00287         if (upgrade && mHull == from->mHull)
00288                 sameHull = true;
00289 
00290         if (ReCost <= 0 || (TheGame->GetTurnPhase() > TP_TECH_CHECK1 && ReCost < TP_TECH_CHECK1) || (TheGame->GetTurnPhase() > TP_TECH_CHECK2 && ReCost < TP_TECH_CHECK2) || (TheGame->GetTurnPhase() > TP_TECH_CHECK3 && ReCost < TP_TECH_CHECK3)) {
00291                 const_cast<Ship *>(this)->ReCost = TheGame->GetTurnPhase();
00292                 if (!sameHull) {
00293                         const_cast<Ship *>(this)->CVCost = mHull->GetCost(owner);
00294                 } else
00295                         mUpCost.Zero();
00296 
00297                 // loop through slots on the ship
00298                 int number;
00299                 for (unsigned int i = 0; i < mSlots.size(); ++i) {
00300                         if (mSlots[i].GetComp() != NULL) {
00301                                 if (sameHull && mSlots[i].GetComp() == from->mSlots[i].GetComp())
00302                                         number = mSlots[i].GetCount() - from->mSlots[i].GetCount();
00303                                 else
00304                                         number = mSlots[i].GetCount();
00305 
00306                                 if (number > 0) {
00307                                         if (sameHull)
00308                                                 mUpCost += mSlots[i].GetComp()->GetCost(owner) * number;
00309                                         else
00310                                                 const_cast<Ship *>(this)->CVCost += mSlots[i].GetComp()->GetCost(owner) * number;
00311                                 } else if (number < 0) {
00312                                         Cost c;
00313                                         c = mSlots[i].GetComp()->GetCost(owner);
00314                                         ScrapRecover(c, -number, planet);
00315                                         mUpCost -= c;
00316                                 }
00317 
00318                                 if (sameHull && mSlots[i].GetComp() != from->mSlots[i].GetComp() && from->mSlots[i].GetComp() != NULL) {
00319                                         mUpCost += mSlots[i].GetComp()->GetCost(owner) * mSlots[i].GetCount();
00320 
00321                                         Cost c;
00322                                         c = from->mSlots[i].GetComp()->GetCost(owner);
00323                                         ScrapRecover(c, from->mSlots[i].GetCount(), planet);
00324                                         mUpCost -= c;
00325                                 }
00326                         }
00327                 }
00328 
00329                 if (IsGift()) {
00330                         for (CargoType ct = 0; ct < Rules::MaxMinType; ++ct)
00331                                 const_cast<Ship *>(this)->CVCost[ct] = long(CVCost[ct] * Rules::GetConstant("GiftPercent") + .5);
00332                 }
00333         }
00334 
00335         if (upgrade && !sameHull) {
00336                 mUpCost = CVCost;
00337                 Cost fr = from->GetCost(owner);
00338                 ScrapRecover(fr, 1, planet);
00339                 mUpCost -= fr;
00340                 return mUpCost;
00341         }
00342 
00343         return CVCost;
00344 }
00345 
00346 void Ship::ScrapRecover(Cost & c, int number, const Planet * planet) const
00347 {
00348         if (number == 0) {
00349                 c.Zero();
00350         } else {
00351                 c.SetResources(long(c.GetResources() * number * (Rules::ScrapResource(planet) + 1.0) / 2.0));
00352                 c.SetCrew(c.GetCrew() * number);        // 100% crew recovery
00353                 for (CargoType ct = 0; ct < Rules::MaxMinType; ++ct)
00354                         c[ct] = long(c[ct] * number * Rules::ScrapRecover(planet, false));
00355         }
00356 }
00357 
00358 void Ship::CopyDesign(const Ship * copy, bool IsGift)
00359 {
00360         mName = copy->mName;
00361         mGraphicNumber = copy->mGraphicNumber;
00362         mGift = IsGift;
00363         mHull = copy->mHull;
00364         mBuilt = 0;
00365         ReCost = 0;
00366 
00367         mSlots.insert(mSlots.begin(), copy->mSlots.begin(), copy->mSlots.end());
00368 
00369         ResetDefaults();
00370 }
00371 
00372 void Ship::Upgrade(const Player * player)
00373 {
00374         const Component * best;
00375         for (deque<Slot>::iterator i = mSlots.begin(); i != mSlots.end(); ++i) {
00376                 if (i->GetComp() != NULL) {
00377                         best = TheGame->GetBestComp(player, i->GetComp()->GetValueType(), (mHull->GetHullType() & HC_COL) != 0);
00378                         if (best != NULL)
00379                                 i->SetComp(best);
00380                 }
00381         }
00382 
00383         ResetDefaults();
00384 }
00385 
00386 bool operator==(const Ship & s1, const Ship & s2)
00387 {
00388         if (s1.mHull != s2.mHull)
00389                 return false;
00390 
00391         if (s1.mGift != s2.mGift)
00392                 return false;
00393 
00394         if (s1.mSlots.size() != s2.mSlots.size())
00395                 return false;
00396 
00397         for (int i = 0; i < s1.mSlots.size(); ++i) {
00398                 if (s1.mSlots[i] != s2.mSlots[i])
00399                         return false;
00400         }
00401 
00402         return true;
00403 }
00404 
00405 
00406 // scanning is a bit complex due to how scanners add to each other and because of builtin scanning
00407 double lGetScanPen(double v, const Slot & s)
00408 {
00409         if (s.GetComp() != NULL)
00410                 return Rules::CalcScanning(v, s.GetComp()->GetScanPen(), s.GetCount());
00411         else
00412                 return v;
00413 }
00414 
00415 long Ship::GetScanPen(const Player * player, long pop /*= 0*/) const
00416 {
00417         if (CVScanPen == -2) {
00418                 const_cast<Ship *>(this)->CVScanPen = long(accumulate(  mSlots.begin(),
00419                                                                         mSlots.end(),
00420                                                                         Rules::CalcScanning(player->BuiltinScan(player, mHull->GetHullType(), true, pop),
00421                                                                                                                 mHull->GetScanPen(),
00422                                                                                                                 1),
00423                                                                         lGetScanPen));
00424         }
00425         return CVScanPen;
00426 }
00427 
00428 double lGetScanSpace(double v, const Slot & s)
00429 {
00430         if (s.GetComp() != NULL)
00431                 return Rules::CalcScanning(v, s.GetComp()->GetScanSpace(), s.GetCount());
00432         else
00433                 return v;
00434 }
00435 
00436 long Ship::GetScanSpace(const Player * player, long pop /*= 0*/) const
00437 {
00438         if (CVScanSpace == -1) {
00439                 const_cast<Ship *>(this)->CVScanSpace = long(accumulate(        mSlots.begin(),
00440                                                                         mSlots.end(),
00441                                                                         Rules::CalcScanning(player->BuiltinScan(player, mHull->GetHullType(), false, pop),
00442                                                                                                                 mHull->GetScanSpace(),
00443                                                                                                                 1),
00444                                                                         lGetScanSpace));
00445         }
00446         return CVScanSpace;
00447 }
00448 
00449 long lGetTechLevel(long v, const Slot & s, TechType t)
00450 {
00451         if (s.GetComp() != NULL) {
00452                 if (t < Rules::MaxTechType)
00453                         return max(v, s.GetComp()->GetTech(t));
00454                 else    // MT Parts, add em up
00455                         return v + (s.GetComp()->GetID() == t - Rules::MaxTechType) ? s.GetCount() : 0;
00456         } else
00457                 return v;
00458 }
00459 
00460 long Ship::TechLevel(TechType tech) const
00461 {
00462         if (tech >= Rules::MaxTechType || CVTechLevel[tech] == -1) {
00463                 long Result = accumulate(       mSlots.begin(),
00464                                                                         mSlots.end(),
00465                                                                         (tech < Rules::MaxTechType) ? mHull->GetTech(tech) : ((mHull->GetID() == tech - Rules::MaxTechType) ? 1 : 0),
00466                                                                         lGetTechLevel,
00467                                                                         tech);
00468                 if (tech < Rules::MaxTechType)
00469                         const_cast<Ship *>(this)->CVTechLevel[tech] = Result;
00470 
00471                 return Result;
00472         } else
00473                 return CVTechLevel[tech];
00474 }
00475 
00476 long lGetSweeping (long v, const Slot & s, long rb)
00477 {
00478         if (s.GetComp() != NULL)
00479                 return v + s.GetComp()->GetSweeping(rb);
00480         else
00481                 return v;
00482 }
00483 
00484 long Ship::GetSweeping() const
00485 {
00486         if (CVSweeping == -1)
00487                 const_cast<Ship *>(this)->CVSweeping = accumulate(mSlots.begin(),
00488                                                                                 mSlots.end(),
00489                                                                                 mHull->GetSweeping((mHull->GetHullType() & HC_BASE) ? 1 : 0),
00490                                                                                 lGetSweeping,
00491                                                                                 (mHull->GetHullType() & HC_BASE) ? 1 : 0);
00492 
00493         return CVSweeping;
00494 }
00495 
00496 // retro is 0x0111
00497 // orbital adjuster is 0x0232
00498 long lGetTerraPower(long v, const Slot & s, long type)
00499 {
00500         if (s.GetComp() == NULL)
00501                 return v;
00502         else {
00503                 if (!(s.GetComp()->GetTerraType() & type & 0x000f))                     // check limit to start or to tech
00504                         return v;
00505                 else if (!(s.GetComp()->GetTerraType() & type & 0x00f0))        // check terraform or deterraform capability
00506                         return v;
00507                 else if (!(s.GetComp()->GetTerraType() & type & 0x0f00))        // check if bomb or not
00508                         return v;
00509                 else
00510                         return v + s.GetComp()->GetTerraPower() * s.GetCount();
00511         }
00512 }
00513 
00514 //      to ask for +terra: type is: 0x12 to initial (if deterraformed for some reason) 0x22 to tech of ship owner
00515 //      to ask for -terra: type is: 0x11 to initial, 0x21 to tech of ship owner
00516 long Ship::GetTerraPower(long type) const
00517 {
00518         return accumulate(      mSlots.begin(),
00519                                                 mSlots.end(),
00520                                                 (mHull->GetTerraType() & type) ? mHull->GetTerraPower() : 0,
00521                                                 lGetTerraPower,
00522                                                 type);
00523 }
00524 
00525 long lGetMineAmount(long v, const Slot & s, long type)
00526 {
00527         if (s.GetComp() != NULL)
00528                 return v + (s.GetComp()->GetMineType() == type) ? s.GetComp()->GetMineAmount() * s.GetCount() : 0;
00529         else
00530                 return v;
00531 }
00532 
00533 long Ship::GetMineAmount(long type) const
00534 {
00535         if (CVMineAmount[type-1] == -1) {
00536                 long Result = accumulate(mSlots.begin(),
00537                                                                 mSlots.end(),
00538                                                                 (mHull->GetMineType() == type) ? mHull->GetMineAmount() : 0,
00539                                                                 lGetMineAmount,
00540                                                                 type);
00541 
00542                 if (mHull->GetHullType() & HC_LAYER)
00543                         Result *= 2;
00544 
00545                 const_cast<Ship *>(this)->CVMineAmount[type-1] = Result;
00546         }
00547         return CVMineAmount[type-1];
00548 }
00549 
00550 long lGetArmor(long v, const Slot & s, const Player * p)
00551 {
00552         if (s.GetComp() != NULL) {
00553                 if (s.GetComp()->GetType() == CT_ARMOR)
00554                         v += long(s.GetComp()->GetArmor() * s.GetCount() * p->ArmorFactor());
00555                 else
00556                         v += s.GetComp()->GetArmor() * s.GetCount();
00557         }
00558 
00559         return v;
00560 }
00561 
00562 long Ship::GetArmor(const Player * p) const
00563 {
00564         if (CVArmor == -1) {
00565                 const_cast<Ship *>(this)->CVArmor =
00566                                         accumulate(     mSlots.begin(),
00567                                                                 mSlots.end(),
00568                                                                 mHull->GetArmor(),
00569                                                                 lGetArmor,
00570                                                                 p);
00571         }
00572         return CVArmor;
00573 }
00574 
00575 long lGetShield(long v, const Slot & s, const Player * p)
00576 {
00577         if (s.GetComp() != NULL)
00578                 v += long(s.GetComp()->GetShield() * s.GetCount() * p->ShieldFactor());
00579 
00580         return v;
00581 }
00582 
00583 long Ship::GetShield(const Player * p) const
00584 {
00585         if (CVShield == -1) {
00586                 const_cast<Ship *>(this)->CVShield =
00587                                         accumulate(     mSlots.begin(),
00588                                                                 mSlots.end(),
00589                                                                 mHull->GetShield(),
00590                                                                 lGetShield,
00591                                                                 p);
00592         }
00593         return CVShield;
00594 }
00595 
00596 double lGetFuelUsage(double v, const Slot & s, long speed)
00597 {
00598         if (s.GetComp() != NULL && s.GetComp()->GetType() == CT_ENGINE) {
00599                 double Result = s.GetComp()->GetFuelUsage(speed);
00600                 if (Result < 0)
00601                         Result *= s.GetCount();
00602                 return v == 0 ? Result : min(v, Result);
00603         } else
00604                 return v;
00605 }
00606 
00607 double Ship::GetFuelUsage(long speed) const
00608 {
00609         if (!CalcedFuelUsage[speed-1]) {
00610                 const_cast<Ship *>(this)->CalcedFuelUsage[speed-1] = true;
00611                 const_cast<Ship *>(this)->CVFuelUsage[speed-1] =
00612                                 accumulate(     mSlots.begin(),
00613                                                         mSlots.end(),
00614                                                         0.0,
00615                                                         lGetFuelUsage,
00616                                                         speed);
00617         }
00618 
00619         return CVFuelUsage[speed-1];
00620 }
00621 
00622 long lGetEngines(long v, const Slot & s)
00623 {
00624         if (s.GetComp() != NULL && s.GetComp()->GetType() == CT_ENGINE)
00625                 return v + s.GetCount();
00626         else
00627                 return v;
00628 }
00629 
00630 long Ship::GetEngines() const
00631 {
00632         if (CVEngines == -1)
00633                 const_cast<Ship *>(this)->CVEngines =
00634                                 accumulate(     mSlots.begin(),
00635                                                         mSlots.end(),
00636                                                         0,
00637                                                         lGetEngines);
00638 
00639         return CVEngines;
00640 }
00641 
00642 long lGetCloaking(long v, const Slot & s)
00643 {
00644         if (s.GetComp() != NULL)
00645                 return v + s.GetComp()->GetCloaking() * s.GetCount();
00646         else
00647                 return v;
00648 }
00649 
00650 long Ship::GetCloaking() const
00651 {
00652         if (CVCloaking == -1)
00653                 const_cast<Ship *>(this)->CVCloaking = GetMass() *
00654                         accumulate(mSlots.begin(),
00655                                                 mSlots.end(),
00656                                                 mHull->GetCloaking(),
00657                                                 lGetCloaking);
00658         return CVCloaking;
00659 }
00660 
00661 long lCountDrivers(long v, const Slot & s, long speed)
00662 {
00663         if (s.GetComp() != NULL && s.GetComp()->GetDriverSpeed() == speed)
00664                 v += s.GetCount();
00665 
00666         return v;
00667 }
00668 
00669 long Ship::CountDrivers() const
00670 {
00671         if (CVCountDrivers == -1) {
00672                 const_cast<Ship *>(this)->CVCountDrivers =
00673                                 accumulate(     mSlots.begin(),
00674                                                         mSlots.end(),
00675                                                         (mHull->GetDriverSpeed() == GetDriverSpeed()) ? 1 : 0,
00676                                                         lCountDrivers,
00677                                                         GetDriverSpeed());
00678         }
00679 
00680         return CVCountDrivers;
00681 }
00682 
00683 bool Ship::DoesRadiate(HabType ht) const
00684 {
00685         if (CVRadiation[ht] != -1)
00686                 return CVRadiation[ht] ? true : false;
00687         const_cast<Ship *>(this)->CVRadiation[ht] = 1;
00688         if (mHull->GetRadiation() == ht)
00689                 return true;
00690         for (deque<Slot>::const_iterator i = mSlots.begin(); i != mSlots.end(); ++i)
00691                 if (i->GetComp() != NULL && i->GetComp()->GetRadiation() == ht)
00692                         return true;
00693         const_cast<Ship *>(this)->CVRadiation[ht] = 0;
00694         return false;
00695 }
00696 
00697 long Ship::GetRating() const
00698 {
00699         if (CVRating == -1) {
00700                 const_cast<Ship *>(this)->CVShoot = 0;
00701                 long Rating = 0;
00702                 double value;
00703                 for (deque<Slot>::const_iterator i = mSlots.begin(); i != mSlots.end(); ++i) {
00704                         value = 0.0;
00705                         switch (i->GetComp()->GetWeaponType()) {
00706                         case WT_BEAM:
00707                                 value = (i->GetComp()->GetRange() + 3.0) / 4.0 * (GetNetSpeed() / 10.0 + 0.4);
00708                                 value *= GetCapacitors();
00709                                 break;
00710                         case WT_SAPPER:
00711                                 value = (i->GetComp()->GetRange() - 1.0) / 4.0 * (GetNetSpeed() / 10.0 + 0.4);
00712                                 value *= GetCapacitors();
00713                                 break;
00714                         case WT_GATLING:
00715                                 value = (i->GetComp()->GetRange() + 4.0) / 4.0 * (GetNetSpeed() / 10.0 + 0.4);
00716                                 value *= GetCapacitors();
00717                                 break;
00718                         case WT_TORP:
00719                         case WT_MISSILE:
00720                                 value = (i->GetComp()->GetRange() - 2.0) / 2.0;
00721                                 break;
00722                         default:
00723                                 break;
00724                         }
00725 
00726                         if (value > 0.0) {
00727                                 const_cast<Ship *>(this)->CVShoot = 1;
00728                                 Rating += long(i->GetComp()->GetPower() * value);
00729                         }
00730                         if (i->GetComp()->GetBombType() != 0)
00731                         {
00732                                 Rating += long(i->GetComp()->GetKillper() * .2) + i->GetComp()->GetInstKill() * 2;
00733                         }
00734                 }
00735                 const_cast<Ship *>(this)->CVRating = Rating;
00736         }
00737 
00738         return CVRating;
00739 }
00740 
00741 bool Ship::CanShoot() const
00742 {
00743         if (CVShoot == -1)
00744                 GetRating();
00745 
00746         return CVShoot == 1 ? true : false;
00747 }
00748 
00749 // returns net battle speed where 10 is 2.5 and 2 is .5. 0 is stationary
00750 long Ship::GetNetSpeed() const
00751 {
00752         if (mHull->GetHullType() | HC_BASE)
00753                 return 0;
00754 
00755         long speed = GetBattleSpeed() - 2 + long(GetSpeedBonus() * 4);
00756         if (speed < 2)
00757                 speed = 2;
00758         if (speed > 10)
00759                 speed = 10;
00760 
00761         return speed;
00762 }
00763 
00764 long Ship::GetNetInit() const
00765 {
00766         return mHull->GetInit() + GetInitAdj();
00767 }
00768 
00769 bool Ship::IsBattleTarget(HullType hc) const
00770 {
00771         switch (hc) {
00772         case HC_NONE:
00773                 return false;
00774         case HC_ALL:
00775                 return true;
00776         case HC_UNARMED:
00777                 return !CanShoot();
00778         case HC_ARMED:
00779                 return CanShoot();
00780         case HC_BASE:
00781                 return (mHull->GetHullType() | HC_BASE) ? true : false;
00782         case HC_FUEL:
00783                 return (mHull->GetHullType() | HC_FUEL) ? true : false;
00784         case HC_FREIGHTER:
00785                 return (mHull->GetHullType() | HC_FREIGHTER) ? true : false;
00786         case HC_BOMBER:
00787                 return (mHull->GetHullType() | HC_BOMBER | HC_FREIGHTER) ? true : false;        // targeting bombers also gets freighters
00788         default:
00789                 return false;   // invalid battle order, target nothing
00790         }
00791 }
00792 
00793 long Ship::GetAttractiveCost(const Player * owner) const
00794 {
00795         long Result = 0;
00796         Cost c = GetCost(owner);
00797         Result = c.GetResources();
00798         for (int i = 0; i < Rules::MaxMinType; ++i) {
00799                 Result += Rules::GetArrayValue("AttractiveMineral", i) * c[i];
00800         }
00801 
00802         return Result;
00803 }
00804 
00805 double Ship::GetAccuracy(const Component & torp, const Ship * target) const
00806 {
00807         if (torp.GetWeaponType() != WT_TORP && torp.GetWeaponType() != WT_MISSILE)
00808                 return 0;
00809 
00810         double Result = torp.GetAccuracy();
00811         double temp = (1.0 - GetCompPower()) - (1.0 - target->GetJamming());
00812         if (temp > 0.0) // more comp power then jamming power
00813                 Result += (1.0 - Result) * temp;
00814         else if (temp < 0.0)    // more jamming then comp power
00815                 Result += Result * temp;
00816 
00817         return Result;
00818 }
00819 
00820 
00821 //Macros for the rest of the functions:
00822 // define a local function that adds current total, and component capability * count
00823 // make a member function that accumulates all slots using the local function, and initial value of the hull capability
00824 
00825 // Get the sum of the hull and all components for a Function
00826 #define GET_SHIP_SUM(Function)                                                          \
00827         long lGet##Function(long v, const Slot & s)                             \
00828         {                                                                                                               \
00829                 if (s.GetComp() != NULL)                                                        \
00830                         return v + s.GetComp()->Get##Function() * s.GetCount(); \
00831                 else                                                                                            \
00832                         return v;                                                                               \
00833         }                                                                                                               \
00834                                                                                                                         \
00835         long Ship::Get##Function() const                                                \
00836         {                                                                                                               \
00837                 if (CV##Function == -1)                                                         \
00838                         const_cast<Ship *>(this)->CV##Function = accumulate(mSlots.begin(), mSlots.end(), mHull->Get##Function(), lGet##Function);      \
00839                 return CV##Function;                                                            \
00840         }
00841 #define GET_SHIP_SUMD(Function)                                                         \
00842         double lGet##Function(double v, const Slot & s)                 \
00843         {                                                                                                               \
00844                 if (s.GetComp() != NULL)                                                        \
00845                         return v + s.GetComp()->Get##Function() * s.GetCount(); \
00846                 else                                                                                            \
00847                         return v;                                                                               \
00848         }                                                                                                               \
00849                                                                                                                         \
00850         double Ship::Get##Function() const                                              \
00851         {                                                                                                               \
00852                 if (!CCalc##Function) {                                                         \
00853                         const_cast<Ship *>(this)->CCalc##Function = true;\
00854                         const_cast<Ship *>(this)->CV##Function = accumulate(mSlots.begin(), mSlots.end(), mHull->Get##Function(), lGet##Function);      \
00855                 }                                                                                                       \
00856                 return CV##Function;                                                            \
00857         }
00858 // Get the product of all components multiplied by each other
00859 #define GET_SHIP_PRODUCT(Function, Min)                                         \
00860         double lGet##Function(double v, const Slot & s)                 \
00861         {                                                                                                               \
00862                 if (s.GetComp() != NULL)                                                        \
00863                         return v * pow(double(s.GetComp()->Get##Function()), s.GetCount());     \
00864                 else                                                                                            \
00865                         return v;                                                                               \
00866         }                                                                                                               \
00867                                                                                                                         \
00868         double Ship::Get##Function() const                                              \
00869         {                                                                                                               \
00870                 if (!CCalc##Function) {                                                         \
00871                         const_cast<Ship *>(this)->CCalc##Function = true;\
00872                         double Result = accumulate(mSlots.begin(), mSlots.end(), mHull->Get##Function(), lGet##Function);       \
00873                         if (Result < Min) Result = Min;                                 \
00874                         const_cast<Ship *>(this)->CV##Function = Result;\
00875                 }                                                                                                       \
00876                 return CV##Function;                                                            \
00877         }
00878 // Get the max value of all on components on the ship
00879 #define GET_SHIP_MAX(Function)                                                          \
00880         long lGet##Function(long v, const Slot & s)                             \
00881         {                                                                                                               \
00882                 if (s.GetComp() != NULL)                                                        \
00883                         return max(v, s.GetComp()->Get##Function());    \
00884                 else                                                                                            \
00885                         return v;                                                                               \
00886         }                                                                                                               \
00887                                                                                                                         \
00888         long Ship::Get##Function() const                                                \
00889         {                                                                                                               \
00890                 if (CV##Function == -1)                                                         \
00891                         const_cast<Ship *>(this)->CV##Function = accumulate(mSlots.begin(), mSlots.end(), mHull->Get##Function(), lGet##Function);      \
00892                 return CV##Function;                                                            \
00893         }
00894 #define GET_SHIP_MAXD(Function)                                                         \
00895         double lGet##Function(double v, const Slot & s)                 \
00896         {                                                                                                               \
00897                 if (s.GetComp() != NULL)                                                        \
00898                         return max(v, s.GetComp()->Get##Function());    \
00899                 else                                                                                            \
00900                         return v;                                                                               \
00901         }                                                                                                               \
00902                                                                                                                         \
00903         double Ship::Get##Function() const                                              \
00904         {                                                                                                               \
00905                 if (!CCalc##Function) {                                                         \
00906                         const_cast<Ship *>(this)->CCalc##Function = true;\
00907                         const_cast<Ship *>(this)->CV##Function = accumulate(mSlots.begin(), mSlots.end(), mHull->Get##Function(), lGet##Function);      \
00908                 }                                                                                                       \
00909                 return CV##Function;                                                            \
00910         }
00911 // Get true if the ship has the capability, false otherwise
00912 #define GET_SHIP_HAS(Function)                                                          \
00913         bool Ship::Can##Function() const                                                \
00914         {                                                                                                               \
00915                 if (CV##Function != -1)                                                         \
00916                         return CV##Function ? true : false;                             \
00917                 const_cast<Ship *>(this)->CV##Function = 1;                     \
00918                 if (mHull->Can##Function())                                                     \
00919                         return true;                                                                    \
00920                 for (deque<Slot>::const_iterator i = mSlots.begin(); i != mSlots.end(); ++i)    \
00921                         if (i->GetComp() != NULL && i->GetComp()->Can##Function())      \
00922                                 return true;                                                            \
00923                 const_cast<Ship *>(this)->CV##Function = 0;                     \
00924                 return false;                                                                           \
00925         }
00926 
00927 GET_SHIP_SUM(FuelCapacity)
00928 GET_SHIP_SUM(FuelGen)
00929 GET_SHIP_SUM(Mass)
00930 GET_SHIP_SUMD(Tachyon)
00931 GET_SHIP_SUM(CargoCapacity)
00932 GET_SHIP_SUM(InitAdj)
00933 GET_SHIP_SUMD(SpeedBonus)
00934 GET_SHIP_SUM(Mines)
00935 GET_SHIP_SUM(ARMaxPop)
00936 GET_SHIP_SUM(Dock)
00937 
00938 GET_SHIP_PRODUCT(CompPower, 0.05)
00939 GET_SHIP_PRODUCT(Jamming, (mHull->GetHullType() & HC_BASE) ? 0.25 : 0.05)
00940 GET_SHIP_PRODUCT(Capacitors, 0.0)
00941 GET_SHIP_PRODUCT(Deflection, 0.0)
00942 
00943 GET_SHIP_MAXD(Dampener)
00944 GET_SHIP_MAXD(RepairRate)
00945 GET_SHIP_MAX(SafeSpeed)
00946 GET_SHIP_MAX(MaxSpeed)
00947 GET_SHIP_MAX(BattleSpeed)
00948 GET_SHIP_MAX(FreeSpeed)
00949 GET_SHIP_MAX(DriverSpeed)
00950 
00951 GET_SHIP_HAS(Colonize)
00952 GET_SHIP_HAS(Refuel)
00953 GET_SHIP_HAS(StealShip)
00954 GET_SHIP_HAS(StealPlanet)
00955 GET_SHIP_HAS(SmartBomb)
00956 GET_SHIP_HAS(TerraBomb)
00957 GET_SHIP_HAS(NormalBomb)
00958 GET_SHIP_HAS(JumpGate)
00959 
00960 GET_SHIP_SUMD(NormalKillper)
00961 //GET_SHIP_SUM(SmartKillper)
00962 GET_SHIP_SUM(MinKill)
00963 GET_SHIP_SUM(InstKill)

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