5.1 KiB
Levels from scripts
Besides the editor, a level can be described as a short script that a level builder turns into a complete WAD: geometry made of boxes, ramps, stairs, trees and sea, objects placed by type name, lighting baked automatically. There are two builders with the same ideas:
| Builder | Language | Used by |
|---|---|---|
tools/levelbuild.py |
Python 3 (numpy, Pillow) | the original test world levels/testwelt.py, the jump lab levels/sprunglabor.py |
levelbuild/LevelBuilder.java |
Java (LevelScript) |
the Test World mod (mods/testworld/), the Alligator Arena, the editor's brushes |
Both start from a base level (default Village 1): its object code, textures and sound are kept; geometry, tile grid, vertex colours, objects and waypoints are generated from scratch. Full documentation of the Python builder, the measured physics and the test world: notes/levelbau.md.
A Python level
LEVEL_ARGS = dict(name='MyLevel', seed=7)
def build(L):
L.sea(0, 0, 60, 60, y=-2.0, kill=(6, 4, 54, 56)) # sea + death plane
L.box(14, 12, 26, 24, -0.4, 0, top='stein', side='stein') # a stone plaza
L.stairs(26, 18, 29, 22, 0, 1.5, 3, '+x') # stairs up to the east
L.box(29, 17, 33, 23, 0, 1.5, top='gras', side='erde')
L.player(20, 14.5, rot=0) # facing +z
L.checkpoint(17, 18.5)
L.coins([(27, 20), (28, 20)])
L.strat('Bunny', 31, 20)
L.box(31, 21, 32, 22, 1.5, 1.56, top='platte', side='stein', mat=16) # exit floor
L.exit(31.5, 21.5) # LevelDoor in the same cell
python3 tools/levelbuild.py my_level.py out/my_level.wad # build
python3 tools/levelbuild.py --types # object types of the base
python3 tools/levelbuild.py --textures tex.png # texture names and a contact sheet
Coordinates are game units: x east, y up, z = grid row ("south"); angles in degrees, 0° faces +z.
Building blocks: floor, box, platform, pillar, ramp, stairs, fence, tree, sea,
quad, collider, obj (an OBJ file), height_at. The exit needs a floor with collision
material 16 in its cell – the test world uses box(..., mat=16) under the door.
Texture names: the Python builder's own names are German (gras, stein, erde, platte,
meer …, list: --textures); the English names of the Java builder (grass, stone, earth,
slab, sea …) work as well and give the same result.
The base level is t1l1m001.wad in the CD folder $LLAMAMOD_CD/wads (default
~/.wine-lama/iso-dk/Setup/Eng/Cd), or --base <file>. --install copies the WAD into the TestLevel
mod of a hand-made Wine setup ($LAMA_WINEPREFIX/mods/testlevel, default ~/.wine-lama) – with
LlamaMod, use a Java level or the editor instead. All variables: Tools: Paths.
A Java level
Implement LevelScript:
public final class MyLevel implements LevelScript {
@Override public String levelName() { return "My Level"; }
@Override public void build(LevelBuilder l) {
l.sea(0, 0, 40, 40, -1.5, new double[] {7, 7, 33, 33});
l.floor(10, 10, 30, 30, 0, "grass");
l.box(18, 24, 22, 25, 0, 0.06, o().top("pattern_purple").mat(16)); // exit floor
l.player(20, 12, 0);
l.checkpoint(12, 12);
l.exit(20.5, 24.5, null, null, new int[] {1, 9, 32});
l.coins(List.of(new double[] {20, 16}, new double[] {20, 18}));
}
}
buildWad(baseWad, wads, opts) returns the WAD. To ship it, write a small
mod whose apply writes wads/T1L9M0nn.wad (chapter 1 or
32–49) and a loading picture – ArenaMod
is a complete example. Texture names are English here (grass, stone, sand, inca, …) and are
matched by picture on the chosen base.
The editor from the command line
The editor's project format can be scripted too:
llamamod --editor-new my.llamalevel t1l1m001 --name "My level" # new project on a base
llamamod --editor-import t1l2m001 jungle.llamalevel # an original level as a project
llamamod --editor-build my.llamalevel out.wad # build the WAD
llamamod --import-level my.llamalevel # install as a level mod
Seeing the result without the game
tools/geom_export.pylevel.wad outdir --collision --objectswrites OBJ files, texture pages and two preview images.tools/vorschau/renders labelled overviews with Blender (Eevee).- In the game: the test harness, see Tools.