diff --git a/src/lang/english.txt b/src/lang/english.txt index 0a50dc63ad..0ae457ed2f 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2941,6 +2941,8 @@ STR_TRACE_RESTRICT_TIME_HOUR_MINUTE_ITEM :current hour an STR_TRACE_RESTRICT_TIME_MINUTE_SHORT :minute STR_TRACE_RESTRICT_TIME_HOUR_SHORT :hour STR_TRACE_RESTRICT_TIME_HOUR_MINUTE_SHORT :hour and minute +STR_TRACE_RESTRICT_TIMETABLE_LATENESS :lateness +STR_TRACE_RESTRICT_TIMETABLE_EARLINESS :earliness STR_TRACE_RESTRICT_VALUE_CAPTION :{WHITE}Value STR_TRACE_RESTRICT_CAPTION :{WHITE}Routefinding restriction STR_TRACE_RESTRICT_CAPTION_SHARED :{WHITE}Routefinding restriction - shared by {COMMA} signals @@ -4936,6 +4938,7 @@ STR_ORDER_CONDITIONAL_CARGO_LOAD_PERCENTAGE :Cargo load perc STR_ORDER_CONDITIONAL_CARGO_WAITING_AMOUNT :Waiting cargo amount STR_ORDER_CONDITIONAL_COUNTER_VALUE :Counter value STR_ORDER_CONDITIONAL_TIME_DATE_VALUE :Current time/date +STR_ORDER_CONDITIONAL_TIMETABLE_STATE :Timetable state STR_ORDER_CONDITIONAL_REQUIRES_SERVICE_ORDER :Requires service {STRING} STR_ORDER_CONDITIONAL_CARGO_WAITING_ORDER :Next station {STRING} {STRING} waiting @@ -4960,6 +4963,7 @@ STR_ORDER_CONDITIONAL_CARGO_TOOLTIP :{BLACK}The carg STR_ORDER_CONDITIONAL_SLOT_TOOLTIP :{BLACK}The train slot to check the occupancy of STR_ORDER_CONDITIONAL_COUNTER_TOOLTIP :{BLACK}The counter to check the value of STR_ORDER_CONDITIONAL_TIME_DATE_TOOLTIP :{BLACK}The current time/date field to check the value of +STR_ORDER_CONDITIONAL_TIMETABLE_TOOLTIP :{BLACK}The timetable field to check the value of STR_ORDER_CONDITIONAL_VALUE_CAPT :{WHITE}Enter value to compare against STR_ORDER_CONDITIONAL_VIA :{BLACK}Via @@ -5110,6 +5114,7 @@ STR_ORDER_CONDITIONAL_CARGO_WAITING_AMOUNT_VIA_DISPLAY :Jump to order { STR_ORDER_CONDITIONAL_COUNTER :Jump to order {COMMA} when value of {TRCOUNTER} {STRING} {COMMA} STR_ORDER_CONDITIONAL_INVALID_COUNTER :Jump to order {COMMA} when value of {PUSH_COLOUR}{RED}{STRING}{POP_COLOUR} {STRING} {COMMA} STR_ORDER_CONDITIONAL_TIME_HHMM :Jump to order {COMMA} when {STRING} {STRING} {TIME_HHMM} +STR_ORDER_CONDITIONAL_TIMETABLE :Jump to order {COMMA} when {STRING} {STRING} {TT_TICKS} STR_ORDER_RELEASE_SLOT :Release slot: {STRING1} diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 59eacb325f..9c919e1f4b 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -1783,6 +1783,10 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 if (data != OCC_IS_TRUE && data != OCC_IS_FALSE && data != OCC_EQUALS && data != OCC_NOT_EQUALS) return CMD_ERROR; break; + case OCV_TIMETABLE: + if (data == OCC_IS_TRUE || data == OCC_IS_FALSE || data == OCC_EQUALS || data == OCC_NOT_EQUALS) return CMD_ERROR; + break; + default: if (data == OCC_IS_TRUE || data == OCC_IS_FALSE) return CMD_ERROR; break; @@ -1815,6 +1819,7 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 case OCV_CARGO_WAITING_AMOUNT: case OCV_COUNTER_VALUE: case OCV_TIME_DATE: + case OCV_TIMETABLE: if (data >= (1 << 16)) return CMD_ERROR; break; @@ -1839,6 +1844,10 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 if (data >= TRTDVF_END) return CMD_ERROR; break; + case OCV_TIMETABLE: + if (data >= OTCM_END) return CMD_ERROR; + break; + default: return CMD_ERROR; } @@ -1951,6 +1960,7 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 bool old_var_was_slot = (order->GetConditionVariable() == OCV_SLOT_OCCUPANCY || order->GetConditionVariable() == OCV_TRAIN_IN_SLOT); bool old_var_was_counter = (order->GetConditionVariable() == OCV_COUNTER_VALUE); bool old_var_was_time = (order->GetConditionVariable() == OCV_TIME_DATE); + bool old_var_was_tt = (order->GetConditionVariable() == OCV_TIMETABLE); order->SetConditionVariable((OrderConditionVariable)data); OrderConditionComparator occ = order->GetConditionComparator(); @@ -1976,6 +1986,11 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) order->SetConditionComparator(OCC_EQUALS); break; + case OCV_TIMETABLE: + if (!old_var_was_tt) order->GetXDataRef() = 0; + if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE || occ == OCC_EQUALS || occ == OCC_NOT_EQUALS) order->SetConditionComparator(OCC_LESS_THAN); + break; + case OCV_CARGO_ACCEPTANCE: case OCV_CARGO_WAITING: if (!old_var_was_cargo) order->SetConditionValue((uint16) GetFirstValidCargo()); @@ -2002,7 +2017,7 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 FALLTHROUGH; default: - if (old_var_was_cargo || old_var_was_slot || old_var_was_counter || old_var_was_time) order->SetConditionValue(0); + if (old_var_was_cargo || old_var_was_slot || old_var_was_counter || old_var_was_time || old_var_was_tt) order->SetConditionValue(0); if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) order->SetConditionComparator(OCC_EQUALS); break; } @@ -2019,6 +2034,7 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 case OCV_TRAIN_IN_SLOT: case OCV_CARGO_LOAD_PERCENTAGE: case OCV_TIME_DATE: + case OCV_TIMETABLE: order->GetXDataRef() = data; break; @@ -2821,6 +2837,23 @@ VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v, boo skip_order = OrderConditionCompare(occ, GetTraceRestrictTimeDateValue(static_cast(value)), order->GetXData()); break; } + case OCV_TIMETABLE: { + int tt_value = 0; + switch (static_cast(value)) { + case OTCM_LATENESS: + tt_value = v->lateness_counter; + break; + + case OTCM_EARLINESS: + tt_value = -v->lateness_counter; + break; + + default: + break; + } + skip_order = OrderConditionCompare(occ, tt_value, order->GetXData()); + break; + } default: NOT_REACHED(); } diff --git a/src/order_gui.cpp b/src/order_gui.cpp index 1ded2bc131..e873deee3e 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -658,6 +658,7 @@ static const OrderConditionVariable _order_conditional_variable[] = { OCV_TRAIN_IN_SLOT, OCV_COUNTER_VALUE, OCV_TIME_DATE, + OCV_TIMETABLE, OCV_PERCENT, OCV_UNCONDITIONALLY, }; @@ -759,6 +760,12 @@ static const StringID _order_time_date_dropdown[] = { INVALID_STRING_ID }; +static const StringID _order_timetable_dropdown[] = { + STR_TRACE_RESTRICT_TIMETABLE_LATENESS, + STR_TRACE_RESTRICT_TIMETABLE_EARLINESS, + INVALID_STRING_ID +}; + /** * Draws an order in order or timetable GUI * @param v Vehicle the order belongs to @@ -985,6 +992,11 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int SetDParam(2, STR_TRACE_RESTRICT_TIME_MINUTE_ITEM + order->GetConditionValue()); SetDParam(3, STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS + order->GetConditionComparator()); SetDParam(4, order->GetXData()); + } else if (ocv == OCV_TIMETABLE) { + SetDParam(0, STR_ORDER_CONDITIONAL_TIMETABLE); + SetDParam(2, STR_TRACE_RESTRICT_TIMETABLE_LATENESS + order->GetConditionValue()); + SetDParam(3, STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS + order->GetConditionComparator()); + SetDParam(4, order->GetXData()); } else { OrderConditionComparator occ = order->GetConditionComparator(); SetDParam(0, (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) ? STR_ORDER_CONDITIONAL_TRUE_FALSE : STR_ORDER_CONDITIONAL_NUM); @@ -1239,7 +1251,8 @@ private: /* WID_O_SEL_COND_AUX */ DP_COND_AUX_CARGO = 0, ///< Display dropdown widget cargo types DP_COND_TIME_DATE = 1, ///< Display dropdown for current time/date field - DP_COND_COUNTER = 2, ///< Display dropdown widget counters + DP_COND_TIMETABLE = 2, ///< Display dropdown for timetable field + DP_COND_COUNTER = 3, ///< Display dropdown widget counters /* WID_O_SEL_COND_AUX2 */ DP_COND_AUX2_VIA = 0, ///< Display via button @@ -1913,6 +1926,7 @@ public: bool is_auxiliary_cargo = (ocv == OCV_CARGO_LOAD_PERCENTAGE || ocv == OCV_CARGO_WAITING_AMOUNT); bool is_counter = (ocv == OCV_COUNTER_VALUE); bool is_time_date = (ocv == OCV_TIME_DATE); + bool is_timetable = (ocv == OCV_TIMETABLE); if (is_cargo) { if (order == nullptr || !CargoSpec::Get(order->GetConditionValue())->IsValid()) { @@ -1945,6 +1959,9 @@ public: } else if (is_time_date) { this->GetWidget(WID_O_COND_TIME_DATE)->widget_data = STR_TRACE_RESTRICT_TIME_MINUTE_ITEM + order->GetConditionValue(); aux_sel->SetDisplayedPlane(DP_COND_TIME_DATE); + } else if (is_timetable) { + this->GetWidget(WID_O_COND_TIMETABLE)->widget_data = STR_TRACE_RESTRICT_TIMETABLE_LATENESS + order->GetConditionValue(); + aux_sel->SetDisplayedPlane(DP_COND_TIMETABLE); } else { aux_sel->SetDisplayedPlane(SZSP_NONE); } @@ -2157,6 +2174,11 @@ public: value = order->GetXData(); break; + case OCV_TIMETABLE: + value = order->GetXData(); + if (!_settings_client.gui.timetable_in_ticks) value /= DATE_UNIT_SIZE; + break; + case OCV_CARGO_WAITING_AMOUNT: case OCV_COUNTER_VALUE: value = GB(order->GetXData(), 0, 16); @@ -2403,6 +2425,12 @@ public: break; } + case WID_O_COND_TIMETABLE: { + ShowDropDownMenu(this, _order_timetable_dropdown, this->vehicle->GetOrder(this->OrderGetSel())->GetConditionValue(), + WID_O_COND_TIMETABLE, 0, 0, UINT_MAX); + break; + } + case WID_O_REVERSE: { VehicleOrderID sel_ord = this->OrderGetSel(); const Order *order = this->vehicle->GetOrder(sel_ord); @@ -2476,6 +2504,10 @@ public: mask = 0x3C; break; + case OCV_TIMETABLE: + mask = 0xC3; + break; + default: mask = 0xC0; break; @@ -2493,6 +2525,11 @@ public: value = order->GetXData(); break; + case OCV_TIMETABLE: + value = order->GetXData(); + if (!_settings_client.gui.timetable_in_ticks) value /= DATE_UNIT_SIZE; + break; + case OCV_CARGO_WAITING_AMOUNT: case OCV_COUNTER_VALUE: value = GB(order->GetXData(), 0, 16); @@ -2563,6 +2600,11 @@ public: value = Clamp(value, 0, 0xFFFF); break; + case OCV_TIMETABLE: + if (!_settings_client.gui.timetable_in_ticks) value *= DATE_UNIT_SIZE; + value = Clamp(value, 0, 0xFFFF); + break; + default: value = Clamp(value, 0, 2047); break; @@ -2637,6 +2679,10 @@ public: this->ModifyOrder(this->OrderGetSel(), MOF_COND_VALUE_2 | index << 4); break; + case WID_O_COND_TIMETABLE: + this->ModifyOrder(this->OrderGetSel(), MOF_COND_VALUE_2 | index << 4); + break; + case WID_O_RELEASE_SLOT: this->ModifyOrder(this->OrderGetSel(), MOF_SLOT | index << 4); break; @@ -2893,6 +2939,8 @@ static const NWidgetPart _nested_orders_train_widgets[] = { SetDataTip(STR_NULL, STR_ORDER_CONDITIONAL_CARGO_TOOLTIP), SetResize(1, 0), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_O_COND_TIME_DATE), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_NULL, STR_ORDER_CONDITIONAL_TIME_DATE_TOOLTIP), SetResize(1, 0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_O_COND_TIMETABLE), SetMinimalSize(124, 12), SetFill(1, 0), + SetDataTip(STR_NULL, STR_ORDER_CONDITIONAL_TIMETABLE_TOOLTIP), SetResize(1, 0), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_O_COND_COUNTER), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_NULL, STR_ORDER_CONDITIONAL_COUNTER_TOOLTIP), SetResize(1, 0), EndContainer(), @@ -3003,6 +3051,8 @@ static const NWidgetPart _nested_orders_widgets[] = { SetDataTip(STR_NULL, STR_ORDER_CONDITIONAL_CARGO_TOOLTIP), SetResize(1, 0), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_O_COND_TIME_DATE), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_NULL, STR_ORDER_CONDITIONAL_TIME_DATE_TOOLTIP), SetResize(1, 0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_O_COND_TIMETABLE), SetMinimalSize(124, 12), SetFill(1, 0), + SetDataTip(STR_NULL, STR_ORDER_CONDITIONAL_TIMETABLE_TOOLTIP), SetResize(1, 0), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_O_SEL_COND_AUX2), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_O_COND_AUX_VIA), SetMinimalSize(36, 12), diff --git a/src/order_type.h b/src/order_type.h index 08a82f7bd8..e2cac04e12 100644 --- a/src/order_type.h +++ b/src/order_type.h @@ -148,6 +148,7 @@ enum OrderConditionVariable { OCV_CARGO_WAITING_AMOUNT, ///< Skip based on the amount of a specific cargo waiting at next station OCV_COUNTER_VALUE, ///< Skip based on counter value OCV_TIME_DATE, ///< Skip based on current time/date + OCV_TIMETABLE, ///< Skip based on timetable state OCV_END }; @@ -212,6 +213,12 @@ enum OrderLeaveType { OLT_END }; +enum OrderTimetableConditionMode { + OTCM_LATENESS = 0, ///< Test timetable lateness + OTCM_EARLINESS = 1, ///< Test timetable earliness + OTCM_END +}; + /** * Enumeration for the data to set in #CmdChangeTimetable. */ diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index 38ca84a4a1..142de3bfe7 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -93,7 +93,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_INFRA_SHARING, XSCF_NULL, 2, 2, "infra_sharing", nullptr, nullptr, "CPDP" }, { XSLFI_VARIABLE_DAY_LENGTH, XSCF_NULL, 2, 2, "variable_day_length", nullptr, nullptr, nullptr }, { XSLFI_ORDER_OCCUPANCY, XSCF_NULL, 2, 2, "order_occupancy", nullptr, nullptr, nullptr }, - { XSLFI_MORE_COND_ORDERS, XSCF_NULL, 9, 9, "more_cond_orders", nullptr, nullptr, nullptr }, + { XSLFI_MORE_COND_ORDERS, XSCF_NULL, 10, 10, "more_cond_orders", nullptr, nullptr, nullptr }, { XSLFI_EXTRA_LARGE_MAP, XSCF_NULL, 0, 1, "extra_large_map", nullptr, nullptr, nullptr }, { XSLFI_REVERSE_AT_WAYPOINT, XSCF_NULL, 1, 1, "reverse_at_waypoint", nullptr, nullptr, nullptr }, { XSLFI_VEH_LIFETIME_PROFIT, XSCF_NULL, 1, 1, "veh_lifetime_profit", nullptr, nullptr, nullptr }, diff --git a/src/settings.cpp b/src/settings.cpp index 8e5bf71838..c7a972d8a3 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1267,6 +1267,12 @@ static bool InvalidateVehTimetableWindow(int32 p1) return true; } +static bool ChangeTimetableInTicksMode(int32 p1) +{ + SetWindowClassesDirty(WC_VEHICLE_ORDERS); + return InvalidateVehTimetableWindow(p1); +} + static bool UpdateTimeSettings(int32 p1) { SetupTimeSettings(); diff --git a/src/strings.cpp b/src/strings.cpp index e215a38e89..bc3dd66418 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -1488,6 +1488,29 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg buff = FormatTimeHHMMString(buff, args->GetInt64(SCC_TIME_HHMM), last, next_substr_case_index); break; + case SCC_TT_TICKS: // {TT_TICKS} + if (_settings_client.gui.timetable_in_ticks) { + int64 args_array[1] = { args->GetInt64(SCC_TT_TICKS) }; + StringParameters tmp_params(args_array); + buff = FormatString(buff, GetStringPtr(STR_TIMETABLE_TICKS), &tmp_params, last); + } else { + StringID str = _settings_time.time_in_minutes ? STR_TIMETABLE_MINUTES : STR_TIMETABLE_DAYS; + int64 ticks = args->GetInt64(SCC_TT_TICKS); + int64 ratio = DATE_UNIT_SIZE; + int64 units = ticks / ratio; + int64 leftover = ticks % ratio; + if (leftover) { + int64 args_array[3] = { str, units, leftover }; + StringParameters tmp_params(args_array); + buff = FormatString(buff, GetStringPtr(STR_TIMETABLE_LEFTOVER_TICKS), &tmp_params, last); + } else { + int64 args_array[1] = { units }; + StringParameters tmp_params(args_array); + buff = FormatString(buff, GetStringPtr(str), &tmp_params, last); + } + } + break; + case SCC_FORCE: { // {FORCE} assert(_settings_game.locale.units_force < lengthof(_units_force)); int64 args_array[1] = {_units_force[_settings_game.locale.units_force].c.ToDisplay(args->GetInt64())}; diff --git a/src/table/control_codes.h b/src/table/control_codes.h index 5c7fb0f055..3d59a6caf5 100644 --- a/src/table/control_codes.h +++ b/src/table/control_codes.h @@ -79,6 +79,7 @@ enum StringControlCode { SCC_DATE_WALLCLOCK_ISO, SCC_TIME_HHMM, + SCC_TT_TICKS, /* Must be consecutive */ SCC_STRING1, diff --git a/src/table/settings.ini b/src/table/settings.ini index deea0d2dbb..93d0e2fbf4 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -36,6 +36,7 @@ static bool CheckFreeformEdges(int32 p1); static bool ChangeDynamicEngines(int32 p1); static bool StationCatchmentChanged(int32 p1); static bool InvalidateVehTimetableWindow(int32 p1); +static bool ChangeTimetableInTicksMode(int32 p1); static bool UpdateTimeSettings(int32 p1); static bool ChangeTimeOverrideMode(int32 p1); static bool InvalidateCompanyLiveryWindow(int32 p1); @@ -4439,7 +4440,7 @@ flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false str = STR_CONFIG_SETTING_TIMETABLE_IN_TICKS strhelp = STR_CONFIG_SETTING_TIMETABLE_IN_TICKS_HELPTEXT -proc = InvalidateVehTimetableWindow +proc = ChangeTimetableInTicksMode cat = SC_EXPERT ;; gui.time_in_minutes diff --git a/src/table/strgen_tables.h b/src/table/strgen_tables.h index e0fffb88a1..569f9b03f1 100644 --- a/src/table/strgen_tables.h +++ b/src/table/strgen_tables.h @@ -101,6 +101,7 @@ static const CmdStruct _cmd_structs[] = { {"DATE_WALLCLOCK_ISO", EmitSingleChar, SCC_DATE_WALLCLOCK_ISO, 1, -1, C_NONE}, {"TIME_HHMM", EmitSingleChar, SCC_TIME_HHMM, 1, -1, C_NONE}, + {"TT_TICKS", EmitSingleChar, SCC_TT_TICKS, 1, -1, C_NONE}, {"STRING", EmitSingleChar, SCC_STRING, 1, -1, C_CASE | C_GENDER}, {"RAW_STRING", EmitSingleChar, SCC_RAW_STRING_POINTER, 1, -1, C_NONE | C_GENDER}, diff --git a/src/widgets/order_widget.h b/src/widgets/order_widget.h index 8a7b358312..66c521d1ba 100644 --- a/src/widgets/order_widget.h +++ b/src/widgets/order_widget.h @@ -39,6 +39,7 @@ enum OrderWidgets { WID_O_COND_SLOT, ///< Choose condition slot. WID_O_COND_COUNTER, ///< Choose condition counter. WID_O_COND_TIME_DATE, ///< Choose time/date value. + WID_O_COND_TIMETABLE, ///< Choose timetable value. WID_O_COND_AUX_VIA, ///< Condition via button. WID_O_RELEASE_SLOT, ///< Choose slot to release. WID_O_SEL_COND_VALUE, ///< Widget for conditional value or conditional cargo type.