Level unlocking language

About the Level unlocking language

Level unlocking language (LUL) is a simple yet expressive text format, used to specify level precedence in games with several levels. With a short line per level you will be able to specify from the most basic to the most complex level progressions.

The basic rules are explained in the first section. In the second section these rules are applied to some common level progression scenarios, such as parallel tracks, branching tree, pyramid, grid and incomplete worlds.

This specification is still a draft, yet to be incorporated in Pedro PSI's game bar and maybe elsewhere.

LUL rules

Single level

by number

Levels can be mentioned by their number (in the game level sequence) or by name.

Thus the number 1 refers to the first level and 99 to the ninety-ninth level. There is no limit to the number of levels though!

by name

Levels may also have name labels. For instance, level 1 may be named Welcome! while level 99 may be labelled Final boss...

current level

To reference the current level (the one to which the condition applies) please use the symbol @.

Labeling rules

All but the following symbols cannot be used in level names: [],(),\/ and @.

If you name another level "9", but you need to mention the ninth level, you will need to label the latter.

Please use different labels for different levels, otherwise all but the last duplicate label will be ignored.

Non-existent levels

Any non-existing levels will be ignored, however they are mentioned or labeled.

Groups of levels

Disconnected groups

To define a group of levels, separate all levels with (any number of) spaces: 1 two 3 five 7 means levels 1, "two", 3, "five" and 7. You may also enclose them in parentheses: (1 two 3 five 7) without change of meaning.

Examples
  • (1 3): levels 1 and 3;
  • (6 4): levels 4 and 6;
  • (7 10 13): levels 7, 10, and 13;
  • (10 secret): levels 10 and "secret".

Ranges

To define a level range, enclose a level group in square brackets. All levels between the extremes of that group will thus be included. Thus writing [first last] means all levels between level "first" and "last" (whichever comes later). If more than two levels are enclosed, only the extremes count, e.g [1 2 5 4] means the same as [1 5].

Further examples
  • [1 3]: levels 1, 2 and 3;
  • [6 4]: levels 4, 5 and 6;
  • [7 10 13]: levels 7, 8, 9, 10, 11, 12, 13;
  • [10 secret]: means all levels between 10 and "secret" or vice-versa, depending on level order.
Split labels

Please note that first boss may refer either to a group of two levels, named "first" and "boss", or the single a level named "first boss". The exact meaning will depend on the actual labels in existence. If both interpretations are possible, the longer names will take precedence - i.e. longer names are tried first, only if they fail to match any label are then the shorter names tried.

Combined ranges

Ranges can be combined too. For instance:, ([1 3] [11 13]) means levels 1,2,3,11,12,13, while ([1 3) (11 13)] includes all levels between 1 and 13. Overlapping ranges are ok, and there is no limit to the number of ranges that may be combined, hence [1 3] [2 4] [3 5] 6 simplifies to [1 6].

Exclusion

To exclude a group of levels from a range, use the forward slash \. So you can write [1 10]\5 to refer to all levels between 1 and 10, except 5. You can also exclude any group of levels from any other group. Finally, if you try to exclude a level multiple times, or that wasn't there in the first place, it will be excluded anyway.

Further examples
  • [1 5]\1: levels 2, 3, 4 and 5;
  • [1 5]\[2 4]: levels 1 and 5 only;
  • [1 5]\(2 4): levels 1, 3 and 5;
  • (1 2 3 4 5)\[2 4]: levels 1 and 5
  • (1 2 3 4 5)\6: levels 1, 2, 3, 4 and 5
  • (1 3 5)\[4 5]: levels 1 and 3
  • (1 3 5)\[(1 6 7)]: levels 3 and 5
  • [1 3] [3 5]\3)]: levels 1, 2, 3, 4 and 5
  • ([1 3] [3 5])\3)]: levels 1, 2, 4 and 5
  • [1 5]\[2 4]\4: levels 1 and 5;
  • [1 5]\([2 4]\4): levels 1, 4 and 5 (he fourth level is excluded from the exclusion group).

Successive exclusion

Exclusions can be applied successively from right to left: [1 7]\2\[3 5]\(6 7) excludes level 2, then 3 to 5, then 6 and 7 so that in the end, only level 1 remains. However, it is usually recommended to combine the exclusions into a single concise group, e.g. writing [1 7]\(2 7).

Position Arithmetic

Increase

To mention a level after a previous one, use the plus sign +. Normal arithmethic applies, e.g. 1+1 is 2, one level + 3 is another level (three levels higher). Relative to the current level, @+1 is the next level and @+3 is three levels afterwards.

Decrease

To mention a level before a previous one, use the minus sign -. Normal arithmethic applies, e.g. 2-1 is 1, another level - 3 is one level (three levels lower). Relative to the current level, @-1 is the previous level while @-3 is three levels before.

Increases and decreases can be combined naturally.

Distribute over ranges

The distributive property of + and - applies to both range types. So (1 2 3)+5 means (6 7 8) and [5 10]-4 means [1 6].

Ranges may also be added from other ranges. Every number from the first range is added to every other number from the second range, forming a new combined range. So (1 2) + (5 10 15) is (5 6 11 12 16 17) , and [1 3] + (1 2) is (2 3 4 5). Overlapping results in the combined range are discarded normally: (1 2) + (1 2) is [2 4] .

Subtraction works in a similar manner, for instance: [1 4] - [1 2] is [1 2 3] , because non-existing numbers (below 1) are ignored.

Labeling conflict resolution

If there are levels labelled quick, run and run-quick, the latter means the label rather than the position of run minus the position of quick. But, if no level was labelled run-quick, then the subtraction applies.

Picking from a group

To pick a set number of levels from a group, use the divider / in this way: [1 10]/2 this pick any two levels from range 1 to 10 while (1 10)/1 picks one level, either 1 or 10. Picking more levels than the group allows is equivalent to selecting the entire group. first area/7 requires seven levels from the first area.

Similarly, picking zero or less is equivalent to picking none, e.g. (1 10)/0 or [1 3]/-1 both mean (unlocked by default). This is useful for instance when implementing level lookaheads, since the initial levels are usually unlocked due to a lookahead leeway larger than these initial positions - usually defined as a subtraction.

Requesting a pick from an empty group will also mean unlocked by default (this situation may occur rarely, possibly due to misspellings).

Picking from a group is the only case in the Level unlocking language where the (dividing) number refers to a level count, rather than to the particular level's position.

Named groups

If there's a group of levels that is referred to very often, it may be useful to name this group. To do so, use the double dot as in the following examples.

  • water-world: [01 10] - group named "water-world", containing levels 1 to 10;
  • ice-world: 11 [12 20] - group named "ice-world", containing levels 11 to 20;
  • air-world: [21 30] - group named "ice-world", containing levels 11 to 20;
  • bosses: 10 20 30 - group named "bosses", containing levels 10, 20 and 30;
  • half-game: water-world [11 15] - group named "half-game", containing levels 01-15.

The same convention can be used to name a single level (here seen as a group with just one level).

Currency

This section is still under consideration. Experimental

A very flexible unlocking mechanism may involve some form of currency. Unlocking a level will provide currency, while some levels may require some currency as unlocking condition.

Any number followed by the £,,$ or ¥ sign will be interpreted as currency.

Currencies are not interchangeable, e.g. 10£ is different from 10€, meaning an unlocking conditions may combine different required amounts of various currencies.

There are two ways in which currency can be requested as unlocking condition:

  • Minimum balance: a set amount of currency is required, but it won't be expended;
  • Expenditure: a certain amount must be expended.

Request currency

Minimum balance

To request a currency balance (e.g. in £) above a certain value, write N£, where N is a natural number. These credits will be preserved.

Examples
  • : require a minimum balance of 1£;
  • 1£ 2€: require a minimum balance of 1£ and 2€;
  • 1£ 2€ 3£: require a minimum balance of 1£, 2€ and 3£;
  • 1£ 5: require a minimum balance of 1£ plus unlocking level 5;
  • (1€ 4¥)/1]: require a minimum balance of either 1€ or 4¥;
  • (4¥ 5)/1]: require either beating level 5 or a minimum balance of 4¥;
Expenditure

To request an expenditure of a certain currency balance (e.g. in £) write -N£, where N is a natural number. These credits will be expended.

When both minimum balance and Expenditure conditions are combined, the expense is only made after verifying that the minimum balance is met. So 1£ -1£ verifies that a minimum balance of 1£ is present, then debits 1£. -1£ 1£ has exactly the same meaning.

Examples
  • -1£: require expending 1£;
  • -1£ -2€: require expending 1£ and 2€;
  • -1£ 2€: require expending 1£ and a minimum balance of 2€;
  • (-1£ 5): require expending 1£ and beating level 5;
Picking

Picking currencies must have special rules.

Minimum balance has priority over expenditures. So (-1£ 1£)/2 will only expend -1£ unless the minimum balance of -1£ fails to be met.

Any impossible expenditures (due to lack of balance) won't be considered as valid alternatives. Then, among possible expenditures in different (or the same) currencies, those causing the least damage will be preferred. So (-1£ -2€)/1 will expend -1£ if this results in a higher balance of £ than €, and vice versa. If both cases fail, then the smallest expenditure will be preferred. If both expenditures are equal still, the first one is used.

Combining

Ranges will be interpreted as disconnected groups, e.g. (-1£ -2€) will be read as (-1£ -2€).

Providing currency

To debit your balance with a set amount of currency, write +10£. This is strictly not an unlocking condition, instead the debit will be awarded upon level completion. The converse rules apply.

Level progressions

Linear progression

Linear progression means that levels are placed on a line, so that when you solve a previous level you unlock the following one(s).

In these examples, assume there are 10 levels: «[«[1 10]

Linear progression, with 1-level lookahead

Solving one level unlocks only one following level.

Conditions for each level:

  • level 1: (none, as the first level is unlocked);
  • level 2: 1 (to unlock level 2, level 1 must be solved first);
  • level 3: 2 (level 2 must be solved first);
  • level 4: 3 (etc...);
  • ...
  • level 10: 9;

Linear progression, with 3-level lookahead

Solving one level unlocks up to three levels afterwards.

Conditions for each level:

  • levels 1 2 3: (none, as the first three levels are unlocked);
  • level 4: [1 3]/1 (solving either 1, 2 or 3 is sufficient to unlock level 4);
  • level 5: [1 4]/2 (solving 2 levels beforehand is sufficient);
  • level 6: [1 5]/3 (a shorter way of expressing the same progression logic);
  • ...
  • level 9: [1 @-1]/(@-3); (an equivalent way of expressing the same progression logic..)
  • level 10: [1 @-1]/(@-3); (... constant in every level.)

Linear progression, with n-level lookahead (general formula)

  • level @: [1 @-1]/(@-n);

Branching tree

You start with a single level, but each solved level unlocks two levels, with 15 levels in total. The unlock conditions would be:

  • level 1: (none for the starting level);
  • levels (2 3): 1 (solving the first level unlocks levels 2 and 3;
  • level (4 5): 2;
  • level (6 7): 3;
  • level (8 9): 4;
  • level (10 11): 5;
  • level (12 13): 6;
  • level (14 15): 7;

Parallel tracks in sync

Imagine two parallel tracks, one named "day" and another "night", with 5 levels each, so 10 in total:

  • day :(1 3 5 7 9)
  • night:(2 4 6 8 10)

Solving any level in one track unlocks the following level on the same track, plus the corresponding level on the parallel track.

Conditions for each level:

  • levels (1 2): (none, as both first levels are unlocked);
  • levels (3 4): (1 2)/1 (solve at least one level from one of the tracks);
  • levels (5 6): (3 4)/1;
  • levels (7 8): (5 6)/1;
  • levels (9 10):(7 8)/1;

Pyramid

Levels form a pyramid, with many easy levels at the base and a single final level at the apex.

  • base layer :[1 5]
  • middle layer:[6 8]
  • apex:9

Solve a full layer to unlock the next layer

Conditions for each level:

  • levels in base layer : (none as every level is unlocked);
  • levels in middle layer: [1 5] or simply base layer;
  • level 9, in apex: [6 8] or simply middle layer.

Solve all but one level per layer, to unlock the next layer

Conditions for each level:

  • levels in base layer : ;
  • levels in middle layer: base layer/3;
  • level 9, in apex: middle layer/2.

Grid

Levels are arranged in a square grid, for example 4x4:

  • A1 B1 C1 D1
  • A2 B2 C2 D2
  • A3 B3 C3 D3
  • A4 B4 C4 D4

Adjacent levels, 4x4 Grid

Solving a level unlocks all adjacent levels in the grid

Conditions for each level:

  • level A1: (none, starting level is unlocked);
  • level B1: (A1 B2 C1)/1 (one adjacent level suffices);
  • level C1: (B1 C2 D1)/1;
  • level D1: (C1 D2)/1 ;
  • level A2: (A1 B2 A3)/1;
  • level B2: (A2 B1 C2 B3)/1 (one adjacent level suffices);
  • etc...
  • level C3: (@-4 @-1 @+4 @+1)/1 (constant formula);
  • etc...

Adjacent levels, NxM Grid

General formula: (@-N @-1 @+N @+1)/1, where N is to be replaced by the actual (horizontal) grid length. In the previous example, N would be 4.

Incomplete worlds

Using the following setup of 30 levels divided in three "worlds", we can specify several conditions.

  • first world :[1 10]
  • second world:[11 20]
  • third world :[21 30]

Complete 7 levels from each world to unlock the next one

Conditions for each level:

  • 1: none (first level is fully accessible);
  • levels 2 to 10 none, like in level 1;
  • level 11: first world/7 (require solving seven levels from the first world)
  • levels 12 to 20 equal to the one in level 11;
  • level 21: second world/7 (require solving seven levels from the second world)
  • levels 22 to 30 equal to the one in level 11;

Complete 7 levels from each world to unlock the next one, but with a maximal lookahead of three levels within each world

Conditions for each level:

  • levels 1 to 3: (none, as first three levels in first world fully accessible);
  • level 4: (1 2 3)/1;
  • level 5: (1 2 3 4)/2;
  • level 6: (1 2 3 4 5)/3;
  • level [7 10]: [1 @]/(@-1-3) (all but three levels until the current one);
  • levels [11 13]: first world/7 (require solving seven levels from the first world)
  • levels [14 20]: first world/7 [11 @]/(@-11-3) seven levels form the first world plus all but three in the second world;
  • levels [21 23]: second world/7 (require solving seven levels from the second world)
  • levels [24 30]: second world/7 [21 @]/(@-21-3).

Special thanks

To minotalen and Elyot Grant for insightful ongoing discussions about the Level unlocking language!