Scheduled dispatch: Add per dispatch slot flags field
Add flag for slot re-use
This commit is contained in:
@@ -305,6 +305,7 @@ CommandProc CmdScheduledDispatchDuplicateSchedule;
|
|||||||
CommandProc CmdScheduledDispatchAppendVehicleSchedules;
|
CommandProc CmdScheduledDispatchAppendVehicleSchedules;
|
||||||
CommandProc CmdScheduledDispatchAdjust;
|
CommandProc CmdScheduledDispatchAdjust;
|
||||||
CommandProc CmdScheduledDispatchSwapSchedules;
|
CommandProc CmdScheduledDispatchSwapSchedules;
|
||||||
|
CommandProcEx CmdScheduledDispatchSetSlotFlags;
|
||||||
|
|
||||||
CommandProc CmdAddPlan;
|
CommandProc CmdAddPlan;
|
||||||
CommandProcEx CmdAddPlanLine;
|
CommandProcEx CmdAddPlanLine;
|
||||||
@@ -569,6 +570,7 @@ static const Command _command_proc_table[] = {
|
|||||||
DEF_CMD(CmdScheduledDispatchAppendVehicleSchedules, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SCHEDULED_DISPATCH_APPEND_VEHICLE_SCHEDULE
|
DEF_CMD(CmdScheduledDispatchAppendVehicleSchedules, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SCHEDULED_DISPATCH_APPEND_VEHICLE_SCHEDULE
|
||||||
DEF_CMD(CmdScheduledDispatchAdjust, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SCHEDULED_DISPATCH_ADJUST
|
DEF_CMD(CmdScheduledDispatchAdjust, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SCHEDULED_DISPATCH_ADJUST
|
||||||
DEF_CMD(CmdScheduledDispatchSwapSchedules, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SCHEDULED_DISPATCH_SWAP_SCHEDULES
|
DEF_CMD(CmdScheduledDispatchSwapSchedules, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SCHEDULED_DISPATCH_SWAP_SCHEDULES
|
||||||
|
DEF_CMD(CmdScheduledDispatchSetSlotFlags, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SCHEDULED_DISPATCH_SET_SLOT_FLAGS
|
||||||
|
|
||||||
DEF_CMD(CmdAddPlan, CMD_NO_TEST, CMDT_OTHER_MANAGEMENT ), // CMD_ADD_PLAN
|
DEF_CMD(CmdAddPlan, CMD_NO_TEST, CMDT_OTHER_MANAGEMENT ), // CMD_ADD_PLAN
|
||||||
DEF_CMD(CmdAddPlanLine, CMD_NO_TEST, CMDT_OTHER_MANAGEMENT ), // CMD_ADD_PLAN_LINE
|
DEF_CMD(CmdAddPlanLine, CMD_NO_TEST, CMDT_OTHER_MANAGEMENT ), // CMD_ADD_PLAN_LINE
|
||||||
|
@@ -521,6 +521,7 @@ enum Commands {
|
|||||||
CMD_SCHEDULED_DISPATCH_APPEND_VEHICLE_SCHEDULE, ///< scheduled dispatch append schedules from another vehicle
|
CMD_SCHEDULED_DISPATCH_APPEND_VEHICLE_SCHEDULE, ///< scheduled dispatch append schedules from another vehicle
|
||||||
CMD_SCHEDULED_DISPATCH_ADJUST, ///< scheduled dispatch adjust time offsets in schedule
|
CMD_SCHEDULED_DISPATCH_ADJUST, ///< scheduled dispatch adjust time offsets in schedule
|
||||||
CMD_SCHEDULED_DISPATCH_SWAP_SCHEDULES, ///< scheduled dispatch swap schedules in order
|
CMD_SCHEDULED_DISPATCH_SWAP_SCHEDULES, ///< scheduled dispatch swap schedules in order
|
||||||
|
CMD_SCHEDULED_DISPATCH_SET_SLOT_FLAGS, ///< scheduled dispatch set flags of dispatch slot
|
||||||
|
|
||||||
CMD_ADD_PLAN,
|
CMD_ADD_PLAN,
|
||||||
CMD_ADD_PLAN_LINE,
|
CMD_ADD_PLAN_LINE,
|
||||||
|
@@ -132,15 +132,19 @@ static bool VehicleSetNextDepartureTime(Ticks *previous_departure, Ticks *waitin
|
|||||||
btree::btree_set<DateTicksScaled> &slot_cache = dept_schedule_last[&ds];
|
btree::btree_set<DateTicksScaled> &slot_cache = dept_schedule_last[&ds];
|
||||||
|
|
||||||
/* Find next available slots */
|
/* Find next available slots */
|
||||||
for (auto current_offset : ds.GetScheduledDispatch()) {
|
for (const DispatchSlot &slot : ds.GetScheduledDispatch()) {
|
||||||
if (current_offset >= dispatch_duration) continue;
|
if (slot.offset >= dispatch_duration) continue;
|
||||||
DateTicksScaled current_departure = begin_time + current_offset;
|
DateTicksScaled current_departure = begin_time + slot.offset;
|
||||||
while (current_departure <= earliest_departure) {
|
while (current_departure <= earliest_departure) {
|
||||||
current_departure += dispatch_duration;
|
current_departure += dispatch_duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure the slots has not already been used previously in this departure board calculation */
|
/* Make sure the slots has not already been used previously in this departure board calculation */
|
||||||
while (slot_cache.count(current_departure) > 0) {
|
while (slot_cache.count(current_departure) > 0) {
|
||||||
|
if (HasBit(slot.flags, DispatchSlot::SDSF_REUSE_SLOT)) {
|
||||||
|
/* Allow re-use of this slot if it's the last seen */
|
||||||
|
if (*slot_cache.rbegin() == current_departure) break;
|
||||||
|
}
|
||||||
current_departure += dispatch_duration;
|
current_departure += dispatch_duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +155,9 @@ static bool VehicleSetNextDepartureTime(Ticks *previous_departure, Ticks *waitin
|
|||||||
|
|
||||||
*waiting_time = (actual_departure - date_ticks_base).AsTicks() - *previous_departure - order->GetTravelTime();
|
*waiting_time = (actual_departure - date_ticks_base).AsTicks() - *previous_departure - order->GetTravelTime();
|
||||||
*previous_departure = (actual_departure - date_ticks_base).AsTicks();
|
*previous_departure = (actual_departure - date_ticks_base).AsTicks();
|
||||||
|
if (!ds.GetScheduledDispatchReuseSlots()) {
|
||||||
slot_cache.insert(actual_departure);
|
slot_cache.insert(actual_departure);
|
||||||
|
}
|
||||||
|
|
||||||
/* Return true means that vehicle lateness should be clear from this point onward */
|
/* Return true means that vehicle lateness should be clear from this point onward */
|
||||||
return true;
|
return true;
|
||||||
|
@@ -2054,7 +2054,7 @@ STR_TMPL_CANT_RENAME :{WHITE}Can't re
|
|||||||
STR_SCHDISPATCH_CAPTION :{WHITE}{VEHICLE} (Scheduled Dispatch)
|
STR_SCHDISPATCH_CAPTION :{WHITE}{VEHICLE} (Scheduled Dispatch)
|
||||||
STR_SCHDISPATCH_ENABLED :{BLACK}Enable
|
STR_SCHDISPATCH_ENABLED :{BLACK}Enable
|
||||||
STR_SCHDISPATCH_ENABLED_TOOLTIP :{BLACK}Enable scheduled dispatching for this order. Requires automatic separation to be off.
|
STR_SCHDISPATCH_ENABLED_TOOLTIP :{BLACK}Enable scheduled dispatching for this order. Requires automatic separation to be off.
|
||||||
STR_SCHDISPATCH_ADD :{BLACK}Add Departure Slot
|
STR_SCHDISPATCH_ADD :{BLACK}Add Slot
|
||||||
STR_SCHDISPATCH_ADD_TOOLTIP :{BLACK}Add new departure slot for this schedule.
|
STR_SCHDISPATCH_ADD_TOOLTIP :{BLACK}Add new departure slot for this schedule.
|
||||||
STR_SCHDISPATCH_ADD_TOOLTIP_EXTRA :{BLACK}{STRING} Ctrl+Click to add multiple departure slots at once.
|
STR_SCHDISPATCH_ADD_TOOLTIP_EXTRA :{BLACK}{STRING} Ctrl+Click to add multiple departure slots at once.
|
||||||
STR_SCHDISPATCH_ADD_CAPTION :{BLACK}Departure slot
|
STR_SCHDISPATCH_ADD_CAPTION :{BLACK}Departure slot
|
||||||
@@ -2074,9 +2074,9 @@ STR_SCHDISPATCH_DELAY_TOOLTIP :{BLACK}Set maxi
|
|||||||
STR_SCHDISPATCH_DELAY_CAPTION_MINUTE :{BLACK}Delay (minutes)
|
STR_SCHDISPATCH_DELAY_CAPTION_MINUTE :{BLACK}Delay (minutes)
|
||||||
STR_SCHDISPATCH_DELAY_CAPTION_DAY :{BLACK}Delay (days)
|
STR_SCHDISPATCH_DELAY_CAPTION_DAY :{BLACK}Delay (days)
|
||||||
STR_SCHDISPATCH_DELAY_CAPTION_TICKS :{BLACK}Delay (ticks)
|
STR_SCHDISPATCH_DELAY_CAPTION_TICKS :{BLACK}Delay (ticks)
|
||||||
STR_SCHDISPATCH_ADJUST :{BLACK}Adjust Departure Slots
|
STR_SCHDISPATCH_ADJUST :{BLACK}Adjust Slots
|
||||||
STR_SCHDISPATCH_ADJUST_TOOLTIP :{BLACK}Adjust all departure slots in this schedule.
|
STR_SCHDISPATCH_ADJUST_TOOLTIP :{BLACK}Adjust all departure slots in this schedule.
|
||||||
STR_SCHDISPATCH_REMOVE :{BLACK}Remove Departure Slots
|
STR_SCHDISPATCH_REMOVE :{BLACK}Remove Slots
|
||||||
STR_SCHDISPATCH_REMOVE_TOOLTIP :{BLACK}Enable removing departure slots from this schedule.
|
STR_SCHDISPATCH_REMOVE_TOOLTIP :{BLACK}Enable removing departure slots from this schedule.
|
||||||
STR_SCHDISPATCH_ADJUST_CAPTION_MINUTE :{BLACK}Adjustment to add (minutes)
|
STR_SCHDISPATCH_ADJUST_CAPTION_MINUTE :{BLACK}Adjustment to add (minutes)
|
||||||
STR_SCHDISPATCH_ADJUST_CAPTION_DAY :{BLACK}Adjustment to add (days)
|
STR_SCHDISPATCH_ADJUST_CAPTION_DAY :{BLACK}Adjustment to add (days)
|
||||||
@@ -2099,8 +2099,11 @@ STR_SCHDISPATCH_DUPLICATE_SCHEDULE :{BLACK}Duplicat
|
|||||||
STR_SCHDISPATCH_DUPLICATE_SCHEDULE_TOOLTIP :{BLACK}Create a copy of this dispatch schedule.
|
STR_SCHDISPATCH_DUPLICATE_SCHEDULE_TOOLTIP :{BLACK}Create a copy of this dispatch schedule.
|
||||||
STR_SCHDISPATCH_APPEND_VEHICLE_SCHEDULES :{BLACK}Append Schedules From Vehicle
|
STR_SCHDISPATCH_APPEND_VEHICLE_SCHEDULES :{BLACK}Append Schedules From Vehicle
|
||||||
STR_SCHDISPATCH_APPEND_VEHICLE_SCHEDULES_TOOLTIP :{BLACK}Append the dispatch schedules from another vehicle.
|
STR_SCHDISPATCH_APPEND_VEHICLE_SCHEDULES_TOOLTIP :{BLACK}Append the dispatch schedules from another vehicle.
|
||||||
STR_SCHDISPATCH_APPEND_REUSE_DEPARTURE_SLOTS :{BLACK}Re-use departure slots
|
STR_SCHDISPATCH_REUSE_DEPARTURE_SLOTS :Re-use departure slots
|
||||||
STR_SCHDISPATCH_APPEND_REUSE_DEPARTURE_SLOTS_TOOLTIP :{BLACK}Set whether departure slots may be used more than once.
|
STR_SCHDISPATCH_REUSE_DEPARTURE_SLOTS_TOOLTIP :{BLACK}Set whether departure slots may be used more than once.
|
||||||
|
STR_SCHDISPATCH_MANAGE_SLOT :{BLACK}Manage Slot
|
||||||
|
STR_SCHDISPATCH_REUSE_THIS_DEPARTURE_SLOT :Re-use departure slot
|
||||||
|
STR_SCHDISPATCH_REUSE_THIS_DEPARTURE_SLOT_TOOLTIP :{BLACK}Set whether the selected departure slot may be used more than once.
|
||||||
STR_SCHDISPATCH_NO_SCHEDULES :{BLACK}No Schedules
|
STR_SCHDISPATCH_NO_SCHEDULES :{BLACK}No Schedules
|
||||||
STR_SCHDISPATCH_SCHEDULE_ID :{BLACK}Schedule {NUM} of {NUM}
|
STR_SCHDISPATCH_SCHEDULE_ID :{BLACK}Schedule {NUM} of {NUM}
|
||||||
STR_SCHDISPATCH_NAMED_SCHEDULE_ID :{BLACK}{RAW_STRING} ({NUM} of {NUM})
|
STR_SCHDISPATCH_NAMED_SCHEDULE_ID :{BLACK}{RAW_STRING} ({NUM} of {NUM})
|
||||||
@@ -2108,6 +2111,7 @@ STR_SCHDISPATCH_RENAME_SCHEDULE_TOOLTIP :{BLACK}Name sch
|
|||||||
STR_SCHDISPATCH_RENAME_SCHEDULE_CAPTION :{WHITE}Name schedule
|
STR_SCHDISPATCH_RENAME_SCHEDULE_CAPTION :{WHITE}Name schedule
|
||||||
STR_ERROR_CAN_T_RENAME_SCHEDULE :{WHITE}Can't name schedule...
|
STR_ERROR_CAN_T_RENAME_SCHEDULE :{WHITE}Can't name schedule...
|
||||||
STR_SCHDISPATCH_MOVE_SCHEDULE :{BLACK}Change position of current schedule in schedule list
|
STR_SCHDISPATCH_MOVE_SCHEDULE :{BLACK}Change position of current schedule in schedule list
|
||||||
|
STR_SCHDISPATCH_DATE_WALLCLOCK_TINY_FLAGGED :{DATE_WALLCLOCK_TINY}*
|
||||||
|
|
||||||
STR_SCHDISPATCH_SUMMARY_NO_LAST_DEPARTURE :{BLACK}No previous departures.
|
STR_SCHDISPATCH_SUMMARY_NO_LAST_DEPARTURE :{BLACK}No previous departures.
|
||||||
STR_SCHDISPATCH_SUMMARY_LAST_DEPARTURE_PAST :{BLACK}Last departure at {DATE_WALLCLOCK_TINY}.
|
STR_SCHDISPATCH_SUMMARY_LAST_DEPARTURE_PAST :{BLACK}Last departure at {DATE_WALLCLOCK_TINY}.
|
||||||
|
@@ -716,11 +716,28 @@ template <typename T, typename F> T CargoMaskValueFilter(CargoTypes &cargo_mask,
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct DispatchSlot {
|
||||||
|
uint32_t offset;
|
||||||
|
uint16_t flags;
|
||||||
|
|
||||||
|
bool operator<(const DispatchSlot &other) const
|
||||||
|
{
|
||||||
|
return this->offset < other.offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag bit numbers for scheduled_dispatch_flags
|
||||||
|
*/
|
||||||
|
enum ScheduledDispatchSlotFlags {
|
||||||
|
SDSF_REUSE_SLOT = 0, ///< Allow this slot to be used more than once
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
struct DispatchSchedule {
|
struct DispatchSchedule {
|
||||||
private:
|
private:
|
||||||
friend SaveLoadTable GetDispatchScheduleDescription(); ///< Saving and loading of dispatch schedules
|
friend SaveLoadTable GetDispatchScheduleDescription(); ///< Saving and loading of dispatch schedules
|
||||||
|
|
||||||
std::vector<uint32_t> scheduled_dispatch; ///< Scheduled dispatch time
|
std::vector<DispatchSlot> scheduled_dispatch; ///< Scheduled dispatch slots
|
||||||
DateTicksScaled scheduled_dispatch_start_tick = -1; ///< Scheduled dispatch start tick
|
DateTicksScaled scheduled_dispatch_start_tick = -1; ///< Scheduled dispatch start tick
|
||||||
uint32_t scheduled_dispatch_duration = 0; ///< Scheduled dispatch duration
|
uint32_t scheduled_dispatch_duration = 0; ///< Scheduled dispatch duration
|
||||||
int32_t scheduled_dispatch_last_dispatch = INVALID_SCHEDULED_DISPATCH_OFFSET; ///< Last vehicle dispatched offset
|
int32_t scheduled_dispatch_last_dispatch = INVALID_SCHEDULED_DISPATCH_OFFSET; ///< Last vehicle dispatched offset
|
||||||
@@ -750,9 +767,10 @@ public:
|
|||||||
* Get the vector of all scheduled dispatch slot
|
* Get the vector of all scheduled dispatch slot
|
||||||
* @return first scheduled dispatch
|
* @return first scheduled dispatch
|
||||||
*/
|
*/
|
||||||
inline const std::vector<uint32_t> &GetScheduledDispatch() const { return this->scheduled_dispatch; }
|
inline const std::vector<DispatchSlot> &GetScheduledDispatch() const { return this->scheduled_dispatch; }
|
||||||
|
inline std::vector<DispatchSlot> &GetScheduledDispatchMutable() { return this->scheduled_dispatch; }
|
||||||
|
|
||||||
void SetScheduledDispatch(std::vector<uint32_t> dispatch_list);
|
void SetScheduledDispatch(std::vector<DispatchSlot> dispatch_list);
|
||||||
void AddScheduledDispatch(uint32_t offset);
|
void AddScheduledDispatch(uint32_t offset);
|
||||||
void RemoveScheduledDispatch(uint32_t offset);
|
void RemoveScheduledDispatch(uint32_t offset);
|
||||||
void AdjustScheduledDispatch(int32_t adjust);
|
void AdjustScheduledDispatch(int32_t adjust);
|
||||||
|
@@ -3068,9 +3068,9 @@ bool EvaluateDispatchSlotConditionalOrder(const Order *order, const Vehicle *v,
|
|||||||
|
|
||||||
bool value;
|
bool value;
|
||||||
if (order->GetConditionValue() & 1) {
|
if (order->GetConditionValue() & 1) {
|
||||||
value = (offset == (int)sched.GetScheduledDispatch().back());
|
value = (offset == (int32_t)sched.GetScheduledDispatch().back().offset);
|
||||||
} else {
|
} else {
|
||||||
value = (offset == (int)sched.GetScheduledDispatch().front());
|
value = (offset == (int32_t)sched.GetScheduledDispatch().front().offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
return OrderConditionCompare(order->GetConditionComparator(), value ? 1 : 0, 0);
|
return OrderConditionCompare(order->GetConditionComparator(), value ? 1 : 0, 0);
|
||||||
|
@@ -647,11 +647,61 @@ CommandCost CmdScheduledDispatchSwapSchedules(TileIndex tile, DoCommandFlag flag
|
|||||||
return CommandCost();
|
return CommandCost();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add scheduled dispatch time offset
|
||||||
|
* @param tile Not used.
|
||||||
|
* @param flags Operation to perform.
|
||||||
|
* @param p1 Vehicle index.
|
||||||
|
* @param p2 Slot offset.
|
||||||
|
* @param p3 various bitstuffed elements
|
||||||
|
* - p3 = (bit 0 - 15) - flag values
|
||||||
|
* - p3 = (bit 16 - 31) - flag mask
|
||||||
|
* @param text unused
|
||||||
|
* @return the cost of this operation or an error
|
||||||
|
*/
|
||||||
|
CommandCost CmdScheduledDispatchSetSlotFlags(TileIndex tile, DoCommandFlag flags, uint32_t p1, uint32_t p2, uint64_t p3, const char *text, const CommandAuxiliaryBase *aux_data)
|
||||||
|
{
|
||||||
|
VehicleID veh = GB(p1, 0, 20);
|
||||||
|
uint schedule_index = GB(p1, 20, 12);
|
||||||
|
uint32_t offset = p2;
|
||||||
|
uint16_t values = (uint16_t)GB(p3, 0, 16);
|
||||||
|
uint16_t mask = (uint16_t)GB(p3, 16, 16);
|
||||||
|
|
||||||
|
const uint16_t permitted_mask = (1 << DispatchSlot::SDSF_REUSE_SLOT);
|
||||||
|
if ((mask & permitted_mask) != mask) return CMD_ERROR;
|
||||||
|
if ((values & (~mask)) != 0) return CMD_ERROR;
|
||||||
|
|
||||||
|
Vehicle *v = Vehicle::GetIfValid(veh);
|
||||||
|
if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
|
||||||
|
|
||||||
|
CommandCost ret = CheckOwnership(v->owner);
|
||||||
|
if (ret.Failed()) return ret;
|
||||||
|
|
||||||
|
if (v->orders == nullptr) return CMD_ERROR;
|
||||||
|
|
||||||
|
if (schedule_index >= v->orders->GetScheduledDispatchScheduleCount()) return CMD_ERROR;
|
||||||
|
|
||||||
|
DispatchSchedule &ds = v->orders->GetDispatchScheduleByIndex(schedule_index);
|
||||||
|
for (DispatchSlot &slot : ds.GetScheduledDispatchMutable()) {
|
||||||
|
if (slot.offset == offset) {
|
||||||
|
if (flags & DC_EXEC) {
|
||||||
|
slot.flags &= ~mask;
|
||||||
|
slot.flags |= values;
|
||||||
|
SchdispatchInvalidateWindows(v);
|
||||||
|
SetTimetableWindowsDirty(v, STWDF_SCHEDULED_DISPATCH);
|
||||||
|
}
|
||||||
|
return CommandCost();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set scheduled dispatch slot list.
|
* Set scheduled dispatch slot list.
|
||||||
* @param dispatch_list The offset time list, must be correctly sorted.
|
* @param dispatch_list The offset time list, must be correctly sorted.
|
||||||
*/
|
*/
|
||||||
void DispatchSchedule::SetScheduledDispatch(std::vector<uint32_t> dispatch_list)
|
void DispatchSchedule::SetScheduledDispatch(std::vector<DispatchSlot> dispatch_list)
|
||||||
{
|
{
|
||||||
this->scheduled_dispatch = std::move(dispatch_list);
|
this->scheduled_dispatch = std::move(dispatch_list);
|
||||||
assert(std::is_sorted(this->scheduled_dispatch.begin(), this->scheduled_dispatch.end()));
|
assert(std::is_sorted(this->scheduled_dispatch.begin(), this->scheduled_dispatch.end()));
|
||||||
@@ -665,11 +715,11 @@ void DispatchSchedule::SetScheduledDispatch(std::vector<uint32_t> dispatch_list)
|
|||||||
void DispatchSchedule::AddScheduledDispatch(uint32_t offset)
|
void DispatchSchedule::AddScheduledDispatch(uint32_t offset)
|
||||||
{
|
{
|
||||||
/* Maintain sorted list status */
|
/* Maintain sorted list status */
|
||||||
auto insert_position = std::lower_bound(this->scheduled_dispatch.begin(), this->scheduled_dispatch.end(), offset);
|
auto insert_position = std::lower_bound(this->scheduled_dispatch.begin(), this->scheduled_dispatch.end(), DispatchSlot{ offset, 0 });
|
||||||
if (insert_position != this->scheduled_dispatch.end() && *insert_position == offset) {
|
if (insert_position != this->scheduled_dispatch.end() && insert_position->offset == offset) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->scheduled_dispatch.insert(insert_position, offset);
|
this->scheduled_dispatch.insert(insert_position, { offset, 0 });
|
||||||
this->UpdateScheduledDispatch(nullptr);
|
this->UpdateScheduledDispatch(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -680,8 +730,8 @@ void DispatchSchedule::AddScheduledDispatch(uint32_t offset)
|
|||||||
void DispatchSchedule::RemoveScheduledDispatch(uint32_t offset)
|
void DispatchSchedule::RemoveScheduledDispatch(uint32_t offset)
|
||||||
{
|
{
|
||||||
/* Maintain sorted list status */
|
/* Maintain sorted list status */
|
||||||
auto erase_position = std::lower_bound(this->scheduled_dispatch.begin(), this->scheduled_dispatch.end(), offset);
|
auto erase_position = std::lower_bound(this->scheduled_dispatch.begin(), this->scheduled_dispatch.end(), DispatchSlot{ offset, 0 });
|
||||||
if (erase_position == this->scheduled_dispatch.end() || *erase_position != offset) {
|
if (erase_position == this->scheduled_dispatch.end() || erase_position->offset != offset) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->scheduled_dispatch.erase(erase_position);
|
this->scheduled_dispatch.erase(erase_position);
|
||||||
@@ -693,11 +743,11 @@ void DispatchSchedule::RemoveScheduledDispatch(uint32_t offset)
|
|||||||
*/
|
*/
|
||||||
void DispatchSchedule::AdjustScheduledDispatch(int32_t adjust)
|
void DispatchSchedule::AdjustScheduledDispatch(int32_t adjust)
|
||||||
{
|
{
|
||||||
for (uint32_t &time : this->scheduled_dispatch) {
|
for (DispatchSlot &slot : this->scheduled_dispatch) {
|
||||||
int32_t t = (int32_t)time + adjust;
|
int32_t t = (int32_t)slot.offset + adjust;
|
||||||
if (t < 0) t += GetScheduledDispatchDuration();
|
if (t < 0) t += GetScheduledDispatchDuration();
|
||||||
if (t >= (int32_t)GetScheduledDispatchDuration()) t -= (int32_t)GetScheduledDispatchDuration();
|
if (t >= (int32_t)GetScheduledDispatchDuration()) t -= (int32_t)GetScheduledDispatchDuration();
|
||||||
time = (uint32_t)t;
|
slot.offset = (uint32_t)t;
|
||||||
}
|
}
|
||||||
std::sort(this->scheduled_dispatch.begin(), this->scheduled_dispatch.end());
|
std::sort(this->scheduled_dispatch.begin(), this->scheduled_dispatch.end());
|
||||||
}
|
}
|
||||||
|
@@ -60,6 +60,7 @@ enum SchdispatchWidgets {
|
|||||||
WID_SCHDISPATCH_MANAGEMENT, ///< Management button
|
WID_SCHDISPATCH_MANAGEMENT, ///< Management button
|
||||||
WID_SCHDISPATCH_ADJUST, ///< Adjust departure times
|
WID_SCHDISPATCH_ADJUST, ///< Adjust departure times
|
||||||
WID_SCHDISPATCH_REMOVE, ///< Remove departure times
|
WID_SCHDISPATCH_REMOVE, ///< Remove departure times
|
||||||
|
WID_SCHDISPATCH_MANAGE_SLOT, ///< Manage slot button
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -129,10 +130,10 @@ static void ScheduleAddCallback(const Window *w, DateTicksScaled date)
|
|||||||
* @param offsets list of all dispatch offsets in the schedule
|
* @param offsets list of all dispatch offsets in the schedule
|
||||||
* @return maxinum number of vehicle required
|
* @return maxinum number of vehicle required
|
||||||
*/
|
*/
|
||||||
static int CalculateMaxRequiredVehicle(Ticks timetable_duration, uint32_t schedule_duration, std::vector<uint32_t> offsets)
|
static int CalculateMaxRequiredVehicle(Ticks timetable_duration, uint32_t schedule_duration, const std::vector<DispatchSlot> &slots)
|
||||||
{
|
{
|
||||||
if (timetable_duration == INVALID_TICKS) return -1;
|
if (timetable_duration == INVALID_TICKS) return -1;
|
||||||
if (offsets.size() == 0) return -1;
|
if (slots.size() == 0) return -1;
|
||||||
|
|
||||||
/* Number of time required to ensure all vehicle are counted */
|
/* Number of time required to ensure all vehicle are counted */
|
||||||
int required_loop = CeilDiv(timetable_duration, schedule_duration) + 1;
|
int required_loop = CeilDiv(timetable_duration, schedule_duration) + 1;
|
||||||
@@ -140,10 +141,10 @@ static int CalculateMaxRequiredVehicle(Ticks timetable_duration, uint32_t schedu
|
|||||||
/* Create indice array to count maximum overlapping range */
|
/* Create indice array to count maximum overlapping range */
|
||||||
std::vector<std::pair<uint32_t, int>> indices;
|
std::vector<std::pair<uint32_t, int>> indices;
|
||||||
for (int i = 0; i < required_loop; i++) {
|
for (int i = 0; i < required_loop; i++) {
|
||||||
for (uint32_t offset : offsets) {
|
for (const DispatchSlot &slot : slots) {
|
||||||
if (offset >= schedule_duration) continue;
|
if (slot.offset >= schedule_duration) continue;
|
||||||
indices.push_back(std::make_pair(i * schedule_duration + offset, 1));
|
indices.push_back(std::make_pair(i * schedule_duration + slot.offset, 1));
|
||||||
indices.push_back(std::make_pair(i * schedule_duration + offset + timetable_duration, -1));
|
indices.push_back(std::make_pair(i * schedule_duration + slot.offset + timetable_duration, -1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (indices.empty()) return -1;
|
if (indices.empty()) return -1;
|
||||||
@@ -204,6 +205,7 @@ struct SchdispatchWindow : GeneralVehicleWindow {
|
|||||||
int arrow_flag_height = 0;
|
int arrow_flag_height = 0;
|
||||||
|
|
||||||
bool remove_slot_mode = false;
|
bool remove_slot_mode = false;
|
||||||
|
uint32_t selected_slot = UINT32_MAX;
|
||||||
|
|
||||||
enum ManagementDropdown {
|
enum ManagementDropdown {
|
||||||
SCH_MD_RESET_LAST_DISPATCHED,
|
SCH_MD_RESET_LAST_DISPATCHED,
|
||||||
@@ -214,6 +216,10 @@ struct SchdispatchWindow : GeneralVehicleWindow {
|
|||||||
SCH_MD_REUSE_DEPARTURE_SLOTS,
|
SCH_MD_REUSE_DEPARTURE_SLOTS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum SlotManagementDropdown {
|
||||||
|
SCH_SMD_REUSE_DEPARTURE_SLOT,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
SchdispatchWindow(WindowDesc *desc, WindowNumber window_number) :
|
SchdispatchWindow(WindowDesc *desc, WindowNumber window_number) :
|
||||||
GeneralVehicleWindow(desc, Vehicle::Get(window_number))
|
GeneralVehicleWindow(desc, Vehicle::Get(window_number))
|
||||||
@@ -248,6 +254,7 @@ struct SchdispatchWindow : GeneralVehicleWindow {
|
|||||||
} else {
|
} else {
|
||||||
this->schedule_index = -1;
|
this->schedule_index = -1;
|
||||||
}
|
}
|
||||||
|
this->selected_slot = UINT32_MAX;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,6 +263,21 @@ struct SchdispatchWindow : GeneralVehicleWindow {
|
|||||||
return this->vehicle->orders->GetDispatchScheduleByIndex(this->schedule_index);
|
return this->vehicle->orders->GetDispatchScheduleByIndex(this->schedule_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DispatchSlot *GetSelectedDispatchSlot() const
|
||||||
|
{
|
||||||
|
if (!this->IsScheduleSelected()) return nullptr;
|
||||||
|
|
||||||
|
const DispatchSchedule &ds = this->GetSelectedSchedule();
|
||||||
|
if (this->selected_slot != UINT32_MAX) {
|
||||||
|
for (const DispatchSlot &slot : ds.GetScheduledDispatch()) {
|
||||||
|
if (slot.offset == this->selected_slot) {
|
||||||
|
return &slot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void UpdateWidgetSize(WidgetID widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
virtual void UpdateWidgetSize(WidgetID widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||||
{
|
{
|
||||||
switch (widget) {
|
switch (widget) {
|
||||||
@@ -263,7 +285,7 @@ struct SchdispatchWindow : GeneralVehicleWindow {
|
|||||||
uint min_height = 0;
|
uint min_height = 0;
|
||||||
|
|
||||||
SetDParamMaxValue(0, _settings_time.time_in_minutes ? 0 : MAX_YEAR * DAYS_IN_YEAR);
|
SetDParamMaxValue(0, _settings_time.time_in_minutes ? 0 : MAX_YEAR * DAYS_IN_YEAR);
|
||||||
Dimension unumber = GetStringBoundingBox(STR_JUST_DATE_WALLCLOCK_TINY);
|
Dimension unumber = GetStringBoundingBox(STR_SCHDISPATCH_DATE_WALLCLOCK_TINY_FLAGGED);
|
||||||
|
|
||||||
const Sprite *spr = GetSprite(SPR_FLAG_VEH_STOPPED, SpriteType::Normal, ZoomMask(ZOOM_LVL_GUI));
|
const Sprite *spr = GetSprite(SPR_FLAG_VEH_STOPPED, SpriteType::Normal, ZoomMask(ZOOM_LVL_GUI));
|
||||||
this->delete_flag_width = UnScaleGUI(spr->width);
|
this->delete_flag_width = UnScaleGUI(spr->width);
|
||||||
@@ -351,6 +373,11 @@ struct SchdispatchWindow : GeneralVehicleWindow {
|
|||||||
this->SetWidgetDisabledState(WID_SCHDISPATCH_MANAGEMENT, disabled);
|
this->SetWidgetDisabledState(WID_SCHDISPATCH_MANAGEMENT, disabled);
|
||||||
this->SetWidgetDisabledState(WID_SCHDISPATCH_ADJUST, no_editable_slots);
|
this->SetWidgetDisabledState(WID_SCHDISPATCH_ADJUST, no_editable_slots);
|
||||||
|
|
||||||
|
if (no_editable_slots || this->GetSelectedDispatchSlot() == nullptr) {
|
||||||
|
this->selected_slot = UINT32_MAX;
|
||||||
|
}
|
||||||
|
this->SetWidgetDisabledState(WID_SCHDISPATCH_MANAGE_SLOT, this->selected_slot == UINT32_MAX);
|
||||||
|
|
||||||
NWidgetCore *remove_slot_widget = this->GetWidget<NWidgetCore>(WID_SCHDISPATCH_REMOVE);
|
NWidgetCore *remove_slot_widget = this->GetWidget<NWidgetCore>(WID_SCHDISPATCH_REMOVE);
|
||||||
remove_slot_widget->SetDisabled(no_editable_slots);
|
remove_slot_widget->SetDisabled(no_editable_slots);
|
||||||
if (no_editable_slots) {
|
if (no_editable_slots) {
|
||||||
@@ -417,7 +444,13 @@ struct SchdispatchWindow : GeneralVehicleWindow {
|
|||||||
add_suffix(STR_SCHDISPATCH_REMOVE_SCHEDULE_TOOLTIP);
|
add_suffix(STR_SCHDISPATCH_REMOVE_SCHEDULE_TOOLTIP);
|
||||||
add_suffix(STR_SCHDISPATCH_DUPLICATE_SCHEDULE_TOOLTIP);
|
add_suffix(STR_SCHDISPATCH_DUPLICATE_SCHEDULE_TOOLTIP);
|
||||||
add_suffix(STR_SCHDISPATCH_APPEND_VEHICLE_SCHEDULES_TOOLTIP);
|
add_suffix(STR_SCHDISPATCH_APPEND_VEHICLE_SCHEDULES_TOOLTIP);
|
||||||
add_suffix(STR_SCHDISPATCH_APPEND_REUSE_DEPARTURE_SLOTS_TOOLTIP);
|
add_suffix(STR_SCHDISPATCH_REUSE_DEPARTURE_SLOTS_TOOLTIP);
|
||||||
|
GuiShowTooltips(this, SPECSTR_TEMP_START, close_cond);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WID_SCHDISPATCH_MANAGE_SLOT: {
|
||||||
|
_temp_special_strings[0] = GetString(STR_SCHDISPATCH_REUSE_THIS_DEPARTURE_SLOT_TOOLTIP);
|
||||||
GuiShowTooltips(this, SPECSTR_TEMP_START, close_cond);
|
GuiShowTooltips(this, SPECSTR_TEMP_START, close_cond);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -436,7 +469,7 @@ struct SchdispatchWindow : GeneralVehicleWindow {
|
|||||||
* @param right Right side of the box to draw in.
|
* @param right Right side of the box to draw in.
|
||||||
* @param y Top of the box to draw in.
|
* @param y Top of the box to draw in.
|
||||||
*/
|
*/
|
||||||
void DrawScheduledTime(const DateTicksScaled time, int left, int right, int y, TextColour colour, bool last, bool next) const
|
void DrawScheduledTime(const DateTicksScaled time, int left, int right, int y, TextColour colour, bool last, bool next, bool flagged) const
|
||||||
{
|
{
|
||||||
bool rtl = _current_text_dir == TD_RTL;
|
bool rtl = _current_text_dir == TD_RTL;
|
||||||
|
|
||||||
@@ -462,7 +495,7 @@ struct SchdispatchWindow : GeneralVehicleWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SetDParam(0, time);
|
SetDParam(0, time);
|
||||||
DrawString(text_left, text_right, y + 2, STR_JUST_DATE_WALLCLOCK_TINY, colour);
|
DrawString(text_left, text_right, y + 2, flagged ? STR_SCHDISPATCH_DATE_WALLCLOCK_TINY_FLAGGED : STR_JUST_DATE_WALLCLOCK_TINY, colour, SA_HOR_CENTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void OnGameTick() override
|
virtual void OnGameTick() override
|
||||||
@@ -502,16 +535,26 @@ struct SchdispatchWindow : GeneralVehicleWindow {
|
|||||||
DateTicksScaled slot = GetScheduledDispatchTime(ds, _scaled_date_ticks);
|
DateTicksScaled slot = GetScheduledDispatchTime(ds, _scaled_date_ticks);
|
||||||
int32_t next_offset = (slot - ds.GetScheduledDispatchStartTick()).AsTicks() % ds.GetScheduledDispatchDuration();
|
int32_t next_offset = (slot - ds.GetScheduledDispatchStartTick()).AsTicks() % ds.GetScheduledDispatchDuration();
|
||||||
|
|
||||||
|
int32_t last_dispatch = ds.GetScheduledDispatchLastDispatch() % ds.GetScheduledDispatchDuration();
|
||||||
|
|
||||||
for (int y = r.top + 1; num < maxval; y += this->resize.step_height) { /* Draw the rows */
|
for (int y = r.top + 1; num < maxval; y += this->resize.step_height) { /* Draw the rows */
|
||||||
for (uint i = 0; i < this->num_columns && num < maxval; i++, num++) {
|
for (uint i = 0; i < this->num_columns && num < maxval; i++, num++) {
|
||||||
/* Draw all departure time in the current row */
|
/* Draw all departure time in the current row */
|
||||||
if (current_schedule != ds.GetScheduledDispatch().end()) {
|
if (current_schedule != ds.GetScheduledDispatch().end()) {
|
||||||
int x = r.left + (rtl ? (this->num_columns - i - 1) : i) * this->resize.step_width;
|
int x = r.left + (rtl ? (this->num_columns - i - 1) : i) * this->resize.step_width;
|
||||||
DateTicksScaled draw_time = start_tick + *current_schedule;
|
DateTicksScaled draw_time = start_tick + current_schedule->offset;
|
||||||
bool last = ds.GetScheduledDispatchLastDispatch() == (int32_t)*current_schedule;
|
bool last = last_dispatch == (int32_t)current_schedule->offset;
|
||||||
bool next = next_offset == (int32_t)*current_schedule;
|
bool next = next_offset == (int32_t)current_schedule->offset;
|
||||||
|
TextColour colour;
|
||||||
|
if (this->selected_slot == current_schedule->offset) {
|
||||||
|
colour = TC_WHITE;
|
||||||
|
} else {
|
||||||
|
colour = draw_time >= end_tick ? TC_RED : TC_BLACK;
|
||||||
|
}
|
||||||
|
auto flags = current_schedule->flags;
|
||||||
|
if (ds.GetScheduledDispatchReuseSlots()) ClrBit(flags, DispatchSlot::SDSF_REUSE_SLOT);
|
||||||
this->DrawScheduledTime(draw_time, x + WidgetDimensions::scaled.framerect.left, x + this->resize.step_width - 1 - (2 * WidgetDimensions::scaled.framerect.left),
|
this->DrawScheduledTime(draw_time, x + WidgetDimensions::scaled.framerect.left, x + this->resize.step_width - 1 - (2 * WidgetDimensions::scaled.framerect.left),
|
||||||
y, draw_time >= end_tick ? TC_RED : TC_BLACK, last, next);
|
y, colour, last, next, flags != 0);
|
||||||
current_schedule++;
|
current_schedule++;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
@@ -699,8 +742,8 @@ struct SchdispatchWindow : GeneralVehicleWindow {
|
|||||||
y += GetCharacterHeight(FS_NORMAL);
|
y += GetCharacterHeight(FS_NORMAL);
|
||||||
|
|
||||||
uint32_t duration = ds.GetScheduledDispatchDuration();
|
uint32_t duration = ds.GetScheduledDispatchDuration();
|
||||||
for (uint32_t slot : ds.GetScheduledDispatch()) {
|
for (const DispatchSlot &slot : ds.GetScheduledDispatch()) {
|
||||||
if (slot >= duration) {
|
if (slot.offset >= duration) {
|
||||||
draw_warning(STR_SCHDISPATCH_SLOT_OUTSIDE_SCHEDULE);
|
draw_warning(STR_SCHDISPATCH_SLOT_OUTSIDE_SCHEDULE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -743,11 +786,26 @@ struct SchdispatchWindow : GeneralVehicleWindow {
|
|||||||
|
|
||||||
const DispatchSchedule &ds = this->GetSelectedSchedule();
|
const DispatchSchedule &ds = this->GetSelectedSchedule();
|
||||||
|
|
||||||
if (pos >= this->item_count || pos >= ds.GetScheduledDispatch().size()) return;
|
if (pos >= this->item_count || pos >= ds.GetScheduledDispatch().size()) {
|
||||||
|
if (this->selected_slot != UINT32_MAX) {
|
||||||
|
this->selected_slot = UINT32_MAX;
|
||||||
|
this->SetWidgetDirty(WID_SCHDISPATCH_MATRIX);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t offset = ds.GetScheduledDispatch()[pos].offset;
|
||||||
|
|
||||||
if (xm <= this->header_width && this->remove_slot_mode) {
|
if (xm <= this->header_width && this->remove_slot_mode) {
|
||||||
DoCommandP(0, this->vehicle->index | (this->schedule_index << 20), ds.GetScheduledDispatch()[pos], CMD_SCHEDULED_DISPATCH_REMOVE | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE));
|
DoCommandP(0, this->vehicle->index | (this->schedule_index << 20), offset, CMD_SCHEDULED_DISPATCH_REMOVE | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this->selected_slot == offset) {
|
||||||
|
this->selected_slot = UINT32_MAX;
|
||||||
|
} else {
|
||||||
|
this->selected_slot = offset;
|
||||||
|
}
|
||||||
|
this->SetWidgetDirty(WID_SCHDISPATCH_MATRIX);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t ProcessDurationForQueryString(int32_t duration) const
|
int32_t ProcessDurationForQueryString(int32_t duration) const
|
||||||
@@ -842,20 +900,26 @@ struct SchdispatchWindow : GeneralVehicleWindow {
|
|||||||
add_item(STR_SCHDISPATCH_REMOVE_SCHEDULE, SCH_MD_REMOVE_SCHEDULE);
|
add_item(STR_SCHDISPATCH_REMOVE_SCHEDULE, SCH_MD_REMOVE_SCHEDULE);
|
||||||
add_item(STR_SCHDISPATCH_DUPLICATE_SCHEDULE, SCH_MD_DUPLICATE_SCHEDULE);
|
add_item(STR_SCHDISPATCH_DUPLICATE_SCHEDULE, SCH_MD_DUPLICATE_SCHEDULE);
|
||||||
add_item(STR_SCHDISPATCH_APPEND_VEHICLE_SCHEDULES, SCH_MD_APPEND_VEHICLE_SCHEDULES);
|
add_item(STR_SCHDISPATCH_APPEND_VEHICLE_SCHEDULES, SCH_MD_APPEND_VEHICLE_SCHEDULES);
|
||||||
list.push_back(std::make_unique<DropDownListCheckedItem>(schedule.GetScheduledDispatchReuseSlots(), STR_SCHDISPATCH_APPEND_REUSE_DEPARTURE_SLOTS, SCH_MD_REUSE_DEPARTURE_SLOTS, false));
|
list.push_back(std::make_unique<DropDownListCheckedItem>(schedule.GetScheduledDispatchReuseSlots(), STR_SCHDISPATCH_REUSE_DEPARTURE_SLOTS, SCH_MD_REUSE_DEPARTURE_SLOTS, false));
|
||||||
ShowDropDownList(this, std::move(list), -1, WID_SCHDISPATCH_MANAGEMENT);
|
ShowDropDownList(this, std::move(list), -1, WID_SCHDISPATCH_MANAGEMENT);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case WID_SCHDISPATCH_PREV:
|
case WID_SCHDISPATCH_PREV:
|
||||||
if (!this->IsScheduleSelected()) break;
|
if (!this->IsScheduleSelected()) break;
|
||||||
if (this->schedule_index > 0) this->schedule_index--;
|
if (this->schedule_index > 0) {
|
||||||
|
this->schedule_index--;
|
||||||
|
this->selected_slot = UINT32_MAX;
|
||||||
|
}
|
||||||
this->ReInit();
|
this->ReInit();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WID_SCHDISPATCH_NEXT:
|
case WID_SCHDISPATCH_NEXT:
|
||||||
if (!this->IsScheduleSelected()) break;
|
if (!this->IsScheduleSelected()) break;
|
||||||
if (this->schedule_index < (int)(this->vehicle->orders->GetScheduledDispatchScheduleCount() - 1)) this->schedule_index++;
|
if (this->schedule_index < (int)(this->vehicle->orders->GetScheduledDispatchScheduleCount() - 1)) {
|
||||||
|
this->schedule_index++;
|
||||||
|
this->selected_slot = UINT32_MAX;
|
||||||
|
}
|
||||||
this->ReInit();
|
this->ReInit();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -885,6 +949,18 @@ struct SchdispatchWindow : GeneralVehicleWindow {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case WID_SCHDISPATCH_MANAGE_SLOT: {
|
||||||
|
const DispatchSlot *selected_slot = this->GetSelectedDispatchSlot();
|
||||||
|
if (selected_slot == nullptr) break;
|
||||||
|
const DispatchSchedule &schedule = this->GetSelectedSchedule();
|
||||||
|
|
||||||
|
DropDownList list;
|
||||||
|
list.push_back(std::make_unique<DropDownListCheckedItem>(HasBit(selected_slot->flags, DispatchSlot::SDSF_REUSE_SLOT),
|
||||||
|
STR_SCHDISPATCH_REUSE_THIS_DEPARTURE_SLOT, SCH_SMD_REUSE_DEPARTURE_SLOT, schedule.GetScheduledDispatchReuseSlots()));
|
||||||
|
ShowDropDownList(this, std::move(list), -1, WID_SCHDISPATCH_MANAGE_SLOT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case WID_SCHDISPATCH_MOVE_LEFT:
|
case WID_SCHDISPATCH_MOVE_LEFT:
|
||||||
if (!this->IsScheduleSelected()) break;
|
if (!this->IsScheduleSelected()) break;
|
||||||
if (this->schedule_index > 0) {
|
if (this->schedule_index > 0) {
|
||||||
@@ -963,6 +1039,23 @@ struct SchdispatchWindow : GeneralVehicleWindow {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WID_SCHDISPATCH_MANAGE_SLOT: {
|
||||||
|
const DispatchSlot *selected_slot = this->GetSelectedDispatchSlot();
|
||||||
|
if (selected_slot == nullptr) break;
|
||||||
|
|
||||||
|
switch((SlotManagementDropdown)index) {
|
||||||
|
case SCH_SMD_REUSE_DEPARTURE_SLOT: {
|
||||||
|
uint64_t p3 = 0;
|
||||||
|
SetBit(p3, SCH_SMD_REUSE_DEPARTURE_SLOT + 16);
|
||||||
|
if (!HasBit(selected_slot->flags, SCH_SMD_REUSE_DEPARTURE_SLOT)) SetBit(p3, SCH_SMD_REUSE_DEPARTURE_SLOT);
|
||||||
|
DoCommandPEx(0, this->vehicle->index | (this->schedule_index << 20), this->selected_slot, p3, CMD_SCHEDULED_DISPATCH_SET_SLOT_FLAGS | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE), nullptr, nullptr, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -1145,6 +1238,7 @@ static constexpr NWidgetPart _nested_schdispatch_widgets[] = {
|
|||||||
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCHDISPATCH_ADD), SetDataTip(STR_SCHDISPATCH_ADD, STR_SCHDISPATCH_ADD_TOOLTIP), SetFill(1, 1), SetResize(1, 0),
|
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCHDISPATCH_ADD), SetDataTip(STR_SCHDISPATCH_ADD, STR_SCHDISPATCH_ADD_TOOLTIP), SetFill(1, 1), SetResize(1, 0),
|
||||||
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCHDISPATCH_ADJUST), SetDataTip(STR_SCHDISPATCH_ADJUST, STR_SCHDISPATCH_ADJUST_TOOLTIP), SetFill(1, 1), SetResize(1, 0),
|
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCHDISPATCH_ADJUST), SetDataTip(STR_SCHDISPATCH_ADJUST, STR_SCHDISPATCH_ADJUST_TOOLTIP), SetFill(1, 1), SetResize(1, 0),
|
||||||
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCHDISPATCH_REMOVE), SetDataTip(STR_SCHDISPATCH_REMOVE, STR_SCHDISPATCH_REMOVE_TOOLTIP), SetFill(1, 1), SetResize(1, 0),
|
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCHDISPATCH_REMOVE), SetDataTip(STR_SCHDISPATCH_REMOVE, STR_SCHDISPATCH_REMOVE_TOOLTIP), SetFill(1, 1), SetResize(1, 0),
|
||||||
|
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SCHDISPATCH_MANAGE_SLOT), SetDataTip(STR_SCHDISPATCH_MANAGE_SLOT, STR_NULL), SetFill(1, 1), SetResize(1, 0),
|
||||||
EndContainer(),
|
EndContainer(),
|
||||||
NWidget(WWT_PANEL, COLOUR_GREY, WID_SCHDISPATCH_SUMMARY_PANEL), SetMinimalSize(400, 22), SetResize(1, 0), EndContainer(),
|
NWidget(WWT_PANEL, COLOUR_GREY, WID_SCHDISPATCH_SUMMARY_PANEL), SetMinimalSize(400, 22), SetResize(1, 0), EndContainer(),
|
||||||
NWidget(NWID_HORIZONTAL),
|
NWidget(NWID_HORIZONTAL),
|
||||||
|
@@ -117,7 +117,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
|
|||||||
{ XSLFI_STATION_CATCHMENT_INC, XSCF_NULL, 1, 1, "station_catchment_inc", nullptr, nullptr, nullptr },
|
{ XSLFI_STATION_CATCHMENT_INC, XSCF_NULL, 1, 1, "station_catchment_inc", nullptr, nullptr, nullptr },
|
||||||
{ XSLFI_CUSTOM_BRIDGE_HEADS, XSCF_NULL, 4, 4, "custom_bridge_heads", nullptr, nullptr, nullptr },
|
{ XSLFI_CUSTOM_BRIDGE_HEADS, XSCF_NULL, 4, 4, "custom_bridge_heads", nullptr, nullptr, nullptr },
|
||||||
{ XSLFI_CHUNNEL, XSCF_NULL, 2, 2, "chunnel", nullptr, nullptr, "TUNN" },
|
{ XSLFI_CHUNNEL, XSCF_NULL, 2, 2, "chunnel", nullptr, nullptr, "TUNN" },
|
||||||
{ XSLFI_SCHEDULED_DISPATCH, XSCF_NULL, 6, 6, "scheduled_dispatch", nullptr, nullptr, nullptr },
|
{ XSLFI_SCHEDULED_DISPATCH, XSCF_NULL, 7, 7, "scheduled_dispatch", nullptr, nullptr, nullptr },
|
||||||
{ XSLFI_MORE_TOWN_GROWTH_RATES, XSCF_NULL, 1, 1, "more_town_growth_rates", nullptr, nullptr, nullptr },
|
{ XSLFI_MORE_TOWN_GROWTH_RATES, XSCF_NULL, 1, 1, "more_town_growth_rates", nullptr, nullptr, nullptr },
|
||||||
{ XSLFI_MULTIPLE_DOCKS, XSCF_NULL, 2, 2, "multiple_docks", nullptr, nullptr, nullptr },
|
{ XSLFI_MULTIPLE_DOCKS, XSCF_NULL, 2, 2, "multiple_docks", nullptr, nullptr, nullptr },
|
||||||
{ XSLFI_TIMETABLE_EXTRA, XSCF_NULL, 7, 7, "timetable_extra", nullptr, nullptr, "ORDX" },
|
{ XSLFI_TIMETABLE_EXTRA, XSCF_NULL, 7, 7, "timetable_extra", nullptr, nullptr, "ORDX" },
|
||||||
|
@@ -22,6 +22,7 @@ std::vector<OrderList *> _jokerpp_non_auto_separation;
|
|||||||
|
|
||||||
static uint16_t _old_scheduled_dispatch_start_full_date_fract;
|
static uint16_t _old_scheduled_dispatch_start_full_date_fract;
|
||||||
btree::btree_map<DispatchSchedule *, uint16_t> _old_scheduled_dispatch_start_full_date_fract_map;
|
btree::btree_map<DispatchSchedule *, uint16_t> _old_scheduled_dispatch_start_full_date_fract_map;
|
||||||
|
static std::vector<uint32_t> _old_scheduled_dispatch_slots;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts this order from an old savegame's version;
|
* Converts this order from an old savegame's version;
|
||||||
@@ -264,7 +265,7 @@ static void Ptrs_ORDR()
|
|||||||
SaveLoadTable GetDispatchScheduleDescription()
|
SaveLoadTable GetDispatchScheduleDescription()
|
||||||
{
|
{
|
||||||
static const SaveLoad _dispatch_scheduled_info_desc[] = {
|
static const SaveLoad _dispatch_scheduled_info_desc[] = {
|
||||||
SLE_VARVEC(DispatchSchedule, scheduled_dispatch, SLE_UINT32),
|
SLEG_CONDVARVEC_X(_old_scheduled_dispatch_slots, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 1, 6)),
|
||||||
SLE_VAR(DispatchSchedule, scheduled_dispatch_duration, SLE_UINT32),
|
SLE_VAR(DispatchSchedule, scheduled_dispatch_duration, SLE_UINT32),
|
||||||
SLE_CONDVAR_X(DispatchSchedule, scheduled_dispatch_start_tick, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 1, 4)),
|
SLE_CONDVAR_X(DispatchSchedule, scheduled_dispatch_start_tick, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 1, 4)),
|
||||||
SLEG_CONDVAR_X(_old_scheduled_dispatch_start_full_date_fract, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 1, 4)),
|
SLEG_CONDVAR_X(_old_scheduled_dispatch_start_full_date_fract, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 1, 4)),
|
||||||
@@ -278,6 +279,16 @@ SaveLoadTable GetDispatchScheduleDescription()
|
|||||||
return _dispatch_scheduled_info_desc;
|
return _dispatch_scheduled_info_desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SaveLoadTable GetDispatchSlotDescription()
|
||||||
|
{
|
||||||
|
static const SaveLoad _dispatch_slot_info_desc[] = {
|
||||||
|
SLE_VAR(DispatchSlot, offset, SLE_UINT32),
|
||||||
|
SLE_VAR(DispatchSlot, flags, SLE_UINT16),
|
||||||
|
};
|
||||||
|
|
||||||
|
return _dispatch_slot_info_desc;
|
||||||
|
}
|
||||||
|
|
||||||
SaveLoadTable GetOrderListDescription()
|
SaveLoadTable GetOrderListDescription()
|
||||||
{
|
{
|
||||||
static const SaveLoad _orderlist_desc[] = {
|
static const SaveLoad _orderlist_desc[] = {
|
||||||
@@ -291,11 +302,13 @@ SaveLoadTable GetOrderListDescription()
|
|||||||
|
|
||||||
static std::vector<SaveLoad> _filtered_ordl_desc;
|
static std::vector<SaveLoad> _filtered_ordl_desc;
|
||||||
static std::vector<SaveLoad> _filtered_ordl_sd_desc;
|
static std::vector<SaveLoad> _filtered_ordl_sd_desc;
|
||||||
|
static std::vector<SaveLoad> _filtered_ordl_slot_desc;
|
||||||
|
|
||||||
static void SetupDescs_ORDL()
|
static void SetupDescs_ORDL()
|
||||||
{
|
{
|
||||||
_filtered_ordl_desc = SlFilterObject(GetOrderListDescription());
|
_filtered_ordl_desc = SlFilterObject(GetOrderListDescription());
|
||||||
_filtered_ordl_sd_desc = SlFilterObject(GetDispatchScheduleDescription());
|
_filtered_ordl_sd_desc = SlFilterObject(GetDispatchScheduleDescription());
|
||||||
|
_filtered_ordl_slot_desc = SlFilterObject(GetDispatchSlotDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Save_ORDL()
|
static void Save_ORDL()
|
||||||
@@ -309,6 +322,11 @@ static void Save_ORDL()
|
|||||||
SlWriteUint32(list->GetScheduledDispatchScheduleCount());
|
SlWriteUint32(list->GetScheduledDispatchScheduleCount());
|
||||||
for (DispatchSchedule &ds : list->GetScheduledDispatchScheduleSet()) {
|
for (DispatchSchedule &ds : list->GetScheduledDispatchScheduleSet()) {
|
||||||
SlObjectSaveFiltered(&ds, _filtered_ordl_sd_desc);
|
SlObjectSaveFiltered(&ds, _filtered_ordl_sd_desc);
|
||||||
|
|
||||||
|
SlWriteUint32((uint32_t)ds.GetScheduledDispatchMutable().size());
|
||||||
|
for (DispatchSlot &slot : ds.GetScheduledDispatchMutable()) {
|
||||||
|
SlObjectSaveFiltered(&slot, _filtered_ordl_slot_desc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, list);
|
}, list);
|
||||||
}
|
}
|
||||||
@@ -344,9 +362,23 @@ static void Load_ORDL()
|
|||||||
if (SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 1, 4) && _old_scheduled_dispatch_start_full_date_fract != 0) {
|
if (SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 1, 4) && _old_scheduled_dispatch_start_full_date_fract != 0) {
|
||||||
_old_scheduled_dispatch_start_full_date_fract_map[&ds] = _old_scheduled_dispatch_start_full_date_fract;
|
_old_scheduled_dispatch_start_full_date_fract_map[&ds] = _old_scheduled_dispatch_start_full_date_fract;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 1, 6)) {
|
||||||
|
ds.GetScheduledDispatchMutable().reserve(_old_scheduled_dispatch_slots.size());
|
||||||
|
for (uint32_t slot : _old_scheduled_dispatch_slots) {
|
||||||
|
ds.GetScheduledDispatchMutable().push_back({ slot, 0 });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ds.GetScheduledDispatchMutable().resize(SlReadUint32());
|
||||||
|
for (DispatchSlot &slot : ds.GetScheduledDispatchMutable()) {
|
||||||
|
SlObjectLoadFiltered(&slot, _filtered_ordl_slot_desc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_old_scheduled_dispatch_slots.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Ptrs_ORDL()
|
void Ptrs_ORDL()
|
||||||
|
@@ -807,10 +807,14 @@ DateTicksScaled GetScheduledDispatchTime(const DispatchSchedule &ds, DateTicksSc
|
|||||||
DateTicksScaled first_slot = -1;
|
DateTicksScaled first_slot = -1;
|
||||||
|
|
||||||
/* Find next available slots */
|
/* Find next available slots */
|
||||||
for (auto current_offset : ds.GetScheduledDispatch()) {
|
for (const DispatchSlot &slot : ds.GetScheduledDispatch()) {
|
||||||
|
auto current_offset = slot.offset;
|
||||||
if (current_offset >= dispatch_duration) continue;
|
if (current_offset >= dispatch_duration) continue;
|
||||||
if ((int32_t)current_offset <= last_dispatched_offset) {
|
|
||||||
current_offset += dispatch_duration * ((last_dispatched_offset + dispatch_duration - current_offset) / dispatch_duration);
|
int32_t threshold = last_dispatched_offset;
|
||||||
|
if (HasBit(slot.flags, DispatchSlot::SDSF_REUSE_SLOT)) threshold--;
|
||||||
|
if ((int32_t)current_offset <= threshold) {
|
||||||
|
current_offset += dispatch_duration * ((threshold + dispatch_duration - current_offset) / dispatch_duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
DateTicksScaled current_departure = begin_time + current_offset;
|
DateTicksScaled current_departure = begin_time + current_offset;
|
||||||
|
Reference in New Issue
Block a user