From The Battle for Wesnoth Wiki
Revision as of 22:32, 4 September 2005 by Ott (talk | contribs) (The WML preprocessor)

The WML preprocessor

Wesnoth loads just one configuration file directly: data/game.cfg. However the WML preprocessor allows game.cfg to load in more files. Whenever a WML file is read by Wesnoth, it is passed through the preprocessor.

The preprocessor is applied recursively, so included files will be parsed for macros, and after macro expansion will be parsed for macros again, and so on. As a result, you should not write a recursive macro, because it will cause an infinite loop. Changes to the preprocessor in 0.9.2 allow recursively nested #ifdefs, but recursively nested macro definitions ('#define') will still cause errors (but not necessarily error messages).

The following directives are used to create and use macros, i.e. shortcuts which reduce repetition of information. See UtilWML, UsefulWMLFragments for examples.

  • #define symbol [parameters] newline substitution #enddef all subsequent occurences of {symbol [arguments]} (see below) will be replaced by substitution with all occurences of any parameter {parameter} within substitution replaced by the parameter's corresponding value in arguments. For example, the UNIT macro used below would be defined:
#define UNIT TYPE X Y## the ordering is important here;
                     ## since WML does not distinguish
                     ## data into different types, only
                     ## the ordering is used to determine which
                     ## arguments apply to which parameters.
type={TYPE}## the unit will be of type TYPE, so different
           ## instantiations
           ## of this macro can create different units.
side=2## the unit will be an enemy, regardless of the parameter
      ## values. This reduces "repetition of information",
      ## since it is no longer necessary to specify
      ## each created unit as an enemy.

(See SingleUnitWML for information on creating units using WML.)

  • {symbol [arguments]} if symbol is defined, the preprocessor will replace this instruction by the expression symbol is defined as, using arguments as parameters. You can create multiple word arguments by using parentheses to restrain the argument. For example, while {UNIT Wolf Rider 18 24} will attempt to create a "Wolf" at (Rider,18), causing Wesnoth to crash, the macro {UNIT (Wolf Rider) 18 24} will create a "Wolf Rider" at (18,24) as it should. (UNIT is defined above). See the #define preprocessor instruction above for information on defining symbols, including symbols with arguments. Several symbols are defined in the normal game code; for reference they are listed in UtilWML.

Unlike the other preprocessor directives, #ifdef is not used for convenience. It is necessary to distinguish between different modes of play.

  • #ifdef symbol substitution-if-stored [#else substitution-if-not-stored] #endif If symbol has been stored, the whole block will be replaced by substitution-if-stored. If not, it will be replaced by substitution-if-not-stored if it is available. symbol can take the following values:
    • a campaign difficulty level. Usually EASY, NORMAL, or HARD, it is decided by the key difficulties (see CampaignWML).
    • a campaign ID. Each campaign stores a preprocessor ID. See define, CampaignWML.
    • MULTIPLAYER is stored when the player is playing or setting up a multiplayer game (i.e. a game with scenario_type=multiplayer).
    • TUTORIAL is stored when the player is playing the tutorial.
    • APPLE is stored if the computer Wesnoth is being run on is an Apple.

These directives expand a file by including other files:

  • {filename} if filename isn't a predefined symbol (see above), Wesnoth will assume it's a path to a file in the main data/ subdirectory of Wesnoth and include the file it points to here "as is". Forward slashes(/) should be used to separate directories from their elements, even if your platform uses a different symbol such as colon (:) or backslash (\). If filename points to a directory, the preprocessor will include all files in the directory filename, non-recursively and in alphabetical order.
  • {~filename} similar to above, but the preprocessor assumes that the filename is relative to the user data directory. The user data directory varies depending on platform:
Platform | User Data Directory
UNIX     | ~/.wesnoth/data/
Mac OS X | ~/Library/Preferences/Wesnoth or ~/.wesnoth/data
Windows  | "main Wesnoth folder"\userdata

In 0.9.3 the functions of {~filename} and {filename} are changed. {~filename} does nothing and {filename} functions the same as {@filename} (which functions the same as it did in 0.9).

  • {@filename} is a convenient way to make Wesnoth look for a file by that name in both the main and the user data directory. It is equivalent to writing {filename//}{~//filename}.
  • {./filename} is similar to the {filename} directive, but is assumed to be relative to the directory which contains the file in which this appears. For example, if used in game.cfg, it is equivalent to {filename}.

See Also