🌌 CMB PURIFIER - نسخه پایدار
by RapidKnight54809 lines28.0 KB
<!DOCTYPE html>
<html lang="fa">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>🌌 CMB PURIFIER - نسخه پایدار</title>
<style>
* {
user-select: none;
touch-action: none;
}
body {
margin: 0;
min-height: 100vh;
background: linear-gradient(135deg, #000000 0%, #0a0a2a 100%);
display: flex;
justify-content: center;
align-items: center;
font-family: 'Orbitron', 'Courier New', monospace;
padding: 15px;
overflow: hidden;
position: fixed;
width: 100%;
height: 100%;
}
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&display=swap');
.game-wrapper {
max-width: 900px;
width: 100%;
position: relative;
}
canvas {
display: block;
width: 100%;
height: auto;
background: radial-gradient(ellipse at center, #0a0a2a 0%, #000000 100%);
border-radius: 30px;
box-shadow: 0 0 40px rgba(0, 255, 255, 0.5);
cursor: none;
touch-action: none;
}
.hud {
display: flex;
justify-content: space-between;
align-items: center;
background: rgba(0, 0, 0, 0.85);
backdrop-filter: blur(15px);
padding: 12px 20px;
border-radius: 50px;
margin-bottom: 15px;
border: 1px solid rgba(0, 255, 255, 0.5);
flex-wrap: wrap;
gap: 10px;
}
.stat-card {
background: rgba(0,0,0,0.6);
padding: 5px 15px;
border-radius: 30px;
text-align: center;
border-left: 3px solid cyan;
}
.stat-card span {
font-size: 0.65rem;
color: #88aaff;
}
.stat-card div {
font-size: 1.4rem;
font-weight: bold;
color: #ffd700;
text-shadow: 0 0 5px orange;
}
.hearts {
display: flex;
gap: 8px;
font-size: 1.8rem;
}
button {
background: linear-gradient(135deg, #ff416c, #ff4b2b);
border: none;
padding: 8px 18px;
border-radius: 30px;
font-family: 'Orbitron', monospace;
font-weight: bold;
font-size: 0.8rem;
color: white;
cursor: pointer;
transition: all 0.2s;
}
button:active {
transform: scale(0.95);
}
.upgrade-panel {
position: fixed;
bottom: 20px;
right: 20px;
background: rgba(0,0,0,0.95);
backdrop-filter: blur(10px);
padding: 15px;
border-radius: 25px;
border: 1px solid #00ffff;
min-width: 200px;
z-index: 100;
font-size: 0.7rem;
}
.upgrade-panel h4 {
margin: 0 0 10px 0;
color: #00ffff;
text-align: center;
}
.upgrade-item {
display: flex;
justify-content: space-between;
align-items: center;
margin: 8px 0;
gap: 10px;
}
.upgrade-item button {
padding: 4px 12px;
font-size: 0.7rem;
background: #1a3a5c;
}
.damage-number {
position: absolute;
pointer-events: none;
font-weight: bold;
font-size: 1rem;
animation: floatUp 0.6s ease-out forwards;
z-index: 200;
text-shadow: 0 0 5px cyan;
}
@keyframes floatUp {
0% { opacity: 1; transform: translateY(0px) scale(0.8); }
100% { opacity: 0; transform: translateY(-50px) scale(1.2); }
}
.game-over-modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0,0,0,0.98);
padding: 30px;
border-radius: 50px;
text-align: center;
border: 3px solid cyan;
z-index: 300;
min-width: 280px;
backdrop-filter: blur(20px);
}
.hidden {
display: none;
}
.cmb-badge {
position: absolute;
top: 10px;
left: 20px;
font-size: 0.6rem;
color: cyan;
background: rgba(0,0,0,0.5);
padding: 4px 12px;
border-radius: 20px;
pointer-events: none;
}
@media (max-width: 700px) {
.upgrade-panel { display: none; }
.stat-card div { font-size: 1rem; }
.hearts { font-size: 1.2rem; }
}
</style>
</head>
<body>
<div class="game-wrapper">
<div class="cmb-badge">🌡️ CMB: 2.725 K | پالایشگر فعال</div>
<div class="hud">
<div class="stat-card">🌡️ <span>یکنواختی</span><div id="scoreVal">0</div></div>
<div class="stat-card">🏆 <span>رکورد CMB</span><div id="highScoreVal">0</div></div>
<div class="hearts" id="heartsDisplay">🔴 🔴 🔴 🔴 🔴</div>
<div class="stat-card">💥 <span>تصفیه شده</span><div id="killCountVal">0</div></div>
<div class="stat-card">⚡ <span>انرژی</span><div id="moneyVal">0</div></div>
</div>
<canvas id="gameCanvas" width="800" height="550"></canvas>
<div style="display: flex; gap: 10px; margin-top: 12px; justify-content: center;">
<button id="restartGameBtn">🌀 بازنشانی کیهان</button>
<button id="toggleUpgradeBtn" style="background: linear-gradient(135deg, #00aaff, #0066cc);">🔬 ارتقا</button>
</div>
<div class="upgrade-panel hidden" id="upgradePanel">
<h4>🔭 ارتقا</h4>
<div class="upgrade-item">🌡️ قدرت تصفیه <button id="upgradeDmg">+ (💰50)</button></div>
<div class="upgrade-item">⚡ سرعت طیفسنج <button id="upgradeSpeed">+ (💰80)</button></div>
<div class="upgrade-item">❤️ سنسور حیاتی <button id="upgradeLife">+ (💰120)</button></div>
<div class="upgrade-item">💫 شانس بحرانی <button id="upgradeCrit">+ (💰100)</button></div>
</div>
<div id="gameOverModal" class="game-over-modal hidden">
<h2>🌌 CMB نامتعادل شد 🌌</h2>
<p id="finalStats"></p>
<button id="playAgainModalBtn">🌀 تصفیه مجدد</button>
</div>
</div>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
canvas.width = 800;
canvas.height = 550;
let gameRunning = true;
let animationId;
// بازیکن
let player = {
x: canvas.width/2,
y: canvas.height - 60,
radius: 18,
lives: 5,
maxLives: 5
};
// آمار
let isotropyScore = 0;
let highScore = localStorage.getItem('cmbPurifierHigh') ? parseInt(localStorage.getItem('cmbPurifierHigh')) : 0;
let anomaliesDestroyed = 0;
let cosmicEnergy = 0;
// آپگریدها
let upgrades = {
purificationPower: 1.0,
spectrometerSpeed: 1.0,
critChance: 0.1,
extraLives: 0
};
let upgradeCost = { dmg: 50, speed: 80, life: 120, crit: 100 };
// موجودیتها
let anomalies = [];
let purificationBeams = [];
let particles = [];
let lastShot = 0;
let shootDelay = 250;
// باس (درست شده)
let boss = null;
let bossActive = false;
let nextBossScore = 200;
// ستارهها
let stars = [];
for(let i = 0; i < 150; i++) {
stars.push({ x: Math.random() * canvas.width, y: Math.random() * canvas.height, size: 1 + Math.random() * 2 });
}
// المانها
const scoreVal = document.getElementById('scoreVal');
const highScoreVal = document.getElementById('highScoreVal');
const heartsDisplay = document.getElementById('heartsDisplay');
const killCountVal = document.getElementById('killCountVal');
const moneyVal = document.getElementById('moneyVal');
const restartBtn = document.getElementById('restartGameBtn');
const toggleUpgradeBtn = document.getElementById('toggleUpgradeBtn');
const upgradePanel = document.getElementById('upgradePanel');
const gameOverModal = document.getElementById('gameOverModal');
const playAgainModalBtn = document.getElementById('playAgainModalBtn');
const finalStats = document.getElementById('finalStats');
highScoreVal.innerText = highScore;
// کلاس ناهمسانی
class CMBAnomaly {
constructor(x, y, type, hp = 1) {
this.x = x;
this.y = y;
this.type = type;
this.radius = 22;
this.hp = hp;
this.maxHp = hp;
this.speedY = 1.0 + Math.random() * 1.3;
this.speedX = (Math.random() - 0.5) * 0.7;
if(type === 'hot') { this.speedY = 1.6; this.hp = 1; this.radius = 18; }
if(type === 'cold') { this.speedY = 1.2; this.hp = 2; this.radius = 24; }
if(type === 'unstable') { this.speedY = 0.7; this.hp = 4; this.radius = 32; }
}
update() {
this.y += this.speedY;
this.x += this.speedX;
if(this.x - this.radius < 0) this.x = this.radius;
if(this.x + this.radius > canvas.width) this.x = canvas.width - this.radius;
return this.y + this.radius > canvas.height;
}
draw() {
const pulse = 0.85 + Math.sin(Date.now() * 0.01) * 0.1;
const gradient = ctx.createRadialGradient(this.x-5, this.y-5, 5, this.x, this.y, this.radius);
if(this.type === 'hot') {
gradient.addColorStop(0, '#ff6644');
gradient.addColorStop(1, '#cc2200');
} else if(this.type === 'cold') {
gradient.addColorStop(0, '#4488ff');
gradient.addColorStop(1, '#0044aa');
} else {
gradient.addColorStop(0, '#aa44ff');
gradient.addColorStop(1, '#5511aa');
}
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius * pulse, 0, Math.PI*2);
ctx.fillStyle = gradient;
ctx.fill();
ctx.fillStyle = 'white';
ctx.font = "bold 16px monospace";
let icon = this.type === 'hot' ? '🌡️+' : (this.type === 'cold' ? '🌡️-' : '⚠️');
ctx.fillText(icon, this.x-10, this.y+8);
if(this.hp > 1) {
ctx.fillStyle = '#ff4444';
ctx.fillRect(this.x-18, this.y-22, 36, 5);
ctx.fillStyle = '#00ff88';
ctx.fillRect(this.x-18, this.y-22, 36 * (this.hp/this.maxHp), 5);
}
}
takeDamage(amount) {
let finalDmg = amount * upgrades.purificationPower;
let isCrit = Math.random() < upgrades.critChance;
if(isCrit) finalDmg *= 2.2;
this.hp -= finalDmg;
this.showDamage(isCrit ? finalDmg.toFixed(0) : finalDmg.toFixed(0), isCrit);
return this.hp <= 0;
}
showDamage(dmg, isCrit) {
const div = document.createElement('div');
div.className = 'damage-number';
div.innerText = isCrit ? `✨ ${dmg}!` : `${dmg}`;
div.style.color = isCrit ? '#ffff00' : '#66ffcc';
div.style.left = (this.x + canvas.getBoundingClientRect().left - 25) + 'px';
div.style.top = (this.y + canvas.getBoundingClientRect().top - 20) + 'px';
div.style.position = 'fixed';
document.body.appendChild(div);
setTimeout(() => div.remove(), 500);
}
}
class PurificationBeam {
constructor(x, y) {
this.x = x;
this.y = y;
this.radius = 6;
this.speed = -7;
}
update() {
this.y += this.speed;
return this.y + this.radius < 0;
}
draw() {
ctx.fillStyle = '#00ffff';
ctx.shadowBlur = 12;
ctx.beginPath();
ctx.arc(this.x, this.y, 6, 0, Math.PI*2);
ctx.fill();
ctx.fillStyle = '#ffffff';
ctx.beginPath();
ctx.arc(this.x, this.y, 3, 0, Math.PI*2);
ctx.fill();
ctx.shadowBlur = 0;
}
}
function addExplosion(x, y, type = 'hot') {
let color = type === 'hot' ? '#ff8844' : (type === 'cold' ? '#4488ff' : '#aa66ff');
for(let i = 0; i < 10; i++) {
particles.push({
x: x + (Math.random() - 0.5) * 20,
y: y + (Math.random() - 0.5) * 20,
life: 1,
size: 2 + Math.random() * 5,
color: color
});
}
}
function movePlayer(e) {
if(!gameRunning) return;
const rect = canvas.getBoundingClientRect();
const scaleX = canvas.width / rect.width;
let clientX;
if(e.touches) clientX = e.touches[0].clientX;
else clientX = e.clientX;
let canvasX = (clientX - rect.left) * scaleX;
canvasX = Math.min(Math.max(canvasX, player.radius + 10), canvas.width - player.radius - 10);
player.x = canvasX;
}
function shoot() {
if(!gameRunning) return;
let now = Date.now();
let delay = shootDelay / upgrades.spectrometerSpeed;
if(now - lastShot > delay) {
purificationBeams.push(new PurificationBeam(player.x, player.y - 12));
lastShot = now;
}
}
function spawnAnomaly() {
if(!gameRunning) return;
if(bossActive) return;
let rand = Math.random();
let type = 'hot';
if(isotropyScore > 300) type = rand < 0.4 ? 'hot' : (rand < 0.7 ? 'cold' : 'unstable');
else if(isotropyScore > 100) type = rand < 0.5 ? 'hot' : (rand < 0.8 ? 'cold' : 'unstable');
else type = rand < 0.6 ? 'hot' : 'cold';
let hp = 1;
if(type === 'cold') hp = 2;
if(type === 'unstable') hp = 3 + Math.floor(isotropyScore / 400);
let anomaly = new CMBAnomaly(30 + Math.random() * (canvas.width - 60), -30, type, hp);
anomalies.push(anomaly);
}
function spawnBoss() {
if(bossActive) return;
bossActive = true;
boss = {
x: canvas.width / 2,
y: 80,
radius: 45,
hp: 25 + Math.floor(isotropyScore / 50),
maxHp: 25 + Math.floor(isotropyScore / 50),
moveDir: 1
};
// پاک کردن دشمنان اضافی
anomalies = anomalies.filter(a => a.y > canvas.height - 150);
}
function updateGame() {
if(!gameRunning) return;
// اسپاون معمولی
if(Math.random() < 0.025 && anomalies.length < 12 && !bossActive) {
spawnAnomaly();
}
// بررسی برای اسپاون باس
if(isotropyScore >= nextBossScore && !bossActive && !boss) {
spawnBoss();
nextBossScore = isotropyScore + 200;
}
// آپدیت ناهمسانیها
for(let i = 0; i < anomalies.length; i++) {
let isOut = anomalies[i].update();
if(isOut) {
anomalies.splice(i, 1);
i--;
continue;
}
let dist = Math.hypot(player.x - anomalies[i].x, player.y - anomalies[i].y);
if(dist < player.radius + anomalies[i].radius) {
player.lives--;
addExplosion(player.x, player.y, anomalies[i].type);
anomalies.splice(i, 1);
updateHearts();
if(player.lives <= 0) endGame();
i--;
}
}
// آپدیت باس (کاملاً بازنویسی شده)
if(boss) {
boss.x += 2.2 * boss.moveDir;
if(boss.x - boss.radius < 40) boss.moveDir = 1;
if(boss.x + boss.radius > canvas.width - 40) boss.moveDir = -1;
// برخورد باس با بازیکن
let distToPlayer = Math.hypot(player.x - boss.x, player.y - boss.y);
if(distToPlayer < player.radius + boss.radius) {
player.lives -= 2;
updateHearts();
addExplosion(boss.x, boss.y, 'unstable');
if(player.lives <= 0) {
endGame();
return;
}
}
}
// گلولهها و برخورد
for(let i = 0; i < purificationBeams.length; i++) {
let isOut = purificationBeams[i].update();
if(isOut) {
purificationBeams.splice(i, 1);
i--;
continue;
}
let hit = false;
// برخورد با دشمنان عادی
for(let j = 0; j < anomalies.length; j++) {
let dist = Math.hypot(purificationBeams[i].x - anomalies[j].x, purificationBeams[i].y - anomalies[j].y);
if(dist < purificationBeams[i].radius + anomalies[j].radius) {
let dead = anomalies[j].takeDamage(12);
purificationBeams.splice(i, 1);
if(dead) {
let reward = 10 + (anomalies[j].type === 'cold' ? 8 : (anomalies[j].type === 'unstable' ? 20 : 5));
isotropyScore += reward;
cosmicEnergy += reward;
anomaliesDestroyed++;
addExplosion(anomalies[j].x, anomalies[j].y, anomalies[j].type);
anomalies.splice(j, 1);
updateUI();
}
hit = true;
break;
}
}
if(hit) { i--; continue; }
// برخورد با باس
if(boss) {
let distToBoss = Math.hypot(purificationBeams[i].x - boss.x, purificationBeams[i].y - boss.y);
if(distToBoss < purificationBeams[i].radius + boss.radius) {
let dmg = 10 * upgrades.purificationPower;
if(Math.random() < upgrades.critChance) dmg *= 2.2;
boss.hp -= dmg;
purificationBeams.splice(i, 1);
// نمایش damage روی باس
const div = document.createElement('div');
div.className = 'damage-number';
div.innerText = `🌀 ${dmg.toFixed(0)}`;
div.style.color = '#ffaa44';
div.style.left = (boss.x + canvas.getBoundingClientRect().left - 30) + 'px';
div.style.top = (boss.y + canvas.getBoundingClientRect().top - 20) + 'px';
div.style.position = 'fixed';
document.body.appendChild(div);
setTimeout(() => div.remove(), 400);
if(boss.hp <= 0) {
let bonus = 120;
isotropyScore += bonus;
cosmicEnergy += bonus;
addExplosion(boss.x, boss.y, 'unstable');
boss = null;
bossActive = false;
updateUI();
}
i--;
continue;
}
}
}
// آپدیت پارتیکلها
for(let i = 0; i < particles.length; i++) {
particles[i].life -= 0.05;
if(particles[i].life <= 0) {
particles.splice(i, 1);
i--;
}
}
// آپدیت رکورد
if(isotropyScore > highScore) {
highScore = isotropyScore;
localStorage.setItem('cmbPurifierHigh', highScore);
highScoreVal.innerText = highScore;
}
scoreVal.innerText = isotropyScore;
moneyVal.innerText = cosmicEnergy;
killCountVal.innerText = anomaliesDestroyed;
}
function updateHearts() {
let str = '';
for(let i = 0; i < player.lives; i++) str += '🔴 ';
for(let i = player.lives; i < player.maxLives + upgrades.extraLives; i++) str += '⚫ ';
heartsDisplay.innerHTML = str;
}
function updateUI() {
scoreVal.innerText = isotropyScore;
moneyVal.innerText = cosmicEnergy;
killCountVal.innerText = anomaliesDestroyed;
if(isotropyScore > highScore) {
highScore = isotropyScore;
highScoreVal.innerText = highScore;
localStorage.setItem('cmbPurifierHigh', highScore);
}
updateHearts();
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// پسزمینه
const grad = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
grad.addColorStop(0, '#030018');
grad.addColorStop(1, '#000008');
ctx.fillStyle = grad;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// نویز CMB
for(let i = 0; i < 200; i++) {
ctx.fillStyle = `rgba(255,200,100,${Math.random() * 0.3})`;
ctx.fillRect(Math.random() * canvas.width, Math.random() * canvas.height, 1.5, 1.5);
}
// ستارهها
for(let s of stars) {
ctx.fillStyle = `rgba(255,255,200,${0.3 + Math.random() * 0.5})`;
ctx.fillRect(s.x, s.y, s.size, s.size);
}
// باس (طراحی جداگانه)
if(boss) {
const pulse = 0.9 + Math.sin(Date.now() * 0.005) * 0.1;
ctx.beginPath();
ctx.arc(boss.x, boss.y, boss.radius * pulse, 0, Math.PI * 2);
const gradBoss = ctx.createRadialGradient(boss.x - 10, boss.y - 10, 10, boss.x, boss.y, boss.radius);
gradBoss.addColorStop(0, '#ff66aa');
gradBoss.addColorStop(1, '#aa00ff');
ctx.fillStyle = gradBoss;
ctx.fill();
ctx.fillStyle = 'white';
ctx.font = "bold 18px Orbitron";
ctx.fillText('🌀 ناهمسانی غولپیکر', boss.x - 90, boss.y - 25);
ctx.fillStyle = '#ff3333';
ctx.fillRect(boss.x - 65, boss.y - 40, 130, 10);
ctx.fillStyle = '#00ffaa';
ctx.fillRect(boss.x - 65, boss.y - 40, 130 * (boss.hp / boss.maxHp), 10);
ctx.fillStyle = 'white';
ctx.font = "bold 22px monospace";
ctx.fillText('👾', boss.x - 15, boss.y + 10);
}
// سفینه
ctx.shadowBlur = 12;
ctx.fillStyle = '#00ccaa';
ctx.beginPath();
ctx.moveTo(player.x, player.y - 20);
ctx.lineTo(player.x - 18, player.y + 8);
ctx.lineTo(player.x - 8, player.y + 4);
ctx.lineTo(player.x - 8, player.y + 14);
ctx.lineTo(player.x, player.y + 10);
ctx.lineTo(player.x + 8, player.y + 14);
ctx.lineTo(player.x + 8, player.y + 4);
ctx.lineTo(player.x + 18, player.y + 8);
ctx.fill();
ctx.fillStyle = '#88ffff';
ctx.beginPath();
ctx.arc(player.x, player.y - 8, 5, 0, Math.PI * 2);
ctx.fill();
ctx.shadowBlur = 0;
// گلولهها
for(let b of purificationBeams) b.draw();
// دشمنان
for(let a of anomalies) a.draw();
// پارتیکلها
for(let p of particles) {
ctx.fillStyle = `rgba(${p.color || '255,100,0'},${p.life})`;
ctx.fillRect(p.x, p.y, p.size, p.size);
}
// متن راهنما
ctx.font = "bold 11px Orbitron";
ctx.fillStyle = "#88aaff";
ctx.fillText("🌡️ حرکت با انگشت | شلیک خودکار | تصفیه ناهمسانیها", 20, 35);
ctx.fillStyle = "#ffaa66";
ctx.fillText(`🌌 دما: ${(2.725 + isotropyScore / 1500).toFixed(3)} K`, canvas.width - 150, 30);
}
let spawnInterval;
function startGameLoop() {
if(spawnInterval) clearInterval(spawnInterval);
spawnInterval = setInterval(() => {
if(gameRunning && !bossActive && anomalies.length < 10) {
spawnAnomaly();
}
}, 1100);
function frame() {
if(!gameRunning) return;
updateGame();
draw();
requestAnimationFrame(frame);
}
frame();
}
function endGame() {
gameRunning = false;
if(spawnInterval) clearInterval(spawnInterval);
finalStats.innerText = `یکنواختی نهایی: ${isotropyScore}\nتصفیه شده: ${anomaliesDestroyed}`;
gameOverModal.classList.remove('hidden');
}
function restart() {
gameRunning = true;
isotropyScore = 0;
anomaliesDestroyed = 0;
cosmicEnergy = 0;
player.lives = 5 + upgrades.extraLives;
player.maxLives = 5 + upgrades.extraLives;
anomalies = [];
purificationBeams = [];
particles = [];
boss = null;
bossActive = false;
nextBossScore = 200;
updateUI();
gameOverModal.classList.add('hidden');
if(spawnInterval) clearInterval(spawnInterval);
spawnInterval = setInterval(() => {
if(gameRunning && !bossActive && anomalies.length < 10) {
spawnAnomaly();
}
}, 1100);
}
// آپگریدها
function upgradeDamage() {
if(cosmicEnergy >= upgradeCost.dmg) {
cosmicEnergy -= upgradeCost.dmg;
upgrades.purificationPower += 0.18;
upgradeCost.dmg = Math.floor(upgradeCost.dmg * 1.4);
moneyVal.innerText = cosmicEnergy;
}
}
function upgradeFireSpeed() {
if(cosmicEnergy >= upgradeCost.speed) {
cosmicEnergy -= upgradeCost.speed;
upgrades.spectrometerSpeed += 0.25;
upgradeCost.speed = Math.floor(upgradeCost.speed * 1.4);
moneyVal.innerText = cosmicEnergy;
}
}
function upgradeLife() {
if(cosmicEnergy >= upgradeCost.life) {
cosmicEnergy -= upgradeCost.life;
upgrades.extraLives++;
player.maxLives = 5 + upgrades.extraLives;
player.lives = player.maxLives;
upgradeCost.life = Math.floor(upgradeCost.life * 1.5);
updateHearts();
moneyVal.innerText = cosmicEnergy;
}
}
function upgradeCrit() {
if(cosmicEnergy >= upgradeCost.crit) {
cosmicEnergy -= upgradeCost.crit;
upgrades.critChance = Math.min(0.55, upgrades.critChance + 0.08);
upgradeCost.crit = Math.floor(upgradeCost.crit * 1.4);
moneyVal.innerText = cosmicEnergy;
}
}
document.getElementById('upgradeDmg').onclick = upgradeDamage;
document.getElementById('upgradeSpeed').onclick = upgradeFireSpeed;
document.getElementById('upgradeLife').onclick = upgradeLife;
document.getElementById('upgradeCrit').onclick = upgradeCrit;
canvas.addEventListener('mousemove', movePlayer);
canvas.addEventListener('touchmove', movePlayer);
canvas.addEventListener('click', () => shoot());
canvas.addEventListener('touchstart', (e) => { e.preventDefault(); shoot(); });
restartBtn.onclick = () => restart();
playAgainModalBtn.onclick = () => restart();
toggleUpgradeBtn.onclick = () => upgradePanel.classList.toggle('hidden');
setInterval(() => { if(gameRunning) shoot(); }, 100);
startGameLoop();
updateHearts();
</script>
</body>
</html>Game Source: 🌌 CMB PURIFIER - نسخه پایدار
Creator: RapidKnight54
Libraries: none
Complexity: complex (809 lines, 28.0 KB)
The full source code is displayed above on this page.
Remix Instructions
To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: cmb-purifier-rapidknight54-mq7uoske" to link back to the original. Then publish at arcadelab.ai/publish.