SyntaxWML

Материал из Wesnoth Life Wiki
Перейти к: навигация, поиск

WML (The Wesnoth Markup Language) - язык, разработанный специально для игры Битва за Веснот. На нём закодировано почти всё, включая сценарии, юниты, файлы сохранения и пользовательский интерфейс. WML файлы просты, понятны, обычно имеют расширение .cfg и похожи на INI и XML файлы.

Базовый синтаксис

WML является построчным языком, то есть перевод на другую строку является концом выражения. Строки, содержащие открывающие и закрывающие теги (см. ниже) не могут содержать другой текст. Когда Вы устанавливаете атрибуты (об этом тоже позже), весь текст до знака равно содержит название ключа, а весь текст после, до конца строки - значение. Соответственно, перевод на другую строку должен находиться между двумя строками key=value, иначе имя нового ключа будет воспринято как продолжение значения предыдущего ключа. Тип перехода на новую строку должен быть во всём файле одинаков, чтобы не запутать игру (обычно такая проблема возникает когда файл редактируется под разными ОС, так как Windows, Linux и Mac завершают строки по разному).

Последовательные пробелы в WML обычно трактуются как одинарный, более того, во многих случаях вообще наличие пробела не обязательно. (Однако, правильная расстановка отступов важна для читабельности файлов; подробнее смотрите ConventionsWML). Более того, во многих случаях пробелы просто игнорируются. В то же время в некоторых случаях, когда для человека пробелы не важны, для игры они играют важное значение и не игнорируются. Если Вы не знаете, как в вашем случае будут интерпретироваться пробелы - просто скопируйте их из рабочего файла. Если речь идёт о тексте, который не будет показан пользователю, зачастую полезно заменить пробелы на нижнее подчёркивание, что позволяет обойти эту проблему.

Комментарии начинаются со знака решётки (#). Если после знака решётки не расположена директива препроцессора, то весь текст после этого знака будет проигнорирован движком WML.

Структура тегов и атрибутов

Синтаксис WML содержит два основных элемента: теги и атрибуты. Сами атрибуты состоят из ключей и значений. Например:

 [tag]
     key=value
 [/tag]

Теги используются для группировки информации, тогда как сами данные содержатся в атрибутах. Ключи определяют тип данных, который должен быть сохранён, а сами данные хранятся в значениях. В процессе обработки WML теги определяют единицы информации, такие как действия, которые должны быть предприняты или даже содержимое всей компании. Они определяют контекст атрибутов, расположенных внутри этого тега. Для каждой строки key=value в пределах тега атрибут с именем key получает значение value. Можно располагать тег внутри другого тега. Внутренний тег содержит потомка внешнего тега, как в данном примере:

 [parent_tag]
     key1=value1
     [child_tag]
         key2=value2
     [/child_tag]
 [/parent_tag]

Каждый тег описывает свою часть игры; разные теги работают по разному, что позволяет тегам быть зависимыми от контекста. Есть различные "теги верхнего уровня", которые могут располагаться вне других тегов; каждый тег определяет допустимые для него теги потомков. Встретив неопознанный тег игра прекращает обработку WML, но есть некоторые ситуации (в частности FilterWML) в которых неопознанные теги просто игнорируются. Для получения списка всех тегов со ссылками на их описания смотрите страницу AlphabeticalWML.

Атрибуты, которые могут быть определены в теге зависят от самого этого тега. Установка значений для допустимых ключей определяет поведение тега. Неопознанные ключи просто игнорируются.

Теги и имена ключей могут состоять только из букв, цифр и символа нижнего подчёркивания. +, -, или пробел в их именах недопустимы. Значения же таких ограничений не имеют.

Синтаксис исправления тега

Добавление плюса перед именем тега позволяет прикрепить его к предыдущему тегу (обычно, с тем же именем) вместо того чтобы объявить новый тег. Таким образом Вы можете добавлять в тег новые атрибуты или переписывать уже имеющиеся.

 [tag]
     key=value
 [/tag]
 [+tag]
     key=value
 [/tag]
  • Всем ключам в +tag будут присвоены заданные значения. Если ключ в этом теге ещё не существует, то он будет в него добавлен. В противном случае его значение будет изменено на новое.
  • Любые потомки +tag`a будут добавлены в качестве потомков к последнему тегу. Имейте ввиду, что оригинальные потомки будут изменены, так как происходит добавление, а не слияние."
  • Вы не можете изменять дочерний тег после того, как закрыт родительский. И использование нескольких [+tag] в одной строке не продвинет Вас в более вложенные области тега. Однако это ограничение может быть изменено в будущих версиях игры.

Синтаксис множественного присваивания

Существует возможность задать несколько атрибутов на одной строке. Это можно сделать перечислив необходимые ключи слева от знака присваивания а справа перечислив соответствующие значения:

 [tag]
     key1,key2,key3=value1,value2,value3
 [/tag]

то же самое что и:

 [tag]
     key1=value1
     key2=value2
     key3=value3
 [/tag]
  • Если в списке присутствуют лишние ключи, то им будет присвоено пустое значение. Если есть лишние значения, то последний ключ получит все эти значения, разделённые запятыми.

Значения специальных атрибутов

Хотя значением атрибута может быть только соответствующий текст, оно может быть задано различными способами, в зависимости от цели использования..

  • key = "value": значение в кавычках - это значение, заключённое в кавычки, как ни странно. Это бесполезно для значений, располагающихся на одной строке, так как они так и интерпретируются. Однако кавычки Вам понадобятся для определение значения на нескольких строчках (чтобы перевод строки не завершал ввод значения). Кроме того, кавычки могут использоваться для того, чтобы лишить некоторые знаки их специального значения и чтобы не отбрасывались нужные пробелы. В правильном WML кавычки никогда не создадут Вам проблем.
  • key = _"value": значение, подлежащее переводу это значение, которое подлежит переводу и должно быть использовано для всех текстов, которые показываются пользователю (чаще всего встречается в [story], [message], name= key при определении юнитов). Такое значение заключено в кавычки и ему предшествует нижнее подчёркивание (_). В терминах синтаксиса WML оно похоже на значение в кавычках, но оно не сравнимо с другими значениями. Эти значения предназначены для отображения на экране, тогда как значения в кавычках лучше подходят для внутренних данных.
  • key = "value1" + "value2": конкатенация строк осуществляется с помощью знака сложения (+). Если знак сложения находится вне кавычек, то это значит, что строка/значение справа будет прикреплена к строке/значению слева. Для включения плюса в само значение его надо заключить в кавычки. На самом деле кавычки не обязательны для применения конкатенации,но их рекомендуется использовать чтобы легко можно было определить где начинается и заканчивается значение и обнаружить некоторые виды ошибок.
  • key = "quoted ""double quoted value"" value": двойные кавычки могут быть использованы для того, чтобы включить знак кавычек в значение в кавычках. Двойные кавычки выдают один знак кавычек и не прерывают цитирование значения (они не обязательно должны быть парными).
  • key = $variable: a замещение переменной устанавливает значение ключа равным значению указанной WML переменной. На это указывает знак доллара ($) и это лишь частный случай замещения переменной, так как переменные могут быть замещены внутри других значений. Тут Вы найдёте больше информации о значениях, основанных на WML переменных. (Учтите, что некоторые ключи должны иметь в качестве значения имя переменной, а не её значение; в таком случае не надо использовать знак доллара.) Замещение переменной поддерживается лишь в некоторых контекстах, таких как IntroWML и EventWML.
  • key = "$(formula-expression)": формула устанавливает значение ключа в результат вычисления формулы. На это указывает занк доллара ($) за которым идёт выражение в скобках. Смотрите FormulaAI для более подробной информации о формулах, типах данных, и встроенных функциях. Кавычки вокруг формул не необходимы во всех случаях, но рекомендуется их использовать, тем более что кавычки - единственный способ использовать плюс (+) внутри формулы (без кавычек плюс будет обозначать операцию конкатенации). Формулы поддерживаются только там, где возможны замещения переменных.

Переменные

Переменные в WML используются для сохранения данных, которые могут понадобиться позже. Каждая переменная имеет уникальное имя, которое может содержать только буквы, цифры и знак нижнего подчёркивания. После того, как переменная создана, она продолжает существовать до завершения компании или до явного её уничтожения. Три основные манипуляции, которые мы можем провести с переменными WML - это присвоение значения, получение значения и удаление переменной.

  • Присвоение значения переменной сохраняет это значение в данной переменной. Это делается с помощью тега [set_variable] или макроса типа {VARIABLE}.
  • Запрос к переменной возвращает последнее сохранённое в ней значение (либо пустую строку, если значение не присвоено). Он осуществляется через помещенный перед именем переменной символ доллара: $variable, а четко указать конец имени переменной можно с помощью вертикальной черты: $variable|.
  • Очистка переменной удаляет её из памяти WML-движка. Это полезно для уменьшения объема используемой памяти, так как все используемые переменные прописываются в файлах в сохранений ;) Для удаления переменной используется тег [clear_variable] или макрос {CLEAR_VARIABLE}.

Виды переменных

Скалярные

Скалярные переменные могут содержать единичную строку или число.

 [set_variable]
     name=my_variable
     value="sample value"
 [/set_variable]

Полное имя скалярной переменной - это то имя, которое Вы ей даёте, в нашем случае - my_variable. Обратите внимание, что значение пременной может быть переводимым и даже содержать формулы (Special Attribute Values).

Массивы

Массивы - это пронумерованная последовательность переменных. Есть несколько специальных тегов для задания информации в виде массива, например [store_unit] и [store_locations]. Можно создать массив и при помощи [set_variable]:

 [set_variable]
     name=my_awesome_array[0].x
     value=10
 [/set_variable]
 [set_variable]
     name=my_awesome_array[1].x
     value=12
 [/set_variable]
 [set_variable]
     name=my_awesome_array[2].x
     value=14
 [/set_variable]

В любом случае при работе с массивами чаще оказывается проще использовать [set_variables]:

 [set_variables]
     name=my_awesome_array
     [value]
         x=10
     [/value]
     [value]
         x=12
     [/value]
     [value]
         x=14
     [/value]
 [/set_variables]

Если foo - имя массива, то foo[0] - это полное имя первой переменной в этом массиве, foo[1] - полное имя второй переменной и т.д. foo.length - это специальная переменная, которая содержит длину массива, т.е. количество содержащихся в нём переменных. Однако, так как нумерация идёт с нуля, если значение foo.length равно 18, значит, последний элемент массива называется. Если Вы хотите обратиться к массиву как к контейнеру, то используйте index[0], поэтому $foo.bar то же самое, что и $foo[0].bar

Внимание: Не пытайтесь сохранить скалярное значение в элемент массива, которые является контейнером скалярных переменных. Поэтому обращение к переменной с именем foo[3] как если бы она была скалярной неверно; вместо этого используйте foo[3].value для сохранения скалярного значения. (Так как в некоторых случаях ошибки при этом не возникает, Вы можете получить непредсказуемое поведение. Например, загрузка названия сохранения такой игры может вызвать ошибку WML.)

Контейнер

Контейнеры могут содержать любое количество скалярных переменных или массивов. Есть теги для присвоения специальной информации, например, [store_side]. Для того, чтобы обратиться к переменной bar, сохранённой в контейнере foo надо написать foo.bar. Конкретный индекс в массиве тоже можно рассматривать как контейнер.

Условия

Переменные могут быть сравнены между собой и могут участвовать в тегах [if] или [while]. Более подробно это описано в ConditionalActionsWML.

Подстановка переменных

Когда перед именем переменной стоит знак $, то вместо этого имени подставляется содержимое этой переменной. Например:

 [event]
     name=turn 1
     [set_variable]
         name=my_variable
         value= _ "Konrad"
     [/set_variable]
     [message]
         speaker=Delfador
         message= _ "Hello, $my_variable|... How are you?"
     [/message]
 [/event]

Этот WML код определяет сообщение, которое Делфадор скажет на первом ходу - "Hello, Konrad... How are you?".

Когда Вы программируете события сценария (EventWML), скалярная переменная может спокойно быть замещена в правой части выражения key=value. Если в этом выражении WML движок встречает знак $, то всё, что между ним и знаком |, трактуется как полное имя переменной и на это место подставляется значение этой переменной.

В некоторых случаях знак |, означающий конец имени переменной может быть опущен. Правило таково: если нет знака |, то имена переменных могут содержать буквы, цифры, знак нижнего подчёркивания, парные квадратные скобки и точки. Все остальные знаки, например, две точки подряд, не включаются в имя переменной. Если имя переменной не указано (при использовании $|), вместо этого будет подставлен только знак $, что позволяет легко добавить знак доллара в интерпретируемую строку.

Текстовый (сырой) режим

Есть несколько мест, где какая-либо замена и подстановка нежелательна. В таких случаях знак $ не имеет никакого специального значения. Для этого используется следующий синтаксис:

  • значение literal= внутри [set_variable]
  • содержимое [literal] внутри [set_variables]

Автоматически сохраняемые значения

  • side_number: номер текущей игровой стороны (может быть пустым в событиях start и prestart)
  • turn_number: номер текущего хода (может быть пустым в событиях start и prestart)
  • x1: x-координата локации, где произошло последнее событие
  • y1: y-координата локации, где произошло последнее событие
  • x2: x-координата локации, которая поспособствовала возникновению последнего события
  • y2: y-координата локации, которая поспособствовала возникновению последнего события
  • unit: в событии - юнит, находящийся в локации $x1,$y1
  • second_unit: в событии - юнит, находящийся в локации $x2,$y2
  • this_unit: в стандартном фильтре бойцов - юнит, рассматриваемый как подходящий под этот фильтр
  • damage_inflicted: в событиях attacker_hits и defender_hits - количество нанесённого ущерба
  • weapon: в событиях attack, attack_end, attacker_hits, attacker_misses, defender_hits, defender_misses, die и last_breath, тут содержится информация об оружии которое используется/использовалось юнитом в локации $x1,$y1. Содержит аттрибуты из [attack], см UnitTypeWML.
  • second_weapon: в событиях attack, attack_end, attacker_hits, attacker_misses, defender_hits, defender_misses, die и last_breath, тут содержится информация об оружии которое используется/использовалось юнитом в локации $x2,$y2. Содержит аттрибуты из [attack], см UnitTypeWML.

Внимание: автоматически сохраняемые контейнеры и массивы сохраняют значения после того, как был осуществлен к ним доступ. Это означает, что Вы можете получить неверный результат, например, если убивается юнит в $x1,$y1 как первое действие в событии moveto, а затем Вы пытаетесь получить зачение $unit.something. Это может быть исправлено путём "бессмысленного" досупа, например, добавив юниту 0 очков здоровья.

Тег [variables]

Тег [variables] используется в сохранённых играх для описания текущего значения каждой переменной, а в файлах сценариев - для установки начальных значений переменным на старте.

Присвоение скалярным переменным происходит с использованием атрибута, где ключ атрибута - имя переменной, а значение - значение, которое надо сохранить в ней.

Контейнерам значение присваивается при помощи соответствующего тега, например для переменной foo это будет тег [foo].

Для присвоения значения массиву с именем foo Вы должны использовать тег [foo] несколько раз, тогда первый раз он описывает foo[0], затем foo[0] и т.д.

Сохранение переменных в юнитах

Иногда полезно хранить собственные WML переменные в юните. Юнит сохраняемый при помощи команды [store_unit] имеет субконтейнер unit.variables, где и можно сохранить переменные для этого юнита. (Не забывайте использовать [unstore_unit] для сохранения изменений.)Один из плюсов такого подхода в состоит в том, что юнит затем может быть отсеян на основании этого значения:

[filter]
  [filter_wml]
    [variables]
      my_variable="test"
    [/variables]
  [/filter_wml]
[/filter]

Примеры использования переменных

Рассмотрим сохранённую игру со следующим тегом [variables] (или только начатый сценарий с этим тегом)

[variables]
    attitude_of_elves=hate
    attitude_of_dwarves=love
    attitude_of_humans=like
    current_opponent=elves
[/variables]

Тогда,

[message]
   message="Oh, I see $current_opponent|! They surely $attitude_of_$current_opponent|| us!"
[/message]

отобразит следующее сообщение:

Oh, I see elves! They surely hate us!

Рассмотрим другую игру с переменными:

[variables]
    our_side=1
    their_side=2
[/variables]

где у стороны 1 75 золота, а у стороны 2 - 50. Тогда,

[store_side]
    side=$our_side
    variable=we
[/store_side]
[store_side]
    side=$their_side
    variable=they
[/store_side]
[message]
    message=We have $we.gold gold, they have $they.gold gold.
[/message]
[if]
    [variable]
        name=we.gold
        greater_than=$they.gold
    [/variable]
    [then]
        [message]
            message=This should be easy!
        [/message]
    [/then]
    [else]
        [message]
            message=This will not be easy!
        [/message]
    [/else]
[/if]
[clear_variable]
    name=we
[/clear_variable]
[clear_variable]
    name=they
[/clear_variable]

Отобразит такое сообщение:

We have 75 gold, they have 50 gold.
This should be easy!

Если же у стороны 2 будет 100 золота, мы увидим это:

We have 75 gold, they have 100 gold.
This will not be easy!

Код

[store_unit]
    [filter]
        canrecruit=yes
        side=1
    [/filter]
    variable=leader
[/store_unit]
[message]
    message=Our leader's first attack does $leader[0].attack[0].damage damage per hit.
[/message]
[clear_variable]
    name=leader
[/clear_variable]

Будет отображать правду ;).

Более сложные примеры использования переменных можно увидеть в разделе UsefulWMLFragments.

Смотри также