Port [object] ActionWML tag from C++ to Lua

Lua API additions:
- wesnoth.show_popup_dialog()
- optional write_to_mods parameter to wesnoth.add_modification
This commit is contained in:
Celtic Minstrel 2015-09-17 11:30:24 -04:00
parent d4835b0157
commit 376020097f
10 changed files with 119 additions and 118 deletions

View file

@ -14,6 +14,7 @@ end
wesnoth.require "lua/wml/objectives.lua"
wesnoth.require "lua/wml/items.lua"
wesnoth.require "lua/wml/message.lua"
wesnoth.require "lua/wml/object.lua"
local helper = wesnoth.require "lua/helper.lua"
local location_set = wesnoth.require "lua/location_set.lua"

80
data/lua/wml/object.lua Normal file
View file

@ -0,0 +1,80 @@
local helper = wesnoth.require "lua/helper.lua"
local utils = wesnoth.require "lua/wml-utils.lua"
local T = helper.set_wml_tag_metatable {}
local wml_actions = wesnoth.wml_actions
local used_items = {}
function wml_actions.object(cfg)
local context = wesnoth.current.event_context
-- If this item has already been used
if cfg.id and used_items[cfg.id] then return end
local unit
local filter = helper.get_child(cfg, "filter")
if filter then
unit = wesnoth.get_units(filter)[1]
end
if not unit then
unit = wesnoth.get_unit(contxt.x, context.y)
end
local command_type, text
if unit then
text = tostring(cfg.description or "")
command_type = "then"
local dvs = cfg.delayed_variable_substitution
local add = cfg.no_write ~= true
if dvs then
wesnoth.add_modification(unit, "object", helper.literal(cfg), add)
else
wesnoth.add_modification(unit, "object", helper.parsed(cfg), add)
end
wesnoth.select_hex(unit.x, unit.y)
-- Mark this item as used up
if cfg.id then used_items[cfg.id] = true end
else
text = tostring(cfg.cannot_use_message or "")
command_type = "else"
end
-- Default to silent if object has no description
local silent = cfg.silent
if silent == nil then silent = (text:len() == 0) end
if not silent then
wml_actions.redraw{}
local name = tostring(cfg.name or "")
wesnoth.show_popup_dialog(name, text, cfg.image)
end
for cmd in helper.child_range(cfg, command_type) do
utils.handle_event_commands(cmd)
end
end
local old_on_load = wesnoth.game_events.on_load
function wesnoth.game_events.on_load(cfg)
for i = 1,#cfg do
if cfg[i][1] == "used_items" then
-- Not quite sure if this will work
-- Might need to loop through and copy each ID separately
used_items = cfg[i][2]
table.remove(cfg, i)
break
end
end
old_on_load(cfg)
end
local old_on_save = wesnoth.game_events.on_save
function wesnoth.game_events.on_save()
local cfg = old_on_save()
table.insert(cfg, T.used_items(used_items) )
return cfg
end

View file

@ -248,11 +248,6 @@ namespace { // Support functions
resources::screen->recalculate_minimap();
resources::screen->invalidate_all();
}
void handle_event_commands(const queued_event& event_info, const vconfig &cfg) {
assert(resources::lua_kernel);
resources::lua_kernel->run_wml_action("command", cfg, event_info);
}
} // end anonymous namespace (support functions)
void handle_deprecated_message(const config& cfg)
@ -492,81 +487,6 @@ WML_HANDLER_FUNCTION(move_units_fake, /*event_info*/, cfg)
LOG_NG << "Units moved\n";
}
WML_HANDLER_FUNCTION(object, event_info, cfg)
{
const vconfig & filter = cfg.child("filter");
boost::optional<unit_filter> ufilt;
if (!filter.null())
ufilt = unit_filter(filter, resources::filter_con);
std::string id = cfg["id"];
// If this item has already been used
assert(resources::game_events);
if ( resources::game_events->item_used(id) )
return;
std::string image = cfg["image"];
std::string caption = cfg["name"];
std::string text;
map_location loc;
if(ufilt) {
unit_const_ptr u_ptr = ufilt->first_match_on_map();
if (u_ptr) {
loc = u_ptr->get_location();
}
}
if(loc.valid() == false) {
loc = event_info.loc1;
}
const unit_map::iterator u = resources::units->find(loc);
std::string command_type = "then";
if ( u != resources::units->end() && (!ufilt || ufilt->matches(*u)) )
{
text = cfg["description"].str();
const bool no_add = cfg["no_write"].to_bool(false);
if(cfg["delayed_variable_substitution"].to_bool(false))
u->add_modification("object", cfg.get_config(), no_add);
else
u->add_modification("object", cfg.get_parsed_config(), no_add);
resources::screen->select_hex(event_info.loc1);
resources::screen->invalidate_unit();
// Mark this item as used up.
resources::game_events->item_used(id, true);
} else {
text = cfg["cannot_use_message"].str();
command_type = "else";
}
// Default to silent if object has no description
const bool silent = cfg.has_attribute("silent") ? cfg["silent"].to_bool() : !cfg.has_attribute("description");
if (!silent)
{
// Redraw the unit, with its new stats
resources::screen->draw();
try {
gui2::show_transient_message(resources::screen->video(), caption, text, image, true);
} catch(utf8::invalid_utf8_exception&) {
// we already had a warning so do nothing.
}
}
BOOST_FOREACH(const vconfig &cmd, cfg.get_children(command_type)) {
handle_event_commands(event_info, cmd);
}
}
/// If we should recall units that match a certain description.
WML_HANDLER_FUNCTION(recall, /*event_info*/, cfg)
{

View file

@ -64,28 +64,6 @@ void manager::add_event_handler(const config & handler, bool is_menu_item)
event_handlers_->add_event_handler(handler, *this, is_menu_item);
}
/**
* Checks if an item has been used.
* (An empty id will never be considered used.)
*/
bool manager::item_used(const std::string & id)
{
return !id.empty() && used_items_.count(id) > 0;
}
/** Records if an item has been used. */
void manager::item_used(const std::string & id, bool used)
{
// Empty IDs are not tracked.
if ( id.empty() )
return;
if ( used )
used_items_.insert(id);
else
used_items_.erase(id);
}
/** Removes an event handler. */
void manager::remove_event_handler(const std::string & id)
{
@ -98,7 +76,6 @@ void manager::remove_event_handler(const std::string & id)
manager::manager(const config& cfg, const boost::shared_ptr<t_context> & res)
: event_handlers_(new t_event_handlers())
, unit_wml_ids_()
, used_items_()
, pump_(new game_events::t_pump(*this, res))
, resources_(res)
, wml_menu_items_()
@ -122,14 +99,6 @@ manager::manager(const config& cfg, const boost::shared_ptr<t_context> & res)
resources_->lua_kernel->set_wml_action(action_cur->first, action_cur->second);
}
const std::string used = cfg["used_items"];
if(!used.empty()) {
const std::vector<std::string>& v = utils::split(used);
for(std::vector<std::string>::const_iterator i = v.begin(); i != v.end(); ++i) {
item_used(*i, true);
}
}
// Create the event handlers for menu items.
wml_menu_items_.init_handlers(me_);
}
@ -238,7 +207,6 @@ void manager::write_events(config& cfg)
cfg.add_child("event", eh->get_config());
}
cfg["used_items"] = utils::join(used_items_);
cfg["unit_wml_ids"] = utils::join(unit_wml_ids_);
wml_menu_items_.to_config(cfg);
}

View file

@ -112,7 +112,6 @@ namespace game_events {
boost::scoped_ptr<t_event_handlers> event_handlers_;
std::set<std::string> unit_wml_ids_;
std::set<std::string> used_items_;
boost::scoped_ptr<game_events::t_pump> pump_;
boost::shared_ptr<t_context> resources_;
@ -127,10 +126,6 @@ namespace game_events {
/// Create an event handler.
void add_event_handler(const config & handler, bool is_menu_item=false);
/// Checks if an item has been used.
bool item_used(const std::string & id);
/// Records if an item has been used.
void item_used(const std::string & id, bool used);
/// Removes an event handler.
void remove_event_handler(const std::string & id);

View file

@ -3307,6 +3307,7 @@ static int intf_get_traits(lua_State* L)
* - Arg 1: unit.
* - Arg 2: string.
* - Arg 3: WML table.
* - Arg 4: (optional) Whether to add to [modifications] - default true
*/
static int intf_add_modification(lua_State *L)
{
@ -3320,9 +3321,13 @@ static int intf_add_modification(lua_State *L)
if (sm != "advancement" && sm != "object" && sm != "trait") {
return luaL_argerror(L, 2, "unknown modification type");
}
bool write_to_mods = true;
if (!lua_isnone(L, 4)) {
write_to_mods = lua_toboolean(L, 4);
}
config cfg = luaW_checkconfig(L, 3);
u->add_modification(sm, cfg);
u->add_modification(sm, cfg, !write_to_mods);
return 0;
}

View file

@ -19,6 +19,7 @@
#include "gui/dialogs/gamestate_inspector.hpp"
#include "gui/dialogs/lua_interpreter.hpp"
#include "gui/dialogs/wml_message.hpp"
#include "gui/dialogs/transient_message.hpp"
#include "gui/widgets/clickable.hpp" // for tclickable_
#include "gui/widgets/control.hpp" // for tcontrol
#include "gui/widgets/multi_page.hpp" // for tmulti_page
@ -294,6 +295,21 @@ int show_message_dialog(lua_State *L, CVideo & video)
return 2;
}
/**
* Displays a popup message
* - Arg 1: Title (allows Pango markup)
* - Arg 2: Message (allows Pango markup)
* - Arg 3: Image (optional)
*/
int show_popup_dialog(lua_State *L, CVideo & video) {
std::string title = luaL_checkstring(L, 1);
std::string msg = luaL_checkstring(L, 2);
std::string image = lua_isnoneornil(L, 3) ? "" : luaL_checkstring(L, 3);
gui2::show_transient_message(video, title, msg, image, true, true);
return 0;
}
/**
* Sets the value of a widget on the current dialog.

View file

@ -33,6 +33,7 @@ int intf_set_dialog_visible(lua_State *L);
int intf_add_dialog_tree_node(lua_State *L);
int show_dialog(lua_State *L, CVideo & video);
int show_message_dialog(lua_State *L, CVideo & video);
int show_popup_dialog(lua_State *L, CVideo & video);
int show_lua_console(lua_State*L, CVideo & video, lua_kernel_base * lk);
int show_gamestate_inspector(CVideo & video, const vconfig & cfg);
int intf_remove_dialog_item(lua_State *L);

View file

@ -130,6 +130,17 @@ int lua_kernel_base::intf_show_message_dialog(lua_State *L)
return lua_gui2::show_message_dialog(L, *video_);
}
int lua_kernel_base::intf_show_popup_dialog(lua_State *L)
{
if (!video_) {
ERR_LUA << "Cannot show dialog, no video object is available to this lua kernel.";
lua_error(L);
return 0;
}
return lua_gui2::show_popup_dialog(L, *video_);
}
// The show lua console callback is similarly a method of lua kernel
int lua_kernel_base::intf_show_lua_console(lua_State *L)
{
@ -269,6 +280,7 @@ lua_kernel_base::lua_kernel_base(CVideo * video)
{ "require", &dispatch<&lua_kernel_base::intf_require> },
{ "show_dialog", &dispatch<&lua_kernel_base::intf_show_dialog> },
{ "show_message_dialog", &dispatch<&lua_kernel_base::intf_show_message_dialog> },
{ "show_popup_dialog", &dispatch<&lua_kernel_base::intf_show_popup_dialog> },
{ "show_lua_console", &dispatch<&lua_kernel_base::intf_show_lua_console> },
{ NULL, NULL }
};

View file

@ -106,6 +106,9 @@ protected:
// Show a message dialog, possibly with options
int intf_show_message_dialog(lua_State * L);
// Show a transient popup message
int intf_show_popup_dialog(lua_State * L);
// Show the interactive lua console (for debugging purposes)
int intf_show_lua_console(lua_State * L);