diff --git a/docs/newgrf-additions-nml.html b/docs/newgrf-additions-nml.html index d1d9f40c5f..1cc147572b 100644 --- a/docs/newgrf-additions-nml.html +++ b/docs/newgrf-additions-nml.html @@ -83,6 +83,14 @@ Additional ship parts may be refitted individually.

This requires the multi_part_ships feature.

+

+ Added callback: refit_part_name
+ This callback is called on the primary vehicle to get the name of each part of the ship (e.g. the name of each cargo hold) in the refit window.
+ This is not called for ships of only one part.
+ The callback handler should return a string or CB_RESULT_NO_TEXT.
+ If this callback is not handled or if CB_RESULT_NO_TEXT is returned, a default name is used.
+ getbits(extra_callback_info1, 0, 8) contains the index of the part of the ship. The first/primary part is 0, each subsequent part increases the value by 1. +

Railtype properties

diff --git a/docs/newgrf-additions.html b/docs/newgrf-additions.html index 6c66438fe0..36edf055e0 100644 --- a/docs/newgrf-additions.html +++ b/docs/newgrf-additions.html @@ -901,6 +901,18 @@ Additional ship parts may be refitted individually.

This is indicated by the feature name: multi_part_ships, version 1

+

Callback EC008002 - Ship part name for refit window
+ This callback is called on the primary vehicle to get the name of each part of the ship (e.g. the name of each cargo hold) in the refit window.
+ This is not called for ships of only one part.
+ If this callback is not handled, a default name is used.
+ Bits 0 - 7 of variable 10 contains the index of the part of the ship. The first/primary part is 0, each subsequent part increases the value by 1. +

+

+ The return value should be the number of a D0xx text to be displayed. The contents of registers 100h..105h are copied onto the text reference stack and can be used with string codes 80/81 to show texts from the D8xx range as well, extending the available unique strings.
+ You can return 400 to use the default name (instead of failing the callback).
+ (This is the same return format as callbacks: 23, 38, 3A, 14D, 15C, 161). +

+

This is indicated by the feature name: multi_part_ships, version 1



Action 3 - Objects

diff --git a/src/lang/extra/english.txt b/src/lang/extra/english.txt index 816b748e16..2457d84076 100644 --- a/src/lang/extra/english.txt +++ b/src/lang/extra/english.txt @@ -2022,3 +2022,7 @@ STR_MODIFIER_TOGGLE_SHIFT_TOOLTIP :{BLACK}Click to STR_MODIFIER_TOGGLE_CTRL_TOOLTIP :{BLACK}Click to invert state of Ctrl key STR_ERROR_TUNNEL_DISALLOWED_ROAD :{WHITE}Tunnels not allowed for this road type + +STR_REFIT_SHIP_PART_DROPDOWN_TOOLTIP :{BLACK}Select which part of this ship to refit +STR_REFIT_WHOLE_SHIP :Whole ship +STR_REFIT_SHIP_PART :Part {NUM} diff --git a/src/newgrf_callbacks.h b/src/newgrf_callbacks.h index b4988bb42b..c7db272f93 100644 --- a/src/newgrf_callbacks.h +++ b/src/newgrf_callbacks.h @@ -287,6 +287,9 @@ enum CallbackID { /** Called to set town zones */ XCBID_TOWN_ZONES = 0xEC008001, + + /** Called to get the name of the part of a ship for the refit window */ + XCBID_SHIP_REFIT_PART_NAME = 0xEC008002, }; /** diff --git a/src/newgrf_debug_gui.cpp b/src/newgrf_debug_gui.cpp index ee9e2735ad..d31f40aa45 100644 --- a/src/newgrf_debug_gui.cpp +++ b/src/newgrf_debug_gui.cpp @@ -1656,6 +1656,7 @@ const char *GetNewGRFCallbackName(CallbackID cbid) CBID(CBID_VEHICLE_SPAWN_VISUAL_EFFECT) CBID(CBID_VEHICLE_NAME) CBID(XCBID_TOWN_ZONES) + CBID(XCBID_SHIP_REFIT_PART_NAME) default: return nullptr; } } diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 8cbcdb1abd..090a9b4831 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -692,6 +692,7 @@ struct RefitWindow : public Window { uint8 num_vehicles; ///< Number of selected vehicles. bool auto_refit; ///< Select cargo for auto-refitting. bool is_virtual_train; ///< TemplateReplacement, whether the selected vehicle is virtual + mutable std::map ship_part_names; ///< Ship part name strings /** * Collects all (cargo, subcargo) refit options of a vehicle chain. @@ -707,6 +708,7 @@ struct RefitWindow : public Window { do { if (v->type == VEH_TRAIN && std::find(vehicles_to_refit.begin(), vehicles_to_refit.end(), v->index) == vehicles_to_refit.end()) continue; + if (v->type == VEH_SHIP && this->num_vehicles == 1 && v->index != this->selected_vehicle) continue; const Engine *e = v->GetEngine(); CargoTypes cmask = e->info.refit_mask; byte callback_mask = e->info.callback_mask; @@ -798,7 +800,7 @@ struct RefitWindow : public Window { } current_index++; } - } while (v->IsGroundVehicle() && (v = v->Next()) != nullptr); + } while (v->IsArticulatedCallbackVehicleType() && (v = v->Next()) != nullptr); } /** @@ -885,7 +887,15 @@ struct RefitWindow : public Window { NWidgetCore *nwi = this->GetWidget(WID_VR_REFIT); nwi->widget_data = STR_REFIT_TRAIN_REFIT_BUTTON + v->type; nwi->tool_tip = STR_REFIT_TRAIN_REFIT_TOOLTIP + v->type; - this->GetWidget(WID_VR_SHOW_HSCROLLBAR)->SetDisplayedPlane(v->IsGroundVehicle() ? 0 : SZSP_HORIZONTAL); + int hscrollbar_pane; + if (v->IsGroundVehicle()) { + hscrollbar_pane = 0; + } else if (v->type == VEH_SHIP && v->Next() != nullptr && this->order == INVALID_VEH_ORDER_ID) { + hscrollbar_pane = 1; + } else { + hscrollbar_pane = SZSP_HORIZONTAL; + } + this->GetWidget(WID_VR_SHOW_HSCROLLBAR)->SetDisplayedPlane(hscrollbar_pane); this->GetWidget(WID_VR_VEHICLE_PANEL_DISPLAY)->tool_tip = (v->type == VEH_TRAIN) ? STR_REFIT_SELECT_VEHICLES_TOOLTIP : STR_NULL; this->FinishInitNested(v->index); @@ -998,9 +1008,45 @@ struct RefitWindow : public Window { } } + const std::string &GetShipPartName(const Vehicle *v) const + { + std::string &name = this->ship_part_names[v->index]; + if (name.empty()) { + char buffer[128] = ""; + const Vehicle *front = v->First(); + uint offset = 0; + for (const Vehicle *u = front; u != v; u = u->Next()) offset++; + uint16 callback = GetVehicleCallback(XCBID_SHIP_REFIT_PART_NAME, offset, 0, front->engine_type, front); + if (callback != CALLBACK_FAILED && callback < 0x400) { + const GRFFile *grffile = v->GetGRF(); + assert(grffile != nullptr); + + StartTextRefStackUsage(grffile, 6); + char *end = GetString(buffer, GetGRFStringID(grffile->grfid, 0xD000 + callback), lastof(buffer)); + StopTextRefStackUsage(); + + name.assign(buffer, end - buffer); + } else { + SetDParam(0, offset + 1); + char *end = GetString(buffer, STR_REFIT_SHIP_PART, lastof(buffer)); + name.assign(buffer, end - buffer); + } + } + return name; + } + void SetStringParameters(int widget) const override { if (widget == WID_VR_CAPTION) SetDParam(0, Vehicle::Get(this->window_number)->index); + + if (widget == WID_VR_VEHICLE_DROPDOWN) { + if (this->num_vehicles == 1) { + SetDParam(0, STR_JUST_RAW_STRING); + SetDParamStr(1, this->GetShipPartName(Vehicle::Get(this->selected_vehicle))); + } else { + SetDParam(0, STR_REFIT_WHOLE_SHIP); + } + } } /** @@ -1147,6 +1193,7 @@ struct RefitWindow : public Window { Vehicle *v = Vehicle::Get(this->window_number); this->selected_vehicle = v->index; this->num_vehicles = UINT8_MAX; + this->ship_part_names.clear(); FALLTHROUGH; } @@ -1246,6 +1293,29 @@ struct RefitWindow : public Window { } } + virtual void OnDropdownSelect(int widget, int index) override + { + if (widget != WID_VR_VEHICLE_DROPDOWN) return; + + const Vehicle *v = Vehicle::Get(this->window_number); + + if (index > 0) { + for (const Vehicle *u = v; u != nullptr; u = u->Next()) { + if (index == 1) { + this->selected_vehicle = u->index; + this->num_vehicles = 1; + this->InvalidateData(2); + return; + } + index--; + } + } + + this->selected_vehicle = v->index; + this->num_vehicles = UINT8_MAX; + this->InvalidateData(2); + } + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { @@ -1288,6 +1358,26 @@ struct RefitWindow : public Window { } } break; + + case WID_VR_VEHICLE_DROPDOWN: { + const Vehicle *v = Vehicle::Get(this->window_number); + if (v->type != VEH_SHIP) break; + + DropDownList dlist; + int selected = 0; + dlist.emplace_back(new DropDownListStringItem(STR_REFIT_WHOLE_SHIP, 0, false)); + + int offset = 1; + for (const Vehicle *u = v; u != nullptr; u = u->Next()) { + if (u->index == this->selected_vehicle && this->num_vehicles == 1) selected = offset; + DropDownListCharStringItem *item = new DropDownListCharStringItem(this->GetShipPartName(u), offset, false); + dlist.emplace_back(item); + offset++; + } + + ShowDropDownList(this, std::move(dlist), selected, WID_VR_VEHICLE_DROPDOWN, 0, true); + break; + } } } @@ -1336,6 +1426,7 @@ static const NWidgetPart _nested_vehicle_refit_widgets[] = { NWidget(WWT_PANEL, COLOUR_GREY, WID_VR_VEHICLE_PANEL_DISPLAY), SetMinimalSize(228, 14), SetResize(1, 0), SetScrollbar(WID_VR_HSCROLLBAR), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_VR_SHOW_HSCROLLBAR), NWidget(NWID_HSCROLLBAR, COLOUR_GREY, WID_VR_HSCROLLBAR), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_VR_VEHICLE_DROPDOWN), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_JUST_STRING1, STR_REFIT_SHIP_PART_DROPDOWN_TOOLTIP), EndContainer(), EndContainer(), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_VR_SELECT_HEADER), SetDataTip(STR_REFIT_TITLE, STR_NULL), SetResize(1, 0), diff --git a/src/widgets/vehicle_widget.h b/src/widgets/vehicle_widget.h index aa12e7c56b..fe337b6fbd 100644 --- a/src/widgets/vehicle_widget.h +++ b/src/widgets/vehicle_widget.h @@ -36,6 +36,7 @@ enum VehicleRefitWidgets { WID_VR_VEHICLE_PANEL_DISPLAY, ///< Display with a representation of the vehicle to refit. WID_VR_SHOW_HSCROLLBAR, ///< Selection widget for the horizontal scrollbar. WID_VR_HSCROLLBAR, ///< Horizontal scrollbar or the vehicle display. + WID_VR_VEHICLE_DROPDOWN, ///< Dropdown for the vehicle display. WID_VR_SELECT_HEADER, ///< Header with question about the cargo to carry. WID_VR_MATRIX, ///< Options to refit to. WID_VR_SCROLLBAR, ///< Scrollbar for the refit options.