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 if (packet == NULL) {
00362 packet = *it;
00363 uint dropped = packet->count - cap;
00364 this->count -= dropped;
00365 this->cargo_days_in_transit -= dropped * packet->days_in_transit;
00366 packet->count = cap;
00367 it = this->packets.erase(it);
00368 } else {
00369 assert(packet->count == cap);
00370 ++it;
00371 }
00372 } else {
00373 it = this->packets.erase(it);
00374 }
00375 static_cast<Tinst *>(this)->RemoveFromCache(packet);
00376 if (load_place != INVALID_TILE) {
00377 packet->loaded_at_xy = load_place;
00378 }
00379 return packet;
00380 }
00381
00385 template <class Tinst, class Tcont>
00386 void CargoList<Tinst, Tcont>::InvalidateCache()
00387 {
00388 this->count = 0;
00389 this->cargo_days_in_transit = 0;
00390
00391 for (ConstIterator it(this->packets.begin()); it != this->packets.end(); it++) {
00392 static_cast<Tinst *>(this)->AddToCache(*it);
00393 }
00394 }
00395
00399 VehicleCargoList::~VehicleCargoList()
00400 {
00401 for (Iterator it(this->reserved.begin()); it != this->reserved.end(); ++it) {
00402 delete *it;
00403 }
00404 }
00405
00414 uint VehicleCargoList::DeliverPacket(Iterator &it, uint cap, CargoPayment *payment)
00415 {
00416 CargoPacket *p = *it;
00417 uint unloaded = 0;
00418 if (p->count <= cap) {
00419 payment->PayFinalDelivery(p, p->count);
00420 it = this->packets.erase(it);
00421 this->RemoveFromCache(p);
00422 unloaded = p->count;
00423 delete p;
00424 } else {
00425 payment->PayFinalDelivery(p, cap);
00426 this->count -= cap;
00427 this->cargo_days_in_transit -= cap * p->days_in_transit;
00428 this->feeder_share -= p->feeder_share;
00429 p->feeder_share = 0;
00430 p->count -= cap;
00431 unloaded = cap;
00432 ++it;
00433 }
00434 return unloaded;
00435 }
00436
00443 uint VehicleCargoList::KeepPacket(Iterator &it)
00444 {
00445 CargoPacket *cp = *it;
00446 this->reserved.push_back(cp);
00447 this->reserved_count += cp->count;
00448 it = this->packets.erase(it);
00449 return cp->count;
00450 }
00451
00463 uint VehicleCargoList::TransferPacket(Iterator &it, uint cap, StationCargoList *dest, CargoPayment *payment, StationID next)
00464 {
00465 CargoPacket *cp = this->RemovePacket(it, cap);
00466 cp->feeder_share += payment->PayTransfer(cp, cp->count);
00467 uint ret = cp->count;
00468 dest->Append(next, cp);
00469 return ret;
00470 }
00471
00481 UnloadType StationCargoList::WillUnloadOld(byte flags, StationID source)
00482 {
00483
00484 bool move = (flags & (UL_DELIVER | UL_ACCEPTED | UL_TRANSFER)) != 0;
00485
00486 bool deliver = (flags & UL_ACCEPTED) && !(flags & UL_TRANSFER) && (source != this->station->index);
00487
00488 bool transfer = (flags & (UL_TRANSFER | UL_DELIVER)) != 0;
00489 if (move) {
00490 if (deliver) {
00491 return UL_DELIVER;
00492 } else if (transfer) {
00493 return UL_TRANSFER;
00494 } else {
00495
00496
00497 return UL_KEEP;
00498 }
00499 } else {
00500 return UL_KEEP;
00501 }
00502 }
00503
00517 UnloadType StationCargoList::WillUnloadCargoDist(byte flags, StationID next, StationID via, StationID source)
00518 {
00519 if (via == this->station->index) {
00520
00521 if (flags & UL_TRANSFER) {
00522
00523 return UL_TRANSFER;
00524 } else if (flags & UL_ACCEPTED) {
00525 return UL_DELIVER;
00526 } else if (flags & UL_DELIVER) {
00527
00528 return UL_TRANSFER;
00529 } else {
00530
00531 return UL_KEEP;
00532 }
00533 } else {
00534
00535 if (flags & UL_DELIVER) {
00536
00537
00538
00539 if ((flags & UL_ACCEPTED) && !(flags & UL_TRANSFER) && source != this->station->index) {
00540 return UL_DELIVER;
00541 } else {
00542
00543 return UL_TRANSFER;
00544 }
00545 } else if (flags & UL_TRANSFER) {
00546
00547 return UL_TRANSFER;
00548 } else if (next == via && next != INVALID_STATION) {
00549
00550 return UL_KEEP;
00551 } else {
00552
00553 return UL_TRANSFER;
00554 }
00555 }
00556 }
00557
00564 void VehicleCargoList::SwapReserved()
00565 {
00566 assert(this->packets.empty());
00567 this->packets.swap(this->reserved);
00568 this->reserved_count = 0;
00569 }
00570
00592 uint StationCargoList::TakeFrom(VehicleCargoList *source, uint max_unload, OrderUnloadFlags order_flags, StationID next, bool has_stopped, CargoPayment *payment)
00593 {
00594 uint remaining_unload = max_unload;
00595 uint unloaded;
00596 byte flags = this->GetUnloadFlags(order_flags);
00597 GoodsEntry *dest = &this->station->goods[this->cargo];
00598 UnloadType action;
00599
00600 for (VehicleCargoList::Iterator c = source->packets.begin(); c != source->packets.end() && remaining_unload > 0;) {
00601 StationID cargo_source = (*c)->source;
00602 FlowStatMap::const_iterator flows_it = dest->flows.find(cargo_source);
00603 StationID via;
00604 if (flows_it != dest->flows.end()) {
00605 via = flows_it->second.GetVia();
00606
00607 action = this->WillUnloadCargoDist(flags, next, via, cargo_source);
00608 } else {
00609 via = INVALID_STATION;
00610
00611 action = this->WillUnloadOld(flags, cargo_source);
00612 }
00613
00614 switch (action) {
00615 case UL_DELIVER:
00616 unloaded = source->DeliverPacket(c, remaining_unload, payment);
00617 remaining_unload -= unloaded;
00618 break;
00619 case UL_TRANSFER:
00620
00621 if (via == this->station->index) via = flows_it->second.GetVia(via);
00622 unloaded = source->TransferPacket(c, remaining_unload, this, payment, via);
00623 remaining_unload -= unloaded;
00624 break;
00625 case UL_KEEP:
00626 unloaded = source->KeepPacket(c);
00627 break;
00628 default:
00629 NOT_REACHED();
00630 }
00631 }
00632 return max_unload - remaining_unload;
00633 }
00634
00638 void VehicleCargoList::OnCleanPool()
00639 {
00640 this->reserved.clear();
00641 this->Parent::OnCleanPool();
00642 }
00643
00649 void VehicleCargoList::RemoveFromCache(const CargoPacket *cp)
00650 {
00651 this->feeder_share -= cp->feeder_share;
00652 this->Parent::RemoveFromCache(cp);
00653 }
00654
00660 void VehicleCargoList::AddToCache(const CargoPacket *cp)
00661 {
00662 this->feeder_share += cp->feeder_share;
00663 this->Parent::AddToCache(cp);
00664 }
00665
00672 uint VehicleCargoList::MoveTo(VehicleCargoList *dest, uint cap)
00673 {
00674 uint orig_cap = cap;
00675 Iterator it = packets.begin();
00676 while (it != packets.end() && cap > 0) {
00677 cap -= MovePacket(dest, it, cap);
00678 }
00679 return orig_cap - cap;
00680 }
00681
00685 void VehicleCargoList::AgeCargo()
00686 {
00687 for (ConstIterator it(this->packets.begin()); it != this->packets.end(); it++) {
00688 CargoPacket *cp = *it;
00689
00690 if (cp->days_in_transit == 0xFF) continue;
00691
00692 cp->days_in_transit++;
00693 this->cargo_days_in_transit += cp->count;
00694 }
00695 }
00696
00697
00698
00699
00700
00701
00702
00708 inline byte StationCargoList::GetUnloadFlags(OrderUnloadFlags order_flags)
00709 {
00710 byte flags = 0;
00711 if (HasBit(this->station->goods[this->cargo].acceptance_pickup, GoodsEntry::GES_ACCEPTANCE)) {
00712 flags |= UL_ACCEPTED;
00713 }
00714 if (order_flags & OUFB_UNLOAD) {
00715 flags |= UL_DELIVER;
00716 }
00717 if (order_flags & OUFB_TRANSFER) {
00718 flags |= UL_TRANSFER;
00719 }
00720 return flags;
00721 }
00722
00731 void StationCargoList::Append(StationID next, CargoPacket *cp)
00732 {
00733 assert(cp != NULL);
00734 this->AddToCache(cp);
00735
00736 StationCargoPacketMap::List &list = this->packets[next];
00737 for (StationCargoPacketMap::List::reverse_iterator it(list.rbegin()); it != list.rend(); it++) {
00738 CargoPacket *icp = *it;
00739 if (StationCargoList::AreMergable(icp, cp) && icp->count + cp->count <= CargoPacket::MAX_COUNT) {
00740 icp->Merge(cp);
00741 return;
00742 }
00743 }
00744
00745
00746 list.push_back(cp);
00747 }
00748
00758 uint StationCargoList::MovePackets(VehicleCargoList *dest, uint cap, Iterator begin, Iterator end, bool reserve)
00759 {
00760 uint orig_cap = cap;
00761 while (begin != end && cap > 0) {
00762 cap -= this->MovePacket(dest, begin, cap, this->station->xy, reserve);
00763 }
00764 return orig_cap - cap;
00765 }
00766
00775 uint StationCargoList::MoveTo(VehicleCargoList *dest, uint cap, StationID next, bool reserve)
00776 {
00777 uint orig_cap = cap;
00778 std::pair<Iterator, Iterator> bounds(this->packets.equal_range(next));
00779 cap -= this->MovePackets(dest, cap, bounds.first, bounds.second, reserve);
00780 if (next != INVALID_STATION && cap > 0) {
00781 bounds = this->packets.equal_range(INVALID_STATION);
00782 cap -= this->MovePackets(dest, cap, bounds.first, bounds.second, reserve);
00783 }
00784 return orig_cap - cap;
00785 }
00786
00791 void StationCargoList::RerouteStalePackets(StationID to)
00792 {
00793 std::pair<Iterator, Iterator> range(this->packets.equal_range(to));
00794 for (Iterator it(range.first); it != range.second && it.GetKey() == to;) {
00795 CargoPacket *packet = *it;
00796 it = this->packets.erase(it);
00797 StationID next = this->station->goods[this->cargo].GetVia(packet->source, this->station->index);
00798 assert(next != to);
00799
00800
00801
00802
00803 this->packets.Insert(next, packet);
00804 }
00805 }
00806
00814 void StationCargoList::CountAndTruncate(uint max_remaining, StationCargoAmountMap &cargo_per_source)
00815 {
00816 uint prev_count = this->count;
00817 uint loop = 0;
00818 while (this->count > max_remaining) {
00819 for (Iterator it(this->packets.begin()); it != this->packets.end();) {
00820 CargoPacket *packet = *it;
00821 if (loop == 0) cargo_per_source[packet->source] += packet->count;
00822
00823 if (RandomRange(prev_count) < max_remaining) {
00824 ++it;
00825 continue;
00826 }
00827
00828 uint diff = this->count - max_remaining;
00829 if (packet->count > diff) {
00830 packet->count -= diff;
00831 this->count = max_remaining;
00832 this->cargo_days_in_transit -= packet->days_in_transit * diff;
00833 if (loop > 0) {
00834 return;
00835 } else {
00836 ++it;
00837 }
00838 } else {
00839 it = this->packets.erase(it);
00840 this->RemoveFromCache(packet);
00841 delete packet;
00842 }
00843 }
00844 loop++;
00845 }
00846 }
00847
00851 void VehicleCargoList::InvalidateCache()
00852 {
00853 this->feeder_share = 0;
00854 this->reserved_count = 0;
00855 this->Parent::InvalidateCache();
00856 for (ConstIterator it(this->reserved.begin()); it != this->reserved.end(); it++) {
00857 this->AddToCache(*it);
00858 this->reserved_count += (*it)->count;
00859 }
00860 }
00861
00867 void StationCargoList::AssignTo(Station *station, CargoID cargo)
00868 {
00869 assert(this->station == NULL);
00870 assert(station != NULL && cargo != INVALID_CARGO);
00871 this->station = station;
00872 this->cargo = cargo;
00873 }
00874
00875
00876
00877
00878
00879 template class CargoList<VehicleCargoList, CargoPacketList>;
00880 template class CargoList<StationCargoList, StationCargoPacketMap>;