Vehicle list commands now take into account cargo type filter

Start/stop
Send to depot type commands
Add to new group
Change order target
pull/453/head
Jonathan G Rennison 2 years ago
parent 728b902e9f
commit 03a9912a2b

@ -517,7 +517,8 @@ CommandCost CmdAlterGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
* @param tile unused
* @param flags type of operation
* @param p1 packed VehicleListIdentifier
* @param p2 unused
* @param p2 bitmask
* - bit 0-7 Cargo filter
* @param text the new name or an empty string when setting to the default
* @return the cost of this operation or an error
*/
@ -527,7 +528,7 @@ CommandCost CmdCreateGroupFromList(TileIndex tile, DoCommandFlag flags, uint32 p
VehicleList list;
if (!vli.UnpackIfValid(p1)) return CMD_ERROR;
if (!IsCompanyBuildableVehicleType(vli.vtype)) return CMD_ERROR;
if (!GenerateVehicleSortList(&list, vli)) return CMD_ERROR;
if (!GenerateVehicleSortList(&list, vli, GB(p2, 0, 8))) return CMD_ERROR;
CommandCost ret = DoCommand(tile, vli.vtype, INVALID_GROUP, flags, CMD_CREATE_GROUP);
if (ret.Failed()) return ret;

@ -881,7 +881,7 @@ public:
case WID_GL_START_ALL:
case WID_GL_STOP_ALL: { // Start/stop all vehicles of the list
DoCommandP(0, (1 << 1) | (widget == WID_GL_START_ALL ? (1 << 0) : 0), this->vli.Pack(), CMD_MASS_START_STOP);
DoCommandP(0, (1 << 1) | (widget == WID_GL_START_ALL ? (1 << 0) : 0) | (this->GetCargoFilter() << 8), this->vli.Pack(), CMD_MASS_START_STOP);
break;
}
@ -1005,7 +1005,7 @@ public:
std::string name = GenerateAutoNameForVehicleGroup(v);
DoCommandP(0, VehicleListIdentifier(_ctrl_pressed ? VL_SHARED_ORDERS : VL_SINGLE_VEH, v->type, v->owner, v->index).Pack(), 0, CMD_CREATE_GROUP_FROM_LIST | CMD_MSG(STR_ERROR_GROUP_CAN_T_CREATE), nullptr, name.c_str());
DoCommandP(0, VehicleListIdentifier(_ctrl_pressed ? VL_SHARED_ORDERS : VL_SINGLE_VEH, v->type, v->owner, v->index).Pack(), CF_ANY, CMD_CREATE_GROUP_FROM_LIST | CMD_MSG(STR_ERROR_GROUP_CAN_T_CREATE), nullptr, name.c_str());
break;
}
@ -1060,14 +1060,14 @@ public:
break;
case ADI_SERVICE: // Send for servicing
case ADI_DEPOT: { // Send to Depots
DoCommandP(0, DEPOT_MASS_SEND | (index == ADI_SERVICE ? DEPOT_SERVICE : 0U), this->vli.Pack(), GetCmdSendToDepot(this->vli.vtype));
DoCommandP(0, DEPOT_MASS_SEND | (index == ADI_SERVICE ? DEPOT_SERVICE : 0U) | this->GetCargoFilter(), this->vli.Pack(), GetCmdSendToDepot(this->vli.vtype));
break;
}
case ADI_DEPOT_SELL:
DoCommandP(0, DEPOT_MASS_SEND | DEPOT_SELL, this->vli.Pack(), GetCmdSendToDepot(this->vli.vtype));
DoCommandP(0, DEPOT_MASS_SEND | DEPOT_SELL | this->GetCargoFilter(), this->vli.Pack(), GetCmdSendToDepot(this->vli.vtype));
break;
case ADI_CANCEL_DEPOT:
DoCommandP(0, DEPOT_MASS_SEND | DEPOT_CANCEL, this->vli.Pack(), GetCmdSendToDepot(this->vli.vtype));
DoCommandP(0, DEPOT_MASS_SEND | DEPOT_CANCEL | this->GetCargoFilter(), this->vli.Pack(), GetCmdSendToDepot(this->vli.vtype));
break;
case ADI_ADD_SHARED: // Add shared Vehicles

@ -3508,6 +3508,7 @@ bool Order::CanLeaveWithCargo(bool has_cargo, CargoID cargo) const
* - p1 = (bit 0 - 15) - The destination ID to change from
* - p1 = (bit 16 - 18) - The vehicle type
* - p1 = (bit 20 - 23) - The order type
* - p1 = (bit 24 - 31) - Cargo filter
* @param p2 various bitstuffed elements
* - p2 = (bit 0 - 15) - The destination ID to change to
* @param text unused
@ -3518,11 +3519,12 @@ CommandCost CmdMassChangeOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, u
DestinationID from_dest = GB(p1, 0, 16);
VehicleType vehtype = Extract<VehicleType, 16, 3>(p1);
OrderType order_type = (OrderType) GB(p1, 20, 4);
CargoID cargo_filter = GB(p1, 24, 8);
DestinationID to_dest = GB(p2, 0, 16);
if (flags & DC_EXEC) {
for (Vehicle *v : Vehicle::Iterate()) {
if (v->type == vehtype && v->IsPrimaryVehicle() && CheckOwnership(v->owner).Succeeded()) {
if (v->type == vehtype && v->IsPrimaryVehicle() && CheckOwnership(v->owner).Succeeded() && VehicleCargoFilter(v, cargo_filter)) {
int index = 0;
bool changed = false;

@ -2971,7 +2971,7 @@ 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(), 0, CMD_CREATE_GROUP_FROM_LIST | CMD_MSG(STR_ERROR_GROUP_CAN_T_CREATE), nullptr, str);
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);
}
}

@ -1146,7 +1146,7 @@ struct TimetableWindow : GeneralVehicleWindow {
}
case WID_VT_ADD_VEH_GROUP: {
DoCommandP(0, VehicleListIdentifier(VL_SINGLE_VEH, v->type, v->owner, v->index).Pack(), 0, CMD_CREATE_GROUP_FROM_LIST | CMD_MSG(STR_ERROR_GROUP_CAN_T_CREATE), nullptr, str);
DoCommandP(0, VehicleListIdentifier(VL_SINGLE_VEH, v->type, v->owner, v->index).Pack(), CF_ANY, CMD_CREATE_GROUP_FROM_LIST | CMD_MSG(STR_ERROR_GROUP_CAN_T_CREATE), nullptr, str);
break;
}
}

@ -704,6 +704,7 @@ CommandCost CmdStartStopVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1,
* @param p1 bitmask
* - bit 0 set = start vehicles, unset = stop vehicles
* - bit 1 if set, then it's a vehicle list window, not a depot and Tile is ignored in this case
* - bit 8-15 Cargo filter
* @param p2 packed VehicleListIdentifier
* @param text unused
* @return the cost of this operation or an error
@ -719,7 +720,7 @@ CommandCost CmdMassStartStopVehicle(TileIndex tile, DoCommandFlag flags, uint32
if (!IsCompanyBuildableVehicleType(vli.vtype)) return CMD_ERROR;
if (vehicle_list_window) {
if (!GenerateVehicleSortList(&list, vli)) return CMD_ERROR;
if (!GenerateVehicleSortList(&list, vli, GB(p1, 8, 8))) return CMD_ERROR;
} else {
if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_company)) return CMD_ERROR;
/* Get the list of vehicles in the depot */
@ -1657,11 +1658,11 @@ CommandCost CmdCloneVehicleFromTemplate(TileIndex tile, DoCommandFlag flags, uin
* @param vli identifier of the vehicle list
* @return 0 for success and CMD_ERROR if no vehicle is able to go to depot
*/
static CommandCost SendAllVehiclesToDepot(DoCommandFlag flags, DepotCommand depot_flags, const VehicleListIdentifier &vli)
static CommandCost SendAllVehiclesToDepot(DoCommandFlag flags, DepotCommand depot_flags, const VehicleListIdentifier &vli, const CargoID cid)
{
VehicleList list;
if (!GenerateVehicleSortList(&list, vli)) return CMD_ERROR;
if (!GenerateVehicleSortList(&list, vli, cid)) return CMD_ERROR;
/* Send all the vehicles to a depot */
bool had_success = false;
@ -1688,7 +1689,8 @@ static CommandCost SendAllVehiclesToDepot(DoCommandFlag flags, DepotCommand depo
* @param tile unused
* @param flags for command type
* @param p1 bitmask
* - p1 0-20: bitvehicle ID to send to the depot
* - p1 0-19: bitvehicle ID to send to the depot
* - p1 0- 7: cargo filter for DEPOT_MASS_SEND mode
* - p1 bits 27-31 - DEPOT_ flags (see vehicle_type.h)
* @param p2 packed VehicleListIdentifier, or specific depot tile
* @param text unused
@ -1702,7 +1704,7 @@ CommandCost CmdSendVehicleToDepot(TileIndex tile, DoCommandFlag flags, uint32 p1
if (!vli.UnpackIfValid(p2)) return CMD_ERROR;
uint32 depot_flags = (p1 & (DEPOT_SERVICE | DEPOT_CANCEL | DEPOT_SELL));
if (!(p1 & DEPOT_CANCEL)) depot_flags |= DEPOT_DONT_CANCEL;
return SendAllVehiclesToDepot(flags, (DepotCommand) depot_flags, vli);
return SendAllVehiclesToDepot(flags, (DepotCommand) depot_flags, vli, GB(p1, 0, 8));
}
Vehicle *v = Vehicle::GetIfValid(GB(p1, 0, 20));

@ -274,45 +274,11 @@ void BaseVehicleListWindow::BuildVehicleList()
this->vscroll->SetCount(static_cast<int>(this->vehgroups.size()));
}
/** Cargo filter functions */
static bool CargoFilter(const Vehicle * const *vid, const CargoID cid)
{
if (cid == BaseVehicleListWindow::CF_ANY) {
return true;
} else if (cid == BaseVehicleListWindow::CF_NONE) {
for (const Vehicle *w = (*vid); w != nullptr; w = w->Next()) {
if (w->cargo_cap > 0) {
return false;
}
}
return true;
} else if (cid == BaseVehicleListWindow::CF_FREIGHT) {
bool have_capacity = false;
for (const Vehicle *w = (*vid); w != nullptr; w = w->Next()) {
if (w->cargo_cap) {
if (IsCargoInClass(w->cargo_type, CC_PASSENGERS)) {
return false;
} else {
have_capacity = true;
}
}
}
return have_capacity;
} else {
for (const Vehicle *w = (*vid); w != nullptr; w = w->Next()) {
if (w->cargo_cap > 0 && w->cargo_type == cid) {
return true;
}
}
return false;
}
}
static bool GroupCargoFilter(const GUIVehicleGroup* group, const CargoID cid)
{
if (cid == BaseVehicleListWindow::CF_ANY) return true;
if (cid == CF_ANY) return true;
for (VehicleList::const_iterator v = group->vehicles_begin; v != group->vehicles_end; ++v) {
if (CargoFilter(&(*v), cid)) return true;
if (VehicleCargoFilter(*v, cid)) return true;
}
return false;
}
@ -2413,7 +2379,7 @@ public:
case WID_VL_STOP_ALL:
case WID_VL_START_ALL:
DoCommandP(0, (1 << 1) | (widget == WID_VL_START_ALL ? (1 << 0) : 0), this->window_number, CMD_MASS_START_STOP);
DoCommandP(0, (1 << 1) | (widget == WID_VL_START_ALL ? (1 << 0) : 0) | (this->GetCargoFilter() << 8), this->window_number, CMD_MASS_START_STOP);
break;
}
}
@ -2446,14 +2412,14 @@ public:
break;
case ADI_SERVICE: // Send for servicing
case ADI_DEPOT: // Send to Depots
DoCommandP(0, DEPOT_MASS_SEND | (index == ADI_SERVICE ? DEPOT_SERVICE : (DepotCommand)0), this->window_number, GetCmdSendToDepot(this->vli.vtype));
DoCommandP(0, DEPOT_MASS_SEND | (index == ADI_SERVICE ? DEPOT_SERVICE : (DepotCommand)0) | this->GetCargoFilter(), this->window_number, GetCmdSendToDepot(this->vli.vtype));
break;
case ADI_CANCEL_DEPOT:
DoCommandP(0, DEPOT_MASS_SEND | DEPOT_CANCEL, this->window_number, GetCmdSendToDepot(this->vli.vtype));
DoCommandP(0, DEPOT_MASS_SEND | DEPOT_CANCEL | this->GetCargoFilter(), this->window_number, GetCmdSendToDepot(this->vli.vtype));
break;
case ADI_DEPOT_SELL:
DoCommandP(0, DEPOT_MASS_SEND | DEPOT_SELL, this->window_number, GetCmdSendToDepot(this->vli.vtype));
DoCommandP(0, DEPOT_MASS_SEND | DEPOT_SELL | this->GetCargoFilter(), this->window_number, GetCmdSendToDepot(this->vli.vtype));
break;
case ADI_CHANGE_ORDER:
@ -2487,7 +2453,7 @@ public:
void OnQueryTextFinished(char *str) override
{
DoCommandP(0, this->window_number, 0, CMD_CREATE_GROUP_FROM_LIST | CMD_MSG(STR_ERROR_GROUP_CAN_T_CREATE), nullptr, str);
DoCommandP(0, this->window_number, this->GetCargoFilter(), CMD_CREATE_GROUP_FROM_LIST | CMD_MSG(STR_ERROR_GROUP_CAN_T_CREATE), nullptr, str);
}
virtual void OnPlaceObject(Point pt, TileIndex tile) override
@ -2499,7 +2465,7 @@ public:
if (this->vli.vtype == VEH_ROAD && GetPresentRoadTramTypes(Depot::Get(this->vli.index)->xy) != GetPresentRoadTramTypes(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);
DoCommandP(0, this->vli.index | (this->vli.vtype << 16) | (OT_GOTO_DEPOT << 20) | (this->GetCargoFilter() << 24), dest, CMD_MASS_CHANGE_ORDER);
ResetObjectToPlace();
return;
}
@ -2510,7 +2476,7 @@ public:
|| (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);
DoCommandP(0, this->vli.index | (this->vli.vtype << 16) | (OT_GOTO_WAYPOINT << 20) | (this->GetCargoFilter() << 24), GetStationIndex(tile), CMD_MASS_CHANGE_ORDER);
ResetObjectToPlace();
return;
}
@ -2528,7 +2494,7 @@ public:
(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);
DoCommandP(0, this->vli.index | (this->vli.vtype << 16) | (OT_GOTO_STATION << 20) | (this->GetCargoFilter() << 24), GetStationIndex(tile), CMD_MASS_CHANGE_ORDER);
ResetObjectToPlace();
return;
}

@ -92,17 +92,12 @@ public:
typedef GUIVehicleGroupList::SortFunction VehicleGroupSortFunction;
typedef GUIVehicleList::SortFunction VehicleIndividualSortFunction;
/** Special cargo filter criteria */
enum CargoFilterSpecialType {
CF_ANY = CT_NO_REFIT, ///< Show all vehicles independent of carried cargo (i.e. no filtering)
CF_NONE = CT_INVALID, ///< Show only vehicles which do not carry cargo (e.g. train engines)
CF_FREIGHT = CT_AUTO_REFIT, ///< Show only vehicles which carry any freight (non-passenger) cargo
};
CargoID cargo_filter[NUM_CARGO + 3]; ///< Available cargo filters; CargoID or CF_ANY or CF_NONE
StringID cargo_filter_texts[NUM_CARGO + 4]; ///< Texts for filter_cargo, terminated by INVALID_STRING_ID
byte cargo_filter_criteria; ///< Selected cargo filter
inline CargoID GetCargoFilter() const { return this->cargo_filter[this->cargo_filter_criteria]; }
enum ActionDropdownItem {
ADI_TEMPLATE_REPLACE,
ADI_REPLACE,

@ -106,20 +106,58 @@ void BuildDepotVehicleList(VehicleType type, TileIndex tile, VehicleList *engine
if (wagons != nullptr && wagons != engines) wagons->shrink_to_fit();
}
/** Cargo filter functions */
bool VehicleCargoFilter(const Vehicle *v, const CargoID cid)
{
if (cid == CF_ANY) {
return true;
} else if (cid == CF_NONE) {
for (const Vehicle *w = v; w != nullptr; w = w->Next()) {
if (w->cargo_cap > 0) {
return false;
}
}
return true;
} else if (cid == CF_FREIGHT) {
bool have_capacity = false;
for (const Vehicle *w = v; w != nullptr; w = w->Next()) {
if (w->cargo_cap) {
if (IsCargoInClass(w->cargo_type, CC_PASSENGERS)) {
return false;
} else {
have_capacity = true;
}
}
}
return have_capacity;
} else {
for (const Vehicle *w = v; w != nullptr; w = w->Next()) {
if (w->cargo_cap > 0 && w->cargo_type == cid) {
return true;
}
}
return false;
}
}
/**
* Generate a list of vehicles based on window type.
* @param list Pointer to list to add vehicles to
* @param vli The identifier of this vehicle list.
* @return false if invalid list is requested
*/
bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli)
bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli, const CargoID cid)
{
list->clear();
auto add_veh = [&](const Vehicle *v) {
if (cid == CF_ANY || VehicleCargoFilter(v, cid)) list->push_back(v);
};
auto fill_all_vehicles = [&]() {
for (const Vehicle *v : Vehicle::Iterate()) {
if (!HasBit(v->subtype, GVSF_VIRTUAL) && v->type == vli.vtype && v->owner == vli.company && v->IsPrimaryVehicle()) {
list->push_back(v);
add_veh(v);
}
}
};
@ -131,7 +169,7 @@ bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli
for (const Order *order : v->Orders()) {
if ((order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT) || order->IsType(OT_IMPLICIT))
&& order->GetDestination() == vli.index) {
list->push_back(v);
add_veh(v);
break;
}
}
@ -145,7 +183,7 @@ bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli
if (v == nullptr || v->type != vli.vtype || !v->IsPrimaryVehicle()) return false;
for (; v != nullptr; v = v->NextShared()) {
list->push_back(v);
add_veh(v);
}
break;
}
@ -155,7 +193,7 @@ bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli
for (const Vehicle *v : Vehicle::Iterate()) {
if (!HasBit(v->subtype, GVSF_VIRTUAL) && v->type == vli.vtype && v->IsPrimaryVehicle() &&
v->owner == vli.company && GroupIsInGroup(v->group_id, vli.index)) {
list->push_back(v);
add_veh(v);
}
}
break;
@ -172,7 +210,7 @@ bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli
if (v->type == vli.vtype && v->IsPrimaryVehicle()) {
for (const Order *order : v->Orders()) {
if (order->IsType(OT_GOTO_DEPOT) && !(order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) && order->GetDestination() == vli.index) {
list->push_back(v);
add_veh(v);
break;
}
}
@ -187,7 +225,7 @@ bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli
const TraceRestrictSlot *slot = TraceRestrictSlot::GetIfValid(vli.index);
if (slot == nullptr) return false;
for (VehicleID id : slot->occupants) {
list->push_back(Vehicle::Get(id));
add_veh(Vehicle::Get(id));
}
}
break;
@ -195,7 +233,7 @@ bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli
case VL_SINGLE_VEH: {
const Vehicle *v = Vehicle::GetIfValid(vli.index);
if (v != nullptr) list->push_back(v);
if (v != nullptr) add_veh(v);
break;
}

@ -14,6 +14,7 @@
#include "vehicle_type.h"
#include "company_type.h"
#include "tile_type.h"
#include "cargo_type.h"
/** Vehicle List type flags */
enum VehicleListType {
@ -51,10 +52,18 @@ struct VehicleListIdentifier {
VehicleListIdentifier() : type(), vtype(), company(), index() {}
};
/** Special cargo filter criteria */
enum VehicleCargoFilterSpecialType {
CF_ANY = CT_NO_REFIT, ///< Show all vehicles independent of carried cargo (i.e. no filtering)
CF_NONE = CT_INVALID, ///< Show only vehicles which do not carry cargo (e.g. train engines)
CF_FREIGHT = CT_AUTO_REFIT, ///< Show only vehicles which carry any freight (non-passenger) cargo
};
/** A list of vehicles. */
typedef std::vector<const Vehicle *> VehicleList;
bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &identifier);
bool VehicleCargoFilter(const Vehicle *v, const CargoID cid);
bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &identifier, const CargoID cid = CF_ANY);
void BuildDepotVehicleList(VehicleType type, TileIndex tile, VehicleList *engine_list, VehicleList *wagon_list, bool individual_wagons = false);
uint GetUnitNumberDigits(VehicleList &vehicles);

Loading…
Cancel
Save