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 "Packet.h"
00029 #include "Order.h"
00030
00031 #ifdef _DEBUG
00032 #define new DEBUG_NEW
00033 #endif
00034
00035 #ifdef _DEBUG
00036 #define new DEBUG_NEW
00037 #endif
00038
00039 ProdOrder::ProdOrder()
00040 : Type(0), Amount(0)
00041 {
00042 init();
00043 }
00044
00045 ProdOrder::ProdOrder(long type, long amount)
00046 : Type(type), Amount(amount)
00047 {
00048 init();
00049 }
00050
00051 ProdOrder::~ProdOrder()
00052 {
00053 }
00054
00055 void ProdOrder::init()
00056 {
00057 }
00058
00059 ProdOrder * ProdOrder::Copy() const
00060 {
00061 if (typeid(*this) == typeid(POShip))
00062 return new POShip(dynamic_cast<const POShip &>(*this));
00063 else if (typeid(*this) == typeid(POBase))
00064 return new POBase(dynamic_cast<const POBase &>(*this));
00065 else if (typeid(*this) == typeid(POPlanetary))
00066 return new POPlanetary(dynamic_cast<const POPlanetary &>(*this));
00067 else if (typeid(*this) == typeid(POPacket))
00068 return new POPacket(dynamic_cast<const POPacket &>(*this));
00069 else if (typeid(*this) == typeid(POTerraform))
00070 return new POTerraform(dynamic_cast<const POTerraform &>(*this));
00071 else if (typeid(*this) == typeid(POAuto))
00072 return new POAuto(dynamic_cast<const POAuto &>(*this));
00073 else {
00074
00075 return NULL;
00076 }
00077 }
00078
00079 deque<ProdOrder *> ProdOrder::ParseNode(const TiXmlNode * node, Planet * planet, Player * player , bool TrustPartials )
00080 {
00081 assert(planet != NULL || player != NULL);
00082 assert(node != NULL);
00083
00084 if (player == NULL)
00085 player = planet->NCGetOwner();
00086
00087 const TiXmlNode * child;
00088
00089 deque<ProdOrder *> neword;
00090 ProdOrder * po = NULL;
00091 long type;
00092 long num;
00093
00094 for (child = node->FirstChild(); child; child = child->NextSibling()) {
00095 if (child->Type() == TiXmlNode::COMMENT)
00096 continue;
00097
00098 po = NULL;
00099 if (stricmp(child->Value(), "Planet") == 0) {
00100 continue;
00101 } else if (stricmp(child->Value(), "Ship") == 0) {
00102 type = GetLong(child->FirstChild("Design"));
00103 if (type <= 0 || type > Rules::GetConstant("MaxShipDesigns")) {
00104 Message * mess = player->AddMessage("Error: Invalid ship design type number");
00105 mess->AddLong("", type);
00106 continue;
00107 }
00108 num = GetLong(child->FirstChild("Number"));
00109 po = new POShip(type, num);
00110 po->CheckPartials(planet, child, TrustPartials);
00111 } else if (stricmp(child->Value(), "Base") == 0) {
00112 type = GetLong(child->FirstChild("Design"));
00113 if (type <= 0 || type > Rules::GetConstant("MaxBaseDesigns")) {
00114 Message * mess = player->AddMessage("Error: Invalid base design");
00115 mess->AddLong("", type);
00116 continue;
00117 }
00118 po = new POBase(type);
00119 po->CheckPartials(planet, child, TrustPartials);
00120 } else if (stricmp(child->Value(), "Factories") == 0) {
00121 num = GetLong(child->FirstChild("Number"));
00122 po = new POPlanetary(POP_FACTS, num);
00123 po->CheckPartials(planet, child, TrustPartials);
00124 } else if (stricmp(child->Value(), "Mines") == 0) {
00125 num = GetLong(child->FirstChild("Number"));
00126 po = new POPlanetary(POP_MINES, num);
00127 po->CheckPartials(planet, child, TrustPartials);
00128 } else if (stricmp(child->Value(), "Defenses") == 0) {
00129 num = GetLong(child->FirstChild("Number"));
00130 po = new POPlanetary(POP_DEFS, num);
00131 po->CheckPartials(planet, child, TrustPartials);
00132 } else if (stricmp(child->Value(), "Alchemy") == 0) {
00133 num = GetLong(child->FirstChild("Number"));
00134 po = new POPlanetary(POP_ALCHEMY, num);
00135 po->CheckPartials(planet, child, TrustPartials);
00136 } else if (stricmp(child->Value(), "Scanner") == 0) {
00137 po = new POPlanetary(POP_SCANNER, 1);
00138 po->CheckPartials(planet, child, TrustPartials);
00139 } else if (stricmp(child->Value(), "Packet") == 0) {
00140 num = GetLong(child->FirstChild("Number"));
00141 const char * ptr = GetString(child->FirstChild("Type"));
00142 long t;
00143 if (stricmp(ptr, "Mixed") == 0)
00144 t = -1;
00145 else {
00146 t = Rules::MineralID(GetString(child->FirstChild("Type")));
00147 if (t < 0) {
00148 Message * mess = player->AddMessage("Error: Invalid packet type");
00149 mess->AddItem("", GetString(child->FirstChild("Type")));
00150 continue;
00151 }
00152 }
00153
00154 po = new POPacket(t, num);
00155 po->CheckPartials(planet, child, TrustPartials);
00156 } else if (stricmp(child->Value(), "Terraform") == 0) {
00157 num = GetLong(child->FirstChild("Number"), 1);
00158 po = new POTerraform(POP_TERRAFORM, num);
00159 po->CheckPartials(planet, child, TrustPartials);
00160 } else if (stricmp(child->Value(), "AutoMine") == 0) {
00161 num = GetLong(child);
00162 po = new POAuto(POP_MINES, num);
00163 } else if (stricmp(child->Value(), "AutoFactory") == 0) {
00164 num = GetLong(child);
00165 po = new POAuto(POP_FACTS, num);
00166 } else if (stricmp(child->Value(), "AutoDefense") == 0) {
00167 num = GetLong(child);
00168 po = new POAuto(POP_DEFS, num);
00169 } else if (strnicmp(child->Value(), "AutoAlchemy", 11) == 0) {
00170 po = new POAuto(POP_ALCHEMY, 1);
00171 } else if (stricmp(child->Value(), "AutoMinTerra") == 0) {
00172 num = GetLong(child);
00173 po = new POAuto(POP_MINTERRA, num);
00174 } else if (stricmp(child->Value(), "AutoMaxTerra") == 0) {
00175 num = GetLong(child);
00176 po = new POAuto(POP_MAXTERRA, num);
00177 } else if (stricmp(child->Value(), "AutoPacket") == 0) {
00178 num = GetLong(child);
00179 po = new POAuto(POP_MIXEDPACKET, num);
00180 } else {
00181 Message * mess = player->AddMessage("Warning: Unknown production entry");
00182 mess->AddItem("", child->Value());
00183 continue;
00184 }
00185
00186 neword.insert(neword.end(), po);
00187 }
00188
00189 return neword;
00190 }
00191
00192 TiXmlNode * ProdOrder::WriteNode(TiXmlNode * node, const deque<ProdOrder *> & ords)
00193 {
00194 TiXmlElement * PQ = new TiXmlElement("ProductionQueue");
00195 for (int i = 0; i < ords.size(); ++i)
00196 ords[i]->WriteNode(node);
00197
00198 node->LinkEndChild(PQ);
00199 return PQ;
00200 }
00201
00202 TiXmlNode * ProdOrder::WriteNode(TiXmlNode * node) const
00203 {
00204 return Partial.WriteCosts(node, "Partial");
00205 }
00206
00207
00208
00209
00210
00211
00212
00213 void ProdOrder::CheckPartials(Planet * planet, const TiXmlNode * node, bool TrustPartials)
00214 {
00215 if (node == NULL || planet == NULL)
00216 return;
00217
00218 Partial.ReadCosts(node->FirstChild("Partial"));
00219 if (TrustPartials)
00220 return;
00221
00222 deque<ProdOrder *>::iterator iter;
00223 for (iter = planet->mProductionQ.begin(); iter != planet->mProductionQ.end(); ++iter)
00224 {
00225 if (typeid(*iter) == typeid(this) && Type == (*iter)->Type)
00226 {
00227 if(Partial == (*iter)->Partial)
00228 {
00229 break;
00230 }
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253 }
00254 }
00255
00256 if (iter == planet->mProductionQ.end()) {
00257
00258 Message * mess = planet->NCGetOwner()->AddMessage("Warning: Incorrect partial values", planet);
00259 mess->AddItem("Item being built", TypeToString());
00260 mess->AddLong("Number ordered", Amount);
00261 Partial.Zero();
00262 } else {
00263
00264 (*iter)->Partial.Zero();
00265 }
00266 }
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324 bool ProdOrder::DoProduce(const Cost & cost, Planet * planet, long * resources, bool * AutoAlchemy, long maxbuild )
00325 {
00326
00327 assert(maxbuild == -1 || dynamic_cast<POAuto *>(this) != NULL || dynamic_cast<POTerraform *>(this) != NULL);
00328
00329 Player * owner = planet->NCGetOwner();
00330 CargoType ct;
00331
00332 double Build;
00333 int lBuilt = 0;
00334 bool Auto = false;
00335 if (maxbuild > 0)
00336 Auto = true;
00337 else
00338 maxbuild = Amount;
00339
00340
00341 Partial.SetResources(min(cost.GetResources(), Partial.GetResources()));
00342 Partial.SetCrew(min(cost.GetCrew(), Partial.GetCrew()));
00343 for (ct = 0; ct < Rules::MaxMinType; ++ct)
00344 Partial[ct] = min(cost[ct], Partial[ct]);
00345
00346 do {
00347
00348 if (Partial.GetResources() > 0) {
00349 *resources += Partial.GetResources();
00350 planet->AdjustPopulation(Partial.GetCrew());
00351 for (ct = 0; ct < Rules::MaxMinType; ++ct)
00352 planet->AdjustAmounts(ct, Partial[ct]);
00353
00354 Partial.Zero();
00355 }
00356
00357
00358
00359 Build = maxbuild;
00360 if (cost.GetResources() > 0)
00361 Build = min(Build, double(*resources) / cost.GetResources());
00362
00363 if (cost.GetCrew() > 0)
00364 Build = min(Build, double(planet->GetPopulation()) / cost.GetCrew());
00365
00366 for (ct = 0; ct < Rules::MaxMinType; ++ct)
00367 if (cost[ct] > 0)
00368 Build = min(Build, double(planet->GetContain(ct)) / cost[ct]);
00369
00370
00371 if (long(Build) >= 1) {
00372 *resources -= long(Build) * cost.GetResources();
00373 planet->AdjustPopulation(-(long(Build) * cost.GetCrew()));
00374 for (ct = 0; ct < Rules::MaxMinType; ++ct)
00375 planet->AdjustAmounts(ct, -(long(Build) * cost[ct]));
00376 }
00377
00378 lBuilt += long(Build);
00379
00380 maxbuild -= long(Build);
00381
00382 if (maxbuild > 0) {
00383 if (!Auto)
00384 BuildPartial(cost, planet, resources, Build);
00385
00386
00387 if ((*AutoAlchemy || (!Auto && owner->GetResearchField() == RESEARCH_ALCHEMY)) && *resources > 0) {
00388 if (*resources >= long(Rules::GetConstant("AlchemyCost") * owner->ComponentCostFactor(CT_ALCHEMY))) {
00389 planet->BuildAlchemy(1);
00390 *resources -= long(Rules::GetConstant("AlchemyCost") * owner->ComponentCostFactor(CT_ALCHEMY));
00391 for (CargoType ct = 0; ct < Rules::MaxMinType; ++ct)
00392 planet->AdjustAmounts(ct, 1);
00393 } else {
00394 POPlanetary * alchem = new POPlanetary(POP_ALCHEMY, 1);
00395 alchem->Partial.SetResources(*resources);
00396 *resources = 0;
00397 planet->mProductionQ.push_front(alchem);
00398 }
00399 }
00400 }
00401 } while (maxbuild > 0 && *resources > 0 && (*AutoAlchemy || (!Auto && owner->GetResearchField() == RESEARCH_ALCHEMY)));
00402
00403 if (maxbuild > 0 && *resources > 0) {
00404 if (Auto) {
00405 BuildPartial(cost, planet, resources, Build);
00406 if (Partial.GetResources() > 0) {
00407 ProdOrder * item = NULL;
00408 if (Type >= POP_MIXEDPACKET && Type <= POP_MIXEDPACKET + Rules::MaxMinType) {
00409 item = new POPacket(Type - POP_MIXEDPACKET - 1, 1);
00410 } else if (Type == POP_MINTERRA || Type == POP_MAXTERRA)
00411 item = new POTerraform(POP_TERRAFORM, 1);
00412 else if (Type == POP_TERRAFORM)
00413 item = NULL;
00414 else
00415 item = new POPlanetary(Type, 1);
00416
00417 if (item != NULL) {
00418 item->Partial = Partial;
00419 Partial.Zero();
00420 planet->mProductionQ.push_front(item);
00421 }
00422 }
00423 } else {
00424
00425 owner->GainTech(*resources);
00426 *resources = 0;
00427 }
00428 }
00429
00430 if (!Auto) Amount = maxbuild;
00431 Built(planet, lBuilt);
00432 *AutoAlchemy = false;
00433 return(!Auto && Amount == 0);
00434 }
00435
00436 void ProdOrder::BuildPartial(const Cost & cost, Planet * planet, long * resources, double Build)
00437 {
00438
00439 double dummy;
00440 double fb = modf(Build, &dummy);
00441
00442
00443
00444
00445 Partial.Zero();
00446 Partial.SetResources(long(fb * cost.GetResources()));
00447 *resources -= Partial.GetResources();
00448 if (Partial.GetResources() > 0) {
00449
00450 for (CargoType ct = 0; ct < Rules::MaxMinType; ++ct) {
00451 Partial[ct] = long(fb * cost[ct] + 1.0 - epsilon);
00452 planet->AdjustAmounts(ct, -Partial[ct]);
00453 }
00454 }
00455 }
00456
00457 POAuto::~POAuto()
00458 {
00459 }
00460
00461 TiXmlNode * POAuto::WriteNode(TiXmlNode * node) const
00462 {
00463 string str;
00464 str = TypeToString();
00465
00466 if (str.empty())
00467 TheGame->AddMessage("Error: Invalid auto procution order");
00468 else
00469 AddLong(node, str.c_str(), Amount);
00470
00471 return node;
00472 }
00473
00474 string POAuto::TypeToString() const
00475 {
00476 string str;
00477 if (Type == POP_MINES)
00478 str = "AutoMine";
00479 else if (Type == POP_FACTS)
00480 str = "AutoFactory";
00481 else if (Type == POP_DEFS)
00482 str = "AutoDefense";
00483 else if (Type == POP_ALCHEMY)
00484 str = "AutoAlchemy";
00485 else if (Type == POP_MIXEDPACKET)
00486 str = "AutoPacket";
00487 else if (Type == POP_MINTERRA)
00488 str = "AutoMinTerra";
00489 else if (Type == POP_MAXTERRA)
00490 str = "AutoMaxTerra";
00491 else
00492 TheGame->AddMessage("Error: Invalid auto procution order");
00493
00494 return str;
00495 }
00496
00497 bool POAuto::Produce(Planet * planet, long * resources, bool * AutoAlchemy)
00498 {
00499 const Player * owner = planet->GetOwner();
00500
00501 if (Type == POP_MINES) {
00502 if (owner->ARTechType() >= 0) {
00503
00504 return true;
00505 }
00506
00507 long maxbuild = min(Amount, planet->MaxMines() - planet->GetMines());
00508 if (maxbuild > 0)
00509 DoProduce(owner->MineCost(), planet, resources, AutoAlchemy, maxbuild);
00510
00511
00512 } else if (Type == POP_FACTS) {
00513 if (owner->ARTechType() >= 0) {
00514
00515 return true;
00516 }
00517
00518 long maxbuild = min(Amount, planet->MaxFactories() - planet->GetFactories());
00519 if (maxbuild > 0)
00520 DoProduce(owner->FactoryCost(), planet, resources, AutoAlchemy, maxbuild);
00521
00522
00523 } else if (Type == POP_DEFS) {
00524 if (owner->ARTechType() >= 0) {
00525
00526 return true;
00527 }
00528
00529 long maxbuild = min(Amount, planet->MaxDefenses() - planet->GetDefenses());
00530 if (maxbuild > 0) {
00531 assert(Component::DefenseCost());
00532 Cost cost;
00533 cost.SetResources(long(Component::DefenseCost()->GetResources() * owner->ComponentCostFactor(CT_DEFENSE) + .5));
00534 cost.SetCrew(long(Component::DefenseCost()->GetCrew() * owner->ComponentCostFactor(CT_DEFENSE) + .5));
00535 for (CargoType ct = 0; ct < Rules::MaxMinType; ++ct)
00536 cost[ct] = long((*Component::DefenseCost())[ct] * owner->ComponentCostFactor(CT_DEFENSE) + .5);
00537
00538 DoProduce(cost, planet, resources, AutoAlchemy, maxbuild);
00539 }
00540
00541
00542 } else if (Type == POP_ALCHEMY) {
00543 *AutoAlchemy = true;
00544
00545 } else if (Type == POP_MINTERRA) {
00546
00547 } else if (Type == POP_MAXTERRA) {
00548
00549 } else if (Type >= POP_MIXEDPACKET && Type <= POP_MIXEDPACKET + Rules::MaxMinType) {
00550 if (POPacket::CheckPacket(planet))
00551 DoProduce(planet->GetPacketCost(Type - POP_MIXEDPACKET - 1), planet, resources, AutoAlchemy, Amount);
00552
00553 } else {
00554 Message * mess = planet->NCGetOwner()->AddMessage("Error: Invalid Production type", planet);
00555 mess->AddLong("Auto", Type);
00556 return true;
00557
00558 }
00559
00560 return false;
00561 }
00562
00563
00564 POBase::~POBase()
00565 {
00566 }
00567
00568 TiXmlNode * POBase::WriteNode(TiXmlNode * node) const
00569 {
00570 TiXmlElement POB("Base");
00571 AddLong(&POB, "Design", Type);
00572 ProdOrder::WriteNode(&POB);
00573 node->InsertEndChild(POB);
00574
00575 return node;
00576 }
00577
00578 string POBase::TypeToString() const
00579 {
00580 string str;
00581 str = "Base design ";
00582 str += Long2String(Type);
00583 return str;
00584 }
00585
00586 bool POBase::Produce(Planet * planet, long * resources, bool * AutoAlchemy)
00587 {
00588 Cost cost;
00589
00590 const Player * owner = planet->GetOwner();
00591 if (planet->GetBaseNumber() == Type)
00592 return true;
00593
00594
00595 if (!owner->GetShipDesign(Type) || !owner->GetShipDesign(Type)->IsValidDesign(owner)) {
00596 Message * mess = planet->NCGetOwner()->AddMessage("Error: Invalid Production type", planet);
00597 mess->AddLong("Base", Type);
00598 return true;
00599 }
00600
00601 if (planet->GetBaseNumber() > 0)
00602 cost = owner->GetBaseDesign(Type)->GetCost(owner, planet->GetBaseDesign(), planet);
00603 else
00604 cost = owner->GetBaseDesign(Type)->GetCost(owner);
00605
00606 return DoProduce(cost, planet, resources, AutoAlchemy);
00607 }
00608
00609 void POBase::Built(Planet * planet, long number)
00610 {
00611 assert(number == 1);
00612 planet->SetBaseNumber(Type);
00613 Message * mess = planet->NCGetOwner()->AddMessage("Base built", planet);
00614 mess->AddLong("BaseDesign", Type);
00615 }
00616
00617
00618 POPacket::~POPacket()
00619 {
00620 }
00621
00622 TiXmlNode * POPacket::WriteNode(TiXmlNode * node) const
00623 {
00624 TiXmlElement POP("Packet");
00625 if (Type == POP_MIXEDPACKET)
00626 AddString(&POP, "Type", "Mixed");
00627 else
00628 AddString(&POP, "Type", Rules::GetCargoName(Type - POP_MIXEDPACKET - 1).c_str());
00629 AddLong(&POP, "Number", Amount);
00630 ProdOrder::WriteNode(&POP);
00631 node->InsertEndChild(POP);
00632
00633 return node;
00634 }
00635
00636 string POPacket::TypeToString() const
00637 {
00638 string str;
00639 str = "Packet ";
00640 str += Long2String(Type - POP_MIXEDPACKET - 1);
00641 return str;
00642 }
00643
00644 bool POPacket::CheckPacket(Planet * planet)
00645 {
00646 if (planet->GetBaseNumber() < 0 || planet->GetBaseDesign()->GetDriverSpeed() <= 0) {
00647 planet->NCGetOwner()->AddMessage("Error: Packet without driver", planet);
00648 return false;
00649 } else if (planet->GetPacketSpeed() > planet->GetBaseDesign()->GetDriverSpeed() + Rules::GetConstant("MaxPacketOverFling")) {
00650 Message * mess = planet->NCGetOwner()->AddMessage("Error: Invalid packet speed", planet);
00651 mess->AddLong("Driver safe speed", planet->GetBaseDesign()->GetDriverSpeed());
00652 mess->AddLong("Packet speed", planet->GetPacketSpeed());
00653 return false;
00654 } else if (planet->GetPacketDest() == NULL) {
00655 planet->NCGetOwner()->AddMessage("Error: Packet without destination", planet);
00656 return false;
00657 } else
00658 return true;
00659 }
00660
00661 bool POPacket::Produce(Planet * planet, long * resources, bool * AutoAlchemy)
00662 {
00663 if (!CheckPacket(planet))
00664 return true;
00665
00666 return DoProduce(planet->GetPacketCost(Type - POP_MIXEDPACKET - 1), planet, resources, AutoAlchemy);
00667 }
00668
00669
00670 POPlanetary::~POPlanetary()
00671 {
00672 }
00673
00674 TiXmlNode * POPlanetary::WriteNode(TiXmlNode * node) const
00675 {
00676 string type = TypeToString();
00677
00678 if (type.empty())
00679 return node;
00680
00681 TiXmlElement POP(type.c_str());
00682 AddLong(&POP, "Number", Amount);
00683 ProdOrder::WriteNode(&POP);
00684 node->InsertEndChild(POP);
00685
00686 return node;
00687 }
00688
00689 string POPlanetary::TypeToString() const
00690 {
00691 string str;
00692 switch (Type) {
00693 case POP_FACTS:
00694 str = "Factories";
00695 break;
00696 case POP_MINES:
00697 str = "Mines";
00698 break;
00699 case POP_DEFS:
00700 str = "Defenses";
00701 break;
00702 case POP_ALCHEMY:
00703 str = "Alchemy";
00704 break;
00705 case POP_SCANNER:
00706 str = "Scanner";
00707 break;
00708 default:
00709 TheGame->AddMessage("Error: Invalid planetary procution order");
00710 break;
00711 }
00712
00713 return str;
00714 }
00715
00716 bool POPlanetary::Produce(Planet * planet, long * resources, bool * AutoAlchemy)
00717 {
00718 const Player * owner = planet->GetOwner();
00719 if (Type == POP_FACTS) {
00720 if (owner->ARTechType() >= 0) {
00721
00722 return true;
00723 }
00724
00725 long max = planet->MaxFactories();
00726 if (Amount + planet->GetFactories() > max) {
00727
00728 Amount = max - planet->GetFactories();
00729 }
00730
00731 return DoProduce(owner->FactoryCost(), planet, resources, AutoAlchemy);
00732 } else if (Type == POP_MINES) {
00733 if (owner->ARTechType() >= 0) {
00734
00735 return true;
00736 }
00737
00738 long max = planet->MaxMines();
00739 if (Amount + planet->GetMines() > max) {
00740
00741 Amount = max - planet->GetMines();
00742 }
00743
00744 return DoProduce(owner->MineCost(), planet, resources, AutoAlchemy);
00745 } else if (Type == POP_DEFS) {
00746 if (owner->ARTechType() >= 0) {
00747
00748 return true;
00749 }
00750
00751 long max = planet->MaxDefenses();
00752 if (Amount + planet->GetDefenses() > max) {
00753
00754 Amount = max - planet->GetDefenses();
00755 }
00756
00757 assert(Component::DefenseCost());
00758 Cost cost;
00759 cost.SetResources(long(Component::DefenseCost()->GetResources() * owner->ComponentCostFactor(CT_DEFENSE) + .5));
00760 cost.SetCrew(long(Component::DefenseCost()->GetCrew() * owner->ComponentCostFactor(CT_DEFENSE) + .5));
00761 for (CargoType ct = 0; ct < Rules::MaxMinType; ++ct)
00762 cost[ct] = long((*Component::DefenseCost())[ct] * owner->ComponentCostFactor(CT_DEFENSE) + .5);
00763
00764 return DoProduce(cost, planet, resources, AutoAlchemy);
00765 } else if (Type == POP_ALCHEMY) {
00766 Cost cost;
00767 cost.SetResources(long(Rules::GetConstant("AlchemyCost") * owner->ComponentCostFactor(CT_ALCHEMY) + .5));
00768 cost.SetCrew(0);
00769 for (CargoType ct = 0; ct < Rules::MaxMinType; ++ct)
00770 cost[ct] = 0;
00771
00772 return DoProduce(cost, planet, resources, AutoAlchemy);
00773 } else if (Type == POP_SCANNER) {
00774 if (owner->ARTechType() >= 0) {
00775
00776 return true;
00777 }
00778
00779 assert(Amount == 1);
00780 if (planet->GetScanner()) {
00781
00782 return true;
00783 }
00784
00785 assert(Component::ScannerCost());
00786 Cost cost;
00787 cost.SetResources(long(Component::ScannerCost()->GetResources() * owner->ComponentCostFactor(CT_PLANSCAN) + .5));
00788 cost.SetCrew(long(Component::ScannerCost()->GetCrew() * owner->ComponentCostFactor(CT_PLANSCAN) + .5));
00789 for (CargoType ct = 0; ct < Rules::MaxMinType; ++ct)
00790 cost[ct] = long((*Component::ScannerCost())[ct] * owner->ComponentCostFactor(CT_PLANSCAN) + .5);
00791
00792 return DoProduce(cost, planet, resources, AutoAlchemy);
00793 } else {
00794 Message * mess = planet->NCGetOwner()->AddMessage("Error: Invalid Production type", planet);
00795 mess->AddLong("Planetary", Type);
00796 return true;
00797 }
00798 }
00799
00800 void POPlanetary::Built(Planet * planet, long number)
00801 {
00802 if (Type >= POP_MIXEDPACKET && Type <= POP_MIXEDPACKET + Rules::MaxMinType) {
00803 Packet * p;
00804 p = new Packet(*planet, planet->GetPacketSpeed(), planet->GetBaseDesign()->GetDriverSpeed(), planet->GetPacketDest());
00805 if (Type == POP_MIXEDPACKET) {
00806 for (long i = 0; i < Rules::MaxMinType; ++i)
00807 p->AdjustAmounts(i, planet->GetOwner()->PacketSizeMixed() * number);
00808 } else {
00809 p->AdjustAmounts(Type - POP_MIXEDPACKET - 1, planet->GetOwner()->PacketSizeOneMin() * number);
00810 }
00811
00812 TheGalaxy->AddPacket(p, planet);
00813 } else if (Type == POP_FACTS) {
00814 planet->BuildFactories(number);
00815 } else if (Type == POP_MINES) {
00816 planet->BuildMines(number);
00817 } else if (Type == POP_DEFS) {
00818 planet->BuildDefenses(number);
00819 } else if (Type == POP_ALCHEMY) {
00820 planet->BuildAlchemy(number);
00821 for (CargoType ct = 0; ct < Rules::MaxMinType; ++ct)
00822 planet->AdjustAmounts(ct, number);
00823 } else if (Type == POP_SCANNER) {
00824 planet->NCGetOwner()->AddMessage("Built scanner", planet);
00825 assert(number == 1);
00826 planet->BuildScanner();
00827 }
00828 }
00829
00830
00831 POShip::~POShip()
00832 {
00833 }
00834
00835 TiXmlNode * POShip::WriteNode(TiXmlNode * node) const
00836 {
00837 TiXmlElement POS("Ship");
00838 AddLong(&POS, "Design", Type);
00839 AddLong(&POS, "Number", Amount);
00840 ProdOrder::WriteNode(&POS);
00841 node->InsertEndChild(POS);
00842 return node;
00843 }
00844
00845 string POShip::TypeToString() const
00846 {
00847 string str;
00848 str = "Ship design ";
00849 str += Long2String(Type);
00850 return str;
00851 }
00852
00853 bool POShip::Produce(Planet * planet, long * resources, bool * AutoAlchemy)
00854 {
00855 const Player * owner = planet->GetOwner();
00856
00857
00858 if (!owner->GetShipDesign(Type) || !owner->GetShipDesign(Type)->IsValidDesign(owner)) {
00859 Message * mess = planet->NCGetOwner()->AddMessage("Error: Invalid Production type", planet);
00860 mess->AddLong("Ship", Type);
00861 return true;
00862 }
00863
00864 if (planet->GetBaseNumber() < 0 ||
00865 (planet->GetBaseDesign()->GetDock() >= 0 &&
00866 owner->GetShipDesign(Type)->GetMass() > planet->GetBaseDesign()->GetDock()))
00867 {
00868 Message * mess = planet->NCGetOwner()->AddMessage("Warning: Ship too big for dock", planet);
00869 mess->AddItem("Ship design", owner->GetShipDesign(Type)->GetName());
00870 mess->AddLong("dock capacity", planet->GetBaseDesign()->GetDock());
00871 return true;
00872 }
00873
00874 return DoProduce(owner->GetShipDesign(Type)->GetCost(owner), planet, resources, AutoAlchemy);
00875 }
00876
00877 void POShip::Built(Planet * planet, long number)
00878 {
00879 Player * player = planet->NCGetOwner();
00880 player->BuildShips(planet, Type, number);
00881 }
00882
00883
00884 POTerraform::~POTerraform()
00885 {
00886 }
00887
00888 TiXmlNode * POTerraform::WriteNode(TiXmlNode * node) const
00889 {
00890 if (Type == POP_MINTERRA)
00891 AddLong(node, "AutoMinTerra", Amount);
00892 else if (Type == POP_MAXTERRA)
00893 AddLong(node, "AutoMaxTerra", Amount);
00894 else {
00895 TiXmlElement POT("Terraform");
00896 AddLong(&POT, "Number", Amount);
00897 ProdOrder::WriteNode(&POT);
00898 node->InsertEndChild(POT);
00899 }
00900
00901 return node;
00902 }
00903
00904 string POTerraform::TypeToString() const
00905 {
00906 string str;
00907 if (Type == POP_MINTERRA)
00908 str = "AutoMinTerra";
00909 else if (Type == POP_MAXTERRA)
00910 str = "AutoMaxTerra";
00911 else
00912 str = "Terraform";
00913
00914 return str;
00915 }
00916
00917 bool POTerraform::Produce(Planet * planet, long * resources, bool * AutoAlchemy)
00918 {
00919 Player * owner = planet->NCGetOwner();
00920 double cf = owner->ComponentCostFactor(CT_TERRAFORM);
00921 if (cf <= epsilon)
00922 return true;
00923
00924 Cost c;
00925
00926
00927 long tempAmt = Amount;
00928 while (Amount > 0 && *resources > 0) {
00929 if (Type == POP_MINTERRA && planet->GetPopulation() <= planet->GetMaxPop() && planet->GetOwner()->HabFactor(planet) >= 0)
00930 return false;
00931
00932 c.Zero();
00933 owner->ResetTerraLimits();
00934 for (unsigned long i = 0; i < TheGame->GetComponents().size(); ++i) {
00935
00936 if (TheGame->GetComponents()[i]->GetType() == CT_TERRAFORM &&
00937 TheGame->GetComponents()[i]->IsBuildable(owner) &&
00938 planet->CanTerraform(TheGame->GetComponents()[i]) &&
00939 (mResCost == 0 || mResCost >= TheGame->GetComponents()[i]->GetCost().GetResources()))
00940 {
00941 owner->SetTerraLimit(TheGame->GetComponents()[i]->GetTerraType(), TheGame->GetComponents()[i]->GetTerraLimit());
00942 c = TheGame->GetComponents()[i]->GetCost();
00943 }
00944 }
00945
00946 if (c.GetResources() == 0) {
00947 if (Type == POP_TERRAFORM)
00948 return true;
00949 else
00950 break;
00951 }
00952
00953 c *= cf;
00954
00955 if (DoProduce(c, planet, resources, AutoAlchemy) == true && Type == POP_TERRAFORM)
00956 return true;
00957 }
00958
00959 if (Type == POP_TERRAFORM)
00960 return Amount == 0;
00961 else {
00962 Amount = tempAmt;
00963 return false;
00964 }
00965 }
00966
00967 void POTerraform::Built(Planet * planet, long number)
00968 {
00969 assert(number == 1);
00970 planet->Terraform(planet->GetOwner(), true);
00971 Amount -= number;
00972 }