diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index aa0f0eacc0..ccfb330dbe 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -1404,8 +1404,10 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 } if (flags & DC_EXEC) { - /* If the destination vehicle had a OrderList, destroy it */ - DeleteVehicleOrders(dst); + /* If the destination vehicle had a OrderList, destroy it. + * We only reset the order indices, if the new orders are obviously different. + * (We mainly do this to keep the order indices valid and in range.) */ + DeleteVehicleOrders(dst, false, dst->GetNumOrders() != src->GetNumOrders()); dst->orders.list = src->orders.list; @@ -1451,8 +1453,10 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 Order *first = NULL; Order **order_dst; - /* If the destination vehicle had an order list, destroy the chain but keep the OrderList */ - DeleteVehicleOrders(dst, true); + /* If the destination vehicle had an order list, destroy the chain but keep the OrderList. + * We only reset the order indices, if the new orders are obviously different. + * (We mainly do this to keep the order indices valid and in range.) */ + DeleteVehicleOrders(dst, true, dst->GetNumOrders() != src->GetNumOrders()); order_dst = &first; FOR_VEHICLE_ORDERS(src, order) { @@ -1674,11 +1678,15 @@ bool Vehicle::HasDepotOrder() const } /** - * * Delete all orders from a vehicle - * + * @param v Vehicle whose orders to reset + * @param keep_orderlist If true, do not free the order list, only empty it. + * @param reset_order_indices If true, reset cur_auto_order_index and cur_real_order_index + * and cancel the current full load order (if the vehicle is loading). + * If false, _you_ have to make sure the order indices are valid after + * your messing with them! */ -void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist) +void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices) { DeleteOrderWarnings(v); @@ -1691,6 +1699,13 @@ void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist) v->orders.list->FreeChain(keep_orderlist); if (!keep_orderlist) v->orders.list = NULL; } + + if (reset_order_indices) { + v->cur_auto_order_index = v->cur_real_order_index = 0; + if (v->current_order.IsType(OT_LOADING)) { + CancelLoadingDueToDeletedOrder(v); + } + } } /** @@ -1927,6 +1942,7 @@ bool ProcessOrders(Vehicle *v) } /* Get the current order */ + assert(v->cur_auto_order_index == 0 || v->cur_auto_order_index < v->GetNumOrders()); v->UpdateRealOrderIndex(); const Order *order = v->GetOrder(v->cur_real_order_index); diff --git a/src/order_func.h b/src/order_func.h index 235f9cdc95..c6ed76d23a 100644 --- a/src/order_func.h +++ b/src/order_func.h @@ -20,7 +20,7 @@ void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination); void InvalidateVehicleOrder(const Vehicle *v, int data); void CheckOrders(const Vehicle*); -void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist = false); +void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist = false, bool reset_order_indices = true); bool ProcessOrders(Vehicle *v); bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth = 0); VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v); diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 17ac9bc814..fe99e3c3e5 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -2564,6 +2564,9 @@ bool AfterLoadGame() FOR_ALL_VEHICLES(v) { if (!v->IsPrimaryVehicle()) continue; + /* Older versions are less strict with indices being in range and fix them on the fly */ + if (v->cur_auto_order_index >= v->GetNumOrders()) v->cur_auto_order_index = 0; + v->cur_real_order_index = v->cur_auto_order_index; v->UpdateRealOrderIndex(); }