From 8a814bbfe3323bd1b9f9391918f1cdba4b0eae4c Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 10 Feb 2021 22:30:22 +0000 Subject: [PATCH] Add release slot train order --- src/lang/english.txt | 5 +++ src/order_base.h | 5 +-- src/order_cmd.cpp | 37 +++++++++++++++++++- src/order_gui.cpp | 72 +++++++++++++++++++++++++++++++++++++- src/order_type.h | 2 ++ src/timetable_cmd.cpp | 4 +++ src/tracerestrict.cpp | 4 +++ src/train_cmd.cpp | 4 +-- src/widgets/order_widget.h | 1 + 9 files changed, 128 insertions(+), 6 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index 6653f61a7f..6e6316a48a 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -4948,8 +4948,11 @@ STR_ORDER_GO_TO_NEAREST_DEPOT :Go to nearest d STR_ORDER_GO_TO_NEAREST_HANGAR :Go to nearest hangar STR_ORDER_CONDITIONAL :Conditional order jump STR_ORDER_SHARE :Share orders +STR_ORDER_RELEASE_SLOT_BUTTON :Release slot STR_ORDERS_GO_TO_TOOLTIP :{BLACK}Insert a new order before the highlighted order, or add to end of list. Ctrl makes station orders 'full load any cargo', waypoint orders 'non-stop' and depot orders 'service'. 'Share orders' or Ctrl lets this vehicle share orders with the selected vehicle. Clicking a vehicle copies the orders from that vehicle. A depot order disables automatic servicing of the vehicle +STR_ORDER_RELEASE_SLOT_TOOLTIP :{BLACK}The train slot to release + STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP :{BLACK}Show all vehicles that share this schedule STR_ORDERS_OCCUPANCY_BUTTON :{BLACK}{STRING2}% @@ -5057,6 +5060,8 @@ STR_ORDER_CONDITIONAL_COUNTER :Jump to order { 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_RELEASE_SLOT :Release slot: {STRING1} + STR_INVALID_ORDER :{RED} (Invalid Order) # Time table window diff --git a/src/order_base.h b/src/order_base.h index 94b6072b7e..f43b45825d 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -168,6 +168,7 @@ public: void MakeImplicit(StationID destination); void MakeWaiting(); void MakeLoadingAdvance(StationID destination); + void MakeReleaseSlot(); /** * Is this a 'goto' order with a real destination? @@ -189,7 +190,7 @@ public: /** * Gets the destination of this order. - * @pre IsType(OT_GOTO_WAYPOINT) || IsType(OT_GOTO_DEPOT) || IsType(OT_GOTO_STATION). + * @pre IsType(OT_GOTO_WAYPOINT) || IsType(OT_GOTO_DEPOT) || IsType(OT_GOTO_STATION) || IsType(OT_RELEASE_SLOT). * @return the destination of the order. */ inline DestinationID GetDestination() const { return this->dest; } @@ -197,7 +198,7 @@ public: /** * Sets the destination of this order. * @param destination the new destination of the order. - * @pre IsType(OT_GOTO_WAYPOINT) || IsType(OT_GOTO_DEPOT) || IsType(OT_GOTO_STATION). + * @pre IsType(OT_GOTO_WAYPOINT) || IsType(OT_GOTO_DEPOT) || IsType(OT_GOTO_STATION) || IsType(OT_RELEASE_SLOT). */ inline void SetDestination(DestinationID destination) { this->dest = destination; } diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index b8e58a561a..ea1bf21b49 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -235,6 +235,12 @@ void Order::MakeLoadingAdvance(StationID destination) this->dest = destination; } +void Order::MakeReleaseSlot() +{ + this->type = OT_RELEASE_SLOT; + this->dest = INVALID_TRACE_RESTRICT_SLOT_ID; +} + /** * Make this depot/station order also a refit order. * @param cargo the cargo type to change to. @@ -647,7 +653,7 @@ CargoMaskedStationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, Ca }); if (invalid) return CargoMaskedStationIDStack(cargo_mask, INVALID_STATION); } - } while (next->IsType(OT_GOTO_DEPOT) || next->GetDestination() == v->last_station_visited); + } while (next->IsType(OT_GOTO_DEPOT) || next->IsType(OT_RELEASE_SLOT) || next->GetDestination() == v->last_station_visited); return CargoMaskedStationIDStack(cargo_mask, next->GetDestination()); } @@ -1173,6 +1179,13 @@ CommandCost CmdInsertOrderIntl(DoCommandFlag flags, Vehicle *v, VehicleOrderID s break; } + case OT_RELEASE_SLOT: { + if (v->type != VEH_TRAIN) return CMD_ERROR; + TraceRestrictSlotID slot = new_order.GetDestination(); + if (slot != INVALID_TRACE_RESTRICT_SLOT_ID && !TraceRestrictSlot::IsValidID(slot)) return CMD_ERROR; + break; + } + default: return CMD_ERROR; } @@ -1693,6 +1706,10 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE && mof != MOF_COND_VALUE_2 && mof != MOF_COND_VALUE_3 && mof != MOF_COND_DESTINATION) return CMD_ERROR; break; + case OT_RELEASE_SLOT: + if (mof != MOF_SLOT) return CMD_ERROR; + break; + default: return CMD_ERROR; } @@ -1845,6 +1862,10 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 case MOF_WAYPOINT_FLAGS: if (data != (data & OWF_REVERSE)) return CMD_ERROR; break; + + case MOF_SLOT: + if (data != INVALID_TRACE_RESTRICT_SLOT_ID && !TraceRestrictSlot::IsValidID(data)) return CMD_ERROR; + break; } if (flags & DC_EXEC) { @@ -2036,6 +2057,10 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 order->SetWaypointFlags((OrderWaypointFlags)data); break; + case MOF_SLOT: + order->SetDestination(data); + break; + default: NOT_REACHED(); } @@ -2906,6 +2931,16 @@ bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool break; } + case OT_RELEASE_SLOT: + assert(!pbs_look_ahead); + if (order->GetDestination() != INVALID_TRACE_RESTRICT_SLOT_ID) { + TraceRestrictSlot *slot = TraceRestrictSlot::GetIfValid(order->GetDestination()); + if (slot != nullptr) slot->Vacate(v->index); + } + UpdateVehicleTimetable(v, true); + v->IncrementRealOrderIndex(); + break; + default: v->SetDestTile(0); return false; diff --git a/src/order_gui.cpp b/src/order_gui.cpp index d4f2cbc382..ae002d6cc2 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -621,6 +621,7 @@ static const StringID _order_goto_dropdown[] = { STR_ORDER_GO_TO_NEAREST_DEPOT, STR_ORDER_CONDITIONAL, STR_ORDER_SHARE, + STR_ORDER_RELEASE_SLOT_BUTTON, INVALID_STRING_ID }; @@ -629,6 +630,7 @@ static const StringID _order_goto_dropdown_aircraft[] = { STR_ORDER_GO_TO_NEAREST_HANGAR, STR_ORDER_CONDITIONAL, STR_ORDER_SHARE, + STR_ORDER_RELEASE_SLOT_BUTTON, INVALID_STRING_ID }; @@ -1023,6 +1025,16 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int break; } + case OT_RELEASE_SLOT: + SetDParam(0, STR_ORDER_RELEASE_SLOT); + if (order->GetDestination() == INVALID_TRACE_RESTRICT_SLOT_ID) { + SetDParam(1, STR_TRACE_RESTRICT_VARIABLE_UNDEFINED_RED); + } else { + SetDParam(1, STR_TRACE_RESTRICT_SLOT_NAME); + SetDParam(2, order->GetDestination()); + } + break; + default: NOT_REACHED(); } @@ -1200,6 +1212,7 @@ private: /* WID_O_SEL_TOP_ROW_GROUNDVEHICLE */ DP_GROUNDVEHICLE_ROW_NORMAL = 0, ///< Display the row for normal/depot orders in the top row of the train/rv order window. DP_GROUNDVEHICLE_ROW_CONDITIONAL = 1, ///< Display the row for conditional orders in the top row of the train/rv order window. + DP_GROUNDVEHICLE_ROW_SLOT = 2, ///< Display the row for release slot orders in the top row of the train/rv order window. /* WID_O_SEL_TOP_LEFT */ DP_LEFT_LOAD = 0, ///< Display 'load' in the left button of the top row of the train/rv order window. @@ -1404,6 +1417,19 @@ private: this->InsertNewOrder(order.Pack()); } + /** + * Handle the click on the release slot button. + */ + void OrderClick_ReleaseSlot() + { + Order order; + order.next = nullptr; + order.index = 0; + order.MakeReleaseSlot(); + + this->InsertNewOrder(order.Pack()); + } + /** * Handle the click on the unload button. */ @@ -1947,6 +1973,19 @@ public: break; } + case OT_RELEASE_SLOT: { + if (row_sel != nullptr) { + NOT_REACHED(); + } else { + train_row_sel->SetDisplayedPlane(DP_GROUNDVEHICLE_ROW_SLOT); + } + + TraceRestrictSlotID slot_id = (order != nullptr && TraceRestrictSlot::IsValidID(order->GetDestination()) ? order->GetDestination() : INVALID_TRACE_RESTRICT_SLOT_ID); + + this->GetWidget(WID_O_RELEASE_SLOT)->widget_data = (slot_id != INVALID_TRACE_RESTRICT_SLOT_ID) ? STR_TRACE_RESTRICT_SLOT_NAME : STR_TRACE_RESTRICT_VARIABLE_UNDEFINED; + break; + } + default: // every other order if (row_sel != nullptr) { row_sel->SetDisplayedPlane(DP_ROW_LOAD); @@ -2145,6 +2184,17 @@ public: SetDParam(1, 0); } break; + + case WID_O_RELEASE_SLOT: { + VehicleOrderID sel = this->OrderGetSel(); + const Order *order = this->vehicle->GetOrder(sel); + + if (order != nullptr && order->IsType(OT_RELEASE_SLOT)) { + TraceRestrictSlotID value = order->GetDestination(); + SetDParam(0, value); + } + break; + } } } @@ -2264,7 +2314,8 @@ public: case OPOS_SHARE: sel = 3; break; default: NOT_REACHED(); } - ShowDropDownMenu(this, this->vehicle->type == VEH_AIRCRAFT ? _order_goto_dropdown_aircraft : _order_goto_dropdown, sel, WID_O_GOTO, 0, 0, 0, DDSF_LOST_FOCUS); + ShowDropDownMenu(this, this->vehicle->type == VEH_AIRCRAFT ? _order_goto_dropdown_aircraft : _order_goto_dropdown, sel, WID_O_GOTO, + 0, (this->vehicle->type == VEH_TRAIN &&_settings_client.gui.show_adv_tracerestrict_features ? 0 : 0x10), 0, DDSF_LOST_FOCUS); } break; @@ -2449,6 +2500,14 @@ public: this->UpdateButtonState(); this->ReInit(); break; + + case WID_O_RELEASE_SLOT: { + int selected; + TraceRestrictSlotID value = this->vehicle->GetOrder(this->OrderGetSel())->GetDestination(); + DropDownList list = GetSlotDropDownList(this->vehicle->owner, value, selected); + if (!list.empty()) ShowDropDownList(this, std::move(list), selected, WID_O_RELEASE_SLOT, 0, true); + break; + } } } @@ -2512,6 +2571,7 @@ public: case 1: this->OrderClick_NearestDepot(); break; case 2: this->OrderClick_Goto(OPOS_CONDITIONAL); break; case 3: this->OrderClick_Goto(OPOS_SHARE); break; + case 4: this->OrderClick_ReleaseSlot(); break; default: NOT_REACHED(); } break; @@ -2552,6 +2612,10 @@ public: 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; + case WID_O_MANAGE_LIST: switch (index) { case 0: this->OrderClick_ReverseOrderList(0); break; @@ -2822,6 +2886,12 @@ static const NWidgetPart _nested_orders_train_widgets[] = { SetDataTip(STR_NULL, STR_ORDER_CONDITIONAL_SLOT_TOOLTIP), SetResize(1, 0), EndContainer(), EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PANEL, COLOUR_GREY), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), EndContainer(), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_O_RELEASE_SLOT), SetMinimalSize(124, 12), SetFill(1, 0), + SetDataTip(STR_NULL, STR_ORDER_RELEASE_SLOT_TOOLTIP), SetResize(1, 0), + EndContainer(), EndContainer(), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_O_OCCUPANCY_TOGGLE), SetMinimalSize(36, 12), SetDataTip(STR_ORDERS_OCCUPANCY_BUTTON, STR_ORDERS_OCCUPANCY_BUTTON_TOOLTIP), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_O_SEL_SHARED), diff --git a/src/order_type.h b/src/order_type.h index 9eb68af856..08a82f7bd8 100644 --- a/src/order_type.h +++ b/src/order_type.h @@ -46,6 +46,7 @@ enum OrderType : byte { OT_IMPLICIT = 8, OT_WAITING = 9, OT_LOADING_ADVANCE = 10, + OT_RELEASE_SLOT = 11, OT_END }; @@ -184,6 +185,7 @@ enum ModifyOrderFlags { MOF_WAYPOINT_FLAGS, ///< Change the waypoint flags MOF_CARGO_TYPE_UNLOAD, ///< Passes an OrderUnloadType and a CargoID. MOF_CARGO_TYPE_LOAD, ///< Passes an OrderLoadType and a CargoID. + MOF_SLOT, ///< Change the slot value MOF_END }; template <> struct EnumPropsT : MakeEnumPropsT {}; diff --git a/src/timetable_cmd.cpp b/src/timetable_cmd.cpp index bb3df347b4..1dcad44542 100644 --- a/src/timetable_cmd.cpp +++ b/src/timetable_cmd.cpp @@ -655,6 +655,10 @@ std::vector PopulateSeparationState(const Vehicle *v_start) // Do not try to separate vehicles on depot service or halt orders separation_valid = false; } + if (order->IsType(OT_RELEASE_SLOT)) { + // Do not try to separate vehicles on release slot orders + separation_valid = false; + } int order_ticks; if (order->GetType() == OT_GOTO_STATION && (v->current_order.IsType(OT_LOADING) || v->current_order.IsType(OT_LOADING_ADVANCE)) && v->last_station_visited == order->GetDestination()) { diff --git a/src/tracerestrict.cpp b/src/tracerestrict.cpp index ddfb2b1eb8..fa3c68c655 100644 --- a/src/tracerestrict.cpp +++ b/src/tracerestrict.cpp @@ -1943,6 +1943,10 @@ void TraceRestrictRemoveSlotID(TraceRestrictSlotID index) o->GetXDataRef() = INVALID_TRACE_RESTRICT_SLOT_ID; changed_order = true; } + if (o->IsType(OT_RELEASE_SLOT) && o->GetDestination() == index) { + o->SetDestination(INVALID_TRACE_RESTRICT_SLOT_ID); + changed_order = true; + } } // update windows diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 80700ded93..7f5742d615 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -4001,7 +4001,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, * Also check if the current order is a service order so we don't reserve a path to * the destination but instead to the next one if service isn't needed. */ CheckIfTrainNeedsService(v); - if (v->current_order.IsType(OT_DUMMY) || v->current_order.IsType(OT_CONDITIONAL) || v->current_order.IsType(OT_GOTO_DEPOT)) ProcessOrders(v); + if (v->current_order.IsType(OT_DUMMY) || v->current_order.IsType(OT_CONDITIONAL) || v->current_order.IsType(OT_GOTO_DEPOT) || v->current_order.IsType(OT_RELEASE_SLOT)) ProcessOrders(v); } /* Save the current train order. The destructor will restore the old order on function exit. */ @@ -5905,7 +5905,7 @@ static bool TrainLocoHandler(Train *v, bool mode) /* exit if train is stopped */ if ((v->vehstatus & VS_STOPPED) && v->cur_speed == 0) return true; - bool valid_order = !v->current_order.IsType(OT_NOTHING) && v->current_order.GetType() != OT_CONDITIONAL; + bool valid_order = !v->current_order.IsType(OT_NOTHING) && v->current_order.GetType() != OT_CONDITIONAL && !v->current_order.IsType(OT_RELEASE_SLOT); if (ProcessOrders(v) && CheckReverseTrain(v)) { v->wait_counter = 0; v->cur_speed = 0; diff --git a/src/widgets/order_widget.h b/src/widgets/order_widget.h index 1271aa3e82..8a7b358312 100644 --- a/src/widgets/order_widget.h +++ b/src/widgets/order_widget.h @@ -40,6 +40,7 @@ enum OrderWidgets { WID_O_COND_COUNTER, ///< Choose condition counter. WID_O_COND_TIME_DATE, ///< Choose time/date 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. WID_O_SEL_COND_AUX, ///< Widget for auxiliary conditional cargo type. WID_O_SEL_COND_AUX2, ///< Widget for auxiliary conditional via button.