Scheduled dispatch: Allow naming departure slot tags

This commit is contained in:
Jonathan G Rennison
2024-06-13 19:32:42 +01:00
parent fe294403aa
commit fff46974fd
11 changed files with 215 additions and 36 deletions

View File

@@ -306,6 +306,7 @@ CommandProc CmdScheduledDispatchAppendVehicleSchedules;
CommandProc CmdScheduledDispatchAdjust; CommandProc CmdScheduledDispatchAdjust;
CommandProc CmdScheduledDispatchSwapSchedules; CommandProc CmdScheduledDispatchSwapSchedules;
CommandProcEx CmdScheduledDispatchSetSlotFlags; CommandProcEx CmdScheduledDispatchSetSlotFlags;
CommandProc CmdScheduledDispatchRenameTag;
CommandProc CmdAddPlan; CommandProc CmdAddPlan;
CommandProcEx CmdAddPlanLine; CommandProcEx CmdAddPlanLine;
@@ -572,6 +573,7 @@ static const Command _command_proc_table[] = {
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(CmdScheduledDispatchSetSlotFlags, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SCHEDULED_DISPATCH_SET_SLOT_FLAGS
DEF_CMD(CmdScheduledDispatchRenameTag, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SCHEDULED_DISPATCH_RENAME_TAG
DEF_CMD(CmdAddPlan, 0, CMDT_OTHER_MANAGEMENT ), // CMD_ADD_PLAN DEF_CMD(CmdAddPlan, 0, 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

View File

@@ -522,6 +522,7 @@ enum Commands {
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_SCHEDULED_DISPATCH_SET_SLOT_FLAGS, ///< scheduled dispatch set flags of dispatch slot
CMD_SCHEDULED_DISPATCH_RENAME_TAG, ///< scheduled dispatch rename departure tag
CMD_ADD_PLAN, CMD_ADD_PLAN,
CMD_ADD_PLAN_LINE, CMD_ADD_PLAN_LINE,

View File

@@ -1723,8 +1723,14 @@ STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_FIRST :is first slot
STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_NOT_FIRST :is not first slot STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_NOT_FIRST :is not first slot
STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_LAST :is last slot STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_LAST :is last slot
STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_NOT_LAST :is not last slot STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_NOT_LAST :is not last slot
###length 2
STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_HAS_TAG :has tag {NUM} STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_HAS_TAG :has tag {NUM}
STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_HAS_TAG_NAMED :has tag {NUM} ({RAW_STRING})
###length 2
STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_DOESNT_HAVE_TAG :doesn't have tag {NUM} STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_DOESNT_HAVE_TAG :doesn't have tag {NUM}
STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_DOESNT_HAVE_TAG_NAMED :doesn't have tag {NUM} ({RAW_STRING})
STR_ORDERS_MANAGE_LIST :{BLACK}Manage List STR_ORDERS_MANAGE_LIST :{BLACK}Manage List
STR_ORDERS_MANAGE_LIST_TOOLTIP :{BLACK}Manage this order list STR_ORDERS_MANAGE_LIST_TOOLTIP :{BLACK}Manage this order list
@@ -2195,10 +2201,16 @@ STR_SCHDISPATCH_APPEND_VEHICLE_SCHEDULES :{BLACK}Append S
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_REUSE_DEPARTURE_SLOTS :Re-use departure slots STR_SCHDISPATCH_REUSE_DEPARTURE_SLOTS :Re-use departure slots
STR_SCHDISPATCH_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_RENAME_DEPARTURE_TAG :Rename tag {NUM}
STR_SCHDISPATCH_RENAME_DEPARTURE_TAG_NAMED :Rename tag {NUM}: {RAW_STRING}
STR_SCHDISPATCH_RENAME_DEPARTURE_TAG_TOOLTIP :{BLACK}Rename departure slot tags (for use with conditional orders)
STR_SCHDISPATCH_RENAME_DEPARTURE_TAG_CAPTION :{BLACK}Name departure slot tag
STR_ERROR_CAN_T_RENAME_DEPARTURE_TAG :{WHITE}Can't name departure tag...
STR_SCHDISPATCH_MANAGE_SLOT :{BLACK}Manage Slot STR_SCHDISPATCH_MANAGE_SLOT :{BLACK}Manage Slot
STR_SCHDISPATCH_REUSE_THIS_DEPARTURE_SLOT :Re-use departure 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_REUSE_THIS_DEPARTURE_SLOT_TOOLTIP :{BLACK}Set whether the selected departure slot may be used more than once.
STR_SCHDISPATCH_TAG_DEPARTURE :Tag {NUM} STR_SCHDISPATCH_TAG_DEPARTURE :Tag {NUM}
STR_SCHDISPATCH_TAG_DEPARTURE_NAMED :Tag {NUM}: {RAW_STRING}
STR_SCHDISPATCH_TAG_DEPARTURE_TOOLTIP :{BLACK}Tag the selected departure slot (for use with conditional orders). STR_SCHDISPATCH_TAG_DEPARTURE_TOOLTIP :{BLACK}Tag the selected departure slot (for use with conditional orders).
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}
@@ -2215,6 +2227,7 @@ STR_SCHDISPATCH_SLOT_TOOLTIP_NEXT :{}Next availabl
STR_SCHDISPATCH_SLOT_TOOLTIP_REUSE :{}Departure slot may be used more than once STR_SCHDISPATCH_SLOT_TOOLTIP_REUSE :{}Departure slot may be used more than once
STR_SCHDISPATCH_SLOT_TOOLTIP_TIME_SUFFIX : ({TT_TIME}) STR_SCHDISPATCH_SLOT_TOOLTIP_TIME_SUFFIX : ({TT_TIME})
STR_SCHDISPATCH_SLOT_TOOLTIP_TAG :{}Tag {NUM} STR_SCHDISPATCH_SLOT_TOOLTIP_TAG :{}Tag {NUM}
STR_SCHDISPATCH_SLOT_TOOLTIP_TAG_NAMED :{}Tag {NUM}: {RAW_STRING}
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 {TT_TIME}. STR_SCHDISPATCH_SUMMARY_LAST_DEPARTURE_PAST :{BLACK}Last departure at {TT_TIME}.

View File

@@ -742,7 +742,13 @@ struct DispatchSlot {
}; };
}; };
enum ScheduledDispatchSupplementaryNameType : uint16_t {
SDSNT_DEPARTURE_TAG = 0, ///< Departure slot tag
};
struct DispatchSchedule { struct DispatchSchedule {
static constexpr uint DEPARTURE_TAG_COUNT = 4;
private: private:
friend SaveLoadTable GetDispatchScheduleDescription(); ///< Saving and loading of dispatch schedules friend SaveLoadTable GetDispatchScheduleDescription(); ///< Saving and loading of dispatch schedules
@@ -754,6 +760,7 @@ private:
uint8_t scheduled_dispatch_flags = 0; ///< Flags uint8_t scheduled_dispatch_flags = 0; ///< Flags
std::string name; ///< Name of dispatch schedule std::string name; ///< Name of dispatch schedule
btree::btree_map<uint32_t, std::string> supplementary_names; ///< Supplementary name strings
inline void CopyBasicFields(const DispatchSchedule &other) inline void CopyBasicFields(const DispatchSchedule &other)
{ {
@@ -869,8 +876,14 @@ public:
inline std::string &ScheduleName() { return this->name; } inline std::string &ScheduleName() { return this->name; }
inline const std::string &ScheduleName() const { return this->name; } inline const std::string &ScheduleName() const { return this->name; }
std::string_view GetSupplementaryName(ScheduledDispatchSupplementaryNameType name_type, uint16_t id) const;
void SetSupplementaryName(ScheduledDispatchSupplementaryNameType name_type, uint16_t id, std::string name);
btree::btree_map<uint32_t, std::string> &GetSupplementaryNameMap() { return this->supplementary_names; }
}; };
static_assert(DispatchSchedule::DEPARTURE_TAG_COUNT == 1 + (DispatchSlot::SDSF_LAST_TAG - DispatchSlot::SDSF_FIRST_TAG));
/** /**
* Shared order list linking together the linked list of orders and the list * Shared order list linking together the linked list of orders and the list
* of vehicles sharing this order list. * of vehicles sharing this order list.

View File

@@ -1121,11 +1121,13 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int
SetDParam(3, STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS + order->GetConditionComparator()); SetDParam(3, STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS + order->GetConditionComparator());
SetDParam(4, order->GetXData()); SetDParam(4, order->GetXData());
} else if (ocv == OCV_DISPATCH_SLOT) { } else if (ocv == OCV_DISPATCH_SLOT) {
const DispatchSchedule *selected_schedule = nullptr;
SetDParam(0, STR_ORDER_CONDITIONAL_DISPATCH_SLOT_DISPLAY); SetDParam(0, STR_ORDER_CONDITIONAL_DISPATCH_SLOT_DISPLAY);
if (GB(order->GetXData(), 0, 16) != UINT16_MAX) { if (GB(order->GetXData(), 0, 16) != UINT16_MAX) {
bool have_name = false; bool have_name = false;
if (GB(order->GetXData(), 0, 16) < v->orders->GetScheduledDispatchScheduleCount()) { if (GB(order->GetXData(), 0, 16) < v->orders->GetScheduledDispatchScheduleCount()) {
const DispatchSchedule &ds = v->orders->GetDispatchScheduleByIndex(GB(order->GetXData(), 0, 16)); const DispatchSchedule &ds = v->orders->GetDispatchScheduleByIndex(GB(order->GetXData(), 0, 16));
selected_schedule = &ds;
if (!ds.ScheduleName().empty()) { if (!ds.ScheduleName().empty()) {
_temp_special_strings[0] = ds.ScheduleName(); _temp_special_strings[0] = ds.ScheduleName();
have_name = true; have_name = true;
@@ -1150,8 +1152,15 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int
break; break;
case OCDM_TAG: { case OCDM_TAG: {
auto tmp_params = MakeParameters(GB(value, ODFLCB_TAG_START, ODFLCB_TAG_COUNT) + 1); StringID str = (order->GetConditionComparator() == OCC_IS_FALSE) ? STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_DOESNT_HAVE_TAG : STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_HAS_TAG;
_temp_special_strings[1] = GetStringWithArgs((order->GetConditionComparator() == OCC_IS_FALSE) ? STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_DOESNT_HAVE_TAG : STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_HAS_TAG, tmp_params); uint tag_id = GB(value, ODFLCB_TAG_START, ODFLCB_TAG_COUNT);
std::string_view name;
if (selected_schedule != nullptr) {
name = selected_schedule->GetSupplementaryName(SDSNT_DEPARTURE_TAG, tag_id);
if (!name.empty()) str++;
}
auto tmp_params = MakeParameters(tag_id + 1, std::string{name});
_temp_special_strings[1] = GetStringWithArgs(str, tmp_params);
SetDParam(4, SPECSTR_TEMP_START + 1); SetDParam(4, SPECSTR_TEMP_START + 1);
break; break;
} }
@@ -3170,23 +3179,32 @@ public:
list.push_back(MakeDropDownListStringItem(STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_LAST, true_cond | first_last_value, false)); list.push_back(MakeDropDownListStringItem(STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_LAST, true_cond | first_last_value, false));
list.push_back(MakeDropDownListStringItem(STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_NOT_LAST, false_cond | first_last_value, false)); list.push_back(MakeDropDownListStringItem(STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_NOT_LAST, false_cond | first_last_value, false));
const DispatchSchedule *ds = nullptr;
uint16_t slot_flags = 0; uint16_t slot_flags = 0;
uint schedule_index = GB(o->GetXData(), 0, 16); uint schedule_index = GB(o->GetXData(), 0, 16);
if (schedule_index < this->vehicle->orders->GetScheduledDispatchScheduleCount()) { if (schedule_index < this->vehicle->orders->GetScheduledDispatchScheduleCount()) {
const DispatchSchedule &ds = this->vehicle->orders->GetDispatchScheduleByIndex(schedule_index); ds = &(this->vehicle->orders->GetDispatchScheduleByIndex(schedule_index));
for (const DispatchSlot &slot : ds.GetScheduledDispatch()) { for (const DispatchSlot &slot : ds->GetScheduledDispatch()) {
slot_flags |= slot.flags; slot_flags |= slot.flags;
} }
} }
for (uint8_t tag = 0; tag <= (DispatchSlot::SDSF_LAST_TAG - DispatchSlot::SDSF_FIRST_TAG); tag++) { for (uint8_t tag = 0; tag < DispatchSchedule::DEPARTURE_TAG_COUNT; tag++) {
if (HasBit(slot_flags, tag + DispatchSlot::SDSF_FIRST_TAG)) { if (HasBit(slot_flags, tag + DispatchSlot::SDSF_FIRST_TAG)) {
int tag_cond_value = 0; int tag_cond_value = 0;
SB(tag_cond_value, ODCB_MODE_START, ODCB_MODE_COUNT, OCDM_TAG); SB(tag_cond_value, ODCB_MODE_START, ODCB_MODE_COUNT, OCDM_TAG);
SB(tag_cond_value, ODFLCB_TAG_START, ODFLCB_TAG_COUNT, tag); SB(tag_cond_value, ODFLCB_TAG_START, ODFLCB_TAG_COUNT, tag);
SetDParam(0, tag + 1); SetDParam(0, tag + 1);
list.push_back(MakeDropDownListStringItem(STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_HAS_TAG, true_cond | tag_cond_value, false)); uint string_offset = 0;
list.push_back(MakeDropDownListStringItem(STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_DOESNT_HAVE_TAG, false_cond | tag_cond_value, false)); if (ds != nullptr) {
std::string_view name = ds->GetSupplementaryName(SDSNT_DEPARTURE_TAG, tag);
if (!name.empty()) {
SetDParamStr(1, name);
string_offset = 1;
}
}
list.push_back(MakeDropDownListStringItem(STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_HAS_TAG + string_offset, true_cond | tag_cond_value, false));
list.push_back(MakeDropDownListStringItem(STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_DOESNT_HAVE_TAG + string_offset, false_cond | tag_cond_value, false));
} }
} }

View File

@@ -480,6 +480,46 @@ CommandCost CmdScheduledDispatchRenameSchedule(TileIndex tile, DoCommandFlag fla
return CommandCost(); return CommandCost();
} }
/**
* Rename scheduled dispatch departure tag
*
* @param tile Not used.
* @param flags Operation to perform.
* @param p1 Vehicle index
* @param p2 Tag ID
* @param text name
* @return the cost of this operation or an error
*/
CommandCost CmdScheduledDispatchRenameTag(TileIndex tile, DoCommandFlag flags, uint32_t p1, uint32_t p2, const char *text)
{
VehicleID veh = GB(p1, 0, 20);
uint schedule_index = GB(p1, 20, 12);
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;
if (p2 >= DispatchSchedule::DEPARTURE_TAG_COUNT) return CMD_ERROR;
std::string name;
if (!StrEmpty(text)) {
if (Utf8StringLength(text) >= MAX_LENGTH_VEHICLE_NAME_CHARS) return CMD_ERROR;
name = text;
}
if (flags & DC_EXEC) {
v->orders->GetDispatchScheduleByIndex(schedule_index).SetSupplementaryName(SDSNT_DEPARTURE_TAG, static_cast<uint16_t>(p2), std::move(name));
SetTimetableWindowsDirty(v, STWDF_SCHEDULED_DISPATCH | STWDF_ORDERS);
}
return CommandCost();
}
/** /**
* Duplicate scheduled dispatch schedule * Duplicate scheduled dispatch schedule
* *
@@ -801,3 +841,25 @@ void DispatchSchedule::UpdateScheduledDispatch(const Vehicle *v)
SetTimetableWindowsDirty(v, STWDF_SCHEDULED_DISPATCH); SetTimetableWindowsDirty(v, STWDF_SCHEDULED_DISPATCH);
} }
} }
static inline uint32_t SupplementaryNameKey(ScheduledDispatchSupplementaryNameType name_type, uint16_t id)
{
return (static_cast<uint32_t>(name_type) << 16) | id;
}
std::string_view DispatchSchedule::GetSupplementaryName(ScheduledDispatchSupplementaryNameType name_type, uint16_t id) const
{
auto iter = this->supplementary_names.find(SupplementaryNameKey(name_type, id));
if (iter == this->supplementary_names.end()) return {};
return iter->second;
}
void DispatchSchedule::SetSupplementaryName(ScheduledDispatchSupplementaryNameType name_type, uint16_t id, std::string name)
{
uint32_t key = SupplementaryNameKey(name_type, id);
if (name.empty()) {
this->supplementary_names.erase(key);
} else {
this->supplementary_names.insert({ key, std::move(name) });
}
}

View File

@@ -191,6 +191,7 @@ static void AddNewScheduledDispatchSchedule(VehicleID vindex)
struct SchdispatchWindow : GeneralVehicleWindow { struct SchdispatchWindow : GeneralVehicleWindow {
int schedule_index; int schedule_index;
int clicked_widget; ///< The widget that was clicked (used to determine what to do in OnQueryTextFinished) int clicked_widget; ///< The widget that was clicked (used to determine what to do in OnQueryTextFinished)
int click_subaction; ///< Subaction for clicked_widget
Scrollbar *vscroll; ///< Verticle scrollbar Scrollbar *vscroll; ///< Verticle scrollbar
uint num_columns; ///< Number of columns. uint num_columns; ///< Number of columns.
@@ -216,6 +217,7 @@ struct SchdispatchWindow : GeneralVehicleWindow {
SCH_MD_DUPLICATE_SCHEDULE, SCH_MD_DUPLICATE_SCHEDULE,
SCH_MD_APPEND_VEHICLE_SCHEDULES, SCH_MD_APPEND_VEHICLE_SCHEDULES,
SCH_MD_REUSE_DEPARTURE_SLOTS, SCH_MD_REUSE_DEPARTURE_SLOTS,
SCH_MD_RENAME_TAG,
}; };
@@ -469,6 +471,7 @@ struct SchdispatchWindow : GeneralVehicleWindow {
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_REUSE_DEPARTURE_SLOTS_TOOLTIP); add_suffix(STR_SCHDISPATCH_REUSE_DEPARTURE_SLOTS_TOOLTIP);
add_suffix(STR_SCHDISPATCH_RENAME_DEPARTURE_TAG_TOOLTIP);
GuiShowTooltips(this, SPECSTR_TEMP_START, close_cond); GuiShowTooltips(this, SPECSTR_TEMP_START, close_cond);
return true; return true;
} }
@@ -547,7 +550,9 @@ struct SchdispatchWindow : GeneralVehicleWindow {
for (uint8_t flag_bit = DispatchSlot::SDSF_FIRST_TAG; flag_bit <= DispatchSlot::SDSF_LAST_TAG; flag_bit++) { for (uint8_t flag_bit = DispatchSlot::SDSF_FIRST_TAG; flag_bit <= DispatchSlot::SDSF_LAST_TAG; flag_bit++) {
if (HasBit(flags, flag_bit)) { if (HasBit(flags, flag_bit)) {
SetDParam(0, 1 + flag_bit - DispatchSlot::SDSF_FIRST_TAG); SetDParam(0, 1 + flag_bit - DispatchSlot::SDSF_FIRST_TAG);
_temp_special_strings[0] += GetString(STR_SCHDISPATCH_SLOT_TOOLTIP_TAG); std::string_view name = ds.GetSupplementaryName(SDSNT_DEPARTURE_TAG, flag_bit - DispatchSlot::SDSF_FIRST_TAG);
SetDParamStr(1, name);
_temp_special_strings[0] += GetString(name.empty() ? STR_SCHDISPATCH_SLOT_TOOLTIP_TAG : STR_SCHDISPATCH_SLOT_TOOLTIP_TAG_NAMED);
} }
} }
} }
@@ -1054,6 +1059,13 @@ struct SchdispatchWindow : GeneralVehicleWindow {
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(MakeDropDownListDividerItem()); list.push_back(MakeDropDownListDividerItem());
list.push_back(MakeDropDownListCheckedItem(schedule.GetScheduledDispatchReuseSlots(), STR_SCHDISPATCH_REUSE_DEPARTURE_SLOTS, SCH_MD_REUSE_DEPARTURE_SLOTS, false)); list.push_back(MakeDropDownListCheckedItem(schedule.GetScheduledDispatchReuseSlots(), STR_SCHDISPATCH_REUSE_DEPARTURE_SLOTS, SCH_MD_REUSE_DEPARTURE_SLOTS, false));
list.push_back(MakeDropDownListDividerItem());
for (uint8_t tag = 0; tag < DispatchSchedule::DEPARTURE_TAG_COUNT; tag++) {
SetDParam(0, tag + 1);
std::string_view name = schedule.GetSupplementaryName(SDSNT_DEPARTURE_TAG, tag);
SetDParamStr(1, name);
add_item(name.empty() ? STR_SCHDISPATCH_RENAME_DEPARTURE_TAG : STR_SCHDISPATCH_RENAME_DEPARTURE_TAG_NAMED, SCH_MD_RENAME_TAG | (tag << 16));
}
ShowDropDownList(this, std::move(list), -1, WID_SCHDISPATCH_MANAGEMENT); ShowDropDownList(this, std::move(list), -1, WID_SCHDISPATCH_MANAGEMENT);
break; break;
} }
@@ -1115,7 +1127,9 @@ struct SchdispatchWindow : GeneralVehicleWindow {
list.push_back(MakeDropDownListDividerItem()); list.push_back(MakeDropDownListDividerItem());
for (uint8_t flag_bit = DispatchSlot::SDSF_FIRST_TAG; flag_bit <= DispatchSlot::SDSF_LAST_TAG; flag_bit++) { for (uint8_t flag_bit = DispatchSlot::SDSF_FIRST_TAG; flag_bit <= DispatchSlot::SDSF_LAST_TAG; flag_bit++) {
SetDParam(0, 1 + flag_bit - DispatchSlot::SDSF_FIRST_TAG); SetDParam(0, 1 + flag_bit - DispatchSlot::SDSF_FIRST_TAG);
add_item(STR_SCHDISPATCH_TAG_DEPARTURE, flag_bit, false); std::string_view name = schedule.GetSupplementaryName(SDSNT_DEPARTURE_TAG, flag_bit - DispatchSlot::SDSF_FIRST_TAG);
SetDParamStr(1, name);
add_item(name.empty() ? STR_SCHDISPATCH_TAG_DEPARTURE : STR_SCHDISPATCH_TAG_DEPARTURE_NAMED, flag_bit, false);
} }
ShowDropDownList(this, std::move(list), -1, WID_SCHDISPATCH_MANAGE_SLOT); ShowDropDownList(this, std::move(list), -1, WID_SCHDISPATCH_MANAGE_SLOT);
@@ -1167,7 +1181,7 @@ struct SchdispatchWindow : GeneralVehicleWindow {
switch (widget) { switch (widget) {
case WID_SCHDISPATCH_MANAGEMENT: { case WID_SCHDISPATCH_MANAGEMENT: {
if (!this->IsScheduleSelected()) break; if (!this->IsScheduleSelected()) break;
switch((ManagementDropdown)index) { switch((ManagementDropdown)index & 0xFFFF) {
case SCH_MD_RESET_LAST_DISPATCHED: case SCH_MD_RESET_LAST_DISPATCHED:
DoCommandP(0, this->vehicle->index | (this->schedule_index << 20), 0, CMD_SCHEDULED_DISPATCH_RESET_LAST_DISPATCH | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE)); DoCommandP(0, this->vehicle->index | (this->schedule_index << 20), 0, CMD_SCHEDULED_DISPATCH_RESET_LAST_DISPATCH | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE));
break; break;
@@ -1201,6 +1215,14 @@ struct SchdispatchWindow : GeneralVehicleWindow {
DoCommandP(0, this->vehicle->index | (this->schedule_index << 20), this->GetSelectedSchedule().GetScheduledDispatchReuseSlots() ? 0 : 1, CMD_SCHEDULED_DISPATCH_SET_REUSE_SLOTS | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE)); DoCommandP(0, this->vehicle->index | (this->schedule_index << 20), this->GetSelectedSchedule().GetScheduledDispatchReuseSlots() ? 0 : 1, CMD_SCHEDULED_DISPATCH_SET_REUSE_SLOTS | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE));
break; break;
} }
case SCH_MD_RENAME_TAG: {
this->clicked_widget = WID_SCHDISPATCH_MANAGEMENT;
this->click_subaction = index;
SetDParamStr(0, this->GetSelectedSchedule().GetSupplementaryName(SDSNT_DEPARTURE_TAG, index >> 16));
ShowQueryString(STR_JUST_RAW_STRING, STR_SCHDISPATCH_RENAME_DEPARTURE_TAG_CAPTION, MAX_LENGTH_VEHICLE_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS);
break;
}
} }
break; break;
} }
@@ -1298,6 +1320,17 @@ struct SchdispatchWindow : GeneralVehicleWindow {
} }
break; break;
} }
case WID_SCHDISPATCH_MANAGEMENT: {
if (str == nullptr) return;
switch (this->click_subaction & 0xFFFF) {
case SCH_MD_RENAME_TAG:
DoCommandP(0, v->index | (this->schedule_index << 20), this->click_subaction >> 16, CMD_SCHEDULED_DISPATCH_RENAME_TAG | CMD_MSG(STR_ERROR_CAN_T_RENAME_DEPARTURE_TAG), nullptr, str);
break;
}
break;
}
} }
this->SetDirty(); this->SetDirty();

View File

@@ -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, 7, 7, "scheduled_dispatch", nullptr, nullptr, nullptr }, { XSLFI_SCHEDULED_DISPATCH, XSCF_NULL, 8, 8, "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" },

View File

@@ -311,6 +311,54 @@ static void SetupDescs_ORDL()
_filtered_ordl_slot_desc = SlFilterObject(GetDispatchSlotDescription()); _filtered_ordl_slot_desc = SlFilterObject(GetDispatchSlotDescription());
} }
static void SaveDispatchSchedule(DispatchSchedule &ds)
{
SlObjectSaveFiltered(&ds, _filtered_ordl_sd_desc);
SlWriteUint32((uint32_t)ds.GetScheduledDispatchMutable().size());
for (DispatchSlot &slot : ds.GetScheduledDispatchMutable()) {
SlObjectSaveFiltered(&slot, _filtered_ordl_slot_desc);
}
{
btree::btree_map<uint32_t, std::string> &names = ds.GetSupplementaryNameMap();
SlWriteUint32((uint32_t)names.size());
for (auto &it : names) {
SlWriteUint32(it.first);
SlStdString(it.second, SLE_STR);
}
}
}
static void LoadDispatchSchedule(DispatchSchedule &ds)
{
SlObjectLoadFiltered(&ds, _filtered_ordl_sd_desc);
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;
}
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);
}
}
if (SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 8)) {
uint32_t string_count = SlReadUint32();
btree::btree_map<uint32_t, std::string> &names = ds.GetSupplementaryNameMap();
for (uint32_t i = 0; i < string_count; i++) {
uint32_t key = SlReadUint32();
SlStdString(names[key], SLE_STR);
}
}
}
static void Save_ORDL() static void Save_ORDL()
{ {
SetupDescs_ORDL(); SetupDescs_ORDL();
@@ -321,12 +369,7 @@ static void Save_ORDL()
SlObjectSaveFiltered(list, _filtered_ordl_desc); SlObjectSaveFiltered(list, _filtered_ordl_desc);
SlWriteUint32(list->GetScheduledDispatchScheduleCount()); SlWriteUint32(list->GetScheduledDispatchScheduleCount());
for (DispatchSchedule &ds : list->GetScheduledDispatchScheduleSet()) { for (DispatchSchedule &ds : list->GetScheduledDispatchScheduleSet()) {
SlObjectSaveFiltered(&ds, _filtered_ordl_sd_desc); SaveDispatchSchedule(ds);
SlWriteUint32((uint32_t)ds.GetScheduledDispatchMutable().size());
for (DispatchSlot &slot : ds.GetScheduledDispatchMutable()) {
SlObjectSaveFiltered(&slot, _filtered_ordl_slot_desc);
}
} }
}, list); }, list);
} }
@@ -358,22 +401,7 @@ static void Load_ORDL()
uint count = SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 3) ? SlReadUint32() : 1; uint count = SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 3) ? SlReadUint32() : 1;
list->GetScheduledDispatchScheduleSet().resize(count); list->GetScheduledDispatchScheduleSet().resize(count);
for (DispatchSchedule &ds : list->GetScheduledDispatchScheduleSet()) { for (DispatchSchedule &ds : list->GetScheduledDispatchScheduleSet()) {
SlObjectLoadFiltered(&ds, _filtered_ordl_sd_desc); LoadDispatchSchedule(ds);
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;
}
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);
}
}
} }
} }
} }
@@ -426,6 +454,8 @@ void Save_BKOR()
* normal games this information isn't needed. */ * normal games this information isn't needed. */
if (!_networking || !_network_server) return; if (!_networking || !_network_server) return;
SetupDescs_ORDL();
for (OrderBackup *ob : OrderBackup::Iterate()) { for (OrderBackup *ob : OrderBackup::Iterate()) {
SlSetArrayIndex(ob->index); SlSetArrayIndex(ob->index);
SlAutolength([](void *data) { SlAutolength([](void *data) {
@@ -433,7 +463,7 @@ void Save_BKOR()
SlObject(ob, GetOrderBackupDescription()); SlObject(ob, GetOrderBackupDescription());
SlWriteUint32((uint)ob->dispatch_schedules.size()); SlWriteUint32((uint)ob->dispatch_schedules.size());
for (DispatchSchedule &ds : ob->dispatch_schedules) { for (DispatchSchedule &ds : ob->dispatch_schedules) {
SlObject(&ds, GetDispatchScheduleDescription()); SaveDispatchSchedule(ds);
} }
}, ob); }, ob);
} }
@@ -443,6 +473,8 @@ void Load_BKOR()
{ {
int index; int index;
SetupDescs_ORDL();
while ((index = SlIterateArray()) != -1) { while ((index = SlIterateArray()) != -1) {
/* set num_orders to 0 so it's a valid OrderList */ /* set num_orders to 0 so it's a valid OrderList */
OrderBackup *ob = new (index) OrderBackup(); OrderBackup *ob = new (index) OrderBackup();
@@ -451,7 +483,11 @@ void Load_BKOR()
uint count = SlReadUint32(); uint count = SlReadUint32();
ob->dispatch_schedules.resize(count); ob->dispatch_schedules.resize(count);
for (DispatchSchedule &ds : ob->dispatch_schedules) { for (DispatchSchedule &ds : ob->dispatch_schedules) {
SlObject(&ds, GetDispatchScheduleDescription()); if (SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 8)) {
LoadDispatchSchedule(ds);
} else {
SlObject(&ds, GetDispatchScheduleDescription());
}
} }
} }
} }

View File

@@ -1254,7 +1254,7 @@ static void SlString(void *ptr, size_t length, VarType conv)
* @param ptr the string being manipulated * @param ptr the string being manipulated
* @param conv must be SLE_FILE_STRING * @param conv must be SLE_FILE_STRING
*/ */
static void SlStdString(std::string &str, VarType conv) void SlStdString(std::string &str, VarType conv)
{ {
switch (_sl.action) { switch (_sl.action) {
case SLA_SAVE: { case SLA_SAVE: {

View File

@@ -1061,6 +1061,7 @@ void SlLoadFromBuffer(const uint8_t *buffer, size_t length, F proc)
} }
void SlGlobList(const SaveLoadTable &slt); void SlGlobList(const SaveLoadTable &slt);
void SlStdString(std::string &str, VarType conv);
void SlArray(void *array, size_t length, VarType conv); void SlArray(void *array, size_t length, VarType conv);
void SlObject(void *object, const SaveLoadTable &slt); void SlObject(void *object, const SaveLoadTable &slt);
bool SlObjectMember(void *object, const SaveLoad &sld); bool SlObjectMember(void *object, const SaveLoad &sld);