diff options
Diffstat (limited to 'src/order_cmd.cpp')
-rw-r--r-- | src/order_cmd.cpp | 52 |
1 files changed, 48 insertions, 4 deletions
diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 833d23ff3..71edbb406 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -351,19 +351,61 @@ Order *OrderList::GetOrderAt(int index) const } /** + * Choose between the two possible next orders so that the given consist can + * load most cargo. + * @param v Head of the consist. + * @param o1 First order to choose from. + * @param o2 Second order to choose from. + * @return Either o1 or o2, depending on the amounts of cargo waiting at the + * vehicle's current station for each. + */ +const Order *OrderList::GetBestLoadableNext(const Vehicle *v, const Order *o2, const Order *o1) const +{ + SmallMap<CargoID, uint> capacities; + v->GetConsistFreeCapacities(capacities); + uint loadable1 = 0; + uint loadable2 = 0; + StationID st1 = o1->GetDestination(); + StationID st2 = o2->GetDestination(); + const Station *cur_station = Station::Get(v->last_station_visited); + for (SmallPair<CargoID, uint> *i = capacities.Begin(); i != capacities.End(); ++i) { + const StationCargoPacketMap *loadable_packets = cur_station->goods[i->first].cargo.Packets(); + uint loadable_cargo = 0; + std::pair<StationCargoPacketMap::const_iterator, StationCargoPacketMap::const_iterator> p = + loadable_packets->equal_range(st1); + for (StationCargoPacketMap::const_iterator j = p.first; j != p.second; ++j) { + loadable_cargo = (*j)->Count(); + } + loadable1 += min(i->second, loadable_cargo); + + loadable_cargo = 0; + p = loadable_packets->equal_range(st2); + for (StationCargoPacketMap::const_iterator j = p.first; j != p.second; ++j) { + loadable_cargo = (*j)->Count(); + } + loadable2 += min(i->second, loadable_cargo); + } + if (loadable1 == loadable2) return RandomRange(2) == 0 ? o1 : o2; + return loadable1 > loadable2 ? o1 : o2; +} + +/** * Get the next order which will make the given vehicle stop at a station * or refit at a depot if its state doesn't change. * @param v The vehicle in question. * @param next The order to start looking at. * @param hops The number of orders we have already looked at. + * @param is_loading If the vehicle is loading. This triggers a different + * behaviour on conditional orders based on load percentage. * @return Either an order or NULL if the vehicle won't stop anymore. + * @see OrderList::GetBestLoadableNext */ -const Order *OrderList::GetNextStoppingOrder(const Vehicle *v, const Order *next, uint hops) const +const Order *OrderList::GetNextStoppingOrder(const Vehicle *v, const Order *next, uint hops, bool is_loading) const { if (hops > this->GetNumOrders() || next == NULL) return NULL; if (next->IsType(OT_CONDITIONAL)) { - if (next->GetConditionVariable() == OCV_LOAD_PERCENTAGE) { + if (is_loading && next->GetConditionVariable() == OCV_LOAD_PERCENTAGE) { /* If the condition is based on load percentage we can't * tell what it will do. So we choose randomly. */ const Order *skip_to = this->GetNextStoppingOrder(v, @@ -373,7 +415,7 @@ const Order *OrderList::GetNextStoppingOrder(const Vehicle *v, const Order *next this->GetNext(next), hops + 1); if (advance == NULL) return skip_to; if (skip_to == NULL) return advance; - return RandomRange(2) == 0 ? skip_to : advance; + return this->GetBestLoadableNext(v, skip_to, advance); } /* Otherwise we're optimistic and expect that the * condition value won't change until it's evaluated. */ @@ -401,6 +443,8 @@ const Order *OrderList::GetNextStoppingOrder(const Vehicle *v, const Order *next * Recursively determine the next deterministic station to stop at. * @param v The vehicle we're looking at. * @return Next stoppping station or INVALID_STATION. + * @pre The vehicle is currently loading and v->last_station_visited is meaningful. + * @note This function may draw a random number. Don't use it from the GUI. */ StationID OrderList::GetNextStoppingStation(const Vehicle *v) const { @@ -420,7 +464,7 @@ StationID OrderList::GetNextStoppingStation(const Vehicle *v) const uint hops = 0; do { - next = this->GetNextStoppingOrder(v, next, ++hops); + next = this->GetNextStoppingOrder(v, next, ++hops, true); /* Don't return a next stop if the vehicle has to unload everything. */ if (next == NULL || (next->GetDestination() == v->last_station_visited && (next->GetUnloadType() & (OUFB_TRANSFER | OUFB_UNLOAD)) == 0)) { |