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 "Stack.h"
00029 #include "TempFleet.h"
00030 #include "Hull.h"
00031 #include "Order.h"
00032 #include "Wormhole.h"
00033
00034 #include <stdlib.h>
00035 #include <algorithm>
00036 #include <functional>
00037
00038 #ifdef _DEBUG
00039 #define new DEBUG_NEW
00040 #endif
00041
00042
00043 Fleet::Fleet(int id, const CargoHolder &loc) : CargoHolder(loc), mStartPos(loc)
00044 {
00045 mID = id;
00046 Init();
00047 }
00048
00049 Fleet::Fleet()
00050 {
00051 Init();
00052 }
00053
00054 void Fleet::Init()
00055 {
00056 mName.erase();
00057 ResetDefaults();
00058 mCanLoadBy.clear();
00059 mCanLoadBy.insert(mCanLoadBy.begin(), TheGame->NumberPlayers(), false);
00060 mRepeatOrders = false;
00061
00062 mRepairRate = 2;
00063 mBattlePlan = 0;
00064 mRepeatOrders = false;
00065 mAlreadyFought = false;
00066 mHasMoved = false;
00067 mChasing = NULL;
00068 mDistMoved = 0;
00069 mFuel = 0;
00070 }
00071
00072 Fleet::~Fleet()
00073 {
00074 mStacks.clear();
00075 mChasers.clear();
00076 int i;
00077 for (i = 0; i < mOrders.size(); ++i)
00078 delete mOrders[i];
00079 }
00080
00081 void Fleet::ResetDefaults()
00082 {
00083
00084 CVCost.Zero();
00085 ReCost = 0;
00086 CVScanPen = -2;
00087 CVScanSpace = -1;
00088 CVMass = -1;
00089
00090 CVCloaking = -1;
00091 CVFuelCapacity = -1;
00092 CVFuelGen = -1;
00093 CVMass = -1;
00094 CCalcMaxMass = false;
00095 CCalcMaxTachyon = false;
00096 CVCargoCapacity = -1;
00097 CVMines = -1;
00098 CVSweeping = -1;
00099
00100 CCalcMaxDampener = false;
00101 CCalcMaxRepairRate = false;
00102 CVMinSafeSpeed = -1;
00103 CVMinMaxSpeed = -1;
00104 CVMinFreeSpeed = -1;
00105 CVMinBattleSpeed = -1;
00106
00107 CVColonize = -1;
00108 CVStealShip = -1;
00109 CVStealPlanet = -1;
00110 CVShoot = -1;
00111
00112 CCalcNormalKillper = false;
00113 CVMinKill = CVInstKill = -1;
00114 CVJumpGate = -1;
00115
00116 CVNormalBomb = CVSmartBomb = CVTerraBomb = -1;
00117
00118 CVMineAmount.erase(CVMineAmount.begin(), CVMineAmount.end());
00119 CVMineAmount.insert(CVMineAmount.begin(), MT_MAXIMUM, -1);
00120
00121 CVTechLevel.erase(CVTechLevel.begin(), CVTechLevel.end());
00122 CVTechLevel.insert(CVTechLevel.begin(), Rules::MaxTechType, -1);
00123
00124 CVRadiation.erase(CVRadiation.begin(), CVRadiation.end());
00125 CVRadiation.insert(CVRadiation.begin(), Rules::MaxHabType, -1);
00126 }
00127
00128 bool Fleet::ParseNode(const TiXmlNode * node, Player * player, bool other)
00129 {
00130 if (!CargoHolder::ParseNode(node, player))
00131 return false;
00132
00133 mStartPos = *this;
00134 const TiXmlNode * child1;
00135 const char * ptr;
00136
00137 if (mID < 1 || mID > (int)Rules::MaxFleets)
00138 return false;
00139
00140 ptr = GetString(node->FirstChild("Name"));
00141 if (ptr != NULL)
00142 mName = ptr;
00143
00144 child1 = node->FirstChild("Contains");
00145 if (child1 != NULL)
00146 mFuel = GetLong(child1->FirstChild("Fuel"));
00147
00148 if (!other) {
00149 mBattlePlan = GetLong(node->FirstChild("BattlePlan"));
00150 if (mBattlePlan < 0 || mBattlePlan >= Rules::GetConstant("MaxBattlePlans"))
00151 return false;
00152
00153 mRepeatOrders = GetBool(node->FirstChild("Repeat"));
00154
00155 Rules::ParseArrayBool(node->FirstChild("CanLoadBy"), "Race", "Number", mCanLoadBy);
00156 }
00157
00158 for (child1 = node->FirstChild("Stack"); child1; child1 = child1->NextSibling("Stack")) {
00159 Stack a;
00160 unsigned long c = GetLong(child1->FirstChild("ShipCount"));
00161 a.SetCount(c);
00162 unsigned long d = GetLong(child1->FirstChild("ShipDesign"));
00163 a.SetDesign(player->GetShipDesign(d));
00164 mStacks.push_back(a);
00165 mStacks.back().ParseNode(child1, player);
00166 mStacks.back().SetFleetIn(this);
00167 }
00168
00169 if (!other) {
00170 WayOrderList ords;
00171 ords.SetFleet(GetID());
00172 ords.ParseNode(node, player);
00173 ChangeWaypoints(ords);
00174 mBattlePlan = GetLong(node->FirstChild("BattlePlan"));
00175 }
00176
00177 return true;
00178 }
00179
00180 TiXmlNode * Fleet::WriteNode(TiXmlNode * node, const Player * viewer) const
00181 {
00182 CargoHolder::WriteNode(node, viewer);
00183
00184 if (viewer == NULL || viewer == GetOwner()) {
00185 TiXmlNode * child1;
00186 child1 = node->FirstChild("Contains");
00187 if (child1 == NULL) {
00188 child1 = new TiXmlElement("Contains");
00189 node->LinkEndChild(child1);
00190 }
00191 AddLong(child1, "Fuel", mFuel);
00192
00193 AddString(node, "Name", mName.c_str());
00194 AddLong(node, "BattlePlan", mBattlePlan);
00195 AddBool(node, "Repeat", mRepeatOrders);
00196 for (int i = 0; i < mOrders.size(); ++i)
00197 mOrders[i]->WriteNode(node);
00198 }
00199 if (viewer == NULL)
00200 node->LinkEndChild(Rules::WriteArrayBool("CanLoadBy", "Race", "Number", mCanLoadBy));
00201
00202 AddLong(node, "Mass", GetMass());
00203 deque<Stack>::const_iterator si;
00204 for (si = mStacks.begin(); si != mStacks.end(); ++si) {
00205 TiXmlElement stack("Stack");
00206 si->WriteNode(&stack, GetOwner(), viewer);
00207 node->InsertEndChild(stack);
00208 }
00209
00210 return node;
00211 }
00212
00213 const string Fleet::GetName(const Player * viewer) const
00214 {
00215 if (viewer == GetOwner() && !mName.empty())
00216 return mName;
00217 else
00218 {
00219 string str;
00220 const Ship * MostShips = NULL;
00221 long count = 0;
00222
00223
00224 deque<Stack>::const_iterator iter;
00225 for (iter = mStacks.begin(); iter != mStacks.end(); ++iter) {
00226 if (iter->GetCount() > count) {
00227 count = iter->GetCount();
00228 MostShips = iter->GetDesign();
00229 }
00230 }
00231
00232 str = MostShips->GetName();
00233 if (str.empty()) {
00234 str = MostShips->GetHull()->GetName();
00235 for (int i = 0; i < Rules::GetConstant("MaxShipDesigns"); ++i) {
00236 if (GetOwner()->GetShipDesign(i) == MostShips) {
00237 str += "(" + Long2String(i) + ")";
00238 break;
00239 }
00240 }
00241 }
00242
00243 if (viewer != GetOwner())
00244 str = GetOwner()->GetSingleName() + " " + str;
00245
00246 if (mStacks.size() > 1)
00247 str += '+';
00248 str += " #" + Long2String(mID);
00249 return str;
00250 }
00251 }
00252
00253 const BattlePlan * Fleet::GetBattlePlan() const
00254 {
00255 return mOwner->GetBattlePlan(mBattlePlan);
00256 }
00257
00258 bool Fleet::Process(FuncType func, bool arg)
00259 {
00260 switch (func) {
00261 case FTScrap:
00262 if (mOrders.size() > 0 && GetFirstOrder()->GetType() == OT_SCRAP)
00263 Scrap(false);
00264 return false;
00265 case FTRemoteMine:
00266 RemoteMine(arg);
00267 return false;
00268 case FTUnload0:
00269 ProcessTransport(false, arg);
00270 return false;
00271 case FTColonize0:
00272 Colonize();
00273 return false;
00274 case FTLoad0:
00275 ProcessTransport(true, arg);
00276 return false;
00277 case FTMove:
00278 if (!mHasMoved)
00279 return Move();
00280 else
00281 return false;
00282 case FTFreighterReproduction:
00283 FreighterReproduction();
00284 return false;
00285 case FTRefuel:
00286 Refuel();
00287 return false;
00288 case FTCheckWaypoint:
00289 CheckWaypoint();
00290 return false;
00291 case FTUnload1:
00292 if (mDoneWaypoint)
00293 ProcessTransport(false, arg);
00294 return false;
00295 case FTColonize1:
00296 if (mDoneWaypoint)
00297 Colonize();
00298 return false;
00299 case FTLoad1:
00300 if (mDoneWaypoint)
00301 ProcessTransport(true, arg);
00302 return false;
00303 case FTMerge:
00304 CheckMerge();
00305 return false;
00306 case FTClearWaypoint:
00307 ClearWaypoint();
00308 return false;
00309 case FTRemoteTerraform:
00310 RemoteTerraform(false);
00311 return false;
00312 case FTRepair:
00313 Repair();
00314 return false;
00315 default:
00316 return false;
00317 }
00318 }
00319
00320 void Fleet::CheckWaypoint()
00321 {
00322 if (mOrders.size() >= 2 && *this == *mOrders[1]->GetLocation()) {
00323 delete mOrders[0];
00324 mOrders.pop_front();
00325 mDoneWaypoint = true;
00326 } else
00327 mDoneWaypoint = false;
00328
00329
00330
00331 Fleet * f = dynamic_cast<Fleet *>(mOrders[0]->NCGetLocation());
00332 if (f != NULL) {
00333 if (!IsWith(*f)) {
00334 mOrders[0]->SetLocation(new Location(*this), true);
00335 WayOrder * wo = new WayOrder(f);
00336 wo->SetType(OT_NONE);
00337 wo->SetSpeed(GetBestSpeed(this, f, OT_PATROL));
00338 mOrders.insert(mOrders.end(), wo);
00339 }
00340 } else {
00341 if (dynamic_cast<Planet *>(mAlsoHere->at(0)) != NULL)
00342 mOrders[0]->SetLocation(mAlsoHere->at(0), false);
00343 else
00344 mOrders[0]->SetLocation(new Location(*this), true);
00345 }
00346 }
00347
00348 void Fleet::ClearWaypoint()
00349 {
00350 switch (mOrders[0]->GetType()) {
00351 case OT_NONE:
00352 case OT_COLONIZE:
00353 case OT_MERGE:
00354 case OT_TRANSFER:
00355 case OT_TRANSPORT:
00356 mOrders[0]->SetType(OT_NONE);
00357 break;
00358 case OT_REMOTEMINE:
00359 break;
00360 case OT_SCRAP:
00361 break;
00362 case OT_ROUTE:
00363 if (mOrders.size() < 2)
00364 SetNextRoute(InOrbit());
00365
00366 mOrders[0]->SetType(OT_NONE);
00367 break;
00368 case OT_LAYMINE:
00369
00370 break;
00371 case OT_PATROL:
00372
00373 break;
00374 default:
00375 break;
00376 }
00377 }
00378
00379 void Fleet::RemoteTerraform(bool bomb)
00380 {
00381 Planet * planet = InOrbit();
00382 if (planet != NULL &&
00383 planet->GetOwner() != NULL &&
00384 (planet->GetOwner()->GetRelations(GetOwner()) > PR_NEUTRAL || planet->GetBaseDesign() < 0))
00385 {
00386 planet->RemoteTerraform(this, bomb);
00387 }
00388 }
00389
00390 void Fleet::Repair()
00391 {
00392 if (mAlreadyFought || mRepairRate == 0)
00393 return;
00394
00395 double rate = Rules::GetFloat("RepairMoved", 0.01);
00396 if (mRepairRate == 2) {
00397 rate = Rules::GetFloat("RepairStill", 0.02);
00398 Planet * p = InOrbit();
00399 if (p != NULL) {
00400 rate = Rules::GetFloat("RepairOrbit", 0.03);
00401 if (GetOwner() == p->GetOwner()) {
00402 rate = Rules::GetFloat("RepairOrbitOwned", 0.05);
00403 if (p->GetBaseDesign() != NULL)
00404 rate = p->GetBaseDesign()->GetRepairRate();
00405 }
00406 }
00407 }
00408
00409
00410 rate *= GetOwner()->RepairFactor();
00411
00412
00413 rate += GetMaxRepairRate();
00414
00415 long repair;
00416 for (int i = 0; i < mStacks.size(); ++i) {
00417 if (mStacks[i].GetDamage() > 0) {
00418 repair = max(1L, long(mStacks[i].GetDesign()->GetArmor(GetOwner()) * rate + .5));
00419 mStacks[i].SetDamage(max(0L, mStacks[i].GetDamage() - repair));
00420 }
00421 }
00422 }
00423
00424 void Fleet::ProcessTransport(bool load, bool dunnage)
00425 {
00426 if (mOrders.size() == 0 || mOrders[0]->GetType() != OT_TRANSPORT)
00427 return;
00428
00429 WayOrderTransport * order = dynamic_cast<WayOrderTransport *>(mOrders[0]);
00430 if (!IsWith(*order->GetLocation()))
00431 return;
00432
00433 CargoHolder * dest = dynamic_cast<CargoHolder *>(order->NCGetLocation());
00434 if (dest == NULL)
00435 return;
00436
00437 for (int i = FUEL; i < Rules::MaxMinType; ++i) {
00438 if (load)
00439 ProcessLoad(dest, order->GetAction(i), i, order->GetValue(i), dunnage);
00440 else
00441 ProcessUnload(dest, order->GetAction(i), i, order->GetValue(i));
00442 }
00443 }
00444
00445 void Fleet::Colonize()
00446 {
00447 if (mOrders.size() == 0 || mOrders[0]->GetType() != OT_COLONIZE)
00448 return;
00449
00450 if (!CanColonize()) {
00451 NCGetOwner()->AddMessage("Colonization failed - no colonization pod", this);
00452 return;
00453 }
00454
00455 Planet * target = InOrbit();
00456 if (target == NULL) {
00457 NCGetOwner()->AddMessage("Colonization failed - not in orbit", this);
00458 return;
00459 }
00460
00461 if (target->GetPopulation() > 0) {
00462 Message * mess = NCGetOwner()->AddMessage("Colonization failed - world occupied", this);
00463 mess->AddItem("World being colonized", target);
00464 mess->AddItem("Owner", target->GetOwner());
00465 return;
00466 }
00467
00468 if (GetPopulation() <= 0) {
00469 Message * mess = NCGetOwner()->AddMessage("Colonization failed - no colonists", this);
00470 mess->AddItem("World being colonized", target);
00471 return;
00472 }
00473
00474 target->Invade(NCGetOwner(), GetPopulation() + GetCost().GetCrew());
00475 Scrap(true);
00476 }
00477
00478 void Fleet::CheckMerge()
00479 {
00480 if (mOrders.size() == 0 || mOrders[0]->GetType() != OT_MERGE)
00481 return;
00482
00483 Fleet * f = dynamic_cast<Fleet *>(mOrders[0]->NCGetLocation());
00484 if (f == NULL) {
00485 NCGetOwner()->AddMessage("Merge failed - destination is not a fleet", this);
00486 return;
00487 }
00488
00489 if (f->GetOwner() != GetOwner()) {
00490 NCGetOwner()->AddMessage("Merge failed - destination fleet is not owned", this);
00491 return;
00492 }
00493
00494 MergeTo(f);
00495 }
00496
00497 void Fleet::Scrap(bool colonize)
00498 {
00499 TechType TechGot = TECH_NONE;
00500 Salvage * salvage = NULL;
00501 Planet * planet = InOrbit();
00502
00503
00504
00505 if (planet && Rules::TechScrap(planet)) {
00506
00507 TechGot = Rules::TechFleet(planet->GetOwner(), this);
00508
00509
00510 }
00511
00512
00513 if (planet) {
00514 double percent = Rules::ScrapRecover(planet, colonize);
00515 long tempMins = 0;
00516 for (int i = 0; i < Rules::MaxMinType; ++i)
00517 {
00518 long temp = GetContain(i);
00519 temp += long(GetCost()[i] * percent + .5);
00520 planet->AdjustAmounts(i, temp);
00521 tempMins += temp;
00522 }
00523
00524 if (GetOwner() == planet->GetOwner()) {
00525 planet->AdjustAmounts(POPULATION, GetPopulation());
00526 planet->AdjustPopulation(GetCost().GetCrew());
00527 }
00528 } else {
00529 Salvage * salvage = TheGalaxy->AddSalvage(*this);
00530 double percent = Rules::ScrapRecover(NULL, false);
00531 for (int i = 0; i < Rules::MaxMinType; ++i) {
00532 long temp = GetContain(i);
00533 temp += long(GetCost()[i] * percent + .5);
00534 salvage->AdjustAmounts(i, temp);
00535 }
00536 }
00537
00538 int URGain = 0;
00539
00540 if (!colonize && planet) {
00541 int percent = Rules::ScrapResource(planet);
00542 if (percent > 0) {
00543 long temp = GetCost().GetResources() * percent;
00544 planet->AddScrapRes(temp);
00545 URGain = (temp*planet->GetResources())/(temp+planet->GetResources());
00546 }
00547 }
00548
00549 string str2;
00550
00551
00552
00553 {
00554
00555
00556 str2 = GetName(GetOwner());
00557 Message * mess;
00558 if (colonize) {
00559 mess = NCGetOwner()->AddMessage("Colonize attempt", planet);
00560 mess->AddItem("Fleet name", GetName(GetOwner()));
00561 } else if (planet) {
00562 mess = NCGetOwner()->AddMessage("Scrap fleet at planet", planet);
00563 mess->AddItem("Fleet name", GetName(GetOwner()));
00564 mess->AddLong("UR resource gain", URGain);
00565 } else {
00566 mess = NCGetOwner()->AddMessage("Scrap fleet in space", salvage);
00567 mess->AddItem("Fleet name", GetName(GetOwner()));
00568 }
00569 }
00570
00571
00572 if (!colonize && planet)
00573 {
00574 str2.erase();
00575 if (planet->GetOwner() != GetOwner()) {
00576 str2 = GetOwner()->GetSingleName();
00577 str2 += " ";
00578 }
00579 str2 += "Fleet #" + Long2String(mID);
00580
00581 Message * mess;
00582 mess = planet->NCGetOwner()->AddMessage("Fleet scrapped at planet", planet);
00583 mess->AddItem("Fleet name", str2);
00584 mess->AddLong("UR resource gain", URGain);
00585 if (TechGot >= 0) {
00586 mess->AddItem("Tech field gained", Rules::GetTechName(TechGot));
00587 long res = planet->GetOwner()->TechCost(TechGot);
00588 mess->AddLong("Tech resources gained", res);
00589 planet->NCGetOwner()->SetGotTech(true);
00590 planet->NCGetOwner()->GainTech(TechGot, res);
00591 }
00592 }
00593
00594 KillFleet();
00595 }
00596
00597 void Fleet::KillFleet()
00598 {
00599 const Planet * planet = InOrbit();
00600 Player * player;
00601 const Fleet * fleet;
00602
00603 for (int i = 0; i < mChasers.size(); ++i) {
00604 player = TheGame->NCGetPlayer(mChasers[i].player);
00605 if (player != NULL) {
00606 fleet = player->GetFleet(mChasers[i].fleet);
00607 Message * mess = player->AddMessage("Fleet has vanished", fleet);
00608 if (planet == NULL)
00609 mess->AddItem("Last location", new Location(*this), true);
00610 else
00611 mess->AddItem("Last location", planet);
00612 }
00613 }
00614
00615 NCGetOwner()->DeleteFleet(this);
00616 }
00617
00618 void Fleet::FreighterReproduction()
00619 {
00620 assert(GetOwner()->FreighterReproduction() > epsilon);
00621
00622 if (GetPopulation() <= 0)
00623 return;
00624
00625 long Grow = long(GetPopulation() * GetOwner()->FreighterReproduction() * GetOwner()->GrowthRate()) / Rules::PopEQ1kT;
00626 long Over = 0;
00627 Planet * p = NULL;
00628
00629 if (GetCargoMass() + Grow > GetCargoCapacity())
00630 Over = (GetCargoCapacity() - GetCargoMass()) * Rules::PopEQ1kT;
00631
00632 Grow = Grow * Rules::PopEQ1kT - Over;
00633 AdjustPopulation(Grow);
00634 if (Over) {
00635 p = InOrbit();
00636 if (p != NULL && p->GetOwner() == GetOwner())
00637 p->AdjustPopulation(Over);
00638 else
00639 Over = 0;
00640 }
00641
00642 if (Grow > 0 || Over > 0) {
00643 Message * mess = NCGetOwner()->AddMessage("Freighter growth", this);
00644 mess->AddLong("Growth", Grow);
00645 if (Over > 0) {
00646 mess->AddLong("Overflow amount", Over);
00647 mess->AddItem("Overflow world", p);
00648 }
00649 }
00650 }
00651
00652
00653 bool Fleet::Move()
00654 {
00655 if (mHasMoved)
00656 return false;
00657
00658 if (mOrders.size() <= 1 || IsWith(*mOrders[1]->GetLocation()) || mOrders[1]->GetSpeed() == 0) {
00659 mHasMoved = true;
00660 return false;
00661 }
00662
00663 const Planet * destp;
00664
00665 destp = dynamic_cast<const Planet *>(mOrders[1]->GetLocation());
00666
00667 if (destp == NULL && !mOrders[1]->GetLocation()->SeenBy(GetOwner())) {
00668 NCGetOwner()->AddMessage("Error: Targeting unseen", this);
00669 return false;
00670 }
00671
00672 if (Randodd(GetOwner()->EngineFailure(mOrders[1]->GetSpeed()))) {
00673 Message * mess = NCGetOwner()->AddMessage("Engines failed");
00674 mess->AddItem("", this);
00675 mHasMoved = true;
00676 return false;
00677 }
00678
00679
00680 if (mOrders[1]->GetSpeed() == -1) {
00681 mHasMoved = true;
00682 const Component * send = NULL;
00683 const Component * recieve = NULL;
00684 Planet * p;
00685
00686 if (destp != NULL && destp->GetBaseNumber() >= 0 && destp->GetOwner()->GetRelations(GetOwner()) >= PR_FRIEND)
00687 recieve = destp->GetBaseDesign()->GetGate();
00688
00689 p = InOrbit();
00690 if (p != NULL && p->GetBaseNumber() >= 0 && p->GetOwner()->GetRelations(GetOwner()) >= PR_FRIEND)
00691 send = p->GetBaseDesign()->GetGate();
00692
00693 if (send == NULL && CanJumpGate())
00694 send = recieve;
00695 else if (send && recieve && GetCargoMass() > 0 && !GetOwner()->GateCargo()) {
00696
00697 if (send && recieve && p->GetOwner() == GetOwner()) {
00698 Message * mess = NCGetOwner()->AddMessage("Can't gate cargo - cargo dropped");
00699 mess->AddItem("", this);
00700 mess->AddItem("Cargo dropped on", p);
00701 for (int i = 0; i < Rules::MaxMinType; ++i) {
00702 p->AdjustAmounts(i, GetContain(i));
00703 AdjustAmounts(i, -GetContain(i));
00704 }
00705
00706 p->AdjustAmounts(POPULATION, GetPopulation());
00707 AdjustAmounts(POPULATION, -GetPopulation());
00708 } else {
00709 Message * mess = NCGetOwner()->AddMessage("Can't gate cargo - gate aborted");
00710 mess->AddItem("", this);
00711 return false;
00712 }
00713 }
00714
00715 if (send == NULL) {
00716 Message * mess = NCGetOwner()->AddMessage("No sending gate");
00717 mess->AddItem("", this);
00718 if (p != NULL)
00719 mess->AddItem("Sending", p);
00720 return false;
00721 }
00722
00723 if (recieve == NULL) {
00724 Message * mess = NCGetOwner()->AddMessage("No recieving gate");
00725 mess->AddItem("", this);
00726 mess->AddItem("Destination", mOrders[1]->GetLocation());
00727 return false;
00728 }
00729
00730
00731 double rdam = Rules::OverGateRange(send->GetGateRange(), long(Distance(*mOrders[1]->GetLocation())));
00732 if (rdam > 1.0 - epsilon) {
00733 Message * mess = NCGetOwner()->AddMessage("Gate too far");
00734 mess->AddItem("", this);
00735 mess->AddItem("Destination", mOrders[1]->GetLocation());
00736 return false;
00737 }
00738
00739
00740 double mdam, tdam, vodds;
00741 bool massOK = true;
00742 bool checkdam = rdam > epsilon;
00743 for (int i = 0; i < mStacks.size(); ++i) {
00744 mdam = Rules::OverGateMass(send->GetGateMass(), recieve->GetGateMass(), mStacks[i].GetDesign()->GetMass());
00745 if (mdam > 1.0 - epsilon)
00746 massOK = false;
00747 else if (mdam > epsilon)
00748 checkdam = true;
00749 }
00750
00751 if (!massOK) {
00752 Message * mess = NCGetOwner()->AddMessage("Ships too massive for gate");
00753 mess->AddItem("", this);
00754 mess->AddItem("Destination", mOrders[1]->GetLocation());
00755 return false;
00756 }
00757
00758 if (checkdam) {
00759 long adam;
00760 Message * mess = NCGetOwner()->AddMessage("Ships damaged by overgating");
00761 mess->AddItem("", this);
00762 for (int i = 0; i < mStacks.size(); ++i) {
00763 mdam = Rules::OverGateMass(send->GetGateMass(), recieve->GetGateMass(), mStacks[i].GetDesign()->GetMass());
00764 tdam = min(0.98, mdam + rdam - mdam * rdam);
00765 vodds = (1.0 - (1.0 - rdam) * (1.0 - tdam)) / 3.0 * GetOwner()->OvergateLossFactor();
00766 adam = long(tdam * mStacks[i].GetDesign()->GetArmor(GetOwner()) + .5);
00767 long lost = mStacks[i].DamageAllShips(adam);
00768 if (mStacks[i].GetCount() > 0 && vodds > epsilon) {
00769
00770 for (int j = 0; j < mStacks[i].GetCount(); ++j) {
00771 if (Randodd(vodds))
00772 lost++;
00773 }
00774 }
00775 if (lost > 0) {
00776 mess->AddItem("Ships lost name", mStacks[i].GetDesign()->GetName());
00777 mess->AddLong("Ships lost number", lost);
00778 if (mStacks[i].KillShips(lost, false)) {
00779 mStacks.erase(mStacks.begin()+i);
00780 i--;
00781 }
00782 ResetDefaults();
00783 }
00784 }
00785
00786 if (GetShipCount() == 0) {
00787 KillFleet();
00788 return false;
00789 }
00790 }
00791
00792
00793 SetLocation(*destp);
00794 Refuel(destp);
00795 TheGame->MoveAlsoHere(this);
00796 mRepairRate = 0;
00797 return false;
00798 }
00799
00800 if (mChasing && !mChasing->mHasMoved)
00801 return true;
00802
00803 double dist = Distance(*mOrders[1]->GetLocation());
00804
00805 long speed = mOrders[1]->GetSpeed();
00806 speed--;
00807 while (dist < speed * speed)
00808 speed--;
00809 speed++;
00810
00811 Location dest = *mOrders[1]->GetLocation();
00812 if (long(dist) > speed * speed) {
00813 MoveToward(*this, dest, &mPX, &mPY, speed * speed);
00814 dist = Distance(mPX, mPY);
00815 } else {
00816 mPX = dest.GetPosX() + epsilon;
00817 mPY = dest.GetPosY() + epsilon;
00818 }
00819
00820 double fuelU = GetFuelUsage(speed);
00821 if (GetFuel() < long(fuelU * dist +.5)) {
00822 dist = GetFuel() / fuelU;
00823 mOrders[1]->SetSpeed(GetMinFreeSpeed());
00824 Message * mess = NCGetOwner()->AddMessage("Out of fuel, slowing down");
00825 mess->AddItem("", this);
00826 MoveToward(*this, dest, &mPX, &mPY, long(dist + .5));
00827 dist = Distance(mPX, mPY);
00828 }
00829
00830 mRepairRate = 1;
00831 double safe;
00832 safe = TheGame->ClosestMinefield(&mPossibleMines, this, mPX, mPY);
00833 if (safe > dist || mPossibleMines.size() == 0) {
00834 SetLocation(long(mPX), long(mPY));
00835 AdjustFuel(-long(fuelU * Distance(mStartPos) + .5));
00836 mHasMoved = true;
00837 if (IsWith(*(mOrders[1]->GetLocation()))) {
00838 const Wormhole * wh = dynamic_cast<const Wormhole *>(mOrders[1]->GetLocation());
00839 if (wh != NULL && wh->GetAttached() != NULL) {
00840 SetLocation(*wh->GetAttached());
00841 wh->Enter(GetID());
00842 wh->GetAttached()->Exit(GetID());
00843 }
00844 }
00845
00846 TheGame->MoveAlsoHere(this);
00847 return false;
00848 } else {
00849 while (safe > 2.0 && dest.Distance(mPX, mPY) > 1.0) {
00850 MoveToward(mStartPos, dest, &mPX, &mPY, long(safe));
00851 safe = TheGame->ClosestMinefield(&mPossibleMines, this, mPX, mPY);
00852 }
00853
00854 if (dest.Distance(mPX, mPY) > 1.0) {
00855 while (!Move1LY(dest, speed))
00856 ;
00857 }
00858
00859 SetLocation(long(mPX), long(mPY));
00860 AdjustFuel(long(fuelU * Distance(mStartPos) + .5));
00861
00862 if (IsWith(*(mOrders[1]->GetLocation()))) {
00863 const Wormhole * wh = dynamic_cast<const Wormhole *>(mOrders[1]->GetLocation());
00864 if (wh != NULL && wh->GetAttached() != NULL) {
00865 SetLocation(*wh->GetAttached());
00866 wh->Enter(GetID());
00867 wh->GetAttached()->Exit(GetID());
00868 }
00869 }
00870
00871 mHasMoved = true;
00872 TheGame->MoveAlsoHere(this);
00873 return false;
00874 }
00875 }
00876
00877 bool Fleet::Move1LY(Location & dest, long speed)
00878 {
00879 mRepairRate = 1;
00880 mDistMoved++;
00881 MoveToward(mStartPos, dest, &mPX, &mPY, mDistMoved);
00882 deque<bool> mineType;
00883 mineType.insert(mineType.begin(), Rules::MaxMineType, false);
00884 for (int i = 0; i < mPossibleMines.size(); i++) {
00885 if (!mineType[mPossibleMines[i]->GetMineType()]) {
00886 mineType[mPossibleMines[i]->GetMineType()] = true;
00887 if (mPossibleMines[i]->TestCollide(*this, speed)) {
00888 mPossibleMines[i]->ReduceFieldCollision();
00889 TakeMinefieldDamage(mPossibleMines[i]);
00890 return false;
00891 }
00892 }
00893 }
00894
00895 if (dest.Distance(mPX, mPY) > 1.0)
00896 return true;
00897 else
00898 return false;
00899 }
00900
00901 bool Fleet::CanLoadBy(const Player * player) const
00902 {
00903 return mCanLoadBy[player->GetID() - 1];
00904 }
00905
00906 void Fleet::SetCanLoadBy(const Player * player)
00907 {
00908 mCanLoadBy[player->GetID()-1] = true;
00909 }
00910
00911 long Fleet::GetCloak(const Player *, bool) const
00912 {
00913 return Rules::CloakValue(GetCloaking(), GetMass() + (GetOwner()->CloakCargo() ? 0 : GetCargoMass()));
00914 }
00915
00916 long Fleet::GetFuelNeeded() const
00917 {
00918 if (mOrders.size() < 1)
00919 return 0;
00920 else
00921 return long(GetFuelUsage(mOrders[1]->GetSpeed()) * Distance(*mOrders[1]->GetLocation()) + .5);
00922 }
00923
00924 void Fleet::AdjustFuel(long amount)
00925 {
00926 mFuel += amount;
00927 if (mFuel < 0)
00928 mFuel = 0;
00929
00930 if (mFuel > GetFuelCapacity())
00931 mFuel = GetFuelCapacity();
00932 }
00933
00934 void Fleet::Refuel(const Planet * p)
00935 {
00936 if (p && p->GetBaseNumber() >= 0 && p->GetBaseDesign()->CanRefuel() && p->GetOwner()->GetRelations(GetOwner()) >= PR_FRIEND)
00937 mFuel = GetFuelCapacity();
00938 }
00939
00940 double Fleet::GetFuelUsage(long speed) const
00941 {
00942 double MinUsage = -1;
00943 double MinUsageDone = 0;
00944 long MinUsageCapacity = 0;
00945 double Result = 0;
00946 long CargoLeft = GetCargoMass();
00947
00948
00949 deque<Stack>::const_iterator iter;
00950 for (iter = mStacks.begin(); iter != mStacks.end(); ++iter) {
00951 if (iter->GetDesign()->GetFreeSpeed() >= speed) {
00952
00953 Result += iter->GetDesign()->GetFuelUsage(speed) * iter->GetCount();
00954 if (CargoLeft > 0)
00955 CargoLeft -= min(CargoLeft, iter->GetDesign()->GetCargoCapacity() * iter->GetCount());
00956 } else if (GetCargoMass() == GetCargoCapacity()) {
00957
00958 Result += iter->GetDesign()->GetFuelUsage(speed) *
00959 iter->GetCount() *
00960 (iter->GetDesign()->GetMass() + iter->GetDesign()->GetCargoCapacity()) *
00961 GetOwner()->FuelFactor();
00962 CargoLeft -= iter->GetDesign()->GetCargoCapacity() * iter->GetCount();
00963 } else {
00964
00965 Result += iter->GetDesign()->GetFuelUsage(speed) *
00966 iter->GetCount() *
00967 iter->GetDesign()->GetMass() *
00968 GetOwner()->FuelFactor();
00969 }
00970 }
00971
00972
00973 while (CargoLeft > 0) {
00974 for (iter = mStacks.begin(); iter != mStacks.end(); ++iter) {
00975 if (iter->GetDesign()->GetFreeSpeed() <= speed)
00976 ;
00977 else if (iter->GetDesign()->GetCargoCapacity() == 0)
00978 ;
00979 else {
00980 double usage = iter->GetDesign()->GetFuelUsage(speed);
00981 if (usage > MinUsageDone && (MinUsage == -1 || usage < MinUsage)) {
00982 MinUsage = usage;
00983 MinUsageCapacity = iter->GetDesign()->GetCargoCapacity() * iter->GetCount();
00984 }
00985 }
00986 }
00987
00988 Result += MinUsage * MinUsageCapacity * GetOwner()->FuelFactor();
00989 CargoLeft -= min(CargoLeft, MinUsageCapacity);
00990 MinUsageDone = MinUsage;
00991 MinUsage = -1;
00992 }
00993
00994 return Result / 200.0;
00995 }
00996
00997 void Fleet::MergeTo(Fleet * to)
00998 {
00999
01000 to->AddChaser(mChasers);
01001 deque<Stack>::iterator iter;
01002 for (iter = mStacks.begin(); iter != mStacks.end(); ++iter) {
01003 to->Merge(*iter, iter->GetCount(), iter->GetDamaged(), mID);
01004 mStacks.erase(iter);
01005 }
01006
01007
01008 for (int i = FUEL; i < Rules::MaxMinType; ++i) {
01009 to->AdjustAmounts(i, GetContain(i));
01010 AdjustAmounts(i, -GetContain(i));
01011 }
01012 }
01013
01014 void Fleet::MergeTo(Fleet * to, const Ship * design, long number, long damaged)
01015 {
01016 Stack* stack = NULL;
01017 for (deque<Stack>::iterator iter = mStacks.begin(); iter != mStacks.end(); ++iter)
01018 {
01019 if (design == iter->GetDesign())
01020 {
01021 stack = &(*iter);
01022 break;
01023 }
01024 }
01025
01026 if (stack == NULL)
01027 {
01028 Message * mess = NCGetOwner()->AddMessage("Error: Split or merge a design not in the fleet", this);
01029 mess->AddItem("Ship design", design->GetName());
01030 return;
01031 }
01032
01033 if (number > stack->GetCount()) {
01034 Message * mess = NCGetOwner()->AddMessage("Error: Split or merge too many ships", this);
01035 mess->AddItem("Ship design", design->GetName());
01036 mess->AddLong("Attempted transfer", number);
01037 number = stack->GetCount();
01038 mess->AddLong("Actual transfer", number);
01039 }
01040
01041 if (damaged > stack->GetDamaged()) {
01042 Message * mess = NCGetOwner()->AddMessage("Error: Split or merge too many damaged ships", this);
01043 mess->AddItem("Ship design", design->GetName());
01044 mess->AddLong("Attempted transfer", damaged);
01045 damaged = stack->GetDamaged();
01046 mess->AddLong("Actual transfer", damaged);
01047 }
01048
01049
01050 if (damaged < stack->GetDamaged() + number - stack->GetCount()) {
01051 Message * mess = NCGetOwner()->AddMessage("Error: Split or merge not enough damaged ships", this);
01052 mess->AddItem("Ship design", design->GetName());
01053 mess->AddLong("Attempted transfer", damaged);
01054 damaged = stack->GetDamaged() + number - stack->GetCount();
01055 mess->AddLong("Actual transfer", damaged);
01056 }
01057
01058
01059 long original_capacity = GetCargoCapacity();
01060
01061
01062 to->Merge(*stack, number, damaged, mID);
01063 to->AddChaser(mChasers);
01064
01065
01066 long capacity = stack->GetDesign()->GetCargoCapacity() * number;
01067 double ratio = double(capacity)/double(original_capacity);
01068 long amt;
01069 if (capacity > 0)
01070 {
01071
01072 amt = GetContain(POPULATION);
01073 if(amt != 0)
01074 {
01075
01076 amt = long(amt * ratio) / Rules::PopEQ1kT;
01077 amt *= Rules::PopEQ1kT;
01078
01079 to->AdjustAmounts(POPULATION, amt);
01080 AdjustAmounts(POPULATION, -amt);
01081 }
01082
01083
01084 for (int i = 0; i < Rules::MaxMinType; ++i)
01085 {
01086 amt = GetContain(i);
01087 if(amt != 0)
01088 {
01089 amt = long(amt * ratio);
01090
01091 to->AdjustAmounts(i, amt);
01092 AdjustAmounts(i, -amt);
01093 }
01094 }
01095 }
01096
01097
01098 original_capacity = GetFuelCapacity();
01099 capacity = stack->GetDesign()->GetFuelCapacity() * number;
01100 ratio = double(capacity)/double(original_capacity);
01101 amt = long(GetFuel() * ratio);
01102 to->AdjustAmounts(FUEL, amt);
01103 AdjustAmounts(FUEL, -amt);
01104
01105 ResetDefaults();
01106
01107 stack->SetCount(stack->GetCount() - number);
01108 stack->SetDamaged(stack->GetDamaged() - damaged);
01109 if (stack->GetCount() <= 0)
01110 remove_if(mStacks.begin(),mStacks.end(),bind2nd(equal_to<Stack>(),*stack));
01111 }
01112
01113 void Fleet::Merge(Stack &stack, long number, long damaged, long Origin)
01114 {
01115 ResetDefaults();
01116 deque<Stack>::iterator iter;
01117 for (iter = mStacks.begin(); iter != mStacks.end(); ++iter) {
01118 if (iter->GetDesign() == stack.GetDesign())
01119 break;
01120 }
01121
01122 if (iter == mStacks.end()) {
01123 iter = mStacks.insert(iter, Stack());
01124 iter->SetDesign(stack.GetDesign());
01125 }
01126
01127
01128 long newdamage = 0;
01129 long Dcount = iter->GetDamaged() + damaged;
01130 if (Dcount > 0)
01131 newdamage = (iter->GetDamaged() * iter->GetDamage() + damaged * stack.GetDamage() + Dcount/2) / Dcount;
01132
01133 iter->SetCount(iter->GetCount() + number);
01134 iter->SetDamaged(iter->GetDamaged() + damaged);
01135 iter->SetDamage(newdamage);
01136
01137
01138 deque<Stack::Origin>::iterator i2;
01139 long nleft = number;
01140 long dleft = damaged;
01141 for (i2 = stack.mOrigins.begin(); i2 != stack.mOrigins.end(); ++i2) {
01142 long n = long(0.5 + double(i2->ships) * number / stack.GetCount());
01143 long d = long(0.5 + double(i2->damaged) * damaged / stack.GetDamaged());
01144 if (n < d)
01145 n = d;
01146
01147 iter->AddFromFleet(i2->fleet, n, d);
01148 i2->ships -= n;
01149 i2->damaged -= n;
01150 nleft -= n;
01151 dleft -= d;
01152 }
01153
01154 iter->AddFromFleet(Origin, nleft, dleft);
01155 }
01156
01157 void Fleet::AddShips(long Type, long number)
01158 {
01159 deque<Stack>::iterator iter;
01160 for (iter = mStacks.begin(); iter != mStacks.end(); ++iter) {
01161 if (iter->GetDesign() == GetOwner()->GetShipDesign(Type))
01162 break;
01163 }
01164
01165 if (iter == mStacks.end()) {
01166 iter = mStacks.insert(iter, Stack());
01167 iter->SetDesign(GetOwner()->GetShipDesign(Type));
01168 }
01169
01170 iter->SetCount(iter->GetCount() + number);
01171 }
01172
01173 void Fleet::ResetSeen()
01174 {
01175 CargoHolder::ResetSeen();
01176
01177 mCanLoadBy.clear();
01178 mCanLoadBy.insert(mCanLoadBy.begin(), TheGame->NumberPlayers(), false);
01179 }
01180
01181 void Fleet::SetSeenBy(long p, bool seen)
01182 {
01183 mSeenBy[p] = seen;
01184
01185 SetSeenDesign(p, seen, TheGame->GetPlayer(p+1)->ScanDesign());
01186 }
01187
01188 void Fleet::SetSeenDesign(long p, bool seen, bool design)
01189 {
01190 deque<Stack>::iterator iter;
01191 for (iter = mStacks.begin(); iter != mStacks.end(); ++iter) {
01192 if (design)
01193 const_cast<Ship *>(iter->GetDesign())->SetSeenDesign(p, seen);
01194 else
01195 const_cast<Ship *>(iter->GetDesign())->SetSeenHull(p, seen);
01196 }
01197 }
01198
01199 void Fleet::ChangeWaypoints(WayOrderList & wol)
01200 {
01201 if (GetOwner()->WriteXFile())
01202 NCGetOwner()->AddOrder(new WaypointOrder(GetID(), &mOrders));
01203 else {
01204 for (int i = 0; i < mOrders.size(); ++i)
01205 delete mOrders[i];
01206 }
01207
01208 wol.SetNoDelete();
01209 mOrders = wol.GetOrders();
01210 }
01211
01212 void Fleet::SetRepeat(bool repeat)
01213 {
01214 if (repeat != mRepeatOrders && GetOwner()->WriteXFile())
01215 NCGetOwner()->AddOrder(new TypedOrder<bool>(&mRepeatOrders, AddBool, "Repeat", "Fleet", Long2String(GetID()).c_str()));
01216
01217 mRepeatOrders = repeat;
01218 }
01219
01220 void Fleet::SetBattlePlan(long bp)
01221 {
01222 if (bp != mBattlePlan && GetOwner()->WriteXFile())
01223 NCGetOwner()->AddOrder(new TypedOrder<long>(&mBattlePlan, AddLong, "BattlePlan"));
01224
01225 mBattlePlan = bp;
01226 }
01227
01228 void Fleet::SetStartOrders(Planet * planet)
01229 {
01230 WayOrder * wo = new WayOrder(planet);
01231 mOrders.insert(mOrders.begin(), wo);
01232 SetNextRoute(planet);
01233 }
01234
01235 void Fleet::SetNextRoute(Planet * planet)
01236 {
01237 if (planet && planet->GetRoute() != NULL) {
01238 WayOrder * wo = new WayOrder(const_cast<Planet *>(planet->GetRoute()));
01239 wo->SetType(OT_ROUTE);
01240 wo->SetSpeed(GetBestSpeed(planet, planet->GetRoute(), OT_ROUTE));
01241 mOrders.insert(mOrders.end(), wo);
01242 }
01243 }
01244
01245 long Fleet::GetBestSpeed(const Location * L1, const Location * L2, OrderType ot)
01246 {
01247 long dist = long(L1->Distance(*L2));
01248
01249 const Planet * p1 = dynamic_cast<const Planet *>(L1);
01250 const Planet * p2 = dynamic_cast<const Planet *>(L2);
01251
01252 bool oneway = (ot == OT_COLONIZE) || CanColonize();
01253
01254 if (p2 && p2->GetBaseNumber() >= 0) {
01255 if (p2->GetBaseDesign()->CanRefuel())
01256 oneway = true;
01257
01258 if (GetCargoMass() == 0 || GetOwner()->GateCargo()) {
01259 if (p1 && p1->GetBaseNumber() >= 0) {
01260 const Component * gate = p1->GetBaseDesign()->GetGate();
01261 if (gate->GetGateMass() >= GetMaxMass() && gate->GetRange() >= dist) {
01262 gate = p2->GetBaseDesign()->GetGate();
01263 if (gate->GetGateMass() >= GetMaxMass())
01264 return -1;
01265 }
01266 }
01267 }
01268 }
01269
01270 long speed;
01271 double fu;
01272
01273
01274 for (speed = GetMinSafeSpeed(); speed > GetMinBattleSpeed(); --speed) {
01275 fu = GetFuelUsage(speed) * dist * (oneway ? 1 : 2);
01276 if (fu <= GetFuel())
01277 break;
01278 }
01279
01280 return speed;
01281 }
01282
01283 void Fleet::AddChaser(unsigned long p, unsigned long f)
01284 {
01285 assert(p != GetOwner()->GetID());
01286 deque<Chaser>::iterator iter;
01287 for (iter = mChasers.begin(); iter != mChasers.end(); ++iter)
01288 if (iter->player == p && iter->fleet == f)
01289 break;
01290
01291 if (iter == mChasers.end()) {
01292 iter = mChasers.insert(mChasers.end(),Chaser());
01293 iter->fleet = f;
01294 iter->player = p;
01295 }
01296 }
01297
01298 void Fleet::AddChaser(const deque<Chaser> &w2)
01299 {
01300 deque<Chaser>::const_iterator iter;
01301 for (iter = w2.begin(); iter != w2.end(); ++iter)
01302 AddChaser(iter->player, iter->fleet);
01303 }
01304
01305 void Fleet::TakeMinefieldDamage(MineField * field)
01306 {
01307 int dpse;
01308 int dpre;
01309 int temp;
01310 long ReportedDamage = 0;
01311 long ReportedKills = 0;
01312
01313 dpse = Rules::GetArrayValue("MineFleetDamage", field->GetMineType());
01314 temp = Rules::GetArrayValue("MineShipDamage", field->GetMineType());
01315 if (dpse < temp * GetShipCount())
01316 dpse = temp * GetShipCount();
01317
01318 dpre = Rules::GetArrayValue("MineFleetRamDamage", field->GetMineType());
01319 temp = Rules::GetArrayValue("MineShipRamDamage", field->GetMineType());
01320 if (dpre < temp * GetShipCount())
01321 dpre = temp * GetShipCount();
01322
01323 if (dpse > 0 || dpre > 0) {
01324 for (int i = 0; i < mStacks.size(); ++i) {
01325 if (mStacks[i].GetDesign()->GetFreeSpeed() > 1)
01326 temp = dpre;
01327 else
01328 temp = dpse;
01329
01330 temp *= mStacks[i].GetDesign()->GetEngines();
01331 ReportedDamage += temp * mStacks[i].GetCount();
01332 temp -= min(mStacks[i].GetDesign()->GetShield(GetOwner()), long((temp + 1) / 2));
01333 long lost = mStacks[i].DamageAllShips(temp);
01334 ReportedKills += lost;
01335 if (mStacks[i].KillShips(lost, true)) {
01336 mStacks.erase(mStacks.begin()+i);
01337 i--;
01338 }
01339 ResetDefaults();
01340 }
01341 }
01342
01343 Message * mess;
01344 mess = NCGetOwner()->AddMessage("Your fleet hit mine");
01345 mess->AddItem("", this);
01346 mess->AddLong("Damage", ReportedDamage);
01347 mess->AddLong("Kills", ReportedKills);
01348 if (ReportedKills > 0)
01349 mess->AddItem("Salvage location", new Location(*this), true);
01350 mess = field->NCGetOwner()->AddMessage("Fleet hit your mine");
01351 mess->AddItem("", field);
01352 mess->AddLong("Damage", ReportedDamage);
01353 mess->AddLong("Kills", ReportedKills);
01354 if (ReportedKills > 0)
01355 mess->AddItem("Salvage location", new Location(*this), true);
01356 }
01357
01358 void Fleet::RemoteMine(bool ARmining)
01359 {
01360 if (mOrders.size() < 1 || mOrders[0]->GetType() != OT_REMOTEMINE)
01361 return;
01362
01363 if (!ARmining && mStartPos != *this)
01364 return;
01365
01366 Planet * planet = InOrbit();
01367 if (planet == NULL)
01368 return;
01369
01370 if (planet->GetOwner() != NULL) {
01371 if (GetOwner()->ARTechType() >= 0 && GetOwner() == planet->GetOwner()) {
01372 if (!ARmining)
01373 return;
01374 } else {
01375
01376 Message * mess;
01377 mess = NCGetOwner()->AddMessage("Warning: Remote mining an owned world", this);
01378 mess->AddItem("", planet);
01379 mess->AddItem("Owner", planet->GetOwner());
01380 return;
01381 }
01382 }
01383
01384 if (GetMines() == 0) {
01385
01386 Message * mess;
01387 mess = NCGetOwner()->AddMessage("Warning: Remote mining without mining ability", this);
01388 mess->AddItem("", planet);
01389 return;
01390 }
01391
01392 planet->Mine(min(GetMines(), Rules::GetConstant("MaxRemoteMining")), GetOwner());
01393 }
01394
01395 long Fleet::GetShipCount() const
01396 {
01397 long Result = 0;
01398 deque<Stack>::const_iterator iter;
01399 for (iter = mStacks.begin(); iter != mStacks.end(); ++iter)
01400 Result += iter->GetCount();
01401
01402 return Result;
01403 }
01404
01405 long Fleet::TechLevel(TechType tech) const
01406 {
01407 if (tech >= Rules::MaxTechType || CVTechLevel[tech] == -1) {
01408
01409 long Level = 0;
01410 deque<Stack>::const_iterator iter;
01411
01412 if (tech < Rules::MaxTechType) {
01413 for (iter = mStacks.begin(); iter != mStacks.end(); ++iter) {
01414 Level = max(Level, iter->GetDesign()->TechLevel(tech));
01415 }
01416 } else {
01417 for (iter = mStacks.begin(); iter != mStacks.end(); ++iter)
01418 Level += iter->GetDesign()->TechLevel(tech);
01419 }
01420 if (tech < Rules::MaxTechType)
01421 const_cast<Fleet *>(this)->CVTechLevel[tech] = Level;
01422
01423 return Level;
01424 } else
01425 return CVTechLevel[tech];
01426 }
01427
01428 const Cost & Fleet::GetCost() const
01429 {
01430 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)) {
01431 const_cast<Fleet *>(this)->ReCost = TheGame->GetTurnPhase();
01432
01433 deque<Stack>::const_iterator iter;
01434
01435 const_cast<Fleet *>(this)->CVCost.Zero();
01436 for (iter = mStacks.begin(); iter != mStacks.end(); ++iter) {
01437 for (CargoType ct = RESOURCES; ct < Rules::MaxMinType; ++ct) {
01438 const_cast<Fleet *>(this)->CVCost[ct] += iter->GetDesign()->GetCost(GetOwner())[ct] * iter->GetCount();
01439 }
01440 }
01441 }
01442
01443 return CVCost;
01444 }
01445
01446
01447
01448
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460 long lGetScanPen(long v, const Stack & s, const Player * player)
01461 {
01462 return max(v, s.GetDesign()->GetScanPen(player));
01463 }
01464
01465 long Fleet::GetScanPen() const
01466 {
01467 if (CVScanPen == -2) {
01468 const_cast<Fleet *>(this)->CVScanPen =
01469 accumulate( mStacks.begin(),
01470 mStacks.end(),
01471 0,
01472 lGetScanPen,
01473 GetOwner());
01474 }
01475
01476 return CVScanPen;
01477 }
01478
01479 long lGetScanSpace(long v, const Stack & s, const Player * player)
01480 {
01481 return max(v, s.GetDesign()->GetScanSpace(player));
01482 }
01483
01484 long Fleet::GetScanSpace() const
01485 {
01486 if (CVScanSpace != -1) {
01487 const_cast<Fleet *>(this)->CVScanSpace =
01488 accumulate( mStacks.begin(),
01489 mStacks.end(),
01490 0,
01491 lGetScanSpace,
01492 GetOwner());
01493
01494 const_cast<Fleet *>(this)->CVScanSpace = long(CVScanSpace * GetOwner()->SpaceScanFactor());
01495 }
01496
01497 return CVScanSpace;
01498 }
01499
01500 long lGetTerraPower(long v, const Stack & s, long type)
01501 {
01502 return v + s.GetDesign()->GetTerraPower(type);
01503 }
01504
01505
01506
01507 long Fleet::GetTerraPower(long type) const
01508 {
01509 return accumulate( mStacks.begin(),
01510 mStacks.end(),
01511 0,
01512 lGetTerraPower,
01513 type);
01514 }
01515
01516 long lGetMineAmount(long v, const Stack & s, long type)
01517 {
01518 return v + s.GetDesign()->GetMineAmount(type);
01519 }
01520
01521 long Fleet::GetMineAmount(long type) const
01522 {
01523 if (CVMineAmount[type-1] == -1) {
01524 long Result = accumulate(mStacks.begin(),
01525 mStacks.end(),
01526 0,
01527 lGetMineAmount,
01528 type);
01529 const_cast<Fleet *>(this)->CVMineAmount[type-1] = Result;
01530 }
01531 return CVMineAmount[type-1];
01532 }
01533
01534 double Fleet::RadDamage() const
01535 {
01536 double Damage = 0.0;
01537 for (HabType ht = 0; ht < Rules::MaxHabType; ++ht) {
01538 if (DoesRadiate(ht))
01539 Damage += GetOwner()->RadDamage(ht);
01540 }
01541
01542 return Damage;
01543 }
01544
01545 bool Fleet::DoesRadiate(HabType ht) const
01546 {
01547 if (CVRadiation[ht] != -1)
01548 return CVRadiation[ht] ? true : false;
01549 const_cast<Fleet *>(this)->CVRadiation[ht] = 1;
01550 for (deque<Stack>::const_iterator i = mStacks.begin(); i != mStacks.end(); ++i)
01551 if (i->GetDesign()->DoesRadiate(ht))
01552 return true;
01553 const_cast<Fleet *>(this)->CVRadiation[ht] = 0;
01554 return false;
01555 }
01556
01557
01558
01559
01560
01561
01562 #define GET_FLEET_SUM(Function) \
01563 long lGet##Function(long v, const Stack & s) \
01564 { \
01565 return v + s.GetDesign()->Get##Function() * s.GetCount(); \
01566 } \
01567 \
01568 long Fleet::Get##Function() const \
01569 { \
01570 if (CV##Function == -1) \
01571 const_cast<Fleet *>(this)->CV##Function = accumulate(mStacks.begin(), mStacks.end(), 0, lGet##Function); \
01572 return CV##Function; \
01573 }
01574 #define GET_FLEET_SUMD(Function) \
01575 double lGet##Function(double v, const Stack & s) \
01576 { \
01577 return v + s.GetDesign()->Get##Function() * s.GetCount(); \
01578 } \
01579 \
01580 double Fleet::Get##Function() const \
01581 { \
01582 if (!CCalc##Function) { \
01583 const_cast<Fleet *>(this)->CCalc##Function = true;\
01584 const_cast<Fleet *>(this)->CV##Function = accumulate(mStacks.begin(), mStacks.end(), 0, lGet##Function); \
01585 } \
01586 return CV##Function; \
01587 }
01588
01589 #define GET_FLEET_MAXD(Function) \
01590 double lGetMax##Function(double v, const Stack & s) \
01591 { \
01592 return max(v, s.GetDesign()->Get##Function()); \
01593 } \
01594 \
01595 double Fleet::GetMax##Function() const \
01596 { \
01597 if (!CCalcMax##Function) { \
01598 const_cast<Fleet *>(this)->CCalcMax##Function = true;\
01599 const_cast<Fleet *>(this)->CVMax##Function = accumulate(mStacks.begin(), mStacks.end(), 0, lGetMax##Function); \
01600 } \
01601 return CVMax##Function; \
01602 }
01603
01604 #define GET_FLEET_MAX(Function) \
01605 long lGetMax##Function(long v, const Stack & s) \
01606 { \
01607 return max(v, s.GetDesign()->Get##Function()); \
01608 } \
01609 \
01610 long Fleet::GetMax##Function() const \
01611 { \
01612 if (!CCalcMax##Function) { \
01613 const_cast<Fleet *>(this)->CCalcMax##Function = true;\
01614 const_cast<Fleet *>(this)->CVMax##Function = accumulate(mStacks.begin(), mStacks.end(), 0, lGetMax##Function); \
01615 } \
01616 return CVMax##Function; \
01617 }
01618
01619 #define GET_FLEET_MIN(Function) \
01620 long lGetMin##Function(long v, const Stack & s) \
01621 { \
01622 return v > 0 ? min(v, s.GetDesign()->Get##Function()) : s.GetDesign()->Get##Function(); \
01623 } \
01624 \
01625 long Fleet::GetMin##Function() const \
01626 { \
01627 if (CVMin##Function == -1) \
01628 const_cast<Fleet *>(this)->CVMin##Function = accumulate(mStacks.begin(), mStacks.end(), 0, lGetMin##Function); \
01629 return CVMin##Function; \
01630 }
01631
01632 #define GET_FLEET_HAS(Function) \
01633 bool Fleet::Can##Function() const \
01634 { \
01635 if (CV##Function != -1) \
01636 return CV##Function ? true : false; \
01637 const_cast<Fleet *>(this)->CV##Function = 1; \
01638 for (deque<Stack>::const_iterator i = mStacks.begin(); i != mStacks.end(); ++i) \
01639 if (i->GetDesign()->Can##Function()) \
01640 return true; \
01641 const_cast<Fleet *>(this)->CV##Function = 0; \
01642 return false; \
01643 }
01644
01645 GET_FLEET_SUM(Cloaking)
01646 GET_FLEET_SUM(FuelCapacity)
01647 GET_FLEET_SUM(FuelGen)
01648 GET_FLEET_SUM(Mass)
01649 GET_FLEET_MAX(Mass)
01650 GET_FLEET_MAXD(Tachyon)
01651 GET_FLEET_SUM(CargoCapacity)
01652 GET_FLEET_SUM(Mines)
01653 GET_FLEET_SUM(Sweeping)
01654
01655 GET_FLEET_MAXD(Dampener)
01656 GET_FLEET_MAXD(RepairRate)
01657 GET_FLEET_MIN(SafeSpeed)
01658 GET_FLEET_MIN(MaxSpeed)
01659 GET_FLEET_MIN(FreeSpeed)
01660 GET_FLEET_MIN(BattleSpeed)
01661
01662 GET_FLEET_HAS(Colonize)
01663 GET_FLEET_HAS(StealShip)
01664 GET_FLEET_HAS(StealPlanet)
01665 GET_FLEET_HAS(Shoot)
01666 GET_FLEET_HAS(NormalBomb)
01667 GET_FLEET_HAS(TerraBomb)
01668 GET_FLEET_HAS(SmartBomb)
01669 GET_FLEET_HAS(JumpGate)
01670
01671 GET_FLEET_SUMD(NormalKillper)
01672
01673 GET_FLEET_SUM(MinKill)
01674 GET_FLEET_SUM(InstKill)