A composite code is a final level code assembled from several parts scattered across codes, bonuses, global bonuses and hints. As soon as the team collects every part, the engine submits the assembled code for the players automatically.
Important (applies to all three methods): the final assembled code must exist on the level as a regular code (or as a bonus). Otherwise the engine keeps submitting a non-existent answer and the players' page reloads in a loop.
There are three ways to implement a composite code:
getAllParts / getAllBonuses — the code is assembled in the browser from answers already shown on the page.code_part — a legacy option, kept for backward compatibility.Templates are evaluated on the server before the page is sent. Until the team has collected all the parts, the final code is present neither on the screen nor in the page source — there is no way to find it in advance.
The idea: nest templates inside each other so that every nesting level checks its own part (a code, a bonus or a global bonus), and the innermost template submits the final code with a script.
Example: the code is assembled from the 1st level code, the 2nd bonus and the 5th global bonus.
{% match code_1 }:{
{%= crocodile}:{
{% match bonus_2 }:{
{%= hippo}:{
{% match gbonus_5 }:{
{%= boar}:{
<script>enter('ZOO')</script>
%}
%}
%}
%}
%}
%}
A branch fires only on an exact answer match, so the nested templates expand down to <script>enter('ZOO')</script> only when all three parts have been submitted. If a part has not been answered yet, its template returns nothing and the templates nested inside it are not evaluated at all.
If a part has several synonyms and you only need to know whether it is solved, use the !any_answer! branch — it matches any submitted answer but, unlike ?, does not match when there is no answer yet.
The nesting stays exactly the same, only each level now holds !any_answer! instead of a specific answer:
{% match code_1 }:{ {%= !any_answer!}:{
{% match bonus_2 }:{ {%= !any_answer!}:{
{% match gbonus_5 }:{ {%= !any_answer!}:{
<script>enter('ZOO')</script>
%} %}
%} %}
%} %}
Important: do not use?in place of!any_answer!— it matches any value, including!no_answer!, so the code would be submitted too early.
Both styles can be mixed inside one nest: use a specific value for a part that has a single answer, and !any_answer! for a part with synonyms.
Templates compare the actual answer value, so the final code may depend on which synonym closed each part: just add several branches with different enter() calls. This is how you build “branching” composite codes that cannot be produced by simply concatenating the parts.
// {% match code_1}:{ {%= crocodile}:{ // {% match bonus_2}:{ {%= hippo}:{ enter('ZOO'); // %} %} // %} %}
What can be checked: code_N, bonus_N, gbonus_N (and also code_first_N, bonus_first_N, gbonus_first_N — the very first answer submitted). Global bonuses can be checked even on levels where they are not displayed. See the Templates page for the full list of parameters.
These functions assemble the final code from the answers already displayed on the page.
// Concatenates the answers in the order of the arguments enter(getAllParts('c1', 'b2', 'gb5'));
getAllParts(…) — accepts the ids of the elements where the engine displays submitted answers:c1, c2, … — level codes;b1, b2, … — level bonuses;gb1, gb2, … — global bonuses.enter() simply does nothing with it.If all the parts sit in a consecutive range of bonuses, there is a shorter form:
// Concatenates the answers of bonuses 1 to 4: the same as getAllParts('b1','b2','b3','b4') enter(getAllBonuses(1, 4));
Put the script into the “Task Script” field; it runs on every level refresh. There is no risk of repeated submissions: enter() submits a code only once.
Keep in mind that what gets concatenated is the answer the team submitted. If a part has synonyms, different teams end up with different final strings — either register every possible variant of the final code, or use method 1.
The parts are written into the task text or into the solution text of bonuses and penalty hints (in Source mode):
<script>code_part(composite_code_number, 'code_part_string', total_composite_parts)</script>
composite_code_number — the index of the composite code if the level has several of them (if there is only one, use 0).'code_part_string' — the code fragment as a string, always quoted (even if it is a number).total_composite_parts — how many parts have to be collected in total. As soon as that many parts are present on the page, the engine submits the concatenated code.What is specific about this method:
code_part calls run, that is, in the order the blocks are rendered on the page: the task text first, then hints, then bonuses, then global bonuses. You cannot define your own order — reordering the bonuses changes the final code.code_part with the same number that ends up on the page. Parts can be scattered freely across hints and bonuses without keeping track of their numbers.| Method | Evaluated | Order of parts | When to use |
|---|---|---|---|
| Nested templates | On the server | Defined by the author | The most universal method: works with synonyms and never reveals the final code in advance. It also takes the most typing — the nest is convenient to generate with AI |
getAllParts / getAllBonuses | In the browser | Defined by the author (argument order) | The least typing, but a poor fit when the parts have answer synonyms |
code_part | In the browser | Order of appearance on the page | Works with synonyms, but the script has to be written by hand into every part |
For method 1, a long nest of templates is convenient to generate with a neural network — see Task Editing and Generation using AI.