🎮ArcadeLab

Лабиринт играть онлайн

by WildFalcon36
2931 lines111.2 KB
▶ Play
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Лабиринт играть онлайн</title>
    <style>
        * {
            box-sizing: border-box;
            user-select: none;
        }

        body {
            margin: 0;
            min-height: 100vh;
            background: linear-gradient(145deg, #1a2a3a, #0f1a24);
            display: flex;
            justify-content: center;
            align-items: center;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }

        .game-wrapper {
            display: flex;
            flex-wrap: wrap;
            align-items: flex-start;
            justify-content: center;
            gap: 20px;
        }

        .left-panel {
            background: #1f3340;
            border-radius: 20px;
            padding: 20px 16px;
            box-shadow: inset 0 0 0 2px #3a5a6e, 0 10px 15px rgba(0, 0, 0, 0.5);
            display: flex;
            flex-direction: column;
            align-items: center;
            min-width: 180px;
            max-width: 220px;
            margin-top: 10px;
            text-align: center;
        }

        .pause-btn {
            background: #4a6a7f;
            border: none;
            border-radius: 50%;
            width: 64px;
            height: 64px;
            font-size: 32px;
            color: #f0f9ff;
            cursor: pointer;
            box-shadow: 0 6px 0 #1f3340, 0 8px 12px rgba(0, 0, 0, 0.3);
            transition: all 0.08s ease;
            display: flex;
            align-items: center;
            justify-content: center;
            margin-bottom: 16px;
            touch-action: none;
        }

        .pause-btn:active {
            transform: translateY(5px);
            box-shadow: 0 1px 0 #1f3340, 0 5px 10px rgba(0, 0, 0, 0.3);
        }

        .pause-btn:hover {
            background: #5c7f97;
        }

        .instructions {
            color: #b8d4e8;
            font-size: 0.9rem;
            line-height: 1.6;
            margin-bottom: 12px;
            text-align: left;
            width: 100%;
        }

        .instructions p {
            margin: 4px 0;
        }

        .mode-task {
            color: #f7d44a;
            font-size: 1.0rem;
            font-weight: 600;
            background: #0f1a24;
            border-radius: 12px;
            padding: 10px 12px;
            margin: 8px 0 12px 0;
            width: 100%;
            text-align: center;
            border: 1px solid #3a5a6e;
            box-shadow: inset 0 0 8px rgba(0,0,0,0.3);
        }

        .mode-task span {
            display: block;
            font-size: 0.85rem;
            font-weight: 400;
            color: #b8d4e8;
            margin-top: 4px;
        }

        .creator {
            color: #f7d44a;
            font-size: 0.9rem;
            font-weight: 500;
            border-top: 1px solid #3a5a6e;
            padding-top: 10px;
            margin-top: 8px;
            width: 100%;
        }

        .game-container {
            background: #2a3f4f;
            padding: 30px 20px 20px 20px;
            border-radius: 40px;
            box-shadow: 0 20px 30px rgba(0, 0, 0, 0.7), inset 0 2px 5px rgba(255, 255, 255, 0.1);
            display: flex;
            flex-direction: column;
            align-items: center;
            position: relative;
        }

        canvas {
            display: block;
            background: #1e2e3b;
            border-radius: 20px;
            box-shadow: inset 0 0 0 2px #3f5a6b, 0 10px 15px rgba(0, 0, 0, 0.5);
            width: 450px;
            height: 450px;
            image-rendering: pixelated;
            touch-action: none;
        }

        .right-panel {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 12px;
            margin-top: 10px;
        }

        .controls-container {
            background: #1f3340;
            border-radius: 20px;
            padding: 15px;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            box-shadow: inset 0 0 0 2px #3a5a6e, 0 10px 15px rgba(0, 0, 0, 0.5);
            width: 130px;
            height: 130px;
        }

        .arrow-grid {
            display: grid;
            grid-template-columns: 50px 50px 50px;
            grid-template-rows: 50px 50px 50px;
            gap: 4px;
            justify-items: center;
            align-items: center;
        }

        .arrow-btn {
            width: 50px;
            height: 50px;
            background: #4a6a7f;
            border: none;
            border-radius: 12px;
            color: #f0f9ff;
            font-size: 26px;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            box-shadow: 0 4px 0 #1f3340, 0 6px 10px rgba(0, 0, 0, 0.3);
            transition: all 0.06s ease;
            touch-action: none;
        }

        .arrow-btn:active {
            transform: translateY(4px);
            box-shadow: 0 1px 0 #1f3340, 0 4px 8px rgba(0, 0, 0, 0.3);
        }

        .arrow-btn:hover {
            background: #5c7f97;
        }

        .arrow-btn.empty {
            background: transparent;
            box-shadow: none;
            cursor: default;
        }

        .arrow-btn.empty:hover {
            background: transparent;
        }

        .shop-section {
            background: #1f3340;
            border-radius: 20px;
            padding: 12px 10px;
            box-shadow: inset 0 0 0 2px #3a5a6e, 0 10px 15px rgba(0, 0, 0, 0.5);
            width: 130px;
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 6px;
        }

        .shop-btn {
            background: #4a6a7f;
            border: none;
            border-radius: 30px;
            padding: 6px 12px;
            font-size: 0.9rem;
            font-weight: 700;
            color: #f0f9ff;
            cursor: pointer;
            box-shadow: 0 4px 0 #1f3340, 0 6px 10px rgba(0, 0, 0, 0.3);
            transition: all 0.08s ease;
            width: 100%;
            letter-spacing: 0.5px;
        }

        .shop-btn:active {
            transform: translateY(4px);
            box-shadow: 0 1px 0 #1f3340, 0 4px 8px rgba(0, 0, 0, 0.3);
        }

        .shop-btn:hover {
            background: #5c7f97;
        }

        .slots-grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 8px;
            width: 100%;
        }

        .slot-item {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 2px;
            cursor: pointer;
        }

        .slot {
            background: #0f1a24;
            border: 2px solid #3a5a6e;
            border-radius: 8px;
            padding: 4px;
            width: 100%;
            aspect-ratio: 1;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 1.4rem;
            color: #b8d4e8;
            box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.5);
            transition: border-color 0.2s;
            min-height: 36px;
        }

        .slot:hover {
            border-color: #f7d44a;
        }

        .slot-count {
            color: #b8d4e8;
            font-size: 0.8rem;
            font-weight: 600;
            text-align: center;
            background: #0f1a24;
            padding: 0 6px;
            border-radius: 4px;
            border: 1px solid #2a3f4f;
            min-width: 20px;
            line-height: 1.4;
        }

        .shop-overlay {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100vw;
            height: 100vh;
            background: rgba(0, 0, 0, 0.75);
            backdrop-filter: blur(8px);
            z-index: 1000;
            justify-content: center;
            align-items: center;
        }

        .shop-overlay.active {
            display: flex;
        }

        .shop-modal {
            background: #2a3f4f;
            border-radius: 30px;
            padding: 30px 35px 35px 35px;
            max-width: 500px;
            width: 90%;
            box-shadow: 0 20px 40px rgba(0, 0, 0, 0.8), inset 0 0 0 2px #3f5a6b;
            color: #b8d4e8;
            position: relative;
            max-height: 90vh;
            overflow-y: auto;
        }

        .shop-modal h2 {
            color: #f7d44a;
            text-align: center;
            font-size: 2rem;
            margin: 0 0 6px 0;
            text-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
        }

        .shop-modal .close-hint {
            text-align: center;
            font-size: 0.8rem;
            color: #7e9fb0;
            margin-bottom: 20px;
        }

        .shop-items {
            display: flex;
            flex-direction: column;
            gap: 12px;
        }

        .shop-item {
            display: flex;
            align-items: center;
            gap: 14px;
            background: #1f3340;
            border-radius: 16px;
            padding: 10px 16px;
            border: 1px solid #3a5a6e;
            transition: all 0.15s;
        }

        .shop-item:hover {
            border-color: #f7d44a;
            background: #26404f;
        }

        .shop-item .icon {
            font-size: 2.2rem;
            min-width: 50px;
            text-align: center;
        }

        .shop-item .info {
            flex: 1;
        }

        .shop-item .info .name {
            font-weight: 600;
            font-size: 1.1rem;
            color: #f0f9ff;
        }

        .shop-item .info .desc {
            font-size: 0.85rem;
            color: #7e9fb0;
            margin-top: 2px;
        }

        .shop-item .price {
            font-size: 1.1rem;
            font-weight: 700;
            color: #f7d44a;
            background: #0f1a24;
            padding: 4px 12px;
            border-radius: 20px;
            border: 1px solid #3a5a6e;
            white-space: nowrap;
        }

        .shop-item .buy-btn {
            background: #4a6a7f;
            border: none;
            border-radius: 30px;
            padding: 6px 18px;
            font-size: 1rem;
            font-weight: 700;
            color: #f0f9ff;
            cursor: pointer;
            box-shadow: 0 4px 0 #1f3340;
            transition: all 0.08s ease;
        }

        .shop-item .buy-btn:active {
            transform: translateY(4px);
            box-shadow: 0 1px 0 #1f3340;
        }

        .shop-item .buy-btn:hover {
            background: #5c7f97;
        }

        .shop-item .buy-btn:disabled {
            opacity: 0.4;
            transform: none;
            box-shadow: 0 4px 0 #1f3340;
            cursor: not-allowed;
        }

        .shop-close-btn {
            display: block;
            margin: 20px auto 0 auto;
            background: #4a6a7f;
            border: none;
            border-radius: 30px;
            padding: 10px 30px;
            font-size: 1rem;
            font-weight: 700;
            color: #f0f9ff;
            cursor: pointer;
            box-shadow: 0 4px 0 #1f3340;
            transition: all 0.08s ease;
        }

        .shop-close-btn:active {
            transform: translateY(4px);
            box-shadow: 0 1px 0 #1f3340;
        }

        .shop-close-btn:hover {
            background: #5c7f97;
        }

        .info-panel {
            width: 100%;
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-top: 18px;
            padding: 0 10px;
            flex-wrap: wrap;
            gap: 8px;
        }

        .status {
            color: #b8d4e8;
            font-size: 1.2rem;
            font-weight: 600;
            text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
            letter-spacing: 0.5px;
            flex: 1 1 auto;
        }

        .status span {
            color: #f7d44a;
            font-weight: 700;
        }

        .stats {
            display: flex;
            gap: 20px;
            color: #b8d4e8;
            font-size: 1.0rem;
            font-weight: 500;
            background: #1f3340;
            padding: 6px 16px;
            border-radius: 40px;
            box-shadow: inset 0 2px 4px rgba(0,0,0,0.3);
            flex-wrap: wrap;
            justify-content: center;
        }

        .stats span {
            color: #f7d44a;
            font-weight: 700;
        }

        .difficulty-selector {
            display: flex;
            gap: 6px;
            background: #1f3340;
            padding: 4px 10px;
            border-radius: 40px;
            box-shadow: inset 0 2px 4px rgba(0,0,0,0.3);
            flex-wrap: wrap;
            justify-content: center;
        }

        .difficulty-selector button {
            background: transparent;
            border: none;
            color: #7e9fb0;
            font-weight: 600;
            font-size: 0.75rem;
            padding: 4px 8px;
            border-radius: 30px;
            cursor: pointer;
            transition: all 0.2s;
            box-shadow: none;
            text-shadow: none;
            margin: 0;
            white-space: nowrap;
            position: relative;
        }

        .difficulty-selector button:hover:not(.locked) {
            background: #3a5a6e;
            color: #f0f9ff;
        }

        .difficulty-selector button.active {
            background: #4a6a7f;
            color: #f0f9ff;
            box-shadow: 0 2px 0 #1f3340;
        }

        .difficulty-selector button.locked {
            opacity: 0.5;
            cursor: not-allowed;
            color: #5a7a8a;
        }

        button {
            background: #4a6a7f;
            border: none;
            border-radius: 30px;
            padding: 10px 28px;
            font-size: 1rem;
            font-weight: 700;
            color: #f0f9ff;
            text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
            box-shadow: 0 6px 0 #1f3340, 0 8px 12px rgba(0, 0, 0, 0.3);
            cursor: pointer;
            transition: all 0.08s ease;
            letter-spacing: 0.8px;
        }

        button:active {
            transform: translateY(5px);
            box-shadow: 0 1px 0 #1f3340, 0 5px 10px rgba(0, 0, 0, 0.3);
        }

        button:hover {
            background: #5c7f97;
            box-shadow: 0 6px 0 #26404f, 0 8px 14px rgba(0, 0, 0, 0.4);
        }

        #nextDifficultyButton {
            display: none;
            background: #f7d44a;
            color: #1a2a3a;
            box-shadow: 0 6px 0 #b8860b, 0 8px 12px rgba(0, 0, 0, 0.3);
            margin-top: 10px;
            font-size: 1.1rem;
        }

        #nextDifficultyButton:hover {
            background: #ffe066;
            box-shadow: 0 6px 0 #b8860b, 0 8px 14px rgba(0, 0, 0, 0.4);
        }

        @media (max-width: 850px) {
            .game-wrapper {
                flex-direction: column;
                align-items: center;
                gap: 10px;
            }
            .left-panel {
                flex-direction: row;
                flex-wrap: wrap;
                justify-content: center;
                min-width: unset;
                max-width: unset;
                width: 100%;
                padding: 12px 16px;
                gap: 12px;
            }
            .left-panel .pause-btn {
                width: 48px;
                height: 48px;
                font-size: 24px;
                margin-bottom: 0;
            }
            .left-panel .instructions {
                display: flex;
                flex-wrap: wrap;
                justify-content: center;
                gap: 6px 16px;
                width: auto;
                margin-bottom: 0;
                font-size: 0.8rem;
            }
            .left-panel .instructions p {
                margin: 0;
            }
            .left-panel .mode-task {
                font-size: 0.9rem;
                padding: 6px 10px;
                margin: 4px 0 8px 0;
                width: auto;
                flex: 1 1 auto;
                min-width: 150px;
            }
            .left-panel .mode-task span {
                font-size: 0.75rem;
            }
            .left-panel .creator {
                border-top: none;
                padding-top: 0;
                margin-top: 0;
                width: auto;
                font-size: 0.8rem;
            }
            .right-panel {
                flex-direction: row;
                flex-wrap: wrap;
                justify-content: center;
                gap: 10px;
                width: 100%;
            }
            .controls-container {
                width: 120px;
                height: 120px;
                padding: 10px;
            }
            .arrow-grid {
                grid-template-columns: 40px 40px 40px;
                grid-template-rows: 40px 40px 40px;
                gap: 3px;
            }
            .arrow-btn {
                width: 40px;
                height: 40px;
                font-size: 20px;
            }
            .shop-section {
                width: 140px;
                padding: 10px;
            }
            .slots-grid {
                gap: 6px;
            }
            .slot {
                min-height: 32px;
                font-size: 1.2rem;
            }
            .slot-count {
                font-size: 0.7rem;
            }
            .game-container {
                padding: 20px 10px 10px 10px;
            }
            canvas {
                width: 330px;
                height: 330px;
            }
            .info-panel {
                flex-direction: column;
                align-items: stretch;
                gap: 6px;
            }
            .stats {
                justify-content: space-around;
            }
            .difficulty-selector {
                justify-content: center;
            }
            button {
                padding: 8px 20px;
                font-size: 0.9rem;
            }
            #nextDifficultyButton {
                font-size: 1rem;
                padding: 8px 20px;
            }
            .shop-modal {
                padding: 20px;
            }
            .shop-item {
                flex-wrap: wrap;
                gap: 8px;
            }
            .shop-item .price {
                font-size: 0.9rem;
                padding: 2px 10px;
            }
            .shop-item .buy-btn {
                font-size: 0.9rem;
                padding: 4px 14px;
            }
        }

        @media (max-width: 450px) {
            canvas {
                width: 280px;
                height: 280px;
            }
            .left-panel {
                padding: 8px 10px;
                gap: 8px;
            }
            .left-panel .pause-btn {
                width: 40px;
                height: 40px;
                font-size: 20px;
            }
            .left-panel .instructions p {
                font-size: 0.7rem;
            }
            .left-panel .mode-task {
                font-size: 0.8rem;
                padding: 4px 8px;
            }
            .left-panel .creator {
                font-size: 0.7rem;
            }
            .right-panel {
                flex-direction: column;
                align-items: center;
                gap: 8px;
            }
            .controls-container {
                width: 100px;
                height: 100px;
                padding: 8px;
            }
            .arrow-grid {
                grid-template-columns: 32px 32px 32px;
                grid-template-rows: 32px 32px 32px;
                gap: 2px;
            }
            .arrow-btn {
                width: 32px;
                height: 32px;
                font-size: 16px;
            }
            .shop-section {
                width: 110px;
                padding: 8px;
            }
            .slots-grid {
                gap: 4px;
            }
            .slot {
                min-height: 28px;
                font-size: 1.0rem;
            }
            .slot-count {
                font-size: 0.65rem;
            }
            .shop-modal {
                padding: 16px;
            }
            .shop-item .icon {
                font-size: 1.6rem;
                min-width: 36px;
            }
            .shop-item .info .name {
                font-size: 0.95rem;
            }
            .shop-item .info .desc {
                font-size: 0.75rem;
            }
        }
    </style>
</head>
<body>
    <div class="game-wrapper">
        <!-- Левая панель -->
        <div class="left-panel">
            <button class="pause-btn" id="pauseButton" title="Пауза (Q/Й)">⚙️</button>
            <div class="mode-task" id="modeTask">
                Задание:
                <span id="modeTaskText">Собери все яблоки 🍎 и уворачивайся от черепов 💀 и врагов 👾</span>
            </div>
            <div class="instructions">
                <p>← ↑ → ↓ / WASD — ход</p>
                <p>Q/Й — пауза</p>
                <p>E/У — магазин</p>
                <p>Shift — новая игра</p>
                <p>Пробел — след. уровень (при победе)</p>
                <p>1-4 — активация предметов</p>
            </div>
            <div class="creator">Создатель игры — riavly (Максим),<br>любит кириешки с соусом</div>
        </div>

        <!-- Игровое поле -->
        <div class="game-container">
            <canvas id="mazeCanvas" width="450" height="450"></canvas>

            <div class="info-panel">
                <div class="status" id="statusDisplay">🚀 Игра <span>активна</span></div>
                <div class="stats">
                    <span>❤️ <span id="livesCounter">3</span></span>
                    <span>⭐ <span id="starsBalance">0</span></span>
                    <span>🍎 <span id="appleProgress">0/20</span></span>
                    <span>🚶 <span id="stepCounter">0</span></span>
                    <span>⏱️ <span id="timeCounter">0</span>с</span>
                    <span id="appleStat">🍎 <span id="itemCounter">0</span>/<span id="totalItems">0</span></span>
                </div>
                <div class="difficulty-selector">
                    <button data-diff="easy" class="active">😊 Простой</button>
                    <button data-diff="medium" class="locked">🤔 Средний 🔒</button>
                    <button data-diff="hard" class="locked">😈 Сложный 🔒</button>
                    <button data-diff="mega" class="locked">🗺️ Мега 🔒</button>
                    <button data-diff="survival" class="locked">🔥 Выживание 🔒</button>
                </div>
                <button id="resetButton">🔄 Новая игра</button>
            </div>
            <button id="nextDifficultyButton">➡️ Следующая сложность</button>
        </div>

        <!-- Правая панель -->
        <div class="right-panel">
            <div class="controls-container">
                <div class="arrow-grid">
                    <div></div>
                    <button class="arrow-btn" id="arrow-up">▲</button>
                    <div></div>
                    <button class="arrow-btn" id="arrow-left">◄</button>
                    <div class="arrow-btn empty"></div>
                    <button class="arrow-btn" id="arrow-right">►</button>
                    <div></div>
                    <button class="arrow-btn" id="arrow-down">▼</button>
                    <div></div>
                </div>
            </div>

            <div class="shop-section">
                <button class="shop-btn" id="shopButton">🏪 Магазин</button>
                <div class="slots-grid">
                    <div class="slot-item" data-key="lightning">
                        <div class="slot">⚡</div>
                        <span class="slot-count" id="count-lightning">0</span>
                    </div>
                    <div class="slot-item" data-key="pickaxe">
                        <div class="slot">⛏️</div>
                        <span class="slot-count" id="count-pickaxe">0</span>
                    </div>
                    <div class="slot-item" data-key="cake">
                        <div class="slot">🎂</div>
                        <span class="slot-count" id="count-cake">0</span>
                    </div>
                    <div class="slot-item" data-key="clock">
                        <div class="slot">⏰</div>
                        <span class="slot-count" id="count-clock">0</span>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Модальное окно магазина -->
    <div class="shop-overlay" id="shopOverlay">
        <div class="shop-modal">
            <h2>🏪 Магазин</h2>
            <div class="close-hint">Нажмите E / У или ✕ для закрытия</div>
            <div class="shop-items" id="shopItems"></div>
            <button class="shop-close-btn" id="shopCloseBtn">✕ Закрыть</button>
        </div>
    </div>

    <script>
        // ========== ЗВУКОВЫЕ ЭФФЕКТЫ (Web Audio API) ==========
        let audioCtx = null;

        function getAudioContext() {
            if (!audioCtx) {
                audioCtx = new (window.AudioContext || window.webkitAudioContext)();
            }
            return audioCtx;
        }

        // Шаг — короткий щелчок
        function playStepSound() {
            try {
                const ctx = getAudioContext();
                const osc = ctx.createOscillator();
                const gain = ctx.createGain();
                osc.connect(gain);
                gain.connect(ctx.destination);
                osc.frequency.value = 400;
                osc.type = 'sine';
                gain.gain.setValueAtTime(0.03, ctx.currentTime);
                gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.05);
                osc.start(ctx.currentTime);
                osc.stop(ctx.currentTime + 0.05);
            } catch (e) { /* тихо игнорируем ошибки */ }
        }

        // Яблоко — приятный звон
        function playAppleSound() {
            try {
                const ctx = getAudioContext();
                const osc = ctx.createOscillator();
                const gain = ctx.createGain();
                osc.connect(gain);
                gain.connect(ctx.destination);
                osc.frequency.setValueAtTime(880, ctx.currentTime);
                osc.frequency.exponentialRampToValueAtTime(1320, ctx.currentTime + 0.1);
                osc.type = 'sine';
                gain.gain.setValueAtTime(0.08, ctx.currentTime);
                gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.12);
                osc.start(ctx.currentTime);
                osc.stop(ctx.currentTime + 0.12);
            } catch (e) { /* тихо игнорируем ошибки */ }
        }

        // Ловушка — низкий грохот
        function playTrapSound() {
            try {
                const ctx = getAudioContext();
                // Смесь шума и низкого тона
                const bufferSize = ctx.sampleRate * 0.2;
                const buffer = ctx.createBuffer(1, bufferSize, ctx.sampleRate);
                const data = buffer.getChannelData(0);
                for (let i = 0; i < bufferSize; i++) {
                    data[i] = (Math.random() * 2 - 1) * Math.exp(-i / bufferSize * 3);
                }
                const noise = ctx.createBufferSource();
                noise.buffer = buffer;
                const gain = ctx.createGain();
                noise.connect(gain);
                gain.connect(ctx.destination);
                gain.gain.setValueAtTime(0.06, ctx.currentTime);
                gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.2);
                noise.start(ctx.currentTime);
                noise.stop(ctx.currentTime + 0.2);

                // Добавим низкий удар
                const osc = ctx.createOscillator();
                const gain2 = ctx.createGain();
                osc.connect(gain2);
                gain2.connect(ctx.destination);
                osc.frequency.setValueAtTime(150, ctx.currentTime);
                osc.frequency.exponentialRampToValueAtTime(80, ctx.currentTime + 0.15);
                osc.type = 'sawtooth';
                gain2.gain.setValueAtTime(0.04, ctx.currentTime);
                gain2.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.15);
                osc.start(ctx.currentTime);
                osc.stop(ctx.currentTime + 0.15);
            } catch (e) { /* тихо игнорируем ошибки */ }
        }


        // --- Конфигурация сложности ---
        const DIFFICULTY = {
            easy:   { size: 15, extraPassages: 0.30, itemCount: 4, trapCount: 3, enemyInterval: 1000, survival: false, mega: false },
            medium: { size: 20, extraPassages: 0.25, itemCount: 6, trapCount: 5, enemyInterval: 750, survival: false, mega: false },
            hard:   { size: 25, extraPassages: 0.05, itemCount: 8, trapCount: 7, enemyInterval: 500, survival: false, mega: false },
            mega:   { size: 30, extraPassages: 0.05, itemCount: 0, trapCount: 0, enemyInterval: 0, survival: false, mega: true },
            survival: { size: 20, extraPassages: 0.25, itemCount: 5, trapCount: 0, enemyInterval: 500, survival: true, mega: false }
        };

        const MAIN_CYCLE = ['easy', 'medium', 'hard', 'mega'];
        const APPLES_PER_LIFE = 20;
        const BOMB_FUSE_TIME = 2;

        const SHOP_ITEMS = [
            { id: 'lightning', icon: '⚡', name: 'Молния', desc: 'Двойной шаг на 10 сек', price: 3, key: 'lightning' },
            { id: 'pickaxe',   icon: '⛏️', name: 'Кирка', desc: 'Ходить по стенам 5 сек', price: 5, key: 'pickaxe' },
            { id: 'cake',      icon: '🎂', name: 'Торт', desc: '+1 жизнь', price: 7, key: 'cake' },
            { id: 'clock',     icon: '⏰', name: 'Часы', desc: 'Замедляет врагов на 5 сек', price: 10, key: 'clock' }
        ];

        // --- DOM элементы ---
        const canvas = document.getElementById('mazeCanvas');
        const ctx = canvas.getContext('2d');
        const statusDisplay = document.getElementById('statusDisplay');
        const stepCounter = document.getElementById('stepCounter');
        const timeCounter = document.getElementById('timeCounter');
        const itemCounter = document.getElementById('itemCounter');
        const totalItemsSpan = document.getElementById('totalItems');
        const livesCounter = document.getElementById('livesCounter');
        const appleProgress = document.getElementById('appleProgress');
        const starsBalanceSpan = document.getElementById('starsBalance');
        const diffButtons = document.querySelectorAll('.difficulty-selector button');
        const nextDiffButton = document.getElementById('nextDifficultyButton');
        const pauseButton = document.getElementById('pauseButton');
        const modeTaskText = document.getElementById('modeTaskText');
        const shopOverlay = document.getElementById('shopOverlay');
        const shopItemsContainer = document.getElementById('shopItems');
        const shopCloseBtn = document.getElementById('shopCloseBtn');
        const shopButton = document.getElementById('shopButton');

        const countCake = document.getElementById('count-cake');
        const countClock = document.getElementById('count-clock');
        const countLightning = document.getElementById('count-lightning');
        const countPickaxe = document.getElementById('count-pickaxe');

        // --- Инвентарь и валюты ---
        const inventory = { cake: 0, clock: 0, lightning: 0, pickaxe: 0 };
        let appleBalance = 0;
        let starsBalance = 0;

        function updateInventoryDisplay() {
            countCake.textContent = inventory.cake;
            countClock.textContent = inventory.clock;
            countLightning.textContent = inventory.lightning;
            countPickaxe.textContent = inventory.pickaxe;
        }

        function updateStarsDisplay() {
            starsBalanceSpan.textContent = starsBalance;
        }

        // --- Предметы на поле ---
        let fieldItems = [];

        // --- Активные эффекты ---
        let doubleStepActive = false;
        let pickaxeActive = false;
        let lightningTimer = null;
        let pickaxeTimer = null;

        // --- Кнопки-стрелки ---
        const arrowUp = document.getElementById('arrow-up');
        const arrowDown = document.getElementById('arrow-down');
        const arrowLeft = document.getElementById('arrow-left');
        const arrowRight = document.getElementById('arrow-right');

        // --- Переменные состояния ---
        let currentSize = 15;
        let cellSize = canvas.width / currentSize;

        let maze = [];
        let playerX = 1;
        let playerY = 1;
        let exitX, exitY;
        let gameOver = false;
        let gameWon = false;

        let items = [];
        let traps = [];
        let collectedItems = 0;
        let totalItems = 0;
        let exitVisible = false;
        let isSurvival = false;
        let isMega = false;

        let lives = 3;
        let applesSinceLastLife = 0;

        let steps = 0;
        let seconds = 0;
        let timerInterval = null;
        let timerStarted = false;

        let enemies = [];
        let enemyInterval = null;
        let currentEnemyIntervalMs = 500;

        let currentDifficulty = 'easy';

        let isPaused = false;
        let isShopOpen = false;
        let redFlash = false;
        let redFlashTimeout = null;
        let yellowFlash = false;
        let yellowFlashTimeout = null;

        let explosionZone = null;
        let shield = null;
        let shieldRespawnTimeout = null;

        let bossHP = 10;
        const MAX_BOSS_HP = 10;
        let sword = null;
        let hasSword = false;

        let bomb = null;
        let bombSpawnTimer = 3;

        let unlocked = {
            easy: true,
            medium: false,
            hard: false,
            mega: false,
            survival: false
        };

        let secret = { pressed6: false, timestamp: 0 };

        // --- Вспомогательные функции ---
        function getSizeFromDifficulty(diffKey) {
            return DIFFICULTY[diffKey].size;
        }

        function getExtraPassages(diffKey) {
            return DIFFICULTY[diffKey].extraPassages;
        }

        function getItemCount(diffKey) {
            return DIFFICULTY[diffKey].itemCount;
        }

        function getTrapCount(diffKey) {
            return DIFFICULTY[diffKey].trapCount;
        }

        function getEnemyInterval(diffKey) {
            return DIFFICULTY[diffKey].enemyInterval;
        }

        function isSurvivalMode(diffKey) {
            return DIFFICULTY[diffKey].survival || false;
        }

        function isMegaMode(diffKey) {
            return DIFFICULTY[diffKey].mega || false;
        }

        function updateModeInstructions() {
            if (isSurvival) {
                modeTaskText.textContent = 'Собери как можно больше яблок 🍎, избегая врагов 👾';
            } else if (isMega) {
                modeTaskText.textContent = 'Снеси все сердца босса ❤️ (10 HP)';
            } else {
                modeTaskText.textContent = 'Собери все яблоки 🍎 и уворачивайся от черепов 💀 и врагов 👾';
            }
        }

        function updateDifficultyButtons() {
            diffButtons.forEach(btn => {
                const diff = btn.dataset.diff;
                const isUnlocked = unlocked[diff] || false;
                if (isUnlocked) {
                    btn.classList.remove('locked');
                    btn.textContent = btn.textContent.replace(/ 🔒$/, '');
                } else {
                    btn.classList.add('locked');
                    if (!btn.textContent.includes('🔒')) {
                        btn.textContent += ' 🔒';
                    }
                }
                if (diff === currentDifficulty) {
                    btn.classList.add('active');
                } else {
                    btn.classList.remove('active');
                }
            });
        }

        function unlockNextLevel() {
            const currentIndex = MAIN_CYCLE.indexOf(currentDifficulty);
            if (currentIndex !== -1 && currentIndex < MAIN_CYCLE.length - 1) {
                const nextDiff = MAIN_CYCLE[currentIndex + 1];
                if (!unlocked[nextDiff]) {
                    unlocked[nextDiff] = true;
                    checkSurvivalUnlock();
                    updateDifficultyButtons();
                }
            } else if (currentDifficulty === 'mega') {
                checkSurvivalUnlock();
                updateDifficultyButtons();
            }
        }

        function checkSurvivalUnlock() {
            if (unlocked.easy && unlocked.medium && unlocked.hard && unlocked.mega) {
                if (!unlocked.survival) {
                    unlocked.survival = true;
                    updateDifficultyButtons();
                }
            }
        }

        // --- Генерация лабиринта ---
        function generateMaze(size, extraPercent, mega) {
            maze = Array.from({ length: size }, () => Array(size).fill(true));
            const startX = 1, startY = 1;
            maze[startY][startX] = false;
            const stack = [{ x: startX, y: startY }];
            const dirs = [
                { dx: 0, dy: -2 },
                { dx: 0, dy: 2 },
                { dx: -2, dy: 0 },
                { dx: 2, dy: 0 }
            ];
            while (stack.length > 0) {
                const current = stack[stack.length - 1];
                const { x, y } = current;
                const neighbors = [];
                for (const d of dirs) {
                    const nx = x + d.dx;
                    const ny = y + d.dy;
                    if (nx > 0 && nx < size - 1 && ny > 0 && ny < size - 1 && maze[ny][nx] === true) {
                        neighbors.push({ x: nx, y: ny, dx: d.dx / 2, dy: d.dy / 2 });
                    }
                }
                if (neighbors.length === 0) {
                    stack.pop();
                } else {
                    const chosen = neighbors[Math.floor(Math.random() * neighbors.length)];
                    maze[y + chosen.dy][x + chosen.dx] = false;
                    maze[chosen.y][chosen.x] = false;
                    stack.push({ x: chosen.x, y: chosen.y });
                }
            }
            exitX = size - 2;
            exitY = size - 2;
            maze[exitY][exitX] = false;
            maze[startY][startX] = false;

            addExtraPassages(size, extraPercent);
            ensureExitAccessible(size);

            if (mega) {
                const center = Math.floor(size / 2);
                const halfBlock = 2;
                for (let dy = -halfBlock; dy <= halfBlock; dy++) {
                    for (let dx = -halfBlock; dx <= halfBlock; dx++) {
                        const row = center + dy;
                        const col = center + dx;
                        if (row >= 0 && row < size && col >= 0 && col < size) {
                            maze[row][col] = true;
                        }
                    }
                }
                for (let dy = -halfBlock - 1; dy <= halfBlock + 1; dy++) {
                    for (let dx = -halfBlock - 1; dx <= halfBlock + 1; dx++) {
                        const row = center + dy;
                        const col = center + dx;
                        if (row >= 0 && row < size && col >= 0 && col < size) {
                            if (Math.abs(dy) <= halfBlock && Math.abs(dx) <= halfBlock) continue;
                            maze[row][col] = false;
                        }
                    }
                }
            }
        }

        function addExtraPassages(size, extraPercent) {
            const innerCells = (size - 2) * (size - 2);
            const extraCount = Math.floor(innerCells * extraPercent);
            let added = 0;
            let attempts = 0;
            const maxAttempts = extraCount * 30;
            while (added < extraCount && attempts < maxAttempts) {
                attempts++;
                const row = 1 + Math.floor(Math.random() * (size - 2));
                const col = 1 + Math.floor(Math.random() * (size - 2));
                if (maze[row][col] === true) continue;

                const dirs = [
                    { dx: 0, dy: -2 },
                    { dx: 0, dy: 2 },
                    { dx: -2, dy: 0 },
                    { dx: 2, dy: 0 }
                ];
                const dir = dirs[Math.floor(Math.random() * dirs.length)];
                const nx = col + dir.dx;
                const ny = row + dir.dy;
                if (nx <= 0 || nx >= size - 1 || ny <= 0 || ny >= size - 1) continue;
                const midX = col + dir.dx / 2;
                const midY = row + dir.dy / 2;
                if (maze[midY][midX] === true && maze[row][col] === false && maze[ny][nx] === false) {
                    maze[midY][midX] = false;
                    added++;
                }
            }
        }

        function ensureExitAccessible(size) {
            const dirs = [
                { dx: 0, dy: -1 },
                { dx: 0, dy: 1 },
                { dx: -1, dy: 0 },
                { dx: 1, dy: 0 }
            ];
            for (const d of dirs) {
                const nx = exitX + d.dx;
                const ny = exitY + d.dy;
                if (nx >= 0 && nx < size && ny >= 0 && ny < size) {
                    maze[ny][nx] = false;
                }
            }
        }

        // --- Спавн врагов ---
        function spawnEnemies(size, survival, mega) {
            enemies = [];
            if (survival) {
                const positions = [
                    { x: 1, y: size - 2 },
                    { x: size - 2, y: 1 },
                    { x: size - 2, y: size - 2 }
                ];
                for (const pos of positions) {
                    if (maze[pos.y][pos.x] === true) {
                        maze[pos.y][pos.x] = false;
                        const dirs = [
                            { dx: 0, dy: -1 }, { dx: 0, dy: 1 },
                            { dx: -1, dy: 0 }, { dx: 1, dy: 0 }
                        ];
                        for (const d of dirs) {
                            const nx = pos.x + d.dx;
                            const ny = pos.y + d.dy;
                            if (nx >= 0 && nx < size && ny >= 0 && ny < size && maze[ny][nx] === true) {
                                maze[ny][nx] = false;
                                break;
                            }
                        }
                    }
                    enemies.push({ x: pos.x, y: pos.y });
                }
            } else if (!mega) {
                let sx = size - 2;
                let sy = 1;
                if (maze[sy][sx] === true) maze[sy][sx] = false;
                const dirs = [
                    { dx: -1, dy: 0 }, { dx: 0, dy: 1 }
                ];
                for (const d of dirs) {
                    const nx = sx + d.dx;
                    const ny = sy + d.dy;
                    if (nx >= 0 && nx < size && ny >= 0 && ny < size && maze[ny][nx] === true) {
                        maze[ny][nx] = false;
                        break;
                    }
                }
                enemies.push({ x: sx, y: sy });
            }
        }

        // --- Размещение предметов и ловушек ---
        function placeItemsAndTraps(size, itemCount, trapCount, survival, mega) {
            items = [];
            traps = [];
            let freeCells = [];
            for (let row = 0; row < size; row++) {
                for (let col = 0; col < size; col++) {
                    if (maze[row][col] === false) {
                        if ((row === 1 && col === 1)) continue;
                        if (!survival && !mega && (row === exitY && col === exitX)) continue;
                        let occupied = false;
                        for (const e of enemies) {
                            if (e.x === col && e.y === row) { occupied = true; break; }
                        }
                        if (occupied) continue;
                        freeCells.push({ x: col, y: row });
                    }
                }
            }
            for (let i = freeCells.length - 1; i > 0; i--) {
                const j = Math.floor(Math.random() * (i + 1));
                [freeCells[i], freeCells[j]] = [freeCells[j], freeCells[i]];
            }

            const actualItemCount = Math.min(itemCount, freeCells.length);
            for (let i = 0; i < actualItemCount; i++) {
                items.push(freeCells[i]);
            }
            if (!survival && !mega) {
                const remaining = freeCells.slice(actualItemCount);
                const actualTrapCount = Math.min(trapCount, remaining.length);
                for (let i = 0; i < actualTrapCount; i++) {
                    traps.push(remaining[i]);
                }
            }
            totalItems = items.length;
            if (survival) {
                totalItemsSpan.textContent = '∞';
                totalItemsSpan.style.display = 'inline';
                totalItems = Infinity;
            } else if (mega) {
                totalItemsSpan.textContent = '0';
                totalItemsSpan.style.display = 'inline';
                totalItems = 0;
                exitVisible = false;
            } else {
                totalItemsSpan.style.display = 'inline';
                totalItemsSpan.textContent = totalItems;
                exitVisible = false;
            }
            collectedItems = 0;
            itemCounter.textContent = '0';
            appleBalance = 0;
            updateInventoryDisplay();
            fieldItems = [];
            doubleStepActive = false;
            pickaxeActive = false;
            if (lightningTimer) clearTimeout(lightningTimer);
            if (pickaxeTimer) clearTimeout(pickaxeTimer);
        }

        // --- Сбор яблок ---
        function collectItem(x, y) {
            const index = items.findIndex(item => item.x === x && item.y === y);
            if (index !== -1) {
                items.splice(index, 1);
                collectedItems++;
                appleBalance++;
                itemCounter.textContent = collectedItems;

                // Звук яблока
                playAppleSound();

                applesSinceLastLife++;
                const progress = applesSinceLastLife % APPLES_PER_LIFE;
                const progressDisplay = progress === 0 ? APPLES_PER_LIFE : progress;
                appleProgress.textContent = `${progressDisplay}/${APPLES_PER_LIFE}`;
                if (applesSinceLastLife >= APPLES_PER_LIFE) {
                    applesSinceLastLife = 0;
                    lives++;
                    livesCounter.textContent = lives;
                    statusDisplay.innerHTML = '❤️ +1 жизнь! (бонус за 20 яблок)';
                    setTimeout(() => {
                        if (!gameOver && !isPaused) {
                            if (isSurvival) {
                                statusDisplay.innerHTML = `🔥 Выживание — собрано ${collectedItems} 🍎, время ${seconds}с`;
                            } else if (isMega) {
                                statusDisplay.innerHTML = `🗺️ Мега — босс имеет ${bossHP} ❤️`;
                            } else if (!exitVisible) {
                                statusDisplay.innerHTML = `🍎 Соберите все предметы (${collectedItems}/${totalItems === Infinity ? '∞' : totalItems})`;
                            } else {
                                statusDisplay.innerHTML = '🔑 Выход открыт! Идите к 🚪';
                            }
                        }
                    }, 1500);
                }

                if (isSurvival) {
                    spawnNewItem();
                } else if (!isMega) {
                    if (collectedItems === totalItems) {
                        exitVisible = true;
                        statusDisplay.innerHTML = '🔑 Все предметы собраны! Ищите выход 🚪';
                    }
                }
                return true;
            }
            return false;
        }

        // --- Остальные функции ---
        function spawnNewItem() {
            if (!isSurvival) return;
            let freeCells = [];
            for (let row = 0; row < currentSize; row++) {
                for (let col = 0; col < currentSize; col++) {
                    if (maze[row][col] === false) {
                        if (row === playerY && col === playerX) continue;
                        let occupied = false;
                        for (const e of enemies) {
                            if (e.x === col && e.y === row) { occupied = true; break; }
                        }
                        if (occupied) continue;
                        for (const it of items) {
                            if (it.x === col && it.y === row) { occupied = true; break; }
                        }
                        if (occupied) continue;
                        if (shield && shield.x === col && shield.y === row) continue;
                        freeCells.push({ x: col, y: row });
                    }
                }
            }
            if (freeCells.length > 0) {
                const idx = Math.floor(Math.random() * freeCells.length);
                items.push(freeCells[idx]);
            }
        }

        function spawnShield() {
            if (!isSurvival) return;
            if (shieldRespawnTimeout) {
                clearTimeout(shieldRespawnTimeout);
                shieldRespawnTimeout = null;
            }
            let freeCells = [];
            for (let row = 0; row < currentSize; row++) {
                for (let col = 0; col < currentSize; col++) {
                    if (maze[row][col] === false) {
                        if (row === playerY && col === playerX) continue;
                        let occupied = false;
                        for (const e of enemies) {
                            if (e.x === col && e.y === row) { occupied = true; break; }
                        }
                        if (occupied) continue;
                        for (const it of items) {
                            if (it.x === col && it.y === row) { occupied = true; break; }
                        }
                        if (occupied) continue;
                        if (shield && shield.x === col && shield.y === row) continue;
                        freeCells.push({ x: col, y: row });
                    }
                }
            }
            if (freeCells.length > 0) {
                const idx = Math.floor(Math.random() * freeCells.length);
                shield = { x: freeCells[idx].x, y: freeCells[idx].y };
            } else {
                shield = null;
            }
            render();
        }

        function activateShield() {
            if (!isSurvival || !shield) return;
            shield = null;
            if (yellowFlashTimeout) clearTimeout(yellowFlashTimeout);
            yellowFlash = true;
            render();
            yellowFlashTimeout = setTimeout(() => {
                yellowFlash = false;
                render();
                yellowFlashTimeout = null;
            }, 2000);

            if (enemyInterval) {
                clearInterval(enemyInterval);
                enemyInterval = null;
            }

            let freeCells = [];
            for (let row = 0; row < currentSize; row++) {
                for (let col = 0; col < currentSize; col++) {
                    if (maze[row][col] === false) {
                        if (row === playerY && col === playerX) continue;
                        let occupied = false;
                        for (const e of enemies) {
                            if (e.x === col && e.y === row) { occupied = true; break; }
                        }
                        if (occupied) continue;
                        for (const it of items) {
                            if (it.x === col && it.y === row) { occupied = true; break; }
                        }
                        if (occupied) continue;
                        freeCells.push({ x: col, y: row });
                    }
                }
            }
            for (let i = 0; i < enemies.length; i++) {
                if (freeCells.length === 0) break;
                const idx = Math.floor(Math.random() * freeCells.length);
                const newPos = freeCells.splice(idx, 1)[0];
                enemies[i].x = newPos.x;
                enemies[i].y = newPos.y;
            }

            setTimeout(() => {
                if (!gameOver) {
                    startEnemy(currentEnemyIntervalMs);
                }
            }, 2000);

            if (shieldRespawnTimeout) clearTimeout(shieldRespawnTimeout);
            shieldRespawnTimeout = setTimeout(() => {
                shieldRespawnTimeout = null;
                if (!gameOver && isSurvival) {
                    spawnShield();
                }
            }, 10000);

            render();
        }

        function checkShieldPickup() {
            if (!isSurvival || !shield) return false;
            if (playerX === shield.x && playerY === shield.y) {
                activateShield();
                return true;
            }
            return false;
        }

        function removeTrap(x, y) {
            traps = traps.filter(t => !(t.x === x && t.y === y));
        }

        function loseLife(reason, teleport = true) {
            if (gameOver) return;
            lives--;
            livesCounter.textContent = lives;

            // Звук ловушки, если причина — trap
            if (reason === 'trap') {
                playTrapSound();
            }

            if (redFlashTimeout) clearTimeout(redFlashTimeout);
            redFlash = true;
            render();
            redFlashTimeout = setTimeout(() => {
                redFlash = false;
                render();
                redFlashTimeout = null;
            }, 500);

            if (lives <= 0) {
                gameOver = true;
                gameWon = false;
                statusDisplay.innerHTML = '💀 Игра <span>проиграна</span>!';
                stopTimer();
                stopEnemy();
                alert('💀 У вас закончились жизни! Вы проиграли!');
                render();
                return;
            }
            if (teleport) {
                playerX = 1;
                playerY = 1;
            }
            const msg = reason === 'trap' ? '💀 Ловушка! -1 жизнь' :
                        reason === 'bomb' ? '💥 Взрыв! -1 жизнь' :
                        '👾 Враг! -1 жизнь';
            statusDisplay.innerHTML = `${msg} (осталось ${lives} ❤️)`;
            setTimeout(() => {
                if (!gameOver) {
                    if (isSurvival) {
                        statusDisplay.innerHTML = `🔥 Выживание — собрано ${collectedItems} 🍎, время ${seconds}с`;
                    } else if (isMega) {
                        statusDisplay.innerHTML = `🗺️ Мега — босс имеет ${bossHP} ❤️`;
                    } else if (!exitVisible) {
                        statusDisplay.innerHTML = `🍎 Соберите все предметы (${collectedItems}/${totalItems === Infinity ? '∞' : totalItems})`;
                    } else {
                        statusDisplay.innerHTML = '🔑 Выход открыт! Идите к 🚪';
                    }
                }
            }, 1500);
            render();
        }

        function moveEnemy() {
            if (gameOver || isPaused || isShopOpen) return;
            if (enemies.length === 0) return;

            for (let i = 0; i < enemies.length; i++) {
                const e = enemies[i];
                if (e.x === -1 || e.y === -1) continue;

                const dx = Math.sign(playerX - e.x);
                const dy = Math.sign(playerY - e.y);

                const candidates = [];
                if (dx !== 0) {
                    const nx = e.x + dx;
                    const ny = e.y;
                    if (nx >= 0 && nx < currentSize && ny >= 0 && ny < currentSize) {
                        candidates.push({ dx: dx, dy: 0 });
                    }
                }
                if (dy !== 0) {
                    const nx = e.x;
                    const ny = e.y + dy;
                    if (nx >= 0 && nx < currentSize && ny >= 0 && ny < currentSize) {
                        candidates.push({ dx: 0, dy: dy });
                    }
                }
                let chosen = null;
                if (candidates.length > 0) {
                    chosen = candidates[Math.floor(Math.random() * candidates.length)];
                } else {
                    const allDirs = [
                        { dx: 0, dy: -1 }, { dx: 0, dy: 1 },
                        { dx: -1, dy: 0 }, { dx: 1, dy: 0 }
                    ];
                    for (let j = allDirs.length - 1; j > 0; j--) {
                        const k = Math.floor(Math.random() * (j + 1));
                        [allDirs[j], allDirs[k]] = [allDirs[k], allDirs[j]];
                    }
                    for (const d of allDirs) {
                        const nx = e.x + d.dx;
                        const ny = e.y + d.dy;
                        if (nx >= 0 && nx < currentSize && ny >= 0 && ny < currentSize) {
                            chosen = d;
                            break;
                        }
                    }
                }

                if (chosen) {
                    e.x += chosen.dx;
                    e.y += chosen.dy;
                    if (e.x === playerX && e.y === playerY) {
                        loseLife('enemy');
                        render();
                        return;
                    }
                }
            }
            render();
        }

        function isWalkable(x, y) {
            if (x < 0 || x >= currentSize || y < 0 || y >= currentSize) return false;
            return !maze[y][x];
        }

        function startEnemy(intervalMs) {
            if (enemyInterval) clearInterval(enemyInterval);
            currentEnemyIntervalMs = intervalMs;
            if (intervalMs > 0) {
                enemyInterval = setInterval(() => {
                    moveEnemy();
                }, intervalMs);
            } else {
                enemyInterval = null;
            }
        }

        function stopEnemy() {
            if (enemyInterval) {
                clearInterval(enemyInterval);
                enemyInterval = null;
            }
        }

        function spawnSword() {
            if (!isMega) return;
            let freeCells = [];
            const center = Math.floor(currentSize / 2);
            const halfBlock = 2;
            for (let row = 0; row < currentSize; row++) {
                for (let col = 0; col < currentSize; col++) {
                    if (maze[row][col] === false) {
                        if (row === 1 && col === 1) continue;
                        if (Math.abs(row - center) <= halfBlock && Math.abs(col - center) <= halfBlock) continue;
                        if (row === playerY && col === playerX) continue;
                        if (shield && shield.x === col && shield.y === row) continue;
                        if (sword && sword.x === col && sword.y === row) continue;
                        freeCells.push({ x: col, y: row });
                    }
                }
            }
            if (freeCells.length > 0) {
                const idx = Math.floor(Math.random() * freeCells.length);
                sword = freeCells[idx];
            } else {
                sword = null;
            }
            render();
        }

        function isAdjacentToBoss(x, y) {
            const center = Math.floor(currentSize / 2);
            const halfBlock = 2;
            for (let dy = -halfBlock; dy <= halfBlock; dy++) {
                for (let dx = -halfBlock; dx <= halfBlock; dx++) {
                    const bx = center + dx;
                    const by = center + dy;
                    const neighbors = [
                        [bx-1, by], [bx+1, by], [bx, by-1], [bx, by+1]
                    ];
                    for (const [nx, ny] of neighbors) {
                        if (nx === x && ny === y) {
                            return true;
                        }
                    }
                }
            }
            return false;
        }

        function attackBoss() {
            if (!isMega) return;
            if (!hasSword) return;
            if (bossHP <= 0) return;
            if (!isAdjacentToBoss(playerX, playerY)) {
                return;
            }
            bossHP--;
            hasSword = false;
            sword = null;

            if (bossHP > 0) {
                spawnSword();
            }

            if (bossHP <= 0) {
                gameWon = true;
                gameOver = true;
                statusDisplay.innerHTML = '🎉 Вы <span>победили</span>! 🎉';
                stopTimer();
                stopEnemy();
                unlockNextLevel();
                updateDifficultyButtons();
                nextDiffButton.style.display = 'inline-block';
                const starsEarned = Math.min(lives, 3);
                starsBalance += starsEarned;
                updateStarsDisplay();
                alert(`🎉 Поздравляем! Вы убили босса! Заработано ${starsEarned} ⭐`);
                render();
                return;
            }
            render();
        }

        function updateBombs() {
            if (!isMega) return;
            if (gameOver || isPaused || isShopOpen) return;
            if (bossHP <= 0) return;

            const isEnraged = (bossHP <= 5);
            const interval = isEnraged ? 2 : 3;
            const radius = isEnraged ? 3 : 2;

            if (bomb === null) {
                bombSpawnTimer--;
                if (bombSpawnTimer <= 0) {
                    const dirs = [
                        [0, -1], [0, 1], [-1, 0], [1, 0]
                    ];
                    for (let i = dirs.length - 1; i > 0; i--) {
                        const j = Math.floor(Math.random() * (i + 1));
                        [dirs[i], dirs[j]] = [dirs[j], dirs[i]];
                    }
                    let placed = false;
                    for (const [dx, dy] of dirs) {
                        const nx = playerX + dx;
                        const ny = playerY + dy;
                        if (isWalkable(nx, ny)) {
                            const center = Math.floor(currentSize / 2);
                            const halfBlock = 2;
                            if (Math.abs(nx - center) <= halfBlock && Math.abs(ny - center) <= halfBlock) continue;
                            if (sword && sword.x === nx && sword.y === ny) continue;
                            if (shield && shield.x === nx && shield.y === ny) continue;
                            bomb = { x: nx, y: ny, timer: BOMB_FUSE_TIME };
                            placed = true;
                            break;
                        }
                    }
                    if (placed) {
                        bombSpawnTimer = interval;
                        render();
                    } else {
                        bombSpawnTimer = 1;
                    }
                }
            } else {
                bomb.timer--;
                if (bomb.timer <= 0) {
                    const bx = bomb.x;
                    const by = bomb.y;
                    explosionZone = { x: bx, y: by };
                    if (window.explosionZoneTimeout) clearTimeout(window.explosionZoneTimeout);
                    window.explosionZoneTimeout = setTimeout(() => {
                        explosionZone = null;
                        render();
                    }, 500);

                    const r = radius;
                    if (playerX >= bx - r && playerX <= bx + r && playerY >= by - r && playerY <= by + r) {
                        loseLife('bomb', false);
                    }
                    bomb = null;
                    bombSpawnTimer = interval;
                    render();
                }
            }
        }

        // --- Функции для активации предметов ---
        function activateItem(key) {
            if (gameOver || isPaused || isShopOpen) return;
            if (inventory[key] <= 0) return;

            let freeCells = [];
            for (let dy = -5; dy <= 5; dy++) {
                for (let dx = -5; dx <= 5; dx++) {
                    const dist = Math.abs(dx) + Math.abs(dy);
                    if (dist > 5 || dist === 0) continue;
                    const nx = playerX + dx;
                    const ny = playerY + dy;
                    if (nx < 0 || nx >= currentSize || ny < 0 || ny >= currentSize) continue;
                    if (!isWalkable(nx, ny)) continue;
                    let occupied = false;
                    if (isMega) {
                        const center = Math.floor(currentSize / 2);
                        const halfBlock = 2;
                        if (Math.abs(nx - center) <= halfBlock && Math.abs(ny - center) <= halfBlock) occupied = true;
                    }
                    if (sword && sword.x === nx && sword.y === ny) occupied = true;
                    if (shield && shield.x === nx && shield.y === ny) occupied = true;
                    if (fieldItems.some(f => f.x === nx && f.y === ny)) occupied = true;
                    if (!occupied) freeCells.push({ x: nx, y: ny });
                }
            }
            if (freeCells.length === 0) {
                alert('Нет места для предмета!');
                return;
            }
            const idx = Math.floor(Math.random() * freeCells.length);
            const pos = freeCells[idx];
            inventory[key]--;
            updateInventoryDisplay();
            fieldItems.push({ x: pos.x, y: pos.y, key: key });
            render();
            statusDisplay.innerHTML = `📍 Предмет появился рядом!`;
            setTimeout(() => {
                if (!gameOver && !isPaused && !isShopOpen) {
                    if (isSurvival) {
                        statusDisplay.innerHTML = `🔥 Выживание — собрано ${collectedItems} 🍎, время ${seconds}с`;
                    } else if (isMega) {
                        statusDisplay.innerHTML = `🗺️ Мега — босс имеет ${bossHP} ❤️`;
                    } else if (!exitVisible) {
                        statusDisplay.innerHTML = `🍎 Соберите все предметы (${collectedItems}/${totalItems === Infinity ? '∞' : totalItems})`;
                    } else {
                        statusDisplay.innerHTML = '🔑 Выход открыт! Идите к 🚪';
                    }
                }
            }, 1500);
        }

        function applyConsumable(key) {
            switch (key) {
                case 'cake':
                    lives++;
                    livesCounter.textContent = lives;
                    statusDisplay.innerHTML = '❤️ +1 жизнь!';
                    break;
                case 'clock':
                    if (enemyInterval) {
                        clearInterval(enemyInterval);
                        currentEnemyIntervalMs = currentEnemyIntervalMs * 2;
                        startEnemy(currentEnemyIntervalMs);
                        statusDisplay.innerHTML = '⏰ Враги замедлены на 5 секунд!';
                        setTimeout(() => {
                            if (!gameOver) {
                                const diff = DIFFICULTY[currentDifficulty];
                                startEnemy(diff.enemyInterval);
                                statusDisplay.innerHTML = '⏰ Скорость врагов восстановлена';
                            }
                        }, 5000);
                    }
                    break;
                case 'lightning':
                    if (pickaxeActive) {
                        pickaxeActive = false;
                        if (pickaxeTimer) {
                            clearTimeout(pickaxeTimer);
                            pickaxeTimer = null;
                        }
                    }
                    doubleStepActive = true;
                    if (lightningTimer) clearTimeout(lightningTimer);
                    lightningTimer = setTimeout(() => {
                        doubleStepActive = false;
                        if (!gameOver) {
                            statusDisplay.innerHTML = '⚡ Эффект молнии закончился';
                        }
                    }, 10000);
                    statusDisplay.innerHTML = '⚡ Молния! Двойной шаг на 10 секунд!';
                    break;
                case 'pickaxe':
                    if (doubleStepActive) {
                        doubleStepActive = false;
                        if (lightningTimer) {
                            clearTimeout(lightningTimer);
                            lightningTimer = null;
                        }
                    }
                    pickaxeActive = true;
                    if (pickaxeTimer) clearTimeout(pickaxeTimer);
                    pickaxeTimer = setTimeout(() => {
                        pickaxeActive = false;
                        if (!gameOver) {
                            statusDisplay.innerHTML = '⛏️ Эффект кирки закончился';
                        }
                    }, 5000);
                    statusDisplay.innerHTML = '⛏️ Кирка! Можно ломать стены 5 секунд!';
                    break;
            }
            render();
        }

        function pickupItem(x, y) {
            const idx = fieldItems.findIndex(f => f.x === x && f.y === y);
            if (idx !== -1) {
                const item = fieldItems[idx];
                fieldItems.splice(idx, 1);
                applyConsumable(item.key);
                render();
                return true;
            }
            return false;
        }

        // --- Игровая логика ---
        function attemptMove(dx, dy) {
            const newX = playerX + dx;
            const newY = playerY + dy;
            if (newX < 0 || newX >= currentSize || newY < 0 || newY >= currentSize) return false;
            if (isMega) {
                const center = Math.floor(currentSize / 2);
                const halfBlock = 2;
                if (Math.abs(newX - center) <= halfBlock && Math.abs(newY - center) <= halfBlock) return false;
            }
            if (pickaxeActive) {
                if (maze[newY][newX] === true) {
                    maze[newY][newX] = false;
                    playerX = newX;
                    playerY = newY;
                    return true;
                } else {
                    if (isWalkable(newX, newY)) {
                        playerX = newX;
                        playerY = newY;
                        return true;
                    }
                    return false;
                }
            } else {
                if (isWalkable(newX, newY)) {
                    playerX = newX;
                    playerY = newY;
                    return true;
                }
                return false;
            }
        }

        function isTrap(x, y) {
            return traps.some(t => t.x === x && t.y === y);
        }

        function movePlayer(dx, dy) {
            if (gameOver || isPaused || isShopOpen) return;
            let stepsToTake = (doubleStepActive && !pickaxeActive) ? 2 : 1;
            for (let i = 0; i < stepsToTake; i++) {
                const moved = attemptMove(dx, dy);
                if (!moved) break;
                // Звук шага
                playStepSound();

                steps++;
                updateStepDisplay();

                if (!timerStarted) {
                    startTimer();
                    timerStarted = true;
                }

                if (!isMega) {
                    collectItem(playerX, playerY);
                }
                if (isTrap(playerX, playerY)) {
                    removeTrap(playerX, playerY);
                    loseLife('trap');
                    if (gameOver) break;
                }
                pickupItem(playerX, playerY);

                if (isSurvival && shield) {
                    checkShieldPickup();
                }

                if (!isSurvival && !isMega && exitVisible && playerX === exitX && playerY === exitY) {
                    gameWon = true;
                    gameOver = true;
                    statusDisplay.innerHTML = '🎉 Вы <span>победили</span>! 🎉';
                    stopTimer();
                    stopEnemy();
                    unlockNextLevel();
                    updateDifficultyButtons();
                    nextDiffButton.style.display = 'inline-block';
                    const starsEarned = Math.min(lives, 3);
                    starsBalance += starsEarned;
                    updateStarsDisplay();
                    alert(`🎉 Поздравляем! Вы выиграли! Заработано ${starsEarned} ⭐`);
                    render();
                    return;
                }

                for (const e of enemies) {
                    if (e.x === playerX && e.y === playerY) {
                        loseLife('enemy');
                        if (gameOver) break;
                    }
                }
                if (gameOver) break;

                if (isMega) {
                    if (sword && !hasSword) {
                        const dxS = Math.abs(playerX - sword.x);
                        const dyS = Math.abs(playerY - sword.y);
                        if ((dxS === 1 && dyS === 0) || (dxS === 0 && dyS === 1)) {
                            sword = null;
                            hasSword = true;
                            render();
                        }
                    }
                    if (hasSword && bossHP > 0) {
                        if (isAdjacentToBoss(playerX, playerY)) {
                            attackBoss();
                            if (gameOver) break;
                        }
                    }
                }

                render();
            }
        }

        function updateStepDisplay() {
            stepCounter.textContent = steps;
        }

        function startTimer() {
            if (timerInterval) clearInterval(timerInterval);
            seconds = 0;
            timeCounter.textContent = seconds;
            timerInterval = setInterval(() => {
                if (!isPaused && !gameOver && !isShopOpen) {
                    seconds++;
                    timeCounter.textContent = seconds;
                    updateBombs();
                }
            }, 1000);
        }

        function stopTimer() {
            if (timerInterval) {
                clearInterval(timerInterval);
                timerInterval = null;
            }
        }

        function togglePause() {
            if (gameOver) return;
            isPaused = !isPaused;
            if (isPaused) {
                statusDisplay.innerHTML = '⏸️ Игра <span>на паузе</span>';
            } else {
                if (isSurvival) {
                    statusDisplay.innerHTML = `🔥 Выживание — собрано ${collectedItems} 🍎, время ${seconds}с`;
                } else if (isMega) {
                    statusDisplay.innerHTML = `🗺️ Мега — босс имеет ${bossHP} ❤️`;
                } else if (!exitVisible) {
                    statusDisplay.innerHTML = `🍎 Соберите все предметы (${collectedItems}/${totalItems === Infinity ? '∞' : totalItems})`;
                } else {
                    statusDisplay.innerHTML = '🔑 Выход открыт! Идите к 🚪';
                }
            }
            render();
        }

        function handleExit() {
            if (gameOver) return;
            if (confirm('Вы уверены, что хотите выйти из игры? (прогресс будет потерян)')) {
                resetGame();
            }
        }

        function goToNextDifficulty() {
            const currentIndex = MAIN_CYCLE.indexOf(currentDifficulty);
            if (currentIndex === -1) {
                const nextDiff = MAIN_CYCLE[0];
                if (unlocked[nextDiff]) {
                    nextDiffButton.style.display = 'none';
                    setDifficulty(nextDiff);
                }
                return;
            }
            const nextIndex = (currentIndex + 1) % MAIN_CYCLE.length;
            const nextDiff = MAIN_CYCLE[nextIndex];
            if (unlocked[nextDiff]) {
                nextDiffButton.style.display = 'none';
                setDifficulty(nextDiff);
            } else {
                for (let i = 0; i < MAIN_CYCLE.length; i++) {
                    const diff = MAIN_CYCLE[i];
                    if (unlocked[diff]) {
                        nextDiffButton.style.display = 'none';
                        setDifficulty(diff);
                        return;
                    }
                }
                nextDiffButton.style.display = 'none';
            }
        }

        function resetGame() {
            stopTimer();
            stopEnemy();
            timerStarted = false;
            isPaused = false;
            isShopOpen = false;
            shopOverlay.classList.remove('active');
            nextDiffButton.style.display = 'none';
            if (shieldRespawnTimeout) clearTimeout(shieldRespawnTimeout);
            shieldRespawnTimeout = null;
            shield = null;
            if (yellowFlashTimeout) clearTimeout(yellowFlashTimeout);
            yellowFlash = false;
            if (redFlashTimeout) clearTimeout(redFlashTimeout);
            redFlash = false;
            if (window.explosionZoneTimeout) clearTimeout(window.explosionZoneTimeout);
            explosionZone = null;
            fieldItems = [];
            doubleStepActive = false;
            pickaxeActive = false;
            if (lightningTimer) clearTimeout(lightningTimer);
            if (pickaxeTimer) clearTimeout(pickaxeTimer);

            const diff = DIFFICULTY[currentDifficulty];
            currentSize = diff.size;
            cellSize = canvas.width / currentSize;
            isSurvival = diff.survival;
            isMega = diff.mega;

            lives = 3;
            livesCounter.textContent = lives;
            applesSinceLastLife = 0;
            appleProgress.textContent = `0/${APPLES_PER_LIFE}`;

            inventory.cake = 0;
            inventory.clock = 0;
            inventory.lightning = 0;
            inventory.pickaxe = 0;
            updateInventoryDisplay();

            generateMaze(currentSize, diff.extraPassages, isMega);
            spawnEnemies(currentSize, isSurvival, isMega);
            playerX = 1;
            playerY = 1;
            exitX = currentSize - 2;
            exitY = currentSize - 2;
            gameOver = false;
            gameWon = false;
            exitVisible = false;
            steps = 0;
            seconds = 0;
            updateStepDisplay();
            timeCounter.textContent = '0';
            placeItemsAndTraps(currentSize, diff.itemCount, diff.trapCount, isSurvival, isMega);
            if (isSurvival) {
                spawnShield();
            }
            if (isMega) {
                bossHP = MAX_BOSS_HP;
                hasSword = false;
                sword = null;
                spawnSword();
                bomb = null;
                bombSpawnTimer = 3;
            } else {
                bossHP = 10;
                hasSword = false;
                sword = null;
                bomb = null;
                bombSpawnTimer = 3;
            }
            statusDisplay.innerHTML = isSurvival ? '🔥 Выживание — собирайте яблоки, избегайте врагов!' :
                                      isMega ? `🗺️ Мега — убейте босса (${bossHP} ❤️)` :
                                      '🚀 Игра <span>активна</span>';
            updateModeInstructions();
            render();
            const interval = getEnemyInterval(currentDifficulty);
            startEnemy(interval);
            if (!timerStarted) {
                startTimer();
                timerStarted = true;
            }
        }

        // --- Магазин ---
        function openShop() {
            if (gameOver) return;
            isShopOpen = true;
            shopOverlay.classList.add('active');
            if (!isPaused) {
                isPaused = true;
                statusDisplay.innerHTML = '🛒 Магазин открыт';
            }
            renderShopItems();
            render();
        }

        function closeShop() {
            isShopOpen = false;
            shopOverlay.classList.remove('active');
            if (isPaused && !gameOver) {
                isPaused = false;
                if (isSurvival) {
                    statusDisplay.innerHTML = `🔥 Выживание — собрано ${collectedItems} 🍎, время ${seconds}с`;
                } else if (isMega) {
                    statusDisplay.innerHTML = `🗺️ Мега — босс имеет ${bossHP} ❤️`;
                } else if (!exitVisible) {
                    statusDisplay.innerHTML = `🍎 Соберите все предметы (${collectedItems}/${totalItems === Infinity ? '∞' : totalItems})`;
                } else {
                    statusDisplay.innerHTML = '🔑 Выход открыт! Идите к 🚪';
                }
            }
            render();
        }

        function renderShopItems() {
            shopItemsContainer.innerHTML = '';
            SHOP_ITEMS.forEach(item => {
                const div = document.createElement('div');
                div.className = 'shop-item';

                const canAfford = starsBalance >= item.price;

                div.innerHTML = `
                    <div class="icon">${item.icon}</div>
                    <div class="info">
                        <div class="name">${item.name}</div>
                        <div class="desc">${item.desc}</div>
                    </div>
                    <div class="price">⭐${item.price}</div>
                    <button class="buy-btn" data-id="${item.id}" data-price="${item.price}" ${!canAfford ? 'disabled' : ''}>
                        Купить
                    </button>
                `;

                shopItemsContainer.appendChild(div);
            });

            document.querySelectorAll('.shop-item .buy-btn').forEach(btn => {
                btn.addEventListener('click', (e) => {
                    const id = btn.dataset.id;
                    const price = parseInt(btn.dataset.price);
                    buyItem(id, price);
                });
            });
        }

        function buyItem(id, price) {
            if (starsBalance < price) {
                alert('Недостаточно звёзд!');
                return;
            }

            starsBalance -= price;
            updateStarsDisplay();
            const itemKey = SHOP_ITEMS.find(i => i.id === id).key;
            inventory[itemKey]++;
            updateInventoryDisplay();
            renderShopItems();
            const itemName = SHOP_ITEMS.find(i => i.id === id).name;
            statusDisplay.innerHTML = `🛒 Куплен ${itemName}! (осталось ${starsBalance} ⭐)`;
            setTimeout(() => {
                if (!gameOver && !isShopOpen) {
                    if (isSurvival) {
                        statusDisplay.innerHTML = `🔥 Выживание — собрано ${collectedItems} 🍎, время ${seconds}с`;
                    } else if (isMega) {
                        statusDisplay.innerHTML = `🗺️ Мега — босс имеет ${bossHP} ❤️`;
                    } else if (!exitVisible) {
                        statusDisplay.innerHTML = `🍎 Соберите все предметы (${collectedItems}/${totalItems === Infinity ? '∞' : totalItems})`;
                    } else {
                        statusDisplay.innerHTML = '🔑 Выход открыт! Идите к 🚪';
                    }
                }
            }, 1500);
        }

        // --- Отрисовка ---
        function render() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);

            for (let row = 0; row < currentSize; row++) {
                for (let col = 0; col < currentSize; col++) {
                    const x = col * cellSize;
                    const y = row * cellSize;
                    if (maze[row][col]) {
                        if (isMega) {
                            const center = Math.floor(currentSize / 2);
                            const halfBlock = 2;
                            const isInBlock = (Math.abs(row - center) <= halfBlock && Math.abs(col - center) <= halfBlock);
                            if (isInBlock) {
                                ctx.fillStyle = '#b8d4e8';
                                ctx.fillRect(x, y, cellSize, cellSize);
                                ctx.fillStyle = '#9bbcd4';
                                ctx.fillRect(x + 1, y + 1, cellSize - 2, cellSize - 2);
                                continue;
                            }
                        }
                        ctx.fillStyle = '#2f4a5c';
                        ctx.fillRect(x, y, cellSize, cellSize);
                        ctx.fillStyle = '#3a5a6e';
                        ctx.fillRect(x + 2, y + 2, cellSize - 4, cellSize - 4);
                        ctx.fillStyle = '#1f3340';
                        ctx.fillRect(x + 4, y + 4, cellSize - 8, cellSize - 8);
                    } else {
                        ctx.fillStyle = '#b8d4e8';
                        ctx.fillRect(x, y, cellSize, cellSize);
                        ctx.fillStyle = '#9bbcd4';
                        ctx.fillRect(x + 1, y + 1, cellSize - 2, cellSize - 2);
                    }
                }
            }

            if (isMega && bossHP <= 5 && bossHP > 0 && !gameOver) {
                ctx.fillStyle = 'rgba(255, 0, 0, 0.15)';
                ctx.fillRect(0, 0, canvas.width, canvas.height);
            }

            if (explosionZone) {
                const ex = explosionZone.x;
                const ey = explosionZone.y;
                const r = (bossHP <= 5 && bossHP > 0) ? 3 : 2;
                const minX = Math.max(0, ex - r) * cellSize;
                const maxX = Math.min(currentSize - 1, ex + r) * cellSize + cellSize;
                const minY = Math.max(0, ey - r) * cellSize;
                const maxY = Math.min(currentSize - 1, ey + r) * cellSize + cellSize;
                ctx.fillStyle = 'rgba(255, 0, 0, 0.35)';
                ctx.fillRect(minX, minY, maxX - minX, maxY - minY);
            }

            if (isMega) {
                const center = Math.floor(currentSize / 2);
                const halfBlock = 2;
                const emojiX = center * cellSize + cellSize - cellSize / 2;
                const emojiY = center * cellSize + cellSize;
                ctx.font = `${5 * cellSize * 0.9}px sans-serif`;
                ctx.textAlign = 'center';
                ctx.textBaseline = 'middle';
                ctx.shadowColor = 'rgba(0,0,0,0.5)';
                ctx.shadowBlur = 10;
                ctx.fillText('👺', emojiX, emojiY);
                ctx.shadowBlur = 0;

                ctx.font = `18px sans-serif`;
                ctx.fillStyle = '#ff6b6b';
                ctx.textAlign = 'center';
                ctx.textBaseline = 'bottom';
                ctx.shadowColor = 'rgba(0,0,0,0.8)';
                ctx.shadowBlur = 6;
                ctx.fillText(`${bossHP} ❤️`, emojiX, emojiY - cellSize * 2 - 4);
                ctx.shadowBlur = 0;
            }

            if (sword) {
                const sx = sword.x * cellSize + cellSize / 2;
                const sy = sword.y * cellSize + cellSize / 2;
                ctx.font = `${cellSize * 0.8}px sans-serif`;
                ctx.textAlign = 'center';
                ctx.textBaseline = 'middle';
                ctx.shadowColor = 'rgba(255,215,0,0.5)';
                ctx.shadowBlur = 10;
                ctx.fillText('🗡️', sx, sy);
                ctx.shadowBlur = 0;
            }

            for (const fi of fieldItems) {
                const sx = fi.x * cellSize + cellSize / 2;
                const sy = fi.y * cellSize + cellSize / 2;
                const icon = SHOP_ITEMS.find(i => i.key === fi.key).icon;
                ctx.font = `${cellSize * 0.7}px sans-serif`;
                ctx.textAlign = 'center';
                ctx.textBaseline = 'middle';
                ctx.shadowColor = 'rgba(255,215,0,0.5)';
                ctx.shadowBlur = 8;
                ctx.fillText(icon, sx, sy);
                ctx.shadowBlur = 0;
            }

            const fontSize = Math.max(14, Math.min(28, cellSize * 0.8));
            ctx.font = `${fontSize}px "Segoe UI Emoji", "Apple Color Emoji", system-ui, sans-serif`;
            ctx.textAlign = 'center';
            ctx.textBaseline = 'middle';
            for (const item of items) {
                const x = item.x * cellSize + cellSize / 2;
                const y = item.y * cellSize + cellSize / 2;
                ctx.shadowColor = 'rgba(0,0,0,0.3)';
                ctx.shadowBlur = 8;
                ctx.fillText('🍎', x, y + 1);
                ctx.shadowBlur = 0;
            }

            for (const trap of traps) {
                const x = trap.x * cellSize + cellSize / 2;
                const y = trap.y * cellSize + cellSize / 2;
                ctx.shadowColor = 'rgba(0,0,0,0.4)';
                ctx.shadowBlur = 8;
                ctx.fillText('💀', x, y + 1);
                ctx.shadowBlur = 0;
            }

            if (shield) {
                const sx = shield.x * cellSize;
                const sy = shield.y * cellSize;
                ctx.shadowColor = 'rgba(0,255,255,0.5)';
                ctx.shadowBlur = 15;
                const shieldSize = Math.max(24, Math.min(40, cellSize * 0.9));
                ctx.font = `${shieldSize}px "Segoe UI Emoji", "Apple Color Emoji", system-ui, sans-serif`;
                ctx.textAlign = 'center';
                ctx.textBaseline = 'middle';
                ctx.fillText('🛡️', sx + cellSize / 2, sy + cellSize / 2 + 1);
                ctx.shadowBlur = 0;
            }

            for (const e of enemies) {
                if (e.x === -1 || e.y === -1) continue;
                if (e.x === playerX && e.y === playerY && gameOver) continue;
                const ex = e.x * cellSize;
                const ey = e.y * cellSize;
                ctx.shadowColor = 'rgba(255,0,0,0.5)';
                ctx.shadowBlur = 15;
                const enemySize = Math.max(24, Math.min(40, cellSize * 0.9));
                ctx.font = `${enemySize}px "Segoe UI Emoji", "Apple Color Emoji", system-ui, sans-serif`;
                ctx.textAlign = 'center';
                ctx.textBaseline = 'middle';
                ctx.fillText('👾', ex + cellSize / 2, ey + cellSize / 2 + 1);
                ctx.shadowBlur = 0;
            }

            if (!isSurvival && !isMega && !(playerX === exitX && playerY === exitY)) {
                const ex = exitX * cellSize;
                const ey = exitY * cellSize;
                ctx.textAlign = 'center';
                ctx.textBaseline = 'middle';
                if (exitVisible) {
                    ctx.shadowColor = 'rgba(0,0,0,0.3)';
                    ctx.shadowBlur = 10;
                    const doorSize = Math.max(24, Math.min(40, cellSize * 1.1));
                    ctx.font = `${doorSize}px "Segoe UI Emoji", "Apple Color Emoji", system-ui, sans-serif`;
                    ctx.fillText('🚪', ex + cellSize / 2, ey + cellSize / 2 + 1);
                    ctx.shadowBlur = 0;
                } else {
                    const lockSize = Math.max(20, Math.min(36, cellSize));
                    ctx.font = `${lockSize}px "Segoe UI Emoji", "Apple Color Emoji", system-ui, sans-serif`;
                    ctx.fillStyle = '#5a7a8a';
                    ctx.fillText('🔒', ex + cellSize / 2, ey + cellSize / 2 + 1);
                }
            }

            const px = playerX * cellSize;
            const py = playerY * cellSize;
            ctx.shadowColor = 'rgba(0,0,0,0.4)';
            ctx.shadowBlur = 12;
            const playerSize = Math.max(24, Math.min(40, cellSize * 0.9));
            ctx.font = `${playerSize}px "Segoe UI Emoji", "Apple Color Emoji", system-ui, sans-serif`;
            ctx.textAlign = 'center';
            ctx.textBaseline = 'middle';
            ctx.fillText('🦧', px + cellSize / 2, py + cellSize / 2 + 1);
            ctx.shadowBlur = 0;

            if (pickaxeActive) {
                const offsets = [
                    [0, -1], [-1, 0], [1, 0], [0, 1]
                ];
                let pickX = playerX;
                let pickY = playerY;
                for (const [dx, dy] of offsets) {
                    const nx = playerX + dx;
                    const ny = playerY + dy;
                    if (nx >= 0 && nx < currentSize && ny >= 0 && ny < currentSize && isWalkable(nx, ny)) {
                        const center = Math.floor(currentSize / 2);
                        const halfBlock = 2;
                        if (Math.abs(nx - center) <= halfBlock && Math.abs(ny - center) <= halfBlock) continue;
                        pickX = nx;
                        pickY = ny;
                        break;
                    }
                }
                if (pickX !== playerX || pickY !== playerY) {
                    const sx = pickX * cellSize + cellSize / 2;
                    const sy = pickY * cellSize + cellSize / 2;
                    ctx.font = `${cellSize * 0.7}px sans-serif`;
                    ctx.textAlign = 'center';
                    ctx.textBaseline = 'middle';
                    ctx.shadowColor = 'rgba(255,215,0,0.5)';
                    ctx.shadowBlur = 8;
                    ctx.fillText('⛏️', sx, sy);
                    ctx.shadowBlur = 0;
                }
            }

            if (bomb) {
                const bx = bomb.x * cellSize + cellSize / 2;
                const by = bomb.y * cellSize + cellSize / 2;
                ctx.font = `${cellSize * 0.8}px sans-serif`;
                ctx.textAlign = 'center';
                ctx.textBaseline = 'middle';
                ctx.shadowColor = 'rgba(255,0,0,0.5)';
                ctx.shadowBlur = 10;
                ctx.fillText('💣', bx, by);
                ctx.shadowBlur = 0;
            }

            if (hasSword) {
                const offsets = [
                    [0, -1], [-1, 0], [1, 0], [0, 1]
                ];
                let swordX = playerX;
                let swordY = playerY;
                for (const [dx, dy] of offsets) {
                    const nx = playerX + dx;
                    const ny = playerY + dy;
                    if (nx >= 0 && nx < currentSize && ny >= 0 && ny < currentSize && isWalkable(nx, ny)) {
                        const center = Math.floor(currentSize / 2);
                        const halfBlock = 2;
                        if (Math.abs(nx - center) <= halfBlock && Math.abs(ny - center) <= halfBlock) continue;
                        swordX = nx;
                        swordY = ny;
                        break;
                    }
                }
                if (swordX !== playerX || swordY !== playerY) {
                    const sx = swordX * cellSize + cellSize / 2;
                    const sy = swordY * cellSize + cellSize / 2;
                    ctx.font = `${cellSize * 0.8}px sans-serif`;
                    ctx.textAlign = 'center';
                    ctx.textBaseline = 'middle';
                    ctx.shadowColor = 'rgba(255,215,0,0.5)';
                    ctx.shadowBlur = 10;
                    ctx.fillText('🗡️', sx, sy);
                    ctx.shadowBlur = 0;
                } else {
                    const sx = px + cellSize / 2;
                    const sy = py + cellSize / 2 - cellSize * 0.2;
                    ctx.font = `${cellSize * 0.7}px sans-serif`;
                    ctx.textAlign = 'center';
                    ctx.textBaseline = 'middle';
                    ctx.shadowColor = 'rgba(255,215,0,0.5)';
                    ctx.shadowBlur = 8;
                    ctx.fillText('🗡️', sx, sy);
                    ctx.shadowBlur = 0;
                }
            }

            if (redFlash) {
                ctx.fillStyle = 'rgba(255, 0, 0, 0.35)';
                ctx.fillRect(0, 0, canvas.width, canvas.height);
            }
            if (yellowFlash) {
                ctx.fillStyle = 'rgba(255, 255, 0, 0.3)';
                ctx.fillRect(0, 0, canvas.width, canvas.height);
            }

            if (isPaused && !gameOver && !isShopOpen) {
                ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
                ctx.fillRect(0, 0, canvas.width, canvas.height);
                ctx.font = 'bold 48px "Segoe UI", sans-serif';
                ctx.textAlign = 'center';
                ctx.textBaseline = 'middle';
                ctx.fillStyle = '#f7d44a';
                ctx.shadowColor = 'rgba(0,0,0,0.8)';
                ctx.shadowBlur = 20;
                ctx.fillText('⏸ ПАУЗА', canvas.width / 2, canvas.height / 2);
                ctx.shadowBlur = 0;
            }

            if (gameOver) {
                ctx.fillStyle = 'rgba(0,0,0,0.3)';
                ctx.fillRect(0, 0, canvas.width, canvas.height);
                ctx.font = 'bold 32px "Segoe UI", sans-serif';
                ctx.textAlign = 'center';
                ctx.textBaseline = 'middle';
                ctx.shadowColor = 'rgba(0,0,0,0.8)';
                ctx.shadowBlur = 20;
                if (gameWon) {
                    ctx.fillStyle = '#f7d44a';
                    ctx.fillText('🏆 ПОБЕДА!', canvas.width / 2, canvas.height / 2 - 30);
                    const starSize = 30;
                    const totalStars = 3;
                    const starSpacing = 45;
                    const startX = canvas.width / 2 - ((totalStars - 1) * starSpacing) / 2;
                    const starY = canvas.height / 2 + 30;
                    for (let i = 0; i < totalStars; i++) {
                        if (i < lives) {
                            ctx.fillStyle = '#f7d44a';
                            ctx.shadowColor = 'rgba(247, 212, 74, 0.8)';
                            ctx.shadowBlur = 15;
                        } else {
                            ctx.fillStyle = '#555';
                            ctx.shadowBlur = 0;
                        }
                        ctx.font = `${starSize}px sans-serif`;
                        ctx.textAlign = 'center';
                        ctx.textBaseline = 'middle';
                        ctx.fillText('★', startX + i * starSpacing, starY);
                    }
                    ctx.shadowBlur = 0;
                } else {
                    ctx.fillStyle = '#ff6b6b';
                    ctx.fillText('💀 ПОРАЖЕНИЕ', canvas.width / 2, canvas.height / 2);
                }
                ctx.shadowBlur = 0;
            }

            if (!gameOver && !isPaused && !isShopOpen) {
                if (isSurvival) {
                    statusDisplay.innerHTML = `🔥 Выживание — собрано ${collectedItems} 🍎, время ${seconds}с`;
                } else if (isMega) {
                    statusDisplay.innerHTML = `🗺️ Мега — босс имеет ${bossHP} ❤️`;
                } else {
                    if (!exitVisible) {
                        statusDisplay.innerHTML = `🍎 Соберите все предметы (${collectedItems}/${totalItems})`;
                    } else {
                        statusDisplay.innerHTML = '🔑 Выход открыт! Идите к 🚪';
                    }
                }
            }
        }

        // --- Обработчики для кнопок-стрелок ---
        function setupArrowButtons() {
            const arrows = [
                { el: arrowUp, dx: 0, dy: -1 },
                { el: arrowDown, dx: 0, dy: 1 },
                { el: arrowLeft, dx: -1, dy: 0 },
                { el: arrowRight, dx: 1, dy: 0 }
            ];
            arrows.forEach(({ el, dx, dy }) => {
                if (!el) return;
                const handler = (e) => {
                    e.preventDefault();
                    movePlayer(dx, dy);
                };
                el.addEventListener('click', handler);
                el.addEventListener('touchstart', handler, { passive: false });
            });
        }

        // --- Обработчики для слотов ---
        function setupSlotClicks() {
            document.querySelectorAll('.slot-item').forEach(el => {
                el.addEventListener('click', () => {
                    const key = el.dataset.key;
                    activateItem(key);
                });
            });
        }

        // --- Управление с клавиатуры ---
        function handleKeydown(e) {
            const key = e.key;

            if (key === 'F1') {
                e.preventDefault();
                inventory.lightning = 999;
                updateInventoryDisplay();
                return;
            }
            if (key === 'F2') {
                e.preventDefault();
                inventory.pickaxe = 999;
                updateInventoryDisplay();
                return;
            }
            if (key === 'F3') {
                e.preventDefault();
                inventory.cake = 999;
                updateInventoryDisplay();
                return;
            }
            if (key === 'F4') {
                e.preventDefault();
                inventory.clock = 999;
                updateInventoryDisplay();
                return;
            }

            const controlKeys = [
                'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight',
                'w', 'W', 'A', 'a', 's', 'S', 'd', 'D',
                'q', 'Q', 'й', 'Й',
                'e', 'E', 'у', 'У',
                'Shift', ' ', '1', '2', '3', '4'
            ];
            if (key === '6' || key === '7') {
                e.preventDefault();
                if (key === '6') {
                    secret.pressed6 = true;
                    secret.timestamp = Date.now();
                } else if (key === '7' && secret.pressed6) {
                    const now = Date.now();
                    if (now - secret.timestamp < 2000) {
                        unlocked.easy = true;
                        unlocked.medium = true;
                        unlocked.hard = true;
                        unlocked.mega = true;
                        unlocked.survival = true;
                        updateDifficultyButtons();
                        statusDisplay.innerHTML = '🔓 Все уровни разблокированы!';
                        setTimeout(() => {
                            if (!gameOver) {
                                statusDisplay.innerHTML = '🚀 Игра активна';
                            }
                        }, 2000);
                    }
                    secret.pressed6 = false;
                }
                return;
            }

            if (key === 'e' || key === 'E' || key === 'у' || key === 'У') {
                e.preventDefault();
                if (isShopOpen) {
                    closeShop();
                } else {
                    openShop();
                }
                return;
            }

            if (key === '1') { e.preventDefault(); activateItem('lightning'); return; }
            if (key === '2') { e.preventDefault(); activateItem('pickaxe'); return; }
            if (key === '3') { e.preventDefault(); activateItem('cake'); return; }
            if (key === '4') { e.preventDefault(); activateItem('clock'); return; }

            if (controlKeys.includes(key) || key === ' ') {
                e.preventDefault();
            }

            if (key === 'q' || key === 'Q' || key === 'й' || key === 'Й') {
                togglePause();
                return;
            }

            if (key === 'Shift') {
                resetGame();
                return;
            }

            if (key === ' ' && gameWon === true) {
                goToNextDifficulty();
                return;
            }

            if (gameOver || isPaused || isShopOpen) return;

            switch (key) {
                case 'ArrowUp':
                case 'w':
                case 'W':
                    movePlayer(0, -1);
                    break;
                case 'ArrowDown':
                case 's':
                case 'S':
                    movePlayer(0, 1);
                    break;
                case 'ArrowLeft':
                case 'a':
                case 'A':
                    movePlayer(-1, 0);
                    break;
                case 'ArrowRight':
                case 'd':
                case 'D':
                    movePlayer(1, 0);
                    break;
                default:
                    return;
            }
        }

        function setDifficulty(diffKey) {
            if (!unlocked[diffKey]) {
                return;
            }
            if (diffKey === currentDifficulty) return;
            currentDifficulty = diffKey;
            diffButtons.forEach(btn => {
                btn.classList.remove('active');
                if (btn.dataset.diff === diffKey) btn.classList.add('active');
            });
            resetGame();
        }

        // --- Инициализация ---
        window.addEventListener('load', () => {
            diffButtons.forEach(btn => {
                btn.addEventListener('click', () => {
                    const diff = btn.dataset.diff;
                    setDifficulty(diff);
                });
            });

            nextDiffButton.addEventListener('click', goToNextDifficulty);

            pauseButton.addEventListener('click', togglePause);

            shopButton.addEventListener('click', openShop);
            shopCloseBtn.addEventListener('click', closeShop);
            shopOverlay.addEventListener('click', (e) => {
                if (e.target === shopOverlay) {
                    closeShop();
                }
            });

            setupArrowButtons();
            setupSlotClicks();

            updateInventoryDisplay();
            updateStarsDisplay();
            updateDifficultyButtons();

            currentDifficulty = 'easy';
            const diff = DIFFICULTY['easy'];
            currentSize = diff.size;
            cellSize = canvas.width / currentSize;
            isSurvival = false;
            isMega = false;
            lives = 3;
            livesCounter.textContent = lives;
            applesSinceLastLife = 0;
            appleProgress.textContent = `0/${APPLES_PER_LIFE}`;
            appleBalance = 0;
            generateMaze(currentSize, diff.extraPassages, false);
            spawnEnemies(currentSize, false, false);
            playerX = 1;
            playerY = 1;
            exitX = currentSize - 2;
            exitY = currentSize - 2;
            gameOver = false;
            gameWon = false;
            exitVisible = false;
            steps = 0;
            seconds = 0;
            timerStarted = false;
            updateStepDisplay();
            timeCounter.textContent = '0';
            placeItemsAndTraps(currentSize, diff.itemCount, diff.trapCount, false, false);
            statusDisplay.innerHTML = '🚀 Игра <span>активна</span>';
            updateModeInstructions();
            render();
            startEnemy(getEnemyInterval(currentDifficulty));
            window.addEventListener('keydown', handleKeydown);
            document.getElementById('resetButton').addEventListener('click', resetGame);
        });

        window.addEventListener('click', () => {});
    </script>
</body>
</html>

Game Source: Лабиринт играть онлайн

Creator: WildFalcon36

Libraries: none

Complexity: complex (2931 lines, 111.2 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: game-wildfalcon36" to link back to the original. Then publish at arcadelab.ai/publish.