diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -510,6 +510,7 @@ add_files(
vehiclelist.cpp
vehiclelist.h
vehiclelist_cmd.h
+ vehiclelist_func.h
viewport.cpp
viewport_cmd.h
viewport_func.h
diff --git a/src/script/api/script_vehiclelist.cpp b/src/script/api/script_vehiclelist.cpp
--- a/src/script/api/script_vehiclelist.cpp
+++ b/src/script/api/script_vehiclelist.cpp
@@ -14,6 +14,7 @@
#include "script_station.hpp"
#include "../../depot_map.h"
#include "../../vehicle_base.h"
+#include "../../vehiclelist_func.h"
#include "../../train.h"
#include "../../core/backup_type.hpp"
#include <../squirrel/sqvm.h>
@@ -111,16 +112,12 @@ ScriptVehicleList_Station::ScriptVehicle
bool is_deity = ScriptCompanyMode::IsDeity();
CompanyID owner = ScriptObject::GetCompany();
- for (const Vehicle *v : Vehicle::Iterate()) {
- if ((v->owner == owner || is_deity) && v->IsPrimaryVehicle()) {
- for (const Order *order : v->Orders()) {
- if ((order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT)) && order->GetDestination() == station_id) {
- this->AddItem(v->index);
- break;
- }
- }
- }
- }
+
+ FindVehiclesWithOrder(
+ [is_deity, owner](const Vehicle *v) { return is_deity || v->owner == owner; },
+ [station_id](const Order *order) { return (order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT)) && order->GetDestination() == station_id; },
+ [this](const Vehicle *v) { this->AddItem(v->index); }
+ );
}
ScriptVehicleList_Depot::ScriptVehicleList_Depot(TileIndex tile)
@@ -162,16 +159,12 @@ ScriptVehicleList_Depot::ScriptVehicleLi
bool is_deity = ScriptCompanyMode::IsDeity();
CompanyID owner = ScriptObject::GetCompany();
- for (const Vehicle *v : Vehicle::Iterate()) {
- if ((v->owner == owner || is_deity) && v->IsPrimaryVehicle() && v->type == type) {
- for (const Order *order : v->Orders()) {
- if (order->IsType(OT_GOTO_DEPOT) && order->GetDestination() == dest) {
- this->AddItem(v->index);
- break;
- }
- }
- }
- }
+
+ FindVehiclesWithOrder(
+ [is_deity, owner, type](const Vehicle *v) { return (is_deity || v->owner == owner) && v->type == type; },
+ [dest](const Order *order) { return order->IsType(OT_GOTO_DEPOT) && order->GetDestination() == dest; },
+ [this](const Vehicle *v) { this->AddItem(v->index); }
+ );
}
ScriptVehicleList_SharedOrders::ScriptVehicleList_SharedOrders(VehicleID vehicle_id)
diff --git a/src/vehiclelist.cpp b/src/vehiclelist.cpp
--- a/src/vehiclelist.cpp
+++ b/src/vehiclelist.cpp
@@ -10,6 +10,7 @@
#include "stdafx.h"
#include "train.h"
#include "vehiclelist.h"
+#include "vehiclelist_func.h"
#include "group.h"
#include "safeguards.h"
@@ -116,17 +117,11 @@ bool GenerateVehicleSortList(VehicleList
switch (vli.type) {
case VL_STATION_LIST:
- for (const Vehicle *v : Vehicle::Iterate()) {
- if (v->type == vli.vtype && v->IsPrimaryVehicle()) {
- 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);
- break;
- }
- }
- }
- }
+ FindVehiclesWithOrder(
+ [&vli](const Vehicle *v) { return v->type == vli.vtype; },
+ [&vli](const Order *order) { return (order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT) || order->IsType(OT_IMPLICIT)) && order->GetDestination() == vli.index; },
+ [&list](const Vehicle *v) { list->push_back(v); }
+ );
break;
case VL_SHARED_ORDERS: {
@@ -161,16 +156,11 @@ bool GenerateVehicleSortList(VehicleList
break;
case VL_DEPOT_LIST:
- for (const Vehicle *v : Vehicle::Iterate()) {
- 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);
- break;
- }
- }
- }
- }
+ FindVehiclesWithOrder(
+ [&vli](const Vehicle *v) { return v->type == vli.vtype; },
+ [&vli](const Order *order) { return order->IsType(OT_GOTO_DEPOT) && !(order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) && order->GetDestination() == vli.index; },
+ [&list](const Vehicle *v) { list->push_back(v); }
+ );
break;
default: return false;
diff --git a/src/vehiclelist_func.h b/src/vehiclelist_func.h
new file mode 100644
--- /dev/null
+++ b/src/vehiclelist_func.h
@@ -0,0 +1,46 @@
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see .
+ */
+
+/** @file vehiclelist_func.h Functions and type for generating vehicle lists. */
+
+#ifndef VEHICLELIST_FUNC_H
+#define VEHICLELIST_FUNC_H
+
+#include "order_base.h"
+#include "vehicle_base.h"
+
+/**
+ * Find vehicles matching an order.
+ * This can be used, e.g. to find all vehicles that stop at a particular station.
+ * @param veh_pred Vehicle selection predicate. This is called only for the first vehicle using the order list.
+ * @param ord_pred Order selection predicate.
+ * @param veh_func Called for each vehicle that matches both vehicle and order predicates.
+ **/
+template
+void FindVehiclesWithOrder(VehiclePredicate veh_pred, OrderPredicate ord_pred, VehicleFunc veh_func)
+{
+ for (const OrderList *orderlist : OrderList::Iterate()) {
+
+ /* We assume all vehicles sharing an order list match the condition. */
+ const Vehicle *v = orderlist->GetFirstSharedVehicle();
+ if (!veh_pred(v)) continue;
+
+ /* Vehicle is a candidate, search for a matching order. */
+ for (const Order *order = orderlist->GetFirstOrder(); order != nullptr; order = order->next) {
+
+ if (!ord_pred(order)) continue;
+
+ /* An order matches, we can add all shared vehicles to the list. */
+ for (; v != nullptr; v = v->NextShared()) {
+ veh_func(v);
+ }
+ break;
+ }
+ }
+}
+
+#endif /* VEHICLELIST_FUNC_H */