@ -43,15 +43,23 @@
typedef btree : : btree_map < const DispatchSchedule * , btree : : btree_set < DateTicksScaled > > schdispatch_cache_t ;
/** A scheduled order. */
typedef struct OrderDate
{
struct OrderDate {
const Order * order ; ///< The order
const Vehicle * v ; ///< The vehicle carrying out the order
DateTicks expected_date ; ///< The date on which the order is expected to complete
Ticks expected_tick ; ///< The tick on which the order is expected to complete
Ticks lateness ; ///< How late this order is expected to finish
DepartureStatus status ; ///< Whether the vehicle has arrived to carry out the order yet
uint scheduled_waiting_time ; ///< Scheduled waiting time if scheduled dispatch is used
} OrderDate ;
Ticks scheduled_waiting_time ; ///< Scheduled waiting time if scheduled dispatch is used
inline Ticks EffectiveWaitingTime ( ) const
{
if ( this - > scheduled_waiting_time > 0 ) {
return this - > scheduled_waiting_time ;
} else {
return this - > order - > GetWaitTime ( ) ;
}
}
} ;
static bool IsDeparture ( const Order * order , StationID station ) {
return ( order - > GetType ( ) = = OT_GOTO_STATION & &
@ -93,7 +101,7 @@ static uint8 GetDepartureConditionalOrderMode(const Order *order, const Vehicle
return _settings_client . gui . departure_conditionals ;
}
static bool VehicleSetNextDepartureTime ( Date Ticks * previous_departure , uint * waiting_time , const DateTicksScaled date_only_scaled , const Vehicle * v , const Order * order , bool arrived_at_timing_point , schdispatch_cache_t & dept_schedule_last )
static bool VehicleSetNextDepartureTime ( Ticks * previous_departure , Ticks * waiting_time , const DateTicksScaled date_ticks_base , const Vehicle * v , const Order * order , bool arrived_at_timing_point , schdispatch_cache_t & dept_schedule_last )
{
if ( HasBit ( v - > vehicle_flags , VF_SCHEDULED_DISPATCH ) ) {
auto is_current_implicit_order = [ & v ] ( const Order * o ) - > bool {
@ -115,7 +123,7 @@ static bool VehicleSetNextDepartureTime(DateTicks *previous_departure, uint *wai
DateTicksScaled earliest_departure = begin_time + ds . GetScheduledDispatchLastDispatch ( ) ;
/* Earliest possible departure according to vehicle current timetable */
const uint32 ready_to_depart_time = date_only_scaled + * previous_departure + order - > GetTravelTime ( ) + order - > GetTimetabledWait ( ) ;
const DateTicksScaled ready_to_depart_time = date_ticks_base + * previous_departure + order - > GetTravelTime ( ) + order - > GetTimetabledWait ( ) ;
if ( earliest_departure + max_delay < ready_to_depart_time ) {
earliest_departure = ready_to_depart_time - max_delay - 1 ;
/* -1 because this number is actually a moment before actual departure */
@ -141,8 +149,8 @@ static bool VehicleSetNextDepartureTime(DateTicks *previous_departure, uint *wai
}
}
* waiting_time = actual_departure - date_only_scaled - * previous_departure - order - > GetTravelTime ( ) ;
* previous_departure = actual_departure - date_only_scaled ;
* waiting_time = ( actual_departure - date_ticks_base ) . AsTicks ( ) - * previous_departure - order - > GetTravelTime ( ) ;
* previous_departure = ( actual_departure - date_ticks_base ) . AsTicks ( ) ;
slot_cache . insert ( actual_departure ) ;
/* Return true means that vehicle lateness should be clear from this point onward */
@ -185,18 +193,18 @@ static void ScheduledDispatchDepartureLocalFix(DepartureList *departure_list)
/* Sort the departure list by arrival time */
std : : sort ( d_list . begin ( ) , d_list . end ( ) , [ ] ( const Departure * const & a , const Departure * const & b ) - > bool {
DateTicksScaled arr_a = a - > scheduled_date - ( a - > scheduled_waiting_time > 0 ? a - > scheduled_waiting_time : a - > order - > GetWaitTime ( ) ) ;
DateTicksScaled arr_b = b - > scheduled_date - ( b - > scheduled_waiting_time > 0 ? b - > scheduled_waiting_time : b - > order - > GetWaitTime ( ) ) ;
DateTicksScaled arr_a = a - > scheduled_date - a - > EffectiveWaitingTime ( ) ;
DateTicksScaled arr_b = b - > scheduled_date - b - > EffectiveWaitingTime ( ) ;
return arr_a < arr_b ;
} ) ;
/* Re-assign them sequentially */
for ( size_t i = 0 ; i < d_list . size ( ) ; i + + ) {
const DateTicksScaled arrival = d_list [ i ] - > scheduled_date - ( d_list [ i ] - > scheduled_waiting_time > 0 ? d_list [ i ] - > scheduled_waiting_time : d_list [ i ] - > order - > GetWaitTime ( ) ) ;
d_list [ i ] - > scheduled_waiting_time = departure_time_list [ i ] - arrival ;
const DateTicksScaled arrival = d_list [ i ] - > scheduled_date - d_list [ i ] - > EffectiveWaitingTime( ) ;
d_list [ i ] - > scheduled_waiting_time = ( departure_time_list [ i ] - arrival ) . AsTicks ( ) ;
d_list [ i ] - > scheduled_date = departure_time_list [ i ] ;
if ( d_list [ i ] - > scheduled_waiting_time = = d_list [ i ] - > order - > GetWaitTime ( ) ) {
if ( d_list [ i ] - > scheduled_waiting_time = = ( Ticks ) d_list [ i ] - > order - > GetWaitTime ( ) ) {
d_list [ i ] - > scheduled_waiting_time = 0 ;
}
}
@ -237,12 +245,11 @@ DepartureList* MakeDepartureList(StationID station, const std::vector<const Vehi
std : : vector < OrderDate * > next_orders ;
/* The maximum possible date for departures to be scheduled to occur. */
DateTicksScaled max_date = GetDeparturesMaxTicksAhead ( ) ;
const Ticks max_ticks = GetDeparturesMaxTicksAhead ( ) ;
DateTicksScaled date_only_scaled = DateToScaledDateTicks ( _date ) ;
DateTicksScaled date_fract_scaled = ( ( DateTicksScaled ) _date_fract * _settings_game . economy . day_length_factor ) + _tick_skip_counter ;
const DateTicksScaled date_ticks_base = _scaled_date_ticks ;
/* The scheduled order in next_orders with the earliest expected_ date field. */
/* The scheduled order in next_orders with the earliest expected_ tick field. */
OrderDate * least_order = nullptr ;
/* Cache for scheduled departure time */
@ -272,20 +279,20 @@ DepartureList* MakeDepartureList(StationID station, const std::vector<const Vehi
const Order * order = v - > GetOrder ( v - > cur_implicit_order_index % v - > GetNumOrders ( ) ) ;
if ( order = = nullptr ) continue ;
DateTicks start_date = date_fract_scaled - v - > current_order_time ;
Ticks start_ticks = - ( ( Ticks ) v - > current_order_time ) ;
if ( v - > cur_timetable_order_index ! = INVALID_VEH_ORDER_ID & & v - > cur_timetable_order_index ! = v - > cur_real_order_index ) {
/* vehicle is taking a conditional order branch, adjust start time to compensate */
const Order * real_current_order = v - > GetOrder ( v - > cur_real_order_index ) ;
const Order * real_timetable_order = v - > GetOrder ( v - > cur_timetable_order_index ) ;
if ( real_timetable_order - > IsType ( OT_CONDITIONAL ) ) {
start_ date + = ( real_timetable_order - > GetWaitTime ( ) - real_current_order - > GetTravelTime ( ) ) ;
start_ ticks + = ( real_timetable_order - > GetWaitTime ( ) - real_current_order - > GetTravelTime ( ) ) ;
} else {
/* This can also occur with implicit orders, when there are no real orders, do nothing */
}
}
DepartureStatus status = D_TRAVELLING ;
bool should_reset_lateness = false ;
uint waiting_time = 0 ;
Ticks waiting_time = 0 ;
/* If the vehicle is stopped in a depot, ignore it. */
if ( v - > IsStoppedInDepot ( ) ) {
@ -301,20 +308,20 @@ DepartureList* MakeDepartureList(StationID station, const std::vector<const Vehi
if ( v - > current_order . IsAnyLoadingType ( ) | | v - > current_order . IsType ( OT_WAITING ) ) {
/* Account for the vehicle having reached the current order and being in the loading phase. */
status = D_ARRIVED ;
start_ date - = order - > GetTravelTime ( ) + ( ( v - > lateness_counter < 0 ) ? v - > lateness_counter : 0 ) ;
start_ ticks - = order - > GetTravelTime ( ) + ( ( v - > lateness_counter < 0 ) ? v - > lateness_counter : 0 ) ;
require_travel_time = false ;
}
/* Loop through the vehicle's orders until we've found a suitable order or we've determined that no such order exists. */
/* We only need to consider each order at most once. */
for ( int i = v - > GetNumOrders ( ) ; i > 0 ; - - i ) {
if ( VehicleSetNextDepartureTime ( & start_ date, & waiting_time , date_only_scaled , v , order , status = = D_ARRIVED , schdispatch_last_planned_dispatch ) ) {
if ( VehicleSetNextDepartureTime ( & start_ ticks, & waiting_time , date_ticks_base , v , order , status = = D_ARRIVED , schdispatch_last_planned_dispatch ) ) {
should_reset_lateness = true ;
}
/* If the order is a conditional branch, handle it. */
if ( order - > IsType ( OT_CONDITIONAL ) ) {
switch ( GetDepartureConditionalOrderMode ( order , v , start_date + date_only_scaled ) ) {
switch ( GetDepartureConditionalOrderMode ( order , v , date_ticks_base + start_ticks ) ) {
case 0 : {
/* Give up */
break ;
@ -329,7 +336,7 @@ DepartureList* MakeDepartureList(StationID station, const std::vector<const Vehi
break ;
}
start_ date - = order - > GetTravelTime ( ) ;
start_ ticks - = order - > GetTravelTime ( ) ;
require_travel_time = false ;
continue ;
}
@ -338,7 +345,7 @@ DepartureList* MakeDepartureList(StationID station, const std::vector<const Vehi
if ( status ! = D_CANCELLED ) {
status = D_TRAVELLING ;
}
start_ date - = order - > GetWaitTime ( ) ; /* Added previously in VehicleSetNextDepartureTime */
start_ ticks - = order - > GetWaitTime ( ) ; /* Added previously in VehicleSetNextDepartureTime */
order = ( order - > next = = nullptr ) ? v - > GetFirstOrder ( ) : order - > next ;
require_travel_time = true ;
continue ;
@ -348,7 +355,7 @@ DepartureList* MakeDepartureList(StationID station, const std::vector<const Vehi
}
/* If the scheduled departure date is too far in the future, stop. */
if ( start_ date - v - > lateness_counter > max_date ) {
if ( start_ ticks - v - > lateness_counter > max_ticks ) {
break ;
}
@ -363,7 +370,7 @@ DepartureList* MakeDepartureList(StationID station, const std::vector<const Vehi
( type = = D_DEPARTURE & & show_vehicles_via & & IsVia ( order , station ) ) | |
( type = = D_ARRIVAL & & IsArrival ( order , station ) ) ) {
/* If the departure was scheduled to have already begun and has been cancelled, do not show it. */
if ( start_ date < 0 & & status = = D_CANCELLED ) {
if ( start_ ticks < 0 & & status = = D_CANCELLED ) {
break ;
}
@ -371,7 +378,7 @@ DepartureList* MakeDepartureList(StationID station, const std::vector<const Vehi
od - > order = order ;
od - > v = v ;
/* We store the expected date for now, so that vehicles will be shown in order of expected time. */
od - > expected_ date = start_date ;
od - > expected_ tick = start_ticks ;
od - > lateness = v - > lateness_counter > 0 ? v - > lateness_counter : 0 ;
od - > status = status ;
od - > scheduled_waiting_time = waiting_time ;
@ -383,15 +390,20 @@ DepartureList* MakeDepartureList(StationID station, const std::vector<const Vehi
/* If we are early, use the scheduled date as the expected date. We also take lateness to be zero. */
if ( ! should_reset_lateness & & v - > lateness_counter < 0 & & ! ( v - > current_order . IsAnyLoadingType ( ) | | v - > current_order . IsType ( OT_WAITING ) ) ) {
od - > expected_ date - = v - > lateness_counter ;
od - > expected_ tick - = v - > lateness_counter ;
}
/* Update least_order if this is the current least order. */
if ( least_order = = nullptr ) {
least_order = od ;
} else if ( int ( least_order - > expected_date - least_order - > lateness - ( type = = D_ARRIVAL ? ( least_order - > scheduled_waiting_time > 0 ? least_order - > scheduled_waiting_time : least_order - > order - > GetWaitTime ( ) ) : 0 ) ) > int ( od - > expected_date - od - > lateness - ( type = = D_ARRIVAL ? ( od - > scheduled_waiting_time > 0 ? od - > scheduled_waiting_time : od - > order - > GetWaitTime ( ) ) : 0 ) ) ) {
/* Somehow my compiler perform an unsigned comparition above so integer cast is required */
least_order = od ;
} else if ( type = = D_ARRIVAL ) {
if ( ( least_order - > expected_tick - least_order - > lateness - least_order - > EffectiveWaitingTime ( ) ) > ( od - > expected_tick - od - > lateness - od - > EffectiveWaitingTime ( ) ) ) {
least_order = od ;
}
} else {
if ( ( least_order - > expected_tick - least_order - > lateness ) > ( od - > expected_tick - od - > lateness ) ) {
least_order = od ;
}
}
next_orders . push_back ( od ) ;
@ -420,22 +432,22 @@ DepartureList* MakeDepartureList(StationID station, const std::vector<const Vehi
for ( int i = 10000 ; i > 0 ; - - i ) {
/* I should probably try to convince you that this loop always terminates regardless of the safeguard. */
/* 1. next_orders contains at least one element. */
/* 2. The loop terminates if result->size() exceeds a fixed (for this loop) value, or if the least order's scheduled date is later than max_ date . */
/* 2. The loop terminates if result->size() exceeds a fixed (for this loop) value, or if the least order's scheduled date is later than max_ ticks . */
/* (We ignore the case that the least order's scheduled date has overflown, as it is a relative rather than absolute date.) */
/* 3. Every time we loop round, either result->size() will have increased -OR- we will have increased the expected_ date of one of the elements of next_orders. */
/* 3. Every time we loop round, either result->size() will have increased -OR- we will have increased the expected_ tick of one of the elements of next_orders. */
/* 4. Therefore the loop must eventually terminate. */
/* least_order is the best candidate for the next departure. */
/* First, we check if we can stop looking for departures yet. */
if ( result - > size ( ) > = _settings_client . gui . max_departures | |
least_order - > expected_ date - least_order - > lateness > max_date ) {
least_order - > expected_ tick - least_order - > lateness > max_ticks ) {
break ;
}
/* We already know the least order and that it's a suitable departure, so make it into a departure. */
Departure * d = new Departure ( ) ;
d - > scheduled_date = date_ only_scaled + least_order - > expected_date - least_order - > lateness ;
d - > scheduled_date = date_ ticks_base + least_order - > expected_tick - least_order - > lateness ;
d - > lateness = least_order - > lateness ;
d - > status = least_order - > status ;
d - > vehicle = least_order - > v ;
@ -751,7 +763,7 @@ DepartureList* MakeDepartureList(StationID station, const std::vector<const Vehi
/* Go to the next order so we don't add the current order again. */
order = ( order - > next = = nullptr ) ? least_order - > v - > GetFirstOrder ( ) : order - > next ;
if ( VehicleSetNextDepartureTime ( & least_order - > expected_ date , & least_order - > scheduled_waiting_time , date_ only_scaled , least_order - > v , order , false , schdispatch_last_planned_dispatch ) ) {
if ( VehicleSetNextDepartureTime ( & least_order - > expected_ tick , & least_order - > scheduled_waiting_time , date_ ticks_base , least_order - > v , order , false , schdispatch_last_planned_dispatch ) ) {
least_order - > lateness = 0 ;
}
@ -762,7 +774,7 @@ DepartureList* MakeDepartureList(StationID station, const std::vector<const Vehi
for ( int i = least_order - > v - > GetNumOrders ( ) ; i > 0 ; - - i ) {
/* If the order is a conditional branch, handle it. */
if ( order - > IsType ( OT_CONDITIONAL ) ) {
switch ( GetDepartureConditionalOrderMode ( order , least_order - > v , least_order - > expected_ date ) ) {
switch ( GetDepartureConditionalOrderMode ( order , least_order - > v , least_order - > expected_ tick ) ) {
case 0 : {
/* Give up */
break ;
@ -774,8 +786,8 @@ DepartureList* MakeDepartureList(StationID station, const std::vector<const Vehi
break ;
}
least_order - > expected_ date - = order - > GetTravelTime ( ) ; /* Added in next VehicleSetNextDepartureTime */
if ( VehicleSetNextDepartureTime ( & least_order - > expected_ date , & least_order - > scheduled_waiting_time , date_ only_scaled , least_order - > v , order , false , schdispatch_last_planned_dispatch ) ) {
least_order - > expected_ tick - = order - > GetTravelTime ( ) ; /* Added in next VehicleSetNextDepartureTime */
if ( VehicleSetNextDepartureTime ( & least_order - > expected_ tick , & least_order - > scheduled_waiting_time , date_ ticks_base , least_order - > v , order , false , schdispatch_last_planned_dispatch ) ) {
least_order - > lateness = 0 ;
}
require_travel_time = false ;
@ -783,9 +795,9 @@ DepartureList* MakeDepartureList(StationID station, const std::vector<const Vehi
}
case 2 : {
/* Do not take the branch */
least_order - > expected_ date - = order - > GetWaitTime ( ) ; /* Added previously in VehicleSetNextDepartureTime */
least_order - > expected_ tick - = order - > GetWaitTime ( ) ; /* Added previously in VehicleSetNextDepartureTime */
order = ( order - > next = = nullptr ) ? least_order - > v - > GetFirstOrder ( ) : order - > next ;
if ( VehicleSetNextDepartureTime ( & least_order - > expected_ date , & least_order - > scheduled_waiting_time , date_ only_scaled , least_order - > v , order , false , schdispatch_last_planned_dispatch ) ) {
if ( VehicleSetNextDepartureTime ( & least_order - > expected_ tick , & least_order - > scheduled_waiting_time , date_ ticks_base , least_order - > v , order , false , schdispatch_last_planned_dispatch ) ) {
least_order - > lateness = 0 ;
}
require_travel_time = true ;
@ -801,7 +813,7 @@ DepartureList* MakeDepartureList(StationID station, const std::vector<const Vehi
}
/* If the departure is scheduled to be too late, then stop. */
if ( least_order - > expected_ date - least_order - > lateness > max_date ) {
if ( least_order - > expected_ tick - least_order - > lateness > max_ticks ) {
break ;
}
@ -815,7 +827,7 @@ DepartureList* MakeDepartureList(StationID station, const std::vector<const Vehi
}
order = ( order - > next = = nullptr ) ? least_order - > v - > GetFirstOrder ( ) : order - > next ;
if ( VehicleSetNextDepartureTime ( & least_order - > expected_ date , & least_order - > scheduled_waiting_time , date_ only_scaled , least_order - > v , order , false , schdispatch_last_planned_dispatch ) ) {
if ( VehicleSetNextDepartureTime ( & least_order - > expected_ tick , & least_order - > scheduled_waiting_time , date_ ticks_base , least_order - > v , order , false , schdispatch_last_planned_dispatch ) ) {
least_order - > lateness = 0 ;
}
require_travel_time = true ;
@ -826,7 +838,7 @@ DepartureList* MakeDepartureList(StationID station, const std::vector<const Vehi
/* Make sure we don't try to get departures out of this order. */
/* This is cheaper than deleting it from next_orders. */
/* If we ever get to a state where _date * DAY_TICKS is close to INT_MAX, then we'll have other problems anyway as departures' scheduled dates will wrap around. */
least_order - > expected_ date = INT32_MAX ;
least_order - > expected_ tick = INT32_MAX ;
}
/* The vehicle can't possibly have arrived at its next candidate departure yet. */
@ -838,15 +850,15 @@ DepartureList* MakeDepartureList(StationID station, const std::vector<const Vehi
for ( uint i = 0 ; i < next_orders . size ( ) ; + + i ) {
OrderDate * od = next_orders [ i ] ;
DateTicks lod = least_order - > expected_ date - least_order - > lateness ;
DateTicks odd = od - > expected_ date - od - > lateness ;
DateTicks lod = least_order - > expected_ tick - least_order - > lateness ;
DateTicks odd = od - > expected_ tick - od - > lateness ;
if ( type = = D_ARRIVAL ) {
lod - = least_order - > scheduled_waiting_time > 0 ? least_order - > scheduled_waiting_time : least_order - > order - > GetWaitTime ( ) ;
odd - = od - > scheduled_waiting_time > 0 ? od - > scheduled_waiting_time : od - > order - > GetWaitTime ( ) ;
}
if ( lod > odd & & od - > expected_ date - od - > lateness < max_date ) {
if ( lod > odd & & od - > expected_ tick - od - > lateness < max_ticks ) {
least_order = od ;
}
}
@ -864,7 +876,7 @@ DepartureList* MakeDepartureList(StationID station, const std::vector<const Vehi
return result ;
}
Date TicksScaled GetDeparturesMaxTicksAhead ( )
Ticks GetDeparturesMaxTicksAhead ( )
{
if ( _settings_time . time_in_minutes ) {
return _settings_client . gui . max_departure_time_minutes * _settings_time . ticks_per_minute ;