1 /* 2 * This file is part of OpenTTD. 3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. 4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>. 6 */ 7 8 /** @file cargopacket.h Base class for cargo packets. */ 9 10 #ifndef CARGOPACKET_H 11 #define CARGOPACKET_H 12 13 #include "core/pool_type.hpp" 14 #include "economy_type.h" 15 #include "station_type.h" 16 #include "order_type.h" 17 #include "cargo_type.h" 18 #include "vehicle_type.h" 19 #include "core/multimap.hpp" 20 #include "saveload/saveload.h" 21 #include <list> 22 23 /** Unique identifier for a single cargo packet. */ 24 typedef uint32 CargoPacketID; 25 struct CargoPacket; 26 27 /** Type of the pool for cargo packets for a little over 16 million packets. */ 28 typedef Pool<CargoPacket, CargoPacketID, 1024, 0xFFF000, PT_NORMAL, true, false> CargoPacketPool; 29 /** The actual pool with cargo packets. */ 30 extern CargoPacketPool _cargopacket_pool; 31 32 struct GoodsEntry; // forward-declare for Stage() and RerouteStalePackets() 33 34 template <class Tinst, class Tcont> class CargoList; 35 class StationCargoList; // forward-declare, so we can use it in VehicleCargoList. 36 extern SaveLoadTable GetCargoPacketDesc(); 37 38 typedef uint32 TileOrStationID; 39 40 /** 41 * Container for cargo from the same location and time. 42 */ 43 struct CargoPacket : CargoPacketPool::PoolItem<&_cargopacket_pool> { 44 private: 45 Money feeder_share; ///< Value of feeder pickup to be paid for on delivery of cargo. 46 uint16 count; ///< The amount of cargo in this packet. 47 byte days_in_transit; ///< Amount of days this packet has been in transit. 48 SourceType source_type; ///< Type of \c source_id. 49 SourceID source_id; ///< Index of source, INVALID_SOURCE if unknown/invalid. 50 StationID source; ///< The station where the cargo came from first. 51 TileIndex source_xy; ///< The origin of the cargo (first station in feeder chain). 52 union { 53 TileOrStationID loaded_at_xy; ///< Location where this cargo has been loaded into the vehicle. 54 TileOrStationID next_station; ///< Station where the cargo wants to go next. 55 }; 56 57 /** The CargoList caches, thus needs to know about it. */ 58 template <class Tinst, class Tcont> friend class CargoList; 59 friend class VehicleCargoList; 60 friend class StationCargoList; 61 /** We want this to be saved, right? */ 62 friend SaveLoadTable GetCargoPacketDesc(); 63 public: 64 /** Maximum number of items in a single cargo packet. */ 65 static const uint16 MAX_COUNT = UINT16_MAX; 66 67 CargoPacket(); 68 CargoPacket(StationID source, TileIndex source_xy, uint16 count, SourceType source_type, SourceID source_id); 69 CargoPacket(uint16 count, byte days_in_transit, StationID source, TileIndex source_xy, TileIndex loaded_at_xy, Money feeder_share = 0, SourceType source_type = ST_INDUSTRY, SourceID source_id = INVALID_SOURCE); 70 71 /** Destroy the packet. */ ~CargoPacketCargoPacket72 ~CargoPacket() { } 73 74 CargoPacket *Split(uint new_size); 75 void Merge(CargoPacket *cp); 76 void Reduce(uint count); 77 78 /** 79 * Sets the tile where the packet was loaded last. 80 * @param load_place Tile where the packet was loaded last. 81 */ SetLoadPlaceCargoPacket82 void SetLoadPlace(TileIndex load_place) { this->loaded_at_xy = load_place; } 83 84 /** 85 * Sets the station where the packet is supposed to go next. 86 * @param next_station Next station the packet should go to. 87 */ SetNextStationCargoPacket88 void SetNextStation(StationID next_station) { this->next_station = next_station; } 89 90 /** 91 * Adds some feeder share to the packet. 92 * @param new_share Feeder share to be added. 93 */ AddFeederShareCargoPacket94 void AddFeederShare(Money new_share) { this->feeder_share += new_share; } 95 96 /** 97 * Gets the number of 'items' in this packet. 98 * @return Item count. 99 */ CountCargoPacket100 inline uint16 Count() const 101 { 102 return this->count; 103 } 104 105 /** 106 * Gets the amount of money already paid to earlier vehicles in 107 * the feeder chain. 108 * @return Feeder share. 109 */ FeederShareCargoPacket110 inline Money FeederShare() const 111 { 112 return this->feeder_share; 113 } 114 115 /** 116 * Gets part of the amount of money already paid to earlier vehicles in 117 * the feeder chain. 118 * @param part Amount of cargo to get the share for. 119 * @return Feeder share for the given amount of cargo. 120 */ FeederShareCargoPacket121 inline Money FeederShare(uint part) const 122 { 123 return this->feeder_share * part / static_cast<uint>(this->count); 124 } 125 126 /** 127 * Gets the number of days this cargo has been in transit. 128 * This number isn't really in days, but in 2.5 days (CARGO_AGING_TICKS = 185 ticks) and 129 * it is capped at 255. 130 * @return Length this cargo has been in transit. 131 */ DaysInTransitCargoPacket132 inline byte DaysInTransit() const 133 { 134 return this->days_in_transit; 135 } 136 137 /** 138 * Gets the type of the cargo's source. industry, town or head quarter. 139 * @return Source type. 140 */ SourceSubsidyTypeCargoPacket141 inline SourceType SourceSubsidyType() const 142 { 143 return this->source_type; 144 } 145 146 /** 147 * Gets the ID of the cargo's source. An IndustryID, TownID or CompanyID. 148 * @return Source ID. 149 */ SourceSubsidyIDCargoPacket150 inline SourceID SourceSubsidyID() const 151 { 152 return this->source_id; 153 } 154 155 /** 156 * Gets the ID of the station where the cargo was loaded for the first time. 157 * @return StationID. 158 */ SourceStationCargoPacket159 inline StationID SourceStation() const 160 { 161 return this->source; 162 } 163 164 /** 165 * Gets the coordinates of the cargo's source station. 166 * @return Source station's coordinates. 167 */ SourceStationXYCargoPacket168 inline TileIndex SourceStationXY() const 169 { 170 return this->source_xy; 171 } 172 173 /** 174 * Gets the coordinates of the cargo's last loading station. 175 * @return Last loading station's coordinates. 176 */ LoadedAtXYCargoPacket177 inline TileIndex LoadedAtXY() const 178 { 179 return this->loaded_at_xy; 180 } 181 182 /** 183 * Gets the ID of station the cargo wants to go next. 184 * @return Next station for this packets. 185 */ NextStationCargoPacket186 inline StationID NextStation() const 187 { 188 return this->next_station; 189 } 190 191 static void InvalidateAllFrom(SourceType src_type, SourceID src); 192 static void InvalidateAllFrom(StationID sid); 193 static void AfterLoad(); 194 }; 195 196 /** 197 * Simple collection class for a list of cargo packets. 198 * @tparam Tinst Actual instantiation of this cargo list. 199 */ 200 template <class Tinst, class Tcont> 201 class CargoList { 202 public: 203 /** The iterator for our container. */ 204 typedef typename Tcont::iterator Iterator; 205 /** The reverse iterator for our container. */ 206 typedef typename Tcont::reverse_iterator ReverseIterator; 207 /** The const iterator for our container. */ 208 typedef typename Tcont::const_iterator ConstIterator; 209 /** The const reverse iterator for our container. */ 210 typedef typename Tcont::const_reverse_iterator ConstReverseIterator; 211 212 /** Kind of actions that could be done with packets on move. */ 213 enum MoveToAction { 214 MTA_BEGIN = 0, 215 MTA_TRANSFER = 0, ///< Transfer the cargo to the station. 216 MTA_DELIVER, ///< Deliver the cargo to some town or industry. 217 MTA_KEEP, ///< Keep the cargo in the vehicle. 218 MTA_LOAD, ///< Load the cargo from the station. 219 MTA_END, 220 NUM_MOVE_TO_ACTION = MTA_END 221 }; 222 223 protected: 224 uint count; ///< Cache for the number of cargo entities. 225 uint cargo_days_in_transit; ///< Cache for the sum of number of days in transit of each entity; comparable to man-hours. 226 227 Tcont packets; ///< The cargo packets in this list. 228 229 void AddToCache(const CargoPacket *cp); 230 231 void RemoveFromCache(const CargoPacket *cp, uint count); 232 233 static bool TryMerge(CargoPacket *cp, CargoPacket *icp); 234 235 public: 236 /** Create the cargo list. */ CargoList()237 CargoList() {} 238 239 ~CargoList(); 240 241 void OnCleanPool(); 242 243 /** 244 * Returns a pointer to the cargo packet list (so you can iterate over it etc). 245 * @return Pointer to the packet list. 246 */ Packets()247 inline const Tcont *Packets() const 248 { 249 return &this->packets; 250 } 251 252 /** 253 * Returns average number of days in transit for a cargo entity. 254 * @return The before mentioned number. 255 */ DaysInTransit()256 inline uint DaysInTransit() const 257 { 258 return this->count == 0 ? 0 : this->cargo_days_in_transit / this->count; 259 } 260 261 void InvalidateCache(); 262 }; 263 264 typedef std::list<CargoPacket *> CargoPacketList; 265 266 /** 267 * CargoList that is used for vehicles. 268 */ 269 class VehicleCargoList : public CargoList<VehicleCargoList, CargoPacketList> { 270 protected: 271 /** The (direct) parent of this class. */ 272 typedef CargoList<VehicleCargoList, CargoPacketList> Parent; 273 274 Money feeder_share; ///< Cache for the feeder share. 275 uint action_counts[NUM_MOVE_TO_ACTION]; ///< Counts of cargo to be transferred, delivered, kept and loaded. 276 277 template<class Taction> 278 void ShiftCargo(Taction action); 279 280 template<class Taction> 281 void PopCargo(Taction action); 282 283 /** 284 * Assert that the designation counts add up. 285 */ AssertCountConsistency()286 inline void AssertCountConsistency() const 287 { 288 assert(this->action_counts[MTA_KEEP] + 289 this->action_counts[MTA_DELIVER] + 290 this->action_counts[MTA_TRANSFER] + 291 this->action_counts[MTA_LOAD] == this->count); 292 } 293 294 void AddToCache(const CargoPacket *cp); 295 void RemoveFromCache(const CargoPacket *cp, uint count); 296 297 void AddToMeta(const CargoPacket *cp, MoveToAction action); 298 void RemoveFromMeta(const CargoPacket *cp, MoveToAction action, uint count); 299 300 static MoveToAction ChooseAction(const CargoPacket *cp, StationID cargo_next, 301 StationID current_station, bool accepted, StationIDStack next_station); 302 303 public: 304 /** The station cargo list needs to control the unloading. */ 305 friend class StationCargoList; 306 /** The super class ought to know what it's doing. */ 307 friend class CargoList<VehicleCargoList, CargoPacketList>; 308 /* So we can use private/protected variables in the saveload code */ 309 friend class SlVehicleCommon; 310 311 friend class CargoShift; 312 friend class CargoTransfer; 313 friend class CargoDelivery; 314 template<class Tsource> 315 friend class CargoRemoval; 316 friend class CargoReturn; 317 friend class VehicleCargoReroute; 318 319 /** 320 * Returns source of the first cargo packet in this list. 321 * @return The before mentioned source. 322 */ Source()323 inline StationID Source() const 324 { 325 return this->count == 0 ? INVALID_STATION : this->packets.front()->source; 326 } 327 328 /** 329 * Returns total sum of the feeder share for all packets. 330 * @return The before mentioned number. 331 */ FeederShare()332 inline Money FeederShare() const 333 { 334 return this->feeder_share; 335 } 336 337 /** 338 * Returns the amount of cargo designated for a given purpose. 339 * @param action Action the cargo is designated for. 340 * @return Amount of cargo designated for the given action. 341 */ ActionCount(MoveToAction action)342 inline uint ActionCount(MoveToAction action) const 343 { 344 return this->action_counts[action]; 345 } 346 347 /** 348 * Returns sum of cargo on board the vehicle (ie not only 349 * reserved). 350 * @return Cargo on board the vehicle. 351 */ StoredCount()352 inline uint StoredCount() const 353 { 354 return this->count - this->action_counts[MTA_LOAD]; 355 } 356 357 /** 358 * Returns sum of cargo, including reserved cargo. 359 * @return Sum of cargo. 360 */ TotalCount()361 inline uint TotalCount() const 362 { 363 return this->count; 364 } 365 366 /** 367 * Returns sum of reserved cargo. 368 * @return Sum of reserved cargo. 369 */ ReservedCount()370 inline uint ReservedCount() const 371 { 372 return this->action_counts[MTA_LOAD]; 373 } 374 375 /** 376 * Returns sum of cargo to be moved out of the vehicle at the current station. 377 * @return Cargo to be moved. 378 */ UnloadCount()379 inline uint UnloadCount() const 380 { 381 return this->action_counts[MTA_TRANSFER] + this->action_counts[MTA_DELIVER]; 382 } 383 384 /** 385 * Returns the sum of cargo to be kept in the vehicle at the current station. 386 * @return Cargo to be kept or loaded. 387 */ RemainingCount()388 inline uint RemainingCount() const 389 { 390 return this->action_counts[MTA_KEEP] + this->action_counts[MTA_LOAD]; 391 } 392 393 void Append(CargoPacket *cp, MoveToAction action = MTA_KEEP); 394 395 void AgeCargo(); 396 397 void InvalidateCache(); 398 399 void SetTransferLoadPlace(TileIndex xy); 400 401 bool Stage(bool accepted, StationID current_station, StationIDStack next_station, uint8 order_flags, const GoodsEntry *ge, CargoPayment *payment); 402 403 /** 404 * Marks all cargo in the vehicle as to be kept. This is mostly useful for 405 * loading old savegames. When loading is aborted the reserved cargo has 406 * to be returned first. 407 */ KeepAll()408 inline void KeepAll() 409 { 410 this->action_counts[MTA_DELIVER] = this->action_counts[MTA_TRANSFER] = this->action_counts[MTA_LOAD] = 0; 411 this->action_counts[MTA_KEEP] = this->count; 412 } 413 414 /* Methods for moving cargo around. First parameter is always maximum 415 * amount of cargo to be moved. Second parameter is destination (if 416 * applicable), return value is amount of cargo actually moved. */ 417 418 template<MoveToAction Tfrom, MoveToAction Tto> 419 uint Reassign(uint max_move, TileOrStationID update = INVALID_TILE); 420 uint Return(uint max_move, StationCargoList *dest, StationID next_station); 421 uint Unload(uint max_move, StationCargoList *dest, CargoPayment *payment); 422 uint Shift(uint max_move, VehicleCargoList *dest); 423 uint Truncate(uint max_move = UINT_MAX); 424 uint Reroute(uint max_move, VehicleCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge); 425 426 /** 427 * Are the two CargoPackets mergeable in the context of 428 * a list of CargoPackets for a Vehicle? 429 * @param cp1 First CargoPacket. 430 * @param cp2 Second CargoPacket. 431 * @return True if they are mergeable. 432 */ AreMergable(const CargoPacket * cp1,const CargoPacket * cp2)433 static bool AreMergable(const CargoPacket *cp1, const CargoPacket *cp2) 434 { 435 return cp1->source_xy == cp2->source_xy && 436 cp1->days_in_transit == cp2->days_in_transit && 437 cp1->source_type == cp2->source_type && 438 cp1->source_id == cp2->source_id && 439 cp1->loaded_at_xy == cp2->loaded_at_xy; 440 } 441 }; 442 443 typedef MultiMap<StationID, CargoPacket *> StationCargoPacketMap; 444 typedef std::map<StationID, uint> StationCargoAmountMap; 445 446 /** 447 * CargoList that is used for stations. 448 */ 449 class StationCargoList : public CargoList<StationCargoList, StationCargoPacketMap> { 450 protected: 451 /** The (direct) parent of this class. */ 452 typedef CargoList<StationCargoList, StationCargoPacketMap> Parent; 453 454 uint reserved_count; ///< Amount of cargo being reserved for loading. 455 456 public: 457 /** The super class ought to know what it's doing. */ 458 friend class CargoList<StationCargoList, StationCargoPacketMap>; 459 /* So we can use private/protected variables in the saveload code */ 460 friend class SlStationGoods; 461 462 friend class CargoLoad; 463 friend class CargoTransfer; 464 template<class Tsource> 465 friend class CargoRemoval; 466 friend class CargoReservation; 467 friend class CargoReturn; 468 friend class StationCargoReroute; 469 470 static void InvalidateAllFrom(SourceType src_type, SourceID src); 471 472 template<class Taction> 473 bool ShiftCargo(Taction &action, StationID next); 474 475 template<class Taction> 476 uint ShiftCargo(Taction action, StationIDStack next, bool include_invalid); 477 478 void Append(CargoPacket *cp, StationID next); 479 480 /** 481 * Check for cargo headed for a specific station. 482 * @param next Station the cargo is headed for. 483 * @return If there is any cargo for that station. 484 */ HasCargoFor(StationIDStack next)485 inline bool HasCargoFor(StationIDStack next) const 486 { 487 while (!next.IsEmpty()) { 488 if (this->packets.find(next.Pop()) != this->packets.end()) return true; 489 } 490 /* Packets for INVALID_STATION can go anywhere. */ 491 return this->packets.find(INVALID_STATION) != this->packets.end(); 492 } 493 494 /** 495 * Returns source of the first cargo packet in this list. 496 * @return The before mentioned source. 497 */ Source()498 inline StationID Source() const 499 { 500 return this->count == 0 ? INVALID_STATION : this->packets.begin()->second.front()->source; 501 } 502 503 /** 504 * Returns sum of cargo still available for loading at the sation. 505 * (i.e. not counting cargo which is already reserved for loading) 506 * @return Cargo on board the vehicle. 507 */ AvailableCount()508 inline uint AvailableCount() const 509 { 510 return this->count; 511 } 512 513 /** 514 * Returns sum of cargo reserved for loading onto vehicles. 515 * @return Cargo reserved for loading. 516 */ ReservedCount()517 inline uint ReservedCount() const 518 { 519 return this->reserved_count; 520 } 521 522 /** 523 * Returns total count of cargo at the station, including 524 * cargo which is already reserved for loading. 525 * @return Total cargo count. 526 */ TotalCount()527 inline uint TotalCount() const 528 { 529 return this->count + this->reserved_count; 530 } 531 532 /* Methods for moving cargo around. First parameter is always maximum 533 * amount of cargo to be moved. Second parameter is destination (if 534 * applicable), return value is amount of cargo actually moved. */ 535 536 uint Reserve(uint max_move, VehicleCargoList *dest, TileIndex load_place, StationIDStack next); 537 uint Load(uint max_move, VehicleCargoList *dest, TileIndex load_place, StationIDStack next); 538 uint Truncate(uint max_move = UINT_MAX, StationCargoAmountMap *cargo_per_source = nullptr); 539 uint Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge); 540 541 /** 542 * Are the two CargoPackets mergeable in the context of 543 * a list of CargoPackets for a Station? 544 * @param cp1 First CargoPacket. 545 * @param cp2 Second CargoPacket. 546 * @return True if they are mergeable. 547 */ AreMergable(const CargoPacket * cp1,const CargoPacket * cp2)548 static bool AreMergable(const CargoPacket *cp1, const CargoPacket *cp2) 549 { 550 return cp1->source_xy == cp2->source_xy && 551 cp1->days_in_transit == cp2->days_in_transit && 552 cp1->source_type == cp2->source_type && 553 cp1->source_id == cp2->source_id; 554 } 555 }; 556 557 #endif /* CARGOPACKET_H */ 558