# cargopacket.cpp

Go to the documentation of this file.

    00001 /* $Id: cargopacket.cpp 16742 2009-07-04 17:39:00Z rubidium $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "station_base.h"
    00007 #include "oldpool_func.h"
    00008 #include "economy_base.h"
    00009
    00010 /* Initialize the cargopacket-pool */
    00011 DEFINE_OLD_POOL_GENERIC(CargoPacket, CargoPacket)
    00012
    00013 void InitializeCargoPackets()
    00014 {
    00015   /* Clean the cargo packet pool and create 1 block in it */
    00016   _CargoPacket_pool.CleanPool();
    00017   _CargoPacket_pool.AddBlockToPool();
    00018 }
    00019
    00020 CargoPacket::CargoPacket(StationID source, uint16 count)
    00021 {
    00022   if (source != INVALID_STATION) assert(count != 0);
    00023
    00024   this->source          = source;
    00025   this->source_xy       = (source != INVALID_STATION) ? GetStation(source)->xy : 0;
    00026   this->loaded_at_xy    = this->source_xy;
    00027
    00028   this->count           = count;
    00029   this->days_in_transit = 0;
    00030   this->feeder_share    = 0;
    00031 }
    00032
    00033 CargoPacket::~CargoPacket()
    00034 {
    00035   this->count = 0;
    00036 }
    00037
    00038 bool CargoPacket::SameSource(const CargoPacket *cp) const
    00039 {
    00040   return this->source_xy == cp->source_xy && this->days_in_transit == cp->days_in_transit;
    00041 }
    00042
    00043 /*
    00044  *
    00045  * Cargo list implementation
    00046  *
    00047  */
    00048
    00049 CargoList::~CargoList()
    00050 {
    00051   while (!packets.empty()) {
    00052     delete packets.front();
    00053     packets.pop_front();
    00054   }
    00055 }
    00056
    00057 const CargoList::List *CargoList::Packets() const
    00058 {
    00059   return &packets;
    00060 }
    00061
    00062 void CargoList::AgeCargo()
    00063 {
    00064   if (empty) return;
    00065
    00066   uint dit = 0;
    00067   for (List::const_iterator it = packets.begin(); it != packets.end(); it++) {
    00068     if ((*it)->days_in_transit != 0xFF) (*it)->days_in_transit++;
    00069     dit += (*it)->days_in_transit * (*it)->count;
    00070   }
    00071   days_in_transit = dit / count;
    00072 }
    00073
    00074 bool CargoList::Empty() const
    00075 {
    00076   return empty;
    00077 }
    00078
    00079 uint CargoList::Count() const
    00080 {
    00081   return count;
    00082 }
    00083
    00084 Money CargoList::FeederShare() const
    00085 {
    00086   return feeder_share;
    00087 }
    00088
    00089 StationID CargoList::Source() const
    00090 {
    00091   return source;
    00092 }
    00093
    00094 uint CargoList::DaysInTransit() const
    00095 {
    00096   return days_in_transit;
    00097 }
    00098
    00099 void CargoList::Append(CargoPacket *cp)
    00100 {
    00101   assert(cp != NULL);
    00102   assert(cp->IsValid());
    00103
    00104   for (List::iterator it = packets.begin(); it != packets.end(); it++) {
    00105     if ((*it)->SameSource(cp) && (*it)->count + cp->count <= 65535) {
    00106       (*it)->count        += cp->count;
    00107       (*it)->feeder_share += cp->feeder_share;
    00108       delete cp;
    00109
    00110       InvalidateCache();
    00111       return;
    00112     }
    00113   }
    00114
    00115   /* The packet could not be merged with another one */
    00116   packets.push_back(cp);
    00117   InvalidateCache();
    00118 }
    00119
    00120
    00121 void CargoList::Truncate(uint count)
    00122 {
    00123   for (List::iterator it = packets.begin(); it != packets.end(); it++) {
    00124     uint local_count = (*it)->count;
    00125     if (local_count <= count) {
    00126       count -= local_count;
    00127       continue;
    00128     }
    00129
    00130     (*it)->count = count;
    00131     count = 0;
    00132   }
    00133
    00134   while (!packets.empty()) {
    00135     CargoPacket *cp = packets.back();
    00136     if (cp->count != 0) break;
    00137     delete cp;
    00138     packets.pop_back();
    00139   }
    00140
    00141   InvalidateCache();
    00142 }
    00143
    00144 bool CargoList::MoveTo(CargoList *dest, uint count, CargoList::MoveToAction mta, CargoPayment *payment, uint data)
    00145 {
    00146   assert(mta == MTA_FINAL_DELIVERY || dest != NULL);
    00147   assert(mta == MTA_UNLOAD || mta == MTA_CARGO_LOAD || payment != NULL);
    00148   CargoList tmp;
    00149
    00150   while (!packets.empty() && count > 0) {
    00151     CargoPacket *cp = *packets.begin();
    00152     if (cp->count <= count) {
    00153       /* Can move the complete packet */
    00154       packets.remove(cp);
    00155       switch (mta) {
    00156         case MTA_FINAL_DELIVERY:
    00157           if (cp->source == data) {
    00158             tmp.Append(cp);
    00159           } else {
    00160             payment->PayFinalDelivery(cp, cp->count);
    00161             count -= cp->count;
    00162             delete cp;
    00163           }
    00164           continue; // of the loop
    00165
    00166         case MTA_CARGO_LOAD:
    00167           cp->loaded_at_xy = data;
    00168           break;
    00169
    00170         case MTA_TRANSFER:
    00171           payment->PayTransfer(cp, cp->count);
    00172           break;
    00173
    00174         case MTA_UNLOAD:
    00175           break;
    00176       }
    00177       count -= cp->count;
    00178       dest->packets.push_back(cp);
    00179     } else {
    00180       /* Can move only part of the packet, so split it into two pieces */
    00181       if (mta != MTA_FINAL_DELIVERY) {
    00182         CargoPacket *cp_new = new CargoPacket();
    00183
    00184         Money fs = cp->feeder_share * count / static_cast<uint>(cp->count);
    00185         cp->feeder_share -= fs;
    00186
    00187         cp_new->source          = cp->source;
    00188         cp_new->source_xy       = cp->source_xy;
    00189         cp_new->loaded_at_xy    = (mta == MTA_CARGO_LOAD) ? data : cp->loaded_at_xy;
    00190
    00191         cp_new->days_in_transit = cp->days_in_transit;
    00192         cp_new->feeder_share    = fs;
    00193
    00194         cp_new->count = count;
    00195         dest->packets.push_back(cp_new);
    00196
    00197         if (mta == MTA_TRANSFER) payment->PayTransfer(cp_new, count);
    00198       } else {
    00199         payment->PayFinalDelivery(cp, count);
    00200       }
    00201       cp->count -= count;
    00202
    00203       count = 0;
    00204     }
    00205   }
    00206
    00207   bool remaining = !packets.empty();
    00208
    00209   if (mta == MTA_FINAL_DELIVERY && !tmp.Empty()) {
    00210     /* There are some packets that could not be delivered at the station, put them back */
    00211     tmp.MoveTo(this, UINT_MAX, MTA_UNLOAD, NULL);
    00212     tmp.packets.clear();
    00213   }
    00214
    00215   if (dest != NULL) dest->InvalidateCache();
    00216   InvalidateCache();
    00217
    00218   return remaining;
    00219 }
    00220
    00221 void CargoList::InvalidateCache()
    00222 {
    00223   empty = packets.empty();
    00224   count = 0;
    00225   feeder_share = 0;
    00226   source = INVALID_STATION;
    00227   days_in_transit = 0;
    00228
    00229   if (empty) return;
    00230
    00231   uint dit = 0;
    00232   for (List::const_iterator it = packets.begin(); it != packets.end(); it++) {
    00233     count        += (*it)->count;
    00234     dit          += (*it)->days_in_transit * (*it)->count;
    00235     feeder_share += (*it)->feeder_share;
    00236   }
    00237   days_in_transit = dit / count;
    00238   source = (*packets.begin())->source;
    00239 }
    00240