WML for Beginners (Updated): Part 2

From The Battle for Wesnoth Wiki
Revision as of 18:49, 3 September 2020 by Volatus (talk | contribs) (Removed Unnecessary Text stating obvious things.)

In the second part of this series, we are going to talk a bit more about tags, now focusing on how they relate to each other, and learning new vocabulary on how to refer to these relations. Secondly, the "types of data" in WML will be mentioned and we are also going to touch the surface of the preprocessor and its properties. As you can see, this part of the tutorial is quite big. Read and understand at your own pace, going back to here multiple times if needed. Use the navigation tab at the end of the page to go between pages and the index.


Tag Relations

As we have previously seen, tags can (and do) enclose attributes and their set values. What I haven't told you yet is that tags can also enclose (and be enclosed by) other tags! This way, one tag either contains or is contained within another tag. When a tag A is enclosed by tag B, we say tag A is a child of B. Thus, when a tag B encloses tag A, we say tag B is the parent of tag A. This can imply complex relationships, like the one below:

[A]
    [B]
        [D]
        [/D]
    [/B]

    [C]
    [/C]
[/A]

In the above case, many things can be stated. First, we can say tag A is the parent of both tags B and C, and the grandparent of the D tag, which by itself is a child of B and a grandchild of A. Furthermore, B and C can be called direct children of A while D (child of B) can be called an indirect child of A (the same way A is a direct parent of B and C but an indirect parent of D). Whew, that was a lot right here. Feel free to read this as many times as you want. Just make sure you have grasped the previous info before further reading.

With these terms in mind, the definition of a top-level tag becomes much simpler to both understand and imply. To the extent of our current terminological knowledge on this topic, the definition of top-level tag can be stated as:

  • top-level tag: a tag which isn't a direct nor indirect child of any other tag and may or may not enclose (be a direct or indirect parent of) another tag(s).


Attribute Values

Attributes can have their values be interpreted differently according to what characters they contain. Some specific attributes will also require specific kinds of values. Learn about these different kinds of values and what they are made of.

Strings and Concatenation

Before entering the specific topic of Attribute Values, we might take a look at what a string is defined as. A string is basically a sequence of characters which, together, comprise one or more lines of text. Both "flying monkeys" and "553 flowers" are strings (note that in the latter the number "553" is also considered part of the sequence and while they are numerical characters, in this specific context, they are also considered text). There are times when we are going to join two strings together, uniting, for example, "flying " (note the single space at the end) and "monkeys" to form the string "flying monkeys". This process is called concatenation.

Simple Text and Translatable Strings

Now that you understand strings and what concatenation is, we can proceed. All attribute values (everything to the right of the assignment operator aka. equals sign) are, at the end of the day, considered strings by the parser (do not worry about this word yet; for now, you must remember this is what converts WML into information the game engine can actually understand and make use of). To represent a string as the value of an attribute, simply make text double-quoted. Take a look at the following example:

[unit]
    name = _ "William"
    type = "Orcish Grunt"
[/unit]

You might have noticed there's an underscore before the value of the first attribute (name) of the unit tag above. Do not worry. This was not a typo. This preceding underscore indicates this is a translatable string. That means it is "marked" as a string that might be translated into other languages. Text that is shown as the campaign's story or as the characters' "speech bubbles" are usually composed of translatable strings while the rest usually isn't.

Another thing to pay attention to is the fact that strings can also be represented without double quotes, and are still passed as strings to the parser. In the following example, both attributes a and b have the same value.

[exampletag]
    a = "This is recognizable text."
    b = This is recognizable text.
    c = "This is also " + "recognizable text." # These are concatenated strings. Use the + (plus sign) to concatenate strings. This will result in "This is also recognizable text."
[/exampletag]

Best practice: always keep your strings enclosed in double quotes to avoid confusion and have well-defined starting and ending points to them. There are a few exceptions to the rule, but those will be explained in another time.

Numerical Values

You are also able to represent numeric values, such as integers and decimals, using strings. These can then be used on mathematical operations such as adding, subtracting, multiplying, and dividing (worry not about how this is done, this is going to be covered further into the tutorial). For a string to be considered a numerical value, it might contain one or more digits from 0 to 9 and, additionally, may contain the following (only one of each):

  • The negative sign ("-").
  • The decimal indicator dot (".").

Any strings not following these rules won't be considered numerical values. See some examples below for a better understanding of acceptable and unacceptable numerical strings:

  • "1056" - valid. It only contains digits.
  • "305.26" - valid. It only contains digits and the decimal indicator dot.
  • "-250.30" - valid. It only contains digits, the decimal indicator dot, and the negative sign.
  • "-456" - valid. It only contains digits and the negative sign.
  • "1056a" - invalid. It contains a letter.
  • "305.2.6" - invalid. It contains two decimal indicator dots.
  • "-250.3bananas" - invalid. It contains additional text.
  • "-456-5" - invalid. It contains two negative signs.
  • "potatoes" - invalid. It does not contain any digit.

Best practice: do not enclose numerical values in double-quotes, unless they are used along with other text, such as in the middle of a string (e.g. they are not alone in their own string, and do not have the objective of strictly representing a numerical value). See the example below.

[exampletag]
    a = "They have captured 6 of our soldiers!" # "6" is part of another string. Enclose in double-quotes.
    b = 256 # "256" is alone and strictly represents a numerical value. Do not enclose in double-quotes.
[/exampletag]

Lists of Values

Some specific attributes require the use of value lists. These are simply values separated by a comma, be them numerical values, strings, and/or translatable strings. See below for an example of this.

[unit]
    recruit = Orcish Grunt, Orcish Assassin # In this case, the strings are not enclosed in double-quotes because they are IDs, and while they CAN be enclosed in double quotes, this isn't recommended. We will talk about this further in the tutorial.
    recruit = "Orcish Grunt", "Orcish Assassin" # Also valid.
[/unit]

As you can see, Value Lists can be defined as simply as separating strings with a comma. You can also make lists of numbers (and as you may imagine, it is done by separating numbers with a comma).


The Preprocessor

Whenever a WML file is read by Wesnoth, it goes through the Preprocessor before anything else. As the name suggests (with the pre- prefix, which means "before"), the Preprocessor goes over the file before processing.

The Preprocessor doesn't understand WML code, so tags, attributes, and values are none of its concern. The Preprocessor understands a much simpler language built with elements we know as Macros. In the Preprocessor arsenal we can also find Preprocessor Directives. Worry not about what all this stuff is; this section is designed to serve as an introduction to the Preprocessor and its capabilities, but the Preprocessor itself will be discussed in more depth at its own section.

The Inclusion Directives

One of the capabilities of the Preprocessor is including other files or directories into our file for ease of access. Using this in combination with the binary_path tag can help our game to find files it can use (such as map and scenario files). Here's how: