{{indexmenu_n>20}} ====== Templates ====== Templates are dynamic expressions evaluated on the server before the page is sent to the players. In the browser, only the result of the expression for their specific team is shown. The template code itself is NOT visible, even in the page source code. Classic applications of templates: * [[en:authors_main:task_editor:advanced:edit_templates#by_team_id|Individual tasks for the team]] (splitting flows). * [[en:authors_main:task_editor:advanced:edit_templates#templates_using_answers_in_the_task|Bonuses whose text depends on which code closed the bonus]]. Templates can be written in regular editor mode or in Source mode in the task description, hint text, or bonus text. Templates can be nested. ===== Google Sheet for Template Generation ===== To make it easier to write template syntax, you can copy and use a special spreadsheet: [[https://docs.google.com/spreadsheets/d/1viqP3CBjYgq_vPYH-Z2USIC1DYrXzQG8_eV2bDw-4JQ/edit?usp=sharing|QEng Template Generation Google Sheet]]. ====== Various Types of Templates ====== ===== Task Modification for a Team ===== ==== By Lineup ID (Sequence) ==== {% match line }:{ {%= 688 /*comment: lineup name*/}:{ Text for lineup with ID 688 %} {%= 643 }:{ Text for lineup with ID 643 %} {%= 653,655 }:{ Text for lineup with ID 653 or 655 %} {%= ?}:{ Text for any other lineup %} %} ==== By Team ID ==== {% match team }:{ {%= 688 /*comment: team name*/}:{ Text for team with ID 688 %} {%= 643 }:{ Text for team with ID 643 %} {%= 653,655 }:{ Text for team with ID 653 or 655 %} {%= ?}:{ Text for any other team %} %} [[https://qeng.org/game.php?jump_to&gid=3493&task_id=54272|Example in game]] ===== Binding a Task Event to Real Time ===== Useful for releasing codes or hints at a specific absolute time. To convert date/time, use [[https://converter.by/unixtime|Unix Time Converter]]. {% unix_time 1639999296/*date in unix time*/, Opens, Left}:{ This text will be shown after the specified time. %} [[https://qeng.org/game.php?jump_to&gid=3493&task_id=54338|Example in game]] ===== Templates Using Answers in the Task ===== ==== Check the Last (Current) Answer Submitted for the First Code ==== *(Replace `code_1` with the required code index, e.g. `code_5` for the fifth code)* {% match code_1 }:{ {%= abc}:{ The answer "abc" is submitted for the first code. %} {%= bac, cba}:{ The answer "bac" or "cba" is submitted for the first code. %} {%= !no_answer!}:{ No correct answer has been submitted for the first code yet. %} {%= ?}:{ Some other answer synonym has been submitted. %} %} ==== Check the Very First Answer Submitted for the Second Code ==== {% match code_first_2 }:{ {%= abc}:{ The first answer submitted for this code was "abc". %} {%= !no_answer!}:{ The code has not been submitted yet. %} {%= ?}:{ Another answer was submitted. %} %} ==== Special Branch Values ==== Besides specific answers, a branch may hold: * **''!no_answer!''** — the correct answer has not been submitted yet. * **''!any_answer!''** — any answer has been submitted. Unlike ''?'', it does **not** match when there is no answer yet. Handy when a code has synonyms and all you care about is that it is solved. * **''?''** — any value, including ''!no_answer!''. Put this branch last: everything listed after it is never checked. {% match bonus_3 }:{ {%= !any_answer!}:{ The bonus is solved — no matter which synonym was used. %} {%= !no_answer!}:{ The bonus is not solved yet. %} %} ==== Check Bonuses and Spanning Bonuses ==== Just like codes, you can check answers for bonuses: * **''bonus_1''** / **''bonus_first_1''** — last or first answer submitted for bonus 1 on the current task. * **''gbonus_1''** / **''gbonus_first_1''** — last or first answer submitted for spanning (global) bonus 1. Spanning bonuses can be checked even on levels where they are not displayed. [[https://qeng.org/game.php?jump_to&gid=3493&task_id=54273|Example in game]] ===== Check Who Submitted the Answer ===== You can prepend ''who_'' to answer checks to find out who in the team submitted the answer. Possible values: * **''me''** — code was submitted by the current logged-in user. * **''other''** — code was submitted by another team member. * **''!no_answer!''** — not submitted yet. *(Anonymous players without registration are treated as the same user).* {% match who_code_1 }:{ {%= me}:{ I submitted the first code. %} {%= other}:{ My teammate submitted the first code. %} {%= !no_answer!}:{ Nobody has submitted the code yet. %} %} ===== Check Which Team Submitted the Answer (for Inter-team Duels) ===== Prepend ''who_team_'' to check which team solved a spanning/shared task: Possible values: * **''me''** — my team solved the code. * **''other''** — an opponent team solved the code. * **''!no_answer!''** — not solved yet. {% match who_team_code_1 }:{ {%= me}:{ Our team solved this code first! %} {%= other}:{ Opponent team solved this code first. %} %} ===== Templates Based on Player Interface Language ===== {% match lang }:{ {%= ru}:{ Russian interface language selected. %} {%= uk }:{ Ukrainian interface language selected (uk). %} {%= en }:{ English interface language selected. %} {%= ?}:{ Some other language. %} %} ==== How to Make a Multilingual Game ==== > **There is an easier way now - for translating text, links and pictures.** A multilingual game is made with **translations**: [[en:authors_main:game_management:localization|Multilingual Game (Translations)]]. The task stays one text, the translations live beside it, and the editor shows what is still untranslated. The template below keeps working and nothing has to be changed in existing games, and for a new game it stays the right choice where a language does not need a different version of the same text (that is exactly what translation is for) but a genuinely **different structure**: its own set of html blocks that other languages do not have, its own logic in the level script rather than just a different string in it, or branching by language combined with another template - by code, by team, by bonus. If you just need a translation - see translations above. This template lets one game run in several languages at once: a player sees only their own branch, and the other translations never reach the page source. Players pick the language in the site menu; it can also be set with a parameter in the page address — ''?lang=de'', ''?lang=uk'' and so on. The choice is remembered in cookies. If the player has never chosen, the language is detected from their browser settings. ''lang'' returns a two-letter language code. The current list of languages is always visible in the language menu on the site; at the time of writing it is ''de'', ''en'', ''es'', ''et'', ''fi'', ''fr'', ''it'', ''lt'', ''lv'', ''nl'', ''pl'', ''ru'', ''uk''. Things worth remembering: * **Always add the ''?'' branch** and put it last. It fires when the player's language has no branch of its own — otherwise such a player sees an empty task. It usually holds the text in the game's main language. * **You do not have to translate into every language.** Branches for your audience's languages plus the fallback branch are enough. * **One branch may cover several languages** — list the codes separated by commas: ''{%= ru, uk}:{ ... %}''. * **The technique works everywhere templates work**: task text, hints, bonuses, texts shown after solving. * **Keep the answer codes the same for all languages** — otherwise you have to make sure the task branches and the level answers do not drift apart. If an answer really is language-dependent (a word found on location, say), put all the variants into the code separated by commas. * Templates do not translate the game name, its description in the game list, or invitation emails — write those in a language the whole audience understands, or give both variants separated by a slash. The easy way to check a translation is to open the game with an explicit language parameter — ''https://qeng.org/game/1234/?lang=lt''. Look at the ''?'' branch too: just pick a language that has no branch of its own. To give the player a language switcher inside the task itself, put a plain ''select'' into the text and its handler into the [[en:authors_main:task_editor:advanced:author_scripts|Task script]]: var select = document.getElementById('lang_select'); if (select) { // document.documentElement.lang is the CONTENT language, which gets // overridden if the game itself also has translations turned on (see // above). The interface language the player actually picked is more // reliably read from the lang cookie. 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|Example in game]] ===== Check Product Purchase Status (Paywall) ===== How to create a product, place a payment button and test the whole thing without real money is described in [[en:authors_main:game_management:payments|Paid Content (Paywall)]]. What follows here is only the template that closes off the paid content. If your game uses paid levels or paid hints, you can check the purchase status: * **''product_KEY''** — where KEY is the product key from settings. Possible values: * **''yes''** — product purchased by the team. * **''pending''** — payment started but not yet finalized. * **''no''** — not purchased. {% match product_level_5 }:{ {%= yes}:{ The team purchased access to level 5. %} {%= pending}:{ Payment is pending. Please wait and refresh the page. %} {%= no}:{ Access closed. Price is $1. Click to purchase: %pay_button level_5% %} %} ===== Templates inside javascript ===== When a template sits in the middle of javascript code, the code editor complains about the ''{% %}'' syntax — for javascript it is a syntax error. To avoid that, the service lines of the template may be commented out with a double slash ''//''. The engine strips those ''//'' before evaluating the template, so the code inside the template becomes live. A ''//'' is stripped only when it is immediately followed (spaces aside) by ''{%'' or ''%}''. A space after ''//'' is optional, and the indent before ''//'' is preserved. show_money(); // {% match gbonus_141}:{ // {%= some_code}:{ enter_silent('the whole game is done'); // %} // {%= ?}:{ play_sound('limit'); // %} // %} A team that entered ''some_code'' into global bonus 141 gets: show_money(); enter_silent('the whole game is done'); Closing brackets may share a line — ''// %} %}'' — and a short template can be written on a single line: // {% match team}:{ {%= 172}:{ var boss = true; %} {%= ?}:{ var boss = false; %} %} Regular comments are not affected: in the line ''// see {% match team}:{ {%= 172}:{ here %} %}'' the ''//'' is followed by text rather than by the start of a template, so the ''//'' stays and the line remains a comment (''// see here'').