diff --git a/src/command.cpp b/src/command.cpp index 29c1289b9c..c973701bcb 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -306,6 +306,7 @@ CommandProc CmdScheduledDispatchAppendVehicleSchedules; CommandProc CmdScheduledDispatchAdjust; CommandProc CmdScheduledDispatchSwapSchedules; CommandProcEx CmdScheduledDispatchSetSlotFlags; +CommandProc CmdScheduledDispatchRenameTag; CommandProc CmdAddPlan; 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(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(CmdScheduledDispatchRenameTag, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SCHEDULED_DISPATCH_RENAME_TAG DEF_CMD(CmdAddPlan, 0, CMDT_OTHER_MANAGEMENT ), // CMD_ADD_PLAN DEF_CMD(CmdAddPlanLine, CMD_NO_TEST, CMDT_OTHER_MANAGEMENT ), // CMD_ADD_PLAN_LINE diff --git a/src/command_type.h b/src/command_type.h index 4b9b8f7824..46fe0e0641 100644 --- a/src/command_type.h +++ b/src/command_type.h @@ -522,6 +522,7 @@ enum Commands { 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_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_LINE, diff --git a/src/lang/extra/english.txt b/src/lang/extra/english.txt index 86c7e9a22e..9396af5472 100644 --- a/src/lang/extra/english.txt +++ b/src/lang/extra/english.txt @@ -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_LAST :is 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_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_NAMED :doesn't have tag {NUM} ({RAW_STRING}) STR_ORDERS_MANAGE_LIST :{BLACK}Manage 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_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_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_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_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_NO_SCHEDULES :{BLACK}No Schedules 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_TIME_SUFFIX : ({TT_TIME}) 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_LAST_DEPARTURE_PAST :{BLACK}Last departure at {TT_TIME}. diff --git a/src/order_base.h b/src/order_base.h index 640b2edf7a..559d78c5c9 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -742,7 +742,13 @@ struct DispatchSlot { }; }; +enum ScheduledDispatchSupplementaryNameType : uint16_t { + SDSNT_DEPARTURE_TAG = 0, ///< Departure slot tag +}; + struct DispatchSchedule { + static constexpr uint DEPARTURE_TAG_COUNT = 4; + private: friend SaveLoadTable GetDispatchScheduleDescription(); ///< Saving and loading of dispatch schedules @@ -754,6 +760,7 @@ private: uint8_t scheduled_dispatch_flags = 0; ///< Flags std::string name; ///< Name of dispatch schedule + btree::btree_map supplementary_names; ///< Supplementary name strings inline void CopyBasicFields(const DispatchSchedule &other) { @@ -869,8 +876,14 @@ public: inline std::string &ScheduleName() { 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 &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 * of vehicles sharing this order list. diff --git a/src/order_gui.cpp b/src/order_gui.cpp index 6fd9c3ed1f..077a106866 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -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(4, order->GetXData()); } else if (ocv == OCV_DISPATCH_SLOT) { + const DispatchSchedule *selected_schedule = nullptr; SetDParam(0, STR_ORDER_CONDITIONAL_DISPATCH_SLOT_DISPLAY); if (GB(order->GetXData(), 0, 16) != UINT16_MAX) { bool have_name = false; if (GB(order->GetXData(), 0, 16) < v->orders->GetScheduledDispatchScheduleCount()) { const DispatchSchedule &ds = v->orders->GetDispatchScheduleByIndex(GB(order->GetXData(), 0, 16)); + selected_schedule = &ds; if (!ds.ScheduleName().empty()) { _temp_special_strings[0] = ds.ScheduleName(); have_name = true; @@ -1150,8 +1152,15 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int break; case OCDM_TAG: { - auto tmp_params = MakeParameters(GB(value, ODFLCB_TAG_START, ODFLCB_TAG_COUNT) + 1); - _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); + StringID str = (order->GetConditionComparator() == OCC_IS_FALSE) ? STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_DOESNT_HAVE_TAG : STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_HAS_TAG; + 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); 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_NOT_LAST, false_cond | first_last_value, false)); + const DispatchSchedule *ds = nullptr; uint16_t slot_flags = 0; uint schedule_index = GB(o->GetXData(), 0, 16); if (schedule_index < this->vehicle->orders->GetScheduledDispatchScheduleCount()) { - const DispatchSchedule &ds = this->vehicle->orders->GetDispatchScheduleByIndex(schedule_index); - for (const DispatchSlot &slot : ds.GetScheduledDispatch()) { + ds = &(this->vehicle->orders->GetDispatchScheduleByIndex(schedule_index)); + for (const DispatchSlot &slot : ds->GetScheduledDispatch()) { 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)) { int tag_cond_value = 0; SB(tag_cond_value, ODCB_MODE_START, ODCB_MODE_COUNT, OCDM_TAG); SB(tag_cond_value, ODFLCB_TAG_START, ODFLCB_TAG_COUNT, tag); SetDParam(0, tag + 1); - list.push_back(MakeDropDownListStringItem(STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_HAS_TAG, true_cond | tag_cond_value, false)); - list.push_back(MakeDropDownListStringItem(STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_DOESNT_HAVE_TAG, false_cond | tag_cond_value, false)); + uint string_offset = 0; + 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)); } } diff --git a/src/schdispatch_cmd.cpp b/src/schdispatch_cmd.cpp index da5a88907e..943c2dd43f 100644 --- a/src/schdispatch_cmd.cpp +++ b/src/schdispatch_cmd.cpp @@ -480,6 +480,46 @@ CommandCost CmdScheduledDispatchRenameSchedule(TileIndex tile, DoCommandFlag fla 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(p2), std::move(name)); + SetTimetableWindowsDirty(v, STWDF_SCHEDULED_DISPATCH | STWDF_ORDERS); + } + + return CommandCost(); +} + /** * Duplicate scheduled dispatch schedule * @@ -801,3 +841,25 @@ void DispatchSchedule::UpdateScheduledDispatch(const Vehicle *v) SetTimetableWindowsDirty(v, STWDF_SCHEDULED_DISPATCH); } } + +static inline uint32_t SupplementaryNameKey(ScheduledDispatchSupplementaryNameType name_type, uint16_t id) +{ + return (static_cast(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) }); + } +} diff --git a/src/schdispatch_gui.cpp b/src/schdispatch_gui.cpp index ebf0d7a2a3..b1acc136c0 100644 --- a/src/schdispatch_gui.cpp +++ b/src/schdispatch_gui.cpp @@ -191,6 +191,7 @@ static void AddNewScheduledDispatchSchedule(VehicleID vindex) struct SchdispatchWindow : GeneralVehicleWindow { int schedule_index; 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 uint num_columns; ///< Number of columns. @@ -216,6 +217,7 @@ struct SchdispatchWindow : GeneralVehicleWindow { SCH_MD_DUPLICATE_SCHEDULE, SCH_MD_APPEND_VEHICLE_SCHEDULES, 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_APPEND_VEHICLE_SCHEDULES_TOOLTIP); add_suffix(STR_SCHDISPATCH_REUSE_DEPARTURE_SLOTS_TOOLTIP); + add_suffix(STR_SCHDISPATCH_RENAME_DEPARTURE_TAG_TOOLTIP); GuiShowTooltips(this, SPECSTR_TEMP_START, close_cond); 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++) { if (HasBit(flags, flag_bit)) { 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); list.push_back(MakeDropDownListDividerItem()); 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); break; } @@ -1115,7 +1127,9 @@ struct SchdispatchWindow : GeneralVehicleWindow { list.push_back(MakeDropDownListDividerItem()); 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); - 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); @@ -1167,7 +1181,7 @@ struct SchdispatchWindow : GeneralVehicleWindow { switch (widget) { case WID_SCHDISPATCH_MANAGEMENT: { if (!this->IsScheduleSelected()) break; - switch((ManagementDropdown)index) { + switch((ManagementDropdown)index & 0xFFFF) { 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)); 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)); 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; } @@ -1298,6 +1320,17 @@ struct SchdispatchWindow : GeneralVehicleWindow { } 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(); diff --git a/src/sl/extended_ver_sl.cpp b/src/sl/extended_ver_sl.cpp index d026ce9d42..f0c3dce00c 100644 --- a/src/sl/extended_ver_sl.cpp +++ b/src/sl/extended_ver_sl.cpp @@ -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_CUSTOM_BRIDGE_HEADS, XSCF_NULL, 4, 4, "custom_bridge_heads", nullptr, nullptr, nullptr }, { 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_MULTIPLE_DOCKS, XSCF_NULL, 2, 2, "multiple_docks", nullptr, nullptr, nullptr }, { XSLFI_TIMETABLE_EXTRA, XSCF_NULL, 7, 7, "timetable_extra", nullptr, nullptr, "ORDX" }, diff --git a/src/sl/order_sl.cpp b/src/sl/order_sl.cpp index 8f26db3cce..bb68a06a25 100644 --- a/src/sl/order_sl.cpp +++ b/src/sl/order_sl.cpp @@ -311,6 +311,54 @@ static void SetupDescs_ORDL() _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 &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 &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() { SetupDescs_ORDL(); @@ -321,12 +369,7 @@ static void Save_ORDL() SlObjectSaveFiltered(list, _filtered_ordl_desc); SlWriteUint32(list->GetScheduledDispatchScheduleCount()); for (DispatchSchedule &ds : list->GetScheduledDispatchScheduleSet()) { - SlObjectSaveFiltered(&ds, _filtered_ordl_sd_desc); - - SlWriteUint32((uint32_t)ds.GetScheduledDispatchMutable().size()); - for (DispatchSlot &slot : ds.GetScheduledDispatchMutable()) { - SlObjectSaveFiltered(&slot, _filtered_ordl_slot_desc); - } + SaveDispatchSchedule(ds); } }, list); } @@ -358,22 +401,7 @@ static void Load_ORDL() uint count = SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 3) ? SlReadUint32() : 1; list->GetScheduledDispatchScheduleSet().resize(count); for (DispatchSchedule &ds : list->GetScheduledDispatchScheduleSet()) { - 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); - } - } + LoadDispatchSchedule(ds); } } } @@ -426,6 +454,8 @@ void Save_BKOR() * normal games this information isn't needed. */ if (!_networking || !_network_server) return; + SetupDescs_ORDL(); + for (OrderBackup *ob : OrderBackup::Iterate()) { SlSetArrayIndex(ob->index); SlAutolength([](void *data) { @@ -433,7 +463,7 @@ void Save_BKOR() SlObject(ob, GetOrderBackupDescription()); SlWriteUint32((uint)ob->dispatch_schedules.size()); for (DispatchSchedule &ds : ob->dispatch_schedules) { - SlObject(&ds, GetDispatchScheduleDescription()); + SaveDispatchSchedule(ds); } }, ob); } @@ -443,6 +473,8 @@ void Load_BKOR() { int index; + SetupDescs_ORDL(); + while ((index = SlIterateArray()) != -1) { /* set num_orders to 0 so it's a valid OrderList */ OrderBackup *ob = new (index) OrderBackup(); @@ -451,7 +483,11 @@ void Load_BKOR() uint count = SlReadUint32(); ob->dispatch_schedules.resize(count); for (DispatchSchedule &ds : ob->dispatch_schedules) { - SlObject(&ds, GetDispatchScheduleDescription()); + if (SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 8)) { + LoadDispatchSchedule(ds); + } else { + SlObject(&ds, GetDispatchScheduleDescription()); + } } } } diff --git a/src/sl/saveload.cpp b/src/sl/saveload.cpp index 98ca8c7b0c..1fe971db83 100644 --- a/src/sl/saveload.cpp +++ b/src/sl/saveload.cpp @@ -1254,7 +1254,7 @@ static void SlString(void *ptr, size_t length, VarType conv) * @param ptr the string being manipulated * @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) { case SLA_SAVE: { diff --git a/src/sl/saveload.h b/src/sl/saveload.h index 3fde1a48cd..7939677dd5 100644 --- a/src/sl/saveload.h +++ b/src/sl/saveload.h @@ -1061,6 +1061,7 @@ void SlLoadFromBuffer(const uint8_t *buffer, size_t length, F proc) } void SlGlobList(const SaveLoadTable &slt); +void SlStdString(std::string &str, VarType conv); void SlArray(void *array, size_t length, VarType conv); void SlObject(void *object, const SaveLoadTable &slt); bool SlObjectMember(void *object, const SaveLoad &sld);