nodes/maps.py

Part of Q1K3.

 1"""Hand-authored Q1K3 maps.
 2
 3Each map is a dict with:
 4- ``blocks``: list of ``(x, y, z, sx, sy, sz, tex_id)`` cuboids in cell units
 5              (xz cell = 32, y cell = 16).
 6- ``entities``: list of ``(kind, (x, y, z), p1)`` where ``kind`` is the spawn
 7                class name and ``p1`` is the first parameter (patrol_dir or
 8                door yaw or texture index, depending on entity).
 9
10Maps are intentionally smaller than upstream: Q1K3's compiled maps are
11~150 blocks each. We aim for ~30-40 blocks: a starting room, a corridor,
12a key room, a locked door, a trigger.
13"""
14
15from __future__ import annotations
16
17from . import textures as T
18
19
20def map_1() -> dict:
21    """First level: lobby → corridor → key room → locked door → trigger."""
22
23    blocks: list[tuple] = []
24
25    # ---- Starting room (10x10 cells, 8 high) at cell origin (10,1,10) ----
26    # Floor
27    blocks.append((10, 0, 10, 14, 1, 14, T.TEX_FLOOR_TILE))
28    # Walls (4 sides, 8 tall starting at y=1)
29    blocks.append((10, 1, 10, 14, 8, 1, T.TEX_WALL_BRICK))  # back wall (-Z)
30    blocks.append((10, 1, 23, 14, 8, 1, T.TEX_WALL_BRICK))  # front wall (+Z)
31    blocks.append((10, 1, 10, 1, 8, 14, T.TEX_WALL_BRICK))  # left wall (-X)
32    blocks.append((23, 1, 10, 1, 8, 14, T.TEX_WALL_BRICK))  # right wall (+X)
33    # Ceiling
34    blocks.append((10, 9, 10, 14, 1, 14, T.TEX_CEILING))
35
36    # Cut a doorway in front wall (replace 2 cell-wide section)
37    # Shrink the front wall and re-add a lintel above
38    blocks.pop(2)  # remove front wall
39    blocks.append((10, 1, 23, 6, 8, 1, T.TEX_WALL_BRICK))  # left half
40    blocks.append((18, 1, 23, 6, 8, 1, T.TEX_WALL_BRICK))  # right half
41    blocks.append((16, 5, 23, 2, 4, 1, T.TEX_WALL_BRICK))  # lintel above doorway
42
43    # ---- Corridor (8 cells long heading +Z) ----
44    blocks.append((16, 0, 24, 2, 1, 8, T.TEX_FLOOR_STONE))  # floor
45    blocks.append((15, 0, 24, 1, 8, 8, T.TEX_WALL_BRICK))  # left wall
46    blocks.append((18, 0, 24, 1, 8, 8, T.TEX_WALL_BRICK))  # right wall
47    blocks.append((16, 8, 24, 2, 1, 8, T.TEX_CEILING))  # ceiling
48
49    # ---- Locked-door room (8x8 cells at z=32) ----
50    # Floor
51    blocks.append((12, 0, 32, 10, 1, 10, T.TEX_FLOOR_WOOD))
52    blocks.append((12, 1, 32, 4, 8, 1, T.TEX_WALL_BRICK))  # front-left
53    blocks.append((20, 1, 32, 2, 8, 1, T.TEX_WALL_BRICK))  # front-right
54    blocks.append((12, 1, 41, 10, 8, 1, T.TEX_WALL_BRICK))  # back wall
55    blocks.append((12, 1, 32, 1, 8, 10, T.TEX_WALL_BRICK))  # left wall
56    blocks.append((21, 1, 32, 1, 8, 10, T.TEX_WALL_BRICK))  # right wall
57    blocks.append((12, 9, 32, 10, 1, 10, T.TEX_CEILING))  # ceiling
58
59    # ---- Key room branch off the corridor (open passage to -X) ----
60    blocks.append((10, 0, 26, 6, 1, 4, T.TEX_FLOOR_STONE))
61    blocks.append((10, 1, 26, 1, 8, 4, T.TEX_WALL_BRICK))  # far -X wall
62    blocks.append((10, 1, 26, 6, 8, 1, T.TEX_WALL_BRICK))  # back wall
63    blocks.append((10, 1, 29, 5, 8, 1, T.TEX_WALL_BRICK))  # front wall
64    blocks.append((10, 8, 26, 6, 1, 4, T.TEX_CEILING))  # ceiling
65
66    entities: list[tuple] = [
67        # Player spawn near centre of starting room (look toward doorway at +Z).
68        ("player", (16, 1, 12), 0),
69        # A grunt patrolling in the corridor
70        ("grunt", (17, 1, 28), 1),
71        # An enforcer in the key-room branch
72        ("enforcer", (12, 1, 27), 0),
73        # A torch on each side of the doorway
74        ("torch", (12, 4, 22), 0),
75        ("torch", (22, 4, 22), 0),
76        # Health pickup in the corridor
77        ("health", (17, 1, 26), 0),
78        # Key in the side room
79        ("key", (12, 1, 27), 0),
80        # Locked door at the end of the corridor entering the locked room
81        ("door", (17, 1, 32), 0),  # yaw=0 → slides along +X
82        # Nailgun pickup in the locked room
83        ("nailgun", (16, 1, 36), 0),
84        # Ogre boss in the locked room
85        ("ogre", (18, 1, 38), 0),
86        # Level trigger past the boss
87        ("level", (16, 1, 40), 0),
88        # A barrel for kaboom fun
89        ("barrel", (14, 1, 35), 0),
90    ]
91
92    return {
93        "blocks": blocks,
94        "entities": entities,
95    }
96
97
98def all_maps() -> list[dict]:
99    return [map_1()]