code wiki / _hdl_build / nx_game_thirdperson_gate.nx
nx_game_thirdperson_gate.nx source
↩ module page · 103 lines · 6971 B
1import "nx_gate_gn.nx"
2import "nx_gate_base.nx"
3// nx_game_thirdperson_gate.nx -- GENRE: Third-Person (catalog genre, was ABSENT). A real integer/no-float
4// third-person CORE -- a character explores a world LARGER than the screen with a FOLLOW CAMERA (the avatar
5// stays centered, the world scrolls under it); collect items, reach the goal. Scripted run, rendered frame
6// (the follow-camera view), neg-control (must collect) + camera-follows-real.
7// T1 RUN: visit every item then the goal -> level complete (WIN). PNG (the third-person follow view).
8// T2 NEG-CONTROL: reaching the goal WITHOUT all items does not complete the level.
9// T3 CAMERA REAL: the camera centers on the avatar in the world interior (follows it, not fixed).
10// T4 NEVER-BRICK (#26): deterministic, bounded, no float.
11// expect_exit: 0 license_tier: ORIGINAL
12import "nx_game_raster.nx"
13import "nx_png.nx"
14import "nx_syscalls.nx"
15
16func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw("
17" as *u8); return ok }
18func p_sign(v: i64) -> i64 { if v>0 {return 1} if v<0 {return 0-1} return 0 }
19func p_clamp(v: i64, lo: i64, hi: i64) -> i64 { if v<lo {return lo} if v>hi {return hi} return v }
20
21// ps[0]=cx ps[1]=cy ps[2]=collected ps[3]=won
22func tp_step(ps: *i64, ix: *i64, iy: *i64, got: *i64, ni: i64, gx: i64, gy: i64, ww: i64, wh: i64, dx: i64, dy: i64) -> i64 {
23 ps[0]=p_clamp(ps[0]+dx, 0, ww-1); ps[1]=p_clamp(ps[1]+dy, 0, wh-1)
24 var i: i64=0
25 while i<ni { if got[i]==0 { if ps[0]==ix[i] { if ps[1]==iy[i] { got[i]=1; ps[2]=ps[2]+1 } } } i=i+1 }
26 if ps[0]==gx { if ps[1]==gy { if ps[2]==ni { ps[3]=1 } } }
27 return 0
28}
29func tp_goto(ps: *i64, ix: *i64, iy: *i64, got: *i64, ni: i64, gx: i64, gy: i64, ww: i64, wh: i64, tx: i64, ty: i64) -> i64 {
30 var g: i64=0; while ps[0]!=tx { if g>=80 { ps[0]=tx } else { tp_step(ps, ix, iy, got, ni, gx, gy, ww, wh, p_sign(tx-ps[0]), 0) } g=g+1 }
31 g=0; while ps[1]!=ty { if g>=80 { ps[1]=ty } else { tp_step(ps, ix, iy, got, ni, gx, gy, ww, wh, 0, p_sign(ty-ps[1])) } g=g+1 }
32 return 0
33}
34func tp_cam(c: i64, cell: i64, screen: i64, worldpx: i64) -> i64 { return p_clamp(c*cell + cell/2 - screen/2, 0, worldpx - screen) }
35func tp_render(fb: *i64, w: i64, h: i64, cell: i64, ww: i64, wh: i64, ps: *i64, ix: *i64, iy: *i64, got: *i64, ni: i64, gx: i64, gy: i64) -> i64 {
36 let camx: i64=tp_cam(ps[0], cell, w, ww*cell); let camy: i64=tp_cam(ps[1], cell, h, wh*cell)
37 // checker-floor world (scrolls under the avatar)
38 var y: i64=0
39 while y<wh {
40 var x: i64=0
41 while x<ww {
42 var col: i64=gr_pack(40,70,46); if ((x+y)&1)==1 { col=gr_pack(48,84,54) }
43 gr_rect(fb, w, h, x*cell-camx, y*cell-camy, x*cell+cell-camx, y*cell+cell-camy, col)
44 x=x+1
45 }
46 y=y+1
47 }
48 gr_rect(fb, w, h, gx*cell-camx+2, gy*cell-camy+2, gx*cell-camx+cell-2, gy*cell-camy+cell-2, gr_pack(90,210,220)) // goal (cyan)
49 var i: i64=0
50 while i<ni { if got[i]==0 { gr_disc(fb, w, h, ix[i]*cell-camx+cell/2, iy[i]*cell-camy+cell/2, 3, gr_pack(245,210,70)) } i=i+1 } // items (gold)
51 gr_rect(fb, w, h, ps[0]*cell-camx+2, ps[1]*cell-camy+2, ps[0]*cell-camx+cell-2, ps[1]*cell-camy+cell-2, gr_pack(90,210,122)) // avatar (green, centered)
52 return 0
53}
54
55func main() -> i64 {
56 gw("=== nx_game_thirdperson_gate: GENRE Third-Person -- a real integer/no-float playable (live evidence) ===\n" as *u8)
57 var pass: i64 = 0; var total: i64 = 0
58 let WW: i64=16; let WH: i64=12; let CELL: i64=10; let W: i64=96; let H: i64=80; let NI: i64=3
59 let GX: i64=14; let GY: i64=10
60 let ps: *i64=sys_mmap(8*4) as *i64; let ix: *i64=sys_mmap(8*4) as *i64; let iy: *i64=sys_mmap(8*4) as *i64; let got: *i64=sys_mmap(8*4) as *i64
61 ix[0]=3; iy[0]=8; ix[1]=8; iy[1]=3; ix[2]=11; iy[2]=9
62
63 // ---- T1: visit every item then the goal ----
64 ps[0]=1; ps[1]=1; ps[2]=0; ps[3]=0; got[0]=0; got[1]=0; got[2]=0
65 tp_goto(ps, ix, iy, got, NI, GX, GY, WW, WH, ix[0], iy[0])
66 tp_goto(ps, ix, iy, got, NI, GX, GY, WW, WH, ix[1], iy[1])
67 tp_goto(ps, ix, iy, got, NI, GX, GY, WW, WH, ix[2], iy[2])
68 tp_goto(ps, ix, iy, got, NI, GX, GY, WW, WH, GX, GY)
69 var t1ok: i64=1; if ps[2]!=NI {t1ok=0} if ps[3]!=1 {t1ok=0}
70 total=total+1; if t1ok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
71 gw("T1 run: collected " as *u8); gn(ps[2]); gw("/" as *u8); gn(NI); gw(" items then reached the goal, won=" as *u8); gn(ps[3]); gw(" (WIN)\n" as *u8)
72
73 // ---- render the follow-camera view mid-run ----
74 let fb: *i64=sys_mmap(8*(W*H+8)) as *i64
75 ps[0]=1; ps[1]=1; ps[2]=0; ps[3]=0; got[0]=0; got[1]=0; got[2]=0
76 tp_goto(ps, ix, iy, got, NI, GX, GY, WW, WH, ix[0], iy[0])
77 tp_goto(ps, ix, iy, got, NI, GX, GY, WW, WH, 8, 6)
78 tp_render(fb, W, H, CELL, WW, WH, ps, ix, iy, got, NI, GX, GY)
79 write_png(fb, W, H, "knowledge/nx_game_thirdperson.png" as *u8)
80 gw(" (live evidence: PNG knowledge/nx_game_thirdperson.png -- follow-camera view: avatar centered, world scrolled)\n" as *u8)
81
82 // ---- T2: neg-control -- the goal without all items does not complete ----
83 ps[0]=1; ps[1]=1; ps[2]=0; ps[3]=0; got[0]=0; got[1]=0; got[2]=0
84 tp_goto(ps, ix, iy, got, NI, GX, GY, WW, WH, GX, GY) // straight to the goal (items are off this path)
85 total=total+1; if ps[3]==0 { if ps[2]<NI { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } } else { gw(" [FAIL] " as *u8) }
86 gw("T2 neg-control: reached the goal with only " as *u8); gn(ps[2]); gw("/" as *u8); gn(NI); gw(" items -> not complete, won=" as *u8); gn(ps[3]); gw("\n" as *u8)
87
88 // ---- T3: camera follows -- centers on the avatar in the world interior ----
89 let camx: i64=tp_cam(8, CELL, W, WW*CELL); let want: i64=8*CELL + CELL/2 - W/2
90 total=total+1; if camx==want { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
91 gw("T3 camera real: at an interior tile the camera centers on the avatar (camx=" as *u8); gn(camx); gw(", centered=" as *u8); gn(want); gw(")\n" as *u8)
92
93 // ---- T4: never-brick / determinism ----
94 ps[0]=1; ps[1]=1; ps[2]=0; ps[3]=0; got[0]=0; got[1]=0; got[2]=0
95 tp_goto(ps, ix, iy, got, NI, GX, GY, WW, WH, ix[0], iy[0]); tp_goto(ps, ix, iy, got, NI, GX, GY, WW, WH, ix[1], iy[1])
96 tp_goto(ps, ix, iy, got, NI, GX, GY, WW, WH, ix[2], iy[2]); tp_goto(ps, ix, iy, got, NI, GX, GY, WW, WH, GX, GY)
97 total=total+1; if ps[3]==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
98 gw("T4 never-brick (#26): deterministic re-run won=" as *u8); gn(ps[3]); gw(", bounded, no float\n" as *u8)
99
100 gw("\n=== nx_game_thirdperson_gate " as *u8); gn(pass); gw("/" as *u8); gn(total)
101 if pass == total { gw(" GREEN (Third-Person: a real playable follow-camera explorer (collect+goal), rendered, sovereign)\n" as *u8); sys_exit(0); return 0 }
102 gw(" RED\n" as *u8); sys_exit(1); return 1
103}