mirror of https://github.com/OpenTTD/OpenTTD.git
Add: [Script] Optional filter parameter to more ScriptXXXList constructors (#11698)
This commit is contained in:
parent
f1e999ec59
commit
c86d918921
|
@ -361,6 +361,15 @@ void sq_setdebughook(HSQUIRRELVM v);
|
||||||
#define sq_isweakref(o) ((o)._type==OT_WEAKREF)
|
#define sq_isweakref(o) ((o)._type==OT_WEAKREF)
|
||||||
#define sq_type(o) ((o)._type)
|
#define sq_type(o) ((o)._type)
|
||||||
|
|
||||||
|
/* Limit the total number of ops that can be consumed by an operation */
|
||||||
|
struct SQOpsLimiter {
|
||||||
|
SQOpsLimiter(HSQUIRRELVM v, SQInteger ops, const char *label);
|
||||||
|
~SQOpsLimiter();
|
||||||
|
private:
|
||||||
|
HSQUIRRELVM _v;
|
||||||
|
SQInteger _ops;
|
||||||
|
};
|
||||||
|
|
||||||
/* deprecated */
|
/* deprecated */
|
||||||
#define sq_createslot(v,n) sq_newslot(v,n,SQFalse)
|
#define sq_createslot(v,n) sq_newslot(v,n,SQFalse)
|
||||||
|
|
||||||
|
|
|
@ -1323,3 +1323,16 @@ void sq_free(void *p,SQUnsignedInteger size)
|
||||||
SQ_FREE(p,size);
|
SQ_FREE(p,size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SQOpsLimiter::SQOpsLimiter(HSQUIRRELVM v, SQInteger ops, const char *label) : _v(v)
|
||||||
|
{
|
||||||
|
this->_ops = v->_ops_till_suspend_error_threshold;
|
||||||
|
if (this->_ops == INT64_MIN) {
|
||||||
|
v->_ops_till_suspend_error_threshold = v->_ops_till_suspend - ops;
|
||||||
|
v->_ops_till_suspend_error_label = label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SQOpsLimiter::~SQOpsLimiter()
|
||||||
|
{
|
||||||
|
this->_v->_ops_till_suspend_error_threshold = this->_ops;
|
||||||
|
}
|
||||||
|
|
|
@ -25,6 +25,11 @@
|
||||||
* \li AIError::ERR_PRECONDITION_TOO_MANY_PARAMETERS, that error is never returned anymore.
|
* \li AIError::ERR_PRECONDITION_TOO_MANY_PARAMETERS, that error is never returned anymore.
|
||||||
*
|
*
|
||||||
* Other changes:
|
* Other changes:
|
||||||
|
* \li AIGroupList accepts an optional filter function
|
||||||
|
* \li AIIndustryList accepts an optional filter function
|
||||||
|
* \li AISignList accepts an optional filter function
|
||||||
|
* \li AISubsidyList accepts an optional filter function
|
||||||
|
* \li AITownList accepts an optional filter function
|
||||||
* \li AIVehicleList accepts an optional filter function
|
* \li AIVehicleList accepts an optional filter function
|
||||||
*
|
*
|
||||||
* \b 13.0
|
* \b 13.0
|
||||||
|
|
|
@ -85,6 +85,11 @@
|
||||||
* \li GSError::ERR_PRECONDITION_TOO_MANY_PARAMETERS, that error is never returned anymore.
|
* \li GSError::ERR_PRECONDITION_TOO_MANY_PARAMETERS, that error is never returned anymore.
|
||||||
*
|
*
|
||||||
* Other changes:
|
* Other changes:
|
||||||
|
* \li GSGroupList accepts an optional filter function
|
||||||
|
* \li GSIndustryList accepts an optional filter function
|
||||||
|
* \li GSSignList accepts an optional filter function
|
||||||
|
* \li GSSubsidyList accepts an optional filter function
|
||||||
|
* \li GSTownList accepts an optional filter function
|
||||||
* \li GSVehicleList accepts an optional filter function
|
* \li GSVehicleList accepts an optional filter function
|
||||||
*
|
*
|
||||||
* \b 13.0
|
* \b 13.0
|
||||||
|
|
|
@ -14,11 +14,11 @@
|
||||||
|
|
||||||
#include "../../safeguards.h"
|
#include "../../safeguards.h"
|
||||||
|
|
||||||
ScriptGroupList::ScriptGroupList()
|
ScriptGroupList::ScriptGroupList(HSQUIRRELVM vm)
|
||||||
{
|
{
|
||||||
EnforceCompanyModeValid_Void();
|
EnforceCompanyModeValid_Void();
|
||||||
CompanyID owner = ScriptObject::GetCompany();
|
CompanyID owner = ScriptObject::GetCompany();
|
||||||
for (const Group *g : Group::Iterate()) {
|
ScriptList::FillList<Group>(vm, this,
|
||||||
if (g->owner == owner) this->AddItem(g->index);
|
[owner](const Group *g) { return g->owner == owner; }
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,35 @@
|
||||||
*/
|
*/
|
||||||
class ScriptGroupList : public ScriptList {
|
class ScriptGroupList : public ScriptList {
|
||||||
public:
|
public:
|
||||||
|
#ifdef DOXYGEN_API
|
||||||
/**
|
/**
|
||||||
* @game @pre ScriptCompanyMode::IsValid().
|
* @game @pre ScriptCompanyMode::IsValid().
|
||||||
*/
|
*/
|
||||||
ScriptGroupList();
|
ScriptGroupList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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).
|
||||||
|
* @game @pre ScriptCompanyMode::IsValid().
|
||||||
|
* @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:
|
||||||
|
* function IsType(group_id, type)
|
||||||
|
* {
|
||||||
|
* return ScriptGroup.GetVehicleType(group_id) == type;
|
||||||
|
* }
|
||||||
|
* ScriptGroupList(IsType, ScriptVehicle.VT_ROAD);
|
||||||
|
*/
|
||||||
|
ScriptGroupList(void *filter_function, int params, ...);
|
||||||
|
#else
|
||||||
|
/**
|
||||||
|
* The constructor wrapper from Squirrel.
|
||||||
|
*/
|
||||||
|
ScriptGroupList(HSQUIRRELVM vm);
|
||||||
|
#endif /* DOXYGEN_API */
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* SCRIPT_GROUPLIST_HPP */
|
#endif /* SCRIPT_GROUPLIST_HPP */
|
||||||
|
|
|
@ -13,23 +13,21 @@
|
||||||
|
|
||||||
#include "../../safeguards.h"
|
#include "../../safeguards.h"
|
||||||
|
|
||||||
ScriptIndustryList::ScriptIndustryList()
|
ScriptIndustryList::ScriptIndustryList(HSQUIRRELVM vm)
|
||||||
{
|
{
|
||||||
for (const Industry *i : Industry::Iterate()) {
|
ScriptList::FillList<Industry>(vm, this);
|
||||||
this->AddItem(i->index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptIndustryList_CargoAccepting::ScriptIndustryList_CargoAccepting(CargoID cargo_id)
|
ScriptIndustryList_CargoAccepting::ScriptIndustryList_CargoAccepting(CargoID cargo_id)
|
||||||
{
|
{
|
||||||
for (const Industry *i : Industry::Iterate()) {
|
ScriptList::FillList<Industry>(this,
|
||||||
if (i->IsCargoAccepted(cargo_id)) this->AddItem(i->index);
|
[cargo_id](const Industry *i) { return i->IsCargoAccepted(cargo_id); }
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptIndustryList_CargoProducing::ScriptIndustryList_CargoProducing(CargoID cargo_id)
|
ScriptIndustryList_CargoProducing::ScriptIndustryList_CargoProducing(CargoID cargo_id)
|
||||||
{
|
{
|
||||||
for (const Industry *i : Industry::Iterate()) {
|
ScriptList::FillList<Industry>(this,
|
||||||
if (i->IsCargoProduced(cargo_id)) this->AddItem(i->index);
|
[cargo_id](const Industry *i) { return i->IsCargoProduced(cargo_id); }
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,32 @@
|
||||||
*/
|
*/
|
||||||
class ScriptIndustryList : public ScriptList {
|
class ScriptIndustryList : public ScriptList {
|
||||||
public:
|
public:
|
||||||
|
#ifdef DOXYGEN_API
|
||||||
ScriptIndustryList();
|
ScriptIndustryList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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:
|
||||||
|
* ScriptIndustryList(ScriptIndustry.HasDock);
|
||||||
|
* function IsType(industry_id, type)
|
||||||
|
* {
|
||||||
|
* return ScriptIndustry.GetIndustryType(industry_id) == type;
|
||||||
|
* }
|
||||||
|
* ScriptIndustryList(IsType, 0);
|
||||||
|
*/
|
||||||
|
ScriptIndustryList(void *filter_function, int params, ...);
|
||||||
|
#else
|
||||||
|
/**
|
||||||
|
* The constructor wrapper from Squirrel.
|
||||||
|
*/
|
||||||
|
ScriptIndustryList(HSQUIRRELVM vm);
|
||||||
|
#endif /* DOXYGEN_API */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -11,9 +11,7 @@
|
||||||
#include "script_list.hpp"
|
#include "script_list.hpp"
|
||||||
#include "script_controller.hpp"
|
#include "script_controller.hpp"
|
||||||
#include "../../debug.h"
|
#include "../../debug.h"
|
||||||
#include "../../core/backup_type.hpp"
|
|
||||||
#include "../../script/squirrel.hpp"
|
#include "../../script/squirrel.hpp"
|
||||||
#include <../squirrel/sqvm.h>
|
|
||||||
|
|
||||||
#include "../../safeguards.h"
|
#include "../../safeguards.h"
|
||||||
|
|
||||||
|
@ -869,12 +867,7 @@ SQInteger ScriptList::Valuate(HSQUIRRELVM vm)
|
||||||
ScriptObject::SetAllowDoCommand(false);
|
ScriptObject::SetAllowDoCommand(false);
|
||||||
|
|
||||||
/* Limit the total number of ops that can be consumed by a valuate operation */
|
/* Limit the total number of ops that can be consumed by a valuate operation */
|
||||||
SQInteger new_ops_error_threshold = vm->_ops_till_suspend_error_threshold;
|
SQOpsLimiter limiter(vm, MAX_VALUATE_OPS, "valuator function");
|
||||||
if (vm->_ops_till_suspend_error_threshold == INT64_MIN) {
|
|
||||||
new_ops_error_threshold = vm->_ops_till_suspend - MAX_VALUATE_OPS;
|
|
||||||
vm->_ops_till_suspend_error_label = "valuator function";
|
|
||||||
}
|
|
||||||
AutoRestoreBackup ops_error_threshold_backup(vm->_ops_till_suspend_error_threshold, new_ops_error_threshold);
|
|
||||||
|
|
||||||
/* Push the function to call */
|
/* Push the function to call */
|
||||||
sq_push(vm, 2);
|
sq_push(vm, 2);
|
||||||
|
|
|
@ -42,6 +42,107 @@ private:
|
||||||
bool initialized; ///< Whether an iteration has been started
|
bool initialized; ///< Whether an iteration has been started
|
||||||
int modifications; ///< Number of modification that has been done. To prevent changing data while valuating.
|
int modifications; ///< Number of modification that has been done. To prevent changing data while valuating.
|
||||||
|
|
||||||
|
protected:
|
||||||
|
template<typename T, class ItemValid, class ItemFilter>
|
||||||
|
static void FillList(ScriptList *list, ItemValid item_valid, ItemFilter item_filter)
|
||||||
|
{
|
||||||
|
for (const T *item : T::Iterate()) {
|
||||||
|
if (!item_valid(item)) continue;
|
||||||
|
if (!item_filter(item)) continue;
|
||||||
|
list->AddItem(item->index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, class ItemValid>
|
||||||
|
static void FillList(ScriptList *list, ItemValid item_valid)
|
||||||
|
{
|
||||||
|
ScriptList::FillList<T>(list, item_valid, [](const T *) { return true; });
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static void FillList(ScriptList *list)
|
||||||
|
{
|
||||||
|
ScriptList::FillList<T>(list, [](const T *) { return true; });
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, class ItemValid>
|
||||||
|
static void FillList(HSQUIRRELVM vm, ScriptList *list, ItemValid item_valid)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
if (nparam < 1) {
|
||||||
|
ScriptList::FillList<T>(list, item_valid);
|
||||||
|
} else {
|
||||||
|
/* Limit the total number of ops that can be consumed by a filter operation, if a filter function is present */
|
||||||
|
SQOpsLimiter limiter(vm, MAX_VALUATE_OPS, "list filter function");
|
||||||
|
|
||||||
|
ScriptList::FillList<T>(list, item_valid,
|
||||||
|
[vm, nparam, backup_allow](const T *item) {
|
||||||
|
/* 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, item->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");
|
||||||
|
}
|
||||||
|
|
||||||
|
SQBool add = SQFalse;
|
||||||
|
|
||||||
|
/* Retrieve the return value */
|
||||||
|
switch (sq_gettype(vm, -1)) {
|
||||||
|
case OT_BOOL:
|
||||||
|
sq_getbool(vm, -1, &add);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ScriptObject::SetAllowDoCommand(backup_allow);
|
||||||
|
throw sq_throwerror(vm, "return value of filter is not valid (not bool)");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pop the return value. */
|
||||||
|
sq_poptop(vm);
|
||||||
|
|
||||||
|
return add;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Pop the filter function */
|
||||||
|
sq_poptop(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptObject::SetAllowDoCommand(backup_allow);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static void FillList(HSQUIRRELVM vm, ScriptList *list)
|
||||||
|
{
|
||||||
|
ScriptList::FillList<T>(vm, list, [](const T *) { return true; });
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef std::set<SQInteger> ScriptItemList; ///< The list of items inside the bucket
|
typedef std::set<SQInteger> ScriptItemList; ///< The list of items inside the bucket
|
||||||
typedef std::map<SQInteger, ScriptItemList> ScriptListBucket; ///< The bucket list per value
|
typedef std::map<SQInteger, ScriptItemList> ScriptListBucket; ///< The bucket list per value
|
||||||
|
|
|
@ -14,9 +14,9 @@
|
||||||
|
|
||||||
#include "../../safeguards.h"
|
#include "../../safeguards.h"
|
||||||
|
|
||||||
ScriptSignList::ScriptSignList()
|
ScriptSignList::ScriptSignList(HSQUIRRELVM vm)
|
||||||
{
|
{
|
||||||
for (const Sign *s : Sign::Iterate()) {
|
ScriptList::FillList<Sign>(vm, this,
|
||||||
if (ScriptSign::IsValidSign(s->index)) this->AddItem(s->index);
|
[](const Sign *s) { return ScriptSign::IsValidSign(s->index); }
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,29 @@
|
||||||
*/
|
*/
|
||||||
class ScriptSignList : public ScriptList {
|
class ScriptSignList : public ScriptList {
|
||||||
public:
|
public:
|
||||||
|
#ifdef DOXYGEN_API
|
||||||
ScriptSignList();
|
ScriptSignList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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:
|
||||||
|
* function Contains(sign_id, str)
|
||||||
|
* {
|
||||||
|
* local name = ScriptSign.GetName(sign_id);
|
||||||
|
* return name != null && name.find(str) != null;
|
||||||
|
* }
|
||||||
|
* ScriptSignList(Contains, "something");
|
||||||
|
*/
|
||||||
|
ScriptSignList(void *filter_function, int params, ...);
|
||||||
|
#else
|
||||||
|
ScriptSignList(HSQUIRRELVM);
|
||||||
|
#endif /* DOXYGEN_API */
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* SCRIPT_SIGNLIST_HPP */
|
#endif /* SCRIPT_SIGNLIST_HPP */
|
||||||
|
|
|
@ -13,9 +13,7 @@
|
||||||
|
|
||||||
#include "../../safeguards.h"
|
#include "../../safeguards.h"
|
||||||
|
|
||||||
ScriptSubsidyList::ScriptSubsidyList()
|
ScriptSubsidyList::ScriptSubsidyList(HSQUIRRELVM vm)
|
||||||
{
|
{
|
||||||
for (const Subsidy *s : Subsidy::Iterate()) {
|
ScriptList::FillList<Subsidy>(vm, this);
|
||||||
this->AddItem(s->index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,28 @@
|
||||||
*/
|
*/
|
||||||
class ScriptSubsidyList : public ScriptList {
|
class ScriptSubsidyList : public ScriptList {
|
||||||
public:
|
public:
|
||||||
|
#ifdef DOXYGEN_API
|
||||||
ScriptSubsidyList();
|
ScriptSubsidyList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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:
|
||||||
|
* function IsType(subsidy_id, type)
|
||||||
|
* {
|
||||||
|
* return ScriptSubsidy.GetSourceType(subsidy_id) == type;
|
||||||
|
* }
|
||||||
|
* ScriptSubsidyList(IsType, ScriptSubsidy.SPT_TOWN);
|
||||||
|
*/
|
||||||
|
ScriptSubsidyList(void *filter_function, int params, ...);
|
||||||
|
#else
|
||||||
|
ScriptSubsidyList(HSQUIRRELVM vm);
|
||||||
|
#endif /* DOXYGEN_API */
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* SCRIPT_SUBSIDYLIST_HPP */
|
#endif /* SCRIPT_SUBSIDYLIST_HPP */
|
||||||
|
|
|
@ -13,11 +13,9 @@
|
||||||
|
|
||||||
#include "../../safeguards.h"
|
#include "../../safeguards.h"
|
||||||
|
|
||||||
ScriptTownList::ScriptTownList()
|
ScriptTownList::ScriptTownList(HSQUIRRELVM vm)
|
||||||
{
|
{
|
||||||
for (const Town *t : Town::Iterate()) {
|
ScriptList::FillList<Town>(vm, this);
|
||||||
this->AddItem(t->index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptTownEffectList::ScriptTownEffectList()
|
ScriptTownEffectList::ScriptTownEffectList()
|
||||||
|
|
|
@ -19,7 +19,29 @@
|
||||||
*/
|
*/
|
||||||
class ScriptTownList : public ScriptList {
|
class ScriptTownList : public ScriptList {
|
||||||
public:
|
public:
|
||||||
|
#ifdef DOXYGEN_API
|
||||||
ScriptTownList();
|
ScriptTownList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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:
|
||||||
|
* ScriptTownList(ScriptTown.IsActionAvailable, ScriptTown.TOWN_ACTION_BRIBE);
|
||||||
|
* function MinPopulation(town_id, pop)
|
||||||
|
* {
|
||||||
|
* return ScriptTown.GetPopulation(town_id) >= pop;
|
||||||
|
* }
|
||||||
|
* ScriptTownList(MinPopulation, 1000);
|
||||||
|
*/
|
||||||
|
ScriptTownList(void *filter_function, int params, ...);
|
||||||
|
#else
|
||||||
|
ScriptTownList(HSQUIRRELVM vm);
|
||||||
|
#endif /* DOXYGEN_API */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
#include "../../vehicle_base.h"
|
#include "../../vehicle_base.h"
|
||||||
#include "../../vehiclelist_func.h"
|
#include "../../vehiclelist_func.h"
|
||||||
#include "../../train.h"
|
#include "../../train.h"
|
||||||
#include "../../core/backup_type.hpp"
|
|
||||||
#include <../squirrel/sqvm.h>
|
|
||||||
|
|
||||||
#include "../../safeguards.h"
|
#include "../../safeguards.h"
|
||||||
|
|
||||||
|
@ -25,84 +23,14 @@ ScriptVehicleList::ScriptVehicleList(HSQUIRRELVM vm)
|
||||||
{
|
{
|
||||||
EnforceDeityOrCompanyModeValid_Void();
|
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);
|
|
||||||
|
|
||||||
/* Limit the total number of ops that can be consumed by a filter operation, if a filter function is present */
|
|
||||||
SQInteger new_ops_error_threshold = vm->_ops_till_suspend_error_threshold;
|
|
||||||
if (nparam >= 1 && vm->_ops_till_suspend_error_threshold == INT64_MIN) {
|
|
||||||
new_ops_error_threshold = vm->_ops_till_suspend - MAX_VALUATE_OPS;
|
|
||||||
vm->_ops_till_suspend_error_label = "vehicle filter function";
|
|
||||||
}
|
|
||||||
AutoRestoreBackup ops_error_threshold_backup(vm->_ops_till_suspend_error_threshold, new_ops_error_threshold);
|
|
||||||
|
|
||||||
bool is_deity = ScriptCompanyMode::IsDeity();
|
bool is_deity = ScriptCompanyMode::IsDeity();
|
||||||
CompanyID owner = ScriptObject::GetCompany();
|
CompanyID owner = ScriptObject::GetCompany();
|
||||||
for (const Vehicle *v : Vehicle::Iterate()) {
|
|
||||||
if (v->owner != owner && !is_deity) continue;
|
|
||||||
if (!v->IsPrimaryVehicle() && !(v->type == VEH_TRAIN && ::Train::From(v)->IsFreeWagon())) continue;
|
|
||||||
|
|
||||||
if (nparam < 1) {
|
ScriptList::FillList<Vehicle>(vm, this,
|
||||||
/* No filter, just add the item. */
|
[is_deity, owner](const Vehicle *v) {
|
||||||
this->AddItem(v->index);
|
return (is_deity || v->owner == owner) && (v->IsPrimaryVehicle() || (v->type == VEH_TRAIN && ::Train::From(v)->IsFreeWagon()));
|
||||||
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: {
|
|
||||||
ScriptObject::SetAllowDoCommand(backup_allow);
|
|
||||||
throw sq_throwerror(vm, "return value of filter is not valid (not bool)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Pop the return value. */
|
|
||||||
sq_poptop(vm);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nparam >= 1) {
|
|
||||||
/* Pop the filter function */
|
|
||||||
sq_poptop(vm);
|
|
||||||
}
|
|
||||||
|
|
||||||
ScriptObject::SetAllowDoCommand(backup_allow);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptVehicleList_Station::ScriptVehicleList_Station(StationID station_id)
|
ScriptVehicleList_Station::ScriptVehicleList_Station(StationID station_id)
|
||||||
|
@ -182,11 +110,11 @@ ScriptVehicleList_Group::ScriptVehicleList_Group(GroupID group_id)
|
||||||
if (!ScriptGroup::IsValidGroup((ScriptGroup::GroupID)group_id)) return;
|
if (!ScriptGroup::IsValidGroup((ScriptGroup::GroupID)group_id)) return;
|
||||||
|
|
||||||
CompanyID owner = ScriptObject::GetCompany();
|
CompanyID owner = ScriptObject::GetCompany();
|
||||||
for (const Vehicle *v : Vehicle::Iterate()) {
|
|
||||||
if (v->owner == owner && v->IsPrimaryVehicle()) {
|
ScriptList::FillList<Vehicle>(this,
|
||||||
if (v->group_id == group_id) this->AddItem(v->index);
|
[owner](const Vehicle *v) { return v->owner == owner && v->IsPrimaryVehicle(); },
|
||||||
}
|
[group_id](const Vehicle *v) { return v->group_id == group_id; }
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptVehicleList_DefaultGroup::ScriptVehicleList_DefaultGroup(ScriptVehicle::VehicleType vehicle_type)
|
ScriptVehicleList_DefaultGroup::ScriptVehicleList_DefaultGroup(ScriptVehicle::VehicleType vehicle_type)
|
||||||
|
@ -195,9 +123,9 @@ ScriptVehicleList_DefaultGroup::ScriptVehicleList_DefaultGroup(ScriptVehicle::Ve
|
||||||
if (vehicle_type < ScriptVehicle::VT_RAIL || vehicle_type > ScriptVehicle::VT_AIR) return;
|
if (vehicle_type < ScriptVehicle::VT_RAIL || vehicle_type > ScriptVehicle::VT_AIR) return;
|
||||||
|
|
||||||
CompanyID owner = ScriptObject::GetCompany();
|
CompanyID owner = ScriptObject::GetCompany();
|
||||||
for (const Vehicle *v : Vehicle::Iterate()) {
|
|
||||||
if (v->owner == owner && v->IsPrimaryVehicle()) {
|
ScriptList::FillList<Vehicle>(this,
|
||||||
if (v->type == (::VehicleType)vehicle_type && v->group_id == ScriptGroup::GROUP_DEFAULT) this->AddItem(v->index);
|
[owner](const Vehicle *v) { return v->owner == owner && v->IsPrimaryVehicle(); },
|
||||||
}
|
[vehicle_type](const Vehicle *v) { return v->type == (::VehicleType)vehicle_type && v->group_id == ScriptGroup::GROUP_DEFAULT; }
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue