@@ -1811,16 +1811,23 @@ function Regression::Vehicle()
print(" SellVehicle(): " + AIVehicle.SellVehicle(12));
print(" GetLastErrorString(): " + AIError.GetLastErrorString());
print(" SendVehicleToDepot(): " + AIVehicle.SendVehicleToDepot(13));
local list = AIVehicleList();
local in_depot = AIVehicleList(AIVehicle.IsInDepot);
local IsType = function(vehicle_id, type) {
return AIVehicle.GetVehicleType(vehicle_id) == type;
}
local rv_list = AIVehicleList(IsType, AIVehicle.VT_ROAD);
print("");
print("--VehicleList--");
print(" Count(): " + list.Count());
print(" InDepot Count(): " + in_depot.Count());
print(" RoadVehicle Count(): " + rv_list.Count());
list.Valuate(AIVehicle.GetLocation);
print(" Location ListDump:");
for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) {
print(" " + i + " => " + list.GetValue(i));
list.Valuate(AIVehicle.GetEngineType);
@@ -9388,12 +9388,14 @@ ERROR: IsEnd() is invalid as Begin() is
GetLastErrorString(): ERR_VEHICLE_NOT_IN_DEPOT
SendVehicleToDepot(): false
GetLastErrorString(): ERR_UNKNOWN
--VehicleList--
Count(): 5
InDepot Count(): 4
RoadVehicle Count(): 2
Location ListDump:
13 => 33417
12 => 33417
14 => 32119
16 => 28479
17 => 10008
@@ -21,12 +21,15 @@
* \li AITown::ROAD_LAYOUT_RANDOM
* \li AIVehicle::IsPrimaryVehicle
*
* API removals:
* \li AIError::ERR_PRECONDITION_TOO_MANY_PARAMETERS, that error is never returned anymore.
* Other changes:
* \li AIVehicleList accepts an optional filter function
* \b 13.0
* API additions:
* \li AICargo::GetWeight
* \li AIIndustryType::ResolveNewGRFID
* \li AIObjectType::ResolveNewGRFID
@@ -81,12 +81,15 @@
* \li GSIndustry::GetProductionLevel
* \li GSIndustry::SetProductionLevel
* \li GSError::ERR_PRECONDITION_TOO_MANY_PARAMETERS, that error is never returned anymore.
* \li GSVehicleList accepts an optional filter function
* \li GSCargo::GetWeight
* \li GSIndustryType::ResolveNewGRFID
* \li GSObjectType::ResolveNewGRFID
@@ -15,18 +15,84 @@
#include "../../depot_map.h"
#include "../../vehicle_base.h"
#include "../../train.h"
#include "../../safeguards.h"
ScriptVehicleList::ScriptVehicleList()
ScriptVehicleList::ScriptVehicleList(HSQUIRRELVM vm)
{
EnforceDeityOrCompanyModeValid_Void();
int nparam = sq_gettop(vm) - 1;
if (nparam >= 1) {
/* Make sure the filter function is really a function, and not any
* other type. It's parameter 2 for us, but for the user it's the
* first parameter they give. */
SQObjectType valuator_type = sq_gettype(vm, 2);
if (valuator_type != OT_CLOSURE && valuator_type != OT_NATIVECLOSURE) {
throw sq_throwerror(vm, "parameter 1 has an invalid type (expected function)");
/* Push the function to call */
sq_push(vm, 2);
/* Don't allow docommand from a Valuator, as we can't resume in
* mid C++-code. */
bool backup_allow = ScriptObject::GetAllowDoCommand();
ScriptObject::SetAllowDoCommand(false);
for (const Vehicle *v : Vehicle::Iterate()) {
if ((v->owner == ScriptObject::GetCompany() || ScriptCompanyMode::IsDeity()) && (v->IsPrimaryVehicle() || (v->type == VEH_TRAIN && ::Train::From(v)->IsFreeWagon()))) this->AddItem(v->index);
if (v->owner != ScriptObject::GetCompany() && !ScriptCompanyMode::IsDeity()) continue;
if (!v->IsPrimaryVehicle() && !(v->type == VEH_TRAIN && ::Train::From(v)->IsFreeWagon())) continue;
if (nparam < 1) {
/* No filter, just add the item. */
this->AddItem(v->index);
continue;
/* Push the root table as instance object, this is what squirrel does for meta-functions. */
sq_pushroottable(vm);
/* Push all arguments for the valuator function. */
sq_pushinteger(vm, v->index);
for (int i = 0; i < nparam - 1; i++) {
sq_push(vm, i + 3);
/* Call the function. Squirrel pops all parameters and pushes the return value. */
if (SQ_FAILED(sq_call(vm, nparam + 1, SQTrue, SQTrue))) {
ScriptObject::SetAllowDoCommand(backup_allow);
throw sq_throwerror(vm, "failed to run filter");
/* Retrieve the return value */
switch (sq_gettype(vm, -1)) {
case OT_BOOL: {
SQBool add;
sq_getbool(vm, -1, &add);
if (add) this->AddItem(v->index);
break;
default: {
throw sq_throwerror(vm, "return value of filter is not valid (not bool)");
/* Pop the return value. */
sq_poptop(vm);
/* Pop the filter function */
ScriptVehicleList_Station::ScriptVehicleList_Station(StationID station_id)
if (!ScriptBaseStation::IsValidBaseStation(station_id)) return;
@@ -17,13 +17,38 @@
* Creates a list of vehicles of which you are the owner.
* @api ai game
* @ingroup ScriptList
*/
class ScriptVehicleList : public ScriptList {
public:
#ifdef DOXYGEN_API
ScriptVehicleList();
/**
* Apply a filter when building the list.
* @param filter_function The function which will be doing the filtering.
* @param params The params to give to the filters (minus the first param,
* which is always the index-value).
* @note You can write your own filters and use them. Just remember that
* the first parameter should be the index-value, and it should return
* a bool.
* @note Example:
* ScriptVehicleList(ScriptVehicle.IsInDepot);
* function IsType(vehicle_id, type)
* {
* return ScriptVehicle.GetVehicleType(vehicle_id) == type;
* }
* ScriptVehicleList(IsType, ScriptVehicle.VT_ROAD);
ScriptVehicleList(void *filter_function, int params, ...);
#else
* The constructor wrapper from Squirrel.
ScriptVehicleList(HSQUIRRELVM vm);
#endif
};
* Creates a list of vehicles that have orders to a given station.
Status change: