# Code Documentation for Lazarr!
This file documents the code of this game.
This file is still in WIP.

## Coding rules
Some general rules for developing this game apply:

1. **Nodes**
    1. All nodes incompatible with lasers MUST have
      the `laser_incompatible=1` group (see below)
    2. Nodes MUST NOT drop multiple items (for `lzr_protection`)
2. **Lasers**
    1. The "ends" of any laser node MUST NOT be visibly
       exposed to the player;
       they MUST either connect to another laser beam,
       or touch the side of a laser-compatible node.
       (thus rule does not apply in the editor or development mode)
    4. All lasers SHOULD look like a clean continuous beam;
       there SHOULD NOT be visible seams between
       laser nodes or anywhere else
    5. The 3 primary laser colors are red, green and blue
    6. Secondary colors are created by mixing:
        * red + green = yellow,
        * red + blue = magenta,
        * green + blue = cyan,
        * red + green + blue = white.
    7. Two colors are mixed by doing a logical OR between
       their primary color components. For example,
       red + yellow = yellow because yellow is made out of
       red and green.
3. **Levels**
    1. Levels must not use nodes with the `laser_incompatible` group
    2. Levels must have exactly one teleporter in off state
    3. Levels must have at least one treasure chest
    4. Player must not get stuck in a hole or be able to
        escape the level bounds (you may use `lzr_core:barrier`
        for the boundaries)

### Laser compatibility

A node is said to be 'laser-compatible' when the visible
laser beam will never end at a gap when it collides with
the node from any side. Opaque full-cube nodes are
laser-compatible, while air is laser-incompatible.
Other drawtypes may or may not be compatible, depending
on their shape and texture. To see if a node is compatible,
shoot a laser to each of the node's sides. If the "end" of the
laser is visibly exposed, i.e. not touching the node's visual
border, it is incompatible. Otherwise, it is compatible.

Incompatible nodes are thus nodes where when the laser collides,
there is a visible gap between the laser beam and the visual
node.

Exception: If the node is immediately destroyed on contact
or transformed into a compatible node, it counts as
compatible.

Incompatible nodes can be also made compatible by adding
variants of the node with a laser beam inside of them,
and adding them as laser blocks in `lzr_laser`.

This is done for slabs and panes, for example.

## Function reference
TODO

## Node special fields reference
This is a list of special fields for node definitions that Lazarr! recognizes:

* `_lzr_active`: If the node has an 'active' counterpart, this contains the
    itemstring of that 'active' counterpart.
    Used by blocks that interact with laser
* `_lzr_inactive`: If the node has an 'inactive' counterpart, this contains the
    itemstring of that 'inactive' counterpart.
    Used by blocks that interact with laser
* `_lzr_fixed`: Node name of fixed (unmovable) variant of a laser block
* `_lzr_rotatable`: Node name of rotatable variant of a laser block (if it exists)
* `_lzr_takable`: Node name of takable variant of a laser block (if it exists)
* `_lzr_next_color`: Contains the name of the node with the next color in a
    sequence of colors, for the color change tool
* `_lzr_prev_color`: Same as `_lzr_next_color`, but for the previous color
* `_lzr_on_toggle(pos, node)`: Function is called when this node
    is toggled on or off. This can happen either by a tool
    or a trigger (a node that triggers other nodes)
    `pos` is node position and `node` is node table
* `_lzr_on_toggle_item(holding_player, item, slot)`: Same as
    `lzr_on_toggle`, but when the node is in item form in a player's
    inventory.
    `holding_player` is the player holding the item, `item` is the
    ItemStack to toggle, slot is the inventory slot in which the
    item resides (in the "main" list). MUST return the modified
    (or unmodified) ItemStack
* `_lzr_unlock(pos, node)`: Function is called on chests to unlock it.
    `pos` is node position and `node` is node table
* `_lzr_send_treasure(pos, node)`: Function is called on open chests
    with treasure to start an animation that "sends" the treasure into
    the sky. Used when a level is completed.
    `pos` is node position and `node` is node table

## Node groups reference

See `GROUPS.md` for a reference of item groups used in this game.

## Debug Mode

There is a hidden Debug Mode in this game. It is used to
enable several debugging and testing features of the game.

To enable the hidden debug mode, set the hidden setting `lzr_debug` to
`true` in `minetest.conf`. This will unlock the following features:

### Laser debug

* Chat commands:
    * `/set_freeze_lasers`: Enable/disable laser updates on map change
    * `/force_laser_update`: Recalculate all lasers
    * `/clear_lasers`: Removes lasers
    * `/emit_lasers [<max. iterations>]`: Emits lasers from emitters
* Tools (Only via `/giveme`)
    * Laser Absorber (`lzr_tools:laser_absorber`): Digs lasers
    * Laser Stepper (`lzr_tools:laser_stepper`): Simulates laser travel up to
      a set number of iterations. Basically a more convenient method for
      `/emit_lasers`

### Development mode

Development mode can be accessed with the `/devmode` command. In this mode,
the world can be altered more freely without the game getting in the way.
Lasers are always frozen in development mode. You can also get all items
in the inventory. This mode was created to test out stuff more easily.

### Solutions recording and testing

You can record solutions for levels and replay them. Solutions record
player interactions in a level in order to replay them for testing
the levels for regressions. The solution system is limited, however,
it only records interactions with nodes but not player movement.

This feature is EXPERIMENTAL and has some rough edges, so
use with care! The main use case for this feature is to record
solutions in level packs, most importantly the core levels.

This feature is useful to test and verify if the levels are still solvable
in a later update in case the behavior of a laser block was accidentally
changed in a compatibility-breaking manner. Passing the test does
NOT guarantee the level is error-free. In particular, if the player
would have to move to a place that is unreachable, the test won't
detect that.

Commands:

* `/record_solution`: Start record a solution for the current level.
  You MUST call this at the beginning of a level, not afterwards.
  Try to solve the level with as few node interactions as you can
  (the solution doesn't have to be perfect tho).
  The recording ends automatically when the level is completed and
  a file is saved into the world directory on success.
  WARNING: Existing files will be silently overwritten!
* `/replay_solution`: Replay the solution for the current level. This
  only works for level pack levels and only when you're at the beginning
  of a level.
* `/test_pack_solutions`: Mass-test ALL levels of a level pack in sequence

The solution test will halt automatically when any inconsistency was
detected. You can always abort the solution test or a recording by
returning to the ship.