{{indexmenu_n>20}}
====== Шаблоны (Темплейты) ======
Шаблоны — это динамические выражения, которые вычисляются на сервере до отправки страницы игрокам. В браузере во время игры отображается только результат вычисления для конкретной команды. Сам код шаблона игрокам не виден (его нет в исходном коде страницы).
Классические применения шаблонов:
* [[authors_main:task_editor:advanced:edit_templates#по_id_команды|Индивидуальные задания для команды]] (разделение потоков).
* [[authors_main:task_editor:advanced:edit_templates#темплейты_с_использованием_ответов_в_задании|Бонусы, контент которых зависит от того, каким именно кодом был закрыт предыдущий бонус]].
Шаблоны можно прописывать в обычном режиме редактора или в режиме исходного кода (Source) в текст заданий, подсказок и бонусов. Шаблоны могут быть вложенными.
===== Google Таблица для генерации шаблонов =====
Для облегчения написания синтаксиса шаблонов вы можете скопировать себе и использовать специальную таблицу:
[[https://docs.google.com/spreadsheets/d/1viqP3CBjYgq_vPYH-Z2USIC1DYrXzQG8_eV2bDw-4JQ/edit?usp=sharing|Google Таблица генерации шаблонов QEng]].
====== Различные виды шаблонов ======
===== Модификация задания для команды =====
==== По ID линейки (прохождения) ====
{% match line }:{
{%= 688 /*комментарий: название линейки*/}:{
Текст для линейки с ID 688
%}
{%= 643 }:{
Текст для линейки с ID 643
%}
{%= 653,655 }:{
Текст для линейки с ID 653 или 655
%}
{%= ?}:{
Текст для любой другой линейки
%}
%}
==== По ID команды ====
{% match team }:{
{%= 688 /*комментарий: название команды*/}:{
Текст для команды с ID 688
%}
{%= 643 }:{
Текст для команды с ID 643
%}
{%= 653,655 }:{
Текст для команды с ID 653 или 655
%}
{%= ?}:{
Текст для любой другой команды
%}
%}
[[https://qeng.org/game.php?jump_to&gid=3493&task_id=54272|Пример в игре]]
===== Привязка события в задании к реальному времени =====
Полезно для выдачи виртуальных кодов/подсказок в строго определенное время. Для перевода даты в метку времени используйте [[https://converter.by/unixtime|Конвертер Unix Time]].
{% unix_time 1639999296/*дата в unix time*/, Откроется, Осталось}:{
Этот текст будет показан только после наступления указанного времени.
%}
[[https://qeng.org/game.php?jump_to&gid=3493&task_id=54338|Пример в игре]]
===== Шаблоны на основе вбитых ответов =====
==== Проверка последнего (текущего) ответа в первый код ====
*(Замените `code_1` на нужный номер кода, например, `code_5` для пятого кода)*
{% match code_1 }:{
{%= abc}:{
В первый код вбит ответ "abc".
%}
{%= bac, cba}:{
В первый код вбит ответ "bac" или "cba".
%}
{%= !no_answer!}:{
В первый код ещё не вводили правильный ответ.
%}
{%= ?}:{
Вбит какой-то другой синоним/ответ в первый код.
%}
%}
==== Проверка самого первого вбитого ответа во второй код ====
{% match code_first_2 }:{
{%= abc}:{
Первым в этот код был вбит ответ "abc".
%}
{%= !no_answer!}:{
Код ещё не вбит.
%}
{%= ?}:{
Был вбит другой ответ.
%}
%}
==== Особые варианты ====
Кроме конкретных ответов, в ветках можно писать:
* **''!no_answer!''** — правильный ответ ещё не введён.
* **''!any_answer!''** — введён любой ответ. В отличие от ''?'', **не** срабатывает, когда ответа ещё нет. Удобно, когда у кода есть синонимы и важен только факт того, что он вбит.
* **''?''** — любое значение, включая ''!no_answer!''. Ставьте эту ветку последней: всё, что описано после неё, уже не проверяется.
{% match bonus_3 }:{
{%= !any_answer!}:{
Бонус закрыт — неважно, каким из синонимов.
%}
{%= !no_answer!}:{
Бонус ещё не закрыт.
%}
%}
==== Проверка бонусов и сквозных бонусов ====
Аналогично кодам, вы можете проверять ответы для бонусов:
* **''bonus_1''** / **''bonus_first_1''** — последний или первый введенный ответ в первый бонус текущего уровня.
* **''gbonus_1''** / **''gbonus_first_1''** — последний или первый введенный ответ в первый сквозной (глобальный) бонус игры. Сквозные бонусы можно проверять даже на тех уровнях, где они не выведены на экран.
[[https://qeng.org/game.php?jump_to&gid=3493&task_id=54273|Пример в игре]]
===== Проверка автора ввода (кто именно вбил код) =====
К параметрам проверки ответов можно добавить приставку ''who_'', чтобы узнать, кто из игроков команды ввел код.
Возможные значения:
* **''me''** — код введен текущим залогиненным пользователем.
* **''other''** — код введен другим участником команды.
* **''!no_answer!''** — ответ еще не введен.
*(Анонимные игроки без регистрации считаются одним пользователем).*
{% match who_code_1 }:{
{%= me}:{
Первый код ввел лично я.
%}
{%= other}:{
Первый код ввел мой напарник по команде.
%}
{%= !no_answer!}:{
Код еще никто не ввел.
%}
%}
===== Проверка команды, вбившей код (для межкомандных дуэлей) =====
Приставка ''who_team_'' позволяет проверить, какая команда ввела код на общем/сквозном задании.
Возможные значения:
* **''me''** — код ввела моя команда.
* **''other''** — код ввела команда соперников.
* **''!no_answer!''** — код еще не введен.
{% match who_team_code_1 }:{
{%= me}:{
Этот код первыми закрыли мы!
%}
{%= other}:{
Увы, соперники успели ввести этот код раньше нас.
%}
%}
===== Шаблоны, зависящие от языка интерфейса игрока =====
{% match lang }:{
{%= ru}:{
Выбран русский язык интерфейса.
%}
{%= uk }:{
Выбран украинский язык интерфейса (uk).
%}
{%= en }:{
Выбран английский язык интерфейса.
%}
{%= ?}:{
Какой-то другой язык.
%}
%}
==== Как сделать многоязычную игру ====
> **Есть способ проще - для перевода текста, ссылок и картинок.** Многоязычную игру теперь делают **переводами**: [[authors_main:game_management:localization|Многоязычная игра (переводы)]]. Задание остаётся одним текстом, переводы лежат рядом, а редактор показывает, что ещё не переведено. Шаблон ниже продолжает работать и ничего менять в готовых играх не надо, а для новых игр остаётся правильным выбором там, где языку нужна не другая версия того же текста (это как раз переводится), а **другая структура**: свой набор html-блоков, которого нет у других языков, своя логика в скрипте задания, а не просто другая строка в нём, или ветвление по языку, скомбинированное с другим шаблоном - по коду, по команде, по бонусу. Если же нужен именно перевод - см. переводы по ссылке выше.
Этим шаблоном одну игру можно выдавать сразу на нескольких языках: игрок увидит только свою ветку, остальные переводы не попадут даже в исходный код страницы.
Игрок выбирает язык в меню сайта; язык можно задать и параметром в адресе страницы — ''?lang=de'', ''?lang=uk'' и так далее. Выбор запоминается в куках. Если игрок ничего не выбирал, язык определяется по настройкам его браузера.
''lang'' возвращает двухбуквенный код языка. Актуальный список языков всегда виден в меню выбора языка на сайте; на момент написания статьи это ''de'', ''en'', ''es'', ''et'', ''fi'', ''fr'', ''it'', ''lt'', ''lv'', ''nl'', ''pl'', ''ru'', ''uk''.
О чём стоит помнить:
* **Всегда добавляйте ветку ''?''** и ставьте её последней. Она сработает, если у языка игрока нет своей ветки, — иначе такой игрок увидит пустое задание. Обычно в неё кладут текст на основном языке игры.
* **Переводить на все языки не обязательно.** Достаточно веток для языков вашей аудитории плюс запасная ветка.
* **Одна ветка может покрывать несколько языков** — коды перечисляются через запятую: ''{%= ru, uk}:{ ... %}''.
* **Приём работает везде, где работают шаблоны**: текст задания, подсказки, бонусы, тексты после решения.
* **Коды-ответы лучше делать одинаковыми для всех языков** — иначе придётся следить, чтобы ветки задания и ответы уровня не разъехались. Если ответ всё-таки языкозависимый (например, слово на локации), впишите в код все варианты через запятую.
* Шаблонами не переводятся название игры, её описание в списке игр и письма-приглашения — их пишут на языке, понятном всей аудитории, или дублируют через слэш.
Проверять перевод удобно, открывая игру с явным параметром языка — ''https://qeng.org/game/1234/?lang=lt''. Загляните и в ветку ''?'': для этого достаточно выбрать язык, для которого ветки нет.
Если хочется дать игроку переключатель языка прямо в задании, добавьте в текст обычный ''select'', а в [[authors_main:task_editor:advanced:author_scripts|Скрипт задания]] — его обработчик:
var select = document.getElementById('lang_select');
if (select) {
// document.documentElement.lang - это язык КОНТЕНТА, он подменяется, если в
// самой игре ещё и включены переводы (см. выше). Настоящий язык интерфейса,
// выбранный игроком, надёжнее читать из куки lang.
var match = document.cookie.match(/(?:^|; )lang=([^;]*)/);
select.value = match ? decodeURIComponent(match[1]) : document.documentElement.lang;
select.onchange = function () {
var url = new URL(window.location.href);
url.searchParams.set('lang', this.value);
window.location.href = url.toString();
};
}
[[https://qeng.org/game.php?jump_to&gid=3493&task_id=83654|Пример в игре]]
===== Проверка статуса оплаты товара (Пейволл) =====
Как завести товар, поставить кнопку оплаты и протестировать всё это без реальных денег, описано в разделе [[authors_main:game_management:payments|Платный контент (Paywall)]]. Здесь — только шаблон, которым закрывается платное содержимое.
Если в вашей игре используются платные уровни или платные подсказки, вы можете проверить статус покупки:
* **''product_KEY''** — где вместо KEY указывается ключ продукта из настроек.
Возможные значения:
* **''yes''** — товар успешно куплен командой.
* **''pending''** — процесс оплаты начат, но транзакция еще обрабатывается.
* **''no''** — товар не оплачен.
{% match product_level_5 }:{
{%= yes}:{
Команда купила доступ к 5 уровню.
%}
{%= pending}:{
Оплата обрабатывается. Пожалуйста, подождите и обновите страницу.
%}
{%= no}:{
Доступ закрыт. Стоимость прохождения — $1. Нажмите для оплаты:
%pay_button level_5%
%}
%}
===== Шаблоны внутри javascript =====
Если шаблон стоит посреди javascript-кода, редактор кода ругается на синтаксис ''{% %}'' — для javascript это ошибка. Чтобы этого не происходило, служебные строки шаблона можно закомментировать двойным слэшем ''//''. Движок уберёт эти ''//'' до вычисления шаблона, и код внутри шаблона станет рабочим.
''//'' убирается только тогда, когда сразу после него (не считая пробелов) идёт ''{%'' или ''%}''. Пробел после ''//'' не обязателен, отступ перед ''//'' сохраняется.
show_money();
// {% match gbonus_141}:{
// {%= some_code}:{
enter_silent('прошли игру целиком');
// %}
// {%= ?}:{
play_sound('limit');
// %}
// %}
Команда, вбившая в сквозной бонус 141 ответ ''some_code'', получит:
show_money();
enter_silent('прошли игру целиком');
Закрывающие скобки можно собрать в одну строку — ''// %} %}'', а короткий шаблон записать целиком в одну строку:
// {% match team}:{ {%= 172}:{ var boss = true; %} {%= ?}:{ var boss = false; %} %}
Обычные комментарии не затрагиваются: в строке ''// смотри {% match team}:{ {%= 172}:{ сюда %} %}'' после ''//'' идёт текст, а не начало шаблона, поэтому ''//'' останется на месте и строка так и будет комментарием (''// смотри сюда'').