<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <title>⚡ TERRAFOLK | Максимальная оптимизация</title>
    <link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet">
    <style>
        * {
            user-select: none;
            -webkit-tap-highlight-color: transparent;
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            background: #0a1a0a;
            overflow: hidden;
            font-family: 'Press Start 2P', monospace;
        }
        canvas {
            display: block;
            cursor: crosshair;
            image-rendering: crisp-edges;
            image-rendering: pixelated;
        }
        #ui {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            z-index: 200;
            font-size: 9px;
        }
        .panel {
            position: absolute;
            background: rgba(0, 0, 0, 0.85);
            backdrop-filter: blur(4px);
            border-radius: 12px;
            border: 1px solid #c9a03c;
            pointer-events: auto;
            padding: 5px 8px;
            color: #fff;
        }
        .stats { top: 10px; left: 10px; width: 210px; }
        .res-row { display: flex; gap: 6px; margin: 5px 0; justify-content: center; }
        .res-item { background: #1a1f12; padding: 3px 5px; border-radius: 8px; text-align: center; min-width: 50px; font-size: 7px; color: #fff; }
        .hp-bg { background: #3a1a1a; height: 8px; border-radius: 6px; overflow: hidden; margin: 4px 0; }
        #hp-fill { background: #e34d4d; width: 100%; height: 100%; transition: width 0.05s; }
        .compass { top: 10px; left: 50%; transform: translateX(-50%); text-align: center; width: 180px; background: #000000aa; padding: 4px 8px; }
        .compass-arrow { font-size: 20px; display: inline-block; filter: drop-shadow(0 0 2px gold); transition: transform 0.05s linear; }
        .quest { top: 10px; right: 10px; width: 220px; }
        #questDesc { font-size: 7px; margin-top: 3px; color: #ffefb0; }
        .build-bar { bottom: 12px; left: 50%; transform: translateX(-50%); display: flex; gap: 10px; background: #000000bb; border-radius: 40px; padding: 5px 12px; }
        .build-btn { background: #2a3620; border: 1px solid #aacc77; color: #fff9e0; padding: 4px 10px; border-radius: 30px; cursor: pointer; font-family: 'Press Start 2P'; font-size: 5px; transition: 0.02s linear; }
        .build-btn:active { transform: scale(0.96); background: #5a8242; }
        .minimap { bottom: 12px; right: 12px; width: 100px; height: 100px; background: #000000cc; border-radius: 8px; border: 1px solid #c9a03c; overflow: hidden; pointer-events: none; }
        .minimap canvas { width: 100%; height: 100%; }
        .weather-time { top: 65px; left: 10px; background: #000000aa; border-radius: 8px; padding: 3px 6px; font-size: 5px; color: #fff; }
        .dialog-box {
            position: fixed;
            bottom: 30%;
            left: 50%;
            transform: translateX(-50%);
            width: 70%;
            max-width: 400px;
            background: #020a00f2;
            border: 3px solid #f5bc70;
            border-radius: 18px;
            padding: 10px 14px;
            text-align: center;
            display: none;
            z-index: 1000;
            font-size: 8px;
            pointer-events: none;
            color: #ffeec2;
            font-family: 'Press Start 2P', monospace;
        }
        @media (max-width: 700px) { 
            .stats { width: 180px; } 
            .quest { width: 190px; } 
            .minimap { width: 80px; height: 80px; } 
            .build-btn { padding: 3px 8px; font-size: 4px; }
            .dialog-box { font-size: 6px; width: 85%; bottom: 35%; }
        }
    </style>
</head>
<body>
<canvas id="gameCanvas"></canvas>
<div id="ui">
    <div class="panel stats">
        <div class="res-row">
            <div class="res-item">🪵 <span id="woodCount">0</span></div>
            <div class="res-item">🪨 <span id="stoneCount">0</span></div>
            <div class="res-item">🔨 <span id="hammerIcon">❌</span></div>
        </div>
        <div class="hp-bg"><div id="hp-fill"></div></div>
        <div style="text-align:center; margin-top:2px; color:#fff;">🐌 <span id="killCount">0</span>/5</div>
    </div>
    <div class="panel compass">
        <div class="compass-arrow" id="compassArrow">⬆️</div>
        <div style="font-size:6px;"><span id="targetName">КУЗНЕЦ</span> <span id="targetDist">0</span> м</div>
    </div>
    <div class="panel quest">
        <div style="color:#ffcc55; font-size:7px;">✦ КВЕСТ ✦</div>
        <div id="questDesc">https://alex009910.gitverse.site/survivalgame/</div>
        <div style="font-size:4px; margin-top:2px; color:#aaa;">[E] у кузнеца</div>
    </div>
    <div class="panel build-bar">
        <div class="build-btn" id="buildWallBtn">🧱 СТЕНА (5🪵)</div>
        <div class="build-btn" id="buildTorchBtn">🔥 ФАКЕЛ (2🪵)</div>
    </div>
    <div class="panel minimap"><canvas id="minimapCanvas" width="100" height="100"></canvas></div>
    <div class="panel weather-time" id="weatherInfo">☀️ ДЕНЬ</div>
    <div id="globalDialog" class="dialog-box"></div>
</div>

<script>
    (function(){
        // ========== НАСТРОЙКИ ПРОИЗВОДИТЕЛЬНОСТИ ==========
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');
        const WORLD_W = 3500;  // Уменьшил мир для производительности
        const WORLD_H = 3500;
        
        let lastFrameTime = 0;
        let frameDelay = 16; // ~60 FPS макс
        
        // ========== ПРОСТЫЕ ТЕКСТУРЫ (без лишней детализации) ==========
        function createSimpleTexture(w, h, color1, color2) {
            let c = document.createElement('canvas');
            c.width = w; c.height = h;
            let cx = c.getContext('2d');
            cx.fillStyle = color1;
            cx.fillRect(0, 0, w, h);
            cx.fillStyle = color2;
            for(let i=0;i<30;i++) cx.fillRect(Math.random()*(w-2), Math.random()*(h-2), 2, 2);
            return c;
        }
        
        const grassTex = createSimpleTexture(64, 64, '#2d6a2a', '#3f8a3a');
        const treeTex = createSimpleTexture(48, 64, '#6b3e1a', '#2c7a2c');
        const stoneTex = createSimpleTexture(48, 48, '#6a6a88', '#8a8aaa');
        const houseTex = createSimpleTexture(80, 80, '#b56a2a', '#e5a050');
        const wallTex = createSimpleTexture(48, 48, '#8a6242', '#ad8258');
        const torchTex = createSimpleTexture(20, 32, '#7a4a22', '#ff7a3a');
        const playerTex = createSimpleTexture(32, 32, '#6faeff', '#ffe0b0');
        const npcTex = createSimpleTexture(32, 32, '#e5b45a', '#b27a42');
        const slimeTex = createSimpleTexture(28, 28, '#6fbf5a', '#a0ff8a');
        const hammerTex = createSimpleTexture(24, 24, '#e5bc5a', '#ffdd88');
        
        // Дорисуем детали на текстуры (простые)
        (function fixTextures() {
            let c = document.createElement('canvas');
            // дерево
            let t = treeTex.getContext('2d');
            t.fillStyle = '#8b5a2a'; t.fillRect(18, 48, 12, 16);
            // камень
            let s = stoneTex.getContext('2d');
            s.fillStyle = '#a0a0c0'; s.fillRect(18, 20, 6, 6); s.fillRect(32, 28, 8, 5);
            // слизень
            let sl = slimeTex.getContext('2d');
            sl.fillStyle = '#000000'; sl.fillRect(10, 12, 3, 3); sl.fillRect(16, 12, 3, 3);
        })();
        
        // ========== ЧАСТИЦЫ (ОЧЕНЬ МАЛО) ==========
        let particles = [];
        function addParticles(x, y, color, count) {
            for(let i=0;i<Math.min(count,3);i++) {
                particles.push({
                    x: x + (Math.random() - 0.5) * 10,
                    y: y + (Math.random() - 0.5) * 10,
                    vx: (Math.random() - 0.5) * 1.5,
                    vy: (Math.random() - 0.5) * 1.5 - 1,
                    life: 8,
                    color: color,
                    size: 2
                });
            }
        }
        
        // ========== УПРОЩЁННАЯ ПОГОДА ==========
        let isDay = true;
        let weather = 'clear';
        let weatherParticles = [];
        let weatherTimer = 0;
        
        function updateEnvironment() {
            weatherTimer++;
            if(weatherTimer > 300) {
                weatherTimer = 0;
                let r = Math.random();
                if(r < 0.6) weather = 'clear';
                else if(r < 0.8) weather = 'rain';
                else weather = 'snow';
            }
            // День/ночь меняется медленно
            isDay = (Math.floor(Date.now() / 30000) % 2) === 0;
            
            if(weather === 'rain' && Math.random() < 0.15) {
                weatherParticles.push({ x: Math.random() * canvas.width, y: -5, vy: 2 + Math.random() * 2 });
            }
            if(weather === 'snow' && Math.random() < 0.1) {
                weatherParticles.push({ x: Math.random() * canvas.width, y: -5, vy: 1 + Math.random() * 1.5 });
            }
            for(let i=0;i<weatherParticles.length;i++) {
                weatherParticles[i].y += weatherParticles[i].vy;
                if(weatherParticles[i].y > canvas.height + 20) weatherParticles.splice(i,1);
            }
            let weatherText = weather === 'clear' ? (isDay ? '☀️ ДЕНЬ' : '🌙 НОЧЬ') : (weather === 'rain' ? '🌧️ ДОЖДЬ' : '❄️ СНЕГ');
            document.getElementById('weatherInfo').innerHTML = weatherText;
        }
        
        // ========== МИНИ-КАРТА (ОБНОВЛЕНИЕ РАЗ В СЕКУНДУ) ==========
        const minimapCanvas = document.getElementById('minimapCanvas');
        const minimapCtx = minimapCanvas.getContext('2d');
        let minimapDirty = true;
        let cachedMinimapData = null;
        
        function updateMinimap(worldObjs, enemiesArr, px, py) {
            minimapCtx.fillStyle = '#1a2a1a';
            minimapCtx.fillRect(0, 0, 100, 100);
            for(let obj of worldObjs) {
                let mx = (obj.x / WORLD_W) * 100;
                let my = (obj.y / WORLD_H) * 100;
                if(obj.type === 'tree') minimapCtx.fillStyle = '#3aa83a';
                else if(obj.type === 'stone') minimapCtx.fillStyle = '#8a8aaa';
                else minimapCtx.fillStyle = '#d4a056';
                minimapCtx.fillRect(mx-1, my-1, 2, 2);
            }
            for(let e of enemiesArr) {
                let mx = (e.x / WORLD_W) * 100;
                let my = (e.y / WORLD_H) * 100;
                minimapCtx.fillStyle = '#ff6666';
                minimapCtx.fillRect(mx-1, my-1, 2, 2);
            }
            let mxp = (px / WORLD_W) * 100;
            let myp = (py / WORLD_H) * 100;
            minimapCtx.fillStyle = '#88ccff';
            minimapCtx.beginPath();
            minimapCtx.arc(mxp, myp, 2, 0, Math.PI*2);
            minimapCtx.fill();
        }
        
        let lastMinimapUpdate = 0;
        function throttledMinimap(worldObjs, enemiesArr, px, py) {
            const now = Date.now();
            if(now - lastMinimapUpdate > 800) {
                updateMinimap(worldObjs, enemiesArr, px, py);
                lastMinimapUpdate = now;
            }
        }
        
        // ========== ИГРОВЫЕ ДАННЫЕ ==========
        let player = { x: 1750, y: 1750, hp: 100, maxHp: 100, wood: 15, stone: 0, hasHammer: false, kills: 0 };
        let worldObjects = [];
        let enemies = [];
        const npcPos = { x: 1950, y: 1850 };
        const cavePos = { x: 650, y: 550 };
        let questStage = 0;
        let keys = { w: false, s: false, a: false, d: false };
        let attackAnim = null;
        
        // Генерация мира (уменьшенное количество объектов)
        function generateWorld() {
            worldObjects = [];
            worldObjects.push({ x: npcPos.x, y: npcPos.y-10, type: 'house' });
            for(let i=0;i<20;i++) {
                worldObjects.push({ x: cavePos.x + (Math.random()-0.5)*120, y: cavePos.y + (Math.random()-0.5)*100, type: 'stone', hp: 3 });
            }
            for(let i=0;i<250;i++) {
                let rx = Math.random() * WORLD_W;
                let ry = Math.random() * WORLD_H;
                if(Math.hypot(rx-1750, ry-1750) < 180) continue;
                if(Math.hypot(rx-npcPos.x, ry-npcPos.y) < 150) continue;
                let type = Math.random() > 0.55 ? 'tree' : 'stone';
                worldObjects.push({ x: rx, y: ry, type: type, hp: type === 'tree' ? 3 : 4 });
            }
        }
        
        function spawnSlimes(count) {
            for(let i=0;i<count;i++) {
                let x = Math.random() * WORLD_W;
                let y = Math.random() * WORLD_H;
                if(Math.hypot(x-player.x, y-player.y) < 200) continue;
                enemies.push({ x: x, y: y, hp: 2 });
            }
        }
        
        function showMessage(text, isErr=false) {
            let div = document.getElementById('globalDialog');
            div.innerText = text;
            div.style.display = 'block';
            div.style.borderColor = isErr ? '#ff8866' : '#f5bc70';
            setTimeout(() => { div.style.display = 'none'; }, 2000);
        }
        
        function updateUI() {
            document.getElementById('woodCount').innerText = player.wood;
            document.getElementById('stoneCount').innerText = player.stone;
            document.getElementById('hammerIcon').innerHTML = player.hasHammer ? '✅' : '❌';
            document.getElementById('hp-fill').style.width = (player.hp / player.maxHp * 100) + '%';
            document.getElementById('killCount').innerText = `${player.kills}/5`;
            let qTexts = ["https://alex009910.gitverse.site/survivalgame/", "🔨 НАЙТИ МОЛОТ", "⛏️ 15 КАМНЯ", "⚔️ 5 СЛИЗНЕЙ", "🏆 ПОБЕДА!"];
            document.getElementById('questDesc').innerHTML = qTexts[questStage];

            let target = (questStage === 1 && !player.hasHammer) ? cavePos : npcPos;
            let nameT = (questStage === 1 && !player.hasHammer) ? "🗻 ПЕЩЕРА" : "⚒️ КУЗНЕЦ";
            let dx = target.x - player.x;
            let dy = target.y - player.y;
            let angle = Math.atan2(dy, dx);
            document.getElementById('compassArrow').style.transform = `rotate(${angle * 180 / Math.PI + 90}deg)`;
            document.getElementById('targetName').innerHTML = nameT;
            document.getElementById('targetDist').innerText = Math.floor(Math.hypot(dx, dy) / 10);
        }
        
        function buildStructure(type) {
            let cost = type === 'wall' ? 5 : 2;
            if(player.wood >= cost) {
                player.wood -= cost;
                worldObjects.push({ x: player.x + 40, y: player.y + 30, type: type, hp: 20 });
                showMessage(`✔️ Построено!`);
                updateUI();
            } else {
                showMessage(`❌ Нужно ${cost} дерева`, true);
            }
        }
        
        function interactWithNPC() {
            let distToNpc = Math.hypot(player.x - npcPos.x, player.y - npcPos.y);
            if(distToNpc < 80) {
                if(questStage === 0 && player.wood >= 10) {
                    player.wood -= 10;
                    questStage = 1;
                    showMessage("Кузнец: 'Найди молот в пещере!'");
                    updateUI();
                } else if(questStage === 1 && player.hasHammer) {
                    questStage = 2;
                    showMessage("Кузнец: 'Собери 15 камней!'");
                    updateUI();
                } else if(questStage === 2 && player.stone >= 15) {
                    player.stone -= 15;
                    questStage = 3;
                    showMessage("Кузнец: 'Убей 5 слизней!'");
                    updateUI();
                } else if(questStage === 3 && player.kills >= 5) {
                    questStage = 4;
                    showMessage("🎉 ПОБЕДА! Ты легенда! 🎉");
                    updateUI();
                } else {
                    if(questStage === 0) showMessage(`Нужно 10 дерева (${player.wood}/10)`);
                    else if(questStage === 2) showMessage(`Нужно 15 камней (${player.stone}/15)`);
                    else if(questStage === 3) showMessage(`Убито: ${player.kills}/5`);
                }
                return true;
            }
            let distCave = Math.hypot(player.x - cavePos.x, player.y - cavePos.y);
            if(questStage === 1 && !player.hasHammer && distCave < 80) {
                player.hasHammer = true;
                showMessage("🔨 Молот найден! Вернись к кузнецу.");
                updateUI();
                return true;
            }
            return false;
        }
        
        function handleAttack(e) {
            const rect = canvas.getBoundingClientRect();
            const scaleX = canvas.width / rect.width;
            const scaleY = canvas.height / rect.height;
            let mouseX = (e.clientX - rect.left) * scaleX;
            let mouseY = (e.clientY - rect.top) * scaleY;
            let worldX = (mouseX - canvas.width/2) + player.x;
            let worldY = (mouseY - canvas.height/2) + player.y;
            
            for(let i=0;i<worldObjects.length;i++) {
                let obj = worldObjects[i];
                if((obj.type === 'tree' || obj.type === 'stone') && Math.hypot(worldX-obj.x, worldY-obj.y) < 45) {
                    obj.hp--;
                    addParticles(obj.x, obj.y, obj.type === 'tree' ? '#6a9a3a' : '#aaaacc', 2);
                    if(obj.hp <= 0) {
                        let gain = 3;
                        if(obj.type === 'tree') player.wood += gain;
                        else player.stone += gain;
                        showMessage(`+${gain} ${obj.type === 'tree' ? 'дерева' : 'камня'}`);
                        worldObjects.splice(i,1);
                    }
                    attackAnim = 5;
                    updateUI();
                    return;
                }
            }
            for(let i=0;i<enemies.length;i++) {
                let e = enemies[i];
                if(Math.hypot(worldX-e.x, worldY-e.y) < 40) {
                    e.hp--;
                    addParticles(e.x, e.y, '#ffaa66', 2);
                    if(e.hp <= 0) {
                        enemies.splice(i,1);
                        player.kills = Math.min(player.kills+1, 5);
                        showMessage(`Слизень убит! (${player.kills}/5)`);
                        if(enemies.length < 4) spawnSlimes(1);
                    }
                    attackAnim = 5;
                    updateUI();
                    return;
                }
            }
        }
        
        // ДВИЖЕНИЕ (СКОРОСТЬ 6)
        function updateMovement() {
            let speed = 6;
            let nx = player.x, ny = player.y;
            if(keys.w) ny -= speed;
            if(keys.s) ny += speed;
            if(keys.a) nx -= speed;
            if(keys.d) nx += speed;
            player.x = Math.min(WORLD_W - 40, Math.max(40, nx));
            player.y = Math.min(WORLD_H - 40, Math.max(40, ny));
            
            if(player.hp < player.maxHp && Math.random() < 0.01) {
                player.hp = Math.min(player.maxHp, player.hp + 0.5);
                updateUI();
            }
            
            for(let i=0;i<enemies.length;i++) {
                let e = enemies[i];
                let dx = player.x - e.x;
                let dy = player.y - e.y;
                let dist = Math.hypot(dx, dy);
                if(dist < 200) {
                    let angle = Math.atan2(dy, dx);
                    e.x += Math.cos(angle) * 1.2;
                    e.y += Math.sin(angle) * 1.2;
                }
                if(dist < 35 && Math.random() < 0.03) {
                    player.hp = Math.max(0, player.hp - 3);
                    updateUI();
                    if(player.hp <= 0) {
                        showMessage("💀 Возрождение...");
                        player.hp = player.maxHp;
                        player.x = 1750;
                        player.y = 1750;
                        updateUI();
                    }
                }
                e.x = Math.min(WORLD_W - 25, Math.max(25, e.x));
                e.y = Math.min(WORLD_H - 25, Math.max(25, e.y));
            }
            
            if(attackAnim) attackAnim--;
            updateEnvironment();
        }
        
        // ОПТИМИЗИРОВАННАЯ ОТРИСОВКА
        function render() {
            const camX = canvas.width/2 - player.x;
            const camY = canvas.height/2 - player.y;
            
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            
            // Трава (только видимая область)
            const startCol = Math.max(0, Math.floor((-camX) / 64));
            const endCol = Math.min(Math.ceil(WORLD_W / 64), Math.floor((-camX + canvas.width) / 64) + 2);
            const startRow = Math.max(0, Math.floor((-camY) / 64));
            const endRow = Math.min(Math.ceil(WORLD_H / 64), Math.floor((-camY + canvas.height) / 64) + 2);
            
            for(let i = startCol; i <= endCol; i++) {
                for(let j = startRow; j <= endRow; j++) {
                    ctx.drawImage(grassTex, i * 64 + camX, j * 64 + camY, 64, 64);
                }
            }
            
            // Объекты (простые прямоугольники для ускорения)
            for(let obj of worldObjects) {
                let tx = obj.x + camX;
                let ty = obj.y + camY;
                let tex = null;
                if(obj.type === 'tree') tex = treeTex;
                else if(obj.type === 'stone') tex = stoneTex;
                else if(obj.type === 'house') tex = houseTex;
                else if(obj.type === 'wall') tex = wallTex;
                else if(obj.type === 'torch') tex = torchTex;
                if(tex) ctx.drawImage(tex, tx - (obj.type === 'house' ? 40 : 24), ty - (obj.type === 'house' ? 40 : 32), 
                    (obj.type === 'house' ? 80 : (obj.type === 'torch' ? 20 : 48)), 
                    (obj.type === 'house' ? 80 : (obj.type === 'torch' ? 32 : 48)));
            }
            
            // Враги
            for(let e of enemies) {
                ctx.drawImage(slimeTex, e.x + camX - 14, e.y + camY - 14, 28, 28);
                // Полоска HP врага
                let hpPercent = e.hp / 2;
                ctx.fillStyle = '#600000';
                ctx.fillRect(e.x + camX - 12, e.y + camY - 20, 24, 3);
                ctx.fillStyle = '#e05555';
                ctx.fillRect(e.x + camX - 12, e.y + camY - 20, 24 * hpPercent, 3);
            }
            
            // NPC
            ctx.drawImage(npcTex, npcPos.x + camX - 16, npcPos.y + camY - 24, 32, 32);
            
            // Молот
            if(questStage === 1 && !player.hasHammer) {
                ctx.drawImage(hammerTex, cavePos.x + camX - 12, cavePos.y + camY - 12, 24, 24);
            }
            
            // Игрок
            ctx.drawImage(playerTex, player.x + camX - 16, player.y + camY - 24, 32, 32);
            
            // Полоска здоровья игрока под ногами
            let hpPercent = player.hp / player.maxHp;
            ctx.fillStyle = '#600000';
            ctx.fillRect(player.x + camX - 20, player.y + camY - 30, 40, 4);
            ctx.fillStyle = '#e34d4d';
            ctx.fillRect(player.x + camX - 20, player.y + camY - 30, 40 * hpPercent, 4);
            
            // Частицы
            for(let i=0;i<particles.length;i++) {
                let p = particles[i];
                ctx.fillStyle = p.color;
                ctx.fillRect(p.x + camX, p.y + camY, p.size, p.size);
                p.x += p.vx;
                p.y += p.vy;
                p.life--;
                if(p.life <= 0) particles.splice(i,1);
            }
            
            // Эффект атаки
            if(attackAnim) {
                ctx.fillStyle = '#ffaa4488';
                ctx.beginPath();
                ctx.arc(player.x + camX, player.y + camY - 8, 18, 0, Math.PI*2);
                ctx.fill();
            }
            
            // Погода
            for(let p of weatherParticles) {
                if(weather === 'rain') ctx.fillStyle = '#88bbffaa';
                else ctx.fillStyle = '#ffffffcc';
                ctx.fillRect(p.x, p.y, 2, 2);
            }
            
            // Наложение ночи
            if(!isDay) {
                ctx.fillStyle = '#00000088';
                ctx.fillRect(0, 0, canvas.width, canvas.height);
            } else if(weather === 'rain') {
                ctx.fillStyle = '#88aaff22';
                ctx.fillRect(0, 0, canvas.width, canvas.height);
            }
            
            throttledMinimap(worldObjects, enemies, player.x, player.y);
        }
        
        // Ограничение FPS для снижения нагрузки
        function gameLoop(now) {
            requestAnimationFrame(gameLoop);
            if(now - lastFrameTime < frameDelay) return;
            lastFrameTime = now;
            updateMovement();
            render();
        }
        
        function init() {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
            generateWorld();
            spawnSlimes(5);
            player.hp = 100;
            player.wood = 15;
            player.stone = 0;
            player.hasHammer = false;
            player.kills = 0;
            questStage = 0;
            player.x = 1750;
            player.y = 1750;
            updateUI();
            
            window.addEventListener('resize', () => {
                canvas.width = window.innerWidth;
                canvas.height = window.innerHeight;
            });
            window.addEventListener('keydown', (e) => {
                let k = e.code;
                if(k === 'KeyW') keys.w = true;
                if(k === 'KeyS') keys.s = true;
                if(k === 'KeyA') keys.a = true;
                if(k === 'KeyD') keys.d = true;
                if(k === 'KeyE') { e.preventDefault(); interactWithNPC(); }
            });
            window.addEventListener('keyup', (e) => {
                let k = e.code;
                if(k === 'KeyW') keys.w = false;
                if(k === 'KeyS') keys.s = false;
                if(k === 'KeyA') keys.a = false;
                if(k === 'KeyD') keys.d = false;
            });
            canvas.addEventListener('click', handleAttack);
            document.getElementById('buildWallBtn').onclick = () => buildStructure('wall');
            document.getElementById('buildTorchBtn').onclick = () => buildStructure('torch');
            requestAnimationFrame(gameLoop);
            setInterval(() => {
                if(enemies.length < 3 && questStage < 4) spawnSlimes(2);
            }, 20000);
        }
        
        init();
    })();
</script>
</body>
</html>
```