diff options
author | rubidium <rubidium@openttd.org> | 2013-02-17 14:36:40 +0000 |
---|---|---|
committer | rubidium <rubidium@openttd.org> | 2013-02-17 14:36:40 +0000 |
commit | d6e2a8aa56337af68f2960cf404edf0ac03f405b (patch) | |
tree | accb17985ebc03652d3c7b42b0dc8c038943a4c3 /src | |
parent | 71bbc130fc3bde400bcf2d46e0d57d974acc83aa (diff) | |
download | openttd-d6e2a8aa56337af68f2960cf404edf0ac03f405b.tar.xz |
(svn r25010) -Codechange: Add general framework for cargo actions, i.e. loading, transfering, delivering and such, to contain this logic in a single place instead of spread around (fonsinchen)
Diffstat (limited to 'src')
-rw-r--r-- | src/cargoaction.cpp | 132 | ||||
-rw-r--r-- | src/cargoaction.h | 106 | ||||
-rw-r--r-- | src/cargopacket.cpp | 77 | ||||
-rw-r--r-- | src/cargopacket.h | 17 |
4 files changed, 310 insertions, 22 deletions
diff --git a/src/cargoaction.cpp b/src/cargoaction.cpp new file mode 100644 index 000000000..eabe657da --- /dev/null +++ b/src/cargoaction.cpp @@ -0,0 +1,132 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * 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. + * 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. + * 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/>. + */ + +/** @file cargoaction.cpp Implementation of cargo actions. */ + +#include "stdafx.h" +#include "economy_base.h" +#include "cargoaction.h" + +/** + * Decides if a packet needs to be split. + * @param cp Packet to be either split or moved in one piece. + * @return Either new packet if splitting was necessary or the given one + * otherwise. + */ +template<class Tsource, class Tdest> +CargoPacket *CargoMovement<Tsource, Tdest>::Preprocess(CargoPacket *cp) +{ + if (this->max_move < cp->Count()) { + cp = cp->Split(this->max_move); + this->max_move = 0; + } else { + this->max_move -= cp->Count(); + } + return cp; +} + +/** + * Determines the amount of cargo to be removed from a packet and removes that + * from the metadata of the list. + * @param cp Packet to be removed completely or partially. + * @return Amount of cargo to be removed. + */ +template<class Tsource> +uint CargoRemoval<Tsource>::Preprocess(CargoPacket *cp) +{ + if (this->max_move >= cp->Count()) { + this->max_move -= cp->Count(); + this->source->RemoveFromCache(cp, cp->Count()); + return cp->Count(); + } else { + uint ret = this->max_move; + this->source->RemoveFromCache(cp, ret); + this->max_move = 0; + return ret; + } +} + +/** + * Finalize cargo removal. Either delete the packet or reduce it. + * @param cp Packet to be removed or reduced. + * @param remove Amount of cargo to be removed. + * @return True if the packet was deleted, False if it was reduced. + */ +template<class Tsource> +bool CargoRemoval<Tsource>::Postprocess(CargoPacket *cp, uint remove) +{ + if (remove == cp->Count()) { + delete cp; + return true; + } else { + cp->Reduce(remove); + return false; + } +} + +/** + * Delivers some cargo. + * @param cp Packet to be delivered. + * @return True if the packet was completely delivered, false if only part of + * it was. + */ +bool CargoDelivery::operator()(CargoPacket *cp) +{ + uint remove = this->Preprocess(cp); + this->payment->PayFinalDelivery(cp, remove); + return this->Postprocess(cp, remove); +} + +/** + * Loads some cargo onto a vehicle. + * @param cp Packet to be loaded. + * @return True if the packet was completely loaded, false if part of it was. + */ +bool CargoLoad::operator()(CargoPacket *cp) +{ + CargoPacket *cp_new = this->Preprocess(cp); + if (cp_new == NULL) return false; + cp_new->SetLoadPlace(this->load_place); + this->source->RemoveFromCache(cp_new, cp_new->Count()); + this->destination->Append(cp_new); + return cp_new == cp; +} + +/** + * Transfers some cargo from a vehicle to a station. + * @param cp Packet to be transfered. + * @return True if the packet was completely reserved, false if part of it was. + */ +bool CargoTransfer::operator()(CargoPacket *cp) +{ + CargoPacket *cp_new = this->Preprocess(cp); + if (cp_new == NULL) return false; + this->source->RemoveFromCache(cp_new, cp_new->Count()); + this->destination->Append(cp_new); + return cp_new == cp; +} + +/** + * Shifts some cargo from a vehicle to another one. + * @param cp Packet to be shifted. + * @return True if the packet was completely shifted, false if part of it was. + */ +bool CargoShift::operator()(CargoPacket *cp) +{ + CargoPacket *cp_new = this->Preprocess(cp); + if (cp_new == NULL) cp_new = cp; + this->source->RemoveFromCache(cp_new, cp_new->Count()); + this->destination->Append(cp_new); + return cp_new == cp; +} + +template uint CargoRemoval<VehicleCargoList>::Preprocess(CargoPacket *cp); +template uint CargoRemoval<StationCargoList>::Preprocess(CargoPacket *cp); +template bool CargoRemoval<VehicleCargoList>::Postprocess(CargoPacket *cp, uint remove); +template bool CargoRemoval<StationCargoList>::Postprocess(CargoPacket *cp, uint remove); diff --git a/src/cargoaction.h b/src/cargoaction.h new file mode 100644 index 000000000..f7ee1a001 --- /dev/null +++ b/src/cargoaction.h @@ -0,0 +1,106 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * 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. + * 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. + * 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/>. + */ + +/** @file cargoaction.h Actions to be applied to cargo packets. */ + +#ifndef CARGOACTION_H +#define CARGOACTION_H + +#include "cargopacket.h" + +/** + * Abstract action of removing cargo from a vehicle or a station. + * @tparam Tsource CargoList subclass to remove cargo from. + */ +template<class Tsource> +class CargoRemoval { +protected: + Tsource *source; ///< Source of the cargo. + uint max_move; ///< Maximum amount of cargo to be removed with this action. + uint Preprocess(CargoPacket *cp); + bool Postprocess(CargoPacket *cp, uint remove); +public: + CargoRemoval(Tsource *source, uint max_move) : source(source), max_move(max_move) {} + + /** + * Returns how much more cargo can be removed with this action. + * @return Amount of cargo this action can still remove. + */ + uint MaxMove() { return this->max_move; } + + /** + * Removes some cargo. + * @param cp Packet to be removed. + * @return True if the packet was completely delivered, false if only part of + * it was. + */ + inline bool operator()(CargoPacket *cp) { return this->Postprocess(cp, this->Preprocess(cp)); } +}; + +/** Action of final delivery of cargo. */ +class CargoDelivery : public CargoRemoval<VehicleCargoList> { +protected: + CargoPayment *payment; ///< Payment object where payments will be registered. +public: + CargoDelivery(VehicleCargoList *source, uint max_move, CargoPayment *payment) : + CargoRemoval<VehicleCargoList>(source, max_move), payment(payment) {} + bool operator()(CargoPacket *cp); +}; + +/** + * Abstract action for moving cargo from one list to another. + * @tparam Tsource CargoList subclass to remove cargo from. + * @tparam Tdest CargoList subclass to add cargo to. + */ +template<class Tsource, class Tdest> +class CargoMovement { +protected: + Tsource *source; ///< Source of the cargo. + Tdest *destination; ///< Destination for the cargo. + uint max_move; ///< Maximum amount of cargo to be moved with this action. + CargoPacket *Preprocess(CargoPacket *cp); +public: + CargoMovement(Tsource *source, Tdest *destination, uint max_move) : source(source), destination(destination), max_move(max_move) {} + + /** + * Returns how much more cargo can be moved with this action. + * @return Amount of cargo this action can still move. + */ + uint MaxMove() { return this->max_move; } +}; + +/** Action of transferring cargo from a vehicle to a station. */ +class CargoTransfer : public CargoMovement<VehicleCargoList, StationCargoList> { +protected: + CargoPayment *payment; ///< Payment object for registering transfer credits. +public: + CargoTransfer(VehicleCargoList *source, StationCargoList *destination, uint max_move, CargoPayment *payment) : + CargoMovement<VehicleCargoList, StationCargoList>(source, destination, max_move), payment(payment) {} + bool operator()(CargoPacket *cp); +}; + +/** Action of loading cargo from a station onto a vehicle. */ +class CargoLoad : public CargoMovement<StationCargoList, VehicleCargoList> { +protected: + TileIndex load_place; ///< TileIndex to be saved in the packets' loaded_at_xy. +public: + CargoLoad(StationCargoList *source, VehicleCargoList *destination, uint max_move, TileIndex load_place) : + CargoMovement<StationCargoList, VehicleCargoList>(source, destination, max_move), load_place(load_place) {} + bool operator()(CargoPacket *cp); +}; + +/** Action of shifting cargo from one vehicle to another. */ +class CargoShift : public CargoMovement<VehicleCargoList, VehicleCargoList> { +public: + CargoShift(VehicleCargoList *source, VehicleCargoList *destination, uint max_move) : + CargoMovement<VehicleCargoList, VehicleCargoList>(source, destination, max_move) {} + bool operator()(CargoPacket *cp); +}; + +#endif /* CARGOACTION_H */ diff --git a/src/cargopacket.cpp b/src/cargopacket.cpp index 42643ffa3..842bf0913 100644 --- a/src/cargopacket.cpp +++ b/src/cargopacket.cpp @@ -12,6 +12,7 @@ #include "stdafx.h" #include "core/pool_func.hpp" #include "economy_base.h" +#include "cargoaction.h" /* Initialize the cargopacket-pool */ CargoPacketPool _cargopacket_pool("CargoPacket"); @@ -225,28 +226,7 @@ template <class Tinst> uint CargoList<Tinst>::Truncate(uint max_move) { max_move = min(this->count, max_move); - uint max_remaining = this->count - max_move; - for (Iterator it(packets.begin()); it != packets.end(); /* done during loop*/) { - CargoPacket *cp = *it; - if (max_remaining == 0) { - /* Nothing should remain, just remove the packets. */ - it = this->packets.erase(it); - static_cast<Tinst *>(this)->RemoveFromCache(cp, cp->count); - delete cp; - continue; - } - - uint local_count = cp->count; - if (local_count > max_remaining) { - uint diff = local_count - max_remaining; - static_cast<Tinst *>(this)->RemoveFromCache(cp, diff); - cp->Reduce(diff); - max_remaining = 0; - } else { - max_remaining -= local_count; - } - ++it; - } + this->PopCargo(CargoRemoval<Tinst>(static_cast<Tinst *>(this), max_move)); return max_move; } @@ -346,6 +326,59 @@ bool CargoList<Tinst>::MoveTo(Tother_inst *dest, uint max_move, MoveToAction mta return it != packets.end(); } +/** + * Shifts cargo from the front of the packet list and applies some action to it. + * @tparam Taction Action class or function to be used. It should define + * "bool operator()(CargoPacket *)". If true is returned the + * cargo packet will be removed from the list. Otherwise it + * will be kept and the loop will be aborted. + * @param action Action instance to be applied. + */ +template <class Tinst> +template <class Taction> +void CargoList<Tinst>::ShiftCargo(Taction action) +{ + Iterator it(this->packets.begin()); + while (it != this->packets.end() && action.MaxMove() > 0) { + CargoPacket *cp = *it; + if (action(cp)) { + it = this->packets.erase(it); + } else { + break; + } + } +} + +/** + * Pops cargo from the back of the packet list and applies some action to it. + * @tparam Taction Action class or function to be used. It should define + * "bool operator()(CargoPacket *)". If true is returned the + * cargo packet will be removed from the list. Otherwise it + * will be kept and the loop will be aborted. + * @param action Action instance to be applied. + */ +template <class Tinst> +template <class Taction> +void CargoList<Tinst>::PopCargo(Taction action) +{ + if (this->packets.empty()) return; + Iterator it(--(this->packets.end())); + Iterator begin(this->packets.begin()); + while (action.MaxMove() > 0) { + CargoPacket *cp = *it; + if (action(cp)) { + if (it != begin) { + this->packets.erase(it--); + } else { + this->packets.erase(it); + break; + } + } else { + break; + } + } +} + /** Invalidates the cached data and rebuilds it. */ template <class Tinst> void CargoList<Tinst>::InvalidateCache() diff --git a/src/cargopacket.h b/src/cargopacket.h index c23df8800..ab0d45f47 100644 --- a/src/cargopacket.h +++ b/src/cargopacket.h @@ -219,6 +219,12 @@ protected: void RemoveFromCache(const CargoPacket *cp, uint count); + template<class Taction> + void ShiftCargo(Taction action); + + template<class Taction> + void PopCargo(Taction action); + static bool TryMerge(CargoPacket *cp, CargoPacket *icp); public: @@ -303,6 +309,12 @@ public: /** The vehicles have a cargo list (and we want that saved). */ friend const struct SaveLoad *GetVehicleDescription(VehicleType vt); + friend class CargoShift; + friend class CargoTransfer; + friend class CargoDelivery; + template<class Tsource> + friend class CargoRemoval; + /** * Returns total sum of the feeder share for all packets. * @return The before mentioned number. @@ -343,6 +355,11 @@ public: /** The stations, via GoodsEntry, have a CargoList. */ friend const struct SaveLoad *GetGoodsDesc(); + friend class CargoLoad; + friend class CargoTransfer; + template<class Tsource> + friend class CargoRemoval; + /** * Are two the two CargoPackets mergeable in the context of * a list of CargoPackets for a Vehicle? |