mirror of https://github.com/OpenTTD/OpenTTD
Feature #8095: Allow automatically separating vehicles in shared orders
parent
661e0cd82d
commit
0f0dbc0b3b
|
@ -42,3 +42,12 @@ void BaseConsist::CopyConsistPropertiesFrom(const BaseConsist *src)
|
|||
}
|
||||
if (HasBit(src->vehicle_flags, VF_SERVINT_IS_CUSTOM)) SetBit(this->vehicle_flags, VF_SERVINT_IS_CUSTOM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets all the data used for automatic separation
|
||||
*/
|
||||
void BaseConsist::ResetAutomaticSeparation()
|
||||
{
|
||||
this->first_order_last_departure = 0;
|
||||
this->first_order_round_trip_time = 0;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,9 @@ struct BaseConsist {
|
|||
TimerGameTick::Ticks lateness_counter; ///< How many ticks late (or early if negative) this vehicle is.
|
||||
TimerGameTick::TickCounter timetable_start; ///< At what tick of TimerGameTick::counter the vehicle should start its timetable.
|
||||
|
||||
TimerGameTick::Ticks first_order_last_departure; ///< When the vehicle last left the first order.
|
||||
TimerGameTick::Ticks first_order_round_trip_time; ///< How many ticks for a single circumnavigation of the orders.
|
||||
|
||||
uint16_t service_interval; ///< The interval for (automatic) servicing; either in days or %.
|
||||
|
||||
VehicleOrderID cur_real_order_index;///< The index to the current real (non-implicit) order
|
||||
|
@ -32,6 +35,7 @@ struct BaseConsist {
|
|||
virtual ~BaseConsist() = default;
|
||||
|
||||
void CopyConsistPropertiesFrom(const BaseConsist *src);
|
||||
void ResetAutomaticSeparation();
|
||||
};
|
||||
|
||||
#endif /* BASE_CONSIST_H */
|
||||
|
|
|
@ -239,6 +239,7 @@ enum Commands : uint16_t {
|
|||
CMD_SKIP_TO_ORDER, ///< skip an order to the next of specific one
|
||||
CMD_DELETE_ORDER, ///< delete an order
|
||||
CMD_INSERT_ORDER, ///< insert a new order
|
||||
CMD_ORDER_AUTOMATIC_SEPARATION, ///< set automatic separation
|
||||
|
||||
CMD_CHANGE_SERVICE_INT, ///< change the server interval of a vehicle
|
||||
|
||||
|
|
|
@ -4485,6 +4485,9 @@ STR_ORDERS_DELETE_ALL_TOOLTIP :{BLACK}Delete a
|
|||
STR_ORDERS_STOP_SHARING_BUTTON :{BLACK}Stop sharing
|
||||
STR_ORDERS_STOP_SHARING_TOOLTIP :{BLACK}Stop sharing the order list. Ctrl+Click additionally deletes all orders for this vehicle
|
||||
|
||||
STR_ORDERS_AUTOMATIC_SEPARATION :{BLACK}Automatic separation
|
||||
STR_ORDERS_AUTOMATIC_SEPARATION_TOOLTIP :{BLACK}Automatically separate all vehicles sharing this order
|
||||
|
||||
STR_ORDERS_GO_TO_BUTTON :{BLACK}Go To
|
||||
STR_ORDER_GO_TO_NEAREST_DEPOT :Go to nearest depot
|
||||
STR_ORDER_GO_TO_NEAREST_HANGAR :Go to nearest hangar
|
||||
|
|
|
@ -271,6 +271,8 @@ private:
|
|||
TimerGameTick::Ticks timetable_duration; ///< NOSAVE: Total timetabled duration of the order list.
|
||||
TimerGameTick::Ticks total_duration; ///< NOSAVE: Total (timetabled or not) duration of the order list.
|
||||
|
||||
bool automatic_separation; ///< Is automatic separation enabled?
|
||||
|
||||
public:
|
||||
/** Default constructor producing an invalid order list. */
|
||||
OrderList(VehicleOrderID num_orders = INVALID_VEH_ORDER_ID)
|
||||
|
@ -392,6 +394,18 @@ public:
|
|||
*/
|
||||
void UpdateTotalDuration(TimerGameTick::Ticks delta) { this->total_duration += delta; }
|
||||
|
||||
/**
|
||||
* Is this order list using automatic separation?
|
||||
* @return whether automatic separation is enabled
|
||||
*/
|
||||
inline bool AutomaticSeparationIsEnabled() const { return this->automatic_separation; }
|
||||
|
||||
/**
|
||||
* Enables or disables automatic separation for this order list
|
||||
* @param enabled whether to enable (true) or disable (false) automatic separation
|
||||
*/
|
||||
void SetAutomaticSeparationIsEnabled(bool enabled) { this->automatic_separation = enabled; }
|
||||
|
||||
void FreeChain(bool keep_orderlist = false);
|
||||
|
||||
void DebugCheckSanity() const;
|
||||
|
|
|
@ -1466,6 +1466,36 @@ static bool CheckAircraftOrderDistance(const Aircraft *v_new, const Vehicle *v_o
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable automatic separation for a vehicle's order list
|
||||
* @param flags operation to perform
|
||||
* @param veh vehicle who's order list is being modified
|
||||
* @param enabled value indicating whether to enable (true) or disable (false) automatic separation
|
||||
* @return the cost of this operation or an error
|
||||
*/
|
||||
CommandCost CmdOrderAutomaticSeparation(DoCommandFlag flags, VehicleID veh, bool enabled)
|
||||
{
|
||||
Vehicle *vehicle = Vehicle::GetIfValid(veh);
|
||||
if (vehicle == nullptr || !vehicle->IsPrimaryVehicle()) return CMD_ERROR;
|
||||
|
||||
CommandCost ret = CheckOwnership(vehicle->owner);
|
||||
if (ret.Failed()) return ret;
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
vehicle->SetAutomaticSeparationIsEnabled(enabled);
|
||||
|
||||
if (!vehicle->AutomaticSeparationIsEnabled()) {
|
||||
Vehicle *v = vehicle->FirstShared();
|
||||
while (v != nullptr) {
|
||||
v->ResetAutomaticSeparation();
|
||||
v = v->NextShared();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CommandCost();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone/share/copy an order-list of another vehicle.
|
||||
* @param flags operation to perform
|
||||
|
@ -1835,6 +1865,8 @@ void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indic
|
|||
if (!keep_orderlist) v->orders = nullptr;
|
||||
}
|
||||
|
||||
v->ResetAutomaticSeparation();
|
||||
|
||||
if (reset_order_indices) {
|
||||
v->cur_implicit_order_index = v->cur_real_order_index = 0;
|
||||
if (v->current_order.IsType(OT_LOADING)) {
|
||||
|
|
|
@ -18,6 +18,7 @@ CommandCost CmdModifyOrder(DoCommandFlag flags, VehicleID veh, VehicleOrderID se
|
|||
CommandCost CmdSkipToOrder(DoCommandFlag flags, VehicleID veh_id, VehicleOrderID sel_ord);
|
||||
CommandCost CmdDeleteOrder(DoCommandFlag flags, VehicleID veh_id, VehicleOrderID sel_ord);
|
||||
CommandCost CmdInsertOrder(DoCommandFlag flags, VehicleID veh, VehicleOrderID sel_ord, const Order &new_order);
|
||||
CommandCost CmdOrderAutomaticSeparation(DoCommandFlag flags, VehicleID veh, bool enabled);
|
||||
CommandCost CmdOrderRefit(DoCommandFlag flags, VehicleID veh, VehicleOrderID order_number, CargoID cargo);
|
||||
CommandCost CmdCloneOrder(DoCommandFlag flags, CloneOptions action, VehicleID veh_dst, VehicleID veh_src);
|
||||
CommandCost CmdMoveOrder(DoCommandFlag flags, VehicleID veh, VehicleOrderID moving_order, VehicleOrderID target_order);
|
||||
|
@ -27,6 +28,7 @@ DEF_CMD_TRAIT(CMD_MODIFY_ORDER, CmdModifyOrder, CMD_LOCATION, CMDT_
|
|||
DEF_CMD_TRAIT(CMD_SKIP_TO_ORDER, CmdSkipToOrder, CMD_LOCATION, CMDT_ROUTE_MANAGEMENT)
|
||||
DEF_CMD_TRAIT(CMD_DELETE_ORDER, CmdDeleteOrder, CMD_LOCATION, CMDT_ROUTE_MANAGEMENT)
|
||||
DEF_CMD_TRAIT(CMD_INSERT_ORDER, CmdInsertOrder, CMD_LOCATION, CMDT_ROUTE_MANAGEMENT)
|
||||
DEF_CMD_TRAIT(CMD_ORDER_AUTOMATIC_SEPARATION, CmdOrderAutomaticSeparation, 0, CMDT_ROUTE_MANAGEMENT)
|
||||
DEF_CMD_TRAIT(CMD_ORDER_REFIT, CmdOrderRefit, CMD_LOCATION, CMDT_ROUTE_MANAGEMENT)
|
||||
DEF_CMD_TRAIT(CMD_CLONE_ORDER, CmdCloneOrder, CMD_LOCATION, CMDT_ROUTE_MANAGEMENT)
|
||||
DEF_CMD_TRAIT(CMD_MOVE_ORDER, CmdMoveOrder, CMD_LOCATION, CMDT_ROUTE_MANAGEMENT)
|
||||
|
|
|
@ -490,9 +490,9 @@ enum {
|
|||
* \section bottom-row Bottom row
|
||||
* The second row (the bottom row) is for manipulating the list of orders:
|
||||
* \verbatim
|
||||
* +-----------------+-----------------+-----------------+
|
||||
* | SKIP | DELETE | GOTO |
|
||||
* +-----------------+-----------------+-----------------+
|
||||
* +-----------------+-----------------+-----------------+-----------------+
|
||||
* | SKIP | DELETE | AUTO SEPARATION | GOTO |
|
||||
* +-----------------+-----------------+-----------------+-----------------+
|
||||
* \endverbatim
|
||||
*
|
||||
* For vehicles of other companies, both button rows are not displayed.
|
||||
|
@ -572,6 +572,16 @@ private:
|
|||
return sel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the click on the automatic separation button
|
||||
*/
|
||||
void OrderClick_AutomaticSeparation()
|
||||
{
|
||||
if (Command<CMD_ORDER_AUTOMATIC_SEPARATION>::Post(this->vehicle->index, !this->vehicle->AutomaticSeparationIsEnabled())) {
|
||||
this->UpdateButtonState();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the click on the goto button.
|
||||
*/
|
||||
|
@ -941,6 +951,10 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
/* automatic separation */
|
||||
this->SetWidgetDisabledState(WID_O_AUTOMATIC_SEPARATION, this->vehicle->GetNumOrders() == 0);
|
||||
this->SetWidgetLoweredState(WID_O_AUTOMATIC_SEPARATION, this->vehicle->AutomaticSeparationIsEnabled());
|
||||
|
||||
/* First row. */
|
||||
this->RaiseWidget(WID_O_FULL_LOAD);
|
||||
this->RaiseWidget(WID_O_UNLOAD);
|
||||
|
@ -1236,6 +1250,10 @@ public:
|
|||
}
|
||||
break;
|
||||
|
||||
case WID_O_AUTOMATIC_SEPARATION:
|
||||
this->OrderClick_AutomaticSeparation();
|
||||
break;
|
||||
|
||||
case WID_O_GOTO:
|
||||
if (this->GetWidget<NWidgetLeaf>(widget)->ButtonHit(pt)) {
|
||||
if (this->goto_type != OPOS_NONE) {
|
||||
|
@ -1629,6 +1647,8 @@ static const NWidgetPart _nested_orders_train_widgets[] = {
|
|||
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_O_STOP_SHARING), SetMinimalSize(124, 12), SetFill(1, 0),
|
||||
SetDataTip(STR_ORDERS_STOP_SHARING_BUTTON, STR_ORDERS_STOP_SHARING_TOOLTIP), SetResize(1, 0),
|
||||
EndContainer(),
|
||||
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_O_AUTOMATIC_SEPARATION), SetMinimalSize(124, 12), SetFill(1, 0),
|
||||
SetDataTip(STR_ORDERS_AUTOMATIC_SEPARATION, STR_ORDERS_AUTOMATIC_SEPARATION_TOOLTIP), SetResize(1, 0),
|
||||
NWidget(NWID_BUTTON_DROPDOWN, COLOUR_GREY, WID_O_GOTO), SetMinimalSize(124, 12), SetFill(1, 0),
|
||||
SetDataTip(STR_ORDERS_GO_TO_BUTTON, STR_ORDERS_GO_TO_TOOLTIP), SetResize(1, 0),
|
||||
EndContainer(),
|
||||
|
@ -1703,6 +1723,8 @@ static const NWidgetPart _nested_orders_widgets[] = {
|
|||
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_O_STOP_SHARING), SetMinimalSize(124, 12), SetFill(1, 0),
|
||||
SetDataTip(STR_ORDERS_STOP_SHARING_BUTTON, STR_ORDERS_STOP_SHARING_TOOLTIP), SetResize(1, 0),
|
||||
EndContainer(),
|
||||
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_O_AUTOMATIC_SEPARATION), SetMinimalSize(124, 12), SetFill(1, 0),
|
||||
SetDataTip(STR_ORDERS_AUTOMATIC_SEPARATION, STR_ORDERS_AUTOMATIC_SEPARATION_TOOLTIP), SetResize(1, 0),
|
||||
NWidget(NWID_BUTTON_DROPDOWN, COLOUR_GREY, WID_O_GOTO), SetMinimalSize(124, 12), SetFill(1, 0),
|
||||
SetDataTip(STR_ORDERS_GO_TO_BUTTON, STR_ORDERS_GO_TO_TOOLTIP), SetResize(1, 0),
|
||||
NWidget(WWT_RESIZEBOX, COLOUR_GREY),
|
||||
|
|
|
@ -202,6 +202,7 @@ SaveLoadTable GetOrderListDescription()
|
|||
{
|
||||
static const SaveLoad _orderlist_desc[] = {
|
||||
SLE_REF(OrderList, first, REF_ORDER),
|
||||
SLE_CONDVAR(OrderList, automatic_separation, SLE_BOOL, SLV_AUTOMATIC_SEPARATION, SL_MAX_VERSION),
|
||||
};
|
||||
|
||||
return _orderlist_desc;
|
||||
|
|
|
@ -331,6 +331,7 @@ enum SaveLoadVersion : uint16_t {
|
|||
SLV_CUSTOM_SUBSIDY_DURATION, ///< 292 PR#9081 Configurable subsidy duration.
|
||||
SLV_SAVELOAD_LIST_LENGTH, ///< 293 PR#9374 Consistency in list length with SL_STRUCT / SL_STRUCTLIST / SL_DEQUE / SL_REFLIST.
|
||||
SLV_RIFF_TO_ARRAY, ///< 294 PR#9375 Changed many CH_RIFF chunks to CH_ARRAY chunks.
|
||||
SLV_AUTOMATIC_SEPARATION, ///< 295 PR#8342 Allow automatically separating vehicles in shared orders.
|
||||
|
||||
SLV_TABLE_CHUNKS, ///< 295 PR#9322 Introduction of CH_TABLE and CH_SPARSE_TABLE.
|
||||
SLV_SCRIPT_INT64, ///< 296 PR#9415 SQInteger is 64bit but was saved as 32bit.
|
||||
|
|
|
@ -724,6 +724,9 @@ public:
|
|||
SLE_CONDVAR(Vehicle, current_order_time, SLE_INT32, SLV_TIMETABLE_TICKS_TYPE, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Vehicle, last_loading_tick, SLE_UINT64, SLV_LAST_LOADING_TICK, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Vehicle, lateness_counter, SLE_INT32, SLV_67, SL_MAX_VERSION),
|
||||
|
||||
SLE_CONDVAR(Vehicle, first_order_last_departure, SLE_INT32, SLV_AUTOMATIC_SEPARATION, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Vehicle, first_order_round_trip_time, SLE_INT32, SLV_AUTOMATIC_SEPARATION, SL_MAX_VERSION),
|
||||
};
|
||||
#if defined(_MSC_VER) && (_MSC_VER == 1915 || _MSC_VER == 1916)
|
||||
return description;
|
||||
|
|
|
@ -1537,6 +1537,7 @@ void VehicleEnterDepot(Vehicle *v)
|
|||
|
||||
v->vehstatus |= VS_HIDDEN;
|
||||
v->cur_speed = 0;
|
||||
v->ResetAutomaticSeparation();
|
||||
|
||||
VehicleServiceInDepot(v);
|
||||
|
||||
|
@ -2338,6 +2339,10 @@ void Vehicle::HandleLoading(bool mode)
|
|||
/* Not the first call for this tick, or still loading */
|
||||
if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) || this->current_order_time < wait_time) return;
|
||||
|
||||
this->UpdateAutomaticSeparation();
|
||||
|
||||
if (this->IsWaitingForAutomaticSeparation()) return;
|
||||
|
||||
this->PlayLeaveStationSound();
|
||||
|
||||
this->LeaveStation();
|
||||
|
@ -2360,6 +2365,96 @@ void Vehicle::HandleLoading(bool mode)
|
|||
this->IncrementImplicitOrderIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a vehicle is waiting for automatic separation (if not,
|
||||
* it is ready to depart)
|
||||
*/
|
||||
bool Vehicle::IsWaitingForAutomaticSeparation() const {
|
||||
TimerGameTick::Ticks now = TimerGameCalendar::date.base() * Ticks::DAY_TICKS + TimerGameCalendar::date_fract;
|
||||
return this->AutomaticSeparationIsEnabled() && this->first_order_last_departure > now;
|
||||
};
|
||||
|
||||
/**
|
||||
* If enabled, calculates the departure time for this vehicle based on the
|
||||
* automatic separation feature.
|
||||
*/
|
||||
void Vehicle::UpdateAutomaticSeparation()
|
||||
{
|
||||
/* Check this feature is enabled on the vehicle's orders */
|
||||
if (!this->AutomaticSeparationIsEnabled()) return;
|
||||
|
||||
/* Only perform the separation at the first manual order (saves on storage) */
|
||||
VehicleOrderID first_manual_order = 0;
|
||||
for (Order *o = this->GetFirstOrder(); o != nullptr && o->IsType(OT_IMPLICIT); o = o->next) {
|
||||
++first_manual_order;
|
||||
}
|
||||
if (this->cur_implicit_order_index != first_manual_order) return;
|
||||
|
||||
/* A "last departure" >= now means we've already calculated the separation */
|
||||
TimerGameTick::Ticks now = TimerGameCalendar::date.base() * Ticks::DAY_TICKS + TimerGameCalendar::date_fract;
|
||||
if (this->first_order_last_departure >= now) return;
|
||||
|
||||
/* Calculate round trip time from last departure and now - automatic separation waiting time is not included */
|
||||
if (this->first_order_last_departure > 0) {
|
||||
this->first_order_round_trip_time = now - this->first_order_last_departure;
|
||||
}
|
||||
|
||||
/* To work out the automatic separation waiting time we need to know:
|
||||
* - When the last vehicle departed or will depart
|
||||
* - Average time to perform the order list (as sum/count)
|
||||
* - How many vehicles are currently operating the order list
|
||||
* - How many vehicles are currently queuing for the first manual order
|
||||
*/
|
||||
TimerGameTick::Ticks last_departure = 0;
|
||||
TimerGameTick::Ticks round_trip_sum = 0;
|
||||
int round_trip_count = 0;
|
||||
int vehicles = 0;
|
||||
int vehicles_queuing = 0;
|
||||
Vehicle *v = this->FirstShared();
|
||||
while (v != nullptr) {
|
||||
last_departure = std::max(last_departure, v->first_order_last_departure);
|
||||
if (v->first_order_round_trip_time > 0) {
|
||||
round_trip_sum += v->first_order_round_trip_time;
|
||||
round_trip_count++;
|
||||
}
|
||||
/* A stopped vehicle is not included; it might be stopped by player or parked in a depot */
|
||||
if (!(v->vehstatus & VS_STOPPED)) {
|
||||
vehicles++;
|
||||
/* Count vehicles queing for the first manual order but not currently in the station */
|
||||
if (v != this && v->cur_speed == 0 && v->cur_implicit_order_index == first_manual_order && !v->current_order.IsType(OT_LOADING)) {
|
||||
vehicles_queuing++;
|
||||
}
|
||||
}
|
||||
v = v->NextShared();
|
||||
}
|
||||
|
||||
/* Calculate the mean round trip time and separation. The time spent queuing for stations is included in vehicle
|
||||
* round trip times.
|
||||
*
|
||||
* For a single shared order into a single station, this will increase and decrease the separation as needed.
|
||||
* However, for multiple shared orders into the same station, each shared order can back up the others and all
|
||||
* the routes will slowly increase their separation until every available vehicle is in the same queue.
|
||||
*
|
||||
* To counter this, we need to reduce the round trip time when vehicles are queuing. The scaling here reduces it
|
||||
* by twice the proportion of queuing vehicles, e.g. if 1/N vehicles are queuing, the RTT is reduced by 2/N.
|
||||
*
|
||||
* This is based on the idea that if only M/N vehicles are progressing, the non-queuing RTT is approximately M/N
|
||||
* of the measured RTT, because (N-M)/N of the RTT is spent in the queue, with the 'twice' coming from the need
|
||||
* to over-compensate rather than aim exactly for the ideal (which is very approximate here). */
|
||||
TimerGameTick::Ticks round_trip_time = round_trip_count > 0 ? round_trip_sum / round_trip_count : 0;
|
||||
int vehicles_moving_ratio = std::max(1, vehicles - 2 * vehicles_queuing);
|
||||
TimerGameTick::Ticks separation = std::max(1, vehicles > 0 ? round_trip_time * vehicles_moving_ratio / vehicles / vehicles : 1);
|
||||
|
||||
/* Finally we can calculate when this vehicle should depart; if that's in the past, it'll depart right now */
|
||||
this->first_order_last_departure = std::max(last_departure + separation, now);
|
||||
|
||||
/* Debug logging can be quite spammy as it prints a line every time a vehicle departs the first manual order */
|
||||
if (_debug_misc_level >= 4) {
|
||||
SetDParam(0, this->index);
|
||||
Debug(misc, 4, "Orders for {}: RTT = {} [{:.2f} days, {} veh], separation = {} [{:.2f} days, {} veh, {} queuing] / gap = {} [{:.2f} days], wait = {} [{:.2f} days]", GetString(STR_VEHICLE_NAME), round_trip_time, (float)round_trip_time / Ticks::DAY_TICKS, round_trip_count, separation, (float)separation / Ticks::DAY_TICKS, vehicles, vehicles_queuing, now - last_departure, (float)(now - last_departure) / Ticks::DAY_TICKS, this->first_order_last_departure - now, (float)(this->first_order_last_departure - now) / Ticks::DAY_TICKS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send this vehicle to the depot using the given command(s).
|
||||
* @param flags the command flags (like execute and such).
|
||||
|
|
|
@ -812,6 +812,13 @@ public:
|
|||
|
||||
inline void SetServiceIntervalIsPercent(bool on) { SB(this->vehicle_flags, VF_SERVINT_IS_PERCENT, 1, on); }
|
||||
|
||||
inline bool AutomaticSeparationIsEnabled() const { return (this->orders == nullptr) ? false : this->orders->AutomaticSeparationIsEnabled(); }
|
||||
|
||||
inline void SetAutomaticSeparationIsEnabled(bool enabled) const { if (this->orders != nullptr) this->orders->SetAutomaticSeparationIsEnabled(enabled); }
|
||||
|
||||
bool IsWaitingForAutomaticSeparation() const;
|
||||
void UpdateAutomaticSeparation();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Advance cur_real_order_index to the next real order.
|
||||
|
|
|
@ -628,6 +628,7 @@ CommandCost CmdStartStopVehicle(DoCommandFlag flags, VehicleID veh_id, bool eval
|
|||
if (v->IsStoppedInDepot() && (flags & DC_AUTOREPLACE) == 0) DeleteVehicleNews(veh_id, STR_NEWS_TRAIN_IS_WAITING + v->type);
|
||||
|
||||
v->vehstatus ^= VS_STOPPED;
|
||||
if (v->vehstatus & VS_STOPPED) v->ResetAutomaticSeparation();
|
||||
if (v->type != VEH_TRAIN) v->cur_speed = 0; // trains can stop 'slowly'
|
||||
v->MarkDirty();
|
||||
SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
|
||||
|
|
|
@ -20,6 +20,7 @@ enum OrderWidgets {
|
|||
WID_O_DELETE, ///< Delete selected order.
|
||||
WID_O_STOP_SHARING, ///< Stop sharing orders.
|
||||
WID_O_NON_STOP, ///< Goto non-stop to destination.
|
||||
WID_O_AUTOMATIC_SEPARATION, ///< Toggle automatic separation.
|
||||
WID_O_GOTO, ///< Goto destination.
|
||||
WID_O_FULL_LOAD, ///< Select full load.
|
||||
WID_O_UNLOAD, ///< Select unload.
|
||||
|
|
Loading…
Reference in New Issue