diff --git a/src/departures.cpp b/src/departures.cpp index e5f242a4f8..327de30bfb 100644 --- a/src/departures.cpp +++ b/src/departures.cpp @@ -462,6 +462,7 @@ DepartureList* MakeDepartureList(StationID station, const std::vectorGetDestination(); } + if (order->GetType() == OT_LABEL && order->GetLabelSubType() == OLST_DEPARTURES_VIA && d->via == INVALID_STATION && pending_via == INVALID_STATION) { + pending_via = (StationID)order->GetDestination(); + } + if (c.scheduled_date != 0 && (order->GetTravelTime() != 0 || order->IsTravelTimetabled())) { c.scheduled_date += order->GetTravelTime(); /* TODO smart terminal may not work correctly */ } else { @@ -562,6 +567,9 @@ DepartureList* MakeDepartureList(StationID station, const std::vectorGetType() == OT_IMPLICIT) && order->GetNonStopType() != ONSF_NO_STOP_AT_ANY_STATION && order->GetNonStopType() != ONSF_NO_STOP_AT_DESTINATION_STATION) { + if (d->via == INVALID_STATION && pending_via != INVALID_STATION) { + d->via = pending_via; + } if (d->via == INVALID_STATION && candidate_via == (StationID)order->GetDestination()) { d->via = (StationID)order->GetDestination(); } diff --git a/src/departures_gui.cpp b/src/departures_gui.cpp index b31932d210..87660d6f21 100644 --- a/src/departures_gui.cpp +++ b/src/departures_gui.cpp @@ -22,6 +22,7 @@ #include "date_func.h" #include "departures_gui.h" #include "station_base.h" +#include "waypoint_base.h" #include "vehicle_gui_base.h" #include "vehicle_base.h" #include "vehicle_gui.h" @@ -821,8 +822,11 @@ void DeparturesWindow::DrawDeparturesListItems(const Rect &r) const } } - if (_settings_client.gui.departure_destination_type && d->via != INVALID_STATION) { - Station *t = Station::Get(d->via); + StationID via = d->via; + if (via == d->terminus.station || via == this->station) via = INVALID_STATION; + + if (_settings_client.gui.departure_destination_type && via != INVALID_STATION && Station::IsValidID(via)) { + Station *t = Station::Get(via); if (t->facilities & FACIL_DOCK && t->facilities & FACIL_AIRPORT && @@ -839,33 +843,41 @@ void DeparturesWindow::DrawDeparturesListItems(const Rect &r) const } /* Destination */ - if (d->via == INVALID_STATION) { + if (via == INVALID_STATION) { /* Only show the terminus. */ SetDParam(0, d->terminus.station); SetDParam(1, icon); ltr ? DrawString( text_left + time_width + type_width + 6, text_right - status_width - (toc_width + veh_width + group_width + 2) - 2, y + 1, STR_DEPARTURES_TERMINUS) : DrawString(text_left + status_width + (toc_width + veh_width + group_width + 2) + 2, text_right - time_width - type_width - 6, y + 1, STR_DEPARTURES_TERMINUS); } else { + auto set_via_dparams = [&](uint offset) { + if (Waypoint::IsValidID(via)) { + SetDParam(offset, STR_WAYPOINT_NAME); + } else { + SetDParam(offset, STR_STATION_NAME); + } + SetDParam(offset + 1, via); + }; /* Show the terminus and the via station. */ SetDParam(0, d->terminus.station); SetDParam(1, icon); - SetDParam(2, d->via); - SetDParam(3, icon_via); + set_via_dparams(2); + SetDParam(4, icon_via); int text_width = (GetStringBoundingBox(STR_DEPARTURES_TERMINUS_VIA_STATION)).width; if (text_width < text_right - status_width - (toc_width + veh_width + group_width + 2) - 2 - (text_left + time_width + type_width + 6)) { /* They will both fit, so show them both. */ SetDParam(0, d->terminus.station); SetDParam(1, icon); - SetDParam(2, d->via); - SetDParam(3, icon_via); + set_via_dparams(2); + SetDParam(4, icon_via); ltr ? DrawString( text_left + time_width + type_width + 6, text_right - status_width - (toc_width + veh_width + group_width + 2) - 2, y + 1, STR_DEPARTURES_TERMINUS_VIA_STATION) : DrawString(text_left + status_width + (toc_width + veh_width + group_width + 2) + 2, text_right - time_width - type_width - 6, y + 1, STR_DEPARTURES_TERMINUS_VIA_STATION); } else { /* They won't both fit, so switch between showing the terminus and the via station approximately every 4 seconds. */ if (this->tick_count & (1 << 7)) { - SetDParam(0, d->via); - SetDParam(1, icon_via); + set_via_dparams(0); + SetDParam(2, icon_via); ltr ? DrawString( text_left + time_width + type_width + 6, text_right - status_width - (toc_width + veh_width + group_width + 2) - 2, y + 1, STR_DEPARTURES_VIA) : DrawString(text_left + status_width + (toc_width + veh_width + group_width + 2) + 2, text_right - time_width - type_width - 6, y + 1, STR_DEPARTURES_VIA); } else { diff --git a/src/lang/extra/english.txt b/src/lang/extra/english.txt index eec1701c4c..aad31cee69 100644 --- a/src/lang/extra/english.txt +++ b/src/lang/extra/english.txt @@ -906,6 +906,8 @@ STR_TRACE_RESTRICT_COUNTER_SET :Set STR_TRACE_RESTRICT_COUNTER_INCREASE_ITEM :Increase counter: {STRING1} by {COMMA} STR_TRACE_RESTRICT_COUNTER_DECREASE_ITEM :Decrease counter: {STRING1} by {COMMA} STR_TRACE_RESTRICT_COUNTER_SET_ITEM :Set counter: {STRING1} to {COMMA} +STR_TRACE_RESTRICT_LABEL_TEXT :Label: {RAW_STRING} +STR_TRACE_RESTRICT_LABEL_DEPARTURES_VIA :Departure board: Show as via: {STRING1} STR_TRACE_RESTRICT_TRAIN_STATUS_EMPTY :empty STR_TRACE_RESTRICT_TRAIN_STATUS_FULL :full STR_TRACE_RESTRICT_TRAIN_STATUS_BROKEN_DOWN :broken down @@ -1282,9 +1284,9 @@ STR_DEPARTURES_TIME_DEP :{ORANGE}{DATE_W STR_DEPARTURES_TIME_ARR :{ORANGE}{DATE_WALLCLOCK_TINY} {RED}{DOWN_ARROW} STR_DEPARTURES_TIME_BOTH :{ORANGE}{1:DATE_WALLCLOCK_TINY} {RED}{DOWN_ARROW} {ORANGE}{0:DATE_WALLCLOCK_TINY} {GREEN}{UP_ARROW} STR_DEPARTURES_TERMINUS :{ORANGE}{STATION}{STRING} -STR_DEPARTURES_TERMINUS_VIA_STATION :{ORANGE}{STATION}{STRING} via {STATION}{STRING} +STR_DEPARTURES_TERMINUS_VIA_STATION :{ORANGE}{STATION}{STRING} via {STRING1}{STRING} STR_DEPARTURES_TERMINUS_VIA :{ORANGE}{STATION}{STRING} via -STR_DEPARTURES_VIA :{ORANGE}via {STATION}{STRING} +STR_DEPARTURES_VIA :{ORANGE}via {STRING1}{STRING} STR_DEPARTURES_TOC :{ORANGE}{COMPANY} STR_DEPARTURES_GROUP :{ORANGE}{GROUP} STR_DEPARTURES_VEH :{ORANGE}{VEHICLE} @@ -1556,6 +1558,11 @@ STR_ORDER_RELEASE_SLOT_TOOLTIP :{BLACK}The trai STR_ORDER_CHANGE_COUNTER_TOOLTIP :{BLACK}The counter to change +STR_ORDER_TEXT_LABEL_CAPTION :{WHITE}Label +STR_ORDER_TEXT_LABEL_BUTTON :Label +STR_ORDER_DEPARTURES_VIA_LABEL_BUTTON :Departure board via +STR_ORDER_TEXT_LABEL_BUTTON_TOOLTIP :{BLACK}Change label text + STR_ORDERS_OCCUPANCY_BUTTON :{BLACK}{STRING2}% STR_ORDERS_OCCUPANCY_BUTTON_TOOLTIP :{BLACK}Show occupancy running averages{}The percentage shown is the overall average of the order occupancies STR_ORDERS_OCCUPANCY_LIST_TOOLTIP :{BLACK}Order occupancy - this shows running averages of recent occupancy levels when leaving a station, for all vehicles sharing these orders diff --git a/src/lang/extra/galician.txt b/src/lang/extra/galician.txt index 7e1300acce..d50df438ad 100644 --- a/src/lang/extra/galician.txt +++ b/src/lang/extra/galician.txt @@ -1235,9 +1235,9 @@ STR_DEPARTURES_TIME_DEP :{ORANGE}{DATE_W STR_DEPARTURES_TIME_ARR :{ORANGE}{DATE_WALLCLOCK_TINY} {RED}{DOWN_ARROW} STR_DEPARTURES_TIME_BOTH :{ORANGE}{1:DATE_WALLCLOCK_TINY} {RED}{DOWN_ARROW} {ORANGE}{0:DATE_WALLCLOCK_TINY} {GREEN}{UP_ARROW} STR_DEPARTURES_TERMINUS :{ORANGE}{STATION}{STRING} -STR_DEPARTURES_TERMINUS_VIA_STATION :{ORANGE}{STATION}{STRING} vía {STATION}{STRING} +STR_DEPARTURES_TERMINUS_VIA_STATION :{ORANGE}{STATION}{STRING} vía {STRING}{STRING} STR_DEPARTURES_TERMINUS_VIA :{ORANGE}{STATION}{STRING} vía -STR_DEPARTURES_VIA :{ORANGE}vía {STATION}{STRING} +STR_DEPARTURES_VIA :{ORANGE}vía {STRING}{STRING} STR_DEPARTURES_TOC :{ORANGE}{COMPANY} STR_DEPARTURES_GROUP :{ORANGE}{GROUP} STR_DEPARTURES_VEH :{ORANGE}{VEHICLE} diff --git a/src/lang/extra/german.txt b/src/lang/extra/german.txt index 9bd56b8c1c..503e0f629d 100644 --- a/src/lang/extra/german.txt +++ b/src/lang/extra/german.txt @@ -1158,9 +1158,9 @@ STR_DEPARTURES_TIME_DEP :{ORANGE}{DATE_W STR_DEPARTURES_TIME_ARR :{ORANGE}{DATE_WALLCLOCK_TINY} {RED}{DOWN_ARROW} STR_DEPARTURES_TIME_BOTH :{ORANGE}{1:DATE_WALLCLOCK_TINY} {RED}{DOWN_ARROW} {ORANGE}{0:DATE_WALLCLOCK_TINY} {GREEN}{UP_ARROW} STR_DEPARTURES_TERMINUS :{ORANGE}{STATION}{STRING} -STR_DEPARTURES_TERMINUS_VIA_STATION :{ORANGE}{STATION}{STRING} über {STATION}{STRING} +STR_DEPARTURES_TERMINUS_VIA_STATION :{ORANGE}{STATION}{STRING} über {STRING}{STRING} STR_DEPARTURES_TERMINUS_VIA :{ORANGE}{STATION}{STRING} über -STR_DEPARTURES_VIA :{ORANGE}über {STATION}{STRING} +STR_DEPARTURES_VIA :{ORANGE}über {STRING}{STRING} STR_DEPARTURES_TOC :{ORANGE}{COMPANY} STR_DEPARTURES_GROUP :{ORANGE}{GROUP} STR_DEPARTURES_VEH :{ORANGE}{VEHICLE} diff --git a/src/lang/extra/japanese.txt b/src/lang/extra/japanese.txt index 4978a3a13b..9d804c58a6 100644 --- a/src/lang/extra/japanese.txt +++ b/src/lang/extra/japanese.txt @@ -51,9 +51,9 @@ STR_DEPARTURES_TIME_DEP :{ORANGE}{DATE_W STR_DEPARTURES_TIME_ARR :{ORANGE}{DATE_WALLCLOCK_TINY} {RED}{DOWN_ARROW} STR_DEPARTURES_TIME_BOTH :{ORANGE}{1:DATE_WALLCLOCK_TINY} {RED}{DOWN_ARROW} {ORANGE}{0:DATE_WALLCLOCK_TINY} {GREEN}{UP_ARROW} STR_DEPARTURES_TERMINUS :{ORANGE}{STATION}{STRING} -STR_DEPARTURES_TERMINUS_VIA_STATION :{ORANGE}{STATION}{STRING} 経由 {STATION}{STRING}経由 +STR_DEPARTURES_TERMINUS_VIA_STATION :{ORANGE}{STATION}{STRING} 経由 {STRING}{STRING}経由 STR_DEPARTURES_TERMINUS_VIA :{ORANGE}{STATION}{STRING} 経由 -STR_DEPARTURES_VIA :{ORANGE} {STATION}{STRING} 経由 +STR_DEPARTURES_VIA :{ORANGE} {STRING}{STRING} 経由 STR_DEPARTURES_TOC :{ORANGE}{COMPANY} STR_DEPARTURES_GROUP :{ORANGE}{GROUP} STR_DEPARTURES_VEH :{ORANGE}{VEHICLE} diff --git a/src/lang/extra/korean.txt b/src/lang/extra/korean.txt index 08dad22eaa..97b7b6b705 100644 --- a/src/lang/extra/korean.txt +++ b/src/lang/extra/korean.txt @@ -1235,9 +1235,9 @@ STR_DEPARTURES_TIME_DEP :{ORANGE}{DATE_W STR_DEPARTURES_TIME_ARR :{ORANGE}{DATE_WALLCLOCK_TINY} {RED}{DOWN_ARROW} STR_DEPARTURES_TIME_BOTH :{ORANGE}{1:DATE_WALLCLOCK_TINY} {RED}{DOWN_ARROW} {ORANGE}{0:DATE_WALLCLOCK_TINY} {GREEN}{UP_ARROW} STR_DEPARTURES_TERMINUS :{ORANGE}{STATION}{STRING} -STR_DEPARTURES_TERMINUS_VIA_STATION :{ORANGE}{STATION}{STRING} 경유 {STATION}{STRING} +STR_DEPARTURES_TERMINUS_VIA_STATION :{ORANGE}{STATION}{STRING} 경유 {STRING}{STRING} STR_DEPARTURES_TERMINUS_VIA :{ORANGE}{STATION}{STRING} 경유 -STR_DEPARTURES_VIA :{ORANGE}경유 {STATION}{STRING} +STR_DEPARTURES_VIA :{ORANGE}경유 {STRING}{STRING} STR_DEPARTURES_TOC :{ORANGE}{COMPANY} STR_DEPARTURES_GROUP :{ORANGE}{GROUP} STR_DEPARTURES_VEH :{ORANGE}{VEHICLE} diff --git a/src/lang/extra/simplified_chinese.txt b/src/lang/extra/simplified_chinese.txt index bc2738de0f..6f065b1da8 100644 --- a/src/lang/extra/simplified_chinese.txt +++ b/src/lang/extra/simplified_chinese.txt @@ -1225,9 +1225,9 @@ STR_DEPARTURES_TIME_DEP :{ORANGE}{DATE_W STR_DEPARTURES_TIME_ARR :{ORANGE}{DATE_WALLCLOCK_TINY} {RED}{DOWN_ARROW} STR_DEPARTURES_TIME_BOTH :{ORANGE}{1:DATE_WALLCLOCK_TINY} {RED}{DOWN_ARROW} {ORANGE}{0:DATE_WALLCLOCK_TINY} {GREEN}{UP_ARROW} STR_DEPARTURES_TERMINUS :{ORANGE}{STATION}{STRING} -STR_DEPARTURES_TERMINUS_VIA_STATION :{ORANGE}{STATION}{STRING}经由{STATION}{STRING} +STR_DEPARTURES_TERMINUS_VIA_STATION :{ORANGE}{STATION}{STRING}经由{STRING}{STRING} STR_DEPARTURES_TERMINUS_VIA :{ORANGE}{STATION}{STRING}经由 -STR_DEPARTURES_VIA :{ORANGE}经由{STATION}{STRING} +STR_DEPARTURES_VIA :{ORANGE}经由{STRING}{STRING} STR_DEPARTURES_TOC :{ORANGE}{COMPANY} STR_DEPARTURES_GROUP :{ORANGE}{GROUP} STR_DEPARTURES_VEH :{ORANGE}{VEHICLE} diff --git a/src/order_base.h b/src/order_base.h index e022ed9694..24c8b7b171 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -184,6 +184,7 @@ public: void MakeLoadingAdvance(StationID destination); void MakeReleaseSlot(); void MakeChangeCounter(); + void MakeLabel(OrderLabelSubType subtype); /** * Is this a 'goto' order with a real destination? @@ -205,7 +206,7 @@ public: /** * Gets the destination of this order. - * @pre IsType(OT_GOTO_WAYPOINT) || IsType(OT_GOTO_DEPOT) || IsType(OT_GOTO_STATION) || IsType(OT_RELEASE_SLOT) || IsType(OT_COUNTER). + * @pre IsType(OT_GOTO_WAYPOINT) || IsType(OT_GOTO_DEPOT) || IsType(OT_GOTO_STATION) || IsType(OT_RELEASE_SLOT) || IsType(OT_COUNTER) || IsType(OT_LABEL). * @return the destination of the order. */ inline DestinationID GetDestination() const { return this->dest; } @@ -213,7 +214,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) || IsType(OT_RELEASE_SLOT) || IsType(OT_COUNTER). + * @pre IsType(OT_GOTO_WAYPOINT) || IsType(OT_GOTO_DEPOT) || IsType(OT_GOTO_STATION) || IsType(OT_RELEASE_SLOT) || IsType(OT_COUNTER) || IsType(OT_LABEL). */ inline void SetDestination(DestinationID destination) { this->dest = destination; } @@ -426,7 +427,7 @@ public: * explicitly set (but travel_time is actually unused for conditionals). */ /* Does this order not have any associated travel or wait times */ - inline bool HasNoTimetableTimes() const { return this->IsType(OT_COUNTER) || this->IsType(OT_RELEASE_SLOT); } + inline bool HasNoTimetableTimes() const { return this->IsType(OT_COUNTER) || this->IsType(OT_RELEASE_SLOT) || this->IsType(OT_LABEL); } /** Does this order have an explicit wait time set? */ inline bool IsWaitTimetabled() const @@ -592,6 +593,14 @@ public: } } + inline OrderLabelSubType GetLabelSubType() const + { + return (OrderLabelSubType)GB(this->flags, 0, 8); + } + + const char *GetLabelText() const; + void SetLabelText(const char *text); + void AssignOrder(const Order &other); bool Equals(const Order &other) const; diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index f74bcc19e1..1824b33b41 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -252,6 +252,12 @@ void Order::MakeChangeCounter() this->flags = 0; } +void Order::MakeLabel(OrderLabelSubType subtype) +{ + this->type = OT_LABEL; + this->flags = subtype; +} + /** * Make this depot/station order also a refit order. * @param cargo the cargo type to change to. @@ -361,6 +367,25 @@ void InvalidateVehicleOrder(const Vehicle *v, int data) SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index); } +const char *Order::GetLabelText() const +{ + assert(this->IsType(OT_LABEL) && this->GetLabelSubType() == OLST_TEXT); + if (this->extra == nullptr) return ""; + const char *text = (const char *)(this->extra->cargo_type_flags); + if (ttd_strnlen(text, lengthof(this->extra->cargo_type_flags)) == lengthof(this->extra->cargo_type_flags)) { + /* Not null terminated, give up */ + return ""; + } + return text; +} + +void Order::SetLabelText(const char *text) +{ + assert(this->IsType(OT_LABEL) && this->GetLabelSubType() == OLST_TEXT); + this->CheckExtraInfoAlloced(); + strecpy((char *)(this->extra->cargo_type_flags), text, (char *)(lastof(this->extra->cargo_type_flags))); +} + /** * * Assign data to an order (from another order) @@ -677,7 +702,7 @@ CargoMaskedStationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, Ca }); if (invalid) return CargoMaskedStationIDStack(cargo_mask, INVALID_STATION); } - } while (next->IsType(OT_GOTO_DEPOT) || next->IsType(OT_RELEASE_SLOT) || next->IsType(OT_COUNTER) || next->IsType(OT_DUMMY) + } while (next->IsType(OT_GOTO_DEPOT) || next->IsType(OT_RELEASE_SLOT) || next->IsType(OT_COUNTER) || next->IsType(OT_DUMMY) || next->IsType(OT_LABEL) || (next->IsBaseStationOrder() && next->GetDestination() == v->last_station_visited)); return CargoMaskedStationIDStack(cargo_mask, next->GetDestination()); @@ -1284,6 +1309,28 @@ CommandCost CmdInsertOrderIntl(DoCommandFlag flags, Vehicle *v, VehicleOrderID s break; } + case OT_LABEL: { + switch (new_order.GetLabelSubType()) { + case OLST_TEXT: + break; + + case OLST_DEPARTURES_VIA: { + const BaseStation *st = BaseStation::GetIfValid(new_order.GetDestination()); + if (st == nullptr) return CMD_ERROR; + + if (st->owner != OWNER_NONE) { + CommandCost ret = CheckInfraUsageAllowed(v->type, st->owner); + if (ret.Failed()) return ret; + } + break; + } + + default: + return CMD_ERROR; + } + break; + } + default: return CMD_ERROR; } @@ -1822,6 +1869,14 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 if (mof != MOF_COUNTER_ID && mof != MOF_COUNTER_OP && mof != MOF_COUNTER_VALUE) return CMD_ERROR; break; + case OT_LABEL: + if (order->GetLabelSubType() == OLST_TEXT) { + if (mof != MOF_LABEL_TEXT) return CMD_ERROR; + } else { + return CMD_ERROR; + } + break; + default: return CMD_ERROR; } @@ -2027,6 +2082,9 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 return CMD_ERROR; } break; + + case MOF_LABEL_TEXT: + break; } if (flags & DC_EXEC) { @@ -2272,6 +2330,10 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 order->SetColour((Colours)data); break; + case MOF_LABEL_TEXT: + order->SetLabelText(text == nullptr ? "" : text); + break; + default: NOT_REACHED(); } @@ -2798,6 +2860,7 @@ void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination, bool if (ot == OT_GOTO_DEPOT && (o->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) return false; if (ot == OT_GOTO_DEPOT && hangar && v->type != VEH_AIRCRAFT) return false; // Not an aircraft? Can't have a hangar order. if (ot == OT_IMPLICIT || (v->type == VEH_AIRCRAFT && ot == OT_GOTO_DEPOT && !hangar)) ot = OT_GOTO_STATION; + if (ot == OT_LABEL && o->GetLabelSubType() == OLST_DEPARTURES_VIA && (type == OT_GOTO_STATION || type == OT_GOTO_WAYPOINT) && o->GetDestination() == destination) return true; return (ot == type && o->GetDestination() == destination); }); } @@ -3355,6 +3418,7 @@ bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool break; case OT_DUMMY: + case OT_LABEL: assert(!pbs_look_ahead); UpdateVehicleTimetable(v, true); v->IncrementRealOrderIndex(); @@ -3632,6 +3696,7 @@ const char *GetOrderTypeName(OrderType order_type) "OT_LOADING_ADVANCE", "OT_RELEASE_SLOT", "OT_COUNTER", + "OT_LABEL", }; static_assert(lengthof(names) == OT_END); if (order_type < OT_END) return names[order_type]; diff --git a/src/order_gui.cpp b/src/order_gui.cpp index 947c0cab5f..2bff6451d5 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -70,9 +70,9 @@ static const uint32 _cargo_type_unload_order_drowdown_hidden_mask = 0x8; // 0100 DropDownList GetSlotDropDownList(Owner owner, TraceRestrictSlotID slot_id, int &selected, VehicleType vehtype, bool show_other_types); DropDownList GetCounterDropDownList(Owner owner, TraceRestrictCounterID ctr_id, int &selected); -static bool ModifyOrder(const Vehicle *v, VehicleOrderID order_id, uint32 p2, bool error_msg = true) +static bool ModifyOrder(const Vehicle *v, VehicleOrderID order_id, uint32 p2, bool error_msg = true, const char *text = nullptr) { - return DoCommandPEx(v->tile, v->index, p2, order_id, CMD_MODIFY_ORDER | (error_msg ? CMD_MSG(STR_ERROR_CAN_T_MODIFY_THIS_ORDER) : 0), nullptr, nullptr, 0); + return DoCommandPEx(v->tile, v->index, p2, order_id, CMD_MODIFY_ORDER | (error_msg ? CMD_MSG(STR_ERROR_CAN_T_MODIFY_THIS_ORDER) : 0), nullptr, text, nullptr); } struct CargoTypeOrdersWindow : public Window { @@ -626,6 +626,8 @@ static const StringID _order_goto_dropdown[] = { STR_ORDER_SHARE, STR_ORDER_RELEASE_SLOT_BUTTON, STR_ORDER_CHANGE_COUNTER_BUTTON, + STR_ORDER_TEXT_LABEL_BUTTON, + STR_ORDER_DEPARTURES_VIA_LABEL_BUTTON, INVALID_STRING_ID }; @@ -636,6 +638,8 @@ static const StringID _order_goto_dropdown_aircraft[] = { STR_ORDER_SHARE, STR_ORDER_RELEASE_SLOT_BUTTON, STR_ORDER_CHANGE_COUNTER_BUTTON, + STR_ORDER_TEXT_LABEL_BUTTON, + STR_ORDER_DEPARTURES_VIA_LABEL_BUTTON, INVALID_STRING_ID }; @@ -1160,6 +1164,31 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int SetDParam(3, order->GetXData()); break; + case OT_LABEL: + switch (order->GetLabelSubType()) { + case OLST_TEXT: { + SetDParam(0, STR_TRACE_RESTRICT_LABEL_TEXT); + const char *text = order->GetLabelText(); + SetDParamStr(1, StrEmpty(text) ? "" : text); + break; + } + + case OLST_DEPARTURES_VIA: + SetDParam(0, STR_TRACE_RESTRICT_LABEL_DEPARTURES_VIA); + if (Waypoint::IsValidID(order->GetDestination())) { + SetDParam(1, STR_WAYPOINT_NAME); + } else { + SetDParam(1, STR_STATION_NAME); + } + SetDParam(2, order->GetDestination()); + break; + + default: + SetDParam(0, STR_TRACE_RESTRICT_VARIABLE_UNDEFINED_RED); + break; + } + break; + default: NOT_REACHED(); } @@ -1339,6 +1368,7 @@ private: OPOS_SHARE, OPOS_COND_VIA, OPOS_CONDITIONAL_RETARGET, + OPOS_DEPARTURE_VIA, OPOS_END, }; @@ -1349,6 +1379,8 @@ private: 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. DP_GROUNDVEHICLE_ROW_COUNTER = 3, ///< Display the row for change counter orders in the top row of the train/rv order window. + DP_GROUNDVEHICLE_ROW_TEXT_LABEL = 4, ///< Display the row for text label orders in the top row of the train/rv order window. + DP_GROUNDVEHICLE_ROW_EMPTY = 5, ///< Display the row for no buttons 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. @@ -1369,6 +1401,8 @@ private: DP_ROW_CONDITIONAL = 2, ///< Display the conditional order buttons in the top row of the ship/airplane order window. DP_ROW_SLOT = 3, ///< Display the release slot buttons in the top row of the ship/airplane order window. DP_ROW_COUNTER = 4, ///< Display the change counter buttons in the top row of the ship/airplane order window. + DP_ROW_TEXT_LABEL = 5, ///< Display the text label buttons in the top row of the ship/airplane order window. + DP_ROW_EMPTY = 6, ///< Display no buttons in the top row of the ship/airplane order window. /* WID_O_SEL_COND_VALUE */ DP_COND_VALUE_NUMBER = 0, ///< Display number widget @@ -1482,9 +1516,9 @@ private: return DoCommandPEx(this->vehicle->tile, this->vehicle->index, this->OrderGetSel(), order_pack, CMD_INSERT_ORDER | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER), nullptr, nullptr, 0); } - bool ModifyOrder(VehicleOrderID sel_ord, uint32 p2, bool error_msg = true) + bool ModifyOrder(VehicleOrderID sel_ord, uint32 p2, bool error_msg = true, const char *text = nullptr) { - return ::ModifyOrder(this->vehicle, sel_ord, p2, error_msg); + return ::ModifyOrder(this->vehicle, sel_ord, p2, error_msg, text); } /** @@ -1500,6 +1534,7 @@ private: HT_VEHICLE, // OPOS_SHARE HT_RECT, // OPOS_COND_VIA HT_NONE, // OPOS_CONDITIONAL_RETARGET + HT_RECT, // OPOS_DEPARTURE_VIA }; SetObjectToPlaceWnd(ANIMCURSOR_PICKSTATION, PAL_NONE, goto_place_style[type - 1], this); this->goto_type = type; @@ -1586,6 +1621,19 @@ private: this->InsertNewOrder(order.Pack()); } + /** + * Handle the click on the text label button. + */ + void OrderClick_TextLabel() + { + Order order; + order.next = nullptr; + order.index = 0; + order.MakeLabel(OLST_TEXT); + + this->InsertNewOrder(order.Pack()); + } + /** * Handle the click on the unload button. * @param unload_type Unload flag to apply. If matches existing unload type, toggles to default of 'unload if possible'. @@ -2195,6 +2243,15 @@ public: break; } + case OT_LABEL: { + if (row_sel != nullptr) { + row_sel->SetDisplayedPlane(order->GetLabelSubType() == OLST_TEXT ? DP_ROW_TEXT_LABEL : DP_ROW_EMPTY); + } else { + train_row_sel->SetDisplayedPlane(order->GetLabelSubType() == OLST_TEXT ? DP_GROUNDVEHICLE_ROW_TEXT_LABEL : DP_GROUNDVEHICLE_ROW_EMPTY); + } + break; + } + default: // every other order if (row_sel != nullptr) { row_sel->SetDisplayedPlane(DP_ROW_LOAD); @@ -2938,6 +2995,14 @@ public: break; } + case WID_O_TEXT_LABEL: { + const Order *order = this->vehicle->GetOrder(this->OrderGetSel()); + this->query_text_widget = widget; + SetDParamStr(0, order->GetLabelText()); + ShowQueryString(STR_JUST_RAW_STRING, STR_ORDER_TEXT_LABEL_CAPTION, NUM_CARGO - 1, this, CS_ALPHANUMERAL, QSF_NONE); + break; + } + case WID_O_TOGGLE_SIZE: { _settings_client.gui.show_order_management_button = !_settings_client.gui.show_order_management_button; InvalidateWindowClassesData(WC_VEHICLE_ORDERS); @@ -2994,6 +3059,10 @@ public: if (this->query_text_widget == WID_O_ADD_VEH_GROUP) { DoCommandP(0, VehicleListIdentifier(VL_SINGLE_VEH, this->vehicle->type, this->vehicle->owner, this->vehicle->index).Pack(), CF_ANY, CMD_CREATE_GROUP_FROM_LIST | CMD_MSG(STR_ERROR_GROUP_CAN_T_CREATE), nullptr, str); } + + if (this->query_text_widget == WID_O_TEXT_LABEL && str != nullptr) { + this->ModifyOrder(this->OrderGetSel(), MOF_LABEL_TEXT, true, str); + } } void OnDropdownSelect(int widget, int index) override @@ -3019,6 +3088,8 @@ public: case 3: this->OrderClick_Goto(OPOS_SHARE); break; case 4: this->OrderClick_ReleaseSlot(); break; case 5: this->OrderClick_ChangeCounter(); break; + case 6: this->OrderClick_TextLabel(); break; + case 7: this->OrderClick_Goto(OPOS_DEPARTURE_VIA); break; default: NOT_REACHED(); } break; @@ -3209,6 +3280,28 @@ public: } } } + } else if (this->goto_type == OPOS_DEPARTURE_VIA) { + if (IsTileType(tile, MP_STATION) || IsTileType(tile, MP_INDUSTRY)) { + const BaseStation *st = nullptr; + + if (IsTileType(tile, MP_STATION)) { + st = BaseStation::GetByTile(tile); + } else { + const Industry *in = Industry::GetByTile(tile); + st = in->neutral_station; + } + if (st != nullptr && IsInfraUsageAllowed(this->vehicle->type, this->vehicle->owner, st->owner)) { + Order order; + order.next = nullptr; + order.index = 0; + order.MakeLabel(OLST_DEPARTURES_VIA); + order.SetDestination(st->index); + + if (this->InsertNewOrder(order.Pack())) { + ResetObjectToPlace(); + } + } + } } } @@ -3446,6 +3539,13 @@ static const NWidgetPart _nested_orders_train_widgets[] = { NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_O_COUNTER_VALUE), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_BLACK_COMMA, STR_TRACE_RESTRICT_COND_VALUE_TOOLTIP), SetResize(1, 0), EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PANEL, COLOUR_GREY), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_O_TEXT_LABEL), SetMinimalSize(124, 12), SetFill(1, 0), + SetDataTip(STR_ORDER_TEXT_LABEL_BUTTON, STR_ORDER_TEXT_LABEL_BUTTON_TOOLTIP), SetResize(1, 0), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 0), 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), @@ -3581,6 +3681,17 @@ static const NWidgetPart _nested_orders_widgets[] = { NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_O_COUNTER_VALUE), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_BLACK_COMMA, STR_TRACE_RESTRICT_COND_VALUE_TOOLTIP), SetResize(1, 0), EndContainer(), + + /* Buttons for changing a text label */ + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PANEL, COLOUR_GREY), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_O_TEXT_LABEL), SetMinimalSize(124, 12), SetFill(1, 0), + SetDataTip(STR_ORDER_TEXT_LABEL_BUTTON, STR_ORDER_TEXT_LABEL_BUTTON_TOOLTIP), SetResize(1, 0), + EndContainer(), + + /* No buttons */ + NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 0), 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), diff --git a/src/order_type.h b/src/order_type.h index 03629f3586..16f3d0e3c0 100644 --- a/src/order_type.h +++ b/src/order_type.h @@ -48,9 +48,15 @@ enum OrderType : byte { OT_LOADING_ADVANCE = 10, OT_RELEASE_SLOT = 11, OT_COUNTER = 12, + OT_LABEL = 13, OT_END }; +enum OrderLabelSubType : byte { + OLST_TEXT = 0, + OLST_DEPARTURES_VIA = 1, +}; + /** * Flags related to the unloading order. */ @@ -203,6 +209,7 @@ enum ModifyOrderFlags { MOF_COUNTER_OP, ///< Change the counter operation MOF_COUNTER_VALUE, ///< Change the counter value MOF_COLOUR, ///< Change the colour value + MOF_LABEL_TEXT, ///< Change the label text value MOF_END }; template <> struct EnumPropsT : MakeEnumPropsT {}; diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index 3bc646492c..9dc4ee333a 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -187,6 +187,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_TNNC_CHUNK, XSCF_IGNORABLE_ALL, 0, 1, "tnnc_chunk", nullptr, nullptr, "TNNC" }, { XSLFI_MULTI_CARGO_SHIPS, XSCF_NULL, 1, 1, "multi_cargo_ships", nullptr, nullptr, nullptr }, { XSLFI_REMAIN_NEXT_ORDER_STATION, XSCF_IGNORABLE_UNKNOWN, 1, 1, "remain_next_order_station", nullptr, nullptr, nullptr }, + { XSLFI_LABEL_ORDERS, XSCF_NULL, 1, 1, "label_orders", nullptr, nullptr, nullptr }, { XSLFI_SCRIPT_INT64, XSCF_NULL, 1, 1, "script_int64", nullptr, nullptr, nullptr }, { XSLFI_U64_TICK_COUNTER, XSCF_NULL, 1, 1, "u64_tick_counter", nullptr, nullptr, nullptr }, { XSLFI_LINKGRAPH_TRAVEL_TIME, XSCF_NULL, 1, 1, "linkgraph_travel_time", nullptr, nullptr, nullptr }, diff --git a/src/saveload/extended_ver_sl.h b/src/saveload/extended_ver_sl.h index 955034154d..4f4074a801 100644 --- a/src/saveload/extended_ver_sl.h +++ b/src/saveload/extended_ver_sl.h @@ -138,6 +138,7 @@ enum SlXvFeatureIndex { XSLFI_TNNC_CHUNK, ///< TNNC chunk XSLFI_MULTI_CARGO_SHIPS, ///< Multi-cargo ships XSLFI_REMAIN_NEXT_ORDER_STATION, ///< Remain in station if next order is for same station + XSLFI_LABEL_ORDERS, ///< Label orders XSLFI_SCRIPT_INT64, ///< See: SLV_SCRIPT_INT64 XSLFI_U64_TICK_COUNTER, ///< See: SLV_U64_TICK_COUNTER diff --git a/src/timetable_cmd.cpp b/src/timetable_cmd.cpp index 1689ea04ec..5e0e7e5f48 100644 --- a/src/timetable_cmd.cpp +++ b/src/timetable_cmd.cpp @@ -707,7 +707,7 @@ 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) || order->IsType(OT_COUNTER) || order->IsType(OT_DUMMY)) { + if (order->IsType(OT_RELEASE_SLOT) || order->IsType(OT_COUNTER) || order->IsType(OT_DUMMY) || order->IsType(OT_LABEL)) { // Do not try to separate vehicles on release slot, change counter, or invalid orders separation_valid = false; } diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 42d49032cd..17408516ef 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -4374,7 +4374,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, * 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) || - v->current_order.IsType(OT_RELEASE_SLOT) || v->current_order.IsType(OT_COUNTER)) { + v->current_order.IsType(OT_RELEASE_SLOT) || v->current_order.IsType(OT_COUNTER) || v->current_order.IsType(OT_LABEL)) { ProcessOrders(v); } } @@ -6468,7 +6468,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 && !v->current_order.IsType(OT_RELEASE_SLOT) && !v->current_order.IsType(OT_COUNTER); + bool valid_order = !v->current_order.IsType(OT_NOTHING) && v->current_order.GetType() != OT_CONDITIONAL && !v->current_order.IsType(OT_RELEASE_SLOT) && !v->current_order.IsType(OT_COUNTER) && !v->current_order.IsType(OT_LABEL); 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 d109cacc8d..3af4551b2c 100644 --- a/src/widgets/order_widget.h +++ b/src/widgets/order_widget.h @@ -49,6 +49,7 @@ enum OrderWidgets { WID_O_COUNTER_OP, ///< Choose counter operation. WID_O_CHANGE_COUNTER, ///< Choose counter to change. WID_O_COUNTER_VALUE, ///< Choose counter value. + WID_O_TEXT_LABEL, ///< Choose text label. 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.