From 649a4c4a4df7f552adc46f7d3a1cad357bfc48f6 Mon Sep 17 00:00:00 2001 From: Televisionhrx Date: Fri, 2 Oct 2026 14:12:56 +0530 Subject: [PATCH 1/2] Add files via upload --- games/Dodge_The_Rocks.js | 218 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 games/Dodge_The_Rocks.js diff --git a/games/Dodge_The_Rocks.js b/games/Dodge_The_Rocks.js new file mode 100644 index 0000000000..8ad47bdb10 --- /dev/null +++ b/games/Dodge_The_Rocks.js @@ -0,0 +1,218 @@ +/* +@title: Dodge_The_Rocks +@description: Fly through an endless asteroid field. Use the laser and bomb to survive as it speeds up. +@author: +@tags: ['arcade', 'survival'] +@addedOn: 2026-10-02 +*/ + +const ship = "p"; +const rock = "r"; +const space = "b"; + +setLegend( + [ship, bitmap` +.......33....... +.......33....... +......3333...... +......3333...... +.....333333..... +.....333333..... +....33333333.... +...3333333333... +..333333333333.. +..33L333333L33.. +..33.C3333C.33.. +.....CCCCCC..... +......CCCC...... +................ +................ +................`], + [rock, bitmap` +................ +......11........ +...1122211111... +..12222221LL11.. +.1222LL22221LL1. +.122LLL2222221L. +.11222222221LL1. +..122222LL22L1.. +.1L2222222LL211. +.11L222222222L1. +..11LL2222LLL1.. +...11LLLLLL11... +.....1111....... +................ +................ +................`], + [space, bitmap` +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000`] +); + +setBackground(space); +setSolids([]); + +const W = 10; +const H = 8; + +setMap(map` +.......... +.......... +.......... +.......... +.......... +.......... +.......... +....p.....`); + +let score = 0; +let alive = true; +let paused = false; +let ammo = 3; +let bombReady = true; +let nextBomb = 0; +let timer; +let safeX = 4; + +function showScore() { + clearText(); + addText("Score: " + score, { x: 1, y: 0, color: color`3` }); + addText("Ammo:" + ammo + " Bomb:" + (bombReady ? "READY" : "..."), { x: 1, y: 1, color: color`3` }); +} + +function hitCheck() { + if (tilesWith(ship, rock).length > 0) { + alive = false; + addText("GAME OVER", { x: 5, y: 6, color: color`3` }); + addText("Press J to retry", { x: 2, y: 9, color: color`3` }); + } +} + +function spawnRocks() { + // the safe lane drifts at most one column per row, so it's always reachable + safeX += Math.floor(Math.random() * 3) - 1; + safeX = Math.max(0, Math.min(W - 1, safeX)); + + const chance = Math.min(0.08 + score / 600, 0.25); + let count = 0; + for (let x = 0; x < W; x++) { + if (x === safeX) continue; + if (count < 3 && Math.random() < chance) { + addSprite(x, 0, rock); + count++; + } + } +} + +function tick() { + getAll(rock).forEach((r) => { + if (r.y >= H - 1) r.remove(); + else r.y += 1; + }); + + hitCheck(); + if (!alive) return; + + if (score % 2 === 0) spawnRocks(); + score++; + + if (score % 20 === 0 && ammo < 3) ammo++; + if (!bombReady && score >= nextBomb) { + bombReady = true; + showScore(); + } + if (score % 5 === 0) showScore(); +} + +function loop() { + if (paused) return; + tick(); + if (alive) { + timer = setTimeout(loop, Math.max(200, 550 - score * 3)); + } +} + +function move(dx, dy) { + if (!alive || paused) return; + const s = getFirst(ship); + const nx = s.x + dx; + const ny = s.y + dy; + if (nx >= 0 && nx < W) s.x = nx; + if (ny >= H - 3 && ny < H) s.y = ny; + hitCheck(); +} + +function shoot() { + if (!alive || paused || ammo <= 0) return; + const s = getFirst(ship); + const targets = getAll(rock).filter((r) => r.x === s.x && r.y < s.y); + if (targets.length === 0) return; + targets.sort((a, b) => b.y - a.y)[0].remove(); + ammo--; + showScore(); +} + +function bomb() { + if (!alive || paused || !bombReady) return; + getAll(rock).forEach((r) => r.remove()); + bombReady = false; + nextBomb = score + 60; + showScore(); +} + +function togglePause() { + if (!alive) return; + paused = !paused; + if (paused) { + clearTimeout(timer); + addText("PAUSED", { x: 7, y: 6, color: color`3` }); + } else { + showScore(); + loop(); + } +} + +function restart() { + getAll(rock).forEach((r) => r.remove()); + const s = getFirst(ship); + s.x = 4; + s.y = H - 1; + score = 0; + ammo = 3; + bombReady = true; + nextBomb = 0; + paused = false; + alive = true; + safeX = 4; + showScore(); + loop(); +} + +// Left pad: move the ship +onInput("a", () => move(-1, 0)); +onInput("d", () => move(1, 0)); +onInput("w", () => move(0, -1)); +onInput("s", () => move(0, 1)); + +// Right pad: actions +onInput("j", () => { if (alive) shoot(); else restart(); }); +onInput("k", () => bomb()); +onInput("i", () => togglePause()); + +showScore(); +loop(); \ No newline at end of file From ac06936954b76ecf8939a3ca227127087ec16457 Mon Sep 17 00:00:00 2001 From: Televisionhrx Date: Wed, 14 Oct 2026 17:39:48 +0530 Subject: [PATCH 2/2] Update Dodge_The_Rocks.js --- games/Dodge_The_Rocks.js | 558 +++++++++++++++++++++++++++++++++++---- 1 file changed, 505 insertions(+), 53 deletions(-) diff --git a/games/Dodge_The_Rocks.js b/games/Dodge_The_Rocks.js index 8ad47bdb10..570056457a 100644 --- a/games/Dodge_The_Rocks.js +++ b/games/Dodge_The_Rocks.js @@ -1,7 +1,8 @@ + /* @title: Dodge_The_Rocks -@description: Fly through an endless asteroid field. Use the laser and bomb to survive as it speeds up. -@author: +@description: Survive an endless asteroid field with shields, power-ups, combos and special rocks. +@author: @tags: ['arcade', 'survival'] @addedOn: 2026-10-02 */ @@ -9,6 +10,9 @@ const ship = "p"; const rock = "r"; const space = "b"; +const armored = "a"; +const fastRock = "f"; +const pickup = "u"; setLegend( [ship, bitmap` @@ -28,6 +32,7 @@ setLegend( ................ ................ ................`], + [rock, bitmap` ................ ......11........ @@ -45,6 +50,61 @@ setLegend( ................ ................ ................`], + + [armored, bitmap` +................ +......6666...... +...6661111666... +..661122221166.. +.66122222222166. +.61222222222216. +.61226611662216. +.61226611662216. +.61222222222216. +.66122222222166. +..661122221166.. +...6661111666... +......6666...... +................ +................ +................`], + + [fastRock, bitmap` +................ +........44...... +......44444..... +....44422144.... +...4422222144... +..442222222144.. +..422222222214.. +..442222222144.. +...4422222144... +....44422144.... +......44444..... +........44...... +................ +................ +................ +................`], + + [pickup, bitmap` +................ +................ +.......55....... +......5775...... +.....577775..... +....57777775.... +....57777775.... +....57777775.... +....57777775.... +.....577775..... +......5775...... +.......55....... +................ +................ +................ +................`], + [space, bitmap` 0000000000000000 0000000000000000 @@ -70,7 +130,7 @@ setSolids([]); const W = 10; const H = 8; -setMap(map` +const INITIAL_MAP = map` .......... .......... .......... @@ -78,141 +138,533 @@ setMap(map` .......... .......... .......... -....p.....`); +....p.....`; + +setMap(INITIAL_MAP); + +// ===================== +// GAME STATE +// ===================== let score = 0; +let health = 3; +let ammo = 3; + let alive = true; let paused = false; -let ammo = 3; + let bombReady = true; let nextBomb = 0; -let timer; + let safeX = 4; +let nextPickup = 12; + +let combo = 0; +let bestCombo = 0; +let comboUntil = 0; + +let shieldUntil = 0; +let shieldCooldownUntil = 0; +let invulnerableUntil = 0; + +let timer = null; + +// ===================== +// HELPERS +// ===================== + +function now() { + return Date.now(); +} + +function hazards() { + return [ + ...getAll(rock), + ...getAll(armored), + ...getAll(fastRock) + ]; +} + +function removeAllHazards() { + hazards().forEach(r => r.remove()); +} function showScore() { clearText(); - addText("Score: " + score, { x: 1, y: 0, color: color`3` }); - addText("Ammo:" + ammo + " Bomb:" + (bombReady ? "READY" : "..."), { x: 1, y: 1, color: color`3` }); + + addText("Score:" + score + " HP:" + health, { + x: 1, y: 0, color: color`3` + }); + + addText("Ammo:" + ammo + " Bomb:" + + (bombReady ? "READY" : "..."), { + x: 1, y: 1, color: color`3` + }); + + let shieldText = "SHIELD READY"; + + if (now() < shieldUntil) { + shieldText = "SHIELD ACTIVE"; + } else if (now() < shieldCooldownUntil) { + shieldText = "SHIELD RECHARGING"; + } + + addText(shieldText, { + x: 1, y: 2, color: color`3` + }); + + if (combo > 1) { + addText("COMBO x" + combo, { + x: 5, y: 3, color: color`5` + }); + } +} + +// ===================== +// COLLISION SYSTEM +// ===================== + +function gameOver() { + if (!alive) return; + + alive = false; + clearTimeout(timer); + timer = null; + + clearText(); + + addText("GAME OVER", { + x: 5, y: 3, color: color`3` + }); + + addText("Score:" + score, { + x: 5, y: 4, color: color`3` + }); + + addText("Best combo:" + bestCombo, { + x: 3, y: 5, color: color`3` + }); + + addText("Press J to retry", { + x: 2, y: 6, color: color`3` + }); } function hitCheck() { - if (tilesWith(ship, rock).length > 0) { - alive = false; - addText("GAME OVER", { x: 5, y: 6, color: color`3` }); - addText("Press J to retry", { x: 2, y: 9, color: color`3` }); + if (!alive) return; + + const s = getFirst(ship); + if (!s) return; + + const collisions = hazards().filter(r => + r.x === s.x && r.y === s.y + ); + + if (collisions.length === 0) return; + + // Shield destroys rocks touching the ship. + if (now() < shieldUntil) { + collisions.forEach(r => r.remove()); + score += collisions.length * 2; + showScore(); + return; + } + + // Brief invulnerability prevents repeated damage. + if (now() < invulnerableUntil) { + return; + } + + collisions.forEach(r => r.remove()); + + health--; + combo = 0; + invulnerableUntil = now() + 1000; + + if (health <= 0) { + gameOver(); + } else { + showScore(); + } +} + +// ===================== +// PICKUPS +// ===================== + +function collectPickups() { + if (!alive) return; + + const s = getFirst(ship); + if (!s) return; + + // getAll returns sprites, unlike tilesWith. + // This lets us safely call item.remove(). + const items = getAll(pickup).filter(item => + item.x === s.x && item.y === s.y + ); + + items.forEach(item => { + item.remove(); + + const reward = Math.floor(Math.random() * 3); + + if (reward === 0) { + ammo = Math.min(5, ammo + 2); + + addText("+2 AMMO", { + x: 5, y: 5, color: color`5` + }); + } else if (reward === 1) { + health = Math.min(3, health + 1); + + addText("+1 HEALTH", { + x: 4, y: 5, color: color`5` + }); + } else { + score += 15; + + addText("+15 POINTS", { + x: 4, y: 5, color: color`5` + }); + } + }); + + if (items.length > 0) { + showScore(); } } +// ===================== +// SPAWNING +// ===================== + + function spawnRocks() { - // the safe lane drifts at most one column per row, so it's always reachable safeX += Math.floor(Math.random() * 3) - 1; safeX = Math.max(0, Math.min(W - 1, safeX)); - const chance = Math.min(0.08 + score / 600, 0.25); + const chance = Math.min(0.12 + score / 500, 0.65); let count = 0; + for (let x = 0; x < W; x++) { if (x === safeX) continue; - if (count < 3 && Math.random() < chance) { - addSprite(x, 0, rock); + if (count >= 3) break; + + if (Math.random() < chance) { + const roll = Math.random(); + + if (roll < 0.15) { + addSprite(x, 0, armored); + } else if (roll < 0.35) { + addSprite(x, 0, fastRock); + } else { + addSprite(x, 0, rock); + } + count++; } } } + +function spawnPickup() { + const x = Math.floor(Math.random() * W); + addSprite(x, 0, pickup); +} + +// ===================== +// SHOOTING +// ===================== + + +function shoot() { + if (!alive || paused || ammo <= 0) return; + + const s = getFirst(ship); + if (!s) return; + + const targets = hazards().filter(r => + r.x === s.x && r.y < s.y + ); + + if (targets.length === 0) { + combo = 0; + showScore(); + return; + } + + targets.sort((a, b) => b.y - a.y); + + const target = targets[0]; + ammo--; + + if (target.type === armored) { + target.remove(); + ammo = Math.min(5, ammo + 1); + combo++; + score += 10 * Math.min(combo, 5); + } else { + target.remove(); + combo++; + score += 5 * Math.min(combo, 5); + } + + if (combo > bestCombo) { + bestCombo = combo; + } + + comboUntil = now() + 2500; + showScore(); +} + + +// ===================== +// BOMB +// ===================== + +function bomb() { + if (!alive || paused || !bombReady) return; + + removeAllHazards(); + + bombReady = false; + nextBomb = score + 60; + + combo = 0; + score += 5; + + showScore(); +} + +// ===================== +// SHIELD +// ===================== + +function activateShield() { + if (!alive || paused) return; + if (now() < shieldCooldownUntil) return; + + shieldUntil = now() + 3000; + shieldCooldownUntil = now() + 20000; + + // Immediately clear rocks touching the ship. + const s = getFirst(ship); + + if (s) { + hazards().forEach(r => { + if (r.x === s.x && r.y === s.y) { + r.remove(); + } + }); + } + + showScore(); +} + +// ===================== +// MAIN GAME TICK +// ===================== + function tick() { - getAll(rock).forEach((r) => { - if (r.y >= H - 1) r.remove(); - else r.y += 1; + if (!alive || paused) return; + + // Move each asteroid. + hazards().forEach(r => { + if (r.y >= H - 1) { + r.remove(); + return; + } + + // Fast rocks move two rows at a time. + if (r.type === fastRock) { + r.y = Math.min(H - 1, r.y + 2); + } else { + r.y += 1; + } }); + // Move power-ups. + getAll(pickup).forEach(p => { + if (p.y >= H - 1) { + p.remove(); + } else { + p.y += 1; + } + }); + + hitCheck(); + if (!alive) return; + + collectPickups(); + hitCheck(); if (!alive) return; - if (score % 2 === 0) spawnRocks(); + // Spawn asteroids. + if (score % 2 === 0) { + spawnRocks(); + } + + // Spawn collectibles periodically. + if (score >= nextPickup) { + spawnPickup(); + + nextPickup = + score + 12 + Math.floor(Math.random() * 8); + } + score++; - if (score % 20 === 0 && ammo < 3) ammo++; + // Regenerate ammo slowly. + if (score % 20 === 0 && ammo < 3) { + ammo++; + } + + // Bomb cooldown. if (!bombReady && score >= nextBomb) { bombReady = true; - showScore(); } - if (score % 5 === 0) showScore(); + + // Combo timeout. + if (combo > 0 && now() > comboUntil) { + combo = 0; + } + + showScore(); } function loop() { - if (paused) return; + if (paused || !alive) return; + tick(); - if (alive) { - timer = setTimeout(loop, Math.max(200, 550 - score * 3)); + + if (alive && !paused) { + const delay = Math.max(180, 550 - score * 2); + timer = setTimeout(loop, delay); } } +// ===================== +// MOVEMENT +// ===================== + function move(dx, dy) { if (!alive || paused) return; + const s = getFirst(ship); + if (!s) return; + const nx = s.x + dx; const ny = s.y + dy; - if (nx >= 0 && nx < W) s.x = nx; - if (ny >= H - 3 && ny < H) s.y = ny; + + if (nx >= 0 && nx < W) { + s.x = nx; + } + + // Keep the ship in the bottom three rows. + if (ny >= H - 3 && ny < H) { + s.y = ny; + } + hitCheck(); -} + if (!alive) return; -function shoot() { - if (!alive || paused || ammo <= 0) return; - const s = getFirst(ship); - const targets = getAll(rock).filter((r) => r.x === s.x && r.y < s.y); - if (targets.length === 0) return; - targets.sort((a, b) => b.y - a.y)[0].remove(); - ammo--; + collectPickups(); showScore(); } -function bomb() { - if (!alive || paused || !bombReady) return; - getAll(rock).forEach((r) => r.remove()); - bombReady = false; - nextBomb = score + 60; - showScore(); -} +// ===================== +// PAUSE +// ===================== function togglePause() { if (!alive) return; + paused = !paused; + if (paused) { clearTimeout(timer); - addText("PAUSED", { x: 7, y: 6, color: color`3` }); + timer = null; + + clearText(); + addText("PAUSED", { + x: 6, y: 4, color: color`3` + }); + + addText("Press I to resume", { + x: 2, y: 5, color: color`3` + }); } else { showScore(); loop(); } } +// ===================== +// RESTART +// ===================== + function restart() { - getAll(rock).forEach((r) => r.remove()); + clearTimeout(timer); + timer = null; + + removeAllHazards(); + getAll(pickup).forEach(p => p.remove()); + const s = getFirst(ship); - s.x = 4; - s.y = H - 1; + + if (s) { + s.x = 4; + s.y = H - 1; + } + score = 0; + health = 3; ammo = 3; + + alive = true; + paused = false; + bombReady = true; nextBomb = 0; - paused = false; - alive = true; + safeX = 4; + nextPickup = 12; + + combo = 0; + bestCombo = 0; + comboUntil = 0; + + shieldUntil = 0; + shieldCooldownUntil = 0; + invulnerableUntil = 0; + showScore(); loop(); } -// Left pad: move the ship +// ===================== +// CONTROLS +// ===================== + onInput("a", () => move(-1, 0)); onInput("d", () => move(1, 0)); onInput("w", () => move(0, -1)); onInput("s", () => move(0, 1)); -// Right pad: actions -onInput("j", () => { if (alive) shoot(); else restart(); }); +onInput("j", () => { + if (alive) { + shoot(); + } else { + restart(); + } +}); + onInput("k", () => bomb()); onInput("i", () => togglePause()); +onInput("l", () => activateShield()); +// Start the game. showScore(); -loop(); \ No newline at end of file +loop();