# cargopacket.cpp

Go to the documentation of this file.

    00001 /* $Id: cargopacket.cpp 14271 2008-09-07 22:31:15Z rubidium $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "openttd.h"
    00007 #include "station.h"
    00008 #include "cargopacket.h"
    00009 #include "saveload.h"
    00010
    00011 /* Initialize the cargopacket-pool */
    00012 DEFINE_OLD_POOL_GENERIC(CargoPacket, CargoPacket)
    00013
    00014 void InitializeCargoPackets()
    00015 {
    00016   /* Clean the cargo packet pool and create 1 block in it */
    00017   _CargoPacket_pool.CleanPool();
    00018   _CargoPacket_pool.AddBlockToPool();
    00019 }
    00020
    00021 CargoPacket::CargoPacket(StationID source, uint16 count)
    00022 {
    00023   if (source != INVALID_STATION) assert(count != 0);
    00024
    00025   this->source          = source;
    00026   this->source_xy       = (source != INVALID_STATION) ? GetStation(source)->xy : 0;
    00027   this->loaded_at_xy    = this->source_xy;
    00028
    00029   this->count           = count;
    00030   this->days_in_transit = 0;
    00031   this->feeder_share    = 0;
    00032   this->paid_for        = false;
    00033 }
    00034
    00035 CargoPacket::~CargoPacket()
    00036 {
    00037   this->count = 0;
    00038 }
    00039
    00040 bool CargoPacket::SameSource(const CargoPacket *cp) const
    00041 {
    00042   return this->source_xy == cp->source_xy && this->days_in_transit == cp->days_in_transit && this->paid_for == cp->paid_for;
    00043 }
    00044
    00045 static const SaveLoad _cargopacket_desc[] = {
    00046   SLE_VAR(CargoPacket, source,          SLE_UINT16),
    00047   SLE_VAR(CargoPacket, source_xy,       SLE_UINT32),
    00048   SLE_VAR(CargoPacket, loaded_at_xy,    SLE_UINT32),
    00049   SLE_VAR(CargoPacket, count,           SLE_UINT16),
    00050   SLE_VAR(CargoPacket, days_in_transit, SLE_UINT8),
    00051   SLE_VAR(CargoPacket, feeder_share,    SLE_INT64),
    00052   SLE_VAR(CargoPacket, paid_for,        SLE_BOOL),
    00053
    00054   SLE_END()
    00055 };
    00056
    00057 static void Save_CAPA()
    00058 {
    00059   CargoPacket *cp;
    00060
    00061   FOR_ALL_CARGOPACKETS(cp) {
    00062     SlSetArrayIndex(cp->index);
    00063     SlObject(cp, _cargopacket_desc);
    00064   }
    00065 }
    00066
    00067 static void Load_CAPA()
    00068 {
    00069   int index;
    00070
    00071   while ((index = SlIterateArray()) != -1) {
    00072     CargoPacket *cp = new (index) CargoPacket();
    00073     SlObject(cp, _cargopacket_desc);
    00074   }
    00075 }
    00076
    00077 extern const ChunkHandler _cargopacket_chunk_handlers[] = {
    00078   { 'CAPA', Save_CAPA, Load_CAPA, CH_ARRAY | CH_LAST},
    00079 };
    00080
    00081 /*
    00082  *
    00083  * Cargo list implementation
    00084  *
    00085  */
    00086
    00087 CargoList::~CargoList()
    00088 {
    00089   while (!packets.empty()) {
    00090     delete packets.front();
    00091     packets.pop_front();
    00092   }
    00093 }
    00094
    00095 const CargoList::List *CargoList::Packets() const
    00096 {
    00097   return &packets;
    00098 }
    00099
    00100 void CargoList::AgeCargo()
    00101 {
    00102   if (empty) return;
    00103
    00104   uint dit = 0;
    00105   for (List::const_iterator it = packets.begin(); it != packets.end(); it++) {
    00106     if ((*it)->days_in_transit != 0xFF) (*it)->days_in_transit++;
    00107     dit += (*it)->days_in_transit * (*it)->count;
    00108   }
    00109   days_in_transit = dit / count;
    00110 }
    00111
    00112 bool CargoList::Empty() const
    00113 {
    00114   return empty;
    00115 }
    00116
    00117 uint CargoList::Count() const
    00118 {
    00119   return count;
    00120 }
    00121
    00122 bool CargoList::UnpaidCargo() const
    00123 {
    00124   return unpaid_cargo;
    00125 }
    00126
    00127 Money CargoList::FeederShare() const
    00128 {
    00129   return feeder_share;
    00130 }
    00131
    00132 StationID CargoList::Source() const
    00133 {
    00134   return source;
    00135 }
    00136
    00137 uint CargoList::DaysInTransit() const
    00138 {
    00139   return days_in_transit;
    00140 }
    00141
    00142 void CargoList::Append(CargoPacket *cp)
    00143 {
    00144   assert(cp != NULL);
    00145   assert(cp->IsValid());
    00146
    00147   for (List::iterator it = packets.begin(); it != packets.end(); it++) {
    00148     if ((*it)->SameSource(cp) && (*it)->count + cp->count <= 65535) {
    00149       (*it)->count        += cp->count;
    00150       (*it)->feeder_share += cp->feeder_share;
    00151       delete cp;
    00152
    00153       InvalidateCache();
    00154       return;
    00155     }
    00156   }
    00157
    00158   /* The packet could not be merged with another one */
    00159   packets.push_back(cp);
    00160   InvalidateCache();
    00161 }
    00162
    00163
    00164 void CargoList::Truncate(uint count)
    00165 {
    00166   for (List::iterator it = packets.begin(); it != packets.end(); it++) {
    00167     uint local_count = (*it)->count;
    00168     if (local_count <= count) {
    00169       count -= local_count;
    00170       continue;
    00171     }
    00172
    00173     (*it)->count = count;
    00174     count = 0;
    00175   }
    00176
    00177   while (!packets.empty()) {
    00178     CargoPacket *cp = packets.back();
    00179     if (cp->count != 0) break;
    00180     delete cp;
    00181     packets.pop_back();
    00182   }
    00183
    00184   InvalidateCache();
    00185 }
    00186
    00187 bool CargoList::MoveTo(CargoList *dest, uint count, CargoList::MoveToAction mta, uint data)
    00188 {
    00189   assert(mta == MTA_FINAL_DELIVERY || dest != NULL);
    00190   CargoList tmp;
    00191
    00192   while (!packets.empty() && count > 0) {
    00193     CargoPacket *cp = *packets.begin();
    00194     if (cp->count <= count) {
    00195       /* Can move the complete packet */
    00196       packets.remove(cp);
    00197       switch (mta) {
    00198         case MTA_FINAL_DELIVERY:
    00199           if (cp->source == data) {
    00200             tmp.Append(cp);
    00201           } else {
    00202             count -= cp->count;
    00203             delete cp;
    00204           }
    00205           break;
    00206         case MTA_CARGO_LOAD:
    00207           cp->loaded_at_xy = data;
    00208           /* When cargo is moved into another vehicle you have *always* paid for it */
    00209           cp->paid_for     = false;
    00210           /* FALL THROUGH */
    00211         case MTA_OTHER:
    00212           count -= cp->count;
    00213           dest->packets.push_back(cp);
    00214           break;
    00215       }
    00216     } else {
    00217       /* Can move only part of the packet, so split it into two pieces */
    00218       if (mta != MTA_FINAL_DELIVERY) {
    00219         CargoPacket *cp_new = new CargoPacket();
    00220
    00221         Money fs = cp->feeder_share * count / static_cast<uint>(cp->count);
    00222         cp->feeder_share -= fs;
    00223
    00224         cp_new->source          = cp->source;
    00225         cp_new->source_xy       = cp->source_xy;
    00226         cp_new->loaded_at_xy    = (mta == MTA_CARGO_LOAD) ? data : cp->loaded_at_xy;
    00227
    00228         cp_new->days_in_transit = cp->days_in_transit;
    00229         cp_new->feeder_share    = fs;
    00230         /* When cargo is moved into another vehicle you have *always* paid for it */
    00231         cp_new->paid_for        = (mta == MTA_CARGO_LOAD) ? false : cp->paid_for;
    00232
    00233         cp_new->count = count;
    00234         dest->packets.push_back(cp_new);
    00235       }
    00236       cp->count -= count;
    00237
    00238       count = 0;
    00239     }
    00240   }
    00241
    00242   bool remaining = !packets.empty();
    00243
    00244   if (mta == MTA_FINAL_DELIVERY && !tmp.Empty()) {
    00245     /* There are some packets that could not be delivered at the station, put them back */
    00246     tmp.MoveTo(this, MAX_UVALUE(uint));
    00247     tmp.packets.clear();
    00248   }
    00249
    00250   if (dest != NULL) dest->InvalidateCache();
    00251   InvalidateCache();
    00252
    00253   return remaining;
    00254 }
    00255
    00256 void CargoList::InvalidateCache()
    00257 {
    00258   empty = packets.empty();
    00259   count = 0;
    00260   unpaid_cargo = false;
    00261   feeder_share = 0;
    00262   source = INVALID_STATION;
    00263   days_in_transit = 0;
    00264
    00265   if (empty) return;
    00266
    00267   uint dit = 0;
    00268   for (List::const_iterator it = packets.begin(); it != packets.end(); it++) {
    00269     count        += (*it)->count;
    00270     unpaid_cargo |= !(*it)->paid_for;
    00271     dit          += (*it)->days_in_transit * (*it)->count;
    00272     feeder_share += (*it)->feeder_share;
    00273   }
    00274   days_in_transit = dit / count;
    00275   source = (*packets.begin())->source;
    00276 }