Add support for multiple scheduled dispatch schedules per order list

This commit is contained in:
Jonathan G Rennison
2022-01-13 19:46:43 +00:00
parent 29521ef883
commit ff3473fe6a
23 changed files with 755 additions and 367 deletions

View File

@@ -48,7 +48,7 @@ static void ChangeTimetable(Vehicle *v, VehicleOrderID order_number, uint32 val,
}
order->SetWaitTime(val);
order->SetWaitTimetabled(timetabled);
if (HasBit(v->vehicle_flags, VF_SCHEDULED_DISPATCH) && timetabled && order->IsWaitTimetabled() && v->GetFirstWaitingLocation(true) == order_number) {
if (HasBit(v->vehicle_flags, VF_SCHEDULED_DISPATCH) && timetabled && order->IsScheduledDispatchOrder(true)) {
for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) {
if (u->cur_implicit_order_index == order_number && (u->last_station_visited == order->GetDestination())) {
u->lateness_counter += timetable_delta;
@@ -84,6 +84,18 @@ static void ChangeTimetable(Vehicle *v, VehicleOrderID order_number, uint32 val,
order->SetLeaveType((OrderLeaveType)val);
break;
case MTF_ASSIGN_SCHEDULE:
if ((int)val >= 0) {
for (int n = 0; n < v->GetNumOrders(); n++) {
Order *o = v->GetOrder(n);
if (o->GetDispatchScheduleIndex() == (int)val) {
o->SetDispatchScheduleIndex(-1);
}
}
}
order->SetDispatchScheduleIndex((int)val);
break;
default:
NOT_REACHED();
}
@@ -119,6 +131,10 @@ static void ChangeTimetable(Vehicle *v, VehicleOrderID order_number, uint32 val,
v->current_order.SetLeaveType((OrderLeaveType)val);
break;
case MTF_ASSIGN_SCHEDULE:
v->current_order.SetDispatchScheduleIndex((int)val);
break;
default:
NOT_REACHED();
}
@@ -170,6 +186,7 @@ CommandCost CmdChangeTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1, u
bool wait_fixed = order->IsWaitFixed();
bool travel_fixed = order->IsTravelFixed();
OrderLeaveType leave_type = order->GetLeaveType();
int dispatch_index = order->GetDispatchScheduleIndex();
switch (mtf) {
case MTF_WAIT_TIME:
wait_time = p2;
@@ -199,6 +216,11 @@ CommandCost CmdChangeTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1, u
if (leave_type >= OLT_END) return CMD_ERROR;
break;
case MTF_ASSIGN_SCHEDULE:
dispatch_index = (int)p2;
if (dispatch_index < -1 || dispatch_index >= (int)v->orders.list->GetScheduledDispatchScheduleCount()) return CMD_ERROR;
break;
default:
NOT_REACHED();
}
@@ -223,6 +245,23 @@ CommandCost CmdChangeTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1, u
}
}
if (dispatch_index != order->GetDispatchScheduleIndex()) {
switch (order->GetType()) {
case OT_GOTO_STATION:
if (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) {
if (mtf == MTF_ASSIGN_SCHEDULE && dispatch_index == -1) break;
return_cmd_error(STR_ERROR_TIMETABLE_NOT_STOPPING_HERE);
}
break;
case OT_GOTO_DEPOT:
case OT_GOTO_WAYPOINT:
break;
default: return_cmd_error(STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS);
}
}
if (travel_time != order->GetTravelTime() && order->IsType(OT_CONDITIONAL)) return CMD_ERROR;
if (max_speed != order->GetMaxSpeed() && (order->IsType(OT_CONDITIONAL) || v->type == VEH_AIRCRAFT)) return CMD_ERROR;
if (wait_fixed != order->IsWaitFixed() && order->IsType(OT_CONDITIONAL)) return CMD_ERROR;
@@ -268,6 +307,12 @@ CommandCost CmdChangeTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1, u
}
break;
case MTF_ASSIGN_SCHEDULE:
if (dispatch_index != order->GetDispatchScheduleIndex()) {
ChangeTimetable(v, order_number, dispatch_index, MTF_ASSIGN_SCHEDULE, true);
}
break;
default:
break;
}
@@ -733,21 +778,16 @@ void UpdateSeparationOrder(Vehicle *v_start)
}
}
static bool IsVehicleAtFirstWaitingLocation(const Vehicle *v)
{
return (v->cur_implicit_order_index == v->GetFirstWaitingLocation(true));
}
static DateTicksScaled GetScheduledDispatchTime(Vehicle *v, int wait_offset)
static DateTicksScaled GetScheduledDispatchTime(const DispatchSchedule &ds, int wait_offset)
{
DateTicksScaled first_slot = -1;
const DateTicksScaled begin_time = v->orders.list->GetScheduledDispatchStartTick();
const int32 last_dispatched_offset = v->orders.list->GetScheduledDispatchLastDispatch();
const uint32 dispatch_duration = v->orders.list->GetScheduledDispatchDuration();
const int32 max_delay = v->orders.list->GetScheduledDispatchDelay();
const DateTicksScaled begin_time = ds.GetScheduledDispatchStartTick();
const int32 last_dispatched_offset = ds.GetScheduledDispatchLastDispatch();
const uint32 dispatch_duration = ds.GetScheduledDispatchDuration();
const int32 max_delay = ds.GetScheduledDispatchDelay();
/* Find next available slots */
for (auto current_offset : v->orders.list->GetScheduledDispatch()) {
for (auto current_offset : ds.GetScheduledDispatch()) {
if (current_offset >= dispatch_duration) continue;
if (int32(current_offset) <= last_dispatched_offset) {
current_offset += dispatch_duration * ((last_dispatched_offset + dispatch_duration - current_offset) / dispatch_duration);
@@ -801,17 +841,20 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling)
bool set_scheduled_dispatch = false;
/* Start scheduled dispatch at first opportunity */
if (HasBit(v->vehicle_flags, VF_SCHEDULED_DISPATCH)) {
if (IsVehicleAtFirstWaitingLocation(v) && travelling) {
if (HasBit(v->vehicle_flags, VF_SCHEDULED_DISPATCH) && v->cur_implicit_order_index != INVALID_VEH_ORDER_ID) {
Order *real_implicit_order = v->GetOrder(v->cur_implicit_order_index);
if (real_implicit_order->IsScheduledDispatchOrder(true) && travelling) {
DispatchSchedule &ds = v->orders.list->GetDispatchScheduleByIndex(real_implicit_order->GetDispatchScheduleIndex());
/* Update scheduled information */
v->orders.list->UpdateScheduledDispatch();
ds.UpdateScheduledDispatch();
const int wait_offset = real_current_order->GetTimetabledWait();
DateTicksScaled slot = GetScheduledDispatchTime(v, wait_offset);
DateTicksScaled slot = GetScheduledDispatchTime(ds, wait_offset);
if (slot > -1) {
SetBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
v->lateness_counter = _scaled_date_ticks - slot + wait_offset;
v->orders.list->SetScheduledDispatchLastDispatch(slot - v->orders.list->GetScheduledDispatchStartTick());
ds.SetScheduledDispatchLastDispatch(slot - ds.GetScheduledDispatchStartTick());
set_scheduled_dispatch = true;
}
}