diff --git a/src/lang/extra/english.txt b/src/lang/extra/english.txt index cb0019f5010..c3ddc1e87be 100644 --- a/src/lang/extra/english.txt +++ b/src/lang/extra/english.txt @@ -59,6 +59,7 @@ 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_DISPATCH_SLOT :Dispatch slot +STR_ORDER_CONDITIONAL_CARGO_WAITING_AMOUNT_PERCENTAGE :Waiting cargo / capacity ##after STR_ORDER_STOP_LOCATION_FAR_END STR_ORDER_STOP_LOCATION_THROUGH :[through load] @@ -1773,12 +1774,16 @@ STR_ORDER_CONDITIONAL_IN_INVALID_SLOT :Jump to order { STR_ORDER_CONDITIONAL_LOAD_PERCENTAGE_DISPLAY :Jump to order {COMMA} when Load percentage of {STRING} {STRING} {COMMA} STR_ORDER_CONDITIONAL_CARGO_WAITING_AMOUNT_DISPLAY :Jump to order {COMMA} when {STRING} at {STRING1} {STRING} {CARGO_SHORT} STR_ORDER_CONDITIONAL_CARGO_WAITING_AMOUNT_VIA_DISPLAY :Jump to order {COMMA} when {STRING} at {STRING1} via {STRING1} {STRING} {CARGO_SHORT} +STR_ORDER_CONDITIONAL_CARGO_WAITING_GENERAL_DISPLAY :Jump to order {COMMA} when {STRING} at {STRING1} {STRING} {STRING} +STR_ORDER_CONDITIONAL_CARGO_WAITING_GENERAL_VIA_DISPLAY :Jump to order {COMMA} when {STRING} at {STRING1} via {STRING1} {STRING} {STRING} 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_CONDITIONAL_DISPATCH_SLOT_DISPLAY :Jump to order {COMMA} when {STRING} {STRING} {STRING} +STR_ORDER_CONDITIONAL_CARGO_WAITING_PERCENT_CAPACITY :{COMMA} percent of {STRING} capacity + STR_ORDER_TRY_ACQUIRE_SLOT :Try to acquire slot: {STRING1} STR_ORDER_RELEASE_SLOT :Release slot: {STRING1} diff --git a/src/order_base.h b/src/order_base.h index 338176bfed2..f0fbfbd5d0a 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -67,6 +67,7 @@ void ClearOrderDestinationRefcountMap(); * OCV_TIMETABLE: Timetable lateness/earliness * OCV_TIME_DATE: Time/date * OCV_CARGO_WAITING_AMOUNT: Bits 0-15: Cargo quantity comparison value, Bits 16-31: Via station ID + 2 + * OCV_CARGO_WAITING_AMOUNT_PERCENTAGE: Bits 0-15: Cargo quantity comparison value, Bits 16-31: Via station ID + 2 * OCV_CARGO_LOAD_PERCENTAGE: Cargo percentage comparison value * OCV_DISPATCH_SLOT: Bits 0-15: Dispatch schedule ID * OCV_PERCENT: Bits 0-7: Jump counter @@ -77,6 +78,7 @@ void ClearOrderDestinationRefcountMap(); * OCV_CARGO_ACCEPTANCE: Bits 0-15: Station ID to test + 1 * OCV_FREE_PLATFORMS: Bits 0-15: Station ID to test + 1 * OCV_CARGO_WAITING_AMOUNT: Bits 0-15: Station ID to test + 1 + * OCV_CARGO_WAITING_AMOUNT_PERCENTAGE: Bits 0-15: Station ID to test + 1 */ struct OrderExtraInfo { diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 5cb06fedf58..0eebcb35fd6 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -973,7 +973,7 @@ TileIndex Order::GetLocation(const Vehicle *v, bool airport) const TileIndex Order::GetAuxiliaryLocation(bool secondary) const { if (this->IsType(OT_CONDITIONAL)) { - if (secondary && this->GetConditionVariable() == OCV_CARGO_WAITING_AMOUNT && GB(this->GetXData(), 16, 16) != 0) { + if (secondary && ConditionVariableTestsCargoWaitingAmount(this->GetConditionVariable()) && GB(this->GetXData(), 16, 16) != 0) { const Station *st = Station::GetIfValid(GB(this->GetXData(), 16, 16) - 2); if (st != nullptr) return st->xy; } @@ -1291,6 +1291,7 @@ static CommandCost CmdInsertOrderIntl(DoCommandFlag flags, Vehicle *v, VehicleOr break; case OCV_CARGO_WAITING_AMOUNT: + case OCV_CARGO_WAITING_AMOUNT_PERCENTAGE: if (!CargoSpec::Get(new_order.GetConditionValue())->IsValid()) return CMD_ERROR; if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) return CMD_ERROR; break; @@ -2074,6 +2075,7 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, uin break; case OCV_CARGO_WAITING_AMOUNT: + case OCV_CARGO_WAITING_AMOUNT_PERCENTAGE: case OCV_COUNTER_VALUE: case OCV_TIME_DATE: case OCV_TIMETABLE: @@ -2095,6 +2097,7 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, uin switch (order->GetConditionVariable()) { case OCV_CARGO_LOAD_PERCENTAGE: case OCV_CARGO_WAITING_AMOUNT: + case OCV_CARGO_WAITING_AMOUNT_PERCENTAGE: if (!(data < NUM_CARGO && CargoSpec::Get(data)->IsValid())) return CMD_ERROR; break; @@ -2124,6 +2127,7 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, uin case MOF_COND_VALUE_3: switch (order->GetConditionVariable()) { case OCV_CARGO_WAITING_AMOUNT: + case OCV_CARGO_WAITING_AMOUNT_PERCENTAGE: if (!(data == NEW_STATION || Station::GetIfValid(data) != nullptr)) return CMD_ERROR; if (GB(order->GetXData2(), 0, 16) - 1 == data) return CMD_ERROR; break; @@ -2284,7 +2288,8 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, uin /* Check whether old conditional variable had a cargo as value */ OrderConditionVariable old_condition = order->GetConditionVariable(); bool old_var_was_cargo = (order->GetConditionVariable() == OCV_CARGO_ACCEPTANCE || order->GetConditionVariable() == OCV_CARGO_WAITING - || order->GetConditionVariable() == OCV_CARGO_LOAD_PERCENTAGE || order->GetConditionVariable() == OCV_CARGO_WAITING_AMOUNT); + || order->GetConditionVariable() == OCV_CARGO_LOAD_PERCENTAGE || order->GetConditionVariable() == OCV_CARGO_WAITING_AMOUNT + || order->GetConditionVariable() == OCV_CARGO_WAITING_AMOUNT_PERCENTAGE); bool old_var_was_slot = (order->GetConditionVariable() == OCV_SLOT_OCCUPANCY || order->GetConditionVariable() == OCV_VEH_IN_SLOT); bool old_var_was_counter = (order->GetConditionVariable() == OCV_COUNTER_VALUE); bool old_var_was_time = (order->GetConditionVariable() == OCV_TIME_DATE); @@ -2336,6 +2341,7 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, uin break; case OCV_CARGO_LOAD_PERCENTAGE: case OCV_CARGO_WAITING_AMOUNT: + case OCV_CARGO_WAITING_AMOUNT_PERCENTAGE: if (!old_var_was_cargo) order->SetConditionValue((uint16_t) GetFirstValidCargo()); order->GetXDataRef() = 0; order->SetConditionComparator(OCC_EQUALS); @@ -2389,6 +2395,7 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, uin break; case OCV_CARGO_WAITING_AMOUNT: + case OCV_CARGO_WAITING_AMOUNT_PERCENTAGE: case OCV_COUNTER_VALUE: SB(order->GetXDataRef(), 0, 16, data); break; @@ -2421,7 +2428,7 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, uin case MOF_COND_STATION_ID: SB(order->GetXData2Ref(), 0, 16, data + 1); - if (order->GetConditionVariable() == OCV_CARGO_WAITING_AMOUNT && data == GB(order->GetXData(), 16, 16) - 2) { + if (ConditionVariableTestsCargoWaitingAmount(order->GetConditionVariable()) && data == GB(order->GetXData(), 16, 16) - 2) { /* Clear via if station is set to the same ID */ SB(order->GetXDataRef(), 16, 16, 0); } @@ -3051,7 +3058,7 @@ void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination, bool RemoveVehicleOrdersIf(v, [&](const Order *o) { OrderType ot = o->GetType(); if (ot == OT_CONDITIONAL) { - if (type == OT_GOTO_STATION && o->GetConditionVariable() == OCV_CARGO_WAITING_AMOUNT) { + if (type == OT_GOTO_STATION && ConditionVariableTestsCargoWaitingAmount(o->GetConditionVariable())) { if (GB(order->GetXData(), 16, 16) - 2 == destination) SB(order->GetXDataRef(), 16, 16, INVALID_STATION + 2); } if (type == OT_GOTO_STATION && ConditionVariableHasStationID(o->GetConditionVariable())) { @@ -3380,6 +3387,27 @@ VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v, Pro } break; } + case OCV_CARGO_WAITING_AMOUNT_PERCENTAGE: { + StationID next_station = GB(order->GetXData2(), 0, 16) - 1; + if (Station::IsValidID(next_station)) { + uint32_t waiting; + if (GB(order->GetXData(), 16, 16) == 0) { + waiting = Station::Get(next_station)->goods[value].CargoAvailableCount(); + } else { + waiting = Station::Get(next_station)->goods[value].CargoAvailableViaCount(GB(order->GetXData(), 16, 16) - 2); + } + + uint32_t veh_capacity = 0; + for (const Vehicle *v_iter = v; v_iter != nullptr; v_iter = v_iter->Next()) { + if (v_iter->cargo_type == value) veh_capacity += v_iter->cargo_cap; + } + uint32_t percentage = GB(order->GetXData(), 0, 16); + uint32_t threshold = static_cast(((uint64_t)veh_capacity * percentage) / 100); + + skip_order = OrderConditionCompare(occ, waiting, threshold); + } + break; + } case OCV_CARGO_ACCEPTANCE: { StationID next_station = GB(order->GetXData2(), 0, 16) - 1; if (Station::IsValidID(next_station)) skip_order = OrderConditionCompare(occ, HasBit(Station::Get(next_station)->goods[value].status, GoodsEntry::GES_ACCEPTANCE), value); diff --git a/src/order_gui.cpp b/src/order_gui.cpp index fe0de05a70b..8febe925da6 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -642,6 +642,7 @@ static const OrderConditionVariable _order_conditional_variable[] = { OCV_REQUIRES_SERVICE, OCV_CARGO_WAITING, OCV_CARGO_WAITING_AMOUNT, + OCV_CARGO_WAITING_AMOUNT_PERCENTAGE, OCV_CARGO_ACCEPTANCE, OCV_FREE_PLATFORMS, OCV_SLOT_OCCUPANCY, @@ -1047,7 +1048,8 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int SetDParam(2, CargoSpec::Get(order->GetConditionValue())->name); SetDParam(3, STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS + order->GetConditionComparator()); SetDParam(4, order->GetXData()); - } else if (ocv == OCV_CARGO_WAITING_AMOUNT) { + } else if (ocv == OCV_CARGO_WAITING_AMOUNT || ocv == OCV_CARGO_WAITING_AMOUNT_PERCENTAGE) { + const bool percent_mode = (ocv == OCV_CARGO_WAITING_AMOUNT_PERCENTAGE); ArrayStringParameters<10> tmp_params; StringID substr; @@ -1055,13 +1057,23 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int tmp_params.SetParam(1, CargoSpec::Get(order->GetConditionValue())->name); set_station_id(2, tmp_params); + auto output_condition_value = [&](int param_offset) { + if (percent_mode) { + auto capacity_params = MakeParameters(GB(order->GetXData(), 0, 16), CargoSpec::Get(order->GetConditionValue())->name); + _temp_special_strings[0] = GetStringWithArgs(STR_ORDER_CONDITIONAL_CARGO_WAITING_PERCENT_CAPACITY, capacity_params); + tmp_params.SetParam(param_offset, SPECSTR_TEMP_START); + } else { + tmp_params.SetParam(param_offset, order->GetConditionValue()); + tmp_params.SetParam(param_offset + 1, GB(order->GetXData(), 0, 16)); + } + }; + if (GB(order->GetXData(), 16, 16) == 0) { - substr = STR_ORDER_CONDITIONAL_CARGO_WAITING_AMOUNT_DISPLAY; + substr = percent_mode ? STR_ORDER_CONDITIONAL_CARGO_WAITING_GENERAL_DISPLAY : STR_ORDER_CONDITIONAL_CARGO_WAITING_AMOUNT_DISPLAY; tmp_params.SetParam(4, STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS + order->GetConditionComparator()); - tmp_params.SetParam(5, order->GetConditionValue()); - tmp_params.SetParam(6, GB(order->GetXData(), 0, 16)); + output_condition_value(5); } else { - substr = STR_ORDER_CONDITIONAL_CARGO_WAITING_AMOUNT_VIA_DISPLAY; + substr = percent_mode ? STR_ORDER_CONDITIONAL_CARGO_WAITING_GENERAL_VIA_DISPLAY : STR_ORDER_CONDITIONAL_CARGO_WAITING_AMOUNT_VIA_DISPLAY; const Station *via_st = Station::GetIfValid(GB(order->GetXData(), 16, 16) - 2); if (via_st == nullptr) { tmp_params.SetParam(4, STR_ORDER_CONDITIONAL_UNDEFINED_STATION); @@ -1070,8 +1082,7 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int tmp_params.SetParam(5, via_st->index); } tmp_params.SetParam(6, STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS + order->GetConditionComparator()); - tmp_params.SetParam(7, order->GetConditionValue()); - tmp_params.SetParam(8, GB(order->GetXData(), 0, 16)); + output_condition_value(7); } _temp_special_strings[0] = GetStringWithArgs(substr, tmp_params); SetDParam(0, SPECSTR_TEMP_START); @@ -2298,7 +2309,7 @@ struct OrdersWindow : public GeneralVehicleWindow { OrderConditionVariable ocv = (order == nullptr) ? OCV_LOAD_PERCENTAGE : order->GetConditionVariable(); bool is_cargo = (ocv == OCV_CARGO_ACCEPTANCE || ocv == OCV_CARGO_WAITING); bool is_slot_occupancy = (ocv == OCV_SLOT_OCCUPANCY || ocv == OCV_VEH_IN_SLOT); - bool is_auxiliary_cargo = (ocv == OCV_CARGO_LOAD_PERCENTAGE || ocv == OCV_CARGO_WAITING_AMOUNT); + bool is_auxiliary_cargo = (ocv == OCV_CARGO_LOAD_PERCENTAGE || ConditionVariableTestsCargoWaitingAmount(ocv)); bool is_counter = (ocv == OCV_COUNTER_VALUE); bool is_time_date = (ocv == OCV_TIME_DATE); bool is_timetable = (ocv == OCV_TIMETABLE); @@ -2347,7 +2358,7 @@ struct OrdersWindow : public GeneralVehicleWindow { aux_sel->SetDisplayedPlane(SZSP_NONE); } - if (ocv == OCV_CARGO_WAITING_AMOUNT) { + if (ConditionVariableTestsCargoWaitingAmount(ocv)) { aux2_sel->SetDisplayedPlane(DP_COND_AUX2_VIA); } else if (is_sched_dispatch) { this->GetWidget(WID_O_COND_SCHED_TEST)->widget_data = STR_TRACE_RESTRICT_DISPATCH_SLOT_SHORT_NEXT + GB(order->GetConditionValue(), ODCB_SRC_START, ODCB_SRC_COUNT); @@ -2611,6 +2622,7 @@ struct OrdersWindow : public GeneralVehicleWindow { break; case OCV_CARGO_WAITING_AMOUNT: + case OCV_CARGO_WAITING_AMOUNT_PERCENTAGE: case OCV_COUNTER_VALUE: value = GB(order->GetXData(), 0, 16); break; @@ -3270,6 +3282,7 @@ struct OrdersWindow : public GeneralVehicleWindow { break; case OCV_CARGO_WAITING_AMOUNT: + case OCV_CARGO_WAITING_AMOUNT_PERCENTAGE: case OCV_COUNTER_VALUE: value = GB(order->GetXData(), 0, 16); break; @@ -3379,6 +3392,7 @@ struct OrdersWindow : public GeneralVehicleWindow { case OCV_COUNTER_VALUE: case OCV_TIME_DATE: + case OCV_CARGO_WAITING_AMOUNT_PERCENTAGE: value = Clamp(value, 0, 0xFFFF); break; diff --git a/src/order_type.h b/src/order_type.h index 1a1ef5953ff..3c78e3ce04c 100644 --- a/src/order_type.h +++ b/src/order_type.h @@ -186,12 +186,18 @@ enum OrderConditionVariable { OCV_TIME_DATE, ///< Skip based on current time/date OCV_TIMETABLE, ///< Skip based on timetable state OCV_DISPATCH_SLOT, ///< Skip based on scheduled dispatch slot state + OCV_CARGO_WAITING_AMOUNT_PERCENTAGE, ///< Skip based on the amount of a specific cargo waiting at station, relative to the vehicle capacity OCV_END }; inline bool ConditionVariableHasStationID(OrderConditionVariable ocv) { - return ocv == OCV_CARGO_WAITING || ocv == OCV_CARGO_ACCEPTANCE || ocv == OCV_FREE_PLATFORMS || ocv == OCV_CARGO_WAITING_AMOUNT; + return ocv == OCV_CARGO_WAITING || ocv == OCV_CARGO_ACCEPTANCE || ocv == OCV_FREE_PLATFORMS || ocv == OCV_CARGO_WAITING_AMOUNT || ocv == OCV_CARGO_WAITING_AMOUNT_PERCENTAGE; +} + +inline bool ConditionVariableTestsCargoWaitingAmount(OrderConditionVariable ocv) +{ + return ocv == OCV_CARGO_WAITING_AMOUNT || ocv == OCV_CARGO_WAITING_AMOUNT_PERCENTAGE; } /** diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 946a9d2520d..9d25af16f00 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -4132,7 +4132,7 @@ bool AfterLoadGame() }; for (Order *order = order_list->GetFirstOrder(); order != nullptr; order = order->next) { - /* Fixup station ID for OCV_CARGO_WAITING, OCV_CARGO_ACCEPTANCE, OCV_FREE_PLATFORMS, OCV_CARGO_WAITING_AMOUNT */ + /* Fixup station ID for OCV_CARGO_WAITING, OCV_CARGO_ACCEPTANCE, OCV_FREE_PLATFORMS, OCV_CARGO_WAITING_AMOUNT, OCV_CARGO_WAITING_AMOUNT_PERCENTAGE */ if (order->IsType(OT_CONDITIONAL) && ConditionVariableHasStationID(order->GetConditionVariable())) { StationID next_id = get_real_station(order); SB(order->GetXData2Ref(), 0, 16, next_id + 1); diff --git a/src/sl/extended_ver_sl.cpp b/src/sl/extended_ver_sl.cpp index 43439063d0f..5c664666088 100644 --- a/src/sl/extended_ver_sl.cpp +++ b/src/sl/extended_ver_sl.cpp @@ -105,7 +105,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, 7, 7, "variable_day_length", nullptr, nullptr, nullptr }, { XSLFI_ORDER_OCCUPANCY, XSCF_NULL, 2, 2, "order_occupancy", nullptr, nullptr, nullptr }, - { XSLFI_MORE_COND_ORDERS, XSCF_NULL, 18, 18, "more_cond_orders", nullptr, nullptr, nullptr }, + { XSLFI_MORE_COND_ORDERS, XSCF_NULL, 19, 19, "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 },