# cargopacket.cpp

Go to the documentation of this file.

    00001 /* $Id$ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
    00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
    00008  */
    00009
    00012 #include "stdafx.h"
    00013 #include "core/pool_func.hpp"
    00014 #include "economy_base.h"
    00015
    00016 /* Initialize the cargopacket-pool */
    00017 CargoPacketPool _cargopacket_pool("CargoPacket");
    00018 INSTANTIATE_POOL_METHODS(CargoPacket)
    00019
    00020
    00023 void InitializeCargoPackets()
    00024 {
    00025   _cargopacket_pool.CleanPool();
    00026 }
    00027
    00031 CargoPacket::CargoPacket()
    00032 {
    00033   this->source_type = ST_INDUSTRY;
    00034   this->source_id   = INVALID_SOURCE;
    00035 }
    00036
    00048 CargoPacket::CargoPacket(StationID source, TileIndex source_xy, uint16 count, SourceType source_type, SourceID source_id) :
    00049   feeder_share(0),
    00050   count(count),
    00051   days_in_transit(0),
    00052   source_id(source_id),
    00053   source(source),
    00054   source_xy(source_xy),
    00055   loaded_at_xy(0)
    00056 {
    00057   assert(count != 0);
    00058   this->source_type  = source_type;
    00059 }
    00060
    00075 CargoPacket::CargoPacket(uint16 count, byte days_in_transit, StationID source, TileIndex source_xy, TileIndex loaded_at_xy, Money feeder_share, SourceType source_type, SourceID source_id) :
    00076     feeder_share(feeder_share),
    00077     count(count),
    00078     days_in_transit(days_in_transit),
    00079     source_id(source_id),
    00080     source(source),
    00081     source_xy(source_xy),
    00082     loaded_at_xy(loaded_at_xy)
    00083 {
    00084   assert(count != 0);
    00085   this->source_type = source_type;
    00086 }
    00087
    00093 FORCEINLINE CargoPacket *CargoPacket::Split(uint new_size)
    00094 {
    00095   if (!CargoPacket::CanAllocateItem()) return NULL;
    00096
    00097   Money fs = this->feeder_share * new_size / static_cast<uint>(this->count);
    00098   CargoPacket *cp_new = new CargoPacket(new_size, this->days_in_transit, this->source, this->source_xy, this->loaded_at_xy, fs, this->source_type, this->source_id);
    00099   this->feeder_share -= fs;
    00100   this->count -= new_size;
    00101   return cp_new;
    00102 }
    00103
    00108 FORCEINLINE void CargoPacket::Merge(CargoPacket *cp)
    00109 {
    00110   this->count += cp->count;
    00111   this->feeder_share += cp->feeder_share;
    00112   delete cp;
    00113 }
    00114
    00120 /* static */ void CargoPacket::InvalidateAllFrom(SourceType src_type, SourceID src)
    00121 {
    00122   CargoPacket *cp;
    00123   FOR_ALL_CARGOPACKETS(cp) {
    00124     if (cp->source_type == src_type && cp->source_id == src) cp->source_id = INVALID_SOURCE;
    00125   }
    00126 }
    00127
    00132 /* static */ void CargoPacket::InvalidateAllFrom(StationID sid)
    00133 {
    00134   CargoPacket *cp;
    00135   FOR_ALL_CARGOPACKETS(cp) {
    00136     if (cp->source == sid) cp->source = INVALID_STATION;
    00137   }
    00138 }
    00139
    00140 /*
    00141  *
    00142  * Cargo list implementation
    00143  *
    00144  */
    00145
    00149 template <class Tinst>
    00150 CargoList<Tinst>::~CargoList()
    00151 {
    00152   for (Iterator it(this->packets.begin()); it != this->packets.end(); ++it) {
    00153     delete *it;
    00154   }
    00155 }
    00156
    00162 template <class Tinst>
    00163 void CargoList<Tinst>::RemoveFromCache(const CargoPacket *cp)
    00164 {
    00165   this->count                 -= cp->count;
    00166   this->cargo_days_in_transit -= cp->days_in_transit * cp->count;
    00167 }
    00168
    00174 template <class Tinst>
    00175 void CargoList<Tinst>::AddToCache(const CargoPacket *cp)
    00176 {
    00177   this->count                 += cp->count;
    00178   this->cargo_days_in_transit += cp->days_in_transit * cp->count;
    00179 }
    00180
    00189 template <class Tinst>
    00190 void CargoList<Tinst>::Append(CargoPacket *cp)
    00191 {
    00192   assert(cp != NULL);
    00193   static_cast<Tinst *>(this)->AddToCache(cp);
    00194
    00195   for (List::reverse_iterator it(this->packets.rbegin()); it != this->packets.rend(); it++) {
    00196     CargoPacket *icp = *it;
    00197     if (Tinst::AreMergable(icp, cp) && icp->count + cp->count <= CargoPacket::MAX_COUNT) {
    00198       icp->Merge(cp);
    00199       return;
    00200     }
    00201   }
    00202
    00203   /* The packet could not be merged with another one */
    00204   this->packets.push_back(cp);
    00205 }
    00206
    00212 template <class Tinst>
    00213 void CargoList<Tinst>::Truncate(uint max_remaining)
    00214 {
    00215   for (Iterator it(packets.begin()); it != packets.end(); /* done during loop*/) {
    00216     CargoPacket *cp = *it;
    00217     if (max_remaining == 0) {
    00218       /* Nothing should remain, just remove the packets. */
    00219       this->packets.erase(it++);
    00220       static_cast<Tinst *>(this)->RemoveFromCache(cp);
    00221       delete cp;
    00222       continue;
    00223     }
    00224
    00225     uint local_count = cp->count;
    00226     if (local_count > max_remaining) {
    00227       uint diff = local_count - max_remaining;
    00228       this->count -= diff;
    00229       this->cargo_days_in_transit -= cp->days_in_transit * diff;
    00230       cp->count = max_remaining;
    00231       max_remaining = 0;
    00232     } else {
    00233       max_remaining -= local_count;
    00234     }
    00235     ++it;
    00236   }
    00237 }
    00238
    00260 template <class Tinst>
    00261 template <class Tother_inst>
    00262 bool CargoList<Tinst>::MoveTo(Tother_inst *dest, uint max_move, MoveToAction mta, CargoPayment *payment, uint data)
    00263 {
    00264   assert(mta == MTA_FINAL_DELIVERY || dest != NULL);
    00265   assert(mta == MTA_UNLOAD || mta == MTA_CARGO_LOAD || payment != NULL);
    00266
    00267   Iterator it(this->packets.begin());
    00268   while (it != this->packets.end() && max_move > 0) {
    00269     CargoPacket *cp = *it;
    00270     if (cp->source == data && mta == MTA_FINAL_DELIVERY) {
    00271       /* Skip cargo that originated from this station. */
    00272       ++it;
    00273       continue;
    00274     }
    00275
    00276     if (cp->count <= max_move) {
    00277       /* Can move the complete packet */
    00278       max_move -= cp->count;
    00279       this->packets.erase(it++);
    00280       static_cast<Tinst *>(this)->RemoveFromCache(cp);
    00281       switch (mta) {
    00282         case MTA_FINAL_DELIVERY:
    00283           payment->PayFinalDelivery(cp, cp->count);
    00284           delete cp;
    00285           continue; // of the loop
    00286
    00287         case MTA_CARGO_LOAD:
    00288           cp->loaded_at_xy = data;
    00289           break;
    00290
    00291         case MTA_TRANSFER:
    00292           cp->feeder_share += payment->PayTransfer(cp, cp->count);
    00293           break;
    00294
    00295         case MTA_UNLOAD:
    00296           break;
    00297       }
    00298       dest->Append(cp);
    00299       continue;
    00300     }
    00301
    00302     /* Can move only part of the packet */
    00303     if (mta == MTA_FINAL_DELIVERY) {
    00304       /* Final delivery doesn't need package splitting. */
    00305       payment->PayFinalDelivery(cp, max_move);
    00306
    00307       /* Remove the delivered data from the cache */
    00308       uint left = cp->count - max_move;
    00309       cp->count = max_move;
    00310       static_cast<Tinst *>(this)->RemoveFromCache(cp);
    00311
    00312       /* Final delivery payment pays the feeder share, so we have to
    00313        * reset that so it is not 'shown' twice for partial unloads. */
    00314       cp->feeder_share = 0;
    00315       cp->count = left;
    00316     } else {
    00317       /* But... the rest needs package splitting. */
    00318       CargoPacket *cp_new = cp->Split(max_move);
    00319
    00320       /* We could not allocate a CargoPacket? Is the map that full? */
    00321       if (cp_new == NULL) return false;
    00322
    00323       static_cast<Tinst *>(this)->RemoveFromCache(cp_new); // this reflects the changes in cp.
    00324
    00325       if (mta == MTA_TRANSFER) {
    00326         /* Add the feeder share before inserting in dest. */
    00327         cp_new->feeder_share += payment->PayTransfer(cp_new, max_move);
    00328       } else if (mta == MTA_CARGO_LOAD) {
    00329         cp_new->loaded_at_xy = data;
    00330       }
    00331
    00332       dest->Append(cp_new);
    00333     }
    00334
    00335     max_move = 0;
    00336   }
    00337
    00338   return it != packets.end();
    00339 }
    00340
    00342 template <class Tinst>
    00343 void CargoList<Tinst>::InvalidateCache()
    00344 {
    00345   this->count = 0;
    00346   this->cargo_days_in_transit = 0;
    00347
    00348   for (ConstIterator it(this->packets.begin()); it != this->packets.end(); it++) {
    00349     static_cast<Tinst *>(this)->AddToCache(*it);
    00350   }
    00351 }
    00352
    00358 void VehicleCargoList::RemoveFromCache(const CargoPacket *cp)
    00359 {
    00360   this->feeder_share -= cp->feeder_share;
    00361   this->Parent::RemoveFromCache(cp);
    00362 }
    00363
    00369 void VehicleCargoList::AddToCache(const CargoPacket *cp)
    00370 {
    00371   this->feeder_share += cp->feeder_share;
    00372   this->Parent::AddToCache(cp);
    00373 }
    00374
    00378 void VehicleCargoList::AgeCargo()
    00379 {
    00380   for (ConstIterator it(this->packets.begin()); it != this->packets.end(); it++) {
    00381     CargoPacket *cp = *it;
    00382     /* If we're at the maximum, then we can't increase no more. */
    00383     if (cp->days_in_transit == 0xFF) continue;
    00384
    00385     cp->days_in_transit++;
    00386     this->cargo_days_in_transit += cp->count;
    00387   }
    00388 }
    00389
    00391 void VehicleCargoList::InvalidateCache()
    00392 {
    00393   this->feeder_share = 0;
    00394   this->Parent::InvalidateCache();
    00395 }
    00396
    00397 /*
    00398  * We have to instantiate everything we want to be usable.
    00399  */
    00400 template class CargoList<VehicleCargoList>;
    00401 template class CargoList<StationCargoList>;
    00402
    00404 template bool CargoList<VehicleCargoList>::MoveTo(VehicleCargoList *, uint max_move, MoveToAction mta, CargoPayment *payment, uint data);
    00406 template bool CargoList<VehicleCargoList>::MoveTo(StationCargoList *, uint max_move, MoveToAction mta, CargoPayment *payment, uint data);
    00408 template bool CargoList<StationCargoList>::MoveTo(VehicleCargoList *, uint max_move, MoveToAction mta, CargoPayment *payment, uint data);