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
00029 #include "RacialTrait.h"
00030
00031 Race::Race()
00032 {
00033 ResetDefaults();
00034 mHabCenter.insert(mHabCenter.begin(), Rules::MaxHabType, 50);
00035 mHabWidth.insert(mHabWidth.begin(), Rules::MaxHabType, 20);
00036 mTechCostFactor.insert(mTechCostFactor.begin(), Rules::MaxTechType, 1.0);
00037 mStartMinerals = 0;
00038 mStartConcentrations = 0;
00039 mStartMines = 0;
00040 mStartFactories = 0;
00041 mStartDefneses = 0;
00042 mStartAt = false;
00043 }
00044
00045 Race::~Race()
00046 {
00047 }
00048
00049 double Race::RadDamage(HabType ht) const
00050 {
00051 if (ht == -1)
00052 return 0.0;
00053 else if (mHabWidth[ht] == -1)
00054 return 0.0;
00055 else if (mHabCenter[ht] >= 85)
00056 return 0.0;
00057 else {
00058 return (86 - mHabCenter[ht]) / 100.0;
00059 }
00060 }
00061
00062 double Race::HabFactor(HabType ht, long tick) const
00063 {
00064 if (ht < 0 && ht >= Rules::MaxHabType)
00065 return 0;
00066 else if (mHabWidth[ht] == -1)
00067 return 1;
00068 else if (tick < mHabCenter[ht] - mHabWidth[ht])
00069 return max(-15L, tick - (mHabCenter[ht] - mHabWidth[ht]));
00070 else if (tick > mHabCenter[ht] + mHabWidth[ht])
00071 return max(-15L, (mHabCenter[ht] + mHabWidth[ht]) - tick);
00072 else
00073 return 1.0 - double(abs(tick - mHabCenter[ht])) / double(mHabWidth[ht]);
00074 }
00075
00076 long Race::HabFactor(const Planet * p) const
00077 {
00078 double Result = 0;
00079 double LowMultiplier = 1;
00080 HabType ht;
00081 for (ht = 0; ht < Rules::MaxHabType; ++ht) {
00082 double temp = HabFactor(ht, p->GetHabValue(ht));
00083 if (temp < 0 && Result < 0)
00084 Result += temp;
00085 else if (temp < 0 && Result >= 0)
00086 Result = temp;
00087 else if (temp >= 0 && Result >= 0) {
00088 Result = Result + temp * temp;
00089 }
00090
00091 if (temp < .5)
00092 LowMultiplier *= temp + 0.5;
00093 }
00094
00095 if (Result < 0)
00096 return long(Result - .5);
00097
00098 Result = sqrt(Result / Rules::MaxHabType);
00099 Result *= LowMultiplier;
00100
00101 return long(Result * 100 + .5);
00102 }
00103
00104 long Race::HabCenter(HabType ht) const
00105 {
00106 if (ht >= 0 && ht < Rules::MaxHabType)
00107 return mHabCenter[ht];
00108 else
00109 return 0;
00110 }
00111
00112 long Race::HabWidth(HabType ht) const
00113 {
00114 if (ht >= 0 && ht < Rules::MaxHabType)
00115 return mHabWidth[ht];
00116 else
00117 return 0;
00118 }
00119
00120 double Race::TechCostFactor(TechType tt) const
00121 {
00122 if (tt >= 0 && tt < Rules::MaxTechType)
00123 return mTechCostFactor[tt];
00124 else
00125 return 0;
00126 }
00127
00128 bool Race::ParseNode(const TiXmlNode * node, bool other)
00129 {
00130 const TiXmlNode * child1;
00131 const TiXmlNode * child2;
00132 long i;
00133 const char * ptr;
00134
00135 for (child1 = node->FirstChild(); child1; child1 = child1->NextSibling()) {
00136 if (child1->Type() == TiXmlNode::COMMENT)
00137 continue;
00138
00139 if (stricmp(child1->Value(), "Randomize") == 0) {
00140
00141 } else if (stricmp(child1->Value(), "SingularName") == 0) {
00142 ptr = GetString(child1);
00143 if (ptr != NULL)
00144 mSingularName = ptr;
00145 } else if (stricmp(child1->Value(), "PluralName") == 0) {
00146 ptr = GetString(child1);
00147 if (ptr != NULL)
00148 mPluralName = ptr;
00149 } else if (stricmp(child1->Value(), "PrimaryRacialTrait") == 0) {
00150 mPRT = TheGame->ParsePRT(GetString(child1));
00151 } else if (stricmp(child1->Value(), "LesserRacialTrait") == 0) {
00152 const RacialTrait * rt;
00153 rt = TheGame->ParseLRT(GetString(child1));
00154 if (rt == NULL) {
00155 Message * mess = TheGame->AddMessage("Error: Invalid racial setting");
00156 mess->AddItem("Race", mSingularName);
00157 mess->AddItem("LesserRacialTrait", GetString(child1));
00158 return false;
00159 } else
00160 mLRTs.insert(mLRTs.end(), rt);
00161 } else if (stricmp(child1->Value(), "HabSettings") == 0) {
00162 for (child2 = child1->FirstChild("Hab"); child2; child2 = child2->NextSibling("Hab")) {
00163 const TiXmlElement * el;
00164 el = child2->ToElement();
00165 int i = Rules::HabID(el->Attribute("Name"));
00166 if (i < 0 || i >= Rules::MaxHabType) {
00167 Message * mess = TheGame->AddMessage("Error: Invalid racial setting");
00168 mess->AddItem("Race", mSingularName);
00169 mess->AddItem("Hab type", el->Attribute("Name"));
00170 return false;
00171 }
00172
00173 mHabCenter[i] = GetLong(child2->FirstChild("Center"));
00174 if (mHabCenter[i] != -1 && (mHabCenter[i] < 10 || mHabCenter[i] > 90)) {
00175 Message * mess = TheGame->AddMessage("Error: Invalid racial setting");
00176 mess->AddItem("Race", mSingularName);
00177 mess->AddLong("Hab center", mHabCenter[i]);
00178 return false;
00179 }
00180 mHabWidth[i] = GetLong(child2->FirstChild("Width"));
00181 if ((mHabCenter[i] == -1 && mHabWidth[i] != -1) ||
00182 (mHabCenter[i] != -1 && mHabWidth[i] == -1) ||
00183 (mHabWidth[i] > mHabCenter[i] || mHabWidth[i] > 100 - mHabCenter[i]))
00184 {
00185 Message * mess = TheGame->AddMessage("Error: Invalid racial setting");
00186 mess->AddItem("Race", mSingularName);
00187 mess->AddLong("Hab width", mHabCenter[i]);
00188 return false;
00189 }
00190 }
00191 } else if (stricmp(child1->Value(), "GrowthRate") == 0) {
00192 mGrowthRate = GetDouble(child1);
00193 if (mGrowthRate < 0.009 || mGrowthRate > 0.201) {
00194 Message * mess = TheGame->AddMessage("Error: Invalid racial setting");
00195 mess->AddItem("Race", mSingularName);
00196 mess->AddFloat("GrowthRate", mGrowthRate);
00197 return false;
00198 }
00199 } else if (stricmp(child1->Value(), "PopEfficiency") == 0) {
00200 mPopEfficiency = GetLong(child1);
00201 if (mPopEfficiency < 700 || mPopEfficiency > 2500) {
00202 Message * mess = TheGame->AddMessage("Error: Invalid racial setting");
00203 mess->AddItem("Race", mSingularName);
00204 mess->AddLong("PopEfficiency", mPopEfficiency);
00205 return false;
00206 }
00207 } else if (stricmp(child1->Value(), "FactoryRate") == 0) {
00208 mFactoryRate = GetLong(child1);
00209 if (mFactoryRate < 5 || mFactoryRate > 15) {
00210 Message * mess = TheGame->AddMessage("Error: Invalid racial setting");
00211 mess->AddItem("Race", mSingularName);
00212 mess->AddLong("FactoryRate", mFactoryRate);
00213 return false;
00214 }
00215 } else if (stricmp(child1->Value(), "FactoryCost") == 0) {
00216 mFactoryCost.ReadCosts(child1);
00217 } else if (stricmp(child1->Value(), "FactoriesRun") == 0) {
00218 mFactoriesRun = GetLong(child1);
00219 if (mFactoriesRun < 5 || mFactoriesRun > 25) {
00220 Message * mess = TheGame->AddMessage("Error: Invalid racial setting");
00221 mess->AddItem("Race", mSingularName);
00222 mess->AddLong("FactoriesRun", mFactoriesRun);
00223 return false;
00224 }
00225 } else if (stricmp(child1->Value(), "MineRate") == 0) {
00226 mMineRate = GetLong(child1);
00227 if (mMineRate < 5 || mMineRate > 15) {
00228 Message * mess = TheGame->AddMessage("Error: Invalid racial setting");
00229 mess->AddItem("Race", mSingularName);
00230 mess->AddLong("MineRate", mMineRate);
00231 return false;
00232 }
00233 } else if (stricmp(child1->Value(), "MineCost") == 0) {
00234 mMineCost.ReadCosts(child1);
00235 } else if (stricmp(child1->Value(), "MinesRun") == 0) {
00236 mMinesRun = GetLong(child1);
00237 if (mMinesRun < 5 || mMinesRun > 25) {
00238 Message * mess = TheGame->AddMessage("Error: Invalid racial setting");
00239 mess->AddItem("Race", mSingularName);
00240 mess->AddLong("MinesRun", mMinesRun);
00241 return false;
00242 }
00243 } else if (stricmp(child1->Value(), "TechFactor") == 0) {
00244 Rules::ParseArrayFloat(child1, mTechCostFactor, TECHS);
00245 } else if (stricmp(child1->Value(), "StartAt") == 0) {
00246 ptr = GetString(child1);
00247 if (ptr && stricmp(ptr, "true") == 0)
00248 mStartAt = true;
00249 } else if (stricmp(child1->Value(), "StartMinerals") == 0) {
00250 mStartMinerals = GetLong(child1);
00251 if (mStartMinerals < 0 || mStartMinerals > 50) {
00252 Message * mess = TheGame->AddMessage("Error: Invalid racial setting");
00253 mess->AddItem("Race", mSingularName);
00254 mess->AddLong("StartMinerals", mStartMinerals);
00255 return false;
00256 }
00257 } else if (stricmp(child1->Value(), "StartConcentrations") == 0) {
00258 mStartConcentrations = GetLong(child1);
00259 if (mStartConcentrations < 0 || mStartConcentrations > 50) {
00260 Message * mess = TheGame->AddMessage("Error: Invalid racial setting");
00261 mess->AddItem("Race", mSingularName);
00262 mess->AddLong("StartConcentrations", mStartConcentrations);
00263 return false;
00264 }
00265 } else if (stricmp(child1->Value(), "StartMines") == 0) {
00266 mStartMines = GetLong(child1);
00267 if (mStartMines < 0 || mStartMines > 50) {
00268 Message * mess = TheGame->AddMessage("Error: Invalid racial setting");
00269 mess->AddItem("Race", mSingularName);
00270 mess->AddLong("StartMines", mStartMines);
00271 return false;
00272 }
00273 } else if (stricmp(child1->Value(), "StartFactories") == 0) {
00274 mStartFactories = GetLong(child1);
00275 if (mStartFactories < 0 || mStartFactories > 50) {
00276 Message * mess = TheGame->AddMessage("Error: Invalid racial setting");
00277 mess->AddItem("Race", mSingularName);
00278 mess->AddLong("StartFactories", mStartFactories);
00279 return false;
00280 }
00281 } else if (stricmp(child1->Value(), "StartDefneses") == 0) {
00282 mStartDefneses = GetLong(child1);
00283 if (mStartDefneses < 0 || mStartDefneses > 50) {
00284 Message * mess = TheGame->AddMessage("Error: Invalid racial setting");
00285 mess->AddItem("Race", mSingularName);
00286 mess->AddLong("StartDefneses", mStartDefneses);
00287 return false;
00288 }
00289 } else if (stricmp(child1->Value(), "RaceEmblem") == 0) {
00290 mRaceEmblem = GetLong(child1);
00291 if (mRaceEmblem < 0 || mRaceEmblem > 16) {
00292 Message * mess = TheGame->AddMessage("Error: Invalid racial setting");
00293 mess->AddItem("Race", mSingularName);
00294 mess->AddLong("RaceEmblem", mRaceEmblem);
00295 return false;
00296 }
00297 } else if (!other && stricmp(child1->Value(), "Password") == 0) {
00298 ptr = GetString(child1);
00299 if (ptr != NULL)
00300 mPassword = ptr;
00301 } else if (stricmp(child1->Value(), "MetaInfo") == 0) {
00302
00303 } else {
00304 Message * mess = TheGame->AddMessage("Warning: Unknown section");
00305 mess->AddItem("Race", mSingularName);
00306 mess->AddItem("Section", child1->Value());
00307 continue;
00308 }
00309 }
00310
00311 if (!other && mPRT == NULL) {
00312 Message * mess = TheGame->AddMessage("Error: Invalid racial setting");
00313 mess->AddItem("Race", mSingularName);
00314 mess->AddItem("Missing PRT", "");
00315 return false;
00316 }
00317 if (!other && mGrowthRate <= 0.009) {
00318 Message * mess = TheGame->AddMessage("Error: Invalid racial setting");
00319 mess->AddItem("Race", mSingularName);
00320 mess->AddFloat("GrowthRate", mGrowthRate);
00321 return false;
00322 }
00323
00324 if (!other) {
00325 for (i = 0; i < Rules::MaxHabType; ++i) {
00326 if (mHabCenter[i] == 0 || mHabWidth[i] == 0) {
00327 Message * mess = TheGame->AddMessage("Error: Invalid racial setting");
00328 mess->AddItem("Race", mSingularName);
00329 mess->AddItem("missing Hab Setting", Rules::GetHabName(i));
00330 return false;
00331 }
00332 }
00333 }
00334
00335 return true;
00336 }
00337
00338 void Race::WriteHabs(TiXmlNode * node) const
00339 {
00340 TiXmlElement HS("HabSettings");
00341 for (int i = 0; i < Rules::MaxHabType; ++i) {
00342 TiXmlElement hab("Hab");
00343 hab.SetAttribute("Name", Rules::GetHabName(i));
00344 AddLong(&hab, "Center", mHabCenter[i]);
00345 AddLong(&hab, "Width", mHabWidth[i]);
00346 HS.InsertEndChild(hab);
00347 }
00348 node->InsertEndChild(HS);
00349 }
00350
00351 void Race::WriteNode(TiXmlNode * node) const
00352 {
00353 AddString(node, "SingularName", mSingularName.c_str());
00354 AddString(node, "PluralName", mPluralName.c_str());
00355 AddString(node, "PrimaryRacialTrait", mPRT->Name().c_str());
00356
00357 deque<const RacialTrait *>::const_iterator rti;
00358 for (rti = mLRTs.begin(); rti != mLRTs.end(); ++rti) {
00359 AddString(node, "LesserRacialTrait", (*rti)->Name().c_str());
00360 }
00361
00362 TiXmlElement HS("HabSettings");
00363 for (int i = 0; i < Rules::MaxHabType; ++i) {
00364 TiXmlElement hab("Hab");
00365 hab.SetAttribute("Name", Rules::GetHabName(i));
00366 AddLong(&hab, "Center", mHabCenter[i]);
00367 AddLong(&hab, "Width", mHabWidth[i]);
00368 HS.InsertEndChild(hab);
00369 }
00370 node->InsertEndChild(HS);
00371
00372 AddDouble(node, "GrowthRate", mGrowthRate);
00373 AddLong(node, "PopEfficiency", mPopEfficiency);
00374 AddLong(node, "FactoryRate", mFactoryRate);
00375 mFactoryCost.WriteCosts(node, "FactoryCost");
00376 AddLong(node, "FactoriesRun", mFactoriesRun);
00377 AddLong(node, "MineRate", mMineRate);
00378 mMineCost.WriteCosts(node, "MineCost");
00379 AddLong(node, "MinesRun", mMinesRun);
00380 node->LinkEndChild(Rules::WriteArrayFloat("TechFactor", mTechCostFactor, TECHS));
00381
00382 if (mStartAt)
00383 AddString(node, "StartAt", "true");
00384
00385 if (mStartMinerals > 0) AddLong(node, "StartMinerals", mStartMinerals);
00386 if (mStartConcentrations > 0) AddLong(node, "StartConcentrations", mStartConcentrations);
00387 if (mStartMines > 0) AddLong(node, "StartMines", mStartMines);
00388 if (mStartFactories > 0) AddLong(node, "StartFactories", mStartFactories);
00389 if (mStartDefneses > 0) AddLong(node, "StartDefneses", mStartDefneses);
00390
00391 AddLong(node, "RaceEmblem", mRaceEmblem);
00392 AddString(node, "Password", mPassword.c_str());
00393
00394 deque<double>::const_iterator li;
00395 li = max_element(CVEngineFailure.begin(), CVEngineFailure.end());
00396 if (*li > 0.0) {
00397 node->LinkEndChild(Rules::WriteArrayFloat("CVEngineFailure", "Warp", "Speed", CVEngineFailure));
00398 }
00399 }
00400
00401 void Race::ResetDefaults()
00402 {
00403 CCalcGroundAttackFactor = false;
00404 CCalcGroundDefenseFactor = false;
00405 CCalcGrowthRateFactor = false;
00406 CCalcPopulationFactor = false;
00407 CVCloakCargo = -1;
00408 CVMineSpeedBonus = -1;
00409 CCalcSpyTechBonus = false;
00410 CCalcBattleSpeedBonus = false;
00411 CCalcPermaformChance = false;
00412 CVCanSeeHabSettings = -1;
00413 CVTemporaryTerraform = -1;
00414 CVScanDesign = -1;
00415 CCalcRepairFactor = false;
00416 CCalcFreighterReproduction = false;
00417 CVMineFieldScanning = -1;
00418 CVCanRemoteDetonate = -1;
00419 CCalcMineDecayFactor = false;
00420
00421 CVPacketTerraform = -1;
00422 CVPacketScanning = -1;
00423 CCalcPacketCostMinFactor = false;
00424 CVPacketSizeOneMin = -1;
00425 CVPacketSizeMixed = -1;
00426 CVPacketCostResources = -1;
00427 CCalcPacketDecayFactor = false;
00428 CCalcPacketCatchFactor = false;
00429 CVPacketDecayPenalty = -1;
00430
00431 CVStartAtBonus = -1;
00432 CVGateCargo = -1;
00433 CCalcOvergateLossFactor = false;
00434 CVGateScanning = -1;
00435 CVARTechType = -2;
00436 CCalcFuelFactor = false;
00437 CVGeneralResearch = -1;
00438 CVUltimateRecycle = -1;
00439 CCalcSpaceScanFactor = false;
00440 CCalcPenScanFactor = false;
00441 CCalcStartingPopFactor = false;
00442 CCalcZeroTechCost = false;
00443 CCalcMaxMiniturize = false;
00444 CCalcMiniturizeRate = false;
00445 CCalcShieldFactor = false;
00446 CCalcArmorFactor = false;
00447 CCalcShieldRegenRate = false;
00448 CCalcDefenseFactor = false;
00449
00450 CVEngineFailure.clear();
00451 CVEngineFailure.insert(CVEngineFailure.begin(), Rules::GetConstant("MaxSpeed"), -1.0);
00452 }
00453
00454 bool Race::HasSecondPlanet() const
00455 {
00456 return mPRT->HasSecondPlanet();
00457 }
00458
00459 long lInherentCloaking(long v, const RacialTrait * lrt, HullType hc)
00460 {
00461 return v + (((lrt->InherentCloakHull() & hc) == hc) ? lrt->InherentCloakAmount() : 0);
00462 }
00463
00464 long Race::InherentCloaking(HullType hc) const
00465 {
00466 return accumulate( mLRTs.begin(),
00467 mLRTs.end(),
00468 ((mPRT->InherentCloakHull() & hc) == hc) ? mPRT->InherentCloakAmount() : 0,
00469 lInherentCloaking,
00470 hc);
00471 }
00472
00473 double lComponentCostFactor(double v, const RacialTrait * lrt, ComponentType ct)
00474 {
00475 return v * (double(lrt->ComponentCostFactor(ct)));
00476 }
00477
00478 double Race::ComponentCostFactor(ComponentType ct) const
00479 {
00480 return accumulate(mLRTs.begin(),
00481 mLRTs.end(),
00482 double(mPRT->ComponentCostFactor(ct)),
00483 lComponentCostFactor,
00484 ct);
00485 }
00486
00487 long lStartingTech(long v, const RacialTrait * lrt, TechType tt)
00488 {
00489 return v + lrt->StartingTech(tt);
00490 }
00491
00492 long Race::PRTStartTech(TechType tt) const
00493 {
00494 return mPRT->StartingTech(tt);
00495 }
00496
00497 long Race::LRTStartTech(TechType tt) const
00498 {
00499 return accumulate( mLRTs.begin(),
00500 mLRTs.end(),
00501 0,
00502 lStartingTech,
00503 tt);
00504 }
00505
00506 double lEngineFailure(double v, const RacialTrait * lrt, long speed)
00507 {
00508 return (1.0 - (1.0 - v) * (1.0 - lrt->EngineFailure(speed)));
00509 }
00510
00511 double Race::EngineFailure(long speed) const
00512 {
00513 if (CVEngineFailure[speed-1] >= 0.0) {
00514 double Result = accumulate(mLRTs.begin(),
00515 mLRTs.end(),
00516 mPRT->EngineFailure(speed),
00517 lEngineFailure,
00518 speed);
00519 const_cast<Race *>(this)->CVEngineFailure[speed-1] = Result;
00520 }
00521 return CVEngineFailure[speed-1];
00522 }
00523
00524 long Race::BuiltinScan(const Player * player, HullType hc, bool PenScan, long pop ) const
00525 {
00526 long Result = mPRT->BuiltinScan(player, hc, PenScan, pop);
00527 deque<const RacialTrait *>::const_iterator lrt;
00528 for (lrt = mLRTs.begin(); lrt != mLRTs.end(); ++lrt)
00529 Result = max(Result, (*lrt)->BuiltinScan(player, hc, PenScan, pop));
00530
00531 return Result;
00532 }
00533
00534
00535
00536
00537
00538
00539
00540 #define GET_RACE_SUM(Function) \
00541 long l##Function(long v, const RacialTrait * lrt) \
00542 { \
00543 return v + lrt->Function(); \
00544 } \
00545 \
00546 long Race::Function() const \
00547 { \
00548 if (CV##Function == -1) \
00549 const_cast<Race *>(this)->CV##Function = accumulate(mLRTs.begin(), mLRTs.end(), mPRT->Function(), l##Function); \
00550 return CV##Function; \
00551 }
00552
00553 #define GET_RACE_SUMD(Function) \
00554 double l##Function(long v, const RacialTrait * lrt) \
00555 { \
00556 return v + lrt->Function(); \
00557 } \
00558 \
00559 double Race::Function() const \
00560 { \
00561 if (!CCalc##Function) { \
00562 const_cast<Race *>(this)->CCalc##Function = true;\
00563 const_cast<Race *>(this)->CV##Function = accumulate(mLRTs.begin(), mLRTs.end(), mPRT->Function(), l##Function); \
00564 } \
00565 return CV##Function; \
00566 }
00567
00568 #define GET_RACE_PRODUCT(Function) \
00569 double l##Function(double v, const RacialTrait * lrt) \
00570 { \
00571 return v * double(lrt->Function()); \
00572 } \
00573 \
00574 double Race::Function() const \
00575 { \
00576 if (!CCalc##Function) { \
00577 const_cast<Race *>(this)->CCalc##Function = true;\
00578 const_cast<Race *>(this)->CV##Function = accumulate(mLRTs.begin(), mLRTs.end(), double(mPRT->Function()), l##Function); \
00579 } \
00580 return CV##Function; \
00581 }
00582
00583 #define GET_RACE_PRODUCT_PER(Function) \
00584 double l##Function(double v, const RacialTrait * lrt) \
00585 { \
00586 return (1.0 - (1.0 - v) * (1.0 - lrt->Function())); \
00587 } \
00588 \
00589 double Race::Function() const \
00590 { \
00591 if (!CCalc##Function) { \
00592 const_cast<Race *>(this)->CCalc##Function = true;\
00593 const_cast<Race *>(this)->CV##Function = accumulate(mLRTs.begin(), mLRTs.end(), mPRT->Function(), l##Function); \
00594 } \
00595 return CV##Function; \
00596 }
00597
00598 #define GET_RACE_MIN(Function) \
00599 long l##Function(long v, const RacialTrait * lrt) \
00600 { \
00601 return min(v, lrt->Function()); \
00602 } \
00603 \
00604 long Race::Function() const \
00605 { \
00606 return accumulate(mLRTs.begin(), mLRTs.end(), mPRT->Function(), l##Function); \
00607 }
00608
00609 #define GET_RACE_MAX(Function) \
00610 long l##Function(long v, const RacialTrait * lrt) \
00611 { \
00612 return max(v, lrt->Function()); \
00613 } \
00614 \
00615 long Race::Function() const \
00616 { \
00617 return accumulate(mLRTs.begin(), mLRTs.end(), mPRT->Function(), l##Function); \
00618 }
00619
00620 #define GET_RACE_MAXD(Function) \
00621 double l##Function(double v, const RacialTrait * lrt) \
00622 { \
00623 return max(v, lrt->Function()); \
00624 } \
00625 \
00626 double Race::Function() const \
00627 { \
00628 return accumulate(mLRTs.begin(), mLRTs.end(), mPRT->Function(), l##Function); \
00629 }
00630
00631 #define GET_RACE_HAS(Function) \
00632 bool Race::Function() const \
00633 { \
00634 if (CV##Function != -1) \
00635 return CV##Function ? true : false; \
00636 const_cast<Race *>(this)->CV##Function = 1; \
00637 if (mPRT->Function()) \
00638 return true; \
00639 for (deque<const RacialTrait *>::const_iterator i = mLRTs.begin(); i != mLRTs.end(); ++i) \
00640 if ((*i)->Function()) \
00641 return true; \
00642 const_cast<Race *>(this)->CV##Function = 0; \
00643 return false; \
00644 }
00645
00646 GET_RACE_PRODUCT(GroundAttackFactor)
00647 GET_RACE_PRODUCT(GroundDefenseFactor)
00648 GET_RACE_PRODUCT(GrowthRateFactor)
00649 GET_RACE_PRODUCT(PopulationFactor)
00650 GET_RACE_HAS(CloakCargo)
00651 GET_RACE_SUM(MineSpeedBonus)
00652 GET_RACE_SUMD(SpyTechBonus)
00653 GET_RACE_SUMD(BattleSpeedBonus)
00654 GET_RACE_PRODUCT_PER(PermaformChance)
00655 GET_RACE_HAS(CanSeeHabSettings)
00656 GET_RACE_HAS(TemporaryTerraform)
00657 GET_RACE_HAS(ScanDesign)
00658 GET_RACE_PRODUCT(RepairFactor)
00659 GET_RACE_PRODUCT_PER(FreighterReproduction)
00660 GET_RACE_HAS(MineFieldScanning)
00661 GET_RACE_HAS(CanRemoteDetonate)
00662 GET_RACE_PRODUCT(MineDecayFactor)
00663
00664 GET_RACE_HAS(PacketTerraform)
00665 GET_RACE_HAS(PacketScanning)
00666 GET_RACE_PRODUCT_PER(PacketCostMinFactor)
00667 GET_RACE_MIN(PacketSizeOneMin)
00668 GET_RACE_MIN(PacketSizeMixed)
00669 GET_RACE_MIN(PacketCostResources)
00670 GET_RACE_PRODUCT(PacketDecayFactor)
00671 GET_RACE_PRODUCT(PacketCatchFactor)
00672 GET_RACE_SUM(PacketDecayPenalty)
00673
00674 GET_RACE_MAX(StartAtBonus)
00675 GET_RACE_HAS(GateCargo)
00676 GET_RACE_PRODUCT(OvergateLossFactor)
00677 GET_RACE_HAS(GateScanning)
00678 GET_RACE_MAX(ARTechType)
00679 GET_RACE_PRODUCT(FuelFactor)
00680 GET_RACE_HAS(GeneralResearch)
00681 GET_RACE_HAS(UltimateRecycle)
00682 GET_RACE_PRODUCT(SpaceScanFactor)
00683 GET_RACE_PRODUCT(PenScanFactor)
00684 GET_RACE_PRODUCT(StartingPopFactor)
00685 GET_RACE_PRODUCT(ZeroTechCost)
00686 GET_RACE_MAXD(MaxMiniturize)
00687 GET_RACE_MAXD(MiniturizeRate)
00688 GET_RACE_PRODUCT(ShieldFactor)
00689 GET_RACE_PRODUCT(ArmorFactor)
00690 GET_RACE_PRODUCT_PER(ShieldRegenRate)
00691
00692 GET_RACE_PRODUCT(DefenseFactor)