diff options
author | frosch <frosch@openttd.org> | 2011-01-31 20:44:15 +0000 |
---|---|---|
committer | frosch <frosch@openttd.org> | 2011-01-31 20:44:15 +0000 |
commit | a97d52a29a990132a8a5e4dd60304483617cec50 (patch) | |
tree | 0d8d42d633feabb438f812cedf0534a3c665074e /src/order_cmd.cpp | |
parent | 67a5cd0b185158ca4926c8cb45f1735a1001e00b (diff) | |
download | openttd-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.cpp | 127 |
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))) { |