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}