Изменения после выхода обучающих видео
С момента выхода оригинальных обучающих видео (5-6 лет назад) Denizen получил множество обновлений! На этой странице собраны изменения, о которых стоит знать ради актуальных best-practices.
Рекомендованный редактор
В обучающих видео в качестве редактора скриптов показывался Notepad++. Это был просто чуть более удобный текстовый редактор. С тех пор у нас появился полноценный скриптовый редактор — расширение для VS Code.
Подробности — на странице «Настройка редактора скриптов».
Обратите внимание, что в связи с этим расширение .yml больше не используется. Вместо него — .dsc.
Мы теперь в Discord
В обучающих видео показано общение с ботом в IRC — если вы попробовали зайти в этот IRC, вы уже видели сообщения о том, что мы переехали в Discord. Вероятно, вы и так это знаете, раз уж добрались до этого руководства.
Но на всякий случай: мы в Discord — заходите!. Там есть живая поддержка людьми, а также бот-помощник для поиска по документации, проверки скриптов и т. п.
Синтаксис с двоеточием
Синтаксис с фигурными скобками заменён на синтаксис с двоеточием. Как описано на странице «Команда if», синтаксис с двоеточием позволяет размещать несколько команд внутри команд вроде if и foreach. В отличие от синтаксиса со скобками, никакой закрывающий символ не нужен — как только вы вернётесь к предыдущему уровню отступов, скрипт продолжит выполняться как обычно.
Если у вас есть скрипты на синтаксисе со скобками, вы можете быстро перевести их на синтаксис с двоеточием: удалите все закрывающие фигурные скобки (}), замените открывающую ({) на двоеточие и уберите лишние пробелы между двоеточием и последним другим символом в строке.
Вот пример такого перевода:
old_brace_syntax:
type: task
script:
- if <player.has_flag[test]> {
- narrate "This is an example of braced syntax!"
}
- narrate "This narrate will always run!"
new_colon_syntax:
type: task
script:
- if <player.has_flag[test]>:
- narrate "This is an example of colon syntax!"
- narrate "This narrate will always run!"
Синтаксис с двоеточием проще, чище выглядит, и в качестве бонуса Denizen ещё и парсит его быстрее!
Синтаксис определений
В команде define произошло два важных изменения: во-первых, изменился синтаксис самого тега определения, а во-вторых, теперь команда define поддерживает data actions.
В видео использовались две разные формы синтаксиса: первая — «древний» процентный синтаксис (вроде %this%), вторая — «старый» синтаксис с тегами (вроде <def[this]>).
Теги определений больше так не выглядят. Теперь они выглядят как <[this]> (для определения с именем this, разумеется). Дополнительные детали об использовании и модификации определений — на странице «Определения».
Учтите, что %name% считается древним и полностью неподдерживаемым, его использовать нельзя. А вот <def[name]> — это более старый/альтернативный синтаксис для современного <[name]> (та же база тегов, только теперь вместо тега с именем def доступен пустой тег).
Вот пример перевода со старого синтаксиса на новый:
old_definition_syntax:
type: task
script:
- define name <player.name>
# Древний
- narrate "Hello, %name%!"
# Старый
- narrate "Hello, <def[name]>!"
new_definition_syntax:
type: task
script:
- define name <player.name>
- narrate "Hello, <[name]>!"
Изменения в команде while
Раньше команда while принимала только один аргумент, поэтому для вычисления условий приходилось использовать теги вроде <player.health.is[>=].to[10]>]>.
Этого ограничения больше нет — команда while теперь поддерживает операторы, как и команда if.
Вот пример task-скрипта, который ждёт, пока у игрока здоровье не упадёт ниже 10, и затем предупреждает его — со старым и современным синтаксисом:
old_while_syntax:
type: task
script:
- narrate "Challenge: don't lose too much health!"
- while <player.health.is[>=].to[10]>:
- wait 1s
- narrate "Your health got too low! You lose!"
new_while_syntax:
type: task
script:
- narrate "Challenge: don't lose too much health!"
- while <player.health> >= 10:
- wait 1s
- narrate "Your health got too low! You lose!"
Заметьте, что конкретно этот стиль «подождать, пока что-то случится» был заменён на специализированную команду waituntil, которую можно использовать так:
waituntil_example:
type: task
script:
- narrate "Challenge: don't lose too much health!"
- waituntil rate:1s <player.health> < 10
- narrate "Your health got too low! You lose!"
Изменения в assignment-скриптах
Раньше на NPC вешали несколько interact-скриптов и использовали условия, чтобы выбрать, какой из них запустится. В Denizen теперь есть шаги внутри interact-скриптов и команда zap, так что нужен (и поддерживается) только один interact-скрипт. Номера рядом с записями interact scripts в assignment-скрипте больше не нужны и их следует убрать.
Вот примеры старого и обновлённого синтаксиса:
old_assignment_script:
type: assignment
interact scripts:
- 10 my_cool_npc_interaction
new_assignment_script:
type: assignment
interact scripts:
- my_cool_npc_interaction
stop — это новый queue clear
Раньше для остановки выполняющейся очереди использовали queue clear. Эту команду обновили до stop.
Замена простая:
old_queue_clear:
type: task
script:
- if <player.has_flag[buff]>:
- queue clear
- narrate "You don't have the necessary buff!"
new_stop:
type: task
script:
- if <player.has_flag[buff]>:
- stop
- narrate "You don't have the necessary buff!"
Для проверки наличия флага используйте .has_flag[]
Раньше, в том числе в обучающем видео «Квест на убийство», .flag[] использовался и для получения значения флага, и для проверки, существует ли флаг вообще.
Теперь правильный способ проверить наличие флага — использовать .has_flag[]. .flag[] теперь используется только для чтения значения и только там, где заведомо известно, что флаг существует (или с fallback'ом). Вот пример:
old_flag:
type: task
script:
- if <player.flag[VIP]>:
- narrate "Your VIP level is <player.flag[VIP]>!"
new_has_flag:
type: task
script:
- if <player.has_flag[VIP]>:
- narrate "Your VIP level is <player.flag[VIP]>!"
Переделка системы флагов
В дополнение к тегу has_flag, в декабре 2020 года произошла полная внутренняя переделка системы флагов.
Самое релевантное изменение по сравнению с видео: тег <player.flag[NAME].expiration> из видео про квест на убийство теперь нужно писать как <player.flag_expiration[NAME].from_now>.
Из-за серьёзных общих изменений в системе флагов используйте более современную документацию, а не старые видео — загляните на страницу «Флаги».
Отмена событий теперь чуть сложнее
В видео про GUI-инвентари учили отменять обобщённое событие клика и выполнять действия в ответ на более конкретное событие.
Сам подход по-прежнему правильный, но в современном Denizen не хватает одного важного кусочка, чтобы всё работало хорошо.
Раньше события просто все срабатывали, и «отмена» события означала, что базовое действие не выполнится. В современном Denizen система умнее и знает, что после отмены события не нужно запускать другие скриптовые события. Это поведение можно просто отключить для соответствующих событий, но лучше гарантировать, что общее событие-отмена отработает последним. Для этого достаточно добавить высокое значение priority к строке события-отмены.
Так что вместо on player clicks in my_inventory: теперь нужно on player clicks in my_inventory priority:100:, и аналогично для события drags. Приоритеты событий обрабатываются по порядку, по умолчанию равны 0. Так что сначала отработают все конкретные события со стандартным приоритетом, и только после них — общие события-отмены (теперь с приоритетом 100).