diff --git a/projects/openttd_vs100.vcxproj b/projects/openttd_vs100.vcxproj index 4ab6f45e71..ebab0e48f6 100644 --- a/projects/openttd_vs100.vcxproj +++ b/projects/openttd_vs100.vcxproj @@ -296,6 +296,7 @@ + @@ -392,6 +393,7 @@ + diff --git a/projects/openttd_vs100.vcxproj.filters b/projects/openttd_vs100.vcxproj.filters index 34a8b4d000..b04bdef5de 100644 --- a/projects/openttd_vs100.vcxproj.filters +++ b/projects/openttd_vs100.vcxproj.filters @@ -117,6 +117,9 @@ Source Files + + Source Files + Source Files @@ -405,6 +408,9 @@ Header Files + + Header Files + Header Files diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj index c6e3e595f7..04373e82af 100644 --- a/projects/openttd_vs80.vcproj +++ b/projects/openttd_vs80.vcproj @@ -454,6 +454,10 @@ RelativePath=".\..\src\bmp.cpp" > + + @@ -842,6 +846,10 @@ RelativePath=".\..\src\cargo_type.h" > + + diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj index b5155a4692..511261dca5 100644 --- a/projects/openttd_vs90.vcproj +++ b/projects/openttd_vs90.vcproj @@ -451,6 +451,10 @@ RelativePath=".\..\src\bmp.cpp" > + + @@ -839,6 +843,10 @@ RelativePath=".\..\src\cargo_type.h" > + + diff --git a/source.list b/source.list index 83dc19e832..5553921388 100644 --- a/source.list +++ b/source.list @@ -4,6 +4,7 @@ animated_tile.cpp articulated_vehicles.cpp autoreplace.cpp bmp.cpp +cargoaction.cpp cargomonitor.cpp cargopacket.cpp cargotype.cpp @@ -125,6 +126,7 @@ base_station_base.h bmp.h bridge.h cargo_type.h +cargoaction.h cargomonitor.h cargopacket.h cargotype.h diff --git a/src/cargoaction.cpp b/src/cargoaction.cpp new file mode 100644 index 0000000000..eabe657da3 --- /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 . + */ + +/** @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 +CargoPacket *CargoMovement::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 +uint CargoRemoval::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 +bool CargoRemoval::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::Preprocess(CargoPacket *cp); +template uint CargoRemoval::Preprocess(CargoPacket *cp); +template bool CargoRemoval::Postprocess(CargoPacket *cp, uint remove); +template bool CargoRemoval::Postprocess(CargoPacket *cp, uint remove); diff --git a/src/cargoaction.h b/src/cargoaction.h new file mode 100644 index 0000000000..f7ee1a0015 --- /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 . + */ + +/** @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 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 { +protected: + CargoPayment *payment; ///< Payment object where payments will be registered. +public: + CargoDelivery(VehicleCargoList *source, uint max_move, CargoPayment *payment) : + CargoRemoval(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 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 { +protected: + CargoPayment *payment; ///< Payment object for registering transfer credits. +public: + CargoTransfer(VehicleCargoList *source, StationCargoList *destination, uint max_move, CargoPayment *payment) : + CargoMovement(source, destination, max_move), payment(payment) {} + bool operator()(CargoPacket *cp); +}; + +/** Action of loading cargo from a station onto a vehicle. */ +class CargoLoad : public CargoMovement { +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(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 { +public: + CargoShift(VehicleCargoList *source, VehicleCargoList *destination, uint max_move) : + CargoMovement(source, destination, max_move) {} + bool operator()(CargoPacket *cp); +}; + +#endif /* CARGOACTION_H */ diff --git a/src/cargopacket.cpp b/src/cargopacket.cpp index 42643ffa3a..842bf09131 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 uint CargoList::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(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(this)->RemoveFromCache(cp, diff); - cp->Reduce(diff); - max_remaining = 0; - } else { - max_remaining -= local_count; - } - ++it; - } + this->PopCargo(CargoRemoval(static_cast(this), max_move)); return max_move; } @@ -346,6 +326,59 @@ bool CargoList::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 +template +void CargoList::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 +template +void CargoList::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 void CargoList::InvalidateCache() diff --git a/src/cargopacket.h b/src/cargopacket.h index c23df88002..ab0d45f47e 100644 --- a/src/cargopacket.h +++ b/src/cargopacket.h @@ -219,6 +219,12 @@ protected: void RemoveFromCache(const CargoPacket *cp, uint count); + template + void ShiftCargo(Taction action); + + template + 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 + 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 + friend class CargoRemoval; + /** * Are two the two CargoPackets mergeable in the context of * a list of CargoPackets for a Vehicle?