4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
10 /** @file cargopacket.cpp Implementation of the cargo packets. */
13 #include "core/pool_func.hpp"
14 #include "economy_base.h"
16 /* Initialize the cargopacket-pool */
17 CargoPacketPool
_cargopacket_pool("CargoPacket");
18 INSTANTIATE_POOL_METHODS(CargoPacket
)
21 * Create a new packet for savegame loading.
23 CargoPacket::CargoPacket()
25 this->source_type
= ST_INDUSTRY
;
26 this->source_id
= INVALID_SOURCE
;
30 * Creates a new cargo packet.
31 * @param source Source station of the packet.
32 * @param source_xy Source location of the packet.
33 * @param count Number of cargo entities to put in this packet.
34 * @param source_type 'Type' of source the packet comes from (for subsidies).
35 * @param source_id Actual source of the packet (for subsidies).
37 * @note We have to zero memory ourselves here because we are using a 'new'
38 * that, in contrary to all other pools, does not memset to 0.
40 CargoPacket::CargoPacket(StationID source
, TileIndex source_xy
, uint16 count
, SourceType source_type
, SourceID source_id
) :
50 this->source_type
= source_type
;
54 * Creates a new cargo packet. Initializes the fields that cannot be changed later.
55 * Used when loading or splitting packets.
56 * @param count Number of cargo entities to put in this packet.
57 * @param days_in_transit Number of days the cargo has been in transit.
58 * @param source Station the cargo was initially loaded.
59 * @param source_xy Station location the cargo was initially loaded.
60 * @param loaded_at_xy Location the cargo was loaded last.
61 * @param feeder_share Feeder share the packet has already accumulated.
62 * @param source_type 'Type' of source the packet comes from (for subsidies).
63 * @param source_id Actual source of the packet (for subsidies).
64 * @note We have to zero memory ourselves here because we are using a 'new'
65 * that, in contrary to all other pools, does not memset to 0.
67 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
) :
68 feeder_share(feeder_share
),
70 days_in_transit(days_in_transit
),
74 loaded_at_xy(loaded_at_xy
)
77 this->source_type
= source_type
;
81 * Split this packet in two and return the split off part.
82 * @param new_size Size of the remaining part.
83 * @return Split off part, or NULL if no packet could be allocated!
85 FORCEINLINE CargoPacket
*CargoPacket::Split(uint new_size
)
87 if (!CargoPacket::CanAllocateItem()) return NULL
;
89 Money fs
= this->feeder_share
* new_size
/ static_cast<uint
>(this->count
);
90 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
);
91 this->feeder_share
-= fs
;
92 this->count
-= new_size
;
97 * Merge another packet into this one.
98 * @param cp Packet to be merged in.
100 FORCEINLINE
void CargoPacket::Merge(CargoPacket
*cp
)
102 this->count
+= cp
->count
;
103 this->feeder_share
+= cp
->feeder_share
;
108 * Invalidates (sets source_id to INVALID_SOURCE) all cargo packets from given source.
109 * @param src_type Type of source.
110 * @param src Index of source.
112 /* static */ void CargoPacket::InvalidateAllFrom(SourceType src_type
, SourceID src
)
115 FOR_ALL_CARGOPACKETS(cp
) {
116 if (cp
->source_type
== src_type
&& cp
->source_id
== src
) cp
->source_id
= INVALID_SOURCE
;
121 * Invalidates (sets source to INVALID_STATION) all cargo packets from given station.
122 * @param sid Station that gets removed.
124 /* static */ void CargoPacket::InvalidateAllFrom(StationID sid
)
127 FOR_ALL_CARGOPACKETS(cp
) {
128 if (cp
->source
== sid
) cp
->source
= INVALID_STATION
;
134 * Cargo list implementation
139 * Destroy the cargolist ("frees" all cargo packets).
141 template <class Tinst
>
142 CargoList
<Tinst
>::~CargoList()
144 for (Iterator
it(this->packets
.begin()); it
!= this->packets
.end(); ++it
) {
150 * Empty the cargo list, but don't free the cargo packets;
151 * the cargo packets are cleaned by CargoPacket's CleanPool.
153 template <class Tinst
>
154 void CargoList
<Tinst
>::OnCleanPool()
156 this->packets
.clear();
160 * Update the cached values to reflect the removal of this packet.
161 * Decreases count and days_in_transit.
162 * @param cp Packet to be removed from cache.
164 template <class Tinst
>
165 void CargoList
<Tinst
>::RemoveFromCache(const CargoPacket
*cp
)
167 this->count
-= cp
->count
;
168 this->cargo_days_in_transit
-= cp
->days_in_transit
* cp
->count
;
172 * Update the cache to reflect adding of this packet.
173 * Increases count and days_in_transit.
174 * @param cp New packet to be inserted.
176 template <class Tinst
>
177 void CargoList
<Tinst
>::AddToCache(const CargoPacket
*cp
)
179 this->count
+= cp
->count
;
180 this->cargo_days_in_transit
+= cp
->days_in_transit
* cp
->count
;
184 * Appends the given cargo packet. Tries to merge it with another one in the
185 * packets list. If no fitting packet is found, appends it.
186 * @warning After appending this packet may not exist anymore!
187 * @note Do not use the cargo packet anymore after it has been appended to this CargoList!
188 * @param cp Cargo packet to add.
191 template <class Tinst
>
192 void CargoList
<Tinst
>::Append(CargoPacket
*cp
)
195 static_cast<Tinst
*>(this)->AddToCache(cp
);
197 for (List::reverse_iterator
it(this->packets
.rbegin()); it
!= this->packets
.rend(); it
++) {
198 CargoPacket
*icp
= *it
;
199 if (Tinst::AreMergable(icp
, cp
) && icp
->count
+ cp
->count
<= CargoPacket::MAX_COUNT
) {
205 /* The packet could not be merged with another one */
206 this->packets
.push_back(cp
);
210 * Truncates the cargo in this list to the given amount. It leaves the
211 * first count cargo entities and removes the rest.
212 * @param max_remaining Maximum amount of entities to be in the list after the command.
214 template <class Tinst
>
215 void CargoList
<Tinst
>::Truncate(uint max_remaining
)
217 for (Iterator
it(packets
.begin()); it
!= packets
.end(); /* done during loop*/) {
218 CargoPacket
*cp
= *it
;
219 if (max_remaining
== 0) {
220 /* Nothing should remain, just remove the packets. */
221 it
= this->packets
.erase(it
);
222 static_cast<Tinst
*>(this)->RemoveFromCache(cp
);
227 uint local_count
= cp
->count
;
228 if (local_count
> max_remaining
) {
229 uint diff
= local_count
- max_remaining
;
231 this->cargo_days_in_transit
-= cp
->days_in_transit
* diff
;
232 cp
->count
= max_remaining
;
235 max_remaining
-= local_count
;
242 * Moves the given amount of cargo to another list.
243 * Depending on the value of mta the side effects of this function differ:
244 * - MTA_FINAL_DELIVERY: Destroys the packets that do not originate from a specific station.
245 * - MTA_CARGO_LOAD: Sets the loaded_at_xy value of the moved packets.
246 * - MTA_TRANSFER: Just move without side effects.
247 * - MTA_UNLOAD: Just move without side effects.
248 * @param dest Destination to move the cargo to.
249 * @param max_move Amount of cargo entities to move.
250 * @param mta How to handle the moving (side effects).
251 * @param data Depending on mta the data of this variable differs:
252 * - MTA_FINAL_DELIVERY - Station ID of packet's origin not to remove.
253 * - MTA_CARGO_LOAD - Station's tile index of load.
254 * - MTA_TRANSFER - Unused.
255 * - MTA_UNLOAD - Unused.
256 * @param payment The payment helper.
258 * @pre mta == MTA_FINAL_DELIVERY || dest != NULL
259 * @pre mta == MTA_UNLOAD || mta == MTA_CARGO_LOAD || payment != NULL
260 * @return True if there are still packets that might be moved from this cargo list.
262 template <class Tinst
>
263 template <class Tother_inst
>
264 bool CargoList
<Tinst
>::MoveTo(Tother_inst
*dest
, uint max_move
, MoveToAction mta
, CargoPayment
*payment
, uint data
)
266 assert(mta
== MTA_FINAL_DELIVERY
|| dest
!= NULL
);
267 assert(mta
== MTA_UNLOAD
|| mta
== MTA_CARGO_LOAD
|| payment
!= NULL
);
269 Iterator
it(this->packets
.begin());
270 while (it
!= this->packets
.end() && max_move
> 0) {
271 CargoPacket
*cp
= *it
;
272 if (cp
->source
== data
&& mta
== MTA_FINAL_DELIVERY
) {
273 /* Skip cargo that originated from this station. */
278 if (cp
->count
<= max_move
) {
279 /* Can move the complete packet */
280 max_move
-= cp
->count
;
281 it
= this->packets
.erase(it
);
282 static_cast<Tinst
*>(this)->RemoveFromCache(cp
);
284 case MTA_FINAL_DELIVERY
:
285 payment
->PayFinalDelivery(cp
, cp
->count
);
287 continue; // of the loop
290 cp
->loaded_at_xy
= data
;
294 cp
->feeder_share
+= payment
->PayTransfer(cp
, cp
->count
);
304 /* Can move only part of the packet */
305 if (mta
== MTA_FINAL_DELIVERY
) {
306 /* Final delivery doesn't need package splitting. */
307 payment
->PayFinalDelivery(cp
, max_move
);
309 /* Remove the delivered data from the cache */
310 uint left
= cp
->count
- max_move
;
311 cp
->count
= max_move
;
312 static_cast<Tinst
*>(this)->RemoveFromCache(cp
);
314 /* Final delivery payment pays the feeder share, so we have to
315 * reset that so it is not 'shown' twice for partial unloads. */
316 cp
->feeder_share
= 0;
319 /* But... the rest needs package splitting. */
320 CargoPacket
*cp_new
= cp
->Split(max_move
);
322 /* We could not allocate a CargoPacket? Is the map that full? */
323 if (cp_new
== NULL
) return false;
325 static_cast<Tinst
*>(this)->RemoveFromCache(cp_new
); // this reflects the changes in cp.
327 if (mta
== MTA_TRANSFER
) {
328 /* Add the feeder share before inserting in dest. */
329 cp_new
->feeder_share
+= payment
->PayTransfer(cp_new
, max_move
);
330 } else if (mta
== MTA_CARGO_LOAD
) {
331 cp_new
->loaded_at_xy
= data
;
334 dest
->Append(cp_new
);
340 return it
!= packets
.end();
343 /** Invalidates the cached data and rebuilds it. */
344 template <class Tinst
>
345 void CargoList
<Tinst
>::InvalidateCache()
348 this->cargo_days_in_transit
= 0;
350 for (ConstIterator
it(this->packets
.begin()); it
!= this->packets
.end(); it
++) {
351 static_cast<Tinst
*>(this)->AddToCache(*it
);
356 * Update the cached values to reflect the removal of this packet.
357 * Decreases count, feeder share and days_in_transit.
358 * @param cp Packet to be removed from cache.
360 void VehicleCargoList::RemoveFromCache(const CargoPacket
*cp
)
362 this->feeder_share
-= cp
->feeder_share
;
363 this->Parent::RemoveFromCache(cp
);
367 * Update the cache to reflect adding of this packet.
368 * Increases count, feeder share and days_in_transit.
369 * @param cp New packet to be inserted.
371 void VehicleCargoList::AddToCache(const CargoPacket
*cp
)
373 this->feeder_share
+= cp
->feeder_share
;
374 this->Parent::AddToCache(cp
);
378 * Ages the all cargo in this list.
380 void VehicleCargoList::AgeCargo()
382 for (ConstIterator
it(this->packets
.begin()); it
!= this->packets
.end(); it
++) {
383 CargoPacket
*cp
= *it
;
384 /* If we're at the maximum, then we can't increase no more. */
385 if (cp
->days_in_transit
== 0xFF) continue;
387 cp
->days_in_transit
++;
388 this->cargo_days_in_transit
+= cp
->count
;
392 /** Invalidates the cached data and rebuild it. */
393 void VehicleCargoList::InvalidateCache()
395 this->feeder_share
= 0;
396 this->Parent::InvalidateCache();
400 * We have to instantiate everything we want to be usable.
402 template class CargoList
<VehicleCargoList
>;
403 template class CargoList
<StationCargoList
>;
405 /** Autoreplace Vehicle -> Vehicle 'transfer'. */
406 template bool CargoList
<VehicleCargoList
>::MoveTo(VehicleCargoList
*, uint max_move
, MoveToAction mta
, CargoPayment
*payment
, uint data
);
407 /** Cargo unloading at a station. */
408 template bool CargoList
<VehicleCargoList
>::MoveTo(StationCargoList
*, uint max_move
, MoveToAction mta
, CargoPayment
*payment
, uint data
);
409 /** Cargo loading at a station. */
410 template bool CargoList
<StationCargoList
>::MoveTo(VehicleCargoList
*, uint max_move
, MoveToAction mta
, CargoPayment
*payment
, uint data
);