summaryrefslogtreecommitdiff
path: root/src/order_cmd.cpp
diff options
context:
space:
mode:
authorfrosch <frosch@openttd.org>2011-01-31 20:44:15 +0000
committerfrosch <frosch@openttd.org>2011-01-31 20:44:15 +0000
commita97d52a29a990132a8a5e4dd60304483617cec50 (patch)
tree0d8d42d633feabb438f812cedf0534a3c665074e /src/order_cmd.cpp
parent67a5cd0b185158ca4926c8cb45f1735a1001e00b (diff)
downloadopenttd-a97d52a29a990132a8a5e4dd60304483617cec50.tar.xz
(svn r21933) -Codechange: Split cur_order_index into cur_auto_order_index and cur_real_order_index to keep track of the current real order in an unambiguous way.
-Fix [FS#4440]: Automatic orders behave now stable wrt. service orders and are not added or removed depending on the need of servicing. -Fix: Various other issues with automatic orders, e.g. vehicles getting stuck with "no orders" when there are automatic orders at the end of the order list.
Diffstat (limited to 'src/order_cmd.cpp')
-rw-r--r--src/order_cmd.cpp127
1 files changed, 94 insertions, 33 deletions
diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp
index 61b1fd5ef..e7456fbdf 100644
--- a/src/order_cmd.cpp
+++ b/src/order_cmd.cpp
@@ -824,12 +824,21 @@ void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord)
assert(v->orders.list == u->orders.list);
/* If there is added an order before the current one, we need
- * to update the selected order */
- if (sel_ord <= u->cur_order_index) {
- uint cur = u->cur_order_index + 1;
+ * to update the selected order. We do not change automatic/real order indices though.
+ * If the new order is between the current auto order and real order, the auto order will
+ * later skip the inserted order. */
+ if (sel_ord <= u->cur_real_order_index) {
+ uint cur = u->cur_real_order_index + 1;
/* Check if we don't go out of bound */
if (cur < u->GetNumOrders()) {
- u->cur_order_index = cur;
+ u->cur_real_order_index = cur;
+ }
+ }
+ if (sel_ord <= u->cur_auto_order_index) {
+ uint cur = u->cur_auto_order_index + 1;
+ /* Check if we don't go out of bound */
+ if (cur < u->GetNumOrders()) {
+ u->cur_auto_order_index = cur;
}
}
/* Update any possible open window of the vehicle */
@@ -917,14 +926,31 @@ void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord)
/* NON-stop flag is misused to see if a train is in a station that is
* on his order list or not */
- if (sel_ord == u->cur_order_index && u->current_order.IsType(OT_LOADING)) {
+ if (sel_ord == u->cur_real_order_index && u->current_order.IsType(OT_LOADING)) {
u->current_order.SetNonStopType(ONSF_STOP_EVERYWHERE);
/* When full loading, "cancel" that order so the vehicle doesn't
* stay indefinitely at this station anymore. */
if (u->current_order.GetLoadType() & OLFB_FULL_LOAD) u->current_order.SetLoadType(OLF_LOAD_IF_POSSIBLE);
}
- if (sel_ord < u->cur_order_index) u->cur_order_index--;
+ if (sel_ord < u->cur_real_order_index) {
+ u->cur_real_order_index--;
+ } else if (sel_ord == u->cur_real_order_index) {
+ u->UpdateRealOrderIndex();
+ }
+
+ if (sel_ord < u->cur_auto_order_index) {
+ u->cur_auto_order_index--;
+ } else if (sel_ord == u->cur_auto_order_index) {
+ /* Make sure the index is valid */
+ if (u->cur_auto_order_index >= u->GetNumOrders()) u->cur_auto_order_index = 0;
+
+ /* Skip non-automatic orders for the auto-order-index (e.g. if the current auto order was deleted */
+ while (u->cur_auto_order_index != u->cur_real_order_index && !u->GetOrder(u->cur_auto_order_index)->IsType(OT_AUTOMATIC)) {
+ u->cur_auto_order_index++;
+ if (u->cur_auto_order_index >= u->GetNumOrders()) u->cur_auto_order_index = 0;
+ }
+ }
/* Update any possible open window of the vehicle */
InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
@@ -965,13 +991,14 @@ CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
Vehicle *v = Vehicle::GetIfValid(veh_id);
- if (v == NULL || !v->IsPrimaryVehicle() || sel_ord == v->cur_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR;
+ if (v == NULL || !v->IsPrimaryVehicle() || sel_ord == v->cur_auto_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR;
CommandCost ret = CheckOwnership(v->owner);
if (ret.Failed()) return ret;
if (flags & DC_EXEC) {
- v->cur_order_index = sel_ord;
+ v->cur_auto_order_index = v->cur_real_order_index = sel_ord;
+ v->UpdateRealOrderIndex();
if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
@@ -1027,13 +1054,36 @@ CommandCost CmdMoveOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
DeleteOrderWarnings(u);
for (; u != NULL; u = u->NextShared()) {
- /* Update the current order */
- if (u->cur_order_index == moving_order) {
- u->cur_order_index = target_order;
- } else if (u->cur_order_index > moving_order && u->cur_order_index <= target_order) {
- u->cur_order_index--;
- } else if (u->cur_order_index < moving_order && u->cur_order_index >= target_order) {
- u->cur_order_index++;
+ /* Update the current order.
+ * There are multiple ways to move orders, which result in cur_auto_order_index
+ * and cur_real_order_index to not longer make any sense. E.g. moving another
+ * real order between them.
+ *
+ * Basically one could choose to preserve either of them, but not both.
+ * While both ways are suitable in this or that case from a human point of view, neither
+ * of them makes really sense.
+ * However, from an AI point of view, preserving cur_real_order_index is the most
+ * predictable and transparent behaviour.
+ *
+ * With that decision it basically does not matter what we do to cur_auto_order_index.
+ * If we change orders between the auto- and real-index, the auto orders are mostly likely
+ * completely out-dated anyway. So, keep it simple and just keep cur_auto_order_index as well.
+ * The worst which can happen is that a lot of automatic orders are removed when reaching current_order.
+ */
+ if (u->cur_real_order_index == moving_order) {
+ u->cur_real_order_index = target_order;
+ } else if (u->cur_real_order_index > moving_order && u->cur_real_order_index <= target_order) {
+ u->cur_real_order_index--;
+ } else if (u->cur_real_order_index < moving_order && u->cur_real_order_index >= target_order) {
+ u->cur_real_order_index++;
+ }
+
+ if (u->cur_auto_order_index == moving_order) {
+ u->cur_auto_order_index = target_order;
+ } else if (u->cur_auto_order_index > moving_order && u->cur_auto_order_index <= target_order) {
+ u->cur_auto_order_index--;
+ } else if (u->cur_auto_order_index < moving_order && u->cur_auto_order_index >= target_order) {
+ u->cur_auto_order_index++;
}
assert(v->orders.list == u->orders.list);
@@ -1289,7 +1339,7 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
* so do not care and those orders should not be active
* when this function is called.
*/
- if (sel_ord == u->cur_order_index &&
+ if (sel_ord == u->cur_real_order_index &&
(u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
u->current_order.GetLoadType() != order->GetLoadType()) {
u->current_order.SetLoadType(order->GetLoadType());
@@ -1468,7 +1518,7 @@ CommandCost CmdOrderRefit(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
InvalidateVehicleOrder(u, -2);
/* If the vehicle already got the current depot set as current order, then update current order as well */
- if (u->cur_order_index == order_number && (u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) {
+ if (u->cur_real_order_index == order_number && (u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) {
u->current_order.SetRefit(cargo, subtype);
}
}
@@ -1742,7 +1792,7 @@ bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth)
case OT_GOTO_DEPOT:
if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) {
UpdateVehicleTimetable(v, true);
- v->IncrementOrderIndex();
+ v->IncrementRealOrderIndex();
break;
}
@@ -1771,7 +1821,7 @@ bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth)
}
UpdateVehicleTimetable(v, true);
- v->IncrementOrderIndex();
+ v->IncrementRealOrderIndex();
} else {
if (v->type != VEH_AIRCRAFT) {
v->dest_tile = Depot::Get(order->GetDestination())->xy;
@@ -1787,12 +1837,15 @@ bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth)
case OT_CONDITIONAL: {
VehicleOrderID next_order = ProcessConditionalOrder(order, v);
if (next_order != INVALID_VEH_ORDER_ID) {
+ /* Jump to next_order. cur_auto_order_index becomes exactly that order,
+ * cur_real_order_index might come after next_order. */
UpdateVehicleTimetable(v, false);
- v->cur_order_index = next_order;
- v->current_order_time += v->GetOrder(next_order)->travel_time;
+ v->cur_auto_order_index = v->cur_real_order_index = next_order;
+ v->UpdateRealOrderIndex();
+ v->current_order_time += v->GetOrder(v->cur_real_order_index)->travel_time;
} else {
UpdateVehicleTimetable(v, true);
- v->IncrementOrderIndex();
+ v->IncrementRealOrderIndex();
}
break;
}
@@ -1802,18 +1855,22 @@ bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth)
return false;
}
- assert(v->cur_order_index < v->GetNumOrders());
+ assert(v->cur_auto_order_index < v->GetNumOrders());
+ assert(v->cur_real_order_index < v->GetNumOrders());
/* Get the current order */
- order = v->GetNextManualOrder(v->cur_order_index);
+ order = v->GetOrder(v->cur_real_order_index);
+ if (order->IsType(OT_AUTOMATIC)) {
+ assert(v->GetNumManualOrders() == 0);
+ order = NULL;
+ }
+
if (order == NULL) {
- order = v->GetNextManualOrder(0);
- if (order == NULL) {
- v->current_order.Free();
- v->dest_tile = 0;
- return false;
- }
+ v->current_order.Free();
+ v->dest_tile = 0;
+ return false;
}
+
v->current_order = *order;
return UpdateOrderDest(v, order, conditional_depth + 1);
}
@@ -1863,13 +1920,17 @@ bool ProcessOrders(Vehicle *v)
* visited station will cause the vehicle to still stop. */
v->last_station_visited = v->current_order.GetDestination();
UpdateVehicleTimetable(v, true);
- v->IncrementOrderIndex();
+ v->IncrementAutoOrderIndex();
}
/* Get the current order */
- if (v->cur_order_index >= v->GetNumOrders()) v->cur_order_index = 0;
+ v->UpdateRealOrderIndex();
- const Order *order = v->GetNextManualOrder(v->cur_order_index);
+ const Order *order = v->GetOrder(v->cur_real_order_index);
+ if (order->IsType(OT_AUTOMATIC)) {
+ assert(v->GetNumManualOrders() == 0);
+ order = NULL;
+ }
/* If no order, do nothing. */
if (order == NULL || (v->type == VEH_AIRCRAFT && !CheckForValidOrders(v))) {