diff --git a/src/lang/english.txt b/src/lang/english.txt index f51b41f9dd..dcf876c6f8 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -4089,6 +4089,8 @@ STR_VEHICLE_VIEW_ROAD_VEHICLE_SEND_TO_DEPOT_TOOLTIP :{BLACK}Send veh STR_VEHICLE_VIEW_SHIP_SEND_TO_DEPOT_TOOLTIP :{BLACK}Send ship to depot. Ctrl+Click will only service STR_VEHICLE_VIEW_AIRCRAFT_SEND_TO_DEPOT_TOOLTIP :{BLACK}Send aircraft to hangar. Ctrl+Click will only service +STR_VEHICLE_VIEW_SEND_TO_DEPOT_TOOLTIP_SHIFT :{STRING}. Shift+Click to select which + STR_VEHICLE_VIEW_CLONE_TRAIN_INFO :{BLACK}This will buy a copy of the train including all cars. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase STR_VEHICLE_VIEW_CLONE_ROAD_VEHICLE_INFO :{BLACK}This will buy a copy of the road vehicle. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase STR_VEHICLE_VIEW_CLONE_SHIP_INFO :{BLACK}This will buy a copy of the ship. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase diff --git a/src/vehicle.cpp b/src/vehicle.cpp index cd84eb3034..f0a0b719c6 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -2789,7 +2789,7 @@ void Vehicle::HandleWaiting(bool stop_waiting) * @param command the command to execute. * @return the cost of the depot action. */ -CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command) +CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command, TileIndex specific_depot) { CommandCost ret = CheckOwnership(this->owner); if (ret.Failed()) return ret; @@ -2797,7 +2797,7 @@ CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command) if (this->vehstatus & VS_CRASHED) return CMD_ERROR; if (this->IsStoppedInDepot()) return CMD_ERROR; - if (this->current_order.IsType(OT_GOTO_DEPOT)) { + if (this->current_order.IsType(OT_GOTO_DEPOT) && !(command & DEPOT_SPECIFIC)) { bool halt_in_depot = (this->current_order.GetDepotActionType() & ODATFB_HALT) != 0; if (!!(command & DEPOT_SERVICE) == halt_in_depot) { /* We called with a different DEPOT_SERVICE setting. @@ -2842,7 +2842,17 @@ CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command) DestinationID destination; bool reverse; static const StringID no_depot[] = {STR_ERROR_UNABLE_TO_FIND_ROUTE_TO, STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT, STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT, STR_ERROR_CAN_T_SEND_AIRCRAFT_TO_HANGAR}; - if (!this->FindClosestDepot(&location, &destination, &reverse)) return_cmd_error(no_depot[this->type]); + if (command & DEPOT_SPECIFIC) { + if (!(IsDepotTile(specific_depot) && GetDepotVehicleType(specific_depot) == this->type && + IsInfraTileUsageAllowed(this->type, this->owner, specific_depot))) { + return_cmd_error(no_depot[this->type]); + } + location = specific_depot; + destination = (this->type == VEH_AIRCRAFT) ? GetStationIndex(specific_depot) : GetDepotIndex(specific_depot); + reverse = false; + } else { + if (!this->FindClosestDepot(&location, &destination, &reverse)) return_cmd_error(no_depot[this->type]); + } if (flags & DC_EXEC) { if (this->current_order.IsType(OT_LOADING)) this->LeaveStation(); diff --git a/src/vehicle_base.h b/src/vehicle_base.h index 29f5620e2d..5893ceb02e 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -819,7 +819,7 @@ public: */ virtual bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse) { return false; } - CommandCost SendToDepot(DoCommandFlag flags, DepotCommand command); + CommandCost SendToDepot(DoCommandFlag flags, DepotCommand command, TileIndex specific_depot = 0); void UpdateVisualEffect(bool allow_power_change = true); void ShowVisualEffect() const; diff --git a/src/vehicle_cmd.cpp b/src/vehicle_cmd.cpp index 476cdbd66a..f1724755e9 100644 --- a/src/vehicle_cmd.cpp +++ b/src/vehicle_cmd.cpp @@ -1521,8 +1521,8 @@ static CommandCost SendAllVehiclesToDepot(DoCommandFlag flags, bool service, con * @param flags for command type * @param p1 bitmask * - p1 0-20: bitvehicle ID to send to the depot - * - p1 bits 25-8 - DEPOT_ flags (see vehicle_type.h) - * @param p2 packed VehicleListIdentifier. + * - p1 bits 27-31 - DEPOT_ flags (see vehicle_type.h) + * @param p2 packed VehicleListIdentifier, or specific depot tile * @param text unused * @return the cost of this operation or an error */ @@ -1539,7 +1539,7 @@ CommandCost CmdSendVehicleToDepot(TileIndex tile, DoCommandFlag flags, uint32 p1 if (v == NULL) return CMD_ERROR; if (!v->IsPrimaryVehicle()) return CMD_ERROR; - return v->SendToDepot(flags, (DepotCommand)(p1 & DEPOT_COMMAND_MASK)); + return v->SendToDepot(flags, (DepotCommand)(p1 & DEPOT_COMMAND_MASK), p2); } /** diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index ab49326859..052aa8905c 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -2578,7 +2578,7 @@ static const NWidgetPart _nested_vehicle_view_widgets[] = { NWidget(NWID_VERTICAL), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_CENTER_MAIN_VIEW), SetMinimalSize(18, 18), SetDataTip(SPR_CENTRE_VIEW_VEHICLE, 0x0 /* filled later */), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_VV_SELECT_DEPOT_CLONE), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_GOTO_DEPOT), SetMinimalSize(18, 18), SetDataTip(0x0 /* filled later */, 0x0 /* filled later */), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_VV_GOTO_DEPOT), SetMinimalSize(18, 18), SetDataTip(0x0 /* filled later */, 0x0 /* filled later */), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_CLONE), SetMinimalSize(18, 18), SetDataTip(0x0 /* filled later */, 0x0 /* filled later */), EndContainer(), /* For trains only, 'ignore signal' button. */ @@ -2721,6 +2721,9 @@ static bool IsVehicleRefitable(const Vehicle *v) /** Window manager class for viewing a vehicle. */ struct VehicleViewWindow : Window { private: + bool depot_select_active = false; + bool depot_select_ctrl_pressed = false; + /** Display planes available in the vehicle view window. */ enum PlaneSelections { SEL_DC_GOTO_DEPOT, ///< Display 'goto depot' button in #WID_VV_SELECT_DEPOT_CLONE stacked widget. @@ -2801,7 +2804,6 @@ public: this->GetWidget(WID_VV_START_STOP)->tool_tip = STR_VEHICLE_VIEW_TRAIN_STATE_START_STOP_TOOLTIP + v->type; this->GetWidget(WID_VV_CENTER_MAIN_VIEW)->tool_tip = STR_VEHICLE_VIEW_TRAIN_LOCATION_TOOLTIP + v->type; this->GetWidget(WID_VV_REFIT)->tool_tip = STR_VEHICLE_VIEW_TRAIN_REFIT_TOOLTIP + v->type; - this->GetWidget(WID_VV_GOTO_DEPOT)->tool_tip = STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP + v->type; this->GetWidget(WID_VV_SHOW_ORDERS)->tool_tip = STR_VEHICLE_VIEW_TRAIN_ORDERS_TOOLTIP + v->type; this->GetWidget(WID_VV_SHOW_DETAILS)->tool_tip = STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP + v->type; this->GetWidget(WID_VV_CLONE)->tool_tip = STR_VEHICLE_VIEW_CLONE_TRAIN_INFO + v->type; @@ -3041,7 +3043,15 @@ public: } case WID_VV_GOTO_DEPOT: // goto hangar - DoCommandP(v->tile, v->index | (_ctrl_pressed ? DEPOT_SERVICE : 0U), 0, GetCmdSendToDepot(v)); + if (_shift_pressed) { + if (HandlePlacePushButton(this, WID_VV_GOTO_DEPOT, ANIMCURSOR_PICKSTATION, HT_RECT)) { + this->depot_select_ctrl_pressed = _ctrl_pressed; + this->depot_select_active = true; + } + } else { + this->HandleButtonClick(WID_VV_GOTO_DEPOT); + DoCommandP(v->tile, v->index | (_ctrl_pressed ? DEPOT_SERVICE : 0U), 0, GetCmdSendToDepot(v)); + } break; case WID_VV_REFIT: // refit ShowVehicleRefitWindow(v, INVALID_VEH_ORDER_ID, this); @@ -3077,6 +3087,48 @@ public: } } + virtual void OnTimeout() + { + if (!this->depot_select_active) { + this->RaiseWidget(WID_VV_GOTO_DEPOT); + this->SetWidgetDirty(WID_VV_GOTO_DEPOT); + } + } + + virtual void OnPlaceObject(Point pt, TileIndex tile) + { + const Vehicle *v = Vehicle::Get(this->window_number); + if (IsDepotTile(tile) && GetDepotVehicleType(tile) == v->type && IsInfraTileUsageAllowed(v->type, v->owner, tile)) { + DoCommandP(v->tile, v->index | (this->depot_select_ctrl_pressed ? DEPOT_SERVICE : 0U) | DEPOT_SPECIFIC, tile, GetCmdSendToDepot(v)); + ResetObjectToPlace(); + this->RaiseButtons(); + } + } + + virtual void OnPlaceObjectAbort() + { + this->depot_select_active = false; + this->RaiseWidget(WID_VV_GOTO_DEPOT); + this->SetWidgetDirty(WID_VV_GOTO_DEPOT); + } + + virtual bool OnRightClick(Point pt, int widget) + { + if (widget == WID_VV_GOTO_DEPOT && _settings_client.gui.hover_delay_ms == 0) { + uint64 arg = STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP + Vehicle::Get(this->window_number)->type; + GuiShowTooltips(this, STR_VEHICLE_VIEW_SEND_TO_DEPOT_TOOLTIP_SHIFT, 1, &arg, TCC_RIGHT_CLICK); + } + return false; + } + + virtual void OnHover(Point pt, int widget) + { + if (widget == WID_VV_GOTO_DEPOT) { + uint64 arg = STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP + Vehicle::Get(this->window_number)->type; + GuiShowTooltips(this, STR_VEHICLE_VIEW_SEND_TO_DEPOT_TOOLTIP_SHIFT, 1, &arg, TCC_HOVER); + } + } + virtual void OnResize() { if (this->viewport != NULL) { diff --git a/src/vehicle_type.h b/src/vehicle_type.h index 312ebb598d..575dfef1cb 100644 --- a/src/vehicle_type.h +++ b/src/vehicle_type.h @@ -65,11 +65,12 @@ enum VehiclePathFinders { /** Flags to add to p1 for goto depot commands. */ enum DepotCommand { + DEPOT_SPECIFIC = (1U << 27), ///< Send vehicle to specific depot DEPOT_SERVICE = (1U << 28), ///< The vehicle will leave the depot right after arrival (serivce only) DEPOT_MASS_SEND = (1U << 29), ///< Tells that it's a mass send to depot command (type in VLW flag) DEPOT_DONT_CANCEL = (1U << 30), ///< Don't cancel current goto depot command if any DEPOT_LOCATE_HANGAR = (1U << 31), ///< Find another airport if the target one lacks a hangar - DEPOT_COMMAND_MASK = 0xFU << 28, + DEPOT_COMMAND_MASK = 0x1FU << 27, }; static const uint MAX_LENGTH_VEHICLE_NAME_CHARS = 32; ///< The maximum length of a vehicle name in characters including '\0'