From a97d52a29a990132a8a5e4dd60304483617cec50 Mon Sep 17 00:00:00 2001 From: frosch Date: Mon, 31 Jan 2011 20:44:15 +0000 Subject: (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. --- src/ai/api/ai_order.cpp | 2 +- src/newgrf_engine.cpp | 2 +- src/order_backup.cpp | 7 ++- src/order_cmd.cpp | 127 +++++++++++++++++++++++++++++++----------- src/order_gui.cpp | 15 +++-- src/roadveh_cmd.cpp | 2 +- src/saveload/afterload.cpp | 8 +++ src/saveload/oldloader_sl.cpp | 2 +- src/saveload/saveload.cpp | 3 +- src/saveload/vehicle_sl.cpp | 3 +- src/ship_cmd.cpp | 6 +- src/timetable_cmd.cpp | 8 +-- src/timetable_gui.cpp | 4 +- src/train_cmd.cpp | 6 +- src/vehicle.cpp | 54 +++++++++--------- src/vehicle_base.h | 84 +++++++++++++++++++++++++--- src/vehicle_gui.cpp | 4 +- 17 files changed, 241 insertions(+), 96 deletions(-) (limited to 'src') diff --git a/src/ai/api/ai_order.cpp b/src/ai/api/ai_order.cpp index fbf284563..3bde539be 100644 --- a/src/ai/api/ai_order.cpp +++ b/src/ai/api/ai_order.cpp @@ -132,7 +132,7 @@ static const Order *ResolveOrder(VehicleID vehicle_id, AIOrder::OrderPosition or if (!AIVehicle::IsValidVehicle(vehicle_id)) return ORDER_INVALID; if (order_position == ORDER_CURRENT) { - int cur_order_pos = ::Vehicle::Get(vehicle_id)->cur_order_index; + int cur_order_pos = ::Vehicle::Get(vehicle_id)->cur_real_order_index; const Order *order = ::Vehicle::Get(vehicle_id)->GetOrder(0); if (order == NULL) return ORDER_INVALID; int num_automatic_orders = 0; diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index 76c5572f0..dc1dffcf4 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -690,7 +690,7 @@ static uint32 VehicleGetVariable(const ResolverObject *object, byte variable, by case 0x0A: return v->current_order.MapOldOrder(); case 0x0B: return v->current_order.GetDestination(); case 0x0C: return v->GetNumOrders(); - case 0x0D: return v->cur_order_index; + case 0x0D: return v->cur_real_order_index; case 0x10: case 0x11: { uint ticks; diff --git a/src/order_backup.cpp b/src/order_backup.cpp index 39f9c5d36..78091d97b 100644 --- a/src/order_backup.cpp +++ b/src/order_backup.cpp @@ -44,7 +44,7 @@ OrderBackup::OrderBackup(const Vehicle *v, uint32 user) { this->user = user; this->tile = v->tile; - this->orderindex = v->cur_order_index; + this->orderindex = v->cur_auto_order_index; this->group = v->group_id; this->service_interval = v->service_interval; @@ -87,7 +87,10 @@ void OrderBackup::DoRestore(Vehicle *v) } uint num_orders = v->GetNumOrders(); - if (num_orders != 0) v->cur_order_index = this->orderindex % num_orders; + if (num_orders != 0) { + v->cur_real_order_index = v->cur_auto_order_index = this->orderindex % num_orders; + v->UpdateRealOrderIndex(); + } v->service_interval = this->service_interval; /* Restore vehicle group */ 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))) { diff --git a/src/order_gui.cpp b/src/order_gui.cpp index 2ad2893e4..d98140432 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -195,8 +195,11 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int SpriteID sprite = rtl ? SPR_ARROW_LEFT : SPR_ARROW_RIGHT; Dimension sprite_size = GetSpriteSize(sprite); - if (v->cur_order_index == order_index) { - DrawSprite(sprite, PAL_NONE, rtl ? right - sprite_size.width : left, y + ((int)FONT_HEIGHT_NORMAL - (int)sprite_size.height) / 2); + if (v->cur_real_order_index == order_index) { + DrawSprite(sprite, PAL_NONE, rtl ? right - sprite_size.width : left, y + ((int)FONT_HEIGHT_NORMAL - (int)sprite_size.height) / 2); + DrawSprite(sprite, PAL_NONE, rtl ? right - 2 * sprite_size.width : left + sprite_size.width, y + ((int)FONT_HEIGHT_NORMAL - (int)sprite_size.height) / 2); + } else if (v->cur_auto_order_index == order_index) { + DrawSprite(sprite, PAL_NONE, rtl ? right - sprite_size.width : left, y + ((int)FONT_HEIGHT_NORMAL - (int)sprite_size.height) / 2); } TextColour colour = TC_BLACK; @@ -207,7 +210,7 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int } SetDParam(0, order_index + 1); - DrawString(left, rtl ? right - sprite_size.width - 3 : middle, y, STR_ORDER_INDEX, colour, SA_RIGHT | SA_FORCE); + DrawString(left, rtl ? right - 2 * sprite_size.width - 3 : middle, y, STR_ORDER_INDEX, colour, SA_RIGHT | SA_FORCE); SetDParam(5, STR_EMPTY); @@ -684,10 +687,10 @@ private: void OrderClick_Skip(int i) { /* Don't skip when there's nothing to skip */ - if (_ctrl_pressed && this->vehicle->cur_order_index == this->OrderGetSel()) return; + if (_ctrl_pressed && this->vehicle->cur_auto_order_index == this->OrderGetSel()) return; if (this->vehicle->GetNumOrders() <= 1) return; - DoCommandP(this->vehicle->tile, this->vehicle->index, _ctrl_pressed ? this->OrderGetSel() : ((this->vehicle->cur_order_index + 1) % this->vehicle->GetNumOrders()), + DoCommandP(this->vehicle->tile, this->vehicle->index, _ctrl_pressed ? this->OrderGetSel() : ((this->vehicle->cur_auto_order_index + 1) % this->vehicle->GetNumOrders()), CMD_SKIP_TO_ORDER | CMD_MSG(_ctrl_pressed ? STR_ERROR_CAN_T_SKIP_TO_ORDER : STR_ERROR_CAN_T_SKIP_ORDER)); } @@ -1026,7 +1029,7 @@ public: bool rtl = _current_text_dir == TD_RTL; SetDParam(0, 99); - int index_column_width = GetStringBoundingBox(STR_ORDER_INDEX).width + GetSpriteSize(rtl ? SPR_ARROW_RIGHT : SPR_ARROW_LEFT).width + 3; + int index_column_width = GetStringBoundingBox(STR_ORDER_INDEX).width + 2 * GetSpriteSize(rtl ? SPR_ARROW_RIGHT : SPR_ARROW_LEFT).width + 3; int middle = rtl ? r.right - WD_FRAMETEXT_RIGHT - index_column_width : r.left + WD_FRAMETEXT_LEFT + index_column_width; int y = r.top + WD_FRAMERECT_TOP; diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index 931c74d1c..2390a8fba 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -525,7 +525,7 @@ TileIndex RoadVehicle::GetOrderStationLocation(StationID station) const Station *st = Station::Get(station); if (!CanVehicleUseStation(this, st)) { /* There is no stop left at the station, so don't even TRY to go there */ - this->IncrementOrderIndex(); + this->IncrementRealOrderIndex(); return 0; } diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 35a5579ba..5948415a6 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -2536,6 +2536,14 @@ bool AfterLoadGame() * it should have set v->z_pos correctly. */ assert(v->tile != TileVirtXY(v->x_pos, v->y_pos) || v->z_pos == GetSlopeZ(v->x_pos, v->y_pos)); } + + /* Fill Vehicle::cur_real_order_index */ + FOR_ALL_VEHICLES(v) { + if (!v->IsPrimaryVehicle()) continue; + + v->cur_real_order_index = v->cur_auto_order_index; + v->UpdateRealOrderIndex(); + } } /* Road stops is 'only' updating some caches */ diff --git a/src/saveload/oldloader_sl.cpp b/src/saveload/oldloader_sl.cpp index e846c1ce5..d177e7207 100644 --- a/src/saveload/oldloader_sl.cpp +++ b/src/saveload/oldloader_sl.cpp @@ -1138,7 +1138,7 @@ static const OldChunks vehicle_chunk[] = { OCL_VAR ( OC_UINT16, 1, &_old_order ), OCL_NULL ( 1 ), ///< num_orders, now calculated - OCL_SVAR( OC_UINT8, Vehicle, cur_order_index ), + OCL_SVAR( OC_UINT8, Vehicle, cur_auto_order_index ), OCL_SVAR( OC_TILE, Vehicle, dest_tile ), OCL_SVAR( OC_UINT16, Vehicle, load_unload_ticks ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, date_of_last_service ), diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index ec0bec7b1..552b008ab 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -222,8 +222,9 @@ * 155 21453 * 156 21728 * 157 21862 + * 158 21933 */ -extern const uint16 SAVEGAME_VERSION = 157; ///< Current savegame version of OpenTTD. +extern const uint16 SAVEGAME_VERSION = 158; ///< Current savegame version of OpenTTD. SavegameType _savegame_type; ///< type of savegame we are loading diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp index 8abcb916b..d1558d966 100644 --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -487,7 +487,8 @@ const SaveLoad *GetVehicleDescription(VehicleType vt) SLE_VAR(Vehicle, tick_counter, SLE_UINT8), SLE_CONDVAR(Vehicle, running_ticks, SLE_UINT8, 88, SL_MAX_VERSION), - SLE_VAR(Vehicle, cur_order_index, SLE_UINT8), + SLE_VAR(Vehicle, cur_auto_order_index, SLE_UINT8), + SLE_CONDVAR(Vehicle, cur_real_order_index, SLE_UINT8, 158, SL_MAX_VERSION), /* num_orders is now part of OrderList and is not saved but counted */ SLE_CONDNULL(1, 0, 104), diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index f5a6ac640..6e733d360 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -234,7 +234,7 @@ TileIndex Ship::GetOrderStationLocation(StationID station) if (st->dock_tile != INVALID_TILE) { return TILE_ADD(st->dock_tile, ToTileIndexDiff(GetDockOffset(st->dock_tile))); } else { - this->IncrementOrderIndex(); + this->IncrementRealOrderIndex(); return 0; } } @@ -480,7 +480,7 @@ static void ShipController(Ship *v) /* We got within 3 tiles of our target buoy, so let's skip to our * next order */ UpdateVehicleTimetable(v, true); - v->IncrementOrderIndex(); + v->IncrementRealOrderIndex(); v->current_order.MakeDummy(); } else { /* Non-buoy orders really need to reach the tile */ @@ -500,7 +500,7 @@ static void ShipController(Ship *v) v->BeginLoading(); } else { // leave stations without docks right aways v->current_order.MakeLeaveStation(); - v->IncrementOrderIndex(); + v->IncrementRealOrderIndex(); } } } diff --git a/src/timetable_cmd.cpp b/src/timetable_cmd.cpp index 94c9812ef..688a5d15e 100644 --- a/src/timetable_cmd.cpp +++ b/src/timetable_cmd.cpp @@ -33,7 +33,7 @@ static void ChangeTimetable(Vehicle *v, VehicleOrderID order_number, uint16 time v->orders.list->UpdateOrderTimetable(delta); for (v = v->FirstShared(); v != NULL; v = v->NextShared()) { - if (v->cur_order_index == order_number && v->current_order.Equals(*order)) { + if (v->cur_real_order_index == order_number && v->current_order.Equals(*order)) { if (is_journey) { v->current_order.travel_time = time; } else { @@ -248,7 +248,7 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling) bool just_started = false; /* This vehicle is arriving at the first destination in the timetable. */ - if (v->cur_order_index == first_manual_order && travelling) { + if (v->cur_real_order_index == first_manual_order && travelling) { /* If the start date hasn't been set, or it was set automatically when * the vehicle last arrived at the first destination, update it to the * current time. Otherwise set the late counter appropriately to when @@ -288,10 +288,10 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling) * processing of different orders when filling the timetable. */ time_taken = CeilDiv(max(time_taken, 1U), DAY_TICKS) * DAY_TICKS; - ChangeTimetable(v, v->cur_order_index, time_taken, travelling); + ChangeTimetable(v, v->cur_real_order_index, time_taken, travelling); } - if (v->cur_order_index == first_manual_order && travelling) { + if (v->cur_real_order_index == first_manual_order && travelling) { /* If we just started we would have returned earlier and have not reached * this code. So obviously, we have completed our round: So turn autofill * off again. */ diff --git a/src/timetable_gui.cpp b/src/timetable_gui.cpp index 6fcd5e9f8..dc807fe77 100644 --- a/src/timetable_gui.cpp +++ b/src/timetable_gui.cpp @@ -206,7 +206,7 @@ struct TimetableWindow : Window { bool travelling = (!v->current_order.IsType(OT_LOADING) || v->current_order.GetNonStopType() == ONSF_STOP_EVERYWHERE); Ticks start_time = _date_fract - v->current_order_time; - FillTimetableArrivalDepartureTable(v, v->cur_order_index % v->GetNumOrders(), travelling, table, start_time); + FillTimetableArrivalDepartureTable(v, v->cur_real_order_index % v->GetNumOrders(), travelling, table, start_time); return (travelling && v->lateness_counter < 0); } @@ -425,7 +425,7 @@ struct TimetableWindow : Window { if (total_time <= 0 || v->GetNumOrders() <= 1 || !HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) break; TimetableArrivalDeparture *arr_dep = AllocaM(TimetableArrivalDeparture, v->GetNumOrders()); - const VehicleOrderID cur_order = v->cur_order_index % v->GetNumOrders(); + const VehicleOrderID cur_order = v->cur_real_order_index % v->GetNumOrders(); VehicleOrderID earlyID = BuildArrivalDepartureList(v, arr_dep) ? cur_order : (VehicleOrderID)INVALID_VEH_ORDER_ID; diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 42ceb8ae8..58f19b6bf 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -2291,7 +2291,7 @@ public: old_order(_v->current_order), old_dest_tile(_v->dest_tile), old_last_station_visited(_v->last_station_visited), - index(_v->cur_order_index) + index(_v->cur_real_order_index) { } @@ -2348,7 +2348,7 @@ public: /* Don't increment inside the while because otherwise conditional * orders can lead to an infinite loop. */ ++this->index; - } while (this->index != this->v->cur_order_index); + } while (this->index != this->v->cur_real_order_index); return false; } @@ -2602,7 +2602,7 @@ TileIndex Train::GetOrderStationLocation(StationID station) const Station *st = Station::Get(station); if (!(st->facilities & FACIL_TRAIN)) { /* The destination station has no trainstation tiles. */ - this->IncrementOrderIndex(); + this->IncrementRealOrderIndex(); return 0; } diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 50aa1c5c5..ada4948ea 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -1266,7 +1266,7 @@ void VehicleEnterDepot(Vehicle *v) if (v->current_order.IsType(OT_GOTO_DEPOT)) { SetWindowDirty(WC_VEHICLE_VIEW, v->index); - const Order *real_order = v->GetNextManualOrder(v->cur_order_index); + const Order *real_order = v->GetOrder(v->cur_real_order_index); Order t = v->current_order; v->current_order.MakeDummy(); @@ -1303,7 +1303,7 @@ void VehicleEnterDepot(Vehicle *v) /* Part of orders */ v->DeleteUnreachedAutoOrders(); UpdateVehicleTimetable(v, true); - v->IncrementOrderIndex(); + v->IncrementAutoOrderIndex(); } if (t.GetDepotActionType() & ODATFB_HALT) { /* Vehicles are always stopped on entering depots. Do not restart this one. */ @@ -1797,11 +1797,25 @@ uint GetVehicleCapacity(const Vehicle *v, uint16 *mail_capacity) */ void Vehicle::DeleteUnreachedAutoOrders() { - const Order *order = this->GetOrder(this->cur_order_index); - while (order != NULL && order->IsType(OT_AUTOMATIC)) { - /* Delete order effectively deletes order, so get the next before deleting it. */ - order = order->next; - DeleteOrder(this, this->cur_order_index); + const Order *order = this->GetOrder(this->cur_auto_order_index); + while (order != NULL) { + if (this->cur_auto_order_index == this->cur_real_order_index) break; + + if (order->IsType(OT_AUTOMATIC)) { + /* Delete order effectively deletes order, so get the next before deleting it. */ + order = order->next; + DeleteOrder(this, this->cur_auto_order_index); + } else { + /* Skip non-automatic orders, e.g. service-orders */ + order = order->next; + this->cur_auto_order_index++; + } + + /* Wrap around */ + if (order == NULL) { + order = this->GetOrder(0); + this->cur_auto_order_index = 0; + } } } @@ -1817,7 +1831,7 @@ void Vehicle::BeginLoading() this->current_order.GetDestination() == this->last_station_visited) { this->DeleteUnreachedAutoOrders(); - /* Now cur_order_index points to the destination station, and we can start loading */ + /* Now both order indices point to the destination station, and we can start loading */ this->current_order.MakeLoading(true); UpdateVehicleTimetable(this, true); @@ -1832,14 +1846,14 @@ void Vehicle::BeginLoading() /* We weren't scheduled to stop here. Insert an automatic order * to show that we are stopping here, but only do that if the order * list isn't empty. */ - Order *in_list = this->GetOrder(this->cur_order_index); + Order *in_list = this->GetOrder(this->cur_auto_order_index); if (in_list != NULL && this->orders.list->GetNumOrders() < MAX_VEH_ORDER_ID && (!in_list->IsType(OT_AUTOMATIC) || in_list->GetDestination() != this->last_station_visited)) { Order *auto_order = new Order(); auto_order->MakeAutomatic(this->last_station_visited); - InsertOrder(this, auto_order, this->cur_order_index); - if (this->cur_order_index > 0) --this->cur_order_index; + InsertOrder(this, auto_order, this->cur_auto_order_index); + if (this->cur_auto_order_index > 0) --this->cur_auto_order_index; } this->current_order.MakeLoading(false); } @@ -1913,7 +1927,7 @@ void Vehicle::HandleLoading(bool mode) default: return; } - this->IncrementOrderIndex(); + this->IncrementAutoOrderIndex(); } /** @@ -1948,7 +1962,7 @@ CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command) if (flags & DC_EXEC) { /* If the orders to 'goto depot' are in the orders list (forced servicing), * then skip to the next order; effectively cancelling this forced service */ - if (this->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) this->IncrementOrderIndex(); + if (this->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) this->IncrementRealOrderIndex(); this->current_order.MakeDummy(); SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH); @@ -2261,20 +2275,6 @@ void Vehicle::RemoveFromShared() this->previous_shared = NULL; } -/** - * Get the next manual (not OT_AUTOMATIC) order after the one at the given index. - * @param index The index to start searching at. - * @return The next manual order at or after index or NULL if there is none. - */ -Order *Vehicle::GetNextManualOrder(int index) const -{ - Order *order = this->GetOrder(index); - while (order != NULL && order->IsType(OT_AUTOMATIC)) { - order = order->next; - } - return order; -} - void VehiclesYearlyLoop() { Vehicle *v; diff --git a/src/vehicle_base.h b/src/vehicle_base.h index 623f534fb..a838edcbf 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -222,7 +222,8 @@ public: byte vehstatus; ///< Status Order current_order; ///< The current order (+ status, like: loading) - VehicleOrderID cur_order_index; ///< The index to the current order + VehicleOrderID cur_real_order_index;///< The index to the current real (non-automatic) order + VehicleOrderID cur_auto_order_index;///< The index to the current automatic order union { OrderList *list; ///< Pointer to the order list for this vehicle @@ -549,7 +550,8 @@ public: { this->unitnumber = src->unitnumber; - this->cur_order_index = src->cur_order_index; + this->cur_real_order_index = src->cur_real_order_index; + this->cur_auto_order_index = src->cur_auto_order_index; this->current_order = src->current_order; this->dest_tile = src->dest_tile; @@ -599,17 +601,85 @@ public: void UpdateVisualEffect(bool allow_power_change = true); void ShowVisualEffect() const; +private: /** - * Increments cur_order_index, keeps care of the wrap-around and invalidates the GUI. + * Advance cur_real_order_index to the next real order. + * cur_auto_order_index is not touched. + */ + void SkipToNextRealOrderIndex() + { + if (this->GetNumManualOrders() > 0) { + /* Advance to next real order */ + do { + this->cur_real_order_index++; + if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0; + } while (this->GetOrder(this->cur_real_order_index)->IsType(OT_AUTOMATIC)); + } else { + this->cur_real_order_index = 0; + } + } + +public: + /** + * Increments cur_auto_order_index, keeps care of the wrap-around and invalidates the GUI. + * cur_real_order_index is incremented as well, if needed. * Note: current_order is not invalidated. */ - void IncrementOrderIndex() + void IncrementAutoOrderIndex() { - this->cur_order_index++; - if (this->cur_order_index >= this->GetNumOrders()) this->cur_order_index = 0; + if (this->cur_auto_order_index == this->cur_real_order_index) { + /* Increment real order index as well */ + this->SkipToNextRealOrderIndex(); + } + + assert(this->cur_real_order_index == 0 || this->cur_real_order_index < this->GetNumOrders()); + + /* Advance to next automatic order */ + do { + this->cur_auto_order_index++; + if (this->cur_auto_order_index >= this->GetNumOrders()) this->cur_auto_order_index = 0; + } while (this->cur_auto_order_index != this->cur_real_order_index && !this->GetOrder(this->cur_auto_order_index)->IsType(OT_AUTOMATIC)); + InvalidateVehicleOrder(this, 0); } + /** + * Advanced cur_real_order_index to the next real order, keeps care of the wrap-around and invalidates the GUI. + * cur_auto_order_index is incremented as well, if it was equal to cur_real_order_index, i.e. cur_real_order_index is skipped + * but not any automatic orders. + * Note: current_order is not invalidated. + */ + void IncrementRealOrderIndex() + { + if (this->cur_auto_order_index == this->cur_real_order_index) { + /* Increment both real and auto order */ + this->IncrementAutoOrderIndex(); + } else { + /* Increment real order only */ + this->SkipToNextRealOrderIndex(); + InvalidateVehicleOrder(this, 0); + } + } + + /** + * Skip automatic orders until cur_real_order_index is a non-automatic order. + */ + void UpdateRealOrderIndex() + { + /* Make sure the index is valid */ + if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0; + + if (this->GetNumManualOrders() > 0) { + /* Advance to next real order */ + while (this->GetOrder(this->cur_real_order_index)->IsType(OT_AUTOMATIC)) { + this->cur_real_order_index++; + if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0; + } + } else { + this->cur_real_order_index = 0; + } + } + /** * Returns order 'index' of a vehicle or NULL when it doesn't exists * @param index the order to fetch @@ -620,8 +690,6 @@ public: return (this->orders.list == NULL) ? NULL : this->orders.list->GetOrderAt(index); } - Order *GetNextManualOrder(int index) const; - /** * Returns the last order of a vehicle, or NULL if it doesn't exists * @return last order of a vehicle, if available diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index e16b8deee..a6197c608 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -1187,7 +1187,7 @@ static void DrawSmallOrderList(const Vehicle *v, int left, int right, int y, Veh VehicleOrderID oid = start; do { - if (oid == v->cur_order_index) DrawString(left, right, y, STR_TINY_RIGHT_ARROW, TC_BLACK); + if (oid == v->cur_real_order_index) DrawString(left, right, y, STR_TINY_RIGHT_ARROW, TC_BLACK); if (order->IsType(OT_GOTO_STATION)) { SetDParam(0, order->GetDestination()); @@ -1294,7 +1294,7 @@ void BaseVehicleListWindow::DrawVehicleListItems(VehicleID selected_vehicle, int DrawString(text_left, text_right, y, STR_TINY_GROUP, TC_BLACK); } - if (show_orderlist) DrawSmallOrderList(v, orderlist_left, orderlist_right, y, v->cur_order_index); + if (show_orderlist) DrawSmallOrderList(v, orderlist_left, orderlist_right, y, v->cur_real_order_index); if (v->IsInDepot()) { str = STR_BLUE_COMMA; -- cgit v1.2.3-70-g09d2