summaryrefslogtreecommitdiff
path: root/src/order_cmd.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/order_cmd.cpp')
-rw-r--r--src/order_cmd.cpp106
1 files changed, 104 insertions, 2 deletions
diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp
index e44447f7c..833d23ff3 100644
--- a/src/order_cmd.cpp
+++ b/src/order_cmd.cpp
@@ -20,6 +20,7 @@
#include "vehicle_func.h"
#include "depot_base.h"
#include "core/pool_func.hpp"
+#include "core/random_func.hpp"
#include "aircraft.h"
#include "roadveh.h"
#include "station_base.h"
@@ -350,6 +351,87 @@ Order *OrderList::GetOrderAt(int index) const
}
/**
+ * 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.
+ * @return Either an order or NULL if the vehicle won't stop anymore.
+ */
+const Order *OrderList::GetNextStoppingOrder(const Vehicle *v, const Order *next, uint hops) const
+{
+ if (hops > this->GetNumOrders() || next == NULL) return NULL;
+
+ if (next->IsType(OT_CONDITIONAL)) {
+ if (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,
+ this->GetOrderAt(next->GetConditionSkipToOrder()),
+ hops + 1);
+ const Order *advance = this->GetNextStoppingOrder(v,
+ this->GetNext(next), hops + 1);
+ if (advance == NULL) return skip_to;
+ if (skip_to == NULL) return advance;
+ return RandomRange(2) == 0 ? skip_to : advance;
+ }
+ /* Otherwise we're optimistic and expect that the
+ * condition value won't change until it's evaluated. */
+ VehicleOrderID skip_to = ProcessConditionalOrder(next, v);
+ if (skip_to != INVALID_VEH_ORDER_ID) {
+ return this->GetNextStoppingOrder(v, this->GetOrderAt(skip_to),
+ hops + 1);
+ }
+ return this->GetNextStoppingOrder(v, this->GetNext(next), hops + 1);
+ }
+
+ if (next->IsType(OT_GOTO_DEPOT)) {
+ if (next->GetDepotActionType() == ODATFB_HALT) return NULL;
+ if (next->IsRefit()) return next;
+ }
+
+ if (!next->CanLoadOrUnload()) {
+ return this->GetNextStoppingOrder(v, this->GetNext(next), hops + 1);
+ }
+
+ return 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.
+ */
+StationID OrderList::GetNextStoppingStation(const Vehicle *v) const
+{
+
+ const Order *next = this->GetOrderAt(v->cur_implicit_order_index);
+ if (next == NULL) {
+ next = this->GetFirstOrder();
+ if (next == NULL) return INVALID_STATION;
+ } else {
+ /* GetNext never returns NULL if there is a valid station in the list.
+ * As the given "next" is already valid and a station in the list, we
+ * don't have to check for NULL here.
+ */
+ next = this->GetNext(next);
+ assert(next != NULL);
+ }
+
+ uint hops = 0;
+ do {
+ next = this->GetNextStoppingOrder(v, next, ++hops);
+ /* 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)) {
+ return INVALID_STATION;
+ }
+ } while (next->IsType(OT_GOTO_DEPOT) || next->GetDestination() == v->last_station_visited);
+
+ return next->GetDestination();
+}
+
+/**
* Insert a new order into the order chain.
* @param new_order is the order to insert into the chain.
* @param index is the position where the order is supposed to be inserted.
@@ -1044,11 +1126,11 @@ CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
if (ret.Failed()) return ret;
if (flags & DC_EXEC) {
+ if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
+
v->cur_implicit_order_index = v->cur_real_order_index = sel_ord;
v->UpdateRealOrderIndex();
- if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
-
InvalidateVehicleOrder(v, VIWD_MODIFY_ORDERS);
}
@@ -2122,3 +2204,23 @@ bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
/* Finally do stop when there is no non-stop flag set for this type of station. */
!(this->GetNonStopType() & (is_dest_station ? ONSF_NO_STOP_AT_DESTINATION_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS));
}
+
+bool Order::CanLoadOrUnload() const
+{
+ return (this->IsType(OT_GOTO_STATION) || this->IsType(OT_IMPLICIT)) &&
+ (this->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) == 0 &&
+ ((this->GetLoadType() & OLFB_NO_LOAD) == 0 ||
+ (this->GetUnloadType() & OUFB_NO_UNLOAD) == 0);
+}
+
+/**
+ * A vehicle can leave the current station with cargo if:
+ * 1. it can load cargo here OR
+ * 2a. it could leave the last station with cargo AND
+ * 2b. it doesn't have to unload all cargo here.
+ */
+bool Order::CanLeaveWithCargo(bool has_cargo) const
+{
+ return (this->GetLoadType() & OLFB_NO_LOAD) == 0 || (has_cargo &&
+ (this->GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == 0);
+}