00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "station_base.h"
00014 #include "core/pool_func.hpp"
00015 #include "core/random_func.hpp"
00016 #include "economy_base.h"
00017
00018
00019 CargoPacketPool _cargopacket_pool("CargoPacket");
00020 INSTANTIATE_POOL_METHODS(CargoPacket)
00021
00022
00025 CargoPacket::CargoPacket()
00026 {
00027 this->source_type = ST_INDUSTRY;
00028 this->source_id = INVALID_SOURCE;
00029 }
00030
00042 CargoPacket::CargoPacket(StationID source, TileIndex source_xy, uint16 count, SourceType source_type, SourceID source_id) :
00043 feeder_share(0),
00044 count(count),
00045 days_in_transit(0),
00046 source_id(source_id),
00047 source(source),
00048 source_xy(source_xy),
00049 loaded_at_xy(0)
00050 {
00051 assert(count != 0);
00052 this->source_type = source_type;
00053 }
00054
00069 CargoPacket::CargoPacket(uint16 count, byte days_in_transit, StationID source, TileIndex source_xy, TileIndex loaded_at_xy, Money feeder_share, SourceType source_type, SourceID source_id) :
00070 feeder_share(feeder_share),
00071 count(count),
00072 days_in_transit(days_in_transit),
00073 source_id(source_id),
00074 source(source),
00075 source_xy(source_xy),
00076 loaded_at_xy(loaded_at_xy)
00077 {
00078 assert(count != 0);
00079 this->source_type = source_type;
00080 }
00081
00087 inline CargoPacket *CargoPacket::Split(uint new_size)
00088 {
00089 if (!CargoPacket::CanAllocateItem()) return NULL;
00090
00091 Money fs = this->feeder_share * new_size / static_cast<uint>(this->count);
00092 CargoPacket *cp_new = new CargoPacket(new_size, this->days_in_transit, this->source, this->source_xy, this->loaded_at_xy, fs, this->source_type, this->source_id);
00093 this->feeder_share -= fs;
00094 this->count -= new_size;
00095 return cp_new;
00096 }
00097
00102 inline void CargoPacket::Merge(CargoPacket *cp)
00103 {
00104 this->count += cp->count;
00105 this->feeder_share += cp->feeder_share;
00106 delete cp;
00107 }
00108
00114 void CargoPacket::InvalidateAllFrom(SourceType src_type, SourceID src)
00115 {
00116 CargoPacket *cp;
00117 FOR_ALL_CARGOPACKETS(cp) {
00118 if (cp->source_type == src_type && cp->source_id == src) cp->source_id = INVALID_SOURCE;
00119 }
00120 }
00121
00126 void CargoPacket::InvalidateAllFrom(StationID sid)
00127 {
00128 CargoPacket *cp;
00129 FOR_ALL_CARGOPACKETS(cp) {
00130 if (cp->source == sid) cp->source = INVALID_STATION;
00131 }
00132 }
00133
00134
00135
00136
00137
00138
00139
00143 template <class Tinst, class Tcont>
00144 CargoList<Tinst, Tcont>::~CargoList()
00145 {
00146 for (Iterator it(this->packets.begin()); it != this->packets.end(); ++it) {
00147 delete *it;
00148 }
00149 }
00150
00155 template <class Tinst, class Tcont>
00156 void CargoList<Tinst, Tcont>::OnCleanPool()
00157 {
00158 this->packets.clear();
00159 }
00160
00166 template <class Tinst, class Tcont>
00167 void CargoList<Tinst, Tcont>::RemoveFromCache(const CargoPacket *cp)
00168 {
00169 this->count -= cp->count;
00170 this->cargo_days_in_transit -= cp->days_in_transit * cp->count;
00171 }
00172
00178 template <class Tinst, class Tcont>
00179 void CargoList<Tinst, Tcont>::AddToCache(const CargoPacket *cp)
00180 {
00181 this->count += cp->count;
00182 this->cargo_days_in_transit += cp->days_in_transit * cp->count;
00183 }
00184
00195 void VehicleCargoList::Append(CargoPacket *cp, bool update_cache)
00196 {
00197 assert(cp != NULL);
00198 if (update_cache) this->AddToCache(cp);
00199 for (CargoPacketList::reverse_iterator it(this->packets.rbegin()); it != this->packets.rend(); it++) {
00200 CargoPacket *icp = *it;
00201 if (VehicleCargoList::AreMergable(icp, cp) && icp->count + cp->count <= CargoPacket::MAX_COUNT) {
00202 icp->Merge(cp);
00203 return;
00204 }
00205 }
00206
00207
00208 this->packets.push_back(cp);
00209 }
00210
00216 template <class Tinst, class Tcont>
00217 void CargoList<Tinst, Tcont>::Truncate(uint max_remaining)
00218 {
00219 for (Iterator it(packets.begin()); it != packets.end(); ) {
00220 CargoPacket *cp = *it;
00221 if (max_remaining == 0) {
00222
00223 it = this->packets.erase(it);
00224 static_cast<Tinst *>(this)->RemoveFromCache(cp);
00225 delete cp;
00226 continue;
00227 }
00228
00229 uint local_count = cp->count;
00230 if (local_count > max_remaining) {
00231 uint diff = local_count - max_remaining;
00232 this->count -= diff;
00233 this->cargo_days_in_transit -= cp->days_in_transit * diff;
00234 cp->count = max_remaining;
00235 max_remaining = 0;
00236 } else {
00237 max_remaining -= local_count;
00238 }
00239 ++it;
00240 }
00241 }
00242
00247 void VehicleCargoList::Reserve(CargoPacket *cp)
00248 {
00249 assert(cp != NULL);
00250 this->AddToCache(cp);
00251 this->reserved_count += cp->count;
00252 this->reserved.push_back(cp);
00253 }
00254
00260 void VehicleCargoList::Unreserve(StationID next, StationCargoList *dest)
00261 {
00262 Iterator it(this->reserved.begin());
00263 while (it != this->reserved.end()) {
00264 CargoPacket *cp = *it;
00265 this->RemoveFromCache(cp);
00266 this->reserved_count -= cp->count;
00267 dest->Append(next, cp);
00268 it = this->reserved.erase(it);
00269 }
00270 }
00271
00277 uint VehicleCargoList::LoadReserved(uint max_move)
00278 {
00279 uint orig_max = max_move;
00280 Iterator it(this->reserved.begin());
00281 while (it != this->reserved.end() && max_move > 0) {
00282 CargoPacket *cp = *it;
00283 if (cp->count <= max_move) {
00284
00285 max_move -= cp->count;
00286 it = this->reserved.erase(it);
00287 this->reserved_count -= cp->count;
00288 this->Append(cp, false);
00289 } else if (CargoPacket::CanAllocateItem()) {
00290 cp->count -= max_move;
00291 CargoPacket *cp_new = new CargoPacket(max_move, cp->days_in_transit, cp->source, cp->source_xy, cp->loaded_at_xy, 0, cp->source_type, cp->source_id);
00292 this->Append(cp_new, false);
00293 this->reserved_count -= max_move;
00294 max_move = 0;
00295 }
00296 }
00297 return orig_max - max_move;
00298 }
00299
00310 template<class Tinst, class Tcont>
00311 uint CargoList<Tinst, Tcont>::MovePacket(VehicleCargoList *dest, Iterator &it, uint cap, TileIndex load_place, bool reserve)
00312 {
00313 CargoPacket *packet = this->RemovePacket(it, cap, load_place);
00314 uint ret = packet->count;
00315 if (reserve) {
00316 dest->Reserve(packet);
00317 } else {
00318 dest->Append(packet);
00319 }
00320 return ret;
00321 }
00322
00332 template<class Tinst, class Tcont>
00333 uint CargoList<Tinst, Tcont>::MovePacket(StationCargoList *dest, StationID next, Iterator &it, uint cap)
00334 {
00335 CargoPacket *packet = this->RemovePacket(it, cap);
00336 uint ret = packet->count;
00337 dest->Append(next, packet);
00338 return ret;
00339 }
00340
00350 template<class Tinst, class Tcont>
00351 CargoPacket *CargoList<Tinst, Tcont>::RemovePacket(Iterator &it, uint cap, TileIndex load_place)
00352 {
00353 CargoPacket *packet = *it;
00354
00355 if (packet->count > cap) {
00356
00357 packet = packet->Split(cap);
00358
00359
00360
00361
00362 if (packet == NULL) {
00363 packet = *it;
00364 uint dropped = packet->count - cap;
00365 this->count -= dropped;
00366 this->cargo_days_in_transit -= dropped * packet->days_in_transit;
00367 packet->count = cap;
00368 it = this->packets.erase(it);
00369 } else {
00370 assert(packet->count == cap);
00371 ++it;
00372 }
00373 } else {
00374 it = this->packets.erase(it);
00375 }
00376 static_cast<Tinst *>(this)->RemoveFromCache(packet);
00377 if (load_place != INVALID_TILE) {
00378 packet->loaded_at_xy = load_place;
00379 }
00380 return packet;
00381 }
00382
00386 template <class Tinst, class Tcont>
00387 void CargoList<Tinst, Tcont>::InvalidateCache()
00388 {
00389 this->count = 0;
00390 this->cargo_days_in_transit = 0;
00391
00392 for (ConstIterator it(this->packets.begin()); it != this->packets.end(); it++) {
00393 static_cast<Tinst *>(this)->AddToCache(*it);
00394 }
00395 }
00396
00400 VehicleCargoList::~VehicleCargoList()
00401 {
00402 for (Iterator it(this->reserved.begin()); it != this->reserved.end(); ++it) {
00403 delete *it;
00404 }
00405 }
00406
00415 uint VehicleCargoList::DeliverPacket(Iterator &it, uint cap, CargoPayment *payment)
00416 {
00417 CargoPacket *p = *it;
00418 uint unloaded = 0;
00419 if (p->count <= cap) {
00420 payment->PayFinalDelivery(p, p->count);
00421 it = this->packets.erase(it);
00422 this->RemoveFromCache(p);
00423 unloaded = p->count;
00424 delete p;
00425 } else {
00426 payment->PayFinalDelivery(p, cap);
00427 this->count -= cap;
00428 this->cargo_days_in_transit -= cap * p->days_in_transit;
00429 this->feeder_share -= p->feeder_share;
00430 p->feeder_share = 0;
00431 p->count -= cap;
00432 unloaded = cap;
00433 ++it;
00434 }
00435 return unloaded;
00436 }
00437
00444 uint VehicleCargoList::KeepPacket(Iterator &it)
00445 {
00446 CargoPacket *cp = *it;
00447 this->reserved.push_back(cp);
00448 this->reserved_count += cp->count;
00449 it = this->packets.erase(it);
00450 return cp->count;
00451 }
00452
00464 uint VehicleCargoList::TransferPacket(Iterator &it, uint cap, StationCargoList *dest, CargoPayment *payment, StationID next)
00465 {
00466 CargoPacket *cp = this->RemovePacket(it, cap);
00467 cp->feeder_share += payment->PayTransfer(cp, cp->count);
00468 uint ret = cp->count;
00469 dest->Append(next, cp);
00470 return ret;
00471 }
00472
00482 UnloadType StationCargoList::WillUnloadOld(byte flags, StationID source)
00483 {
00484
00485 bool move = (flags & (UL_DELIVER | UL_ACCEPTED | UL_TRANSFER)) != 0;
00486
00487 bool deliver = (flags & UL_ACCEPTED) && !(flags & UL_TRANSFER) && (source != this->station->index);
00488
00489 bool transfer = (flags & (UL_TRANSFER | UL_DELIVER)) != 0;
00490 if (move) {
00491 if(deliver) {
00492 return UL_DELIVER;
00493 } else if (transfer) {
00494 return UL_TRANSFER;
00495 } else {
00496
00497
00498
00499 return UL_KEEP;
00500 }
00501 } else {
00502 return UL_KEEP;
00503 }
00504 }
00505
00519 UnloadType StationCargoList::WillUnloadCargoDist(byte flags, StationID next, StationID via, StationID source)
00520 {
00521 if (via == this->station->index) {
00522
00523 if (flags & UL_TRANSFER) {
00524
00525 return UL_TRANSFER;
00526 } else if (flags & UL_ACCEPTED) {
00527 return UL_DELIVER;
00528 } else if (flags & UL_DELIVER) {
00529
00530 return UL_TRANSFER;
00531 } else {
00532
00533 return UL_KEEP;
00534 }
00535 } else {
00536
00537 if (flags & UL_DELIVER) {
00538
00539
00540
00541 if ((flags & UL_ACCEPTED) && !(flags & UL_TRANSFER) && source != this->station->index) {
00542 return UL_DELIVER;
00543 } else {
00544
00545 return UL_TRANSFER;
00546 }
00547 } else if (flags & UL_TRANSFER) {
00548
00549 return UL_TRANSFER;
00550 } else if (next == via && next != INVALID_STATION) {
00551
00552 return UL_KEEP;
00553 } else {
00554
00555 return UL_TRANSFER;
00556 }
00557 }
00558 }
00559
00566 void VehicleCargoList::SwapReserved()
00567 {
00568 assert(this->packets.empty());
00569 this->packets.swap(this->reserved);
00570 this->reserved_count = 0;
00571 }
00572
00594 uint StationCargoList::TakeFrom(VehicleCargoList *source, uint max_unload, OrderUnloadFlags order_flags, StationID next, bool has_stopped, CargoPayment *payment)
00595 {
00596 uint remaining_unload = max_unload;
00597 uint unloaded;
00598 byte flags = this->GetUnloadFlags(order_flags);
00599 GoodsEntry *dest = &this->station->goods[this->cargo];
00600 UnloadType action;
00601
00602 for (VehicleCargoList::Iterator c = source->packets.begin(); c != source->packets.end() && remaining_unload > 0;) {
00603 StationID cargo_source = (*c)->source;
00604 FlowStatMap::const_iterator flows_it = dest->flows.find(cargo_source);
00605 StationID via;
00606 if (flows_it != dest->flows.end()) {
00607 via = flows_it->second.GetVia();
00608
00609 action = this->WillUnloadCargoDist(flags, next, via, cargo_source);
00610 } else {
00611 via = INVALID_STATION;
00612
00613 action = this->WillUnloadOld(flags, cargo_source);
00614 }
00615
00616 switch (action) {
00617 case UL_DELIVER:
00618 unloaded = source->DeliverPacket(c, remaining_unload, payment);
00619 remaining_unload -= unloaded;
00620 break;
00621 case UL_TRANSFER:
00622
00623 if (via == this->station->index) via = flows_it->second.GetVia(via);
00624 unloaded = source->TransferPacket(c, remaining_unload, this, payment, via);
00625 remaining_unload -= unloaded;
00626 break;
00627 case UL_KEEP:
00628 unloaded = source->KeepPacket(c);
00629 break;
00630 default:
00631 NOT_REACHED();
00632 }
00633 }
00634 return max_unload - remaining_unload;
00635 }
00636
00640 void VehicleCargoList::OnCleanPool()
00641 {
00642 this->reserved.clear();
00643 this->Parent::OnCleanPool();
00644 }
00645
00651 void VehicleCargoList::RemoveFromCache(const CargoPacket *cp)
00652 {
00653 this->feeder_share -= cp->feeder_share;
00654 this->Parent::RemoveFromCache(cp);
00655 }
00656
00662 void VehicleCargoList::AddToCache(const CargoPacket *cp)
00663 {
00664 this->feeder_share += cp->feeder_share;
00665 this->Parent::AddToCache(cp);
00666 }
00667
00674 uint VehicleCargoList::MoveTo(VehicleCargoList *dest, uint cap)
00675 {
00676 uint orig_cap = cap;
00677 Iterator it = packets.begin();
00678 while (it != packets.end() && cap > 0) {
00679 cap -= MovePacket(dest, it, cap);
00680 }
00681 return orig_cap - cap;
00682 }
00683
00687 void VehicleCargoList::AgeCargo()
00688 {
00689 for (ConstIterator it(this->packets.begin()); it != this->packets.end(); it++) {
00690 CargoPacket *cp = *it;
00691
00692 if (cp->days_in_transit == 0xFF) continue;
00693
00694 cp->days_in_transit++;
00695 this->cargo_days_in_transit += cp->count;
00696 }
00697 }
00698
00699
00700
00701
00702
00703
00704
00710 inline byte StationCargoList::GetUnloadFlags(OrderUnloadFlags order_flags)
00711 {
00712 byte flags = 0;
00713 if (HasBit(this->station->goods[this->cargo].acceptance_pickup, GoodsEntry::GES_ACCEPTANCE)) {
00714 flags |= UL_ACCEPTED;
00715 }
00716 if (order_flags & OUFB_UNLOAD) {
00717 flags |= UL_DELIVER;
00718 }
00719 if (order_flags & OUFB_TRANSFER) {
00720 flags |= UL_TRANSFER;
00721 }
00722 return flags;
00723 }
00724
00733 void StationCargoList::Append(StationID next, CargoPacket *cp)
00734 {
00735 assert(cp != NULL);
00736 this->AddToCache(cp);
00737
00738 StationCargoPacketMap::List &list = this->packets[next];
00739 for (StationCargoPacketMap::List::reverse_iterator it(list.rbegin()); it != list.rend(); it++) {
00740 CargoPacket *icp = *it;
00741 if (StationCargoList::AreMergable(icp, cp) && icp->count + cp->count <= CargoPacket::MAX_COUNT) {
00742 icp->Merge(cp);
00743 return;
00744 }
00745 }
00746
00747
00748 list.push_back(cp);
00749 }
00750
00760 uint StationCargoList::MovePackets(VehicleCargoList *dest, uint cap, Iterator begin, Iterator end, bool reserve)
00761 {
00762 uint orig_cap = cap;
00763 while (begin != end && cap > 0) {
00764 cap -= this->MovePacket(dest, begin, cap, this->station->xy, reserve);
00765 }
00766 return orig_cap - cap;
00767 }
00768
00777 uint StationCargoList::MoveTo(VehicleCargoList *dest, uint cap, StationID next, bool reserve)
00778 {
00779 uint orig_cap = cap;
00780 std::pair<Iterator, Iterator> bounds(this->packets.equal_range(next));
00781 cap -= this->MovePackets(dest, cap, bounds.first, bounds.second, reserve);
00782 if (next != INVALID_STATION && cap > 0) {
00783 bounds = this->packets.equal_range(INVALID_STATION);
00784 cap -= this->MovePackets(dest, cap, bounds.first, bounds.second, reserve);
00785 }
00786 return orig_cap - cap;
00787 }
00788
00793 void StationCargoList::RerouteStalePackets(StationID to)
00794 {
00795 std::pair<Iterator, Iterator> range(this->packets.equal_range(to));
00796 for (Iterator it(range.first); it != range.second && it.GetKey() == to;) {
00797 CargoPacket *packet = *it;
00798 it = this->packets.erase(it);
00799 StationID next = this->station->goods[this->cargo].GetVia(packet->source, this->station->index);
00800 assert(next != to);
00801
00802
00803
00804
00805
00806 this->packets.Insert(next, packet);
00807 }
00808 }
00809
00817 void StationCargoList::CountAndTruncate(uint max_remaining, StationCargoAmountMap &cargo_per_source)
00818 {
00819 uint prev_count = this->count;
00820 uint loop = 0;
00821 while (this->count > max_remaining) {
00822 for (Iterator it(this->packets.begin()); it != this->packets.end();) {
00823 CargoPacket *packet = *it;
00824 if (loop == 0) cargo_per_source[packet->source] += packet->count;
00825
00826 if (RandomRange(prev_count) < max_remaining) {
00827 ++it;
00828 continue;
00829 }
00830
00831 uint diff = this->count - max_remaining;
00832 if (packet->count > diff) {
00833 packet->count -= diff;
00834 this->count = max_remaining;
00835 this->cargo_days_in_transit -= packet->days_in_transit * diff;
00836 if (loop > 0) {
00837 return;
00838 } else {
00839 ++it;
00840 }
00841 } else {
00842 it = this->packets.erase(it);
00843 this->RemoveFromCache(packet);
00844 delete packet;
00845 }
00846 }
00847 loop++;
00848 }
00849 }
00850
00854 void VehicleCargoList::InvalidateCache()
00855 {
00856 this->feeder_share = 0;
00857 this->reserved_count = 0;
00858 this->Parent::InvalidateCache();
00859 for (ConstIterator it(this->reserved.begin()); it != this->reserved.end(); it++) {
00860 this->AddToCache(*it);
00861 this->reserved_count += (*it)->count;
00862 }
00863 }
00864
00870 void StationCargoList::AssignTo(Station *station, CargoID cargo)
00871 {
00872 assert(this->station == NULL);
00873 assert(station != NULL && cargo != INVALID_CARGO);
00874 this->station = station;
00875 this->cargo = cargo;
00876 }
00877
00878
00879
00880
00881
00882 template class CargoList<VehicleCargoList, CargoPacketList>;
00883 template class CargoList<StationCargoList, StationCargoPacketMap>;