WML for Complete Beginners: Chapter 1

From The Battle for Wesnoth Wiki
Revision as of 21:14, 16 December 2017 by Sapient (talk | contribs) (Attributes)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)


Chapter 1: Syntax

First things first; let's go over the syntax of WML.

For those of you who might not know what the "syntax" of a language is, think of it as a set of rules for how WML needs to be written in order for the game to understand it. This concept may sound a bit confusing, but whether you realize it or not you have been using the concept of syntax your entire life! Think of the structure of a sentence in English: "I like jelly and cheese sandwiches." That sentence uses a certain set of rules, or syntax in order to make sense to people who hear or read it. If you said instead, "Like cheese I and sandwiches jelly", that would make no sense, and no one would understand what you were saying. Likewise, if you said "I like cheese sandwiches and jelly", that would change the entire meaning of the sentence!

Just like the syntax of the English language, WML syntax also requires proper capitalization, spelling, grammar and punctuation in order for others to understand what you're saying or writing. For example, if you decided to ignore the syntax of the English language and wrote something like this: "won day mary and i had went to seen the elefant at the zoo it's trunc was reely long", chances are people would not understand much of what you wrote. On the other hand, if you used the correct syntax and wrote: "One day Mary and I went to see the elephant at the zoo. Its trunk was really long!", people can easily understand what you wrote because it is written in the syntax they recognize and understand. Just as English-reading people would be unable to understand something were it not written in the correct English syntax, the Battle for Wesnoth game is unable to read any WML that is not written in the correct WML syntax.

So now let's go over the basics of WML syntax. Later on you will be gradually introduced to more complex WML syntax, but for now we'll just go over the basic stuff, enough to get you started.

Basic Components: Tags and Attributes

WML, as one can infer from the meaning of the acronym, is a "markup language." This means that the syntax of the entire language consists of two fundamental elements: tags and attributes.


Tags

A tag is a string of lowercase text encapsulated by two square brackets, one at either end. This is an example of a "campaign" tag:
[campaign]
Tags can only contain alphanumeric characters (letters and numbers) and underscores "_". Notice I said earlier that "a tag is a string of lowercase text". This is a fundamental aspect of the WML syntax: all tags are always written in lowercase letters. If you try using capital letters (even just one), the WML engine won't be able to understand what tag you're trying to use and will give you an error when it tries to read the incorrect tag.
As with most markup languages, in WML tags are always used in pairs: one opening tag and one closing tag. Think of the opening tag and the closing tag like the covers of a book: when you open the front cover, you know you're at the beginning. When you reach the back cover, you know you're done reading the book. Likewise, when the WML engine finds an opening tag, it realizes it's at the beginning of a task. When it reaches the closing tag, it realizes it has finished the task.
Closing tags are exactly the same as opening tags except for one key component: closing tags always have a forward slash "/" immediately after the first square bracket. This forward slash tells the WML engine that this tag is a closing tag and not another opening tag. Here is an example of the closing "campaign" tag:
[/campaign]
The opening and closing tag together are referred to as a tagset. A tagset always contains exactly two tags: the opening tag and the closing tag. For example, the "campaign" tagset would look like this:
[campaign]
[/campaign]


So now we know how the WML engine knows where the beginning and end of a task are, and what syntax to use when writing them. These are the basics of tags in WML. Later on we'll go over the more complicated aspects of tags; for now though, make sure you understand the concepts introduced here.
Before we move on to the next section, let's review the points we've learned in this section about tags:
  • A tag is a string of lowercase text encapsulated by two square brackets, one at either end.
  • A closing tag is exactly the same as an opening tag, except a closing tag has a forward slash immediately following the first square bracket.
  • The opening tag and the closing tag together are called a "tagset".
  • A tagset can only ever consist of exactly two tags: the opening tag and the closing tag.
Now we know how to tell the WML engine where the beginning and the end of a task are, but what about actually making it do the task? This is where attributes come in.


Attributes

Attributes consist of two principal elements: keys and values, and are written like so:
key=value
The basic function of attributes is to store information that is needed by the WML engine. The key of the attribute specifies what kind of information is stored, and the value of the attribute is the actual data that is stored. All text to the left of the equals sign "=" is considered to be the key, and all text to the right of the equals sign is considered to be the value of the key.
This may sound rather confusing, so let's illustrate by a practical example:
Let's say you wanted your friend to go to the grocery store and pick you up a loaf of bread. Would you just say to him, "Go"? Of course not! He wouldn't understand what you wanted him to do, which means you'd have no bread for dinner. Likewise, if you only write a tagset, that's equivalent to telling the WML engine to "do", but that's not enough. You will need to be more specific about exactly what the WML engine should do. If your friend were a human WML engine and you wanted him to go to the grocery store to get some bread, you might give him this code to read (note: this code isn't actually real WML, it is "pseudocode", i.e. made up code for the purpose of illustration. If I ever use pseudocode during this tutorial I will tell you that it is pseudocode before you read the example, like I am doing now.):
[go]
    where=grocery_store
    get=bread
[/go]
Tags tell the WML engine what to do generally (like telling your friend to "go"), but without attributes to specify exactly what to do (like telling your friend where and when to go, and what to do when he gets there), the WML engine won't be able to do anything because you haven't given it enough specific information. If you told your friend, "Go," he'd understand that you want him to go somewhere, but he'd be unable to actually perform the task because he doesn't know where to go or what to do when he gets there.
  • Keys
Keys are sequences of lowercase alphabetic characters that tell the game what kind of information it is dealing with when it reads the attribute. Keys are case-sensetive (i.e., you can't use capital letters) and must be spelled correctly.
  • Values
WML keys deal with one and only one type of data, called strings. A string is simply a sequence of ASCII characters that can include pretty much any character on your keyboard. Strings may be divided into two categories: Standard and Numerical.


1. Standard Strings
A standard string is simply a sequence of ASCII characters that is neither a numerical nor a translatable string. For example, this is a standard string:
grocery_store
as is this:
bread
If a standard string is more than one simple identifier, it is better for it to be enclosed within double quotes:
"Everything in these double quotes is a single string. This is the number one: 1. Hooray! :) We are now coming to the end of this string."
Everything within the double quotes (including the colon and parenthesis emoticon) is considered to be one long string by the game.
Sometimes you will want to mark a standard string as translatable so that it can be translated into other languages. The only difference between a translatable sting and a non-translatable is that translatable strings are marked so that translators know that they need to translate that string, and non-translatable strings are not marked, so the translators know that they don't translate those strings.
To mark a string as translatable, all you have to do is add an underscore before the first double quote that marks the beginning of the string. Example of a translatable string:
 _ "This is a translatable string."
If the WML engine does not find an underscore in front of the string, it will assume the string is non-translatable.
Although not strictly necessary, it is generally considered a good practice to include a space before and after the underscore that marks a string as translatable. For instance, if we were to assign the translatable string "Hello World!" to this key, it would be considered good syntax to write
key= _ "Hello World!"
rather than
key=_"Hello World!"
However, the game considers both of the above strings to be equivalent, and will therefore recognize both as translatable strings. Adding whitespaces just allows for better human readability in your WML code.


2. Numerical Strings
Unsurprisingly, numerical strings are strings that contain only numbers, decimal points, or minus signs "-". If a string contains anything other than numbers, decimal points and/or a minus sign, the string becomes a standard string instead of a numerical one. Numerical strings can be either a single numeric character like this:
2
a sequence of numeric characters, like this:
230001
or floating-point values (that's just a fancy way of saying that they can contain decimal points), like these two examples:
2.6
395667.49382345
or negative numbers, like these examples:
-49
-594.932
For all intents and purposes, you can treat numerical strings just as you would numbers in real life. You can add, divide, and otherwise mathematically employ them in mathematical computations (we'll discuss Variable Manipulation in chapter 7). Just remember that if you include any characters other than numbers, decimal points, or minus signs, the string will cease to be a numeric string and will become a standard string, which means you won't be able to use it in mathematical calculations.
Directory paths are simply special strings that tell the game where to find a specific file or folder. Here is an example of a directory path:
{data/add-ons/my_first_campaign}

This directory path tells the game where the folder "my_first_campaign" is located.

More About Tags

So now you should understand the basics about tags and attributes. As I promised earlier, we will now discuss some of the more involved aspects of tags.

Nested Tags: Parents and Children

A fundamental aspect of markup languages is that you can use tagsets inside other tagsets. Tagsets located inside other tagsets are called nested tagsets. In the example below, the "side" tagset is nested inside the "scenario" tagset:
[scenario]
    [side]
    [/side]
[/scenario]
When referring to nested tagsets, the tagset located inside the other is called the child tagset, and the tagset that encloses the child tagset is known ast he parent tagset. To illustrate with pseudocode:
[parent]
    [child]
    [/child]
[/parent]
Tagsets that are not child tagsets of any other tagsets are called toplevel tagsets. In this next example, the [scenario] tagset is a toplevel tagset, because it is not the child tagset of any other tagset. The [event] tagset is the child tagset of [scenario], because it is located inside the [scenario] tagset. The tagset [event] is also the parent tagset of the [message] tagset, because the [message] tagset is located inside the [event] tagset. That means that since [event] is the parent of [message], [message] is the child tagset of [event].
[scenario]
    [event]
        [message]
        [/message]
    [/event]
[/scenario]


Indentation and Levels

You may have noticed that in the examples above, the child tagsets are indented four spaces further to the right than are their parent tagsets. Why is this? It's because proper indentation (although not technically required by the WML engine) makes you code a lot easier to read and maintain. It's like writing an outline for a school paper, where you would write something like this:
I.
    A.
    B.
    C.
II.
    A.
        1.
        2.
    B.
    C.
Indentation makes it much easier to see whether tagset is the child or parent of other tagsets. The amount of indentation before a tagset determines in what level that tagset is located. If the tagset is a toplevel tagset (i.e. has no spaces in front of it because it is not the child of any other tagset), that tagset is located at level one. Tagsets with an indentation of four spaces in front of them are located in level 2, because they are the children of the toplevel (level 1) tagset. Tagsets that are children of level 2 tagsets are called level 3 tagsets (and are indented 8 spaces), tagsets inside level 3 tagsets are called level 4 tagsets (and are indented 12 spaces), etc. As a general rule, all the attributes of a tagset, along with any child tagsets of that tagset, are indented one level deeper than that tagset. To illustrate in pseudocode:
[toplevel_tagset]
    level_2_attribute=value
    [level_2_tagset]
        level_3_attribute=value
        [level_3_tagset]
            level_4_attribute=value
        [/level_3_tagset]
    [/level_2_tagset]
[/toplevel_tagset]
Indenting tagsets and attributes into levels like this makes it much easier for you (and others) to read, fix and maintain your code. It is strongly recommended that you indent exactly four spaces for each new level, although you can also use tabs instead of hitting the space key 4 times, if you'd prefer.

Next Chapter: WML for Complete Beginners: Chapter 2

Return to introduction: WML for Complete Beginners: Introduction

Return to Main Index: WML for Complete Beginners

This page was last edited on 16 December 2017, at 21:14.