Implement event priority

For any given event name, events execute in order of decreasing priority.

Priority is a real number, and may be assigned via the `priority` attribute for
the WML [event] tag, or through the Lua APIs:

- wesnoth.game_events.add({priority = number})
- wesnoth.game_events.add_repeating(name, action, [priority])

Note that delayed variable substitution is not currently supported in the WML attribute.
This commit is contained in:
Ivo Julca 2023-05-02 00:53:10 -05:00 committed by Steve Cotton
parent 9887d0ca26
commit 5ebc9a790a
17 changed files with 509 additions and 10 deletions

View file

@ -126,6 +126,7 @@
{SIMPLE_KEY filter_formula string}
{DEFAULT_KEY first_time_only bool yes}
{DEFAULT_KEY delayed_variable_substitution bool no}
{DEFAULT_KEY priority s_real 0.0}
{FILTER_TAG "filter" unit ()}
{FILTER_TAG "filter_second" unit ()}

View file

@ -0,0 +1,31 @@
#####
# API(s) being tested: wesnoth.game_events.add
##
# Actions:
# Use lua's game_events.add to attach a low-priority "new turn" event.
# Use lua's game_events.add to attach a high-priority "new turn" event.
##
# Expected end state:
# The test passes when high-priority event is triggered.
#####
{GENERIC_UNIT_TEST "events_test_lua_events_add_priority_vs_origin" (
[event]
name=preload
[lua]
code=<<
wesnoth.game_events.add{
id = 'low',
name = 'start',
priority = -1,
action = unit_test.fail
}
wesnoth.game_events.add{
id = 'high',
name = 'start',
priority = 1,
action = unit_test.succeed
};
>>
[/lua]
[/event]
)}

View file

@ -0,0 +1,21 @@
#####
# API(s) being tested: wesnoth.game_events.add_repeating
##
# Actions:
# Use lua's game_events.add_repeating to attach a low-priority "new turn" event.
# Use lua's game_events.add_repeating to attach a high-priority "new turn" event.
##
# Expected end state:
# The test passes when high-priority event is triggered.
#####
{GENERIC_UNIT_TEST "events_test_lua_events_add_repeating_priority_vs_origin" (
[event]
name=preload
[lua]
code=<<
wesnoth.game_events.add_repeating('start', unit_test.fail, -1)
wesnoth.game_events.add_repeating('start', unit_test.succeed, 1)
>>
[/lua]
[/event]
)}

View file

@ -0,0 +1,28 @@
#####
# API(s) being tested: [event]priority=
##
# Actions:
# Set X to 1 in the prestart event.
# Add a low-priority start event handler.
# In a new high-priority start event: Check if X is 1, Set X to 2.
# In the added low-priority start event handler: Check if X is 2.
##
# Expected end state:
# The test passes when the low-priority event is executed last.
#####
{GENERIC_UNIT_TEST "events_test_priority_vs_origin" (
[event]
name = prestart
{VARIABLE X 1}
[event]
name = start
{RETURN ({VARIABLE_CONDITIONAL X equals 2})}
[/event]
[event]
name = start
priority = 1
{ASSERT ({VARIABLE_CONDITIONAL X equals 1})}
{VARIABLE X 2}
[/event]
[/event]
)}

View file

@ -0,0 +1,29 @@
#####
# API(s) being tested: [event]priority=
##
# Actions:
# Set X to 1 in the prestart event.
# In a start event handler with negative priority: Check if X is 1, Set X to 2.
# In a start event handler with the same priority: Check if X is 2.
##
# Expected end state:
# The test passes when the second event is executed last.
#####
{GENERIC_UNIT_TEST "events_test_same_priority" (
[event]
name = prestart
{VARIABLE X 1}
[event]
name = start
priority = -1
{ASSERT ({VARIABLE_CONDITIONAL X equals 1})}
{VARIABLE X 2}
[/event]
[event]
name = start
priority = -1
{ASSERT ({VARIABLE_CONDITIONAL X equals 2})}
{SUCCEED}
[/event]
[/event]
)}

View file

@ -0,0 +1,169 @@
#####
# API(s) being tested: [event]priority=
##
# Actions:
# Use event handlers to append alphabet letters to X.
# Each event handler increases Y by 1.
# Each event handler checks the current value of X, Y vs expectation.
##
# Expected end state:
# The test passes when X is `abcdefghijklmnopq` and Y is 17.
#####
{GENERIC_UNIT_TEST "events_test_multi_int" (
[event]
name = prestart
{VARIABLE X "a"}
{VARIABLE Y 1}
[event]
id = final-check
name = start
priority = -999999
{ASSERT ({VARIABLE_CONDITIONAL Y equals 17})}
{RETURN ({VARIABLE_CONDITIONAL X equals abcdefghijklmnopq})}
[/event]
[event]
id = step-3
name = start
priority = 13
{ASSERT ({VARIABLE_CONDITIONAL Y equals 3})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abc})}
{VARIABLE_OP X formula "'$X'..'d'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-5
name = start
priority = 8
{ASSERT ({VARIABLE_CONDITIONAL Y equals 5})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcde})}
{VARIABLE_OP X formula "'$X'..'f'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-2
name = start
priority = 14
{ASSERT ({VARIABLE_CONDITIONAL Y equals 2})}
{ASSERT ({VARIABLE_CONDITIONAL X equals ab})}
{VARIABLE_OP X formula "'$X'..'c'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-1
name = start
priority = 15
{ASSERT ({VARIABLE_CONDITIONAL Y equals 1})}
{ASSERT ({VARIABLE_CONDITIONAL X equals a})}
{VARIABLE_OP X formula "'$X'..'b'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-4
name = start
priority = 12
{ASSERT ({VARIABLE_CONDITIONAL Y equals 4})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcd})}
{VARIABLE_OP X formula "'$X'..'e'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-8
name = start
priority = 1
{ASSERT ({VARIABLE_CONDITIONAL Y equals 8})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcdefgh})}
{VARIABLE_OP X formula "'$X'..'i'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-6
name = start
priority = 7
{ASSERT ({VARIABLE_CONDITIONAL Y equals 6})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcdef})}
{VARIABLE_OP X formula "'$X'..'g'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-9
name = start
priority = -2
{ASSERT ({VARIABLE_CONDITIONAL Y equals 9})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcdefghi})}
{VARIABLE_OP X formula "'$X'..'j'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-10
name = start
priority = -2
{ASSERT ({VARIABLE_CONDITIONAL Y equals 10})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcdefghij})}
{VARIABLE_OP X formula "'$X'..'k'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-7
name = start
priority = 7
{ASSERT ({VARIABLE_CONDITIONAL Y equals 7})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcdefg})}
{VARIABLE_OP X formula "'$X'..'h'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-11
name = start
priority = -10
{ASSERT ({VARIABLE_CONDITIONAL Y equals 11})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcdefghijk})}
{VARIABLE_OP X formula "'$X'..'l'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-12
name = start
priority = -11
{ASSERT ({VARIABLE_CONDITIONAL Y equals 12})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcdefghijkl})}
{VARIABLE_OP X formula "'$X'..'m'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-14
name = start
priority = -2000
{ASSERT ({VARIABLE_CONDITIONAL Y equals 14})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcdefghijklmn})}
{VARIABLE_OP X formula "'$X'..'o'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-16
name = start
priority = -800000
{ASSERT ({VARIABLE_CONDITIONAL Y equals 16})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcdefghijklmnop})}
{VARIABLE_OP X formula "'$X'..'q'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-13
name = start
priority = -1000
{ASSERT ({VARIABLE_CONDITIONAL Y equals 13})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcdefghijklm})}
{VARIABLE_OP X formula "'$X'..'n'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-15
name = start
priority = -40000
{ASSERT ({VARIABLE_CONDITIONAL Y equals 15})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcdefghijklmno})}
{VARIABLE_OP X formula "'$X'..'p'"}
{VARIABLE_OP Y add 1}
[/event]
[/event]
)}

View file

@ -0,0 +1,171 @@
#####
# API(s) being tested: [event]priority=
##
# Actions:
# Use event handlers to append alphabet letters to X.
# Each event handler increases Y by 1.
# Each event handler checks the current value of X, Y vs expectation.
##
# Expected end state:
# The test passes when X is `abcdefghijklmnopq` and Y is 17.
#####
{GENERIC_UNIT_TEST "events_test_multi_float" (
[event]
name = prestart
{VARIABLE X "a"}
{VARIABLE Y 1}
[event]
id = final-check
name = start
priority = -999999
{ASSERT ({VARIABLE_CONDITIONAL Y equals 17})}
{RETURN ({VARIABLE_CONDITIONAL X equals abcdefghijklmnopq})}
[/event]
[event]
id = step-3
name = start
priority = 4.1
{ASSERT ({VARIABLE_CONDITIONAL Y equals 3})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abc})}
{VARIABLE_OP X formula "'$X'..'d'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-5
name = start
priority = 3.99999
{ASSERT ({VARIABLE_CONDITIONAL Y equals 5})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcde})}
{VARIABLE_OP X formula "'$X'..'f'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-2
name = start
priority = 4.2
{ASSERT ({VARIABLE_CONDITIONAL Y equals 2})}
{ASSERT ({VARIABLE_CONDITIONAL X equals ab})}
{VARIABLE_OP X formula "'$X'..'c'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-1
name = start
priority = 5
{ASSERT ({VARIABLE_CONDITIONAL Y equals 1})}
{ASSERT ({VARIABLE_CONDITIONAL X equals a})}
{VARIABLE_OP X formula "'$X'..'b'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-4
name = start
priority = "$(4.0)"
delayed_variable_substitution=no
{ASSERT ({VARIABLE_CONDITIONAL Y equals 4})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcd})}
{VARIABLE_OP X formula "'$|X'..'e'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-8
name = start
priority = 1
{ASSERT ({VARIABLE_CONDITIONAL Y equals 8})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcdefgh})}
{VARIABLE_OP X formula "'$X'..'i'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-6
name = start
priority = 1.5
{ASSERT ({VARIABLE_CONDITIONAL Y equals 6})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcdef})}
{VARIABLE_OP X formula "'$X'..'g'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-9
name = start
# Default to 0
priority = "$X"
{ASSERT ({VARIABLE_CONDITIONAL Y equals 9})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcdefghi})}
{VARIABLE_OP X formula "'$X'..'j'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-10
name = start
priority = -2
{ASSERT ({VARIABLE_CONDITIONAL Y equals 10})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcdefghij})}
{VARIABLE_OP X formula "'$X'..'k'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-7
name = start
priority = 1.5
{ASSERT ({VARIABLE_CONDITIONAL Y equals 7})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcdefg})}
{VARIABLE_OP X formula "'$X'..'h'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-11
name = start
priority = -3.5
{ASSERT ({VARIABLE_CONDITIONAL Y equals 11})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcdefghijk})}
{VARIABLE_OP X formula "'$X'..'l'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-12
name = start
priority = -3.6
{ASSERT ({VARIABLE_CONDITIONAL Y equals 12})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcdefghijkl})}
{VARIABLE_OP X formula "'$X'..'m'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-14
name = start
priority = -2000
{ASSERT ({VARIABLE_CONDITIONAL Y equals 14})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcdefghijklmn})}
{VARIABLE_OP X formula "'$X'..'o'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-16
name = start
priority = -800000
{ASSERT ({VARIABLE_CONDITIONAL Y equals 16})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcdefghijklmnop})}
{VARIABLE_OP X formula "'$X'..'q'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-13
name = start
priority = -1000
{ASSERT ({VARIABLE_CONDITIONAL Y equals 13})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcdefghijklm})}
{VARIABLE_OP X formula "'$X'..'n'"}
{VARIABLE_OP Y add 1}
[/event]
[event]
id = step-15
name = start
priority = -40000
{ASSERT ({VARIABLE_CONDITIONAL Y equals 15})}
{ASSERT ({VARIABLE_CONDITIONAL X equals abcdefghijklmno})}
{VARIABLE_OP X formula "'$X'..'p'"}
{VARIABLE_OP Y add 1}
[/event]
[/event]
)}

View file

@ -163,6 +163,7 @@ void event_handler::write_config(config &cfg, bool include_nonserializable) cons
if(!types_.empty()) cfg["name"] = types_;
if(!id_.empty()) cfg["id"] = id_;
cfg["first_time_only"] = first_time_only_;
cfg["priority"] = priority_;
for(const auto& filter : filters_) {
filter->serialize(cfg);
}

View file

@ -94,6 +94,11 @@ public:
return id_;
}
const double& priority() const
{
return priority_;
}
bool empty() const;
bool repeatable() const
@ -111,6 +116,10 @@ public:
first_time_only_ = !repeat;
}
void set_priority(double priority)
{
priority_ = priority;
}
void set_menu_item(bool imi)
{
is_menu_item_ = imi;
@ -149,6 +158,7 @@ private:
*/
bool has_preloaded_;
int event_ref_;
double priority_;
config args_;
std::vector<std::shared_ptr<event_filter>> filters_;
std::string id_, types_;

View file

@ -67,14 +67,20 @@ namespace game_events
/** Create an event handler. */
void manager::add_event_handler_from_wml(const config& handler, game_lua_kernel& lk, bool is_menu_item)
{
auto new_handler = event_handlers_->add_event_handler(handler["name"], handler["id"], !handler["first_time_only"].to_bool(true), is_menu_item);
auto new_handler = event_handlers_->add_event_handler(
handler["name"],
handler["id"],
!handler["first_time_only"].to_bool(true),
handler["priority"].to_double(0.),
is_menu_item
);
if(new_handler.valid()) {
new_handler->read_filters(handler);
// Strip out anything that's used by the event system itself.
config args;
for(const auto& [attr, val] : handler.attribute_range()) {
if(attr == "id" || attr == "name" || attr == "first_time_only" || attr.compare(0, 6, "filter") == 0) {
if(attr == "id" || attr == "name" || attr == "first_time_only" || attr == "priority" || attr.compare(0, 6, "filter") == 0) {
continue;
}
args[attr] = val;
@ -90,6 +96,7 @@ void manager::add_event_handler_from_wml(const config& handler, game_lua_kernel&
<< (new_handler->names_raw().empty() ? "" : "'" + new_handler->names_raw() + "'")
<< (new_handler->id().empty() ? "" : "{id=" + new_handler->id() + "}")
<< (new_handler->repeatable() ? " (repeating" : " (first time only")
<< "; priority " + std::to_string(new_handler->priority())
<< (is_menu_item ? "; menu item)" : ")")
<< " with the following actions:\n"
<< args.debug();
@ -98,9 +105,9 @@ void manager::add_event_handler_from_wml(const config& handler, game_lua_kernel&
}
}
pending_event_handler manager::add_event_handler_from_lua(const std::string& name, const std::string& id, bool repeat, bool is_menu_item)
pending_event_handler manager::add_event_handler_from_lua(const std::string& name, const std::string& id, bool repeat, double priority, bool is_menu_item)
{
return event_handlers_->add_event_handler(name, id, repeat, is_menu_item);
return event_handlers_->add_event_handler(name, id, repeat, priority, is_menu_item);
}
/** Removes an event handler. */

View file

@ -63,7 +63,7 @@ public:
/** Create an event handler from an [event] tag. */
void add_event_handler_from_wml(const config& handler, game_lua_kernel& lk, bool is_menu_item = false);
/** Create an empty event handler. Expects the caller to finish setting up the event. */
pending_event_handler add_event_handler_from_lua(const std::string& name, const std::string& id, bool repeat = false, bool is_menu_item = false);
pending_event_handler add_event_handler_from_lua(const std::string& name, const std::string& id, bool repeat = false, double priority = 0., bool is_menu_item = false);
/** Removes an event handler. */
void remove_event_handler(const std::string& id);

View file

@ -75,6 +75,11 @@ std::string event_handlers::standardize_name(const std::string& name)
return retval;
}
bool event_handlers::cmp(const handler_ptr lhs, const handler_ptr rhs)
{
return lhs->priority() < rhs->priority();
}
/**
* Read-only access to the handlers with fixed event names, by event name.
*/
@ -93,7 +98,7 @@ handler_list& event_handlers::get(const std::string& name)
* An event with a nonempty ID will not be added if an event with that
* ID already exists.
*/
pending_event_handler event_handlers::add_event_handler(const std::string& name, const std::string& id, bool repeat, bool is_menu_item)
pending_event_handler event_handlers::add_event_handler(const std::string& name, const std::string& id, bool repeat, double priority, bool is_menu_item)
{
if(!id.empty()) {
// Ignore this handler if there is already one with this ID.
@ -119,6 +124,7 @@ pending_event_handler event_handlers::add_event_handler(const std::string& name,
// Create a new handler.
auto handler = std::make_shared<event_handler>(name, id);
handler->set_menu_item(is_menu_item);
handler->set_priority(priority);
handler->set_repeatable(repeat);
return {*this, handler};
}
@ -138,6 +144,7 @@ void event_handlers::finish_adding_event_handler(handler_ptr handler)
// construct weak_ptrs from the shared one.
DBG_EH << "inserting event handler for name=" << names << " with id=" << id;
active_.emplace_back(handler);
std::stable_sort(active_.rbegin(), active_.rend(), cmp);
// File by name.
if(utils::might_contain_variables(names)) {

View file

@ -85,6 +85,9 @@ public:
/** Utility to standardize the event names used in by_name_. */
static std::string standardize_name(const std::string& name);
/** Compare function to sort event handlers by priority. */
static bool cmp(const handler_ptr lhs, const handler_ptr rhs);
event_handlers()
: active_()
, by_name_()
@ -114,7 +117,7 @@ public:
handler_list& get(const std::string& name);
/** Adds an event handler. */
pending_event_handler add_event_handler(const std::string& name, const std::string& id, bool repeat, bool is_menu_item = false);
pending_event_handler add_event_handler(const std::string& name, const std::string& id, bool repeat, double priority = 0., bool is_menu_item = false);
/** Removes an event handler, identified by its ID. */
void remove_event_handler(const std::string& id);

View file

@ -362,6 +362,7 @@ void wml_menu_item::update_command(const config& new_command)
command_["name"] = event_name_;
command_["first_time_only"] = false;
command_["priority"] = 0.;
// Register the event.
LOG_NG << "Setting command for " << event_name_ << " to:\n" << command_;

View file

@ -3991,9 +3991,13 @@ static std::string read_event_name(lua_State* L, int idx)
* id: Event ID
* menu_item: True if this is a menu item (an ID is required); this means removing the menu item will automatically remove this event. Default false.
* first_time_only: Whether this event should fire again after the first time; default true.
* priority: Number that determines execution order. Events execute in order of decreasing priority, and secondarily in order of addition.
* filter: Event filters as a config with filter tags, a table of the form {filter_type = filter_contents}, or a function
* filter_args: Arbitrary data that will be passed to the filter, if it is a function. Ignored if the filter is specified as WML or a table.
* content: The content of the event. This is a WML table passed verbatim into the event when it fires. If no function is specified, it will be interpreted as ActionWML.
* action: The function to call when the event triggers. Defaults to wesnoth.wml_actions.command.
*
* Lua API: wesnoth.game_events.add
*/
int game_lua_kernel::intf_add_event(lua_State *L)
{
@ -4001,6 +4005,7 @@ int game_lua_kernel::intf_add_event(lua_State *L)
using namespace std::literals;
std::string name, id = luaW_table_get_def(L, 1, "id", ""s);
bool repeat = !luaW_table_get_def(L, 1, "first_time_only", true), is_menu_item = luaW_table_get_def(L, 1, "menu_item", false);
double priority = luaW_table_get_def(L, 1, "priority", 0.);
if(luaW_tableget(L, 1, "name")) {
name = read_event_name(L, -1);
} else if(is_menu_item) {
@ -4012,7 +4017,7 @@ int game_lua_kernel::intf_add_event(lua_State *L)
if(id.empty() && name.empty()) {
return luaL_argerror(L, 1, "either a name or id is required");
}
auto new_handler = man.add_event_handler_from_lua(name, id, repeat, is_menu_item);
auto new_handler = man.add_event_handler_from_lua(name, id, repeat, priority, is_menu_item);
if(new_handler.valid()) {
bool has_lua_filter = false;
new_handler->set_arguments(luaW_table_get_def(L, 1, "content", config{"__empty_lua_event", true}));
@ -4071,6 +4076,10 @@ int game_lua_kernel::intf_add_event(lua_State *L)
/** Add a new event handler
* Arg 1: Event to handle, as a string or list of strings; or menu item ID if this is a menu item
* Arg 2: The function to call when the event triggers
*
* Lua API:
* - wesnoth.game_events.add_repeating
* - wesnoth.game_events.add_menu
*/
template<bool is_menu_item>
int game_lua_kernel::intf_add_event_simple(lua_State *L)
@ -4078,6 +4087,7 @@ int game_lua_kernel::intf_add_event_simple(lua_State *L)
game_events::manager & man = *game_state_.events_manager_;
bool repeat = true;
std::string name = read_event_name(L, 1), id;
double priority = luaL_optnumber(L, 3, 0.);
if(name.empty()) {
return luaL_argerror(L, 1, "must not be empty");
}
@ -4085,7 +4095,7 @@ int game_lua_kernel::intf_add_event_simple(lua_State *L)
id = name;
name = "menu item " + name;
}
auto new_handler = man.add_event_handler_from_lua(name, id, repeat, is_menu_item);
auto new_handler = man.add_event_handler_from_lua(name, id, repeat, priority, is_menu_item);
if(new_handler.valid()) {
// An event with empty arguments is not added, so set some dummy arguments
new_handler->set_arguments(config{"__quick_lua_event", true});
@ -4096,6 +4106,8 @@ int game_lua_kernel::intf_add_event_simple(lua_State *L)
/** Add a new event handler
* Arg: A full event specification as a WML config
*
* WML API: [event]
*/
int game_lua_kernel::intf_add_event_wml(lua_State *L)
{

View file

@ -39,6 +39,7 @@ function wesnoth.game_events.on_mouse_move(x, y) end
---@field id string Event ID
---@field menu_item boolean True if this is a menu item (an ID is required); this means removing the menu item will automatically remove this event. Default false.
---@field first_time_only boolean Whether this event should fire again after the first time; default true.
---@field priority number Events execute in order of decreasing priority, and secondarily in order of addition
---@field filter WML|event_filter|fun(cfg:WML):boolean Event filters as a config with filter tags, a table of the form {filter_type = filter_contents}, or a function
---@field filter_args WML Arbitrary data that will be passed to the filter, if it is a function. Ignored if the filter is specified as WML or a table.
---@field content WML The content of the event. This is a WML table passed verbatim into the event when it fires. If no function is specified, it will be interpreted as ActionWML.
@ -51,7 +52,8 @@ function wesnoth.game_events.add(opts) end
---Add a repeating game event handler bound directly to a Lua function
---@param name string|string[] The event or events to handle
---@param action fun(WML) The function called when the event triggers
function wesnoth.game_events.add_repeating(name, action) end
---@param priority? number Events execute in order of decreasing priority, and secondarily in order of addition
function wesnoth.game_events.add_repeating(name, action, priority) end
---Add a game event handler triggered from a menu item, bound directly to a Lua function
---@param id string

View file

@ -445,6 +445,12 @@
0 order_of_variable_events3
0 premature_end_turn1
2 premature_end_turn2
0 events_test_priority_vs_origin
0 events_test_same_priority
0 events_test_multi_int
0 events_test_multi_float
0 events_test_lua_events_add_priority_vs_origin
0 events_test_lua_events_add_repeating_priority_vs_origin
0 kill_fires_events
# Game mechanics
0 heal