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 }

Generated on Mon Sep 22 20:34:15 2008 for openttd by  doxygen 1.5.6