From The Battle for Wesnoth Wiki

This page contains a summary of the major Lua API changes between 1.12 and 1.15, to help make updating older code simpler.

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.

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.

Functions in wesnoth namespace

  • wesnoth.remove_fog renamed to wesnoth.sides.remove_fog
  • wesnoth.add_ai_component renamed to wesnoth.sides.add_ai_component
  • wesnoth.add_fog renamed to wesnoth.sides.place_fog
  • wesnoth.add_modification renamed to wesnoth.units.add_modification
  • wesnoth.add_sound_source replaced with mapping (write to key)
    • -- wesnoth.add_sound_source{id=my_id, x=15, y=22, sound='my-sound.ogg'} = {x=15, y=22, sound='my-sound.ogg'}
  • wesnoth.add_tile_overlay renamed to wesnoth.interface.add_hex_overlay
  • wesnoth.add_widget_definition renamed to gui.add_widget_definition
  • wesnoth.advance_unit renamed to wesnoth.units.advance
  • wesnoth.alert renamed to gui.alert
  • wesnoth.allow_end_turn renamed to wesnoth.interface.allow_end_turn
  • wesnoth.append_ai renamed to wesnoth.sides.append_ai
  • wesnoth.canonical_path renamed to filesystem.canonical_path
  • wesnoth.change_ai_component renamed to wesnoth.sides.change_ai_component
  • wesnoth.clear_messages renamed to wesnoth.interface.clear_chat_messages
  • wesnoth.color_adjust replaced with wesnoth.interface.color_adjust
  • wesnoth.compare_versions replaced with wesnoth.version, which creates a version object that can be compared with standard comparison operators
    • -- if wesnoth.compare_versions(wesnoth.game_config.version, '<=', '1.13') then
      if wesnoth.current_version() <= wesnoth.version '1.13' then
          -- do version-specific stuff
  • wesnoth.confirm renamed to gui.confirm
  • wesnoth.copy_unit renamed to wesnoth.units.clone
  • wesnoth.create_animator renamed to wesnoth.units.create_animator
  • wesnoth.create_side renamed to wesnoth.sides.create
  • wesnoth.create_unit renamed to wesnoth.units.create
  • wesnoth.create_weapon renamed to wesnoth.units.create_weapon
  • wesnoth.debug_ai renamed to wesnoth.sides.debug_ai
  • wesnoth.debug renamed to wml.tostring; in addition, it now produces an output that is valid WML, meaning that wml.parse(wml.tostring(wml_table)) will output a clone of wml_table (though for this purpose there's a separate wml.clone function which is probably faster).
  • wesnoth.delay renamed to wesnoth.interface.delay
  • wesnoth.delete_ai_component renamed to wesnoth.sides.delete_ai_component
  • wesnoth.deselect_hex renamed to wesnoth.interface.deselect_hex
  • wesnoth.end_level replaced with assignable wesnoth.scenario.end_level_data
  • wesnoth.end_turn renamed to wesnoth.interface.end_turn
  • wesnoth.erase_unit renamed to wesnoth.units.erase
  • wesnoth.eval_conditional renamed to wml.eval_conditional
  • wesnoth.extract_unit renamed to wesnoth.units.extract
  • wesnoth.find_cost_map renamed to wesnoth.paths.find_cost_map
  • wesnoth.find_path renamed to wesnoth.paths.find_path
  • wesnoth.find_reach renamed to wesnoth.paths.find_reach
  • wesnoth.find_vacant_tile renamed to wesnoth.paths.find_vacant_hex
  • wesnoth.find_vision_range renamed to wesnoth.paths.find_vision_range
  • renamed to
  • wesnoth.float_label renamed to wesnoth.interface.float_label
  • wesnoth.format_conjunct_list renamed to stringx.format_conjunct_list
  • wesnoth.format_disjunct_list renamed to stringx.format_disjunct_list
  • wesnoth.format renamed to stringx.vformat and can also be called directly on a string literal
  • wesnoth.gamestate_inspector renamed to gui.show_inspector
  • wesnoth.get_all_vars replaced with read-only variable wml.all_variables (but it should still be used sparingly)
  • wesnoth.get_displayed_unit renamed to wesnoth.interface.get_displayed_unit
  • wesnoth.get_end_level_data replaced with readable wesnoth.scenario.end_level_data
  • wesnoth.get_image_size renamed to filesystem.image_size
  • wesnoth.get_max_liminal_bonus replaced with read-only wesnoth.current.schedule.liminal_bonus
  • wesnoth.get_mouseover_tile renamed to wesnoth.interface.get_hovered_hex
  • wesnoth.get_recall_units renamed to wesnoth.units.find_on_recall
  • wesnoth.get_selected_tile renamed to wesnoth.interface.get_selected_hex
  • 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.
    • -- local old_value = wesnoth.get_side_variable(1, 'my_value')
      local old_value = wesnoth.sides[1].variables['my_value'] -- or variables.myvalue
      local new_value = old_value * 2
      -- wesnoth.set_side_variable(1, 'my_value', new_value)
      wesnoth.sides[1].variables['my_value'] = new_value
  • wesnoth.get_sides renamed to wesnoth.sides.find
  • wesnoth.get_sound_source replaced with mapping (read key)
  • wesnoth.get_starting_location replaced by starting_location member in side data
  • 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
    • -- local global_tod = wesnoth.get_time_of_day(wesnoth.current.turn + 1)
      local global_tod = wesnoth.schedule.get_time_of_day(nil, wesnoth.current.turn + 1)
      -- local base_tod = wesnoth.get_time_of_day(wesnoth.current.turn + 1, {44, 23})
      local base_tod = wesnoth.schedule.get_time_of_day({44, 23}, wesnoth.current.turn + 1)
      -- local final_tod = wesnoth.get_time_of_day(wesnoth.current.turn + 1, {44, 23, true})
      local final_tod = wesnoth.schedule.get_illumination({44, 24}, wesnoth.current.turn + 1)
  • wesnoth.get_time_stamp renamed to wesnoth.ms_since_init
  • wesnoth.get_traits replaced with wesnoth.game_config.global_traits, which is the table it formerly returned
  • wesnoth.get_unit renamed to wesnoth.units.get
  • wesnoth.get_units renamed to wesnoth.units.find_on_map
  • 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
    • -- local old_value = wesnoth.get_variable('my_array[2].value')
      local old_value = wml.variables['my_array[2].value']
      local new_value = old_value * 2
      -- wesnoth.set_variable('my_array[2].value', new_value)
      wml.variables['my_array[2].value'] = new_value
  • wesnoth.have_file renamed to filesystem.have_file
  • wesnoth.highlight_hex renamed to wesnoth.interface.highlight_hex
  • wesnoth.invoke_synced_command renamed to wesnoth.sync.invoke_command
  • wesnoth.is_enemy renamed to wesnoth.sides.is_enemy
  • wesnoth.is_fogged renamed to wesnoth.sides.is_fogged
  • wesnoth.is_shrouded renamed to wesnoth.sides.is_shrouded
  • wesnoth.is_skipping_messages renamed to wesnoth.interface.is_skipping_messages
  • wesnoth.lock_view renamed to wesnoth.interface.lock
  • wesnoth.match_side renamed to wesnoth.sides.matches
  • wesnoth.match_unit renamed to wesnoth.units.matches
  • wesnoth.message renamed to wesnoth.interface.add_chat_message
  • wesnoth.music_list renamed to
  • wesnoth.open_help renamed to gui.show_help
  • wesnoth.place_shroud replaced with wesnoth.sides.place_shroud and wesnoth.sides.override_shroud
  • wesnoth.play_sound renamed to
  • wesnoth.put_recall_unit renamed to wesnoth.units.to_recall
  • wesnoth.put_unit replaced with wesnoth.units.to_map, which reordered the arguments, so that the unit info has now moved from the 3rd position to the first
  • wesnoth.random renamed to mathx.random
  • wesnoth.read_file renamed to filesystem.read_file
  • wesnoth.remove_modifications renamed to wesnoth.units.remove_modifications
  • wesnoth.remove_sound_source replaced with mapping (assign nil to key)
  • wesnoth.remove_tile_overlay renamed to wesnoth.interface.remove_hex_overlay
  • wesnoth.replace_schedule renamed to wesnoth.schedule.replace
  • wesnoth.scroll_to_tile renamed to wesnoth.interface.scroll_to_hex
  • wesnoth.scroll renamed to wesnoth.interface.scroll
  • wesnoth.select_unit renamed to (also available as wesnoth.interface.select_unit)
  • wesnoth.set_end_campaign_credits replaced with assignable wesnoth.scenario.show_credits
  • wesnoth.set_end_campaign_text replaced with assignable wesnoth.scenario.end_text and wesnoth.scenario.end_text_duration
  • wesnoth.set_next_scenario replaced with assignable
  • wesnoth.set_side_id renamed to wesnoth.sides.set_id
  • 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
  • wesnoth.show_lua_console renamed to gui.show_lua_console
  • wesnoth.show_menu renamed to gui.show_menu
  • wesnoth.show_message_box renamed to gui.show_prompt
  • wesnoth.show_message_dialog renamed to gui.show_narration
  • wesnoth.show_popup_dialog renamed to gui.show_popup
  • wesnoth.show_story renamed to gui.show_story
  • wesnoth.skip_messages renamed to wesnoth.interface.skip_messages
  • wesnoth.sound_volume replaced with read-write
  • wesnoth.switch_ai renamed to wesnoth.sides.switch_ai
  • wesnoth.synchronize_choice renamed to wesnoth.sync.evaluate_single
  • wesnoth.synchronize_choices renamed to wesnoth.sync.evaluate_multiple
  • wesnoth.teleport renamed to wesnoth.units.teleport
  • wesnoth.theme_items renamed to wesnoth.interface.game_display - it's still a table with the same keys as before
  • wesnoth.tovconfig renamed to wml.tovconfig
  • wesnoth.transform_unit renamed to wesnoth.units.transform
  • wesnoth.unit_ability renamed to wesnoth.units.ability
  • wesnoth.unit_defense renamed to wesnoth.units.chance_to_be_hit
  • wesnoth.unit_jamming_cost renamed to wesnoth.units.jamming_on
  • wesnoth.unit_movement_cost renamed to wesnoth.units.movement_on
  • wesnoth.unit_resistance replaced by wesnoth.units.resistance_against - new function returns (100 - old function)
  • wesnoth.unit_vision_cost renamed to wesnoth.units.vision_on
  • wesnoth.unsynced renamed to wesnoth.sync.run_unsynced
  • wesnoth.view_locked renamed to wesnoth.interface.is_locked
  • wesnoth.wml_matches_filter renamed to wml.matches_filter
  • wesnoth.zoom renamed to wesnoth.interface.zoom

wesnoth.tovconfig and related functions in plugins

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 --plugin command-line parameter, primarily intended for creating bots on the multiplayer server.

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).

In addition, the helper functions parsed, literal, shallow_parsed, and shallow_literal are not available in the plugin context.


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.

  • 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
  • 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.
  • 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.
  • wesnoth.set_dialog_active removed; instead assign the enabled member of a widget
    • -- local function preshow()
      local function preshow(self)
          local var_a = true
          -- whatever you are doing to determine if button should be active
          -- wesnoth.set_dialog_active(var_a, "my_button_id")
          local widget_handle = self:find('my_button_id') -- or just self.my_button_id
          widget_handle.enabled = var_a
          -- ...
  • wesnoth.set_dialog_callback removed; instead simply assign to a widget's callback handler, eg my_widget.on_modified = function() end
    • -- local function preshow()
      local function preshow(self)
          local function on_text_modified()
              -- Do whatever you need to do
          -- This example shows an on_modified event; there's also on_left_click and on_button_click
          -- Use one of the click events if you were setting the callback on a button.
          -- wesnoth.set_dialog_callback(on_text_modified, "my_text_id")
          local widget_handle = self:find('my_text_id') -- or just self.my_text_id
          widget_handle.on_modified = set_dialog_callback
          -- Or you could have defined the function here like this:
          -- function widget_handle.on_modified()
          -- ...
  • 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
  • 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
    • -- local function preshow()
      local function preshow(self)
          -- wesnoth.set_dialog_focus("my_text_id")
          local widget_handle = self:find('my_text_id') -- or just self.my_text_id
          -- ...
  • wesnoth.set_dialog_markup removed; instead assign the use_markup member of a widget
  • wesnoth.set_dialog_tooltip removed; instead assign the tooltip member of a widget
    • -- local function preshow()
      local function preshow(self)
          local var_a = 'Some explanation'
          -- whatever you are doing to determine the button's tooltip
          -- wesnoth.set_dialog_tooltip(var_a, "my_button_id")
          local widget_handle = self:find('my_button_id') -- or just self.my_button_id
          widget_handle.tooltip = var_a
          -- ...
  • wesnoth.set_dialog_visible removed; instead assign the visible member of a widget
    • -- local function preshow()
      local function preshow(self)
          local var_a = true
          -- whatever you are doing to determine if button should be visible
          -- wesnoth.set_dialog_visible(var_a, "my_button_id")
          local widget_handle = self:find('my_button_id') -- or just self.my_button_id
          widget_handle.visible = var_a
          -- ...
  • wesnoth.show_dialog renamed to gui.show_dialog
  • 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.


Due to a major rehaul of the map API, many map functions are now methods on the map object, available as (abbreviated in the below listing to just map).

  • wesnoth.add_time_area renamed to
  • wesnoth.get_locations renamed to
  • wesnoth.get_map_size replaced with map.playable_width, map.playable_height, and map.border_size
    • -- local width, height, border_size = wesnoth.get_map_size()
      local width, height =,
      local border_size =
      -- local width_with_border, height_with_border = width + border_size * 2, height + border_size * 2
      local width_with_border, height_with_border = and
  • wesnoth.get_terrain_info replaced with wesnoth.terrain_types
    • -- local info = wesnoth.get_terrain_info('Gg')
      local info = wesnoth.terrain_types['Gg']
  • wesnoth.get_terrain replaced with map[{x,y}]
    • -- local terrain = wesnoth.get_terrain(x, y)
      local terrain =[{x,y}]
      -- local terrain_under_unit = wesnoth.get_terrain(unit.x, unit.y)
      local terrain_under_unit =[unit]
  • wesnoth.get_village_owner renamed to
  • wesnoth.get_villages replaced with (with gives_income = true)
    • -- For example, get all villages in [time_area]id=shadowed
      -- local villages = wesnoth.get_villages{area = 'shadowed'}
      local villages ={area = 'shadowed', gives_income = true}
  • wesnoth.label renamed to
  • wesnoth.match_location renamed to
  • wesnoth.remove_time_area renamed to
  • wesnoth.set_terrain replaced with assigning map[{x,y}] - helper functions in 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
    • -- wesnoth.set_terrain(x, y, 'Gg')[{x,y}] = 'Gg'
      -- Or be explicit about layer:[{x,y}] = 'Gg'
      -- wesnoth.set_terrain(x, y, 'Gg', 'base')[{x,y}] = 'Gg'
      -- wesnoth.set_terrain(x, y, '^Vh', 'overlay')[{x,y}] = '^Vh'
      -- wesnoth.set_terrain(x, y, 'Gg^Vh', 'overlay', true)[{x,y}] ='Gg^Vh', 'overlay')
  • wesnoth.set_village_owner renamed to
  • wesnoth.special_locations renamed to map.special_locations (note: the length operator is no longer supported)
  • wesnoth.terrain_mask replaced with map:terrain_mask

The following functions are only available in map generation scripts:

  • wesnoth.create_filter renamed to
  • wesnoth.create_map renamed to
  • wesnoth.default_generate_height_map renamed to
  • wesnoth.generate_default_map renamed to
  • map:get_locations renamed to map:find
  • map:get_tiles_radius replaced with map::find_in_radius (and the order of arguments changed)
    • -- This example assumes you have a variable f defined as in World Conquest (engine.lua)
      -- local in_radius = map:get_tiles_radius(12, 22, f.terrain 'Gg', 5)
      local in_radius = map:find_in_radius(12, 22, 5, f.terrain 'Gg')

helper module

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 local helper = wesnoth.require "helper" or the like, but many people call it H instead of helper, so keep that in mind.

  • helper.child_array renamed to wml.child_array
  • helper.child_count renamed to wml.child_count
  • helper.child_range renamed to wml.child_range
  • helper.distance_between renamed to
  • helper.find_attack renamed to wesnoth.units.find_attack
  • helper.get_child renamed to wml.get_child
  • helper.get_nth_child renamed to wml.get_nth_child
  • helper.get_user_choice renamed to gui.get_user_choice
  • helper.get_variable_array renamed to wml.array_access.get
  • helper.get_variable_proxy_array renamed to wml.array_access.get_proxy
  • helper.literal renamed to wml.literal
  • helper.modify_unit renamed to wesnoth.units.modify
  • helper.move_unit_fake renamed to wesnoth.interface.move_unit_fake
  • helper.parsed renamed to wml.parsed
  • helper.rand renamed to mathx.random_choice
  • helper.round renamed to mathx.round
  • helper.set_variable_array renamed to wml.array_access.set
  • helper.set_wml_tag_metatable replaced with wml.tag, which is a table that works exactly the same as what this function would return
    • -- local T = helper.set_wml_tag_metatable{}
      local T = wml.tag -- Or you can dispense with T and use wml.tag directly
  • 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
  • helper.set_wml_action_metatable replaced with, which can be used as if it were the table that this function would return
  • helper.shallow_literal renamed to wml.shallow_literal
  • helper.shallow_parsed renamed to wml.shallow_parsed
  • helper.shuffle renamed to mathx.shuffle
  • helper.wml_error renamed to wml.error

items module

There were also a few things in an "items" module that have been moved into the main API.

  • items.place_halo renamed to wesnoth.interface.add_item_halo
  • items.place_image renamed to wesnoth.interface.add_item_image
  • items.remove renamed to wesnoth.interface.remove_item
This page was last edited on 23 November 2022, at 14:00.