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}