code wiki / _hdl_build / nx_wire_diablo2_gate.nx
nx_wire_diablo2_gate.nx
buildroot/runtime/_hdl_build/nx_wire_diablo2_gate.nx
about
nx_wire_diablo2_gate.nx -- TITLE WIRING #2: Open Diablo II (ARPG). An actual playable hack-and-slash
loop built ONLY from certified parts: procgen act maps seed monster packs (nx_entity_store), every kill
grants XP (nx_rpgstats) and rolls LOOT (nx_loottable) whose affixes EQUIP as stat modifiers
(rs_apply_mods -- order-independent by construction), the act theme renders through nx_gamemusic, and
the whole game state round-trips through nx_gamesave with the GX-9 transparency test.
CAPS EXERCISED (bit = nx_gamebench capability index; the measured mask is payload[0] of the artifact):
bit 10 loot-item-tables bit 9 rpg-stats-progression bit 3 procgen-world
bit 6 entity-component-sim bit 16 audio-sfx-music bit 15 save-load-persistence
bit 18 ui-menus-hud (nx_gamehud: every DROP's equip-or-keep decision goes THROUGH a modal menu --
item 0 carries the tier policy, the RETURNED id drives the equip mutation; HUD binds live
hp/lvl/act/kills/tier per round, render-chain deterministic across replays)
NOT exercised (title requires, loop does not prove): bit 7 pathfinding, bit 0 render-2d,
bit 17 input-realtime -- the board must down-score these for this title.
FLAGSHIP (mutation target): the kill->loot wiring. Skipping the roll must drive the loot tooth RED
(no tiers observed) while the game still plays to a win (anti-vacuity stays GREEN).
DIALECT: no `else if`, no `||`, no multiline `else` -- those DESYNC the nx_cc parser (found by the
NetHack wiring; minimal repro nx_wire_probe.nx aux2). Plain ifs + flag vars only.
license_tier: ORIGINAL expect_exit: 0
dependencies 16 imports · 0 importers
diagram shows first 10 each side; +6 more imports, +0 more importers in the complete lists below.
imports: nx_syscalls.nxnx_gamesave.nxnx_rpgstats.nxnx_entity_store.nxnx_loottable.nxnx_gamemusic.nxnx_audio_wav.nxnx_gamehud.nxnx_game_raster.nxnx_frame_sanity.nxnx_wire_harness.nxnx_gate_verdict.nxnx_pathfind.nxnx_input_abstract.nxnx_trimesh.nxnx_objload.nx
imported by: nobody (leaf or entry point)
structs
| none |
consts
| 40 | const D2_W: i64 = 20 |
| 41 | const D2_H: i64 = 10 |
| 42 | const D2_ACTS: i64 = 3 |
| 43 | const D2_NMON: i64 = 8 |
| 44 | const D2_CAP: i64 = 12 |
| 45 | const D2_NCOMP: i64 = 3 // 0=hp 1=xp_reward 2=packed pos |
| 46 | const D2_CARVE: i64 = 90 |
| 47 | const D2_MAXT: i64 = 400 |
| 49 | const D2_XB: i64 = 20 |
| 50 | const D2_XQ: i64 = 10 |
| 51 | const D2_HPB: i64 = 20 |
| 52 | const D2_HPC: i64 = 2 |
| 53 | const D2_HPL: i64 = 4 |
| 54 | const D2_CON: i64 = 12 |
| 55 | const D2_BDMG: i64 = 8 // base weapon damage before mods |
| 56 | const D2_STRIKERS: i64 = 2 // how many monsters strike back per round |
| 58 | const D2_NTIER: i64 = 4 // normal / magic / rare / unique |
| 59 | const D2_NAFF: i64 = 5 // +dmg / +dmg% / +hp / +hp% / +armor |
| 61 | const D2_HDRN: i64 = 56 // 2026-08-23: grew 48 -> 56 for the wiring-drain fields |
| 62 | const D2_NSV: i64 = 93 // 56 hdr + 1 n + 12*3 monsters |
| 63 | const D2_SCHEMA: i64 = 7338 // schema BUMPED with the header growth (old 7308 saves refuse cleanly) |
| 64 | const D2_ART_SCHEMA: i64 = 7318 |
| 66 | const D2_T1W: i64 = 22 |
| 67 | const D2_T2W: i64 = 46 |
| 69 | const DG_O_GRID: i64 = 64 // 200 cells |
| 70 | const DG_O_CARVE: i64 = 272 // 208 |
| 71 | const DG_O_ENT: i64 = 480 // en_words(12,3)=4+60+36+8=108 pad 112 |
| 72 | const DG_O_HUD: i64 = 640 // nx_gamehud arena (GH_WORDS=64) APPENDED; UI transient, out of the save |
| 75 | const DG_O_PG: i64 = 704 |
| 76 | const DG_O_PF2: i64 = 912 |
| 77 | const DG_O_PCAME: i64 = 1120 |
| 78 | const DG_O_POPEN: i64 = 1328 |
| 79 | const DG_O_PCLOSED: i64 = 1536 |
| 80 | const DG_O_PPATH: i64 = 1744 |
| 81 | const DG_WORDS: i64 = 1952 |
| 82 | const D2_HUDINK: i64 = 50 // min ink px for a non-vacuous HUD frame (T10 guard) |
| 84 | const D_WS: i64 = 0 |
| 85 | const D_ACT: i64 = 1 |
| 86 | const D_TURN: i64 = 2 |
| 87 | const D_XP: i64 = 3 |
| 88 | const D_LVL: i64 = 4 |
| 89 | const D_HP: i64 = 5 |
| 90 | const D_KILLS: i64 = 6 |
| 91 | const D_DROPS: i64 = 7 |
| 92 | const D_T0: i64 = 8 |
| 93 | const D_T1: i64 = 9 |
| 94 | const D_T2: i64 = 10 |
| 95 | const D_T3: i64 = 11 |
| 96 | const D_WIN: i64 = 12 |
| 97 | const D_SPAWNED: i64 = 13 |
| 98 | const D_EQUIPS: i64 = 14 |
| 99 | const D_GENRNG: i64 = 15 |
| 100 | const D_DUPAFF: i64 = 16 // duplicate-affix violations observed (must stay 0) |
| 101 | const D_AFFBAD: i64 = 17 // affix value out of declared range (must stay 0) |
| 102 | const D_WT: i64 = 18 // equipped weapon tier (-1 none) |
| 103 | const D_WNA: i64 = 19 // weapon affix count |
| 104 | const D_WPAIR: i64 = 20 // 6 pairs (affix,val) -> 20..31 |
| 105 | const D_AT: i64 = 32 |
| 106 | const D_ANA: i64 = 33 |
| 107 | const D_APAIR: i64 = 34 // 34..45 |
| 108 | const D_ORDCHK: i64 = 46 // multi-mod drops where fwd/rev order equality was verified |
| 109 | const D_ORDBAD: i64 = 47 // order-dependence violations observed (must stay 0) |
| 112 | const D_PX: i64 = 48 // player x (click-to-move position, pf_astar-driven) |
| 113 | const D_PY: i64 = 49 // player y |
| 114 | const D_PSTEPS: i64 = 50 // A* steps actually walked |
| 115 | const D_PATHBAD: i64 = 51 // path violations observed in-loop (must stay 0) |
| 116 | const D_INEV: i64 = 52 // confirm edges consumed through the F1102 input part |
| 117 | const D_WALKS: i64 = 53 // click-to-move approaches issued |
| 118 | const D_INSCRIPT: i64 = 54 // 1 = input script armed; 0 = control run (nothing can equip) |
| 119 | const D_RES55: i64 = 55 // reserved |
| 500 | const R2_CELL: i64 = 16 |
| 501 | const R2_W: i64 = 320 |
| 502 | const R2_H: i64 = 180 |
functions
| 121 | func ww(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } |
| 122 | func wn(v: i64) -> i64 |
| 131 | func dbit(i: i64) -> i64 { var v: i64=1; var k: i64=0; while k<i { v=v*2; k=k+1 } return v } |
| 132 | func drng(d: *i64) -> i64 |
| 141 | func dckv(ck: i64, v0: i64) -> i64 |
| 147 | func d2_tables(tw: *i64, ta: *i64, aw: *i64, alo: *i64, ahi: *i64) -> i64 |
| 159 | func d2_genact(d: *i64) -> i64 |
| 228 | func d2_new(d: *i64, ws: i64) -> i64 |
| 245 | func d2_wmods(d: *i64, mods: *i64) -> i64 |
| 258 | func d2_amods(d: *i64, mods: *i64) -> i64 |
| 270 | func d2_maxhp(d: *i64) -> i64 |
| 277 | func d2_tick(d: *i64) -> i64 |
| 503 | func d2_render(d: *i64, fb: *i64) -> i64 |
| 535 | func d2_fbck(fb: *i64) -> i64 |
| 540 | func d2_rchain(seed: i64, turns: i64, out: *i64) -> i64 |
| 563 | func d2_hudchain(seed: i64, turns: i64, out: *i64) -> i64 |
| 603 | func d2_run_full(d: *i64) -> i64 |
| 617 | func d2_serialize(d: *i64, S: *i64) -> i64 |
| 639 | func d2_restore(d: *i64, S: *i64) -> i64 |
| 665 | func d2_ck(d: *i64) -> i64 |
| 686 | func d2_song(sng: *i64, k: i64, a2: i64, b2: i64, c2: i64) -> i64 |
| 690 | func d2_render_theme(smp: *i64, nsamp: i64) -> i64 |
| 727 | func d_clearfb(fb: *i64, n: i64, c: i64) -> i64 { var i: i64=0; while i<n { fb[i]=c; i=i+1 } return 0 } |
| 728 | func d_filled(fb: *i64, n: i64, bg: i64) -> i64 { var c: i64=0; var i: i64=0; while i<n { if fb[i]!=bg { c=c+1 } i=i+1 } return c } |
| 729 | func d_fbck(fb: *i64, n: i64) -> i64 { var ck: i64=1469598103; var i: i64=0; while i<n { ck = dckv(ck, fb[i]); i=i+1 } return ck } |
| 731 | func main() -> i64 |