00001 /* $Id: cargopacket.cpp 15299 2009-01-31 20:16:06Z smatz $ */ 00002 00005 #include "stdafx.h" 00006 #include "station_base.h" 00007 #include "oldpool_func.h" 00008 00009 /* Initialize the cargopacket-pool */ 00010 DEFINE_OLD_POOL_GENERIC(CargoPacket, CargoPacket) 00011 00012 void InitializeCargoPackets() 00013 { 00014 /* Clean the cargo packet pool and create 1 block in it */ 00015 _CargoPacket_pool.CleanPool(); 00016 _CargoPacket_pool.AddBlockToPool(); 00017 } 00018 00019 CargoPacket::CargoPacket(StationID source, uint16 count) 00020 { 00021 if (source != INVALID_STATION) assert(count != 0); 00022 00023 this->source = source; 00024 this->source_xy = (source != INVALID_STATION) ? GetStation(source)->xy : 0; 00025 this->loaded_at_xy = this->source_xy; 00026 00027 this->count = count; 00028 this->days_in_transit = 0; 00029 this->feeder_share = 0; 00030 this->paid_for = false; 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 && this->paid_for == cp->paid_for; 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 bool CargoList::UnpaidCargo() const 00085 { 00086 return unpaid_cargo; 00087 } 00088 00089 Money CargoList::FeederShare() const 00090 { 00091 return feeder_share; 00092 } 00093 00094 StationID CargoList::Source() const 00095 { 00096 return source; 00097 } 00098 00099 uint CargoList::DaysInTransit() const 00100 { 00101 return days_in_transit; 00102 } 00103 00104 void CargoList::Append(CargoPacket *cp) 00105 { 00106 assert(cp != NULL); 00107 assert(cp->IsValid()); 00108 00109 for (List::iterator it = packets.begin(); it != packets.end(); it++) { 00110 if ((*it)->SameSource(cp) && (*it)->count + cp->count <= 65535) { 00111 (*it)->count += cp->count; 00112 (*it)->feeder_share += cp->feeder_share; 00113 delete cp; 00114 00115 InvalidateCache(); 00116 return; 00117 } 00118 } 00119 00120 /* The packet could not be merged with another one */ 00121 packets.push_back(cp); 00122 InvalidateCache(); 00123 } 00124 00125 00126 void CargoList::Truncate(uint count) 00127 { 00128 for (List::iterator it = packets.begin(); it != packets.end(); it++) { 00129 uint local_count = (*it)->count; 00130 if (local_count <= count) { 00131 count -= local_count; 00132 continue; 00133 } 00134 00135 (*it)->count = count; 00136 count = 0; 00137 } 00138 00139 while (!packets.empty()) { 00140 CargoPacket *cp = packets.back(); 00141 if (cp->count != 0) break; 00142 delete cp; 00143 packets.pop_back(); 00144 } 00145 00146 InvalidateCache(); 00147 } 00148 00149 bool CargoList::MoveTo(CargoList *dest, uint count, CargoList::MoveToAction mta, uint data) 00150 { 00151 assert(mta == MTA_FINAL_DELIVERY || dest != NULL); 00152 CargoList tmp; 00153 00154 while (!packets.empty() && count > 0) { 00155 CargoPacket *cp = *packets.begin(); 00156 if (cp->count <= count) { 00157 /* Can move the complete packet */ 00158 packets.remove(cp); 00159 switch (mta) { 00160 case MTA_FINAL_DELIVERY: 00161 if (cp->source == data) { 00162 tmp.Append(cp); 00163 } else { 00164 count -= cp->count; 00165 delete cp; 00166 } 00167 break; 00168 case MTA_CARGO_LOAD: 00169 cp->loaded_at_xy = data; 00170 /* When cargo is moved into another vehicle you have *always* paid for it */ 00171 cp->paid_for = false; 00172 /* FALL THROUGH */ 00173 case MTA_OTHER: 00174 count -= cp->count; 00175 dest->packets.push_back(cp); 00176 break; 00177 } 00178 } else { 00179 /* Can move only part of the packet, so split it into two pieces */ 00180 if (mta != MTA_FINAL_DELIVERY) { 00181 CargoPacket *cp_new = new CargoPacket(); 00182 00183 Money fs = cp->feeder_share * count / static_cast<uint>(cp->count); 00184 cp->feeder_share -= fs; 00185 00186 cp_new->source = cp->source; 00187 cp_new->source_xy = cp->source_xy; 00188 cp_new->loaded_at_xy = (mta == MTA_CARGO_LOAD) ? data : cp->loaded_at_xy; 00189 00190 cp_new->days_in_transit = cp->days_in_transit; 00191 cp_new->feeder_share = fs; 00192 /* When cargo is moved into another vehicle you have *always* paid for it */ 00193 cp_new->paid_for = (mta == MTA_CARGO_LOAD) ? false : cp->paid_for; 00194 00195 cp_new->count = count; 00196 dest->packets.push_back(cp_new); 00197 } 00198 cp->count -= count; 00199 00200 count = 0; 00201 } 00202 } 00203 00204 bool remaining = !packets.empty(); 00205 00206 if (mta == MTA_FINAL_DELIVERY && !tmp.Empty()) { 00207 /* There are some packets that could not be delivered at the station, put them back */ 00208 tmp.MoveTo(this, UINT_MAX); 00209 tmp.packets.clear(); 00210 } 00211 00212 if (dest != NULL) dest->InvalidateCache(); 00213 InvalidateCache(); 00214 00215 return remaining; 00216 } 00217 00218 void CargoList::InvalidateCache() 00219 { 00220 empty = packets.empty(); 00221 count = 0; 00222 unpaid_cargo = false; 00223 feeder_share = 0; 00224 source = INVALID_STATION; 00225 days_in_transit = 0; 00226 00227 if (empty) return; 00228 00229 uint dit = 0; 00230 for (List::const_iterator it = packets.begin(); it != packets.end(); it++) { 00231 count += (*it)->count; 00232 unpaid_cargo |= !(*it)->paid_for; 00233 dit += (*it)->days_in_transit * (*it)->count; 00234 feeder_share += (*it)->feeder_share; 00235 } 00236 days_in_transit = dit / count; 00237 source = (*packets.begin())->source; 00238 } 00239