Skip to content

Commit

Permalink
Port [object] ActionWML tag from C++ to Lua
Browse files Browse the repository at this point in the history
Lua API additions:
- wesnoth.show_popup_dialog()
- optional write_to_mods parameter to wesnoth.add_modification
  • Loading branch information
CelticMinstrel committed Sep 19, 2015
1 parent d4835b0 commit 3760200
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 118 deletions.
1 change: 1 addition & 0 deletions data/lua/wml-tags.lua
Expand Up @@ -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"
Expand Down
80 changes: 80 additions & 0 deletions data/lua/wml/object.lua
@@ -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
80 changes: 0 additions & 80 deletions src/game_events/action_wml.cpp
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
{
Expand Down
32 changes: 0 additions & 32 deletions src/game_events/manager.cpp
Expand Up @@ -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)
{
Expand All @@ -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_()
Expand All @@ -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_);
}
Expand Down Expand Up @@ -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);
}
Expand Down
5 changes: 0 additions & 5 deletions src/game_events/manager.hpp
Expand Up @@ -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_;
Expand All @@ -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);

Expand Down
7 changes: 6 additions & 1 deletion src/scripting/game_lua_kernel.cpp
Expand Up @@ -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)
{
Expand All @@ -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;
}

Expand Down
16 changes: 16 additions & 0 deletions src/scripting/lua_gui2.cpp
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions src/scripting/lua_gui2.hpp
Expand Up @@ -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);
Expand Down
12 changes: 12 additions & 0 deletions src/scripting/lua_kernel_base.cpp
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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 }
};
Expand Down
3 changes: 3 additions & 0 deletions src/scripting/lua_kernel_base.hpp
Expand Up @@ -106,6 +106,9 @@ class lua_kernel_base {

// 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);
Expand Down

0 comments on commit 3760200

Please sign in to comment.