Events are now a Lua function instead of WML
The function is specified by [event]code= and will be passed the entire contents of the [event] tag (including the code itself). If code= is omitted, a default is supplied which runs ActionWML; however, internally it is still a function rather than a list of ActionWML commands.
This commit is contained in:
parent
30df6fe4ff
commit
11e5700848
14 changed files with 115 additions and 31 deletions
|
@ -40,13 +40,14 @@ namespace game_events
|
|||
{
|
||||
/* ** event_handler ** */
|
||||
|
||||
event_handler::event_handler(config&& cfg, bool imi, const std::vector<std::string>& types)
|
||||
event_handler::event_handler(config&& cfg, bool imi, const std::vector<std::string>& types, game_lua_kernel& lk)
|
||||
: first_time_only_(cfg["first_time_only"].to_bool(true))
|
||||
, is_menu_item_(imi)
|
||||
, disabled_(false)
|
||||
, cfg_(cfg)
|
||||
, types_(types)
|
||||
{
|
||||
event_ref_ = lk.save_wml_event(cfg);
|
||||
}
|
||||
|
||||
void event_handler::disable()
|
||||
|
@ -69,7 +70,7 @@ void event_handler::handle_event(const queued_event& event_info, game_lua_kernel
|
|||
disable();
|
||||
}
|
||||
|
||||
lk.run_wml_action("command", vconfig(cfg_, false), event_info);
|
||||
lk.run_wml_event(event_ref_, vconfig(cfg_, false), event_info);
|
||||
sound::commit_music_changes();
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ struct queued_event;
|
|||
class event_handler
|
||||
{
|
||||
public:
|
||||
event_handler(config&& cfg, bool is_menu_item, const std::vector<std::string>& types);
|
||||
event_handler(config&& cfg, bool is_menu_item, const std::vector<std::string>& types, game_lua_kernel& lk);
|
||||
|
||||
const std::vector<std::string>& names() const
|
||||
{
|
||||
|
@ -76,6 +76,7 @@ private:
|
|||
bool is_menu_item_;
|
||||
bool disabled_;
|
||||
config cfg_;
|
||||
int event_ref_;
|
||||
std::vector<std::string> types_;
|
||||
};
|
||||
|
||||
|
|
|
@ -64,9 +64,9 @@ namespace
|
|||
namespace game_events
|
||||
{
|
||||
/** Create an event handler. */
|
||||
void manager::add_event_handler(const config& handler, bool is_menu_item)
|
||||
void manager::add_event_handler(const config& handler, game_lua_kernel& lk, bool is_menu_item)
|
||||
{
|
||||
event_handlers_->add_event_handler(handler, is_menu_item);
|
||||
event_handlers_->add_event_handler(handler, lk, is_menu_item);
|
||||
}
|
||||
|
||||
/** Removes an event handler. */
|
||||
|
@ -91,10 +91,10 @@ manager::manager()
|
|||
{
|
||||
}
|
||||
|
||||
void manager::read_scenario(const config& scenario_cfg)
|
||||
void manager::read_scenario(const config& scenario_cfg, game_lua_kernel& lk)
|
||||
{
|
||||
for(const config& ev : scenario_cfg.child_range("event")) {
|
||||
add_event_handler(ev);
|
||||
add_event_handler(ev, lk);
|
||||
}
|
||||
|
||||
for(const std::string& id : utils::split(scenario_cfg["unit_wml_ids"])) {
|
||||
|
@ -104,14 +104,14 @@ void manager::read_scenario(const config& scenario_cfg)
|
|||
wml_menu_items_.set_menu_items(scenario_cfg);
|
||||
|
||||
// Create the event handlers for menu items.
|
||||
wml_menu_items_.init_handlers();
|
||||
wml_menu_items_.init_handlers(lk);
|
||||
}
|
||||
|
||||
manager::~manager()
|
||||
{
|
||||
}
|
||||
|
||||
void manager::add_events(const config::const_child_itors& cfgs, const std::string& type)
|
||||
void manager::add_events(const config::const_child_itors& cfgs, game_lua_kernel& lk, const std::string& type)
|
||||
{
|
||||
if(!type.empty()) {
|
||||
if(std::find(unit_wml_ids_.begin(), unit_wml_ids_.end(), type) != unit_wml_ids_.end()) {
|
||||
|
@ -127,7 +127,7 @@ void manager::add_events(const config::const_child_itors& cfgs, const std::strin
|
|||
continue;
|
||||
}
|
||||
|
||||
add_event_handler(new_ev);
|
||||
add_event_handler(new_ev, lk);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
class filter_context;
|
||||
class game_data;
|
||||
class game_lua_kernel;
|
||||
|
||||
namespace game_events
|
||||
{
|
||||
|
@ -55,11 +56,11 @@ public:
|
|||
manager& operator=(const manager&) = delete;
|
||||
|
||||
explicit manager();
|
||||
void read_scenario(const config& scenario_cfg);
|
||||
void read_scenario(const config& scenario_cfg, game_lua_kernel& lk);
|
||||
~manager();
|
||||
|
||||
/** Create an event handler. */
|
||||
void add_event_handler(const config& handler, bool is_menu_item = false);
|
||||
void add_event_handler(const config& handler, game_lua_kernel& lk, bool is_menu_item = false);
|
||||
|
||||
/** Removes an event handler. */
|
||||
void remove_event_handler(const std::string& id);
|
||||
|
@ -67,7 +68,7 @@ public:
|
|||
/** Gets an event handler by ID */
|
||||
const handler_ptr get_event_handler_by_id(const std::string& id);
|
||||
|
||||
void add_events(const config::const_child_itors& cfgs, const std::string& type = std::string());
|
||||
void add_events(const config::const_child_itors& cfgs, game_lua_kernel& lk, const std::string& type = std::string());
|
||||
|
||||
void write_events(config& cfg) const;
|
||||
|
||||
|
|
|
@ -92,7 +92,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.
|
||||
*/
|
||||
void event_handlers::add_event_handler(const config& cfg, bool is_menu_item)
|
||||
void event_handlers::add_event_handler(const config& cfg, game_lua_kernel& lk, bool is_menu_item)
|
||||
{
|
||||
// Someone decided to register an empty event... bail.
|
||||
if(cfg.empty()) {
|
||||
|
@ -145,7 +145,7 @@ void event_handlers::add_event_handler(const config& cfg, bool is_menu_item)
|
|||
// Do note active_ holds the main shared_ptr, and the other three containers
|
||||
// construct weak_ptrs from the shared one.
|
||||
DBG_EH << "inserting event handler for name=" << name << " with id=" << id << "\n";
|
||||
active_.emplace_back(new event_handler(std::move(event_cfg), is_menu_item, standardized_names));
|
||||
active_.emplace_back(new event_handler(std::move(event_cfg), is_menu_item, standardized_names, lk));
|
||||
|
||||
//
|
||||
// !! event_cfg is invalid past this point! DO NOT USE!
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include <deque>
|
||||
#include <unordered_map>
|
||||
|
||||
class game_lua_kernel;
|
||||
|
||||
namespace game_events
|
||||
{
|
||||
// event_handlers is essentially the implementation details of the manager
|
||||
|
@ -82,7 +84,7 @@ public:
|
|||
handler_list& get(const std::string& name);
|
||||
|
||||
/** Adds an event handler. */
|
||||
void add_event_handler(const config& cfg, bool is_menu_item = false);
|
||||
void add_event_handler(const config& cfg, game_lua_kernel& lk, bool is_menu_item = false);
|
||||
|
||||
/** Removes an event handler, identified by its ID. */
|
||||
void remove_event_handler(const std::string& id);
|
||||
|
|
|
@ -204,12 +204,12 @@ void wml_menu_item::finish_handler()
|
|||
}
|
||||
}
|
||||
|
||||
void wml_menu_item::init_handler()
|
||||
void wml_menu_item::init_handler(game_lua_kernel& lk)
|
||||
{
|
||||
// If this menu item has a [command], add a handler for it.
|
||||
if(!command_.empty()) {
|
||||
assert(resources::game_events);
|
||||
resources::game_events->add_event_handler(command_, true);
|
||||
resources::game_events->add_event_handler(command_, lk, true);
|
||||
}
|
||||
|
||||
// Hotkey support
|
||||
|
@ -367,7 +367,8 @@ void wml_menu_item::update_command(const config& new_command)
|
|||
// Register the event.
|
||||
LOG_NG << "Setting command for " << event_name_ << " to:\n" << command_;
|
||||
assert(resources::game_events);
|
||||
resources::game_events->add_event_handler(command_, true);
|
||||
assert(resources::lua_kernel);
|
||||
resources::game_events->add_event_handler(command_, *resources::lua_kernel, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
class filter_context;
|
||||
class game_data;
|
||||
class game_lua_kernel;
|
||||
struct map_location;
|
||||
|
||||
namespace game_events
|
||||
|
@ -109,7 +110,7 @@ public:
|
|||
void finish_handler();
|
||||
|
||||
/** Initializes the implicit event handler for an inlined [command]. */
|
||||
void init_handler();
|
||||
void init_handler(game_lua_kernel& lk);
|
||||
|
||||
/**
|
||||
* The text to put in a menu for this item.
|
||||
|
|
|
@ -163,7 +163,7 @@ wmi_manager::item_ptr wmi_manager::get_item(const std::string& id) const
|
|||
/**
|
||||
* Initializes the implicit event handlers for inlined [command]s.
|
||||
*/
|
||||
void wmi_manager::init_handlers() const
|
||||
void wmi_manager::init_handlers(game_lua_kernel& lk) const
|
||||
{
|
||||
// Applying default hotkeys here currently does not work because
|
||||
// the hotkeys are reset by play_controler::init_managers() ->
|
||||
|
@ -179,7 +179,7 @@ void wmi_manager::init_handlers() const
|
|||
// Loop through each menu item.
|
||||
for(const auto& item : wml_menu_items_) {
|
||||
// If this menu item has a [command], add a handler for it.
|
||||
item.second->init_handler();
|
||||
item.second->init_handler(lk);
|
||||
|
||||
// Count the menu items (for the diagnostic message).
|
||||
++wmi_count;
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
class config;
|
||||
class filter_context;
|
||||
class game_data;
|
||||
class game_lua_kernel;
|
||||
struct map_location;
|
||||
class unit_map;
|
||||
class vconfig;
|
||||
|
@ -79,7 +80,7 @@ public:
|
|||
unit_map& units) const;
|
||||
|
||||
/** Initializes the implicit event handlers for inlined [command]s. */
|
||||
void init_handlers() const;
|
||||
void init_handlers(game_lua_kernel& lk) const;
|
||||
|
||||
void to_config(config& cfg) const;
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ game_state::game_state(const config& level, play_controller& pc, game_board& boa
|
|||
, first_human_team_(-1)
|
||||
{
|
||||
lua_kernel_->load_core();
|
||||
events_manager_->read_scenario(level);
|
||||
events_manager_->read_scenario(level, *lua_kernel_);
|
||||
if(const config& endlevel_cfg = level.child("end_level_data")) {
|
||||
end_level_data el_data;
|
||||
el_data.read(endlevel_cfg);
|
||||
|
@ -178,7 +178,7 @@ void game_state::place_sides_in_preferred_locations(const config& level)
|
|||
|
||||
void game_state::init(const config& level, play_controller & pc)
|
||||
{
|
||||
events_manager_->read_scenario(level);
|
||||
events_manager_->read_scenario(level, *lua_kernel_);
|
||||
gui2::dialogs::loading_screen::progress(loading_stage::init_teams);
|
||||
if (level["modify_placing"].to_bool()) {
|
||||
LOG_NG << "modifying placing..." << std::endl;
|
||||
|
|
|
@ -103,6 +103,7 @@
|
|||
#include "units/map.hpp" // for unit_map, etc
|
||||
#include "units/ptr.hpp" // for unit_const_ptr, unit_ptr
|
||||
#include "units/types.hpp" // for unit_type_data, unit_types, etc
|
||||
#include "utils/scope_exit.hpp"
|
||||
#include "variable.hpp" // for vconfig, etc
|
||||
#include "variable_info.hpp"
|
||||
#include "whiteboard/manager.hpp" // for whiteboard
|
||||
|
@ -3695,9 +3696,9 @@ int game_lua_kernel::intf_add_event(lua_State *L)
|
|||
game_events::manager & man = *game_state_.events_manager_;
|
||||
|
||||
if (!cfg["delayed_variable_substitution"].to_bool(true)) {
|
||||
man.add_event_handler(cfg.get_parsed_config());
|
||||
man.add_event_handler(cfg.get_parsed_config(), *this);
|
||||
} else {
|
||||
man.add_event_handler(cfg.get_config());
|
||||
man.add_event_handler(cfg.get_config(), *this);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -4481,6 +4482,7 @@ game_lua_kernel::game_lua_kernel(game_state & gs, play_controller & pc, reports
|
|||
, play_controller_(pc)
|
||||
, reports_(reports_object)
|
||||
, level_lua_()
|
||||
, EVENT_TABLE(LUA_NOREF)
|
||||
, queued_events_()
|
||||
, map_locked_(0)
|
||||
{
|
||||
|
@ -5225,6 +5227,73 @@ bool game_lua_kernel::run_wml_conditional(const std::string& cmd, const vconfig&
|
|||
return b;
|
||||
}
|
||||
|
||||
static int intf_run_event_wml(lua_State* L)
|
||||
{
|
||||
int argIdx = lua_gettop(L);
|
||||
if(!luaW_getglobal(L, "wesnoth", "wml_actions", "command")) {
|
||||
return luaL_error(L, "wesnoth.wml_actions.command is missing");
|
||||
}
|
||||
lua_pushvalue(L, argIdx);
|
||||
lua_call(L, 1, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int game_lua_kernel::save_wml_event(const config& evt)
|
||||
{
|
||||
lua_State* L = mState;
|
||||
if(EVENT_TABLE == LUA_NOREF) {
|
||||
lua_newtable(L);
|
||||
EVENT_TABLE = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
}
|
||||
lua_geti(L, LUA_REGISTRYINDEX, EVENT_TABLE);
|
||||
int evtIdx = lua_gettop(L);
|
||||
ON_SCOPE_EXIT(L) {
|
||||
lua_pop(L, 1);
|
||||
};
|
||||
if(evt.has_attribute("code")) {
|
||||
std::ostringstream name;
|
||||
name << "event ";
|
||||
if(evt.has_attribute("name")) {
|
||||
name << evt["name"];
|
||||
} else {
|
||||
name << "<anon>";
|
||||
}
|
||||
if(evt.has_attribute("id")) {
|
||||
name << "[id=" << evt["id"] << "]";
|
||||
}
|
||||
if(!load_string(evt["code"].str().c_str(), name.str())) {
|
||||
ERR_LUA << "Failed to register WML event: " << name.str();
|
||||
return LUA_NOREF;
|
||||
}
|
||||
} else {
|
||||
lua_pushcfunction(L, intf_run_event_wml);
|
||||
}
|
||||
int ref = luaL_ref(L, evtIdx);
|
||||
return ref;
|
||||
}
|
||||
|
||||
void game_lua_kernel::clear_wml_event(int ref)
|
||||
{
|
||||
lua_State* L = mState;
|
||||
lua_geti(L, LUA_REGISTRYINDEX, EVENT_TABLE);
|
||||
luaL_unref(L, -1, ref);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
bool game_lua_kernel::run_wml_event(int ref, const vconfig& args, const game_events::queued_event& ev)
|
||||
{
|
||||
lua_State* L = mState;
|
||||
lua_geti(L, LUA_REGISTRYINDEX, EVENT_TABLE);
|
||||
ON_SCOPE_EXIT(L) {
|
||||
lua_pop(L, 1);
|
||||
};
|
||||
lua_geti(L, -1, ref);
|
||||
if(lua_isnil(L, -1)) return false;
|
||||
luaW_pushvconfig(L, args);
|
||||
queued_event_context dummy(&ev, queued_events_);
|
||||
return protected_call(1, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Runs a script from a location filter.
|
||||
|
|
|
@ -58,6 +58,7 @@ class game_lua_kernel : public lua_kernel_base
|
|||
tod_manager & tod_man();
|
||||
|
||||
config level_lua_;
|
||||
int EVENT_TABLE;
|
||||
|
||||
std::stack<game_events::queued_event const * > queued_events_;
|
||||
|
||||
|
@ -218,6 +219,12 @@ public:
|
|||
bool run_filter(char const *name, const team& t);
|
||||
bool run_filter(char const *name, int nArgs);
|
||||
bool run_wml_conditional(const std::string&, const vconfig&);
|
||||
/** Store a WML event in the Lua registry, as a function */
|
||||
int save_wml_event(const config& evt);
|
||||
/** Clear a WML event store in the Lua registry */
|
||||
void clear_wml_event(int ref);
|
||||
/** Run a WML store in the Lua registry */
|
||||
bool run_wml_event(int ref, const vconfig& args, const game_events::queued_event& ev);
|
||||
|
||||
virtual void log_error(char const* msg, char const* context = "Lua error") override;
|
||||
|
||||
|
|
|
@ -421,8 +421,8 @@ void unit::init(const config& cfg, bool use_traits, const vconfig* vcfg)
|
|||
}
|
||||
}
|
||||
|
||||
if(resources::game_events) {
|
||||
resources::game_events->add_events(events_.child_range("event"));
|
||||
if(resources::game_events && resources::lua_kernel) {
|
||||
resources::game_events->add_events(events_.child_range("event"), *resources::lua_kernel);
|
||||
}
|
||||
|
||||
random_traits_ = cfg["random_traits"].to_bool(true);
|
||||
|
@ -997,8 +997,8 @@ void unit::advance_to(const unit_type& u_type, bool use_traits)
|
|||
}
|
||||
|
||||
// In case the unit carries EventWML, apply it now
|
||||
if(resources::game_events) {
|
||||
resources::game_events->add_events(new_type.events(), new_type.id());
|
||||
if(resources::game_events && resources::lua_kernel) {
|
||||
resources::game_events->add_events(new_type.events(), *resources::lua_kernel, new_type.id());
|
||||
}
|
||||
bool bool_small_profile = get_attr_changed(UA_SMALL_PROFILE);
|
||||
bool bool_profile = get_attr_changed(UA_PROFILE);
|
||||
|
|
Loading…
Add table
Reference in a new issue