00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "core/pool_func.hpp"
00014 #include "economy_base.h"
00015 #include "station_base.h"
00016 #include "cargodest_func.h"
00017 #include "cargodest_base.h"
00018 #include "settings_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 this->dest_xy = INVALID_TILE;
00032 this->dest_id = INVALID_SOURCE;
00033 this->dest_type = ST_INDUSTRY;
00034 this->flags = 0;
00035 this->next_order = INVALID_ORDER;
00036 this->next_station = INVALID_STATION;
00037 }
00038
00056 CargoPacket::CargoPacket(StationID source, TileIndex source_xy, uint16 count, SourceType source_type, SourceID source_id, TileIndex dest_xy, SourceType dest_type, SourceID dest_id, OrderID next_order, StationID next_station, byte flags) :
00057 feeder_share(0),
00058 count(count),
00059 days_in_transit(0),
00060 source_id(source_id),
00061 source(source),
00062 source_xy(source_xy),
00063 loaded_at_xy(0),
00064 dest_xy(dest_xy),
00065 dest_id(dest_id),
00066 flags(flags),
00067 next_order(next_order),
00068 next_station(next_station)
00069 {
00070 assert(count != 0);
00071 this->source_type = source_type;
00072 this->dest_type = dest_type;
00073 }
00074
00095 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, TileIndex dest_xy, SourceType dest_type, SourceID dest_id, OrderID next_order, StationID next_station, byte flags) :
00096 feeder_share(feeder_share),
00097 count(count),
00098 days_in_transit(days_in_transit),
00099 source_id(source_id),
00100 source(source),
00101 source_xy(source_xy),
00102 loaded_at_xy(loaded_at_xy),
00103 dest_xy(dest_xy),
00104 dest_id(dest_id),
00105 flags(flags),
00106 next_order(next_order),
00107 next_station(next_station)
00108 {
00109 assert(count != 0);
00110 this->source_type = source_type;
00111 this->dest_type = dest_type;
00112 }
00113
00119 FORCEINLINE CargoPacket *CargoPacket::Split(uint new_size)
00120 {
00121 if (!CargoPacket::CanAllocateItem()) return NULL;
00122
00123 Money fs = this->feeder_share * new_size / static_cast<uint>(this->count);
00124 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, this->dest_xy, this->dest_type, this->dest_id, this->next_order, this->next_station, this->flags);
00125 this->feeder_share -= fs;
00126 this->count -= new_size;
00127 return cp_new;
00128 }
00129
00134 FORCEINLINE void CargoPacket::Merge(CargoPacket *cp)
00135 {
00136 this->count += cp->count;
00137 this->feeder_share += cp->feeder_share;
00138 delete cp;
00139 }
00140
00146 void CargoPacket::InvalidateAllFrom(SourceType src_type, SourceID src)
00147 {
00148
00149 StationCargoList::InvalidateAllTo(src_type, src);
00150
00151 CargoPacket *cp;
00152 FOR_ALL_CARGOPACKETS(cp) {
00153 if (cp->source_type == src_type && cp->source_id == src) cp->source_id = INVALID_SOURCE;
00154 if (cp->dest_type == src_type && cp->dest_id == src) {
00155 cp->dest_id = INVALID_SOURCE;
00156 cp->dest_xy = INVALID_TILE;
00157 }
00158 }
00159 }
00160
00165 void CargoPacket::InvalidateAllFrom(StationID sid)
00166 {
00167 CargoPacket *cp;
00168 FOR_ALL_CARGOPACKETS(cp) {
00169 if (cp->source == sid) cp->source = INVALID_STATION;
00170 if (cp->next_station == sid) cp->next_station = INVALID_STATION;
00171 }
00172 }
00173
00174
00175
00176
00177
00178
00179
00183 template <class Tinst>
00184 CargoList<Tinst>::~CargoList()
00185 {
00186 for (Iterator it(this->packets.begin()); it != this->packets.end(); ++it) {
00187 delete *it;
00188 }
00189 }
00190
00195 template <class Tinst>
00196 void CargoList<Tinst>::OnCleanPool()
00197 {
00198 this->packets.clear();
00199 }
00200
00206 template <class Tinst>
00207 void CargoList<Tinst>::RemoveFromCache(const CargoPacket *cp)
00208 {
00209 this->count -= cp->count;
00210 this->cargo_days_in_transit -= cp->days_in_transit * cp->count;
00211 }
00212
00218 template <class Tinst>
00219 void CargoList<Tinst>::AddToCache(const CargoPacket *cp)
00220 {
00221 this->count += cp->count;
00222 this->cargo_days_in_transit += cp->days_in_transit * cp->count;
00223 }
00224
00233 template <class Tinst>
00234 void CargoList<Tinst>::Append(CargoPacket *cp)
00235 {
00236 assert(cp != NULL);
00237 static_cast<Tinst *>(this)->AddToCache(cp);
00238
00239 for (List::reverse_iterator it(this->packets.rbegin()); it != this->packets.rend(); it++) {
00240 CargoPacket *icp = *it;
00241 if (Tinst::AreMergable(icp, cp) && icp->count + cp->count <= CargoPacket::MAX_COUNT) {
00242 icp->Merge(cp);
00243 return;
00244 }
00245 }
00246
00247
00248 this->packets.push_back(cp);
00249 }
00250
00256 template <class Tinst>
00257 void CargoList<Tinst>::Truncate(uint max_remaining)
00258 {
00259 for (Iterator it(packets.begin()); it != packets.end(); ) {
00260 CargoPacket *cp = *it;
00261 if (max_remaining == 0) {
00262
00263 this->packets.erase(it++);
00264 static_cast<Tinst *>(this)->RemoveFromCache(cp);
00265 delete cp;
00266 continue;
00267 }
00268
00269 uint local_count = cp->count;
00270 if (local_count > max_remaining) {
00271 uint diff = local_count - max_remaining;
00272 this->count -= diff;
00273 this->cargo_days_in_transit -= cp->days_in_transit * diff;
00274 static_cast<Tinst *>(this)->RemoveFromCacheLocal(cp, diff);
00275 cp->count = max_remaining;
00276 max_remaining = 0;
00277 } else {
00278 max_remaining -= local_count;
00279 }
00280 ++it;
00281 }
00282 }
00283
00305 template <class Tinst>
00306 template <class Tother_inst>
00307 bool CargoList<Tinst>::MoveTo(Tother_inst *dest, uint max_move, MoveToAction mta, CargoPayment *payment, StationID st, OrderID cur_order, CargoID cid, bool *did_transfer)
00308 {
00309 assert(mta == MTA_FINAL_DELIVERY || dest != NULL);
00310 assert(mta == MTA_UNLOAD || mta == MTA_CARGO_LOAD || payment != NULL);
00311 assert(st != INVALID_STATION || (mta != MTA_CARGO_LOAD && payment == NULL));
00312
00313 restart:;
00314 Iterator it(this->packets.begin());
00315 while (it != this->packets.end() && max_move > 0) {
00316 CargoPacket *cp = *it;
00317 MoveToAction cp_mta = mta;
00318 OrderID current_next_order = cp->NextHop();
00319 StationID current_next_unload = cp->NextStation();
00320
00321 if (cp_mta == MTA_CARGO_LOAD) {
00322
00323 if (current_next_order == INVALID_ORDER && cp->DestinationID() != INVALID_SOURCE) {
00324 if (!this->UpdateCargoNextHop(cp, Station::Get(st), cid)) {
00325
00326 it = this->packets.erase(it);
00327 continue;
00328 }
00329 current_next_order = cp->NextHop();
00330 current_next_unload = cp->NextStation();
00331 }
00332
00333
00334 if (current_next_order != cur_order) {
00335 ++it;
00336 continue;
00337 }
00338 }
00339
00340
00341 if (cp->DestinationID() != INVALID_SOURCE && cp_mta != MTA_CARGO_LOAD && payment != NULL) {
00342
00343 if (cp_mta != MTA_UNLOAD && cp->NextStation() != INVALID_STATION && cp->NextStation() != st) {
00344 ++it;
00345 continue;
00346 }
00347
00348 Station *station = Station::Get(st);
00349
00350 bool found;
00351 StationID next_unload;
00352 RouteLink *link = FindRouteLinkForCargo(station, cid, cp, &next_unload, cur_order, &found);
00353 if (!found) {
00354
00355 static_cast<Tinst *>(this)->RemoveFromCache(cp);
00356 delete cp;
00357 it = this->packets.erase(it);
00358 continue;
00359 }
00360
00361 if (link != NULL) {
00362
00363 if (link->GetOriginOrderId() == cur_order && cp_mta != MTA_UNLOAD) {
00364
00365 ++it;
00366 continue;
00367 }
00368
00369 cp_mta = MTA_TRANSFER;
00370 current_next_order = link->GetOriginOrderId();
00371 current_next_unload = next_unload;
00372 } else {
00373
00374 cp_mta = MTA_FINAL_DELIVERY;
00375 }
00376 } else if (cp_mta == MTA_NO_ACTION || (cp->source == st && cp_mta == MTA_FINAL_DELIVERY)) {
00377
00378 ++it;
00379 continue;
00380 }
00381
00382 if (did_transfer != NULL && cp_mta == MTA_TRANSFER) *did_transfer = true;
00383
00384 if (cp->count <= max_move) {
00385
00386 max_move -= cp->count;
00387 this->packets.erase(it++);
00388 static_cast<Tinst *>(this)->RemoveFromCache(cp);
00389 cp->next_order = current_next_order;
00390 cp->next_station = current_next_unload;
00391 switch (cp_mta) {
00392 case MTA_FINAL_DELIVERY:
00393 payment->PayFinalDelivery(cp, cp->count);
00394 delete cp;
00395 continue;
00396
00397 case MTA_CARGO_LOAD:
00398 cp->loaded_at_xy = Station::Get(st)->xy;
00399 break;
00400
00401 case MTA_TRANSFER:
00402 cp->feeder_share += payment->PayTransfer(cp, cp->count);
00403 break;
00404
00405 default:
00406 break;
00407 }
00408 dest->Append(cp);
00409 continue;
00410 }
00411
00412
00413 if (cp_mta == MTA_FINAL_DELIVERY) {
00414
00415 payment->PayFinalDelivery(cp, max_move);
00416
00417
00418 uint left = cp->count - max_move;
00419 cp->count = max_move;
00420 static_cast<Tinst *>(this)->RemoveFromCache(cp);
00421
00422
00423
00424 cp->feeder_share = 0;
00425 cp->count = left;
00426 } else {
00427
00428 CargoPacket *cp_new = cp->Split(max_move);
00429
00430
00431 if (cp_new == NULL) return false;
00432
00433 static_cast<Tinst *>(this)->RemoveFromCache(cp_new);
00434 cp_new->next_order = current_next_order;
00435 cp_new->next_station = current_next_unload;
00436
00437 if (cp_mta == MTA_TRANSFER) {
00438
00439 cp_new->feeder_share += payment->PayTransfer(cp_new, max_move);
00440 } else if (cp_mta == MTA_CARGO_LOAD) {
00441 cp_new->loaded_at_xy = Station::Get(st)->xy;
00442 }
00443
00444 dest->Append(cp_new);
00445 }
00446
00447 max_move = 0;
00448 }
00449
00450 if (max_move > 0 && mta == MTA_CARGO_LOAD && cur_order != INVALID_ORDER && Station::Get(st)->goods[cid].cargo.CountForNextHop(INVALID_ORDER) > 0) {
00451
00452 cur_order = INVALID_ORDER;
00453 goto restart;
00454 }
00455
00456 return it != packets.end();
00457 }
00458
00460 template <class Tinst>
00461 void CargoList<Tinst>::InvalidateCache()
00462 {
00463 this->count = 0;
00464 this->cargo_days_in_transit = 0;
00465
00466 for (ConstIterator it(this->packets.begin()); it != this->packets.end(); it++) {
00467 static_cast<Tinst *>(this)->AddToCache(*it);
00468 }
00469 }
00470
00476 void VehicleCargoList::RemoveFromCache(const CargoPacket *cp)
00477 {
00478 this->feeder_share -= cp->feeder_share;
00479 this->Parent::RemoveFromCache(cp);
00480 }
00481
00487 void VehicleCargoList::AddToCache(const CargoPacket *cp)
00488 {
00489 this->feeder_share += cp->feeder_share;
00490 this->Parent::AddToCache(cp);
00491 }
00492
00496 void VehicleCargoList::AgeCargo()
00497 {
00498 for (ConstIterator it(this->packets.begin()); it != this->packets.end(); it++) {
00499 CargoPacket *cp = *it;
00500
00501 if (cp->days_in_transit == 0xFF) continue;
00502
00503 cp->days_in_transit++;
00504 this->cargo_days_in_transit += cp->count;
00505 }
00506 }
00507
00509 void VehicleCargoList::InvalidateCache()
00510 {
00511 this->feeder_share = 0;
00512 this->Parent::InvalidateCache();
00513 }
00514
00516 void VehicleCargoList::InvalidateNextStation()
00517 {
00518 for (VehicleCargoList::ConstIterator it = this->packets.begin(); it != this->packets.end(); ++it) {
00519 (*it)->next_station = INVALID_STATION;
00520 }
00521 }
00522
00528 void StationCargoList::RemoveFromCacheLocal(const CargoPacket *cp, uint amount)
00529 {
00530 this->order_cache[cp->next_order] -= amount;
00531 if (this->order_cache[cp->next_order] == 0) this->order_cache.erase(cp->next_order);
00532 }
00533
00539 void StationCargoList::RemoveFromCache(const CargoPacket *cp)
00540 {
00541 this->RemoveFromCacheLocal(cp, cp->count);
00542 this->Parent::RemoveFromCache(cp);
00543 }
00544
00550 void StationCargoList::AddToCache(const CargoPacket *cp)
00551 {
00552 this->order_cache[cp->next_order] += cp->count;
00553 this->Parent::AddToCache(cp);
00554 }
00555
00557 void StationCargoList::InvalidateCache()
00558 {
00559 this->order_cache.clear();
00560 this->Parent::InvalidateCache();
00561 }
00562
00570 bool StationCargoList::UpdateCargoNextHop(CargoPacket *cp, Station *st, CargoID cid)
00571 {
00572 StationID next_unload;
00573 RouteLink *l = FindRouteLinkForCargo(st, cid, cp, &next_unload);
00574
00575 if (l == NULL) {
00576
00577 this->RemoveFromCache(cp);
00578 delete cp;
00579 return false;
00580 }
00581
00582
00583 this->RemoveFromCache(cp);
00584 cp->next_station = next_unload;
00585 cp->next_order = l->GetOriginOrderId();
00586 this->AddToCache(cp);
00587
00588 return true;
00589 }
00590
00596 void StationCargoList::UpdateCargoNextHop(Station *st, CargoID cid)
00597 {
00598 uint count = 0;
00599 StationCargoList::Iterator iter;
00600 for (iter = this->packets.begin(); count < this->next_start + _settings_game.economy.cargodest.route_recalc_chunk && iter != this->packets.end(); count++) {
00601 if (count < this->next_start) continue;
00602 if ((*iter)->DestinationID() != INVALID_SOURCE) {
00603 if (this->UpdateCargoNextHop(*iter, st, cid)) {
00604 ++iter;
00605 } else {
00606 iter = this->packets.erase(iter);
00607 }
00608 } else {
00609 ++iter;
00610 }
00611 }
00612
00613
00614 this->next_start = count;
00615 if (this->next_start >= this->packets.size()) this->next_start = 0;
00616 }
00617
00623 void StationCargoList::InvalidateAllTo(OrderID order, StationID st_unload)
00624 {
00625 Station *st;
00626 FOR_ALL_STATIONS(st) {
00627 for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
00628 for (StationCargoList::Iterator it = st->goods[cid].cargo.packets.begin(); it != st->goods[cid].cargo.packets.end(); ++it) {
00629 CargoPacket *cp = *it;
00630 if (cp->next_order == order || cp->next_station == st_unload) {
00631
00632
00633 st->goods[cid].cargo.RemoveFromCache(cp);
00634 cp->next_order = INVALID_ORDER;
00635 cp->next_station = INVALID_STATION;
00636 st->goods[cid].cargo.AddToCache(cp);
00637 }
00638 }
00639 }
00640 }
00641 }
00642
00647 void StationCargoList::InvalidateAllTo(SourceType type, SourceID dest)
00648 {
00649 Station *st;
00650 FOR_ALL_STATIONS(st) {
00651 for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
00652 for (StationCargoList::Iterator it = st->goods[cid].cargo.packets.begin(); it != st->goods[cid].cargo.packets.end(); ++it) {
00653 CargoPacket *cp = *it;
00654 if (cp->dest_id == dest && cp->dest_type == type) {
00655
00656
00657 st->goods[cid].cargo.RemoveFromCache(cp);
00658 cp->next_order = INVALID_ORDER;
00659 cp->next_station = INVALID_STATION;
00660 st->goods[cid].cargo.AddToCache(cp);
00661 }
00662 }
00663 }
00664 }
00665 }
00666
00667
00668
00669
00670 template class CargoList<VehicleCargoList>;
00671 template class CargoList<StationCargoList>;
00672
00674 template bool CargoList<VehicleCargoList>::MoveTo(VehicleCargoList *, uint max_move, MoveToAction mta, CargoPayment *payment, StationID st, OrderID cur_order, CargoID cid, bool *did_transfer);
00676 template bool CargoList<VehicleCargoList>::MoveTo(StationCargoList *, uint max_move, MoveToAction mta, CargoPayment *payment, StationID st, OrderID cur_order, CargoID cid, bool *did_transfer);
00678 template bool CargoList<StationCargoList>::MoveTo(VehicleCargoList *, uint max_move, MoveToAction mta, CargoPayment *payment, StationID st, OrderID cur_order, CargoID cid, bool *did_transfer);