Skip to content

Commit 9131af2

Browse files
authored
Add files via upload
1 parent f86465f commit 9131af2

File tree

1 file changed

+303
-0
lines changed

1 file changed

+303
-0
lines changed

games/Toxic Zone Survival.js

Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
// Toxic Zone Survival - Sprig Edition (Lowercase-only IDs)
2+
3+
const p = "p"
4+
const t = "t"
5+
const o = "o"
6+
const w = "w"
7+
8+
setLegend(
9+
[p, bitmap`
10+
................
11+
................
12+
.......33.......
13+
......3333......
14+
.....333333.....
15+
....33222333....
16+
....33222333....
17+
.....333333.....
18+
......3333......
19+
.......33.......
20+
................
21+
................
22+
................
23+
................
24+
................
25+
................`],
26+
27+
[t, bitmap`
28+
................
29+
................
30+
....22222222....
31+
...2222222222...
32+
..222222222222..
33+
..222211112222..
34+
..222211112222..
35+
..222222222222..
36+
...2222222222...
37+
....22222222....
38+
................
39+
................
40+
................
41+
................
42+
................
43+
................`],
44+
45+
[o, bitmap`
46+
................
47+
................
48+
.......44.......
49+
......4444......
50+
.....444444.....
51+
......4444......
52+
.......44.......
53+
................
54+
................
55+
................
56+
................
57+
................
58+
................
59+
................
60+
................
61+
................`],
62+
63+
[w, bitmap`
64+
1111111111111111
65+
1111111111111111
66+
1111111111111111
67+
1111111111111111
68+
1111111111111111
69+
1111111111111111
70+
1111111111111111
71+
1111111111111111
72+
1111111111111111
73+
1111111111111111
74+
1111111111111111
75+
1111111111111111
76+
1111111111111111
77+
1111111111111111
78+
1111111111111111
79+
1111111111111111`]
80+
)
81+
82+
setMap(map`
83+
wwwwwwwwwwwwww
84+
w............w
85+
w............w
86+
w............w
87+
w............w
88+
w............w
89+
w............w
90+
w............w
91+
w............w
92+
w............w
93+
wwwwwwwwwwwwww`)
94+
95+
const W = width()
96+
const H = height()
97+
98+
// CONFIG
99+
const cfg = {
100+
tick: 140,
101+
oxyMax: 100,
102+
hpMax: 100,
103+
oxyDrain: 3,
104+
cloudMul: 4,
105+
dmg: 10,
106+
tankOxy: 36,
107+
tankSpawn: 6000,
108+
tankLife: 14000,
109+
cloudSpawn: 4200,
110+
cloudMin: 900,
111+
grow: 0.28
112+
}
113+
114+
let state = "idle"
115+
let pl = { x: Math.floor(W/2), y: Math.floor(H/2), oxy: cfg.oxyMax, hp: cfg.hpMax }
116+
let dir = {x:0,y:0}
117+
let nextDir = null
118+
let clouds = []
119+
let tanks = []
120+
let tickLoop = null
121+
let nextTank = performance.now() + 1000
122+
let nextCloud = performance.now() + 1200
123+
let cloudRate = cfg.cloudSpawn
124+
let start = 0
125+
let time = 0
126+
let best = Number(localStorage.getItem("highScoreSprigTZS") || 0)
127+
128+
// UTIL
129+
function r(a,b){ return Math.random()*(b-a)+a }
130+
function solid(x,y){ return getTile(x,y).some(s=>s.type===w) }
131+
132+
// CLOUD/TANK SPAWN
133+
function makeCloud(){
134+
const edge = Math.floor(Math.random()*4)
135+
let x,y
136+
if(edge===0){ x=0; y=Math.floor(r(1,H-2)) }
137+
if(edge===1){ x=W-1; y=Math.floor(r(1,H-2)) }
138+
if(edge===2){ x=Math.floor(r(1,W-2)); y=0 }
139+
if(edge===3){ x=Math.floor(r(1,W-2)); y=H-1 }
140+
const ang = Math.atan2(H/2-y, W/2-x)
141+
clouds.push({ x, y, r:r(1.2,2.4), vx:Math.cos(ang)*r(0.02,0.18), vy:Math.sin(ang)*r(0.02,0.18) })
142+
}
143+
144+
function makeTank(){
145+
const arr = []
146+
for(let x=1;x<W-1;x++){
147+
for(let y=1;y<H-1;y++){
148+
if(!(x===pl.x && y===pl.y) && !solid(x,y)) arr.push({x,y})
149+
}
150+
}
151+
if(arr.length===0) return
152+
const p0 = arr[Math.floor(Math.random()*arr.length)]
153+
tanks.push({ x:p0.x, y:p0.y, born:performance.now() })
154+
}
155+
156+
// DRAW
157+
function clearInside(){
158+
for(let x=1;x<W-1;x++){
159+
for(let y=1;y<H-1;y++){
160+
clearTile(x,y)
161+
}
162+
}
163+
}
164+
165+
function draw(){
166+
for(const tn of tanks) addSprite(tn.x, tn.y, o)
167+
for(const c of clouds){
168+
const R = c.r
169+
const xmin = Math.max(1, Math.floor(c.x - R))
170+
const xmax = Math.min(W-2, Math.floor(c.x + R))
171+
const ymin = Math.max(1, Math.floor(c.y - R))
172+
const ymax = Math.min(H-2, Math.floor(c.y + R))
173+
for(let xx=xmin; xx<=xmax; xx++){
174+
for(let yy=ymin; yy<=ymax; yy++){
175+
const dx = xx - c.x, dy = yy - c.y
176+
if(Math.sqrt(dx*dx+dy*dy) <= R+0.3) addSprite(xx,yy,t)
177+
}
178+
}
179+
}
180+
addSprite(pl.x, pl.y, p)
181+
}
182+
183+
// GAME LOGIC
184+
function step(){
185+
if(state!=="play") return
186+
const now = performance.now()
187+
188+
// movement
189+
if(nextDir){
190+
if(!(dir.x===-nextDir.x && dir.y===-nextDir.y)) dir = nextDir
191+
nextDir = null
192+
}
193+
if(dir.x||dir.y){
194+
const nx = pl.x + dir.x, ny = pl.y + dir.y
195+
if(!solid(nx,ny)){ pl.x = nx; pl.y = ny }
196+
}
197+
198+
// clouds
199+
for(const c of clouds){
200+
c.r += cfg.grow
201+
c.x += c.vx
202+
c.y += c.vy
203+
}
204+
clouds = clouds.filter(c => !(c.x<-3||c.x>W+3||c.y<-3||c.y>H+3||c.r>10))
205+
206+
// spawn clouds
207+
cloudRate = Math.max(cfg.cloudMin, cfg.cloudSpawn - (time/60)*300)
208+
if(now>=nextCloud){
209+
makeCloud()
210+
nextCloud = now + r(cloudRate*0.7, cloudRate*1.2)
211+
}
212+
213+
// tanks
214+
if(now>=nextTank){
215+
makeTank()
216+
nextTank = now + r(cfg.tankSpawn*0.6, cfg.tankSpawn*1.4)
217+
}
218+
tanks = tanks.filter(tk => now - tk.born <= cfg.tankLife)
219+
220+
// pickup
221+
for(let i=tanks.length-1;i>=0;i--){
222+
if(tanks[i].x===pl.x && tanks[i].y===pl.y){
223+
pl.oxy = Math.min(cfg.oxyMax, pl.oxy + cfg.tankOxy)
224+
tanks.splice(i,1)
225+
try{ playTune("c5:6") }catch(e){}
226+
}
227+
}
228+
229+
// oxygen drain
230+
let inside=false
231+
for(const c of clouds){
232+
const dx=pl.x-c.x, dy=pl.y-c.y
233+
if(Math.sqrt(dx*dx+dy*dy)<=c.r+0.2){ inside=true; break }
234+
}
235+
const dt = cfg.tick/1000
236+
pl.oxy = Math.max(0, pl.oxy - cfg.oxyDrain * (inside?cfg.cloudMul:1) * dt)
237+
if(pl.oxy<=0) pl.hp = Math.max(0, pl.hp - cfg.dmg*dt)
238+
239+
// score
240+
time = (now-start)/1000
241+
242+
// redraw
243+
clearInside()
244+
draw()
245+
246+
try{ clearText() }catch(e){}
247+
addText("TIME "+time.toFixed(1), {x:1,y:0,color:color`3`})
248+
addText("OXY "+Math.floor(pl.oxy), {x:9,y:0,color:color`4`})
249+
addText("HP "+Math.floor(pl.hp), {x:14,y:0,color:color`2`})
250+
addText("BEST "+Math.floor(best), {x:1,y:H-1,color:color`5`})
251+
252+
// game over
253+
if(pl.hp<=0){
254+
endGame()
255+
}
256+
}
257+
258+
function endGame(){
259+
state="end"
260+
if(tickLoop) clearInterval(tickLoop)
261+
const final = Math.floor(time)
262+
if(final>best){
263+
best=final
264+
localStorage.setItem("highScoreSprigTZS",String(best))
265+
}
266+
try{ clearText() }catch(e){}
267+
addText("GAME OVER", {x:5,y:3,color:color`2`})
268+
addText("TIME "+final+"s", {x:5,y:5,color:color`3`})
269+
addText("PRESS ANY KEY", {x:3,y:7,color:color`4`})
270+
try{ playTune("e4:6 r:2 c4:8") }catch(e){}
271+
}
272+
273+
function startGame(){
274+
pl.x=Math.floor(W/2); pl.y=Math.floor(H/2)
275+
pl.oxy=cfg.oxyMax; pl.hp=cfg.hpMax
276+
clouds=[]; tanks=[]
277+
dir={x:0,y:0}; nextDir=null
278+
start=performance.now()
279+
time=0
280+
state="play"
281+
if(tickLoop) clearInterval(tickLoop)
282+
tickLoop=setInterval(step,cfg.tick)
283+
makeCloud()
284+
makeTank()
285+
}
286+
287+
// INPUT HANDLERS
288+
function move(x,y){ nextDir={x,y}; if(state==="idle") startGame(); if(state==="end") startGame() }
289+
290+
onInput("w",()=>move(0,-1))
291+
onInput("s",()=>move(0,1))
292+
onInput("a",()=>move(-1,0))
293+
onInput("d",()=>move(1,0))
294+
onInput("i",()=>move(0,-1))
295+
onInput("k",()=>move(0,1))
296+
onInput("j",()=>move(-1,0))
297+
onInput("l",()=>move(1,0))
298+
299+
// START SCREEN
300+
try{ clearText() }catch(e){}
301+
addText("TOXIC ZONE SURVIVAL",{x:2,y:2,color:color`3`})
302+
addText("Move: WASD / IJKL",{x:3,y:4,color:color`4`})
303+
addText("Press any key",{x:4,y:6,color:color`5`})

0 commit comments

Comments
 (0)