diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -743,8 +743,17 @@ CommandCost CmdInsertOrder(DoCommandFlag /* Filter invalid load/unload types. */ switch (new_order.GetLoadType()) { - case OLF_LOAD_IF_POSSIBLE: case OLFB_FULL_LOAD: case OLF_FULL_LOAD_ANY: case OLFB_NO_LOAD: break; - default: return CMD_ERROR; + case OLF_LOAD_IF_POSSIBLE: + case OLFB_NO_LOAD: + break; + + case OLFB_FULL_LOAD: + case OLF_FULL_LOAD_ANY: + if (v->HasUnbunchingOrder()) return_cmd_error(STR_ERROR_UNBUNCHING_NO_FULL_LOAD); + break; + + default: + return CMD_ERROR; } switch (new_order.GetUnloadType()) { case OUF_UNLOAD_IF_POSSIBLE: case OUFB_UNLOAD: case OUFB_TRANSFER: case OUFB_NO_UNLOAD: break; @@ -849,6 +858,7 @@ CommandCost CmdInsertOrder(DoCommandFlag VehicleOrderID skip_to = new_order.GetConditionSkipToOrder(); if (skip_to != 0 && skip_to >= v->GetNumOrders()) return CMD_ERROR; // Always allow jumping to the first (even when there is no order). if (new_order.GetConditionVariable() >= OCV_END) return CMD_ERROR; + if (v->HasUnbunchingOrder()) return_cmd_error(STR_ERROR_UNBUNCHING_NO_CONDITIONAL); OrderConditionComparator occ = new_order.GetConditionComparator(); if (occ >= OCC_END) return CMD_ERROR; @@ -937,6 +947,9 @@ void InsertOrder(Vehicle *v, Order *new_ u->cur_implicit_order_index = cur; } } + /* Unbunching data is no longer valid. */ + u->ResetDepotUnbunching(); + /* Update any possible open window of the vehicle */ InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 8)); } @@ -1051,6 +1064,8 @@ void DeleteOrder(Vehicle *v, VehicleOrde if (u->cur_implicit_order_index >= u->GetNumOrders()) u->cur_implicit_order_index = 0; } } + /* Unbunching data is no longer valid. */ + u->ResetDepotUnbunching(); /* Update any possible open window of the vehicle */ InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8)); @@ -1097,6 +1112,9 @@ CommandCost CmdSkipToOrder(DoCommandFlag v->cur_implicit_order_index = v->cur_real_order_index = sel_ord; v->UpdateRealOrderIndex(); + /* Unbunching data is no longer valid. */ + v->ResetDepotUnbunching(); + InvalidateVehicleOrder(v, VIWD_MODIFY_ORDERS); /* We have an aircraft/ship, they have a mini-schedule, so update them all */ @@ -1173,6 +1191,9 @@ CommandCost CmdMoveOrder(DoCommandFlag f } else if (u->cur_implicit_order_index < moving_order && u->cur_implicit_order_index >= target_order) { u->cur_implicit_order_index++; } + /* Unbunching data is no longer valid. */ + u->ResetDepotUnbunching(); + assert(v->orders == u->orders); /* Update any possible open window of the vehicle */ @@ -1274,10 +1295,27 @@ CommandCost CmdModifyOrder(DoCommandFlag if (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) return CMD_ERROR; if (data > OLFB_NO_LOAD || data == 1) return CMD_ERROR; if (data == order->GetLoadType()) return CMD_ERROR; + if ((data & (OLFB_FULL_LOAD | OLF_FULL_LOAD_ANY)) && v->HasUnbunchingOrder()) return_cmd_error(STR_ERROR_UNBUNCHING_NO_FULL_LOAD); break; case MOF_DEPOT_ACTION: if (data >= DA_END) return CMD_ERROR; + /* The vehicle must always go to the depot (not just if it needs servicing) in order to unbunch there. */ + if ((data == DA_SERVICE) && (order->GetDepotActionType() & ODATFB_UNBUNCH)) return_cmd_error(STR_ERROR_UNBUNCHING_NO_SERVICE_IF_NEEDED); + + /* Check if we are allowed to add unbunching. We are always allowed to remove it. */ + if (data == DA_UNBUNCH) { + /* Only one unbunching order is allowed in a vehicle's orders. If this order already has an unbunching action, no error is needed. */ + if (v->HasUnbunchingOrder() && !(order->GetDepotActionType() & ODATFB_UNBUNCH)) return_cmd_error(STR_ERROR_UNBUNCHING_ONLY_ONE_ALLOWED); + for (Order *o : v->Orders()) { + /* We don't allow unbunching if the vehicle has a conditional order. */ + if (o->IsType(OT_CONDITIONAL)) return_cmd_error(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_CONDITIONAL); + /* We don't allow unbunching if the vehicle has a full load order. */ + if (o->IsType(OT_GOTO_STATION) && o->GetLoadType() & (OLFB_FULL_LOAD | OLF_FULL_LOAD_ANY)) return_cmd_error(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_FULL_LOAD); + /* The vehicle must always go to the depot (not just if it needs servicing) in order to unbunch there. */ + if (o->IsType(OT_GOTO_DEPOT) && o->GetDepotOrderType() & ODTFB_SERVICE) return_cmd_error(STR_ERROR_UNBUNCHING_NO_SERVICE_IF_NEEDED); + } + } break; case MOF_COND_VARIABLE: @@ -1350,6 +1388,7 @@ CommandCost CmdModifyOrder(DoCommandFlag case DA_ALWAYS_GO: order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE)); order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT)); + order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_UNBUNCH)); break; case DA_SERVICE: @@ -1360,10 +1399,17 @@ CommandCost CmdModifyOrder(DoCommandFlag case DA_STOP: order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE)); + order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_UNBUNCH)); order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() | ODATFB_HALT)); order->SetRefit(CARGO_NO_REFIT); break; + case DA_UNBUNCH: + order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE)); + order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT)); + order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() | ODATFB_UNBUNCH)); + break; + default: NOT_REACHED(); } @@ -1430,6 +1476,10 @@ CommandCost CmdModifyOrder(DoCommandFlag u->current_order.GetLoadType() != order->GetLoadType()) { u->current_order.SetLoadType(order->GetLoadType()); } + + /* Unbunching data is no longer valid. */ + u->ResetDepotUnbunching(); + InvalidateVehicleOrder(u, VIWD_MODIFY_ORDERS); } } @@ -1835,6 +1885,9 @@ void DeleteVehicleOrders(Vehicle *v, boo if (!keep_orderlist) v->orders = nullptr; } + /* Unbunching data is no longer valid. */ + v->ResetDepotUnbunching(); + if (reset_order_indices) { v->cur_implicit_order_index = v->cur_real_order_index = 0; if (v->current_order.IsType(OT_LOADING)) {