{{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}:{ сюда %} %}'' после ''//'' идёт текст, а не начало шаблона, поэтому ''//'' останется на месте и строка так и будет комментарием (''// смотри сюда'').