https://wiki.wesnoth.org/api.php?action=feedcontributions&user=Edward+Chernenko&feedformat=atomThe Battle for Wesnoth Wiki - User contributions [en]2024-03-29T14:19:20ZUser contributionsMediaWiki 1.31.16https://wiki.wesnoth.org/index.php?title=LuaAPI/UpdatingFrom14&diff=69136LuaAPI/UpdatingFrom142022-01-06T05:55:56Z<p>Edward Chernenko: /* Functions in wesnoth namespace */ typo</p>
<hr />
<div><br />
This page contains a summary of the major Lua API changes between 1.12 and 1.15, to help make updating older code simpler.<br />
<br />
In general, when it says "renamed", the new function is a drop-in replacement for the old one. When it says "replaced", the new function probably has a different API (such as different arguments) or might not even be a function at all.<br />
<br />
For some of these that are more than just a simple rename, an example is given where the old, pre-1.16 code is shown commented out and the new code is shown below it.<br />
<br />
=== Functions in wesnoth namespace ===<br />
<br />
* '''wesnoth.remove_fog''' renamed to '''wesnoth.sides.remove_fog'''<br />
* '''wesnoth.add_ai_component''' renamed to '''wesnoth.sides.add_ai_component'''<br />
* '''wesnoth.add_fog''' renamed to '''wesnoth.sides.place_fog'''<br />
* '''wesnoth.add_modification''' renamed to '''wesnoth.units.add_modification'''<br />
* '''wesnoth.add_sound_source''' replaced with '''wesnoth.audio.sources''' mapping (write to key)<br />
**<syntaxhighlight lang=lua><br />
-- wesnoth.add_sound_source{id=my_id, x=15, y=22, sound='my-sound.ogg'}<br />
wesnoth.audio.sources.my_id = {x=15, y=22, sound='my-sound.ogg'}<br />
</syntaxhighlight><br />
* '''wesnoth.add_tile_overlay''' renamed to '''wesnoth.interface.add_hex_overlay'''<br />
* '''wesnoth.add_widget_definition''' renamed to '''gui.add_widget_definition'''<br />
* '''wesnoth.advance_unit''' renamed to '''wesnoth.units.advance'''<br />
* '''wesnoth.alert''' renamed to '''gui.alert'''<br />
* '''wesnoth.allow_end_turn''' renamed to '''wesnoth.interface.allow_end_turn'''<br />
* '''wesnoth.append_ai''' renamed to '''wesnoth.sides.append_ai'''<br />
* '''wesnoth.canonical_path''' renamed to '''filesystem.canonical_path'''<br />
* '''wesnoth.change_ai_component''' renamed to '''wesnoth.sides.change_ai_component'''<br />
* '''wesnoth.clear_messages''' renamed to '''wesnoth.interface.clear_chat_messages'''<br />
* '''wesnoth.color_adjust''' replaced with '''wesnoth.interface.color_adjust'''<br />
* '''wesnoth.compare_versions''' replaced with '''wesnoth.version''', which creates a version object that can be compared with standard comparison operators<br />
**<syntaxhighlight lang=lua><br />
-- if wesnoth.compare_versions(wesnoth.game_config.version, '<=', '1.13') then<br />
if wesnoth.current_version() <= wesnoth.version '1.13' then<br />
-- do version-specific stuff<br />
end</syntaxhighlight><br />
* '''wesnoth.confirm''' renamed to '''gui.confirm'''<br />
* '''wesnoth.copy_unit''' renamed to '''wesnoth.units.clone'''<br />
* '''wesnoth.create_animator''' renamed to '''wesnoth.units.create_animator'''<br />
* '''wesnoth.create_side''' renamed to '''wesnoth.sides.create'''<br />
* '''wesnoth.create_unit''' renamed to '''wesnoth.units.create'''<br />
* '''wesnoth.create_weapon''' renamed to '''wesnoth.units.create_weapon'''<br />
* '''wesnoth.debug_ai''' renamed to '''wesnoth.sides.debug_ai'''<br />
* '''wesnoth.debug''' renamed to '''wml.tostring'''; in addition, it now produces an output that is valid WML, meaning that <syntaxhighlight lang=lua inline>wml.parse(wml.tostring(wml_table))</syntaxhighlight> will output a clone of '''wml_table''' (though for this purpose there's a separate '''wml.clone''' function which is probably faster).<br />
* '''wesnoth.delay''' renamed to '''wesnoth.interface.delay'''<br />
* '''wesnoth.delete_ai_component''' renamed to '''wesnoth.sides.delete_ai_component'''<br />
* '''wesnoth.deselect_hex''' renamed to '''wesnoth.interface.deselect_hex'''<br />
* '''wesnoth.end_level''' replaced with assignable '''wesnoth.scenario.end_level_data'''<br />
* '''wesnoth.end_turn''' renamed to '''wesnoth.interface.end_turn'''<br />
* '''wesnoth.erase_unit''' renamed to '''wesnoth.units.erase'''<br />
* '''wesnoth.eval_conditional''' renamed to '''wml.eval_conditional'''<br />
* '''wesnoth.extract_unit''' renamed to '''wesnoth.units.extract'''<br />
* '''wesnoth.find_cost_map''' renamed to '''wesnoth.paths.find_cost_map'''<br />
* '''wesnoth.find_path''' renamed to '''wesnoth.paths.find_path'''<br />
* '''wesnoth.find_reach''' renamed to '''wesnoth.paths.find_reach'''<br />
* '''wesnoth.find_vacant_tile''' renamed to '''wesnoth.paths.find_vacant_hex'''<br />
* '''wesnoth.find_vision_range''' renamed to '''wesnoth.paths.find_vision_range'''<br />
* '''wesnoth.float_label''' renamed to '''wesnoth.interface.float_label'''<br />
* '''wesnoth.format_conjunct_list''' renamed to '''stringx.format_conjunct_list'''<br />
* '''wesnoth.format_disjunct_list''' renamed to '''stringx.format_disjunct_list'''<br />
* '''wesnoth.format''' renamed to '''stringx.vformat''' and can also be called directly on a string literal<br />
* '''wesnoth.gamestate_inspector''' renamed to '''gui.show_inspector'''<br />
* '''wesnoth.get_all_vars''' replaced with read-only variable '''wml.all_variables''' (but it should still be used sparingly)<br />
* '''wesnoth.get_displayed_unit''' renamed to '''wesnoth.interface.get_displayed_unit'''<br />
* '''wesnoth.get_end_level_data''' replaced with readable '''wesnoth.scenario.end_level_data'''<br />
* '''wesnoth.get_image_size''' renamed to '''filesystem.image_size'''<br />
* '''wesnoth.get_max_liminal_bonus''' replaced with read-only '''wesnoth.current.schedule.liminal_bonus'''<br />
* '''wesnoth.get_mouseover_tile''' renamed to '''wesnoth.interface.get_hovered_hex'''<br />
* '''wesnoth.get_recall_units''' renamed to '''wesnoth.units.find_on_recall'''<br />
* '''wesnoth.get_selected_tile''' renamed to '''wesnoth.interface.get_selected_hex'''<br />
* '''wesnoth.get_side_variable''' and '''wesnoth.set_side_variable''' replaced by '''variables''' member in side data (found in '''wesnoth.sides''' array). This otherwise works the same as '''wml.variables'''.<br />
** <syntaxhighlight lang=lua><br />
-- local old_value = wesnoth.get_side_variable(1, 'my_value')<br />
local old_value = wesnoth.sides[1].variables['my_value'] -- or variables.myvalue<br />
local new_value = old_value * 2<br />
-- wesnoth.set_side_variable(1, 'my_value', new_value)<br />
wesnoth.sides[1].variables['my_value'] = new_value<br />
</syntaxhighlight><br />
* '''wesnoth.get_sides''' renamed to '''wesnoth.sides.find'''<br />
* '''wesnoth.get_sound_source''' replaced with '''wesnoth.audio.sources''' mapping (read key)<br />
* '''wesnoth.get_starting_location''' replaced by '''starting_location''' member in side data<br />
* '''wesnoth.get_time_of_day''' replaced with '''wesnoth.schedule.get_time_of_day''' and '''wesnoth.schedule.get_illumination''' as well as '''wesnoth.current.schedule.time_of_day'''<br />
** <syntaxhighlight lang=lua><br />
-- local global_tod = wesnoth.get_time_of_day(wesnoth.current.turn + 1)<br />
local global_tod = wesnoth.schedule.get_time_of_day(nil, wesnoth.current.turn + 1)<br />
-- local base_tod = wesnoth.get_time_of_day(wesnoth.current.turn + 1, {44, 23})<br />
local base_tod = wesnoth.schedule.get_time_of_day({44, 23}, wesnoth.current.turn + 1)<br />
-- local final_tod = wesnoth.get_time_of_day(wesnoth.current.turn + 1, {44, 23, true})<br />
local final_tod = wesnoth.schedule.get_illumination({44, 24}, wesnoth.current.turn + 1)<br />
</syntaxhighlight><br />
* '''wesnoth.get_time_stamp''' renamed to '''wesnoth.ms_since_init'''<br />
* '''wesnoth.get_traits''' replaced with '''wesnoth.game_config.global_traits''', which is the table it formerly returned<br />
* '''wesnoth.get_unit''' renamed to '''wesnoth.units.get'''<br />
* '''wesnoth.get_units''' renamed to '''wesnoth.units.find_on_map'''<br />
* '''wesnoth.get_variable''' and '''wesnoth.set_variable''' are replaced by '''wml.variables''' which can be indexed with a variable path - set a variable by assigning to it<br />
** <syntaxhighlight lang=lua><br />
-- local old_value = wesnoth.get_variable('my_array[2].value')<br />
local old_value = wml.variables['my_array[2].value']<br />
local new_value = old_value * 2<br />
-- wesnoth.set_variable('my_array[2].value', new_value)<br />
wml.variables['my_array[2].value'] = new_value<br />
</syntaxhighlight><br />
* '''wesnoth.have_file''' renamed to '''filesystem.have_file'''<br />
* '''wesnoth.highlight_hex''' renamed to '''wesnoth.interface.highlight_hex'''<br />
* '''wesnoth.invoke_synced_command''' renamed to '''wesnoth.sync.invoke_command'''<br />
* '''wesnoth.is_enemy''' renamed to '''wesnoth.sides.is_enemy'''<br />
* '''wesnoth.is_fogged''' renamed to '''wesnoth.sides.is_fogged'''<br />
* '''wesnoth.is_shrouded''' renamed to '''wesnoth.sides.is_shrouded'''<br />
* '''wesnoth.is_skipping_messages''' renamed to '''wesnoth.interface.is_skipping_messages'''<br />
* '''wesnoth.lock_view''' renamed to '''wesnoth.interface.lock'''<br />
* '''wesnoth.match_side''' renamed to '''wesnoth.sides.matches'''<br />
* '''wesnoth.match_unit''' renamed to '''wesnoth.units.matches'''<br />
* '''wesnoth.message''' renamed to '''wesnoth.interface.add_chat_message'''<br />
* '''wesnoth.music_list''' renamed to '''wesnoth.audio.music_list'''<br />
* '''wesnoth.open_help''' renamed to '''gui.show_help'''<br />
* '''wesnoth.place_shroud''' replaced with '''wesnoth.sides.place_shroud''' and '''wesnoth.sides.override_shroud'''<br />
* '''wesnoth.play_sound''' renamed to '''wesnoth.audio.play'''<br />
* '''wesnoth.put_recall_unit''' renamed to '''wesnoth.units.to_recall'''<br />
* '''wesnoth.put_unit''' renamed to '''wesnoth.units.to_map'''<br />
* '''wesnoth.random''' renamed to '''mathx.random'''<br />
* '''wesnoth.read_file''' renamed to '''filesystem.read_file'''<br />
* '''wesnoth.remove_modifications''' renamed to '''wesnoth.units.remove_modifications'''<br />
* '''wesnoth.remove_sound_source''' replaced with '''wesnoth.audio.sources''' mapping (assign nil to key)<br />
* '''wesnoth.remove_tile_overlay''' renamed to '''wesnoth.interface.remove_hex_overlay'''<br />
* '''wesnoth.replace_schedule''' renamed to '''wesnoth.schedule.replace'''<br />
* '''wesnoth.scroll_to_tile''' renamed to '''wesnoth.interface.scroll_to_hex'''<br />
* '''wesnoth.scroll''' renamed to '''wesnoth.interface.scroll'''<br />
* '''wesnoth.select_unit''' renamed to '''wesnoth.units.select''' (also available as wesnoth.interface.select_unit)<br />
* '''wesnoth.set_end_campaign_credits''' replaced with assignable '''wesnoth.scenario.show_credits'''<br />
* '''wesnoth.set_end_campaign_text''' replaced with assignable '''wesnoth.scenario.end_text''' and '''wesnoth.scenario.end_text_duration'''<br />
* '''wesnoth.set_next_scenario''' replaced with assignable '''wesnoth.scenario.next'''<br />
* '''wesnoth.set_side_id''' renamed to '''wesnoth.sides.set_id'''<br />
* '''wesnoth.set_time_of_day''' (which was undocumented and unofficial) replaced with assigning '''wesnoth.current.schedule.time_of_day''', though that only covers part of the original functionality<br />
* '''wesnoth.show_lua_console''' renamed to '''gui.show_lua_console'''<br />
* '''wesnoth.show_menu''' renamed to '''gui.show_menu'''<br />
* '''wesnoth.show_message_box''' renamed to '''gui.show_prompt'''<br />
* '''wesnoth.show_message_dialog''' renamed to '''gui.show_narration'''<br />
* '''wesnoth.show_popup_dialog''' renamed to '''gui.show_popup'''<br />
* '''wesnoth.show_story''' renamed to '''gui.show_story'''<br />
* '''wesnoth.skip_messages''' renamed to '''wesnoth.interface.skip_messages'''<br />
* '''wesnoth.sound_volume''' replaced with read-write '''wesnoth.audio.volume'''<br />
* '''wesnoth.switch_ai''' renamed to '''wesnoth.sides.switch_ai'''<br />
* '''wesnoth.synchronize_choice''' renamed to '''wesnoth.sync.evaluate_single'''<br />
* '''wesnoth.synchronize_choices''' renamed to '''wesnoth.sync.evaluate_multiple'''<br />
* '''wesnoth.teleport''' renamed to '''wesnoth.units.teleport'''<br />
* '''wesnoth.theme_items''' renamed to '''wesnoth.interface.game_display''' - it's still a table with the same keys as before<br />
* '''wesnoth.tovconfig''' renamed to '''wml.tovconfig'''<br />
* '''wesnoth.transform_unit''' renamed to '''wesnoth.units.transform'''<br />
* '''wesnoth.unit_ability''' renamed to '''wesnoth.units.ability'''<br />
* '''wesnoth.unit_defense''' renamed to '''wesnoth.units.chance_to_be_hit'''<br />
* '''wesnoth.unit_jamming_cost''' renamed to '''wesnoth.units.jamming_on'''<br />
* '''wesnoth.unit_movement_cost''' renamed to '''wesnoth.units.movement_on'''<br />
* '''wesnoth.unit_resistance''' replaced by '''wesnoth.units.resistance_against''' - new function returns (100 - old function)<br />
* '''wesnoth.unit_vision_cost''' renamed to '''wesnoth.units.vision_on'''<br />
* '''wesnoth.unsynced''' renamed to '''wesnoth.sync.run_unsynced'''<br />
* '''wesnoth.view_locked''' renamed to '''wesnoth.interface.is_locked'''<br />
* '''wesnoth.wml_matches_filter''' renamed to '''wml.matches_filter'''<br />
* '''wesnoth.zoom''' renamed to '''wesnoth.interface.zoom'''<br />
<br />
==== wesnoth.tovconfig and related functions in plugins ====<br />
<br />
The '''wesnoth.tovconfig''' function has been removed from the plugin context. This will have no effect on most people, as the plugin context is rarely used. A plugin context is any Lua script loaded using the <tt>--plugin</tt> command-line parameter, primarily intended for creating bots on the multiplayer server.<br />
<br />
If you were calling '''wesnoth.tovconfig''' in a plugin, then you have several options for updating your code. If you simply needed to verify that a variable holds a valid WML table, you can use '''wml.valid''' instead. If you need to substitute variables into a WML table, you can also use '''wml.interpolate''' to replicate the behaviour of '''wml.tovconfig''', supplying the variables themselves as an extra argument (another WML table).<br />
<br />
In addition, the helper functions '''parsed''', '''literal''', '''shallow_parsed''', and '''shallow_literal''' are not available in the plugin context.<br />
<br />
==== GUI2 API ====<br />
<br />
There has been a major rehaul of the GUI2 API for arbitrary custom dialogs. See [[LuaAPI/types/widget]] and [[LuaAPI/gui/widget]] for details; the changes are also summarized below.<br />
<br />
* '''wesnoth.add_dialog_tree_node''' renamed to '''gui.widget.add_item_of_type''' and now takes a reference to the widget instead of a path to it; use '''gui.widget.find''' to convert a path to a reference<br />
* '''wesnoth.get_dialog_value''' and '''wesnoth.set_dialog_value''' removed; instead access the appropriate member of the widget, such as '''selected_index''' or '''selected''' or '''text''' or '''value''' or '''percentage''' or '''selected_item_path''' or '''unfolded''' or '''unit''' or '''label'''. Some of these may be write-only.<br />
* '''wesnoth.remove_dialog_item''' renamed to '''gui.widget.remove_items_at''' and now takes a reference to the widget instead of a path to it; use '''gui.widget.find''' to convert a path to a reference.<br />
* '''wesnoth.set_dialog_active''' removed; instead assign the '''enabled''' member of a widget<br />
**<syntaxhighlight lang=lua ><br />
-- local function preshow()<br />
local function preshow(self)<br />
local var_a = true<br />
-- whatever you are doing to determine if button should be active<br />
-- wesnoth.set_dialog_active(var_a, "my_button_id")<br />
local widget_handle = self:find('my_button_id') -- or just self.my_button_id<br />
widget_handle.enabled = var_a<br />
-- ...<br />
end<br />
</syntaxhighlight><br />
* '''wesnoth.set_dialog_callback''' removed; instead simply assign to a widget's callback handler, eg <syntaxhighlight lang=lua inline>my_widget.on_modified = function() end</syntaxhighlight><br />
**<syntaxhighlight lang=lua ><br />
-- local function preshow()<br />
local function preshow(self)<br />
local function on_text_modified()<br />
-- Do whatever you need to do<br />
end<br />
-- This example shows an on_modified event; there's also on_left_click and on_button_click<br />
-- Use one of the click events if you were setting the callback on a button.<br />
-- wesnoth.set_dialog_callback(on_text_modified, "my_text_id")<br />
local widget_handle = self:find('my_text_id') -- or just self.my_text_id<br />
widget_handle.on_modified = set_dialog_callback<br />
-- Or you could have defined the function here like this:<br />
-- function widget_handle.on_modified()<br />
-- ...<br />
end<br />
</syntaxhighlight><br />
* '''wesnoth.set_dialog_canvas''' renamed to '''gui.widget.set_canvas''' and now takes a reference to the widget instead of a path to it; use '''gui.widget.find''' to convert a path to a reference<br />
* '''wesnoth.set_dialog_focus''' renamed to '''gui.widget.focus''' and now takes a reference to the widget instead of a path to it; use '''gui.widget.find''' to convert a path to a reference<br />
**<syntaxhighlight lang=lua ><br />
-- local function preshow()<br />
local function preshow(self)<br />
-- wesnoth.set_dialog_focus("my_text_id")<br />
local widget_handle = self:find('my_text_id') -- or just self.my_text_id<br />
widget_handle:focus()<br />
-- ...<br />
end<br />
</syntaxhighlight><br />
* '''wesnoth.set_dialog_markup''' removed; instead assign the '''use_markup''' member of a widget<br />
* '''wesnoth.set_dialog_tooltip''' removed; instead assign the '''tooltip''' member of a widget<br />
**<syntaxhighlight lang=lua ><br />
-- local function preshow()<br />
local function preshow(self)<br />
local var_a = 'Some explanation'<br />
-- whatever you are doing to determine the button's tooltip<br />
-- wesnoth.set_dialog_tooltip(var_a, "my_button_id")<br />
local widget_handle = self:find('my_button_id') -- or just self.my_button_id<br />
widget_handle.tooltip = var_a<br />
-- ...<br />
end<br />
</syntaxhighlight><br />
* '''wesnoth.set_dialog_visible''' removed; instead assign the '''visible''' member of a widget<br />
**<syntaxhighlight lang=lua ><br />
-- local function preshow()<br />
local function preshow(self)<br />
local var_a = true<br />
-- whatever you are doing to determine if button should be visible<br />
-- wesnoth.set_dialog_visible(var_a, "my_button_id")<br />
local widget_handle = self:find('my_button_id') -- or just self.my_button_id<br />
widget_handle.visible = var_a<br />
-- ...<br />
end<br />
</syntaxhighlight><br />
* '''wesnoth.show_dialog''' renamed to '''gui.show_dialog'''<br />
* The '''preshow''' and '''postshow''' functions passed to '''gui.show_dialog''' now take a single parameter, which is a reference to the dialog's root widget (a widget of type "window"). This can be passed to '''gui.widget.find''' to look up widgets by their path. You can also access direct child widgets by simply indexing the root widget.<br />
<br />
==== Map API ====<br />
<br />
Due to a major rehaul of the map API, many map functions are now methods on the map object, available as '''wesnoth.current.map''' (abbreviated in the below listing to just '''map''').<br />
<br />
* '''wesnoth.add_time_area''' renamed to '''wesnoth.map.place_area'''<br />
* '''wesnoth.get_locations''' renamed to '''wesnoth.map.find'''<br />
* '''wesnoth.get_map_size''' replaced with '''map.playable_width''', '''map.playable_height''', and '''map.border_size'''<br />
**<syntaxhighlight lang=lua><br />
-- local width, height, border_size = wesnoth.get_map_size()<br />
local width, height = wesnoth.current.map.playable_width, wesnoth.current.map.playable_height<br />
local border_size = wesnoth.current.map.border_size<br />
-- local width_with_border, height_with_border = width + border_size * 2, height + border_size * 2<br />
local width_with_border, height_with_border = wesnoth.current.map.width and wesnoth.current.map.height<br />
</syntaxhighlight<br />
* '''wesnoth.get_terrain_info''' replaced with '''wesnoth.terrain_types'''<br />
**<syntaxhighlight lang=lua><br />
-- local info = wesnoth.get_terrain_info('Gg')<br />
local info = wesnoth.terrain_types['Gg']<br />
</syntaxhighlight><br />
* '''wesnoth.get_terrain''' replaced with '''map[{x,y}]'''<br />
**<syntaxhighlight lang=lua><br />
-- local terrain = wesnoth.get_terrain(x, y)<br />
local terrain = wesnoth.current.map[{x,y}]<br />
-- local terrain_under_unit = wesnoth.get_terrain(unit.x, unit.y)<br />
local terrain_under_unit = wesnoth.current.map[unit]<br />
</syntaxhighlight><br />
* '''wesnoth.get_village_owner''' renamed to '''wesnoth.map.get_owner'''<br />
* '''wesnoth.get_villages''' replaced with '''wesnoth.map.find''' (with '''gives_income = true''')<br />
**<syntaxhighlight lang=lua><br />
-- For example, get all villages in [time_area]id=shadowed<br />
-- local villages = wesnoth.get_villages{area = 'shadowed'}<br />
local villages = wesnoth.map.find{area = 'shadowed', gives_income = true}<br />
</syntaxhighlight><br />
* '''wesnoth.label''' renamed to '''wesnoth.map.add_label'''<br />
* '''wesnoth.match_location''' renamed to '''wesnoth.map.matches'''<br />
* '''wesnoth.remove_time_area''' renamed to '''wesnoth.map.remove_area'''<br />
* '''wesnoth.set_terrain''' replaced with assigning '''map[{x,y}]''' - helper functions in '''wesnoth.map''' expose the more advanced assignment operations ('''replace_overlay''', '''replace_both''', '''replace_if_failed''') - just assign the result of one of these functions to the hex<br />
**<syntaxhighlight lang=lua><br />
-- wesnoth.set_terrain(x, y, 'Gg')<br />
wesnoth.current.map[{x,y}] = 'Gg'<br />
-- Or be explicit about layer:<br />
wesnoth.current.map[{x,y}] = wesnoth.map.replace_both 'Gg'<br />
-- wesnoth.set_terrain(x, y, 'Gg', 'base')<br />
wesnoth.current.map[{x,y}] = wesnoth.map.replace_base 'Gg'<br />
-- wesnoth.set_terrain(x, y, '^Vh', 'overlay')<br />
wesnoth.current.map[{x,y}] = wesnoth.map.replace_overlay '^Vh'<br />
-- wesnoth.set_terrain(x, y, 'Gg^Vh', 'overlay', true)<br />
wesnoth.current.map[{x,y}] = wesnoth.map.replace_if_failed('Gg^Vh', 'overlay')<br />
</syntaxhighlight><br />
* '''wesnoth.set_village_owner''' renamed to '''wesnoth.map.set_owner'''<br />
* '''wesnoth.special_locations''' renamed to '''map.special_locations''' (note: the length operator is no longer supported)<br />
* '''wesnoth.terrain_mask''' replaced with '''map:terrain_mask'''<br />
<br />
The following functions are only available in map generation scripts:<br />
<br />
* '''wesnoth.create_filter''' renamed to '''wesnoth.map.filter'''<br />
* '''wesnoth.create_map''' renamed to '''wesnoth.map.create'''<br />
* '''wesnoth.default_generate_height_map''' renamed to '''wesnoth.map.generate_height_map'''<br />
* '''wesnoth.generate_default_map''' renamed to '''wesnoth.map.generate'''<br />
* '''map:get_locations''' renamed to '''map:find'''<br />
* '''map:get_tiles_radius''' replaced with '''map::find_in_radius''' (and the order of arguments changed)<br />
**<syntaxhighlight lang=lua><br />
-- This example assumes you have a variable f defined as in World Conquest (engine.lua)<br />
-- local in_radius = map:get_tiles_radius(12, 22, f.terrain 'Gg', 5)<br />
local in_radius = map:find_in_radius(12, 22, 5, f.terrain 'Gg')<br />
</syntaxhighlight><br />
<br />
=== helper module ===<br />
<br />
The helper module is being phased out, so quite a lot of things have been moved out of it. This section is written under the assumption that you loaded it with <syntaxhighlight lang=lua inline>local helper = wesnoth.require "helper"</syntaxhighlight> or the like, but many people call it '''H''' instead of '''helper''', so keep that in mind.<br />
<br />
* '''helper.child_array''' renamed to '''wml.child_array'''<br />
* '''helper.child_count''' renamed to '''wml.child_count'''<br />
* '''helper.child_range''' renamed to '''wml.child_range'''<br />
* '''helper.distance_between''' renamed to '''wesnoth.map.distance_between'''<br />
* '''helper.find_attack''' renamed to '''wesnoth.units.find_attack'''<br />
* '''helper.get_child''' renamed to '''wml.get_child'''<br />
* '''helper.get_nth_child''' renamed to '''wml.get_nth_child'''<br />
* '''helper.get_user_choice''' renamed to '''gui.get_user_choice'''<br />
* '''helper.get_variable_array''' renamed to '''wml.array_access.get'''<br />
* '''helper.get_variable_proxy_array''' renamed to '''wml.array_access.get_proxy'''<br />
* '''helper.literal''' renamed to '''wml.literal'''<br />
* '''helper.modify_unit''' renamed to '''wesnoth.units.modify'''<br />
* '''helper.move_unit_fake''' renamed to '''wesnoth.interface.move_unit_fake'''<br />
* '''helper.parsed''' renamed to '''wml.parsed'''<br />
* '''helper.rand''' renamed to '''mathx.random_choice'''<br />
* '''helper.round''' renamed to '''mathx.round'''<br />
* '''helper.set_variable_array''' renamed to '''wml.array_access.set'''<br />
* '''helper.set_wml_tag_metatable''' replaced with '''wml.tag''', which is a table that works exactly the same as what this function would return<br />
**<syntaxhighlight lang=lua><br />
-- local T = helper.set_wml_tag_metatable{}<br />
local T = wml.tag -- Or you can dispense with T and use wml.tag directly<br />
</syntaxhighlight><br />
* '''helper.set_wml_var_metatable''' replaced with '''wml.variable.proxy''', which is a table that works exactly the same as what this function would return<br />
* '''helper.shallow_literal''' renamed to '''wml.shallow_literal'''<br />
* '''helper.shallow_parsed''' renamed to '''wml.shallow_parsed'''<br />
* '''helper.shuffle''' renamed to '''mathx.shuffle'''<br />
* '''helper.wml_error''' renamed to '''wml.error'''<br />
<br />
=== items module ===<br />
<br />
There were also a few things in an "items" module that have been moved into the main API.<br />
<br />
* '''items.place_halo''' renamed to '''wesnoth.interface.add_item_halo'''<br />
* '''items.place_image''' renamed to '''wesnoth.interface.add_item_image'''<br />
* '''items.remove''' renamed to '''wesnoth.interface.remove_item'''<br />
<br />
[[Category:Lua Reference]]</div>Edward Chernenkohttps://wiki.wesnoth.org/index.php?title=LuaAPI/UpdatingFrom14&diff=68972LuaAPI/UpdatingFrom142021-11-25T00:08:58Z<p>Edward Chernenko: typo</p>
<hr />
<div><br />
This page contains a summary of the major Lua API changes between 1.12 and 1.15, to help make updating older code simpler.<br />
<br />
In general, when it says "renamed", the new function is a drop-in replacement for the old one. When it says "replaced", the new function probably has a different API (such as different arguments) or might not even be a function at all.<br />
<br />
For some of these that are more than just a simple rename, an example is given where the old, pre-1.16 code is shown commented out and the new code is shown below it.<br />
<br />
=== Functions in wesnoth namespace ===<br />
<br />
* '''weesnoth.remove_fog''' renamed to '''wesnoth.sides.remove_fog'''<br />
* '''wesnoth.add_ai_component''' renamed to '''wesnoth.sides.add_ai_component'''<br />
* '''wesnoth.add_fog''' renamed to '''wesnoth.sides.place_fog'''<br />
* '''wesnoth.add_modification''' renamed to '''wesnoth.units.add_modification'''<br />
* '''wesnoth.add_sound_source''' replaced with '''wesnoth.audio.sources''' mapping (write to key)<br />
**<syntaxhighlight lang=lua><br />
-- wesnoth.add_sound_source{id=my_id, x=15, y=22, sound='my-sound.ogg'}<br />
wesnoth.audio.sources.my_id = {x=15, y=22, sound='my-sound.ogg'}<br />
</syntaxhighlight><br />
* '''wesnoth.add_tile_overlay''' renamed to '''wesnoth.interface.add_hex_overlay'''<br />
* '''wesnoth.add_widget_definition''' renamed to '''gui.add_widget_definition'''<br />
* '''wesnoth.advance_unit''' renamed to '''wesnoth.units.advance'''<br />
* '''wesnoth.alert''' renamed to '''gui.alert'''<br />
* '''wesnoth.allow_end_turn''' renamed to '''wesnoth.interface.allow_end_turn'''<br />
* '''wesnoth.append_ai''' renamed to '''wesnoth.sides.append_ai'''<br />
* '''wesnoth.canonical_path''' renamed to '''filesystem.canonical_path'''<br />
* '''wesnoth.change_ai_component''' renamed to '''wesnoth.sides.change_ai_component'''<br />
* '''wesnoth.clear_messages''' renamed to '''wesnoth.interface.clear_chat_messages'''<br />
* '''wesnoth.color_adjust''' replaced with '''wesnoth.interface.color_adjust'''<br />
* '''wesnoth.compare_versions''' replaced with '''wesnoth.version''', which creates a version object that can be compared with standard comparison operators<br />
**<syntaxhighlight lang=lua><br />
-- if wesnoth.compare_versions(wesnoth.game_config.version, '<=', '1.13') then<br />
if wesnoth.current_version() <= wesnoth.version '1.13' then<br />
-- do version-specific stuff<br />
end</syntaxhighlight><br />
* '''wesnoth.confirm''' renamed to '''gui.confirm'''<br />
* '''wesnoth.copy_unit''' renamed to '''wesnoth.units.clone'''<br />
* '''wesnoth.create_animator''' renamed to '''wesnoth.units.create_animator'''<br />
* '''wesnoth.create_side''' renamed to '''wesnoth.sides.create'''<br />
* '''wesnoth.create_unit''' renamed to '''wesnoth.units.create'''<br />
* '''wesnoth.create_weapon''' renamed to '''wesnoth.units.create_weapon'''<br />
* '''wesnoth.debug_ai''' renamed to '''wesnoth.sides.debug_ai'''<br />
* '''wesnoth.debug''' renamed to '''wml.tostring'''; in addition, it now produces an output that is valid WML, meaning that <syntaxhighlight lang=lua inline>wml.parse(wml.tostring(wml_table))</syntaxhighlight> will output a clone of '''wml_table''' (though for this purpose there's a separate '''wml.clone''' function which is probably faster).<br />
* '''wesnoth.delay''' renamed to '''wesnoth.interface.delay'''<br />
* '''wesnoth.delete_ai_component''' renamed to '''wesnoth.sides.delete_ai_component'''<br />
* '''wesnoth.deselect_hex''' renamed to '''wesnoth.interface.deselect_hex'''<br />
* '''wesnoth.end_level''' replaced with assignable '''wesnoth.scenario.end_level_data'''<br />
* '''wesnoth.end_turn''' renamed to '''wesnoth.interface.end_turn'''<br />
* '''wesnoth.erase_unit''' renamed to '''wesnoth.units.erase'''<br />
* '''wesnoth.eval_conditional''' renamed to '''wml.eval_conditional'''<br />
* '''wesnoth.extract_unit''' renamed to '''wesnoth.units.extract'''<br />
* '''wesnoth.find_cost_map''' renamed to '''wesnoth.paths.find_cost_map'''<br />
* '''wesnoth.find_path''' renamed to '''wesnoth.paths.find_path'''<br />
* '''wesnoth.find_reach''' renamed to '''wesnoth.paths.find_reach'''<br />
* '''wesnoth.find_vacant_tile''' renamed to '''wesnoth.paths.find_vacant_hex'''<br />
* '''wesnoth.find_vision_range''' renamed to '''wesnoth.paths.find_vision_range'''<br />
* '''wesnoth.float_label''' renamed to '''wesnoth.interface.float_label'''<br />
* '''wesnoth.format_conjunct_list''' renamed to '''stringx.format_conjunct_list'''<br />
* '''wesnoth.format_disjunct_list''' renamed to '''stringx.format_disjunct_list'''<br />
* '''wesnoth.format''' renamed to '''stringx.vformat''' and can also be called directly on a string literal<br />
* '''wesnoth.gamestate_inspector''' renamed to '''gui.show_inspector'''<br />
* '''wesnoth.get_all_vars''' replaced with read-only variable '''wml.all_variables''' (but it should still be used sparingly)<br />
* '''wesnoth.get_displayed_unit''' renamed to '''wesnoth.interface.get_displayed_unit'''<br />
* '''wesnoth.get_end_level_data''' replaced with readable '''wesnoth.scenario.end_level_data'''<br />
* '''wesnoth.get_image_size''' renamed to '''filesystem.image_size'''<br />
* '''wesnoth.get_max_liminal_bonus''' replaced with read-only '''wesnoth.current.schedule.liminal_bonus'''<br />
* '''wesnoth.get_mouseover_tile''' renamed to '''wesnoth.interface.get_hovered_hex'''<br />
* '''wesnoth.get_recall_units''' renamed to '''wesnoth.units.find_on_recall'''<br />
* '''wesnoth.get_selected_tile''' renamed to '''wesnoth.interface.get_selected_hex'''<br />
* '''wesnoth.get_side_variable''' and '''wesnoth.set_side_variable''' replaced by '''variables''' member in side data (found in '''wesnoth.sides''' array). This otherwise works the same as '''wml.variables'''.<br />
** <syntaxhighlight lang=lua><br />
-- local old_value = wesnoth.get_side_variable(1, 'my_value')<br />
local old_value = wesnoth.sides[1].variables['my_value'] -- or variables.myvalue<br />
local new_value = old_value * 2<br />
-- wesnoth.set_side_variable(1, 'my_value', new_value)<br />
wesnoth.sides[1].variables['my_value'] = new_value<br />
</syntaxhighlight><br />
* '''wesnoth.get_sides''' renamed to '''wesnoth.sides.find'''<br />
* '''wesnoth.get_sound_source''' replaced with '''wesnoth.audio.sources''' mapping (read key)<br />
* '''wesnoth.get_starting_location''' replaced by '''starting_location''' member in side data<br />
* '''wesnoth.get_time_of_day''' replaced with '''wesnoth.schedule.get_time_of_day''' and '''wesnoth.schedule.get_illumination''' as well as '''wesnoth.current.schedule.time_of_day'''<br />
** <syntaxhighlight lang=lua><br />
-- local global_tod = wesnoth.get_time_of_day(wesnoth.current.turn + 1)<br />
local global_tod = wesnoth.schedule.get_time_of_day(nil, wesnoth.current.turn + 1)<br />
-- local base_tod = wesnoth.get_time_of_day(wesnoth.current.turn + 1, {44, 23})<br />
local base_tod = wesnoth.schedule.get_time_of_day({44, 23}, wesnoth.current.turn + 1)<br />
-- local final_tod = wesnoth.get_time_of_day(wesnoth.current.turn + 1, {44, 23, true})<br />
local final_tod = wesnoth.schedule.get_illumination({44, 24}, wesnoth.current.turn + 1)<br />
</syntaxhighlight><br />
* '''wesnoth.get_time_stamp''' renamed to '''wesnoth.ms_since_init'''<br />
* '''wesnoth.get_traits''' replaced with '''wesnoth.game_config.global_traits''', which is the table it formerly returned<br />
* '''wesnoth.get_unit''' renamed to '''wesnoth.units.get'''<br />
* '''wesnoth.get_units''' renamed to '''wesnoth.units.find_on_map'''<br />
* '''wesnoth.get_variable''' and '''wesnoth.set_variable''' are replaced by '''wml.variables''' which can be indexed with a variable path - set a variable by assigning to it<br />
** <syntaxhighlight lang=lua><br />
-- local old_value = wesnoth.get_variable('my_array[2].value')<br />
local old_value = wml.variables['my_array[2].value']<br />
local new_value = old_value * 2<br />
-- wesnoth.set_variable('my_array[2].value', new_value)<br />
wml.variables['my_array[2].value'] = new_value<br />
</syntaxhighlight><br />
* '''wesnoth.have_file''' renamed to '''filesystem.have_file'''<br />
* '''wesnoth.highlight_hex''' renamed to '''wesnoth.interface.highlight_hex'''<br />
* '''wesnoth.invoke_synced_command''' renamed to '''wesnoth.sync.invoke_command'''<br />
* '''wesnoth.is_enemy''' renamed to '''wesnoth.sides.is_enemy'''<br />
* '''wesnoth.is_fogged''' renamed to '''wesnoth.sides.is_fogged'''<br />
* '''wesnoth.is_shrouded''' renamed to '''wesnoth.sides.is_shrouded'''<br />
* '''wesnoth.is_skipping_messages''' renamed to '''wesnoth.interface.is_skipping_messages'''<br />
* '''wesnoth.lock_view''' renamed to '''wesnoth.interface.lock'''<br />
* '''wesnoth.match_side''' renamed to '''wesnoth.sides.matches'''<br />
* '''wesnoth.match_unit''' renamed to '''wesnoth.units.matches'''<br />
* '''wesnoth.message''' renamed to '''wesnoth.interface.add_chat_message'''<br />
* '''wesnoth.music_list''' renamed to '''wesnoth.audio.music_list'''<br />
* '''wesnoth.open_help''' renamed to '''gui.show_help'''<br />
* '''wesnoth.place_shroud''' replaced with '''wesnoth.sides.place_shroud''' and '''wesnoth.sides.override_shroud'''<br />
* '''wesnoth.play_sound''' renamed to '''wesnoth.audio.play'''<br />
* '''wesnoth.put_recall_unit''' renamed to '''wesnoth.units.to_recall'''<br />
* '''wesnoth.put_unit''' renamed to '''wesnoth.units.to_map'''<br />
* '''wesnoth.random''' renamed to '''mathx.random'''<br />
* '''wesnoth.read_file''' renamed to '''filesystem.read_file'''<br />
* '''wesnoth.remove_modifications''' renamed to '''wesnoth.units.remove_modifications'''<br />
* '''wesnoth.remove_sound_source''' replaced with '''wesnoth.audio.sources''' mapping (assign nil to key)<br />
* '''wesnoth.remove_tile_overlay''' renamed to '''wesnoth.interface.remove_hex_overlay'''<br />
* '''wesnoth.replace_schedule''' renamed to '''wesnoth.schedule.replace'''<br />
* '''wesnoth.scroll_to_tile''' renamed to '''wesnoth.interface.scroll_to_hex'''<br />
* '''wesnoth.scroll''' renamed to '''wesnoth.interface.scroll'''<br />
* '''wesnoth.select_unit''' renamed to '''wesnoth.units.select''' (also available as wesnoth.interface.select_unit)<br />
* '''wesnoth.set_end_campaign_credits''' replaced with assignable '''wesnoth.scenario.show_credits'''<br />
* '''wesnoth.set_end_campaign_text''' replaced with assignable '''wesnoth.scenario.end_text''' and '''wesnoth.scenario.end_text_duration'''<br />
* '''wesnoth.set_next_scenario''' replaced with assignable '''wesnoth.scenario.next'''<br />
* '''wesnoth.set_side_id''' renamed to '''wesnoth.sides.set_id'''<br />
* '''wesnoth.set_time_of_day''' (which was undocumented and unofficial) replaced with assigning '''wesnoth.current.schedule.time_of_day''', though that only covers part of the original functionality<br />
* '''wesnoth.show_lua_console''' renamed to '''gui.show_lua_console'''<br />
* '''wesnoth.show_menu''' renamed to '''gui.show_menu'''<br />
* '''wesnoth.show_message_box''' renamed to '''gui.show_prompt'''<br />
* '''wesnoth.show_message_dialog''' renamed to '''gui.show_narration'''<br />
* '''wesnoth.show_popup_dialog''' renamed to '''gui.show_popup'''<br />
* '''wesnoth.show_story''' renamed to '''gui.show_story'''<br />
* '''wesnoth.skip_messages''' renamed to '''wesnoth.interface.skip_messages'''<br />
* '''wesnoth.sound_volume''' replaced with read-write '''wesnoth.audio.volume'''<br />
* '''wesnoth.switch_ai''' renamed to '''wesnoth.sides.switch_ai'''<br />
* '''wesnoth.synchronize_choice''' renamed to '''wesnoth.sync.evaluate_single'''<br />
* '''wesnoth.synchronize_choices''' renamed to '''wesnoth.sync.evaluate_multiple'''<br />
* '''wesnoth.teleport''' renamed to '''wesnoth.units.teleport'''<br />
* '''wesnoth.theme_items''' renamed to '''wesnoth.interface.game_display''' - it's still a table with the same keys as before<br />
* '''wesnoth.tovconfig''' renamed to '''wml.tovconfig'''<br />
* '''wesnoth.transform_unit''' renamed to '''wesnoth.units.transform'''<br />
* '''wesnoth.unit_ability''' renamed to '''wesnoth.units.ability'''<br />
* '''wesnoth.unit_defense''' renamed to '''wesnoth.units.chance_to_be_hit'''<br />
* '''wesnoth.unit_jamming_cost''' renamed to '''wesnoth.units.jamming_on'''<br />
* '''wesnoth.unit_movement_cost''' renamed to '''wesnoth.units.movement_on'''<br />
* '''wesnoth.unit_resistance''' replaced by '''wesnoth.units.resistance_against''' - new function returns (100 - old function)<br />
* '''wesnoth.unit_vision_cost''' renamed to '''wesnoth.units.vision_on'''<br />
* '''wesnoth.unsynced''' renamed to '''wesnoth.sync.run_unsynced'''<br />
* '''wesnoth.view_locked''' renamed to '''wesnoth.interface.is_locked'''<br />
* '''wesnoth.wml_matches_filter''' renamed to '''wml.matches_filter'''<br />
* '''wesnoth.zoom''' renamed to '''wesnoth.interface.zoom'''<br />
<br />
==== wesnoth.tovconfig and related functions in plugins ====<br />
<br />
The '''wesnoth.tovconfig''' function has been removed from the plugin context. This will have no effect on most people, as the plugin context is rarely used. A plugin context is any Lua script loaded using the <tt>--plugin</tt> command-line parameter, primarily intended for creating bots on the multiplayer server.<br />
<br />
If you were calling '''wesnoth.tovconfig''' in a plugin, then you have several options for updating your code. If you simply needed to verify that a variable holds a valid WML table, you can use '''wml.valid''' instead. If you need to substitute variables into a WML table, you can also use '''wml.interpolate''' to replicate the behaviour of '''wml.tovconfig''', supplying the variables themselves as an extra argument (another WML table).<br />
<br />
In addition, the helper functions '''parsed''', '''literal''', '''shallow_parsed''', and '''shallow_literal''' are not available in the plugin context.<br />
<br />
==== GUI2 API ====<br />
<br />
There has been a major rehaul of the GUI2 API for arbitrary custom dialogs. See [[LuaAPI/types/widget]] and [[LuaAPI/gui/widget]] for details; the changes are also summarized below.<br />
<br />
* '''wesnoth.add_dialog_tree_node''' renamed to '''gui.widget.add_item_of_type''' and now takes a reference to the widget instead of a path to it; use '''gui.widget.find''' to convert a path to a reference<br />
* '''wesnoth.get_dialog_value''' and '''wesnoth.set_dialog_value''' removed; instead access the appropriate member of the widget, such as '''selected_index''' or '''selected''' or '''text''' or '''value''' or '''percentage''' or '''selected_item_path''' or '''unfolded''' or '''unit''' or '''label'''. Some of these may be write-only.<br />
* '''wesnoth.remove_dialog_item''' renamed to '''gui.widget.remove_items_at''' and now takes a reference to the widget instead of a path to it; use '''gui.widget.find''' to convert a path to a reference.<br />
* '''wesnoth.set_dialog_active''' removed; instead assign the '''enabled''' member of a widget<br />
**<syntaxhighlight lang=lua ><br />
-- local function preshow()<br />
local function preshow(self)<br />
local var_a = true<br />
-- whatever you are doing to determine if button should be active<br />
-- wesnoth.set_dialog_active(var_a, "my_button_id")<br />
local widget_handle = self:find('my_button_id') -- or just self.my_button_id<br />
widget_handle.enabled = var_a<br />
-- ...<br />
end<br />
</syntaxhighlight><br />
* '''wesnoth.set_dialog_callback''' removed; instead simply assign to a widget's callback handler, eg <syntaxhighlight lang=lua inline>my_widget.on_modified = function() end</syntaxhighlight><br />
**<syntaxhighlight lang=lua ><br />
-- local function preshow()<br />
local function preshow(self)<br />
local function on_text_modified()<br />
-- Do whatever you need to do<br />
end<br />
-- This example shows an on_modified event; there's also on_left_click and on_button_click<br />
-- Use one of the click events if you were setting the callback on a button.<br />
-- wesnoth.set_dialog_callback(on_text_modified, "my_text_id")<br />
local widget_handle = self:find('my_text_id') -- or just self.my_text_id<br />
widget_handle.on_modified = set_dialog_callback<br />
-- Or you could have defined the function here like this:<br />
-- function widget_handle.on_modified()<br />
-- ...<br />
end<br />
</syntaxhighlight><br />
* '''wesnoth.set_dialog_canvas''' renamed to '''gui.widget.set_canvas''' and now takes a reference to the widget instead of a path to it; use '''gui.widget.find''' to convert a path to a reference<br />
* '''wesnoth.set_dialog_focus''' renamed to '''gui.widget.focus''' and now takes a reference to the widget instead of a path to it; use '''gui.widget.find''' to convert a path to a reference<br />
**<syntaxhighlight lang=lua ><br />
-- local function preshow()<br />
local function preshow(self)<br />
-- wesnoth.set_dialog_focus("my_text_id")<br />
local widget_handle = self:find('my_text_id') -- or just self.my_text_id<br />
widget_handle:focus()<br />
-- ...<br />
end<br />
</syntaxhighlight><br />
* '''wesnoth.set_dialog_markup''' removed; instead assign the '''use_markup''' member of a widget<br />
* '''wesnoth.set_dialog_tooltip''' removed; instead assign the '''tooltip''' member of a widget<br />
**<syntaxhighlight lang=lua ><br />
-- local function preshow()<br />
local function preshow(self)<br />
local var_a = 'Some explanation'<br />
-- whatever you are doing to determine the button's tooltip<br />
-- wesnoth.set_dialog_tooltip(var_a, "my_button_id")<br />
local widget_handle = self:find('my_button_id') -- or just self.my_button_id<br />
widget_handle.tooltip = var_a<br />
-- ...<br />
end<br />
</syntaxhighlight><br />
* '''wesnoth.set_dialog_visible''' removed; instead assign the '''visible''' member of a widget<br />
**<syntaxhighlight lang=lua ><br />
-- local function preshow()<br />
local function preshow(self)<br />
local var_a = true<br />
-- whatever you are doing to determine if button should be visible<br />
-- wesnoth.set_dialog_visible(var_a, "my_button_id")<br />
local widget_handle = self:find('my_button_id') -- or just self.my_button_id<br />
widget_handle.visible = var_a<br />
-- ...<br />
end<br />
</syntaxhighlight><br />
* '''wesnoth.show_dialog''' renamed to '''gui.show_dialog'''<br />
* The '''preshow''' and '''postshow''' functions passed to '''gui.show_dialog''' now take a single parameter, which is a reference to the dialog's root widget (a widget of type "window"). This can be passed to '''gui.widget.find''' to look up widgets by their path. You can also access direct child widgets by simply indexing the root widget.<br />
<br />
==== Map API ====<br />
<br />
Due to a major rehaul of the map API, many map functions are now methods on the map object, available as '''wesnoth.current.map''' (abbreviated in the below listing to just '''map''').<br />
<br />
* '''wesnoth.add_time_area''' renamed to '''wesnoth.map.place_area'''<br />
* '''wesnoth.get_locations''' renamed to '''wesnoth.map.find'''<br />
* '''wesnoth.get_map_size''' replaced with '''map.playable_width''', '''map.playable_height''', and '''map.border_size'''<br />
**<syntaxhighlight lang=lua><br />
-- local width, height, border_size = wesnoth.get_map_size()<br />
local width, height = wesnoth.current.map.playable_width, wesnoth.current.map.playable_height<br />
local border_size = wesnoth.current.map.border_size<br />
-- local width_with_border, height_with_border = width + border_size * 2, height + border_size * 2<br />
local width_with_border, height_with_border = wesnoth.current.map.width and wesnoth.current.map.height<br />
</syntaxhighlight<br />
* '''wesnoth.get_terrain_info''' replaced with '''wesnoth.terrain_types'''<br />
**<syntaxhighlight lang=lua><br />
-- local info = wesnoth.get_terrain_info('Gg')<br />
local info = wesnoth.terrain_types['Gg']<br />
</syntaxhighlight><br />
* '''wesnoth.get_terrain''' replaced with '''map[{x,y}]'''<br />
**<syntaxhighlight lang=lua><br />
-- local terrain = wesnoth.get_terrain(x, y)<br />
local terrain = wesnoth.current.map[{x,y}]<br />
-- local terrain_under_unit = wesnoth.get_terrain(unit.x, unit.y)<br />
local terrain_under_unit = wesnoth.current.map[unit]<br />
</syntaxhighlight><br />
* '''wesnoth.get_village_owner''' renamed to '''wesnoth.map.get_owner'''<br />
* '''wesnoth.get_villages''' replaced with '''wesnoth.map.find''' (with '''gives_income = true''')<br />
**<syntaxhighlight lang=lua><br />
-- For example, get all villages in [time_area]id=shadowed<br />
-- local villages = wesnoth.get_villages{area = 'shadowed'}<br />
local villages = wesnoth.map.find{area = 'shadowed', gives_income = true}<br />
</syntaxhighlight><br />
* '''wesnoth.label''' renamed to '''wesnoth.map.add_label'''<br />
* '''wesnoth.match_location''' renamed to '''wesnoth.map.matches'''<br />
* '''wesnoth.remove_time_area''' renamed to '''wesnoth.map.remove_area'''<br />
* '''wesnoth.set_terrain''' replaced with assigning '''map[{x,y}]''' - helper functions in '''wesnoth.map''' expose the more advanced assignment operations ('''replace_overlay''', '''replace_both''', '''replace_if_failed''') - just assign the result of one of these functions to the hex<br />
**<syntaxhighlight lang=lua><br />
-- wesnoth.set_terrain(x, y, 'Gg')<br />
wesnoth.current.map[{x,y}] = 'Gg'<br />
-- Or be explicit about layer:<br />
wesnoth.current.map[{x,y}] = wesnoth.map.replace_both 'Gg'<br />
-- wesnoth.set_terrain(x, y, 'Gg', 'base')<br />
wesnoth.current.map[{x,y}] = wesnoth.map.replace_base 'Gg'<br />
-- wesnoth.set_terrain(x, y, '^Vh', 'overlay')<br />
wesnoth.current.map[{x,y}] = wesnoth.map.replace_overlay '^Vh'<br />
-- wesnoth.set_terrain(x, y, 'Gg^Vh', 'overlay', true)<br />
wesnoth.current.map[{x,y}] = wesnoth.map.replace_if_failed('Gg^Vh', 'overlay')<br />
</syntaxhighlight><br />
* '''wesnoth.set_village_owner''' renamed to '''wesnoth.map.set_owner'''<br />
* '''wesnoth.special_locations''' renamed to '''map.special_locations''' (note: the length operator is no longer supported)<br />
* '''wesnoth.terrain_mask''' replaced with '''map:terrain_mask'''<br />
<br />
The following functions are only available in map generation scripts:<br />
<br />
* '''wesnoth.create_filter''' renamed to '''wesnoth.map.filter'''<br />
* '''wesnoth.create_map''' renamed to '''wesnoth.map.create'''<br />
* '''wesnoth.default_generate_height_map''' renamed to '''wesnoth.map.generate_height_map'''<br />
* '''wesnoth.generate_default_map''' renamed to '''wesnoth.map.generate'''<br />
* '''map:get_locations''' renamed to '''map:find'''<br />
* '''map:get_tiles_radius''' replaced with '''map::find_in_radius''' (and the order of arguments changed)<br />
**<syntaxhighlight lang=lua><br />
-- This example assumes you have a variable f defined as in World Conquest (engine.lua)<br />
-- local in_radius = map:get_tiles_radius(12, 22, f.terrain 'Gg', 5)<br />
local in_radius = map:find_in_radius(12, 22, 5, f.terrain 'Gg')<br />
</syntaxhighlight><br />
<br />
=== helper module ===<br />
<br />
The helper module is being phased out, so quite a lot of things have been moved out of it. This section is written under the assumption that you loaded it with <syntaxhighlight lang=lua inline>local helper = wesnoth.require "helper"</syntaxhighlight> or the like, but many people call it '''H''' instead of '''helper''', so keep that in mind.<br />
<br />
* '''helper.child_array''' renamed to '''wml.child_array'''<br />
* '''helper.child_count''' renamed to '''wml.child_count'''<br />
* '''helper.child_range''' renamed to '''wml.child_range'''<br />
* '''helper.distance_between''' renamed to '''wesnoth.map.distance_between'''<br />
* '''helper.find_attack''' renamed to '''wesnoth.units.find_attack'''<br />
* '''helper.get_child''' renamed to '''wml.get_child'''<br />
* '''helper.get_nth_child''' renamed to '''wml.get_nth_child'''<br />
* '''helper.get_user_choice''' renamed to '''gui.get_user_choice'''<br />
* '''helper.get_variable_array''' renamed to '''wml.array_access.get'''<br />
* '''helper.get_variable_proxy_array''' renamed to '''wml.array_access.get_proxy'''<br />
* '''helper.literal''' renamed to '''wml.literal'''<br />
* '''helper.modify_unit''' renamed to '''wesnoth.units.modify'''<br />
* '''helper.move_unit_fake''' renamed to '''wesnoth.interface.move_unit_fake'''<br />
* '''helper.parsed''' renamed to '''wml.parsed'''<br />
* '''helper.rand''' renamed to '''mathx.random_choice'''<br />
* '''helper.round''' renamed to '''mathx.round'''<br />
* '''helper.set_variable_array''' renamed to '''wml.array_access.set'''<br />
* '''helper.set_wml_tag_metatable''' replaced with '''wml.tag''', which is a table that works exactly the same as what this function would return<br />
**<syntaxhighlight lang=lua><br />
-- local T = helper.set_wml_tag_metatable{}<br />
local T = wml.tag -- Or you can dispense with T and use wml.tag directly<br />
</syntaxhighlight><br />
* '''helper.set_wml_var_metatable''' replaced with '''wml.variable.proxy''', which is a table that works exactly the same as what this function would return<br />
* '''helper.shallow_literal''' renamed to '''wml.shallow_literal'''<br />
* '''helper.shallow_parsed''' renamed to '''wml.shallow_parsed'''<br />
* '''helper.shuffle''' renamed to '''mathx.shuffle'''<br />
* '''helper.wml_error''' renamed to '''wml.error'''<br />
<br />
=== items module ===<br />
<br />
There were also a few things in an "items" module that have been moved into the main API.<br />
<br />
* '''items.place_halo''' renamed to '''wesnoth.interface.add_item_halo'''<br />
* '''items.place_image''' renamed to '''wesnoth.interface.add_item_image'''<br />
* '''items.remove''' renamed to '''wesnoth.interface.remove_item'''<br />
<br />
[[Category:Lua Reference]]</div>Edward Chernenkohttps://wiki.wesnoth.org/index.php?title=LuaAPI/UpdatingFrom14&diff=68945LuaAPI/UpdatingFrom142021-11-21T02:38:05Z<p>Edward Chernenko: fix typo</p>
<hr />
<div><br />
This page contains a summary of the major Lua API changes between 1.12 and 1.15, to help make updating older code simpler.<br />
<br />
In general, when it says "renamed", the new function is a drop-in replacement for the old one. When it says "replaced", the new function probably has a different API (such as different arguments) or might not even be a function at all.<br />
<br />
For some of these that are more than just a simple rename, an example is given where the old, pre-1.16 code is shown commented out and the new code is shown below it.<br />
<br />
=== Functions in wesnoth namespace ===<br />
<br />
* '''weesnoth.remove_fog''' renamed to '''wesnoth.sides.remove_fog'''<br />
* '''wesnoth.add_ai_component''' renamed to '''wesnoth.sides.add_ai_component'''<br />
* '''wesnoth.add_fog''' renamed to '''wesnoth.sides.place_fog'''<br />
* '''wesnoth.add_modification''' renamed to '''wesnoth.units.add_modification'''<br />
* '''wesnoth.add_sound_source''' replaced with '''wesnoth.audio.sources''' mapping (write to key)<br />
**<syntaxhighlight lang=lua><br />
-- wesnoth.add_sound_source{id=my_id, x=15, y=22, sound='my-sound.ogg'}<br />
wesnoth.audio.sources.my_id = {x=15, y=22, sound='my-sound.ogg'}<br />
</syntaxhighlight><br />
* '''wesnoth.add_tile_overlay''' renamed to '''wesnoth.interface.add_hex_overlay'''<br />
* '''wesnoth.add_widget_definition''' renamed to '''gui.add_widget_definition'''<br />
* '''wesnoth.advance_unit''' renamed to '''wesnoth.units.advance'''<br />
* '''wesnoth.alert''' renamed to '''gui.alert'''<br />
* '''wesnoth.allow_end_turn''' renamed to '''wesnoth.interface.allow_end_turn'''<br />
* '''wesnoth.append_ai''' renamed to '''wesnoth.sides.append_ai'''<br />
* '''wesnoth.canonical_path''' renamed to '''filesystem.canonical_path'''<br />
* '''wesnoth.change_ai_component''' renamed to '''wesnoth.sides.change_ai_component'''<br />
* '''wesnoth.clear_messages''' renamed to '''wesnoth.interface.clear_chat_messages'''<br />
* '''wesnoth.color_adjust''' replaced with '''wesnoth.interface.color_adjust'''<br />
* '''wesnoth.compare_versions''' replaced with '''wesnoth.version''', which creates a version object that can be compared with standard comparison operators<br />
**<syntaxhighlight lang=lua><br />
-- if wesnoth.compare_versions(wesnoth.game_config.version, '<=', '1.13') then<br />
if wesnoth.current_version() <= wesnoth.version '1.13' then<br />
-- do version-specific stuff<br />
end</syntaxhighlight><br />
* '''wesnoth.confirm''' renamed to '''gui.confirm'''<br />
* '''wesnoth.copy_unit''' renamed to '''wesnoth.units.clone'''<br />
* '''wesnoth.create_animator''' renamed to '''wesnoth.units.create_animator'''<br />
* '''wesnoth.create_side''' renamed to '''wesnoth.sides.create'''<br />
* '''wesnoth.create_unit''' renamed to '''wesnoth.units.create'''<br />
* '''wesnoth.create_weapon''' renamed to '''wesnoth.units.create_weapon'''<br />
* '''wesnoth.debug_ai''' renamed to '''wesnoth.sides.debug_ai'''<br />
* '''wesnoth.debug''' renamed to '''wml.tostring'''; in addition, it now produces an output that is valid WML, meaning that <syntaxhighlight lang=lua inline>wml.parse(wml.tostring(wml_table))</syntaxhighlight> will output a clone of '''wml_table''' (though for this purpose there's a separate '''wml.clone''' function which is probably faster).<br />
* '''wesnoth.delay''' renamed to '''wesnoth.interface.delay'''<br />
* '''wesnoth.delete_ai_component''' renamed to '''wesnoth.sides.delete_ai_component'''<br />
* '''wesnoth.deselect_hex''' renamed to '''wesnoth.interface.deselect_hex'''<br />
* '''wesnoth.end_level''' replaced with assignable '''wesnoth.scenario.end_level_data'''<br />
* '''wesnoth.end_turn''' renamed to '''wesnoth.interface.end_turn'''<br />
* '''wesnoth.erase_unit''' renamed to '''wesnoth.units.erase'''<br />
* '''wesnoth.eval_conditional''' renamed to '''wml.eval_conditional'''<br />
* '''wesnoth.extract_unit''' renamed to '''wesnoth.units.extract'''<br />
* '''wesnoth.find_cost_map''' renamed to '''wesnoth.paths.find_cost_map'''<br />
* '''wesnoth.find_path''' renamed to '''wesnoth.paths.find_path'''<br />
* '''wesnoth.find_reach''' renamed to '''wesnoth.paths.find_reach'''<br />
* '''wesnoth.find_vacant_tile''' renamed to '''wesnoth.paths.find_vacant_hex'''<br />
* '''wesnoth.find_vision_range''' renamed to '''wesnoth.paths.find_vision_range'''<br />
* '''wesnoth.float_label''' renamed to '''wesnoth.interface.float_label'''<br />
* '''wesnoth.format_conjunct_list''' renamed to '''stringx.format_conjunct_list'''<br />
* '''wesnoth.format_disjunct_list''' renamed to '''stringx.format_disjunct_list'''<br />
* '''wesnoth.format''' renamed to '''stringx.vformat''' and can also be called directly on a string literal<br />
* '''wesnoth.gamestate_inspector''' renamed to '''gui.show_inspector'''<br />
* '''wesnoth.get_all_vars''' replaced with read-only variable '''wml.all_variables''' (but it should still be used sparingly)<br />
* '''wesnoth.get_displayed_unit''' renamed to '''wesnoth.interface.get_displayed_unit'''<br />
* '''wesnoth.get_end_level_data''' replaced with readable '''wesnoth.scenario.end_level_data'''<br />
* '''wesnoth.get_image_size''' renamed to '''filesystem.image_size'''<br />
* '''wesnoth.get_max_liminal_bonus''' replaced with read-only '''wesnoth.current.schedule.liminal_bonus'''<br />
* '''wesnoth.get_mouseover_tile''' renamed to '''wesnoth.interface.get_hovered_hex'''<br />
* '''wesnoth.get_recall_units''' renamed to '''wesnoth.units.find_on_recall'''<br />
* '''wesnoth.get_selected_tile''' renamed to '''wesnoth.interface.get_selected_hex'''<br />
* '''wesnoth.get_side_variable''' and '''wesnoth.set_side_variable''' replaced by '''variables''' member in side data (found in '''wesnoth.sides''' array). This otherwise works the same as '''wml.variables'''.<br />
** <syntaxhighlight lang=lua><br />
-- local old_value = wesnoth.get_side_variable(1, 'my_value')<br />
local old_value = wesnoth.sides[1].variables['my_value'] -- or variables.myvalue<br />
local new_value = old_value * 2<br />
-- wesnoth.set_side_variable(1, 'my_value', new_value)<br />
wesnoth.sides[1].variables['my_value'] = new_value<br />
</syntaxhighlight><br />
* '''wesnoth.get_sides''' renamed to '''wesnoth.sides.find'''<br />
* '''wesnoth.get_sound_source''' replaced with '''wesnoth.audio.sources''' mapping (read key)<br />
* '''wesnoth.get_starting_location''' replaced by '''starting_location''' member in side data<br />
* '''wesnoth.get_time_of_day''' replaced with '''wesnoth.schedule.get_time_of_day''' and '''wesnoth.schedule.get_illumination''' as well as '''wesnoth.current.schedule.time_of_day'''<br />
** <syntaxhighlight lang=lua><br />
-- local global_tod = wesnoth.get_time_of_day(wesnoth.current.turn + 1)<br />
local global_tod = wesnoth.schedule.get_time_of_day(nil, wesnoth.current.turn + 1)<br />
-- local base_tod = wesnoth.get_time_of_day(wesnoth.current.turn + 1, {44, 23})<br />
local base_tod = wesnoth.schedule.get_time_of_day({44, 23}, wesnoth.current.turn + 1)<br />
-- local final_tod = wesnoth.get_time_of_day(wesnoth.current.turn + 1, {44, 23, true})<br />
local final_tod = wesnoth.schedule.get_illumination({44, 24}, wesnoth.current.turn + 1)<br />
</syntaxhighlight><br />
* '''wesnoth.get_time_stamp''' renamed to '''wesnoth.ms_since_init'''<br />
* '''wesnoth.get_traits''' replaced with '''wesnoth.game_config.global_traits''', which is the table it formerly returned<br />
* '''wesnoth.get_unit''' renamed to '''wesnoth.units.get'''<br />
* '''wesnoth.get_units''' renamed to '''wesnoth.units.find_on_map'''<br />
* '''wesnoth.get_variable''' and '''wesnoth.set_variable''' are replaced by '''wml.variables''' which can be indexed with a variable path - set a variable by assigning to it<br />
** <syntaxhighlight lang=lua><br />
-- local old_value = wesnoth.get_variable('my_array[2].value')<br />
local old_value = wesnoth.variables['my_array[2].value']<br />
local new_value = old_value * 2<br />
-- wesnoth.set_variable('my_array[2].value', new_value)<br />
wesnoth.variables['my_array[2].value'] = new_value<br />
</syntaxhighlight><br />
* '''wesnoth.have_file''' renamed to '''filesystem.have_file'''<br />
* '''wesnoth.highlight_hex''' renamed to '''wesnoth.interface.highlight_hex'''<br />
* '''wesnoth.invoke_synced_command''' renamed to '''wesnoth.sync.invoke_command'''<br />
* '''wesnoth.is_enemy''' renamed to '''wesnoth.sides.is_enemy'''<br />
* '''wesnoth.is_fogged''' renamed to '''wesnoth.sides.is_fogged'''<br />
* '''wesnoth.is_shrouded''' renamed to '''wesnoth.sides.is_shrouded'''<br />
* '''wesnoth.is_skipping_messages''' renamed to '''wesnoth.interface.is_skipping_messages'''<br />
* '''wesnoth.lock_view''' renamed to '''wesnoth.interface.lock'''<br />
* '''wesnoth.match_side''' renamed to '''wesnoth.sides.matches'''<br />
* '''wesnoth.match_unit''' renamed to '''wesnoth.units.matches'''<br />
* '''wesnoth.message''' renamed to '''wesnoth.interface.add_chat_message'''<br />
* '''wesnoth.music_list''' renamed to '''wesnoth.audio.music_list'''<br />
* '''wesnoth.open_help''' renamed to '''gui.show_help'''<br />
* '''wesnoth.place_shroud''' replaced with '''wesnoth.sides.place_shroud''' and '''wesnoth.sides.override_shroud'''<br />
* '''wesnoth.play_sound''' renamed to '''wesnoth.audio.play'''<br />
* '''wesnoth.put_recall_unit''' renamed to '''wesnoth.units.to_recall'''<br />
* '''wesnoth.put_unit''' renamed to '''wesnoth.units.to_map'''<br />
* '''wesnoth.random''' renamed to '''mathx.random'''<br />
* '''wesnoth.read_file''' renamed to '''filesystem.read_file'''<br />
* '''wesnoth.remove_modifications''' renamed to '''wesnoth.units.remove_modifications'''<br />
* '''wesnoth.remove_sound_source''' replaced with '''wesnoth.audio.sources''' mapping (assign nil to key)<br />
* '''wesnoth.remove_tile_overlay''' renamed to '''wesnoth.interface.remove_hex_overlay'''<br />
* '''wesnoth.replace_schedule''' renamed to '''wesnoth.schedule.replace'''<br />
* '''wesnoth.scroll_to_tile''' renamed to '''wesnoth.interface.scroll_to_hex'''<br />
* '''wesnoth.scroll''' renamed to '''wesnoth.interface.scroll'''<br />
* '''wesnoth.select_unit''' renamed to '''wesnoth.units.select''' (also available as wesnoth.interface.select_unit)<br />
* '''wesnoth.set_end_campaign_credits''' replaced with assignable '''wesnoth.scenario.show_credits'''<br />
* '''wesnoth.set_end_campaign_text''' replaced with assignable '''wesnoth.scenario.end_text''' and '''wesnoth.scenario.end_text_duration'''<br />
* '''wesnoth.set_next_scenario''' replaced with assignable '''wesnoth.scenario.next'''<br />
* '''wesnoth.set_side_id''' renamed to '''wesnoth.sides.set_id'''<br />
* '''wesnoth.set_time_of_day''' (which was undocumented and unofficial) replaced with assigning '''wesnoth.current.schedule.time_of_day''', though that only covers part of the original functionality<br />
* '''wesnoth.show_lua_console''' renamed to '''gui.show_lua_console'''<br />
* '''wesnoth.show_menu''' renamed to '''gui.show_menu'''<br />
* '''wesnoth.show_message_box''' renamed to '''gui.show_prompt'''<br />
* '''wesnoth.show_message_dialog''' renamed to '''gui.show_narration'''<br />
* '''wesnoth.show_popup_dialog''' renamed to '''gui.show_popup'''<br />
* '''wesnoth.show_story''' renamed to '''gui.show_story'''<br />
* '''wesnoth.skip_messages''' renamed to '''wesnoth.interface.skip_messages'''<br />
* '''wesnoth.sound_volume''' replaced with read-write '''wesnoth.audio.volume'''<br />
* '''wesnoth.switch_ai''' renamed to '''wesnoth.sides.switch_ai'''<br />
* '''wesnoth.synchronize_choice''' renamed to '''wesnoth.sync.evaluate_single'''<br />
* '''wesnoth.synchronize_choices''' renamed to '''wesnoth.sync.evaluate_multiple'''<br />
* '''wesnoth.teleport''' renamed to '''wesnoth.units.teleport'''<br />
* '''wesnoth.theme_items''' renamed to '''wesnoth.interface.game_display''' - it's still a table with the same keys as before<br />
* '''wesnoth.tovconfig''' renamed to '''wml.tovconfig'''<br />
* '''wesnoth.transform_unit''' renamed to '''wesnoth.units.transform'''<br />
* '''wesnoth.unit_ability''' renamed to '''wesnoth.units.ability'''<br />
* '''wesnoth.unit_defense''' renamed to '''wesnoth.units.chance_to_be_hit'''<br />
* '''wesnoth.unit_jamming_cost''' renamed to '''wesnoth.units.jamming_on'''<br />
* '''wesnoth.unit_movement_cost''' renamed to '''wesnoth.units.movement_on'''<br />
* '''wesnoth.unit_resistance''' replaced by '''wesnoth.units.resistance_against''' - new function returns (100 - old function)<br />
* '''wesnoth.unit_vision_cost''' renamed to '''wesnoth.units.vision_on'''<br />
* '''wesnoth.unsynced''' renamed to '''wesnoth.sync.run_unsynced'''<br />
* '''wesnoth.view_locked''' renamed to '''wesnoth.interface.is_locked'''<br />
* '''wesnoth.wml_matches_filter''' renamed to '''wml.matches_filter'''<br />
* '''wesnoth.zoom''' renamed to '''wesnoth.interface.zoom'''<br />
<br />
==== wesnoth.tovconfig and related functions in plugins ====<br />
<br />
The '''wesnoth.tovconfig''' function has been removed from the plugin context. This will have no effect on most people, as the plugin context is rarely used. A plugin context is any Lua script loaded using the <tt>--plugin</tt> command-line parameter, primarily intended for creating bots on the multiplayer server.<br />
<br />
If you were calling '''wesnoth.tovconfig''' in a plugin, then you have several options for updating your code. If you simply needed to verify that a variable holds a valid WML table, you can use '''wml.valid''' instead. If you need to substitute variables into a WML table, you can also use '''wml.interpolate''' to replicate the behaviour of '''wml.tovconfig''', supplying the variables themselves as an extra argument (another WML table).<br />
<br />
In addition, the helper functions '''parsed''', '''literal''', '''shallow_parsed''', and '''shallow_literal''' are not available in the plugin context.<br />
<br />
==== GUI2 API ====<br />
<br />
There has been a major rehaul of the GUI2 API for arbitrary custom dialogs. See [[LuaAPI/types/widget]] and [[LuaAPI/gui/widget]] for details; the changes are also summarized below.<br />
<br />
* '''wesnoth.add_dialog_tree_node''' renamed to '''gui.widget.add_item_of_type''' and now takes a reference to the widget instead of a path to it; use '''gui.widget.find''' to convert a path to a reference<br />
* '''wesnoth.get_dialog_value''' and '''wesnoth.set_dialog_value''' removed; instead access the appropriate member of the widget, such as '''selected_index''' or '''selected''' or '''text''' or '''value''' or '''percentage''' or '''selected_item_path''' or '''unfolded''' or '''unit''' or '''label'''. Some of these may be write-only.<br />
* '''wesnoth.remove_dialog_item''' renamed to '''gui.widget.remove_items_at''' and now takes a reference to the widget instead of a path to it; use '''gui.widget.find''' to convert a path to a reference.<br />
* '''wesnoth.set_dialog_active''' removed; instead assign the '''enabled''' member of a widget<br />
**<syntaxhighlight lang=lua ><br />
-- local function preshow()<br />
local function preshow(self)<br />
local var_a = true<br />
-- whatever you are doing to determine if button should be active<br />
-- wesnoth.set_dialog_active(var_a, "my_button_id")<br />
local widget_handle = self:find('my_button_id') -- or just self.my_button_id<br />
widget_handle.enabled = var_a<br />
-- ...<br />
end<br />
</syntaxhighlight><br />
* '''wesnoth.set_dialog_callback''' removed; instead simply assign to a widget's callback handler, eg <syntaxhighlight lang=lua inline>my_widget.on_modified = function() end</syntaxhighlight><br />
**<syntaxhighlight lang=lua ><br />
-- local function preshow()<br />
local function preshow(self)<br />
local function on_text_modified()<br />
-- Do whatever you need to do<br />
end<br />
-- This example shows an on_modified event; there's also on_left_click and on_button_click<br />
-- Use one of the click events if you were setting the callback on a button.<br />
-- wesnoth.set_dialog_callback(on_text_modified, "my_text_id")<br />
local widget_handle = self:find('my_text_id') -- or just self.my_text_id<br />
widget_handle.on_modified = set_dialog_callback<br />
-- Or you could have defined the function here like this:<br />
-- function widget_handle.on_modified()<br />
-- ...<br />
end<br />
</syntaxhighlight><br />
* '''wesnoth.set_dialog_canvas''' renamed to '''gui.widget.set_canvas''' and now takes a reference to the widget instead of a path to it; use '''gui.widget.find''' to convert a path to a reference<br />
* '''wesnoth.set_dialog_focus''' renamed to '''gui.widget.focus''' and now takes a reference to the widget instead of a path to it; use '''gui.widget.find''' to convert a path to a reference<br />
**<syntaxhighlight lang=lua ><br />
-- local function preshow()<br />
local function preshow(self)<br />
-- wesnoth.set_dialog_focus("my_text_id")<br />
local widget_handle = self:find('my_text_id') -- or just self.my_text_id<br />
widget_handle:focus()<br />
-- ...<br />
end<br />
</syntaxhighlight><br />
* '''wesnoth.set_dialog_markup''' removed; instead assign the '''use_markup''' member of a widget<br />
* '''wesnoth.set_dialog_tooltip''' removed; instead assign the '''tooltip''' member of a widget<br />
**<syntaxhighlight lang=lua ><br />
-- local function preshow()<br />
local function preshow(self)<br />
local var_a = 'Some explanation'<br />
-- whatever you are doing to determine the button's tooltip<br />
-- wesnoth.set_dialog_tooltip(var_a, "my_button_id")<br />
local widget_handle = self:find('my_button_id') -- or just self.my_button_id<br />
widget_handle.tooltip = var_a<br />
-- ...<br />
end<br />
</syntaxhighlight><br />
* '''wesnoth.set_dialog_visible''' removed; instead assign the '''visible''' member of a widget<br />
**<syntaxhighlight lang=lua ><br />
-- local function preshow()<br />
local function preshow(self)<br />
local var_a = true<br />
-- whatever you are doing to determine if button should be visible<br />
-- wesnoth.set_dialog_visible(var_a, "my_button_id")<br />
local widget_handle = self:find('my_button_id') -- or just self.my_button_id<br />
widget_handle.visible = var_a<br />
-- ...<br />
end<br />
</syntaxhighlight><br />
* '''wesnoth.show_dialog''' renamed to '''gui.show_dialog'''<br />
* The '''preshow''' and '''postshow''' functions passed to '''gui.show_dialog''' now take a single parameter, which is a reference to the dialog's root widget (a widget of type "window"). This can be passed to '''gui.widget.find''' to look up widgets by their path. You can also access direct child widgets by simply indexing the root widget.<br />
<br />
==== Map API ====<br />
<br />
Due to a major rehaul of the map API, many map functions are now methods on the map object, available as '''wesnoth.current.map''' (abbreviated in the below listing to just '''map''').<br />
<br />
* '''wesnoth.add_time_area''' renamed to '''wesnoth.map.place_area'''<br />
* '''wesnoth.get_locations''' renamed to '''wesnoth.map.find'''<br />
* '''wesnoth.get_map_size''' replaced with '''map.playable_width''', '''map.playable_height''', and '''map.border_size'''<br />
**<syntaxhighlight lang=lua><br />
-- local width, height, border_size = wesnoth.get_map_size()<br />
local width, height = wesnoth.current.map.playable_width, wesnoth.current.map.playable_height<br />
local border_size = wesnoth.current.map.border_size<br />
-- local width_with_border, height_with_border = width + border_size * 2, height + border_size * 2<br />
local width_with_border, height_with_border = wesnoth.current.map.width and wesnoth.current.map.height<br />
</syntaxhighlight<br />
* '''wesnoth.get_terrain_info''' replaced with '''wesnoth.terrain_types'''<br />
**<syntaxhighlight lang=lua><br />
-- local info = wesnoth.get_terrain_info('Gg')<br />
local info = wesnoth.terrain_types['Gg']<br />
</syntaxhighlight><br />
* '''wesnoth.get_terrain''' replaced with '''map[{x,y}]'''<br />
**<syntaxhighlight lang=lua><br />
-- local terrain = wesnoth.get_terrain(x, y)<br />
local terrain = wesnoth.current.map[{x,y}]<br />
-- local terrain_under_unit = wesnoth.get_terrain(unit.x, unit.y)<br />
local terrain_under_unit = wesnoth.current.map[unit]<br />
</syntaxhighlight><br />
* '''wesnoth.get_village_owner''' renamed to '''wesnoth.map.get_owner'''<br />
* '''wesnoth.get_villages''' replaced with '''wesnoth.map.find''' (with '''gives_income = true''')<br />
**<syntaxhighlight lang=lua><br />
-- For example, get all villages in [time_area]id=shadowed<br />
-- local villages = wesnoth.get_villages{area = 'shadowed'}<br />
local villages = wesnoth.map.find{area = 'shadowed', gives_income = true}<br />
</syntaxhighlight><br />
* '''wesnoth.label''' renamed to '''wesnoth.map.add_label'''<br />
* '''wesnoth.match_location''' renamed to '''wesnoth.map.matches'''<br />
* '''wesnoth.remove_time_area''' renamed to '''wesnoth.map.remove_area'''<br />
* '''wesnoth.set_terrain''' replaced with assigning '''map[{x,y}]''' - helper functions in '''wesnoth.map''' expose the more advanced assignment operations ('''replace_overlay''', '''replace_both''', '''replace_if_failed''') - just assign the result of one of these functions to the hex<br />
**<syntaxhighlight lang=lua><br />
-- wesnoth.set_terrain(x, y, 'Gg')<br />
wesnoth.current.map[{x,y}] = 'Gg'<br />
-- Or be explicit about layer:<br />
wesnoth.current.map[{x,y}] = wesnoth.map.replace_both 'Gg'<br />
-- wesnoth.set_terrain(x, y, 'Gg', 'base')<br />
wesnoth.current.map[{x,y}] = wesnoth.map.replace_base 'Gg'<br />
-- wesnoth.set_terrain(x, y, '^Vh', 'overlay')<br />
wesnoth.current.map[{x,y}] = wesnoth.map.replace_overlay '^Vh'<br />
-- wesnoth.set_terrain(x, y, 'Gg^Vh', 'overlay', true)<br />
wesnoth.current.map[{x,y}] = wesnoth.map.replace_if_failed('Gg^Vh', 'overlay')<br />
</syntaxhighlight><br />
* '''wesnoth.set_village_owner''' renamed to '''wesnoth.map.set_owner'''<br />
* '''wesnoth.special_locations''' renamed to '''map.special_locations''' (note: the length operator is no longer supported)<br />
* '''wesnoth.terrain_mask''' replaced with '''map:terrain_mask'''<br />
<br />
The following functions are only available in map generation scripts:<br />
<br />
* '''wesnoth.create_filter''' renamed to '''wesnoth.map.filter'''<br />
* '''wesnoth.create_map''' renamed to '''wesnoth.map.create'''<br />
* '''wesnoth.default_generate_height_map''' renamed to '''wesnoth.map.generate_height_map'''<br />
* '''wesnoth.generate_default_map''' renamed to '''wesnoth.map.generate'''<br />
* '''map:get_locations''' renamed to '''map:find'''<br />
* '''map:get_tiles_radius''' replaced with '''map::find_in_radius''' (and the order of arguments changed)<br />
**<syntaxhighlight lang=lua><br />
-- This example assumes you have a variable f defined as in World Conquest (engine.lua)<br />
-- local in_radius = map:get_tiles_radius(12, 22, f.terrain 'Gg', 5)<br />
local in_radius = map:find_in_radius(12, 22, 5, f.terrain 'Gg')<br />
</syntaxhighlight><br />
<br />
=== helper module ===<br />
<br />
The helper module is being phased out, so quite a lot of things have been moved out of it. This section is written under the assumption that you loaded it with <syntaxhighlight lang=lua inline>local helper = wesnoth.require "helper"</syntaxhighlight> or the like, but many people call it '''H''' instead of '''helper''', so keep that in mind.<br />
<br />
* '''helper.child_array''' renamed to '''wml.child_array'''<br />
* '''helper.child_count''' renamed to '''wml.child_count'''<br />
* '''helper.child_range''' renamed to '''wml.child_range'''<br />
* '''helper.distance_between''' renamed to '''wesnoth.map.distance_between'''<br />
* '''helper.find_attack''' renamed to '''wesnoth.units.find_attack'''<br />
* '''helper.get_child''' renamed to '''wml.get_child'''<br />
* '''helper.get_nth_child''' renamed to '''wml.get_nth_child'''<br />
* '''helper.get_user_choice''' renamed to '''gui.get_user_choice'''<br />
* '''helper.get_variable_array''' renamed to '''wml.array_access.get'''<br />
* '''helper.get_variable_proxy_array''' renamed to '''wml.array_access.get_proxy'''<br />
* '''helper.literal''' renamed to '''wml.literal'''<br />
* '''helper.modify_unit''' renamed to '''wesnoth.units.modify'''<br />
* '''helper.move_unit_fake''' renamed to '''wesnoth.interface.move_unit_fake'''<br />
* '''helper.parsed''' renamed to '''wml.parsed'''<br />
* '''helper.rand''' renamed to '''mathx.random_choice'''<br />
* '''helper.round''' renamed to '''mathx.round'''<br />
* '''helper.set_variable_array''' renamed to '''wml.array_access.set'''<br />
* '''helper.set_wml_tag_metatable''' replaced with '''wml.tag''', which is a table that works exactly the same as what this function would return<br />
**<syntaxhighlight lang=lua><br />
-- local T = helper.set_wml_tag_metatable{}<br />
local T = wml.tag -- Or you can dispense with T and use wml.tag directly<br />
</syntaxhighlight><br />
* '''helper.set_wml_var_metatable''' replaced with '''wml.variable.proxy''', which is a table that works exactly the same as what this function would return<br />
* '''helper.shallow_literal''' renamed to '''wml.shallow_literal'''<br />
* '''helper.shallow_parsed''' renamed to '''wml.shallow_parsed'''<br />
* '''helper.shuffle''' renamed to '''mathx.shuffle'''<br />
* '''helper.wml_error''' renamed to '''wml.error'''<br />
<br />
=== items module ===<br />
<br />
There were also a few things in an "items" module that have been moved into the main API.<br />
<br />
* '''items.place_halo''' renamed to '''wesnoth.interface.add_item_halo'''<br />
* '''items.place_image''' renamed to '''wesnoth.interface.add_item_image'''<br />
* '''items.remove''' renamed to '''wesnoth.interface.remove_item'''<br />
<br />
[[Category:Lua Reference]]</div>Edward Chernenkohttps://wiki.wesnoth.org/index.php?title=LuaWML/Units&diff=65554LuaWML/Units2020-04-24T01:29:41Z<p>Edward Chernenko: typo</p>
<hr />
<div>This page describes the [[LuaWML]] functions for handling units.<br />
<br />
A unit is a proxy table with the following fields:<br />
* '''x''', '''y''': integers (read only, read/write if the unit is not on the map. {{DevFeature1.13|11}} These are now read/write under all circumstances, including for on-map units)<br />
* '''loc''': {{DevFeature1.13|11}} shortcut to get/set both x and y at once (read/write). Setting x and y individually would result in two moves, and there's the possibility that the intermediate move fails if the hex is occupied by another unit. In general, note that moving a unit by changing the proxy unit's coordinates does not work if the goal hex is occupied (it is not executed), so it is necessary to check if the hex is available first.<br />
* '''side''': integer (read/write)<br />
* '''id''': string (read only)<br />
* '''type''': string (read only)<br />
* '''name''': translatable string (read only)<br />
* '''cost''' {{DevFeature1.13|10}}: integer (read)<br />
* '''max_hitpoints''', '''max_experience''', '''max_moves''': integers (read only)<br />
* '''max_attacks''': integer (read only)<br />
* '''attacks_left''': integer (read/write) Setting below 0 is limited to 0.<br />
* '''extra_recruit''': table (read/write)<br />
* '''advances_to''': table (read/write)<br />
* '''hitpoints''', '''experience''': integer (read/write)<br />
* '''moves''': integer (read/write)<br />
* '''level''': {{DevFeature1.13|5}} integer (read/write)<br />
* '''resting''': boolean (read/write)<br />
* '''hidden''': boolean (read/write)<br />
* '''petrified''', '''canrecruit''': booleans (read only)<br />
* '''role''', '''facing''': strings (read/write)<br />
* '''status''': proxy associative table (read only, read/write fields), provides fields like [[SingleUnitWML#Unit_State|poisoned, slowed, petrified, uncovered, guardian, unhealable, invulnerable]]<br />
* '''image_mods''': string (read only)<br />
* '''upkeep''' {{DevFeature1.13|5}}: one of 'loyal', 'full' or a number (read/writre)<br />
* '''variables''': proxy associative table (read only, read/write fields, including ''variables.__cfg''), only toplevel named fields are proxied. {{DevFeature1.13|2}} subcontainers can be accessed by using the usual variable syntax: <syntaxhighlight inline lang='lua'>unit.variables["a.b.c[6].d"]</syntaxhighlight><br />
* '''attacks''': {{DevFeature1.13|0}}an object to access the units attacks, you can use the attacks index or the attacks name to index an attack. every attack has the following members:<br />
** '''description''': translatable string (read/write)<br />
** '''name''': string (read)<br />
** '''type''': string (read/write)<br />
** '''range''': string (read/write)<br />
** '''damage''': number(read/write)<br />
** '''number''': number(read/write)<br />
** '''movement_used''': number(read/write)<br />
** '''attack_weight''': number(read/write)<br />
** '''defense_weight''': number(read/write)<br />
** '''specials''' wml table(read/write)<br />
* '''valid''': string or nil (read only)<br />
* '''advancements''': {{DevFeature1.13|2}} an array of wml tables (read/write)<br />
* '''__cfg''': WML table (dump) ([[SingleUnitWML]])<br />
* {{DevFeature1.13|2}} The following fields are unit methods synonymous to one of the functions described on this page:<br />
** '''[[#wesnoth.match_unit|matches]]'''<br />
** '''[[#wesnoth.put_recall_unit|to_recall]]'''<br />
** '''[[#wesnoth.put_unit|to_map]]'''<br />
** '''[[#wesnoth.erase_unit|erase]]'''<br />
** '''[[#wesnoth.copy_unit|clone]]'''<br />
** '''[[#wesnoth.extract_unit|extract]]'''<br />
** '''[[#wesnoth.advance_unit|advance]]'''<br />
** '''[[#wesnoth.add_modification|add_modification]]'''<br />
** '''[[#wesnoth.remove_modifications|remove_modifications]]'''<br />
** '''[[#wesnoth.unit_resistance|resistance]]'''<br />
** '''[[#wesnoth.unit_defense|defense]]'''<br />
** '''[[#wesnoth.unit_movement_cost|movement]]'''<br />
** '''[[#wesnoth.unit_vision_cost|vision]]'''<br />
** '''[[#wesnoth.unit_jamming_cost|jamming]]'''<br />
** '''[[#wesnoth.unit_ability|ability]]'''<br />
** '''[[#wesnoth.transform_unit|transform]]'''<br />
The metatable of these proxy tables appears as '''"unit"'''.<br />
<br />
A unit can be either visible on the map ([[#wesnoth.get_units]], [[#wesnoth.put_unit]]), or on a recall list ([[#wesnoth.get_recall_units]], [[#wesnoth.put_recall_unit]]), or private to the Lua code ([[#wesnoth.create_unit]], [[#wesnoth.copy_unit]], [[#wesnoth.extract_unit]]). The Lua code has complete control over the private units; they will not be modified unless accessed through the proxy unit. Units on the map and on the recall lists, however, can be modified by the user, the engine, WML, independently of the Lua code. In particular, if a unit is killed, any further use of the proxy unit will cause an error. For units on the map, the proxy unit is valid as long as there is a unit on the map that has the same "underlying_id" WML field as the original one. The behavior is similar for units on the recall lists. The ''valid'' field reflects the unit availability by returning '''"map"''', '''"recall"''', '''"private"''', or ''nil''. The latter value is used for units that were removed (e.g. killed). In that case, the ''valid'' field is the only one that can be read without causing an error.<br />
<br />
The term "proxy", here in particular "proxy unit", means that the variable retrieved in the lua code (with get_units for example) is an accessor (reference) to the C++ object which represents that unit. This is very different from unit variables obtained by [store_unit] in wml. The fields marked as "writable" above can be modified without the need to use put_unit afterwards. This same reason explains that modifications to the unit from outside the lua code (like [kill] invalidating the proxy unit) have immediate effect on the lua code's proxy unit variable (with the exception of private proxy units).<br />
<br />
<br />
==== wesnoth.get_units ====<br />
<br />
* '''wesnoth.get_units(''filter'')'''<br />
* {{DevFeature1.13|12}} '''wesnoth.get_units(''filter'', ''fake_location'')'''<br />
* {{DevFeature1.13|12}} '''wesnoth.get_units(''filter'', ''other_unit'')'''<br />
<br />
Returns an array of all the units on the map matching the WML filter passed as the first argument. See [[StandardUnitFilter]] for details about filters. If a second unit is passed, it can be referenced via the $other_unit variable in the main filter as well as via the "other" variable in WFL formulas used in the main filter. If a location is passed, the filter is run as if the unit were at that location (rather than its real location). This affects things such as [filter_adjacent] and ability_active, and should work even for a unit on the recall list.<br />
<br />
<syntaxhighlight lang='lua'><br />
local leaders_on_side_two = wesnoth.get_units { side = 2, canrecruit = true }<br />
local name_of_leader = leaders_on_side_two[1].name<br />
</syntaxhighlight><br />
<br />
==== wesnoth.get_unit ====<br />
<br />
* '''wesnoth.get_unit(''x'', ''y'')'''<br />
* '''wesnoth.get_unit(''id'')'''<br />
<br />
Returns the unit at the given location or with the given ID.<br />
<br />
<syntaxhighlight lang='lua'><br />
local args = ...<br />
local unit = wesnoth.get_unit(args.x1, args.y1)<br />
</syntaxhighlight><br />
<br />
==== wesnoth.match_unit ====<br />
<br />
* '''wesnoth.match_unit(''unit'', ''filter'')'''<br />
* {{DevFeature1.13|2}} '''wesnoth.match_unit(''unit'', ''filter'', ''other_unit'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':matches(''filter'', [''other_unit''])'''<br />
* {{DevFeature1.13|2}} '''wesnoth.match_unit(''unit'', ''filter'', ''location'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':matches(''filter'', [''location''])'''<br />
<br />
Returns true if the given unit matches the WML filter passed as the second argument. If ''other_unit'' is specified, it is used for the ''$other_unit'' auto-stored variable in the filter. Otherwise, this variable is not stored for the filter. If an extra ''location'' is specified, the filter matches as if the unit were at that location.<br />
<br />
<syntaxhighlight lang='lua'><br />
assert(unit.canrecruit == wesnoth.match_unit(unit, { canrecruit = true }))<br />
</syntaxhighlight><br />
<br />
==== wesnoth.put_unit ====<br />
<br />
* '''wesnoth.put_unit(''unit'')'''<br />
* '''wesnoth.put_unit(''x'', ''y'', ''unit'')'''<br />
* '''wesnoth.put_unit(''x'', ''y'')'''<br />
* {{DevFeature1.13|2}} '''wesnoth.put_unit(''unit'', ''x'', ''y'')''' -- The above two forms are also deprecated.<br />
* {{DevFeature1.13|2}} '''''unit'':to_map([''x'', ''y''])<br />
<br />
Places a unit on the map. This unit is described either by a WML table or by a proxy unit. Coordinates can be passed as the first two arguments, otherwise the table is expected to have two fields '''x''' and '''y''', which indicate where the unit will be placed. If the function is called with coordinates only, the unit on the map at the given coordinates is removed instead. {{DevFeature1.13|2}} This use is now deprecated; use wesnoth.erase_unit instead.<br />
<br />
<syntaxhighlight lang='lua'><br />
-- create a unit with random traits, then erase it<br />
wesnoth.put_unit(17, 42, { type = "Elvish Lady" })<br />
wesnoth.put_unit(17, 42)<br />
</syntaxhighlight><br />
<br />
When the argument is a proxy unit, no duplicate is created. In particular, if the unit was private or on a recall list, it no longer is; and if the unit was on the map, it has been moved to the new location. Note: passing a WML table is just a shortcut for calling [[#wesnoth.create_unit]] and then putting the resulting unit on the map.<br />
<br />
<syntaxhighlight lang='lua'><br />
-- move the leader back to the top-left corner<br />
wesnoth.put_unit(1, 1, wesnoth.get_units({ canrecruit = true })[1])<br />
</syntaxhighlight><br />
<br />
If x,y is a village, this function does not capture it (as of 1.14). Use [[LuaWML:Sides#wesnoth.set_village_owner|wesnoth.set_village_owner(x, y, unit.side)]] if that's what you want.<br />
<br />
==== wesnoth.erase_unit ====<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
* '''wesnoth.erase_unit(''unit'')'''<br />
* '''wesnoth.erase_unit(''x'', ''y'')'''<br />
* '''''unit'':erase()'''<br />
<br />
Erases a unit from the map. After calling this on a unit, the unit is no longer valid.<br />
<br />
==== wesnoth.get_recall_units ====<br />
<br />
* '''wesnoth.get_recall_units()'''<br />
<br />
Returns an array of all the units on the recall lists matching the WML filter passed as the first argument.<br />
<br />
==== wesnoth.put_recall_unit ====<br />
<br />
* '''wesnoth.put_recall_unit(''unit'', [''side''])'''<br />
* {{DevFeature1.13|2}} '''''unit'':to_recall([''side''])'''<br />
<br />
Places a unit on a recall list. This unit is described either by a WML table or by a proxy unit. The side of the recall list is given by the second argument, or by the side of the unit if missing.<br />
<br />
<syntaxhighlight lang='lua'><br />
-- put the unit at location 17,42 on the recall list for side 2<br />
wesnoth.put_recall_unit(wesnoth.get_units({ x= 17, y = 42 })[1], 2)<br />
</syntaxhighlight><br />
<br />
When the argument is a proxy unit, no duplicate is created. In particular, if the unit was private or on the map, it no longer is. Note: passing a WML table is just a shortcut for calling [[#wesnoth.create_unit]] and then putting the resulting unit on a recall list.<br />
<br />
==== wesnoth.create_unit ====<br />
<br />
* '''wesnoth.create_unit(''unit_info'')'''<br />
<br />
Creates a private unit from a WML table.<br />
<br />
<syntaxhighlight lang='lua'><br />
local u = wesnoth.create_unit { type = "White Mage", gender = "female" }<br />
</syntaxhighlight><br />
<br />
==== wesnoth.copy_unit ====<br />
<br />
* '''wesnoth.copy_unit(''unit'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':clone()'''<br />
<br />
Creates a private unit from another unit.<br />
<br />
<syntaxhighlight lang='lua'><br />
-- extract a unit from the map<br />
local u = wesnoth.copy_unit(wesnoth.get_units({ type = "Thug" })[1])<br />
wesnoth.erase_unit(u.x, u.y)<br />
-- u is still valid at this point<br />
</syntaxhighlight><br />
<br />
==== wesnoth.extract_unit ====<br />
<br />
* '''wesnoth.extract_unit(''unit'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':extract()'''<br />
<br />
Removes a unit from the map or from a recall list and makes it private.<br />
<br />
<syntaxhighlight lang='lua'><br />
-- remove all the units from the recall list of side 1 and put them in a WML container<br />
local l = {}<br />
for i,u in ipairs(wesnoth.get_recall_units { side = 1 }) do<br />
wesnoth.extract_unit(u)<br />
table.insert(l, u.__cfg)<br />
end<br />
helper.set_variable_array("player_recall_list", l)<br />
</syntaxhighlight><br />
<br />
Note: if the unit is on the map, it is just a shortcut for calling [[#wesnoth.copy_unit]] and then [[#wesnoth.put_unit]] without a unit. It is, however, the only way for removing a unit from a recall list without putting it on the map.<br />
<br />
<br />
==== wesnoth.advance_unit ====<br />
<br />
* '''wesnoth.advance_unit(''unit'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':advance()'''<br />
<br />
{{DevFeature1.13|0}} Advances the unit (and shows the advance unit dialog if needed) if the unit has enough xp. This function should be called after modifying the units experience directly. A similar function is called by wesnoth internally after unit combat. The second argument is a boodean value that specifies whether the advancement should be animated. The third agrument is a boodean value that specifies whether advancement related events should be fired.<br />
<br />
<br />
This function only works for units on the map.<br />
<br />
This function can also trigger multiple advancements if the unit has enough xp.<br />
<br />
==== wesnoth.add_modification ====<br />
<br />
* '''wesnoth.add_modification(''unit'', ''type'', ''effects'', [''write_to_mods''])'''<br />
* {{DevFeature1.13|2}} '''''unit'':add_modification(''type'', ''effects'', [''write_to_mods''])'''<br />
<br />
Modifies a given unit. It needs to be a proxy unit. The second argument is the type of the modification (one of "trait", "object", or "advance"). The option "advance" applies effects as if the unit would advance (e.g. AMLA effects). The third argument is a WML table describing the effect, so mostly containing '''[effect]''' children. See [[EffectWML]] for details about effects.<br />
<br />
{{DevFeature1.13|2}} In 1.13.2 and later, the "advance" type is replaced with "advancement", to match the equivalent tag in [[UnitTypeWML|[unit_type]]]. Also, it takes a fourth argument which, if false, causes it to not write the modification tag to the unit's [modifications] (as would be done with an [object] with no_write=true).<br />
<br />
<syntaxhighlight lang='lua'><br />
local T = wml.tag<br />
local u = wesnoth.get_units { canrecruit = true }[1]<br />
local effects = {<br />
id = "my_effect_id",<br />
T.effect { <br />
apply_to = "image_mod", <br />
replace = "RC(red>blue)" <br />
},<br />
T.effect {<br />
apply_to = "new_animation",<br />
T.standing_animation {<br />
-- AnimationWML<br />
}<br />
}<br />
} <br />
wesnoth.add_modification(u, "object", effects)<br />
</syntaxhighlight><br />
<br />
==== wesnoth.remove_modifications ====<br />
<br />
* {{DevFeature1.13|?}} '''wesnoth.remove_modifications(''unit'', ''cfg'' [, ''type''])'''<br />
* {{DevFeature1.13|?}} '''''unit'':remove_modifications(''cfg'' [, ''type''])'''<br />
<br />
Modifies a given unit. The unit needs to be a proxy unit. The second argument is a filter for the modifications to remove. It takes the same syntax as [[FilterWML#Filtering_on_WML_data|[filter_wml]]]; all matching modifications will be removed. The third argument is the type (tag name) of the modifications to search for; it defaults to <tt>"object"</tt>, but you can also pass <tt>"trait"</tt> or <tt>"advancement"</tt>.<br />
<br />
<syntaxhighlight lang='lua'><br />
local u = wesnoth.get_units { canrecruit = true }[1]<br />
wesnoth.remove_modifications(u, { id = "my_effect_id" })<br />
</syntaxhighlight><br />
<br />
==== wesnoth.unit_resistance ====<br />
<br />
* '''wesnoth.unit_resistance(''unit'', ''damage_type'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':resistance(''damage_type'')'''<br />
<br />
Returns the resistance of a unit against an attack type. (Note: it is a WML resistance. So the higher it is, the weaker the unit is.) The third argument indicates whether the unit is the attacker. Last arguments are the coordinates of an optional map location (for the purpose of taking abilities into account).<br />
<br />
<syntaxhighlight lang='lua'><br />
local fire_resistance = 100 - wesnoth.unit_resistance(u, "fire")<br />
</syntaxhighlight><br />
<br />
==== wesnoth.unit_defense ====<br />
<br />
* '''wesnoth.unit_defense(''unit'', ''terrain_code'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':defense(''terrain_code'')'''<br />
<br />
Returns the defense of a unit on a particular terrain. (Note: it is a WML defense. So the higher it is, the weaker the unit is.)<br />
<br />
<syntaxhighlight lang='lua'><br />
local flat_defense = 100 - wesnoth.unit_defense(u, "Gt")<br />
</syntaxhighlight><br />
<br />
==== wesnoth.unit_movement_cost ====<br />
<br />
* '''wesnoth.unit_movement_cost(''unit'', ''terrain_code'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':movement(''terrain_code'')'''<br />
<br />
Returns the movement cost of a unit on a particular terrain.<br />
<br />
<syntaxhighlight lang='lua'><br />
local move_cost = wesnoth.unit_movement_cost(u, "Gt")<br />
<syntaxhighlight><br />
<br />
==== wesnoth.unit_vision_cost ====<br />
<br />
* '''wesnoth.unit_vision_cost(''unit'', ''terrain_code'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':vision(''terrain_code'')'''<br />
<br />
Returns the vision cost of a unit on a particular terrain.<br />
<br />
<syntaxhighlight lang='lua'><br />
local see_cost = wesnoth.unit_vision_cost(u, "Gt")<br />
</syntaxhighlight><br />
<br />
==== wesnoth.unit_jamming_cost ====<br />
<br />
* '''wesnoth.unit_jamming_cost(''unit'', ''terrain_code'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':jamming(''terrain_code'')'''<br />
<br />
Returns the jamming cost of a unit on a particular terrain.<br />
<br />
<syntaxhighlight lang='lua'><br />
local jam_cost = wesnoth.unit_jamming_cost(u, "Gt")<br />
</syntaxhighlight><br />
<br />
==== wesnoth.unit_ability ====<br />
<br />
* '''wesnoth.unit_ability(''unit'', ''ability_tag'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':ability(''ability_tag'')'''<br />
<br />
Returns true if the unit is currently under effect by an ability with this given TAG NAME. This means that the ability could be owned by the unit itself, or by an adjacent unit.<br />
<br />
<syntaxhighlight lang='lua'><br />
function has_teleport(u)<br />
return wesnoth.unit_ability(u, "teleport")<br />
end<br />
</syntaxhighlight><br />
<br />
==== wesnoth.unit_types ====<br />
<br />
This is not a function but a read-only table indexed by unit type ids. Its elements are proxy tables with these fields:<br />
<br />
* '''id''': string<br />
* '''name''': translatable string (read only)<br />
* '''max_moves''', '''max_experience''', '''max_hitpoints''', '''level''', '''cost''': integers (read only)<br />
* '''abilities''': array of ability keys (strings), e.g. {"curing", "regenerates"}<br />
* {{DevFeature1.13|11}} '''advances_to''': array of unit types to which unit can advance<br />
* {{DevFeature1.13|11}} '''advances_from''': array of unit types from which unit can advance. Note: this is OOS-unsafe in Multiplayer games. Different clients may have additional Era-s with units upgradable to this unit type.<br />
* '''__cfg''': WML table (dump), see [[UnitTypeWML]]<br />
<br />
The metatable of these proxy tables appears as '''"unit type"'''.<br />
<br />
<syntaxhighlight lang='lua'><br />
local lich_cost = wesnoth.unit_types["Ancient Lich"].cost<br />
</syntaxhighlight><br />
<br />
Note that different clients have different set of available units in a Multiplayer game. It is OOS-unsafe to e.g. count the number of units.<br />
Presuming correctly written add-ons, it is still safe to e.g. access any given unit or its properties.<br />
<br />
==== wesnoth.races ====<br />
<br />
This is not a function but a table indexed by race ids. Its elements are proxy tables for all races the engine knows about.<br />
known fields of each element:<br />
* '''id''': string<br />
* '''description''', '''name''', '''plural_name''' (translatable strings)<br />
* '''num_traits''' (integer)<br />
* '''ignore_global_traits''' (boolean)<br />
* '''undead_variation''' (string)<br />
(all read only)<br />
* '''__cfg''': WML table (dump)<br />
<br />
<syntaxhighlight lang='lua'><br />
wesnoth.message(tostring(wesnoth.races["lizard"].name))<br />
</syntaxhighlight><br />
<br />
==== wesnoth.get_traits ====<br />
<br />
* '''wesnoth.get_traits()'''<br />
<br />
Returns a table with named fields (trait id strings) holding the wml tables defining the traits. arguments: none. All global traits the engine knows about, race-specific traits are not included.<br />
Known fields and subtags of each element are the ones which were given in the wml definition of the [[SingleUnitWML|trait]].<br />
wesnoth.message(tostring(wesnoth.get_traits().strong.male_name))<br />
<br />
==== wesnoth.simulate_combat ====<br />
<br />
* '''wesnoth.simulate_combat(''attacker'', [''attacker_weapon_index''], ''defender'', [''defender_weapon_index''])'''<br />
<br />
Computes the hitpoint distribution and status chance after a combat between two units. The first unit is the attacker; it does not have to be on the map, though its location should be meaningful. The second unit is the defender; it has to be on the map.<br />
<br />
Optional integers can be passed after each unit to select a particular weapon, otherwise the "best" one is selected. When giving the weapon, the parameter is the weapon number (integer, starting at 1) and not an element from the table returned by helper.child_range(att, "attack").<br />
<br />
<syntaxhighlight lang='lua'><br />
local function display_stats(n, t)<br />
wesnoth.message(string.format(<br />
"Chance for the %s\n to be slowed: %f,\n to be poisoned: %f,\n to die: %f.\nAverage HP: %f.",<br />
n, t.slowed, t.poisoned, t.hp_chance[0], t.average_hp))<br />
end<br />
local att_stats, def_stats = wesnoth.simulate_combat(att, att_weapon, def, def_weapon)<br />
display_stats("attacker", att_stats)<br />
display_stats("defender", def_stats)<br />
</syntaxhighlight><br />
<br />
Returns 2 additional tables which contain information about the weapons and the effect of single hits with these keys: num_blows, damage, chance_to_hit, poisons, slows, petrifies, plagues, plague_type, backstabs, rounds, firststrike, drains, drain_constant, drain_percent, attack_num, name. <br />
Name is the wml name not the description. If there is no weapon, then name will be nil<br />
<br />
<syntaxhighlight lang='lua'><br />
local att_stats, def_stats, att_weapon, def_weapon = wesnoth.simulate_combat(attacker, att_weapon_number, defender)<br />
wesnoth.message(string.format(<br />
"The attack %s should be countered with %s, which does %d damage, has %d%% chance to hit and forces %d attack rounds due to its berserk ability.",<br />
att_weapon.name, def_weapon.name or "no weapon", def_weapon.damage, def_weapon.chance_to_hit, def_weapon.rounds))<br />
</syntaxhighlight><br />
<br />
==== wesnoth.transform_unit ====<br />
<br />
* '''wesnoth.transform_unit(''unit'', ''to_type'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':transform(''to_type'')'''<br />
<br />
Changes the type of a unit and adjust attributes accordingly. Note that hit points are only changed if necessary to accommodate the new maximum hit points. Poison is automatically removed if the transformed unit is immune.<br />
<br />
<syntaxhighlight lang='lua'><br />
local ev = wesnoth.current.event_context<br />
local u = wesnoth.get_units{x=ev.x1, y=ev.y1}[1]<br />
wesnoth.transform_unit(u, "Spearman")<br />
-- If a full heal is desired:<br />
u.hitpoints = u.max_hitpoints<br />
u.status.poisoned = false<br />
</syntaxhighlight><br />
<br />
==== wesnoth.add_known_unit ====<br />
<br />
* {{DevFeature1.13|10}} '''wesnoth.add_known_unit(''unit_type_id'')'''<br />
<br />
adds the unit type with the given id to the list of known units (so that they appear in the help)<br />
<br />
==== wesnoth.create_animator ====<br />
<br />
{{DevFeature1.13|7}}<br />
<br />
* '''wesnoth.create_animator()'''<br />
<br />
Returns an object that can be used to set up and run an animation. The object has three methods:<br />
<br />
* '''animator:run()'''<br />
<br />
Runs the animation. {{DevFeature1.15|0}} Implicitly clears the animator.<br />
<br />
* '''animator:clear()'''<br />
<br />
Clears any units previously added to the animation.<br />
<br />
* '''animator:add(''unit'', ''flag'', ''hits'', ''params'')'''<br />
<br />
Adds a unit to the animation. The ''flag'' specifies which animation to play, and the ''hits'' parameter is required for attack animations to specify which variant of the animation to play. Possibly keys in ''params'' are:<br />
<br />
* '''facing''': A location. The animation will be played with the unit facing that location.<br />
* '''value''': Either a number or a list of two numbers. Use this to pass ''value'' and/or ''value_second'' to default animations that use them.<br />
* '''with_bars''': Whether to show HP bars and such while the animation plays.<br />
* '''text''': Text to float as the animation plays.<br />
* '''color''': Color of the floating text - a list of red, green, blue.<br />
* '''primary''': The primary weapon to use for the animation. Must be a Lua unit attack proxy.<br />
* '''secondary''': The secondary weapon to use for the animation.<br />
<br />
Normal usage would be to create it, call '''add''' one or more times, then call '''run'''.<br />
<br />
==== wesnoth.effects ====<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
This table contains the implementation of custom [[EffectWML|[effect]]]s. Each value is a function that takes a unit and the effect config. Note that the default effects defined by the Wesnoth engine are not in this table. <br />
<br />
<syntaxhighlight lang='lua'><br />
function wesnoth.effects.min_resistance(u, cfg)<br />
local resistance_new = {}<br />
local resistance_old = helper.parsed(helper.get_child(cfg, "resistance"))<br />
for k,v in pairs(resistance_old) do<br />
if type(k) == "string" and type(v) == "number" and wesnoth.unit_resistance(u, k) >= v then<br />
resistance_new[k] = v<br />
end<br />
end<br />
--important: use wesnoth.add_modification(..., false) so that the function will only execute the effects of that object and not store the object in the unit.<br />
wesnoth.add_modification(u, "object", {<br />
T.effect {<br />
apply_to = "resistance",<br />
replace = true,<br />
T.resistance (resistance_new),<br />
},<br />
}, false)<br />
end<br />
</syntaxhighlight><br />
<br />
The code above adds a new <code>min_resistance</code> effect that will set the resistances to specific values if they are currently below that value. It can then be used like this (for example, in [[DirectActionsWML#.5Bobject.5D|[object]]]):<br />
<br />
<syntaxhighlight lang='wml'><br />
[effect]<br />
apply_to=min_resistance<br />
[resistance]<br />
cold=50<br />
[/resistance]<br />
[/effect]<br />
</syntaxhighlight><br />
<br />
Note that in order work properly effects must be registered before any units are created. This means it must be places into toplevel or scenario/era/modification level [lua] tag and in particular must not be done from within a preload event.<br />
<br />
<br />
{{DevFeature1.13|5}}<br />
<br />
Built-in effects are now present in the <code>wesnoth.effects</code> table and can be called by custom effects or by other Lua code. They take the same two arguments that a custom effect function does - the unit, and the effect WML.<br />
<br />
In addition, you can now specify description modifiers to be used if a custom effect is placed in a <code>[trait]</code> tag. Instead of setting a function as the effect, you set a table with a <code>__call</code> metafunction which does what the function would have done. The table can then have an additional <code>__descr</code> metafunction which updates descriptions as necessary. The built-in effects all use this structure. This metafunction takes the same arguments as the regular effect function, but should not modify the unit. Instead, it returns a string to be appended to the trait's effect description.<br />
<br />
[[Category: Lua Reference]]</div>Edward Chernenkohttps://wiki.wesnoth.org/index.php?title=LuaWML&diff=60133LuaWML2019-01-02T00:34:09Z<p>Edward Chernenko: /* Miscellaneous */ replaced helper.set_wml_tag_metatable with wml.tag</p>
<hr />
<div>{{WML Tags}}<br />
<br />
== The '''[lua]''' tag ==<br />
<br />
This tag is a part of [[ActionWML]], thus can be used inside [event] and at other places where [[ActionWML]] can be used. It makes it possible to write actions with the [http://www.lua.org Lua 5.3] language.<br />
<br />
It is also possible to put this tag inside a [scenario] [[ScenarioWML]], those tags will be executed immediately when the lua engine loads which is even before the scenario preload event is fired.<br />
<br />
{{DevFeature1.13|0}}<br />
[lua] is now also allowed in [era] and [modification] those [lua] tags are then copied into the [scenario]/[multiplayer] when it is played just like [event]s inside [era] or [modification]<br />
<br />
The tag supports only the '''code''' key, which is a string containing the Lua scripts. Since Lua makes usage of the quotes and the { and } symbols, it is certainly wise to enclose the script between stronger quotes, as they prevent the preprocessor from performing macro expansion and tokenization.<br />
<br />
<syntaxhighlight lang='wml'><br />
[lua]<br />
code = << wesnoth.message "Hello World!" >><br />
[/lua]<br />
</syntaxhighlight><br />
<br />
The Lua kernel can also be accessed from the [[CommandMode|command mode]]:<br />
<br />
:lua local u = wesnoth.get_units({ id = "Konrad" })[1]; u.moves = 5<br />
<br />
The '''[args]''' sub-tag can be used to pass a WML object to the script via its variadic local variable "'''...'''".<br />
<br />
<syntaxhighlight lang='wml'><br />
[lua]<br />
code = << local t = ...; wesnoth.message(tostring(t.text)) >><br />
[args]<br />
text = _ "Hello world!"<br />
[/args]<br />
[/lua]<br />
</syntaxhighlight><br />
<br />
== Global environment ==<br />
<br />
All the Lua scripts of a scenario share the same global environment (aka Lua state). For instance, a function defined in an event can be used in all the events that happen after it.<br />
<br />
<syntaxhighlight lang='wml'><br />
[event]<br />
name = preload<br />
first_time_only = no<br />
[lua]<br />
code = <<<br />
function narrator(t)<br />
-- Behave like the [message] tag.<br />
wesnoth.fire("message",<br />
{ speaker = "narrator", message = t.sentence })<br />
end<br />
>><br />
[/lua]<br />
[/event]<br />
<br />
[event]<br />
name = turn 1<br />
[lua]<br />
code = << narrator(...) >><br />
[args]<br />
sentence = _ "Hello world!"<br />
[/args]<br />
[/lua]<br />
[lua]<br />
code = << narrator(...) >><br />
[args]<br />
sentence = _ "How are you today?"<br />
[/args]<br />
[/lua]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
In the example above, the redundant structure could be hidden behind macros. But it may be better to simply define a new WML tag.<br />
<br />
<syntaxhighlight lang='wml'><br />
[event]<br />
name = preload<br />
first_time_only = no<br />
[lua]<br />
code = <<<br />
-- The function is now placed in the wesnoth.wml_actions table<br />
-- The tag is [narrator], same as the function name<br />
function wesnoth.wml_actions.narrator(t)<br />
-- Behave like the [message] tag.<br />
wesnoth.fire("message",<br />
{ speaker = "narrator", message = t.sentence })<br />
end<br />
>><br />
[/lua]<br />
[/event]<br />
<br />
[event]<br />
name = turn 1<br />
[narrator]<br />
sentence = _ "Hello world!"<br />
[/narrator]<br />
[narrator]<br />
sentence = _ "How are you today?"<br />
[/narrator]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
The global environment is not preserved over save/load cycles. Therefore, storing values in the global environment is generally a bad idea. The only time assigning global variables (including function definitions) makes sense is in a [lua] block directly in [scenario] or during a [[EventWML#Predefined 'name' Key Values|preload]] event, as this event is always run. Therefore, helper functions defined at that time will be available to all the later scripts.<br />
<br />
The global environment initially contains the following modules: [http://www.lua.org/manual/5.1/manual.html#5.1 basic] (no name), [http://www.lua.org/manual/5.1/manual.html#5.4 string], [http://www.lua.org/manual/5.1/manual.html#5.5 table], and [http://www.lua.org/manual/5.1/manual.html#5.6 math]. A '''wesnoth''' module is also available, it provides access to the [[#Interface to the C++ engine|C++ engine]]. Additionally, the functions clock, date, time and difftime from the [http://www.lua.org/manual/5.1/manual.html#5.8 os] library (keep in mind that they aren't multiplayer- and replay-safe), as well as traceback from the [http://www.lua.org/manual/5.1/manual.html#5.9 debug] library are also available.<br />
<br />
At the start of a script, the variadic local variable '''...''' (three dots) is a proxy table representing [[#Encoding WML objects into Lua tables|WML data]]. This table is the content of the '''[args]''' sub-tag of the '''[lua]''' tag, if any.<br />
<br />
== Examples ==<br />
<br />
The following WML event is taken from Wesnoth' tutorial. It will serve as an example to present how Lua scripts are embedded into Wesnoth. The event is fired whenever a unit from side 1 (that is, the hero controlled by the user) moves to a tile that is not the one set in the WML variable ''target_hex''.<br />
<br />
<syntaxhighlight lang='wml'><br />
# General catch for them moving to the wrong place.<br />
[event]<br />
name=moveto<br />
first_time_only=no<br />
[allow_undo][/allow_undo]<br />
[filter]<br />
side=1<br />
[/filter]<br />
<br />
[if]<br />
[variable]<br />
name=target_hex.is_set<br />
equals=yes<br />
[/variable]<br />
[then]<br />
[if]<br />
[variable]<br />
name=x1<br />
equals=$target_hex.x<br />
[/variable]<br />
[variable]<br />
name=y1<br />
equals=$target_hex.y<br />
[/variable]<br />
[then]<br />
[/then]<br />
[else]<br />
[redraw][/redraw]<br />
[message]<br />
speaker=narrator<br />
message=_ "*Oops!<br />
You moved to the wrong place! After this message, you can press 'u' to undo, then try again." +<br />
_ "<br />
*Left click or press spacebar to continue..."<br />
[/message]<br />
[/else]<br />
[/if]<br />
[/then]<br />
[/if]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
A Lua script that performs the same action is presented below.<br />
<br />
<syntaxhighlight lang='wml'><br />
[event]<br />
name=moveto<br />
first_time_only=no<br />
[allow_undo][/allow_undo]<br />
[filter]<br />
side=1<br />
[/filter]<br />
<br />
[lua]<br />
code = <<<br />
local event_data = wesnoth.current.event_context<br />
if V.target_hex.is_set and<br />
(event_data.x1 ~= V.target_hex.x or event_data.y1 ~= V.target_hex.y)<br />
then<br />
W.redraw()<br />
narrator_says(_ "*Oops!\nYou moved to the wrong place! After this message, you can press 'u' to undo, then try again.")<br />
end<br />
>><br />
[/lua]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
Here is a more detailed explanation of the Lua code. Its first line<br />
<br />
<syntaxhighlight lang='lua'><br />
local event_data = wesnoth.current.event_context<br />
</syntaxhighlight><br />
<br />
puts the event data into the ''event_data'' local variable. Since it is a ''moveto'' event, the ''event_data'' table contains the destination of the unit in the ''x1'' and ''y1'' fields.<br />
<br />
The next two lines then test<br />
<br />
<syntaxhighlight lang='lua'><br />
if V.target_hex.is_set and<br />
(event_data.x1 ~= V.target_hex.x or event_data.y1 ~= V.target_hex.y)<br />
</syntaxhighlight><br />
<br />
whether the variable ''V.target_hex'' matches the event parameters. Since ''V'' is not a local variable, it is taken from the global environment. Usually, variables from the global environment are not persistent (they get lost on reloading), so it shouldn't be used to store data. In order to have an easy way to access the usual persistent Wml variables, the global variable ''V'' was mapped to the storage of WML variables by the following ''preload'' event.<br />
<br />
<syntaxhighlight lang='wml'><br />
[event]<br />
name=preload<br />
first_time_only=no<br />
[lua]<br />
code = <<<br />
H = wesnoth.require "lua/helper.lua"<br />
-- skipping some other initializations<br />
-- ...<br />
V = H.set_wml_var_metatable {}<br />
>><br />
[/lua]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
Without a prelude redirecting ''V'', the conditional would have been written<br />
<br />
<syntaxhighlight lang='lua'><br />
if wesnoth.get_variable("target_hex.is_set") and<br />
(event_data.x1 ~= wesnoth.get_variable("target_hex.x") or event_data.y1 ~= wesnoth.get_variable("target_hex.y")<br />
</syntaxhighlight><br />
<br />
The body of the conditional then performs the [[InterfaceActionsWML#Other interface tags|[redraw]]] action.<br />
<br />
<syntaxhighlight lang='lua'><br />
W.redraw()<br />
</syntaxhighlight><br />
<br />
Again, this short syntax is made possible by a line of the prelude that makes ''W'' a proxy for performing WML actions.<br />
<br />
<syntaxhighlight lang='lua'><br />
W = H.set_wml_action_metatable {}<br />
</syntaxhighlight><br />
<br />
Without this shortcut, the first statement would have been written<br />
<br />
<syntaxhighlight lang='lua'><br />
wesnoth.fire("redraw")<br />
</syntaxhighlight><br />
<br />
Finally the script displays a message by<br />
<br />
<syntaxhighlight lang='lua'><br />
narrator_says(_ "*Oops!\nYou moved to the wrong place! After this message, you can press 'u' to undo, then try again.")<br />
</syntaxhighlight><br />
<br />
The ''narrator_says'' function is defined in the prelude too, since the construct behind it occurs several times in the tutorial. In plain WML, macros would have been used instead. The definition of the function is<br />
<br />
<syntaxhighlight lang='lua'><br />
function narrator_says(m)<br />
W.message { speaker="narrator",<br />
message = m .. _ "\n*Left click or press spacebar to continue..." }<br />
end<br />
</syntaxhighlight><br />
<br />
The function fires a [[InterfaceActionsWML#.5Bmessage.5D|[message]]] action and passes a WML object containing the usual two fields to it. The second field is initialized by concatenating the function argument with another string. Both strings are prefixed by the ''_'' symbol to mark them as translatable. (Note that ''_'' is just a unary function, not a keyword.) Again, this is made possible by a specific line of the prelude:<br />
<br />
<syntaxhighlight lang='lua'><br />
_ = wesnoth.textdomain "wesnoth-tutorial"<br />
</syntaxhighlight><br />
<br />
A longer translation of the tutorial is available at [https://gna.org/patch/download.php?file_id=5483].<br />
<br />
== Interface to the engine and helper functions ==<br />
<br />
<br><div class="navtemplate" style="width: auto; max-width: 75%; margin: 0 auto; border: 1px solid #c60; border-left-width: 8px"><div style="float:left;position:relative;top:-14px;left:-6px">https://raw.github.com/wesnoth/wesnoth/master/data/core/images/items/bones.png</div><p style="margin:0"><strong>This section is in the process of being moved.</strong> The information here remains accurate as of 1.14.0, but for 1.15.0 and later, [[LuaAPI]] is planned to be the definitive source.</p></div><br><br />
<br />
Functionalities of the game engine are available through the functions contained in the '''wesnoth''' global table. Some of these functions return proxy tables. Writes to fields marked "read-only" are ignored. The '''__cfg''' fields return plain tables; in particular, writes do not modify the original object, and reads return the values from the time the dump was performed.<br />
<br />
Some helper functions are provided by the '''lua/helper.lua''' library. They are stored inside a table that is returned when loading the library with [[LuaWML:Files#wesnoth.require|wesnoth.require]].<br />
<br />
<syntaxhighlight lang='lua'><br />
helper = wesnoth.require "lua/helper.lua"<br />
</syntaxhighlight><br />
<br />
=== WML variables ===<br />
<br />
* [[LuaWML:Variables#wesnoth.get_variable|wesnoth.get_variable]]<br />
* [[LuaWML:Variables#wesnoth.set_variable|wesnoth.set_variable]]<br />
* [[LuaWML:Variables#wesnoth.get_all_vars|wesnoth.get_all_vars]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Variables#wesnoth.wml_matches_filter|wesnoth.wml_matches_filter]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Variables#helper.set_wml_var_metatable|helper.set_wml_var_metatable]]<br />
* [[LuaWML:Variables#helper.get_child|helper.get_child]]<br />
* [[LuaWML:Variables#helper.get_nth_child|helper.get_nth_child]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Variables#helper.child_count|helper.child_count]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Variables#helper.child_range|helper.child_range]]<br />
* [[LuaWML:Variables#helper.child_array|helper.child_array]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Variables#helper.get_variable_array|helper.get_variable_array]]<br />
* [[LuaWML:Variables#helper.get_variable_proxy_array|helper.get_variable_proxy_array]]<br />
* [[LuaWML:Variables#helper.set_variable_array|helper.set_variable_array]]<br />
<br />
=== Events and WML actions ===<br />
<br />
* [[LuaWML:Events#wesnoth.fire|wesnoth.fire]]<br />
* [[LuaWML:Events#wesnoth.wml_actions|wesnoth.wml_actions]]<br />
* [[LuaWML:Events#wesnoth.wml_actions|wesnoth.wml_conditionals]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Events#wesnoth.game_events|wesnoth.game_events]]<br />
* [[LuaWML:Events#wesnoth.persistent_tags|wesnoth.persistent_tags]] {{DevFeature1.13|12}}<br />
* [[LuaWML:Events#wesnoth.fire_event|wesnoth.fire_event]]<br />
* [[LuaWML:Events#wesnoth.fire_event_by_id|wesnoth.fire_event_by_id]] {{DevFeature1.13|6}}<br />
* [[LuaWML:Events#wesnoth.add_event_handler|wesnoth.add_event_handler]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Events#wesnoth.remove_event_handler|wesnoth.remove_event_handler]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Events#wesnoth.eval_conditional|wesnoth.eval_conditional]]<br />
* [[LuaWML:Events#wesnoth.tovconfig|wesnoth.tovconfig]]<br />
* [[LuaWML:Events#helper.set_wml_action_metatable|helper.set_wml_action_metatable]]<br />
* [[LuaWML:Events#helper.wml_error|helper.wml_error]]<br />
* [[LuaWML:Events#helper.literal|helper.literal]]<br />
* [[LuaWML:Events#helper.parsed|helper.parsed]]<br />
* [[LuaWML:Events#helper.shallow_literal|helper.shallow_literal]]<br />
* [[LuaWML:Events#helper.shallow_parsed|helper.shallow_parsed]]<br />
* [[LuaWML:Events#on_event.lua|on_event.on_event]] {{DevFeature1.13|6}}<br />
<br />
=== User interface ===<br />
* [[LuaWML:Display#wesnoth.get_viewing_side|wesnoth.get_viewing_side]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Display#wesnoth.message|wesnoth.message]]<br />
* [[LuaWML:Display#wesnoth.clear_messages|wesnoth.clear_messages]]<br />
* [[LuaWML:Display#wesnoth.textdomain|wesnoth.textdomain]]<br />
* [[LuaWML:Display#wesnoth.delay|wesnoth.delay]]<br />
* [[LuaWML:Display#wesnoth.float_label|wesnoth.float_label]]<br />
* [[LuaWML:Display#wesnoth.select_unit|wesnoth.select_hex]]<br />
* [[LuaWML:Display#wesnoth.select_unit|wesnoth.select_unit]]<br />
* [[LuaWML:Display#wesnoth.highlight_hex|wesnoth.highlight_hex]]<br />
* [[LuaWML:Display#wesnoth.deselect_hex|wesnoth.deselect_hex]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.scroll_to_tile|wesnoth.scroll_to_tile]]<br />
* [[LuaWML:Display#wesnoth.lock_view|wesnoth.lock_view]]<br />
* [[LuaWML:Display#wesnoth.view_locked|wesnoth.view_locked]]<br />
* [[LuaWML:Display#wesnoth.play_sound|wesnoth.play_sound]]<br />
* [[LuaWML:Display#wesnoth.set_music|wesnoth.set_music]]<br />
* [[LuaWML:Display#wesnoth.music_list|wesnoth.music_list]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.sound_volume|wesnoth.sound_volume]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_dialog|wesnoth.show_message_dialog]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.show_popup_dialog|wesnoth.show_popup_dialog]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.show_story|wesnoth.show_story]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_box|wesnoth.show_message_box]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_menu|wesnoth.show_menu]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_box|wesnoth.alert]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_box|wesnoth.confirm]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_dialog|wesnoth.show_dialog]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_value|wesnoth.set_dialog_value]]<br />
* [[LuaWML:Display#wesnoth.get_dialog_value|wesnoth.get_dialog_value]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_active|wesnoth.set_dialog_active]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_callback|wesnoth.set_dialog_callback]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_markup|wesnoth.set_dialog_markup]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_focus|wesnoth.set_dialog_focus]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.set_dialog_visible|wesnoth.set_dialog_visible]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.set_dialog_canvas|wesnoth.set_dialog_canvas]]<br />
* [[LuaWML:Display#wesnoth.add_dialog_tree_node|wesnoth.add_dialog_tree_node]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Display#wesnoth.remove_dialog_item|wesnoth.remove_dialog_item]] {{DevFeature1.13|1}}<br />
* [[LuaWML:Display#wesnoth.get_displayed_unit|wesnoth.get_displayed_unit]]<br />
* [[LuaWML:Display#wesnoth.theme_items|wesnoth.theme_items]]<br />
* [[LuaWML:Display#helper.get_user_choice|helper.get_user_choice]]<br />
* [[LuaWML:Display#wesnoth.is_skipping_messages|wesnoth.is_skipping_messages]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.skip_messages|wesnoth.skip_messages]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.log|wesnoth.log]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Display#wesnoth.zoom|wesnoth.zoom]] {{DevFeature1.13|8}}<br />
<br />
=== Map and terrains ===<br />
<br />
* [[LuaWML:Tiles#wesnoth.get_map_size|wesnoth.get_map_size]]<br />
* [[LuaWML:Tiles#wesnoth.get_terrain|wesnoth.get_terrain]]<br />
* [[LuaWML:Tiles#wesnoth.set_terrain|wesnoth.set_terrain]]<br />
* [[LuaWML:Tiles#wesnoth.get_terrain_info|wesnoth.get_terrain_info]]<br />
* [[LuaWML:Tiles#wesnoth.get_selected_tile|wesnoth.get_selected_tile]]<br />
* [[LuaWML:Tiles#wesnoth.get_locations|wesnoth.get_locations]]<br />
* [[LuaWML:Tiles#wesnoth.get_villages|wesnoth.get_villages]]<br />
* [[LuaWML:Tiles#wesnoth.match_location|wesnoth.match_location]]<br />
* [[LuaWML:Tiles#wesnoth.add_tile_overlay|wesnoth.add_tile_overlay]]<br />
* [[LuaWML:Tiles#wesnoth.remove_tile_overlay|wesnoth.remove_tile_overlay]]<br />
* [[LuaWML:Tiles#wesnoth.add_fog|wesnoth.add_fog]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.remove_fog|wesnoth.remove_fog]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.add_sound_source|wesnoth.add_sound_source]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.remove_sound_source|wesnoth.remove_sound_source]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.get_sound_source|wesnoth.get_sound_source]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.map.get_direction|wesnoth.map.get_direction]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.get_relative_dir|wesnoth.map.get_relative_dir]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.rotate_right_around_center|wesnoth.map.rotate_right_around_center]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.get_adjacent_tiles|wesnoth.map.get_adjacent_tiles]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.tiles_adjacent|wesnoth.map.tiles_adjacent]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.distance_between|wesnoth.map.distance_between]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.label|wesnoth.label]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Tiles#wesnoth.special_locations|wesnoth.special_locations]] {{DevFeature1.13|12}}<br />
* [[LuaWML:Tiles#items.place_image|items.place_image]]<br />
* [[LuaWML:Tiles#items.place_halo|items.place_halo]]<br />
* [[LuaWML:Tiles#items.remove|items.remove]]<br />
<br />
=== Time of day schedule ===<br />
<br />
* [[LuaWML:Time#wesnoth.get_time_of_day|wesnoth.get_time_of_day]]<br />
* [[LuaWML:Time#wesnoth.add_time_area|wesnoth.add_time_area]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Time#wesnoth.remove_time_area|wesnoth.remove_time_area]] {{DevFeature1.13|0}}<br />
<br />
=== Units ===<br />
<br />
* [[LuaWML:Units#wesnoth.get_units|wesnoth.get_units]]<br />
* [[LuaWML:Units#wesnoth.get_unit|wesnoth.get_unit]]<br />
* [[LuaWML:Units#wesnoth.match_unit|wesnoth.match_unit]]<br />
* [[LuaWML:Units#wesnoth.put_unit|wesnoth.put_unit]]<br />
* [[LuaWML:Units#wesnoth.erase_unit|wesnoth.erase_unit]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Units#wesnoth.get_recall_units|wesnoth.get_recall_units]]<br />
* [[LuaWML:Units#wesnoth.put_recall_unit|wesnoth.put_recall_unit]]<br />
* [[LuaWML:Units#wesnoth.create_unit|wesnoth.create_unit]]<br />
* [[LuaWML:Units#wesnoth.copy_unit|wesnoth.copy_unit]]<br />
* [[LuaWML:Units#wesnoth.extract_unit|wesnoth.extract_unit]]<br />
* [[LuaWML:Units#wesnoth.add_modification|wesnoth.add_modification]]<br />
* [[LuaWML:Units#wesnoth.remove_modifications|wesnoth.remove_modifications]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Units#wesnoth.unit_resistance|wesnoth.unit_resistance]]<br />
* [[LuaWML:Units#wesnoth.unit_defense|wesnoth.unit_defense]]<br />
* [[LuaWML:Units#wesnoth.unit_movement_cost|wesnoth.unit_movement_cost]]<br />
* [[LuaWML:Units#wesnoth.unit_vision_cost|wesnoth.unit_vision_cost]]<br />
* [[LuaWML:Units#wesnoth.unit_jamming_cost|wesnoth.unit_jamming_cost]]<br />
* [[LuaWML:Units#wesnoth.unit_ability|wesnoth.unit_ability]]<br />
* [[LuaWML:Units#wesnoth.unit_types|wesnoth.unit_types]]<br />
* [[LuaWML:Units#wesnoth.races|wesnoth.races]]<br />
* [[LuaWML:Units#wesnoth.get_traits|wesnoth.get_traits]]<br />
* [[LuaWML:Units#wesnoth.advance_unit|wesnoth.advance_unit]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Units#wesnoth.add_known_unit|wesnoth.add_known_unit]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Units#wesnoth.simulate_combat|wesnoth.simulate_combat]]<br />
* [[LuaWML:Units#wesnoth.transform_unit|wesnoth.transform_unit]]<br />
* [[LuaWML:Units#wesnoth.create_animator|wesnoth.create_animator]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Units#wesnoth.effects|wesnoth.effects]] {{DevFeature1.13|2}}<br />
<br />
=== Sides ===<br />
<br />
* [[LuaWML:Sides#wesnoth.sides|wesnoth.sides]]<br />
* [[LuaWML:Sides#wesnoth.get_sides|wesnoth.get_sides]]<br />
* [[LuaWML:Sides#wesnoth.get_village_owner|wesnoth.get_village_owner]]<br />
* [[LuaWML:Sides#wesnoth.set_village_owner|wesnoth.set_village_owner]]<br />
* [[LuaWML:Sides#wesnoth.is_enemy|wesnoth.is_enemy]]<br />
* [[LuaWML:Sides#wesnoth.match_side|wesnoth.match_side]]<br />
* [[LuaWML:Sides#wesnoth.get_starting_location|wesnoth.get_starting_location]]<br />
* [[LuaWML:Sides#wesnoth.set_side_id|wesnoth.set_side_id]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.place_shroud|wesnoth.place_shroud]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.remove_shroud|wesnoth.remove_shroud]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.is_fogged|wesnoth.is_fogged]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.is_shrouded|wesnoth.is_shrouded]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.switch_ai|wesnoth.switch_ai]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.append_ai|wesnoth.append_ai]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.add_ai_component|wesnoth.add_ai_component]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.change_ai_component|wesnoth.change_ai_component]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.delete_ai_component|wesnoth.delete_ai_component]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#helper.all_teams|helper.all_teams]]<br />
* [[LuaWML:Sides#helper.get_side_variable|helper.get_side_variable]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Sides#helper.set_side_variable|helper.set_side_variable]] {{DevFeature1.13|?}}<br />
<br />
=== Pathfinder ===<br />
<br />
* [[LuaWML:Pathfinder#wesnoth.find_path|wesnoth.find_path]]<br />
* [[LuaWML:Pathfinder#wesnoth.find_vacant_tile|wesnoth.find_vacant_tile]]<br />
* [[LuaWML:Pathfinder#wesnoth.find_reach|wesnoth.find_reach]]<br />
* [[LuaWML:Pathfinder#wesnoth.find_cost_map|wesnoth.find_cost_map]]<br />
* [[LuaWML:Pathfinder#helper.distance_between|helper.distance_between]]<br />
* [[LuaWML:Pathfinder#helper.adjacent_tiles|helper.adjacent_tiles]]<br />
<br />
=== Lua files ===<br />
<br />
* [[LuaWML:Files#wesnoth.dofile|wesnoth.dofile]]<br />
* [[LuaWML:Files#wesnoth.require|wesnoth.require]]<br />
* [[LuaWML:Files#wesnoth.have_file|wesnoth.have_file]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Files#wesnoth.read_file|wesnoth.read_file]] {{DevFeature1.13|5}}<br />
<br />
=== Location sets ===<br />
<br />
* [[LuaWML:Location_set#location_set.create|location_set.create]]<br />
* [[LuaWML:Location_set#location_set.of_pairs|location_set.of_pairs]]<br />
* [[LuaWML:Location_set#location_set.of_wml_var|location_set.of_wml_var]]<br />
* [[LuaWML:Location_set#location_set:empty|location_set:empty]]<br />
* [[LuaWML:Location_set#location_set:size|location_set:size]]<br />
* [[LuaWML:Location_set#location_set:clear|location_set:clear]]<br />
* [[LuaWML:Location_set#location_set:get|location_set:get]]<br />
* [[LuaWML:Location_set#location_set:insert|location_set:insert]]<br />
* [[LuaWML:Location_set#location_set:remove|location_set:remove]]<br />
* [[LuaWML:Location_set#location_set:of_pairs|location_set:of_pairs]]<br />
* [[LuaWML:Location_set#location_set:of_wml_var|location_set:of_wml_var]]<br />
* [[LuaWML:Location_set#location_set:to_pairs|location_set:to_pairs]]<br />
* [[LuaWML:Location_set#location_set:to_stable_pairs|location_set:to_stable_pairs]]<br />
* [[LuaWML:Location_set#location_set:to_wml_var|location_set:to_wml_var]]<br />
* [[LuaWML:Location_set#location_set:union|location_set:union]]<br />
* [[LuaWML:Location_set#location_set:inter|location_set:inter]]<br />
* [[LuaWML:Location_set#location_set:iter|location_set:iter]]<br />
* [[LuaWML:Location_set#location_set:stable_iter|location_set:stable_iter]]<br />
* [[LuaWML:Location_set#location_set:filter|location_set:filter]]<br />
* [[LuaWML:Location_set#location_set:union_merge|location_set:union_merge]]<br />
* [[LuaWML:Location_set#location_set:inter_merge|location_set:inter_merge]]<br />
<br />
=== Miscellaneous ===<br />
<br />
* [[LuaWML:Misc#wesnoth.game_config|wesnoth.game_config]]<br />
* [[LuaWML:Misc#wesnoth.get_era|wesnoth.get_era]]<br />
* [[LuaWML:Misc#wesnoth.current|wesnoth.current]]<br />
* [[LuaWML:Misc#wesnoth.synchronize_choice|wesnoth.synchronize_choice]]<br />
* [[LuaWML:Misc#wesnoth.synchronize_choices|wesnoth.synchronize_choices]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Misc#wesnoth.unsynced|wesnoth.unsynced]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Misc#wesnoth.get_image_size|wesnoth.get_image_size]]<br />
* [[LuaWML:Misc#wesnoth.compare_versions|wesnoth.compare_versions]]<br />
* [[LuaWML:Misc#wesnoth.have_file|wesnoth.have_file]]<br />
* [[LuaWML:Misc#wesnoth.debug|wesnoth.debug]]<br />
* [[LuaWML:Misc#wesnoth.get_time_stamp|wesnoth.get_time_stamp]]<br />
* [[LuaWML:Misc#wesnoth.random|wesnoth.random]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Misc#wesnoth.eval_formula|wesnoth.eval_formula]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.compile_formula|wesnoth.compile_formula]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.name_generator|wesnoth.name_generator]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.set_next_scenario|wesnoth.set_next_scenario]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.format|wesnoth.format]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Misc#wesnoth.format_conjunct_list|wesnoth.format_conjunct_list]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Misc#wesnoth.format_disjunct_list|wesnoth.format_disjunct_list]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Misc#wesnoth.wesnoth.end_turn|wesnoth.end_turn]] {{DevFeature1.13|ß}}<br />
* [[LuaWML:Misc#wml.tag|wml.tag]]<br />
* [[LuaWML:Misc#helper.modify_unit|helper.modify_unit]]<br />
* [[LuaWML:Misc#helper.move_unit_fake|helper.move_unit_fake]]<br />
* [[LuaWML:Misc#helper.rand|helper.rand]]<br />
* [[LuaWML:Misc#helper.round|helper.round]]<br />
* [[LuaWML:Misc#helper.shuffle|helper.shuffle]]<br />
<br />
=== Functions that should not be used ===<br />
<br />
If you take a look at Wesnoth's own lua files, you might find some undocumented functions use in the implementations of WML tags. Where possible, you should avoid using them, as they might be changed or removed with no compatibility for further releases. Instead, use the corresponding wml tags (in lua you can use <tt>wesnoth.wml_actions.tag_name(cfg)</tt>, though keep in mind that this won't substitute variables in the config).<br />
<br />
If uncertain whether an undocumented feature is safe to use, ask on the forums, Discord, or IRC. It may turn out that someone simply forgot to add it to the wiki.<br />
<br />
* wesnoth.redraw<br />
* wesnoth.set_menu_item<br />
* wesnoth.clear_menu_item<br />
* wesnoth.modify_ai<br />
* wesnoth.print<br />
* wesnoth.end_level<br />
<br />
== Encoding WML objects into Lua tables ==<br />
<br />
Function [[LuaWML:Events#wesnoth.fire|wesnoth.fire]] expects a table representing a WML object as its second argument (if needed). Function [[LuaWML:Variables#wesnoth.set_variable|wesnoth.set_variable]] allows to modify whole WML objects, again by passing it a table. Function [[LuaWML:Variables#wesnoth.get_variable|wesnoth.get_variable]] transforms a WML object into a table, if its second argument is not set to ''true''. All these tables have the same format.<br />
<br />
Scalar fields are transformed into WML attributes. For instance, the following Lua table<br />
<br />
<syntaxhighlight lang='lua'><br />
{<br />
a_bool = true,<br />
an_int = 42,<br />
a_float = 1.25,<br />
a_string = "scout",<br />
a_translation = _ "Hello World!"<br />
}<br />
</syntaxhighlight><br />
<br />
is equivalent to the content of the following WML object<br />
<br />
<syntaxhighlight lang='wml'><br />
[dummy]<br />
a_bool = "yes"<br />
an_int = "42"<br />
a_float = "1.25"<br />
a_string = "scout"<br />
a_translation = _ "Hello World!"<br />
[/dummy]<br />
</syntaxhighlight><br />
<br />
WML child objects are not stored as Lua named fields, since several of them can have the same tag. Moreover, their tags can conflict with the attribute keys. So child objects are stored as pairs string + table in the unnamed fields in definition order. This means that for every subtag appearing in the wml code there is an additional table "layer" in the corresponding WML table of the form <code>{[1] = "tag_name", [2] = {}}</code> which is equivalent to <code>{"tag_name", {}}</code>. [1] etc are the unnamed fields (as opposed to wml attributes). The table under [2] in this subtable then holds the wml attributes from inside the wml subtag. So every subtag other than the toplevel tag corresponds to two nested tables each. For instance, the following Lua table<br />
<br />
<syntaxhighlight lang='lua'><br />
{<br />
foo = 42,<br />
{ "bar", { v = 1, w = 2 } },<br />
{ "foo", { x = false } },<br />
{ "bar", { y = "foo" } },<br />
{ "foobar", { z = 5, { "barfoo", {} } } }<br />
}<br />
</syntaxhighlight><br />
<br />
is equivalent to the content of the following WML object<br />
<br />
<syntaxhighlight lang='wml'><br />
[dummy]<br />
foo = 42<br />
[bar]<br />
v = 1<br />
w = 2<br />
[/bar]<br />
[foo]<br />
x = no<br />
[/foo]<br />
[bar]<br />
y = foo<br />
[bar]<br />
[foobar]<br />
z = 5<br />
[barfoo]<br />
[/barfoo]<br />
[/foobar]<br />
[/dummy]<br />
</syntaxhighlight><br />
<br />
Both tables above are also equivalent to this WML table, where all unnamed fields are displayed:<br />
<br />
<syntaxhighlight lang='lua'><br />
{<br />
foo = 42,<br />
[1] = { [1] = "bar", [2] = { v = 1, w = 2 } },<br />
[2] = { [1] = "foo", [2] = { x = false } },<br />
[3] = { [1] = "bar", [2] = { y = "foo" } },<br />
[4] = { [1] = "foobar", [2] = { z = 5, [1] = { [1] = "barfoo", [2] = {} } } }<br />
}<br />
</syntaxhighlight><br />
<br />
So assuming ''cfg'' contains the above WML object, the following accesses are possible:<br />
<br />
<syntaxhighlight lang=lua><br />
a_int = cfg.foo -- "dummy.foo", 42<br />
a_string = cfg[3][2].y -- "dummy.bar[1].y", "foo"<br />
a_table = cfg[4][2] -- "dummy.foobar", { z = 5, { "barfoo", {} } }<br />
</syntaxhighlight><br />
<br />
For creating valid wml table in lua it is usully easier to use ''T = helper.set_wml_tag_metatable {}'' asuming you did that you can create the above wml document with<br />
<syntaxhighlight lang=lua><br />
{<br />
foo = 42,<br />
T.bar {<br />
v = 1,<br />
w = 1,<br />
},<br />
T.foo {<br />
x = false,<br />
},<br />
T.bar {<br />
y = "foo",<br />
},<br />
T.foobar {<br />
z = 5,<br />
T.barfoo {<br />
},<br />
},<br />
}<br />
</syntaxhighlight><br />
<br />
Consider using the [[LuaWML:Variables#helper.get_child|helper.get_child]] and [[LuaWML:Variables#helper.child_range|helper.child_range]] to ease the access to subtags.<br />
<br />
{{DevFeature1.13|5}} As a convenience, attributes with array values (tables with only integer keys) are concatenated into a string when converting a Lua table into WML. For example, the following Lua code:<br />
<br />
<syntaxhighlight lang=lua><br />
{<br />
x = {1, 2, 3, 4},<br />
y = {7, 8, 9, 10}<br />
}<br />
</syntaxhighlight><br />
<br />
produces the following WML table:<br />
<br />
<syntaxhighlight lang=wml><br />
[dummy]<br />
x=1,2,3,4<br />
y=7,8,9,10<br />
[/dummy]<br />
</syntaxhighlight><br />
<br />
Functions registered in [[LuaWML:Events#wesnoth.wml_actions|wesnoth.wml_actions]] receive their data in a userdata object which has the exact same structure as above. It is read-only however. Accessing fields or children performs variable substitution on the fly. Its '''__parsed''' and '''__literal''' fields provide translations to plain tables (therefore writable). '''__literal''' returns the original text of the data (including dollar symbols in attributes and [insert_tag] children), while '''__parsed''' performs a variable substitution.<br />
<br />
For instance, if you cannot stand any longer the fact that '''first_time_only''' is set to yes by default for the '''[event]''' tag, you can redefine it. But we have to be careful not to cause variable substitution, since the engine would perform a second variable substitution afterwards.<br />
<br />
<syntaxhighlight lang=lua><br />
local old_event_handler = wesnoth.wml_actions.event<br />
function wesnoth.wml_actions.event(cfg)<br />
-- Get the plain text from the user.<br />
local new_cfg = cfg.__literal<br />
-- The expression below is equivalent to cfg.__parsed.first_time_only,<br />
-- only faster. It is needed, since the first_time_only attribute may<br />
-- reference variables.<br />
local first = cfg.first_time_only<br />
-- Modify the default behavior of first_time_only.<br />
if first == nil then first = false end<br />
new_cfg.first_time_only = first<br />
-- Call the engine handler.<br />
old_event_handler(new_cfg)<br />
end<br />
</syntaxhighlight><br />
<br />
(Note: The above example will only affect nested events. Toplevel events will still default to ''first_time_only=yes''.)<br />
<!-- This should probably be replaced with a better example. --><br />
<br />
Note that, since the object is a userdata and not a table, '''pairs''' and '''ipairs''' are unfortunately not usable on it. So scripts have to work at a lower level. For instance, the following function returns the first sub-tag with a given name and it works both on WML tables and WML userdata:<br />
<br />
<syntaxhighlight lang=lua><br />
function get_child(cfg, name)<br />
for i = 1, #cfg do<br />
local v = cfg[i]<br />
if v[1] == name then return v[2] end<br />
end<br />
end<br />
</syntaxhighlight><br />
<br />
{{DevFeature1.13|2}} '''pairs''' and '''ipairs''' now work on vconfig objects (contrary to the above statement). However, '''pairs''' works a little differently than on plain configs (tables) - it returns only string keys (attributes in WML terms) and not integer keys (tags in WML terms).<br />
<br />
Another approach for handling userdata and tables in the same way, would be to convert the former into the latter beforehand:<br />
<br />
<syntaxhighlight lang=lua><br />
if getmetatable(cfg) == "wml object" then cfg = cfg.__parsed end<br />
</syntaxhighlight><br />
<br />
The WML userdata provides two other special fields: '''__shallow_parsed''' and '''__shallow_literal'''. They return a table corresponding to the WML userdata with variable substitution performed on the attributes (or not). [insert_tag] tags have also been parsed, so the number of children is faithful. But contrarily to '''__parsed''' and '''__literal''', the process is not recursive: all the children are still WML userdata and variable substitution can still happen for them. These shallow translators are meant as optimized versions of the deep ones, when only the toplevel attributes need to be writable.<br />
<br />
== Skeleton of a preload event ==<br />
<br />
The following event is a skeleton for a prelude enabling Lua in your WML events. It creates a table ''H'' containing the functions from helper.lua and a table ''W'' that serves as a proxy for firing WML actions. It sets up a table ''T'' so be used for easier creation of valid WML tables. It also sets up a table ''V'' so that any access to it is redirected to the persistent WML storage. Finally, it loads a textdomain to be accessed through the ''_'' variable.<br />
<br />
<syntaxhighlight lang='wml'><br />
[event]<br />
name=preload<br />
first_time_only=no<br />
[lua]<br />
code = <<<br />
H = wesnoth.require "lua/helper.lua"<br />
W = H.set_wml_action_metatable {}<br />
T = H.set_wml_tag_metatable {}<br />
V = H.set_wml_var_metatable {}<br />
_ = wesnoth.textdomain "my-campaign"<br />
<br />
-- Define your global constants here.<br />
-- ...<br />
<br />
<br />
-- Define your global functions here.<br />
-- ...<br />
>><br />
[/lua]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
It may be worth putting the whole Lua script above inside a separate file and having the ''preload'' event load it:<br />
<br />
<syntaxhighlight lang='wml'><br />
[event]<br />
name=preload<br />
first_time_only=no<br />
[lua]<br />
code = << wesnoth.dofile "~add-ons/Whatever/file.lua" >><br />
[/lua]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
== Remarks on Random Numbers ==<br />
<br />
The math.random function is not safe for replays and multiplayer games, since the random values will be different each time and on all the clients. Instead, the Lua code should use the [[LuaWML:Misc#helper.rand|helper.rand()]] function to synchronize random values. It takes the same argument in the same format as [[InternalActionsWML#.5Bset_variable.5D|[set_variable]]] rand=.<br />
<br />
<syntaxhighlight lang='lua'><br />
local random_variable = helper.rand("1,2,3")<br />
</syntaxhighlight><br />
<br />
Also available is [[LuaWML:Misc#wesnoth.random|wesnoth.random]], which has the same interface as math.random but is multiplayer-safe.<br />
<br />
== Random Lua table iteration ==<br />
<br />
Table iteration order ('''pairs''') is not strictly defined in Lua. If your code depends on the order of iteration, different clients may have different data in a multiplayer game. For example:<br />
<br />
<syntaxhighlight lang='lua'><br />
local table = { ["Mage"] = true, ["Wose"] = true }<br />
local concat = ""<br />
local bad_usage = next(table) -- wrong, leads to OOS<br />
for k, _ in pairs(table) do -- wrong, leads to OOS<br />
concat = concat .. k<br />
end<br />
</syntaxhighlight><br />
<br />
To avoid the problem, sort the table keys before iterating. Or alternatively, use Lua "arrays" and the '''ipairs''' function, which have a strictly defined order and never lead to OOS. Example of correct code:<br />
<br />
<syntaxhighlight lang='lua'><br />
local array = { "Mage", "Wose" }<br />
local good_usage = table[1] -- correct<br />
local concat = ""<br />
for _, v in ipairs(array) do -- correct<br />
concat = concat .. v<br />
end<br />
</syntaxhighlight><br />
<br />
[[Category: Lua Reference|*]]<br />
[[Category: WML Reference]]</div>Edward Chernenkohttps://wiki.wesnoth.org/index.php?title=LuaWML/Misc&diff=60132LuaWML/Misc2019-01-02T00:33:03Z<p>Edward Chernenko: /* helper.set_wml_tag_metatable */ this is deprecated. Replaced with wml.tag</p>
<hr />
<div>This page describes miscellaneous [[LuaWML]] objects and helpers.<br />
<br />
==== wesnoth.game_config ====<br />
<br />
Contrarily to the other values of the ''wesnoth'' table, ''game_config'' is simply a proxy table. Its fields offer an interface to the global settings of Wesnoth:<br />
<br />
* '''version''': string (read only)<br />
* '''base_income''': integer (read/write)<br />
* '''village_income''': integer (read/write)<br />
* '''poison_amount''': integer (read/write)<br />
* '''rest_heal_amount''': integer (read/write)<br />
* '''recall_cost''': integer (read/write)<br />
* '''combat_experience''': integer (read/write)<br />
* '''kill_experience''': integer (read/write)<br />
* '''last_turn''': integer (read/write) turn limit, maximum number of turns<br />
* '''debug''': boolean (read only)<br />
* '''mp_debug''': boolean (read only)<br />
* '''campaign_type''': string (read only) Indicates what type of game this is, e.g. "multiplayer"<br />
* '''theme''': {{DevFeature1.13|8}} string (read/write) The ID of the current scenario theme. If the scenario uses the default theme from preferences, this will be an empty string.<br />
* '''mp_settings''': table. In a multiplayer game, this is a proxy table which gives read only access to all MP-only configuration options which appear as attributes of [multiplayer] tag in a save game file:<br />
** '''active_mods''': string (read only) A list of all active modifications<br />
** '''hash''': string (read only) A hash of mp data<br />
** '''mp_campaign''': string (read only) Name of mp campaign<br />
** '''mp_scenario''': string (read only) ID of this mp scenario<br />
** '''mp_scenario_name''': string (read only) Name of this mp scenario<br />
** '''scenario''': string (read only) MP lobby title <br />
** '''difficulty_define''': string (read only) The campaign difficulty string for an mp campaign<br />
** '''mp_village_gold''': integer (read only) <br />
** '''mp_village_support''': integer (read only) <br />
** '''mp_num_turns''': integer (read only) <br />
** '''mp_era''': string (read only) The id of the chosen era<br />
** '''mp_eras''': string (read only) A list of all era ids<br />
** '''mp_fog''': boolean (read only) <br />
** '''mp_shroud''': boolean (read only) <br />
** '''mp_random_start_time''': boolean (read only) <br />
** '''experience_modifier''': integer (read only) <br />
** '''mp_use_map_settings''': boolean (read only) <br />
** '''mp_countdown''': boolean (read only) Whether the timer is enabled<br />
** '''mp_countdown_action_bonus''': integer (read only) <br />
** '''mp_countdown_init_time''': integer (read only) <br />
** '''mp_countdown_reservoir_time''': integer (read only) <br />
** '''mp_countdown_turn_bonus''': integer (read only) <br />
** '''observer''': boolean (read only) <br />
** '''shuffle_sides''': boolean (read only) <br />
** '''savegame''': boolean (read only) Whether this is a reloaded game<br />
** '''side_users''': string (read only) List of how sides are assigned to users (at game start)<br />
* '''era''': table. A proxy table for the entire era tag corresponding to the current era. Its id will always match wesnoth.game_config.mp_settings.mp_era<br />
Note: wesnoth.game_config.mp_settings, and wesnoth.game_config.era, will only exist if wesnoth.game_config.campaign_type == "multiplayer"<br />
<br />
<br />
-- Poison a bit weak? Let's boost it!<br />
wesnoth.game_config.poison_amount = 15<br />
<br />
-- Warn users when they use bad settings:<br />
if (wesnoth.game_config.mp_settings.shuffle_sides) then<br />
wesnoth.message("Warning: This scenario is not intended to be played with shuffle sides!")<br />
end<br />
<br />
-- Collect basic info about the current era:<br />
local era = wesnoth.game_config.era<br />
local helper = wesnoth.require("lua/helper.lua")<br />
local count = 0<br />
wesnoth.set_variable("era_name", era.name)<br />
for multiplayer_side in helper.child_range(era, "multiplayer_side") do<br />
count = count + 1<br />
wesnoth.set_variable("faction" .. tostring(count) .. "_name", multiplayer_side.name)<br />
wesnoth.set_variable("faction" .. tostring(count) .. "_recruit", multiplayer_side.recruit)<br />
end<br />
wesnoth.set_variable("num_factions", count)<br />
<br />
==== wesnoth.get_era ====<br />
<br />
* '''wesnoth.get_era(''id'')'''<br />
<br />
A function which takes one argument, an era id, and returns the entire era tag corresponding to that id. For a list of valid era ids, use wesnoth.game_config.mp_settings.mp_eras.<br />
<br />
==== wesnoth.current ====<br />
<br />
As with ''game_config'', ''current'' is a proxy table. Its fields are getter for game-related properties:<br />
<br />
* '''side''': integer (read only)<br />
* '''turn''': integer (read only)<br />
* '''event_context''': WML table with attributes ''name'', ''x1'', ''y1'', ''x2'', ''y2'', and children ''weapon'', ''second_weapon'', describing the trigger for the current event. {{DevFeature1.13|2}} ''unit_x'', ''unit_y'' contain the location of the primary unit involved in the event. Currently the only case where this cam be different from ''x1'' and ''y1'' are enter_hex and exit_hex events.<br />
* '''synced_state''' {{DevFeature1.13|0}} whether the current code runs in a synced contex, this returns a string, the possible values are:<br />
** '''synced''' the current code runs on all mp clients, this is the normal context, in which all gamestatechaning actions should take place.<br />
** '''unsynced''' for example during '''select''' events or during the calculation of a wesnoth.theme_items, don't change the gamestate in this context because the current code only runs on one machine, so changign the gamestate here will cause OOS. Typical things to do here are UI related things, or entering the synced state via '''[do_command]'''<br />
** '''local_choice''' the current code was invoked by wesnoth.synchronize_choice and runs only on one local client to calculate the return value for wesnoth.synchronize_choice. You cannot enter the synced context with '''[do_command]''' now.<br />
** '''preload''' we are currently running a preload event or an even earlier event, this behaves similar to '''local_choice'''<br />
<br />
wesnoth.message(string.format("Turn %d, side %d is playing.", wesnoth.current.turn, wesnoth.current.side))<br />
<br />
==== wesnoth.end_turn ====<br />
<br />
* '''wesnoth.end_turn ([''next_side''])'''<br />
<br />
like [endturn] actionwml, has a integer parmaeter that allows to specify the next side that should gain control, any integer in the range [1, 2*nsides] is allowed, where a number greater than nsides also changes the turn counter by one.<br />
<br />
==== wesnoth.synchronize_choice ====<br />
<br />
* '''wesnoth.synchronize_choice(''function'', [''ai_function''])'''<br />
* {{DevFeature1.13|2}} '''wesnoth.synchronize_choice([''description''], ''function'', [''ai_function''], [''for_side''])'''<br />
<br />
Recovers a WML table that was computed on one client only or was stored in a replay. The actual computation is performed by the function passed as the first function argument, assuming that the client is the side currently playing. For all the other clients, the function will not be called. An optional second function can be passed; if present, it will be used instead of the first one when the client happens to be an AI (hence not enable to interact with a user interface).<br />
<br />
local result = wesnoth.synchronize_choice(<br />
function()<br />
-- Called only on the client handling the current side, if it is a human.<br />
local choice = 0<br />
wesnoth.show_dialog(<br />
some_dialog_cfg, nil,<br />
function()<br />
choice = wesnoth.get_dialog_value "some_list"<br />
end)<br />
return { value = choice }<br />
end,<br />
function()<br />
-- Called only on the client handling the current side, if it is an AI.<br />
return { value = math.random(some_list_size) }<br />
end)<br />
wesnoth.message(string.format("Selected item: %d", result.value))<br />
<br />
Note: The return value must be a valid WML table - the same kind of thing you could store to a WML variable, and not, for instance, a proxy unit, anything else that uses metatables, or a lua table with another table as the value of a string attribute. Unlike other lua functions, wesnoth.synchronize_choice will NOT throw an error if the table is invalid, but will silently strip out the contents of any invalid subtag.<br />
<br />
When wesnoth is running in debug mode (e.g. --debug flag on command line) synchronize_choice will chat a "Lua Warning" if it finds that the table returned was partially invalid.<br />
<br />
{{DevFeature1.13|2}}<br />
This function takes now takes these arguments:<br />
* An optional translatable string describing the type of the user input. This is displayed to the other clients while one client executes the passed function. Defaults to "input".<br />
* A function: (as before).<br />
* An optional function: for ai sides (as before).<br />
* An optional integer: on which side the function should be evaluated. Defaults to the currently playing side. If the specified side is empty/null controlled the engine will choose another side.<br />
<br />
==== wesnoth.synchronize_choices ====<br />
<br />
* '''wesnoth.synchronize_choices([''description''], ''function'', [''default_function''], [''for_sides''])'''<br />
<br />
{{DevFeature1.13|2}} Similar to the singular form above, this function takes a function parameter and evaluates it on the specified sides. It takes the following arguments:<br />
* An optional translatable string descibing the type of the user input. This is displayed to the other clients while the specified clients execute the passeed function. Defaults to "input"<br />
* A function that evaluates the choice returning a wml table. Unlike above, this function is called for ai and human sides (use if controller == "ai" for checking if it is a ai side)<br />
* An optional function for evaluating the choice in case this side was null controlled. If this function is called, it is called on all clients (unlike the first passed function) defaults to a function returning an empty table.<br />
* An array of integers specifying on which sides this function should be evaluated, the function is evaluated on all passed sides, each side may only appear once in this array. All specified sides execute the function simultaniously.<br />
<br />
This function returns a table with integer as keys and WML tables as values. the keys are the sides where that action was evaluated. The values are the values computed by the passed function.<br />
Example:<br />
[event]<br />
name = "start"<br />
[lua]<br />
code = <<<br />
wesnoth.set_variable("input1",nil)<br />
local result = wesnoth.synchronize_choices(<br />
function()<br />
local option1 = T.option { message = "No", T.command { T.set_variable { name = "input1", value = "No"}}}<br />
local option2 = T.option { message = "Yes", T.command { T.set_variable { name = "input1", value = "Yes"}}}<br />
wesnoth.fire(T.message{ message = "Are you sure you want to play this game?", option1, option2})<br />
return { value = wesnoth.get_variable("input1") }<br />
end,<br />
{1,2})<br />
wesnoth.set_variable("input1",nil)<br />
wesnoth.message("Player 1 wants to play: " .. result[1].value)<br />
wesnoth.message("Player 2 wants to play: " .. result[2].value)<br />
>><br />
[/lua]<br />
[/event]<br />
<br />
==== wesnoth.get_image_size ====<br />
<br />
* '''wesnoth.get_image_size(''filename'')'''<br />
<br />
Returns the width and height of an image.<br />
<br />
local w, h = wesnoth.get_image_size "units/transport/galleon.png"<br />
<br />
==== wesnoth.compare_versions ====<br />
<br />
* '''wesnoth.compare_versions(''version1'', ''operator'', ''version2'')'''<br />
<br />
Takes two versions strings and an operator, returns whether the comparison yields true.<br />
Follows the same rules like the #ifver preprocessor statement.<br />
<br />
local function version_is_sufficient(required)<br />
if not wesnoth.compare_versions then return false end<br />
return wesnoth.compare_versions(wesnoth.game_config.version, ">=", required)<br />
end<br />
local required = "1.9.6"<br />
if not version_is_sufficient(required) then wesnoth.message(string.format(<br />
"Your BfW version is insufficient, please get BfW %s or greater!", required)) end<br />
<br />
==== wesnoth.have_file ====<br />
<br />
* '''wesnoth.have_file(''filename'')'''<br />
<br />
Checks if the file (not necessarily a Lua file) or the directory passed as argument exists. Returns true if the file exists, false otherwise. Follows the same rules like the #ifhave preprocessor statement.<br />
<br />
-- Does the user have installed the UMC Music Book 1?<br />
local umc_music = wesnoth.have_file( "~add-ons/UMC_Music_Book_1/_main.cfg" )<br />
-- and if we want to check for the folder?<br />
local music_folder = wesnoth.have_file( "~add-ons/UMC_Music_Book_1/" )<br />
<br />
==== wesnoth.debug ====<br />
<br />
* '''wesnoth.debug(''wml_table'')'''<br />
<br />
Takes a userdata with metatable wml object or a wml table and dumps its content into a pretty string.<br />
wesnoth.set_variable("number", 100)<br />
local vconfig = wesnoth.tovconfig({ key = "$number", another_key = true,<br />
{"a_subtag", { a_key_in_the_subtag = "foo" }}<br />
})<br />
wesnoth.message(wesnoth.debug(vconfig))<br />
wesnoth.message(wesnoth.debug(vconfig.__literal))<br />
<br />
==== wesnoth.get_time_stamp ====<br />
<br />
* '''wesnoth.get_time_stamp()'''<br />
<br />
This function retrieves the current time stamp, that is the amount of milliseconds passed from when the SDL library was initialized. It takes no arguments and returns an integer.<br />
'''WARNING:''' this function uses the same code as [set_variable] time=stamp, and so it is MP-unsafe. It is provided only for benchmark purposes and AI development, although it should work inside wesnoth.synchronize_choice() as well.<br />
local stamp = wesnoth.get_time_stamp()<br />
<br />
==== wesnoth.random ====<br />
<br />
* '''wesnoth.random([''m'', [''n'']])'''<br />
<br />
{{DevFeature1.13|2}} This function returns a random number generated by the synced random generator which is also used by [set_variable]rand= (and thus also by helper.rand). This function has the same interface as [http://www.lua.org/manual/5.2/manual.html#pdf-math.random math.random] so it can take 0, 1 or 2 arguments.<br />
<br />
In map generation scripts, the values returned by this function depend on the seed the map author has input (if any).<br />
<br />
Be careful as '''random''' is not safe in certain events, see [[EventWML#Multiplayer_safety|Multiplayer_safety]].<br />
<br />
==== wesnoth.unsynced ====<br />
<br />
* '''wesnoth.unsynced(''func'')'''<br />
<br />
calls the given function in a unsynced context, that is in particular, while executing that function random results will not be synced in mp.<br />
<br />
==== wesnoth.compile_formula ====<br />
<br />
* '''wesnoth.compile_formula(''formula'')'''<br />
<br />
{{DevFeature1.13|5}} Compiles a [[Wesnoth Formula Language]] formula into a Lua callable userdata. The callable value returned by this function can take an optional table as argument, which defines variables available to the formula. It can also take a unit proxy as argument, which evaluates the formula in that unit's context just as if it had been used in a [[StandardUnitFilter]].<br />
<br />
A compiled formula can be converted back to valid code using the built-in <code>tostring</code> function.<br />
<br />
==== wesnoth.eval_formula ====<br />
<br />
* '''wesnoth.eval_formula(''formula'', [''variables''])'''<br />
<br />
{{DevFeature1.13|5}} Equivalent to <syntaxhighlight lang='lua' inline>wesnoth.compile_formula(formula)(variables)</syntaxhighlight>. It can also evaluate an already-compiled formula, which is equivalent to calling the formula.<br />
<br />
==== wesnoth.name_generator ====<br />
<br />
* '''wesnoth.name_generator(''type'', ''definition'', [''additional params''])'''<br />
<br />
{{DevFeature1.13|5}} Constructs a name generator for use in generating names using either the Markov chain algorithm used in older versions of Wesnoth or the context-free grammar generator used since 1.13.5. The type parameter indicates which algorithm to use (either markov or cfg). The definition can be a string, just like it would be in a config file, or it can be formatted as a table. Additional parameters may be passed, depending on the type of generator. The function returns a callable userdata, which will return a new name each time it is called (with no parameters).<br />
<br />
* '''Markov chain''': A Markov chain generator works by analyzing a list of input names and noticing tendencies in the way the letters are strung together. It can then apply those tendencies to produce new similar names that were not in the original list. Longer lists give better results. The definition is a list of names, formatted either as a comma-separated string or as an array-like table. The Markov generator can take two additional parameters. The first additional parameter is ''chain_size'', and the second is ''max_length''.<br />
** A value greater than 1 for the chain_size causes the analyzer to consider the words in chunks, which is similar to analyzing them syllable by syllable instead of letter by letter. The default chain size is 2, meaning that the analyzer treats words as consisting of 2-character syllables.<br />
** The max_length places a cap on the total length of the name. The default value is 12 characters.<br />
* '''Context-free grammar''': A [[context-free grammar]] is a way of specifying how strings can be constructed. The definition may be specified as a multi-line string, just as described in the preceding link, or it can be formatted as a table where the keys are non-terminals and the values are what they expand to. The expansion of each non-terminal can be formatted either as a |-separated list as described in the preceding link, or as an array-like table. (Mixing the two forms is permissible too.) The context-free generator has no additional parameters.<br />
<br />
==== wesnoth.format ====<br />
<br />
* '''wesnoth.format(''format_string'', ''values'')'''<br />
<br />
Similar to '''string.format''' but using Wesnoth's variable substitution syntax, and also supporting translatable strings. Any valid config can be passed as the values, though typically you will only need key-value pairs. You could also substitute WML variables into a string by passing '''wesnoth.get_all_vars()''' as the second parameter.<br />
<br />
This function preserves the translatability of the input format string.<br />
<br />
==== wesnoth.format_conjunct_list ====<br />
<br />
* '''wesnoth.format_conjunct_list(''list_of_strings'')'''<br />
<br />
Formats a list of usually-translatable strings into a localized list string of the form "A, B, and C".<br />
<br />
==== wesnoth.format_disjunct_list ====<br />
<br />
* '''wesnoth.format_disjunct_list(''list_of_strings'')'''<br />
<br />
Formats a list of usually-translatable strings into a localized list string of the form "A, B, or C".<br />
<br />
==== wml.tag ====<br />
<br />
* '''wml.tag.something'''<br />
<br />
Can be used to create subtags with less brackets, for example:<br />
W.event { name = "new turn", wml.tag.message { speaker = "narrator", message = "?" } }<br />
<br />
==== helper.modify_unit ====<br />
<br />
* '''helper.modify_unit(''filter'', ''keys'')'''<br />
<br />
Modifies all the units satisfying the given filter (argument 1) with some WML attributes/objects (argument 2). This is a Lua implementation of the [http://www.wesnoth.org/macro-reference.xhtml MODIFY_UNIT] macro.<br />
<br />
helper.modify_unit({ id="Delfador" }, { moves=0 })<br />
<br />
'''Note:''' This appears to be less powerful than the [modify_unit] tag and may be removed at some point in the future.<br />
<br />
==== helper.move_unit_fake ====<br />
<br />
* '''helper.move_unit_fake(''unit'', ''destination'')'''<br />
<br />
Fakes the move of a unit satisfying the given filter (argument 1) to the given position (argument 2). This is a Lua implementation of the [http://www.wesnoth.org/macro-reference.xhtml MOVE_UNIT] macro.<br />
<br />
helper.move_unit_fake({ id="Delfador" }, 14, 8)<br />
<br />
==== helper.rand ====<br />
<br />
* '''helper.rand(''spec'')'''<br />
<br />
(A shortcut to [[InternalActionsWML#.5Bset_variable.5D|set_variable's rand=]] since math.rand is an OOS magnet and therefore disabled.) Pass a string like you would to set_variable's rand=.<br />
<br />
create a random unit at (1, 1) on side=1 :<br />
wesnoth.put_unit(1, 1, { type = helper.rand("Dwarvish Fighter,Dwarvish Thunderer,Dwarvish Scout") })<br />
<br />
Note that '''random''' is only safe in certain events, see [[EventWML#Multiplayer_safety|Multiplayer Safety]].<br />
<br />
==== helper.round ====<br />
<br />
* '''helper.round(''n'')'''<br />
<br />
Unlike other languages (Python, Perl, Javascript, ...), Lua does not include a round function. This helper function allows rounding numbers, following the "round half away from zero method", see Wikipedia [[http://en.wikipedia.org/wiki/Rounding_numbers#Round_half_away_from_zero]]. Returns the number rounded to the nearest integer.<br />
<br />
-- this number will be rounded up<br />
helper.round(345.67) -- returns 346<br />
-- this one will be rounded down<br />
helper.round(543.21) -- returns 543<br />
-- an integer stays integer<br />
helper.round(123) -- returns 123<br />
-- works also for negative numbers<br />
helper.round(-369.84) -- returns -370<br />
helper.round(-246.42) -- returns -246<br />
<br />
==== helper.shuffle ====<br />
<br />
* '''helper.shuffle(''array'')'''<br />
* {{DevFeature1.13|2}} '''helper.shuffle(''array'', ''[random_function]'')'''<br />
This function randomly sorts in place the elements of the table passed as argument, following the Fisher-Yates algorithm. It returns no value.<br />
'''WARNING:''' this function uses Lua's math.random(), and so it is '''not''' MP-safe. It is provided mainly for AI development, although it should work inside wesnoth.synchronize_choice() as well.<br />
<br />
local locs = wesnoth.get_locations( { terrain="G*" } )<br />
helper.shuffle( locs )<br />
<br />
{{DevFeature1.13|2}}<br />
This function now uses the synced RNG by default and should not cause OOS anymore. It is also possible now to pass a different random generator as a second argument; a random generator is a function that takes two integers <i>a</i> and <i>b</i> and returns a random integer in the range [<i>a</i>,<i>b</i>]. For example, math.random can be passed to get the 1.12 behavior:<br />
<br />
local locs = wesnoth.get_locations( { terrain="G*" } )<br />
helper.shuffle( locs, math.random )<br />
<br />
[[Category: Lua Reference]]</div>Edward Chernenkohttps://wiki.wesnoth.org/index.php?title=LuaWML/Display&diff=60128LuaWML/Display2018-12-31T01:47:40Z<p>Edward Chernenko: there is no true/false flag here, just the path: set_dialog_focus() always enables the focus</p>
<hr />
<div>This page describes the [[LuaWML]] functions and helpers for interfacing with the user.<br />
<br />
==== wesnoth.message ====<br />
<br />
* '''wesnoth.message([''speaker'',] ''message'')'''<br />
<br />
Displays a string in the chat window and dumps it to the lua/info log domain (''--log-info=scripting/lua'' on the command-line).<br />
<br />
wesnoth.message "Hello World!"<br />
<br />
The chat line header is "<Lua>" by default, but it can be changed by passing a string before the message.<br />
<br />
wesnoth.message("Big Brother", "I'm watching you.") -- will result in "&lt;Big Brother&gt; I'm watching you."<br />
<br />
See also [[LuaWML:Events#helper.wml_error|helper.wml_error]] for displaying error messages.<br />
<br />
==== wesnoth.clear_messages ====<br />
<br />
* '''wesnoth.clear_messages()'''<br />
<br />
Removes all messages from the chat window. No argument or returned values.<br />
<br />
==== wesnoth.textdomain ====<br />
<br />
* '''wesnoth.textdomain(''domain'')'''<br />
<br />
Creates a function proxy for lazily translating strings from the given domain.<br />
<br />
-- #textdomain "my-campaign"<br />
-- the comment above ensures the subsequent strings will be extracted to the proper domain<br />
_ = wesnoth.textdomain "my-campaign"<br />
wesnoth.set_variable("my_unit.description", _ "the unit formerly known as Hero")<br />
<br />
The metatable of the function proxy appears as '''"message domain"'''. The metatable of the translatable strings (results of the proxy) appears as '''"translatable string"'''.<br />
<br />
The translatable strings can be appended to other strings/numbers with the standard '''..''' operator. Translation can be forced with the standard '''tostring''' operator in order to get a plain string.<br />
<br />
wesnoth.message(string.format(tostring(_ "You gain %d gold."), amount))<br />
<br />
==== wesnoth.delay ====<br />
<br />
* '''wesnoth.delay(''milliseconds'')'''<br />
<br />
Delays the engine like the [delay] tag. one argument: time to delay in milliseconds<br />
<br />
wesnoth.delay(500)<br />
<br />
==== wesnoth.float_label ====<br />
<br />
* '''wesnoth.float_label(''x'', ''y'', ''text'')'''<br />
<br />
Pops some text above a map tile.<br />
<br />
wesnoth.float_label(unit.x, unit.y, "&lt;span color='#ff0000'&gt;Ouch&lt;/span&gt;")<br />
<br />
==== wesnoth.get_viewing_side ====<br />
<br />
* '''wesnoth.get_viewing_side()'''<br />
<br />
returns two values 1) the number of the side of the current viewpoint, 2) a boolean specifying whether it has full vision (can only only true happen in replays or for observers)<br />
<br />
==== wesnoth.select_unit ====<br />
<br />
* '''wesnoth.select_hex(''x'', ''y'', [''show_movement'', [''fire_events'']])'''<br />
* {{DevFeature1.13|5}} '''wesnoth.select_unit(''unit'', [''show_movement'', [''fire_events'']])'''<br />
* {{DevFeature1.13|5}} '''''unit'':select([''show_movement'', [''fire_events'']])'''<br />
<br />
Selects the given unit in the game map as if the player had clicked on it.<br />
Argument 3: boolean, whether to show the movement range of any unit on that location (def: true)<br />
Argument 4: boolean, whether to fire any select events (def: false). Note: currently (1.14.1), this argument has no effect (events are never fired).<br />
<br />
wesnoth.select_unit(14,6, true, true)<br />
<br />
The '''wesnoth.select_hex''' form is deprecated. If there is a unit on the location, it does the same thing as '''wesnoth.select_unit''', but if ''show_movement'' is true it also calls '''wesnoth.highlight_hex''' for the location. If there is no unit on the location, '''wesnoth.select_hex''' does not do anything useful.<br />
<br />
If called without arguments, '''wesnoth.select_unit''' deselects the current unit from the map as long as the mouse cursor is not on its hex. It will continue to be displayed on the UI sidebar in any case.<br />
<br />
==== wesnoth.highlight_hex ====<br />
<br />
* '''wesnoth.highlight_hex(''x'', ''y'')'''<br />
<br />
Draws an outline around the specified hex.<br />
<br />
==== wesnoth.deselect_hex ====<br />
<br />
* '''wesnoth.deselect_hex()'''<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Reverses any select_hex call, leaving all locations unhighlighted. Takes no arguments.<br />
<br />
==== wesnoth.scroll_to_tile ====<br />
<br />
* '''wesnoth.scroll_to_tile(''x'', ''y'', [''only_if_visible'', [''instant'']])'''<br />
* {{DevFeature1.13|7}} '''wesnoth.scroll_to_tile(''x'', ''y'', [''only_if_visible'', [''instant'', [''only_if_needed'']]])'''<br />
<br />
Scrolls the map to the given location. If true is passed as the third parameter, scrolling is disabled if the tile is hidden under the fog. If true is passed as the fourth parameter, the view instantly warps to the location regardless of the scroll speed setting in Preferences. If true is passed as the fifth parameter, no scrolling occurs if the target location is already visible onscreen.<br />
<br />
local u = wesnoth.get_units({ id = "hero" })[1]<br />
wesnoth.scroll_to_tile(u.x, u.y)<br />
<br />
==== wesnoth.lock_view ====<br />
<br />
* '''wesnoth.lock_view(''lock'')'''<br />
<br />
Locks or unlocks gamemap view scrolling for human players. If true is passed as the first parameter, the view is locked; pass false to unlock.<br />
<br />
Human players cannot scroll the gamemap view as long as it is locked, but Lua or WML actions such as wesnoth.scroll_to_tile still can; the locked/unlocked state is preserved when saving the current game. This feature is generally intended to be used in cutscenes to prevent the player scrolling away from scripted actions.<br />
<br />
wesnoth.lock_view(true)<br />
wesnoth.scroll_to_tile(12, 14, false, true)<br />
<br />
==== wesnoth.view_locked ====<br />
<br />
* '''wesnoth.view_locked()'''<br />
<br />
Returns a boolean indicating whether gamemap view scrolling is currently locked.<br />
<br />
==== wesnoth.play_sound ====<br />
<br />
* '''wesnoth.play_sound(''sound'', [''repeat_count''])'''<br />
<br />
Plays the given sound file once, optionally repeating it one or more more times if an integer value is provided as a second argument (note that the sound is ''repeated'' the number of times specified in the second argument, i.e. a second argument of 4 will cause the sound to be played once and then repeated four more times for a total of 5 plays. See the example below).<br />
<br />
wesnoth.play_sound "ambient/birds1.ogg"<br />
wesnoth.play_sound("magic-holy-miss-3.ogg", 4) -- played 1 + 4 = 5 times<br />
<br />
==== wesnoth.set_music ====<br />
<br />
* '''wesnoth.set_music(''music_entry'')'''<br />
<br />
Sets the given table as an entry into the music list. See [[MusicListWML]] for the recognized attributes.<br />
<br />
wesnoth.set_music { name = "traveling_minstrels.ogg" }<br />
<br />
Passing no argument forces the engine to take into account all the recent changes to the music list. (Note: this is done automatically when sequences of WML commands end, so it is useful only for long events.)<br />
<br />
{{DevFeature1.13|8}} This function is now deprecated. Use the '''wesnoth.music_list''' table instead<br />
<br />
==== wesnoth.music_list ====<br />
<br />
{{DevFeature1.13|8}}<br />
<br />
This is a table giving access to the current music playlist. It can be accessed as a normal array, including the Lua length operator. If you assign a music config to an entry, the track is replaced. It is not a normal array however and cannot be manipulated with the table library.<br />
<br />
In addition, it has the following named fields:<br />
<br />
* '''wesnoth.music_list.current''' (read-write): The currently-playing track. This may sometimes be a track that's not on the playlist - "play once" tracks are not placed on the playlist.<br />
* '''wesnoth.music_list.current.__cfg''' (read-only): Returns a copy of the current track information.<br />
* '''wesnoth.music_list.previous''' (read-write): The track played before the current one. This may sometimes be a track that's not on the playlist - "play once" tracks are not placed on the playlist.<br />
* '''wesnoth.music_list.previous.__cfg''' (read-only): Returns a copy of the previous track information. NOTE: Wesnoth's playlist implementation effectively "plays" every song as it's added to the playlist, so when replacing one playlist with another, this will return information on the second-to-last track added to the new playlist, not the track you actually heard playing from the playlist that was replaced.<br />
* '''wesnoth.music_list.current_i''' (read-write): The index of the currently-playing track on the playlist, or nil if the currently-playing track is not on the playlist.<br />
* '''wesnoth.music_list.volume''' (read-write): The current music volume, as a percentage of the user's preferred volume set in preferences.<br />
* '''wesnoth.music_list.all''' (read-only): Returns a copy of the music list as an array of WML tables.<br />
<br />
It also contains some functions:<br />
<br />
* '''wesnoth.music_list.add(''track_name'', [''immediate'',] [''ms_before'', [''ms_after'']])''': Appends a track to the playlist. If true is passed, also start playing the new track.<br />
* '''wesnoth.music_list.remove(''n1'', ...)''': Removes one or more tracks by their index. You can pass as many indices as you wish. If one of the removed tracks is currently playing, it continues to play.<br />
* '''wesnoth.music_list.clear()''': Clears the playlist. The currently-playing track continues to play.<br />
* '''wesnoth.music_list.next()''': Stop playing the current track and move on to the next one. This honours the shuffle settings.<br />
* '''wesnoth.music_list.play(''track_name'')''': Start playing a track without appending it to the playlist.<br />
<br />
Each track contains the following fields:<br />
<br />
* '''shuffle''' (read-write)<br />
* '''once''' (read-write): generally only true for '''wesnoth.music_list.current'''<br />
* '''ms_before''' (read-write)<br />
* '''ms_after''' (read-write)<br />
* '''immediate''' (read-only)<br />
* '''name''' (read-only): the unresolved track filename<br />
* '''title''' (read-only): a user-friendly track title<br />
<br />
==== wesnoth.sound_volume ====<br />
<br />
{{DevFeature1.13|8}}<br />
<br />
* '''wesnoth.sound_volume(''new_volume'')'''<br />
<br />
Sets the current sound volume, as a percentage of the user's preferred volume set in preferences.<br />
Returns the previous sound volume in the same format.<br />
<br />
==== wesnoth.show_menu ====<br />
<br />
* '''wesnoth.show_menu(''items'' [, ''initial''] [, ''markup''])'''<br />
<br />
Shows a popup menu onscreen at the current mouse location. This could be used for example to produce a sort of submenu in a <tt>[set_menu_item]</tt>. The items are specified as a Lua array of tables, each of which supports the following keys:<br />
<br />
* ''icon'': An icon to display in the leftmost column of the menu.<br />
* ''image'': An image to display in the main column of the menu. If this is present, ''label'' is ignored.<br />
* ''label'': A label to display in the main column of the menu.<br />
* ''details'': A secondary label to display in the right column of the menu.<br />
* ''tooltip'': Text to display when mousing over this option.<br />
<br />
The ''initial'' argument must be a valid index into the ''items'' array, or 0 to indicate that no element is initially selected (which is the default but typically not what you want).<br />
<br />
The ''markup'' argument specifies whether Pango markup will be parsed in the menuitems. It defaults to false.<br />
<br />
The ''initial'' and ''markup'' arguments can be passed in either order; the game will understand which is meant based on the type of the argument.<br />
<br />
==== wesnoth.show_message_box ====<br />
<br />
* '''wesnoth.show_message_box(''title'', ''message'' [, ''button''] [, ''markup''])'''<br />
* '''wesnoth.confirm([''title'',] ''message'')'''<br />
* '''wesnoth.alert([''title''], ''message'')'''<br />
<br />
Shows a standard message box onscreen (similar to the quit confirmation message, for example). The button can be any arbitrary potentially-translatable string (in which case, there will be one button with that label), or it can be one of the following special values:<br />
<br />
* ''ok'' or nil: A single OK button; this is the default<br />
* ''cancel'': A single Cancel button<br />
* ''close'': A single Close button<br />
* ''ok_cancel'': Two buttons labelled OK and Cancel<br />
* ''yes_no'': Two buttons labelled Yes and No<br />
* an empty string: No buttons; the dialog automatically closes after a few seconds<br />
<br />
The alert and confirm functions are simpler wrappers for this function, using a single OK button and a pair of Yes/No buttons, respectively. Both confirm and show_message_box return false if No or Cancel was clicked, and true otherwise.<br />
<br />
==== wesnoth.show_message_dialog ====<br />
<br />
* '''wesnoth.show_message_dialog(''attributes'', [''options'', [''text_input_attributes'']])'''<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Shows a message dialog, of the type used by the [message] ActionWML tag. Unlike the [message] tag, this is unsynced; if you need it synced, you must do it yourself. The first argument is a table describing the dialog with the following keys:<br />
<br />
* ''title'' - The title to show on the message. For example, the speaker's name.<br />
* ''message'' - The message content.<br />
* ''portrait'' - An image to show along with the message. By default, no image is shown.<br />
* ''left_side'' - The default is true; set to false to show the image on the right.<br />
* ''mirror'' - If true, the image will be flipped horizontally.<br />
<br />
The second argument is a list of options as a Lua array. Each option is either a (possibly-translatable) string or a config with [[DescriptionWML#WML_Format|DescriptionWML]] keys. The array itself can also have an optional '''default''' key which if present should be the index of the initially selected option (useful if you don't need full DescriptionWML but want to set a default). If present it overrides any defaults set in individual options.<br />
<br />
The third argument is a table describing the text input field with the following keys:<br />
<br />
* ''label'' - A label to show to the left of the text field.<br />
* ''text'' - Initial contents of the text field.<br />
* ''max_length'' - Maximum input length in characters (defaults to 256).<br />
<br />
You need at least one key for the text input to be shown. Both the second arguments are option, but if you want text input with no options, you must pass nil for the second parameter.<br />
<br />
This function returns two values. The first is the numeric result of the dialog. If there are no options and no text input, this is -2 if the user closed by pressing Escape, otherwise it's -1. If there are options, this is the index of the option chosen (starting from 1). If there is text input but no options, the first return value is 0. If there was text input, the second value contains the text entered.<br />
<br />
Example:<br />
<br />
wesnoth.show_message_dialog({<br />
title = "Make your choice:",<br />
message = "Select an option and enter some text.",<br />
portrait = "wesnoth-icon.png",<br />
}, {<br />
"The first choice is always the best!",<br />
"Pick me! Second choices are better!",<br />
"You know you want the third option!",<br />
}, {<br />
label = "Text:",<br />
text = "?",<br />
max_length = 16<br />
})<br />
<br />
(You don't have to format it like that, of course.)<br />
<br />
==== wesnoth.show_popup_dialog ====<br />
<br />
* '''wesnoth.show_popup_dialog(''title'', ''message'', [''image''])'''<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Shows a simple popup dialog in the centre of the screen. Takes three arguments, which in order are:<br />
<br />
# A title string for the dialog<br />
# The message content for the dialog.<br />
# An image to show.<br />
<br />
Both the title and the message support Pango markup. The image is optional.<br />
<br />
==== wesnoth.show_story ====<br />
<br />
* '''wesnoth.show_story(''story_config'', ''default_title'')'''<br />
<br />
{{DevFeature1.13|8}}<br />
<br />
Shows the storyscreen. The passed config is identical to the contents of [[IntroWML|[story]]]. The second parameter is the default title used if a part does not specify one — unlike intro storyscreens, a Lua-invoked one does not default to the scenario name.<br />
<br />
==== wesnoth.show_dialog ====<br />
<br />
* '''wesnoth.show_dialog(''wml_dialog_table'', [''pre_show_function'', [''post_show_function'']])'''<br />
<br />
Displays a dialog box described by a WML table and returns:<br />
* if the dialog was dismissed by a button click, the integer value associated to the button via the "return_value" keyword.<br />
* if the dialog was closed with the enter key, -1.<br />
* if the dialog was closed with the escape key, -2.<br />
<br />
The dialog box is equivalent to the resolution section of a GUI window as described in [[GUIToolkitWML#Window_definition|GUIToolkitWML]] and must therefore contain at least the following children: '''[tooltip]''', '''[helptip]''', and '''[grid]'''. The [grid] must contain nested [row], [column] and [grid] tags which describe the layout of the window. (More information can be found in [[GUILayout]]; suffice to say that the basic structure is grid -> row -> column -> widget, where the widget is considered to be in a cell defined by the row and column of the grid. A list of widgets can be found at [[GUIWidgetInstanceWML]].)<br />
<br />
Two optional functions can be passed as second and third arguments; the first one is called once the dialog is created and before it is shown; the second one is called once the dialog is closed. These functions are helpful in setting the initial values of the fields and in recovering the final user values. These functions can call the [[#wesnoth.set_dialog_value]], [[#wesnoth.get_dialog_value]], and [[#wesnoth.set_dialog_callback]] functions for this purpose.<br />
<br />
This function should be called in conjunction with [[LuaWML:Misc#wesnoth.synchronize_choice|#wesnoth.synchronize_choice]], in order to ensure that only one client displays the dialog and that the other ones recover the same input values from this single client.<br />
<br />
The example below defines a dialog with a list and two buttons on the left, and a big image on the right. The ''preshow'' function fills the list and defines a callback on it. This ''select'' callback changes the displayed image whenever a new list item is selected. The ''postshow'' function recovers the selected item before the dialog is destroyed.<br />
<br />
<syntaxhighlight lang=lua><br />
local helper = wesnoth.require "lua/helper.lua"<br />
local T = wml.tag<br />
local _ = wesnoth.textdomain "wesnoth"<br />
<br />
local dialog = {<br />
T.tooltip { id = "tooltip_large" },<br />
T.helptip { id = "tooltip_large" },<br />
T.grid { T.row {<br />
T.column { T.grid {<br />
T.row { T.column { horizontal_grow = true, T.listbox { id = "the_list",<br />
T.list_definition { T.row { T.column { horizontal_grow = true,<br />
T.toggle_panel { return_value = -1, T.grid { T.row {<br />
T.column { horizontal_alignment = "left", T.label { id = "the_label" } },<br />
T.column { T.image { id = "the_icon" } }<br />
} } }<br />
} } }<br />
} } },<br />
T.row { T.column { T.grid { T.row {<br />
T.column { T.button { id = "ok", label = _"OK" } },<br />
T.column { T.button { id = "cancel", label = _"Cancel" } }<br />
} } } }<br />
} },<br />
T.column { T.image { id = "the_image" } }<br />
} }<br />
}<br />
<br />
local function preshow()<br />
local t = { "Ancient Lich", "Ancient Wose", "Elvish Avenger" }<br />
local function select()<br />
local i = wesnoth.get_dialog_value "the_list"<br />
local ut = wesnoth.unit_types[t[i]].__cfg<br />
wesnoth.set_dialog_value(string.gsub(ut.profile, "([^/]+)$", "transparent/%1"), "the_image")<br />
end<br />
wesnoth.set_dialog_callback(select, "the_list")<br />
for i,v in ipairs(t) do<br />
local ut = wesnoth.unit_types[v].__cfg<br />
wesnoth.set_dialog_value(ut.name, "the_list", i, "the_label")<br />
wesnoth.set_dialog_value(ut.image, "the_list", i, "the_icon")<br />
end<br />
wesnoth.set_dialog_value(2, "the_list")<br />
select()<br />
end<br />
<br />
local li<br />
local function postshow()<br />
li = wesnoth.get_dialog_value "the_list"<br />
end<br />
<br />
local r = wesnoth.show_dialog(dialog, preshow, postshow)<br />
wesnoth.message(string.format("Button %d pressed. Item %d selected.", r, li))<br />
</syntaxhighlight><br />
<br />
==== wesnoth.set_dialog_value ====<br />
<br />
* '''wesnoth.set_dialog_value(''value'', ''path, to, widget, id'')'''<br />
<br />
Sets the value of a widget on the current dialog. The value is given by the first argument; its semantic depends on the type of widget it is applied to. The last argument is the ''id'' of the widget. If it does not point to a unique widget in the dialog, some discriminating parents should be given on its left, making a path that is read from left to right by the engine. The row of a list is specified by giving the ''id' of the list as a first argument and the 1-based row number as the next argument.<br />
<br />
-- sets the value of a widget "bar" in the 7th row of the list "foo"<br />
wesnoth.set_dialog_value(_"Hello world", "foo", 7, "bar")<br />
<br />
Notes: When the row of a list does not exist, it is created. The value associated to a list is the selected row.<br />
<br />
==== wesnoth.get_dialog_value ====<br />
<br />
* '''wesnoth.get_dialog_value(''path, to, widget, id'')'''<br />
<br />
Gets the value of a widget on the current dialog. The arguments described the path for reaching the widget (see [[#wesnoth.set_dialog_value]]).<br />
<br />
{{DevFeature1.13|0}}<br />
For treeviews this function returns a table descibing the currently selected node.<br />
If for example in this treeview<br />
+Section1<br />
+Subsection11<br />
*Item1<br />
*Item2<br />
*Item3<br />
+Subsection12<br />
*Item4<br />
*Item5<br />
*Item6<br />
+Section2<br />
+Subsection21<br />
*Item7<br />
*Item8<br />
*Item9<br />
+Subsection22<br />
*Item10<br />
*Item11<br />
*Item12<br />
Item 9 is selcted the value will be {2,1,3}<br />
<br />
==== wesnoth.set_dialog_active ====<br />
<br />
* '''wesnoth.set_dialog_active(''active?'', ''path, to, widget, id'')'''<br />
<br />
Enables or disables a widget. The first argument is a boolean specifying whether the widget should be active (true) or inactive (false). The remaining arguments are the path to locate the widget in question (see [[#wesnoth.set_dialog_value]]).<br />
<br />
==== wesnoth.set_dialog_callback ====<br />
<br />
* '''wesnoth.set_dialog_callback(''callback_function'', ''path, to, widget, id'')'''<br />
<br />
Sets the first argument as a callback function for the widget obtained by following the path of the other arguments (see [[#wesnoth.set_dialog_value]]). This function will be called whenever the user modifies something about the widget, so that the dialog can react to it.<br />
<br />
==== wesnoth.set_dialog_markup ====<br />
<br />
* '''wesnoth.set_dialog_markup(''allowed?'', ''path, to, widget, id'')'''<br />
<br />
Sets the flag associated to a widget to enable or disable Pango markup. The new flag value is passed as the first argument (boolean), and the widget to modify is obtained by following the path of the other arguments (see [[#wesnoth.set_dialog_value]]). Most widgets start with Pango markup disabled unless this function is used to set their flag to true.<br />
<br />
wesnoth.set_dialog_markup(true, "notice_label")<br />
wesnoth.set_dialog_value("&lt;big&gt;NOTICE!&lt;/big&gt;", "notice_label")<br />
<br />
==== wesnoth.set_dialog_focus ====<br />
<br />
* '''wesnoth.set_dialog_focus(''path, to, widget, id'')'''<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Switches the keyboard focus to the widget found following the given path (see [[#wesnoth.set_dialog_value]]). This is often useful for dialogs containing a central listbox, so that it can be controlled with the keyboard as soon as it is displayed.<br />
<br />
wesnoth.set_dialog_focus("my_listbox")<br />
<br />
==== wesnoth.set_dialog_visible ====<br />
<br />
* '''wesnoth.set_dialog_visible(''visible?'', ''path, to, widget, id'')'''<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Sets a widget's visibility status. The new status is passed as the first argument, and the path to the widget is specified by the remaining arguments (see [[#wesnoth.set_dialog_value]]). The following visibility statuses are recognized:<br />
<br />
{| clasS="wikitable"<br />
! String value !! Boolean shorthand !! Meaning<br />
|-<br />
| visible || true || The widget is visible and handles events.<br />
|-<br />
| hidden || || The widget is not visible, doesn't handle events, but still takes up space on the dialog grid.<br />
|-<br />
| invisible || false || The widget is not visible, doesn't handle events, and does not take up space on the dialog grid.<br />
|}<br />
<br />
wesnoth.set_dialog_visible(false, "secret_button")<br />
<br />
==== wesnoth.set_dialog_canvas ====<br />
<br />
* '''wesnoth.set_dialog_canvas(''index'', ''content'', ''path, to, widget, id'')'''<br />
<br />
Sets the WML passed as the second argument as the canvas content (index given by the first argument) of the widget obtained by following the path of the other arguments (see [[#wesnoth.set_dialog_value]]). The content of the WML table is described at [[GUICanvasWML]].<br />
<br />
-- draw two rectangles in the upper-left corner of the window (empty path = window widget)<br />
wesnoth.set_dialog_canvas(2, {<br />
T.rectangle { x = 20, y = 20, w = 20, h = 20, fill_color= "0,0,255,255" },<br />
T.rectangle { x = 30, y = 30, w = 20, h = 20, fill_color = "255,0,0,255" }<br />
})<br />
<br />
The meaning of the canvas index depends on the chosen widget. It may be the disabled / enabled states of the widget, or its background / foreground planes, or... For instance, overwriting canvas 1 of the window with an empty canvas causes the window to become transparent.<br />
<br />
==== wesnoth.add_dialog_tree_node ====<br />
<br />
* '''wesnoth.add_dialog_tree_node(''type'', ''index'', ''path, to, widget, id'')'''<br />
<br />
{{DevFeature1.13|0}}<br />
<br />
Adds a childnode to a treeview widget or a treeview node. The type (id of the node definition) of the node is passed in the first parameter. The second parameter (integer) spcifies where the node should be inserted in the parentnode. The other arguments describe the path of the parent treeview (-node)<br />
<br />
==== wesnoth.remove_dialog_item ====<br />
<br />
* '''wesnoth.remove_dialog_item(''index'', ''count'', ''path, to, widget, id'')'''<br />
<br />
{{DevFeature1.13|1}}<br />
<br />
Removes an item from a listbox, a multipage or a treeview. First parameter is the index of the item to delete, second parameter is the number of items to delete and the remaining parameters describe the path to the listbox, the multipage or the parent treview node.<br />
<br />
<br />
==== wesnoth.add_widget_definition====<br />
<br />
* '''wesnoth.add_widget_definition(''widget_type'', ''definition_id'', ''wml_content'')'''<br />
<br />
{{DevFeature1.13|?}}<br />
<br />
Creates a new wml widget definition see https://github.com/wesnoth/wesnoth/tree/1.14/data/gui/widget for examples wml_content<br />
<br />
==== wesnoth.is_skipping_messages ====<br />
<br />
* '''wesnoth.is_skipping_messages()'''<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Returns true if messages are currently being skipped, for example because the player has chosen to skip replay, or has pressed escape to dismiss a message.<br />
<br />
==== wesnoth.skip_messages ====<br />
<br />
* '''wesnoth.skip_messages([''skip?'')'''<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Sets the skip messages flag. By default it sets it to true, but you can also pass false to unset the flag.<br />
<br />
==== wesnoth.get_displayed_unit ====<br />
<br />
* '''wesnoth.get_displayed_unit()'''<br />
<br />
Returns a proxy to the unit currently displayed in the side pane of the user interface, if any.<br />
<br />
local name = tostring(wesnoth.get_displayed_unit().name)<br />
<br />
==== wesnoth.log ====<br />
<br />
* '''wesnoth.log([''logger''], ''message', ''in_chat'')'''<br />
<br />
{{DevFeature1.13|5}} Logs a message to the console. These messages are normally not visible unless Wesnoth is run from the command-line or (in Windows) with the --wconsole switch. The in_chat argument, however, can be set to true to also echo the message to the in-game chat area.<br />
<br />
Possible loggers are info, debug, warning, error, and wml. The wml logger is special and is intended for WML errors; it always goes to chat, so the in_chat argument is ignored and can be omitted. The default logger is info.<br />
<br />
==== wesnoth.theme_items ====<br />
<br />
This field is not a function but an associative table. It links item names to the functions that describe their content. These functions are called whenever the user interface is refreshed. The description of an item is a WML table containing '''[element]''' children. Each subtag shall contain either a '''text''' or an '''image''' field that is displayed to the user. It can also contain a '''tooltip''' field that is displayed to the user when moused over, and a "help" field that points to the help section that is displayed when the user clicks on the theme item.<br />
<br />
Note that the ''wesnoth.theme_items'' table is originally empty and using ''pairs'' or ''next'' on it will not return the items from the current theme. Its metatable ensures that the drawing functions of existing items can be recovered though, as long as their name is known. The example below shows how to modify the ''unit_status'' item to display a custom status:<br />
<br />
<syntaxhighlight lang=lua><br />
local old_unit_status = wesnoth.theme_items.unit_status<br />
function wesnoth.theme_items.unit_status()<br />
local _ = wesnoth.textdomain "mydomain"<br />
local u = wesnoth.get_displayed_unit()<br />
if not u then return {} end<br />
local s = old_unit_status()<br />
if u.status.entangled then<br />
table.insert(s, wml.tag.element {<br />
image = "entangled.png",<br />
tooltip = _"entangled: This unit is entangled. It cannot move but it can still attack."<br />
})<br />
end<br />
return s<br />
end<br />
</syntaxhighlight><br />
<br />
The things that would need to be to modified in the above code are:<br />
<br />
* the domain of your addon ("mydomain"), assuming that you are using translations. Otherwise just remove the underscore in the tooltip line.<br />
* the name of the status (u.status.entangled). Note that if the attribute happens to be inside [variables], so be it: u.variables.whatever.<br />
* the path to the image ("entangled.png").<br />
* the tooltip of the status ("entangled: This unit ...").<br />
<br />
The following is a list of valid entries in wesnoth.theme_items which will have an effect in the game. Unfortunately when this feature was created the full range of capabilities of the feature was never properly documented. The following list is automatically generated. To find out what each entry will do, you will have to make guesses and experiment, or read the source code at src/reports.cpp. If you find out what an entry does, you are more than welcome to edit the wiki and give a proper description to any of these fields.<br />
<br />
* '''unit_name'''<br />
* '''selected_unit_name'''<br />
* '''unit_type'''<br />
* '''selected_unit_type'''<br />
* '''unit_race'''<br />
* '''selected_unit_race'''<br />
* '''unit_side'''<br />
* '''selected_unit_side'''<br />
* '''unit_level'''<br />
* '''selected_unit_level'''<br />
* '''unit_amla'''<br />
* '''unit_traits'''<br />
* '''selected_unit_traits'''<br />
* '''unit_status'''<br />
* '''selected_unit_status'''<br />
* '''unit_alignment'''<br />
* '''selected_unit_alignment'''<br />
* '''unit_abilities'''<br />
* '''selected_unit_abilities'''<br />
* '''unit_hp'''<br />
* '''selected_unit_hp'''<br />
* '''unit_xp'''<br />
* '''selected_unit_xp'''<br />
* '''unit_advancement_options'''<br />
* '''selected_unit_advancement_options'''<br />
* '''unit_defense'''<br />
* '''selected_unit_defense'''<br />
* '''unit_vision'''<br />
* '''selected_unit_vision'''<br />
* '''unit_moves'''<br />
* '''selected_unit_moves'''<br />
* '''unit_weapons'''<br />
The default generator expresses each weapon line as a separate <code>element</code><br />
<syntaxhighlight lang=lua><br />
return { <br />
wml.tag.element { text = "weapon text",<br />
tooltip = _"weapon tooltip"<br />
}<br />
-- ...<br />
}<br />
</syntaxhighlight><br />
* '''highlighted_unit_weapons'''<br />
* '''selected_unit_weapons'''<br />
* '''unit_image'''<br />
* '''selected_unit_image'''<br />
* '''selected_unit_profile'''<br />
* '''unit_profile'''<br />
* '''tod_stats'''<br />
* '''time_of_day'''<br />
* '''unit_box'''<br />
* '''turn'''<br />
* '''gold'''<br />
* '''villages'''<br />
* '''num_units'''<br />
* '''upkeep'''<br />
* '''expenses'''<br />
* '''income'''<br />
* '''terrain_info'''<br />
* '''terrain'''<br />
** <nowiki>Text for terrain of the active hex. Same as the one displayed on the UI. It probably returns an empty table when no hex is active. Otherwise, it returns something like {{"element",{text="Grassland (Flat)"}}}.</nowiki><br />
* '''zoom_level'''<br />
* '''position'''<br />
* '''side_playing'''<br />
* '''observers'''<br />
** <nowiki>When there is no observer, it returns an empty table. When there are observers, it gives<br />
{{"element",<br />
{tooltip="Observers\n<observer1>\n<observer2>\n", image="misc/eye.png"}<br />
}}<br />
<br />
</nowiki><br />
* '''selected_terrain'''<br />
* '''edit_left_button_function'''<br />
* '''report_clock'''<br />
** <nowiki>wesnoth.theme_items.report_clock() gives a table {{"element", text=<time>}}, where <time> is HH:MM of local time. It probably return 12hr or 24hr formats depending on user preference. </nowiki><br />
* '''report_countdown'''<br />
** <nowiki>wesnoth.theme_items.report_countdown() gives a table {{"element", text=<time>}}, where <time> is MM:SS of time limit for player's turn. If turn limit < 120 or 60, add <span foreground="#c8c800"><br />
or <span foreground="#c80000"> html tags. </nowiki><br />
<br />
==== helper.get_user_choice ====<br />
<br />
* '''helper.get_user_choice(''message_table'', ''options'')'''<br />
<br />
Displays a WML message box querying a choice from the user. Attributes and options are taken from given tables (see [[InterfaceActionsWML#.5Bmessage.5D|[message]]]). The index of the selected option is returned.<br />
<br />
local result = helper.get_user_choice({ speaker = "narrator" }, { "Choice 1", "Choice 2" })<br />
<br />
[[Category: Lua Reference]]<br />
<br />
==== wesnoth.zoom ====<br />
<br />
{{DevFeature1.13|8}}<br />
<br />
* '''wesnoth.zoom(''factor''[, ''relative''])'''<br />
<br />
Changes the zoom level of the map. If relative is false, which is the default, it simply sets the zoom level. If relative is true, it zooms relative to the current zoom level. So, for example, if the zoom level is currently 0.5, then wesnoth.zoom(2) sets it to 2, while wesnoth.zoom(2, true) sets it to 1 (2 * 0.5).<br />
<br />
This function also returns the resulting zoom level. Because of this, you can call wesnoth.zoom(1) to simply get the current zoom level.<br />
<br />
Note that this function cannot zoom to a level that the user would not be able to reach from the UI. Attempting to do so will simply select the nearest allowed zoom level.</div>Edward Chernenkohttps://wiki.wesnoth.org/index.php?title=LuaWML/Display&diff=60125LuaWML/Display2018-12-29T16:38:15Z<p>Edward Chernenko: replaced deprecated helper.set_wml_tag_metatable with wml.tag</p>
<hr />
<div>This page describes the [[LuaWML]] functions and helpers for interfacing with the user.<br />
<br />
==== wesnoth.message ====<br />
<br />
* '''wesnoth.message([''speaker'',] ''message'')'''<br />
<br />
Displays a string in the chat window and dumps it to the lua/info log domain (''--log-info=scripting/lua'' on the command-line).<br />
<br />
wesnoth.message "Hello World!"<br />
<br />
The chat line header is "<Lua>" by default, but it can be changed by passing a string before the message.<br />
<br />
wesnoth.message("Big Brother", "I'm watching you.") -- will result in "&lt;Big Brother&gt; I'm watching you."<br />
<br />
See also [[LuaWML:Events#helper.wml_error|helper.wml_error]] for displaying error messages.<br />
<br />
==== wesnoth.clear_messages ====<br />
<br />
* '''wesnoth.clear_messages()'''<br />
<br />
Removes all messages from the chat window. No argument or returned values.<br />
<br />
==== wesnoth.textdomain ====<br />
<br />
* '''wesnoth.textdomain(''domain'')'''<br />
<br />
Creates a function proxy for lazily translating strings from the given domain.<br />
<br />
-- #textdomain "my-campaign"<br />
-- the comment above ensures the subsequent strings will be extracted to the proper domain<br />
_ = wesnoth.textdomain "my-campaign"<br />
wesnoth.set_variable("my_unit.description", _ "the unit formerly known as Hero")<br />
<br />
The metatable of the function proxy appears as '''"message domain"'''. The metatable of the translatable strings (results of the proxy) appears as '''"translatable string"'''.<br />
<br />
The translatable strings can be appended to other strings/numbers with the standard '''..''' operator. Translation can be forced with the standard '''tostring''' operator in order to get a plain string.<br />
<br />
wesnoth.message(string.format(tostring(_ "You gain %d gold."), amount))<br />
<br />
==== wesnoth.delay ====<br />
<br />
* '''wesnoth.delay(''milliseconds'')'''<br />
<br />
Delays the engine like the [delay] tag. one argument: time to delay in milliseconds<br />
<br />
wesnoth.delay(500)<br />
<br />
==== wesnoth.float_label ====<br />
<br />
* '''wesnoth.float_label(''x'', ''y'', ''text'')'''<br />
<br />
Pops some text above a map tile.<br />
<br />
wesnoth.float_label(unit.x, unit.y, "&lt;span color='#ff0000'&gt;Ouch&lt;/span&gt;")<br />
<br />
==== wesnoth.get_viewing_side ====<br />
<br />
* '''wesnoth.get_viewing_side()'''<br />
<br />
returns two values 1) the number of the side of the current viewpoint, 2) a boolean specifying whether it has full vision (can only only true happen in replays or for observers)<br />
<br />
==== wesnoth.select_unit ====<br />
<br />
* '''wesnoth.select_hex(''x'', ''y'', [''show_movement'', [''fire_events'']])'''<br />
* {{DevFeature1.13|5}} '''wesnoth.select_unit(''unit'', [''show_movement'', [''fire_events'']])'''<br />
* {{DevFeature1.13|5}} '''''unit'':select([''show_movement'', [''fire_events'']])'''<br />
<br />
Selects the given unit in the game map as if the player had clicked on it.<br />
Argument 3: boolean, whether to show the movement range of any unit on that location (def: true)<br />
Argument 4: boolean, whether to fire any select events (def: false). Note: currently (1.14.1), this argument has no effect (events are never fired).<br />
<br />
wesnoth.select_unit(14,6, true, true)<br />
<br />
The '''wesnoth.select_hex''' form is deprecated. If there is a unit on the location, it does the same thing as '''wesnoth.select_unit''', but if ''show_movement'' is true it also calls '''wesnoth.highlight_hex''' for the location. If there is no unit on the location, '''wesnoth.select_hex''' does not do anything useful.<br />
<br />
If called without arguments, '''wesnoth.select_unit''' deselects the current unit from the map as long as the mouse cursor is not on its hex. It will continue to be displayed on the UI sidebar in any case.<br />
<br />
==== wesnoth.highlight_hex ====<br />
<br />
* '''wesnoth.highlight_hex(''x'', ''y'')'''<br />
<br />
Draws an outline around the specified hex.<br />
<br />
==== wesnoth.deselect_hex ====<br />
<br />
* '''wesnoth.deselect_hex()'''<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Reverses any select_hex call, leaving all locations unhighlighted. Takes no arguments.<br />
<br />
==== wesnoth.scroll_to_tile ====<br />
<br />
* '''wesnoth.scroll_to_tile(''x'', ''y'', [''only_if_visible'', [''instant'']])'''<br />
* {{DevFeature1.13|7}} '''wesnoth.scroll_to_tile(''x'', ''y'', [''only_if_visible'', [''instant'', [''only_if_needed'']]])'''<br />
<br />
Scrolls the map to the given location. If true is passed as the third parameter, scrolling is disabled if the tile is hidden under the fog. If true is passed as the fourth parameter, the view instantly warps to the location regardless of the scroll speed setting in Preferences. If true is passed as the fifth parameter, no scrolling occurs if the target location is already visible onscreen.<br />
<br />
local u = wesnoth.get_units({ id = "hero" })[1]<br />
wesnoth.scroll_to_tile(u.x, u.y)<br />
<br />
==== wesnoth.lock_view ====<br />
<br />
* '''wesnoth.lock_view(''lock'')'''<br />
<br />
Locks or unlocks gamemap view scrolling for human players. If true is passed as the first parameter, the view is locked; pass false to unlock.<br />
<br />
Human players cannot scroll the gamemap view as long as it is locked, but Lua or WML actions such as wesnoth.scroll_to_tile still can; the locked/unlocked state is preserved when saving the current game. This feature is generally intended to be used in cutscenes to prevent the player scrolling away from scripted actions.<br />
<br />
wesnoth.lock_view(true)<br />
wesnoth.scroll_to_tile(12, 14, false, true)<br />
<br />
==== wesnoth.view_locked ====<br />
<br />
* '''wesnoth.view_locked()'''<br />
<br />
Returns a boolean indicating whether gamemap view scrolling is currently locked.<br />
<br />
==== wesnoth.play_sound ====<br />
<br />
* '''wesnoth.play_sound(''sound'', [''repeat_count''])'''<br />
<br />
Plays the given sound file once, optionally repeating it one or more more times if an integer value is provided as a second argument (note that the sound is ''repeated'' the number of times specified in the second argument, i.e. a second argument of 4 will cause the sound to be played once and then repeated four more times for a total of 5 plays. See the example below).<br />
<br />
wesnoth.play_sound "ambient/birds1.ogg"<br />
wesnoth.play_sound("magic-holy-miss-3.ogg", 4) -- played 1 + 4 = 5 times<br />
<br />
==== wesnoth.set_music ====<br />
<br />
* '''wesnoth.set_music(''music_entry'')'''<br />
<br />
Sets the given table as an entry into the music list. See [[MusicListWML]] for the recognized attributes.<br />
<br />
wesnoth.set_music { name = "traveling_minstrels.ogg" }<br />
<br />
Passing no argument forces the engine to take into account all the recent changes to the music list. (Note: this is done automatically when sequences of WML commands end, so it is useful only for long events.)<br />
<br />
{{DevFeature1.13|8}} This function is now deprecated. Use the '''wesnoth.music_list''' table instead<br />
<br />
==== wesnoth.music_list ====<br />
<br />
{{DevFeature1.13|8}}<br />
<br />
This is a table giving access to the current music playlist. It can be accessed as a normal array, including the Lua length operator. If you assign a music config to an entry, the track is replaced. It is not a normal array however and cannot be manipulated with the table library.<br />
<br />
In addition, it has the following named fields:<br />
<br />
* '''wesnoth.music_list.current''' (read-write): The currently-playing track. This may sometimes be a track that's not on the playlist - "play once" tracks are not placed on the playlist.<br />
* '''wesnoth.music_list.current.__cfg''' (read-only): Returns a copy of the current track information.<br />
* '''wesnoth.music_list.previous''' (read-write): The track played before the current one. This may sometimes be a track that's not on the playlist - "play once" tracks are not placed on the playlist.<br />
* '''wesnoth.music_list.previous.__cfg''' (read-only): Returns a copy of the previous track information. NOTE: Wesnoth's playlist implementation effectively "plays" every song as it's added to the playlist, so when replacing one playlist with another, this will return information on the second-to-last track added to the new playlist, not the track you actually heard playing from the playlist that was replaced.<br />
* '''wesnoth.music_list.current_i''' (read-write): The index of the currently-playing track on the playlist, or nil if the currently-playing track is not on the playlist.<br />
* '''wesnoth.music_list.volume''' (read-write): The current music volume, as a percentage of the user's preferred volume set in preferences.<br />
* '''wesnoth.music_list.all''' (read-only): Returns a copy of the music list as an array of WML tables.<br />
<br />
It also contains some functions:<br />
<br />
* '''wesnoth.music_list.add(''track_name'', [''immediate'',] [''ms_before'', [''ms_after'']])''': Appends a track to the playlist. If true is passed, also start playing the new track.<br />
* '''wesnoth.music_list.remove(''n1'', ...)''': Removes one or more tracks by their index. You can pass as many indices as you wish. If one of the removed tracks is currently playing, it continues to play.<br />
* '''wesnoth.music_list.clear()''': Clears the playlist. The currently-playing track continues to play.<br />
* '''wesnoth.music_list.next()''': Stop playing the current track and move on to the next one. This honours the shuffle settings.<br />
* '''wesnoth.music_list.play(''track_name'')''': Start playing a track without appending it to the playlist.<br />
<br />
Each track contains the following fields:<br />
<br />
* '''shuffle''' (read-write)<br />
* '''once''' (read-write): generally only true for '''wesnoth.music_list.current'''<br />
* '''ms_before''' (read-write)<br />
* '''ms_after''' (read-write)<br />
* '''immediate''' (read-only)<br />
* '''name''' (read-only): the unresolved track filename<br />
* '''title''' (read-only): a user-friendly track title<br />
<br />
==== wesnoth.sound_volume ====<br />
<br />
{{DevFeature1.13|8}}<br />
<br />
* '''wesnoth.sound_volume(''new_volume'')'''<br />
<br />
Sets the current sound volume, as a percentage of the user's preferred volume set in preferences.<br />
Returns the previous sound volume in the same format.<br />
<br />
==== wesnoth.show_menu ====<br />
<br />
* '''wesnoth.show_menu(''items'' [, ''initial''] [, ''markup''])'''<br />
<br />
Shows a popup menu onscreen at the current mouse location. This could be used for example to produce a sort of submenu in a <tt>[set_menu_item]</tt>. The items are specified as a Lua array of tables, each of which supports the following keys:<br />
<br />
* ''icon'': An icon to display in the leftmost column of the menu.<br />
* ''image'': An image to display in the main column of the menu. If this is present, ''label'' is ignored.<br />
* ''label'': A label to display in the main column of the menu.<br />
* ''details'': A secondary label to display in the right column of the menu.<br />
* ''tooltip'': Text to display when mousing over this option.<br />
<br />
The ''initial'' argument must be a valid index into the ''items'' array, or 0 to indicate that no element is initially selected (which is the default but typically not what you want).<br />
<br />
The ''markup'' argument specifies whether Pango markup will be parsed in the menuitems. It defaults to false.<br />
<br />
The ''initial'' and ''markup'' arguments can be passed in either order; the game will understand which is meant based on the type of the argument.<br />
<br />
==== wesnoth.show_message_box ====<br />
<br />
* '''wesnoth.show_message_box(''title'', ''message'' [, ''button''] [, ''markup''])'''<br />
* '''wesnoth.confirm([''title'',] ''message'')'''<br />
* '''wesnoth.alert([''title''], ''message'')'''<br />
<br />
Shows a standard message box onscreen (similar to the quit confirmation message, for example). The button can be any arbitrary potentially-translatable string (in which case, there will be one button with that label), or it can be one of the following special values:<br />
<br />
* ''ok'' or nil: A single OK button; this is the default<br />
* ''cancel'': A single Cancel button<br />
* ''close'': A single Close button<br />
* ''ok_cancel'': Two buttons labelled OK and Cancel<br />
* ''yes_no'': Two buttons labelled Yes and No<br />
* an empty string: No buttons; the dialog automatically closes after a few seconds<br />
<br />
The alert and confirm functions are simpler wrappers for this function, using a single OK button and a pair of Yes/No buttons, respectively. Both confirm and show_message_box return false if No or Cancel was clicked, and true otherwise.<br />
<br />
==== wesnoth.show_message_dialog ====<br />
<br />
* '''wesnoth.show_message_dialog(''attributes'', [''options'', [''text_input_attributes'']])'''<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Shows a message dialog, of the type used by the [message] ActionWML tag. Unlike the [message] tag, this is unsynced; if you need it synced, you must do it yourself. The first argument is a table describing the dialog with the following keys:<br />
<br />
* ''title'' - The title to show on the message. For example, the speaker's name.<br />
* ''message'' - The message content.<br />
* ''portrait'' - An image to show along with the message. By default, no image is shown.<br />
* ''left_side'' - The default is true; set to false to show the image on the right.<br />
* ''mirror'' - If true, the image will be flipped horizontally.<br />
<br />
The second argument is a list of options as a Lua array. Each option is either a (possibly-translatable) string or a config with [[DescriptionWML#WML_Format|DescriptionWML]] keys. The array itself can also have an optional '''default''' key which if present should be the index of the initially selected option (useful if you don't need full DescriptionWML but want to set a default). If present it overrides any defaults set in individual options.<br />
<br />
The third argument is a table describing the text input field with the following keys:<br />
<br />
* ''label'' - A label to show to the left of the text field.<br />
* ''text'' - Initial contents of the text field.<br />
* ''max_length'' - Maximum input length in characters (defaults to 256).<br />
<br />
You need at least one key for the text input to be shown. Both the second arguments are option, but if you want text input with no options, you must pass nil for the second parameter.<br />
<br />
This function returns two values. The first is the numeric result of the dialog. If there are no options and no text input, this is -2 if the user closed by pressing Escape, otherwise it's -1. If there are options, this is the index of the option chosen (starting from 1). If there is text input but no options, the first return value is 0. If there was text input, the second value contains the text entered.<br />
<br />
Example:<br />
<br />
wesnoth.show_message_dialog({<br />
title = "Make your choice:",<br />
message = "Select an option and enter some text.",<br />
portrait = "wesnoth-icon.png",<br />
}, {<br />
"The first choice is always the best!",<br />
"Pick me! Second choices are better!",<br />
"You know you want the third option!",<br />
}, {<br />
label = "Text:",<br />
text = "?",<br />
max_length = 16<br />
})<br />
<br />
(You don't have to format it like that, of course.)<br />
<br />
==== wesnoth.show_popup_dialog ====<br />
<br />
* '''wesnoth.show_popup_dialog(''title'', ''message'', [''image''])'''<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Shows a simple popup dialog in the centre of the screen. Takes three arguments, which in order are:<br />
<br />
# A title string for the dialog<br />
# The message content for the dialog.<br />
# An image to show.<br />
<br />
Both the title and the message support Pango markup. The image is optional.<br />
<br />
==== wesnoth.show_story ====<br />
<br />
* '''wesnoth.show_story(''story_config'', ''default_title'')'''<br />
<br />
{{DevFeature1.13|8}}<br />
<br />
Shows the storyscreen. The passed config is identical to the contents of [[IntroWML|[story]]]. The second parameter is the default title used if a part does not specify one — unlike intro storyscreens, a Lua-invoked one does not default to the scenario name.<br />
<br />
==== wesnoth.show_dialog ====<br />
<br />
* '''wesnoth.show_dialog(''wml_dialog_table'', [''pre_show_function'', [''post_show_function'']])'''<br />
<br />
Displays a dialog box described by a WML table and returns:<br />
* if the dialog was dismissed by a button click, the integer value associated to the button via the "return_value" keyword.<br />
* if the dialog was closed with the enter key, -1.<br />
* if the dialog was closed with the escape key, -2.<br />
<br />
The dialog box is equivalent to the resolution section of a GUI window as described in [[GUIToolkitWML#Window_definition|GUIToolkitWML]] and must therefore contain at least the following children: '''[tooltip]''', '''[helptip]''', and '''[grid]'''. The [grid] must contain nested [row], [column] and [grid] tags which describe the layout of the window. (More information can be found in [[GUILayout]]; suffice to say that the basic structure is grid -> row -> column -> widget, where the widget is considered to be in a cell defined by the row and column of the grid. A list of widgets can be found at [[GUIWidgetInstanceWML]].)<br />
<br />
Two optional functions can be passed as second and third arguments; the first one is called once the dialog is created and before it is shown; the second one is called once the dialog is closed. These functions are helpful in setting the initial values of the fields and in recovering the final user values. These functions can call the [[#wesnoth.set_dialog_value]], [[#wesnoth.get_dialog_value]], and [[#wesnoth.set_dialog_callback]] functions for this purpose.<br />
<br />
This function should be called in conjunction with [[LuaWML:Misc#wesnoth.synchronize_choice|#wesnoth.synchronize_choice]], in order to ensure that only one client displays the dialog and that the other ones recover the same input values from this single client.<br />
<br />
The example below defines a dialog with a list and two buttons on the left, and a big image on the right. The ''preshow'' function fills the list and defines a callback on it. This ''select'' callback changes the displayed image whenever a new list item is selected. The ''postshow'' function recovers the selected item before the dialog is destroyed.<br />
<br />
<syntaxhighlight lang=lua><br />
local helper = wesnoth.require "lua/helper.lua"<br />
local T = wml.tag<br />
local _ = wesnoth.textdomain "wesnoth"<br />
<br />
local dialog = {<br />
T.tooltip { id = "tooltip_large" },<br />
T.helptip { id = "tooltip_large" },<br />
T.grid { T.row {<br />
T.column { T.grid {<br />
T.row { T.column { horizontal_grow = true, T.listbox { id = "the_list",<br />
T.list_definition { T.row { T.column { horizontal_grow = true,<br />
T.toggle_panel { return_value = -1, T.grid { T.row {<br />
T.column { horizontal_alignment = "left", T.label { id = "the_label" } },<br />
T.column { T.image { id = "the_icon" } }<br />
} } }<br />
} } }<br />
} } },<br />
T.row { T.column { T.grid { T.row {<br />
T.column { T.button { id = "ok", label = _"OK" } },<br />
T.column { T.button { id = "cancel", label = _"Cancel" } }<br />
} } } }<br />
} },<br />
T.column { T.image { id = "the_image" } }<br />
} }<br />
}<br />
<br />
local function preshow()<br />
local t = { "Ancient Lich", "Ancient Wose", "Elvish Avenger" }<br />
local function select()<br />
local i = wesnoth.get_dialog_value "the_list"<br />
local ut = wesnoth.unit_types[t[i]].__cfg<br />
wesnoth.set_dialog_value(string.gsub(ut.profile, "([^/]+)$", "transparent/%1"), "the_image")<br />
end<br />
wesnoth.set_dialog_callback(select, "the_list")<br />
for i,v in ipairs(t) do<br />
local ut = wesnoth.unit_types[v].__cfg<br />
wesnoth.set_dialog_value(ut.name, "the_list", i, "the_label")<br />
wesnoth.set_dialog_value(ut.image, "the_list", i, "the_icon")<br />
end<br />
wesnoth.set_dialog_value(2, "the_list")<br />
select()<br />
end<br />
<br />
local li<br />
local function postshow()<br />
li = wesnoth.get_dialog_value "the_list"<br />
end<br />
<br />
local r = wesnoth.show_dialog(dialog, preshow, postshow)<br />
wesnoth.message(string.format("Button %d pressed. Item %d selected.", r, li))<br />
</syntaxhighlight><br />
<br />
==== wesnoth.set_dialog_value ====<br />
<br />
* '''wesnoth.set_dialog_value(''value'', ''path, to, widget, id'')'''<br />
<br />
Sets the value of a widget on the current dialog. The value is given by the first argument; its semantic depends on the type of widget it is applied to. The last argument is the ''id'' of the widget. If it does not point to a unique widget in the dialog, some discriminating parents should be given on its left, making a path that is read from left to right by the engine. The row of a list is specified by giving the ''id' of the list as a first argument and the 1-based row number as the next argument.<br />
<br />
-- sets the value of a widget "bar" in the 7th row of the list "foo"<br />
wesnoth.set_dialog_value(_"Hello world", "foo", 7, "bar")<br />
<br />
Notes: When the row of a list does not exist, it is created. The value associated to a list is the selected row.<br />
<br />
==== wesnoth.get_dialog_value ====<br />
<br />
* '''wesnoth.get_dialog_value(''path, to, widget, id'')'''<br />
<br />
Gets the value of a widget on the current dialog. The arguments described the path for reaching the widget (see [[#wesnoth.set_dialog_value]]).<br />
<br />
{{DevFeature1.13|0}}<br />
For treeviews this function returns a table descibing the currently selected node.<br />
If for example in this treeview<br />
+Section1<br />
+Subsection11<br />
*Item1<br />
*Item2<br />
*Item3<br />
+Subsection12<br />
*Item4<br />
*Item5<br />
*Item6<br />
+Section2<br />
+Subsection21<br />
*Item7<br />
*Item8<br />
*Item9<br />
+Subsection22<br />
*Item10<br />
*Item11<br />
*Item12<br />
Item 9 is selcted the value will be {2,1,3}<br />
<br />
==== wesnoth.set_dialog_active ====<br />
<br />
* '''wesnoth.set_dialog_active(''active?'', ''path, to, widget, id'')'''<br />
<br />
Enables or disables a widget. The first argument is a boolean specifying whether the widget should be active (true) or inactive (false). The remaining arguments are the path to locate the widget in question (see [[#wesnoth.set_dialog_value]]).<br />
<br />
==== wesnoth.set_dialog_callback ====<br />
<br />
* '''wesnoth.set_dialog_callback(''callback_function'', ''path, to, widget, id'')'''<br />
<br />
Sets the first argument as a callback function for the widget obtained by following the path of the other arguments (see [[#wesnoth.set_dialog_value]]). This function will be called whenever the user modifies something about the widget, so that the dialog can react to it.<br />
<br />
==== wesnoth.set_dialog_markup ====<br />
<br />
* '''wesnoth.set_dialog_markup(''allowed?'', ''path, to, widget, id'')'''<br />
<br />
Sets the flag associated to a widget to enable or disable Pango markup. The new flag value is passed as the first argument (boolean), and the widget to modify is obtained by following the path of the other arguments (see [[#wesnoth.set_dialog_value]]). Most widgets start with Pango markup disabled unless this function is used to set their flag to true.<br />
<br />
wesnoth.set_dialog_markup(true, "notice_label")<br />
wesnoth.set_dialog_value("&lt;big&gt;NOTICE!&lt;/big&gt;", "notice_label")<br />
<br />
==== wesnoth.set_dialog_focus ====<br />
<br />
* '''wesnoth.set_dialog_focus(''focused?'', ''path, to, widget, id'')'''<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Switches the keyboard focus to the widget found following the given path (see [[#wesnoth.set_dialog_value]]). This is often useful for dialogs containing a central listbox, so that it can be controlled with the keyboard as soon as it is displayed.<br />
<br />
wesnoth.set_dialog_focus("my_listbox")<br />
<br />
==== wesnoth.set_dialog_visible ====<br />
<br />
* '''wesnoth.set_dialog_visible(''visible?'', ''path, to, widget, id'')'''<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Sets a widget's visibility status. The new status is passed as the first argument, and the path to the widget is specified by the remaining arguments (see [[#wesnoth.set_dialog_value]]). The following visibility statuses are recognized:<br />
<br />
{| clasS="wikitable"<br />
! String value !! Boolean shorthand !! Meaning<br />
|-<br />
| visible || true || The widget is visible and handles events.<br />
|-<br />
| hidden || || The widget is not visible, doesn't handle events, but still takes up space on the dialog grid.<br />
|-<br />
| invisible || false || The widget is not visible, doesn't handle events, and does not take up space on the dialog grid.<br />
|}<br />
<br />
wesnoth.set_dialog_visible(false, "secret_button")<br />
<br />
==== wesnoth.set_dialog_canvas ====<br />
<br />
* '''wesnoth.set_dialog_canvas(''index'', ''content'', ''path, to, widget, id'')'''<br />
<br />
Sets the WML passed as the second argument as the canvas content (index given by the first argument) of the widget obtained by following the path of the other arguments (see [[#wesnoth.set_dialog_value]]). The content of the WML table is described at [[GUICanvasWML]].<br />
<br />
-- draw two rectangles in the upper-left corner of the window (empty path = window widget)<br />
wesnoth.set_dialog_canvas(2, {<br />
T.rectangle { x = 20, y = 20, w = 20, h = 20, fill_color= "0,0,255,255" },<br />
T.rectangle { x = 30, y = 30, w = 20, h = 20, fill_color = "255,0,0,255" }<br />
})<br />
<br />
The meaning of the canvas index depends on the chosen widget. It may be the disabled / enabled states of the widget, or its background / foreground planes, or... For instance, overwriting canvas 1 of the window with an empty canvas causes the window to become transparent.<br />
<br />
==== wesnoth.add_dialog_tree_node ====<br />
<br />
* '''wesnoth.add_dialog_tree_node(''type'', ''index'', ''path, to, widget, id'')'''<br />
<br />
{{DevFeature1.13|0}}<br />
<br />
Adds a childnode to a treeview widget or a treeview node. The type (id of the node definition) of the node is passed in the first parameter. The second parameter (integer) spcifies where the node should be inserted in the parentnode. The other arguments describe the path of the parent treeview (-node)<br />
<br />
==== wesnoth.remove_dialog_item ====<br />
<br />
* '''wesnoth.remove_dialog_item(''index'', ''count'', ''path, to, widget, id'')'''<br />
<br />
{{DevFeature1.13|1}}<br />
<br />
Removes an item from a listbox, a multipage or a treeview. First parameter is the index of the item to delete, second parameter is the number of items to delete and the remaining parameters describe the path to the listbox, the multipage or the parent treview node.<br />
<br />
<br />
==== wesnoth.add_widget_definition====<br />
<br />
* '''wesnoth.add_widget_definition(''widget_type'', ''definition_id'', ''wml_content'')'''<br />
<br />
{{DevFeature1.13|?}}<br />
<br />
Creates a new wml widget definition see https://github.com/wesnoth/wesnoth/tree/1.14/data/gui/widget for examples wml_content<br />
<br />
==== wesnoth.is_skipping_messages ====<br />
<br />
* '''wesnoth.is_skipping_messages()'''<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Returns true if messages are currently being skipped, for example because the player has chosen to skip replay, or has pressed escape to dismiss a message.<br />
<br />
==== wesnoth.skip_messages ====<br />
<br />
* '''wesnoth.skip_messages([''skip?'')'''<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Sets the skip messages flag. By default it sets it to true, but you can also pass false to unset the flag.<br />
<br />
==== wesnoth.get_displayed_unit ====<br />
<br />
* '''wesnoth.get_displayed_unit()'''<br />
<br />
Returns a proxy to the unit currently displayed in the side pane of the user interface, if any.<br />
<br />
local name = tostring(wesnoth.get_displayed_unit().name)<br />
<br />
==== wesnoth.log ====<br />
<br />
* '''wesnoth.log([''logger''], ''message', ''in_chat'')'''<br />
<br />
{{DevFeature1.13|5}} Logs a message to the console. These messages are normally not visible unless Wesnoth is run from the command-line or (in Windows) with the --wconsole switch. The in_chat argument, however, can be set to true to also echo the message to the in-game chat area.<br />
<br />
Possible loggers are info, debug, warning, error, and wml. The wml logger is special and is intended for WML errors; it always goes to chat, so the in_chat argument is ignored and can be omitted. The default logger is info.<br />
<br />
==== wesnoth.theme_items ====<br />
<br />
This field is not a function but an associative table. It links item names to the functions that describe their content. These functions are called whenever the user interface is refreshed. The description of an item is a WML table containing '''[element]''' children. Each subtag shall contain either a '''text''' or an '''image''' field that is displayed to the user. It can also contain a '''tooltip''' field that is displayed to the user when moused over, and a "help" field that points to the help section that is displayed when the user clicks on the theme item.<br />
<br />
Note that the ''wesnoth.theme_items'' table is originally empty and using ''pairs'' or ''next'' on it will not return the items from the current theme. Its metatable ensures that the drawing functions of existing items can be recovered though, as long as their name is known. The example below shows how to modify the ''unit_status'' item to display a custom status:<br />
<br />
<syntaxhighlight lang=lua><br />
local old_unit_status = wesnoth.theme_items.unit_status<br />
function wesnoth.theme_items.unit_status()<br />
local _ = wesnoth.textdomain "mydomain"<br />
local u = wesnoth.get_displayed_unit()<br />
if not u then return {} end<br />
local s = old_unit_status()<br />
if u.status.entangled then<br />
table.insert(s, wml.tag.element {<br />
image = "entangled.png",<br />
tooltip = _"entangled: This unit is entangled. It cannot move but it can still attack."<br />
})<br />
end<br />
return s<br />
end<br />
</syntaxhighlight><br />
<br />
The things that would need to be to modified in the above code are:<br />
<br />
* the domain of your addon ("mydomain"), assuming that you are using translations. Otherwise just remove the underscore in the tooltip line.<br />
* the name of the status (u.status.entangled). Note that if the attribute happens to be inside [variables], so be it: u.variables.whatever.<br />
* the path to the image ("entangled.png").<br />
* the tooltip of the status ("entangled: This unit ...").<br />
<br />
The following is a list of valid entries in wesnoth.theme_items which will have an effect in the game. Unfortunately when this feature was created the full range of capabilities of the feature was never properly documented. The following list is automatically generated. To find out what each entry will do, you will have to make guesses and experiment, or read the source code at src/reports.cpp. If you find out what an entry does, you are more than welcome to edit the wiki and give a proper description to any of these fields.<br />
<br />
* '''unit_name'''<br />
* '''selected_unit_name'''<br />
* '''unit_type'''<br />
* '''selected_unit_type'''<br />
* '''unit_race'''<br />
* '''selected_unit_race'''<br />
* '''unit_side'''<br />
* '''selected_unit_side'''<br />
* '''unit_level'''<br />
* '''selected_unit_level'''<br />
* '''unit_amla'''<br />
* '''unit_traits'''<br />
* '''selected_unit_traits'''<br />
* '''unit_status'''<br />
* '''selected_unit_status'''<br />
* '''unit_alignment'''<br />
* '''selected_unit_alignment'''<br />
* '''unit_abilities'''<br />
* '''selected_unit_abilities'''<br />
* '''unit_hp'''<br />
* '''selected_unit_hp'''<br />
* '''unit_xp'''<br />
* '''selected_unit_xp'''<br />
* '''unit_advancement_options'''<br />
* '''selected_unit_advancement_options'''<br />
* '''unit_defense'''<br />
* '''selected_unit_defense'''<br />
* '''unit_vision'''<br />
* '''selected_unit_vision'''<br />
* '''unit_moves'''<br />
* '''selected_unit_moves'''<br />
* '''unit_weapons'''<br />
The default generator expresses each weapon line as a separate <code>element</code><br />
<syntaxhighlight lang=lua><br />
return { <br />
wml.tag.element { text = "weapon text",<br />
tooltip = _"weapon tooltip"<br />
}<br />
-- ...<br />
}<br />
</syntaxhighlight><br />
* '''highlighted_unit_weapons'''<br />
* '''selected_unit_weapons'''<br />
* '''unit_image'''<br />
* '''selected_unit_image'''<br />
* '''selected_unit_profile'''<br />
* '''unit_profile'''<br />
* '''tod_stats'''<br />
* '''time_of_day'''<br />
* '''unit_box'''<br />
* '''turn'''<br />
* '''gold'''<br />
* '''villages'''<br />
* '''num_units'''<br />
* '''upkeep'''<br />
* '''expenses'''<br />
* '''income'''<br />
* '''terrain_info'''<br />
* '''terrain'''<br />
** <nowiki>Text for terrain of the active hex. Same as the one displayed on the UI. It probably returns an empty table when no hex is active. Otherwise, it returns something like {{"element",{text="Grassland (Flat)"}}}.</nowiki><br />
* '''zoom_level'''<br />
* '''position'''<br />
* '''side_playing'''<br />
* '''observers'''<br />
** <nowiki>When there is no observer, it returns an empty table. When there are observers, it gives<br />
{{"element",<br />
{tooltip="Observers\n<observer1>\n<observer2>\n", image="misc/eye.png"}<br />
}}<br />
<br />
</nowiki><br />
* '''selected_terrain'''<br />
* '''edit_left_button_function'''<br />
* '''report_clock'''<br />
** <nowiki>wesnoth.theme_items.report_clock() gives a table {{"element", text=<time>}}, where <time> is HH:MM of local time. It probably return 12hr or 24hr formats depending on user preference. </nowiki><br />
* '''report_countdown'''<br />
** <nowiki>wesnoth.theme_items.report_countdown() gives a table {{"element", text=<time>}}, where <time> is MM:SS of time limit for player's turn. If turn limit < 120 or 60, add <span foreground="#c8c800"><br />
or <span foreground="#c80000"> html tags. </nowiki><br />
<br />
==== helper.get_user_choice ====<br />
<br />
* '''helper.get_user_choice(''message_table'', ''options'')'''<br />
<br />
Displays a WML message box querying a choice from the user. Attributes and options are taken from given tables (see [[InterfaceActionsWML#.5Bmessage.5D|[message]]]). The index of the selected option is returned.<br />
<br />
local result = helper.get_user_choice({ speaker = "narrator" }, { "Choice 1", "Choice 2" })<br />
<br />
[[Category: Lua Reference]]<br />
<br />
==== wesnoth.zoom ====<br />
<br />
{{DevFeature1.13|8}}<br />
<br />
* '''wesnoth.zoom(''factor''[, ''relative''])'''<br />
<br />
Changes the zoom level of the map. If relative is false, which is the default, it simply sets the zoom level. If relative is true, it zooms relative to the current zoom level. So, for example, if the zoom level is currently 0.5, then wesnoth.zoom(2) sets it to 2, while wesnoth.zoom(2, true) sets it to 1 (2 * 0.5).<br />
<br />
This function also returns the resulting zoom level. Because of this, you can call wesnoth.zoom(1) to simply get the current zoom level.<br />
<br />
Note that this function cannot zoom to a level that the user would not be able to reach from the UI. Attempting to do so will simply select the nearest allowed zoom level.</div>Edward Chernenkohttps://wiki.wesnoth.org/index.php?title=LuaWML/Variables&diff=60124LuaWML/Variables2018-12-29T16:36:44Z<p>Edward Chernenko: set_wml_tag_metatable is deprecated</p>
<hr />
<div>This page describes the [[LuaWML]] functions and helpers for handling WML variables and containers.<br />
<br />
==== wesnoth.get_variable ====<br />
<br />
* '''wesnoth.get_variable(''var_name'')'''<br />
<br />
Loads a WML variable with the given qualified name (argument 1) and converts it into a Lua object. Returns ''nil'' if the name does not point to anything, a scalar for a WML attribute, and a table for a WML object. The format of the table is described in [[LuaWML#Encoding WML objects into Lua tables]].<br />
<br />
<syntaxhighlight lang=lua><br />
wesnoth.fire("store_unit", { variable="my_unit", { "filter", { id="hero" } } })<br />
local heros_hp = wesnoth.get_variable("my_unit[0].hitpoints")<br />
wesnoth.message(string.format("The 'hero' unit has %d hitpoints.", heros_hp))<br />
</syntaxhighlight><br />
<br />
Argument 2, if ''true'', prevents the recursive conversion when the name points to an object; a fresh empty table is returned in this case. This is mainly used for writing proxy objects, e.g. in [[#helper.set_wml_var_metatable]].<br />
<br />
Note that, if the variable name happens to designate a sequence of WML objects, only the first one (index 0) is fetched. If all the WML objects with this name should have been returned, use [[#helper.get_variable_array]] instead.<br />
<br />
==== wesnoth.set_variable ====<br />
<br />
* '''wesnoth.set_variable(''var_name'', ''value'')'''<br />
<br />
Converts and stores a Lua object (argument 2) to a WML variable (argument 1). A WML object is created for a table, an attribute otherwise.<br />
<br />
<syntaxhighlight lang=lua><br />
wesnoth.set_variable("my_unit.hitpoints", heros_hp + 10)<br />
</syntaxhighlight><br />
<br />
Setting a WML variable to nil erases it.<br />
<br />
==== wesnoth.get_all_vars ====<br />
<br />
* '''wesnoth.get_all_vars()'''<br />
<br />
{{DevFeature1.13|0}} Returns all the WML variables currently set in form of a WML table. This function accepts no arguments.<br />
<br />
<syntaxhighlight lang=lua><br />
for key, value in pairs( wesnoth.get_all_vars() ) do<br />
if type( value ) == "table" then<br />
print( key, value[1], value[2] )<br />
else<br />
print( key, value )<br />
end<br />
end<br />
</syntaxhighlight><br />
<br />
==== wesnoth.wml_matches_filter ====<br />
<br />
* '''wesnoth.wml_matches_filter(''config'', ''filter'')'''<br />
<br />
Test if a config matches a WML filter (as <tt>[filter_wml]</tt>).<br />
<br />
==== helper.get_child ====<br />
<br />
* '''helper.get_child(''config'', ''child_tag_name'')'''<br />
<br />
Returns the first sub-tag of a WML object with the given name.<br />
<br />
<syntaxhighlight lang=lua><br />
local u = wesnoth.get_units({ id = "Delfador" })[1]<br />
local costs = helper.get_child(u.__cfg, "movement_costs")<br />
wesnoth.message(string.format("Delfador needs %d points to move through a forest.", costs.forest))<br />
</syntaxhighlight><br />
<br />
If a third parameter is passed, only children having a ''id'' attribute equal to it are considered.<br />
<br />
==== helper.get_nth_child ====<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
* '''helper.get_nth_child(''config'', ''child_tag_name'', ''n'')'''<br />
<br />
Returns the ''n''th sub-tag of a WML object with the given name.<br />
<br />
==== helper.child_count ====<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
* '''helper.child_count(''config'', ''child_tag_name'')<br />
<br />
Returns the number of children in the config with the given tag name.<br />
<br />
==== helper.child_range ====<br />
<br />
* '''helper.child_range(''config'', ''child_tag_name'')'''<br />
<br />
Returns an iterator over all the sub-tags of a WML object with the given name.<br />
<br />
<syntaxhighlight lang=lua><br />
local u = wesnoth.get_units({ id = "Delfador" })[1]<br />
for att in helper.child_range(u.__cfg, "attack") do<br />
wesnoth.message(tostring(att.description))<br />
end<br />
</syntaxhighlight><br />
<br />
==== helper.child_array ====<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
* '''helper.child_array(''config'', ''child_tag_name'')'''<br />
<br />
Like helper.child_range, but returns an array instead of an iterator. Useful if you need random access to the children.<br />
<br />
==== helper.get_variable_array ====<br />
<br />
* '''helper.get_variable_array(''var_name'')'''<br />
* {{DevFeature1.13|8}} '''helper.get_variable_array(''var_name'' [, ''context''])'''<br />
<br />
Fetches all the WML container variables with given name and returns a table containing them (starting at index 1). The context specifies where to get variables from. You can pass either a unit or a side as the context in order to get an array from the unit variables or side variables, respectively.<br />
<br />
<syntaxhighlight lang=lua><br />
function get_recall_list(side)<br />
wesnoth.fire("store_unit", { x = "recall", variable = "LUA_recall_list" })<br />
local l = get_variable_array "LUA_recall_list"<br />
wesnoth.set_variable "LUA_recall_list"<br />
return l<br />
end<br />
</syntaxhighlight><br />
<br />
==== helper.get_variable_proxy_array ====<br />
<br />
* '''helper.get_variable_proxy_array(''var_name'')'''<br />
<br />
Creates proxies for all the WML container variables with given name and returns a table containing them (starting at index 1). This function is similar to [[#helper.get_variable_array]], except that the proxies can be used for modifying WML containers.<br />
<br />
==== helper.set_variable_array ====<br />
<br />
* '''helper.set_variable_array(''varname'', ''array'')'''<br />
* {{DevFeature1.13|8}} '''helper.set_variable_array(''varname'', ''array'' [, ''context''])'''<br />
<br />
Creates WML container variables with given name from given table. The context specifies where to put the variables. You can pass either a unit or a side as the context in order to set an array in the unit variables or side variables, respectively.<br />
<br />
<syntaxhighlight lang=lua><br />
helper.set_variable_array("target", { {t=t1}, {t=t2}, {t=t3} })<br />
-- target[0].t <- t1; target[1].t <- t2; target[2].t <- t3<br />
</syntaxhighlight><br />
<br />
[[Category: Lua Reference]]</div>Edward Chernenkohttps://wiki.wesnoth.org/index.php?title=LuaWML/Units&diff=60123LuaWML/Units2018-12-29T00:49:25Z<p>Edward Chernenko: ... and it got replaced with normal id= of the unit</p>
<hr />
<div>This page describes the [[LuaWML]] functions for handling units.<br />
<br />
A unit is a proxy table with the following fields:<br />
* '''x''', '''y''': integers (read only, read/write if the unit is not on the map. {{DevFeature1.13|11}} These are now read/write under all circumstances, including for on-map units)<br />
* '''loc''': {{DevFeature1.13|11}} shortcut to get/set both x and y at once (read/write). Setting x and y individually would result in two moves, and there's the possibility that the intermediate move fails if the hex is occupied by another unit. In general, note that moving a unit by changing the proxy unit's coordinates does not work if the goal hex is occupied (it is not executed), so it is necessary to check if the hex is available first.<br />
* '''side''': integer (read/write)<br />
* '''id''': string (read only)<br />
* '''type''': string (read only)<br />
* '''name''': translatable string (read only)<br />
* '''cost''' {{DevFeature1.13|10}}: integer (read)<br />
* '''max_hitpoints''', '''max_experience''', '''max_moves''': integers (read only)<br />
* '''max_attacks''': integer (read only)<br />
* '''attacks_left''': integer (read/write) Setting below 0 is limited to 0.<br />
* '''extra_recruit''': table (read/write)<br />
* '''advances_to''': table (read/write)<br />
* '''hitpoints''', '''experience''': integer (read/write)<br />
* '''moves''': integer (read/write)<br />
* '''level''': {{DevFeature1.13|5}} integer (read/write)<br />
* '''resting''': boolean (read/write)<br />
* '''hidden''': boolean (read/write)<br />
* '''petrified''', '''canrecruit''': booleans (read only)<br />
* '''role''', '''facing''': strings (read/write)<br />
* '''status''': proxy associative table (read only, read/write fields), provides fields like [[SingleUnitWML#Unit_State|poisoned, slowed, petrified, uncovered, guardian, unhealable, invulnerable]]<br />
* '''image_mods''': string (read only)<br />
* '''upkeep''' {{DevFeature1.13|5}}: one of 'loyal', 'full' or a number (read/writre)<br />
* '''variables''': proxy associative table (read only, read/write fields, including ''variables.__cfg''), only toplevel named fields are proxied. {{DevFeature1.13|2}} subcontainers can be accessed by using the usual variable syntax: <syntaxhighlight inline lang='lua'>unit.variables["a.b.c[6].d"]</syntaxhighlight><br />
* '''attacks''': {{DevFeature1.13|0}}an object to access the units attacks, you can use the attacks index or the attacks name to index an attack. every attack has the following members:<br />
** '''description''': translatable string (read/write)<br />
** '''name''': string (read)<br />
** '''type''': string (read/write)<br />
** '''range''': string (read/write)<br />
** '''damage''': number(read/write)<br />
** '''number''': number(read/write)<br />
** '''movement_used''': number(read/write)<br />
** '''attack_weight''': number(read/write)<br />
** '''defense_weight''': number(read/write)<br />
** '''specials''' wml table(read/write)<br />
* '''valid''': string or nil (read only)<br />
* '''advancements''': {{DevFeature1.13|2}} an array of wml tables (read/write)<br />
* '''__cfg''': WML table (dump) ([[SingleUnitWML]])<br />
* {{DevFeature1.13|2}} The following fields are unit methods synonymous to one of the functions described on this page:<br />
** '''[[#wesnoth.match_unit|matches]]'''<br />
** '''[[#wesnoth.put_recall_unit|to_recall]]'''<br />
** '''[[#wesnoth.put_unit|to_map]]'''<br />
** '''[[#wesnoth.erase_unit|erase]]'''<br />
** '''[[#wesnoth.copy_unit|clone]]'''<br />
** '''[[#wesnoth.extract_unit|extract]]'''<br />
** '''[[#wesnoth.advance_unit|advance]]'''<br />
** '''[[#wesnoth.add_modification|add_modification]]'''<br />
** '''[[#wesnoth.remove_modifications|remove_modifications]]'''<br />
** '''[[#wesnoth.unit_resistance|resistance]]'''<br />
** '''[[#wesnoth.unit_defense|defense]]'''<br />
** '''[[#wesnoth.unit_movement_cost|movement]]'''<br />
** '''[[#wesnoth.unit_vision_cost|vision]]'''<br />
** '''[[#wesnoth.unit_jamming_cost|jamming]]'''<br />
** '''[[#wesnoth.unit_ability|ability]]'''<br />
** '''[[#wesnoth.transform_unit|transform]]'''<br />
The metatable of these proxy tables appears as '''"unit"'''.<br />
<br />
A unit can be either visible on the map ([[#wesnoth.get_units]], [[#wesnoth.put_unit]]), or on a recall list ([[#wesnoth.get_recall_units]], [[#wesnoth.put_recall_unit]]), or private to the Lua code ([[#wesnoth.create_unit]], [[#wesnoth.copy_unit]], [[#wesnoth.extract_unit]]). The Lua code has complete control over the private units; they will not be modified unless accessed through the proxy unit. Units on the map and on the recall lists, however, can be modified by the user, the engine, WML, independently of the Lua code. In particular, if a unit is killed, any further use of the proxy unit will cause an error. For units on the map, the proxy unit is valid as long as there is a unit on the map that has the same "underlying_id" WML field as the original one. The behavior is similar for units on the recall lists. The ''valid'' field reflects the unit availability by returning '''"map"''', '''"recall"''', '''"private"''', or ''nil''. The latter value is used for units that were removed (e.g. killed). In that case, the ''valid'' field is the only one that can be read without causing an error.<br />
<br />
The term "proxy", here in particular "proxy unit", means that the variable retrieved in the lua code (with get_units for example) is an accessor (reference) to the C++ object which represents that unit. This is very different from unit variables obtained by [store_unit] in wml. The fields marked as "writable" above can be modified without the need to use put_unit afterwards. This same reason explains that modifications to the unit from outside the lua code (like [kill] invalidating the proxy unit) have immediate effect on the lua code's proxy unit variable (with the exception of private proxy units).<br />
<br />
<br />
==== wesnoth.get_units ====<br />
<br />
* '''wesnoth.get_units(''filter'')'''<br />
* {{DevFeature1.13|12}} '''wesnoth.get_units(''filter'', ''fake_location'')'''<br />
* {{DevFeature1.13|12}} '''wesnoth.get_units(''filter'', ''other_unit'')'''<br />
<br />
Returns an array of all the units on the map matching the WML filter passed as the first argument. See [[StandardUnitFilter]] for details about filters. If a second unit is passed, it can be referenced via the $other_unit variable in the main filter as well as via the "other" variable in WFL formulas used in the main filter. If a location is passed, the filter is run as if the unit were at that location (rather than its real location). This affects things such as [filter_adjacent] and ability_active, and should work even for a unit on the recall list.<br />
<br />
<syntaxhighlight lang='lua'><br />
local leaders_on_side_two = wesnoth.get_units { side = 2, canrecruit = true }<br />
local name_of_leader = leaders_on_side_two[1].name<br />
</syntaxhighlight><br />
<br />
==== wesnoth.get_unit ====<br />
<br />
* '''wesnoth.get_unit(''x'', ''y'')'''<br />
* '''wesnoth.get_unit(''id'')'''<br />
<br />
Returns the unit at the given location or with the given underlying ID.<br />
<br />
<syntaxhighlight lang='lua'><br />
local args = ...<br />
local unit = wesnoth.get_unit(args.x1, args.y1)<br />
</syntaxhighlight><br />
<br />
==== wesnoth.match_unit ====<br />
<br />
* '''wesnoth.match_unit(''unit'', ''filter'')'''<br />
* {{DevFeature1.13|2}} '''wesnoth.match_unit(''unit'', ''filter'', ''other_unit'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':matches(''filter'', [''other_unit''])'''<br />
* {{DevFeature1.13|2}} '''wesnoth.match_unit(''unit'', ''filter'', ''location'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':matches(''filter'', [''location''])'''<br />
<br />
Returns true if the given unit matches the WML filter passed as the second argument. If ''other_unit'' is specified, it is used for the ''$other_unit'' auto-stored variable in the filter. Otherwise, this variable is not stored for the filter. If an extra ''location'' is specified, the filter matches as if the unit were at that location.<br />
<br />
<syntaxhighlight lang='lua'><br />
assert(unit.canrecruit == wesnoth.match_unit(unit, { canrecruit = true }))<br />
</syntaxhighlight><br />
<br />
==== wesnoth.put_unit ====<br />
<br />
* '''wesnoth.put_unit(''unit'')'''<br />
* '''wesnoth.put_unit(''x'', ''y'', ''unit'')'''<br />
* '''wesnoth.put_unit(''x'', ''y'')'''<br />
* {{DevFeature1.13|2}} '''wesnoth.put_unit(''unit'', ''x'', ''y'')''' -- The above two forms are also deprecated.<br />
* {{DevFeature1.13|2}} '''''unit'':to_map([''x'', ''y''])<br />
<br />
Places a unit on the map. This unit is described either by a WML table or by a proxy unit. Coordinates can be passed as the first two arguments, otherwise the table is expected to have two fields '''x''' and '''y''', which indicate where the unit will be placed. If the function is called with coordinates only, the unit on the map at the given coordinates is removed instead. {{DevFeature1.13|2}} This use is now deprecated; use wesnoth.erase_unit instead.<br />
<br />
<syntaxhighlight lang='lua'><br />
-- create a unit with random traits, then erase it<br />
wesnoth.put_unit(17, 42, { type = "Elvish Lady" })<br />
wesnoth.put_unit(17, 42)<br />
</syntaxhighlight><br />
<br />
When the argument is a proxy unit, no duplicate is created. In particular, if the unit was private or on a recall list, it no longer is; and if the unit was on the map, it has been moved to the new location. Note: passing a WML table is just a shortcut for calling [[#wesnoth.create_unit]] and then putting the resulting unit on the map.<br />
<br />
<syntaxhighlight lang='lua'><br />
-- move the leader back to the top-left corner<br />
wesnoth.put_unit(1, 1, wesnoth.get_units({ canrecruit = true })[1])<br />
</syntaxhighlight><br />
<br />
==== wesnoth.erase_unit ====<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
* '''wesnoth.erase_unit(''unit'')'''<br />
* '''wesnoth.erase_unit(''x'', ''y'')'''<br />
* '''''unit'':erase()'''<br />
<br />
Erases a unit from the map. After calling this on a unit, the unit is no longer valid.<br />
<br />
==== wesnoth.get_recall_units ====<br />
<br />
* '''wesnoth.get_recall_units()'''<br />
<br />
Returns an array of all the units on the recall lists matching the WML filter passed as the first argument.<br />
<br />
==== wesnoth.put_recall_unit ====<br />
<br />
* '''wesnoth.put_recall_unit(''unit'', [''side''])'''<br />
* {{DevFeature1.13|2}} '''''unit'':to_recall([''side''])'''<br />
<br />
Places a unit on a recall list. This unit is described either by a WML table or by a proxy unit. The side of the recall list is given by the second argument, or by the side of the unit if missing.<br />
<br />
<syntaxhighlight lang='lua'><br />
-- put the unit at location 17,42 on the recall list for side 2<br />
wesnoth.put_recall_unit(wesnoth.get_units({ x= 17, y = 42 })[1], 2)<br />
</syntaxhighlight><br />
<br />
When the argument is a proxy unit, no duplicate is created. In particular, if the unit was private or on the map, it no longer is. Note: passing a WML table is just a shortcut for calling [[#wesnoth.create_unit]] and then putting the resulting unit on a recall list.<br />
<br />
==== wesnoth.create_unit ====<br />
<br />
* '''wesnoth.create_unit(''unit_info'')'''<br />
<br />
Creates a private unit from a WML table.<br />
<br />
<syntaxhighlight lang='lua'><br />
local u = wesnoth.create_unit { type = "White Mage", gender = "female" }<br />
</syntaxhighlight><br />
<br />
==== wesnoth.copy_unit ====<br />
<br />
* '''wesnoth.copy_unit(''unit'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':clone()'''<br />
<br />
Creates a private unit from another unit.<br />
<br />
<syntaxhighlight lang='lua'><br />
-- extract a unit from the map<br />
local u = wesnoth.copy_unit(wesnoth.get_units({ type = "Thug" })[1])<br />
wesnoth.erase_unit(u.x, u.y)<br />
-- u is still valid at this point<br />
</syntaxhighlight><br />
<br />
==== wesnoth.extract_unit ====<br />
<br />
* '''wesnoth.extract_unit(''unit'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':extract()'''<br />
<br />
Removes a unit from the map or from a recall list and makes it private.<br />
<br />
<syntaxhighlight lang='lua'><br />
-- remove all the units from the recall list of side 1 and put them in a WML container<br />
local l = {}<br />
for i,u in ipairs(wesnoth.get_recall_units { side = 1 }) do<br />
wesnoth.extract_unit(u)<br />
table.insert(l, u.__cfg)<br />
end<br />
helper.set_variable_array("player_recall_list", l)<br />
</syntaxhighlight><br />
<br />
Note: if the unit is on the map, it is just a shortcut for calling [[#wesnoth.copy_unit]] and then [[#wesnoth.put_unit]] without a unit. It is, however, the only way for removing a unit from a recall list without putting it on the map.<br />
<br />
<br />
==== wesnoth.advance_unit ====<br />
<br />
* '''wesnoth.advance_unit(''unit'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':advance()'''<br />
<br />
{{DevFeature1.13|0}} Advances the unit (and shows the advance unit dialog if needed) if the unit has enough xp. This function should be called after modifying the units experience directly. A similar function is called by wesnoth internally after unit combat. The second argument is a boodean value that specifies whether the advancement should be animated. The third agrument is a boodean value that specifies whether advancement related events should be fired.<br />
<br />
<br />
This function only works for units on the map.<br />
<br />
This function can also trigger multiple advancements if the unit has enough xp.<br />
<br />
==== wesnoth.add_modification ====<br />
<br />
* '''wesnoth.add_modification(''unit'', ''type'', ''effects'', [''write_to_mods''])'''<br />
* {{DevFeature1.13|2}} '''''unit'':add_modification(''type'', ''effects'', [''write_to_mods''])'''<br />
<br />
Modifies a given unit. It needs to be a proxy unit. The second argument is the type of the modification (one of "trait", "object", or "advance"). The option "advance" applies effects as if the unit would advance (e.g. AMLA effects). The third argument is a WML table describing the effect, so mostly containing '''[effect]''' children. See [[EffectWML]] for details about effects.<br />
<br />
{{DevFeature1.13|2}} In 1.13.2 and later, the "advance" type is replaced with "advancement", to match the equivalent tag in [[UnitTypeWML|[unit_type]]]. Also, it takes a fourth argument which, if false, causes it to not write the modification tag to the unit's [modifications] (as would be done with an [object] with no_write=true).<br />
<br />
<syntaxhighlight lang='lua'><br />
local T = wml.tags<br />
local u = wesnoth.get_units { canrecruit = true }[1]<br />
local effects = {<br />
id = "my_effect_id",<br />
T.effect { <br />
apply_to = "image_mod", <br />
replace = "RC(red>blue)" <br />
},<br />
T.effect {<br />
apply_to = "new_animation",<br />
T.standing_animation {<br />
-- AnimationWML<br />
}<br />
}<br />
} <br />
wesnoth.add_modification(u, "object", effects)<br />
</syntaxhighlight><br />
<br />
==== wesnoth.remove_modifications ====<br />
<br />
* {{DevFeature1.13|?}} '''wesnoth.remove_modifications(''unit'', ''cfg'' [, ''type''])'''<br />
* {{DevFeature1.13|?}} '''''unit'':remove_modifications(''cfg'' [, ''type''])'''<br />
<br />
Modifies a given unit. The unit needs to be a proxy unit. The second argument is a filter for the modifications to remove. It takes the same syntax as [[FilterWML#Filtering_on_WML_data|[filter_wml]]]; all matching modifications will be removed. The third argument is the type (tag name) of the modifications to search for; it defaults to <tt>"object"</tt>, but you can also pass <tt>"trait"</tt> or <tt>"advancement"</tt>.<br />
<br />
<syntaxhighlight lang='lua'><br />
local u = wesnoth.get_units { canrecruit = true }[1]<br />
wesnoth.remove_modifications(u, { id = "my_effect_id" })<br />
</syntaxhighlight><br />
<br />
==== wesnoth.unit_resistance ====<br />
<br />
* '''wesnoth.unit_resistance(''unit'', ''damage_type'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':resistance(''damage_type'')'''<br />
<br />
Returns the resistance of a unit against an attack type. (Note: it is a WML resistance. So the higher it is, the weaker the unit is.) The third argument indicates whether the unit is the attacker. Last arguments are the coordinates of an optional map location (for the purpose of taking abilities into account).<br />
<br />
<syntaxhighlight lang='lua'><br />
local fire_resistance = 100 - wesnoth.unit_resistance(u, "fire")<br />
</syntaxhighlight><br />
<br />
==== wesnoth.unit_defense ====<br />
<br />
* '''wesnoth.unit_defense(''unit'', ''terrain_code'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':defense(''terrain_code'')'''<br />
<br />
Returns the defense of a unit on a particular terrain. (Note: it is a WML defense. So the higher it is, the weaker the unit is.)<br />
<br />
<syntaxhighlight lang='lua'><br />
local flat_defense = 100 - wesnoth.unit_defense(u, "Gt")<br />
</syntaxhighlight><br />
<br />
==== wesnoth.unit_movement_cost ====<br />
<br />
* '''wesnoth.unit_movement_cost(''unit'', ''terrain_code'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':movement(''terrain_code'')'''<br />
<br />
Returns the movement cost of a unit on a particular terrain.<br />
<br />
<syntaxhighlight lang='lua'><br />
local move_cost = wesnoth.unit_movement_cost(u, "Gt")<br />
<syntaxhighlight><br />
<br />
==== wesnoth.unit_vision_cost ====<br />
<br />
* '''wesnoth.unit_vision_cost(''unit'', ''terrain_code'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':vision(''terrain_code'')'''<br />
<br />
Returns the vision cost of a unit on a particular terrain.<br />
<br />
<syntaxhighlight lang='lua'><br />
local see_cost = wesnoth.unit_vision_cost(u, "Gt")<br />
</syntaxhighlight><br />
<br />
==== wesnoth.unit_jamming_cost ====<br />
<br />
* '''wesnoth.unit_jamming_cost(''unit'', ''terrain_code'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':jamming(''terrain_code'')'''<br />
<br />
Returns the jamming cost of a unit on a particular terrain.<br />
<br />
<syntaxhighlight lang='lua'><br />
local jam_cost = wesnoth.unit_jamming_cost(u, "Gt")<br />
</syntaxhighlight><br />
<br />
==== wesnoth.unit_ability ====<br />
<br />
* '''wesnoth.unit_ability(''unit'', ''ability_tag'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':ability(''ability_tag'')'''<br />
<br />
Returns true if the unit is currently under effect by an ability with this given TAG NAME. This means that the ability could be owned by the unit itself, or by an adjacent unit.<br />
<br />
<syntaxhighlight lang='lua'><br />
function has_teleport(u)<br />
return wesnoth.unit_ability(u, "teleport")<br />
end<br />
</syntaxhighlight><br />
<br />
==== wesnoth.unit_types ====<br />
<br />
This is not a function but a read-only table indexed by unit type ids. Its elements are proxy tables with these fields:<br />
<br />
* '''id''': string<br />
* '''name''': translatable string (read only)<br />
* '''max_moves''', '''max_experience''', '''max_hitpoints''', '''level''', '''cost''': integers (read only)<br />
* '''abilities''': array of ability keys (strings), e.g. {"curing", "regenerates"}<br />
* {{DevFeature1.13|11}} '''advances_to''': array of unit types to which unit can advance<br />
* {{DevFeature1.13|11}} '''advances_from''': array of unit types from which unit can advance. Note: this is OOS-unsafe in Multiplayer games. Different clients may have additional Era-s with units upgradable to this unit type.<br />
* '''__cfg''': WML table (dump), see [[UnitTypeWML]]<br />
<br />
The metatable of these proxy tables appears as '''"unit type"'''.<br />
<br />
<syntaxhighlight lang='lua'><br />
local lich_cost = wesnoth.unit_types["Ancient Lich"].cost<br />
</syntaxhighlight><br />
<br />
Note that different clients have different set of available units in a Multiplayer game. It is OOS-unsafe to e.g. count the number of units.<br />
Presuming correctly written add-ons, it is still safe to e.g. access any given unit or its properties.<br />
<br />
==== wesnoth.races ====<br />
<br />
This is not a function but a table indexed by race ids. Its elements are proxy tables for all races the engine knows about.<br />
known fields of each element:<br />
* '''id''': string<br />
* '''description''', '''name''', '''plural_name''' (translatable strings)<br />
* '''num_traits''' (integer)<br />
* '''ignore_global_traits''' (boolean)<br />
* '''undead_variation''' (string)<br />
(all read only)<br />
* '''__cfg''': WML table (dump)<br />
<br />
<syntaxhighlight lang='lua'><br />
wesnoth.message(tostring(wesnoth.races["lizard"].name))<br />
</syntaxhighlight><br />
<br />
==== wesnoth.get_traits ====<br />
<br />
* '''wesnoth.get_traits()'''<br />
<br />
Returns a table with named fields (trait id strings) holding the wml tables defining the traits. arguments: none. All global traits the engine knows about, race-specific traits are not included.<br />
Known fields and subtags of each element are the ones which were given in the wml definition of the [[SingleUnitWML|trait]].<br />
wesnoth.message(tostring(wesnoth.get_traits().strong.male_name))<br />
<br />
==== wesnoth.simulate_combat ====<br />
<br />
* '''wesnoth.simulate_combat(''attacker'', [''attacker_weapon_index''], ''defender'', [''defender_weapon_index''])'''<br />
<br />
Computes the hitpoint distribution and status chance after a combat between two units. The first unit is the attacker; it does not have to be on the map, though its location should be meaningful. The second unit is the defender; it has to be on the map.<br />
<br />
Optional integers can be passed after each unit to select a particular weapon, otherwise the "best" one is selected. When giving the weapon, the parameter is the weapon number (integer, starting at 1) and not an element from the table returned by helper.child_range(att, "attack").<br />
<br />
<syntaxhighlight lang='lua'><br />
local function display_stats(n, t)<br />
wesnoth.message(string.format(<br />
"Chance for the %s\n to be slowed: %f,\n to be poisoned: %f,\n to die: %f.\nAverage HP: %f.",<br />
n, t.slowed, t.poisoned, t.hp_chance[0], t.average_hp))<br />
end<br />
local att_stats, def_stats = wesnoth.simulate_combat(att, att_weapon, def, def_weapon)<br />
display_stats("attacker", att_stats)<br />
display_stats("defender", def_stats)<br />
</syntaxhighlight><br />
<br />
Returns 2 additional tables which contain information about the weapons and the effect of single hits with these keys: num_blows, damage, chance_to_hit, poisons, slows, petrifies, plagues, plague_type, backstabs, rounds, firststrike, drains, drain_constant, drain_percent, attack_num, name. <br />
Name is the wml name not the description. If there is no weapon, then name will be nil<br />
<br />
<syntaxhighlight lang='lua'><br />
local att_stats, def_stats, att_weapon, def_weapon = wesnoth.simulate_combat(attacker, att_weapon_number, defender)<br />
wesnoth.message(string.format(<br />
"The attack %s should be countered with %s, which does %d damage, has %d%% chance to hit and forces %d attack rounds due to its berserk ability.",<br />
att_weapon.name, def_weapon.name or "no weapon", def_weapon.damage, def_weapon.chance_to_hit, def_weapon.rounds))<br />
</syntaxhighlight><br />
<br />
==== wesnoth.transform_unit ====<br />
<br />
* '''wesnoth.transform_unit(''unit'', ''to_type'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':transform(''to_type'')'''<br />
<br />
Changes the type of a unit and adjust attributes accordingly. Note that hit points are only changed if necessary to accommodate the new maximum hit points. Poison is automatically removed if the transformed unit is immune.<br />
<br />
<syntaxhighlight lang='lua'><br />
local ev = wesnoth.current.event_context<br />
local u = wesnoth.get_units{x=ev.x1, y=ev.y1}[1]<br />
wesnoth.transform_unit(u, "Spearman")<br />
-- If a full heal is desired:<br />
u.hitpoints = u.max_hitpoints<br />
u.status.poisoned = false<br />
</syntaxhighlight><br />
<br />
==== wesnoth.add_known_unit ====<br />
<br />
* {{DevFeature1.13|10}} '''wesnoth.add_known_unit(''unit_type_id'')'''<br />
<br />
adds the unit type with the given id to the list of known units (so that they appear in the help)<br />
<br />
==== wesnoth.create_animator ====<br />
<br />
{{DevFeature1.13|7}}<br />
<br />
* '''wesnoth.create_animator()'''<br />
<br />
Returns an object that can be used to set up and run an animation. The object has three methods:<br />
<br />
* '''animator:run()'''<br />
<br />
Runs the animation. {{DevFeature1.15|0}} Implicitly clears the animator.<br />
<br />
* '''animator:clear()'''<br />
<br />
Clears any units previously added to the animation.<br />
<br />
* '''animator:add(''unit'', ''flag'', ''hits'', ''params'')'''<br />
<br />
Adds a unit to the animation. The ''flag'' specifies which animation to play, and the ''hits'' parameter is required for attack animations to specify which variant of the animation to play. Possibly keys in ''params'' are:<br />
<br />
* '''facing''': A location. The animation will be played with the unit facing that location.<br />
* '''value''': Either a number or a list of two numbers. Use this to pass ''value'' and/or ''value_second'' to default animations that use them.<br />
* '''with_bars''': Whether to show HP bars and such while the animation plays.<br />
* '''text''': Text to float as the animation plays.<br />
* '''color''': Color of the floating text - a list of red, green, blue.<br />
* '''primary''': The primary weapon to use for the animation. Must be a Lua unit attack proxy.<br />
* '''secondary''': The secondary weapon to use for the animation.<br />
<br />
Normal usage would be to create it, call '''add''' one or more times, then call '''run'''.<br />
<br />
==== wesnoth.effects ====<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
This table contains the implementation of custom [[EffectWML|[effect]]]s. Each value is a function that takes a unit and the effect config. Note that the default effects defined by the Wesnoth engine are not in this table. <br />
<br />
<syntaxhighlight lang='lua'><br />
function wesnoth.effects.min_resistance(u, cfg)<br />
local resistance_new = {}<br />
local resistance_old = helper.parsed(helper.get_child(cfg, "resistance"))<br />
for k,v in pairs(resistance_old) do<br />
if type(k) == "string" and type(v) == "number" and wesnoth.unit_resistance(u, k) >= v then<br />
resistance_new[k] = v<br />
end<br />
end<br />
--important: use wesnoth.add_modification(..., false) so that the function will only execute the effects of that object and not store the object in the unit.<br />
wesnoth.add_modification(u, "object", {<br />
T.effect {<br />
apply_to = "resistance",<br />
replace = true,<br />
T.resistance (resistance_new),<br />
},<br />
}, false)<br />
end<br />
</syntaxhighlight><br />
<br />
The code above adds a new <code>min_resistance</code> effect that will set the resistances to specific values if they are currently below that value. It can then be used like this (for example, in [[DirectActionsWML#.5Bobject.5D|[object]]]):<br />
<br />
<syntaxhighlight lang='wml'><br />
[effect]<br />
apply_to=min_resistance<br />
[resistance]<br />
cold=50<br />
[/resistance]<br />
[/effect]<br />
</syntaxhighlight><br />
<br />
Note that because currently all Lua code is executed after [unit]s in [side] are created, it is currently not possible to use these effects in [unit]s in [side]<br />
<br />
{{DevFeature1.13|5}}<br />
<br />
Built-in effects are now present in the <code>wesnoth.effects</code> table and can be called by custom effects or by other Lua code. They take the same two arguments that a custom effect function does - the unit, and the effect WML.<br />
<br />
In addition, you can now specify description modifiers to be used if a custom effect is placed in a <code>[trait]</code> tag. Instead of setting a function as the effect, you set a table with a <code>__call</code> metafunction which does what the function would have done. The table can then have an additional <code>__descr</code> metafunction which updates descriptions as necessary. The built-in effects all use this structure. This metafunction takes the same arguments as the regular effect function, but should not modify the unit. Instead, it returns a string to be appended to the trait's effect description.<br />
<br />
[[Category: Lua Reference]]</div>Edward Chernenkohttps://wiki.wesnoth.org/index.php?title=LuaWML/Units&diff=60122LuaWML/Units2018-12-29T00:47:49Z<p>Edward Chernenko: was removed in 1.13.2</p>
<hr />
<div>This page describes the [[LuaWML]] functions for handling units.<br />
<br />
A unit is a proxy table with the following fields:<br />
* '''x''', '''y''': integers (read only, read/write if the unit is not on the map. {{DevFeature1.13|11}} These are now read/write under all circumstances, including for on-map units)<br />
* '''loc''': {{DevFeature1.13|11}} shortcut to get/set both x and y at once (read/write). Setting x and y individually would result in two moves, and there's the possibility that the intermediate move fails if the hex is occupied by another unit. In general, note that moving a unit by changing the proxy unit's coordinates does not work if the goal hex is occupied (it is not executed), so it is necessary to check if the hex is available first.<br />
* '''side''': integer (read/write)<br />
* '''id''': string (read only)<br />
* '''type''': string (read only)<br />
* '''name''': translatable string (read only)<br />
* '''cost''' {{DevFeature1.13|10}}: integer (read)<br />
* '''max_hitpoints''', '''max_experience''', '''max_moves''': integers (read only)<br />
* '''max_attacks''': integer (read only)<br />
* '''attacks_left''': integer (read/write) Setting below 0 is limited to 0.<br />
* '''extra_recruit''': table (read/write)<br />
* '''advances_to''': table (read/write)<br />
* '''hitpoints''', '''experience''': integer (read/write)<br />
* '''moves''': integer (read/write)<br />
* '''level''': {{DevFeature1.13|5}} integer (read/write)<br />
* '''resting''': boolean (read/write)<br />
* '''hidden''': boolean (read/write)<br />
* '''petrified''', '''canrecruit''': booleans (read only)<br />
* '''role''', '''facing''': strings (read/write)<br />
* '''status''': proxy associative table (read only, read/write fields), provides fields like [[SingleUnitWML#Unit_State|poisoned, slowed, petrified, uncovered, guardian, unhealable, invulnerable]]<br />
* '''image_mods''': string (read only)<br />
* '''upkeep''' {{DevFeature1.13|5}}: one of 'loyal', 'full' or a number (read/writre)<br />
* '''variables''': proxy associative table (read only, read/write fields, including ''variables.__cfg''), only toplevel named fields are proxied. {{DevFeature1.13|2}} subcontainers can be accessed by using the usual variable syntax: <syntaxhighlight inline lang='lua'>unit.variables["a.b.c[6].d"]</syntaxhighlight><br />
* '''attacks''': {{DevFeature1.13|0}}an object to access the units attacks, you can use the attacks index or the attacks name to index an attack. every attack has the following members:<br />
** '''description''': translatable string (read/write)<br />
** '''name''': string (read)<br />
** '''type''': string (read/write)<br />
** '''range''': string (read/write)<br />
** '''damage''': number(read/write)<br />
** '''number''': number(read/write)<br />
** '''movement_used''': number(read/write)<br />
** '''attack_weight''': number(read/write)<br />
** '''defense_weight''': number(read/write)<br />
** '''specials''' wml table(read/write)<br />
* '''valid''': string or nil (read only)<br />
* '''advancements''': {{DevFeature1.13|2}} an array of wml tables (read/write)<br />
* '''__cfg''': WML table (dump) ([[SingleUnitWML]])<br />
* {{DevFeature1.13|2}} The following fields are unit methods synonymous to one of the functions described on this page:<br />
** '''[[#wesnoth.match_unit|matches]]'''<br />
** '''[[#wesnoth.put_recall_unit|to_recall]]'''<br />
** '''[[#wesnoth.put_unit|to_map]]'''<br />
** '''[[#wesnoth.erase_unit|erase]]'''<br />
** '''[[#wesnoth.copy_unit|clone]]'''<br />
** '''[[#wesnoth.extract_unit|extract]]'''<br />
** '''[[#wesnoth.advance_unit|advance]]'''<br />
** '''[[#wesnoth.add_modification|add_modification]]'''<br />
** '''[[#wesnoth.remove_modifications|remove_modifications]]'''<br />
** '''[[#wesnoth.unit_resistance|resistance]]'''<br />
** '''[[#wesnoth.unit_defense|defense]]'''<br />
** '''[[#wesnoth.unit_movement_cost|movement]]'''<br />
** '''[[#wesnoth.unit_vision_cost|vision]]'''<br />
** '''[[#wesnoth.unit_jamming_cost|jamming]]'''<br />
** '''[[#wesnoth.unit_ability|ability]]'''<br />
** '''[[#wesnoth.transform_unit|transform]]'''<br />
The metatable of these proxy tables appears as '''"unit"'''.<br />
<br />
A unit can be either visible on the map ([[#wesnoth.get_units]], [[#wesnoth.put_unit]]), or on a recall list ([[#wesnoth.get_recall_units]], [[#wesnoth.put_recall_unit]]), or private to the Lua code ([[#wesnoth.create_unit]], [[#wesnoth.copy_unit]], [[#wesnoth.extract_unit]]). The Lua code has complete control over the private units; they will not be modified unless accessed through the proxy unit. Units on the map and on the recall lists, however, can be modified by the user, the engine, WML, independently of the Lua code. In particular, if a unit is killed, any further use of the proxy unit will cause an error. For units on the map, the proxy unit is valid as long as there is a unit on the map that has the same "underlying_id" WML field as the original one. The behavior is similar for units on the recall lists. The ''valid'' field reflects the unit availability by returning '''"map"''', '''"recall"''', '''"private"''', or ''nil''. The latter value is used for units that were removed (e.g. killed). In that case, the ''valid'' field is the only one that can be read without causing an error.<br />
<br />
The term "proxy", here in particular "proxy unit", means that the variable retrieved in the lua code (with get_units for example) is an accessor (reference) to the C++ object which represents that unit. This is very different from unit variables obtained by [store_unit] in wml. The fields marked as "writable" above can be modified without the need to use put_unit afterwards. This same reason explains that modifications to the unit from outside the lua code (like [kill] invalidating the proxy unit) have immediate effect on the lua code's proxy unit variable (with the exception of private proxy units).<br />
<br />
<br />
==== wesnoth.get_units ====<br />
<br />
* '''wesnoth.get_units(''filter'')'''<br />
* {{DevFeature1.13|12}} '''wesnoth.get_units(''filter'', ''fake_location'')'''<br />
* {{DevFeature1.13|12}} '''wesnoth.get_units(''filter'', ''other_unit'')'''<br />
<br />
Returns an array of all the units on the map matching the WML filter passed as the first argument. See [[StandardUnitFilter]] for details about filters. If a second unit is passed, it can be referenced via the $other_unit variable in the main filter as well as via the "other" variable in WFL formulas used in the main filter. If a location is passed, the filter is run as if the unit were at that location (rather than its real location). This affects things such as [filter_adjacent] and ability_active, and should work even for a unit on the recall list.<br />
<br />
<syntaxhighlight lang='lua'><br />
local leaders_on_side_two = wesnoth.get_units { side = 2, canrecruit = true }<br />
local name_of_leader = leaders_on_side_two[1].name<br />
</syntaxhighlight><br />
<br />
==== wesnoth.get_unit ====<br />
<br />
* '''wesnoth.get_unit(''x'', ''y'')'''<br />
<br />
Returns the unit at the given location or with the given underlying ID.<br />
<br />
<syntaxhighlight lang='lua'><br />
local args = ...<br />
local unit = wesnoth.get_unit(args.x1, args.y1)<br />
</syntaxhighlight><br />
<br />
==== wesnoth.match_unit ====<br />
<br />
* '''wesnoth.match_unit(''unit'', ''filter'')'''<br />
* {{DevFeature1.13|2}} '''wesnoth.match_unit(''unit'', ''filter'', ''other_unit'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':matches(''filter'', [''other_unit''])'''<br />
* {{DevFeature1.13|2}} '''wesnoth.match_unit(''unit'', ''filter'', ''location'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':matches(''filter'', [''location''])'''<br />
<br />
Returns true if the given unit matches the WML filter passed as the second argument. If ''other_unit'' is specified, it is used for the ''$other_unit'' auto-stored variable in the filter. Otherwise, this variable is not stored for the filter. If an extra ''location'' is specified, the filter matches as if the unit were at that location.<br />
<br />
<syntaxhighlight lang='lua'><br />
assert(unit.canrecruit == wesnoth.match_unit(unit, { canrecruit = true }))<br />
</syntaxhighlight><br />
<br />
==== wesnoth.put_unit ====<br />
<br />
* '''wesnoth.put_unit(''unit'')'''<br />
* '''wesnoth.put_unit(''x'', ''y'', ''unit'')'''<br />
* '''wesnoth.put_unit(''x'', ''y'')'''<br />
* {{DevFeature1.13|2}} '''wesnoth.put_unit(''unit'', ''x'', ''y'')''' -- The above two forms are also deprecated.<br />
* {{DevFeature1.13|2}} '''''unit'':to_map([''x'', ''y''])<br />
<br />
Places a unit on the map. This unit is described either by a WML table or by a proxy unit. Coordinates can be passed as the first two arguments, otherwise the table is expected to have two fields '''x''' and '''y''', which indicate where the unit will be placed. If the function is called with coordinates only, the unit on the map at the given coordinates is removed instead. {{DevFeature1.13|2}} This use is now deprecated; use wesnoth.erase_unit instead.<br />
<br />
<syntaxhighlight lang='lua'><br />
-- create a unit with random traits, then erase it<br />
wesnoth.put_unit(17, 42, { type = "Elvish Lady" })<br />
wesnoth.put_unit(17, 42)<br />
</syntaxhighlight><br />
<br />
When the argument is a proxy unit, no duplicate is created. In particular, if the unit was private or on a recall list, it no longer is; and if the unit was on the map, it has been moved to the new location. Note: passing a WML table is just a shortcut for calling [[#wesnoth.create_unit]] and then putting the resulting unit on the map.<br />
<br />
<syntaxhighlight lang='lua'><br />
-- move the leader back to the top-left corner<br />
wesnoth.put_unit(1, 1, wesnoth.get_units({ canrecruit = true })[1])<br />
</syntaxhighlight><br />
<br />
==== wesnoth.erase_unit ====<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
* '''wesnoth.erase_unit(''unit'')'''<br />
* '''wesnoth.erase_unit(''x'', ''y'')'''<br />
* '''''unit'':erase()'''<br />
<br />
Erases a unit from the map. After calling this on a unit, the unit is no longer valid.<br />
<br />
==== wesnoth.get_recall_units ====<br />
<br />
* '''wesnoth.get_recall_units()'''<br />
<br />
Returns an array of all the units on the recall lists matching the WML filter passed as the first argument.<br />
<br />
==== wesnoth.put_recall_unit ====<br />
<br />
* '''wesnoth.put_recall_unit(''unit'', [''side''])'''<br />
* {{DevFeature1.13|2}} '''''unit'':to_recall([''side''])'''<br />
<br />
Places a unit on a recall list. This unit is described either by a WML table or by a proxy unit. The side of the recall list is given by the second argument, or by the side of the unit if missing.<br />
<br />
<syntaxhighlight lang='lua'><br />
-- put the unit at location 17,42 on the recall list for side 2<br />
wesnoth.put_recall_unit(wesnoth.get_units({ x= 17, y = 42 })[1], 2)<br />
</syntaxhighlight><br />
<br />
When the argument is a proxy unit, no duplicate is created. In particular, if the unit was private or on the map, it no longer is. Note: passing a WML table is just a shortcut for calling [[#wesnoth.create_unit]] and then putting the resulting unit on a recall list.<br />
<br />
==== wesnoth.create_unit ====<br />
<br />
* '''wesnoth.create_unit(''unit_info'')'''<br />
<br />
Creates a private unit from a WML table.<br />
<br />
<syntaxhighlight lang='lua'><br />
local u = wesnoth.create_unit { type = "White Mage", gender = "female" }<br />
</syntaxhighlight><br />
<br />
==== wesnoth.copy_unit ====<br />
<br />
* '''wesnoth.copy_unit(''unit'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':clone()'''<br />
<br />
Creates a private unit from another unit.<br />
<br />
<syntaxhighlight lang='lua'><br />
-- extract a unit from the map<br />
local u = wesnoth.copy_unit(wesnoth.get_units({ type = "Thug" })[1])<br />
wesnoth.erase_unit(u.x, u.y)<br />
-- u is still valid at this point<br />
</syntaxhighlight><br />
<br />
==== wesnoth.extract_unit ====<br />
<br />
* '''wesnoth.extract_unit(''unit'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':extract()'''<br />
<br />
Removes a unit from the map or from a recall list and makes it private.<br />
<br />
<syntaxhighlight lang='lua'><br />
-- remove all the units from the recall list of side 1 and put them in a WML container<br />
local l = {}<br />
for i,u in ipairs(wesnoth.get_recall_units { side = 1 }) do<br />
wesnoth.extract_unit(u)<br />
table.insert(l, u.__cfg)<br />
end<br />
helper.set_variable_array("player_recall_list", l)<br />
</syntaxhighlight><br />
<br />
Note: if the unit is on the map, it is just a shortcut for calling [[#wesnoth.copy_unit]] and then [[#wesnoth.put_unit]] without a unit. It is, however, the only way for removing a unit from a recall list without putting it on the map.<br />
<br />
<br />
==== wesnoth.advance_unit ====<br />
<br />
* '''wesnoth.advance_unit(''unit'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':advance()'''<br />
<br />
{{DevFeature1.13|0}} Advances the unit (and shows the advance unit dialog if needed) if the unit has enough xp. This function should be called after modifying the units experience directly. A similar function is called by wesnoth internally after unit combat. The second argument is a boodean value that specifies whether the advancement should be animated. The third agrument is a boodean value that specifies whether advancement related events should be fired.<br />
<br />
<br />
This function only works for units on the map.<br />
<br />
This function can also trigger multiple advancements if the unit has enough xp.<br />
<br />
==== wesnoth.add_modification ====<br />
<br />
* '''wesnoth.add_modification(''unit'', ''type'', ''effects'', [''write_to_mods''])'''<br />
* {{DevFeature1.13|2}} '''''unit'':add_modification(''type'', ''effects'', [''write_to_mods''])'''<br />
<br />
Modifies a given unit. It needs to be a proxy unit. The second argument is the type of the modification (one of "trait", "object", or "advance"). The option "advance" applies effects as if the unit would advance (e.g. AMLA effects). The third argument is a WML table describing the effect, so mostly containing '''[effect]''' children. See [[EffectWML]] for details about effects.<br />
<br />
{{DevFeature1.13|2}} In 1.13.2 and later, the "advance" type is replaced with "advancement", to match the equivalent tag in [[UnitTypeWML|[unit_type]]]. Also, it takes a fourth argument which, if false, causes it to not write the modification tag to the unit's [modifications] (as would be done with an [object] with no_write=true).<br />
<br />
<syntaxhighlight lang='lua'><br />
local T = wml.tags<br />
local u = wesnoth.get_units { canrecruit = true }[1]<br />
local effects = {<br />
id = "my_effect_id",<br />
T.effect { <br />
apply_to = "image_mod", <br />
replace = "RC(red>blue)" <br />
},<br />
T.effect {<br />
apply_to = "new_animation",<br />
T.standing_animation {<br />
-- AnimationWML<br />
}<br />
}<br />
} <br />
wesnoth.add_modification(u, "object", effects)<br />
</syntaxhighlight><br />
<br />
==== wesnoth.remove_modifications ====<br />
<br />
* {{DevFeature1.13|?}} '''wesnoth.remove_modifications(''unit'', ''cfg'' [, ''type''])'''<br />
* {{DevFeature1.13|?}} '''''unit'':remove_modifications(''cfg'' [, ''type''])'''<br />
<br />
Modifies a given unit. The unit needs to be a proxy unit. The second argument is a filter for the modifications to remove. It takes the same syntax as [[FilterWML#Filtering_on_WML_data|[filter_wml]]]; all matching modifications will be removed. The third argument is the type (tag name) of the modifications to search for; it defaults to <tt>"object"</tt>, but you can also pass <tt>"trait"</tt> or <tt>"advancement"</tt>.<br />
<br />
<syntaxhighlight lang='lua'><br />
local u = wesnoth.get_units { canrecruit = true }[1]<br />
wesnoth.remove_modifications(u, { id = "my_effect_id" })<br />
</syntaxhighlight><br />
<br />
==== wesnoth.unit_resistance ====<br />
<br />
* '''wesnoth.unit_resistance(''unit'', ''damage_type'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':resistance(''damage_type'')'''<br />
<br />
Returns the resistance of a unit against an attack type. (Note: it is a WML resistance. So the higher it is, the weaker the unit is.) The third argument indicates whether the unit is the attacker. Last arguments are the coordinates of an optional map location (for the purpose of taking abilities into account).<br />
<br />
<syntaxhighlight lang='lua'><br />
local fire_resistance = 100 - wesnoth.unit_resistance(u, "fire")<br />
</syntaxhighlight><br />
<br />
==== wesnoth.unit_defense ====<br />
<br />
* '''wesnoth.unit_defense(''unit'', ''terrain_code'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':defense(''terrain_code'')'''<br />
<br />
Returns the defense of a unit on a particular terrain. (Note: it is a WML defense. So the higher it is, the weaker the unit is.)<br />
<br />
<syntaxhighlight lang='lua'><br />
local flat_defense = 100 - wesnoth.unit_defense(u, "Gt")<br />
</syntaxhighlight><br />
<br />
==== wesnoth.unit_movement_cost ====<br />
<br />
* '''wesnoth.unit_movement_cost(''unit'', ''terrain_code'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':movement(''terrain_code'')'''<br />
<br />
Returns the movement cost of a unit on a particular terrain.<br />
<br />
<syntaxhighlight lang='lua'><br />
local move_cost = wesnoth.unit_movement_cost(u, "Gt")<br />
<syntaxhighlight><br />
<br />
==== wesnoth.unit_vision_cost ====<br />
<br />
* '''wesnoth.unit_vision_cost(''unit'', ''terrain_code'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':vision(''terrain_code'')'''<br />
<br />
Returns the vision cost of a unit on a particular terrain.<br />
<br />
<syntaxhighlight lang='lua'><br />
local see_cost = wesnoth.unit_vision_cost(u, "Gt")<br />
</syntaxhighlight><br />
<br />
==== wesnoth.unit_jamming_cost ====<br />
<br />
* '''wesnoth.unit_jamming_cost(''unit'', ''terrain_code'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':jamming(''terrain_code'')'''<br />
<br />
Returns the jamming cost of a unit on a particular terrain.<br />
<br />
<syntaxhighlight lang='lua'><br />
local jam_cost = wesnoth.unit_jamming_cost(u, "Gt")<br />
</syntaxhighlight><br />
<br />
==== wesnoth.unit_ability ====<br />
<br />
* '''wesnoth.unit_ability(''unit'', ''ability_tag'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':ability(''ability_tag'')'''<br />
<br />
Returns true if the unit is currently under effect by an ability with this given TAG NAME. This means that the ability could be owned by the unit itself, or by an adjacent unit.<br />
<br />
<syntaxhighlight lang='lua'><br />
function has_teleport(u)<br />
return wesnoth.unit_ability(u, "teleport")<br />
end<br />
</syntaxhighlight><br />
<br />
==== wesnoth.unit_types ====<br />
<br />
This is not a function but a read-only table indexed by unit type ids. Its elements are proxy tables with these fields:<br />
<br />
* '''id''': string<br />
* '''name''': translatable string (read only)<br />
* '''max_moves''', '''max_experience''', '''max_hitpoints''', '''level''', '''cost''': integers (read only)<br />
* '''abilities''': array of ability keys (strings), e.g. {"curing", "regenerates"}<br />
* {{DevFeature1.13|11}} '''advances_to''': array of unit types to which unit can advance<br />
* {{DevFeature1.13|11}} '''advances_from''': array of unit types from which unit can advance. Note: this is OOS-unsafe in Multiplayer games. Different clients may have additional Era-s with units upgradable to this unit type.<br />
* '''__cfg''': WML table (dump), see [[UnitTypeWML]]<br />
<br />
The metatable of these proxy tables appears as '''"unit type"'''.<br />
<br />
<syntaxhighlight lang='lua'><br />
local lich_cost = wesnoth.unit_types["Ancient Lich"].cost<br />
</syntaxhighlight><br />
<br />
Note that different clients have different set of available units in a Multiplayer game. It is OOS-unsafe to e.g. count the number of units.<br />
Presuming correctly written add-ons, it is still safe to e.g. access any given unit or its properties.<br />
<br />
==== wesnoth.races ====<br />
<br />
This is not a function but a table indexed by race ids. Its elements are proxy tables for all races the engine knows about.<br />
known fields of each element:<br />
* '''id''': string<br />
* '''description''', '''name''', '''plural_name''' (translatable strings)<br />
* '''num_traits''' (integer)<br />
* '''ignore_global_traits''' (boolean)<br />
* '''undead_variation''' (string)<br />
(all read only)<br />
* '''__cfg''': WML table (dump)<br />
<br />
<syntaxhighlight lang='lua'><br />
wesnoth.message(tostring(wesnoth.races["lizard"].name))<br />
</syntaxhighlight><br />
<br />
==== wesnoth.get_traits ====<br />
<br />
* '''wesnoth.get_traits()'''<br />
<br />
Returns a table with named fields (trait id strings) holding the wml tables defining the traits. arguments: none. All global traits the engine knows about, race-specific traits are not included.<br />
Known fields and subtags of each element are the ones which were given in the wml definition of the [[SingleUnitWML|trait]].<br />
wesnoth.message(tostring(wesnoth.get_traits().strong.male_name))<br />
<br />
==== wesnoth.simulate_combat ====<br />
<br />
* '''wesnoth.simulate_combat(''attacker'', [''attacker_weapon_index''], ''defender'', [''defender_weapon_index''])'''<br />
<br />
Computes the hitpoint distribution and status chance after a combat between two units. The first unit is the attacker; it does not have to be on the map, though its location should be meaningful. The second unit is the defender; it has to be on the map.<br />
<br />
Optional integers can be passed after each unit to select a particular weapon, otherwise the "best" one is selected. When giving the weapon, the parameter is the weapon number (integer, starting at 1) and not an element from the table returned by helper.child_range(att, "attack").<br />
<br />
<syntaxhighlight lang='lua'><br />
local function display_stats(n, t)<br />
wesnoth.message(string.format(<br />
"Chance for the %s\n to be slowed: %f,\n to be poisoned: %f,\n to die: %f.\nAverage HP: %f.",<br />
n, t.slowed, t.poisoned, t.hp_chance[0], t.average_hp))<br />
end<br />
local att_stats, def_stats = wesnoth.simulate_combat(att, att_weapon, def, def_weapon)<br />
display_stats("attacker", att_stats)<br />
display_stats("defender", def_stats)<br />
</syntaxhighlight><br />
<br />
Returns 2 additional tables which contain information about the weapons and the effect of single hits with these keys: num_blows, damage, chance_to_hit, poisons, slows, petrifies, plagues, plague_type, backstabs, rounds, firststrike, drains, drain_constant, drain_percent, attack_num, name. <br />
Name is the wml name not the description. If there is no weapon, then name will be nil<br />
<br />
<syntaxhighlight lang='lua'><br />
local att_stats, def_stats, att_weapon, def_weapon = wesnoth.simulate_combat(attacker, att_weapon_number, defender)<br />
wesnoth.message(string.format(<br />
"The attack %s should be countered with %s, which does %d damage, has %d%% chance to hit and forces %d attack rounds due to its berserk ability.",<br />
att_weapon.name, def_weapon.name or "no weapon", def_weapon.damage, def_weapon.chance_to_hit, def_weapon.rounds))<br />
</syntaxhighlight><br />
<br />
==== wesnoth.transform_unit ====<br />
<br />
* '''wesnoth.transform_unit(''unit'', ''to_type'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':transform(''to_type'')'''<br />
<br />
Changes the type of a unit and adjust attributes accordingly. Note that hit points are only changed if necessary to accommodate the new maximum hit points. Poison is automatically removed if the transformed unit is immune.<br />
<br />
<syntaxhighlight lang='lua'><br />
local ev = wesnoth.current.event_context<br />
local u = wesnoth.get_units{x=ev.x1, y=ev.y1}[1]<br />
wesnoth.transform_unit(u, "Spearman")<br />
-- If a full heal is desired:<br />
u.hitpoints = u.max_hitpoints<br />
u.status.poisoned = false<br />
</syntaxhighlight><br />
<br />
==== wesnoth.add_known_unit ====<br />
<br />
* {{DevFeature1.13|10}} '''wesnoth.add_known_unit(''unit_type_id'')'''<br />
<br />
adds the unit type with the given id to the list of known units (so that they appear in the help)<br />
<br />
==== wesnoth.create_animator ====<br />
<br />
{{DevFeature1.13|7}}<br />
<br />
* '''wesnoth.create_animator()'''<br />
<br />
Returns an object that can be used to set up and run an animation. The object has three methods:<br />
<br />
* '''animator:run()'''<br />
<br />
Runs the animation. {{DevFeature1.15|0}} Implicitly clears the animator.<br />
<br />
* '''animator:clear()'''<br />
<br />
Clears any units previously added to the animation.<br />
<br />
* '''animator:add(''unit'', ''flag'', ''hits'', ''params'')'''<br />
<br />
Adds a unit to the animation. The ''flag'' specifies which animation to play, and the ''hits'' parameter is required for attack animations to specify which variant of the animation to play. Possibly keys in ''params'' are:<br />
<br />
* '''facing''': A location. The animation will be played with the unit facing that location.<br />
* '''value''': Either a number or a list of two numbers. Use this to pass ''value'' and/or ''value_second'' to default animations that use them.<br />
* '''with_bars''': Whether to show HP bars and such while the animation plays.<br />
* '''text''': Text to float as the animation plays.<br />
* '''color''': Color of the floating text - a list of red, green, blue.<br />
* '''primary''': The primary weapon to use for the animation. Must be a Lua unit attack proxy.<br />
* '''secondary''': The secondary weapon to use for the animation.<br />
<br />
Normal usage would be to create it, call '''add''' one or more times, then call '''run'''.<br />
<br />
==== wesnoth.effects ====<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
This table contains the implementation of custom [[EffectWML|[effect]]]s. Each value is a function that takes a unit and the effect config. Note that the default effects defined by the Wesnoth engine are not in this table. <br />
<br />
<syntaxhighlight lang='lua'><br />
function wesnoth.effects.min_resistance(u, cfg)<br />
local resistance_new = {}<br />
local resistance_old = helper.parsed(helper.get_child(cfg, "resistance"))<br />
for k,v in pairs(resistance_old) do<br />
if type(k) == "string" and type(v) == "number" and wesnoth.unit_resistance(u, k) >= v then<br />
resistance_new[k] = v<br />
end<br />
end<br />
--important: use wesnoth.add_modification(..., false) so that the function will only execute the effects of that object and not store the object in the unit.<br />
wesnoth.add_modification(u, "object", {<br />
T.effect {<br />
apply_to = "resistance",<br />
replace = true,<br />
T.resistance (resistance_new),<br />
},<br />
}, false)<br />
end<br />
</syntaxhighlight><br />
<br />
The code above adds a new <code>min_resistance</code> effect that will set the resistances to specific values if they are currently below that value. It can then be used like this (for example, in [[DirectActionsWML#.5Bobject.5D|[object]]]):<br />
<br />
<syntaxhighlight lang='wml'><br />
[effect]<br />
apply_to=min_resistance<br />
[resistance]<br />
cold=50<br />
[/resistance]<br />
[/effect]<br />
</syntaxhighlight><br />
<br />
Note that because currently all Lua code is executed after [unit]s in [side] are created, it is currently not possible to use these effects in [unit]s in [side]<br />
<br />
{{DevFeature1.13|5}}<br />
<br />
Built-in effects are now present in the <code>wesnoth.effects</code> table and can be called by custom effects or by other Lua code. They take the same two arguments that a custom effect function does - the unit, and the effect WML.<br />
<br />
In addition, you can now specify description modifiers to be used if a custom effect is placed in a <code>[trait]</code> tag. Instead of setting a function as the effect, you set a table with a <code>__call</code> metafunction which does what the function would have done. The table can then have an additional <code>__descr</code> metafunction which updates descriptions as necessary. The built-in effects all use this structure. This metafunction takes the same arguments as the regular effect function, but should not modify the unit. Instead, it returns a string to be appended to the trait's effect description.<br />
<br />
[[Category: Lua Reference]]</div>Edward Chernenkohttps://wiki.wesnoth.org/index.php?title=SingleUnitWML&diff=60120SingleUnitWML2018-12-27T13:02:12Z<p>Edward Chernenko: fix wikilink (shouldn't include "[" or "]")</p>
<hr />
<div>{{WML Tags}}<br />
The '''[unit]''' tag describes a single unit on the map or in memory, for example Konrad.<br />
It is different from the [unit_type] in [units], which describes a class of units. However it takes many of the same keys and thus can generally override the inherited properties from the associated [unit_type].<br />
<br />
[unit] can be used inside [side] ([[SideWML]]) for units present at start of the scenario, or as [[DirectActionsWML]] for units created during the game. (It is also used in save-files.)<br />
<br />
This contains keys and tags which describe the unit's [[#Unit Data|persistent data]], as well as certain [[#Unit State|state variables]] which will also persist with the unit but will change frequently as gameplay progresses. Finally, there are some keys to set certain [[#Creation Options|one-time options]] for how the unit will be initially created, which will ''not'' persist beyond initial creation.<br />
<br />
== Unit Data ==<br />
The following keys and tags describe the unit itself, and will persist with the unit (though some may change automatically when the unit advances):<br />
* <span id="type">'''type'''</span>: the ID of the unit's unit type. This key is mandatory. See [[UnitTypeWML]].<br />
<br />
* '''variation''': the [variation] of the [unit_type] as which the unit will appear.<br />
<br />
* '''parent_type''': overrides '''type''' if this is present. This is likely of little use to WML authors; it is automatically generated when needed by the game (to keep track of some [unit_type][variation]s).<br />
<br />
* '''side''': the side that the unit is on. It has to be an existing side, even if the unit is created in a variable. Defaults to 1, except when the [unit] tag appears inside a [side], in which case the unit always belongs to that side, and this key is ignored.<br />
<br />
* '''id''': a unique identifier for the unit. This is (usually) not displayed to the player, but is to be used only for identifying and filtering units. If not specified, a random one will be generated for the unit to ensure that each unit has a unique '''id''' attribute (as will happen when a unit is recruited normally). In older versions, the '''description''' attribute specified a unique ID. (The one instance when an id is displayed to the player is when the leader's id is used as the default for a [[SideWML|side]]'s '''current_player''' attribute.) Note: While it IS technically possible to create multiple units with the same ID, doing so may produce unpredictable results in many cases. WML should therefore be structured in such a way that no two units in existence ever end up with the same ID.<br />
<br />
* '''gender''': can be set to male or female to designate the gender of the unit. Default is male (unless [[#random_gender|'''random_gender''']] is set to "yes"), but if the unit has only a female variant it will be female.<br />
<br />
* '''name''': the user-visible name of the unit. Note that the player may use the "rename unit" action to change this (unless '''unrenamable''' is also set).<br />
<br />
* <span id="unrenamable">'''unrenamable'''</span>: if 'yes', the user-visible name of the unit cannot be changed by the player (which is only possible when the unit is on the player's side anyway).<br />
<br />
* '''canrecruit''': a special key for leaders.<br />
** '''no''': default. Unit cannot recruit.<br />
** '''yes''': unit can recruit.<br />
: Normally when a team controls no units with '''canrecruit=yes''', that team loses. However, even if your team has lost you continue to play with whatever units you still have until the scenario is over. Usually scenarios end when only one team is left with a leader that can recruit, but special victory conditions can be set up in campaigns. Normally you want to set the leader of a side with '''canrecruit=yes'''. If you don't want the leader to recruit, it is usually better to just not give him any unit types to recruit, than to make a special victory condition. Units with '''canrecruit=yes''' are exempt from upkeep costs. So that leaders do not need to be given the ''loyal'' trait.<br />
: More than one unit with '''canrecruit=yes''' for the same side (see [[SideWML]]) are allowed in single player, if the side is human-controlled.<br />
<br />
* '''extra_recruit''': a list of unit types which this unit can recruit in addition to the ones given by its [side]recruit= (only relevant for units with '''canrecruit=yes''').<br />
<br />
* '''[filter_recall]''' A leader can only recall those units which pass the SUF. (Meaningful only if canrecruit=yes.)<br />
**'''[[StandardUnitFilter]]''' tags and keys<br />
<br />
* '''level''': the unit's current level. Defaults to the level of the [unit_type] described by [[#type|'''type''']]. This is generally not set manually.<br />
<br />
* '''upkeep''': the amount of upkeep the unit will require each turn.<br />
** '''loyal''': no upkeep cost. Can be changed by the effect 'loyal' (see [[EffectWML]])<br />
** '''free''': synonymous with "loyal".<br />
** '''full''': unit costs ''level'' upkeep (see [[UnitTypeWML]]).<br />
** An integer can be used to set the upkeep cost to that number.<br />
** The default is "full".<br />
** Leaders (units with '''canrecruit=yes''') never pay upkeep no matter what upkeep is set to.<br />
** Normally you don't want to muck with this value. If you want to give a side units without upkeep costs, give those units the 'loyal' trait.<br />
<br />
* {{DevFeature1.13|0}} '''recall_cost''': the recall cost of this unit. Overrides the values specified by the unit's type ([[UnitTypeWML|[unit_type]]]), its side ([[SideWML|[side]]]), and the global [[GameConfigWML|[game_config]]] value. A value of -1 is equivalent to not specifying this attribute. {{DevFeature1.15|0}} Units are now recalled for AI sides even if the recall_cost is larger than the unit's worth (essentially its cost, plus potentially a bonus for experience points). In 1.14 and earlier, units were not recalled by the AI in this case even if this was the only recall/recruit action possible to the AI.<br />
<br />
* '''overlays''': a comma-separated list of images that are overlayed on the unit.<br />
<br />
* <span id="max_hitpoints">'''max_hitpoints'''</span>: The maximum hitpoints the unit has when at full health. Default is the max HP set for the [unit_type] described by [[#type|'''type''']].<br />
<br />
* '''max_experience''': The experience the unit needs to advance. Default is the experience required for the [unit_type] described by [[#type|'''type''']].<br />
<br />
* <span id="max_moves">'''max_moves'''</span>: The maximum number of movement points the unit has. Default is the number of movement specified for the [unit_type] described by [[#type|'''type''']].<br />
<br />
* '''vision''': The the number of vision points to calculate the unit's sight range. Default is the number of vision points specified for the [unit_type] described by [[#type|'''type''']].<br />
<br />
* '''jamming''': {{DevFeature1.15|0}} The number of jamming points for the unit. Default is the number of jamming points specified for the [unit_type] described by [[#type|'''type''']].<br />
<br />
* <span id="max_attacks">'''max_attacks'''</span>: The number of attacks the unit can have per turn. Default is the number of attacks specified for the [unit_type] described by [[#type|'''type''']].<br />
<br />
* '''profile''': sets a portrait image for this unit. Default is the portrait image set for the [unit_type] described by [[#type|'''type''']]. When the unit advances, if the value of profile is different from the unit-type portrait, that value is preserved. If the profile field is empty or the same as the unit-type portrait, the level-advance changes the unit portrait to the default for the new level and type. See [[UnitTypeWML]] for the rules used for locating files.<br />
** If "unit_image" is given instead of a filename, uses the unit's base image as the portrait (in the same manner that unit types without portraits do by default).<br />
<br />
* '''small_profile''': sets a small portrait image for this unit. See the '''profile''' attribute above for advancement and special values. As with [[UnitTypeWML]], the location heuristic of the '''profile''' attribute is disabled when the '''small_profile''' attribute is provided.<br />
<br />
* '''role''': used in standard unit filter ([[FilterWML]]). Can be set using [role] (see [[InternalActionsWML]]).<br />
<br />
* '''[variables]''' a set of variables that will be stored when this unit is stored (See [store_unit], [[InternalActionsWML]]). The attribute '''variable'''='''value''' means that when the unit is stored in the array ''unit'', the variable '''unit'''.variables.''variable'' will have the value ''value'' (See [[VariablesWML]]).<br />
<br />
* '''[modifications]''' changes that have been made to the unit.<br />
** '''[trait]''' a trait the unit has. Same format as [[UnitsWML#.5Btrait.5D|[trait], UnitsWML]].<br />
** '''[object]''' an object the unit has. Same format as [[DirectActionsWML#.5Bobject.5D|[object], DirectActionsWML]].<br />
** '''[advance]''' an advancement that has already been applied to the unit. Same format as [[UnitTypeWML#After max level advancement (AMLA)|AMLA [advancement], UnitTypeWML]]. These are automatically added as the unit has AMLA advancements applied to it, but can also be specified manually to indicate that the unit already has a particular advancement applied, or to disable certain advancements (by ID). {{DevFeature1.13|2}} In 1.13.2 and later this has been renamed to [advancement], to match the UnitTypeWML tag of the same name.<br />
<br />
* '''[event]''' The event is copied from this unit's WML description into the scenario. The event is carried along with the unit (even during advancement) and inserted into a scenario whenever this unit is first included. A [unit][event] requires a non-empty id= attribute.<br />
<br />
* '''unit_description''': overrides the unit type description for this unit. Note that this will be reset when the unit advances. To avoid this, one can either set up a ''post_advance'' [[EventWML|event]] to override the default description after promotion, or use an [object] with a profile [[EffectWML|effect]] to change the unit description.<br />
<br />
* '''hp_bar_scaling''': Overrides the attribute in [[GameConfigWML]] (and the [unit_type], if present).<br />
<br />
* '''xp_bar_scaling''': Overrides the attribute in [[GameConfigWML]] (and the [unit_type], if present).<br />
<br />
* '''ai_special''': causes the unit to act differently<br />
** "guardian" the unit will not move, except to attack something in the turn it moves (so, it only can move if an enemy unit gets within range of it). Does the same as '''[status] guardian = 'yes''''.<br />
<br />
* '''[ai]''' This affects how the computer will control this unit (currently only used by [[FormulaAI]]).<br />
** '''formula''': if set, the unit will execute this code during the "unit_formulas" stage, assuming that the "unit_formulas" stage has been enabled for this side<br />
** '''priority''', '''loop_formula''', '''[vars]''': see the [[FormulaAI]] documentation for details<br />
<br />
* '''traits_description''': the description of the unit's traits which is displayed. However if it is not specified explicitly, the unit's actual traits' names will be used instead, so it is normally not necessary to set this.<br />
<br />
*'''alignment''': one of lawful/neutral/chaotic/liminal (See [[TimeWML]]). Default is the alignment of the [unit_type] described by [[#type|'''type''']]. This is generally not set manually.<br />
<br />
*'''advances_to''': comma-separated list of unit types to which this unit can advance. Will override the default provided by the [unit_type]. This is generally not set manually.<br />
<br />
*'''race''': See {{tag|UnitsWML|race}}. Will override the default provided by the [unit_type]. This is generally not set manually.<br />
<br />
*'''undead_variation''': Will override the default provided by the [unit_type]. This is generally not set manually.<br />
<br />
*'''usage''': Will override the default provided by the [unit_type]. This is generally not set manually.<br />
<br />
*'''zoc''': whether the unit has a zone of control. Will override the default provided by the [unit_type]. This is generally not set manually.<br />
<br />
*'''[movement_costs]''', '''[vision_costs]''', '''[defense]''', and '''[resistance]''': Can be used to modify [[UnitsWML#.5Bmovetype.5D|existing values]].<br />
<br />
*'''[attack]''': Takes the same syntax as [[UnitTypeWML#Attacks|[unit_type][attack]]]. By default, the attacks from the [unit_type] will be included. '''Note:''' using this tag will replace ''all'' [attack] tags with the new one.<br />
<br />
== Unit State ==<br />
The following keys and tags describe the current state of the unit, and will change regularly as gameplay progresses:<br />
* '''x''', '''y''': the location of the unit. By default (unless modified by [[#placement|'''placement''']] below) if a location isn't provided and the side the unit will belong to has a recall list, the unit will be created on the recall list. The recall list can also be explicitly specified as the location with "recall,recall".<br />
<br />
* '''location_id''': {{DevFeature1.13|8}} the location of the unit, referencing one of the special locations defined by the map. This overrides '''x''' and '''y''' if present but otherwise has the same effect and can be modified by the placement options.<br />
<br />
* '''facing''': which way the unit is facing (this only affects how the unit is displayed).<br />
** Possible values are '''se''', '''s''', '''sw''', '''nw''', '''n''', '''ne'''. Note that some unit types may not have distinct animations for each direction.<br />
<br />
* '''goto_x''':, '''goto_y''': the unit's current movement destination. Default is 0,0 i.e. the unit is not on a course.<br />
<br />
* '''hitpoints''': the HP of the unit. Default [[#max_hitpoints|'''max_hitpoints''']].<br />
<br />
* '''experience''': the XP of the unit. Default is 0.<br />
<br />
* '''moves''': number of movement points the unit has left. Default is [[#max_moves|'''max_moves''']].<br />
: '''Note:''' Do not assume that moves=max_moves on turns when the unit doesn't move. The wesnoth AIs sometimes manipulate the moves variable during its turn, for internal reasons.<br />
<br />
* '''resting''': whether the unit has not moved yet this turn. Used to decide whether to give the unit rest healing. Note that this can be true even if moves is not equal to max_moves.<br />
<br />
* '''attacks_left''': number of attacks the unit has left. Default is '''max_attacks'''.<br />
<br />
* '''[status]''' the status of the unit. This affects different features of the unit, for example whether the unit loses health each turn. Default for all keys is 'no', but this can be changed by the scenario or by special abilities (see [[AbilitiesWML]]). The Status Table displays the status of each unit using the three images '''misc/poisoned.png''', '''misc/slowed.png''' and '''misc/petrified.png'''; other keys do not appear in the Status Table.<br />
** '''poisoned''': if 'yes', the unit loses 8 HP each turn. See also ''heals'', ''cures'', [[AbilitiesWML]].<br />
** '''slowed''': if 'yes', the unit has 50% of its normal movement and does half damage. When the controller of the unit's turn is over, '''slowed''' is set to 'no'. <br />
** '''petrified''': if 'yes', the unit cannot move, attack, or be attacked.<br />
** '''uncovered''': if 'yes', the unit has performed an action (e.g. attacking) that causes it to no longer be hidden until the next turn.<br />
** '''guardian''': if 'yes', the unit will not move, except to attack something in the turn it moves (so, it only can move if an enemy unit gets within range of it). Does the same as '''ai_special = "guardian"'''.<br />
** '''unhealable''': if set to 'yes', the unit cannot be healed.<br />
** {{DevFeature1.13|6}} '''invulnerable''': if 'yes', attacks can't hit the unit.<br />
** One can add other keys to [status], but they must have boolean values, and they will not do anything meaningful on their own (but can be checked from events and acted upon accordingly). For example, a scenario can set unit.status.''my_custom_key'' to 'yes' or 'no'.<br />
<br />
* {{DevFeature1.13|6}} '''invulnerable''': a shorthand to set the ''invulnerable'' status.<br />
<br />
== Creation Options ==<br />
In addition to the unit's persistent data itself, there are several options for controlling how the unit will be created, as follows:<br />
* <span id="placement">'''placement'''</span>: How the unit should be placed: can be one value or a comma-separated list of values. Default value is 'map,leader' for a leader given directly in [side], "" otherwise. By default, 'map,recall' is implicitly appended to the end of the list.<br />
** '''map''': If x,y (or location_id) are explicitly given and point to a valid on-map location - try to place the unit at the nearest free location to there, never overwriting existing units. Successful if x,y (or location_id) are given and a valid on-map vacant location near it can be found.<br />
** '''leader''': Try to place unit near the leader, if leader is not present or is in recall list - try to place unit near the start location for this side. Successful if a valid on-map vacant location can be found near leader or near start location.<br />
** '''recall''': Place unit on recall list. Always successful. <br />
** '''map_overwrite''': If x,y are explicitly given and point to a valid on-map location - try to place unit at this location, if there was a unit there - overwriting it, without firing events. {{DevFeature1.13|8}} Deprecated, use placement=map and overwrite=yes instead.<br />
** '''map_passable''': If x,y are explicitly given and point to a valid on-map location - try to place unit at this location; if the hex is of an impassable terrain for the unit being placed, or is already occupied by another unit, the new unit will be placed in the nearest vacant hex. {{DevFeature1.13|8}} Deprecated, use placement=map and passable=yes instead.<br />
** '''leader_passable''': Similar to "leader", with the additional restriction that the selected location is not impassable for the unit being placed. {{DevFeature1.13|8}} Deprecated, use placement=leader and passable=yes instead.<br />
* '''passable''': {{DevFeature1.13|8}} (default=no) If yes, and the specified location is of an impassable terrain for the unit being placed, the new unit will be placed in the nearest hex that is of a passable terrain for it.<br />
* '''overwrite''': {{DevFeature1.13|8}} (default=no) If yes, always place the unit at the exact specified location, overwriting the existing unit if there is one. Generally you don't want to use this together with placement=leader.<br />
<br />
* '''generate_name''': (default=yes) will generate a new '''name''' if there isn't one specified for the unit, as if the unit were a freshly-recruited one.<br />
* '''random_traits''': "no" will prevent random trait generation for units. You should only need to set this for placed nonleaders in multiplayer games or if you want to give the unit fewer traits than it would normally get for its unit type. When generating traits for a unit, first traits the unit has already been given are excluded. Then "musthave" traits (undead, mechanical) for the unit type are given. Then for leaders ('''canrecruit=yes''') traits that are not available to "any" (currently that's all of them to avoid a multiplayer OOS issue, but later will be restricted based on multiplayer play balance issues) are removed from consideration. Then traits are added randomly until the maximum allowed for the unit type is reached or there are no more available traits. Random traits can now be used in MP games but only when spawned in an event, so not for leaders and other units in the [side] definition.<br />
<br />
* <span id="random_gender">'''random_gender'''</span>: "yes" will cause the gender of the unit with male and female variations to be male 50% of the time, female 50% of the time. If the unit has only one gender variant it will always be given the correct one.<br />
<br />
* '''to_variable''': (only for [event][unit]) creates the unit into the given variable instead of placing it on the map.<br />
<br />
* '''animate''': whether to display the recruitment animation for this unit as if it were being recruited/recalled. Defaults to "no". Irrelevant when the [unit] tag appears inside a [side].<br />
<br />
== See Also ==<br />
<br />
* [[UnitTypeWML]]<br />
* [[InternalActionsWMLUnitTags]]<br />
* [[ReferenceWML]]<br />
<br />
[[Category:WML Reference]]</div>Edward Chernenkohttps://wiki.wesnoth.org/index.php?title=How_to_play_Undead&diff=60111How to play Undead2018-12-20T02:31:42Z<p>Edward Chernenko: typo</p>
<hr />
<div>==General Undead Strategies:==<br />
As a style of personal preference, I enjoy using the massive damage dealing Dark Adepts en masse. The most dreadful attacker of the Undead is also the most pitiful defender, being the only unit in Default to have no melee weapon. Because of this you'll need a good mix of Skeletons, Adepts, and support units.<br />
<br />
A safe first turn recruit against Random would have 1 skeleton, 1 Adept, 1 Ghost, 1 ghoul and a couple more units. When you see what your opponent has, go to the appropriate section below.<br />
<br />
The biggest aspect of Undead that you'll have to become comfortable with is almost overextending yourself at night. Your damage is so high that even Northerners can't keep up except with having more units. You'll make your first attacks with Adepts usually so that you can protect them with your advancing forces that take the place of the units they defeat. Skeletons do this best, usually, as they are your heaviest melee hitter, and at night there isn't a single level 1 unit that can take them out in one attack.<br />
<br />
In order to get the most for your money, you should attack as dusk breaks - especially if you're second player. You'll begin your attack and your opponent will have to counter at night. If your opponent is lawful, the right time to leave the attack can be tricky. Otherwise simply retreat as night is ending. Against lawful units you may want an extra turn to get space between the two of you.<br />
<br />
Since Undead have major resistance strengths and weaknesses every opponent will have a specific plan to counter you. This will consist of Fire and Impact units. It just so happens that Adepts are best at countering these units whether it be defensively against Fire units or offensively against Impact units. A good note is that Ghouls have 10% Fire resistance and no Impact vulnerability. They are a good defensive unit to use on villages for the most part.<br />
<br />
==Undead vs Drakes:==<br />
Possibly the deadliest matchup in Wesnoth, this game will result in lots of casualties, and very quickly. Both factions are incredibly offensive and of opposite alignment. Skeletons are weak to Fire, Adepts to melee, and Drakes are weak to Pierce and Cold. Basically, whoever is left standing wins.<br />
<br />
'''Skeleton''': You'll want these guys if Saurians become a problem. Otherwise, you should invest in Skeletal Archers if you want the Blade and Pierce resistance.<br />
<br />
'''Skeleton Archer''': 14 gold, 5-3 ranged Pierce against Drakes during day in defense, and great resists to their melee attacks, this is a great unit choice against Drakes. Your army should have a couple of these.<br />
<br />
'''Walking Corpse''': Do not recruit this unit when fighting Drakes.<br />
<br />
'''Vampire Bat''': Do not recruit this unit when fighting Drakes unless the map requires a quick scout for water areas and village grabbing. Usually a Ghost will be enough of a scout unit that combines with Cold ranged and melee.<br />
<br />
'''Ghoul''': Very limited in it's usefulness against Drakes as they have so much hp and can easily fly back to towns to heal, your money is better spent.<br />
<br />
'''Dark Adept''': The meat of your army will be this unit. Doing 12-2 damage to Drakes during daytime makes them an obvious choice, and at night you will get an incredible 17-2 magical with a 16 gold level 1 unit. Recruit lots of these, but not so many that you can't cover them with other units. Clashers will literally eat these guys during the day, as will Drake Fighters. Beware of Skirmishers at night, as they are the best counter agsint these guys. Like I said, if Skirmishers become a problem, bring a Skeleton with you to chop them up.<br />
<br />
'''Ghost''': A decent buy for early grabbing and for scouting, but for Cold damage Adepts are better. Ghosts die easily in the day, but having the mobility at night can prove quite useful. Don't recruit more than 1 early, or you'll be burned to death very quickly.<br />
<br />
A good first turn recruit would consist of a Skeleton Archer, a Ghost, 2 Adepts, and perhaps a Skeleton with more Archers and Adepts to be recruited later. Don't shy away from the fact that you'll have to freeze Drakes into submission. Use Adepts on Burners and Archers on other Drakes, but always finish what you start - don't leave Drakes hanging around until daytime because they will put a hurt on. It's better to kill 1 Drake than to hurt 2. If Saurians do skirmish in behind you, use Adepts on them to finish them quickly if no Skeletons are around. They are weak to Cold and they do cost 15 gold. If you end up not killing a Drake with that Adept then he at least earned his cost by killing that one unit.<br />
<br />
In defense, put Skeleton Archers on towns, and keep your Ghost(s) away from the front line. a Burner can tear them apart and any flyer can come in to help if they need to. Don't be afraid to use Adepts to counter even in day, but don't attack Burners with them at this time; they'll do too much damage in return, so focus on killing Clasher and Fighters during the day.<br />
<br />
==Undead vs Loyalists:==<br />
Like Drakes, there will be a heavy day/night push and pull. Ghosts will be more effective here as the Loyalists are less mobile and have less Fire. Loyalists are the most versatile faction, so you'll need to be prepared to handle anything.<br />
<br />
'''Skeleton''': A good staple unit. Use this to hack up any unit except HI. You'll do equal damage to Spearmen in day and everyone else is cake.<br />
<br />
'''Skeleton Archer''': Another good unit to have 1 or 2 of. Mix and match your skeletons, or just use one brand. Recruit these if your opponent has mounted units - especially Cold resistant Cavalry. These guys are useful against most other Loyalist units as well, and do decent return damage to Mages at dawn/dusk. Keep them far from HI unless you can finish them that turn.<br />
<br />
'''Walking Corpse''': These guys may be useful, but money on heavier hitters is money better spent. These guys are best used to clean up a mess you don't want to waste a Skeleton or Dark Adept on. Beware, they can be easily destroyed by heavy infantry<br />
<br />
'''Vampire Bat''': Don't recruit this unit when fighting Loyalists unless you need a scout unit to cross water to gather villages quickly. For 7 more gold you can get a Ghost who is a great frontline unit if your opponent has no Mages in range.<br />
<br />
'''Ghoul''': Useful to hold villages and scare off high hp units. Does your opponent have too many HI to kill in one turn? Poison one and make sure you kill the rest. This guy resists everything except Impact (and obviously Holy) just a little bit, so he can be a nice damage soaker - especially if your opponent focuses on melee.<br />
<br />
'''Dark Adept''': Again, your meat. Not as much as with Drakes, but you'll want these guys near your front line at all times to counter-attack HI and to knock out the high defense Fencers. Mermen will resist you 20%, but you will cut through their high defense as well. At night these guys are killers, plain and simple. Go for HI and Horsemen first, then any other non-Cavalry units - the more expensive the better. Even using Adepts on Mages is smart at night if you're low on Skeletons.<br />
<br />
'''Ghost''': Get one and probably no more than that. Mages can kill this unit alone in day, and the 20 gold is far too much to waste. Their Drain ability makes them good attackers of Spearmen, as their Firststrike ability actually works against them. Usually you'll want to ranged attack HI or melee Mages, but keep in mid that your nighttime Drain + 50% defense + good resists means you'll usually go unscathed in melee at night.<br />
<br />
A good first turn recruit would consist of a Gost for grabbing, an Adept or two, a combination of 2 or 3 Skeletons + Archers, and perhaps a Ghoul depending on how you want to play it.<br />
<br />
If your opponent has no HI then your nighttime attack plan is simple: lead with Adepts to freeze everything out of your path and then cover them with your skeleton units. Again, don't be afraid to freeze Mages at night, as 12-2 will kill 2 out 6 Mages (based on hp they get from traits), and they will only deal 5-3 back, or 5-1 if you kill them. Doing this is a coin-flip though, so judge accordingly.<br />
<br />
If your opponent has HI, and has them in front, same game plan, just freeze the HI exclusively. They are the only unit weak to Cold in their army, it is their only weakness that you can exploit, and they have the most hp (tied). The math is simple. You must use Cold - preferably from Adepts - to kill these guys. After they're down, advance as before.<br />
<br />
If your opponent has HI in the back, bust your way through wil what units you have. If you can't reach them with your Adepts at the end, blast whatever the hell you can, because you have to apply their damage somewhere. Even if you hang them out to dry in the front lines, all Loyalists get -25% damage at night, so they're a lot safer than you may think. Do keep them covered if you left any Horsemen alive though, which you shouldn't, as they are a high priority kill.<br />
<br />
In defense: leave Skeleton Archers in front. They will resist all damage other than from Mages and HI, and they will do some damage back to Mages (in addition to being your cheapest fighting unit). If HI are coming your way put a Ghoul up front. If your opponent only recruits HI and Mages, recruit only DAs, Ghouls, and Skeletons. Skeles kill Mages, DAs kill HI, Ghouls defend.<br />
<br />
==Undead versus Undead:==<br />
<br />
This matchup is no longer as boring as it was before. Most of your units are undead, making most of them vulnerable to the arcane damage by dark adepts and ghosts. Ghouls in this matchup are less useful for their poison; their resistance to blade, cold, arcane and pierce makes them your tank of sorts, but vulnerable to walking corpses. In general, use a combination of ranged and or walking corpses to kill ghouls, and ghosts and dark adepts to kill all arcane-vulnerable units.<br />
<br />
'''Dark Adept''': Your most important unit. Get a lot of these. At night, 1 unit can kill ghosts and walking corpses. 2 of these have a good chance of killing all skeleton units. They are still useful against ghosts, while least effective against ghouls. Considering the bat's 60% defense, you might still want to use adepts against them. They are vulnerable to all other units' melee attacks. Protect them well.<br />
<br />
'''Ghoul''': This unit is important, not for its damage, but for its range of resistances; it has no resistances to only impact. Use these to protect your dark adepts from all other melee units. Do remember that ghouls are only 10% resistant to blade, and still vulnerable to skeletons at night. When possible, poison opponents' dark adepts, as it will make him/her consider pulling back to heal. Poisoning bats is also an important option, as they are quite difficult to kill. This is your tank in Undead versus Undead matches.<br />
<br />
'''Skeleton''': This unit is important for its high melee damage, which will be the main way for you to kill dark adepts, as well as ghouls. Skeletons however are vulnerable to walking corpses and ghosts in melee, and dark adepts' range. Only use them to kill walking corpses if you have to; using ghosts/dark adepts are almost always better. <br />
<br />
'''Skeleton Archer''': Not much use. Skeletons and ghouls are pierce resistant, while dark adepts will not give soft retaliation. Only really useful against bats and walking corpses, of which dark adepts are better, as they are similarly useful against them. Not recommended for your initial recruit.<br />
<br />
'''Walking Corpse''': They are useful for their impact damage, and their plague ability. They are a cheap unit to get full damage against ghouls, and severely damage any skeleton unit, especially skeleton archers. One way to use them is by having dark adepts to provide the initial hits against skeleton/ghoul, followed by walking corpses, as they have a higher damage/gold ratio against ghouls than skeletons. Whenever possible, use them to finish off any dark adepts or bats, as the plague ability will provide you with an extra unit. <br />
<br />
'''Vampire Bat''': They are useful for village grabbing and attacking vulnerable units (dark adepts mostly, and finishing off walking corpses and ghouls). They are cold and arcane resistant with 60% default defense, making them quite difficult to kill unless using magic, for which its attacks are resisted. Beware of it being attacked from multiple hexes, as impact damage from walking corpses will easily kill it; be careful of the threat of ghouls as well. When possible use them to steal villages or threaten them. They are certainly worth your gold. Once leveled up, they are very difficult to kill by other Undead players.<br />
<br />
'''Ghost''': Recruiting this unit depends on your preference, this author does not recommend using them. They have arcane melee, which is useful against all units except bats and ghouls. On the other hand, they do not drain, losing a major advantage of using them. At night, a single dark adept can kill a ghost in one turn. And they cost 20 gold, which might be better spent. If you recruit these, be prepared for a lot of healing this unit in your villages instead of being up front in the attack.<br />
<br />
A good initial recruit should be a mixture of skeletons, dark adepts, ghouls and walking corpses, with the dark adepts being the core. Get a bat for medium to large maps.<br />
<br />
Your main aim is to kill dark adepts, which are usually protected by other units. In general, use ranged attacks, with melee to finish off ghouls; this will be your primary problem. If they are not positioned well, you might want to save your adepts and use your walking corpses instead. Use arcane to kill off walking corpses. In general, you want to have as many hexes as possible to kill dark adepts, it might sometimes be better to ignore the ghoul and focus on killing other units first. Remember that a skeleton used to kill ghouls means a less skeleton to kill adepts. Once vulnerable, use your skeletons, bats and walking corpses to kill them. Make sure that you kill them, as their retaliation damage on their turn will hurt you. If that is not possible, poison them; the ghoul itself will also be a problem for your opponent, who will need to use at least 2-3 units to kill it. When possible, threaten villages with your bats. If you have a lot of walking corpses, use them to whittle down enemy ghouls whenever possible. A loss of a ghoul will definitely force your opponent to retreat. <br />
<br />
On defense, use ghouls and walking corpses to shield your other units. If you can ZOC shield on good terrain especially with ghouls, your opponents will have a very difficult time attacking you without exposing his/her units on bad terrain. Position yourself so that you are the first to attack at night. Regroup at day.<br />
<br />
==Undead vs Northerners:==<br />
An interesting battle as both factions are Chaotic. You'll deal more damage at night, so you should usually be the aggressor at this time. You'll be facing a lot of Whelps and Archers most likely, with maybe some Grunts and other units sparsed in.<br />
<br />
'''Skeleton''': Good for taking out any units except Whelps, you'll want to have a couple of these guys in your front line.<br />
<br />
'''Skeleton Archer''': These guys are less deadly than Skeletons and fall faster to Whelps (they do less return damage). They are a good choice if your opponent recruits Grunts and Spearmen though.<br />
<br />
'''Walking Corpse''': These guys may be useful as they deal Impact damage that will go around Whelp resistancies. Having 1 or 2 of these may prove useful if you can effectively use them to shield your attacking forces or to spawn more allies.<br />
<br />
'''Vampire Bat''': If you need a scout, the Ghost is a far better choice against Northerners. Only the Archer has a decent chance of killing a Ghost whereas a simple Grunt can walk of and cut down a Bat. Grunts are also cheaper than Bats. Don't recruit this unit.<br />
<br />
'''Ghoul''': A good unit to use against Northerners. Their focus on melee wil make nearly every unit that attacks you subject to Poison. With 10% resistance to Blade and Fire they will survive long enough to Poison enough units to be a menace. Having 1 or 2 of this guy will be enough.<br />
<br />
'''Dark Adept''': This guy just kills things. He is your Whelp killing instrument as Whelps will resist your Blade and Pierce attacks 20%. Adepts are good to use against any unit though, as every unit other than the Archer has no significant ranged attack. You'll want several of these in your army, but make sure that they have protection from Grunts and Whelps in both attack and defense.<br />
<br />
'''Ghost''': A great unit to have. Only Archers can reliably take this unit out. His cost is high - especially when compared to the cost of Northerners, but his ability to survive - especially on a village - will make him a thorn in your opponents side. You should be able to see where your opponents archers are, so stay away from them. Use his ranged attack to assist you in killing melee units so that you don't run into a situation of bad luck getting you hurt.<br />
<br />
A good first turn recruit would consist of a Ghost, Skeleton, Ghoul, DA, and another DA, Ghost, or skeleton type. The Ghoul can also be exchanged for a damage dealer.<br />
<br />
Keep your Skeletons and Ghouls up front to deal return damage in defense and against counter-attacks. Ghouls are your best defensive weapon as they will Poison any who attack them, and Archers will need 4 hits with their Fire arrows at night to get you to 1hp.<br />
<br />
Use your DAs to tear through the otherwise hard-to-kill Whelps, and make sure to finish them as fast as possible, or at least Poison them, or you'll waste 8 damage a turn. If your opponent has any Nagas, punish them with your Adepts and Ghosts - you'll deal 120% damage.<br />
<br />
You'll want to press at night and defend at day as usual, but the reason may not be so clear as Northerners are also Chaotic. The reason is that Undead deal more damage per unit, but are also more expensive. At night your ability to quickly tear through units and finish them off is impressive. During the day it is not; if you cannot take out units in your attack you will be swarmed by larger numbers of Northerners that will trap and kill you. The Regeneration of Whelps becomes a much larger effect during the day as well. Because of these reasons you'll want to defend during the day and take out as many units as possible in each night-time attack.<br />
<br />
==Undead vs Rebels:==<br />
You'll likely see a bunch of Woses and Mages in this battle as they are the best unit to deal damage to your forces. Because they are Lawful there will again be a strong day/night push. If your opponent does not recruit many of these units you shouldn't have much of a challenge ahead of you if you simply recruit Skeletons and Archers.<br />
<br />
'''Skeleton''': A necessity. These guys resist Blade and Pierce greatly - the 2 major weapons of Elves. These guys will also chop through Mages and are even good to kill Woses at night. Keep these guys away from Woses and Mages during the day.<br />
<br />
'''Skeleton Archer''': It's better to buy Skeletons than Archers here. Skeletons only cost 1g more but deal more damage on their primary attack and their Blade cuts through Wose resistancies as well as avoids magical return damage from the Mage. Don't recruit this guy unless your opponent recruits no Woses or Mages.<br />
<br />
'''Walking Corpse''': If you can turn 1 or 2 units to your side this unit has paid for himself. Recruit sparingly, though he can be quite useful against Mages if they are foolish enough to stay close after daytime.<br />
<br />
'''Vampire Bat''': Since the Ghost isn't the best bargain against Rebels, if you need a scout unit, the Bat should be your choice. Having more than 1 quickly leads to diminishing returns, so save your gold for units that can fight.<br />
<br />
'''Ghoul''': A decent unit to have 1 of. Fighting Woses at night he deals 5-3 plus prevents Regeneration and takes 10-2 in return. If you can't kill a Wose in one turn, hitting him with a Ghoul is a good idea. Also useful against any Elves that decide to entrench themselves in forest, this guy is a utility unit, not an en-masse unit. He does resist Fire at 10%, so of all your units to take hits from Mages, this is probably the one you want to do it on defense.<br />
<br />
'''Dark Adept''': Good for knocking out Elves in forest, the main reason you'll recruit this guy is to attack Woses without return damage. Showing no weakeness to Fire, the Adept can also kill Mages at night with his 12-2 attack suffering 5-3 in return (if he fails to kill). If your opponent's leader is a White Mage you'll want to recruit even more of these guys as they are your only unit that resists Holy damage and doesn't have a lopsided weakness to it. Good for several reasons, 1 or 2 of this guy is a must.<br />
<br />
'''Ghost''': The ranged specialist Rebels can take out this unit with relative ease; they can even kill it without Mages, though obviously that would be their first choice. Since Mermen and Woses resist Cold, and all other units have high defense or a strong ranged counter-attack, this unit isn't the best buy against Rebels.<br />
<br />
A good first turn recruit would consist of 2 Skeletons, a Ghoul, a DA, perhaps a Bat, and another useful unit. Keep your Ghoul(s) up front during the day to minimize the Rebel offensive, and retreat if necessary.<br />
<br />
On the offensive, kill Woses and Mages as quickly as possible. Hack up Mages first, and freeze and Poison the Woses. If you have any Skeletons left, try to chop down the trees as well. If you have Archers use them on any Elves your opponent has. Bats can be used on Mages, and use WCs on any unit that they have a chance to kill.<br />
<br />
Try to focus xp on single Skeletons. Levelling one into a Deathblade will prove deadly for your opponent. His extra move will hunt down Mages and Elves and his extra strike will ensure their deaths. The unit also becomes a real Wose killer at night dealing up to 50 of 52 damage. Levelling a Bat will also prove a useful Mage hunting tool.<br />
<br />
==Undead vs Knalgans:==<br />
You'll want to catch Knalgans on poor terrain. Dwarves on hills or mountains are hard to move - they usually have to move themselves. To combat this you'll need to use Poison and magic to make them move.<br />
<br />
'''Skeleton''': A good standard unit, Skeletons are only in serious danger from Dwarvish Fighters, of which you will likely face several. This unit can take on all of the Outlaws as well as the dangerous Ulfserker. At night, his 6-3 attacks on Guardsmen will also be quite useful. You'll need one to counter an Ulfserker.<br />
<br />
'''Skeleton Archer''': A good cheap unit who is most in danger from Fighters and Ulfserkers, his role is to pick at Fighters, Gryphons, and Guardsmen, though money is better spent elsewhere.<br />
<br />
'''Walking Corpse''': Not a good unit to combat Dwarves, the WC is better to hold villages against sneaky Gryphons or to kill trapped ones. There's no need to recruit these early.<br />
<br />
'''Vampire Bat''': Do not recruit this unit when fighting Knalgans. The superior Gryphon will easily kill this unit resulting in a loss of 13g.<br />
<br />
'''Ghoul''': A crucial unit in your fight against Knalgans, the Ghoul's Poison should be used to cut through their resistance and make the slow movers retreat from advantageous positions. Also used as a good Gryphon deterrent, this unit is worth having 2 of.<br />
<br />
'''Dark Adept''': The key unit in your arsenal, the DA deals 11-2 damage to Dwarves at night, 10-2 to Guardsmen. Also having the capability to ignore the superior defenses of Knalgans, these guys are invaluable in your nighttime assaults. Their major drawback that is easily exploitable by Knalgans is their lack of melee, so keep them protected at all times.<br />
<br />
'''Ghost''': As Knalgans have no true counter for Ghosts, these scouts should be used exclusively over Bats. Their greatest use is using their ranged attack on melee exclusive units. Their Drain melee and high resistances makes the Ghost essentially impossible for melee units to kill. The sole exception to this is the Ulfserker. At night, and even possibly at dusk/dawn, the Ghost has an excellent chance of killing an Ulfserker with his Drain attack. During the day, however, the Ghost is in real jeopardy of defeat from this unit. Try to keep the ghost from Thunderers as well, as 2 shots will take him down, and you won't want to lose this unit so easily.<br />
<br />
A good first turn recruit would consist of a Ghost, a Skeleton, a Ghoul, a DA, and another useful unit like another Skelton, Archer, or DA. Don't let Dwarves get on mountains if you can stop it. Ghosts are great for this, but Ghouls and Skeletons work nicely too. If Dwarves do end up on mountains either ignore them and make them move to unfavorable terrain, Poison them to force them to move, or use Adepts on them.<br />
<br />
In defense, Ghouls on villages or mountains will prove very bothersome to Knalgans. Keep them in the front line to Poison oncoming attackers. They'll take Thunderer shots (at 13-1), so they'll last a while too. Skeletons are alright to keep in front too, due to their resistances outside of Impact. Make sure your Adepts stay behind so they don't get Ulfs.<br />
<br />
On the offense, you'll want to take out Ulfs first and then anything on poor terrain. Terrain plays a huge factor in the damage you will deal Dwarves, so sometimes it will be better to ignore Dwarves on mountains and to kill other units instead. Adepts can remove problem Dwarves though, so have a couple. At the end of your assault put your Ghouls in front to protect your units and to Poison the surviving forces.<br />
<br />
==See also==<br />
[[How to play Mages]]<br />
<br />
{{Factionbox}}<br />
<br />
[[Category:How to Play]]</div>Edward Chernenkohttps://wiki.wesnoth.org/index.php?title=FilterWML&diff=60110FilterWML2018-12-17T23:16:46Z<p>Edward Chernenko: /* Filtering Vision */ deprecated name of parameter</p>
<hr />
<div>{{WML Tags}}<br />
== Filtering in WML ==<br />
<br />
A ''filter'' is a special WML block.<br />
Filters are used to describe a set of units, hexes, weapons or something else.<br />
Filters are defined as matching something if all the keys in the filter match that thing.<br />
For example, if a unit filter contains two keys,<br />
a unit must match both of the keys in order to match the filter.<br />
<br />
A StandardUnit(Location, Side, ...)Filter is the place where the set of such keys and tags can appear. A StandardFilter sometimes needs an according surrounding tag but often doesn't. It should be mentioned at the place in the wiki where it's said that you can use at a certain code position a StandardFilter whether you need a surrounding tag or not.<br />
<br />
== Filtering Units ==<br />
<br />
Filters are often used in action tags (see [[EventWML]]).<br />
In this case the phrase "standard unit filter" is used in place of the set of standard keys.<br />
Sometimes a filter is used to find the first unit that matches the filter;<br />
for example, the '''[recall]''' tag recalls that unit.<br />
<br />
Standard unit filters are also used in the tags '''[filter]''' and '''[filter_second]'''.<br />
These are subtags of '''[event]''' which describe when the event should trigger.<br />
Most event names (see [[EventWML]]) have units related to them called "primary unit" and "secondary unit".<br />
In order for an event to be triggered, ''primary unit'' must match the filter contained in '''[filter]''',<br />
and ''secondary unit'' must match the filter contained in '''[filter_second]'''.<br />
<br />
See [[StandardUnitFilter]] for details.<br />
<br />
== Filtering Locations ==<br />
<br />
As you have seen, standard unit filter can contain a location filter.<br />
Several actions, such as '''[terrain]''', also use location filters.<br />
Location filters are represented on this site by the phrase "standard location filter".<br />
A common use for location filters is to check the terrain of a space.<br />
<br />
See [[StandardLocationFilter]] for details.<br />
<br />
== Filtering Sides ==<br />
Sometimes, it's needed to get a list of sides which satisfy certain criteria. For this, a side filter can be used.<br />
Side filters are represented on this site by the phrase "standard side filter".<br />
<br />
See [[StandardSideFilter]] for details.<br />
<br />
== Filtering Weapons ==<br />
<br />
Sometimes weapons/attacks are filtered on in WML. See also [[EventWML]], [[EffectWML]], [[AnimationWML]].<br />
<br />
These keys are used as filter input for attack filters.<br />
<br />
* '''range''': a range to filter<br />
** '''melee''': only melee weapons pass <br />
** '''ranged''': only ranged weapons pass <br />
* '''name''': filter on the attack's name. See <code>data/units/</code> or http://www.wesnoth.org/units/ to find the name of a particular unit's attack.<br />
* '''type''': filter on the attack's type. Values are 'blade', 'pierce', 'impact', 'fire', 'cold', and 'arcane'.<br />
* '''damage''': filter on damage value. Can be a specific number or a list of ranges like 'damage=0-5,7-99'<br />
* '''special''': filter on the attack's special power. For values see [[AbilitiesWML]].<br />
* '''special_active''': {{DevFeature1.13|8}} filter on the attack's special power and whether it's active on the current location.<br />
* '''number''': {{DevFeature1.13|5}} filter on number of attacks<br />
* '''parry''': {{DevFeature1.13|5}} filter on parry value<br />
* '''accuracy''': {{DevFeature1.13|5}} filter on accuracy value<br />
* '''movement_used''': {{DevFeature1.13|5}} filter on attack's movement cost<br />
* '''formula''': {{DevFeature1.13|5}} filter using [[Wesnoth Formula Language]]<br />
<br />
'''[and]''', '''[or]''', and '''[not]''' subfilters are also supported.<br />
<br />
== Filtering Vision ==<br />
<br />
The '''[filter_vision]''' tag allows you to filter units or locations based on whether or not the hex is obscured by fog or shroud from the point-of-view of a viewing side, and (in the case of units) whether or not the unit is hidden (via the {{tag|AbilitiesWML|hides}} ability).<br />
<br />
* '''visible''':<br />
** '''yes''' (default): matches when the location is not obscured by fog or shroud for the ''side'' and, when in a SUF, the unit is not hiding.<br />
** '''no''': matches when the location is obscured by fog or shroud for the ''side'' or, when in a SUF, the unit is hiding.<br />
* '''respect_fog''': yes or no, default yes. In a location filter (only), setting this to "no" will cause the test to ignore fog; it becomes a test for shrouded or not shrouded. <br />
** When multiple viewing sides are listed, all of the sides must pass the visibility check in order for the [filter_vision] filter to return a successful match.<br />
** When no viewing sides are listed, all enemy sides must pass the visibility check.<br />
*'''[[StandardSideFilter]]''' tags and keys; all matching sides must be able to see the unit/location. If an empty filter, all sides (instead of only all enemy sides) match. If there is *at least one* matching side which can see the unit / location (accounting for fog / hiding / shroud) then the filter matches, and otherwise it fails to match.<br />
<br />
'''Example:''' This event will fire when the enemy (side 2) moves to a location within the player's (side 1's) field of vision:<br />
[event]<br />
name=moveto<br />
first_time_only=yes<br />
[filter]<br />
side=2<br />
[filter_vision]<br />
side=1 <br />
[/filter_vision]<br />
[/filter]<br />
[message]<br />
speaker=unit<br />
message="I am your enemy. I know that you can see me here."<br />
[/message]<br />
[/event]<br />
<br />
'''Note:''' In a location filter, this tag is only useful when the viewing side is under a fog or shroud. You ''can'' set a shroud over an AI side. This will allow you to use the vision filter from the point-of-view of an AI side. The fog/shroud does not currently affect AI movement patterns, but the AI algorithm may become constrained by fog/shroud in the future.<br />
<br />
== Filtering on WML data ==<br />
<br />
Some places allow you to filter directly on WML data. WML filters are more free-form than other filters, allowing arbitrary WML data that is to be matched. The following conventions are possible:<br />
<br />
* '''key=value''': Means that the key '''key''' must be present with the specified value.<br />
* '''glob_on_key=glob''': {{DevFeature1.15|0}} Means that the key '''key''' must be present with a value that matches the specified glob. In addition to the obvious, this is useful for matching the absence of a key - just place '''glob_on_key=*''' in a '''[not]''' tag.<br />
* '''[some_tag]''': In a WML filter, all tags contain further WML filter data as children. The presence of a tag in the filter means that the WML must have at least one tag '''some_tag''' present, and at least one of the '''some_tag''' tags must match the WML filter contained in '''[some_tag]'''.<br />
* '''[not]''': The WML filter contained in '''[not]''' ''must not'' match the WML.<br />
* '''[and]''': {{DevFeature1.15|0}} In addition to the main filter, the filter contained in '''[and]''' must also match the WML. In most cases this tag is not necessary (the two filters can simply be merged), but in some unusual cases (particularly when globs are involved) it might be needed to get the desired result.<br />
* '''[or]''': {{DevFeature1.15|0}} Adds another filter that is allowed to match in place of the main filter. Note that when combining several WML filters with '''[or]''' tags, the first filter must not be wrapped in '''[or]''' tags - doing so would mean that the first filter is actually an empty filter, which matches everything, meaning the other '''[or]''' tags are irrelevant.<br />
<br />
== Tutorial ==<br />
* [http://wiki.wesnoth.org/FilterWML/Examples_-_How_to_use_Filter How To Use Filter (with examples)]<br />
<br />
== See Also ==<br />
<br />
* [[UnitTypeWML]]<br />
* [[EventWML]]<br />
* [[ReferenceWML]]<br />
<br />
[[Category: WML Reference]]</div>Edward Chernenkohttps://wiki.wesnoth.org/index.php?title=LuaWML/Misc&diff=60109LuaWML/Misc2018-12-16T19:26:57Z<p>Edward Chernenko: typo</p>
<hr />
<div>This page describes miscellaneous [[LuaWML]] objects and helpers.<br />
<br />
==== wesnoth.game_config ====<br />
<br />
Contrarily to the other values of the ''wesnoth'' table, ''game_config'' is simply a proxy table. Its fields offer an interface to the global settings of Wesnoth:<br />
<br />
* '''version''': string (read only)<br />
* '''base_income''': integer (read/write)<br />
* '''village_income''': integer (read/write)<br />
* '''poison_amount''': integer (read/write)<br />
* '''rest_heal_amount''': integer (read/write)<br />
* '''recall_cost''': integer (read/write)<br />
* '''combat_experience''': integer (read/write)<br />
* '''kill_experience''': integer (read/write)<br />
* '''last_turn''': integer (read/write) turn limit, maximum number of turns<br />
* '''debug''': boolean (read only)<br />
* '''mp_debug''': boolean (read only)<br />
* '''campaign_type''': string (read only) Indicates what type of game this is, e.g. "multiplayer"<br />
* '''theme''': {{DevFeature1.13|8}} string (read/write) The ID of the current scenario theme. If the scenario uses the default theme from preferences, this will be an empty string.<br />
* '''mp_settings''': table. In a multiplayer game, this is a proxy table which gives read only access to all MP-only configuration options which appear as attributes of [multiplayer] tag in a save game file:<br />
** '''active_mods''': string (read only) A list of all active modifications<br />
** '''hash''': string (read only) A hash of mp data<br />
** '''mp_campaign''': string (read only) Name of mp campaign<br />
** '''mp_scenario''': string (read only) ID of this mp scenario<br />
** '''mp_scenario_name''': string (read only) Name of this mp scenario<br />
** '''scenario''': string (read only) MP lobby title <br />
** '''difficulty_define''': string (read only) The campaign difficulty string for an mp campaign<br />
** '''mp_village_gold''': integer (read only) <br />
** '''mp_village_support''': integer (read only) <br />
** '''mp_num_turns''': integer (read only) <br />
** '''mp_era''': string (read only) The id of the chosen era<br />
** '''mp_eras''': string (read only) A list of all era ids<br />
** '''mp_fog''': boolean (read only) <br />
** '''mp_shroud''': boolean (read only) <br />
** '''mp_random_start_time''': boolean (read only) <br />
** '''experience_modifier''': integer (read only) <br />
** '''mp_use_map_settings''': boolean (read only) <br />
** '''mp_countdown''': boolean (read only) Whether the timer is enabled<br />
** '''mp_countdown_action_bonus''': integer (read only) <br />
** '''mp_countdown_init_time''': integer (read only) <br />
** '''mp_countdown_reservoir_time''': integer (read only) <br />
** '''mp_countdown_turn_bonus''': integer (read only) <br />
** '''observer''': boolean (read only) <br />
** '''shuffle_sides''': boolean (read only) <br />
** '''savegame''': boolean (read only) Whether this is a reloaded game<br />
** '''side_users''': string (read only) List of how sides are assigned to users (at game start)<br />
* '''era''': table. A proxy table for the entire era tag corresponding to the current era. Its id will always match wesnoth.game_config.mp_settings.mp_era<br />
Note: wesnoth.game_config.mp_settings, and wesnoth.game_config.era, will only exist if wesnoth.game_config.campaign_type == "multiplayer"<br />
<br />
<br />
-- Poison a bit weak? Let's boost it!<br />
wesnoth.game_config.poison_amount = 15<br />
<br />
-- Warn users when they use bad settings:<br />
if (wesnoth.game_config.mp_settings.shuffle_sides) then<br />
wesnoth.message("Warning: This scenario is not intended to be played with shuffle sides!")<br />
end<br />
<br />
-- Collect basic info about the current era:<br />
local era = wesnoth.game_config.era<br />
local helper = wesnoth.require("lua/helper.lua")<br />
local count = 0<br />
wesnoth.set_variable("era_name", era.name)<br />
for multiplayer_side in helper.child_range(era, "multiplayer_side") do<br />
count = count + 1<br />
wesnoth.set_variable("faction" .. tostring(count) .. "_name", multiplayer_side.name)<br />
wesnoth.set_variable("faction" .. tostring(count) .. "_recruit", multiplayer_side.recruit)<br />
end<br />
wesnoth.set_variable("num_factions", count)<br />
<br />
==== wesnoth.get_era ====<br />
<br />
* '''wesnoth.get_era(''id'')'''<br />
<br />
A function which takes one argument, an era id, and returns the entire era tag corresponding to that id. For a list of valid era ids, use wesnoth.game_config.mp_settings.mp_eras.<br />
<br />
==== wesnoth.current ====<br />
<br />
As with ''game_config'', ''current'' is a proxy table. Its fields are getter for game-related properties:<br />
<br />
* '''side''': integer (read only)<br />
* '''turn''': integer (read only)<br />
* '''event_context''': WML table with attributes ''name'', ''x1'', ''y1'', ''x2'', ''y2'', and children ''weapon'', ''second_weapon'', describing the trigger for the current event. {{DevFeature1.13|2}} ''unit_x'', ''unit_y'' contain the location of the primary unit involved in the event. Currently the only case where this cam be different from ''x1'' and ''y1'' are enter_hex and exit_hex events.<br />
* '''synced_state''' {{DevFeature1.13|0}} whether the current code runs in a synced contex, this returns a string, the possible values are:<br />
** '''synced''' the current code runs on all mp clients, this is the normal context, in which all gamestatechaning actions should take place.<br />
** '''unsynced''' for example during '''select''' events or during the calculation of a wesnoth.theme_items, don't change the gamestate in this context because the current code only runs on one machine, so changign the gamestate here will cause OOS. Typical things to do here are UI related things, or entering the synced state via '''[do_command]'''<br />
** '''local_choice''' the current code was invoked by wesnoth.synchronize_choice and runs only on one local client to calculate the return value for wesnoth.synchronize_choice. You cannot enter the synced context with '''[do_command]''' now.<br />
** '''preload''' we are currently running a preload event or an even earlier event, this behaves similar to '''local_choice'''<br />
<br />
wesnoth.message(string.format("Turn %d, side %d is playing.", wesnoth.current.turn, wesnoth.current.side))<br />
<br />
==== wesnoth.end_turn ====<br />
<br />
* '''wesnoth.end_turn ([''next_side''])'''<br />
<br />
like [endturn] actionwml, has a integer parmaeter that allows to specify the next side that should gain control, any integer in the range [1, 2*nsides] is allowed, where a number greater than nsides also changes the turn counter by one.<br />
<br />
==== wesnoth.synchronize_choice ====<br />
<br />
* '''wesnoth.synchronize_choice(''function'', [''ai_function''])'''<br />
* {{DevFeature1.13|2}} '''wesnoth.synchronize_choice([''description''], ''function'', [''ai_function''], [''for_side''])'''<br />
<br />
Recovers a WML table that was computed on one client only or was stored in a replay. The actual computation is performed by the function passed as the first function argument, assuming that the client is the side currently playing. For all the other clients, the function will not be called. An optional second function can be passed; if present, it will be used instead of the first one when the client happens to be an AI (hence not enable to interact with a user interface).<br />
<br />
local result = wesnoth.synchronize_choice(<br />
function()<br />
-- Called only on the client handling the current side, if it is a human.<br />
local choice = 0<br />
wesnoth.show_dialog(<br />
some_dialog_cfg, nil,<br />
function()<br />
choice = wesnoth.get_dialog_value "some_list"<br />
end)<br />
return { value = choice }<br />
end,<br />
function()<br />
-- Called only on the client handling the current side, if it is an AI.<br />
return { value = math.random(some_list_size) }<br />
end)<br />
wesnoth.message(string.format("Selected item: %d", result.value))<br />
<br />
Note: The return value must be a valid WML table - the same kind of thing you could store to a WML variable, and not, for instance, a proxy unit, anything else that uses metatables, or a lua table with another table as the value of a string attribute. Unlike other lua functions, wesnoth.synchronize_choice will NOT throw an error if the table is invalid, but will silently strip out the contents of any invalid subtag.<br />
<br />
When wesnoth is running in debug mode (e.g. --debug flag on command line) synchronize_choice will chat a "Lua Warning" if it finds that the table returned was partially invalid.<br />
<br />
{{DevFeature1.13|2}}<br />
This function takes now takes these arguments:<br />
* An optional translatable string describing the type of the user input. This is displayed to the other clients while one client executes the passed function. Defaults to "input".<br />
* A function: (as before).<br />
* An optional function: for ai sides (as before).<br />
* An optional integer: on which side the function should be evaluated. Defaults to the currently playing side. If the specified side is empty/null controlled the engine will choose another side.<br />
<br />
==== wesnoth.synchronize_choices ====<br />
<br />
* '''wesnoth.synchronize_choices([''description''], ''function'', [''default_function''], [''for_sides''])'''<br />
<br />
{{DevFeature1.13|2}} Similar to the singular form above, this function takes a function parameter and evaluates it on the specified sides. It takes the following arguments:<br />
* An optional translatable string descibing the type of the user input. This is displayed to the other clients while the specified clients execute the passeed function. Defaults to "input"<br />
* A function that evaluates the choice returning a wml table. Unlike above, this function is called for ai and human sides (use if controller == "ai" for checking if it is a ai side)<br />
* An optional function for evaluating the choice in case this side was null controlled. If this function is called, it is called on all clients (unlike the first passed function) defaults to a function returning an empty table.<br />
* An array of integers specifying on which sides this function should be evaluated, the function is evaluated on all passed sides, each side may only appear once in this array. All specified sides execute the function simultaniously.<br />
<br />
This function returns a table with integer as keys and WML tables as values. the keys are the sides where that action was evaluated. The values are the values computed by the passed function.<br />
Example:<br />
[event]<br />
name = "start"<br />
[lua]<br />
code = <<<br />
wesnoth.set_variable("input1",nil)<br />
local result = wesnoth.synchronize_choices(<br />
function()<br />
local option1 = T.option { message = "No", T.command { T.set_variable { name = "input1", value = "No"}}}<br />
local option2 = T.option { message = "Yes", T.command { T.set_variable { name = "input1", value = "Yes"}}}<br />
wesnoth.fire(T.message{ message = "Are you sure you want to play this game?", option1, option2})<br />
return { value = wesnoth.get_variable("input1") }<br />
end,<br />
{1,2})<br />
wesnoth.set_variable("input1",nil)<br />
wesnoth.message("Player 1 wants to play: " .. result[1].value)<br />
wesnoth.message("Player 2 wants to play: " .. result[2].value)<br />
>><br />
[/lua]<br />
[/event]<br />
<br />
==== wesnoth.get_image_size ====<br />
<br />
* '''wesnoth.get_image_size(''filename'')'''<br />
<br />
Returns the width and height of an image.<br />
<br />
local w, h = wesnoth.get_image_size "units/transport/galleon.png"<br />
<br />
==== wesnoth.compare_versions ====<br />
<br />
* '''wesnoth.compare_versions(''version1'', ''operator'', ''version2'')'''<br />
<br />
Takes two versions strings and an operator, returns whether the comparison yields true.<br />
Follows the same rules like the #ifver preprocessor statement.<br />
<br />
local function version_is_sufficient(required)<br />
if not wesnoth.compare_versions then return false end<br />
return wesnoth.compare_versions(wesnoth.game_config.version, ">=", required)<br />
end<br />
local required = "1.9.6"<br />
if not version_is_sufficient(required) then wesnoth.message(string.format(<br />
"Your BfW version is insufficient, please get BfW %s or greater!", required)) end<br />
<br />
==== wesnoth.have_file ====<br />
<br />
* '''wesnoth.have_file(''filename'')'''<br />
<br />
Checks if the file (not necessarily a Lua file) or the directory passed as argument exists. Returns true if the file exists, false otherwise. Follows the same rules like the #ifhave preprocessor statement.<br />
<br />
-- Does the user have installed the UMC Music Book 1?<br />
local umc_music = wesnoth.have_file( "~add-ons/UMC_Music_Book_1/_main.cfg" )<br />
-- and if we want to check for the folder?<br />
local music_folder = wesnoth.have_file( "~add-ons/UMC_Music_Book_1/" )<br />
<br />
==== wesnoth.debug ====<br />
<br />
* '''wesnoth.debug(''wml_table'')'''<br />
<br />
Takes a userdata with metatable wml object or a wml table and dumps its content into a pretty string.<br />
wesnoth.set_variable("number", 100)<br />
local vconfig = wesnoth.tovconfig({ key = "$number", another_key = true,<br />
{"a_subtag", { a_key_in_the_subtag = "foo" }}<br />
})<br />
wesnoth.message(wesnoth.debug(vconfig))<br />
wesnoth.message(wesnoth.debug(vconfig.__literal))<br />
<br />
==== wesnoth.get_time_stamp ====<br />
<br />
* '''wesnoth.get_time_stamp()'''<br />
<br />
This function retrieves the current time stamp, that is the amount of milliseconds passed from when the SDL library was initialized. It takes no arguments and returns an integer.<br />
'''WARNING:''' this function uses the same code as [set_variable] time=stamp, and so it is MP-unsafe. It is provided only for benchmark purposes and AI development, although it should work inside wesnoth.synchronize_choice() as well.<br />
local stamp = wesnoth.get_time_stamp()<br />
<br />
==== wesnoth.random ====<br />
<br />
* '''wesnoth.random([''m'', [''n'']])'''<br />
<br />
{{DevFeature1.13|2}} This function returns a random number generated by the synced random generator which is also used by [set_variable]rand= (and thus also by helper.rand). This function has the same interface as [http://www.lua.org/manual/5.2/manual.html#pdf-math.random math.random] so it can take 0, 1 or 2 arguments.<br />
<br />
In map generation scripts, the values returned by this function depend on the seed the map author has input (if any).<br />
<br />
Be careful as '''random''' is not safe in certain events, see [[EventWML#Multiplayer_safety|Multiplayer_safety]].<br />
<br />
==== wesnoth.unsynced ====<br />
<br />
* '''wesnoth.unsynced(''func'')'''<br />
<br />
calls the given function in a unsynced context, that is in particular, while executing that function random results will not be synced in mp.<br />
<br />
==== wesnoth.compile_formula ====<br />
<br />
* '''wesnoth.compile_formula(''formula'')'''<br />
<br />
{{DevFeature1.13|5}} Compiles a [[Wesnoth Formula Language]] formula into a Lua callable userdata. The callable value returned by this function can take an optional table as argument, which defines variables available to the formula. It can also take a unit proxy as argument, which evaluates the formula in that unit's context just as if it had been used in a [[StandardUnitFilter]].<br />
<br />
A compiled formula can be converted back to valid code using the built-in <code>tostring</code> function.<br />
<br />
==== wesnoth.eval_formula ====<br />
<br />
* '''wesnoth.eval_formula(''formula'', [''variables''])'''<br />
<br />
{{DevFeature1.13|5}} Equivalent to <syntaxhighlight lang='lua' inline>wesnoth.compile_formula(formula)(variables)</syntaxhighlight>. It can also evaluate an already-compiled formula, which is equivalent to calling the formula.<br />
<br />
==== wesnoth.name_generator ====<br />
<br />
* '''wesnoth.name_generator(''type'', ''definition'', [''additional params''])'''<br />
<br />
{{DevFeature1.13|5}} Constructs a name generator for use in generating names using either the Markov chain algorithm used in older versions of Wesnoth or the context-free grammar generator used since 1.13.5. The type parameter indicates which algorithm to use (either markov or cfg). The definition can be a string, just like it would be in a config file, or it can be formatted as a table. Additional parameters may be passed, depending on the type of generator. The function returns a callable userdata, which will return a new name each time it is called (with no parameters).<br />
<br />
* '''Markov chain''': A Markov chain generator works by analyzing a list of input names and noticing tendencies in the way the letters are strung together. It can then apply those tendencies to produce new similar names that were not in the original list. Longer lists give better results. The definition is a list of names, formatted either as a comma-separated string or as an array-like table. The Markov generator can take two additional parameters. The first additional parameter is ''chain_size'', and the second is ''max_length''.<br />
** A value greater than 1 for the chain_size causes the analyzer to consider the words in chunks, which is similar to analyzing them syllable by syllable instead of letter by letter. The default chain size is 2, meaning that the analyzer treats words as consisting of 2-character syllables.<br />
** The max_length places a cap on the total length of the name. The default value is 12 characters.<br />
* '''Context-free grammar''': A [[context-free grammar]] is a way of specifying how strings can be constructed. The definition may be specified as a multi-line string, just as described in the preceding link, or it can be formatted as a table where the keys are non-terminals and the values are what they expand to. The expansion of each non-terminal can be formatted either as a |-separated list as described in the preceding link, or as an array-like table. (Mixing the two forms is permissible too.) The context-free generator has no additional parameters.<br />
<br />
==== wesnoth.format ====<br />
<br />
* '''wesnoth.format(''format_string'', ''values'')'''<br />
<br />
Similar to '''string.format''' but using Wesnoth's variable substitution syntax, and also supporting translatable strings. Any valid config can be passed as the values, though typically you will only need key-value pairs. You could also substitute WML variables into a string by passing '''wesnoth.get_all_vars()''' as the second parameter.<br />
<br />
This function preserves the translatability of the input format string.<br />
<br />
==== wesnoth.format_conjunct_list ====<br />
<br />
* '''wesnoth.format_conjunct_list(''list_of_strings'')'''<br />
<br />
Formats a list of usually-translatable strings into a localized list string of the form "A, B, and C".<br />
<br />
==== wesnoth.format_disjunct_list ====<br />
<br />
* '''wesnoth.format_disjunct_list(''list_of_strings'')'''<br />
<br />
Formats a list of usually-translatable strings into a localized list string of the form "A, B, or C".<br />
<br />
==== helper.set_wml_tag_metatable ====<br />
<br />
* '''helper.set_wml_tag_metatable{}'''<br />
<br />
Sets the metable of a table so that it can be used to create subtags with less brackets. Returns the table. The fields of the table are simple wrappers around table constructors.<br />
<br />
T = helper.set_wml_tag_metatable {}<br />
W.event { name = "new turn", T.message { speaker = "narrator", message = "?" } }<br />
<br />
==== helper.modify_unit ====<br />
<br />
* '''helper.modify_unit(''filter'', ''keys'')'''<br />
<br />
Modifies all the units satisfying the given filter (argument 1) with some WML attributes/objects (argument 2). This is a Lua implementation of the [http://www.wesnoth.org/macro-reference.xhtml MODIFY_UNIT] macro.<br />
<br />
helper.modify_unit({ id="Delfador" }, { moves=0 })<br />
<br />
'''Note:''' This appears to be less powerful than the [modify_unit] tag and may be removed at some point in the future.<br />
<br />
==== helper.move_unit_fake ====<br />
<br />
* '''helper.move_unit_fake(''unit'', ''destination'')'''<br />
<br />
Fakes the move of a unit satisfying the given filter (argument 1) to the given position (argument 2). This is a Lua implementation of the [http://www.wesnoth.org/macro-reference.xhtml MOVE_UNIT] macro.<br />
<br />
helper.move_unit_fake({ id="Delfador" }, 14, 8)<br />
<br />
==== helper.rand ====<br />
<br />
* '''helper.rand(''spec'')'''<br />
<br />
(A shortcut to [[InternalActionsWML#.5Bset_variable.5D|set_variable's rand=]] since math.rand is an OOS magnet and therefore disabled.) Pass a string like you would to set_variable's rand=.<br />
<br />
create a random unit at (1, 1) on side=1 :<br />
wesnoth.put_unit(1, 1, { type = helper.rand("Dwarvish Fighter,Dwarvish Thunderer,Dwarvish Scout") })<br />
<br />
Note that '''random''' is only safe in certain events, see [[EventWML#Multiplayer_safety|Multiplayer Safety]].<br />
<br />
==== helper.round ====<br />
<br />
* '''helper.round(''n'')'''<br />
<br />
Unlike other languages (Python, Perl, Javascript, ...), Lua does not include a round function. This helper function allows rounding numbers, following the "round half away from zero method", see Wikipedia [[http://en.wikipedia.org/wiki/Rounding_numbers#Round_half_away_from_zero]]. Returns the number rounded to the nearest integer.<br />
<br />
-- this number will be rounded up<br />
helper.round(345.67) -- returns 346<br />
-- this one will be rounded down<br />
helper.round(543.21) -- returns 543<br />
-- an integer stays integer<br />
helper.round(123) -- returns 123<br />
-- works also for negative numbers<br />
helper.round(-369.84) -- returns -370<br />
helper.round(-246.42) -- returns -246<br />
<br />
==== helper.shuffle ====<br />
<br />
* '''helper.shuffle(''array'')'''<br />
* {{DevFeature1.13|2}} '''helper.shuffle(''array'', ''[random_function]'')'''<br />
This function randomly sorts in place the elements of the table passed as argument, following the Fisher-Yates algorithm. It returns no value.<br />
'''WARNING:''' this function uses Lua's math.random(), and so it is '''not''' MP-safe. It is provided mainly for AI development, although it should work inside wesnoth.synchronize_choice() as well.<br />
<br />
local locs = wesnoth.get_locations( { terrain="G*" } )<br />
helper.shuffle( locs )<br />
<br />
{{DevFeature1.13|2}}<br />
This function now uses the synced RNG by default and should not cause OOS anymore. It is also possible now to pass a different random generator as a second argument; a random generator is a function that takes two integers <i>a</i> and <i>b</i> and returns a random integer in the range [<i>a</i>,<i>b</i>]. For example, math.random can be passed to get the 1.12 behavior:<br />
<br />
local locs = wesnoth.get_locations( { terrain="G*" } )<br />
helper.shuffle( locs, math.random )<br />
<br />
[[Category: Lua Reference]]</div>Edward Chernenkohttps://wiki.wesnoth.org/index.php?title=InterfaceActionsWML&diff=60097InterfaceActionsWML2018-12-13T15:57:26Z<p>Edward Chernenko: typo</p>
<hr />
<div>{{WML Tags}}<br />
== Interface actions ==<br />
<br />
Part of [[ActionWML]], interface actions are actions that do not have a direct effect on gameplay;<br />
instead, they show something to the player. The main interface tags<br />
are '''[message]''' and '''[objectives]''', but several other tags affect<br />
the interface also.<br />
<br />
== [inspect] ==<br />
This user interface instantly displays the gamestate inspector dialog at the current scenario state (the same one that can be brought up with [[CommandMode|the ''':inspect''' command]]), which can be used to inspect the values of WML variables, AI configuration, recall lists, and more.<br />
<br />
* '''name''': optional attribute to specify the name of this gamestate inspector dialog. It is just a label to help differentiate between different invocations of gamestate inspector dialog.<br />
<br />
== [message] ==<br />
The most commonly used interface action is [message], which displays a message to the user in a dialog box. It can also be used to take input from the user.<br />
<br />
The following key/tags are accepted for [message]:<br />
* [[StandardUnitFilter]]: The unit whose profile and name are displayed. Do not use a [filter] tag. If no unit matching this filter is found, the message is not displayed (The unit has probably been killed).<br>[message] elements should be constructed so that it is either guaranteed that a certain unit is alive, or so that dialog flows smoothly even if the message isn't displayed.<br />
<br />
* '''speaker''': an alternative to standard unit filter. You may specify as the value of the speaker attribute a unit id or any of the following special values:<br />
** '''narrator''': the dialog box is displayed without a caption for the unit speaking or a unit image<br />
** '''unit''': the primary unit for the event is speaking<br />
** '''second_unit''': {{DevFeature1.13|6}} the secondary unit for the event is speaking<br />
<br />
* '''message''': (translatable) the text to display to the right of the image. ''message'' is sometimes multiple lines; if it is, be sure to use quotes(''' ' ''' or ''' " ''')<br />
* '''male_message''', '''female_message''': {{DevFeature1.13|2}} (translatable) Used instead of ''message'' if the unit's gender matches. Never used if there is no unit (ie ''speaker=narrator''). {{DevFeature1.13|6}} This matches the primary unit, not the secondary unit.<br />
* '''wait_description''': {{DevFeature1.13|2}} the description of this message displayed when other players in a mp game wait for one player doing input in a [message] (with [option]s or [text_input]).<br />
* '''[show_if]''': if present then this message will only be displayed if the conditional statement in this tag is passed (see [[ConditionalActionsWML#Condition_Tags|ConditionalActionsWML]])<br />
* '''side_for''': (default: all sides) comma-separated list of sides for who message is shown. This will <b>not</b> work with messages that take user input ([option]/[text_input]), which can only ever be shown to the current player. {{DevFeature1.13|0}} side_for= is now also accepted for messages with user input, it specifies on which side the message is shown (defaults to the currently playing side). For messages with input it does not accept a comma seperated list only a single number.<br />
* '''image''': (default: profile image of speaker) the image to display to the left of the message text. Append ~RIGHT() if you want the image to appear on the right side. <br />
** {{DevFeature1.13|0}} <b>none:</b> display no image<br />
* '''mirror''': {{DevFeature1.13|5}}whether to mirror the image specified by the '''image''' attribute.<br />
* '''second_image''': {{DevFeature1.13|6}}same as the '''image''' attribute, but the image is displayed on the right of the message text.<br />
* '''second_mirror''': {{DevFeature1.13|6}}same as '''mirror''', but for the '''second_image''' attribute.<br />
* '''image_pos''': {{DevFeature1.13|5}} whether to show the image on the left or right; supercedes the use of ~RIGHT() described above<br />
* '''caption''': (default: name of speaker) the caption to display beside the image. Name to be displayed. Note: use a translation mark to avoid wmllint errors.<br />
* '''scroll''': Boolean specifying whether the game view should scroll to the speaking unit. Defaults to ''yes''.<br />
* '''highlight''': {{DevFeature1.13|5}} Boolean specifying whether to highlight the speaker. Defaults to ''yes''.<br />
* '''sound''': a sound effect (wav file) to play as the message is displayed. This can be a comma-separated list, from which one will be randomly chosen.<br />
* '''voice''': {{DevFeature1.13|?}} a sound to be played as the message is displayed. This can also be a comma-separated list, from which one will be randomly chosen. This is intended for voiceovers for the message.<br />
* '''[option]''': No '''[option]''' elements have to be used. If '''[option]''' elements are present, then each option will be displayed in a menu for the user to select one option. ''Note: Messages with options will not be shown at all in prestart events''<br />
** '''message''': (translatable) the text displayed for the option (see [[DescriptionWML]]) {{DevFeature1.13|2}} This is now a synonym for '''label='''.<br />
** '''image''', '''label''', '''description''', '''default''': See [[DescriptionWML#WML_Format|DescriptionWML]].<br />
** '''value''': {{DevFeature1.13|?}} Gives the option a value to be stored in a variable, if this behavior is enabled.<br />
** '''[show_if]''': if present then this option will only be displayed if the conditional statement in this tag is passed (see [[ConditionalActionsWML#Condition_Tags|ConditionalActionsWML]])<br />
** '''[command]''': an element containing actions which are executed if the option is selected.<br />
* '''variable''': {{DevFeature1.13|?}} If present, either the index or the value of the chosen option will be stored in the specified variable.<br />
* '''[text_input]''': there can be only one [text_input] tag. this adds a text input field to the message. ''Note: Messages with text_input will not be shown at all in prestart events''<br />
** '''variable''': the variable that the user's input will be written to<br />
** '''label''': a text label to the left of the input field<br />
** '''max_length''': the maximum number of characters that may be typed into the field<br />
** '''text''': text that is written into the field in the beginning<br />
* Check [[EventWML#Multiplayer_safety]] to find out in which events you can safely use '''[option]''' and '''[text_input]''' without causing OOS.<br />
<br />
=== Formatting ===<br />
'''[message]''' and other tags such as unit names (user_description), objectives, and floating text can make use of [http://developer.gnome.org/pango/unstable/PangoMarkupFormat.html Pango markup formatting codes].<br />
<br />
Remember to use single quotes (') instead of double quotes (") within the formatting string, as double quotes cannot be escaped, and the string will appear fragmented and possibly cause errors. Escaping markup is described in https://github.com/wesnoth/wesnoth/blob/master/src/font/pango/escape.hpp#L35-L39.<br />
<br />
For example, if you wanted to write "You are victorious!" in large, italic, gold letters, you might write it this way:<br />
<br />
<nowiki><span color='#BCB088' size='large' font-style='italic'>You are victorious!</span></nowiki><br />
<br />
<br />
These are the codes taken from the Pango markup formatting guide:<br />
<br />
*'''font''', '''font_desc''': A font description string, such as "Sans Italic 12".<br />
*'''font_family''', '''face''': A font family name.<br />
*'''font_size''', '''size''': Font size in 1024ths of a point, or one of the absolute sizes 'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large', or one of the relative sizes 'smaller' or 'larger'.<br />
*'''font_style''', '''style''': One of 'normal', 'oblique', 'italic'.<br />
*'''font_weight''', '''weight''': One of 'ultralight', 'light', 'normal', 'bold', 'ultrabold', 'heavy', or a numeric weight.<br />
*'''font_variant''', '''variant''': One of 'normal' or 'smallcaps'.<br />
*'''font_stretch''', '''stretch''': One of 'ultracondensed', 'extracondensed', 'condensed', 'semicondensed', 'normal', 'semiexpanded', 'expanded', 'extraexpanded', 'ultraexpanded'.<br />
*'''foreground''', '''fgcolor''', '''color''': An RGB color specification such as '#00FF00' or a color name such as 'red'.<br />
*'''background, bgcolor''': An RGB color specification such as '#00FF00' or a color name such as 'red'.<br />
*'''underline''': One of 'none', 'single', 'double', 'low', 'error'.<br />
*'''underline_color''': The color of underlines; an RGB color specification such as '#00FF00' or a color name such as 'red'.<br />
*'''rise''': Vertical displacement, in 10000ths of an em. Can be negative for subscript, positive for superscript.<br />
*'''strikethrough''': 'true' or 'false' whether to strike through the text.<br />
*'''strikethrough_color''': The color of strikethrough lines; an RGB color specification such as '#00FF00' or a color name such as 'red'<br />
*'''fallback''': 'true' or 'false' whether to enable fallback. If disabled, then characters will only be used from the closest matching font on the system. No fallback will be done to other fonts on the system that might contain the characters in the text. Fallback is enabled by default. Most applications should not disable fallback.<br />
*'''letter_spacing''': Inter-letter spacing in 1024ths of a point.<br />
*'''gravity''': One of 'south', 'east', 'north', 'west', 'auto'.<br />
*'''gravity_hint''': One of 'natural', 'strong', 'line'.<br />
<br />
The following pango attributes are also available directly as attributes of the '''[message]''' tag:<br />
{{DevFeature1.13|4}}<br />
<br />
*'''font'''<br />
*'''font_family'''<br />
*'''font_size'''<br />
*'''font_style'''<br />
*'''font_weight'''<br />
*'''font_variant'''<br />
*'''font_stretch'''<br />
*'''color'''<br />
*'''bgcolor'''<br />
*'''underline'''<br />
*'''underline_color'''<br />
*'''rise'''<br />
*'''strikethrough'''<br />
*'''strikethrough_color'''<br />
*'''fallback'''<br />
*'''letter_spacing'''<br />
*'''gravity'''<br />
*'''gravity_hint'''<br />
<br />
== [objectives] ==<br />
The other tag used for plot development is '''[objectives]'''.<br />
The '''[objectives]''' tag overwrites any previously set objectives,<br />
and displays text which should describe the objectives of the scenario.<br />
Scenario objectives are displayed on the player's first turn after the tag is used,<br />
or as part of the event if it triggers during that player's turn.<br />
Objectives can also be accessed at any time in a scenario using the<br />
"Scenario Objectives" game menu option, making this tag useful for<br />
scenario-specific information that the player may need to refer to during play.<br />
<br />
Attributes of '''[objectives]''':<br />
* '''side''': Default '0'. The side to set the objectives for. A value of 0 sets objectives for all sides. note: There are side-specific objectives and default objectives, which are used in case a side doesn't have specific ones. Specifying 0 sets the default ones.<br />
* '''[[StandardSideFilter]]''' tags and keys: Sets the objectives of all matching sides to these passed specifications (the rest of this [objectives] tag). If no sides (such as when passing side=0) or all sides match, sets the default objectives, and the side specific ones for the matching sides otherwise.<br />
* '''bullet''': Default '• '. Replaces the default bullet, with whatever is passed, for all objectives, gold carryover notes, and notes defined with [note].<br />
* '''summary''': Displayed first in the objectives text, this should describe the basic objective for the overall scenario. Can be omitted.<br />
* '''note''': Displayed last in the objectives text, this is sometimes used for hints or additional information. Can be omitted.<br />
* '''victory_string''': Default ' _ "Victory:"', this text precedes the victory objectives. Can be set to "" too.<br />
* '''defeat_string''': Default ' _ "Defeat:"', this text precedes the defeat objectives. Can be set to "" too.<br />
* '''gold_carryover_string''': Default ' _ "Gold carryover:"', this text precedes the gold carryover information.<br />
* '''notes_string''': Default ' _ "Notes:"', this text precedes the notes.<br />
* '''silent''': Default: not present. If set to "yes", the objectives are silently changed. Else, they will be shown to the user when appropriate.<br />
* '''delayed_variable_substitution''': {{DevFeature1.13|8}} If set to yes, any variables or [insert_tag] are not substituted right away. Instead, they are substituted whenever the objectives are actually viewed.<br />
<br />
Tags of '''[objectives]''':<br />
* '''[objective]''': describes a win or loss condition. Most scenarios have multiple win or loss conditions, so use a separate [objective] subtag for each line; this helps with translations.<br />
** '''bullet''': Default '• ' or whatever is set in the parent [objectives] block. Replaces the default bullet, with whatever is provided, for the objective defined by the [objective] block.<br />
** '''red''': Default '0' for winning objectives, '255' for losing objectives. Overrides the default red coloring of the entire objective, including the bullet.<br />
** '''green''': Default '255' for winning objectives, '0' for losing objectives. Overrides the default green coloring of the entire objective, including the bullet.<br />
** '''blue''': Default '0'. Overrides the default blue coloring of the entire objective, including the bullet.<br />
** '''description''': text for the specific win or loss condition.<br />
** '''caption''': a text which will be displayed above the ''description''. This can be used to display a subcategory of objectives below ''victory_string'' or ''defeat_string''.<br />
** '''condition''': The color and placement of the text. Values are 'win'(colored green, placed after ''victory_string'') and 'lose'(colored red, placed after ''defeat_string'').<br />
** '''show_turn_counter''': If set to yes, displays the number of turns remaining in the scenario. Default is no.<br />
** '''[show_if]''': A condition that disables the objective if it doesn't hold. Conditional objectives are refreshed at '''[show_objectives]''' time only, or when manually opening the scenario objectives.<br />
* '''[gold_carryover]''': describes how the gold carryover works in this scenario. This is intended to be a more convenient way of displaying carryover information than using the note= key in [objectives].<br />
** '''bullet''': Default '• ' or whatever is set in the parent [objectives] block. Replaces the default bullet with whatever is provided.<br />
** '''red''': Default '255'. Overrides the default red coloring of the entire objective, including the bullet.<br />
** '''green''': Default '255'. Overrides the default green coloring of the entire objective, including the bullet.<br />
** '''blue''': Default '192'. Overrides the default blue coloring of the entire objective, including the bullet.<br />
** '''bonus''' (boolean): whether an early finish bonus is granted. If omitted, early finish bonus is not mentioned.<br />
** '''carryover_percentage''': the amount of carryover gold. If omitted, the amount is not mentioned.<br />
** '''[show_if]''': {{DevFeature1.13|11}} Gold carryover will not be shown if the specified condition isn't met. Conditional gold carryover is refreshed at '''[show_objectives]''' time only.<br />
* '''[note]''': describes a note, usually used for hints or additional information. This is an easier way of adding several notes than concatenating them together into a single string to use with the ''note='' key.<br />
** '''bullet''': Default '• ' or whatever is set in the parent [objectives] block. Replaces the default bullet with whatever is provided for the note defined by the [note] block.<br />
** '''red''': Default '255'. Overrides the default red coloring of the entire note, including the bullet.<br />
** '''green''': Default '255'. Overrides the default green coloring of the entire note, including the bullet.<br />
** '''blue''': Default '255'. Overrides the default blue coloring of the entire note, including the bullet.<br />
** '''description''': the text of the note.<br />
** '''[show_if]''': The note will not be shown if the specified condition isn't met. Conditional notes are refreshed at '''[show_objectives]''' time only.<br />
<br />
== [set_menu_item] ==<br />
This tag is used to add a custom option in the right-click context menu which can then be used to trigger arbitrary WML commands. The menu items can be set and modified during any event, for example during "start" or "prestart" events. The user can also assign hotkeys to these WML commands unless specified otherwise. When the hotkey is pressed the event will be fired/filtered at the current mouse position.<br />
<br />
'''Note:''' Due to limitations in portable devices where there are no scroll bars for context menus, there is a hard-coded limit of 7 custom WML menu items. If you really need to have more than 7 menu items, try combining some of them in a submenu. {{DevFeature1.13|0}} This limitation is being removed in a [http://forums.wesnoth.org/viewtopic.php?p=572554#p572554 future version] of Wesnoth.<br />
<br />
* '''id''': the unique id for this menu item. If a menu item with this id already exists, it allows you to set specific changes to that item.<br />
* '''description''': the in-game text that will appear for this item in the menu.<br />
* '''image''': the image to display next to this item.<br />
* '''needs_select''': if ''yes'' (default ''no''), then the latest select event (see [[EventWML]]) that triggered before this menu item was chosen will be transmitted over the network before this menu item action will be. This only has any effect in networked multiplayer, and is intended to allow more elaborate menu item behaviour there without causing out of sync errors. If you don't know what this means, just leave it. {{DevFeature1.13|6}} ''needs_select=yes'' is deprecated, consider using manual variable syncing with [sync_variable].<br />
* '''synced''' {{DevFeature1.13|1}}: if ''no'' (default ''yes'') the command handler will only be run on the client that invoked the menu item; this means that changing the gamestate in a command handler of a menu item with ''synced=no'' will cause OOS<br />
* '''use_hotkey''': if ''no'' (default ''yes''), then the user cannot assign hotkeys to this menu item. If ''only'', the menu item is only accessible via hotkeys, not via right-click context; you can use this in combination with [default_hotkey] if you want custom hotkeys in your campaign/mp. <br />
* '''[show_if]''': If present, the menu item will only be available if the conditional statement (see [[ConditionalActionsWML#Condition_Tags|ConditionalActionsWML]]) within evaluates to true. When this is evaluated, the WML variables ''$x1'' and ''$y1'' will point to the location on which the context menu was invoked, so it's possible to for example only enable the option on empty hexes or on a particular unit.<br />
* '''[filter_location]''': contains a location filter similar to the one found inside Single Unit Filters (see [[FilterWML]]). The menu item will only be available on matching locations.<br />
* '''[default_hotkey]''': contains a hotkey WML to specify what hotkey to assign to this, '''if the user has no hotkey assigned to this yet'''. (Unlike the rest of a menu item definition, modifying this tag has no effect on the game; it is only effective when initially defining a menu item.) Hotkey WML matches the format in the preferences file and contains the following keys:<br />
** '''key''': a string that contains the key to assign to this.<br />
** '''alt''', '''shift''', '''cmd'''(apple only), '''ctrl''': boolean values.<br />
** '''repeat_on_hold''' {{DevFeature1.13|12}}: if ''yes'' (default ''no''), holding the hotkey will repeat the action continuously, unless it blocks input with something like '''[message]'''. Due to a bug, versions older than 1.13.12 always repeat the action, with no way to disable it.<br />
* '''[command]''': contains the WML actions to be executed when the menu item is selected. Again, the WML variables ''$x1'' and ''$y1'' will point to the location on which the context menu was invoked on.<br />
** '''delayed_variable_substitution ''' (boolean yes|no, default: yes): If no, forces a variable substitution run onto the wml included in this [command] block. Use this, if you want variables which are to substitute to get the values they have at execution time of the event where this set_menu_item appears. Other than that, they get the values they have at invocation time of the menu item.<br />
<br />
== [clear_menu_item] ==<br />
<br />
Removes a menu item from the scenario.<br />
Normally menu items are, including all their defining wml, automatically carried over between scenarios. This tag prevents this. (The behavior is comparable to set_variable/clear_variable).<br />
* '''id''': (string): id of the menu item to clear. Can be a comma-separated list.<br />
<br />
== Other interface tags ==<br />
<br />
The following tags are also action tags:<br />
<br />
=== [change_theme] ===<br />
<br />
{{DevFeature1.13|8}}<br />
<br />
Change the current interface theme.<br />
<br />
* '''theme''': The ID of the new theme. Use <code>theme=</code> (empty key) to switch back to the theme that the player has selected in Preferences. On <b>1.14.2</b> and later it is also possible to omit the key entirely to achieve the same effect (on previous versions this will crash the Lua engine).<br />
<br />
=== [item] ===<br />
Makes a graphical item appear on a certain hex. Note this only places the graphics for an item. It does not make the item do anything. Use a moveto event to make moving onto the item do something. <tt>''('''Hint:''' There are a number of predefined items that are used in various campaigns that you can make use of. You can find [http://www.wesnoth.org/macro-reference.xhtml#file:items.cfg a list of them] if you look into the items.cfg file in the wesnoth install directory (under /data/core/macros).)''</tt><br />
* '''x''', '''y''': the location to place the item. (only for [event][item]: full [[StandardLocationFilter|SLF]] support)<br />
* '''image''': the image (in ''images/'' as .png) to place on the hex. This image is aligned with the top-left of the hex (which is 72 pixels wide and 72 pixels tall). It is drawn underneath units. ''('''Hint:''' If using an image smaller than 72x72, then it might be useful to [[ImagePathFunctionWML#Blit_Function|BLIT]] the image onto <tt>misc/blank-hex.png</tt> (a blank 72x72 image).)''<br />
* '''halo''': an image to place centered on the hex. It is drawn on top of units. Use this instead of ''image'' if the image is bigger than the hex or if you want to animate an image.<br />
* '''name''' an id that can be used to remove the item.<br />
''Example (where the integer after the colon is the duration of each frame or square bracket expansion as per AnimationWML is used): halo=scenery/fire1.png:100,scenery/fire2.png:100,scenery/fire3.png:100,scenery/fire4.png:100,scenery/fire5.png:100,scenery/fire6.png:100,scenery/fire7.png:100,scenery/fire8.png:100''<br />
or equivalently (requires Wesnoth 1.11.2+):<br />
''halo=scenery/fire[1~8].png:100''<br />
* '''team_name''': name of the team for which the item is to be displayed (hidden for others). For multiple teams just put all the names in one string, for example separated by commas. {{DevFeature1.15|0}} In 1.14 the '''[side]team_name''' attribute was expected to be a substring of this '''team_name'''. In 1.15 both are expected to be comma-separated lists of names and the item is visible if the lists intersect. ([[https://github.com/wesnoth/wesnoth/pull/3533|#3533]])<br />
* '''visible_in_fog''': whether the item should be visible through fog or not. Default yes.<br />
* '''redraw''': (boolean yes|no, default: yes): If no, disables implicit calls to [[InterfaceActionsWML#.5Bredraw.5D|[redraw]]] when placing the items.<br />
* '''[filter_team]''': {{DevFeature1.15|0}} A [[StandardSideFilter]]. Set '''team_name''' to the union of all '''[side]team_name''' attributes of all sides that match the SSF. ([[https://github.com/wesnoth/wesnoth/pull/3533|#3533]])<br />
* {{DevFeature1.15|0}} If both '''team_name''' and '''[filter_team]''' are set, '''team_name''' is ignored.<br />
<br />
=== [remove_item] ===<br />
Removes any graphical items on a given hex.<br />
* [[StandardLocationFilter]]: the hexes to remove items off<br />
* '''image''' if specified, only removes the given image item (This image name must include any [[ImagePathFunctionWML|image path functions]] appended to the original image name.)<br />
<br />
=== [print] ===<br />
Displays a message across the screen. The message will disappear after a certain time.<br />
* '''text''': (translatable) the text to display.<br />
* '''size''': (default=12) the pointsize of the font to use<br />
* '''duration''': (default=50) the length of time to display the text for. This is measured in the number of 'frames'. A frame in Wesnoth is usually displayed for around 30ms.<br />
* '''red''', '''green''', '''blue''': (default=0,0,0) the color to display the text in. Values vary from 0-255. {{DevFeature1.13|x}} Use of red, green, blue is now deprecated; use color=0,0,0 instead.<br />
<br />
=== [move_unit_fake] ===<br />
Moves an image of a unit along a certain path on the map. The path does not need to be a continuous list of adjacent hexes, so for example only the start and end points can be given, in which case the straightest line between those points will be calculated and used.<br />
* '''type''': the type of the unit whose image to use<br />
* '''x''': a comma-separated list of x locations to move along<br />
* '''y''': a comma-separated list of y locations to move along (x and y values are matched pairs)<br />
* '''side''': the side of the fake unit, used for team-coloring the fake unit<br />
* '''gender''': the gender of the fake unit. Example: gender=female<br />
* '''variation''': the variation of the fake unit. Example: variation=undead<br />
* '''image_mods''': [[ImagePathFunctionWML|image path functions]] sequence to be applied on the fake unit.<br />
* '''force_scroll''': Whether to scroll the map or not even when [[#.5Block_view.5D|[lock_view]]] is in effect or ''Follow Unit Actions'' is disabled in ''Advanced Preferences''. Defaults to ''yes'' starting with version '''1.11.6'''; the attribute did not exist in previous versions and this action behaved as if ''no'' was passed instead.<br />
<br />
=== [move_units_fake] ===<br />
moves multiple images of units along paths on the map. These units are moved in lockstep.<br />
* '''force_scroll''': {{DevFeature1.15|0}} Has the same meaning as in [move_unit_fake] but a different default.<br />
* '''[fake_unit]''': A fake unit to move<br />
** '''type''': the type of unit whose image to use<br />
** '''x''': a comma-separated list of x locations to move along<br />
** '''y''': a comma-separated list of y locations to move along (x and y values are matched pairs)<br />
** '''side''': the side of the fake unit, used for team-coloring the fake unit<br />
** '''skip_steps''': the number of steps to skip before this unit starts moving<br />
<br />
=== [hide_unit] ===<br />
Temporarily prevents the engine from displaying the given unit. The unit does not become invisible, as it would be with the '''[hides]''' ability; it is still the same plain unit, but without an image. Useful in conjunction with '''[move_unit_fake]''': to move a leader unit into position on-screen. Until 1.8 each '''[hide_unit]''' tag only hides one unit.<br />
* [[StandardUnitFilter]]: All matching units will be hidden<br />
<br />
=== [unhide_unit] ===<br />
Stops the currently hidden units from being hidden.<br />
* [[StandardUnitFilter]]: Only the matching units will be unhidden<br />
<br />
=== [lock_view] ===<br />
Locks gamemap view scrolling for human players, so they cannot scroll the gamemap view until it is unlocked. WML or Lua actions such as '''[scroll_to]''' will continue to work normally, as they ignore this restriction; the locked/unlocked state is preserved when saving the current game.<br />
<br />
This feature is generally intended to be used in cutscenes to prevent the player scrolling away from scripted actions.<br />
<br />
{{DevFeature1.13|8}} This now also blocks the player from zooming the gamemap view. WML or Lua zoom will continue to work normally.<br />
<br />
=== [unlock_view] ===<br />
Unlocks gamemap view scrolling for human players.<br />
<br />
=== [scroll] ===<br />
Scroll a certain number of pixels in a given direction. Useful for earthquake/shaking effects.<br />
* '''x''', '''y''': the number of pixels to scroll along the x and y axis<br />
* '''side''': the side or sides for which this should happen. By default, the [scroll] happens for everyone.<br />
* '''[filter_side]''': a [[StandardSideFilter]] to select the sides for which this should happen. By default, the [scroll] happens for everyone.<br />
<br />
=== [scroll_to] ===<br />
Scroll to a given hex<br />
* [[StandardLocationFilter]], do not use a [filter_location] sub-tag. If more than one location matches the filter, only the first matching location will be used.<br />
* '''check_fogged''': whether to scroll even to locations covered in fog or shroud. Possible values ''yes'' (don't scroll to fog) and ''no'' (scroll even to fog), with ''no'' as the default.<br />
* '''immediate''': whether to instantly warp to the target hex regardless of the scroll speed setting in Preferences (defaults to ''no'').<br />
* '''highlight''': {{DevFeature1.13|5}} Whether to highlight the hex being scrolled to (defaults to ''no'').<br />
* '''side''': the side or sides for which this should happen. By default, the [scroll_to] happens for everyone.<br />
* '''[filter_side]''': a [[StandardSideFilter]] to select the sides for which this should happen. By default, the [scroll_to] happens for everyone.<br />
<br />
=== [scroll_to_unit] ===<br />
Scroll to a given unit<br />
* [[StandardUnitFilter]]<br />
* '''check_fogged''': whether to scroll even to locations covered in fog or shroud. Possible values ''yes'' (don't scroll to fog) and ''no'' (scroll even to fog), with ''no'' as the default.<br />
* '''immediate''': whether to instantly warp to the target hex regardless of the scroll speed setting in Preferences (defaults to ''no'').<br />
* '''highlight''': {{DevFeature1.13|5}} Whether to highlight the hex the unit is on (defaults to ''no'').<br />
* '''for_side''': the side or sides for which this should happen. By default, the [scroll_to_unit] happens for everyone.<br />
* '''[for_side]''': a [[StandardSideFilter]] to select the sides for which this should happen. By default, the [scroll_to_unit] happens for everyone.<br />
<br />
=== [select_unit] ===<br />
Selects a given unit.<br />
* [[StandardUnitFilter]]: The first unit found will be selected.<br />
* '''fire_event''': whether a ''select'' event should be triggered or not (def. ''no''). (Note that select events aren't multiplayer save.)<br />
* '''highlight''': whether the unit's current hex should be highlighted (def. ''yes'').<br />
<br />
=== [sound]===<br />
Plays a sound<br />
* '''name''': the filename of the sound to play (in ''sounds/'' as .wav or .ogg). This can be a comma-separated list, from which one sound will be chosen randomly.<br />
* '''repeat''': repeats the sound for a specified additional number of times (default=0)<br />
<br />
=== [sound_source] ===<br />
Creates a sound source. "Sound sources" is a general name for a mechanism which makes possible for map elements to emit sounds according to some rules, where "map elements" can be specific locations or terrain types. For now, only sound sources tied to locations are supported.<br />
* '''id''': a unique identification key of the sound source<br />
* '''sounds''': a list of comma separated, randomly played sounds associated with the sound source<br />
* '''delay''': a numerical value (in milliseconds) of the minimal delay between two playbacks of the source's sound if the source remains visible on the screen; if one scrolls out and back in, the source will be considered as ready to play<br />
* '''chance''': a percentage (a value from 0 to 100) describing the chance of the source being activated every second after the delay has passed or when the source's location appears on the screen (note that it cannot play more than one file at the same time)<br />
* '''check_fogged''': possible values ''yes'' and ''no'' - ''yes'' means the source will not play if its locations are fogged<br />
* '''check_shrouded''': possible values ''yes'' and ''no'' - ''yes'' means the source will not play if its locations are shrouded<br />
* '''x,y''': similar to x,y as found in a [[StandardLocationFilter]], these are the locations associated with the sound source<br />
* '''fade_range''' (default = 3): distance in hexes that determines a "circular" area around the one specified by '''full_range''' where sound volume fades out linearly<br />
* '''full_range''' (default = 14): distance in hexes that determines a "circular" area where source plays with full volume, relative to screen center<br />
* '''loop''': number of times a sound sample should be looped if it stays visible. -1 means infinite (~65000)<br />
<br />
=== [story] ===<br />
{{DevFeature1.13|8}}<br />
<br />
Shows the story screen.<br />
* '''title''': Default title used if a part does not specify one — unlike the intro storyscreen, the scenario name is not used as a default title.<br />
* '''[part]''': As [[IntroWML]].<br />
<br />
=== [remove_sound_source] ===<br />
Removes a previously defined sound source.<br />
* '''id''': the identification key of the sound source to remove<br />
<br />
=== [music]===<br />
Switches to playing different music<br />
* '''name''': the filename of the music to play (in ''music/'' as .ogg)<br />
* see [[MusicListWML]] for the correct syntax<br />
===[volume]===<br />
Changes the game volume to a percent of the preferences volume for the game being played. Values can go from 0 to 100: <br />
* '''music''': Changes the music volume.<br />
* '''sound''': Changes the sound volume.<br />
=== [color_adjust]===<br />
Tints the color of the screen.<br />
* '''red''', '''green''', '''blue''': values from -255 to 255, the amount to tint by for each color<br />
=== [delay] ===<br />
Pauses the game.<br />
* '''time''': the time to pause in milliseconds<br />
* '''accelerate ''' (boolean yes|no, default no): {{DevFeature1.13|0}} whether the delay is affected by acceleration. When [delay] is used to make an animation, this should be set to yes so that your animation matches the ones generated by the game.<br />
<br />
=== [redraw] ===<br />
Redraws the screen (this normally isn't done during events, although some of the other interface actions cause the screen or parts of it to be redrawn).<br />
* '''clear_shroud''' (boolean yes|no, default no): If yes, clears fog and shroud around existing units. Useful if you, for example, spawn friendly units in the middle of an event and want the shroud to update accordingly (otherwise units that spawn inside fog would remain invisible for the duration of the event, since the fog would not automatically get cleared around them).<br />
* '''[[StandardSideFilter]]''': the sides for which to recalculate fog and shroud.<br />
* '''side''': If used (forces clear_shroud=yes), clears fog and shroud for that side.<br />
<br />
=== [unit_overlay] ===<br />
Sets an image that will be drawn over a particular unit, and follow it around<br />
* [[StandardUnitFilter]]: All matching units will get the overlay (do not use [filter])<br />
* '''image''': the image to place on the unit<br />
<br />
=== [remove_unit_overlay] ===<br />
removes a particular overlayed image from a unit<br />
* [[StandardUnitFilter]]: The overlay will get removed from all matching units (do not use [filter])<br />
* '''image''': the image to remove from the unit<br />
<br />
=== [animate_unit] ===<br />
Uses an animation of a unit to animate it on screen (if the unit has the corresponding animation).<br />
* '''flag''': The key to find the custom animation in the unit description (see the '''[extra_anim]''' description in [[AnimationWML]]). Standard animations can be triggered with the following keywords: ''leading recruited standing idling levelout levelin healing healed poisoned movement defend attack death victory pre_teleport post_teleport''<br />
* '''[filter]''' with a [[StandardUnitFilter]] as argument, see [[FilterWML]]. By default, the unit at the event location will be animated. You can use this tag to choose any other unit to animate.<br />
* '''[primary_attack]''': If this tag is not present, the filter for animation will be triggered with no attack. If it is here, all attacks from the unit will be filtered, and a matching one will be used to filter the animation. Takes a weapon filter as argument, see [[FilterWML]].<br />
* '''[secondary_attack]''': Similar to '''[primary_attack]'''. May be needed to trigger a defense animation correctly, if there are more than one animations available for the defending unit.<br />
* '''hits''': yes/no/hit/miss/kill: which according variation of a attack/defense animation shall be chosen (required)<br />
* '''text''': a text to hover during the animation <br />
* '''male_text''', '''female_text''': {{DevFeature1.13|2}} (translatable) gender-specific versions of the above<br />
* '''red''': red value for the text color (0-255)<br />
* '''green''': green value for the text color<br />
* '''blue''': blue value for the text color<br />
* '''with_bars''': yes/no: whether to display the status bars during the animation (e.g. the hitpoint bar)<br />
* '''[animate]''': a sub block with the same syntax as '''[animate_unit]''' except that the '''[filter]''' block is mandatory to find the unit. This block will find and animate another unit simultaneously.<br />
* '''[facing]''': a [[StandardLocationFilter]] specifying what direction the unit should be facing when animated<br />
<br />
=== [label] ===<br />
Places a label on the map.<br />
* '''x''', '''y''': the location of the label. {{DevFeature1.13|1}} (only for [event][label]: full [[StandardLocationFilter|SLF]] support)<br />
* '''text''': what the label should say<br />
* '''team_name''': if specified, the label will only be visible to the given team.<br />
* '''color''': color of the label. The format is r,g,b; r, g and b are numbers between 0 and 255.<br />
* '''visible_in_fog''': whether the label should be visible through fog or not. Default yes.<br />
* '''visible_in_shroud''': whether the label should be visible through shroud or not. Default no.<br />
* '''immutable''': whether this label is protected from being removed or changed by players. Default yes.<br />
* '''category''': the Show/Hide Labels dialog allows showing/hiding all labels of a given category by toggling a checkbox.<br />
* '''tooltip''': A tooltip visible when mouseovering the hex the label is on<br />
* '''side''': the number of the side that placed the label. Can be 0 for labels placed by WML.<br />
<br />
=== [floating_text]===<br />
Floats text (similar to the damage and healing numbers) on the given locations.<br />
* [[StandardLocationFilter]]: the text will be floated on all matching locations simultaneously.<br />
* '''text''': the text to display.<br />
<br />
The default text color is <span style="color: #6b8cff;">'''#6b8cff'''</span>. To change the color, use [[#Formatting|Pango markup]]. For example:<br />
<br />
<pre><br />
# Float some golden yellow text at 20,20.<br />
[floating_text]<br />
x,y=20,20<br />
text="<span color='#cccc33'>" + _ "Your text here" + "</span>"<br />
[/floating_text]<br />
</pre><br />
<br />
=== [deprecated_message] ===<br />
Shows a deprecated message in the message area, this feature is only intended to be used to warn about deprecated macros in mainline. The message is not translatable.<br />
* '''message''': the message to show.<br />
* '''level''': {{DevFeature1.13|10}} The deprecation level, a number from 1 to 3.<br />
* '''what''': {{DevFeature1.13|10}} The name of the thing being deprecated. Use this instead of '''message''' if possible; a stock message will be generated from it. Use '''message''' only if more information is required; it will be appended to the stock message. This should not be translatable<br />
* '''version''': {{DevFeature1.13|10}} For deprecation levels 2 and 3, this indicates the version in which the feature could be removed. It does ''not'' indicate the version in which it became deprecated. <br />
<br />
The meanings of the deprecation levels are as follows:<br />
<br />
# Deprecated, but will only be removed if absolutely necessary. The '''version''' key is ignored.<br />
# It will be removed no earlier than a specified version.<br />
# It will be removed in the next stable version<br />
# It has already been removed, leaving just a stub to inform users of how to update their code.<br />
<br />
Note that as of 1.13.11, deprecation messages show only in the log, not in the chat message area. The '''message''' can be translatable, but does not need to be.<br />
<br />
=== [wml_message] ===<br />
Outputs a message to Wesnoth's console output. Intended for campaign designers to output silent text to the console, without annoying the player; then, that text might contain information useful for later bug-reporting. The log domain for it is '''wml''', and the '''debug/dbg''' log level is available for use with the '''logger''' attribute. Depending on the current log level ('''error''' by default), which may be changed with the in-game :log command, or the --log-<level>=wml command line switch, the messages are echoed to the in-game chat.<br />
* '''message''': the message to show.<br />
* '''logger''': the Wesnoth engine output logger that should catch the text; this might be 'err' (the errors log level), 'warn'/'wrn' (the warnings log level) or anything else (the information log level). Not all information will be displayed depending on the log level chosen when starting Wesnoth.<br />
<br />
Note: As of 1.9.4/1.9.5 (r48805) the following "loggers" should work: If in [wml_message]: err/error, warn/wrn/warning, debug/dbg; using the :log command: Only the long forms error, warning, info and debug (this part gathered by trying rather than source inspecting). The long forms are most likely also the only ones working when starting wesnoth with --log-<level>=wml.<br />
For log level warning or error (as during normal play), only wml_messages with logger error or warning display (for both). With logger info or debug, additionally wml_messages with logger info or debug display (for both).<br />
<br />
=== [test_condition] ===<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Evaluates the contained conditional tags. If they evaluate to the expected value, it prints out a message to the console explaining which part of the condition caused this result in a way similar to [wml_message]. This can be used if your conditional test is failing and you're not sure why.<br />
<br />
* '''result''': Whether you expect the conditions to fail or succeed. If no (the default), a message will be printed if the conditional tags fail. If yes, a message will instead be printed if the conditional tags pass.<br />
* '''logger''': Same as for [wml_message]. Defaults to "warning".<br />
<br />
=== [open_help] ===<br />
Opens the in-game help.<br />
* '''topic''': the id of the topic to open<br />
=== [show_objectives] ===<br />
refreshes the objectives defined by [objectives] and its [show_if] tags, and displays them. (It is also called whenever the user explicitly asks for the objectives; this matters only if the tag was overridden by a [[LuaWML#register_wml_action|Lua]] script.)<br />
* '''side''': the side to show the objectives. If not set, all sides are used.<br />
* '''[[StandardSideFilter]]''' tags and keys: Tag affects the matching sides instead of just all or the one given by the integer value of the side= key.<br />
<br />
=== [chat] ===<br />
Displays a message in the chat area, not visible for observers. Alternative unconditionally visible for everyone: [[LuaWML:Display#wesnoth.message]]. {{DevFeature1.13|9}} can be visible for observers.<br />
* '''speaker''': (default="WML") A string for the name of the sender of the message.<br />
* '''message''': The message that should be displayed.<br />
* '''observable''' (boolean yes|no, default yes): {{DevFeature1.13|9}} Whether the message is displayed for observers.<br />
* '''[[StandardSideFilter]]''' tags and keys as argument; if the same client controls multiple sides that match, then the message will only be displayed once.<br />
<br />
=== [zoom] ===<br />
<br />
{{DevFeature1.13|8}}<br />
<br />
Changes the zoom level of the map.<br />
<br />
* '''factor''': The new zoom factor<br />
* '''relative''': If yes, zoom relative to current zoom level. Otherwise, set the absolute zoom level. Default no.<br />
<br />
== Useful Macros ==<br />
There are some predefined macros that you find useful for interface actions. You can find a complete list along with a detailed explanation of how they work [http://www.wesnoth.org/macro-reference.xhtml here].<br />
* '''{HIGHLIGHT_UNIT}''' Highlight a unit on the map. Use this to show important units<br />
* '''{HIGHLIGHT_IMAGE}''' Places and highlights an image on the map. Use this to show important items or locations<br />
* '''{SET_IMAGE}''' Places an image on the map which has no other function.<br />
* '''{QUAKE <soundfile>}''' Creates a tremor-like screenshake and plays <soundfile>. For example, '''{QUAKE (rumble.ogg)}'''.<br />
* '''{FLASH_WHITE}''' Flash the screen white momentarily. You can also replace WHITE with RED, BLUE or GREEN for a different colour.<br />
<br />
== See Also ==<br />
* [[DirectActionsWML]]<br />
* [[InternalActionsWML]]<br />
* [[EventWML]]<br />
* [[ReferenceWML]]<br />
<br />
<br />
[[Category: WML Reference]]<br />
[[Category: ActionsWML]]</div>Edward Chernenkohttps://wiki.wesnoth.org/index.php?title=LuaWML/Variables&diff=60095LuaWML/Variables2018-12-12T21:55:33Z<p>Edward Chernenko: typo (missing ")</p>
<hr />
<div>This page describes the [[LuaWML]] functions and helpers for handling WML variables and containers.<br />
<br />
==== wesnoth.get_variable ====<br />
<br />
* '''wesnoth.get_variable(''var_name'')'''<br />
<br />
Loads a WML variable with the given qualified name (argument 1) and converts it into a Lua object. Returns ''nil'' if the name does not point to anything, a scalar for a WML attribute, and a table for a WML object. The format of the table is described in [[LuaWML#Encoding WML objects into Lua tables]].<br />
<br />
<syntaxhighlight lang=lua><br />
wesnoth.fire("store_unit", { variable="my_unit", { "filter", { id="hero" } } })<br />
local heros_hp = wesnoth.get_variable("my_unit[0].hitpoints")<br />
wesnoth.message(string.format("The 'hero' unit has %d hitpoints.", heros_hp))<br />
</syntaxhighlight><br />
<br />
Argument 2, if ''true'', prevents the recursive conversion when the name points to an object; a fresh empty table is returned in this case. This is mainly used for writing proxy objects, e.g. in [[#helper.set_wml_var_metatable]].<br />
<br />
Note that, if the variable name happens to designate a sequence of WML objects, only the first one (index 0) is fetched. If all the WML objects with this name should have been returned, use [[#helper.get_variable_array]] instead.<br />
<br />
==== wesnoth.set_variable ====<br />
<br />
* '''wesnoth.set_variable(''var_name'', ''value'')'''<br />
<br />
Converts and stores a Lua object (argument 2) to a WML variable (argument 1). A WML object is created for a table, an attribute otherwise.<br />
<br />
<syntaxhighlight lang=lua><br />
wesnoth.set_variable("my_unit.hitpoints", heros_hp + 10)<br />
</syntaxhighlight><br />
<br />
Setting a WML variable to nil erases it.<br />
<br />
==== wesnoth.get_all_vars ====<br />
<br />
* '''wesnoth.get_all_vars()'''<br />
<br />
{{DevFeature1.13|0}} Returns all the WML variables currently set in form of a WML table. This function accepts no arguments.<br />
<br />
<syntaxhighlight lang=lua><br />
for key, value in pairs( wesnoth.get_all_vars() ) do<br />
if type( value ) == "table" then<br />
print( key, value[1], value[2] )<br />
else<br />
print( key, value )<br />
end<br />
end<br />
</syntaxhighlight><br />
<br />
==== wesnoth.wml_matches_filter ====<br />
<br />
* '''wesnoth.wml_matches_filter(''config'', ''filter'')'''<br />
<br />
Test if a config matches a WML filter (as <tt>[filter_wml]</tt>).<br />
<br />
==== helper.set_wml_var_metatable ====<br />
<br />
* '''helper.set_wml_var_metatable{}'''<br />
<br />
Sets the metatable of a table so that it can be used to access WML variables. Returns the table. The fields of the tables are then proxies to the WML objects with the same names; reading/writing to them will directly access the WML variables.<br />
<br />
<syntaxhighlight lang=lua><br />
helper.set_wml_var_metatable(_G)<br />
my_persistent_variable = 42<br />
</syntaxhighlight><br />
<br />
It's not recommended to use helper.set_wml_var_metatable(_G) because that limits possible global variables to valid wml attributes or tables. This can have some surprising effects:<br />
<br />
<syntaxhighlight lang=lua><br />
c = { a= 9}<br />
d = c<br />
c.a = 8<br />
wesnoth.message(d.a) -- normally prints 8 but prints 9 with helper.set_wml_var_metatable(_G)<br />
<br />
local lla = { {"a", {}}}<br />
lla[1][2] = lla<br />
la = lla -- crashes wesnoth with helper.set_wml_var_metatable(_G)<br />
<br />
helper = wesnoth.require("lua/helper.lua")<br />
helper.set_wml_var_metatable(_G)<br />
-- some code later (maybe in another addon)<br />
H = wesnoth.require("lua/helper.lua") -- fails because wesnoth.require("lua/helper.lua") doesn' return a valid wmltable..<br />
<br />
helper = wesnoth.require("lua/helper.lua")<br />
helper.set_wml_var_metatable(_G)<br />
-- some code later (maybe in another addon)<br />
T = helper.set_wml_tag_metatable {} -- doesn't work<br />
V = helper.set_wml_var_metatable({}) -- doesn't work<br />
</syntaxhighlight><br />
<br />
Even if you don't use such code in your addon, it's still bad because other code of modifications or eras to be used with your addon might. And you'll mess up their code. This is also true for SP campaigns because it might interfere with ai code and we plan to enable modifications in SP too.<br />
Instead you should use set_wml_var_metatable with another table ('V' in this example):<br />
<br />
<syntaxhighlight lang=lua><br />
V = helper.set_wml_var_metatable({})<br />
V.my_persistent_variable = 42<br />
</syntaxhighlight><br />
<br />
==== helper.get_child ====<br />
<br />
* '''helper.get_child(''config'', ''child_tag_name'')'''<br />
<br />
Returns the first sub-tag of a WML object with the given name.<br />
<br />
<syntaxhighlight lang=lua><br />
local u = wesnoth.get_units({ id = "Delfador" })[1]<br />
local costs = helper.get_child(u.__cfg, "movement_costs")<br />
wesnoth.message(string.format("Delfador needs %d points to move through a forest.", costs.forest))<br />
</syntaxhighlight><br />
<br />
If a third parameter is passed, only children having a ''id'' attribute equal to it are considered.<br />
<br />
==== helper.get_nth_child ====<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
* '''helper.get_nth_child(''config'', ''child_tag_name'', ''n'')'''<br />
<br />
Returns the ''n''th sub-tag of a WML object with the given name.<br />
<br />
==== helper.child_count ====<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
* '''helper.child_count(''config'', ''child_tag_name'')<br />
<br />
Returns the number of children in the config with the given tag name.<br />
<br />
==== helper.child_range ====<br />
<br />
* '''helper.child_range(''config'', ''child_tag_name'')'''<br />
<br />
Returns an iterator over all the sub-tags of a WML object with the given name.<br />
<br />
<syntaxhighlight lang=lua><br />
local u = wesnoth.get_units({ id = "Delfador" })[1]<br />
for att in helper.child_range(u.__cfg, "attack") do<br />
wesnoth.message(tostring(att.description))<br />
end<br />
</syntaxhighlight><br />
<br />
==== helper.child_array ====<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
* '''helper.child_array(''config'', ''child_tag_name'')'''<br />
<br />
Like helper.child_range, but returns an array instead of an iterator. Useful if you need random access to the children.<br />
<br />
==== helper.get_variable_array ====<br />
<br />
* '''helper.get_variable_array(''var_name'')'''<br />
* {{DevFeature1.13|8}} '''helper.get_variable_array(''var_name'' [, ''context''])'''<br />
<br />
Fetches all the WML container variables with given name and returns a table containing them (starting at index 1). The context specifies where to get variables from. You can pass either a unit or a side as the context in order to get an array from the unit variables or side variables, respectively.<br />
<br />
<syntaxhighlight lang=lua><br />
function get_recall_list(side)<br />
wesnoth.fire("store_unit", { x = "recall", variable = "LUA_recall_list" })<br />
local l = get_variable_array "LUA_recall_list"<br />
wesnoth.set_variable "LUA_recall_list"<br />
return l<br />
end<br />
</syntaxhighlight><br />
<br />
==== helper.get_variable_proxy_array ====<br />
<br />
* '''helper.get_variable_proxy_array(''var_name'')'''<br />
<br />
Creates proxies for all the WML container variables with given name and returns a table containing them (starting at index 1). This function is similar to [[#helper.get_variable_array]], except that the proxies can be used for modifying WML containers.<br />
<br />
==== helper.set_variable_array ====<br />
<br />
* '''helper.set_variable_array(''varname'', ''array'')'''<br />
* {{DevFeature1.13|8}} '''helper.set_variable_array(''varname'', ''array'' [, ''context''])'''<br />
<br />
Creates WML container variables with given name from given table. The context specifies where to put the variables. You can pass either a unit or a side as the context in order to set an array in the unit variables or side variables, respectively.<br />
<br />
<syntaxhighlight lang=lua><br />
helper.set_variable_array("target", { {t=t1}, {t=t2}, {t=t3} })<br />
-- target[0].t <- t1; target[1].t <- t2; target[2].t <- t3<br />
</syntaxhighlight><br />
<br />
[[Category: Lua Reference]]</div>Edward Chernenkohttps://wiki.wesnoth.org/index.php?title=LuaAPI/gui&diff=60087LuaAPI/gui2018-12-08T21:41:39Z<p>Edward Chernenko: /* gui.show_menu */ right-column text parameter is called "details", not "second_label". Latter does nothing and isn't mentioned anywhere in the code</p>
<hr />
<div>{{DevFeature1.15|0}}<br />
<br />
==== gui.show_menu ====<br />
<br />
* '''gui.show_menu'''(''items'' [, ''initial''] [, ''markup'']) &rarr; ''index''<br />
<br />
Shows a popup menu onscreen at the current mouse location. This could be used for example to produce a sort of submenu in a <tt>[set_menu_item]</tt>. The items are specified as a Lua array of tables, each of which supports the following keys:<br />
<br />
* ''icon'': An icon to display in the leftmost column of the menu.<br />
* ''image'': An image to display in the main column of the menu. If this is present, ''label'' is ignored.<br />
* ''label'': A label to display in the main column of the menu.<br />
* ''details'': A secondary label to display in the right column of the menu.<br />
* ''tooltip'': Text to display when mousing over this option.<br />
<br />
The ''initial'' argument must be a valid index into the ''items'' array, or 0 to indicate that no element is initially selected (which is the default but typically not what you want).<br />
<br />
The ''markup'' argument specifies whether Pango markup will be parsed in the menuitems. It defaults to false.<br />
<br />
The ''initial'' and ''markup'' arguments can be passed in either order; the game will understand which is meant based on the type of the argument.<br />
<br />
This function returns the index of the selected item. If the user cancelled by clicking outside the menu's boundary, 0 is returned.<br />
<br />
==== gui.show_narration ====<br />
<br />
* '''gui.show_narration'''(''attributes'', [''options'', [''text_input_attributes'']]) &rarr; ''result_code'' [, ''entered_text'']<br />
<br />
Shows a message dialog, of the type used by the <tt>[message]</tt> ActionWML tag. Unlike the <tt>[message]</tt> tag, this is unsynced; if you need it synced, you must do it yourself. The first argument is a table describing the dialog with the following keys:<br />
<br />
* ''title'' - The title to show on the message. For example, the speaker's name.<br />
* ''message'' - The message content.<br />
* ''portrait'' - An image to show along with the message. By default, no image is shown.<br />
* ''left_side'' - The default is true; set to false to show the image on the right.<br />
* ''mirror'' - If true, the image will be flipped horizontally.<br />
<br />
The second argument is a list of options as a Lua array. Each option is either a (possibly-translatable) string or a config with [[DescriptionWML#WML_Format|DescriptionWML]] keys. The array itself can also have an optional '''default''' key which if present should be the index of the initially selected option (useful if you don't need full DescriptionWML but want to set a default). If present it overrides any defaults set in individual options.<br />
<br />
The third argument is a table describing the text input field with the following keys:<br />
<br />
* ''label'' - A label to show to the left of the text field.<br />
* ''text'' - Initial contents of the text field.<br />
* ''max_length'' - Maximum input length in characters (defaults to 256).<br />
<br />
You need at least one key for the text input to be shown. Both the second and third arguments are optional, but if you want text input with no options, you must pass nil for the second parameter.<br />
<br />
This function returns one or two values. The first value returned is the numeric result of the dialog:<br />
<br />
* If there are no options and no text input, the result is -2 if the user pressed Escape, or -1 if they closed by clicking or pressing Space.<br />
* If there are options, the result is the index of the option chosen (starting from 1).<br />
* If there is text input but no options, the first return value is 0.<br />
<br />
The second value returned is the text entered, if there was text input. Otherwise there is no second value (it is nil).<br />
<br />
Example:<br />
<br />
<syntaxhighlight lang='lua'><br />
gui.show_narration({<br />
title = "Make your choice:",<br />
message = "Select an option and enter some text.",<br />
portrait = "wesnoth-icon.png",<br />
}, {<br />
"The first choice is always the best!",<br />
"Pick me! Second choices are better!",<br />
"You know you want the third option!",<br />
}, {<br />
label = "Text:",<br />
text = "?",<br />
max_length = 16<br />
})<br />
</syntaxhighlight><br />
<br />
(You don't have to format it like that, of course.)<br />
<br />
==== gui.show_popup ====<br />
<br />
* '''gui.show_popup'''(''title'', ''message'', [''image''])<br />
<br />
Shows a simple popup dialog in the centre of the screen. Takes three arguments, which in order are:<br />
<br />
# A title string for the dialog<br />
# The message content for the dialog.<br />
# An image to show.<br />
<br />
Both the title and the message support Pango markup. The image is optional.<br />
<br />
==== gui.show_prompt ====<br />
<br />
* '''gui.show_prompt'''(''title'', ''message'' [, ''button''] [, ''markup'']) &rarr; ''result''<br />
* '''wesnoth.confirm'''([''title'',] ''message'') &rarr; ''result''<br />
* '''wesnoth.alert'''([''title''], ''message'')<br />
<br />
Shows a standard message box onscreen (similar to the quit confirmation message, for example). The button can be any arbitrary potentially-translatable string (in which case, there will be one button with that label), or it can be one of the following special string values:<br />
<br />
* ''ok'' or nil: A single OK button; this is the default<br />
* ''cancel'': A single Cancel button<br />
* ''close'': A single Close button<br />
* ''ok_cancel'': Two buttons labelled OK and Cancel<br />
* ''yes_no'': Two buttons labelled Yes and No<br />
* an empty string: No buttons; the dialog automatically closes after a few seconds<br />
<br />
The alert and confirm functions are simpler wrappers for this function, using a single OK button and a pair of Yes/No buttons, respectively. Both confirm and show_prompt return false if No or Cancel was clicked, and true otherwise. The alert function returns nothing.<br />
<br />
==== gui.show_story ====<br />
<br />
* '''gui.show_story'''(''story_config'', ''default_title'')<br />
<br />
Shows the storyscreen. The passed config is identical to the contents of [[IntroWML|[story]]]. The second parameter is the default title used if a part does not specify one — unlike intro storyscreens, a Lua-invoked one does not default to the scenario name.<br />
<br />
[[Category:Lua Reference]]</div>Edward Chernenkohttps://wiki.wesnoth.org/index.php?title=LuaWML/Display&diff=60086LuaWML/Display2018-12-08T21:41:25Z<p>Edward Chernenko: /* wesnoth.show_menu */ right-column text parameter is called "details", not "second_label". Latter does nothing and isn't mentioned anywhere in the code</p>
<hr />
<div>This page describes the [[LuaWML]] functions and helpers for interfacing with the user.<br />
<br />
==== wesnoth.message ====<br />
<br />
* '''wesnoth.message([''speaker'',] ''message'')'''<br />
<br />
Displays a string in the chat window and dumps it to the lua/info log domain (''--log-info=scripting/lua'' on the command-line).<br />
<br />
wesnoth.message "Hello World!"<br />
<br />
The chat line header is "<Lua>" by default, but it can be changed by passing a string before the message.<br />
<br />
wesnoth.message("Big Brother", "I'm watching you.") -- will result in "&lt;Big Brother&gt; I'm watching you."<br />
<br />
See also [[LuaWML:Events#helper.wml_error|helper.wml_error]] for displaying error messages.<br />
<br />
==== wesnoth.clear_messages ====<br />
<br />
* '''wesnoth.clear_messages()'''<br />
<br />
Removes all messages from the chat window. No argument or returned values.<br />
<br />
==== wesnoth.textdomain ====<br />
<br />
* '''wesnoth.textdomain(''domain'')'''<br />
<br />
Creates a function proxy for lazily translating strings from the given domain.<br />
<br />
-- #textdomain "my-campaign"<br />
-- the comment above ensures the subsequent strings will be extracted to the proper domain<br />
_ = wesnoth.textdomain "my-campaign"<br />
wesnoth.set_variable("my_unit.description", _ "the unit formerly known as Hero")<br />
<br />
The metatable of the function proxy appears as '''"message domain"'''. The metatable of the translatable strings (results of the proxy) appears as '''"translatable string"'''.<br />
<br />
The translatable strings can be appended to other strings/numbers with the standard '''..''' operator. Translation can be forced with the standard '''tostring''' operator in order to get a plain string.<br />
<br />
wesnoth.message(string.format(tostring(_ "You gain %d gold."), amount))<br />
<br />
==== wesnoth.delay ====<br />
<br />
* '''wesnoth.delay(''milliseconds'')'''<br />
<br />
Delays the engine like the [delay] tag. one argument: time to delay in milliseconds<br />
<br />
wesnoth.delay(500)<br />
<br />
==== wesnoth.float_label ====<br />
<br />
* '''wesnoth.float_label(''x'', ''y'', ''text'')'''<br />
<br />
Pops some text above a map tile.<br />
<br />
wesnoth.float_label(unit.x, unit.y, "&lt;span color='#ff0000'&gt;Ouch&lt;/span&gt;")<br />
<br />
==== wesnoth.get_viewing_side ====<br />
<br />
* '''wesnoth.get_viewing_side()'''<br />
<br />
returns two values 1) the number of the side of the current viewpoint, 2) a boolean specifying whether it has full vision (can only only true happen in replays or for observers)<br />
<br />
==== wesnoth.select_unit ====<br />
<br />
* '''wesnoth.select_hex(''x'', ''y'', [''show_movement'', [''fire_events'']])'''<br />
* {{DevFeature1.13|5}} '''wesnoth.select_unit(''unit'', [''show_movement'', [''fire_events'']])'''<br />
* {{DevFeature1.13|5}} '''''unit'':select([''show_movement'', [''fire_events'']])'''<br />
<br />
Selects the given unit in the game map as if the player had clicked on it.<br />
Argument 3: boolean, whether to show the movement range of any unit on that location (def: true)<br />
Argument 4: boolean, whether to fire any select events (def: false). Note: currently (1.14.1), this argument has no effect (events are never fired).<br />
<br />
wesnoth.select_unit(14,6, true, true)<br />
<br />
The '''wesnoth.select_hex''' form is deprecated. If there is a unit on the location, it does the same thing as '''wesnoth.select_unit''', but if ''show_movement'' is true it also calls '''wesnoth.highlight_hex''' for the location. If there is no unit on the location, '''wesnoth.select_hex''' does not do anything useful.<br />
<br />
If called without arguments, '''wesnoth.select_unit''' deselects the current unit from the map as long as the mouse cursor is not on its hex. It will continue to be displayed on the UI sidebar in any case.<br />
<br />
==== wesnoth.highlight_hex ====<br />
<br />
* '''wesnoth.highlight_hex(''x'', ''y'')'''<br />
<br />
Draws an outline around the specified hex.<br />
<br />
==== wesnoth.deselect_hex ====<br />
<br />
* '''wesnoth.deselect_hex()'''<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Reverses any select_hex call, leaving all locations unhighlighted. Takes no arguments.<br />
<br />
==== wesnoth.scroll_to_tile ====<br />
<br />
* '''wesnoth.scroll_to_tile(''x'', ''y'', [''only_if_visible'', [''instant'']])'''<br />
* {{DevFeature1.13|7}} '''wesnoth.scroll_to_tile(''x'', ''y'', [''only_if_visible'', [''instant'', [''only_if_needed'']]])'''<br />
<br />
Scrolls the map to the given location. If true is passed as the third parameter, scrolling is disabled if the tile is hidden under the fog. If true is passed as the fourth parameter, the view instantly warps to the location regardless of the scroll speed setting in Preferences. If true is passed as the fifth parameter, no scrolling occurs if the target location is already visible onscreen.<br />
<br />
local u = wesnoth.get_units({ id = "hero" })[1]<br />
wesnoth.scroll_to_tile(u.x, u.y)<br />
<br />
==== wesnoth.lock_view ====<br />
<br />
* '''wesnoth.lock_view(''lock'')'''<br />
<br />
Locks or unlocks gamemap view scrolling for human players. If true is passed as the first parameter, the view is locked; pass false to unlock.<br />
<br />
Human players cannot scroll the gamemap view as long as it is locked, but Lua or WML actions such as wesnoth.scroll_to_tile still can; the locked/unlocked state is preserved when saving the current game. This feature is generally intended to be used in cutscenes to prevent the player scrolling away from scripted actions.<br />
<br />
wesnoth.lock_view(true)<br />
wesnoth.scroll_to_tile(12, 14, false, true)<br />
<br />
==== wesnoth.view_locked ====<br />
<br />
* '''wesnoth.view_locked()'''<br />
<br />
Returns a boolean indicating whether gamemap view scrolling is currently locked.<br />
<br />
==== wesnoth.play_sound ====<br />
<br />
* '''wesnoth.play_sound(''sound'', [''repeat_count''])'''<br />
<br />
Plays the given sound file once, optionally repeating it one or more more times if an integer value is provided as a second argument (note that the sound is ''repeated'' the number of times specified in the second argument, i.e. a second argument of 4 will cause the sound to be played once and then repeated four more times for a total of 5 plays. See the example below).<br />
<br />
wesnoth.play_sound "ambient/birds1.ogg"<br />
wesnoth.play_sound("magic-holy-miss-3.ogg", 4) -- played 1 + 4 = 5 times<br />
<br />
==== wesnoth.set_music ====<br />
<br />
* '''wesnoth.set_music(''music_entry'')'''<br />
<br />
Sets the given table as an entry into the music list. See [[MusicListWML]] for the recognized attributes.<br />
<br />
wesnoth.set_music { name = "traveling_minstrels.ogg" }<br />
<br />
Passing no argument forces the engine to take into account all the recent changes to the music list. (Note: this is done automatically when sequences of WML commands end, so it is useful only for long events.)<br />
<br />
{{DevFeature1.13|8}} This function is now deprecated. Use the '''wesnoth.music_list''' table instead<br />
<br />
==== wesnoth.music_list ====<br />
<br />
{{DevFeature1.13|8}}<br />
<br />
This is a table giving access to the current music playlist. It can be accessed as a normal array, including the Lua length operator. If you assign a music config to an entry, the track is replaced. It is not a normal array however and cannot be manipulated with the table library.<br />
<br />
In addition, it has the following named fields:<br />
<br />
* '''wesnoth.music_list.current''' (read-write): The currently-playing track. This may sometimes be a track that's not on the playlist - "play once" tracks are not placed on the playlist.<br />
* '''wesnoth.music_list.current.__cfg''' (read-only): Returns a copy of the current track information.<br />
* '''wesnoth.music_list.previous''' (read-write): The track played before the current one. This may sometimes be a track that's not on the playlist - "play once" tracks are not placed on the playlist.<br />
* '''wesnoth.music_list.previous.__cfg''' (read-only): Returns a copy of the previous track information. NOTE: Wesnoth's playlist implementation effectively "plays" every song as it's added to the playlist, so when replacing one playlist with another, this will return information on the second-to-last track added to the new playlist, not the track you actually heard playing from the playlist that was replaced.<br />
* '''wesnoth.music_list.current_i''' (read-write): The index of the currently-playing track on the playlist, or nil if the currently-playing track is not on the playlist.<br />
* '''wesnoth.music_list.volume''' (read-write): The current music volume, as a percentage of the user's preferred volume set in preferences.<br />
* '''wesnoth.music_list.all''' (read-only): Returns a copy of the music list as an array of WML tables.<br />
<br />
It also contains some functions:<br />
<br />
* '''wesnoth.music_list.add(''track_name'', [''immediate'',] [''ms_before'', [''ms_after'']])''': Appends a track to the playlist. If true is passed, also start playing the new track.<br />
* '''wesnoth.music_list.remove(''n1'', ...)''': Removes one or more tracks by their index. You can pass as many indices as you wish. If one of the removed tracks is currently playing, it continues to play.<br />
* '''wesnoth.music_list.clear()''': Clears the playlist. The currently-playing track continues to play.<br />
* '''wesnoth.music_list.next()''': Stop playing the current track and move on to the next one. This honours the shuffle settings.<br />
* '''wesnoth.music_list.play(''track_name'')''': Start playing a track without appending it to the playlist.<br />
<br />
Each track contains the following fields:<br />
<br />
* '''shuffle''' (read-write)<br />
* '''once''' (read-write): generally only true for '''wesnoth.music_list.current'''<br />
* '''ms_before''' (read-write)<br />
* '''ms_after''' (read-write)<br />
* '''immediate''' (read-only)<br />
* '''name''' (read-only): the unresolved track filename<br />
* '''title''' (read-only): a user-friendly track title<br />
<br />
==== wesnoth.sound_volume ====<br />
<br />
{{DevFeature1.13|8}}<br />
<br />
* '''wesnoth.sound_volume(''new_volume'')'''<br />
<br />
Sets the current sound volume, as a percentage of the user's preferred volume set in preferences.<br />
Returns the previous sound volume in the same format.<br />
<br />
==== wesnoth.show_menu ====<br />
<br />
* '''wesnoth.show_menu(''items'' [, ''initial''] [, ''markup''])'''<br />
<br />
Shows a popup menu onscreen at the current mouse location. This could be used for example to produce a sort of submenu in a <tt>[set_menu_item]</tt>. The items are specified as a Lua array of tables, each of which supports the following keys:<br />
<br />
* ''icon'': An icon to display in the leftmost column of the menu.<br />
* ''image'': An image to display in the main column of the menu. If this is present, ''label'' is ignored.<br />
* ''label'': A label to display in the main column of the menu.<br />
* ''details'': A secondary label to display in the right column of the menu.<br />
* ''tooltip'': Text to display when mousing over this option.<br />
<br />
The ''initial'' argument must be a valid index into the ''items'' array, or 0 to indicate that no element is initially selected (which is the default but typically not what you want).<br />
<br />
The ''markup'' argument specifies whether Pango markup will be parsed in the menuitems. It defaults to false.<br />
<br />
The ''initial'' and ''markup'' arguments can be passed in either order; the game will understand which is meant based on the type of the argument.<br />
<br />
==== wesnoth.show_message_box ====<br />
<br />
* '''wesnoth.show_message_box(''title'', ''message'' [, ''button''] [, ''markup''])'''<br />
* '''wesnoth.confirm([''title'',] ''message'')'''<br />
* '''wesnoth.alert([''title''], ''message'')'''<br />
<br />
Shows a standard message box onscreen (similar to the quit confirmation message, for example). The button can be any arbitrary potentially-translatable string (in which case, there will be one button with that label), or it can be one of the following special values:<br />
<br />
* ''ok'' or nil: A single OK button; this is the default<br />
* ''cancel'': A single Cancel button<br />
* ''close'': A single Close button<br />
* ''ok_cancel'': Two buttons labelled OK and Cancel<br />
* ''yes_no'': Two buttons labelled Yes and No<br />
* an empty string: No buttons; the dialog automatically closes after a few seconds<br />
<br />
The alert and confirm functions are simpler wrappers for this function, using a single OK button and a pair of Yes/No buttons, respectively. Both confirm and show_message_box return false if No or Cancel was clicked, and true otherwise.<br />
<br />
==== wesnoth.show_message_dialog ====<br />
<br />
* '''wesnoth.show_message_dialog(''attributes'', [''options'', [''text_input_attributes'']])'''<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Shows a message dialog, of the type used by the [message] ActionWML tag. Unlike the [message] tag, this is unsynced; if you need it synced, you must do it yourself. The first argument is a table describing the dialog with the following keys:<br />
<br />
* ''title'' - The title to show on the message. For example, the speaker's name.<br />
* ''message'' - The message content.<br />
* ''portrait'' - An image to show along with the message. By default, no image is shown.<br />
* ''left_side'' - The default is true; set to false to show the image on the right.<br />
* ''mirror'' - If true, the image will be flipped horizontally.<br />
<br />
The second argument is a list of options as a Lua array. Each option is either a (possibly-translatable) string or a config with [[DescriptionWML#WML_Format|DescriptionWML]] keys. The array itself can also have an optional '''default''' key which if present should be the index of the initially selected option (useful if you don't need full DescriptionWML but want to set a default). If present it overrides any defaults set in individual options.<br />
<br />
The third argument is a table describing the text input field with the following keys:<br />
<br />
* ''label'' - A label to show to the left of the text field.<br />
* ''text'' - Initial contents of the text field.<br />
* ''max_length'' - Maximum input length in characters (defaults to 256).<br />
<br />
You need at least one key for the text input to be shown. Both the second arguments are option, but if you want text input with no options, you must pass nil for the second parameter.<br />
<br />
This function returns two values. The first is the numeric result of the dialog. If there are no options and no text input, this is -2 if the user closed by pressing Escape, otherwise it's -1. If there are options, this is the index of the option chosen (starting from 1). If there is text input but no options, the first return value is 0. If there was text input, the second value contains the text entered.<br />
<br />
Example:<br />
<br />
wesnoth.show_message_dialog({<br />
title = "Make your choice:",<br />
message = "Select an option and enter some text.",<br />
portrait = "wesnoth-icon.png",<br />
}, {<br />
"The first choice is always the best!",<br />
"Pick me! Second choices are better!",<br />
"You know you want the third option!",<br />
}, {<br />
label = "Text:",<br />
text = "?",<br />
max_length = 16<br />
})<br />
<br />
(You don't have to format it like that, of course.)<br />
<br />
==== wesnoth.show_popup_dialog ====<br />
<br />
* '''wesnoth.show_popup_dialog(''title'', ''message'', [''image''])'''<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Shows a simple popup dialog in the centre of the screen. Takes three arguments, which in order are:<br />
<br />
# A title string for the dialog<br />
# The message content for the dialog.<br />
# An image to show.<br />
<br />
Both the title and the message support Pango markup. The image is optional.<br />
<br />
==== wesnoth.show_story ====<br />
<br />
* '''wesnoth.show_story(''story_config'', ''default_title'')'''<br />
<br />
{{DevFeature1.13|8}}<br />
<br />
Shows the storyscreen. The passed config is identical to the contents of [[IntroWML|[story]]]. The second parameter is the default title used if a part does not specify one — unlike intro storyscreens, a Lua-invoked one does not default to the scenario name.<br />
<br />
==== wesnoth.show_dialog ====<br />
<br />
* '''wesnoth.show_dialog(''wml_dialog_table'', [''pre_show_function'', [''post_show_function'']])'''<br />
<br />
Displays a dialog box described by a WML table and returns:<br />
* if the dialog was dismissed by a button click, the integer value associated to the button via the "return_value" keyword.<br />
* if the dialog was closed with the enter key, -1.<br />
* if the dialog was closed with the escape key, -2.<br />
<br />
The dialog box is equivalent to the resolution section of a GUI window as described in [[GUIToolkitWML#Window_definition|GUIToolkitWML]] and must therefore contain at least the following children: '''[tooltip]''', '''[helptip]''', and '''[grid]'''. The [grid] must contain nested [row], [column] and [grid] tags which describe the layout of the window. (More information can be found in [[GUILayout]]; suffice to say that the basic structure is grid -> row -> column -> widget, where the widget is considered to be in a cell defined by the row and column of the grid. A list of widgets can be found at [[GUIWidgetInstanceWML]].)<br />
<br />
Two optional functions can be passed as second and third arguments; the first one is called once the dialog is created and before it is shown; the second one is called once the dialog is closed. These functions are helpful in setting the initial values of the fields and in recovering the final user values. These functions can call the [[#wesnoth.set_dialog_value]], [[#wesnoth.get_dialog_value]], and [[#wesnoth.set_dialog_callback]] functions for this purpose.<br />
<br />
This function should be called in conjunction with [[LuaWML:Misc#wesnoth.synchronize_choice|#wesnoth.synchronize_choice]], in order to ensure that only one client displays the dialog and that the other ones recover the same input values from this single client.<br />
<br />
The example below defines a dialog with a list and two buttons on the left, and a big image on the right. The ''preshow'' function fills the list and defines a callback on it. This ''select'' callback changes the displayed image whenever a new list item is selected. The ''postshow'' function recovers the selected item before the dialog is destroyed.<br />
<br />
<syntaxhighlight lang=lua><br />
local helper = wesnoth.require "lua/helper.lua"<br />
local T = helper.set_wml_tag_metatable {}<br />
local _ = wesnoth.textdomain "wesnoth"<br />
<br />
local dialog = {<br />
T.tooltip { id = "tooltip_large" },<br />
T.helptip { id = "tooltip_large" },<br />
T.grid { T.row {<br />
T.column { T.grid {<br />
T.row { T.column { horizontal_grow = true, T.listbox { id = "the_list",<br />
T.list_definition { T.row { T.column { horizontal_grow = true,<br />
T.toggle_panel { return_value = -1, T.grid { T.row {<br />
T.column { horizontal_alignment = "left", T.label { id = "the_label" } },<br />
T.column { T.image { id = "the_icon" } }<br />
} } }<br />
} } }<br />
} } },<br />
T.row { T.column { T.grid { T.row {<br />
T.column { T.button { id = "ok", label = _"OK" } },<br />
T.column { T.button { id = "cancel", label = _"Cancel" } }<br />
} } } }<br />
} },<br />
T.column { T.image { id = "the_image" } }<br />
} }<br />
}<br />
<br />
local function preshow()<br />
local t = { "Ancient Lich", "Ancient Wose", "Elvish Avenger" }<br />
local function select()<br />
local i = wesnoth.get_dialog_value "the_list"<br />
local ut = wesnoth.unit_types[t[i]].__cfg<br />
wesnoth.set_dialog_value(string.gsub(ut.profile, "([^/]+)$", "transparent/%1"), "the_image")<br />
end<br />
wesnoth.set_dialog_callback(select, "the_list")<br />
for i,v in ipairs(t) do<br />
local ut = wesnoth.unit_types[v].__cfg<br />
wesnoth.set_dialog_value(ut.name, "the_list", i, "the_label")<br />
wesnoth.set_dialog_value(ut.image, "the_list", i, "the_icon")<br />
end<br />
wesnoth.set_dialog_value(2, "the_list")<br />
select()<br />
end<br />
<br />
local li<br />
local function postshow()<br />
li = wesnoth.get_dialog_value "the_list"<br />
end<br />
<br />
local r = wesnoth.show_dialog(dialog, preshow, postshow)<br />
wesnoth.message(string.format("Button %d pressed. Item %d selected.", r, li))<br />
</syntaxhighlight><br />
<br />
==== wesnoth.set_dialog_value ====<br />
<br />
* '''wesnoth.set_dialog_value(''value'', ''path, to, widget, id'')'''<br />
<br />
Sets the value of a widget on the current dialog. The value is given by the first argument; its semantic depends on the type of widget it is applied to. The last argument is the ''id'' of the widget. If it does not point to a unique widget in the dialog, some discriminating parents should be given on its left, making a path that is read from left to right by the engine. The row of a list is specified by giving the ''id' of the list as a first argument and the 1-based row number as the next argument.<br />
<br />
-- sets the value of a widget "bar" in the 7th row of the list "foo"<br />
wesnoth.set_dialog_value(_"Hello world", "foo", 7, "bar")<br />
<br />
Notes: When the row of a list does not exist, it is created. The value associated to a list is the selected row.<br />
<br />
==== wesnoth.get_dialog_value ====<br />
<br />
* '''wesnoth.get_dialog_value(''path, to, widget, id'')'''<br />
<br />
Gets the value of a widget on the current dialog. The arguments described the path for reaching the widget (see [[#wesnoth.set_dialog_value]]).<br />
<br />
{{DevFeature1.13|0}}<br />
For treeviews this function returns a table descibing the currently selected node.<br />
If for example in this treeview<br />
+Section1<br />
+Subsection11<br />
*Item1<br />
*Item2<br />
*Item3<br />
+Subsection12<br />
*Item4<br />
*Item5<br />
*Item6<br />
+Section2<br />
+Subsection21<br />
*Item7<br />
*Item8<br />
*Item9<br />
+Subsection22<br />
*Item10<br />
*Item11<br />
*Item12<br />
Item 9 is selcted the value will be {2,1,3}<br />
<br />
==== wesnoth.set_dialog_active ====<br />
<br />
* '''wesnoth.set_dialog_active(''active?'', ''path, to, widget, id'')'''<br />
<br />
Enables or disables a widget. The first argument is a boolean specifying whether the widget should be active (true) or inactive (false). The remaining arguments are the path to locate the widget in question (see [[#wesnoth.set_dialog_value]]).<br />
<br />
==== wesnoth.set_dialog_callback ====<br />
<br />
* '''wesnoth.set_dialog_callback(''callback_function'', ''path, to, widget, id'')'''<br />
<br />
Sets the first argument as a callback function for the widget obtained by following the path of the other arguments (see [[#wesnoth.set_dialog_value]]). This function will be called whenever the user modifies something about the widget, so that the dialog can react to it.<br />
<br />
==== wesnoth.set_dialog_markup ====<br />
<br />
* '''wesnoth.set_dialog_markup(''allowed?'', ''path, to, widget, id'')'''<br />
<br />
Sets the flag associated to a widget to enable or disable Pango markup. The new flag value is passed as the first argument (boolean), and the widget to modify is obtained by following the path of the other arguments (see [[#wesnoth.set_dialog_value]]). Most widgets start with Pango markup disabled unless this function is used to set their flag to true.<br />
<br />
wesnoth.set_dialog_markup(true, "notice_label")<br />
wesnoth.set_dialog_value("&lt;big&gt;NOTICE!&lt;/big&gt;", "notice_label")<br />
<br />
==== wesnoth.set_dialog_focus ====<br />
<br />
* '''wesnoth.set_dialog_focus(''focused?'', ''path, to, widget, id'')'''<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Switches the keyboard focus to the widget found following the given path (see [[#wesnoth.set_dialog_value]]). This is often useful for dialogs containing a central listbox, so that it can be controlled with the keyboard as soon as it is displayed.<br />
<br />
wesnoth.set_dialog_focus("my_listbox")<br />
<br />
==== wesnoth.set_dialog_visible ====<br />
<br />
* '''wesnoth.set_dialog_visible(''visible?'', ''path, to, widget, id'')'''<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Sets a widget's visibility status. The new status is passed as the first argument, and the path to the widget is specified by the remaining arguments (see [[#wesnoth.set_dialog_value]]). The following visibility statuses are recognized:<br />
<br />
{| clasS="wikitable"<br />
! String value !! Boolean shorthand !! Meaning<br />
|-<br />
| visible || true || The widget is visible and handles events.<br />
|-<br />
| hidden || || The widget is not visible, doesn't handle events, but still takes up space on the dialog grid.<br />
|-<br />
| invisible || false || The widget is not visible, doesn't handle events, and does not take up space on the dialog grid.<br />
|}<br />
<br />
wesnoth.set_dialog_visible(false, "secret_button")<br />
<br />
==== wesnoth.set_dialog_canvas ====<br />
<br />
* '''wesnoth.set_dialog_canvas(''index'', ''content'', ''path, to, widget, id'')'''<br />
<br />
Sets the WML passed as the second argument as the canvas content (index given by the first argument) of the widget obtained by following the path of the other arguments (see [[#wesnoth.set_dialog_value]]). The content of the WML table is described at [[GUICanvasWML]].<br />
<br />
-- draw two rectangles in the upper-left corner of the window (empty path = window widget)<br />
wesnoth.set_dialog_canvas(2, {<br />
T.rectangle { x = 20, y = 20, w = 20, h = 20, fill_color= "0,0,255,255" },<br />
T.rectangle { x = 30, y = 30, w = 20, h = 20, fill_color = "255,0,0,255" }<br />
})<br />
<br />
The meaning of the canvas index depends on the chosen widget. It may be the disabled / enabled states of the widget, or its background / foreground planes, or... For instance, overwriting canvas 1 of the window with an empty canvas causes the window to become transparent.<br />
<br />
==== wesnoth.add_dialog_tree_node ====<br />
<br />
* '''wesnoth.add_dialog_tree_node(''type'', ''index'', ''path, to, widget, id'')'''<br />
<br />
{{DevFeature1.13|0}}<br />
<br />
Adds a childnode to a treeview widget or a treeview node. The type (id of the node definition) of the node is passed in the first parameter. The second parameter (integer) spcifies where the node should be inserted in the parentnode. The other arguments describe the path of the parent treeview (-node)<br />
<br />
==== wesnoth.remove_dialog_item ====<br />
<br />
* '''wesnoth.remove_dialog_item(''index'', ''count'', ''path, to, widget, id'')'''<br />
<br />
{{DevFeature1.13|1}}<br />
<br />
Removes an item from a listbox, a multipage or a treeview. First parameter is the index of the item to delete, second parameter is the number of items to delete and the remaining parameters describe the path to the listbox, the multipage or the parent treview node.<br />
<br />
<br />
==== wesnoth.add_widget_definition====<br />
<br />
* '''wesnoth.add_widget_definition(''widget_type'', ''definition_id'', ''wml_content'')'''<br />
<br />
{{DevFeature1.13|?}}<br />
<br />
Creates a new wml widget definition see https://github.com/wesnoth/wesnoth/tree/1.14/data/gui/widget for examples wml_content<br />
<br />
==== wesnoth.is_skipping_messages ====<br />
<br />
* '''wesnoth.is_skipping_messages()'''<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Returns true if messages are currently being skipped, for example because the player has chosen to skip replay, or has pressed escape to dismiss a message.<br />
<br />
==== wesnoth.skip_messages ====<br />
<br />
* '''wesnoth.skip_messages([''skip?'')'''<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Sets the skip messages flag. By default it sets it to true, but you can also pass false to unset the flag.<br />
<br />
==== wesnoth.get_displayed_unit ====<br />
<br />
* '''wesnoth.get_displayed_unit()'''<br />
<br />
Returns a proxy to the unit currently displayed in the side pane of the user interface, if any.<br />
<br />
local name = tostring(wesnoth.get_displayed_unit().name)<br />
<br />
==== wesnoth.log ====<br />
<br />
* '''wesnoth.log([''logger''], ''message', ''in_chat'')'''<br />
<br />
{{DevFeature1.13|5}} Logs a message to the console. These messages are normally not visible unless Wesnoth is run from the command-line or (in Windows) with the --wconsole switch. The in_chat argument, however, can be set to true to also echo the message to the in-game chat area.<br />
<br />
Possible loggers are info, debug, warning, error, and wml. The wml logger is special and is intended for WML errors; it always goes to chat, so the in_chat argument is ignored and can be omitted. The default logger is info.<br />
<br />
==== wesnoth.theme_items ====<br />
<br />
This field is not a function but an associative table. It links item names to the functions that describe their content. These functions are called whenever the user interface is refreshed. The description of an item is a WML table containing '''[element]''' children. Each subtag shall contain either a '''text''' or an '''image''' field that is displayed to the user. It can also contain a '''tooltip''' field that is displayed to the user when moused over, and a "help" field that points to the help section that is displayed when the user clicks on the theme item.<br />
<br />
Note that the ''wesnoth.theme_items'' table is originally empty and using ''pairs'' or ''next'' on it will not return the items from the current theme. Its metatable ensures that the drawing functions of existing items can be recovered though, as long as their name is known. The example below shows how to modify the ''unit_status'' item to display a custom status:<br />
<br />
<syntaxhighlight lang=lua><br />
local old_unit_status = wesnoth.theme_items.unit_status<br />
function wesnoth.theme_items.unit_status()<br />
local _ = wesnoth.textdomain "mydomain"<br />
local u = wesnoth.get_displayed_unit()<br />
if not u then return {} end<br />
local s = old_unit_status()<br />
if u.status.entangled then<br />
table.insert(s, wml.tag.element {<br />
image = "entangled.png",<br />
tooltip = _"entangled: This unit is entangled. It cannot move but it can still attack."<br />
})<br />
end<br />
return s<br />
end<br />
</syntaxhighlight><br />
<br />
The things that would need to be to modified in the above code are:<br />
<br />
* the domain of your addon ("mydomain"), assuming that you are using translations. Otherwise just remove the underscore in the tooltip line.<br />
* the name of the status (u.status.entangled). Note that if the attribute happens to be inside [variables], so be it: u.variables.whatever.<br />
* the path to the image ("entangled.png").<br />
* the tooltip of the status ("entangled: This unit ...").<br />
<br />
The following is a list of valid entries in wesnoth.theme_items which will have an effect in the game. Unfortunately when this feature was created the full range of capabilities of the feature was never properly documented. The following list is automatically generated. To find out what each entry will do, you will have to make guesses and experiment, or read the source code at src/reports.cpp. If you find out what an entry does, you are more than welcome to edit the wiki and give a proper description to any of these fields.<br />
<br />
* '''unit_name'''<br />
* '''selected_unit_name'''<br />
* '''unit_type'''<br />
* '''selected_unit_type'''<br />
* '''unit_race'''<br />
* '''selected_unit_race'''<br />
* '''unit_side'''<br />
* '''selected_unit_side'''<br />
* '''unit_level'''<br />
* '''selected_unit_level'''<br />
* '''unit_amla'''<br />
* '''unit_traits'''<br />
* '''selected_unit_traits'''<br />
* '''unit_status'''<br />
* '''selected_unit_status'''<br />
* '''unit_alignment'''<br />
* '''selected_unit_alignment'''<br />
* '''unit_abilities'''<br />
* '''selected_unit_abilities'''<br />
* '''unit_hp'''<br />
* '''selected_unit_hp'''<br />
* '''unit_xp'''<br />
* '''selected_unit_xp'''<br />
* '''unit_advancement_options'''<br />
* '''selected_unit_advancement_options'''<br />
* '''unit_defense'''<br />
* '''selected_unit_defense'''<br />
* '''unit_vision'''<br />
* '''selected_unit_vision'''<br />
* '''unit_moves'''<br />
* '''selected_unit_moves'''<br />
* '''unit_weapons'''<br />
The default generator expresses each weapon line as a separate <code>element</code><br />
<syntaxhighlight lang=lua><br />
return { <br />
wml.tag.element { text = "weapon text",<br />
tooltip = _"weapon tooltip"<br />
}<br />
-- ...<br />
}<br />
</syntaxhighlight><br />
* '''highlighted_unit_weapons'''<br />
* '''selected_unit_weapons'''<br />
* '''unit_image'''<br />
* '''selected_unit_image'''<br />
* '''selected_unit_profile'''<br />
* '''unit_profile'''<br />
* '''tod_stats'''<br />
* '''time_of_day'''<br />
* '''unit_box'''<br />
* '''turn'''<br />
* '''gold'''<br />
* '''villages'''<br />
* '''num_units'''<br />
* '''upkeep'''<br />
* '''expenses'''<br />
* '''income'''<br />
* '''terrain_info'''<br />
* '''terrain'''<br />
** <nowiki>Text for terrain of the active hex. Same as the one displayed on the UI. It probably returns an empty table when no hex is active. Otherwise, it returns something like {{"element",{text="Grassland (Flat)"}}}.</nowiki><br />
* '''zoom_level'''<br />
* '''position'''<br />
* '''side_playing'''<br />
* '''observers'''<br />
** <nowiki>When there is no observer, it returns an empty table. When there are observers, it gives<br />
{{"element",<br />
{tooltip="Observers\n<observer1>\n<observer2>\n", image="misc/eye.png"}<br />
}}<br />
<br />
</nowiki><br />
* '''selected_terrain'''<br />
* '''edit_left_button_function'''<br />
* '''report_clock'''<br />
** <nowiki>wesnoth.theme_items.report_clock() gives a table {{"element", text=<time>}}, where <time> is HH:MM of local time. It probably return 12hr or 24hr formats depending on user preference. </nowiki><br />
* '''report_countdown'''<br />
** <nowiki>wesnoth.theme_items.report_countdown() gives a table {{"element", text=<time>}}, where <time> is MM:SS of time limit for player's turn. If turn limit < 120 or 60, add <span foreground="#c8c800"><br />
or <span foreground="#c80000"> html tags. </nowiki><br />
<br />
==== helper.get_user_choice ====<br />
<br />
* '''helper.get_user_choice(''message_table'', ''options'')'''<br />
<br />
Displays a WML message box querying a choice from the user. Attributes and options are taken from given tables (see [[InterfaceActionsWML#.5Bmessage.5D|[message]]]). The index of the selected option is returned.<br />
<br />
local result = helper.get_user_choice({ speaker = "narrator" }, { "Choice 1", "Choice 2" })<br />
<br />
[[Category: Lua Reference]]<br />
<br />
==== wesnoth.zoom ====<br />
<br />
{{DevFeature1.13|8}}<br />
<br />
* '''wesnoth.zoom(''factor''[, ''relative''])'''<br />
<br />
Changes the zoom level of the map. If relative is false, which is the default, it simply sets the zoom level. If relative is true, it zooms relative to the current zoom level. So, for example, if the zoom level is currently 0.5, then wesnoth.zoom(2) sets it to 2, while wesnoth.zoom(2, true) sets it to 1 (2 * 0.5).<br />
<br />
This function also returns the resulting zoom level. Because of this, you can call wesnoth.zoom(1) to simply get the current zoom level.<br />
<br />
Note that this function cannot zoom to a level that the user would not be able to reach from the UI. Attempting to do so will simply select the nearest allowed zoom level.</div>Edward Chernenko