code wiki / _hdl_build / nx_game_gen.nx

nx_game_gen.nx source

↩ module page · 133 lines · 5827 B

1// nx_game_gen.nx -- the GENERATIVE game front-end ("mythos level"): a high-level INTENT 2// (theme + difficulty) in, a complete game-SPEC out. This is the top of the Nishi game 3// ecosystem: you author at the description level; nx_game_gen writes the data game-spec, 4// nx_game_emit turns the spec into a per-game module, nx_game_engine_lib runs it native. 5// So the whole chain is: describe -> spec -> playable game, hands-off. 6// 7// usage: nx_game_gen <name> <THEME> <difficulty> 8// name module name, e.g. _game_forest 9// THEME one word, becomes the title "THE <THEME>" 10// difficulty easy | normal | hard | nightmare (scales walls/foes/hp/dmg/loot; 11// hard+ use a NO-FLEE combat FSM = scarier) 12// 13// Writes knowledge/specs/<name>.spec. HONEST: this front-end is TUTOR tooling; the GAME 14// it leads to is emitter output. Difficulty->params is a deterministic design table (no 15// magic numbers buried in logic -- the tiers ARE the data). license_tier: ORIGINAL 16import "nx_syscalls.nx" 17import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc) 18 19func p_w(fd: i64, s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(fd, s, n); return 0 } 20func p_c(fd: i64, c: i64) -> i64 { let b: *u8 = sys_mmap(8); b[0] = c as u8; sys_write(fd, b, 1); return 0 } 21// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer 22// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the 23// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls). 24// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign. 25func p_wn(fd: i64, v: i64) -> i64 { nxi_fd(fd, v); return 0 } 26func streq(a: *u8, b: *u8) -> i64 { 27 var i: i64 = 0 28 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } 29 if b[i] != (0 as u8) { return 0 } 30 return 1 31} 32func sp_kv(fd: i64, key: *u8, val: i64) -> i64 { p_w(fd, key); p_c(fd, 32); p_wn(fd, val); p_c(fd, 10); return 0 } 33 34// difficulty word -> tier 0..3 (default normal=1) 35func tier_of(d: *u8) -> i64 { 36 if streq(d, "easy" as *u8) == 1 { return 0 } 37 if streq(d, "normal" as *u8) == 1 { return 1 } 38 if streq(d, "hard" as *u8) == 1 { return 2 } 39 if streq(d, "nightmare" as *u8) == 1 { return 3 } 40 return 1 41} 42 43func build_spec_path(name: *u8, out: *u8) -> i64 { 44 let pre: *u8 = "knowledge/specs/" as *u8 45 var w: i64 = 0 46 var i: i64 = 0 47 while pre[i] != (0 as u8) { out[w] = pre[i]; w = w + 1; i = i + 1 } 48 i = 0 49 while name[i] != (0 as u8) { out[w] = name[i]; w = w + 1; i = i + 1 } 50 let suf: *u8 = ".spec" as *u8 51 i = 0 52 while suf[i] != (0 as u8) { out[w] = suf[i]; w = w + 1; i = i + 1 } 53 out[w] = 0 as u8 54 return w 55} 56 57func write_fsm(fd: i64, noflee: i64) -> i64 { 58 // dungenc convention table; flee transition (state1,event4 -> 4) removed when noflee 59 let t: *i64 = sys_mmap(512) as *i64 60 var i: i64 = 0 61 while i < 36 { t[i] = 0 - 1; i = i + 1 } 62 t[0 * 6 + 0] = 1 // START --enter--> PLAYER_TURN 63 t[1 * 6 + 1] = 2 // PLAYER --attack--> ENEMY_TURN 64 t[1 * 6 + 3] = 3 // PLAYER --defeat--> WIN 65 t[1 * 6 + 4] = 4 // PLAYER --flee--> FLEE 66 t[2 * 6 + 2] = 1 // ENEMY --enemy_act--> PLAYER_TURN 67 t[3 * 6 + 5] = 5 // WIN --resolve--> END 68 t[4 * 6 + 5] = 5 // FLEE --resolve--> END 69 if noflee == 1 { t[1 * 6 + 4] = 0 - 1 } 70 p_w(fd, "fsm 6 6\n" as *u8) 71 var r: i64 = 0 72 while r < 6 { 73 p_w(fd, "row" as *u8) 74 var c: i64 = 0 75 while c < 6 { p_c(fd, 32); p_wn(fd, t[r * 6 + c]); c = c + 1 } 76 p_c(fd, 10) 77 r = r + 1 78 } 79 return 0 80} 81 82func main(argc: i64, argv: *i64) -> i64 { 83 if argc < 4 { p_w(1, "usage: nx_game_gen <name> <THEME> <difficulty>\n" as *u8); sys_exit(2); return 2 } 84 let name: *u8 = argv[1] as *u8 85 let theme: *u8 = argv[2] as *u8 86 let diff: *u8 = argv[3] as *u8 87 let tier: i64 = tier_of(diff) 88 89 // deterministic difficulty design table (the tiers ARE the data) 90 let walls: i64 = 16 + tier * 6 91 let eb: i64 = 2 + tier 92 let epl: i64 = 1 93 let hb: i64 = 14 + tier * 6 94 let hpl: i64 = 3 + tier 95 var loot: i64 = 4 - tier 96 if loot < 1 { loot = 1 } 97 var db: i64 = 10 - tier 98 if db < 6 { db = 6 } 99 let dr: i64 = 8 100 var noflee: i64 = 0 101 if tier >= 2 { noflee = 1 } 102 103 let path: *u8 = sys_mmap(256) 104 build_spec_path(name, path) 105 let fd: i64 = sys_openat_wr(path, 0x1a4) 106 if fd < 0 { p_w(1, "GAMEGEN REFUSED: cannot open spec path\n" as *u8); sys_exit(1); return 1 } 107 108 p_w(fd, "# generated by nx_game_gen (intent -> spec): theme=" as *u8); p_w(fd, theme) 109 p_w(fd, " difficulty=" as *u8); p_w(fd, diff); p_w(fd, " tier=" as *u8); p_wn(fd, tier); p_c(fd, 10) 110 p_w(fd, "name " as *u8); p_w(fd, name); p_c(fd, 10) 111 p_w(fd, "title THE " as *u8); p_w(fd, theme); p_c(fd, 10) 112 sp_kv(fd, "walls" as *u8, walls) 113 sp_kv(fd, "enemy_base" as *u8, eb) 114 sp_kv(fd, "enemy_per_level" as *u8, epl) 115 sp_kv(fd, "ehp_base" as *u8, hb) 116 sp_kv(fd, "ehp_per_level" as *u8, hpl) 117 sp_kv(fd, "loot" as *u8, loot) 118 sp_kv(fd, "dmg_base" as *u8, db) 119 sp_kv(fd, "dmg_rand" as *u8, dr) 120 p_w(fd, "needs save\n" as *u8) 121 write_fsm(fd, noflee) 122 sys_close(fd) 123 124 p_w(1, "GAMEGEN GREEN name=" as *u8); p_w(1, name) 125 p_w(1, " title=THE " as *u8); p_w(1, theme) 126 p_w(1, " difficulty=" as *u8); p_w(1, diff) 127 p_w(1, " (walls=" as *u8); p_wn(1, walls); p_w(1, " foes=" as *u8); p_wn(1, eb) 128 p_w(1, " ehp=" as *u8); p_wn(1, hb); p_w(1, " noflee=" as *u8); p_wn(1, noflee); p_w(1, ")\n" as *u8) 129 p_w(1, " -> " as *u8); p_w(1, path); p_c(1, 10) 130 p_w(1, " next: nx_game_emit " as *u8); p_w(1, path); p_c(1, 10) 131 sys_exit(0) 132 return 0 133}