nx_wasm_city.nx source
↩ module page · 140 lines · 5956 B
1// nx_wasm_city.nx -- BROWSER-PLAYABLE sovereign City-Building: BASE-RELATIVE integer core, runs native (-> PNG)
2// AND in the browser (base = 0). NO float, NO JS logic, NO canvas drawing. CLICK a toolbar button to pick a
3// building, CLICK the grid to place it (costs gold): farms make food, houses raise population capacity, and
4// population grows when fed; markets make gold. Balance food vs houses vs markets to grow the city. Uses the
5// click(x,y) export. init()/tick(input)/render()/score()/ww()/hh()/fb_off()/click(x,y) = the wasm interface.
6// license_tier: ORIGINAL
7import "nx_nishi_font_core.nx"
8const W: i64 = 200
9const H: i64 = 170
10const GW: i64 = 10
11const GH: i64 = 7
12const CELL: i64 = 20
13const GY0: i64 = 24 // grid top (toolbar above)
14const TOOLH: i64 = 22
15const ECON: i64 = 30 // economy ticks
16const HCOST: i64 = 10
17const FCOST: i64 = 8
18const MCOST: i64 = 12
19const O_FB: i64 = 0 // framebuffer W*H i64
20const O_MAP: i64 = 272000 // map[GW*GH]: 0 empty,1 house,2 farm,3 market (W*H*8)
21const O_ST: i64 = 272560 // scalars[16]: 0=gold 1=food 2=pop 3=sel 4=tick 5=nhouse 6=nfarm 7=nmarket
22const O_MSK: i64 = 272688
23const O_STR: i64 = 280880
24
25func rgb(r: i64, g: i64, b: i64) -> i64 { return (r & 255) | ((g & 255) << 8) | ((b & 255) << 16) }
26
27func fillr(base: i64, x0: i64, y0: i64, x1: i64, y1: i64, c: i64) -> i64 {
28 let fb: *i64 = (base + O_FB) as *i64
29 var yy: i64 = y0; if yy < 0 { yy = 0 }
30 var ye: i64 = y1; if ye > H { ye = H }
31 while yy < ye {
32 var xx: i64 = x0; if xx < 0 { xx = 0 }
33 var xe: i64 = x1; if xe > W { xe = W }
34 while xx < xe { fb[yy*W + xx] = c; xx = xx + 1 }
35 yy = yy + 1
36 }
37 return 0
38}
39func bcolor(typ: i64) -> i64 {
40 if typ == 1 { return rgb(80, 130, 220) } // house blue
41 if typ == 2 { return rgb(90, 200, 110) } // farm green
42 return rgb(235, 200, 80) // market gold
43}
44func bcost(typ: i64) -> i64 { if typ == 1 { return HCOST } if typ == 2 { return FCOST } return MCOST }
45
46func init_impl(base: i64) -> i64 {
47 let mp: *i64 = (base + O_MAP) as *i64
48 let st: *i64 = (base + O_ST) as *i64
49 var i: i64 = 0; while i < GW*GH { mp[i] = 0; i = i + 1 }
50 st[0] = 50; st[1] = 15; st[2] = 0; st[3] = 2; st[4] = 0; st[5] = 0; st[6] = 0; st[7] = 0
51 return 0
52}
53
54func click_impl(base: i64, x: i64, y: i64) -> i64 {
55 let mp: *i64 = (base + O_MAP) as *i64
56 let st: *i64 = (base + O_ST) as *i64
57 if y < TOOLH {
58 if x < 20 { st[3] = 1 } else { if x < 40 { st[3] = 2 } else { if x < 60 { st[3] = 3 } } }
59 return 0
60 }
61 let gx: i64 = x / CELL
62 let gy: i64 = (y - GY0) / CELL
63 if gx < 0 { return 0 } if gy < 0 { return 0 } if gx >= GW { return 0 } if gy >= GH { return 0 }
64 if mp[gy*GW + gx] != 0 { return 0 }
65 let typ: i64 = st[3]
66 let cost: i64 = bcost(typ)
67 if st[0] < cost { return 0 }
68 mp[gy*GW + gx] = typ; st[0] = st[0] - cost
69 if typ == 1 { st[5] = st[5] + 1 } else { if typ == 2 { st[6] = st[6] + 1 } else { st[7] = st[7] + 1 } }
70 return 0
71}
72
73func tick_impl(base: i64, input: i64) -> i64 {
74 let st: *i64 = (base + O_ST) as *i64
75 st[4] = st[4] + 1
76 if (st[4] % ECON) == 0 {
77 st[1] = st[1] + st[6]*3 - st[2] // food += farms*3 - population eats
78 if st[1] < 0 { st[1] = 0 }
79 let cap: i64 = st[5]*4 // house capacity
80 if st[1] > 0 { if st[2] < cap { st[2] = st[2] + 1; st[1] = st[1] - 1 } }
81 st[0] = st[0] + st[7]*2 // gold += markets*2
82 }
83 return 0
84}
85
86func num(base: i64, x: i64, off: i64, val: i64, col: i64) -> i64 {
87 let fb: *i64 = (base + O_FB) as *i64
88 let sbuf: *u8 = (base + O_STR + off) as *u8
89 var slen: i64 = 0; var sv: i64 = val
90 if sv <= 0 { sbuf[0] = 48 as u8; slen = 1 } else {
91 let tmp: *u8 = (base + O_STR + off + 12) as *u8; var k: i64 = 0
92 while sv > 0 { tmp[k] = (48 + (sv % 10)) as u8; sv = sv / 10; k = k + 1 }
93 var q: i64 = 0; while q < k { sbuf[q] = tmp[k - 1 - q]; q = q + 1 }
94 slen = k
95 }
96 let mask: *u8 = (base + O_MSK) as *u8
97 nf_draw_text_mem(fb, W, H, mask, x, 4, 16, sbuf, slen, col)
98 return 0
99}
100func render_impl(base: i64) -> i64 {
101 let fb: *i64 = (base + O_FB) as *i64
102 let mp: *i64 = (base + O_MAP) as *i64
103 let st: *i64 = (base + O_ST) as *i64
104 var p: i64 = 0; while p < W*H { fb[p] = rgb(30, 40, 34); p = p + 1 }
105 // toolbar
106 fillr(base, 0, 0, W, TOOLH, rgb(20, 26, 24))
107 var b: i64 = 1
108 while b <= 3 {
109 let bx: i64 = (b-1)*20
110 fillr(base, bx+2, 3, bx+18, 19, bcolor(b))
111 if st[3] == b { fillr(base, bx+1, 1, bx+19, 2, rgb(240,240,255)); fillr(base, bx+1, 20, bx+19, 21, rgb(240,240,255)); fillr(base, bx+1, 1, bx+2, 21, rgb(240,240,255)); fillr(base, bx+18, 1, bx+19, 21, rgb(240,240,255)) }
112 b = b + 1
113 }
114 num(base, 70, 0, st[0], rgb(235,200,80)) // gold
115 num(base, 120, 32, st[1], rgb(90,200,110)) // food
116 num(base, 165, 64, st[2], rgb(235,240,250)) // population
117 // grid
118 var gy: i64 = 0
119 while gy < GH {
120 var gx: i64 = 0
121 while gx < GW {
122 let cx: i64 = gx*CELL; let cy: i64 = GY0 + gy*CELL
123 fillr(base, cx+1, cy+1, cx+CELL-1, cy+CELL-1, rgb(44, 56, 48))
124 let c: i64 = mp[gy*GW + gx]
125 if c != 0 { fillr(base, cx+3, cy+3, cx+CELL-3, cy+CELL-3, bcolor(c)) }
126 gx = gx + 1
127 }
128 gy = gy + 1
129 }
130 return 0
131}
132
133func init() -> i64 { return init_impl(0) }
134func tick(input: i64) -> i64 { return tick_impl(0, input) }
135func render() -> i64 { return render_impl(0) }
136func click(x: i64, y: i64) -> i64 { return click_impl(0, x, y) }
137func score() -> i64 { let st: *i64 = (0 + O_ST) as *i64; return st[2] }
138func fb_off() -> i64 { return O_FB }
139func ww() -> i64 { return W }
140func hh() -> i64 { return H }