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 #ifdef _DEBUG
00029 #define new DEBUG_NEW
00030 #endif
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 void CargoHolder::Init()
00044 {
00045 mContains.insert(mContains.begin(), Rules::MaxMinType, 0);
00046 mPopulation = 0;
00047 mSeenBy.insert(mSeenBy.begin(), TheGame->NumberPlayers(), 0L);
00048 mID = 0;
00049 }
00050
00051 CargoHolder::~CargoHolder()
00052 {
00053 }
00054
00055 bool CargoHolder::ParseNode(const TiXmlNode * node)
00056 {
00057 unsigned long num = GetLong(node->FirstChild("Owner"));
00058 if (num < 0 || num > TheGame->NumberPlayers()) {
00059 Message * mess = TheGame->AddMessage("Error: Invalid player number");
00060 mess->AddLong("", num);
00061 mess->AddItem("Owener of", this);
00062 return false;
00063 }
00064
00065 return ParseNode(node, TheGame->NCGetPlayer(num));
00066 }
00067
00068 bool CargoHolder::ParseNode(const TiXmlNode * node, Player * player)
00069 {
00070 if (!Location::ParseNode(node->FirstChild("Location")))
00071 return false;
00072
00073 mOwner = player;
00074 const TiXmlElement * tie = node->ToElement();
00075 mID = atol(tie->Attribute("IDNumber"));
00076 Rules::ReadCargo(node->FirstChild("Contains"), mContains, &mPopulation);
00077 Rules::ParseArray(node->FirstChild("SeenBy"), "Race", "Number", mSeenBy);
00078
00079 return true;
00080 }
00081
00082 TiXmlNode * CargoHolder::WriteNode(TiXmlNode * node, const Player * viewer) const
00083 {
00084 if (!SeenBy(viewer))
00085 return NULL;
00086
00087 if (mAlsoHere && mAlsoHere->at(0) != this && dynamic_cast<Planet *>(mAlsoHere->at(0)) != NULL) {
00088 TiXmlElement *loc = new TiXmlElement("Location");
00089 AddString(loc, "Planet", mAlsoHere->at(0)->GetName(NULL).c_str());
00090 node->LinkEndChild(loc);
00091 } else
00092 Location::WriteNode(node);
00093
00094 if (SeenBy(viewer) & SEEN_OWNER) {
00095 if (GetOwner() == NULL)
00096 AddLong(node, "Owner", 0);
00097 else
00098 AddLong(node, "Owner", GetOwner()->GetID());
00099 }
00100
00101 assert(mID != 0);
00102 TiXmlElement * tie = node->ToElement();
00103 tie->SetAttribute("IDNumber", mID);
00104 TiXmlElement * cargo = NULL;
00105 if (viewer == NULL || viewer == GetOwner())
00106 cargo = Rules::WriteCargo(node, "Contains", mContains, mPopulation);
00107 else if (CanLoadBy(viewer))
00108 cargo = Rules::WriteCargo(node, "Contains", mContains, 0);
00109
00110 if (viewer == NULL)
00111 node->LinkEndChild(Rules::WriteArray("SeenBy", "Race", "Number", mSeenBy));
00112
00113 return node;
00114 }
00115
00116 TiXmlNode * CargoHolder::WriteTransport(TiXmlNode * node) const
00117 {
00118 const Planet * p = dynamic_cast<const Planet *>(this);
00119 if (p != NULL) {
00120 AddString(node, "Planet", p->GetName().c_str());
00121 return node;
00122 }
00123
00124 const Fleet * f = dynamic_cast<const Fleet *>(this);
00125 if (f != NULL) {
00126 AddLong(node, "Fleet", GetID());
00127 AddLong(node, "Owner", GetOwner()->GetID());
00128 return node;
00129 }
00130
00131
00132
00133
00134
00135
00136 return node;
00137 }
00138
00139 void CargoHolder::ProcessUnload(CargoHolder * dest, long ct, TransferType tt, long value)
00140 {
00141 assert(dest->IsWith(*this));
00142 assert(dest != this);
00143
00144 if (value < 0) {
00145 Message * mess = NCGetOwner()->AddMessage("Error: Transfer order is negative", this);
00146 mess->AddLong("Amount transferred", value);
00147 return;
00148 }
00149
00150 if (value > Rules::GetConstant("MaxTransfer")) {
00151 Message * mess = NCGetOwner()->AddMessage("Error: Transfer order is over max", this);
00152 mess->AddLong("Amount transferred", value);
00153 return;
00154 }
00155
00156 long destAmt = dest->GetContain(ct);
00157 if (GetOwner() != dest->GetOwner() && (ct == POPULATION || !dest->CanLoadBy(GetOwner())))
00158 destAmt = 0;
00159
00160 long amount = 0;
00161 switch (tt) {
00162 case TRANSFER_LOADALL:
00163
00164 break;
00165
00166 case TRANSFER_DROPNLOAD:
00167 case TRANSFER_UNLOADALL:
00168 amount = TransferAmount(ct, this, dest, GetContain(ct));
00169 break;
00170
00171 case TRANSFER_LOADAMT:
00172
00173 break;
00174
00175 case TRANSFER_UNLOADAMT:
00176 amount = TransferAmount(ct, this, dest, value);
00177 break;
00178
00179 case TRANSFER_FILLPER:
00180 case TRANSFER_WAITPER:
00181
00182 break;
00183
00184 case TRANSFER_LOADDUNN:
00185
00186 break;
00187
00188 case TRANSFER_SETTOPER:
00189 if (value > 100) {
00190 Message * mess = NCGetOwner()->AddMessage("Error: Transfer percent over 100%", this);
00191 mess->AddLong("Amount transferred", value);
00192 return;
00193 }
00194 value = GetCargoCapacity() * value / 100;
00195
00196 case TRANSFER_AMOUNTTO:
00197 if (GetContain(ct) > value)
00198 amount = TransferAmount(ct, this, dest, GetContain(ct) - value);
00199 break;
00200
00201 case TRANSFER_DESTTO:
00202
00203 if (ct == POPULATION && GetOwner() != dest->GetOwner())
00204 amount = TransferAmount(ct, this, dest, GetContain(ct));
00205 else if (destAmt < value)
00206 amount = TransferAmount(ct, this, dest, value - destAmt);
00207 break;
00208
00209 default:
00210 Message * mess = NCGetOwner()->AddMessage("Error: Invalid transfer order", this);
00211 mess->AddLong("Transfer code", tt);
00212 return;
00213 }
00214
00215 if (amount > 0 && ct == POPULATION && GetOwner() != dest->GetOwner()) {
00216
00217 if (dest->GetOwner() == NULL) {
00218 Message * mess;
00219 mess = NCGetOwner()->AddMessage("Warning: Pop drop on unowned world", this);
00220 return;
00221 }
00222
00223
00224 Planet * destP = dynamic_cast<Planet *>(dest);
00225 if (destP && destP->GetBaseNumber() >= 0) {
00226 Message * mess;
00227 mess = NCGetOwner()->AddMessage("Warning: Pop drop with base", this);
00228 mess->AddItem("", destP);
00229 return;
00230 }
00231
00232
00233 Fleet * destF = dynamic_cast<Fleet *>(dest);
00234 if (destF) {
00235 Message * mess;
00236 mess = NCGetOwner()->AddMessage("Warning: Transfer pop to unowned fleet", this);
00237 mess->AddItem("", destF);
00238 return;
00239 }
00240
00241 if (GetOwner()->GroundAttackFactor() <= 0.01) {
00242 Message * mess;
00243 mess = NCGetOwner()->AddMessage("Warning: AR trying to invade", this);
00244 mess->AddItem("", dest);
00245 return;
00246 }
00247
00248 destP->Invade(NCGetOwner(), amount);
00249 }
00250
00251 assert(amount >= 0);
00252 dest->AdjustAmounts(ct, amount);
00253 AdjustAmounts(ct, -amount);
00254 }
00255
00256 void CargoHolder::ProcessLoad(CargoHolder * dest, long ct, TransferType tt, long value, bool dunnage)
00257 {
00258 assert(dest->IsWith(*this));
00259 assert(dest != this);
00260
00261 if (value < 0) {
00262 Message * mess = NCGetOwner()->AddMessage("Error: Transfer order is negative", this);
00263 mess->AddLong("Amount transferred", value);
00264 return;
00265 }
00266
00267 if (value > Rules::GetConstant("MaxTransfer")) {
00268 Message * mess = NCGetOwner()->AddMessage("Error: Transfer order is over max", this);
00269 mess->AddLong("Amount transferred", value);
00270 return;
00271 }
00272
00273 long destAmt = dest->GetContain(ct);
00274 if (GetOwner() != dest->GetOwner() && (ct == POPULATION || !dest->CanLoadBy(GetOwner())))
00275 destAmt = 0;
00276
00277 long amount = 0;
00278 switch (tt) {
00279 case TRANSFER_DROPNLOAD:
00280 case TRANSFER_LOADALL:
00281 if (dunnage) break;
00282 amount = TransferAmount(ct, dest, this, destAmt);
00283 break;
00284
00285 case TRANSFER_UNLOADALL:
00286 break;
00287
00288 case TRANSFER_LOADAMT:
00289 if (dunnage) break;
00290 amount = TransferAmount(ct, dest, this, value);
00291 break;
00292
00293 case TRANSFER_UNLOADAMT:
00294 break;
00295
00296 case TRANSFER_FILLPER:
00297 case TRANSFER_WAITPER:
00298 if (dunnage) break;
00299 if (value > 100) {
00300 Message * mess = NCGetOwner()->AddMessage("Error: Transfer percent over 100%", this);
00301 mess->AddLong("Amount transferred", value);
00302 return;
00303 }
00304 amount = TransferAmount(ct, dest, this, GetCargoCapacity() * value / 100);
00305 break;
00306
00307 case TRANSFER_LOADDUNN:
00308 if (!dunnage) break;
00309
00310 if (ct == FUEL) {
00311 Fleet * f = dynamic_cast<Fleet *>(this);
00312 int Need = f->GetFuelNeeded() - f->GetFuel();
00313 if (Need > 0)
00314 amount = TransferAmount(ct, dest, this, Need);
00315 else
00316 amount = -TransferAmount(ct, this, dest, -Need);
00317 } else {
00318 amount = TransferAmount(ct, dest, this, destAmt);
00319 }
00320 break;
00321
00322 case TRANSFER_SETTOPER:
00323 if (value > 100) {
00324 Message * mess = NCGetOwner()->AddMessage("Error: Transfer percent over 100%", this);
00325 mess->AddLong("Amount transferred", value);
00326 return;
00327
00328
00329 }
00330 value = GetCargoCapacity() * value / 100;
00331
00332 case TRANSFER_AMOUNTTO:
00333 if (dunnage) break;
00334 if (GetContain(ct) < value)
00335 amount = TransferAmount(ct, dest, this, value - GetContain(ct));
00336 break;
00337
00338 case TRANSFER_DESTTO:
00339 if (dunnage) break;
00340 if (destAmt > value)
00341 amount = TransferAmount(ct, dest, this, destAmt - value);
00342 break;
00343
00344 default:
00345 Message * mess = NCGetOwner()->AddMessage("Error: Invalid transfer order", this);
00346 mess->AddLong("Transfer code", tt);
00347 return;
00348 }
00349
00350 assert(amount >= 0 || tt == TRANSFER_LOADDUNN && ct == FUEL);
00351
00352 if (amount > 0 && dest->GetOwner() != GetOwner()) {
00353 if (!dest->CanLoadBy(GetOwner())) {
00354 Message * mess = NCGetOwner()->AddMessage("Warning: No theiving component at location", this);
00355 mess->AddItem("", dest);
00356 return;
00357 } else if (!Rules::Stealable(ct)) {
00358 Message * mess = NCGetOwner()->AddMessage("Warning: Cargo cannot be stolen", this);
00359 mess->AddItem("", dest);
00360 mess->AddLong("Cargo type", ct);
00361 return;
00362 }
00363 }
00364
00365 dest->AdjustAmounts(ct, -amount);
00366 AdjustAmounts(ct, amount);
00367 }
00368
00369 long CargoHolder::GetCargoMass() const
00370 {
00371 long Result = mPopulation / Rules::PopEQ1kT;
00372 for (int i = 0; i < Rules::MaxMinType; ++i)
00373 Result += this->mContains[i];
00374
00375 return Result;
00376 }
00377
00378 long CargoHolder::TransferAmount(long ct, CargoHolder * from, CargoHolder * to, long Request)
00379 {
00380 assert(from->IsWith(*to));
00381 assert(from != to);
00382 assert(Request >= 0);
00383 assert(FUEL <= ct && ct < Rules::MaxMinType);
00384
00385 long Result = Request;
00386 if (Result > from->GetContain(ct))
00387 Result = from->GetContain(ct);
00388
00389 long cap = to->GetCargoCapacity() - to->GetCargoMass();
00390 if (cap >= 0 && Result > cap)
00391 Result = cap;
00392
00393 return Result;
00394 }
00395
00396 long CargoHolder::SeenBy(const Player * p) const
00397 {
00398 if (p == NULL)
00399 return SEEN_HOST;
00400 else if (p == GetOwner())
00401 return SEEN_BYOWNER;
00402 else
00403 return SeenBy(p->GetID()-1);
00404 }
00405
00406 long CargoHolder::SeenBy(unsigned long p) const
00407 {
00408 if (p < 0 || p >= TheGame->NumberPlayers())
00409 return false;
00410 else
00411 return mSeenBy[p];
00412 }
00413
00414 void CargoHolder::TransferCargo(CargoHolder * dest, long ct, long * amount, Player * player)
00415 {
00416 if (*amount == 0)
00417 return;
00418 assert(*amount > 0);
00419
00420 if (GetContain(ct) < *amount) {
00421 Message * mess = player->AddMessage("Warning: Transfer more then carried", this);
00422 mess->AddLong("Attempted amount", *amount);
00423 *amount = GetContain(ct);
00424 mess->AddLong("Actual amount", *amount);
00425 }
00426
00427 if (ct == POPULATION) {
00428 *amount -= *amount % Rules::PopEQ1kT;
00429 if (dest->GetCargoCapacity() >= 0 && dest->GetCargoCapacity() < dest->GetCargoMass() + (*amount / Rules::PopEQ1kT)) {
00430 Message * mess = player->AddMessage("Warning: Transfer more then capacity", this);
00431 mess->AddItem("", dest);
00432 mess->AddLong("Attempted amount", *amount);
00433 *amount = (dest->GetCargoCapacity() - dest->GetCargoMass()) * Rules::PopEQ1kT;
00434 mess->AddLong("Actual amount", *amount);
00435 }
00436 } else if (ct == FUEL) {
00437 Fleet * destf = dynamic_cast<Fleet *>(dest);
00438 if (destf->GetFuelCapacity() >= 0 && destf->GetFuelCapacity() < destf->GetFuel() + *amount) {
00439 Message * mess = player->AddMessage("Warning: Transfer more then capacity", this);
00440 mess->AddItem("", dest);
00441 mess->AddLong("Attempted amount", *amount);
00442 *amount = destf->GetFuelCapacity() - destf->GetFuel();
00443 mess->AddLong("Actual amount", *amount);
00444 }
00445 } else {
00446 if (dest->GetCargoCapacity() >= 0 && dest->GetCargoCapacity() < dest->GetCargoMass() + *amount) {
00447 Message * mess = player->AddMessage("Warning: Transfer more then capacity", this);
00448 mess->AddItem("", dest);
00449 mess->AddLong("Attempted amount", *amount);
00450 *amount = dest->GetCargoCapacity() - dest->GetCargoMass();
00451 mess->AddLong("Actual amount", *amount);
00452 }
00453 }
00454
00455 if (ct == POPULATION && GetOwner() != dest->GetOwner()) {
00456 assert(false);
00457 Planet * destp = dynamic_cast<Planet *>(dest);
00458 if (destp) {
00459 if (destp->GetBaseNumber() >= 0) {
00460 player->AddMessage("Warning: Invading world with base", this);
00461 return;
00462 } else {
00463 AdjustAmounts(ct, -*amount);
00464 destp->Invade(NCGetOwner(), *amount);
00465 return;
00466 }
00467 } else {
00468 Message * mess = player->AddMessage("Warning: Transfer pop to unowned fleet", this);
00469 mess->AddItem("", dest);
00470 return;
00471 }
00472 }
00473
00474 dest->AdjustAmounts(ct, *amount);
00475 AdjustAmounts(ct, -*amount);
00476 }
00477
00478 long CargoHolder::GetContain(long ct) const
00479 {
00480 if (ct >= 0)
00481 return mContains[ct];
00482 else if (ct == POPULATION)
00483 return GetPopulation();
00484 else if (ct == FUEL) {
00485 const Fleet * f = dynamic_cast<const Fleet *>(this);
00486 if (f == NULL)
00487 return 0;
00488 else
00489 return f->GetFuel();
00490 } else {
00491 assert(false);
00492 return 0;
00493 }
00494 }
00495
00496 void CargoHolder::AdjustAmounts(long ct, long amount)
00497 {
00498 if (amount == 0)
00499 return;
00500
00501 if (ct >= 0) {
00502 mContains[ct] += amount;
00503 } else if (ct == POPULATION) {
00504 mPopulation += amount;
00505 } else if (ct == FUEL) {
00506 Fleet * f = dynamic_cast<Fleet *>(this);
00507 if (f == NULL) {
00508 assert(false);
00509 } else
00510 f->AdjustFuel(amount);
00511 } else {
00512 assert(false);
00513 }
00514 }
00515
00516 void CargoHolder::ResetSeen()
00517 {
00518 mSeenBy.clear();
00519 mSeenBy.insert(mSeenBy.begin(), TheGame->NumberPlayers(), false);
00520 }