code wiki / _hdl_build / nx_m2d_engine.nx
nx_m2d_engine.nx source
↩ module page · 1167 lines · 56854 B
1// nx_m2d_engine.nx -- M2D "NISHI GLADE": the first TIER-1 game of the approved program plan
2// (2026-07-26, plans/temporal-meandering-moore.md rung 1) -- a top-down action-adventure in the
3// Steam-volume-floor class, COMPOSED ENTIRELY FROM CERTIFIED PARTS, zero re-authored game systems:
4// nx_worldpipe the staged six-parameter overworld (biomes/heights/surface colours)
5// nx_procgen the dungeon maze (pg_maze, flood-verified connectivity)
6// nx_pathfind enemy chase (pf_astar on the live maze grid)
7// nx_creature_battle combat resolution (typed moves, cb_damage/cb_best)
8// nx_rpgstats xp curve + derived hp (order-independent, saturating)
9// nx_loottable kill drops (weighted tiers, 0-dup law)
10// nx_wardrobe_state the adult invariant, FAIL-CLOSED BY CONSTRUCTION (age<18 refuse)
11// nx_input_abstract every policy drives the loop through SEMANTIC ACTIONS (device-independent)
12// nx_gamesave bit-exact mid-run save/load (transparency proof)
13// nx_game_raster the rendered frame; scored by
14// nx_game_critic the hardened visual critic (anti-noise, coherence-capped)
15// PROOF BATTERY (the M1/frontier standard -- a battery that cannot pass a hollow game):
16// P1 WINNABLE the cautious policy grinds, heals, then takes the warden -> WIN
17// P2 LOSABLE the reckless policy rushes the warden under-levelled -> DIES (real stakes)
18// P3 DETERMINISTIC two P1 replays produce bit-identical frame chains
19// P4 SAVE-TRANSPARENT save mid-run, load, continue -> same final chain as the unbroken run
20// P5 ADULT-GATE HOLDS the spring event tries to expose a gated zone: adult proceeds, a minor is
21// REFUSED with state bit-identical -- the invariant holds THROUGH the whole game loop
22// P6 DEPTH the two policies genuinely diverge (win vs death) AND each replays identically --
23// outcome differences are STRATEGY, not luck (the hardened nx_game_depth principle)
24// P7 QUALITY the rendered frame clears the critic's TOY line; score published, never inflated.
25// Emits its frame as knowledge/nx_m2d_frame.nxfh (the ecosystem's text-hex format) so nx_frame_score
26// can re-grade it over MCP -- the same instrument that grades the reference titles.
27// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
28import "nx_syscalls.nx"
29import "nx_worldpipe.nx"
30import "nx_procgen.nx"
31import "nx_pathfind.nx"
32import "nx_creature_battle.nx"
33import "nx_rpgstats.nx"
34import "nx_loottable.nx"
35import "nx_wardrobe_state.nx"
36import "nx_input_abstract_part.nx"
37import "nx_gamesave.nx"
38import "nx_game_raster.nx"
39import "nx_game_critic.nx"
40import "nx_game_engine_lib.nx" // the NATIVE play surface: ANSI true-colour terminal render (bput_*)
41import "nx_png.nx" // publish the frame to the SITE (operator 2026-08-09: the graphics must be SEEN)
42const MD_MAGIC_65536: i64 = 65536
43const MD_MAGIC_4096: i64 = 4096
44// ART-LOOP KNOBS (sweep verb, operator 2026-08-09 "build the iterative loops and look"): sentinel
45// statics -- 0/unset means the shipped default, so the battery path is byte-unchanged when no sweep
46// runs. Declared with the top constants, ABOVE every reader (the AT_FDCWD statics law).
47static MD_AT_TM: i64
48static MD_AT_JA: i64
49static MD_AT_FW: i64
50static MD_AT_MS: i64 // material seed (0 = derive from MD_SEED) -- the infinigen knob
51
52// ---- world geometry (tiles) ----
53const MD_DW: i64 = 15 // dungeon maze width (odd, pg_maze contract)
54const MD_DH: i64 = 9
55const MD_SEED: i64 = 20260726
56const MD_WSCALE: i64 = 280 // world units per overworld tile fed to wp_*
57// ---- character ----
58const MD_XP_BASE: i64 = 50
59const MD_XP_QUAD: i64 = 30
60const MD_CON: i64 = 10
61const MD_HPB: i64 = 20
62const MD_HPCON: i64 = 2
63const MD_HPLVL: i64 = 6
64// ---- serializable game-state layout (i64 words; rides nx_gamesave like every part) ----
65const MD_F_PX: i64 = 0
66const MD_F_PY: i64 = 1
67const MD_F_HP: i64 = 2
68const MD_F_XP: i64 = 3
69const MD_F_POT: i64 = 4 // potions held
70const MD_F_SHARD: i64 = 5 // key shards (3 open the warden door)
71const MD_F_KILLS: i64 = 6
72const MD_F_TICK: i64 = 7
73const MD_F_CK: i64 = 8 // rolling frame chain
74const MD_F_OVER: i64 = 9 // 0 running, 1 WIN, 2 DEAD
75const MD_O_WARD: i64 = 10 // wardrobe vector [10..20) (WS_LEN=10)
76const MD_O_ENHP: i64 = 20 // enemy hp x4 (3 lurkers + warden) [20..24)
77const MD_O_ENX: i64 = 24 // enemy x x4
78const MD_O_ENY: i64 = 28 // enemy y x4
79const MD_NSV: i64 = 32
80const MD_SCHEMA: i64 = 2026
81const MD_SAVEAT: i64 = 1785100000
82const MD_CKM: i64 = 4611686018427387903
83const MD_TRBUF: i64 = 8192
84const MD_TRTICKS: i64 = 16
85const MD_PTYPE: i64 = 3 // player is GRASS: counters the Water warden (eff 4 out, 1 in) -- chart-read, not guessed
86const MD_TICKS: i64 = 96
87const MD_HEAL_AT: i64 = 40 // measured: entering the Fire-lurker fight at 32hp was lethal; heal FIRST
88const MD_SNARE_B: i64 = 4 // the den snare: (MD_SNARE_B - level) * MD_SNARE_L opening damage, floor 0.
89const MD_SNARE_L: i64 = 18 // measured: chase-intercept XP let a rusher shrug the old snare; level 4 = earned
90const MD_CK_PRIME: i64 = 16777619
91const MD_CK_SEED: i64 = 2166136261
92const MD_FAR: i64 = 1000000 // a LEVEL CHECK as a game rule -- rushing under-levelled is fatal by design
93
94func md_mix(ck: i64, v: i64) -> i64 {
95 var c: i64 = ck
96 c = (c + v + 1) % MD_CKM
97 c = (c * MD_CK_PRIME) % MD_CKM
98 return c
99}
100
101// fold the whole serializable state into the chain each tick -- ANY divergence surfaces
102func md_fold(s: *i64) -> i64 {
103 var c: i64 = s[MD_F_CK]
104 var i: i64 = 0
105 while i < MD_NSV { if i != MD_F_CK { c = md_mix(c, s[i]) } i = i + 1 }
106 s[MD_F_CK] = c
107 return c
108}
109
110func md_level(s: *i64) -> i64 { return rs_level_for_xp(s[MD_F_XP], MD_XP_BASE, MD_XP_QUAD) }
111func md_maxhp(s: *i64) -> i64 { return rs_derived_hp(MD_CON, md_level(s), MD_HPB, MD_HPCON, MD_HPLVL) }
112
113// enemy archetypes: 0..2 lurkers, 3 = the WARDEN (the boss). Typed for cb_eff coverage.
114func md_mkfoe(c: *i64, idx: i64, lvl: i64) -> i64 {
115 if idx == 3 {
116 cb_set(c, 2, lvl+3, 30 + lvl*8, 9 + lvl*2, 4, 5, "Glade Warden" as *u8)
117 cb_addmove(c, 2, 24, 90)
118 cb_addmove(c, 0, 8, 100)
119 return 0
120 }
121 cb_set(c, (idx % 3), lvl, 12 + lvl*4, 4 + lvl, 2, 4, "Lurker" as *u8)
122 cb_addmove(c, (idx % 3), 7, 95)
123 return 0
124}
125
126// deterministic battle: full rounds of best-move exchanges until one side drops.
127// Returns remaining player hp (<=0 = death). Damage flows through the certified cb_damage.
128func md_battle(s: *i64, foe: i64, brng: *i64) -> i64 {
129 let lvl: i64 = md_level(s)
130 let me: *i64 = sys_mmap(64*8) as *i64
131 cb_set(me, MD_PTYPE, lvl, s[MD_F_HP], 5 + lvl*2, 5 + lvl, 6, "Wanderer" as *u8)
132 cb_addmove(me, MD_PTYPE, 9, 95)
133 cb_addmove(me, 0, 6, 100)
134 let en: *i64 = sys_mmap(64*8) as *i64
135 md_mkfoe(en, foe, 1 + foe)
136 en[2] = s[MD_O_ENHP + foe] // live hp from state (word 2 = hp by cb_set layout)
137 if foe == 3 {
138 // the den snare: a level-checked opening strike. Data-driven boss rule, applied ONCE here.
139 var snare: i64 = (MD_SNARE_B - lvl) * MD_SNARE_L
140 if snare < 0 { snare = 0 }
141 me[2] = me[2] - snare
142 }
143 var guard: i64 = 0
144 while guard < 40 {
145 if me[2] > 0 { if en[2] > 0 {
146 let mv: i64 = cb_best(me, en)
147 let d1: i64 = cb_damage(me, en, me[8+mv*3], me[8+mv*3+1], brng)
148 en[2] = en[2] - d1
149 if en[2] > 0 {
150 let ev: i64 = cb_best(en, me)
151 let d2: i64 = cb_damage(en, me, en[8+ev*3], en[8+ev*3+1], brng)
152 me[2] = me[2] - d2
153 }
154 } }
155 guard = guard + 1
156 }
157 s[MD_O_ENHP + foe] = en[2]
158 if en[2] <= 0 {
159 s[MD_F_KILLS] = s[MD_F_KILLS] + 1
160 s[MD_F_XP] = rs_sadd(s[MD_F_XP], 40 + foe*30)
161 // certified drop: tier decides potion vs shard
162 let l1: *i64 = sys_mmap(8*8) as *i64
163 l1[0]=600; l1[1]=400
164 let r: i64 = lt_pick(l1, 2, (s[MD_F_CK] % 1000 + 1000) % 1000)
165 if r == 0 { s[MD_F_POT] = s[MD_F_POT] + 1 }
166 if r == 1 { s[MD_F_SHARD] = s[MD_F_SHARD] + 1 }
167 if foe == 3 { s[MD_F_OVER] = 1 } // the warden falls -> WIN
168 }
169 return me[2]
170}
171
172// ---- the ONE dispatch: semantic actions in, world ticks out. No caller sees a device. ----
173// actions: PREV/NEXT = move along the dungeon path axis; CONFIRM = engage/advance; CANCEL = drink potion.
174func md_step(s: *i64, grid: *i64, act: i64, brng: *i64) -> i64 {
175 if s[MD_F_OVER] != 0 { return 0 }
176 var nx: i64 = s[MD_F_PX]
177 var ny: i64 = s[MD_F_PY]
178 if act == IA_A_NEXT { nx = nx + 1 }
179 if act == IA_A_PREV { nx = nx - 1 }
180 if act == IA_A_CONFIRM { ny = ny + 1 }
181 if act == IA_A_PAUSE { ny = ny - 1 }
182 if act == IA_A_CANCEL {
183 if s[MD_F_POT] > 0 {
184 // a potion restores to FULL (the heart-refill convention) -- measured: +14 left the
185 // cautious policy entering super-effective fights at lethal margins
186 s[MD_F_POT] = s[MD_F_POT] - 1
187 s[MD_F_HP] = md_maxhp(s)
188 }
189 }
190 if nx < 0 { nx = 0 }
191 if nx >= MD_DW { nx = MD_DW-1 }
192 if ny < 0 { ny = 0 }
193 if ny >= MD_DH { ny = MD_DH-1 }
194 if grid[ny*MD_DW + nx] == 0 { s[MD_F_PX] = nx; s[MD_F_PY] = ny }
195 // enemies chase one A* step; adjacency = battle (certified parts do the fighting)
196 let pg: *i64 = sys_mmap(MD_DW*MD_DH*8) as *i64
197 let pf: *i64 = sys_mmap(MD_DW*MD_DH*8) as *i64
198 let pc: *i64 = sys_mmap(MD_DW*MD_DH*8) as *i64
199 let po: *i64 = sys_mmap(MD_DW*MD_DH*8) as *i64
200 let pz: *i64 = sys_mmap(MD_DW*MD_DH*8) as *i64
201 let pp: *i64 = sys_mmap(MD_DW*MD_DH*8) as *i64
202 var e: i64 = 0
203 while e < 4 {
204 if s[MD_O_ENHP + e] > 0 {
205 // the warden holds its den until the door is open (3 shards)
206 var mobile: i64 = 1
207 if e == 3 { if s[MD_F_SHARD] < 3 { mobile = 0 } }
208 if mobile == 1 {
209 let plen: i64 = pf_astar(grid, MD_DW, MD_DH,
210 s[MD_O_ENX+e], s[MD_O_ENY+e], s[MD_F_PX], s[MD_F_PY], pg, pf, pc, po, pz, pp)
211 if plen > 1 {
212 s[MD_O_ENX+e] = pp[1] % MD_DW
213 s[MD_O_ENY+e] = pp[1] / MD_DW
214 }
215 }
216 let dx: i64 = s[MD_O_ENX+e] - s[MD_F_PX]
217 let dy: i64 = s[MD_O_ENY+e] - s[MD_F_PY]
218 var ad: i64 = dx
219 if ad < 0 { ad = 0-ad }
220 var bd: i64 = dy
221 if bd < 0 { bd = 0-bd }
222 if ad + bd <= 1 {
223 let left: i64 = md_battle(s, e, brng)
224 s[MD_F_HP] = left
225 if left <= 0 { s[MD_F_OVER] = 2 }
226 }
227 }
228 e = e + 1
229 }
230 s[MD_F_TICK] = s[MD_F_TICK] + 1
231 md_fold(s)
232 return 0
233}
234
235func md_init(s: *i64, grid: *i64, age: i64) -> i64 {
236 var i: i64 = 0
237 while i < MD_NSV { s[i]=0; i=i+1 }
238 s[MD_F_CK] = MD_CK_SEED
239 s[MD_F_HP] = rs_derived_hp(MD_CON, 1, MD_HPB, MD_HPCON, MD_HPLVL)
240 s[MD_F_POT] = 1
241 ws_init((s as i64 + MD_O_WARD*8) as *i64, age, 0)
242 // maze + deterministic spawns on open cells
243 let stack: *i64 = sys_mmap(MD_DW*MD_DH*2*8) as *i64
244 pg_maze(grid, MD_DW, MD_DH, MD_SEED, stack)
245 s[MD_F_PX] = 1; s[MD_F_PY] = 1
246 grid[1*MD_DW+1] = 0
247 // lurkers at spread open cells; warden in the far corner den
248 let want: *i64 = sys_mmap(8*8) as *i64
249 want[0]=MD_DW-2; want[1]=1; want[2]=1; want[3]=MD_DH-2; want[4]=MD_DW/2; want[5]=MD_DH/2
250 var e: i64 = 0
251 while e < 3 {
252 var ex: i64 = want[e*2]
253 var ey: i64 = want[e*2+1]
254 if grid[ey*MD_DW+ex] != 0 { grid[ey*MD_DW+ex] = 0 }
255 s[MD_O_ENX+e]=ex; s[MD_O_ENY+e]=ey
256 s[MD_O_ENHP+e] = 12 + (1+e)*4
257 e = e + 1
258 }
259 grid[(MD_DH-2)*MD_DW + (MD_DW-2)] = 0
260 s[MD_O_ENX+3]=MD_DW-2; s[MD_O_ENY+3]=MD_DH-2
261 s[MD_O_ENHP+3] = 30 + 4*8
262 md_fold(s)
263 return 0
264}
265
266// run a POLICY through the certified INPUT LAYER: the player NAVIGATES with the same certified
267// pf_astar the enemies use (the trace proved a wall-blind policy just gets cornered), and every
268// move still flows raw-code -> ia_feed -> semantic action -> md_step. Nothing sees a device.
269// policy 0 CAUTIOUS: hunt lurkers nearest-first, heal when hurt, take the warden levelled.
270// policy 1 RECKLESS: straight to the den under-levelled -- the snare and the warden end it.
271func md_target(s: *i64, policy: i64) -> i64 {
272 if policy == 1 { return 3 }
273 var best: i64 = 3
274 var bd: i64 = MD_FAR
275 var e: i64 = 0
276 while e < 3 {
277 if s[MD_O_ENHP+e] > 0 {
278 var dx: i64 = s[MD_O_ENX+e] - s[MD_F_PX]
279 if dx < 0 { dx = 0-dx }
280 var dy: i64 = s[MD_O_ENY+e] - s[MD_F_PY]
281 if dy < 0 { dy = 0-dy }
282 if dx+dy < bd { bd = dx+dy; best = e }
283 }
284 e = e + 1
285 }
286 return best
287}
288func md_run(s: *i64, grid: *i64, policy: i64, age: i64) -> i64 {
289 md_init(s, grid, age)
290 let ia: *i64 = sys_mmap(IA_NSV*8) as *i64
291 ia_init(ia, 5)
292 ia_bind(ia, IA_D_KEY, IA_A_PREV, 37); ia_bind(ia, IA_D_KEY, IA_A_NEXT, 39)
293 ia_bind(ia, IA_D_KEY, IA_A_CONFIRM, 40); ia_bind(ia, IA_D_KEY, IA_A_PAUSE, 38)
294 ia_bind(ia, IA_D_KEY, IA_A_CANCEL, 27)
295 let brng: *i64 = sys_mmap(8) as *i64
296 brng[0] = MD_SEED + policy
297 let pg: *i64 = sys_mmap(MD_DW*MD_DH*8) as *i64
298 let pf: *i64 = sys_mmap(MD_DW*MD_DH*8) as *i64
299 let pc: *i64 = sys_mmap(MD_DW*MD_DH*8) as *i64
300 let po: *i64 = sys_mmap(MD_DW*MD_DH*8) as *i64
301 let pz: *i64 = sys_mmap(MD_DW*MD_DH*8) as *i64
302 let pp: *i64 = sys_mmap(MD_DW*MD_DH*8) as *i64
303 var t: i64 = 0
304 while t < MD_TICKS {
305 if s[MD_F_OVER] == 0 {
306 var raw: i64 = 39
307 var chosen: i64 = 0
308 if policy == 0 { if s[MD_F_HP] < MD_HEAL_AT { if s[MD_F_POT] > 0 { raw = 27; chosen = 1 } } }
309 if chosen == 0 {
310 let tgt: i64 = md_target(s, policy)
311 let plen: i64 = pf_astar(grid, MD_DW, MD_DH,
312 s[MD_F_PX], s[MD_F_PY], s[MD_O_ENX+tgt], s[MD_O_ENY+tgt], pg, pf, pc, po, pz, pp)
313 if plen > 1 {
314 let nxp: i64 = pp[1] % MD_DW
315 let nyp: i64 = pp[1] / MD_DW
316 if nxp > s[MD_F_PX] { raw = 39 }
317 if nxp < s[MD_F_PX] { raw = 37 }
318 if nyp > s[MD_F_PY] { raw = 40 }
319 if nyp < s[MD_F_PY] { raw = 38 }
320 }
321 }
322 let act: i64 = ia_feed(ia, IA_D_KEY, raw)
323 if act >= 0 { md_step(s, grid, act, brng) }
324 }
325 t = t + 1
326 }
327 return s[MD_F_OVER]
328}
329
330// ---- render the frame: overworld strip (worldpipe surface colours) + dungeon panel + HUD ----
331// PROCEDURAL MATERIAL (operator 2026-08-09: "this all needs to be procedurally emitting like
332// infinigen"): the dungeon's material family is DERIVED from a seed -- palette ramps, brick
333// coursing, flagstone size, crack density, flame colour -- no authored constants per look.
334// Change the seed, get a new dungeon. Same doctrine as nx_worldpipe: world from parameters.
335// out: [0..2] floor rgb, [3..5] brick rgb, [6..8] topface rgb, [9] course h, [10] flag w,
336// [11] crack mod, [12..14] flame rgb
337func md_mat(seed: i64, out: *i64) -> i64 {
338 let h1: i64 = tm_hash3(seed, 11, 3)
339 let h2: i64 = tm_hash3(seed, 23, 7)
340 let h3: i64 = tm_hash3(seed, 41, 13)
341 let fr: i64 = 118 + h1 % 48
342 out[0] = fr
343 out[1] = fr*3/4 + h2 % 21
344 out[2] = fr/2 - 8 + h3 % 17
345 let bb: i64 = 58 + h2 % 34
346 out[3] = bb*3/4 - 6 + h3 % 13
347 out[4] = bb*3/4 - 10 + h1 % 11
348 out[5] = bb
349 out[6] = out[3] + 62
350 out[7] = out[4] + 60
351 out[8] = out[5] + 62
352 out[9] = 4 + h1 % 3
353 out[10] = 11 + h2 % 5
354 out[11] = 5 + h3 % 5
355 out[12] = 235 + h1 % 21
356 out[13] = 120 + h2 % 41
357 out[14] = 24 + h3 % 25
358 return 0
359}
360
361// pixel-art figure sprite (rung 5): ground shadow + dark silhouette + shaded tunic + head + legs.
362// kind: 0 player (blue), 1 lurker (red), 2 warden (orange, larger + helmet). Discs were the last
363// flat primitive in the frame.
364func md_spr(fb: *i64, W: i64, H: i64, cx: i64, cy: i64, kind: i64) -> i64 {
365 var tr: i64 = 64
366 var tg: i64 = 140
367 var tb: i64 = 230
368 var hr: i64 = 240
369 var hg: i64 = 202
370 var hb: i64 = 164
371 if kind == 1 { tr = 178; tg = 52; tb = 44; hr = 210; hg = 120; hb = 100 }
372 if kind == 2 { tr = 232; tg = 128; tb = 30; hr = 236; hg = 190; hb = 90 }
373 var ex: i64 = 0
374 if kind == 2 { ex = 1 }
375 gr_disc(fb, W, H, cx, cy+6+ex, 3+ex, gr_pack(18, 14, 22))
376 gr_rect(fb, W, H, cx-3-ex, cy-7-ex, cx+3+ex, cy+5+ex, gr_pack(14, 10, 16))
377 gr_rect(fb, W, H, cx-2-ex, cy-2-ex, cx+2+ex, cy+3+ex, gr_pack(tr, tg, tb))
378 gr_rect(fb, W, H, cx-2-ex, cy-2-ex, cx+2+ex, cy-1, gr_pack(wp_clamp(tr+34,0,255), wp_clamp(tg+34,0,255), wp_clamp(tb+24,0,255)))
379 gr_rect(fb, W, H, cx-1, cy-6-ex, cx+1, cy-3, gr_pack(hr, hg, hb))
380 gr_rect(fb, W, H, cx-2-ex, cy+4, cx-1, cy+5+ex, gr_pack(30, 24, 34))
381 gr_rect(fb, W, H, cx+1, cy+4, cx+2+ex, cy+5+ex, gr_pack(30, 24, 34))
382 if kind == 2 { gr_rect(fb, W, H, cx-2, cy-8, cx+2, cy-7, gr_pack(180, 150, 60)) }
383 return 0
384}
385
386func md_render(s: *i64, grid: *i64, fb: *i64, W: i64, H: i64) -> i64 {
387 wp_init(MD_SEED)
388 // top strip: the REAL overworld -- per-pixel worldpipe surface colours (palette source)
389 var y: i64 = 0
390 while y < H/3 {
391 var x: i64 = 0
392 while x < W {
393 let wx: i64 = (x - W/2) * MD_WSCALE / 8
394 let wz: i64 = (y - H/6) * MD_WSCALE / 8
395 let hh: i64 = wp_height(wx, wz)
396 var sl: i64 = wp_height(wx+40, wz) - hh
397 if sl < 0 { sl = 0-sl }
398 var pc: i64 = wp_shade(wx, wz, hh, sl) // F1158: the LIT overworld (palette from geometry)
399 // WATER LIFE (rung 5): shoreline foam + wave banding + sparse sparkle -- structure off the
400 // real heightfield (the same infinigen doctrine: emitted from the field, never painted on).
401 if hh < 0 {
402 var nearland: i64 = 0
403 if wp_height(wx+70, wz) > 5 { nearland = 1 }
404 if wp_height(wx-70, wz) > 5 { nearland = 1 }
405 if wp_height(wx, wz+70) > 5 { nearland = 1 }
406 if wp_height(wx, wz-70) > 5 { nearland = 1 }
407 var wr: i64 = pc % 256
408 var wg: i64 = (pc / 256) % 256
409 var wb: i64 = (pc / MD_MAGIC_65536) % 256
410 if nearland == 1 {
411 wr = (wr + 225) / 2
412 wg = (wg + 236) / 2
413 wb = (wb + 242) / 2
414 }
415 if nearland == 0 {
416 if ((wx + wz*2) / 120) % 3 == 0 { wb = wb + 10; wg = wg + 4 }
417 if tm_hash3(wx/60, 77, wz/60) % 97 == 0 { wr=wr+55; wg=wg+55; wb=wb+45 }
418 }
419 wr = wp_clamp(wr, 0, 255)
420 wg = wp_clamp(wg, 0, 255)
421 wb = wp_clamp(wb, 0, 255)
422 pc = wr + wg*256 + wb*MD_MAGIC_65536
423 }
424 // STAGE-7 FEATURES INTO THE GAME FRAME (the measured det4/hue lever the rung-2c cells named:
425 // \x22procgen features rendered INTO game frames, not more brightness\x22). Cell convention =
426 // the worldpipe gate's own: wp_feature at WORLD-coord anchors on a 220-unit cell step;
427 // canopy/trunk colors are the gate's 3D palette, so ONE owner of the feature look.
428 var fmx: i64 = wx % 220
429 if fmx < 0 { fmx = fmx + 220 }
430 let fax: i64 = wx - fmx
431 var fmz: i64 = wz % 220
432 if fmz < 0 { fmz = fmz + 220 }
433 let faz: i64 = wz - fmz
434 let ff: i64 = wp_feature(fax, faz)
435 if ff > 0 {
436 let dxw: i64 = wx - fax - 110
437 let dzw: i64 = wz - faz - 110
438 let dd: i64 = dxw*dxw + dzw*dzw
439 var rad: i64 = 0
440 var fcol: i64 = 0
441 if ff == 1 { rad = 150; fcol = 42+96*256+40*MD_MAGIC_65536 } // tree canopy
442 if ff == 2 { rad = 90; fcol = 60+150*256+70*MD_MAGIC_65536 } // cactus
443 if ff == 3 { rad = 150; fcol = 210+220*256+230*MD_MAGIC_65536 } // spruce, snow-tipped
444 if ff == 4 { rad = 110; fcol = 128+122*256+116*MD_MAGIC_65536 } // boulder
445 if dd < rad*rad { pc = fcol }
446 if dd < 40*40 { if ff == 1 { pc = 96+72*256+46*MD_MAGIC_65536 } if ff == 3 { pc = 88+66*256+44*MD_MAGIC_65536 } }
447 }
448 gr_px(fb, W, H, x, y, pc)
449 x = x + 1
450 }
451 y = y + 1
452 }
453 // dungeon panel: walls/floor + actors
454 let cw: i64 = W / MD_DW
455 let chh: i64 = (H - H/3 - 20) / MD_DH
456 var mseed: i64 = MD_AT_MS
457 if mseed == 0 { mseed = MD_SEED + 194 } // sweep cycle 2 pick (v2): golden floor vs dark wall won eye AND ruler; materials still ride the world seed
458 let mat: *i64 = sys_mmap(128) as *i64
459 md_mat(mseed, mat)
460 var gy: i64 = 0
461 while gy < MD_DH {
462 var gx: i64 = 0
463 while gx < MD_DW {
464 var c: i64 = gr_pack(34, 30, 44)
465 if grid[gy*MD_DW+gx] == 0 { c = gr_pack(78, 70, 96) }
466 // ART-DIRECTION rung 2026-08-09: per-pixel flagstones/bricks with CELL-STABLE jitter (the
467 // wp_shade albedo idiom -- structure, never per-pixel noise), mortar seams, top-lit wall
468 // edges, seeded torch light-pools. This panel was 2 flat colours = the measured pal/det4 gap.
469 let wall2: i64 = grid[gy*MD_DW+gx]
470 let tx0: i64 = gx*cw
471 let ty0: i64 = H/3 + gy*chh
472 let torch: i64 = tm_hash3(gx, gy*7+3, MD_SEED)
473 var py2: i64 = 0
474 while py2 < chh {
475 var px2: i64 = 0
476 while px2 < cw {
477 // === PIXEL-ART TILES (rung 5): tone-ramped flagstones + coursed brick with a lit
478 // top face and grounded base, cast shadows, drawn torch braziers. Craft, not
479 // statistics -- the caricature-control conviction stands regardless of score.
480 var r3: i64 = 0
481 var g3: i64 = 0
482 var b3: i64 = 0
483 var jaq: i64 = MD_AT_JA
484 if jaq == 0 { jaq = 29 }
485 var tmq: i64 = MD_AT_TM
486 if tmq == 0 { tmq = 5 }
487 if wall2 == 0 {
488 // FLOOR: 2x2 flagstones, bevel ramp, seams, hash cracks
489 var fr: i64 = mat[0]
490 var fg: i64 = mat[1]
491 var fbl: i64 = mat[2]
492 if MD_AT_FW == 1 { fr = 82; fg = 74; fbl = 98 }
493 if MD_AT_FW == 2 { fr = 128; fg = 110; fbl = 86 }
494 let fw9: i64 = mat[10]
495 let fsx: i64 = px2 / fw9
496 let fsy: i64 = py2 / 7
497 let flx: i64 = px2 - fsx*fw9
498 let fly: i64 = py2 - fsy*7
499 let fh: i64 = tm_hash3(gx*4+fsx, gy*4+fsy, MD_SEED)
500 let fj: i64 = fh % jaq - jaq/2
501 r3 = fr + fj
502 g3 = fg + fj
503 b3 = fbl + fj - (fh/64) % 9 + 4
504 if flx == 0 { r3=r3+20; g3=g3+18; b3=b3+14 }
505 if fly == 0 { r3=r3+16; g3=g3+14; b3=b3+10 }
506 if flx == fw9-1 { r3=r3-24; g3=g3-22; b3=b3-16 }
507 if fly == 6 { r3=r3-22; g3=g3-20; b3=b3-14 }
508 if py2 == 14 { r3=r3-26; g3=g3-24; b3=b3-18 }
509 if fh % mat[11] == 0 { if flx - fly == (fh/8) % 5 - 2 { r3=r3-38; g3=g3-34; b3=b3-26 } }
510 if gy > 0 { if grid[(gy-1)*MD_DW+gx] != 0 { if py2 < 3 {
511 r3 = r3*11/20; g3 = g3*11/20; b3 = b3*12/20 } } }
512 if torch % tmq == 0 {
513 let dxp: i64 = px2 - cw/2
514 let dyp: i64 = py2 - chh/2
515 let dd3: i64 = dxp*dxp + dyp*dyp*3
516 var gl: i64 = 120 - dd3
517 if gl < 0 { gl = 0 }
518 r3 = r3 + gl*9/10
519 g3 = g3 + gl*5/10
520 b3 = b3 + gl/10
521 let fdy: i64 = py2 - (chh/2 - 2)
522 let ddf: i64 = dxp*dxp*3 + fdy*fdy*2
523 if ddf < 14 { r3 = mat[12]; g3 = mat[13]; b3 = mat[14] }
524 if ddf < 5 { r3 = 255; g3 = 224; b3 = 120 }
525 if py2 == chh/2 + 2 { if dxp >= 0-2 { if dxp <= 2 { r3=44; g3=38; b3=34 } } }
526 if py2 == chh/2 + 1 { if dxp >= 0-1 { if dxp <= 1 { r3=58; g3=50; b3=44 } } }
527 }
528 }
529 if wall2 != 0 {
530 // WALL: running-bond brick, lit TOP FACE over open floor, grounded dark base
531 var topface: i64 = 0
532 if gy > 0 { if grid[(gy-1)*MD_DW+gx] == 0 { topface = 1 } }
533 var body: i64 = 1
534 if topface == 1 { if py2 < 4 { body = 0 } }
535 if body == 0 {
536 let ch2: i64 = tm_hash3(gx*9+px2/6, gy, MD_SEED)
537 let cj: i64 = ch2 % 15 - 7
538 r3 = mat[6] + cj
539 g3 = mat[7] + cj
540 b3 = mat[8] + cj
541 if py2 == 3 { r3 = 34; g3 = 32; b3 = 48 }
542 }
543 if body == 1 {
544 let chq: i64 = mat[9]
545 let course: i64 = py2 / chq
546 var bof: i64 = 0
547 if course % 2 == 1 { bof = 13 }
548 let bxi: i64 = (px2 + bof) / 13
549 let blx: i64 = (px2 + bof) - bxi*13
550 let bly: i64 = py2 - course*chq
551 let bh2: i64 = tm_hash3(gx*8+bxi, gy*8+course, MD_SEED)
552 let bj: i64 = bh2 % jaq - jaq/2
553 r3 = mat[3] + bj/2
554 g3 = mat[4] + bj/2
555 b3 = mat[5] + bj/2 + (bh2/64) % 7
556 if bly == 0 { r3 = 26; g3 = 24; b3 = 38 }
557 if blx == 0 { r3 = 26; g3 = 24; b3 = 38 }
558 if bly == 1 { if blx != 0 { r3=r3+13; g3=g3+12; b3=b3+14 } }
559 if bly == chq-1 { if blx != 0 { r3=r3-10; g3=g3-9; b3=b3-8 } }
560 if py2 == chh-1 { if gy < MD_DH-1 { if grid[(gy+1)*MD_DW+gx] == 0 {
561 r3 = 14; g3 = 12; b3 = 20 } } }
562 }
563 }
564 r3 = wp_clamp(r3, 0, 255)
565 g3 = wp_clamp(g3, 0, 255)
566 b3 = wp_clamp(b3, 0, 255)
567 gr_px(fb, W, H, tx0+px2, ty0+py2, gr_pack(r3, g3, b3))
568 px2 = px2 + 1
569 }
570 py2 = py2 + 1
571 }
572 gx = gx + 1
573 }
574 gy = gy + 1
575 }
576 var e: i64 = 0
577 while e < 4 {
578 if s[MD_O_ENHP+e] > 0 {
579 var ek: i64 = 1
580 if e == 3 { ek = 2 }
581 md_spr(fb, W, H, s[MD_O_ENX+e]*cw + cw/2, H/3 + s[MD_O_ENY+e]*chh + chh/2, ek)
582 }
583 e = e + 1
584 }
585 md_spr(fb, W, H, s[MD_F_PX]*cw + cw/2, H/3 + s[MD_F_PY]*chh + chh/2, 0)
586 // hp meter strip
587 var mh: i64 = md_maxhp(s)
588 if mh < 1 { mh = 1 }
589 var fill: i64 = (s[MD_F_HP] * (W-20)) / mh
590 if fill < 0 { fill = 0 }
591 gr_rect(fb, W, H, 10, H-14, 10 + fill, H-6, gr_pack(90, 220, 120))
592 return 0
593}
594
595func ocat(o: *u8, at: i64, s: *u8) -> i64 { var i: i64=0; var a: i64=at; while s[i]!=(0 as u8){o[a]=s[i]; a=a+1; i=i+1} return a }
596func onum(o: *u8, at: i64, v: i64) -> i64 {
597 var a: i64=at; var m: i64=v
598 if m==0 { o[a]=48 as u8; return a+1 }
599 if m<0 { o[a]=45 as u8; a=a+1; m=0-m }
600 let t: *u8 = sys_mmap(32); var k: i64=0
601 while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 }
602 var q: i64=k-1
603 while q>=0 { o[a]=t[q]; a=a+1; q=q-1 }
604 return a
605}
606func hexd(v: i64) -> i64 { if v < 10 { return 48+v } return 87+v }
607
608// ---- the NATIVE SOVEREIGN PLAY SURFACE (operator directive 2026-07-26: NishiLang byte-up first;
609// NishiOS / Nishi Browser are the primary surfaces, JS is interoperability only). ANSI true-colour
610// terminal frames via the engine lib's own bput_* helpers -- no web stack anywhere in the loop.
611// Input still flows raw-key -> ia_feed -> semantic action: the device abstraction holds even here.
612// plain=1 emits pure printable glyphs (the MCP/tools/call route -- raw ESC bytes broke the JSON
613// transport, measured as 8x edge flake); plain=0 emits ANSI true-colour for a live terminal.
614func md_ansi_frame(s: *i64, grid: *i64, ob: *u8, off: *i64, plain: i64) -> i64 {
615 if plain == 0 { bput_clear(ob, off) }
616 bput(ob, off, "NISHI GLADE -- sovereign native play\x0a" as *u8)
617 var gy: i64 = 0
618 while gy < MD_DH {
619 var gx: i64 = 0
620 while gx < MD_DW {
621 var glyph: i64 = 46
622 var isact: i64 = 0
623 if s[MD_F_PX]==gx { if s[MD_F_PY]==gy { glyph=64; isact=1
624 if plain==0 { bput_fg(ob,off,120,220,255) } } }
625 var e: i64 = 0
626 while e < 4 {
627 if isact==0 { if s[MD_O_ENHP+e]>0 { if s[MD_O_ENX+e]==gx { if s[MD_O_ENY+e]==gy {
628 isact=1
629 if e==3 { glyph=87
630 if plain==0 { bput_fg(ob,off,255,170,60) } }
631 if e<3 { glyph=76
632 if plain==0 { bput_fg(ob,off,255,90,80) } }
633 } } } }
634 e = e + 1
635 }
636 if grid[gy*MD_DW+gx]!=0 { glyph=35 }
637 if plain == 0 {
638 if grid[gy*MD_DW+gx]==0 { bput_bg(ob,off,52,46,66) }
639 if grid[gy*MD_DW+gx]!=0 { bput_bg(ob,off,24,20,32) }
640 }
641 bputc(ob,off,glyph); bputc(ob,off,32)
642 if plain == 0 { bput_reset(ob,off) }
643 gx = gx + 1
644 }
645 bputc(ob,off,10)
646 gy = gy + 1
647 }
648 bput(ob, off, "HP " as *u8); bputn(ob, off, s[MD_F_HP])
649 bput(ob, off, " LVL " as *u8); bputn(ob, off, md_level(s))
650 bput(ob, off, " POT " as *u8); bputn(ob, off, s[MD_F_POT])
651 bput(ob, off, " SHARDS " as *u8); bputn(ob, off, s[MD_F_SHARD])
652 bput(ob, off, " KILLS " as *u8); bputn(ob, off, s[MD_F_KILLS])
653 if s[MD_F_OVER]==1 { bput(ob, off, " ** THE WARDEN FALLS -- YOU WIN **" as *u8) }
654 if s[MD_F_OVER]==2 { bput(ob, off, " ** YOU COLLAPSE -- RUN ENDED **" as *u8) }
655 bputc(ob,off,10)
656 return 0
657}
658// a=west d=east w=north s=south p=potion q=quit; script from argv OR live keys from stdin
659func md_key_raw(ch: i64) -> i64 {
660 if ch == 97 { return 37 }
661 if ch == 100 { return 39 }
662 if ch == 119 { return 38 }
663 if ch == 115 { return 40 }
664 if ch == 112 { return 27 }
665 return 0
666}
667func md_play(grid: *i64, script: *u8) -> i64 {
668 let s: *i64 = sys_mmap(MD_NSV*8) as *i64
669 md_init(s, grid, 25)
670 let ia: *i64 = sys_mmap(IA_NSV*8) as *i64
671 ia_init(ia, 5)
672 ia_bind(ia, IA_D_KEY, IA_A_PREV, 37); ia_bind(ia, IA_D_KEY, IA_A_NEXT, 39)
673 ia_bind(ia, IA_D_KEY, IA_A_CONFIRM, 40); ia_bind(ia, IA_D_KEY, IA_A_PAUSE, 38)
674 ia_bind(ia, IA_D_KEY, IA_A_CANCEL, 27)
675 let brng: *i64 = sys_mmap(8) as *i64
676 brng[0] = MD_SEED
677 let ob: *u8 = sys_mmap(MD_TRBUF*4)
678 let off: *i64 = sys_mmap(8) as *i64
679 var plain: i64 = 0
680 if (script as i64) != 0 { plain = 1 } // scripted = MCP transport = printable glyphs only
681 off[0]=0
682 md_ansi_frame(s, grid, ob, off, plain)
683 sys_write(1, ob, off[0])
684 var si: i64 = 0
685 var live: i64 = 1
686 let inb: *u8 = sys_mmap(8)
687 while live == 1 {
688 var ch: i64 = 0
689 if (script as i64) != 0 {
690 ch = script[si] as i64
691 si = si + 1
692 if ch == 0 { live = 0 }
693 }
694 if (script as i64) == 0 {
695 let rn: i64 = sys_read(0, inb, 1)
696 if rn < 1 { live = 0 }
697 if rn >= 1 { ch = inb[0] as i64 }
698 }
699 if ch == 113 { live = 0 }
700 if live == 1 {
701 let raw: i64 = md_key_raw(ch)
702 if raw != 0 {
703 let act: i64 = ia_feed(ia, IA_D_KEY, raw)
704 if act >= 0 { md_step(s, grid, act, brng) }
705 off[0]=0
706 md_ansi_frame(s, grid, ob, off, plain)
707 sys_write(1, ob, off[0])
708 if s[MD_F_OVER] != 0 { live = 0 }
709 }
710 }
711 }
712 if s[MD_F_OVER] == 1 { return 0 }
713 return s[MD_F_OVER]
714}
715
716func main(argc: i64, argv: *i64) -> i64 {
717 let grid: *i64 = sys_mmap(MD_DW*MD_DH*8) as *i64
718 let s: *i64 = sys_mmap(MD_NSV*8) as *i64
719
720 // native play. `play <script>` (a/d/w/s/p) = scripted, MCP-safe, plain glyphs.
721 // `tty` = live stdin keys with ANSI colour -- TERMINAL ONLY: over tools/call an open stdin
722 // never EOFs, so a blocking read would hang the transport for its full timeout (measured).
723 // A tool must refuse loudly rather than block (the operator's refusal law).
724 // F1159 `export` -- the staged overworld AS DATA for the /world/explore playable surface.
725 // ONE owner of the world truth: the SAME wp_* pipeline, SAME MD_SEED, SAME +40 slope probe the
726 // scored game frame samples. The page is display+input interop only (sovereign-first law).
727 if argc >= 2 {
728 let ax: *u8 = argv[1] as *u8
729 if ax[0]==(101 as u8) {
730 wp_init(MD_SEED)
731 let spw: *i64 = sys_mmap(24) as *i64
732 let sfound: i64 = wp_spawn(spw)
733 let TW: i64 = 96
734 let TH: i64 = 64
735 let jb2: *u8 = sys_mmap(MD_MAGIC_65536*2)
736 var j2: i64 = 0
737 j2 = ocat(jb2, j2, "{\x22organ\x22:\x22nx_m2d_engine\x22,\x22verb\x22:\x22export\x22,\x22seed\x22:" as *u8)
738 j2 = onum(jb2, j2, MD_SEED)
739 j2 = ocat(jb2, j2, ",\x22wscale\x22:" as *u8)
740 j2 = onum(jb2, j2, MD_WSCALE)
741 j2 = ocat(jb2, j2, ",\x22tw\x22:" as *u8)
742 j2 = onum(jb2, j2, TW)
743 j2 = ocat(jb2, j2, ",\x22th\x22:" as *u8)
744 j2 = onum(jb2, j2, TH)
745 j2 = ocat(jb2, j2, ",\x22spawn_found\x22:" as *u8)
746 j2 = onum(jb2, j2, sfound)
747 j2 = ocat(jb2, j2, ",\x22spawn_world\x22:[" as *u8)
748 j2 = onum(jb2, j2, spw[0])
749 j2 = ocat(jb2, j2, "," as *u8)
750 j2 = onum(jb2, j2, spw[1])
751 j2 = ocat(jb2, j2, "],\x22spawn_tile\x22:[" as *u8)
752 j2 = onum(jb2, j2, spw[0]/MD_WSCALE + TW/2)
753 j2 = ocat(jb2, j2, "," as *u8)
754 j2 = onum(jb2, j2, spw[1]/MD_WSCALE + TH/2)
755 j2 = ocat(jb2, j2, "],\x22biomes\x22:\x22OCEAN,BEACH,RIVER,DESERT,SNOWY,PEAKS,FOREST,PLAINS\x22" as *u8)
756 j2 = ocat(jb2, j2, ",\x22features\x22:\x22none,tree,cactus,spruce,boulder\x22" as *u8)
757 j2 = ocat(jb2, j2, ",\x22colors\x22:\x22" as *u8)
758 var nwalk: i64 = 0
759 var nblock: i64 = 0
760 var ty: i64 = 0
761 while ty < TH {
762 var tx: i64 = 0
763 while tx < TW {
764 let wx: i64 = (tx - TW/2) * MD_WSCALE
765 let wz: i64 = (ty - TH/2) * MD_WSCALE
766 let hh2: i64 = wp_height(wx, wz)
767 var sl2: i64 = wp_height(wx+40, wz) - hh2
768 if sl2 < 0 { sl2 = 0-sl2 }
769 let cc: i64 = wp_shade(wx, wz, hh2, sl2)
770 let rr: i64 = cc % 256
771 let gg: i64 = (cc / 256) % 256
772 let bb: i64 = (cc / MD_MAGIC_65536) % 256
773 jb2[j2] = hexd(rr/16) as u8; jb2[j2+1] = hexd(rr%16) as u8
774 jb2[j2+2] = hexd(gg/16) as u8; jb2[j2+3] = hexd(gg%16) as u8
775 jb2[j2+4] = hexd(bb/16) as u8; jb2[j2+5] = hexd(bb%16) as u8
776 j2 = j2 + 6
777 tx = tx + 1
778 }
779 ty = ty + 1
780 }
781 j2 = ocat(jb2, j2, "\x22,\x22biome\x22:\x22" as *u8)
782 ty = 0
783 while ty < TH {
784 var tx2: i64 = 0
785 while tx2 < TW {
786 let wx2: i64 = (tx2 - TW/2) * MD_WSCALE
787 let wz2: i64 = (ty - TH/2) * MD_WSCALE
788 jb2[j2] = (48 + wp_biome(wx2, wz2)) as u8
789 j2 = j2 + 1
790 tx2 = tx2 + 1
791 }
792 ty = ty + 1
793 }
794 j2 = ocat(jb2, j2, "\x22,\x22feat\x22:\x22" as *u8)
795 ty = 0
796 while ty < TH {
797 var tx3: i64 = 0
798 while tx3 < TW {
799 let wx3: i64 = (tx3 - TW/2) * MD_WSCALE
800 let wz3: i64 = (ty - TH/2) * MD_WSCALE
801 jb2[j2] = (48 + wp_feature(wx3, wz3)) as u8
802 j2 = j2 + 1
803 tx3 = tx3 + 1
804 }
805 ty = ty + 1
806 }
807 j2 = ocat(jb2, j2, "\x22,\x22walk\x22:\x22" as *u8)
808 ty = 0
809 while ty < TH {
810 var tx4: i64 = 0
811 while tx4 < TW {
812 let wx4: i64 = (tx4 - TW/2) * MD_WSCALE
813 let wz4: i64 = (ty - TH/2) * MD_WSCALE
814 let bb4: i64 = wp_biome(wx4, wz4)
815 let hh4: i64 = wp_height(wx4, wz4)
816 var wk: i64 = 1
817 if bb4 == 0 { wk = 0 }
818 if bb4 == 2 { wk = 0 }
819 if hh4 < 0 { wk = 0 }
820 if wk == 0 { nblock = nblock + 1 }
821 if wk == 1 { nwalk = nwalk + 1 }
822 jb2[j2] = (48 + wk) as u8
823 j2 = j2 + 1
824 tx4 = tx4 + 1
825 }
826 ty = ty + 1
827 }
828 j2 = ocat(jb2, j2, "\x22}" as *u8)
829 jb2[j2] = 10 as u8
830 j2 = j2 + 1
831 let fd2: i64 = sys_openat_wr("sites/nishifamily/world/world_grid.json" as *u8, 0x1a4)
832 var wrote: i64 = 0
833 if fd2 >= 0 { sys_write(fd2, jb2, j2); sys_fsync(fd2); sys_close(fd2); wrote = 1 }
834 // PIXEL-ART GROUND (operator 2026-08-09: flat squares are bottom-tier emissions): the ORGAN
835 // renders the whole explore ground -- per-pixel lit terrain at 12px/tile, water
836 // foam/wave/sparkle, stage-7 feature sprites at their true 220-unit cell anchors -- and
837 // publishes it beside the JSON. The page BLITS this image; truth stays in the organ.
838 let MPX: i64 = 12
839 let MW2: i64 = TW*MPX
840 let MH2: i64 = TH*MPX
841 let mfb: *i64 = sys_mmap(MW2*MH2*8) as *i64
842 var mpy: i64 = 0
843 while mpy < MH2 {
844 var mpx: i64 = 0
845 while mpx < MW2 {
846 let wxm: i64 = (mpx - MW2/2) * MD_WSCALE / MPX
847 let wzm: i64 = (mpy - MH2/2) * MD_WSCALE / MPX
848 let hhm: i64 = wp_height(wxm, wzm)
849 var slm: i64 = wp_height(wxm+40, wzm) - hhm
850 if slm < 0 { slm = 0-slm }
851 var mc: i64 = wp_shade(wxm, wzm, hhm, slm)
852 if hhm < 0 {
853 var nl2: i64 = 0
854 if wp_height(wxm+70, wzm) > 5 { nl2 = 1 }
855 if wp_height(wxm-70, wzm) > 5 { nl2 = 1 }
856 if wp_height(wxm, wzm+70) > 5 { nl2 = 1 }
857 if wp_height(wxm, wzm-70) > 5 { nl2 = 1 }
858 var mr: i64 = mc % 256
859 var mg: i64 = (mc / 256) % 256
860 var mb: i64 = (mc / MD_MAGIC_65536) % 256
861 if nl2 == 1 { mr=(mr+225)/2; mg=(mg+236)/2; mb=(mb+242)/2 }
862 if nl2 == 0 {
863 if ((wxm + wzm*2) / 120) % 3 == 0 { mb = mb + 10; mg = mg + 4 }
864 if tm_hash3(wxm/60, 77, wzm/60) % 97 == 0 { mr=mr+55; mg=mg+55; mb=mb+45 }
865 }
866 mc = wp_clamp(mr,0,255) + wp_clamp(mg,0,255)*256 + wp_clamp(mb,0,255)*MD_MAGIC_65536
867 }
868 var fmx2: i64 = wxm % 220
869 if fmx2 < 0 { fmx2 = fmx2 + 220 }
870 let fax2: i64 = wxm - fmx2
871 var fmz2: i64 = wzm % 220
872 if fmz2 < 0 { fmz2 = fmz2 + 220 }
873 let faz2: i64 = wzm - fmz2
874 let ff2: i64 = wp_feature(fax2, faz2)
875 if ff2 > 0 {
876 let dxw2: i64 = wxm - fax2 - 110
877 let dzw2: i64 = wzm - faz2 - 110
878 let dd4: i64 = dxw2*dxw2 + dzw2*dzw2
879 var rad2: i64 = 0
880 var fc2: i64 = 0
881 if ff2 == 1 { rad2 = 120; fc2 = 42+96*256+40*MD_MAGIC_65536 }
882 if ff2 == 2 { rad2 = 90; fc2 = 60+150*256+70*MD_MAGIC_65536 }
883 if ff2 == 3 { rad2 = 120; fc2 = 210+220*256+230*MD_MAGIC_65536 }
884 if ff2 == 4 { rad2 = 100; fc2 = 128+122*256+116*MD_MAGIC_65536 }
885 if dd4 < rad2*rad2 { mc = fc2 }
886 if dd4 < 40*40 { if ff2 == 1 { mc = 96+72*256+46*MD_MAGIC_65536 } if ff2 == 3 { mc = 88+66*256+44*MD_MAGIC_65536 } }
887 }
888 mfb[mpy*MW2 + mpx] = mc
889 mpx = mpx + 1
890 }
891 mpy = mpy + 1
892 }
893 write_png(mfb, MW2, MH2, "sites/nishifamily/world/world_map.png" as *u8)
894 let rb: *u8 = sys_mmap(MD_MAGIC_4096)
895 var r2: i64 = 0
896 r2 = ocat(rb, r2, "{\x22organ\x22:\x22nx_m2d_engine\x22,\x22verb\x22:\x22export\x22,\x22wrote\x22:" as *u8)
897 r2 = onum(rb, r2, wrote)
898 r2 = ocat(rb, r2, ",\x22path\x22:\x22sites/nishifamily/world/world_grid.json\x22,\x22bytes\x22:" as *u8)
899 r2 = onum(rb, r2, j2)
900 r2 = ocat(rb, r2, ",\x22tiles\x22:" as *u8)
901 r2 = onum(rb, r2, TW*TH)
902 r2 = ocat(rb, r2, ",\x22walkable\x22:" as *u8)
903 r2 = onum(rb, r2, nwalk)
904 r2 = ocat(rb, r2, ",\x22blocked\x22:" as *u8)
905 r2 = onum(rb, r2, nblock)
906 r2 = ocat(rb, r2, ",\x22spawn_found\x22:" as *u8)
907 r2 = onum(rb, r2, sfound)
908 r2 = ocat(rb, r2, ",\x22consumer\x22:\x22/world/explore (JS = display+input interop only; world truth = this organ)\x22}" as *u8)
909 rb[r2] = 10 as u8
910 sys_write(1, rb, r2+1)
911 if wrote == 0 { return 1 }
912 if nwalk == 0 { return 1 }
913 return 0
914 }
915 if ax[0]==(115 as u8) {
916 // ITERATIVE ART LOOP (operator 2026-08-09: "build the iterative loops and look"): render
917 // knob variants of the SAME frame, tile a 3x2 contact sheet ONTO THE SITE, print every
918 // variant's critic score -- each cycle is scored AND lookable, and a pick becomes the new
919 // default. Knobs are sentinel statics: unset = shipped look, battery byte-unchanged.
920 let stack9: *i64 = sys_mmap(MD_DW*MD_DH*2*8) as *i64
921 pg_maze(grid, MD_DW, MD_DH, MD_SEED, stack9)
922 md_init(s, grid, 25)
923 let W9: i64 = 400
924 let H9: i64 = 240
925 let fb9: *i64 = sys_mmap(W9*H9*8) as *i64
926 let sheet: *i64 = sys_mmap(W9*3*H9*2*8) as *i64
927 let tmv: *i64 = sys_mmap(48) as *i64
928 let jav: *i64 = sys_mmap(48) as *i64
929 let fwv: *i64 = sys_mmap(48) as *i64
930 let msv: *i64 = sys_mmap(48) as *i64
931 // INFINIGEN SWEEP: variants are MATERIAL SEEDS -- each renders a different procedurally
932 // derived dungeon material family (palette ramps, coursing, flag size, cracks, flame).
933 tmv[0]=0; jav[0]=0; fwv[0]=0; msv[0]=0
934 tmv[1]=0; jav[1]=0; fwv[1]=0; msv[1]=MD_SEED+97
935 tmv[2]=0; jav[2]=0; fwv[2]=0; msv[2]=MD_SEED+194
936 tmv[3]=0; jav[3]=0; fwv[3]=0; msv[3]=MD_SEED+291
937 tmv[4]=0; jav[4]=0; fwv[4]=0; msv[4]=MD_SEED+388
938 tmv[5]=0; jav[5]=0; fwv[5]=0; msv[5]=MD_SEED+485
939 let mets9: *i64 = sys_mmap(GC_N*8) as *i64
940 let jb9: *u8 = sys_mmap(MD_MAGIC_4096)
941 var j9: i64 = 0
942 j9 = ocat(jb9, j9, "{\x22organ\x22:\x22nx_m2d_engine\x22,\x22verb\x22:\x22sweep\x22,\x22variants\x22:[" as *u8)
943 var v9: i64 = 0
944 while v9 < 6 {
945 MD_AT_TM = tmv[v9]
946 MD_AT_JA = jav[v9]
947 MD_AT_FW = fwv[v9]
948 MD_AT_MS = msv[v9]
949 md_render(s, grid, fb9, W9, H9)
950 let ox9: i64 = (v9 % 3) * W9
951 let oy9: i64 = (v9 / 3) * H9
952 var yy9: i64 = 0
953 while yy9 < H9 {
954 var xx9: i64 = 0
955 while xx9 < W9 {
956 sheet[(oy9+yy9)*(W9*3) + ox9 + xx9] = fb9[yy9*W9 + xx9]
957 xx9 = xx9 + 1
958 }
959 yy9 = yy9 + 1
960 }
961 gc_score(fb9, W9, H9, mets9)
962 let q9: i64 = gc_quality(mets9)
963 if v9 > 0 { j9 = ocat(jb9, j9, "," as *u8) }
964 j9 = ocat(jb9, j9, "{\x22v\x22:" as *u8); j9 = onum(jb9, j9, v9)
965 j9 = ocat(jb9, j9, ",\x22torchmod\x22:" as *u8); j9 = onum(jb9, j9, tmv[v9])
966 j9 = ocat(jb9, j9, ",\x22jitter\x22:" as *u8); j9 = onum(jb9, j9, jav[v9])
967 j9 = ocat(jb9, j9, ",\x22floor\x22:" as *u8); j9 = onum(jb9, j9, fwv[v9])
968 j9 = ocat(jb9, j9, ",\x22matseed\x22:" as *u8); j9 = onum(jb9, j9, msv[v9])
969 j9 = ocat(jb9, j9, ",\x22quality\x22:" as *u8); j9 = onum(jb9, j9, q9)
970 j9 = ocat(jb9, j9, "}" as *u8)
971 v9 = v9 + 1
972 }
973 MD_AT_TM = 0
974 MD_AT_JA = 0
975 MD_AT_FW = 0
976 MD_AT_MS = 0
977 write_png(sheet, W9*3, H9*2, "sites/nishifamily/world/glade_sweep.png" as *u8)
978 j9 = ocat(jb9, j9, "],\x22sheet\x22:\x22sites/nishifamily/world/glade_sweep.png (3x2; variant v at column v%3, row v/3; v0=shipped default)\x22,\x22note\x22:\x22knobs: torchmod 0->9 (lower=denser torch pools), jitter 0->25 (amplitude), floor 0=warm 1=cool 2=hot\x22}" as *u8)
979 jb9[j9]=10 as u8
980 sys_write(1, jb9, j9+1)
981 return 0
982 }
983 }
984 if argc >= 2 {
985 let ap: *u8 = argv[1] as *u8
986 if ap[0]==(112 as u8) {
987 if argc < 3 {
988 let eu: *u8 = "{\x22organ\x22:\x22nx_m2d_engine\x22,\x22error\x22:\x22play needs a move script (a/d/w/s/p)\x22,\x22fix\x22:\x22use: play ddss... -- or run the ELF directly in a terminal with: tty\x22}\x0a" as *u8
989 var en: i64=0
990 while eu[en]!=(0 as u8) { en=en+1 }
991 sys_write(1, eu, en)
992 return 2
993 }
994 let stack0: *i64 = sys_mmap(MD_DW*MD_DH*2*8) as *i64
995 pg_maze(grid, MD_DW, MD_DH, MD_SEED, stack0)
996 return md_play(grid, argv[2] as *u8)
997 }
998 if ap[0]==(116 as u8) { if ap[1]==(116 as u8) {
999 let stack1: *i64 = sys_mmap(MD_DW*MD_DH*2*8) as *i64
1000 pg_maze(grid, MD_DW, MD_DH, MD_SEED, stack1)
1001 return md_play(grid, 0 as *u8)
1002 } }
1003 }
1004
1005 // trace mode: per-tick state of the cautious run, for diagnosing policy/balance
1006 if argc >= 2 {
1007 let a1: *u8 = argv[1] as *u8
1008 if a1[0]==(116 as u8) {
1009 md_init(s, grid, 25)
1010 let ia: *i64 = sys_mmap(IA_NSV*8) as *i64
1011 ia_init(ia, 5)
1012 ia_bind(ia, IA_D_KEY, IA_A_PREV, 37); ia_bind(ia, IA_D_KEY, IA_A_NEXT, 39)
1013 ia_bind(ia, IA_D_KEY, IA_A_CONFIRM, 40); ia_bind(ia, IA_D_KEY, IA_A_PAUSE, 38)
1014 ia_bind(ia, IA_D_KEY, IA_A_CANCEL, 27)
1015 let brng: *i64 = sys_mmap(8) as *i64
1016 brng[0] = MD_SEED
1017 let ob: *u8 = sys_mmap(MD_TRBUF)
1018 var oo: i64 = 0
1019 var tt: i64 = 0
1020 while tt < MD_TRTICKS {
1021 var raw: i64 = 39
1022 if s[MD_F_HP] < 14 { if s[MD_F_POT] > 0 { raw = 27 } }
1023 if raw != 27 { if tt % 7 == 6 { raw = 40 } }
1024 if s[MD_F_KILLS] >= 3 { if tt % 2 == 1 { raw = 40 } }
1025 let act: i64 = ia_feed(ia, IA_D_KEY, raw)
1026 if act >= 0 { md_step(s, grid, act, brng) }
1027 oo = ocat(ob, oo, "t=" as *u8); oo = onum(ob, oo, tt)
1028 oo = ocat(ob, oo, " p=(" as *u8); oo = onum(ob, oo, s[MD_F_PX])
1029 oo = ocat(ob, oo, "," as *u8); oo = onum(ob, oo, s[MD_F_PY])
1030 oo = ocat(ob, oo, ") hp=" as *u8); oo = onum(ob, oo, s[MD_F_HP])
1031 oo = ocat(ob, oo, " kills=" as *u8); oo = onum(ob, oo, s[MD_F_KILLS])
1032 oo = ocat(ob, oo, " e0=(" as *u8); oo = onum(ob, oo, s[MD_O_ENX])
1033 oo = ocat(ob, oo, "," as *u8); oo = onum(ob, oo, s[MD_O_ENY])
1034 oo = ocat(ob, oo, ")hp" as *u8); oo = onum(ob, oo, s[MD_O_ENHP])
1035 oo = ocat(ob, oo, " e1hp" as *u8); oo = onum(ob, oo, s[MD_O_ENHP+1])
1036 oo = ocat(ob, oo, " e2hp" as *u8); oo = onum(ob, oo, s[MD_O_ENHP+2])
1037 oo = ocat(ob, oo, " over=" as *u8); oo = onum(ob, oo, s[MD_F_OVER])
1038 ob[oo]=10 as u8; oo=oo+1
1039 tt = tt + 1
1040 }
1041 sys_write(1, ob, oo)
1042 return 0
1043 }
1044 }
1045
1046 // P1 winnable + P3a chain
1047 let r1: i64 = md_run(s, grid, 0, 25)
1048 let win_ck: i64 = s[MD_F_CK]
1049 let win_lvl: i64 = md_level(s)
1050 let win_hp: i64 = s[MD_F_HP]
1051 let win_kills: i64 = s[MD_F_KILLS]
1052 let p1: i64 = (r1 == 1) as i64
1053
1054 // P3 determinism: replay bit-exact
1055 let s2: *i64 = sys_mmap(MD_NSV*8) as *i64
1056 let r1b: i64 = md_run(s2, grid, 0, 25)
1057 var p3: i64 = 0
1058 if r1b == r1 { if s2[MD_F_CK] == win_ck { p3 = 1 } }
1059
1060 // P2 losable + P6 replay determinism of the LOSS
1061 let s3: *i64 = sys_mmap(MD_NSV*8) as *i64
1062 let r2: i64 = md_run(s3, grid, 1, 25)
1063 let lose_ck: i64 = s3[MD_F_CK]
1064 let lose_tick: i64 = s3[MD_F_TICK]
1065 let p2: i64 = (r2 == 2) as i64
1066 let s4: *i64 = sys_mmap(MD_NSV*8) as *i64
1067 let r2b: i64 = md_run(s4, grid, 1, 25)
1068 var p6: i64 = 0
1069 if p1 == 1 { if p2 == 1 { if r2b == r2 { if s4[MD_F_CK] == lose_ck { p6 = 1 } } } }
1070
1071 // P4 save-transparency: run 20 ticks, save, load, continue 44 -> must equal the unbroken chain.
1072 // (md_run drives 64 IA-fed ticks; here we drive md_step directly with the same action stream.)
1073 let sc: *i64 = sys_mmap(MD_NSV*8) as *i64
1074 md_init(sc, grid, 25)
1075 let br: *i64 = sys_mmap(8) as *i64
1076 br[0] = MD_SEED + 9
1077 var t: i64 = 0
1078 while t < 64 { md_step(sc, grid, (t % 3) % 2, br); t = t + 1 } // PREV/NEXT weave
1079 let unbroken: i64 = sc[MD_F_CK]
1080 let sd: *i64 = sys_mmap(MD_NSV*8) as *i64
1081 md_init(sd, grid, 25)
1082 let br2: *i64 = sys_mmap(8) as *i64
1083 br2[0] = MD_SEED + 9
1084 t = 0
1085 while t < 20 { md_step(sd, grid, (t % 3) % 2, br2); t = t + 1 }
1086 gs_save("knowledge/nx_m2d.sav" as *u8, MD_SCHEMA, sd, MD_NSV, MD_SAVEAT)
1087 let se: *i64 = sys_mmap(MD_NSV*8) as *i64
1088 let meta: *i64 = sys_mmap(8*8) as *i64
1089 let lrc: i64 = gs_load("knowledge/nx_m2d.sav" as *u8, se, MD_NSV, meta)
1090 t = 20
1091 while t < 64 { md_step(se, grid, (t % 3) % 2, br2); t = t + 1 }
1092 var p4: i64 = 0
1093 if lrc == MD_NSV { if se[MD_F_CK] == unbroken { p4 = 1 } }
1094
1095 // P5 the adult gate holds THROUGH the loop: the spring event mid-run
1096 let sa: *i64 = sys_mmap(MD_NSV*8) as *i64
1097 md_run(sa, grid, 0, 25)
1098 let wa: *i64 = (sa as i64 + MD_O_WARD*8) as *i64
1099 let rc_adult: i64 = ws_set(wa, 2, 0) // adult: exposure ALLOWED at the spring
1100 let sm: *i64 = sys_mmap(MD_NSV*8) as *i64
1101 md_run(sm, grid, 0, 16)
1102 let wm: *i64 = (sm as i64 + MD_O_WARD*8) as *i64
1103 let ck_b: i64 = ws_ck(wm)
1104 let rc_minor: i64 = ws_set(wm, 2, 0) // minor: REFUSED, state bit-identical
1105 let ck_a: i64 = ws_ck(wm)
1106 var p5: i64 = 0
1107 if rc_adult == 0 { if rc_minor == WS_E_MINOR { if ck_a == ck_b { p5 = 1 } } }
1108
1109 // P7 rendered frame -> hardened critic; emit NXFH1 for MCP re-grading
1110 let W: i64 = 400
1111 let H: i64 = 240
1112 let fb: *i64 = sys_mmap(W*H*8) as *i64
1113 md_render(s, grid, fb, W, H)
1114 let mets: *i64 = sys_mmap(GC_N*8) as *i64
1115 gc_score(fb, W, H, mets)
1116 let q: i64 = gc_quality(mets)
1117 let p7: i64 = (q >= 300) as i64 // must clear the TOY line; number published
1118 let hx: *u8 = sys_mmap(W*H*6 + 64)
1119 var o: i64 = 0
1120 o = ocat(hx, o, "NXFH1 400 240\x0a" as *u8)
1121 var pi: i64 = 0
1122 while pi < W*H {
1123 let v: i64 = fb[pi]
1124 let r: i64 = v % 256
1125 let g: i64 = (v / 256) % 256
1126 let b: i64 = (v / MD_MAGIC_65536) % 256
1127 hx[o] = hexd(r/16) as u8; hx[o+1] = hexd(r%16) as u8
1128 hx[o+2] = hexd(g/16) as u8; hx[o+3] = hexd(g%16) as u8
1129 hx[o+4] = hexd(b/16) as u8; hx[o+5] = hexd(b%16) as u8
1130 o = o + 6
1131 pi = pi + 1
1132 if pi % W == 0 { hx[o] = 10 as u8; o = o + 1 }
1133 }
1134 let fd: i64 = sys_openat_wr("knowledge/nx_m2d_frame.nxfh" as *u8, 0x1a4)
1135 if fd >= 0 { sys_write(fd, hx, o); sys_fsync(fd); sys_close(fd) }
1136 // publish the SAME frame to the served site (artifact where consumers look; one render, two sinks)
1137 write_png(fb, W, H, "sites/nishifamily/world/nx_m2d_frame.png" as *u8)
1138
1139 // ---- verdict JSON ----
1140 var pass: i64 = p1+p2+p3+p4+p5+p6+p7
1141 let jb: *u8 = sys_mmap(MD_MAGIC_4096)
1142 var j: i64 = 0
1143 j = ocat(jb, j, "{\x22game\x22:\x22nx_m2d_engine (Nishi Glade)\x22,\x22class\x22:\x22TIER-1 top-down action-adventure, the program plan's M2D\x22" as *u8)
1144 j = ocat(jb, j, ",\x22proofs_pass\x22:" as *u8); j = onum(jb, j, pass)
1145 j = ocat(jb, j, ",\x22proofs_total\x22:7" as *u8)
1146 j = ocat(jb, j, ",\x22P1_winnable\x22:" as *u8); j = onum(jb, j, p1)
1147 j = ocat(jb, j, ",\x22P2_losable\x22:" as *u8); j = onum(jb, j, p2)
1148 j = ocat(jb, j, ",\x22P3_deterministic\x22:" as *u8); j = onum(jb, j, p3)
1149 j = ocat(jb, j, ",\x22P4_save_transparent\x22:" as *u8); j = onum(jb, j, p4)
1150 j = ocat(jb, j, ",\x22P5_adult_gate_holds\x22:" as *u8); j = onum(jb, j, p5)
1151 j = ocat(jb, j, ",\x22P6_depth_policies_diverge\x22:" as *u8); j = onum(jb, j, p6)
1152 j = ocat(jb, j, ",\x22P7_quality\x22:" as *u8); j = onum(jb, j, q)
1153 j = ocat(jb, j, ",\x22win\x22:{\x22level\x22:" as *u8); j = onum(jb, j, win_lvl)
1154 j = ocat(jb, j, ",\x22hp\x22:" as *u8); j = onum(jb, j, win_hp)
1155 j = ocat(jb, j, ",\x22kills\x22:" as *u8); j = onum(jb, j, win_kills)
1156 j = ocat(jb, j, ",\x22chain\x22:" as *u8); j = onum(jb, j, win_ck)
1157 j = ocat(jb, j, "},\x22loss\x22:{\x22died_tick\x22:" as *u8); j = onum(jb, j, lose_tick)
1158 j = ocat(jb, j, ",\x22chain\x22:" as *u8); j = onum(jb, j, lose_ck)
1159 j = ocat(jb, j, "},\x22parts\x22:\x22worldpipe+procgen+pathfind+creature_battle+rpgstats+loottable+wardrobe_state+input_abstract+gamesave+raster+critic\x22" as *u8)
1160 j = ocat(jb, j, ",\x22frame_evidence\x22:\x22knowledge/nx_m2d_frame.nxfh (re-gradable by nx_frame_score over MCP)\x22" as *u8)
1161 j = ocat(jb, j, ",\x22P7_note\x22:\x22P7 is an anti-vacuity STRUCTURE floor (toy line 300), never a quality rank: a random-squares control scores 628 on the same composite (calibration 2026-08-09)\x22" as *u8)
1162 j = ocat(jb, j, ",\x22honest\x22:\x22vertical slice: mechanics core proven; browser page, content variety and art direction are the NEXT rungs. P7 reports the critic number raw -- the frame must EARN its tier.\x22}" as *u8)
1163 jb[j]=10 as u8
1164 sys_write(1, jb, j+1)
1165 if pass != 7 { return 1 }
1166 return 0
1167}