Шаблоны — это динамические выражения, которые вычисляются на сервере до отправки страницы игрокам. В браузере во время игры отображается только результат вычисления для конкретной команды. Сам код шаблона игрокам не виден (его нет в исходном коде страницы).
Классические применения шаблонов:
Шаблоны можно прописывать в обычном режиме редактора или в режиме исходного кода (Source) в текст заданий, подсказок и бонусов. Шаблоны могут быть вложенными.
Для облегчения написания синтаксиса шаблонов вы можете скопировать себе и использовать специальную таблицу: Google Таблица генерации шаблонов QEng.
{% match line }:{
{%= 688 /*комментарий: название линейки*/}:{
Текст для линейки с ID 688
%}
{%= 643 }:{
Текст для линейки с ID 643
%}
{%= 653,655 }:{
Текст для линейки с ID 653 или 655
%}
{%= ?}:{
Текст для любой другой линейки
%}
%}
{% match team }:{
{%= 688 /*комментарий: название команды*/}:{
Текст для команды с ID 688
%}
{%= 643 }:{
Текст для команды с ID 643
%}
{%= 653,655 }:{
Текст для команды с ID 653 или 655
%}
{%= ?}:{
Текст для любой другой команды
%}
%}
Полезно для выдачи виртуальных кодов/подсказок в строго определенное время. Для перевода даты в метку времени используйте Конвертер Unix Time.
{% unix_time 1639999296/*дата в unix time*/, Откроется, Осталось}:{
Этот текст будет показан только после наступления указанного времени.
%}
*(Замените `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 — последний или первый введенный ответ в первый сквозной (глобальный) бонус игры. Сквозные бонусы можно проверять даже на тех уровнях, где они не выведены на экран.
К параметрам проверки ответов можно добавить приставку 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 }:{
Выбран английский язык интерфейса.
%}
{%= ?}:{
Какой-то другой язык.
%}
%}
Есть способ проще - для перевода текста, ссылок и картинок. Многоязычную игру теперь делают переводами: Многоязычная игра (переводы). Задание остаётся одним текстом, переводы лежат рядом, а редактор показывает, что ещё не переведено. Шаблон ниже продолжает работать и ничего менять в готовых играх не надо, а для новых игр остаётся правильным выбором там, где языку нужна не другая версия того же текста (это как раз переводится), а другая структура: свой набор 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, а в Скрипт задания — его обработчик:
<select id="lang_select"> <option value="en">English (en)</option> <option value="uk">Українська (uk)</option> </select>
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(); }; }
Как завести товар, поставить кнопку оплаты и протестировать всё это без реальных денег, описано в разделе Платный контент (Paywall). Здесь — только шаблон, которым закрывается платное содержимое.
Если в вашей игре используются платные уровни или платные подсказки, вы можете проверить статус покупки:
product_KEY — где вместо KEY указывается ключ продукта из настроек.Возможные значения:
yes — товар успешно куплен командой.pending — процесс оплаты начат, но транзакция еще обрабатывается.no — товар не оплачен.{% match product_level_5 }:{
{%= yes}:{
Команда купила доступ к 5 уровню.
%}
{%= pending}:{
Оплата обрабатывается. Пожалуйста, подождите и обновите страницу.
%}
{%= no}:{
Доступ закрыт. Стоимость прохождения — $1. Нажмите для оплаты:
%pay_button level_5%
%}
%}
Если шаблон стоит посреди javascript-кода, редактор кода ругается на синтаксис {% %} — для javascript это ошибка. Чтобы этого не происходило, служебные строки шаблона можно закомментировать двойным слэшем до вычисления шаблона, и код внутри шаблона станет рабочим.
. Движок уберёт эти
не обязателен, отступ перед убирается только тогда, когда сразу после него (не считая пробелов) идёт {% или %}. Пробел после , а короткий шаблон записать целиком в одну строку:
сохраняется.
<code JavaScript>
show_money();
{% match gbonus_141}:{
{%= some_code}:{
enter_silent('прошли игру целиком');
%}
{%= ?}:{
play_sound('limit');
%}
%}
</code>
Команда, вбившая в сквозной бонус 141 ответ some_code, получит:
<code JavaScript>
show_money();
enter_silent('прошли игру целиком');
</code>
Закрывающие скобки можно собрать в одну строку — %} %}
// {% match team}:{ {%= 172}:{ var boss = true; %} {%= ?}:{ var boss = false; %} %}
Обычные комментарии не затрагиваются: в строке смотри {% match team}:{ {%= 172}:{ сюда %} %} идёт текст, а не начало шаблона, поэтому после ).
останется на месте и строка так и будет комментарием ( смотри сюда