Difference between revisions of "LuaAPI/wml-utils"

From The Battle for Wesnoth Wiki
(Add context specifiers to each entry)
(utils.check_key: One of the parameters was undocumented!)
Line 10: Line 10:
 
* '''utils.check_key'''(''value'', ''key'', [''convert_spaces'') → ''value''
 
* '''utils.check_key'''(''value'', ''key'', [''convert_spaces'') → ''value''
  
Checks if ''value'' is a valid WML key, optionally after replacing spaces with underscores, and returns the resulting value after conversion. This could also be used to test for event names.
+
Checks if ''value'' is a valid WML key, optionally after replacing spaces with underscores, and returns the resulting value after conversion. This could also be used to test for event names. The ''key'' represents the WML key that the value was found in, and is only used for an error message if the test fails.
  
 
=== utils.vwriter ===
 
=== utils.vwriter ===

Revision as of 12:47, 29 June 2022

The wml-utils module contains miscellaneous utility functions that are useful for implementing custom Action WML tags. All examples on this page will assume it has been loaded by:

local utils = wesnoth.require "wml-utils"

utils.check_key

  • utils.check_key(value, key, [convert_spaces) → value

Checks if value is a valid WML key, optionally after replacing spaces with underscores, and returns the resulting value after conversion. This could also be used to test for event names. The key represents the WML key that the value was found in, and is only used for an error message if the test fails.

utils.vwriter

  • utils.vwriter.init(settings, default variable) → vwriter
  • utils.vwriter.write(vwriter)

A utility interface for writing arrays of WML variables.

The init function returns a control table which is then passed to the write function. Possible keys in settings are:

  • variable: The name of the variable. Can be a path, eg some.variable[4].key.
  • mode: The mode. One of always_clear, replace, or append. In always_clear mode, the array is emptied before starting, whereas replace overwrites the beginning of the array but may leave later elements untouched.

The settings table may have other keys as well; they will simply be ignored. Thus, a WML action can just pass its entire config as the settings table.

The write function writes an element to the array and increments the internal counter. Thus, calling write multiple times will successively add new elements to the array.

-- Store all side leaders in an array
function wesnoth.wml_actions.store_leaders(cfg)
  local writer = utils.vwriter.init(cfg, 'leaders')
  local leaders = wesnoth.units.find{canrecruit = true}
  for i,u in ipairs(leaders) do
    utils.vwriter.write(writer, u.__cfg)
  end
end

This example creates an ActionWML tag that can be used like this:

[store_leaders]
  variable=possible_targets
  mode=append
[/store_leader]

utils.get_sides

  • utils.get_sides(wml table, key, tag) → array of sides

Produces a list of sides either from a comma-separated list or a StandardSideFilter. If a tag called tag exists in the wml table, it will be used as a filter to determine the sides to return. Otherwise, if a key called key exists in the wml table, it's taken as a comma-separated list of sides to return. If neither exists, an empty array is returned.

utils.optional_side_filter

  • utils.optional_side_filter(wml table, key, tag) → boolean

Similar to utils.get_sides, but instead of returning the list of sides, it returns true if the list is either empty or contains a local human-controlled side.

utils.handle_event_commands

  • utils.handle_event_commands(wml actions, [scope type]) → exit type

Executes a table of WML actions. With one parameter, this is equivalent to the [command] tag (in fact, all the [command] tag does is call this function). The scope type and exit type are both strings.

Possible scope types:

  • plain: ordinary scope, no special features; eg [command] or [event]
  • conditional: scope that's executing because of a condition, eg [then] or [else]
  • switch: scope that's part of a switch statement, eg [case] or [else]
  • loop: scope that's part of a loop, eg [do]

Possible exit types:

  • none: ordinary execution
  • break: exiting a loop scope
  • return: immediate termination (exit all scopes)
  • continue: jumping to the end of a loop scope

A loop scope is terminated if nested command execution exits with continue, and if any command execution exits with return, all enclosing executions also exit.

utils.set_exiting

  • utils.set_exiting(exit type)

Controls the return code of the enclosing utils.handle_event_commands. The normal usage is to set it to "none" after a nested utils.handle_event_commands returned something different. This is needed to implement a custom WML loop tag, for example.

function wesnoth.wml_actions.iterate_weapons(cfg)
  local u = wesnoth.units.find(cfg)[1]
  local var_name = cfg.var or 'weapon'
  local var <close> = utils.scoped_var(var_name)
  for i = 1, #u.attacks do
    var:set(u.attacks[i].__cfg)
    for do_child in wml.child_range(cfg, "do") do
      local action = utils.handle_event_commands(do_child, "loop")
      if action == "break" then
        utils.set_exiting("none")
        return
      elseif action == "continue" then
        utils.set_exiting("none")
        break -- since we're in a nested loop over [do] tags
      elseif action ~= "none" then
        return
      end
    end
  end
end

This creates an Action WML tag that can be used like this:

[iterate_weapons]
  id=delfador
  [do]
    [message]
      message="$delfador.name has a $weapon.range $weapon.name that does $weapon.damage×$weapon.number $weapon.type!"
    [/message]
  [/do]
[/iterate_weapons]

Note: While the above example does illustrate the use of the example tag, it's also a great example of how to make an add-on impossible to translate. See the gettext manual for more details on why.

utils.scoped_var

  • utils.scoped_var(name) → scoped variable

Returns a closable scoped variable object that will automatically restore the variable to its original value when it's closed. The resulting scoped variable object supports the following actions:

  • scoped_var:set(value) — Set the value of the scoped variable.
  • scoped_var:get() → value — Retrieve the value of the scoped variable.
  • scoped_var.__originalvalue — Retrieve the former value of the variable, which it will be reset to when the scoped variable is closed.

See #utils.set_exiting for an example of its use.