# Level packs

A level pack is a collection of levels that belong together.

This is the best way to store and share custom levels, but it requires
Lua programming skills to add a new level pack.

To add a new level pack, a new Luanti mod must be created containing these things:

1) Level schematic (`*.mts`) files. These are for the blocks of the level
2) Level metadata in a level data CSV file. This contains all information that
   the schematic file cannot hold, e.g. title, boundary blocks, weather, sky, etc.
   The level data CSV specifies the metadata for ALL levels at once.
   This file may also define the level order, if there is no level order file
3) Optionally a level ordering file to specify the order and categorization
   of levels
4) Lua code to register the level pack (see below)

The mod must depend on `lzr_levels`.

The mod *should* follow the naming convention `lzr_pack_<name>`.

Apart from this, the mod can be like any other mod and may add or
change other things on top of just the levels themselves.

## File structure

Normally, the file structure of the mod is as follows:

* `mod.conf`: Must declare dependency on `lzr_levels`
* `init.lua`: Lua code to register level pack (see below)
* `data/level_data.csv`: CSV file for level metadata for ALL levels
* `data/level_order.csv`: (optional) CSV file for level order and difficulty ratings
* `schematics/`: The level `*.mts` files go here
* `solutions/`: (optional) Level solution files `*.sol.csv` go here.
* `locale/`: (optional) To store the locale files, if present

Some of these file locations may be changed by parameters of the
function `lzr_levels.register_level_pack`.

## Level metadata files

### `level_data.csv`

`level_data.csv` is a list of all levels’ metadata. Each record has the
same structure as the CSV file for a single level, except it may contain
multiple CSV records, one for each level.

If `level_order.csv` doesn’t exist, the order of the levels in the game
is the same order as they appear in this file.

### `level_order.csv`

This file only works for the core/built-in level pack. It does nothing
in custom level packs.

`level_order.csv` can be used to define difficulty ratings and override
the level order.

It must list every available level (as specified in `level_data.csv`)
exactly once, and not add additional levels.

In this CSV file, each record has 2 columns:

Column 1 is the row type. It has 2 possible values:

* 0: append level
* 1: set difficulty

Column 2 depends on the row type.

For row type 0 (append level), column 2 must contain the level file name.
This will append that level to the end of the level list of the current difficulty,
as well for the special “All levels” listing.

It must be identical to the level file name in `level_order.csv`.

For row type 1 (set difficulty), column 2 sets the difficulty for all the
levels after this row. Possible values are:

* 0: tutorial
* 1: very easy
* 2: easy
* 3: medium
* 4: hard
* 5: very hard

The tutorial difficulty is a special difficulty for levels that are *primarily*
tutorial levels and explain an aspect of the game or level pack. Which levels
you count as tutorial, and which ones not, is up to you.

The very first row should set the difficulty.

Example:

    1,0
    0,tutorial1.mts
    0,tutorial2.mts
    0,tutorial3.mts
    1,1
    0,very_easy1.mts
    0,very_easy2.mts
    1,5
    0,ultra_hard.mts

This adds 6 levels: Three tutorial levels (difficulty 0), two very easy levels (difficulty 1), and a very hard level (difficulty 5).



## Register the level pack

To register a level pack, you must call `lzr_levels.register_level_pack`.
The definition of this function is as follows:

### `lzr_levels.register_level_pack(name, info)`

Register a level pack. For this to work, the level-related data must be present in the
locations defined at `level_data_file`, `schematic_path` and (optionally) `solutions_path`
and/or `level_order_file` described below.

If successful, the level pack will appear in the game under the custom levels menu.

Parameters:

* `name`: Level pack ID. A string. The allowed characters are `a-z`, `A-Z`, `0-9` and `_` (underscore). IDs starting with two underscores are reserved to Lazarr!
* `info`: Table of optional additional information, with these fields:
	* `title`: human-readable level pack title
	* `description`: short description/explanation about this level pack. 1-3 sentences.
	* `textdomain_level_names`: textdomain of the translation file containing the translated level names (default: no translation)
	* `textdomain_npc_texts`: textdomain of the translation file containing the translated texts for NPCs like Goldie the Parrot (default: no translation)
	* `level_data_file`: Path to CSV file containing metadata of all levels (default: `<modpath>/data/level_data.csv`)
	* `level_order_file`: Path to CSV file containing ordering of all levels (default: `<modpath>/data/level_order.csv`)
	* `schematic_path`: Path to directory containing the level '.mts' schematic files (default: `<modpath>/schematics`)
	* `solutions_path`: Path to directory containing the *optional* level '.sol.csv' solution files (default: `<modpath>/solutions`)

If successful, the level pack will appear in the game under the custom levels menu.

#### A note about solution files

Solution files exist for internal purposes, for the quality assurance and game stability of
Lazarr! to ensure the levels still work after major changes to the game. This feature mainly
exists for the core levels and it’s not necessary for custom level packs to create them.


### Example

A simple example with one level, translated into German.

We call the mod `lzr_pack_example`.

Here’s the file structure:

* `mod.conf`
* `init.lua`
* `schematics`
    * `lzr_pack_example_example.mts`
* `data`
    * `level_data.csv`
* `locale`
    * `lzr_pack_example.pot`
    * `lzr_pack_example.po.de`
    * `lzr_pack_example_level_names.pot`
    * `lzr_pack_example_level_names.de.po`
    * `lzr_pack_example_npc_texts.pot`
    * `lzr_pack_example_npc_texts.de.po`

The code of `init.lua`:


    local S = minetest.get_translator("lzr_pack_example")
    
    lzr_levels.register_level_pack("example", {
        title = S("My Example Levels"),
        description = S("Some example levels to test things."),
        textdomain_level_names = "lzr_pack_example_level_names",
        textdomain_npc_texts = "lzr_pack_example_npc_texts",
    })

