# cargopacket.cpp

Go to the documentation of this file.

    00001 /* $Id: cargopacket.cpp 23640 2011-12-20 17:57:56Z truebrain $ */
    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 CargoPacket::CargoPacket()
    00024 {
    00025   this->source_type = ST_INDUSTRY;
    00026   this->source_id   = INVALID_SOURCE;
    00027 }
    00028
    00040 CargoPacket::CargoPacket(StationID source, TileIndex source_xy, uint16 count, SourceType source_type, SourceID source_id) :
    00041   feeder_share(0),
    00042   count(count),
    00043   days_in_transit(0),
    00044   source_id(source_id),
    00045   source(source),
    00046   source_xy(source_xy),
    00047   loaded_at_xy(0)
    00048 {
    00049   assert(count != 0);
    00050   this->source_type  = source_type;
    00051 }
    00052
    00067 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) :
    00068     feeder_share(feeder_share),
    00069     count(count),
    00070     days_in_transit(days_in_transit),
    00071     source_id(source_id),
    00072     source(source),
    00073     source_xy(source_xy),
    00074     loaded_at_xy(loaded_at_xy)
    00075 {
    00076   assert(count != 0);
    00077   this->source_type = source_type;
    00078 }
    00079
    00085 inline CargoPacket *CargoPacket::Split(uint new_size)
    00086 {
    00087   if (!CargoPacket::CanAllocateItem()) return NULL;
    00088
    00089   Money fs = this->feeder_share * new_size / static_cast<uint>(this->count);
    00090   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);
    00091   this->feeder_share -= fs;
    00092   this->count -= new_size;
    00093   return cp_new;
    00094 }
    00095
    00100 inline void CargoPacket::Merge(CargoPacket *cp)
    00101 {
    00102   this->count += cp->count;
    00103   this->feeder_share += cp->feeder_share;
    00104   delete cp;
    00105 }
    00106
    00112 /* static */ void CargoPacket::InvalidateAllFrom(SourceType src_type, SourceID src)
    00113 {
    00114   CargoPacket *cp;
    00115   FOR_ALL_CARGOPACKETS(cp) {
    00116     if (cp->source_type == src_type && cp->source_id == src) cp->source_id = INVALID_SOURCE;
    00117   }
    00118 }
    00119
    00124 /* static */ void CargoPacket::InvalidateAllFrom(StationID sid)
    00125 {
    00126   CargoPacket *cp;
    00127   FOR_ALL_CARGOPACKETS(cp) {
    00128     if (cp->source == sid) cp->source = INVALID_STATION;
    00129   }
    00130 }
    00131
    00132 /*
    00133  *
    00134  * Cargo list implementation
    00135  *
    00136  */
    00137
    00141 template <class Tinst>
    00142 CargoList<Tinst>::~CargoList()
    00143 {
    00144   for (Iterator it(this->packets.begin()); it != this->packets.end(); ++it) {
    00145     delete *it;
    00146   }
    00147 }
    00148
    00153 template <class Tinst>
    00154 void CargoList<Tinst>::OnCleanPool()
    00155 {
    00156   this->packets.clear();
    00157 }
    00158
    00164 template <class Tinst>
    00165 void CargoList<Tinst>::RemoveFromCache(const CargoPacket *cp)
    00166 {
    00167   this->count                 -= cp->count;
    00168   this->cargo_days_in_transit -= cp->days_in_transit * cp->count;
    00169 }
    00170
    00176 template <class Tinst>
    00177 void CargoList<Tinst>::AddToCache(const CargoPacket *cp)
    00178 {
    00179   this->count                 += cp->count;
    00180   this->cargo_days_in_transit += cp->days_in_transit * cp->count;
    00181 }
    00182
    00191 template <class Tinst>
    00192 void CargoList<Tinst>::Append(CargoPacket *cp)
    00193 {
    00194   assert(cp != NULL);
    00195   static_cast<Tinst *>(this)->AddToCache(cp);
    00196
    00197   for (List::reverse_iterator it(this->packets.rbegin()); it != this->packets.rend(); it++) {
    00198     CargoPacket *icp = *it;
    00199     if (Tinst::AreMergable(icp, cp) && icp->count + cp->count <= CargoPacket::MAX_COUNT) {
    00200       icp->Merge(cp);
    00201       return;
    00202     }
    00203   }
    00204
    00205   /* The packet could not be merged with another one */
    00206   this->packets.push_back(cp);
    00207 }
    00208
    00214 template <class Tinst>
    00215 void CargoList<Tinst>::Truncate(uint max_remaining)
    00216 {
    00217   for (Iterator it(packets.begin()); it != packets.end(); /* done during loop*/) {
    00218     CargoPacket *cp = *it;
    00219     if (max_remaining == 0) {
    00220       /* Nothing should remain, just remove the packets. */
    00221       it = this->packets.erase(it);
    00222       static_cast<Tinst *>(this)->RemoveFromCache(cp);
    00223       delete cp;
    00224       continue;
    00225     }
    00226
    00227     uint local_count = cp->count;
    00228     if (local_count > max_remaining) {
    00229       uint diff = local_count - max_remaining;
    00230       this->count -= diff;
    00231       this->cargo_days_in_transit -= cp->days_in_transit * diff;
    00232       cp->count = max_remaining;
    00233       max_remaining = 0;
    00234     } else {
    00235       max_remaining -= local_count;
    00236     }
    00237     ++it;
    00238   }
    00239 }
    00240
    00262 template <class Tinst>
    00263 template <class Tother_inst>
    00264 bool CargoList<Tinst>::MoveTo(Tother_inst *dest, uint max_move, MoveToAction mta, CargoPayment *payment, uint data)
    00265 {
    00266   assert(mta == MTA_FINAL_DELIVERY || dest != NULL);
    00267   assert(mta == MTA_UNLOAD || mta == MTA_CARGO_LOAD || payment != NULL);
    00268
    00269   Iterator it(this->packets.begin());
    00270   while (it != this->packets.end() && max_move > 0) {
    00271     CargoPacket *cp = *it;
    00272     if (cp->source == data && mta == MTA_FINAL_DELIVERY) {
    00273       /* Skip cargo that originated from this station. */
    00274       ++it;
    00275       continue;
    00276     }
    00277
    00278     if (cp->count <= max_move) {
    00279       /* Can move the complete packet */
    00280       max_move -= cp->count;
    00281       it = this->packets.erase(it);
    00282       static_cast<Tinst *>(this)->RemoveFromCache(cp);
    00283       switch (mta) {
    00284         case MTA_FINAL_DELIVERY:
    00285           payment->PayFinalDelivery(cp, cp->count);
    00286           delete cp;
    00287           continue; // of the loop
    00288
    00289         case MTA_CARGO_LOAD:
    00290           cp->loaded_at_xy = data;
    00291           break;
    00292
    00293         case MTA_TRANSFER:
    00294           cp->feeder_share += payment->PayTransfer(cp, cp->count);
    00295           break;
    00296
    00297         case MTA_UNLOAD:
    00298           break;
    00299       }
    00300       dest->Append(cp);
    00301       continue;
    00302     }
    00303
    00304     /* Can move only part of the packet */
    00305     if (mta == MTA_FINAL_DELIVERY) {
    00306       /* Final delivery doesn't need package splitting. */
    00307       payment->PayFinalDelivery(cp, max_move);
    00308
    00309       /* Remove the delivered data from the cache */
    00310       uint left = cp->count - max_move;
    00311       cp->count = max_move;
    00312       static_cast<Tinst *>(this)->RemoveFromCache(cp);
    00313
    00314       /* Final delivery payment pays the feeder share, so we have to
    00315        * reset that so it is not 'shown' twice for partial unloads. */
    00316       cp->feeder_share = 0;
    00317       cp->count = left;
    00318     } else {
    00319       /* But... the rest needs package splitting. */
    00320       CargoPacket *cp_new = cp->Split(max_move);
    00321
    00322       /* We could not allocate a CargoPacket? Is the map that full? */
    00323       if (cp_new == NULL) return false;
    00324
    00325       static_cast<Tinst *>(this)->RemoveFromCache(cp_new); // this reflects the changes in cp.
    00326
    00327       if (mta == MTA_TRANSFER) {
    00328         /* Add the feeder share before inserting in dest. */
    00329         cp_new->feeder_share += payment->PayTransfer(cp_new, max_move);
    00330       } else if (mta == MTA_CARGO_LOAD) {
    00331         cp_new->loaded_at_xy = data;
    00332       }
    00333
    00334       dest->Append(cp_new);
    00335     }
    00336
    00337     max_move = 0;
    00338   }
    00339
    00340   return it != packets.end();
    00341 }
    00342
    00344 template <class Tinst>
    00345 void CargoList<Tinst>::InvalidateCache()
    00346 {
    00347   this->count = 0;
    00348   this->cargo_days_in_transit = 0;
    00349
    00350   for (ConstIterator it(this->packets.begin()); it != this->packets.end(); it++) {
    00351     static_cast<Tinst *>(this)->AddToCache(*it);
    00352   }
    00353 }
    00354
    00360 void VehicleCargoList::RemoveFromCache(const CargoPacket *cp)
    00361 {
    00362   this->feeder_share -= cp->feeder_share;
    00363   this->Parent::RemoveFromCache(cp);
    00364 }
    00365
    00371 void VehicleCargoList::AddToCache(const CargoPacket *cp)
    00372 {
    00373   this->feeder_share += cp->feeder_share;
    00374   this->Parent::AddToCache(cp);
    00375 }
    00376
    00380 void VehicleCargoList::AgeCargo()
    00381 {
    00382   for (ConstIterator it(this->packets.begin()); it != this->packets.end(); it++) {
    00383     CargoPacket *cp = *it;
    00384     /* If we're at the maximum, then we can't increase no more. */
    00385     if (cp->days_in_transit == 0xFF) continue;
    00386
    00387     cp->days_in_transit++;
    00388     this->cargo_days_in_transit += cp->count;
    00389   }
    00390 }
    00391
    00393 void VehicleCargoList::InvalidateCache()
    00394 {
    00395   this->feeder_share = 0;
    00396   this->Parent::InvalidateCache();
    00397 }
    00398
    00399 /*
    00400  * We have to instantiate everything we want to be usable.
    00401  */
    00402 template class CargoList<VehicleCargoList>;
    00403 template class CargoList<StationCargoList>;
    00404
    00406 template bool CargoList<VehicleCargoList>::MoveTo(VehicleCargoList *, uint max_move, MoveToAction mta, CargoPayment *payment, uint data);
    00408 template bool CargoList<VehicleCargoList>::MoveTo(StationCargoList *, uint max_move, MoveToAction mta, CargoPayment *payment, uint data);
    00410 template bool CargoList<StationCargoList>::MoveTo(VehicleCargoList *, uint max_move, MoveToAction mta, CargoPayment *payment, uint data);