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()]