00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "FSServer.h"
00027
00028 #include "Hull.h"
00029
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;
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());
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
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
00231 if (mSlots[i].GetCount() > mHull->GetSlot(i).GetCount())
00232 return false;
00233
00234
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
00252 {
00253
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
00267
00268
00269
00270
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 , const Planet * planet ) 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
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);
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
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 ) 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 ) 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
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
00497
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))
00504 return v;
00505 else if (!(s.GetComp()->GetTerraType() & type & 0x00f0))
00506 return v;
00507 else if (!(s.GetComp()->GetTerraType() & type & 0x0f00))
00508 return v;
00509 else
00510 return v + s.GetComp()->GetTerraPower() * s.GetCount();
00511 }
00512 }
00513
00514
00515
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
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;
00788 default:
00789 return false;
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)
00813 Result += (1.0 - Result) * temp;
00814 else if (temp < 0.0)
00815 Result += Result * temp;
00816
00817 return Result;
00818 }
00819
00820
00821
00822
00823
00824
00825
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
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
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
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
00962 GET_SHIP_SUM(MinKill)
00963 GET_SHIP_SUM(InstKill)