code wiki / _hdl_build / nx_game_emit.nx

nx_game_emit.nx source

↩ module page · 290 lines · 11049 B

1// nx_game_emit.nx -- the GAME EMITTER: a data game-spec in, a complete playable game 2// module out, hands-off. This is the autonomous game-gen lever (operator's choice): 3// feed specs -> get games. It reads a game-spec (difficulty/theme/title + the combat 4// FSM transition table) and WRITES a per-game .nx module that fills the engine config + 5// FSM table and calls eng_run (nx_game_engine_lib). The generated game is then built 6// native by Nishi's own toolchain and proven playable by a playthrough gate. 7// 8// Spec grammar (one key per line): 9// name _game_foo module name (-> runtime/_hdl_build/_game_foo.nx) 10// title THE CRYPT HUD title (rest of line) 11// walls 22 interior wall count 12// enemy_base 2 enemies at depth 1 13// enemy_per_level 1 extra enemies per depth 14// ehp_base 18 enemy hp at depth 1 15// ehp_per_level 4 extra enemy hp per depth 16// loot 3 loot pickups per level 17// dmg_base 8 player base damage 18// dmg_rand 8 player random damage span 19// fsm 6 6 combat FSM dims (nstates nevents; dungenc convention) 20// row ... one transition-table row per state (nevents ints, -1=none) 21// 22// HONEST AUTHORSHIP: this emitter + the engine library are TUTOR-authored tooling. The 23// GAMES it writes are emitter output (the autonomy). Usage: nx_game_emit <specpath>. 24// license_tier: ORIGINAL 25import "nx_syscalls.nx" 26const K_MAGIC_2048: i64 = 2048 27 28func 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 } 29func 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 } 30func p_wn(fd: i64, v: i64) -> i64 { 31 var m: i64 = v 32 if m < 0 { p_c(fd, 45); m = 0 - m } 33 let bb: *u8 = sys_mmap(28) 34 let t: *u8 = sys_mmap(28) 35 var k: i64 = 0 36 if m == 0 { t[0] = 48 as u8; k = 1 } 37 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 38 var i: i64 = 0 39 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } 40 sys_write(fd, bb, k) 41 return 0 42} 43 44func gcstr_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 45func gmatch(buf: *u8, pos: i64, key: *u8) -> i64 { 46 var i: i64 = 0 47 while key[i] != (0 as u8) { if buf[pos + i] != key[i] { return 0 } i = i + 1 } 48 return 1 49} 50func gline_start(buf: *u8, pos: i64) -> i64 { 51 if pos == 0 { return 1 } 52 if buf[pos - 1] == (10 as u8) { return 1 } 53 return 0 54} 55func gfind(buf: *u8, len: i64, key: *u8) -> i64 { 56 let kl: i64 = gcstr_len(key) 57 var i: i64 = 0 58 while i < len { 59 if gline_start(buf, i) == 1 { 60 if gmatch(buf, i, key) == 1 { 61 if buf[i + kl] == (32 as u8) { return i + kl + 1 } 62 } 63 } 64 i = i + 1 65 } 66 return 0 - 1 67} 68func gpint(buf: *u8, pos: i64) -> i64 { 69 var p: i64 = pos 70 while buf[p] == (32 as u8) { p = p + 1 } 71 var neg: i64 = 0 72 if buf[p] == (45 as u8) { neg = 1; p = p + 1 } 73 var v: i64 = 0 74 var go: i64 = 1 75 while go == 1 { 76 let c: i64 = buf[p] as i64 77 if c < 48 { go = 0 } 78 if c > 57 { go = 0 } 79 if go == 1 { v = v * 10 + (c - 48); p = p + 1 } 80 } 81 if neg == 1 { return 0 - v } 82 return v 83} 84func gint(buf: *u8, len: i64, key: *u8, dflt: i64) -> i64 { 85 let p: i64 = gfind(buf, len, key) 86 if p < 0 { return dflt } 87 return gpint(buf, p) 88} 89// copy "key <value-to-EOL>" into out (NUL-terminated); returns length 90func gstr(buf: *u8, len: i64, key: *u8, out: *u8) -> i64 { 91 let p: i64 = gfind(buf, len, key) 92 if p < 0 { out[0] = 0 as u8; return 0 } 93 var r: i64 = 0 94 var w: i64 = 0 95 var go: i64 = 1 96 while go == 1 { 97 let c: i64 = buf[p + r] as i64 98 if c == 10 { go = 0 } 99 if c == 0 { go = 0 } 100 if go == 1 { 101 if c != 13 { out[w] = c as u8; w = w + 1 } 102 r = r + 1 103 } 104 } 105 out[w] = 0 as u8 106 return w 107} 108// collect all "row " lines' ints (in order) into tbl; returns count 109func gtable(buf: *u8, len: i64, tbl: *i64) -> i64 { 110 var count: i64 = 0 111 var i: i64 = 0 112 while i < len { 113 if gline_start(buf, i) == 1 { 114 if gmatch(buf, i, "row" as *u8) == 1 { 115 if buf[i + 3] == (32 as u8) { 116 var p: i64 = i + 3 117 var go: i64 = 1 118 while go == 1 { 119 while buf[p] == (32 as u8) { p = p + 1 } 120 let c: i64 = buf[p] as i64 121 if c == 10 { go = 0 } 122 if c == 13 { go = 0 } 123 if c == 0 { go = 0 } 124 if go == 1 { 125 tbl[count] = gpint(buf, p) 126 count = count + 1 127 if buf[p] == (45 as u8) { p = p + 1 } 128 var d: i64 = 1 129 while d == 1 { 130 let cc: i64 = buf[p] as i64 131 if cc < 48 { d = 0 } 132 if cc > 57 { d = 0 } 133 if d == 1 { p = p + 1 } 134 } 135 } 136 } 137 } 138 } 139 } 140 i = i + 1 141 } 142 return count 143} 144 145// parse `needs <part>` lines into a bitmask (bit0=save 1=networking 2=audio 3=accounts) 146func gneeds(buf: *u8, len: i64) -> i64 { 147 var m: i64 = 0 148 var i: i64 = 0 149 while i < len { 150 if gline_start(buf, i) == 1 { 151 if gmatch(buf, i, "needs " as *u8) == 1 { 152 let p: i64 = i + 6 153 if gmatch(buf, p, "save" as *u8) == 1 { m = m | 1 } 154 if gmatch(buf, p, "networking" as *u8) == 1 { m = m | 2 } 155 if gmatch(buf, p, "audio" as *u8) == 1 { m = m | 4 } 156 if gmatch(buf, p, "accounts" as *u8) == 1 { m = m | 8 } 157 } 158 } 159 i = i + 1 160 } 161 return m 162} 163 164func build_path(name: *u8, out: *u8) -> i64 { 165 let pre: *u8 = "runtime/_hdl_build/" as *u8 166 var w: i64 = 0 167 var i: i64 = 0 168 while pre[i] != (0 as u8) { out[w] = pre[i]; w = w + 1; i = i + 1 } 169 i = 0 170 while name[i] != (0 as u8) { out[w] = name[i]; w = w + 1; i = i + 1 } 171 let suf: *u8 = ".nx" as *u8 172 i = 0 173 while suf[i] != (0 as u8) { out[w] = suf[i]; w = w + 1; i = i + 1 } 174 out[w] = 0 as u8 175 return w 176} 177 178func emit_assign(fd: i64, idx: i64, val: i64) -> i64 { 179 p_w(fd, " cfg[" as *u8); p_wn(fd, idx); p_w(fd, "] = " as *u8); p_wn(fd, val); p_w(fd, "\n" as *u8) 180 return 0 181} 182func emit_head(fd: i64) -> i64 { 183 p_w(fd, "// AUTHORED BY nx_game_emit from a data game-spec -- per-game module over nx_game_engine_lib\n" as *u8) 184 p_w(fd, "import " as *u8); p_c(fd, 34); p_w(fd, "nx_syscalls.nx" as *u8); p_c(fd, 34); p_w(fd, "\n" as *u8) 185 p_w(fd, "import " as *u8); p_c(fd, 34); p_w(fd, "nx_game_engine_lib.nx" as *u8); p_c(fd, 34); p_w(fd, "\n" as *u8) 186 p_w(fd, "func main() -> i64 {\n" as *u8) 187 p_w(fd, " let cfg: *i64 = sys_mmap(256) as *i64\n" as *u8) 188 return 0 189} 190func emit_cfg(fd: i64, vals: *i64) -> i64 { 191 emit_assign(fd, 13, vals[0]) 192 emit_assign(fd, 14, vals[1]) 193 emit_assign(fd, 15, vals[2]) 194 emit_assign(fd, 16, vals[3]) 195 emit_assign(fd, 17, vals[4]) 196 emit_assign(fd, 18, vals[5]) 197 emit_assign(fd, 19, vals[6]) 198 emit_assign(fd, 20, vals[7]) 199 return 0 200} 201// wire composed parts: cfg[25]=needs-mask, cfg[26]=save-file path (the parts-composition mechanism) 202func emit_needs(fd: i64, name: *u8, mask: i64) -> i64 { 203 emit_assign(fd, 25, mask) 204 p_w(fd, " cfg[26] = " as *u8); p_c(fd, 34) 205 p_w(fd, "knowledge/store/" as *u8); p_w(fd, name); p_w(fd, ".save" as *u8) 206 p_c(fd, 34); p_w(fd, " as *u8 as i64\n" as *u8) 207 return 0 208} 209func emit_title(fd: i64, title: *u8) -> i64 { 210 p_w(fd, " cfg[21] = " as *u8); p_c(fd, 34); p_w(fd, title); p_c(fd, 34); p_w(fd, " as *u8 as i64\n" as *u8) 211 return 0 212} 213func emit_table(fd: i64, tbl: *i64, n: i64) -> i64 { 214 p_w(fd, " let t: *i64 = sys_mmap(2048) as *i64\n" as *u8) 215 var k: i64 = 0 216 while k < n { 217 p_w(fd, " t[" as *u8); p_wn(fd, k); p_w(fd, "] = " as *u8) 218 let v: i64 = tbl[k] 219 if v < 0 { p_w(fd, "0 - " as *u8); p_wn(fd, 0 - v) } else { p_wn(fd, v) } 220 p_w(fd, "\n" as *u8) 221 k = k + 1 222 } 223 return 0 224} 225func emit_tail(fd: i64, ns: i64, ne: i64) -> i64 { 226 p_w(fd, " cfg[22] = t as i64\n" as *u8) 227 emit_assign(fd, 23, ns) 228 emit_assign(fd, 24, ne) 229 p_w(fd, " return eng_run(cfg)\n" as *u8) 230 p_w(fd, "}\n" as *u8) 231 return 0 232} 233 234func main(argc: i64, argv: *i64) -> i64 { 235 if argc < 2 { p_w(1, "usage: nx_game_emit <specpath>\n" as *u8); sys_exit(2); return 2 } 236 let sp: *u8 = argv[1] as *u8 237 let lenp: *i64 = sys_mmap(16) as *i64 238 let buf: *u8 = sys_read_file(sp, lenp) 239 if buf == (0 as i64) as *u8 { p_w(1, "GAMEEMIT REFUSED: cannot read spec\n" as *u8); sys_exit(1); return 1 } 240 let len: i64 = lenp[0] 241 242 let name: *u8 = sys_mmap(128) 243 let title: *u8 = sys_mmap(128) 244 gstr(buf, len, "name" as *u8, name) 245 gstr(buf, len, "title" as *u8, title) 246 if name[0] == (0 as u8) { p_w(1, "GAMEEMIT REFUSED: no name\n" as *u8); sys_exit(1); return 1 } 247 248 let vals: *i64 = sys_mmap(128) as *i64 249 vals[0] = gint(buf, len, "walls" as *u8, 20) 250 vals[1] = gint(buf, len, "enemy_base" as *u8, 3) 251 vals[2] = gint(buf, len, "enemy_per_level" as *u8, 1) 252 vals[3] = gint(buf, len, "ehp_base" as *u8, 20) 253 vals[4] = gint(buf, len, "ehp_per_level" as *u8, 5) 254 vals[5] = gint(buf, len, "loot" as *u8, 2) 255 vals[6] = gint(buf, len, "dmg_base" as *u8, 8) 256 vals[7] = gint(buf, len, "dmg_rand" as *u8, 8) 257 let ns: i64 = gint(buf, len, "fsm" as *u8, 6) 258 let nep: i64 = gfind(buf, len, "fsm" as *u8) 259 var ne: i64 = 6 260 if nep >= 0 { 261 var q: i64 = nep 262 while buf[q] == (32 as u8) { q = q + 1 } 263 var d: i64 = 1 264 while d == 1 { let c: i64 = buf[q] as i64; if c < 48 { d = 0 } if c > 57 { d = 0 } if d == 1 { q = q + 1 } } 265 ne = gpint(buf, q) 266 } 267 let tbl: *i64 = sys_mmap(K_MAGIC_2048) as *i64 268 let tcount: i64 = gtable(buf, len, tbl) 269 let needs: i64 = gneeds(buf, len) 270 271 let modpath: *u8 = sys_mmap(256) 272 build_path(name, modpath) 273 let fd: i64 = sys_openat_wr(modpath, 0x1a4) 274 if fd < 0 { p_w(1, "GAMEEMIT REFUSED: cannot open module path\n" as *u8); sys_exit(1); return 1 } 275 emit_head(fd) 276 emit_cfg(fd, vals) 277 emit_needs(fd, name, needs) 278 emit_title(fd, title) 279 emit_table(fd, tbl, tcount) 280 emit_tail(fd, ns, ne) 281 sys_close(fd) 282 283 p_w(1, "GAMEEMIT GREEN name=" as *u8); p_w(1, name) 284 p_w(1, " title=" as *u8); p_w(1, title) 285 p_w(1, " fsm=" as *u8); p_wn(1, ns); p_w(1, "x" as *u8); p_wn(1, ne) 286 p_w(1, " tbl=" as *u8); p_wn(1, tcount) 287 p_w(1, " -> " as *u8); p_w(1, modpath); p_w(1, "\n" as *u8) 288 sys_exit(0) 289 return 0 290}