code wiki / (root) / nx_visual_novel_test.nx

nx_visual_novel_test.nx source

↩ module page · 118 lines · 4674 B

1// nx_visual_novel_test.nx -- VN0 KAT: the engine's ops, branching, vars, 2// determinism, and chaos-user invariants, against the demo story whose pc 3// layout is FIXED (asserted here). Exit = failing assertion number; 4// 0 + marker = green. 5// license_tier: ORIGINAL 6import "nx_syscalls.nx" 7import "nx_visual_novel.nx" 8 9func vt_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 10 11func vt_fresh() -> *i64 { return nx_vn_init() } 12 13func main() -> i64 { 14 // 1: fresh state opens on the narrator SAY, not ended, vars zero 15 let s1: *i64 = vt_fresh() 16 if nx_vn_kind(s1) != VN_OP_SAY { return 1 } 17 if nx_vn_ended(s1) != 0 { return 1 } 18 if nx_vn_var(s1, VN_VAR_TEND) != 0 { return 1 } 19 20 // 2: advance walks SAY->SAY->CHOICE (silent ops invisible to the player) 21 if nx_vn_advance(s1) != 1 { return 2 } 22 if nx_vn_kind(s1) != VN_OP_SAY { return 2 } 23 if nx_vn_advance(s1) != 1 { return 2 } 24 if nx_vn_kind(s1) != VN_OP_CHOICE { return 2 } 25 26 // 3: advance on a CHOICE is a no-op (the player must choose) 27 let h3: i64 = nx_vn_state_hash(s1) 28 if nx_vn_advance(s1) != 0 { return 3 } 29 if nx_vn_state_hash(s1) != h3 { return 3 } 30 31 // 4: out-of-range choice is a no-op 32 if nx_vn_choose(s1, 5) != 0 { return 4 } 33 if nx_vn_choose(s1, 0 - 1) != 0 { return 4 } 34 if nx_vn_state_hash(s1) != h3 { return 4 } 35 36 // 5: choice 0 (tomatoes) lands on the KID say at pc 3 (tend still 0 -- 37 // the ADD sits AFTER the say); advancing past it runs ADD+JUMP silently 38 // and lands on the afternoon say with tend=1 39 if nx_vn_choose(s1, 0) != 1 { return 5 } 40 if nx_vn_kind(s1) != VN_OP_SAY { return 5 } 41 if nx_vn_var(s1, VN_VAR_TEND) != 0 { return 5 } 42 if nx_vn_advance(s1) != 1 { return 5 } 43 if nx_vn_kind(s1) != VN_OP_SAY { return 5 } 44 if nx_vn_var(s1, VN_VAR_TEND) != 1 { return 5 } 45 46 // 6: the two branches DIVERGE (different hashes after each choice) 47 let sa: *i64 = vt_fresh() 48 nx_vn_advance(sa) 49 nx_vn_advance(sa) 50 nx_vn_choose(sa, 0) 51 let sb: *i64 = vt_fresh() 52 nx_vn_advance(sb) 53 nx_vn_advance(sb) 54 nx_vn_choose(sb, 1) 55 if nx_vn_state_hash(sa) == nx_vn_state_hash(sb) { return 6 } 56 57 // 7: BLOOM ending -- tend twice (plant + water) -> tend=2 -> happy end 58 let s7: *i64 = vt_fresh() 59 nx_vn_advance(s7) 60 nx_vn_advance(s7) 61 nx_vn_choose(s7, 0) // tomatoes (tend=1) 62 nx_vn_advance(s7) // jump-chain to the afternoon say (pc 9) 63 nx_vn_advance(s7) // -> water choice (pc 10) 64 if nx_vn_kind(s7) != VN_OP_CHOICE { return 7 } 65 nx_vn_choose(s7, 0) // water (tend=2) -> mom say 66 nx_vn_advance(s7) // -> ifgoto -> pc 19 kid say 67 if nx_vn_kind(s7) != VN_OP_SAY { return 7 } 68 nx_vn_advance(s7) // -> END (bloom) 69 if nx_vn_kind(s7) != VN_OP_END { return 7 } 70 if nx_vn_ended(s7) != 1 { return 7 } 71 if nx_vn_var(s7, VN_VAR_TEND) != 2 { return 7 } 72 73 // 8: SPROUT ending -- skip watering -> tend=1 -> modest end at pc 17 74 let s8: *i64 = vt_fresh() 75 nx_vn_advance(s8) 76 nx_vn_advance(s8) 77 nx_vn_choose(s8, 1) // sunflowers (tend=1) 78 nx_vn_advance(s8) 79 nx_vn_advance(s8) 80 nx_vn_choose(s8, 1) // run off and play 81 nx_vn_advance(s8) // narrator dry-ground say -> ifgoto fails -> END at 17 82 if nx_vn_kind(s8) != VN_OP_END { return 8 } 83 if nx_vn_var(s8, VN_VAR_TEND) != 1 { return 8 } 84 85 // 9: the two ENDINGS differ (different epilogue pointers + hashes) 86 if nx_vn_op_field(s7, 1) == nx_vn_op_field(s8, 1) { return 9 } 87 if nx_vn_state_hash(s7) == nx_vn_state_hash(s8) { return 9 } 88 89 // 10: ended story ignores advance + choose (post-game chaos clicks) 90 let h10: i64 = nx_vn_state_hash(s7) 91 if nx_vn_advance(s7) != 0 { return 10 } 92 if nx_vn_choose(s7, 0) != 0 { return 10 } 93 if nx_vn_state_hash(s7) != h10 { return 10 } 94 95 // 11: determinism -- same path twice = identical hash 96 let r1: *i64 = vt_fresh() 97 nx_vn_advance(r1) 98 nx_vn_advance(r1) 99 nx_vn_choose(r1, 0) 100 let r2: *i64 = vt_fresh() 101 nx_vn_advance(r2) 102 nx_vn_advance(r2) 103 nx_vn_choose(r2, 0) 104 if nx_vn_state_hash(r1) != nx_vn_state_hash(r2) { return 11 } 105 106 // 12: action API (the browser entry surface) -- restart resets pristine 107 let s12: *i64 = vt_fresh() 108 let h_fresh: i64 = nx_vn_state_hash(s12) 109 nx_vn_action(s12, 1, 0, 0, 0, 0) 110 nx_vn_action(s12, 1, 0, 0, 0, 0) 111 nx_vn_action(s12, 2, 0, 0, 0, 0) 112 if nx_vn_state_hash(s12) == h_fresh { return 12 } 113 nx_vn_action(s12, 3, 0, 0, 0, 0) 114 if nx_vn_state_hash(s12) != h_fresh { return 12 } 115 116 vt_puts("VN-KAT ALL-PASS\n" as *u8) 117 return 0 118}