code wiki / _hdl_build / nx_game_session_drive.nx

nx_game_session_drive.nx source

↩ module page · 89 lines · 4007 B

1// nx_game_session_drive.nx -- TUTOR-AUTHORED SCAFFOLD (Claude), NOT emitter output. 2// 3// Binds an emitter-authored game-system FSM (the team's _pe_*) to the game-engine 4// SUBSTRATE (tissue world + 1bpp framebuffer + input) and runs a DETERMINISTIC 5// session: input/event -> FSM step -> render-to-substrate. This closes the first 6// inch of the "unified API" gap that surfaces.tsv names on the game-engine surface 7// (maturity=PARTIAL, gap=unified API): an emitter-authored game-system drives the 8// hardware-floor engine end to end, and the result is gate-verifiable. 9// 10// HONEST AUTHORSHIP (operator law: do not claim tutor work is team work): 11// - The FSMs this drives ARE emitter-authored: _pe_roglrun (new this rung) and 12// _pe_dungenc (DONE), both written by nx_auto_builder from data-only specs. 13// - This driver + its KAT + the gate are TUTOR (Claude) authored TOOLING. 14// - The RUNG that makes THIS binding emitter-authored too -- a GAME_BIND / 15// compose-loop emitter shape so the Builder emits the binding from a spec -- 16// is filed as G-R2 in the game-engine rung ladder. Until then this is a 17// hand-built scaffold, and the autonomy meter correctly does NOT credit it as 18// team self-authoring (METER-INTEGRITY law). 19// 20// LAWS honored: <=6 args/func, flat ifs, no &&/||, integer-only, additive. 21// license_tier: ORIGINAL 22import "nx_tier.nx" 23import "nx_syscalls.nx" 24import "nx_palette.nx" 25import "nx_tissue.nx" 26import "nx_fb_1bpp.nx" 27import "nx_input_gpio.nx" 28import "_pe_roglrun.nx" 29import "_pe_dungenc.nx" 30 31// dispatch to the selected emitter-authored FSM (which: 0=roglrun 1=dungenc). 32// This if-ladder is exactly what a GAME_BIND emitter shape would generate from a 33// spec at G-R2 -- here it is hand-written so the rung-1 binding exists today. 34func gs_step(which: i64, s: i64, e: i64) -> i64 { 35 if which == 0 { return _pe_roglrun_step(s, e) } 36 if which == 1 { return _pe_dungenc_step(s, e) } 37 return 0 - 1 38} 39 40// per-game input scheme: roguelite controls -> roglrun events. 41// UP=start RIGHT=spawn A=clear B=pick DOWN=win LEFT=die 42func gs_btn_to_event_roglrun(btn: i64) -> i64 { 43 if btn == NX_BTN_UP { return 0 } 44 if btn == NX_BTN_RIGHT { return 1 } 45 if btn == NX_BTN_ACTION_A { return 2 } 46 if btn == NX_BTN_ACTION_B { return 3 } 47 if btn == NX_BTN_DOWN { return 4 } 48 if btn == NX_BTN_LEFT { return 5 } 49 return 0 - 1 50} 51 52// render the visited FSM state into the engine substrate (deterministic): 53// - tissue: mark voxel (state, step, 0) with palette idx=state (a session trail) 54// - framebuffer: fill a column of height (state+1) at x=step 55// So the substrate state is a pure function of the FSM-driven session = the binding 56// is real (not a mock), and gate-checkable via count_on / count_nonzero. 57func gs_render(world: *NxTissue, fb: *NxFb1bpp, s: i64, i: i64) -> i64 { 58 nx_tissue_set(world, s, i, 0, s) 59 nx_fb_1bpp_fill_rect(fb, i, 0, 1, s + 1, 1) 60 return 0 61} 62 63// the engine core session loop (FSM-AGNOSTIC): event[] -> FSM step -> render. 64// returns the final state, or -1 if the FSM rejected an event (the liar-kill 65// surface: an illegal transition aborts the session, it never silently continues). 66func gs_session(world: *NxTissue, fb: *NxFb1bpp, ev: *i64, n: i64, which: i64, s0: i64) -> i64 { 67 var s: i64 = s0 68 var i: i64 = 0 69 while i < n { 70 s = gs_step(which, s, ev[i]) 71 if s < 0 { return 0 - 1 } 72 gs_render(world, fb, s, i) 73 i = i + 1 74 } 75 return s 76} 77 78// input-driven variant for roglrun: button[] -> events -> session. 79// This is the full chain a player touches: controls -> game events -> FSM -> 80// engine render, all on the ESP32-class substrate. 81func gs_session_btn_roglrun(world: *NxTissue, fb: *NxFb1bpp, btn: *i64, n: i64, s0: i64) -> i64 { 82 let ev: *i64 = sys_mmap(256) as *i64 83 var i: i64 = 0 84 while i < n { 85 ev[i] = gs_btn_to_event_roglrun(btn[i]) 86 i = i + 1 87 } 88 return gs_session(world, fb, ev, n, 0, s0) 89}