(svn r23005) -Fix (r23004): Of course there's still the 16-sprite version for shore...
[openttd/fttd.git] / src / cargopacket.cpp
blob8bd6b651d286de4f816bc1a9043b578cfda1cbcd
1 /* $Id$ */
3 /*
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/>.
8 */
10 /** @file cargopacket.cpp Implementation of the cargo packets. */
12 #include "stdafx.h"
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)
20 /**
21 * Create a new packet for savegame loading.
23 CargoPacket::CargoPacket()
25 this->source_type = ST_INDUSTRY;
26 this->source_id = INVALID_SOURCE;
29 /**
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).
36 * @pre count != 0
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) :
41 feeder_share(0),
42 count(count),
43 days_in_transit(0),
44 source_id(source_id),
45 source(source),
46 source_xy(source_xy),
47 loaded_at_xy(0)
49 assert(count != 0);
50 this->source_type = source_type;
53 /**
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),
69 count(count),
70 days_in_transit(days_in_transit),
71 source_id(source_id),
72 source(source),
73 source_xy(source_xy),
74 loaded_at_xy(loaded_at_xy)
76 assert(count != 0);
77 this->source_type = source_type;
80 /**
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;
93 return cp_new;
96 /**
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;
104 delete cp;
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)
114 CargoPacket *cp;
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)
126 CargoPacket *cp;
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) {
145 delete *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.
189 * @pre cp != NULL
191 template <class Tinst>
192 void CargoList<Tinst>::Append(CargoPacket *cp)
194 assert(cp != NULL);
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) {
200 icp->Merge(cp);
201 return;
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);
223 delete cp;
224 continue;
227 uint local_count = cp->count;
228 if (local_count > max_remaining) {
229 uint diff = local_count - max_remaining;
230 this->count -= diff;
231 this->cargo_days_in_transit -= cp->days_in_transit * diff;
232 cp->count = max_remaining;
233 max_remaining = 0;
234 } else {
235 max_remaining -= local_count;
237 ++it;
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. */
274 ++it;
275 continue;
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);
283 switch (mta) {
284 case MTA_FINAL_DELIVERY:
285 payment->PayFinalDelivery(cp, cp->count);
286 delete cp;
287 continue; // of the loop
289 case MTA_CARGO_LOAD:
290 cp->loaded_at_xy = data;
291 break;
293 case MTA_TRANSFER:
294 cp->feeder_share += payment->PayTransfer(cp, cp->count);
295 break;
297 case MTA_UNLOAD:
298 break;
300 dest->Append(cp);
301 continue;
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;
317 cp->count = left;
318 } else {
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);
337 max_move = 0;
340 return it != packets.end();
343 /** Invalidates the cached data and rebuilds it. */
344 template <class Tinst>
345 void CargoList<Tinst>::InvalidateCache()
347 this->count = 0;
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);