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 #include "cargoaction.h"
00018 #include "order_type.h"
00019
00020
00021 CargoPacketPool _cargopacket_pool("CargoPacket");
00022 INSTANTIATE_POOL_METHODS(CargoPacket)
00023
00024
00027 CargoPacket::CargoPacket()
00028 {
00029 this->source_type = ST_INDUSTRY;
00030 this->source_id = INVALID_SOURCE;
00031 }
00032
00044 CargoPacket::CargoPacket(StationID source, TileIndex source_xy, uint16 count, SourceType source_type, SourceID source_id) :
00045 feeder_share(0),
00046 count(count),
00047 days_in_transit(0),
00048 source_id(source_id),
00049 source(source),
00050 source_xy(source_xy),
00051 loaded_at_xy(0)
00052 {
00053 assert(count != 0);
00054 this->source_type = source_type;
00055 }
00056
00071 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) :
00072 feeder_share(feeder_share),
00073 count(count),
00074 days_in_transit(days_in_transit),
00075 source_id(source_id),
00076 source(source),
00077 source_xy(source_xy),
00078 loaded_at_xy(loaded_at_xy)
00079 {
00080 assert(count != 0);
00081 this->source_type = source_type;
00082 }
00083
00089 CargoPacket *CargoPacket::Split(uint new_size)
00090 {
00091 if (!CargoPacket::CanAllocateItem()) return NULL;
00092
00093 Money fs = this->FeederShare(new_size);
00094 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);
00095 this->feeder_share -= fs;
00096 this->count -= new_size;
00097 return cp_new;
00098 }
00099
00104 void CargoPacket::Merge(CargoPacket *cp)
00105 {
00106 this->count += cp->count;
00107 this->feeder_share += cp->feeder_share;
00108 delete cp;
00109 }
00110
00115 void CargoPacket::Reduce(uint count)
00116 {
00117 assert(count < this->count);
00118 this->feeder_share -= this->FeederShare(count);
00119 this->count -= count;
00120 }
00121
00127 void CargoPacket::InvalidateAllFrom(SourceType src_type, SourceID src)
00128 {
00129 CargoPacket *cp;
00130 FOR_ALL_CARGOPACKETS(cp) {
00131 if (cp->source_type == src_type && cp->source_id == src) cp->source_id = INVALID_SOURCE;
00132 }
00133 }
00134
00139 void CargoPacket::InvalidateAllFrom(StationID sid)
00140 {
00141 CargoPacket *cp;
00142 FOR_ALL_CARGOPACKETS(cp) {
00143 if (cp->source == sid) cp->source = INVALID_STATION;
00144 }
00145 }
00146
00147
00148
00149
00150
00151
00152
00156 template <class Tinst, class Tcont>
00157 CargoList<Tinst, Tcont>::~CargoList()
00158 {
00159 for (Iterator it(this->packets.begin()); it != this->packets.end(); ++it) {
00160 delete *it;
00161 }
00162 }
00163
00168 template <class Tinst, class Tcont>
00169 void CargoList<Tinst, Tcont>::OnCleanPool()
00170 {
00171 this->packets.clear();
00172 }
00173
00180 template <class Tinst, class Tcont>
00181 void CargoList<Tinst, Tcont>::RemoveFromCache(const CargoPacket *cp, uint count)
00182 {
00183 assert(count <= cp->count);
00184 this->count -= count;
00185 this->cargo_days_in_transit -= cp->days_in_transit * count;
00186 }
00187
00193 template <class Tinst, class Tcont>
00194 void CargoList<Tinst, Tcont>::AddToCache(const CargoPacket *cp)
00195 {
00196 this->count += cp->count;
00197 this->cargo_days_in_transit += cp->days_in_transit * cp->count;
00198 }
00199
00201 template <class Tinst, class Tcont>
00202 void CargoList<Tinst, Tcont>::InvalidateCache()
00203 {
00204 this->count = 0;
00205 this->cargo_days_in_transit = 0;
00206
00207 for (ConstIterator it(this->packets.begin()); it != this->packets.end(); it++) {
00208 static_cast<Tinst *>(this)->AddToCache(*it);
00209 }
00210 }
00211
00219 template <class Tinst, class Tcont>
00220 bool CargoList<Tinst, Tcont>::TryMerge(CargoPacket *icp, CargoPacket *cp)
00221 {
00222 if (Tinst::AreMergable(icp, cp) &&
00223 icp->count + cp->count <= CargoPacket::MAX_COUNT) {
00224 icp->Merge(cp);
00225 return true;
00226 } else {
00227 return false;
00228 }
00229 }
00230
00231
00232
00233
00234
00235
00236
00252 void VehicleCargoList::Append(CargoPacket *cp, MoveToAction action)
00253 {
00254 assert(cp != NULL);
00255 assert(action == MTA_LOAD ||
00256 (action == MTA_KEEP && this->action_counts[MTA_LOAD] == 0));
00257 this->AddToMeta(cp, action);
00258
00259 if (this->count == cp->count) {
00260 this->packets.push_back(cp);
00261 return;
00262 }
00263
00264 uint sum = cp->count;
00265 for (ReverseIterator it(this->packets.rbegin()); it != this->packets.rend(); it++) {
00266 CargoPacket *icp = *it;
00267 if (VehicleCargoList::TryMerge(icp, cp)) return;
00268 sum += icp->count;
00269 if (sum >= this->action_counts[action]) {
00270 this->packets.push_back(cp);
00271 return;
00272 }
00273 }
00274
00275 NOT_REACHED();
00276 }
00277
00286 template<class Taction>
00287 void VehicleCargoList::ShiftCargo(Taction action)
00288 {
00289 Iterator it(this->packets.begin());
00290 while (it != this->packets.end() && action.MaxMove() > 0) {
00291 CargoPacket *cp = *it;
00292 if (action(cp)) {
00293 it = this->packets.erase(it);
00294 } else {
00295 break;
00296 }
00297 }
00298 }
00299
00308 template<class Taction>
00309 void VehicleCargoList::PopCargo(Taction action)
00310 {
00311 if (this->packets.empty()) return;
00312 Iterator it(--(this->packets.end()));
00313 Iterator begin(this->packets.begin());
00314 while (action.MaxMove() > 0) {
00315 CargoPacket *cp = *it;
00316 if (action(cp)) {
00317 if (it != begin) {
00318 this->packets.erase(it--);
00319 } else {
00320 this->packets.erase(it);
00321 break;
00322 }
00323 } else {
00324 break;
00325 }
00326 }
00327 }
00328
00335 void VehicleCargoList::RemoveFromCache(const CargoPacket *cp, uint count)
00336 {
00337 this->feeder_share -= cp->FeederShare(count);
00338 this->Parent::RemoveFromCache(cp, count);
00339 }
00340
00346 void VehicleCargoList::AddToCache(const CargoPacket *cp)
00347 {
00348 this->feeder_share += cp->feeder_share;
00349 this->Parent::AddToCache(cp);
00350 }
00351
00358 void VehicleCargoList::RemoveFromMeta(const CargoPacket *cp, MoveToAction action, uint count)
00359 {
00360 this->AssertCountConsistency();
00361 this->RemoveFromCache(cp, count);
00362 this->action_counts[action] -= count;
00363 this->AssertCountConsistency();
00364 }
00365
00371 void VehicleCargoList::AddToMeta(const CargoPacket *cp, MoveToAction action)
00372 {
00373 this->AssertCountConsistency();
00374 this->AddToCache(cp);
00375 this->action_counts[action] += cp->count;
00376 this->AssertCountConsistency();
00377 }
00378
00382 void VehicleCargoList::AgeCargo()
00383 {
00384 for (ConstIterator it(this->packets.begin()); it != this->packets.end(); it++) {
00385 CargoPacket *cp = *it;
00386
00387 if (cp->days_in_transit == 0xFF) continue;
00388
00389 cp->days_in_transit++;
00390 this->cargo_days_in_transit += cp->count;
00391 }
00392 }
00393
00401 void VehicleCargoList::SetTransferLoadPlace(TileIndex xy)
00402 {
00403 uint sum = 0;
00404 for (Iterator it = this->packets.begin(); sum < this->action_counts[MTA_TRANSFER]; ++it) {
00405 CargoPacket *cp = *it;
00406 cp->loaded_at_xy = xy;
00407 sum += cp->count;
00408 }
00409 }
00410
00424 bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationID next_station, uint8 order_flags, const GoodsEntry *ge, CargoPayment *payment)
00425 {
00426 this->AssertCountConsistency();
00427 assert(this->action_counts[MTA_LOAD] == 0);
00428 this->action_counts[MTA_TRANSFER] = this->action_counts[MTA_DELIVER] = this->action_counts[MTA_KEEP] = 0;
00429 Iterator deliver = this->packets.end();
00430 Iterator it = this->packets.begin();
00431 uint sum = 0;
00432
00433 bool force_keep = (order_flags & OUFB_NO_UNLOAD) != 0;
00434 bool force_unload = (order_flags & OUFB_UNLOAD) != 0;
00435 bool force_transfer = (order_flags & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0;
00436 assert(this->count > 0 || it == this->packets.end());
00437 while (sum < this->count) {
00438 CargoPacket *cp = *it;
00439
00440 this->packets.erase(it++);
00441 StationID cargo_next = INVALID_STATION;
00442 MoveToAction action = MTA_LOAD;
00443 if (force_keep) {
00444 action = MTA_KEEP;
00445 } else if (force_unload && accepted && cp->source != current_station) {
00446 action = MTA_DELIVER;
00447 } else if (force_transfer) {
00448 action = MTA_TRANSFER;
00449 cargo_next = ge->GetVia(cp->source, current_station, next_station);
00450 assert((cargo_next != next_station || cargo_next == INVALID_STATION) &&
00451 cargo_next != current_station);
00452 } else {
00453 cargo_next = ge->GetVia(cp->source);
00454 if (cargo_next == INVALID_STATION) {
00455 action = (accepted && cp->source != current_station) ? MTA_DELIVER : MTA_KEEP;
00456 } else if (cargo_next == current_station) {
00457 action = MTA_DELIVER;
00458 } else if (cargo_next == next_station) {
00459 action = MTA_KEEP;
00460 } else {
00461 action = MTA_TRANSFER;
00462 }
00463 }
00464 switch (action) {
00465 case MTA_KEEP:
00466 this->packets.push_back(cp);
00467 if (deliver == this->packets.end()) --deliver;
00468 break;
00469 case MTA_DELIVER:
00470 this->packets.insert(deliver, cp);
00471 break;
00472 case MTA_TRANSFER:
00473 this->packets.push_front(cp);
00474 cp->feeder_share += payment->PayTransfer(cp, cp->count);
00475 cp->next_station = cargo_next;
00476 break;
00477 default:
00478 NOT_REACHED();
00479 }
00480 this->action_counts[action] += cp->count;
00481 sum += cp->count;
00482 }
00483 this->AssertCountConsistency();
00484 return this->action_counts[MTA_DELIVER] > 0 || this->action_counts[MTA_TRANSFER] > 0;
00485 }
00486
00488 void VehicleCargoList::InvalidateCache()
00489 {
00490 this->feeder_share = 0;
00491 this->Parent::InvalidateCache();
00492 }
00493
00501 uint VehicleCargoList::Reassign(uint max_move, MoveToAction from, MoveToAction to)
00502 {
00503 max_move = min(this->action_counts[from], max_move);
00504 assert(Delta((int)from, (int)to) == 1);
00505 this->action_counts[from] -= max_move;
00506 this->action_counts[to] += max_move;
00507 return max_move;
00508 }
00509
00517 uint VehicleCargoList::Return(uint max_move, StationCargoList *dest, StationID next)
00518 {
00519 max_move = min(this->action_counts[MTA_LOAD], max_move);
00520 this->PopCargo(CargoReturn(this, dest, max_move, next));
00521 return max_move;
00522 }
00523
00530 uint VehicleCargoList::Shift(uint max_move, VehicleCargoList *dest)
00531 {
00532 max_move = min(this->count, max_move);
00533 this->PopCargo(CargoShift(this, dest, max_move));
00534 return max_move;
00535 }
00536
00545 uint VehicleCargoList::Unload(uint max_move, StationCargoList *dest, CargoPayment *payment)
00546 {
00547 uint moved = 0;
00548 if (this->action_counts[MTA_TRANSFER] > 0) {
00549 uint move = min(this->action_counts[MTA_TRANSFER], max_move);
00550 this->ShiftCargo(CargoTransfer(this, dest, move, payment));
00551 moved += move;
00552 }
00553 if (this->action_counts[MTA_TRANSFER] == 0 && this->action_counts[MTA_DELIVER] > 0 && moved < max_move) {
00554 uint move = min(this->action_counts[MTA_DELIVER], max_move - moved);
00555 this->ShiftCargo(CargoDelivery(this, move, payment));
00556 moved += move;
00557 }
00558 return moved;
00559 }
00560
00567 uint VehicleCargoList::Truncate(uint max_move)
00568 {
00569 max_move = min(this->count, max_move);
00570 this->PopCargo(CargoRemoval<VehicleCargoList>(this, max_move));
00571 return max_move;
00572 }
00573
00574
00575
00576
00577
00578
00579
00588 void StationCargoList::Append(CargoPacket *cp, StationID next)
00589 {
00590 assert(cp != NULL);
00591 this->AddToCache(cp);
00592
00593 StationCargoPacketMap::List &list = this->packets[next];
00594 for (StationCargoPacketMap::List::reverse_iterator it(list.rbegin());
00595 it != list.rend(); it++) {
00596 if (StationCargoList::TryMerge(*it, cp)) return;
00597 }
00598
00599
00600 list.push_back(cp);
00601 }
00602
00615 template <class Taction>
00616 bool StationCargoList::ShiftCargo(Taction &action, StationID next)
00617 {
00618 std::pair<Iterator, Iterator> range(this->packets.equal_range(next));
00619 for (Iterator it(range.first); action.MaxMove() > 0 && it != range.second && it.GetKey() == next;) {
00620 CargoPacket *cp = *it;
00621 if (action(cp)) {
00622 it = this->packets.erase(it);
00623 } else {
00624 return false;
00625 }
00626 }
00627 return true;
00628 }
00629
00644 template <class Taction>
00645 uint StationCargoList::ShiftCargo(Taction action, StationID next, bool include_invalid)
00646 {
00647 uint max_move = action.MaxMove();
00648 if (this->ShiftCargo(action, next) && include_invalid && action.MaxMove() > 0) {
00649 this->ShiftCargo(action, INVALID_STATION);
00650 }
00651 return max_move - action.MaxMove();
00652 }
00653
00662 uint StationCargoList::Truncate(uint max_move, StationCargoAmountMap *cargo_per_source)
00663 {
00664 max_move = min(max_move, this->count);
00665 uint prev_count = this->count;
00666 uint moved = 0;
00667 uint loop = 0;
00668 bool do_count = cargo_per_source != NULL;
00669 while (max_move > moved) {
00670 for (Iterator it(this->packets.begin()); it != this->packets.end();) {
00671 CargoPacket *cp = *it;
00672 if (prev_count > max_move && RandomRange(prev_count) < prev_count - max_move) {
00673 if (do_count && loop == 0) {
00674 (*cargo_per_source)[cp->source] += cp->count;
00675 }
00676 ++it;
00677 continue;
00678 }
00679 uint diff = max_move - moved;
00680 if (cp->count > diff) {
00681 if (diff > 0) {
00682 this->RemoveFromCache(cp, diff);
00683 cp->Reduce(diff);
00684 moved += diff;
00685 }
00686 if (loop > 0) {
00687 if (do_count) (*cargo_per_source)[cp->source] -= diff;
00688 return moved;
00689 } else {
00690 if (do_count) (*cargo_per_source)[cp->source] += cp->count;
00691 ++it;
00692 }
00693 } else {
00694 it = this->packets.erase(it);
00695 if (do_count && loop > 0) {
00696 (*cargo_per_source)[cp->source] -= cp->count;
00697 }
00698 moved += cp->count;
00699 this->RemoveFromCache(cp, cp->count);
00700 delete cp;
00701 }
00702 }
00703 loop++;
00704 }
00705 return moved;
00706 }
00707
00715 uint StationCargoList::Reserve(uint max_move, VehicleCargoList *dest, TileIndex load_place, StationID next)
00716 {
00717 max_move = min(this->count, max_move);
00718 this->ShiftCargo(CargoReservation(this, dest, max_move, load_place), next, true);
00719 return max_move;
00720 }
00721
00729 uint StationCargoList::Load(uint max_move, VehicleCargoList *dest, TileIndex load_place, StationID next_station)
00730 {
00731 uint move = min(dest->ActionCount(VehicleCargoList::MTA_LOAD), max_move);
00732 if (move > 0) {
00733 this->reserved_count -= move;
00734 dest->Reassign(move, VehicleCargoList::MTA_LOAD, VehicleCargoList::MTA_KEEP);
00735 return move;
00736 } else {
00737 move = min(this->count, max_move);
00738 return this->ShiftCargo(CargoLoad(this, dest, move, load_place), next_station, true);
00739 }
00740 }
00741
00750 uint StationCargoList::Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge)
00751 {
00752 return this->ShiftCargo(CargoReroute(this, dest, max_move, avoid, avoid2, ge), avoid, false);
00753 }
00754
00755
00756
00757
00758 template class CargoList<VehicleCargoList, CargoPacketList>;
00759 template class CargoList<StationCargoList, StationCargoPacketMap>;