cargopacket.cpp

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

Generated on Fri Nov 21 19:01:31 2008 for openttd by  doxygen 1.5.6