Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List

CargoHolder.cpp

00001 /*
00002 Copyright 2003 - 2005 Elliott Kleinrock, Dan Neely, Kurt W. Over, Damon Domjan
00003 
00004 This file is part of FreeStars, a free clone of the Stars! game.
00005 
00006 FreeStars is free software; you can redistribute it and/or modify
00007 it under the terms of the GNU General Public License as published by
00008 the Free Software Foundation; either version 2 of the License, or
00009 (at your option) any later version.
00010 
00011 FreeStars is distributed in the hope that it will be useful,
00012 but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 GNU General Public License for more details.
00015 
00016 You should have received a copy of the GNU General Public License
00017 along with FreeStars; if not, write to the Free Software
00018 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 
00020 The full GPL Copyright notice should be in the file COPYING.txt
00021 
00022 Contact:
00023 Email Elliott at 9jm0tjj02@sneakemail.com
00024 */
00025 
00026 #include "FSServer.h"
00027 
00028 #ifdef _DEBUG
00029 #define new DEBUG_NEW
00030 #endif
00031 
00032 /*
00033         Random by player #, then sequential by fleet, then by mineral type:
00034                 Process all unloads (sets that drop count as unloads here)
00035         Ground combat
00036         Random by player #, then sequential by fleet
00037                 by mineral type:
00038                         Process all loads execpt dunnage (sets that lift count as unloads here, even if they counted as unloads before)
00039                 by mineral type again:
00040                         Process all dunnage loads
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 //      const Packet * pac = dynamic_cast<const Packet *>(this);
00132 //      if (pac != NULL) {
00133 //              return node;
00134 //      }
00135 
00136         return node;
00137 }
00138 
00139 void CargoHolder::ProcessUnload(CargoHolder * dest, long ct, TransferType tt, long value)       // value usage depends on TransferType
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;        // actual amount moved;
00161         switch (tt) {
00162         case TRANSFER_LOADALL:
00163                 // processing unloads, skip loads.
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                 // processing unloads, skip loads.
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:  // affects movement too
00181                 // processing unloads, skip loads.
00182                 break;
00183 
00184         case TRANSFER_LOADDUNN:
00185                 // processing unloads, skip loads.
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                 // drop to a regualr transfer amount
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                 // Allow set dest to for pop to do a maximal invade, followed by a setto load
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                 // try to drop pop on an uninhabited world
00217                 if (dest->GetOwner() == NULL) {
00218                         Message * mess;
00219                         mess = NCGetOwner()->AddMessage("Warning: Pop drop on unowned world", this);
00220                         return;
00221                 }
00222 
00223                 // Dropping pop on a world with a base
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                 // unloading pop to some one elses fleet
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);        // add cargo to destination
00253         AdjustAmounts(ct, -amount);             // remove it from the source
00254 }
00255 
00256 void CargoHolder::ProcessLoad(CargoHolder * dest, long ct, TransferType tt, long value, bool dunnage)   // value usage depends on TransferType
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;        // actual amount moved;
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:  // affects movement too
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                 // order of loading is different, but this is basicly a loadall -- execpt fuel
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                 // drop to a regualr transfer amount
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);       // remove cargo from destination
00366         AdjustAmounts(ct, amount);              // add it to the source
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;   // only transfer full groups
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);  // should never get here now
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 }

Generated on Mon Aug 8 21:33:42 2005 for Freestars by  doxygen 1.4.2-20050421