Port "trivial" WML tags to Lua

This is more about adding Lua API for things that should have it than porting WML tags to Lua.
The following new Lua API functions have been added to the wesnoth table:
- add_fog, remove_fog
- add_sound_source, remove_sound_source, get_sound_source
- log
This commit is contained in:
Celtic Minstrel 2016-04-05 02:24:42 -04:00
parent ff618e7eb3
commit 5cf12798ce
11 changed files with 212 additions and 117 deletions

View file

@ -120,6 +120,13 @@ Version 1.13.4+dev:
of the time in the overall schedule (eg, 1 would be dawn in the default
schedule). Optional second argument takes a time area ID, to set
local instead of global time.
* New wesnoth.add_fog and wesnoth.remove_fog functions allow changing fog
on the map. The [lift_fog] and [clear_fog] tags now use this.
* New wesnoth.add_sound_source, wesnoth.remove_sound_source, and
wesnoth.get_sound_source functions to allow manipulation of sound
sources. The [sound_source] and [remove_sound_source] now use these.
* New wesnoth.log function for printing log messages. The [wml_message]
and [deprecated_message] tags now use this.
* WML tables defined in Lua now accept string keys with array values
(where "array" is a table whose keys are all integers). This joins
the elements of the array with commas and produces a single string

View file

@ -1003,3 +1003,39 @@ wml_actions.teleport = function(cfg)
end
wesnoth.teleport(unit, cfg.check_passability == false, cfg.clear_shroud ~= false, cfg.animate)
end
function wml_actions.remove_sound_source(cfg)
wesnoth.remove_sound_source(cfg.id)
end
function wml_actions.sound_source(cfg)
wesnoth.add_sound_source(cfg)
end
function wml_actions.deprecated_message(cfg)
wesnoth.log('wml', cfg.message)
end
function wml_actions.wml_message(cfg)
local logger = logger_aliases[cfg.logger] or ''
wesnoth.log(cfg.logger or 'warn', cfg.message. cfg.to_chat)
end
local function parse_fog_cfg(cfg)
-- Side filter
local ssf = helper.child(cfg, "filter_side")
local sides = wesnoth.get_sides(ssf or {})
-- Location filter
local locs = wesnoth.get_locations(cfg)
return locs, sides
end
function wml_actions.lift_fog(cfg)
local locs, sides = parse_fog_cfg(cfg)
wesnoth.remove_fog(sides, locs, not cfg.multiturn)
end
function wml_actions.reset_fog(cfg)
local locs, sides = parse_fog_cfg(cfg)
wesnoth.add_fog(sides, locs, cfg.reset_view)
end

View file

@ -5,10 +5,7 @@ local location_set = wesnoth.require "lua/location_set.lua"
local _ = wesnoth.textdomain "wesnoth"
local function log(msg, level)
wesnoth.wml_actions.wml_message({
message = msg,
logger = level,
})
wesnoth.log(level, msg, true)
end
local function get_image(cfg, speaker)

View file

@ -205,71 +205,8 @@ namespace { // Support functions
}
return path;
}
/**
* Implements the lifting and resetting of fog via WML.
* Keeping affect_normal_fog as false causes only the fog override to be affected.
* Otherwise, fog lifting will be implemented similar to normal sight (cannot be
* individually reset and ends at the end of the turn), and fog resetting will, in
* addition to removing overrides, extend the specified teams' normal fog to all
* hexes.
*/
void toggle_fog(const bool clear, const vconfig& cfg, const bool affect_normal_fog=false)
{
// Filter the sides.
const vconfig &ssf = cfg.child("filter_side");
const side_filter s_filter(ssf.null() ? vconfig::empty_vconfig() : ssf, resources::filter_con);
const std::vector<int> sides = s_filter.get_teams();
// Filter the locations.
std::set<map_location> locs;
const terrain_filter t_filter(cfg, resources::filter_con);
t_filter.get_locations(locs, true);
// Loop through sides.
for (const int &side_num : sides)
{
team &t = (*resources::teams)[side_num-1];
if ( !clear )
{
// Extend fog.
t.remove_fog_override(locs);
if ( affect_normal_fog )
t.refog();
}
else if ( !affect_normal_fog )
// Force the locations clear of fog.
t.add_fog_override(locs);
else
// Simply clear fog from the locations.
for (const map_location &hex : locs) {
t.clear_fog(hex);
}
}
// Flag a screen update.
resources::screen->recalculate_minimap();
resources::screen->invalidate_all();
}
} // end anonymous namespace (support functions)
void handle_deprecated_message(const config& cfg)
{
// Note: no need to translate the string, since only used for deprecated things.
const std::string& message = cfg["message"];
lg::wml_error() << message << '\n';
}
void handle_wml_log_message(const config& cfg)
{
const std::string& logger = cfg["logger"];
const std::string& msg = cfg["message"];
bool in_chat = cfg["to_chat"].to_bool(true);
resources::game_events->pump().put_wml_message(logger,msg,in_chat);
}
/**
* Using this constructor for a static object outside action_wml.cpp
* will likely lead to a static initialization fiasco.
@ -324,11 +261,6 @@ WML_HANDLER_FUNCTION(clear_global_variable,,pcfg)
verify_and_clear_global_variable(pcfg);
}
WML_HANDLER_FUNCTION(deprecated_message,, cfg)
{
handle_deprecated_message( cfg.get_parsed_config() );
}
static void on_replay_error(const std::string& message, bool /*b*/)
{
ERR_NG << "Error via [do_command]:" << std::endl;
@ -385,11 +317,6 @@ WML_HANDLER_FUNCTION(get_global_variable,,pcfg)
verify_and_get_global_variable(pcfg);
}
WML_HANDLER_FUNCTION(lift_fog,, cfg)
{
toggle_fog(true, cfg, !cfg["multiturn"].to_bool(false));
}
WML_HANDLER_FUNCTION(modify_turns,, cfg)
{
config::attribute_value value = cfg["value"];
@ -573,10 +500,6 @@ WML_HANDLER_FUNCTION(recall,, cfg)
LOG_WML << "A [recall] tag with the following content failed:\n" << cfg.get_config().debug();
}
WML_HANDLER_FUNCTION(remove_sound_source,, cfg)
{
resources::soundsources->remove(cfg["id"]);
}
namespace {
struct map_choice : public mp_sync::user_choice
{
@ -616,6 +539,7 @@ namespace {
};
}
/// Experimental map replace
/// @todo Finish experimenting.
WML_HANDLER_FUNCTION(replace_map,, cfg)
@ -676,11 +600,6 @@ WML_HANDLER_FUNCTION(replace_map,, cfg)
ai::manager::raise_map_changed();
}
WML_HANDLER_FUNCTION(reset_fog,, cfg)
{
toggle_fog(false, cfg, cfg["reset_view"].to_bool(false));
}
/// Experimental data persistence
/// @todo Finish experimenting.
WML_HANDLER_FUNCTION(set_global_variable,,pcfg)
@ -1029,19 +948,6 @@ WML_HANDLER_FUNCTION(set_variables,, cfg)
}
}
WML_HANDLER_FUNCTION(sound_source,, cfg)
{
config parsed = cfg.get_parsed_config();
try {
soundsource::sourcespec spec(parsed);
resources::soundsources->add(spec);
} catch (bad_lexical_cast &) {
ERR_NG << "Error when parsing sound_source config: bad lexical cast." << std::endl;
ERR_NG << "sound_source config was: " << parsed.debug() << std::endl;
ERR_NG << "Skipping this sound source..." << std::endl;
}
}
/// Store the relative direction from one hex to another in a WML variable.
/// This is mainly useful as a diagnostic tool, but could be useful
/// for some kind of scenario.
@ -1274,11 +1180,6 @@ WML_HANDLER_FUNCTION(volume,, cfg)
}
WML_HANDLER_FUNCTION(wml_message,, cfg)
{
handle_wml_log_message( cfg.get_parsed_config() );
}
WML_HANDLER_FUNCTION(on_undo,, cfg)
{
if(cfg["delayed_variable_substitution"].to_bool(false)) {

View file

@ -72,11 +72,6 @@ namespace game_events
*/
void change_terrain(const map_location &loc, const t_translation::t_terrain &t,
terrain_type_data::tmerge_mode mode, bool replace_if_failed);
/** Used for [deprecated_message]. */
void handle_deprecated_message(const config& cfg);
/** Used for [wml_message]. */
void handle_wml_log_message(const config& cfg);
}
#endif // GAME_EVENTS_ACTION_WML_H_INCLUDED

View file

@ -85,6 +85,7 @@
#include "sdl/utils.hpp" // for surface
#include "side_filter.hpp" // for side_filter
#include "sound.hpp" // for commit_music_changes, etc
#include "soundsource.hpp"
#include "synced_context.hpp" // for synced_context, etc
#include "synced_user_choice.hpp"
#include "team.hpp" // for team, village_owner
@ -121,6 +122,7 @@
#include <set> // for set
#include <sstream> // for operator<<, basic_ostream, etc
#include <utility> // for pair
#include <algorithm>
#include <vector> // for vector, etc
#include <SDL_timer.h> // for SDL_GetTicks
#include <SDL_video.h> // for SDL_Color, SDL_Surface
@ -4233,6 +4235,139 @@ int game_lua_kernel::intf_teleport(lua_State *L)
return 0;
}
/**
* Removes a sound source by its ID
* Arg 1: sound source ID
*/
int game_lua_kernel::intf_remove_sound_source(lua_State *L)
{
soundsource::manager* man = play_controller_.get_soundsource_man();
std::string id = luaL_checkstring(L, 1);
man->remove(id);
return 0;
}
/**
* Add a new sound source
* Arg 1: Table containing keyword arguments
*/
int game_lua_kernel::intf_add_sound_source(lua_State *L)
{
soundsource::manager* man = play_controller_.get_soundsource_man();
config cfg = luaW_checkconfig(L, 1);
try {
soundsource::sourcespec spec(cfg);
man->add(spec);
} catch (bad_lexical_cast &) {
ERR_LUA << "Error when parsing sound_source config: invalid parameter." << std::endl;
ERR_LUA << "sound_source config was: " << cfg.debug() << std::endl;
ERR_LUA << "Skipping this sound source..." << std::endl;
}
return 0;
}
/**
* Get an existing sound source
* Arg 1: The sound source ID
* Return: Config of sound source info, or nil if it didn't exist
* This is a copy of the sound source info, so you need to call
* add_sound_source again after changing it.
*/
int game_lua_kernel::intf_get_sound_source(lua_State *L)
{
soundsource::manager* man = play_controller_.get_soundsource_man();
std::string id = luaL_checkstring(L, 1);
config cfg = man->get(id);
if(cfg.empty()) {
return 0;
}
// Sound sources do not know their own string ID
// Thus, we need to add this manually
cfg["id"] = id;
luaW_pushconfig(L, cfg);
return 1;
}
/**
* Logs a message
* Arg 1: (optional) Logger; "wml" for WML errors or deprecations
* Arg 2: Message
* Arg 3: Whether to print to chat (always true if arg 1 is "wml")
*/
int game_lua_kernel::intf_log(lua_State *L)
{
const std::string& logger = lua_isstring(L, 2) ? luaL_checkstring(L, 1) : "";
const std::string& msg = lua_isstring(L, 2) ? luaL_checkstring(L, 2) : luaL_checkstring(L, 1);
if(logger == "wml" || logger == "WML") {
lg::wml_error() << msg << '\n';
} else {
bool in_chat = luaW_toboolean(L, -1);
game_state_.events_manager_->pump().put_wml_message(logger,msg,in_chat);
}
return 0;
}
/**
* Implements the lifting and resetting of fog via WML.
* Keeping affect_normal_fog as false causes only the fog override to be affected.
* Otherwise, fog lifting will be implemented similar to normal sight (cannot be
* individually reset and ends at the end of the turn), and fog resetting will, in
* addition to removing overrides, extend the specified teams' normal fog to all
* hexes.
*
* Arg 1: (optional) Side number, or list of side numbers
* Arg 2: List of locations; each is a two-element array or a table with x and y keys
* Arg 3: (optional) boolean
*/
int game_lua_kernel::intf_toggle_fog(lua_State *L, const bool clear)
{
bool affect_normal_fog = false;
if(lua_isboolean(L, -1)) {
affect_normal_fog = luaW_toboolean(L, -1);
}
std::set<int> sides;
if(lua_isnumber(L, 1)) {
sides.insert(lua_tonumber(L, 1));
} else if(lua_istable(L, 2)) {
const auto& v = lua_check<std::vector<int>>(L, 1);
sides.insert(v.begin(), v.end());
} else {
for(const team& t : teams()) {
sides.insert(t.side()+1);
}
}
const auto& v_locs = lua_check<std::vector<map_location>>(L, lua_istable(L, 2) ? 2 : 1);
std::set<map_location> locs(v_locs.begin(), v_locs.end());
for(const int &side_num : sides) {
if(side_num < 1 || static_cast<size_t>(side_num) > teams().size()) {
continue;
}
team &t = teams()[side_num-1];
if(!clear) {
// Extend fog.
t.remove_fog_override(locs);
if(affect_normal_fog) {
t.refog();
}
} else if(!affect_normal_fog) {
// Force the locations clear of fog.
t.add_fog_override(locs);
} else {
// Simply clear fog from the locations.
for(const map_location &hex : locs) {
t.clear_fog(hex);
}
}
}
// Flag a screen update.
game_display_->recalculate_minimap();
game_display_->invalidate_all();
return 0;
}
// END CALLBACK IMPLEMENTATION
game_board & game_lua_kernel::board() {
@ -4325,8 +4460,10 @@ game_lua_kernel::game_lua_kernel(CVideo * video, game_state & gs, play_controlle
{ "unit_resistance", &intf_unit_resistance },
{ "unsynced", &intf_do_unsynced },
{ "add_event_handler", &dispatch<&game_lua_kernel::intf_add_event > },
{ "add_fog", &dispatch2<&game_lua_kernel::intf_toggle_fog, true > },
{ "add_tile_overlay", &dispatch<&game_lua_kernel::intf_add_tile_overlay > },
{ "add_time_area", &dispatch<&game_lua_kernel::intf_add_time_area > },
{ "add_sound_source", &dispatch<&game_lua_kernel::intf_add_sound_source > },
{ "allow_end_turn", &dispatch<&game_lua_kernel::intf_allow_end_turn > },
{ "allow_undo", &dispatch<&game_lua_kernel::intf_allow_undo > },
{ "animate_unit", &dispatch<&game_lua_kernel::intf_animate_unit > },
@ -4354,6 +4491,7 @@ game_lua_kernel::game_lua_kernel(CVideo * video, game_state & gs, play_controlle
{ "get_recall_units", &dispatch<&game_lua_kernel::intf_get_recall_units > },
{ "get_selected_tile", &dispatch<&game_lua_kernel::intf_get_selected_tile > },
{ "get_sides", &dispatch<&game_lua_kernel::intf_get_sides > },
{ "get_sound_source", &dispatch<&game_lua_kernel::intf_get_sound_source > },
{ "get_starting_location", &dispatch<&game_lua_kernel::intf_get_starting_location > },
{ "get_terrain", &dispatch<&game_lua_kernel::intf_get_terrain > },
{ "get_terrain_info", &dispatch<&game_lua_kernel::intf_get_terrain_info > },
@ -4371,6 +4509,7 @@ game_lua_kernel::game_lua_kernel(CVideo * video, game_state & gs, play_controlle
{ "kill", &dispatch<&game_lua_kernel::intf_kill > },
{ "label", &dispatch<&game_lua_kernel::intf_label > },
{ "lock_view", &dispatch<&game_lua_kernel::intf_lock_view > },
{ "log", &dispatch<&game_lua_kernel::intf_log > },
{ "match_location", &dispatch<&game_lua_kernel::intf_match_location > },
{ "match_side", &dispatch<&game_lua_kernel::intf_match_side > },
{ "match_unit", &dispatch<&game_lua_kernel::intf_match_unit > },
@ -4385,8 +4524,10 @@ game_lua_kernel::game_lua_kernel(CVideo * video, game_state & gs, play_controlle
{ "random", &dispatch<&game_lua_kernel::intf_random > },
{ "redraw", &dispatch<&game_lua_kernel::intf_redraw > },
{ "remove_event_handler", &dispatch<&game_lua_kernel::intf_remove_event > },
{ "remove_fog", &dispatch2<&game_lua_kernel::intf_toggle_fog, false > },
{ "remove_tile_overlay", &dispatch<&game_lua_kernel::intf_remove_tile_overlay > },
{ "remove_time_area", &dispatch<&game_lua_kernel::intf_remove_time_area > },
{ "remove_sound_source", &dispatch<&game_lua_kernel::intf_remove_sound_source > },
{ "replace_schedule", &dispatch<&game_lua_kernel::intf_replace_schedule > },
{ "scroll", &dispatch<&game_lua_kernel::intf_scroll > },
{ "scroll_to_tile", &dispatch<&game_lua_kernel::intf_scroll_to_tile > },

View file

@ -164,6 +164,11 @@ class game_lua_kernel : public lua_kernel_base
int intf_fire_event(lua_State *L);
int intf_fire_wml_menu_item(lua_State *L);
int intf_teleport(lua_State *L);
int intf_remove_sound_source(lua_State *L);
int intf_add_sound_source(lua_State *L);
int intf_get_sound_source(lua_State *L);
int intf_log(lua_State *L);
int intf_toggle_fog(lua_State *L, const bool clear);
//private helpers
std::string synced_state();

View file

@ -67,6 +67,16 @@ void manager::add(const sourcespec &spec)
}
}
config manager::get(const std::string &id)
{
config cfg;
positional_source_iterator it = sources_.find(id);
if(it != sources_.end()) {
it->second->write_config(cfg);
}
return cfg;
}
void manager::remove(const std::string &id)
{
positional_source_iterator it;

View file

@ -93,6 +93,7 @@ public:
// add or replace a soundsource
void add(const sourcespec &source);
void remove(const std::string &id);
config get(const std::string &id);
void update();
// checks which sound sources are visible

View file

@ -26,8 +26,9 @@
#include "asserts.hpp"
#include "variable.hpp"
#include "game_events/action_wml.hpp"
#include "game_events/conditional_wml.hpp"
#include "game_events/manager.hpp"
#include "game_events/pump.hpp"
#include "game_data.hpp"
#include "gettext.hpp"
#include "intro.hpp"
@ -129,13 +130,13 @@ void controller::resolve_wml(const vconfig& cfg)
// [deprecated_message]
else if(key == "deprecated_message") {
// Won't appear until the scenario start event finishes.
game_events::handle_deprecated_message(node.get_parsed_config());
lg::wml_error() << node["message"] << '\n';
}
// [wml_message]
else if(key == "wml_message") {
// Pass to game events handler. As with [deprecated_message],
// As with [deprecated_message],
// it won't appear until the scenario start event is complete.
game_events::handle_wml_log_message(node.get_parsed_config());
resources::game_events->pump().put_wml_message(node["logger"],node["message"],node["in_chat"]);
}
}
}

View file

@ -25,8 +25,9 @@
#include "config.hpp"
#include "game_data.hpp"
#include "game_events/action_wml.hpp"
#include "game_events/conditional_wml.hpp"
#include "game_events/manager.hpp"
#include "game_events/pump.hpp"
#include "image.hpp"
#include "serialization/string_utils.hpp"
#include "util.hpp"
@ -349,13 +350,13 @@ void part::resolve_wml(const vconfig &cfg)
// [deprecated_message]
else if(key == "deprecated_message") {
// Won't appear until the scenario start event finishes.
game_events::handle_deprecated_message(node.get_parsed_config());
lg::wml_error() << node["message"] << '\n';
}
// [wml_message]
else if(key == "wml_message") {
// Pass to game events handler. As with [deprecated_message],
// As with [deprecated_message],
// it won't appear until the scenario start event is complete.
game_events::handle_wml_log_message(node.get_parsed_config());
resources::game_events->pump().put_wml_message(node["logger"],node["message"],node["in_chat"]);
}
}
}