Scheduled dispatch: Allow tagging departure slots, add to conditional order

This commit is contained in:
Jonathan G Rennison
2024-01-28 17:14:03 +00:00
parent be469405df
commit 9bea1e3cc3
8 changed files with 191 additions and 58 deletions

View File

@@ -1640,6 +1640,8 @@ 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
STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_HAS_TAG :has tag {NUM}
STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_DOESNT_HAVE_TAG :doesn't have tag {NUM}
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
@@ -2105,6 +2107,8 @@ STR_SCHDISPATCH_REUSE_DEPARTURE_SLOTS_TOOLTIP :{BLACK}Set whet
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_REUSE_THIS_DEPARTURE_TAG :Tag {NUM}
STR_SCHDISPATCH_REUSE_THIS_DEPARTURE_TAG_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}
STR_SCHDISPATCH_NAMED_SCHEDULE_ID :{BLACK}{RAW_STRING} ({NUM} of {NUM}) STR_SCHDISPATCH_NAMED_SCHEDULE_ID :{BLACK}{RAW_STRING} ({NUM} of {NUM})
@@ -2119,6 +2123,7 @@ STR_SCHDISPATCH_SLOT_TOOLTIP_LAST :{}Last departur
STR_SCHDISPATCH_SLOT_TOOLTIP_NEXT :{}Next available departure slot STR_SCHDISPATCH_SLOT_TOOLTIP_NEXT :{}Next available departure slot
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 : ({DATE_WALLCLOCK_TINY}) STR_SCHDISPATCH_SLOT_TOOLTIP_TIME_SUFFIX : ({DATE_WALLCLOCK_TINY})
STR_SCHDISPATCH_SLOT_TOOLTIP_TAG :{}Tag {NUM}
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 {DATE_WALLCLOCK_TINY}. STR_SCHDISPATCH_SUMMARY_LAST_DEPARTURE_PAST :{BLACK}Last departure at {DATE_WALLCLOCK_TINY}.

View File

@@ -730,6 +730,8 @@ struct DispatchSlot {
*/ */
enum ScheduledDispatchSlotFlags { enum ScheduledDispatchSlotFlags {
SDSF_REUSE_SLOT = 0, ///< Allow this slot to be used more than once SDSF_REUSE_SLOT = 0, ///< Allow this slot to be used more than once
SDSF_FIRST_TAG = 8, ///< First tag flag
SDSF_LAST_TAG = 11, ///< Last tag flag
}; };
}; };

View File

@@ -1992,7 +1992,6 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, uin
case OCV_COUNTER_VALUE: case OCV_COUNTER_VALUE:
case OCV_TIME_DATE: case OCV_TIME_DATE:
case OCV_TIMETABLE: case OCV_TIMETABLE:
case OCV_DISPATCH_SLOT:
break; break;
default: default:
@@ -2021,7 +2020,9 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, uin
break; break;
case OCV_DISPATCH_SLOT: case OCV_DISPATCH_SLOT:
if (data >= OSDSCM_END) return CMD_ERROR; if (data != UINT16_MAX && data >= v->orders->GetScheduledDispatchScheduleCount()) {
return CMD_ERROR;
}
break; break;
default: default:
@@ -2293,7 +2294,6 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, uin
case OCV_CARGO_WAITING_AMOUNT: case OCV_CARGO_WAITING_AMOUNT:
case OCV_COUNTER_VALUE: case OCV_COUNTER_VALUE:
case OCV_DISPATCH_SLOT:
SB(order->GetXDataRef(), 0, 16, data); SB(order->GetXDataRef(), 0, 16, data);
break; break;
@@ -2309,6 +2309,10 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, uin
SB(order->GetXDataRef(), 16, 16, data); SB(order->GetXDataRef(), 16, 16, data);
break; break;
case OCV_DISPATCH_SLOT:
SB(order->GetXDataRef(), 0, 16, data);
break;
default: default:
order->SetConditionValue(data); order->SetConditionValue(data);
break; break;
@@ -3051,7 +3055,7 @@ bool EvaluateDispatchSlotConditionalOrder(const Order *order, const Vehicle *v,
if (predicted != nullptr) *predicted = true; if (predicted != nullptr) *predicted = true;
int32_t offset; int32_t offset;
if (order->GetConditionValue() & 2) { if (HasBit(order->GetConditionValue(), ODCB_LAST_DISPATCHED)) {
int32_t last = sched.GetScheduledDispatchLastDispatch(); int32_t last = sched.GetScheduledDispatchLastDispatch();
if (last == INVALID_SCHEDULED_DISPATCH_OFFSET) { if (last == INVALID_SCHEDULED_DISPATCH_OFFSET) {
/* No last dispatched */ /* No last dispatched */
@@ -3066,11 +3070,26 @@ bool EvaluateDispatchSlotConditionalOrder(const Order *order, const Vehicle *v,
offset = (slot - sched.GetScheduledDispatchStartTick()).base() % sched.GetScheduledDispatchDuration(); offset = (slot - sched.GetScheduledDispatchStartTick()).base() % sched.GetScheduledDispatchDuration();
} }
bool value; bool value = false;
if (order->GetConditionValue() & 1) { switch ((OrderDispatchConditionModes)GB(order->GetConditionValue(), ODCB_MODE_START, ODCB_MODE_COUNT)) {
value = (offset == (int32_t)sched.GetScheduledDispatch().back().offset); case ODCM_FIRST_LAST:
} else { if (HasBit(order->GetConditionValue(), ODFLCB_LAST_SLOT)) {
value = (offset == (int32_t)sched.GetScheduledDispatch().front().offset); value = (offset == (int32_t)sched.GetScheduledDispatch().back().offset);
} else {
value = (offset == (int32_t)sched.GetScheduledDispatch().front().offset);
}
break;
case OCDM_TAG: {
uint8_t tag = (uint8_t)GB(order->GetConditionValue(), ODFLCB_TAG_START, ODFLCB_TAG_COUNT);
for (const DispatchSlot &slot : sched.GetScheduledDispatch()) {
if (offset == (int32_t)slot.offset) {
value = HasBit(slot.flags, DispatchSlot::SDSF_FIRST_TAG + tag);
break;
}
}
break;
}
} }
return OrderConditionCompare(order->GetConditionComparator(), value ? 1 : 0, 0); return OrderConditionCompare(order->GetConditionComparator(), value ? 1 : 0, 0);

View File

@@ -756,6 +756,18 @@ static const StringID _order_conditional_condition_dispatch_slot_last[] = {
INVALID_STRING_ID, INVALID_STRING_ID,
}; };
static const StringID _order_conditional_condition_dispatch_slot_tag[] = {
STR_NULL,
STR_NULL,
STR_NULL,
STR_NULL,
STR_NULL,
STR_NULL,
STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_HAS_TAG,
STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_DOESNT_HAVE_TAG,
INVALID_STRING_ID,
};
extern uint ConvertSpeedToDisplaySpeed(uint speed, VehicleType type); extern uint ConvertSpeedToDisplaySpeed(uint speed, VehicleType type);
extern uint ConvertDisplaySpeedToSpeed(uint speed, VehicleType type); extern uint ConvertDisplaySpeedToSpeed(uint speed, VehicleType type);
@@ -1101,20 +1113,43 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int
} else if (ocv == OCV_DISPATCH_SLOT) { } else if (ocv == OCV_DISPATCH_SLOT) {
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) {
const DispatchSchedule &ds = v->orders->GetDispatchScheduleByIndex(GB(order->GetXData(), 0, 16)); bool have_name = false;
if (ds.ScheduleName().empty()) { if (GB(order->GetXData(), 0, 16) < v->orders->GetScheduledDispatchScheduleCount()) {
const DispatchSchedule &ds = v->orders->GetDispatchScheduleByIndex(GB(order->GetXData(), 0, 16));
if (!ds.ScheduleName().empty()) {
_temp_special_strings[0] = ds.ScheduleName();
have_name = true;
}
}
if (!have_name) {
auto tmp_params = MakeParameters(GB(order->GetXData(), 0, 16) + 1); auto tmp_params = MakeParameters(GB(order->GetXData(), 0, 16) + 1);
_temp_special_strings[0] = GetStringWithArgs(STR_TIMETABLE_ASSIGN_SCHEDULE_ID, tmp_params); _temp_special_strings[0] = GetStringWithArgs(STR_TIMETABLE_ASSIGN_SCHEDULE_ID, tmp_params);
} else {
_temp_special_strings[0] = ds.ScheduleName();
} }
SetDParam(2, SPECSTR_TEMP_START); SetDParam(2, SPECSTR_TEMP_START);
} else { } else {
SetDParam(2, STR_TIMETABLE_ASSIGN_SCHEDULE_NONE); SetDParam(2, STR_TIMETABLE_ASSIGN_SCHEDULE_NONE);
} }
SetDParam(3, STR_TRACE_RESTRICT_DISPATCH_SLOT_NEXT + (order->GetConditionValue() / 2));
SetDParam(4, STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_FIRST + ((order->GetConditionComparator() == OCC_IS_FALSE) ? 1 : 0) + const uint16_t value = order->GetConditionValue();
((order->GetConditionValue() % 2) ? 2 : 0)); SetDParam(3, HasBit(value, ODCB_LAST_DISPATCHED) ? STR_TRACE_RESTRICT_DISPATCH_SLOT_LAST : STR_TRACE_RESTRICT_DISPATCH_SLOT_NEXT);
switch ((OrderDispatchConditionModes)GB(value, ODCB_MODE_START, ODCB_MODE_COUNT)) {
case ODCM_FIRST_LAST:
SetDParam(4, STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_FIRST + ((order->GetConditionComparator() == OCC_IS_FALSE) ? 1 : 0) +
(HasBit(value, ODFLCB_LAST_SLOT) ? 2 : 0));
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);
SetDParam(4, SPECSTR_TEMP_START + 1);
break;
}
default:
SetDParam(4, STR_UNDEFINED);
break;
}
} else { } else {
OrderConditionComparator occ = order->GetConditionComparator(); OrderConditionComparator occ = order->GetConditionComparator();
SetDParam(0, (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) ? STR_ORDER_CONDITIONAL_TRUE_FALSE : STR_ORDER_CONDITIONAL_NUM); SetDParam(0, (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) ? STR_ORDER_CONDITIONAL_TRUE_FALSE : STR_ORDER_CONDITIONAL_NUM);
@@ -1562,8 +1597,19 @@ private:
case OCV_VEH_IN_SLOT: case OCV_VEH_IN_SLOT:
return v->type == VEH_TRAIN ? _order_conditional_condition_is_in_slot : _order_conditional_condition_is_in_slot_non_train; return v->type == VEH_TRAIN ? _order_conditional_condition_is_in_slot : _order_conditional_condition_is_in_slot_non_train;
case OCV_DISPATCH_SLOT: case OCV_DISPATCH_SLOT: {
return (order->GetConditionValue() % 2) == 0 ? _order_conditional_condition_dispatch_slot_first : _order_conditional_condition_dispatch_slot_last; const uint16_t value = order->GetConditionValue();
switch ((OrderDispatchConditionModes)GB(value, ODCB_MODE_START, ODCB_MODE_COUNT)) {
case ODCM_FIRST_LAST:
return HasBit(value, ODFLCB_LAST_SLOT) ? _order_conditional_condition_dispatch_slot_last : _order_conditional_condition_dispatch_slot_first;
case OCDM_TAG:
return _order_conditional_condition_dispatch_slot_tag;
default:
return _order_conditional_condition;
}
}
default: default:
return _order_conditional_condition; return _order_conditional_condition;
@@ -2288,7 +2334,7 @@ public:
if (ocv == OCV_CARGO_WAITING_AMOUNT) { if (ocv == OCV_CARGO_WAITING_AMOUNT) {
aux2_sel->SetDisplayedPlane(DP_COND_AUX2_VIA); aux2_sel->SetDisplayedPlane(DP_COND_AUX2_VIA);
} else if (is_sched_dispatch) { } else if (is_sched_dispatch) {
this->GetWidget<NWidgetCore>(WID_O_COND_SCHED_TEST)->widget_data = STR_TRACE_RESTRICT_DISPATCH_SLOT_SHORT_NEXT + (order->GetConditionValue() / 2); this->GetWidget<NWidgetCore>(WID_O_COND_SCHED_TEST)->widget_data = HasBit(order->GetConditionValue(), ODCB_LAST_DISPATCHED) ? STR_TRACE_RESTRICT_DISPATCH_SLOT_SHORT_LAST : STR_TRACE_RESTRICT_DISPATCH_SLOT_SHORT_NEXT;
aux2_sel->SetDisplayedPlane(DP_COND_AUX2_SCHED_TEST); aux2_sel->SetDisplayedPlane(DP_COND_AUX2_SCHED_TEST);
} else { } else {
aux2_sel->SetDisplayedPlane(SZSP_NONE); aux2_sel->SetDisplayedPlane(SZSP_NONE);
@@ -2564,6 +2610,16 @@ public:
break; break;
} }
case WID_O_COND_COMPARATOR: {
VehicleOrderID sel = this->OrderGetSel();
const Order *order = this->vehicle->GetOrder(sel);
if (order != nullptr && order->IsType(OT_CONDITIONAL) && order->GetConditionVariable() == OCV_DISPATCH_SLOT) {
SetDParam(0, GB(order->GetConditionValue(), ODFLCB_TAG_START, ODFLCB_TAG_COUNT) + 1);
}
break;
}
case WID_O_COND_SLOT: { case WID_O_COND_SLOT: {
VehicleOrderID sel = this->OrderGetSel(); VehicleOrderID sel = this->OrderGetSel();
const Order *order = this->vehicle->GetOrder(sel); const Order *order = this->vehicle->GetOrder(sel);
@@ -2986,8 +3042,8 @@ public:
} }
case WID_O_COND_SCHED_TEST: { case WID_O_COND_SCHED_TEST: {
ShowDropDownMenu(this, _order_dispatch_slot_dropdown, this->vehicle->GetOrder(this->OrderGetSel())->GetConditionValue() / 2, uint16_t value = this->vehicle->GetOrder(this->OrderGetSel())->GetConditionValue();
WID_O_COND_SCHED_TEST, 0, 0); ShowDropDownMenu(this, _order_dispatch_slot_dropdown, HasBit(value, ODCB_LAST_DISPATCHED) ? 1 : 0, WID_O_COND_SCHED_TEST, 0, 0);
break; break;
} }
@@ -3062,11 +3118,38 @@ public:
const Order *o = this->vehicle->GetOrder(this->OrderGetSel()); const Order *o = this->vehicle->GetOrder(this->OrderGetSel());
if (o->GetConditionVariable() == OCV_DISPATCH_SLOT) { if (o->GetConditionVariable() == OCV_DISPATCH_SLOT) {
DropDownList list; DropDownList list;
list.emplace_back(new DropDownListStringItem(STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_FIRST, 0x100, false));
list.emplace_back(new DropDownListStringItem(STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_NOT_FIRST, 0x101, false)); const int true_cond = ((int)OCC_IS_TRUE) << 16;
list.emplace_back(new DropDownListStringItem(STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_LAST, 0x102, false)); const int false_cond = ((int)OCC_IS_FALSE) << 16;
list.emplace_back(new DropDownListStringItem(STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_NOT_LAST, 0x103, false)); int first_last_value = 0;
int selected = 0x100 + ((o->GetConditionValue() % 2) * 2) + ((o->GetConditionComparator() == OCC_IS_FALSE) ? 1 : 0); SB(first_last_value, ODCB_MODE_START, ODCB_MODE_COUNT, ODCM_FIRST_LAST);
list.emplace_back(new DropDownListStringItem(STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_FIRST, true_cond | first_last_value, false));
list.emplace_back(new DropDownListStringItem(STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_NOT_FIRST, false_cond | first_last_value, false));
SetBit(first_last_value, ODFLCB_LAST_SLOT);
list.emplace_back(new DropDownListStringItem(STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_LAST, true_cond | first_last_value, false));
list.emplace_back(new DropDownListStringItem(STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_NOT_LAST, false_cond | first_last_value, false));
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()) {
slot_flags |= slot.flags;
}
}
for (uint8_t tag = 0; tag <= (DispatchSlot::SDSF_LAST_TAG - DispatchSlot::SDSF_FIRST_TAG); 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.emplace_back(new DropDownListStringItem(STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_HAS_TAG, true_cond | tag_cond_value, false));
list.emplace_back(new DropDownListStringItem(STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_DOESNT_HAVE_TAG, false_cond | tag_cond_value, false));
}
}
int selected = (((int)o->GetConditionComparator()) << 16) | (o->GetConditionValue() & ~GetBitMaskSC<uint16_t>(ODCB_LAST_DISPATCHED, 1));
ShowDropDownList(this, std::move(list), selected, WID_O_COND_COMPARATOR, 0); ShowDropDownList(this, std::move(list), selected, WID_O_COND_COMPARATOR, 0);
break; break;
} }
@@ -3295,16 +3378,17 @@ public:
this->ModifyOrder(this->OrderGetSel(), MOF_COND_VARIABLE | index << 8); this->ModifyOrder(this->OrderGetSel(), MOF_COND_VARIABLE | index << 8);
break; break;
case WID_O_COND_COMPARATOR: case WID_O_COND_COMPARATOR: {
if (index >= 0x100) { const Order *o = this->vehicle->GetOrder(this->OrderGetSel());
const Order *o = this->vehicle->GetOrder(this->OrderGetSel()); if (o == nullptr) return;
if (o == nullptr || o->GetConditionVariable() != OCV_DISPATCH_SLOT) return; if (o->GetConditionVariable() == OCV_DISPATCH_SLOT) {
this->ModifyOrder(this->OrderGetSel(), MOF_COND_COMPARATOR | ((index & 1) ? OCC_IS_FALSE : OCC_IS_TRUE) << 8); this->ModifyOrder(this->OrderGetSel(), MOF_COND_COMPARATOR | (index >> 16) << 8);
this->ModifyOrder(this->OrderGetSel(), MOF_COND_VALUE_2 | ((o->GetConditionValue() & 2) | ((index & 2) >> 1)) << 8); this->ModifyOrder(this->OrderGetSel(), MOF_COND_VALUE | ((o->GetConditionValue() & GetBitMaskSC<uint16_t>(ODCB_LAST_DISPATCHED, 1)) | (index & 0xFFFF)) << 8);
} else { } else {
this->ModifyOrder(this->OrderGetSel(), MOF_COND_COMPARATOR | index << 8); this->ModifyOrder(this->OrderGetSel(), MOF_COND_COMPARATOR | index << 8);
} }
break; break;
}
case WID_O_COND_CARGO: case WID_O_COND_CARGO:
this->ModifyOrder(this->OrderGetSel(), MOF_COND_VALUE | index << 8); this->ModifyOrder(this->OrderGetSel(), MOF_COND_VALUE | index << 8);
@@ -3331,14 +3415,15 @@ public:
break; break;
case WID_O_COND_SCHED_SELECT: case WID_O_COND_SCHED_SELECT:
this->ModifyOrder(this->OrderGetSel(), MOF_COND_VALUE | index << 8); this->ModifyOrder(this->OrderGetSel(), MOF_COND_VALUE_2 | index << 8);
break; break;
case WID_O_COND_SCHED_TEST: { case WID_O_COND_SCHED_TEST: {
const Order *o = this->vehicle->GetOrder(this->OrderGetSel()); const Order *o = this->vehicle->GetOrder(this->OrderGetSel());
if (o == nullptr) return; if (o == nullptr) return;
index = (index * 2) | (o->GetConditionValue() & 1); const uint16_t last = GetBitMaskSC<uint16_t>(ODCB_LAST_DISPATCHED, 1);
this->ModifyOrder(this->OrderGetSel(), MOF_COND_VALUE_2 | index << 8); index = (index != 0 ? last : 0) | (o->GetConditionValue() & ~last);
this->ModifyOrder(this->OrderGetSel(), MOF_COND_VALUE | index << 8);
break; break;
} }

View File

@@ -268,12 +268,24 @@ enum OrderTimetableConditionMode {
OTCM_END OTCM_END
}; };
enum OrderScheduledDispatchSlotConditionMode { enum OrderDispatchConditionBits {
OSDSCM_NEXT_FIRST = 0, ///< Test if next departure is first slot ODCB_LAST_DISPATCHED = 1,
OSDSCM_NEXT_LAST = 1, ///< Test if next departure is last slot ODCB_MODE_START = 8,
OSDSCM_LAST_FIRST = 2, ///< Test if last departure was first slot ODCB_MODE_COUNT = 3,
OSDSCM_LAST_LAST = 3, ///< Test if last departure was last slot };
OSDSCM_END
enum OrderDispatchConditionModes : uint8_t {
ODCM_FIRST_LAST = 0,
OCDM_TAG = 1,
};
enum OrderDispatchFirstLastConditionBits {
ODFLCB_LAST_SLOT = 0,
};
enum OrderDispatchTagConditionBits {
ODFLCB_TAG_START = 4,
ODFLCB_TAG_COUNT = 2,
}; };
/** /**

View File

@@ -667,7 +667,7 @@ CommandCost CmdScheduledDispatchSetSlotFlags(TileIndex tile, DoCommandFlag flags
uint16_t values = (uint16_t)GB(p3, 0, 16); uint16_t values = (uint16_t)GB(p3, 0, 16);
uint16_t mask = (uint16_t)GB(p3, 16, 16); uint16_t mask = (uint16_t)GB(p3, 16, 16);
const uint16_t permitted_mask = (1 << DispatchSlot::SDSF_REUSE_SLOT); const uint16_t permitted_mask = GetBitMaskSC<uint16_t>(DispatchSlot::SDSF_REUSE_SLOT, 1) | GetBitMaskFL<uint16_t>(DispatchSlot::SDSF_FIRST_TAG, DispatchSlot::SDSF_LAST_TAG);
if ((mask & permitted_mask) != mask) return CMD_ERROR; if ((mask & permitted_mask) != mask) return CMD_ERROR;
if ((values & (~mask)) != 0) return CMD_ERROR; if ((values & (~mask)) != 0) return CMD_ERROR;

View File

@@ -216,10 +216,6 @@ struct SchdispatchWindow : GeneralVehicleWindow {
SCH_MD_REUSE_DEPARTURE_SLOTS, SCH_MD_REUSE_DEPARTURE_SLOTS,
}; };
enum SlotManagementDropdown {
SCH_SMD_REUSE_DEPARTURE_SLOT,
};
SchdispatchWindow(WindowDesc *desc, WindowNumber window_number) : SchdispatchWindow(WindowDesc *desc, WindowNumber window_number) :
GeneralVehicleWindow(desc, Vehicle::Get(window_number)) GeneralVehicleWindow(desc, Vehicle::Get(window_number))
@@ -451,6 +447,11 @@ struct SchdispatchWindow : GeneralVehicleWindow {
case WID_SCHDISPATCH_MANAGE_SLOT: { case WID_SCHDISPATCH_MANAGE_SLOT: {
_temp_special_strings[0] = GetString(STR_SCHDISPATCH_REUSE_THIS_DEPARTURE_SLOT_TOOLTIP); _temp_special_strings[0] = GetString(STR_SCHDISPATCH_REUSE_THIS_DEPARTURE_SLOT_TOOLTIP);
auto add_suffix = [&](StringID str) {
SetDParam(0, str);
_temp_special_strings[0] += GetString(STR_SCHDISPATCH_MANAGE_TOOLTIP_SUFFIX);
};
add_suffix(STR_SCHDISPATCH_REUSE_THIS_DEPARTURE_TAG_TOOLTIP);
GuiShowTooltips(this, SPECSTR_TEMP_START, close_cond); GuiShowTooltips(this, SPECSTR_TEMP_START, close_cond);
return true; return true;
} }
@@ -512,6 +513,13 @@ struct SchdispatchWindow : GeneralVehicleWindow {
if (HasBit(flags, DispatchSlot::SDSF_REUSE_SLOT)) { if (HasBit(flags, DispatchSlot::SDSF_REUSE_SLOT)) {
_temp_special_strings[0] += GetString(STR_SCHDISPATCH_SLOT_TOOLTIP_REUSE); _temp_special_strings[0] += GetString(STR_SCHDISPATCH_SLOT_TOOLTIP_REUSE);
} }
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);
}
}
} }
GuiShowTooltips(this, SPECSTR_TEMP_START, close_cond); GuiShowTooltips(this, SPECSTR_TEMP_START, close_cond);
} }
@@ -1033,8 +1041,15 @@ struct SchdispatchWindow : GeneralVehicleWindow {
const DispatchSchedule &schedule = this->GetSelectedSchedule(); const DispatchSchedule &schedule = this->GetSelectedSchedule();
DropDownList list; DropDownList list;
list.push_back(std::make_unique<DropDownListCheckedItem>(HasBit(selected_slot->flags, DispatchSlot::SDSF_REUSE_SLOT), auto add_item = [&](StringID str, uint bit, bool disabled) {
STR_SCHDISPATCH_REUSE_THIS_DEPARTURE_SLOT, SCH_SMD_REUSE_DEPARTURE_SLOT, schedule.GetScheduledDispatchReuseSlots())); list.push_back(std::make_unique<DropDownListCheckedItem>(HasBit(selected_slot->flags, bit), str, bit, disabled));
};
add_item(STR_SCHDISPATCH_REUSE_THIS_DEPARTURE_SLOT, DispatchSlot::SDSF_REUSE_SLOT, schedule.GetScheduledDispatchReuseSlots());
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_REUSE_THIS_DEPARTURE_TAG, flag_bit, false);
}
ShowDropDownList(this, std::move(list), -1, WID_SCHDISPATCH_MANAGE_SLOT); ShowDropDownList(this, std::move(list), -1, WID_SCHDISPATCH_MANAGE_SLOT);
break; break;
} }
@@ -1124,15 +1139,10 @@ struct SchdispatchWindow : GeneralVehicleWindow {
const DispatchSlot *selected_slot = this->GetSelectedDispatchSlot(); const DispatchSlot *selected_slot = this->GetSelectedDispatchSlot();
if (selected_slot == nullptr) break; if (selected_slot == nullptr) break;
switch((SlotManagementDropdown)index) { uint64_t p3 = 0;
case SCH_SMD_REUSE_DEPARTURE_SLOT: { SetBit(p3, index + 16);
uint64_t p3 = 0; if (!HasBit(selected_slot->flags, index)) SetBit(p3, index);
SetBit(p3, SCH_SMD_REUSE_DEPARTURE_SLOT + 16); 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);
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; break;
} }

View File

@@ -105,7 +105,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
{ XSLFI_INFRA_SHARING, XSCF_NULL, 2, 2, "infra_sharing", nullptr, nullptr, "CPDP" }, { XSLFI_INFRA_SHARING, XSCF_NULL, 2, 2, "infra_sharing", nullptr, nullptr, "CPDP" },
{ XSLFI_VARIABLE_DAY_LENGTH, XSCF_NULL, 3, 3, "variable_day_length", nullptr, nullptr, nullptr }, { XSLFI_VARIABLE_DAY_LENGTH, XSCF_NULL, 3, 3, "variable_day_length", nullptr, nullptr, nullptr },
{ XSLFI_ORDER_OCCUPANCY, XSCF_NULL, 2, 2, "order_occupancy", nullptr, nullptr, nullptr }, { XSLFI_ORDER_OCCUPANCY, XSCF_NULL, 2, 2, "order_occupancy", nullptr, nullptr, nullptr },
{ XSLFI_MORE_COND_ORDERS, XSCF_NULL, 16, 16, "more_cond_orders", nullptr, nullptr, nullptr }, { XSLFI_MORE_COND_ORDERS, XSCF_NULL, 17, 17, "more_cond_orders", nullptr, nullptr, nullptr },
{ XSLFI_EXTRA_LARGE_MAP, XSCF_NULL, 0, 1, "extra_large_map", 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_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 }, { XSLFI_VEH_LIFETIME_PROFIT, XSCF_NULL, 1, 1, "veh_lifetime_profit", nullptr, nullptr, nullptr },