code wiki / (root) / nx_wasm_td.nx

nx_wasm_td.nx source

↩ module page · 173 lines · 7261 B

1// nx_wasm_td.nx -- BROWSER-PLAYABLE sovereign Tower-Defence: BASE-RELATIVE integer core, runs native (-> PNG) 2// AND in the browser (base = 0). NO float, NO JS logic, NO canvas drawing. CLICK to place a tower (costs gold) 3// near the lane; towers auto-fire at creeps in range; creeps walk the lane to your base (lose a life if they 4// reach it); kills pay gold; escalating waves. Adds a click(x,y) export (the shim maps a canvas click to game 5// coords). init()/tick(input)/render()/score()/ww()/hh()/fb_off()/click(x,y) = the wasm interface. licen_tier: ORIGINAL 6import "nx_nishi_font_core.nx" 7const W: i64 = 220 8const H: i64 = 140 9const NC: i64 = 6 10const PY: i64 = 78 // lane center y 11const RANGE: i64 = 34 12const DMG: i64 = 3 13const FIRE_CD: i64 = 10 14const SPEED: i64 = 1 15const COST: i64 = 10 16const REWARD: i64 = 4 17const MAXT: i64 = 14 18const O_FB: i64 = 0 // framebuffer W*H i64 19const O_CX: i64 = 246400 // creep x[16] (W*H*8) 20const O_CHP: i64 = 246528 21const O_CA: i64 = 246656 // creep on-field[16] 22const O_TX: i64 = 246784 // tower x[16] 23const O_TY: i64 = 246912 24const O_TC: i64 = 247040 // tower cooldown[16] 25const O_ST: i64 = 247168 // scalars[16]: 0=gold 1=lives 2=wave 3=ntowers 4=tick 5=gameover 26const O_MSK: i64 = 247296 27const O_STR: i64 = 255488 28 29func rgb(r: i64, g: i64, b: i64) -> i64 { return (r & 255) | ((g & 255) << 8) | ((b & 255) << 16) } 30func iabs(v: i64) -> i64 { if v < 0 { return 0 - v } return v } 31 32func fillr(base: i64, x0: i64, y0: i64, x1: i64, y1: i64, c: i64) -> i64 { 33 let fb: *i64 = (base + O_FB) as *i64 34 var yy: i64 = y0; if yy < 0 { yy = 0 } 35 var ye: i64 = y1; if ye > H { ye = H } 36 while yy < ye { 37 var xx: i64 = x0; if xx < 0 { xx = 0 } 38 var xe: i64 = x1; if xe > W { xe = W } 39 while xx < xe { fb[yy*W + xx] = c; xx = xx + 1 } 40 yy = yy + 1 41 } 42 return 0 43} 44func disc(base: i64, cx: i64, cy: i64, rad: i64, c: i64) -> i64 { 45 let fb: *i64 = (base + O_FB) as *i64 46 var dy: i64 = 0 - rad; let r2: i64 = rad*rad 47 while dy <= rad { 48 var dx: i64 = 0 - rad 49 while dx <= rad { 50 if dx*dx + dy*dy <= r2 { let x: i64 = cx+dx; let y: i64 = cy+dy 51 if x >= 0 { if y >= 0 { if x < W { if y < H { fb[y*W + x] = c } } } } } 52 dx = dx + 1 53 } 54 dy = dy + 1 55 } 56 return 0 57} 58 59func spawn_wave(base: i64) -> i64 { 60 let cx: *i64 = (base + O_CX) as *i64 61 let chp: *i64 = (base + O_CHP) as *i64 62 let ca: *i64 = (base + O_CA) as *i64 63 let st: *i64 = (base + O_ST) as *i64 64 var i: i64 = 0 65 while i < NC { cx[i] = 0 - (i*30 + 10); chp[i] = 5 + st[2]*2; ca[i] = 1; i = i + 1 } 66 return 0 67} 68func init_impl(base: i64) -> i64 { 69 let st: *i64 = (base + O_ST) as *i64 70 st[0] = 40; st[1] = 10; st[2] = 1; st[3] = 0; st[4] = 0; st[5] = 0 71 spawn_wave(base) 72 return 0 73} 74 75func click_impl(base: i64, x: i64, y: i64) -> i64 { 76 let tx: *i64 = (base + O_TX) as *i64 77 let ty: *i64 = (base + O_TY) as *i64 78 let tc: *i64 = (base + O_TC) as *i64 79 let st: *i64 = (base + O_ST) as *i64 80 if st[5] == 1 { init_impl(base); return 0 } // click restarts after game over 81 if iabs(y - PY) <= 11 { return 0 } // can't build on the lane 82 if st[3] >= MAXT { return 0 } 83 if st[0] < COST { return 0 } 84 var t: i64 = 0 85 while t < st[3] { if iabs(tx[t]-x) < 16 { if iabs(ty[t]-y) < 16 { return 0 } } t = t + 1 } // occupied 86 tx[st[3]] = x; ty[st[3]] = y; tc[st[3]] = 0; st[3] = st[3] + 1; st[0] = st[0] - COST 87 return 0 88} 89 90func tick_impl(base: i64, input: i64) -> i64 { 91 let cx: *i64 = (base + O_CX) as *i64 92 let chp: *i64 = (base + O_CHP) as *i64 93 let ca: *i64 = (base + O_CA) as *i64 94 let tx: *i64 = (base + O_TX) as *i64 95 let ty: *i64 = (base + O_TY) as *i64 96 let tc: *i64 = (base + O_TC) as *i64 97 let st: *i64 = (base + O_ST) as *i64 98 if st[5] == 1 { return 0 } 99 var t: i64 = 0 100 while t < st[3] { 101 if tc[t] > 0 { tc[t] = tc[t] - 1 } else { 102 var i: i64 = 0; var fired: i64 = 0 103 while i < NC { 104 if fired == 0 { if ca[i] == 1 { if cx[i] >= 0 { 105 let dx: i64 = cx[i] - tx[t]; let dy: i64 = PY - ty[t] 106 if dx*dx + dy*dy < RANGE*RANGE { 107 chp[i] = chp[i] - DMG; tc[t] = FIRE_CD; fired = 1 108 if chp[i] <= 0 { ca[i] = 0; st[0] = st[0] + REWARD } 109 } 110 } } } 111 i = i + 1 112 } 113 } 114 t = t + 1 115 } 116 var j: i64 = 0; var resolved: i64 = 1 117 while j < NC { 118 if ca[j] == 1 { cx[j] = cx[j] + SPEED; if cx[j] >= W { ca[j] = 0; st[1] = st[1] - 1 } else { resolved = 0 } } 119 j = j + 1 120 } 121 if resolved == 1 { st[2] = st[2] + 1; spawn_wave(base) } 122 if st[1] <= 0 { st[5] = 1 } 123 st[4] = st[4] + 1 124 return 0 125} 126 127func hud(base: i64, x: i64, off: i64, val: i64, col: i64) -> i64 { 128 let fb: *i64 = (base + O_FB) as *i64 129 let sbuf: *u8 = (base + O_STR + off) as *u8 130 var slen: i64 = 0; var sv: i64 = val 131 if sv <= 0 { sbuf[0] = 48 as u8; slen = 1 } else { 132 let tmp: *u8 = (base + O_STR + off + 12) as *u8; var k: i64 = 0 133 while sv > 0 { tmp[k] = (48 + (sv % 10)) as u8; sv = sv / 10; k = k + 1 } 134 var q: i64 = 0; while q < k { sbuf[q] = tmp[k - 1 - q]; q = q + 1 } 135 slen = k 136 } 137 let mask: *u8 = (base + O_MSK) as *u8 138 nf_draw_text_mem(fb, W, H, mask, x, 3, 16, sbuf, slen, col) 139 return 0 140} 141func render_impl(base: i64) -> i64 { 142 let fb: *i64 = (base + O_FB) as *i64 143 let cx: *i64 = (base + O_CX) as *i64 144 let chp: *i64 = (base + O_CHP) as *i64 145 let ca: *i64 = (base + O_CA) as *i64 146 let tx: *i64 = (base + O_TX) as *i64 147 let ty: *i64 = (base + O_TY) as *i64 148 let st: *i64 = (base + O_ST) as *i64 149 var p: i64 = 0; while p < W*H { fb[p] = rgb(28, 36, 26); p = p + 1 } 150 fillr(base, 0, PY-9, W, PY+9, rgb(120, 110, 86)) // lane 151 fillr(base, W-9, PY-13, W, PY+13, rgb(90, 200, 120)) // base 152 var t: i64 = 0 153 while t < st[3] { disc(base, tx[t], ty[t], 6, rgb(70, 110, 210)); disc(base, tx[t], ty[t], 2, rgb(160,190,240)); t = t + 1 } 154 var i: i64 = 0 155 while i < NC { if ca[i] == 1 { if cx[i] >= 0 { 156 disc(base, cx[i], PY, 5, rgb(224, 80, 58)) 157 let hpw: i64 = chp[i]; if hpw > 0 { fillr(base, cx[i]-5, PY-9, cx[i]-5+hpw, PY-7, rgb(120,220,120)) } 158 } } i = i + 1 } 159 hud(base, 4, 0, st[0], rgb(245,210,90)) // gold 160 hud(base, 80, 32, st[1], rgb(120,220,150)) // lives 161 hud(base, 150, 64, st[2], rgb(200,200,230)) // wave 162 if st[5] == 1 { fillr(base, 0,0,W,4, rgb(200,40,40)); fillr(base, 0,H-4,W,H, rgb(200,40,40)); fillr(base, 0,0,4,H, rgb(200,40,40)); fillr(base, W-4,0,W,H, rgb(200,40,40)) } 163 return 0 164} 165 166func init() -> i64 { return init_impl(0) } 167func tick(input: i64) -> i64 { return tick_impl(0, input) } 168func render() -> i64 { return render_impl(0) } 169func click(x: i64, y: i64) -> i64 { return click_impl(0, x, y) } 170func score() -> i64 { let st: *i64 = (0 + O_ST) as *i64; return st[2] } 171func fb_off() -> i64 { return O_FB } 172func ww() -> i64 { return W } 173func hh() -> i64 { return H }