🎮ArcadeLab

🌌 CMB PURIFIER - نسخه پایدار

by RapidKnight54
809 lines28.0 KB
▶ Play
<!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.