XTaylorSpenceX

Nano Bot Breach

Sep 15th, 2025
59
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 44.25 KB | None | 0 0
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>Nano Bot Breach - Vascular Maze Navigator</title>
  7.     <style>
  8.         * {
  9.             margin: 0;
  10.             padding: 0;
  11.             box-sizing: border-box;
  12.         }
  13.  
  14.         body {
  15.             background: linear-gradient(135deg, #0a0012 0%, #1a0033 50%, #0a0012 100%);
  16.             font-family: 'Courier New', monospace;
  17.             display: flex;
  18.             justify-content: center;
  19.             align-items: center;
  20.             min-height: 100vh;
  21.             overflow: hidden;
  22.             position: relative;
  23.         }
  24.  
  25.         body::before {
  26.             content: '';
  27.             position: absolute;
  28.             width: 200%;
  29.             height: 200%;
  30.             background: radial-gradient(circle, transparent 0%, rgba(255,0,150,0.03) 50%, transparent 100%);
  31.             animation: pulse 8s ease-in-out infinite;
  32.         }
  33.  
  34.         @keyframes pulse {
  35.             0%, 100% { transform: scale(1) rotate(0deg); }
  36.             50% { transform: scale(1.2) rotate(180deg); }
  37.         }
  38.  
  39.         #gameContainer {
  40.             position: relative;
  41.             border: 2px solid #ff00ff;
  42.             box-shadow:
  43.                 0 0 30px rgba(255,0,255,0.5),
  44.                 inset 0 0 30px rgba(0,255,255,0.1);
  45.             background: #000;
  46.             animation: borderGlow 2s ease-in-out infinite alternate;
  47.         }
  48.  
  49.         @keyframes borderGlow {
  50.             from { box-shadow: 0 0 30px rgba(255,0,255,0.5), inset 0 0 30px rgba(0,255,255,0.1); }
  51.             to { box-shadow: 0 0 50px rgba(0,255,255,0.8), inset 0 0 50px rgba(255,0,255,0.2); }
  52.         }
  53.  
  54.         canvas {
  55.             display: block;
  56.             image-rendering: crisp-edges;
  57.         }
  58.  
  59.         #ui {
  60.             position: absolute;
  61.             top: 10px;
  62.             left: 10px;
  63.             color: #00ffff;
  64.             text-shadow: 0 0 10px currentColor;
  65.             font-size: 14px;
  66.             user-select: none;
  67.             z-index: 10;
  68.         }
  69.  
  70.         .stat {
  71.             margin: 5px 0;
  72.             display: flex;
  73.             align-items: center;
  74.             gap: 10px;
  75.             background: rgba(0,0,0,0.7);
  76.             padding: 5px 10px;
  77.             border: 1px solid rgba(0,255,255,0.3);
  78.             border-radius: 3px;
  79.         }
  80.  
  81.         .stat-label {
  82.             color: #ff00ff;
  83.             min-width: 100px;
  84.         }
  85.  
  86.         .stat-value {
  87.             color: #00ff00;
  88.             font-weight: bold;
  89.         }
  90.  
  91.         .bar {
  92.             width: 100px;
  93.             height: 8px;
  94.             background: rgba(255,255,255,0.1);
  95.             border: 1px solid rgba(0,255,255,0.5);
  96.             position: relative;
  97.             overflow: hidden;
  98.         }
  99.  
  100.         .bar-fill {
  101.             height: 100%;
  102.             background: linear-gradient(90deg, #00ff00, #00ffff);
  103.             transition: width 0.3s ease;
  104.             box-shadow: 0 0 10px currentColor;
  105.         }
  106.  
  107.         #controls {
  108.             position: absolute;
  109.             bottom: 10px;
  110.             left: 50%;
  111.             transform: translateX(-50%);
  112.             display: flex;
  113.             gap: 10px;
  114.             z-index: 10;
  115.         }
  116.  
  117.         button {
  118.             padding: 10px 20px;
  119.             background: linear-gradient(135deg, #ff00ff, #00ffff);
  120.             border: none;
  121.             color: white;
  122.             font-weight: bold;
  123.             cursor: pointer;
  124.             border-radius: 5px;
  125.             text-transform: uppercase;
  126.             letter-spacing: 1px;
  127.             transition: all 0.3s ease;
  128.             box-shadow: 0 0 20px rgba(255,0,255,0.5);
  129.         }
  130.  
  131.         button:hover {
  132.             transform: translateY(-2px);
  133.             box-shadow: 0 5px 30px rgba(0,255,255,0.7);
  134.         }
  135.  
  136.         button:active {
  137.             transform: translateY(0);
  138.         }
  139.  
  140.         button:disabled {
  141.             opacity: 0.5;
  142.             cursor: not-allowed;
  143.         }
  144.  
  145.         #gameOver {
  146.             position: absolute;
  147.             top: 50%;
  148.             left: 50%;
  149.             transform: translate(-50%, -50%);
  150.             background: rgba(0,0,0,0.9);
  151.             padding: 30px;
  152.             border: 2px solid #ff00ff;
  153.             border-radius: 10px;
  154.             text-align: center;
  155.             display: none;
  156.             z-index: 100;
  157.             box-shadow: 0 0 50px rgba(255,0,255,0.8);
  158.         }
  159.  
  160.         #gameOver h2 {
  161.             color: #ff00ff;
  162.             margin-bottom: 20px;
  163.             text-shadow: 0 0 20px currentColor;
  164.             animation: textPulse 1s ease-in-out infinite;
  165.         }
  166.  
  167.         @keyframes textPulse {
  168.             0%, 100% { opacity: 1; }
  169.             50% { opacity: 0.7; }
  170.         }
  171.  
  172.         #gameOver p {
  173.             color: #00ffff;
  174.             margin: 10px 0;
  175.         }
  176.  
  177.         .particle {
  178.             position: absolute;
  179.             pointer-events: none;
  180.             width: 2px;
  181.             height: 2px;
  182.             background: radial-gradient(circle, #00ffff, transparent);
  183.             animation: particleFloat 2s ease-out forwards;
  184.         }
  185.  
  186.         @keyframes particleFloat {
  187.             0% {
  188.                 opacity: 1;
  189.                 transform: translate(0, 0) scale(1);
  190.             }
  191.             100% {
  192.                 opacity: 0;
  193.                 transform: translate(var(--dx), var(--dy)) scale(0);
  194.             }
  195.         }
  196.     </style>
  197. </head>
  198. <body>
  199.     <div id="gameContainer">
  200.         <canvas id="gameCanvas"></canvas>
  201.         <div id="ui">
  202.             <div class="stat">
  203.                 <span class="stat-label">NANOBOTS:</span>
  204.                 <span class="stat-value" id="botCount">0</span>
  205.             </div>
  206.             <div class="stat">
  207.                 <span class="stat-label">ENERGY:</span>
  208.                 <div class="bar">
  209.                     <div class="bar-fill" id="energyBar"></div>
  210.                 </div>
  211.             </div>
  212.             <div class="stat">
  213.                 <span class="stat-label">WAVE:</span>
  214.                 <span class="stat-value" id="waveCount">1</span>
  215.             </div>
  216.             <div class="stat">
  217.                 <span class="stat-label">THREATS:</span>
  218.                 <span class="stat-value" id="threatCount">0</span>
  219.             </div>
  220.             <div class="stat">
  221.                 <span class="stat-label">CONTROLS:</span>
  222.                 <span style="color: #00ffff; font-size: 11px;">↑↓←→ or WASD to move</span>
  223.             </div>
  224.         </div>
  225.         <div id="controls">
  226.             <button id="splitBtn">SPLIT [SPACE]</button>
  227.             <button id="mergeBtn">MERGE [M]</button>
  228.             <button id="boostBtn">BOOST [B]</button>
  229.         </div>
  230.         <div id="gameOver">
  231.             <h2>MISSION COMPLETE</h2>
  232.             <p>Wave Reached: <span id="finalWave">0</span></p>
  233.             <p>Nanobots Saved: <span id="finalBots">0</span></p>
  234.             <button onclick="location.reload()">RESTART MISSION</button>
  235.         </div>
  236.     </div>
  237.  
  238.     <script>
  239.         const canvas = document.getElementById('gameCanvas');
  240.         const ctx = canvas.getContext('2d');
  241.         const gameContainer = document.getElementById('gameContainer');
  242.        
  243.         // Game dimensions
  244.         const CELL_SIZE = 20;
  245.         const GRID_WIDTH = 40;
  246.         const GRID_HEIGHT = 30;
  247.        
  248.         canvas.width = GRID_WIDTH * CELL_SIZE;
  249.         canvas.height = GRID_HEIGHT * CELL_SIZE;
  250.         gameContainer.style.width = canvas.width + 'px';
  251.         gameContainer.style.height = canvas.height + 'px';
  252.        
  253.         // Game state
  254.         const game = {
  255.             grid: [],
  256.             nanobots: [],
  257.             immuneCells: [],
  258.             obstacles: [],
  259.             particles: [],
  260.             energy: 100,
  261.             maxEnergy: 100,
  262.             wave: 1,
  263.             target: null,
  264.             selectedBots: [],
  265.             mouseX: 0,
  266.             mouseY: 0,
  267.             splitCooldown: 0,
  268.             mergeCooldown: 0,
  269.             boostActive: false,
  270.             boostCooldown: 0,
  271.             keys: {
  272.                 up: false,
  273.                 down: false,
  274.                 left: false,
  275.                 right: false,
  276.                 w: false,
  277.                 a: false,
  278.                 s: false,
  279.                 d: false
  280.             }
  281.         };
  282.        
  283.         // Maze generation
  284.         class MazeGenerator {
  285.             static generate() {
  286.                 const grid = Array(GRID_HEIGHT).fill().map(() => Array(GRID_WIDTH).fill(0));
  287.                
  288.                 // Create walls
  289.                 for (let y = 0; y < GRID_HEIGHT; y++) {
  290.                    for (let x = 0; x < GRID_WIDTH; x++) {
  291.                        if (x === 0 || x === GRID_WIDTH - 1 || y === 0 || y === GRID_HEIGHT - 1) {
  292.                            grid[y][x] = 1;
  293.                        }
  294.                    }
  295.                }
  296.                
  297.                // Add random obstacles (vascular walls)
  298.                const obstacleCount = 15 + game.wave * 2;
  299.                for (let i = 0; i < obstacleCount; i++) {
  300.                    const x = Math.floor(Math.random() * (GRID_WIDTH - 4)) + 2;
  301.                    const y = Math.floor(Math.random() * (GRID_HEIGHT - 4)) + 2;
  302.                    const width = Math.floor(Math.random() * 3) + 2;
  303.                    const height = Math.floor(Math.random() * 3) + 2;
  304.                    
  305.                    for (let dy = 0; dy < height; dy++) {
  306.                        for (let dx = 0; dx < width; dx++) {
  307.                            if (x + dx < GRID_WIDTH - 1 && y + dy < GRID_HEIGHT - 1) {
  308.                                grid[y + dy][x + dx] = 1;
  309.                            }
  310.                        }
  311.                    }
  312.                }
  313.                
  314.                // Ensure path exists
  315.                grid[1][1] = 0;
  316.                grid[GRID_HEIGHT - 2][GRID_WIDTH - 2] = 0;
  317.                
  318.                return grid;
  319.            }
  320.        }
  321.        
  322.        // A* Pathfinding
  323.        class AStar {
  324.            static findPath(start, end, grid) {
  325.                const openSet = [start];
  326.                const closedSet = new Set();
  327.                const cameFrom = new Map();
  328.                const gScore = new Map();
  329.                const fScore = new Map();
  330.                
  331.                const key = (pos) => `${pos.x},${pos.y}`;
  332.                
  333.                 gScore.set(key(start), 0);
  334.                 fScore.set(key(start), this.heuristic(start, end));
  335.                
  336.                 while (openSet.length > 0) {
  337.                     let current = openSet.reduce((a, b) =>
  338.                         (fScore.get(key(a)) || Infinity) < (fScore.get(key(b)) || Infinity) ? a : b
  339.                    );
  340.                    
  341.                    if (current.x === end.x && current.y === end.y) {
  342.                        return this.reconstructPath(cameFrom, current);
  343.                    }
  344.                    
  345.                    openSet.splice(openSet.indexOf(current), 1);
  346.                    closedSet.add(key(current));
  347.                    
  348.                    const neighbors = this.getNeighbors(current, grid);
  349.                    for (const neighbor of neighbors) {
  350.                        const neighborKey = key(neighbor);
  351.                        if (closedSet.has(neighborKey)) continue;
  352.                        
  353.                        const tentativeGScore = (gScore.get(key(current)) || Infinity) + 1;
  354.                        
  355.                        if (!openSet.some(n => n.x === neighbor.x && n.y === neighbor.y)) {
  356.                            openSet.push(neighbor);
  357.                         } else if (tentativeGScore >= (gScore.get(neighborKey) || Infinity)) {
  358.                             continue;
  359.                         }
  360.                        
  361.                         cameFrom.set(neighborKey, current);
  362.                         gScore.set(neighborKey, tentativeGScore);
  363.                         fScore.set(neighborKey, tentativeGScore + this.heuristic(neighbor, end));
  364.                     }
  365.                 }
  366.                
  367.                 return [];
  368.             }
  369.            
  370.             static heuristic(a, b) {
  371.                 return Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
  372.             }
  373.            
  374.             static getNeighbors(pos, grid) {
  375.                 const neighbors = [];
  376.                 const dirs = [[0, -1], [1, 0], [0, 1], [-1, 0]];
  377.                
  378.                 for (const [dx, dy] of dirs) {
  379.                     const x = pos.x + dx;
  380.                     const y = pos.y + dy;
  381.                    
  382.                     if (x >= 0 && x < GRID_WIDTH && y >= 0 && y < GRID_HEIGHT && grid[y][x] === 0) {
  383.                        neighbors.push({x, y});
  384.                     }
  385.                 }
  386.                
  387.                 return neighbors;
  388.             }
  389.            
  390.             static reconstructPath(cameFrom, current) {
  391.                 const path = [current];
  392.                 const key = (pos) => `${pos.x},${pos.y}`;
  393.                
  394.                 while (cameFrom.has(key(current))) {
  395.                     current = cameFrom.get(key(current));
  396.                     path.unshift(current);
  397.                 }
  398.                
  399.                 return path;
  400.             }
  401.         }
  402.        
  403.         // Nanobot class
  404.         class Nanobot {
  405.             constructor(x, y) {
  406.                 this.x = x;
  407.                 this.y = y;
  408.                 this.vx = 0;
  409.                 this.vy = 0;
  410.                 this.targetX = x;
  411.                 this.targetY = y;
  412.                 this.path = [];
  413.                 this.speed = 0.15;
  414.                 this.size = 3 + Math.random() * 2;
  415.                 this.energy = 50;
  416.                 this.health = 100;
  417.                 this.selected = false;
  418.                 this.merging = false;
  419.                 this.angle = Math.random() * Math.PI * 2;
  420.                 this.wobble = Math.random() * Math.PI * 2;
  421.                 this.attackCooldown = 0;
  422.             }
  423.            
  424.             update() {
  425.                 this.wobble += 0.1;
  426.                
  427.                 if (game.boostActive) {
  428.                     this.speed = 0.3;
  429.                 } else {
  430.                     this.speed = 0.15;
  431.                 }
  432.                
  433.                 // Apply keyboard movement if selected or if no selection
  434.                 if (this.selected || game.selectedBots.length === 0) {
  435.                     this.vx *= 0.9; // Friction
  436.                     this.vy *= 0.9;
  437.                    
  438.                     if (game.keys.up || game.keys.w) this.vy -= this.speed * 0.1;
  439.                     if (game.keys.down || game.keys.s) this.vy += this.speed * 0.1;
  440.                     if (game.keys.left || game.keys.a) this.vx -= this.speed * 0.1;
  441.                     if (game.keys.right || game.keys.d) this.vx += this.speed * 0.1;
  442.                    
  443.                     // Apply velocity
  444.                     const nextX = this.x + this.vx;
  445.                     const nextY = this.y + this.vy;
  446.                    
  447.                     // Check collision with walls
  448.                     if (nextX >= 0 && nextX < GRID_WIDTH && nextY >= 0 && nextY < GRID_HEIGHT) {
  449.                        if (game.grid[Math.floor(nextY)][Math.floor(nextX)] === 0) {
  450.                            this.x = nextX;
  451.                             this.y = nextY;
  452.                         } else {
  453.                             this.vx = 0;
  454.                             this.vy = 0;
  455.                         }
  456.                     }
  457.                 }
  458.                
  459.                 // Follow path if set
  460.                 if (this.path.length > 0) {
  461.                     const target = this.path[0];
  462.                     const dx = target.x - this.x;
  463.                     const dy = target.y - this.y;
  464.                     const dist = Math.sqrt(dx * dx + dy * dy);
  465.                    
  466.                     if (dist < 0.5) {
  467.                        this.path.shift();
  468.                    } else {
  469.                        this.x += (dx / dist) * this.speed;
  470.                        this.y += (dy / dist) * this.speed;
  471.                        this.angle = Math.atan2(dy, dx);
  472.                    }
  473.                }
  474.                
  475.                // Swarm behavior
  476.                let avgX = 0, avgY = 0, count = 0;
  477.                for (const bot of game.nanobots) {
  478.                    if (bot !== this) {
  479.                        const dx = bot.x - this.x;
  480.                        const dy = bot.y - this.y;
  481.                        const dist = Math.sqrt(dx * dx + dy * dy);
  482.                        
  483.                        if (dist < 2 && dist > 0) {
  484.                             // Separation
  485.                             this.x -= (dx / dist) * 0.02;
  486.                             this.y -= (dy / dist) * 0.02;
  487.                         } else if (dist < 4) {
  488.                            // Cohesion
  489.                            avgX += bot.x;
  490.                            avgY += bot.y;
  491.                            count++;
  492.                        }
  493.                    }
  494.                }
  495.                
  496.                if (count > 0) {
  497.                     avgX /= count;
  498.                     avgY /= count;
  499.                     this.x += (avgX - this.x) * 0.005;
  500.                     this.y += (avgY - this.y) * 0.005;
  501.                 }
  502.                
  503.                 // Attack nearby immune cells
  504.                 if (this.attackCooldown > 0) this.attackCooldown--;
  505.                
  506.                 for (let i = game.immuneCells.length - 1; i >= 0; i--) {
  507.                     const immune = game.immuneCells[i];
  508.                     const dx = immune.x - this.x;
  509.                     const dy = immune.y - this.y;
  510.                     const dist = Math.sqrt(dx * dx + dy * dy);
  511.                    
  512.                     // Attack if close enough
  513.                     if (dist < 2 && this.attackCooldown === 0) {
  514.                        immune.health -= 20;
  515.                        this.attackCooldown = 30;
  516.                        createParticles(immune.x * CELL_SIZE, immune.y * CELL_SIZE, '#00ff00');
  517.                        
  518.                        if (immune.health <= 0) {
  519.                            game.immuneCells.splice(i, 1);
  520.                            this.energy = Math.min(100, this.energy + 20);
  521.                            createParticles(immune.x * CELL_SIZE, immune.y * CELL_SIZE, '#ffff00');
  522.                        }
  523.                    }
  524.                }
  525.                
  526.                // Stay within bounds
  527.                this.x = Math.max(0.5, Math.min(GRID_WIDTH - 0.5, this.x));
  528.                this.y = Math.max(0.5, Math.min(GRID_HEIGHT - 0.5, this.y));
  529.                
  530.                // Check health
  531.                if (this.health <= 0) {
  532.                    createParticles(this.x * CELL_SIZE, this.y * CELL_SIZE, '#ff0000');
  533.                    return false;
  534.                }
  535.                
  536.                // Regenerate energy and health slowly
  537.                this.energy = Math.min(100, this.energy + 0.05);
  538.                this.health = Math.min(100, this.health + 0.02);
  539.                
  540.                return true;
  541.            }
  542.            
  543.            setTarget(x, y) {
  544.                const start = {x: Math.floor(this.x), y: Math.floor(this.y)};
  545.                const end = {x: Math.floor(x), y: Math.floor(y)};
  546.                this.path = AStar.findPath(start, end, game.grid);
  547.            }
  548.            
  549.            draw() {
  550.                const screenX = this.x * CELL_SIZE;
  551.                const screenY = this.y * CELL_SIZE;
  552.                
  553.                // Save context state
  554.                ctx.save();
  555.                
  556.                // Glow effect
  557.                ctx.shadowBlur = 20;
  558.                ctx.shadowColor = this.selected ? '#ffff00' : '#00ffff';
  559.                
  560.                // Draw nanobot core
  561.                const healthRatio = this.health / 100;
  562.                ctx.fillStyle = this.selected ? '#ffff00' : `rgb(0, ${Math.floor(255 * healthRatio)}, 0)`;
  563.                ctx.beginPath();
  564.                ctx.arc(screenX, screenY, this.size, 0, Math.PI * 2);
  565.                ctx.fill();
  566.                
  567.                // Inner glow
  568.                ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';
  569.                ctx.beginPath();
  570.                ctx.arc(screenX, screenY, this.size * 0.3, 0, Math.PI * 2);
  571.                ctx.fill();
  572.                
  573.                // Health bar
  574.                if (this.health < 100) {
  575.                    ctx.shadowBlur = 0;
  576.                    ctx.fillStyle = 'rgba(255, 0, 0, 0.3)';
  577.                    ctx.fillRect(screenX - 10, screenY - 12, 20, 3);
  578.                    ctx.fillStyle = `rgb(${Math.floor(255 * (1 - healthRatio))}, ${Math.floor(255 * healthRatio)}, 0)`;
  579.                    ctx.fillRect(screenX - 10, screenY - 12, 20 * healthRatio, 3);
  580.                }
  581.                
  582.                // Energy indicator ring
  583.                ctx.shadowBlur = 0;
  584.                ctx.strokeStyle = `rgba(255, 255, 255, ${this.energy / 100})`;
  585.                ctx.lineWidth = 1;
  586.                ctx.beginPath();
  587.                ctx.arc(screenX, screenY, this.size + 3 + Math.sin(this.wobble) * 2, 0, Math.PI * 2);
  588.                ctx.stroke();
  589.                
  590.                // Attack indicator
  591.                if (this.attackCooldown > 0) {
  592.                     ctx.strokeStyle = '#00ff00';
  593.                     ctx.lineWidth = 2;
  594.                     ctx.beginPath();
  595.                     ctx.arc(screenX, screenY, this.size + 6, 0, (1 - this.attackCooldown / 30) * Math.PI * 2);
  596.                     ctx.stroke();
  597.                 }
  598.                
  599.                 // Restore context state
  600.                 ctx.restore();
  601.             }
  602.         }
  603.        
  604.         // Immune Cell class
  605.         class ImmuneCell {
  606.             constructor(x, y) {
  607.                 this.x = x;
  608.                 this.y = y;
  609.                 this.targetX = x;
  610.                 this.targetY = y;
  611.                 this.speed = 0.02 + game.wave * 0.005;
  612.                 this.detectionRange = 3 + game.wave * 0.5;
  613.                 this.angle = 0;
  614.                 this.patrolPath = this.generatePatrolPath();
  615.                 this.patrolIndex = 0;
  616.                 this.learningFactor = 1;
  617.                 this.health = 100;
  618.                 this.attackCooldown = 0;
  619.             }
  620.            
  621.             generatePatrolPath() {
  622.                 const path = [];
  623.                 const radius = 5 + Math.random() * 5;
  624.                 const steps = 8;
  625.                
  626.                 for (let i = 0; i < steps; i++) {
  627.                    const angle = (i / steps) * Math.PI * 2;
  628.                    const px = this.x + Math.cos(angle) * radius;
  629.                    const py = this.y + Math.sin(angle) * radius;
  630.                    
  631.                    if (px > 1 && px < GRID_WIDTH - 1 && py > 1 && py < GRID_HEIGHT - 1) {
  632.                        path.push({x: px, y: py});
  633.                     }
  634.                 }
  635.                
  636.                 return path;
  637.             }
  638.            
  639.             update() {
  640.                 this.angle += 0.05;
  641.                
  642.                 if (this.attackCooldown > 0) this.attackCooldown--;
  643.                
  644.                 // Hunt nanobots
  645.                 let closestBot = null;
  646.                 let closestDist = Infinity;
  647.                
  648.                 for (const bot of game.nanobots) {
  649.                     const dx = bot.x - this.x;
  650.                     const dy = bot.y - this.y;
  651.                     const dist = Math.sqrt(dx * dx + dy * dy);
  652.                    
  653.                     if (dist < this.detectionRange && dist < closestDist) {
  654.                        closestBot = bot;
  655.                        closestDist = dist;
  656.                    }
  657.                }
  658.                
  659.                if (closestBot) {
  660.                    // Chase detected nanobot
  661.                    const dx = closestBot.x - this.x;
  662.                    const dy = closestBot.y - this.y;
  663.                    const dist = Math.sqrt(dx * dx + dy * dy);
  664.                    
  665.                    this.x += (dx / dist) * this.speed * this.learningFactor;
  666.                    this.y += (dy / dist) * this.speed * this.learningFactor;
  667.                    
  668.                    // Attack if close enough
  669.                    if (dist < 1.5 && this.attackCooldown === 0) {
  670.                        closestBot.health -= 15;
  671.                        this.attackCooldown = 20;
  672.                        createParticles(closestBot.x * CELL_SIZE, closestBot.y * CELL_SIZE, '#ff0000');
  673.                        
  674.                        // Learn from successful attacks
  675.                        this.learningFactor = Math.min(2, this.learningFactor + 0.05);
  676.                    }
  677.                } else {
  678.                    // Patrol
  679.                    if (this.patrolPath.length > 0) {
  680.                         const target = this.patrolPath[this.patrolIndex];
  681.                         const dx = target.x - this.x;
  682.                         const dy = target.y - this.y;
  683.                         const dist = Math.sqrt(dx * dx + dy * dy);
  684.                        
  685.                         if (dist < 0.5) {
  686.                            this.patrolIndex = (this.patrolIndex + 1) % this.patrolPath.length;
  687.                        } else {
  688.                            this.x += (dx / dist) * this.speed;
  689.                            this.y += (dy / dist) * this.speed;
  690.                        }
  691.                    }
  692.                }
  693.                
  694.                // Check walls and stay within bounds
  695.                const gridX = Math.floor(this.x);
  696.                const gridY = Math.floor(this.y);
  697.                
  698.                if (gridX >= 0 && gridX < GRID_WIDTH && gridY >= 0 && gridY < GRID_HEIGHT) {
  699.                    if (game.grid[gridY][gridX] === 1) {
  700.                        // Back away from wall
  701.                        this.x = Math.max(1, Math.min(GRID_WIDTH - 1, this.x + (Math.random() - 0.5)));
  702.                         this.y = Math.max(1, Math.min(GRID_HEIGHT - 1, this.y + (Math.random() - 0.5)));
  703.                     }
  704.                 }
  705.                
  706.                 // Stay within bounds
  707.                 this.x = Math.max(1, Math.min(GRID_WIDTH - 1, this.x));
  708.                 this.y = Math.max(1, Math.min(GRID_HEIGHT - 1, this.y));
  709.                
  710.                 return this.health > 0;
  711.             }
  712.            
  713.             draw() {
  714.                 const screenX = this.x * CELL_SIZE;
  715.                 const screenY = this.y * CELL_SIZE;
  716.                
  717.                 // Detection range
  718.                 ctx.fillStyle = 'rgba(255, 0, 0, 0.1)';
  719.                 ctx.beginPath();
  720.                 ctx.arc(screenX, screenY, this.detectionRange * CELL_SIZE, 0, Math.PI * 2);
  721.                 ctx.fill();
  722.                
  723.                 // Immune cell body
  724.                 ctx.shadowBlur = 20;
  725.                 ctx.shadowColor = '#ff0000';
  726.                
  727.                 ctx.fillStyle = '#ff4444';
  728.                 ctx.beginPath();
  729.                 for (let i = 0; i < 6; i++) {
  730.                    const angle = this.angle + (i / 6) * Math.PI * 2;
  731.                    const r = i % 2 === 0 ? 8 : 5;
  732.                    const px = screenX + Math.cos(angle) * r;
  733.                    const py = screenY + Math.sin(angle) * r;
  734.                    
  735.                    if (i === 0) ctx.moveTo(px, py);
  736.                    else ctx.lineTo(px, py);
  737.                }
  738.                ctx.closePath();
  739.                ctx.fill();
  740.                
  741.                ctx.shadowBlur = 0;
  742.            }
  743.        }
  744.        
  745.        // Particle effects
  746.        function createParticles(x, y, color) {
  747.            for (let i = 0; i < 10; i++) {
  748.                game.particles.push({
  749.                    x: x,
  750.                    y: y,
  751.                    vx: (Math.random() - 0.5) * 4,
  752.                    vy: (Math.random() - 0.5) * 4,
  753.                    life: 1,
  754.                    color: color || '#00ffff'
  755.                });
  756.            }
  757.        }
  758.        
  759.        // Initialize game
  760.        function init() {
  761.            game.grid = MazeGenerator.generate();
  762.            game.nanobots = [];
  763.            game.immuneCells = [];
  764.            game.particles = [];
  765.            
  766.            // Spawn initial nanobots with better visibility
  767.            for (let i = 0; i < 5; i++) {
  768.                const bot = new Nanobot(2 + Math.random() * 2, 2 + Math.random() * 2);
  769.                bot.size = 5; // Ensure minimum size
  770.                game.nanobots.push(bot);
  771.            }
  772.            
  773.            // Set target
  774.            game.target = {x: GRID_WIDTH - 3, y: GRID_HEIGHT - 3};
  775.            
  776.            // Spawn immune cells
  777.            const immuneCount = 2 + Math.floor(game.wave / 2);
  778.            for (let i = 0; i < immuneCount; i++) {
  779.                const x = Math.random() * (GRID_WIDTH - 10) + 5;
  780.                const y = Math.random() * (GRID_HEIGHT - 10) + 5;
  781.                game.immuneCells.push(new ImmuneCell(x, y));
  782.            }
  783.            
  784.            // Debug log to verify nanobots exist
  785.            console.log(`Initialized ${game.nanobots.length} nanobots`);
  786.            
  787.            updateUI();
  788.        }
  789.        
  790.        // Update game state
  791.        function update() {
  792.            // Update cooldowns
  793.            if (game.splitCooldown > 0) game.splitCooldown--;
  794.             if (game.mergeCooldown > 0) game.mergeCooldown--;
  795.             if (game.boostCooldown > 0) {
  796.                 game.boostCooldown--;
  797.                 if (game.boostCooldown === 0) game.boostActive = false;
  798.             }
  799.            
  800.             // Update nanobots
  801.             game.nanobots = game.nanobots.filter(bot => bot.update());
  802.            
  803.             // Update immune cells (remove dead ones)
  804.             game.immuneCells = game.immuneCells.filter(immune => immune.update());
  805.            
  806.             // Update particles
  807.             game.particles = game.particles.filter(p => {
  808.                 p.x += p.vx;
  809.                 p.y += p.vy;
  810.                 p.life -= 0.02;
  811.                 p.vx *= 0.98;
  812.                 p.vy *= 0.98;
  813.                 return p.life > 0;
  814.             });
  815.            
  816.             // Check win condition - nanobots reach target
  817.             let botsAtTarget = 0;
  818.             for (const bot of game.nanobots) {
  819.                 const dx = bot.x - game.target.x;
  820.                 const dy = bot.y - game.target.y;
  821.                 if (Math.sqrt(dx * dx + dy * dy) < 2) {
  822.                    botsAtTarget++;
  823.                }
  824.            }
  825.            
  826.            if (botsAtTarget >= Math.min(3, game.nanobots.length) && game.nanobots.length > 0) {
  827.                nextWave();
  828.             }
  829.            
  830.             // Check lose condition
  831.             if (game.nanobots.length === 0) {
  832.                 gameOver();
  833.             }
  834.            
  835.             // Regenerate energy
  836.             game.energy = Math.min(game.maxEnergy, game.energy + 0.1);
  837.            
  838.             updateUI();
  839.         }
  840.        
  841.         // Draw game
  842.         function draw() {
  843.             // Clear canvas with solid black
  844.             ctx.fillStyle = '#000000';
  845.             ctx.fillRect(0, 0, canvas.width, canvas.height);
  846.            
  847.             // Draw grid/maze
  848.             ctx.strokeStyle = 'rgba(128, 0, 255, 0.3)';
  849.             ctx.lineWidth = 1;
  850.             for (let y = 0; y <= GRID_HEIGHT; y++) {
  851.                ctx.beginPath();
  852.                ctx.moveTo(0, y * CELL_SIZE);
  853.                ctx.lineTo(canvas.width, y * CELL_SIZE);
  854.                ctx.stroke();
  855.            }
  856.            for (let x = 0; x <= GRID_WIDTH; x++) {
  857.                ctx.beginPath();
  858.                ctx.moveTo(x * CELL_SIZE, 0);
  859.                ctx.lineTo(x * CELL_SIZE, canvas.height);
  860.                ctx.stroke();
  861.            }
  862.            
  863.            // Draw walls
  864.            ctx.fillStyle = '#440066';
  865.            for (let y = 0; y < GRID_HEIGHT; y++) {
  866.                for (let x = 0; x < GRID_WIDTH; x++) {
  867.                    if (game.grid[y][x] === 1) {
  868.                        ctx.fillRect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
  869.                        
  870.                        // Wall glow
  871.                        ctx.strokeStyle = 'rgba(255, 0, 255, 0.2)';
  872.                        ctx.strokeRect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
  873.                    }
  874.                }
  875.            }
  876.            
  877.            // Draw target
  878.            const targetX = game.target.x * CELL_SIZE;
  879.            const targetY = game.target.y * CELL_SIZE;
  880.            const pulse = Math.sin(Date.now() * 0.003) * 10 + 20;
  881.            
  882.            ctx.save();
  883.            ctx.shadowBlur = 30;
  884.            ctx.shadowColor = '#00ff00';
  885.            ctx.strokeStyle = '#00ff00';
  886.            ctx.lineWidth = 2;
  887.            ctx.beginPath();
  888.            ctx.arc(targetX, targetY, pulse, 0, Math.PI * 2);
  889.            ctx.stroke();
  890.            ctx.beginPath();
  891.            ctx.arc(targetX, targetY, pulse - 10, 0, Math.PI * 2);
  892.            ctx.stroke();
  893.            ctx.restore();
  894.            
  895.            // Draw particles
  896.            for (const p of game.particles) {
  897.                const alpha = Math.floor(p.life * 255).toString(16).padStart(2, '0');
  898.                ctx.fillStyle = p.color + alpha;
  899.                ctx.fillRect(p.x - 1, p.y - 1, 2, 2);
  900.            }
  901.            
  902.            // Draw immune cells
  903.            for (const immune of game.immuneCells) {
  904.                immune.draw();
  905.            }
  906.            
  907.            // Draw nanobots - ensure they're on top
  908.            for (const bot of game.nanobots) {
  909.                bot.draw();
  910.            }
  911.            
  912.            // Draw selection box if dragging
  913.            if (game.selecting) {
  914.                ctx.strokeStyle = 'rgba(255, 255, 0, 0.5)';
  915.                ctx.lineWidth = 2;
  916.                ctx.setLineDash([5, 5]);
  917.                ctx.strokeRect(
  918.                    Math.min(game.selectStart.x, game.mouseX),
  919.                    Math.min(game.selectStart.y, game.mouseY),
  920.                    Math.abs(game.mouseX - game.selectStart.x),
  921.                    Math.abs(game.mouseY - game.selectStart.y)
  922.                );
  923.                ctx.setLineDash([]);
  924.            }
  925.        }
  926.        
  927.        // Update UI
  928.        function updateUI() {
  929.            document.getElementById('botCount').textContent = game.nanobots.length;
  930.            document.getElementById('energyBar').style.width = (game.energy / game.maxEnergy * 100) + '%';
  931.            document.getElementById('waveCount').textContent = game.wave;
  932.            document.getElementById('threatCount').textContent = game.immuneCells.length;
  933.            
  934.            // Update button states
  935.            document.getElementById('splitBtn').disabled = game.splitCooldown > 0 || game.energy < 20 || game.nanobots.length === 0;
  936.            document.getElementById('mergeBtn').disabled = game.mergeCooldown > 0 || game.nanobots.length < 2;
  937.            document.getElementById('boostBtn').disabled = game.boostCooldown > 0 || game.energy < 30;
  938.        }
  939.        
  940.        // Split nanobots
  941.        function splitBots() {
  942.            if (game.splitCooldown > 0 || game.energy < 20) return;
  943.            
  944.            const toSplit = game.selectedBots.length > 0 ? game.selectedBots : game.nanobots.slice(0, Math.min(3, game.nanobots.length));
  945.            
  946.             for (const bot of toSplit) {
  947.                 if (game.energy >= 20) {
  948.                     const newBot = new Nanobot(bot.x + Math.random() - 0.5, bot.y + Math.random() - 0.5);
  949.                     newBot.energy = bot.energy / 2;
  950.                     bot.energy = bot.energy / 2;
  951.                     game.nanobots.push(newBot);
  952.                     game.energy -= 20;
  953.                     createParticles(bot.x * CELL_SIZE, bot.y * CELL_SIZE, '#00ff00');
  954.                 }
  955.             }
  956.            
  957.             game.splitCooldown = 60;
  958.         }
  959.        
  960.         // Merge nanobots
  961.         function mergeBots() {
  962.             if (game.mergeCooldown > 0 || game.nanobots.length < 2) return;
  963.            
  964.            const toMerge = game.selectedBots.length >= 2 ? game.selectedBots : game.nanobots.slice(0, 2);
  965.            
  966.             if (toMerge.length >= 2) {
  967.                 const bot1 = toMerge[0];
  968.                 const bot2 = toMerge[1];
  969.                
  970.                 bot1.energy = Math.min(100, bot1.energy + bot2.energy);
  971.                 bot1.size = Math.min(8, bot1.size + bot2.size / 2);
  972.                
  973.                 const index = game.nanobots.indexOf(bot2);
  974.                 if (index > -1) {
  975.                     game.nanobots.splice(index, 1);
  976.                 }
  977.                
  978.                 createParticles(bot1.x * CELL_SIZE, bot1.y * CELL_SIZE, '#ffff00');
  979.                 game.energy = Math.min(game.maxEnergy, game.energy + 10);
  980.                 game.mergeCooldown = 40;
  981.             }
  982.         }
  983.        
  984.         // Boost speed
  985.         function boostSpeed() {
  986.             if (game.boostCooldown > 0 || game.energy < 30) return;
  987.            
  988.            game.boostActive = true;
  989.            game.boostCooldown = 180;
  990.            game.energy -= 30;
  991.            
  992.            for (const bot of game.nanobots) {
  993.                createParticles(bot.x * CELL_SIZE, bot.y * CELL_SIZE, '#ffffff');
  994.            }
  995.        }
  996.        
  997.        // Next wave
  998.        function nextWave() {
  999.            game.wave++;
  1000.            game.energy = game.maxEnergy;
  1001.            
  1002.            // Generate new maze
  1003.            game.grid = MazeGenerator.generate();
  1004.            
  1005.            // Add more immune cells
  1006.            const immuneCount = 2 + Math.floor(game.wave / 2);
  1007.            game.immuneCells = [];
  1008.            for (let i = 0; i < immuneCount; i++) {
  1009.                const x = Math.random() * (GRID_WIDTH - 10) + 5;
  1010.                const y = Math.random() * (GRID_HEIGHT - 10) + 5;
  1011.                game.immuneCells.push(new ImmuneCell(x, y));
  1012.            }
  1013.            
  1014.            // Reset bot positions
  1015.            for (const bot of game.nanobots) {
  1016.                bot.x = 2 + Math.random();
  1017.                bot.y = 2 + Math.random();
  1018.                bot.path = [];
  1019.            }
  1020.            
  1021.            // Create celebration particles
  1022.            for (let i = 0; i < 50; i++) {
  1023.                createParticles(
  1024.                    Math.random() * canvas.width,
  1025.                    Math.random() * canvas.height,
  1026.                    ['#00ff00', '#00ffff', '#ff00ff'][Math.floor(Math.random() * 3)]
  1027.                );
  1028.            }
  1029.        }
  1030.        
  1031.        // Game over
  1032.        function gameOver() {
  1033.            document.getElementById('gameOver').style.display = 'block';
  1034.            document.getElementById('finalWave').textContent = game.wave;
  1035.            document.getElementById('finalBots').textContent = game.nanobots.length;
  1036.        }
  1037.        
  1038.        // Mouse controls
  1039.        canvas.addEventListener('mousedown', (e) => {
  1040.             const rect = canvas.getBoundingClientRect();
  1041.             const x = e.clientX - rect.left;
  1042.             const y = e.clientY - rect.top;
  1043.            
  1044.             if (e.button === 0) { // Left click
  1045.                 game.selecting = true;
  1046.                 game.selectStart = {x, y};
  1047.                 game.selectedBots = [];
  1048.             } else if (e.button === 2) { // Right click
  1049.                 e.preventDefault();
  1050.                 const gridX = x / CELL_SIZE;
  1051.                 const gridY = y / CELL_SIZE;
  1052.                
  1053.                 // Set target for selected bots or all bots
  1054.                 const bots = game.selectedBots.length > 0 ? game.selectedBots : game.nanobots;
  1055.                 for (const bot of bots) {
  1056.                     bot.setTarget(gridX, gridY);
  1057.                 }
  1058.                
  1059.                 createParticles(x, y, '#ffffff');
  1060.             }
  1061.         });
  1062.        
  1063.         canvas.addEventListener('mousemove', (e) => {
  1064.             const rect = canvas.getBoundingClientRect();
  1065.             game.mouseX = e.clientX - rect.left;
  1066.             game.mouseY = e.clientY - rect.top;
  1067.            
  1068.             if (game.selecting) {
  1069.                 // Update selection
  1070.                 game.selectedBots = [];
  1071.                 const minX = Math.min(game.selectStart.x, game.mouseX) / CELL_SIZE;
  1072.                 const maxX = Math.max(game.selectStart.x, game.mouseX) / CELL_SIZE;
  1073.                 const minY = Math.min(game.selectStart.y, game.mouseY) / CELL_SIZE;
  1074.                 const maxY = Math.max(game.selectStart.y, game.mouseY) / CELL_SIZE;
  1075.                
  1076.                 for (const bot of game.nanobots) {
  1077.                     bot.selected = false;
  1078.                     if (bot.x >= minX && bot.x <= maxX && bot.y >= minY && bot.y <= maxY) {
  1079.                        game.selectedBots.push(bot);
  1080.                         bot.selected = true;
  1081.                     }
  1082.                 }
  1083.             }
  1084.         });
  1085.        
  1086.         canvas.addEventListener('mouseup', (e) => {
  1087.             if (e.button === 0) {
  1088.                 game.selecting = false;
  1089.             }
  1090.         });
  1091.        
  1092.         canvas.addEventListener('contextmenu', (e) => {
  1093.             e.preventDefault();
  1094.         });
  1095.        
  1096.         // Keyboard controls
  1097.         document.addEventListener('keydown', (e) => {
  1098.             // Movement keys
  1099.             switch(e.key.toLowerCase()) {
  1100.                 case 'arrowup':
  1101.                     e.preventDefault();
  1102.                     game.keys.up = true;
  1103.                     break;
  1104.                 case 'arrowdown':
  1105.                     e.preventDefault();
  1106.                     game.keys.down = true;
  1107.                     break;
  1108.                 case 'arrowleft':
  1109.                     e.preventDefault();
  1110.                     game.keys.left = true;
  1111.                     break;
  1112.                 case 'arrowright':
  1113.                     e.preventDefault();
  1114.                     game.keys.right = true;
  1115.                     break;
  1116.                 case 'w':
  1117.                     game.keys.w = true;
  1118.                     break;
  1119.                 case 'a':
  1120.                     game.keys.a = true;
  1121.                     break;
  1122.                 case 's':
  1123.                     game.keys.s = true;
  1124.                     break;
  1125.                 case 'd':
  1126.                     game.keys.d = true;
  1127.                     break;
  1128.                 case ' ':
  1129.                     e.preventDefault();
  1130.                     splitBots();
  1131.                     break;
  1132.                 case 'm':
  1133.                     mergeBots();
  1134.                     break;
  1135.                 case 'b':
  1136.                     boostSpeed();
  1137.                     break;
  1138.                 case 'escape':
  1139.                     // Deselect all
  1140.                     game.selectedBots = [];
  1141.                     game.nanobots.forEach(bot => bot.selected = false);
  1142.                     break;
  1143.             }
  1144.         });
  1145.        
  1146.         document.addEventListener('keyup', (e) => {
  1147.             // Movement keys
  1148.             switch(e.key.toLowerCase()) {
  1149.                 case 'arrowup':
  1150.                     game.keys.up = false;
  1151.                     break;
  1152.                 case 'arrowdown':
  1153.                     game.keys.down = false;
  1154.                     break;
  1155.                 case 'arrowleft':
  1156.                     game.keys.left = false;
  1157.                     break;
  1158.                 case 'arrowright':
  1159.                     game.keys.right = false;
  1160.                     break;
  1161.                 case 'w':
  1162.                     game.keys.w = false;
  1163.                     break;
  1164.                 case 'a':
  1165.                     game.keys.a = false;
  1166.                     break;
  1167.                 case 's':
  1168.                     game.keys.s = false;
  1169.                     break;
  1170.                 case 'd':
  1171.                     game.keys.d = false;
  1172.                     break;
  1173.             }
  1174.         });
  1175.        
  1176.         // Button controls
  1177.         document.getElementById('splitBtn').addEventListener('click', splitBots);
  1178.         document.getElementById('mergeBtn').addEventListener('click', mergeBots);
  1179.         document.getElementById('boostBtn').addEventListener('click', boostSpeed);
  1180.        
  1181.         // Game loop
  1182.         function gameLoop() {
  1183.             update();
  1184.             draw();
  1185.             requestAnimationFrame(gameLoop);
  1186.         }
  1187.        
  1188.         // Start game
  1189.         init();
  1190.         gameLoop();
  1191.     </script>
  1192. </body>
  1193. </html>
  1194.  
Advertisement
Add Comment
Please, Sign In to add comment