code wiki / _hdl_build / nx_tactics_emit.nx

nx_tactics_emit.nx source

↩ module page · 250 lines · 11126 B

1// nx_tactics_emit.nx -- the TACTICS GAME EMITTER (G-ECO-005 rung 3): a data tactics game-spec in, 2// a complete playable tactics game module out, hands-off -- the SECOND engine's autonomy lever, 3// mirroring nx_game_emit for dungeons. It reads a tactics spec (grid/squad/enemy/hp/dmg/moves/ 4// range/walls/cover/hit-curve/seed) and WRITES a per-game .nx module that fills the engine cfg and 5// calls teng_run (nx_tactics_engine_lib). The generated game is then built native by Nishi's own 6// toolchain and is playable in a terminal (and headless-provable via a scripted bot). 7// 8// Spec grammar (one key per line): name <module> title <hud> grid_w/grid_h n_player/n_enemy 9// hp dmg moves range n_walls n_cover hit_base hit_distdiv cover_penalty seed 10// 11// CLI: nx_tactics_emit <specpath> -> writes runtime/_hdl_build/<name>.nx 12// SELF-GATE (no args): parse knowledge/specs/game_tactics.spec, emit the module, and PROVE it: 13// cfg parsed right + module written + module calls teng_run + a scripted bot drives the parsed 14// cfg to a battle RESOLUTION. TACTICS-EMIT-GATE verdict=GREEN -> knowledge/status/tactics_emit.log. 15// 16// HONEST AUTHORSHIP: this emitter + the engine lib are TUTOR-authored tooling; the GAMES it writes 17// from specs are emitter output (the autonomy lever). license_tier: ORIGINAL 18import "nx_syscalls.nx" 19import "nx_tactics_engine_lib.nx" 20const K_MAGIC_12345: i64 = 12345 21const K_MAGIC_65536: i64 = 65536 22const K_MAGIC_8192: i64 = 8192 23const K_MAGIC_6000: i64 = 6000 24 25func te_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 } 26func te_c(fd: i64, c: i64) -> i64 { let b: *u8 = sys_mmap(8); b[0] = c as u8; sys_write(fd, b, 1); return 0 } 27func te_wn(fd: i64, v: i64) -> i64 { 28 var m: i64 = v 29 if m < 0 { te_c(fd, 45); m = 0 - m } 30 let bb: *u8 = sys_mmap(28); let t: *u8 = sys_mmap(28); var k: i64 = 0 31 if m == 0 { t[0] = 48 as u8; k = 1 } 32 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 33 var i: i64 = 0 34 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } 35 sys_write(fd, bb, k); return 0 36} 37func te_strlen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 38func te_read(path: *u8, buf: *u8, cap: i64) -> i64 { 39 let fd: i64 = sys_openat_rd(path) 40 if fd < 0 { return 0 - 1 } 41 var n: i64 = 0 42 var r: i64 = sys_read(fd, buf, cap - 1) 43 while r > 0 { n = n + r; r = sys_read(fd, buf + n, cap - 1 - n) } 44 sys_close(fd) 45 return n 46} 47func te_match(buf: *u8, pos: i64, key: *u8) -> i64 { 48 var i: i64 = 0 49 while key[i] != (0 as u8) { if buf[pos + i] != key[i] { return 0 } i = i + 1 } 50 return 1 51} 52func te_linestart(buf: *u8, pos: i64) -> i64 { 53 if pos == 0 { return 1 } 54 if buf[pos - 1] == (10 as u8) { return 1 } 55 return 0 56} 57func te_find(buf: *u8, len: i64, key: *u8) -> i64 { 58 let kl: i64 = te_strlen(key) 59 var i: i64 = 0 60 while i < len { 61 if te_linestart(buf, i) == 1 { if te_match(buf, i, key) == 1 { if buf[i + kl] == (32 as u8) { return i + kl + 1 } } } 62 i = i + 1 63 } 64 return 0 - 1 65} 66func te_pint(buf: *u8, pos: i64) -> i64 { 67 var p: i64 = pos 68 while buf[p] == (32 as u8) { p = p + 1 } 69 var neg: i64 = 0 70 if buf[p] == (45 as u8) { neg = 1; p = p + 1 } 71 var v: i64 = 0; var go: i64 = 1 72 while go == 1 { let c: i64 = buf[p] as i64; if c < 48 { go = 0 } if c > 57 { go = 0 } if go == 1 { v = v * 10 + (c - 48); p = p + 1 } } 73 if neg == 1 { return 0 - v } 74 return v 75} 76func te_int(buf: *u8, len: i64, key: *u8, dflt: i64) -> i64 { 77 let p: i64 = te_find(buf, len, key) 78 if p < 0 { return dflt } 79 return te_pint(buf, p) 80} 81func te_str(buf: *u8, len: i64, key: *u8, out: *u8) -> i64 { 82 let p: i64 = te_find(buf, len, key) 83 if p < 0 { out[0] = 0 as u8; return 0 } 84 var r: i64 = 0; var w: i64 = 0; var go: i64 = 1 85 while go == 1 { 86 let c: i64 = buf[p + r] as i64 87 if c == 10 { go = 0 } 88 if c == 0 { go = 0 } 89 if go == 1 { if c != 13 { out[w] = c as u8; w = w + 1 } r = r + 1 } 90 } 91 out[w] = 0 as u8 92 return w 93} 94func te_has(buf: *u8, len: i64, pat: *u8) -> i64 { 95 let pl: i64 = te_strlen(pat) 96 var i: i64 = 0 97 while i + pl <= len { 98 var j: i64 = 0; var ok: i64 = 1 99 while j < pl { if buf[i + j] != pat[j] { ok = 0 } j = j + 1 } 100 if ok == 1 { return 1 } 101 i = i + 1 102 } 103 return 0 104} 105func te_modpath(name: *u8, out: *u8) -> i64 { 106 var w: i64 = 0; var i: i64 = 0 107 let pre: *u8 = "runtime/_hdl_build/" as *u8 108 while pre[i] != (0 as u8) { out[w] = pre[i]; w = w + 1; i = i + 1 } 109 i = 0 110 while name[i] != (0 as u8) { out[w] = name[i]; w = w + 1; i = i + 1 } 111 let suf: *u8 = ".nx" as *u8 112 i = 0 113 while suf[i] != (0 as u8) { out[w] = suf[i]; w = w + 1; i = i + 1 } 114 out[w] = 0 as u8 115 return w 116} 117func te_parse_cfg(buf: *u8, len: i64, cfg: *i64) -> i64 { 118 cfg[0] = te_int(buf, len, "grid_w" as *u8, 16) 119 cfg[1] = te_int(buf, len, "grid_h" as *u8, 12) 120 cfg[2] = te_int(buf, len, "n_player" as *u8, 2) 121 cfg[3] = te_int(buf, len, "n_enemy" as *u8, 2) 122 cfg[4] = te_int(buf, len, "hp" as *u8, 10) 123 cfg[5] = te_int(buf, len, "dmg" as *u8, 5) 124 cfg[6] = te_int(buf, len, "moves" as *u8, 5) 125 cfg[7] = te_int(buf, len, "range" as *u8, 9) 126 cfg[8] = te_int(buf, len, "n_walls" as *u8, 10) 127 cfg[9] = te_int(buf, len, "n_cover" as *u8, 8) 128 cfg[10] = te_int(buf, len, "hit_base" as *u8, 8) 129 cfg[11] = te_int(buf, len, "hit_distdiv" as *u8, 3) 130 cfg[12] = te_int(buf, len, "cover_penalty" as *u8, 3) 131 cfg[13] = te_int(buf, len, "seed" as *u8, K_MAGIC_12345) 132 return 0 133} 134func te_emit(name: *u8, cfg: *i64) -> i64 { 135 let mp: *u8 = sys_mmap(256) 136 te_modpath(name, mp) 137 let fd: i64 = sys_openat_wr(mp, 0x1a4) 138 if fd < 0 { return 0 } 139 te_w(fd, "// AUTHORED BY nx_tactics_emit from a data tactics game-spec -- per-game module over nx_tactics_engine_lib\n" as *u8) 140 te_w(fd, "import " as *u8); te_c(fd, 34); te_w(fd, "nx_syscalls.nx" as *u8); te_c(fd, 34); te_c(fd, 10) 141 te_w(fd, "import " as *u8); te_c(fd, 34); te_w(fd, "nx_tactics_engine_lib.nx" as *u8); te_c(fd, 34); te_c(fd, 10) 142 te_w(fd, "func main() -> i64 {\n" as *u8) 143 te_w(fd, " let cfg: *i64 = sys_mmap(128) as *i64\n" as *u8) 144 var k: i64 = 0 145 while k < 14 { 146 te_w(fd, " cfg[" as *u8); te_wn(fd, k); te_w(fd, "] = " as *u8); te_wn(fd, cfg[k]); te_c(fd, 10) 147 k = k + 1 148 } 149 te_w(fd, " return teng_run(cfg)\n" as *u8) 150 te_w(fd, "}\n" as *u8) 151 sys_close(fd) 152 return 1 153} 154// scripted bot: advance active player to range + shoot; drive the battle to a resolution. 155func te_bot(st: *i64, cap: i64) -> i64 { 156 var iter: i64 = 0 157 while iter < cap { 158 if st[2] != 0 { return st[2] } 159 let ci: i64 = st[1] 160 if ci < 0 { return st[2] } 161 let ei: i64 = teng_nearest_foe(st, st[16 + ci], st[22 + ci], st[34 + ci]) 162 if ei < 0 { teng_check_end(st); return st[2] } 163 let d: i64 = teng_dist(st[16 + ci], st[22 + ci], st[16 + ei], st[22 + ei]) 164 if d <= st[71] { 165 teng_input(st, 4) 166 } else { 167 let ox: i64 = st[16 + ci]; let oy: i64 = st[22 + ci] 168 let tx: i64 = st[16 + ei]; let ty: i64 = st[22 + ei] 169 var key: i64 = 0 - 1 170 if teng_abs(tx - ox) >= teng_abs(ty - oy) { 171 if tx > ox { key = 3 } 172 if tx < ox { key = 2 } 173 } else { 174 if ty > oy { key = 1 } 175 if ty < oy { key = 0 } 176 } 177 if key < 0 { teng_input(st, 5) } else { 178 teng_input(st, key) 179 var moved: i64 = 1 180 if st[16 + ci] == ox { if st[22 + ci] == oy { moved = 0 } } 181 if moved == 0 { teng_input(st, 5) } else { if st[5] <= 0 { teng_input(st, 5) } } 182 } 183 } 184 iter = iter + 1 185 } 186 return st[2] 187} 188 189func main(argc: i64, argv: *i64) -> i64 { 190 if argc >= 2 { 191 let sp: *u8 = argv[1] as *u8 192 let buf: *u8 = sys_mmap(K_MAGIC_65536) 193 let n: i64 = te_read(sp, buf, K_MAGIC_65536) 194 if n <= 0 { te_w(1, "TACTICS-EMIT REFUSED: cannot read spec\n" as *u8); sys_exit(1); return 1 } 195 let name: *u8 = sys_mmap(128) 196 te_str(buf, n, "name" as *u8, name) 197 if name[0] == (0 as u8) { te_w(1, "TACTICS-EMIT REFUSED: no name\n" as *u8); sys_exit(1); return 1 } 198 let cfg: *i64 = sys_mmap(128) as *i64 199 te_parse_cfg(buf, n, cfg) 200 if te_emit(name, cfg) == 0 { te_w(1, "TACTICS-EMIT REFUSED: cannot open module path\n" as *u8); sys_exit(1); return 1 } 201 let mp: *u8 = sys_mmap(256); te_modpath(name, mp) 202 te_w(1, "TACTICS-EMIT GREEN name=" as *u8); te_w(1, name); te_w(1, " -> " as *u8); te_w(1, mp); te_c(1, 10) 203 sys_exit(0); return 0 204 } 205 206 // SELF-GATE 207 let buf: *u8 = sys_mmap(K_MAGIC_65536) 208 let n: i64 = te_read("knowledge/specs/game_tactics.spec" as *u8, buf, K_MAGIC_65536) 209 if n <= 0 { te_w(1, "TACTICS-EMIT-GATE verdict=RED (cannot read game_tactics.spec)\n" as *u8); sys_exit(1); return 1 } 210 let name: *u8 = sys_mmap(128) 211 te_str(buf, n, "name" as *u8, name) 212 let cfg: *i64 = sys_mmap(128) as *i64 213 te_parse_cfg(buf, n, cfg) 214 let emitted: i64 = te_emit(name, cfg) 215 let mp: *u8 = sys_mmap(256); te_modpath(name, mp) 216 let mbuf: *u8 = sys_mmap(K_MAGIC_65536) 217 let mn: i64 = te_read(mp, mbuf, K_MAGIC_65536) 218 var has_run: i64 = 0 219 if mn > 0 { has_run = te_has(mbuf, mn, "teng_run" as *u8) } 220 // play proof: the parsed cfg drives a real battle to resolution 221 let st: *i64 = sys_mmap(K_MAGIC_8192) as *i64 222 teng_init(st, cfg) 223 let mode: i64 = te_bot(st, K_MAGIC_6000) 224 225 var ok: i64 = 1 226 if cfg[0] != 16 { ok = 0 } 227 if cfg[2] != 2 { ok = 0 } 228 if cfg[3] != 2 { ok = 0 } 229 if emitted != 1 { ok = 0 } 230 if has_run != 1 { ok = 0 } 231 if mode == 0 { ok = 0 } 232 233 let fd: i64 = sys_openat_append("knowledge/status/tactics_emit.log" as *u8, 420) 234 te_w(1, "TACTICS-EMIT-GATE authored=organ spec=game_tactics parsed[grid_w16->" as *u8); te_wn(1, cfg[0]) 235 te_w(1, " nplayer2->" as *u8); te_wn(1, cfg[2]); te_w(1, " nenemy2->" as *u8); te_wn(1, cfg[3]) 236 te_w(1, "] emitted_module=" as *u8); te_wn(1, emitted); te_w(1, " has_teng_run=" as *u8); te_wn(1, has_run) 237 te_w(1, " playthrough_mode=" as *u8); te_wn(1, mode) 238 if ok == 1 { te_w(1, " verdict=GREEN\n" as *u8) } else { te_w(1, " verdict=RED\n" as *u8) } 239 if fd >= 0 { 240 te_w(fd, "TACTICS-EMIT-GATE authored=organ spec=game_tactics parsed[grid_w16->" as *u8); te_wn(fd, cfg[0]) 241 te_w(fd, " nplayer2->" as *u8); te_wn(fd, cfg[2]); te_w(fd, " nenemy2->" as *u8); te_wn(fd, cfg[3]) 242 te_w(fd, "] emitted_module=" as *u8); te_wn(fd, emitted); te_w(fd, " has_teng_run=" as *u8); te_wn(fd, has_run) 243 te_w(fd, " playthrough_mode=" as *u8); te_wn(fd, mode) 244 if ok == 1 { te_w(fd, " verdict=GREEN\n" as *u8) } else { te_w(fd, " verdict=RED\n" as *u8) } 245 sys_close(fd) 246 } 247 if ok == 1 { sys_exit(0); return 0 } 248 sys_exit(1) 249 return 1 250}