nx_world_state_test.nx source
↩ module page · 148 lines · 6132 B
1// nx_world_state_test.nx -- carry-forward + continuity check.
2
3import "nx_syscalls.nx"
4import "nx_tier.nx"
5import "nx_directors_note.nx"
6import "nx_world_state.nx"
7
8func main() -> nx_int {
9 // ===== Build a world for character #7 (universe 100) ===========
10 let ws: *WorldState = nx_world_alloc(100, 0 - 1, 4, 4)
11 if ws.universe_id != 100 { return 1 }
12 if ws.parent_universe_id != 0 - 1 { return 2 }
13 if ws.character_count != 0 { return 3 }
14 if ws.scene_count != 0 { return 4 }
15
16 let slot: nx_int = nx_world_register_character(ws, 7, 0xCAFE, 9)
17 if slot != 0 { return 5 }
18 if ws.character_count != 1 { return 6 }
19 if nx_world_get_char_field(ws, 7, NX_WS_CHAR_F_IDENTITY_SEED) != 0xCAFE { return 7 }
20 if nx_world_get_char_field(ws, 7, NX_WS_CHAR_F_ARCHETYPE_ID) != 9 { return 8 }
21
22 nx_world_register_location(ws, 100, 0xDEAD)
23 nx_world_register_location(ws, 101, 0xBEEF)
24 if ws.location_count != 2 { return 9 }
25
26 // ===== Scene 1: WAKE_UP in bedroom (loc 100), robe (outfit 200) =
27 //
28 // First scene: character has no prior outfit/location, so any
29 // assignment is legitimate (no continuity to violate yet).
30 let dn1: *DirectorsNote = nx_dn_alloc()
31 dn1.character_id = 7
32 dn1.body_archetype_id = 9
33 dn1.outfit_key_id = 200
34 dn1.location_id = 100
35 dn1.affect_axis = NX_AF_NEUTRAL
36
37 let v1: nx_int = nx_continuity_check(ws, dn1)
38 if v1 != NX_CONT_CONSISTENT { return 10 }
39
40 let c1: nx_int = nx_world_commit_scene(ws, dn1, 420) // 7:00 AM
41 if c1 != NX_CONT_CONSISTENT { return 11 }
42 if ws.day_clock_minutes != 420 { return 12 }
43 if ws.scene_count != 1 { return 13 }
44 if nx_world_get_char_field(ws, 7, NX_WS_CHAR_F_OUTFIT_ID) != 200 { return 14 }
45 if nx_world_get_char_field(ws, 7, NX_WS_CHAR_F_LOCATION_ID) != 100 { return 15 }
46
47 // ===== Scene 2: try to teleport to kitchen WITHOUT story beat ===
48 //
49 // Should flag VIOLATES_LOCATION_TELEPORT because location moved
50 // from 100 -> 101 with no NX_WS_BEAT_LOCATION_CHANGE_OK armed.
51 let dn2: *DirectorsNote = nx_dn_alloc()
52 dn2.character_id = 7
53 dn2.body_archetype_id = 9
54 dn2.outfit_key_id = 200
55 dn2.location_id = 101
56 dn2.affect_axis = NX_AF_NEUTRAL
57
58 let v2: nx_int = nx_continuity_check(ws, dn2)
59 if v2 != NX_CONT_VIOLATES_LOCATION_TELEPORT { return 20 }
60
61 // ===== Arm the location beat, then commit -- now passes =========
62 nx_world_arm_beat(ws, NX_WS_BEAT_LOCATION_CHANGE_OK)
63 let v3: nx_int = nx_continuity_check(ws, dn2)
64 if v3 != NX_CONT_CONSISTENT { return 21 }
65
66 let c2: nx_int = nx_world_commit_scene(ws, dn2, 450)
67 if c2 != NX_CONT_CONSISTENT { return 22 }
68 if ws.pending_beat != NX_WS_BEAT_NONE { return 23 } // beat consumed
69 if ws.scene_count != 2 { return 24 }
70
71 // ===== Scene 3: try outfit change without beat -> violation =====
72 let dn3: *DirectorsNote = nx_dn_alloc()
73 dn3.character_id = 7
74 dn3.body_archetype_id = 9
75 dn3.outfit_key_id = 201 // changed from 200
76 dn3.location_id = 101 // same as scene 2
77 dn3.affect_axis = NX_AF_NEUTRAL
78
79 let v4: nx_int = nx_continuity_check(ws, dn3)
80 if v4 != NX_CONT_VIOLATES_OUTFIT { return 30 }
81
82 // Arm outfit beat, retry, commit
83 nx_world_arm_beat(ws, NX_WS_BEAT_OUTFIT_CHANGE_OK)
84 if nx_continuity_check(ws, dn3) != NX_CONT_CONSISTENT { return 31 }
85 nx_world_commit_scene(ws, dn3, 480)
86 if nx_world_get_char_field(ws, 7, NX_WS_CHAR_F_OUTFIT_ID) != 201 { return 32 }
87
88 // ===== Time reversal blocked ====================================
89 //
90 // Try to commit at a clock earlier than current -> VIOLATES_TIME_REVERSAL.
91 let dn4: *DirectorsNote = nx_dn_alloc()
92 dn4.character_id = 7
93 dn4.body_archetype_id = 9
94 dn4.outfit_key_id = 201
95 dn4.location_id = 101
96 dn4.affect_axis = NX_AF_NEUTRAL
97
98 let c4: nx_int = nx_world_commit_scene(ws, dn4, 400) // earlier than 480
99 if c4 != NX_CONT_VIOLATES_TIME_REVERSAL { return 40 }
100
101 // ===== Character not registered ================================
102 let dn5: *DirectorsNote = nx_dn_alloc()
103 dn5.character_id = 99 // never registered
104 dn5.body_archetype_id = 9
105 dn5.outfit_key_id = 201
106 dn5.location_id = 101
107 let v5: nx_int = nx_continuity_check(ws, dn5)
108 if v5 != NX_CONT_VIOLATES_CHARACTER_ABSENT { return 50 }
109
110 // ===== BOTH beat permits outfit+location simultaneously ========
111 let dn6: *DirectorsNote = nx_dn_alloc()
112 dn6.character_id = 7
113 dn6.body_archetype_id = 9
114 dn6.outfit_key_id = 202 // changed
115 dn6.location_id = 100 // changed
116 dn6.affect_axis = NX_AF_PLAYFUL
117
118 if nx_continuity_check(ws, dn6) != NX_CONT_VIOLATES_OUTFIT { return 60 }
119 nx_world_arm_beat(ws, NX_WS_BEAT_BOTH_OK)
120 if nx_continuity_check(ws, dn6) != NX_CONT_CONSISTENT { return 61 }
121
122 // ===== Multiverse branch =======================================
123 //
124 // Fork at scene 3. Child should inherit chars + locs + clock
125 // but reset scene_count + pending_beat.
126 let child: *WorldState = nx_world_branch(ws, 200)
127 if child.universe_id != 200 { return 70 }
128 if child.parent_universe_id != 100 { return 71 }
129 if child.character_count != ws.character_count { return 72 }
130 if child.location_count != ws.location_count { return 73 }
131 if child.day_clock_minutes != ws.day_clock_minutes { return 74 }
132 if child.scene_count != 0 { return 75 }
133 if child.pending_beat != NX_WS_BEAT_NONE { return 76 }
134
135 // Child's character carry-forward should mirror parent's
136 if nx_world_get_char_field(child, 7, NX_WS_CHAR_F_OUTFIT_ID)
137 != nx_world_get_char_field(ws, 7, NX_WS_CHAR_F_OUTFIT_ID) { return 77 }
138 if nx_world_get_char_field(child, 7, NX_WS_CHAR_F_LOCATION_ID)
139 != nx_world_get_char_field(ws, 7, NX_WS_CHAR_F_LOCATION_ID) { return 78 }
140
141 // Commits to child don't affect parent
142 nx_world_arm_beat(child, NX_WS_BEAT_BOTH_OK)
143 nx_world_commit_scene(child, dn6, child.day_clock_minutes + 30)
144 if child.scene_count != 1 { return 79 }
145 if ws.scene_count != 3 { return 80 } // parent unchanged
146
147 return 0
148}