Scheduled dispatch: Add per dispatch slot flags field

Add flag for slot re-use
This commit is contained in:
Jonathan G Rennison
2024-01-28 01:48:54 +00:00
parent dee611f5f3
commit 6c329871f1
11 changed files with 260 additions and 49 deletions

View File

@@ -60,6 +60,7 @@ enum SchdispatchWidgets {
WID_SCHDISPATCH_MANAGEMENT, ///< Management button
WID_SCHDISPATCH_ADJUST, ///< Adjust 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
* @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 (offsets.size() == 0) return -1;
if (slots.size() == 0) return -1;
/* Number of time required to ensure all vehicle are counted */
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 */
std::vector<std::pair<uint32_t, int>> indices;
for (int i = 0; i < required_loop; i++) {
for (uint32_t offset : offsets) {
if (offset >= schedule_duration) continue;
indices.push_back(std::make_pair(i * schedule_duration + offset, 1));
indices.push_back(std::make_pair(i * schedule_duration + offset + timetable_duration, -1));
for (const DispatchSlot &slot : slots) {
if (slot.offset >= schedule_duration) continue;
indices.push_back(std::make_pair(i * schedule_duration + slot.offset, 1));
indices.push_back(std::make_pair(i * schedule_duration + slot.offset + timetable_duration, -1));
}
}
if (indices.empty()) return -1;
@@ -204,6 +205,7 @@ struct SchdispatchWindow : GeneralVehicleWindow {
int arrow_flag_height = 0;
bool remove_slot_mode = false;
uint32_t selected_slot = UINT32_MAX;
enum ManagementDropdown {
SCH_MD_RESET_LAST_DISPATCHED,
@@ -214,6 +216,10 @@ struct SchdispatchWindow : GeneralVehicleWindow {
SCH_MD_REUSE_DEPARTURE_SLOTS,
};
enum SlotManagementDropdown {
SCH_SMD_REUSE_DEPARTURE_SLOT,
};
SchdispatchWindow(WindowDesc *desc, WindowNumber window_number) :
GeneralVehicleWindow(desc, Vehicle::Get(window_number))
@@ -248,6 +254,7 @@ struct SchdispatchWindow : GeneralVehicleWindow {
} else {
this->schedule_index = -1;
}
this->selected_slot = UINT32_MAX;
}
}
@@ -256,6 +263,21 @@ struct SchdispatchWindow : GeneralVehicleWindow {
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
{
switch (widget) {
@@ -263,7 +285,7 @@ struct SchdispatchWindow : GeneralVehicleWindow {
uint min_height = 0;
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));
this->delete_flag_width = UnScaleGUI(spr->width);
@@ -351,6 +373,11 @@ struct SchdispatchWindow : GeneralVehicleWindow {
this->SetWidgetDisabledState(WID_SCHDISPATCH_MANAGEMENT, disabled);
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);
remove_slot_widget->SetDisabled(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_DUPLICATE_SCHEDULE_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);
return true;
}
@@ -436,7 +469,7 @@ struct SchdispatchWindow : GeneralVehicleWindow {
* @param right Right side 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;
@@ -462,7 +495,7 @@ struct SchdispatchWindow : GeneralVehicleWindow {
}
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
@@ -502,16 +535,26 @@ struct SchdispatchWindow : GeneralVehicleWindow {
DateTicksScaled slot = GetScheduledDispatchTime(ds, _scaled_date_ticks);
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 (uint i = 0; i < this->num_columns && num < maxval; i++, num++) {
/* Draw all departure time in the current row */
if (current_schedule != ds.GetScheduledDispatch().end()) {
int x = r.left + (rtl ? (this->num_columns - i - 1) : i) * this->resize.step_width;
DateTicksScaled draw_time = start_tick + *current_schedule;
bool last = ds.GetScheduledDispatchLastDispatch() == (int32_t)*current_schedule;
bool next = next_offset == (int32_t)*current_schedule;
DateTicksScaled draw_time = start_tick + current_schedule->offset;
bool last = last_dispatch == (int32_t)current_schedule->offset;
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),
y, draw_time >= end_tick ? TC_RED : TC_BLACK, last, next);
y, colour, last, next, flags != 0);
current_schedule++;
} else {
break;
@@ -699,8 +742,8 @@ struct SchdispatchWindow : GeneralVehicleWindow {
y += GetCharacterHeight(FS_NORMAL);
uint32_t duration = ds.GetScheduledDispatchDuration();
for (uint32_t slot : ds.GetScheduledDispatch()) {
if (slot >= duration) {
for (const DispatchSlot &slot : ds.GetScheduledDispatch()) {
if (slot.offset >= duration) {
draw_warning(STR_SCHDISPATCH_SLOT_OUTSIDE_SCHEDULE);
break;
}
@@ -743,11 +786,26 @@ struct SchdispatchWindow : GeneralVehicleWindow {
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) {
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
@@ -842,20 +900,26 @@ struct SchdispatchWindow : GeneralVehicleWindow {
add_item(STR_SCHDISPATCH_REMOVE_SCHEDULE, SCH_MD_REMOVE_SCHEDULE);
add_item(STR_SCHDISPATCH_DUPLICATE_SCHEDULE, SCH_MD_DUPLICATE_SCHEDULE);
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);
break;
}
case WID_SCHDISPATCH_PREV:
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();
break;
case WID_SCHDISPATCH_NEXT:
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();
break;
@@ -885,6 +949,18 @@ struct SchdispatchWindow : GeneralVehicleWindow {
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:
if (!this->IsScheduleSelected()) break;
if (this->schedule_index > 0) {
@@ -963,6 +1039,23 @@ struct SchdispatchWindow : GeneralVehicleWindow {
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:
@@ -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_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_DROPDOWN, COLOUR_GREY, WID_SCHDISPATCH_MANAGE_SLOT), SetDataTip(STR_SCHDISPATCH_MANAGE_SLOT, STR_NULL), SetFill(1, 1), SetResize(1, 0),
EndContainer(),
NWidget(WWT_PANEL, COLOUR_GREY, WID_SCHDISPATCH_SUMMARY_PANEL), SetMinimalSize(400, 22), SetResize(1, 0), EndContainer(),
NWidget(NWID_HORIZONTAL),