diff --git a/src/command.cpp b/src/command.cpp index a0c3da57db..c746692b3c 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -95,6 +95,7 @@ CommandProc CmdModifyOrder; CommandProc CmdSkipToOrder; CommandProc CmdDeleteOrder; CommandProc CmdInsertOrder; +CommandProc CmdMassChangeOrder; CommandProc CmdChangeServiceInt; CommandProc CmdBuildIndustry; @@ -273,6 +274,7 @@ static const Command _command_proc_table[] = { DEF_CMD(CmdSkipToOrder, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SKIP_TO_ORDER DEF_CMD(CmdDeleteOrder, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_DELETE_ORDER DEF_CMD(CmdInsertOrder, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_INSERT_ORDER + DEF_CMD(CmdMassChangeOrder, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_MASS_CHANGE_ORDER DEF_CMD(CmdChangeServiceInt, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_CHANGE_SERVICE_INT diff --git a/src/command_type.h b/src/command_type.h index 75e4d26bc0..e583e3616b 100644 --- a/src/command_type.h +++ b/src/command_type.h @@ -228,6 +228,7 @@ enum Commands { CMD_SKIP_TO_ORDER, ///< skip an order to the next of specific one CMD_DELETE_ORDER, ///< delete an order CMD_INSERT_ORDER, ///< insert a new order + CMD_MASS_CHANGE_ORDER, ///< mass change the target of an order CMD_CHANGE_SERVICE_INT, ///< change the server interval of a vehicle diff --git a/src/lang/english.txt b/src/lang/english.txt index bdb8a4614c..ec801303f8 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -3781,6 +3781,13 @@ STR_VEHICLE_LIST_MASS_START_LIST_TOOLTIP :{BLACK}Click to STR_VEHICLE_LIST_SHARED_ORDERS_LIST_CAPTION :{WHITE}Shared orders of {COMMA} Vehicle{P "" s} +STR_VEHICLE_LIST_CHANGE_ORDER_STATION :Move order to another station +STR_VEHICLE_LIST_CHANGE_ORDER_WAYPOINT :Move order to another waypoint +STR_VEHICLE_LIST_CHANGE_ORDER_TRAIN_DEPOT :Move order to another depot +STR_VEHICLE_LIST_CHANGE_ORDER_ROAD_VEHICLE_DEPOT :Move order to another depot +STR_VEHICLE_LIST_CHANGE_ORDER_SHIP_DEPOT :Move order to another depot +STR_VEHICLE_LIST_CHANGE_ORDER_AIRCRAFT_HANGAR :Move order to another hangar + # Group window STR_GROUP_ALL_TRAINS :All trains STR_GROUP_ALL_ROAD_VEHICLES :All road vehicles diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 7809af4968..ab73aeb0b3 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -752,7 +752,7 @@ uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int * @param flags operation to perform * @param p1 various bitstuffed elements * - p1 = (bit 0 - 19) - ID of the vehicle - * - p1 = (bit 24 - 31) - the selected order (if any). If the last order is given, + * - p1 = (bit 20 - 27) - the selected order (if any). If the last order is given, * the order will be inserted before that one * the maximum vehicle order id is 254. * @param p2 packed order to insert @@ -2468,3 +2468,57 @@ bool Order::CanLeaveWithCargo(bool has_cargo) const return (this->GetLoadType() & OLFB_NO_LOAD) == 0 || (has_cargo && (this->GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == 0); } + +/** + * Mass change the target of an order. + * This implemented by adding a new order and if that succeeds deleting the previous one. + * @param tile unused + * @param flags operation to perform + * @param p1 various bitstuffed elements + * - p1 = (bit 0 - 15) - The destination ID to change from + * - p1 = (bit 16 - 18) - The vehicle type + * - p1 = (bit 20 - 23) - The order type + * @param p2 various bitstuffed elements + * - p2 = (bit 0 - 15) - The destination ID to change to + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdMassChangeOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + DestinationID from_dest = GB(p1, 0, 16); + VehicleType vehtype = Extract(p1); + OrderType order_type = (OrderType) GB(p1, 20, 4); + DestinationID to_dest = GB(p2, 0, 16); + + if (flags & DC_EXEC) { + Vehicle *v; + FOR_ALL_VEHICLES(v) { + if (v->type == vehtype && v->IsPrimaryVehicle() && CheckOwnership(v->owner).Succeeded()) { + Order *order; + int index = 0; + + FOR_VEHICLE_ORDERS(v, order) { + if (order->GetDestination() == from_dest && order->IsType(order_type) && + !(order_type == OT_GOTO_DEPOT && order->GetDepotActionType() & ODATFB_NEAREST_DEPOT)) { + Order new_order; + new_order.AssignOrder(*order); + new_order.SetDestination(to_dest); + new_order.SetWaitTimetabled(false); + new_order.SetTravelTimetabled(false); + if (DoCommand(0, v->index | ((index + 1) << 20), new_order.Pack(), flags, CMD_INSERT_ORDER).Succeeded()) { + DoCommand(0, v->index, index, flags, CMD_DELETE_ORDER); + + order = v->orders.list->GetOrderAt(index); + order->SetRefit(new_order.GetRefitCargo()); + order->SetMaxSpeed(new_order.GetMaxSpeed()); + } + + new_order.Free(); + } + index++; + } + } + } + } + return CommandCost(); +} diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 46ded2240e..e930a8abf1 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -150,7 +150,7 @@ void BaseVehicleListWindow::BuildVehicleList() * @param show_group If true include group-related stuff. * @return Required size. */ -Dimension BaseVehicleListWindow::GetActionDropdownSize(bool show_autoreplace, bool show_group) +Dimension BaseVehicleListWindow::GetActionDropdownSize(bool show_autoreplace, bool show_group, StringID change_order_str) { Dimension d = {0, 0}; @@ -163,6 +163,10 @@ Dimension BaseVehicleListWindow::GetActionDropdownSize(bool show_autoreplace, bo d = maxdim(d, GetStringBoundingBox(STR_GROUP_REMOVE_ALL_VEHICLES)); } + if (change_order_str != 0) { + d = maxdim(d, GetStringBoundingBox(change_order_str)); + } + return d; } @@ -172,7 +176,7 @@ Dimension BaseVehicleListWindow::GetActionDropdownSize(bool show_autoreplace, bo * @param show_group If true include group-related stuff. * @return Itemlist for dropdown */ -DropDownList *BaseVehicleListWindow::BuildActionDropdownList(bool show_autoreplace, bool show_group) +DropDownList *BaseVehicleListWindow::BuildActionDropdownList(bool show_autoreplace, bool show_group, StringID change_order_str) { DropDownList *list = new DropDownList(); @@ -184,6 +188,9 @@ DropDownList *BaseVehicleListWindow::BuildActionDropdownList(bool show_autorepla *list->Append() = new DropDownListStringItem(STR_GROUP_ADD_SHARED_VEHICLE, ADI_ADD_SHARED, false); *list->Append() = new DropDownListStringItem(STR_GROUP_REMOVE_ALL_VEHICLES, ADI_REMOVE_ALL, false); } + if (change_order_str != 0) { + *list->Append() = new DropDownListStringItem(change_order_str, ADI_CHANGE_ORDER, false); + } return list; } @@ -1526,6 +1533,17 @@ private: BP_HIDE_BUTTONS, ///< Show the empty panel. }; + StringID GetChangeOrderStringID() const + { + if (VehicleListIdentifier(this->window_number).type == VL_STATION_LIST) { + return (Station::Get(this->vli.index)->facilities & FACIL_WAYPOINT) ? STR_VEHICLE_LIST_CHANGE_ORDER_WAYPOINT : STR_VEHICLE_LIST_CHANGE_ORDER_STATION; + } else if (VehicleListIdentifier(this->window_number).type == VL_DEPOT_LIST) { + return STR_VEHICLE_LIST_CHANGE_ORDER_TRAIN_DEPOT + this->vli.vtype; + } else { + return 0; + } + } + public: VehicleListWindow(WindowDesc *desc, WindowNumber window_number) : BaseVehicleListWindow(desc, window_number) { @@ -1596,7 +1614,7 @@ public: } case WID_VL_MANAGE_VEHICLES_DROPDOWN: { - Dimension d = this->GetActionDropdownSize(this->vli.type == VL_STANDARD, false); + Dimension d = this->GetActionDropdownSize(this->vli.type == VL_STANDARD, false, this->GetChangeOrderStringID()); d.height += padding.height; d.width += padding.width; *size = maxdim(*size, d); @@ -1721,7 +1739,8 @@ public: break; case WID_VL_MANAGE_VEHICLES_DROPDOWN: { - DropDownList *list = this->BuildActionDropdownList(VehicleListIdentifier(this->window_number).type == VL_STANDARD, false); + DropDownList *list = this->BuildActionDropdownList(VehicleListIdentifier(this->window_number).type == VL_STANDARD, false, + this->GetChangeOrderStringID()); ShowDropDownList(this, list, 0, WID_VL_MANAGE_VEHICLES_DROPDOWN); break; } @@ -1751,6 +1770,10 @@ public: DoCommandP(0, DEPOT_MASS_SEND | (index == ADI_SERVICE ? DEPOT_SERVICE : (DepotCommand)0), this->window_number, GetCmdSendToDepot(this->vli.vtype)); break; + case ADI_CHANGE_ORDER: + SetObjectToPlaceWnd(ANIMCURSOR_PICKSTATION, PAL_NONE, HT_RECT, this); + break; + default: NOT_REACHED(); } break; @@ -1759,6 +1782,49 @@ public: this->SetDirty(); } + virtual void OnPlaceObject(Point pt, TileIndex tile) + { + /* check depot first */ + if (IsDepotTile(tile) && GetDepotVehicleType(tile) == this->vli.vtype) { + if (this->vli.type != VL_DEPOT_LIST) return; + if (!IsInfraTileUsageAllowed(this->vli.vtype, this->vli.company, tile)) return; + + DestinationID dest = (this->vli.vtype == VEH_AIRCRAFT) ? GetStationIndex(tile) : GetDepotIndex(tile); + DoCommandP(0, this->vli.index | (this->vli.vtype << 16) | (OT_GOTO_DEPOT << 20), dest, CMD_MASS_CHANGE_ORDER); + ResetObjectToPlace(); + return; + } + + /* check rail waypoint or buoy (no ownership) */ + if ((IsRailWaypointTile(tile) && this->vli.vtype == VEH_TRAIN && !IsInfraTileUsageAllowed(VEH_TRAIN, this->vli.company, tile)) + || (IsBuoyTile(tile) && this->vli.vtype == VEH_SHIP)) { + if (this->vli.type != VL_STATION_LIST) return; + if (!(Station::Get(this->vli.index)->facilities & FACIL_WAYPOINT)) return; + DoCommandP(0, this->vli.index | (this->vli.vtype << 16) | (OT_GOTO_WAYPOINT << 20), GetStationIndex(tile), CMD_MASS_CHANGE_ORDER); + ResetObjectToPlace(); + return; + } + + if (IsTileType(tile, MP_STATION)) { + if (this->vli.type != VL_STATION_LIST) return; + if (Station::Get(this->vli.index)->facilities & FACIL_WAYPOINT) return; + + StationID st_index = GetStationIndex(tile); + const Station *st = Station::Get(st_index); + + if (!IsInfraUsageAllowed(this->vli.vtype, this->vli.company, st->owner)) return; + + if ((this->vli.vtype == VEH_SHIP && st->facilities & FACIL_DOCK) || + (this->vli.vtype == VEH_TRAIN && st->facilities & FACIL_TRAIN) || + (this->vli.vtype == VEH_AIRCRAFT && st->facilities & FACIL_AIRPORT) || + (this->vli.vtype == VEH_ROAD && st->facilities & (FACIL_BUS_STOP | FACIL_TRUCK_STOP))) { + DoCommandP(0, this->vli.index | (this->vli.vtype << 16) | (OT_GOTO_STATION << 20), GetStationIndex(tile), CMD_MASS_CHANGE_ORDER); + ResetObjectToPlace(); + return; + } + } + } + virtual void OnTick() { if (_pause_mode != PM_UNPAUSED) return; diff --git a/src/vehicle_gui_base.h b/src/vehicle_gui_base.h index 1c03f7b34d..db87db2d01 100644 --- a/src/vehicle_gui_base.h +++ b/src/vehicle_gui_base.h @@ -32,6 +32,7 @@ struct BaseVehicleListWindow : public Window { ADI_DEPOT, ADI_ADD_SHARED, ADI_REMOVE_ALL, + ADI_CHANGE_ORDER, }; static const StringID vehicle_depot_name[]; @@ -46,8 +47,8 @@ struct BaseVehicleListWindow : public Window { void DrawVehicleListItems(VehicleID selected_vehicle, int line_height, const Rect &r) const; void SortVehicleList(); void BuildVehicleList(); - Dimension GetActionDropdownSize(bool show_autoreplace, bool show_group); - DropDownList *BuildActionDropdownList(bool show_autoreplace, bool show_group); + Dimension GetActionDropdownSize(bool show_autoreplace, bool show_group, StringID change_order_str = 0); + DropDownList *BuildActionDropdownList(bool show_autoreplace, bool show_group, StringID change_order_str = 0); }; uint GetVehicleListHeight(VehicleType type, uint divisor = 1);