🔬 AI発明ギャラリー yuusei_shingoji ユウクラめいろ
🔒 サンドボックス内で実行中 ⛶ 全画面で遊ぶ
HTML / CSS / JS
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>Minecraft Style Maze Game - 6-Story Mansion Update</title>
    <!-- Tailwind CSS for UI styling -->
    <script src="https://cdn.tailwindcss.com"></script>
    <!-- Google Pixel Font -->
    <link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&family=DotGothic16&display=swap" rel="stylesheet">
    <style>
        body {
            font-family: 'DotGothic16', 'Press Start 2P', sans-serif;
            background-color: #111116;
            color: #e5e5e5;
            user-select: none;
            touch-action: manipulation;
        }
        .pixel-text {
            font-family: 'Press Start 2P', cursive;
        }
        /* Style for Minecraft look buttons */
        .mc-btn {
            background-color: #4a4a4a;
            border: 4px solid #000;
            border-top-color: #8b8b8b;
            border-left-color: #8b8b8b;
            border-right-color: #2c2c2c;
            border-bottom-color: #2c2c2c;
            text-shadow: 2px 2px #000;
            image-rendering: pixelated;
        }
        .mc-btn:active {
            border-top-color: #2c2c2c;
            border-left-color: #2c2c2c;
            border-right-color: #8b8b8b;
            border-bottom-color: #8b8b8b;
            padding-top: 6px;
            padding-bottom: 2px;
        }
        /* Canvas rendering optimizations */
        canvas {
            image-rendering: pixelated;
            box-shadow: 0 15px 35px -5px rgba(0, 0, 0, 0.9);
            border: 6px solid #444;
            background-color: #1a1a1a;
        }
        /* Virtual Controller Style */
        .controller-btn {
            background-color: #3e3e3e;
            border: 3px solid #1a1a1a;
            border-radius: 8px;
            box-shadow: inset 0 3px 0 rgba(255,255,255,0.2), 0 3px 5px rgba(0,0,0,0.5);
        }
        .controller-btn:active {
            background-color: #1e1e1e;
            transform: translateY(2px);
            box-shadow: none;
        }
        .attack-btn {
            background: linear-gradient(135deg, #55ffff, #00aaaa);
            border: 3px solid #000;
            border-radius: 50%;
            box-shadow: 0 4px 0 #005555;
            text-shadow: 1px 1px #000;
        }
        .attack-btn:active {
            transform: scale(0.9) translateY(2px);
            box-shadow: none;
        }
    </style>
</head>
<body class="min-h-screen flex flex-col items-center justify-between p-4 overflow-x-hidden">

    <header class="w-full max-w-lg text-center mt-1">
        <h1 class="text-3xl sm:text-4xl text-[#55FF55] tracking-wider font-bold mb-1 drop-shadow-[0_4px_0_rgba(0,0,0,1)] flex items-center justify-center gap-2">
            <span>🏠</span> MINECRAFT MAZE
        </h1>
        <p class="text-xs text-cyan-400 pixel-text tracking-widest mb-3">6-STORY MANSION UPDATE</p>
    </header>

    <!-- Main Game Area -->
    <div class="w-full max-w-2xl flex flex-col items-center">
        <!-- Status Bar -->
        <div class="w-full max-w-[540px] bg-[#2d2d2d] border-4 border-black p-3 mb-2 flex flex-col gap-2 text-xs sm:text-sm">
            <div class="flex justify-between items-center w-full">
                <!-- Hearts -->
                <div class="flex items-center gap-1">
                    <span class="text-xs text-gray-400 mr-1">LIFE:</span>
                    <span id="hearts-container" class="flex gap-0.5 text-red-500 text-lg">❤️❤️❤️</span>
                </div>
                <!-- Diamonds collected -->
                <div class="flex items-center gap-2">
                    <span class="text-cyan-400">💎</span>
                    <span id="diamond-counter" class="font-bold text-cyan-300">0 / 0</span>
                </div>
                <!-- Level Display -->
                <div class="text-[#FFFF55] font-bold">
                    STAGE: <span id="stage-num">1</span>
                </div>
            </div>
            <!-- Item & Floor slot -->
            <div class="flex items-center justify-between bg-black/40 px-2 py-1 border border-gray-600 rounded text-[11px]">
                <span class="text-gray-400">装備/階層:</span>
                <span id="sword-status" class="text-gray-300 font-bold">❌ なし (素手)</span>
                <span id="floor-status" class="text-green-400 font-bold">階層: 🏠 1F 地上</span>
                <span id="respawn-status" class="text-yellow-400 text-[9px] font-bold">📍 初期地点</span>
            </div>
        </div>

        <!-- Canvas Container - Broad 540px layout -->
        <div class="relative w-full aspect-square max-w-[540px] flex items-center justify-center bg-black rounded-lg">
            <canvas id="gameCanvas" class="w-full h-full max-w-full max-h-full"></canvas>
           
            <!-- System Chat Log Overlay -->
            <div id="game-chat" class="absolute left-4 top-4 bg-black/75 p-2 rounded text-[11px] text-white max-w-[85%] border border-gray-700 transition-opacity duration-300 pointer-events-none opacity-0">
                [システム] ベッドでリスポーン地点を設定した!
            </div>

            <!-- Level Clear / Game Over Overlays -->
            <div id="overlay" class="absolute inset-0 bg-black/85 flex flex-col items-center justify-center hidden p-6 text-center z-10">
                <h2 id="overlay-title" class="text-4xl font-bold mb-4 drop-shadow-[0_4px_0_rgba(0,0,0,1)]"></h2>
                <p id="overlay-sub" class="text-sm text-gray-300 mb-6"></p>
                <button id="overlay-btn" class="mc-btn px-6 py-3 text-lg font-bold text-white rounded w-52 transition-all">
                    次へ進む ➔
                </button>
            </div>
        </div>
    </div>

    <div class="w-full max-w-lg mt-2 flex flex-col gap-3">
        <!-- Game Configuration / Info -->
        <div class="flex justify-between items-center gap-1 px-1">
            <div class="flex gap-1">
                <button id="difficulty-btn" class="mc-btn px-2.5 py-1.5 text-xs font-bold text-white rounded">
                    難易度: 普通
                </button>
                <button id="fov-btn" class="mc-btn px-2.5 py-1.5 text-xs font-bold text-cyan-300 rounded">
                    🔍 視野: 広め
                </button>
                <button id="sound-btn" class="mc-btn px-2.5 py-1.5 text-xs font-bold text-white rounded">
                    🔊 音: ON
                </button>
            </div>
            <button id="reset-btn" class="mc-btn px-2.5 py-1.5 text-xs font-bold text-yellow-300 rounded">
                🔄 リセット
            </button>
        </div>

        <!-- Touch Controls -->
        <div id="touch-controls" class="flex items-center justify-between px-4 py-1">
            <!-- D-Pad -->
            <div class="grid grid-cols-3 gap-2 w-32 aspect-square">
                <div></div>
                <button id="btn-up" class="controller-btn flex items-center justify-center text-xl text-white">▲</button>
                <div></div>
                <button id="btn-left" class="controller-btn flex items-center justify-center text-xl text-white">◀</button>
                <div class="flex items-center justify-center text-[9px] text-gray-500 font-bold">MOVE</div>
                <button id="btn-right" class="controller-btn flex items-center justify-center text-xl text-white">▶</button>
                <div></div>
                <button id="btn-down" class="controller-btn flex items-center justify-center text-xl text-white font-bold">▼</button>
                <div></div>
            </div>

            <!-- Attack Action Button -->
            <div class="flex flex-col items-center justify-center gap-1">
                <button id="btn-attack" class="attack-btn w-20 h-20 flex flex-col items-center justify-center text-white active:bg-cyan-600">
                    <span class="text-3xl">🗡️</span>
                    <span class="text-[9px] font-bold tracking-wider">ATTACK</span>
                </button>
                <span class="text-[9px] text-gray-400">剣を振る</span>
            </div>
        </div>
    </div>

    <!-- Footer Description -->
    <footer class="text-center text-xs text-gray-500 mt-2 px-2 max-w-md">
        <p>PC: <span class="bg-gray-800 px-1 py-0.5 rounded text-gray-300">WASD</span> / <span class="bg-gray-800 px-1 py-0.5 rounded text-gray-300">矢印</span> で移動 / <span class="bg-gray-800 px-1 py-0.5 rounded text-gray-300">Space</span> で攻撃</p>
        <p class="mt-1 text-[10px] text-cyan-500">※3階で「エンチャントテーブル」に重なると最強の【ダイヤの剣】に覚醒!</p>
    </footer>

    <script>
        // --- STREAMING_CHUNK: Initializing Audio Engine for custom sounds... ---
        class SoundEngine {
            constructor() {
                this.ctx = null;
                this.enabled = true;
            }

            init() {
                if (!this.ctx) {
                    this.ctx = new (window.AudioContext || window.webkitAudioContext)();
                }
            }

            playStep() {
                if (!this.enabled) return;
                this.init();
                const osc = this.ctx.createOscillator();
                const gain = this.ctx.createGain();
                osc.connect(gain);
                gain.connect(this.ctx.destination);

                osc.type = 'triangle';
                osc.frequency.setValueAtTime(110, this.ctx.currentTime);
                osc.frequency.exponentialRampToValueAtTime(35, this.ctx.currentTime + 0.08);

                gain.gain.setValueAtTime(0.12, this.ctx.currentTime);
                gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + 0.08);

                osc.start();
                osc.stop(this.ctx.currentTime + 0.08);
            }

            playStairs() {
                if (!this.enabled) return;
                this.init();
                const now = this.ctx.currentTime;
                const playClack = (time, freq) => {
                    const osc = this.ctx.createOscillator();
                    const gain = this.ctx.createGain();
                    osc.connect(gain);
                    gain.connect(this.ctx.destination);
                    osc.type = 'triangle';
                    osc.frequency.setValueAtTime(freq, time);
                    gain.gain.setValueAtTime(0.12, time);
                    gain.gain.exponentialRampToValueAtTime(0.01, time + 0.08);
                    osc.start(time);
                    osc.stop(time + 0.08);
                };
                playClack(now, 160);
                playClack(now + 0.08, 220);
                playClack(now + 0.16, 280);
            }

            playDiamond() {
                if (!this.enabled) return;
                this.init();
                const osc = this.ctx.createOscillator();
                const gain = this.ctx.createGain();
                osc.connect(gain);
                gain.connect(this.ctx.destination);

                osc.type = 'sine';
                osc.frequency.setValueAtTime(987.77, this.ctx.currentTime); // B5
                osc.frequency.setValueAtTime(1318.51, this.ctx.currentTime + 0.08); // E6

                gain.gain.setValueAtTime(0.1, this.ctx.currentTime);
                gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + 0.3);

                osc.start();
                osc.stop(this.ctx.currentTime + 0.3);
            }

            playEnchant() {
                if (!this.enabled) return;
                this.init();
                const now = this.ctx.currentTime;
                const playTone = (freq, start, duration, type='sine') => {
                    const osc = this.ctx.createOscillator();
                    const gain = this.ctx.createGain();
                    osc.type = type;
                    osc.frequency.setValueAtTime(freq, start);
                    gain.gain.setValueAtTime(0.1, start);
                    gain.gain.exponentialRampToValueAtTime(0.001, start + duration);
                    osc.connect(gain);
                    gain.connect(this.ctx.destination);
                    osc.start(start);
                    osc.stop(start + duration);
                };
                playTone(440, now, 0.1);
                playTone(554, now + 0.08, 0.1);
                playTone(659, now + 0.16, 0.1);
                playTone(880, now + 0.24, 0.4, 'triangle');
            }

            playHiss() {
                if (!this.enabled) return;
                this.init();
                const bufferSize = this.ctx.sampleRate * 0.8;
                const buffer = this.ctx.createBuffer(1, bufferSize, this.ctx.sampleRate);
                const data = buffer.getChannelData(0);
                for (let i = 0; i < bufferSize; i++) {
                    data[i] = Math.random() * 2 - 1;
                }

                const noise = this.ctx.createBufferSource();
                noise.buffer = buffer;

                const filter = this.ctx.createBiquadFilter();
                filter.type = 'bandpass';
                filter.frequency.value = 3500;

                const gain = this.ctx.createGain();
                gain.gain.setValueAtTime(0.1, this.ctx.currentTime);
                gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + 0.8);

                noise.connect(filter);
                filter.connect(gain);
                gain.connect(this.ctx.destination);

                noise.start();
            }

            playExplode() {
                if (!this.enabled) return;
                this.init();
                const osc = this.ctx.createOscillator();
                const gain = this.ctx.createGain();
                osc.type = 'sawtooth';
                osc.frequency.setValueAtTime(100, this.ctx.currentTime);
                osc.frequency.exponentialRampToValueAtTime(10, this.ctx.currentTime + 0.6);

                const bufferSize = this.ctx.sampleRate * 0.6;
                const buffer = this.ctx.createBuffer(1, bufferSize, this.ctx.sampleRate);
                const data = buffer.getChannelData(0);
                for (let i = 0; i < bufferSize; i++) {
                    data[i] = Math.random() * 2 - 1;
                }
                const noise = this.ctx.createBufferSource();
                noise.buffer = buffer;

                const filter = this.ctx.createBiquadFilter();
                filter.type = 'lowpass';
                filter.frequency.setValueAtTime(800, this.ctx.currentTime);
                filter.frequency.exponentialRampToValueAtTime(80, this.ctx.currentTime + 0.5);

                const noiseGain = this.ctx.createGain();
                noiseGain.gain.setValueAtTime(0.35, this.ctx.currentTime);
                noiseGain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + 0.6);

                gain.gain.setValueAtTime(0.25, this.ctx.currentTime);
                gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + 0.5);

                osc.connect(gain);
                gain.connect(this.ctx.destination);

                noise.connect(filter);
                filter.connect(noiseGain);
                noiseGain.connect(this.ctx.destination);

                osc.start();
                osc.stop(this.ctx.currentTime + 0.6);
                noise.start();
            }

            playHurt() {
                if (!this.enabled) return;
                this.init();
                const osc = this.ctx.createOscillator();
                const gain = this.ctx.createGain();
                osc.connect(gain);
                gain.connect(this.ctx.destination);

                osc.type = 'sawtooth';
                osc.frequency.setValueAtTime(160, this.ctx.currentTime);
                osc.frequency.exponentialRampToValueAtTime(80, this.ctx.currentTime + 0.2);

                gain.gain.setValueAtTime(0.18, this.ctx.currentTime);
                gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + 0.2);

                osc.start();
                osc.stop(this.ctx.currentTime + 0.2);
            }

            playWin() {
                if (!this.enabled) return;
                this.init();
                const now = this.ctx.currentTime;
                const playTone = (freq, start, duration) => {
                    const osc = this.ctx.createOscillator();
                    const gain = this.ctx.createGain();
                    osc.type = 'triangle';
                    osc.frequency.setValueAtTime(freq, start);
                    gain.gain.setValueAtTime(0.12, start);
                    gain.gain.exponentialRampToValueAtTime(0.01, start + duration);
                    osc.connect(gain);
                    gain.connect(this.ctx.destination);
                    osc.start(start);
                    osc.stop(start + duration);
                };

                playTone(523.25, now, 0.15); // C5
                playTone(659.25, now + 0.15, 0.15); // E5
                playTone(783.99, now + 0.3, 0.15); // G5
                playTone(1046.50, now + 0.45, 0.4); // C6
            }

            playEquip() {
                if (!this.enabled) return;
                this.init();
                const osc = this.ctx.createOscillator();
                const gain = this.ctx.createGain();
                osc.connect(gain);
                gain.connect(this.ctx.destination);

                osc.type = 'sine';
                osc.frequency.setValueAtTime(550, this.ctx.currentTime);
                osc.frequency.exponentialRampToValueAtTime(1100, this.ctx.currentTime + 0.12);

                gain.gain.setValueAtTime(0.08, this.ctx.currentTime);
                gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + 0.12);

                osc.start();
                osc.stop(this.ctx.currentTime + 0.12);
            }

            playDoor() {
                if (!this.enabled) return;
                this.init();
                const osc = this.ctx.createOscillator();
                const gain = this.ctx.createGain();
                osc.connect(gain);
                gain.connect(this.ctx.destination);

                osc.type = 'triangle';
                osc.frequency.setValueAtTime(180, this.ctx.currentTime);
                osc.frequency.exponentialRampToValueAtTime(130, this.ctx.currentTime + 0.18);

                gain.gain.setValueAtTime(0.08, this.ctx.currentTime);
                gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + 0.18);

                osc.start();
                osc.stop(this.ctx.currentTime + 0.18);
            }

            playHeal() {
                if (!this.enabled) return;
                this.init();
                const now = this.ctx.currentTime;
                const playTone = (freq, start, duration) => {
                    const osc = this.ctx.createOscillator();
                    const gain = this.ctx.createGain();
                    osc.type = 'sine';
                    osc.frequency.setValueAtTime(freq, start);
                    gain.gain.setValueAtTime(0.08, start);
                    gain.gain.exponentialRampToValueAtTime(0.01, start + duration);
                    osc.connect(gain);
                    gain.connect(this.ctx.destination);
                    osc.start(start);
                    osc.stop(start + duration);
                };
                playTone(523.25, now, 0.18); // C5
                playTone(659.25, now + 0.08, 0.18); // E5
                playTone(783.99, now + 0.16, 0.35); // G5
            }

            playClick() {
                if (!this.enabled) return;
                this.init();
                const osc = this.ctx.createOscillator();
                const gain = this.ctx.createGain();
                osc.connect(gain);
                gain.connect(this.ctx.destination);
                osc.type = 'sine';
                osc.frequency.setValueAtTime(750, this.ctx.currentTime);
                gain.gain.setValueAtTime(0.04, this.ctx.currentTime);
                gain.gain.exponentialRampToValueAtTime(0.001, this.ctx.currentTime + 0.04);
                osc.start();
                osc.stop(this.ctx.currentTime + 0.04);
            }
        }

        const sound = new SoundEngine();

        // --- STREAMING_CHUNK: Setting up the layout grid values and block types... ---
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');
        ctx.imageSmoothingEnabled = false;

        const TILE_SIZE = 32;
       
        const FOV_LEVELS = [
            { name: '標準 (11x11)', tiles: 11 },
            { name: '広め (15x15)', tiles: 15 },
            { name: '広域 (19x19)', tiles: 19 }
        ];
        let currentFovIndex = 1;
        let viewportTiles = FOV_LEVELS[currentFovIndex].tiles;

        const DIFFICULTIES = [
            { name: 'イージー', size: 15, diamonds: 4, creepers: 1 },
            { name: 'ノーマル', size: 25, diamonds: 8, creepers: 3 },
            { name: 'ハード', size: 39, diamonds: 14, creepers: 6 }
        ];

        // Block definition including library and enchanting tables
        const BLOCK = {
            GRASS: 0,
            COBBLE: 1,
            DIAMOND: 2,
            PORTAL: 3,
            WOOD_WALL: 4,
            WOOD_FLOOR: 5,
            DOOR: 6,
            CHEST: 7,
            BED: 8,
            CRAFTING: 9,
            GLASS: 10,
            STAIRS_UP: 11,
            STAIRS_DOWN: 12,
            FENCE: 13,
            CHEST_2F: 14,
            BOOKSHELF: 15,
            ENCHANT_TABLE: 16,
            CHEST_3F: 17,
            CHEST_4F: 18,
            BREWING_STAND: 19,
            CHEST_5F: 20,
            NETHER_BRICK: 21,
            NETHER_WART: 22,
            CHEST_6F: 23,
            DRAGON_EGG: 24
        };

        let currentDifficultyIndex = 1;
        let stage = 1;
        let lives = 3;
        let diamondsCollected = 0;
        let totalStageDiamonds = 0;

        let mazeWidth = 25;
        let mazeHeight = 25;
        let grid = [];
        let player = { x: 1, y: 1, targetX: 1, targetY: 1, moveProgress: 0, dir: 'down' };
        let creepers = [];
        let particles = [];
        let animationFrameId = null;
        let gameOver = false;
        let gameClear = false;
        let tickCount = 0;

        // --- HOUSE & ITEM STATE VARIABLES ---
        let swordLevel = 0; // 0: None, 1: Iron Sword, 2: Diamond Sword
        let speedBuffTimer = 0; // Speed potion buff duration
        let attackTicks = 0;
        let respawnX = 1;
        let respawnY = 1;
        let openedChests = new Set();
        let openDoors = new Set();
        let houseArea = { minX: 0, maxX: 0, minY: 0, maxY: 0 };

        // 6 Floors Mansion Model
        let currentFloor = 1; // 1:1F, 2:2F, 3:3F, 4:4F, 5:5F, 6:6F
        let grid2F = [];
        let grid3F = [];
        let grid4F = [];
        let grid5F = [];
        let grid6F = [];

        let openedChests2F = new Set();
        let openedChests3F = new Set();
        let openedChests4F = new Set();
        let openedChests5F = new Set();
        let openedChests6F = new Set();

        function resizeCanvas() {
            canvas.width = viewportTiles * TILE_SIZE;
            canvas.height = viewportTiles * TILE_SIZE;
        }

        function drawPixelRect(ctx, x, y, w, h, color) {
            ctx.fillStyle = color;
            ctx.fillRect(Math.floor(x), Math.floor(y), Math.floor(w), Math.floor(h));
        }

        function showSystemChat(msg) {
            const chatBox = document.getElementById('game-chat');
            chatBox.textContent = `[システム] ${msg}`;
            chatBox.style.opacity = '1';
           
            if (window.chatTimeout) clearTimeout(window.chatTimeout);
            window.chatTimeout = setTimeout(() => {
                chatBox.style.opacity = '0';
            }, 3500);
        }

        // --- STREAMING_CHUNK: Handling particle physics and walking dust... ---
        function spawnWalkParticle(x, y, blockType) {
            const count = 3 + Math.floor(Math.random() * 3);
            let isGrass = (blockType === BLOCK.GRASS);
            let isWood = (blockType === BLOCK.WOOD_FLOOR || blockType === BLOCK.BED || blockType === BLOCK.CHEST || blockType === BLOCK.BOOKSHELF);
           
            for (let i = 0; i < count; i++) {
                let color = '#866043';
                if (isGrass) {
                    color = Math.random() < 0.4 ? '#5c8e32' : '#866043';
                } else if (isWood) {
                    color = Math.random() < 0.5 ? '#cd853f' : '#8b5a2b';
                } else if (blockType === BLOCK.COBBLE) {
                    color = '#737373';
                } else if (blockType === BLOCK.ENCHANT_TABLE || blockType === BLOCK.DRAGON_EGG) {
                    color = Math.random() < 0.5 ? '#7f1d1d' : '#a21caf'; // Magic particles
                } else if (blockType === BLOCK.NETHER_BRICK || blockType === BLOCK.NETHER_WART) {
                    color = '#800000'; // Nether Crimson Red
                }

                particles.push({
                    x: x * TILE_SIZE + TILE_SIZE / 2 + (Math.random() - 0.5) * 16,
                    y: y * TILE_SIZE + TILE_SIZE - 4 + (Math.random() - 0.5) * 6,
                    vx: (Math.random() - 0.5) * 1.5,
                    vy: -Math.random() * 1.5 - 0.5,
                    color: color,
                    alpha: 1.0,
                    size: 2 + Math.floor(Math.random() * 3),
                    life: 1.0,
                    decay: 0.04 + Math.random() * 0.04
                });
            }
        }

        // Spawns potion swirly particles
        function spawnPotionParticles(x, y) {
            if (Math.random() < 0.15) {
                particles.push({
                    x: x * TILE_SIZE + TILE_SIZE / 2 + (Math.random() - 0.5) * 20,
                    y: y * TILE_SIZE + TILE_SIZE / 2 + (Math.random() - 0.5) * 20,
                    vx: (Math.random() - 0.5) * 0.6,
                    vy: -Math.random() * 0.8 - 0.2,
                    color: '#eab308', // Yellow speed sparkles
                    alpha: 1.0,
                    size: 2 + Math.floor(Math.random() * 2),
                    life: 0.8,
                    decay: 0.03
                });
            }
        }

        function updateParticles() {
            for (let i = particles.length - 1; i >= 0; i--) {
                const p = particles[i];
                p.x += p.vx;
                p.y += p.vy;
                p.vy += 0.08;
                p.life -= p.decay;
                if (p.life <= 0) {
                    particles.splice(i, 1);
                }
            }
        }

        function drawParticles(ctx, cameraX, cameraY) {
            particles.forEach(p => {
                ctx.save();
                ctx.globalAlpha = p.life;
                const rx = p.x - cameraX * TILE_SIZE;
                const ry = p.y - cameraY * TILE_SIZE;
                drawPixelRect(ctx, rx, ry, p.size, p.size, p.color);
                ctx.restore();
            });
        }

        // --- STREAMING_CHUNK: Rendering block textures... ---

        // Cobblestone Wall
        function drawCobbleWall(ctx, x, y, size) {
            drawPixelRect(ctx, x, y, size, size, '#737373');
            const p = size / 8;
            const dark = '#4d4d4d';
            const light = '#9b9b9b';

            drawPixelRect(ctx, x, y, size, p, light);
            drawPixelRect(ctx, x, y, p, size, light);
            drawPixelRect(ctx, x, y + p*4, size, p, dark);
            drawPixelRect(ctx, x, y + size - p, size, p, dark);
            drawPixelRect(ctx, x + p*4, y, p, p*4, dark);
            drawPixelRect(ctx, x + p*2, y + p*4, p, p*4, dark);
            drawPixelRect(ctx, x + p*6, y + p*4, p, p*4, dark);

            drawPixelRect(ctx, x + p*2, y + p*2, p, p, dark);
            drawPixelRect(ctx, x + p*6, y + p*1, p, p, light);
            drawPixelRect(ctx, x + p*1, y + p*6, p, p, light);
            drawPixelRect(ctx, x + p*5, y + p*5, p, p, dark);
        }

        // Grass Floor
        function drawGrassFloor(ctx, x, y, size) {
            drawPixelRect(ctx, x, y, size, size, '#866043');
            const p = size / 8;

            drawPixelRect(ctx, x, y, size, p*2, '#5c8e32');
            drawPixelRect(ctx, x + p, y + p*2, p, p, '#5c8e32');
            drawPixelRect(ctx, x + p*3, y + p*2, p, p, '#5c8e32');
            drawPixelRect(ctx, x + p*5, y + p*2, p, p, '#5c8e32');
            drawPixelRect(ctx, x + p*7, y + p*2, p, p, '#5c8e32');
           
            drawPixelRect(ctx, x + p*2, y + p*5, p, p, '#573d26');
            drawPixelRect(ctx, x + p*5, y + p*6, p, p, '#573d26');
            drawPixelRect(ctx, x + p*6, y + p*4, p, p, '#a0785a');
            drawPixelRect(ctx, x + p*1, y + p*7, p, p, '#a0785a');
        }

        // Planks (Wall)
        function drawWoodWall(ctx, x, y, size) {
            drawPixelRect(ctx, x, y, size, size, '#8b5a2b');
            const p = size / 8;
           
            drawPixelRect(ctx, x, y + p*2, size, p, '#573d26');
            drawPixelRect(ctx, x, y + p*4, size, p, '#573d26');
            drawPixelRect(ctx, x, y + p*6, size, p, '#573d26');
            drawPixelRect(ctx, x, y + size - p, size, p, '#573d26');
           
            drawPixelRect(ctx, x, y, size, p/2, '#b8860b');
            drawPixelRect(ctx, x, y + p*2.5, size, p/2, '#b8860b');
            drawPixelRect(ctx, x, y + p*4.5, size, p/2, '#b8860b');
            drawPixelRect(ctx, x, y + p*6.5, size, p/2, '#b8860b');
        }

        // Nether Brick (Wall)
        function drawNetherBrick(ctx, x, y, size) {
            drawPixelRect(ctx, x, y, size, size, '#2c1115'); // Very dark burgundy/brown
            const p = size / 8;
            const darkOutline = '#150508';
            const lighterRed = '#401e23';

            // Horizontal brick rows
            drawPixelRect(ctx, x, y + p*2, size, p/2, darkOutline);
            drawPixelRect(ctx, x, y + p*4, size, p/2, darkOutline);
            drawPixelRect(ctx, x, y + p*6, size, p/2, darkOutline);
            drawPixelRect(ctx, x, y + size - p/2, size, p/2, darkOutline);

            // Brick segments
            drawPixelRect(ctx, x + p*3, y, p/2, p*2, darkOutline);
            drawPixelRect(ctx, x + p*5, y + p*2, p/2, p*2, darkOutline);
            drawPixelRect(ctx, x + p*2, y + p*4, p/2, p*2, darkOutline);
            drawPixelRect(ctx, x + p*6, y + p*6, p/2, p*2, darkOutline);

            // Red highlights
            drawPixelRect(ctx, x + p, y + p, p, p/2, lighterRed);
            drawPixelRect(ctx, x + p*6, y + p*3, p, p/2, lighterRed);
            drawPixelRect(ctx, x + p*3, y + p*5, p, p/2, lighterRed);
        }

        // Nether Wart (5F Garden block)
        function drawNetherWart(ctx, x, y, size) {
            drawPixelRect(ctx, x, y, size, size, '#4a2c2a'); // Soul sand floor look
            const p = size / 8;
            const cropRed = '#900c3f';
            const cropBright = '#c70039';

            // Draw wart stalks
            drawPixelRect(ctx, x + p*2, y + p*3, p, p*4, cropRed);
            drawPixelRect(ctx, x + p*5, y + p*2, p, p*5, cropRed);
            drawPixelRect(ctx, x + p*1, y + p*2, p*2, p, cropBright);
            drawPixelRect(ctx, x + p*4, y + p, p*3, p, cropBright);
            drawPixelRect(ctx, x + p*2, y + p*4, p, p, '#ff5733'); // glowing hot point
        }

        // Dragon Egg (6F Ender Altar)
        function drawDragonEgg(ctx, x, y, size) {
            drawWoodFloor(ctx, x, y, size);
            const p = size / 8;

            // Draw obsidian pedestal
            drawPixelRect(ctx, x + p*2, y + p*5, p*4, p*2.5, '#190a2a');
            drawPixelRect(ctx, x + p*1.5, y + p*7, p*5, p, '#0c0216');

            // Float physics
            const pulse = Math.sin(tickCount * 0.12) * 2;
            const ex = x + p*2.5;
            const ey = y + p*1.5 + pulse;

            // Egg structure
            drawPixelRect(ctx, ex + p, ey, p, p, '#2e0854'); // Obsidian-purple egg top
            drawPixelRect(ctx, ex, ey + p, p*3, p*2.5, '#120224'); // Center body
            drawPixelRect(ctx, ex + p/2, ey + p*3.5, p*2, p, '#000000'); // Bottom
            drawPixelRect(ctx, ex + p, ey + p, p/2, p*2, '#d1c4e9'); // Specular highlight
        }

        // Birch Planks (Floor)
        function drawWoodFloor(ctx, x, y, size) {
            drawPixelRect(ctx, x, y, size, size, '#dfb175');
            const p = size / 8;
           
            drawPixelRect(ctx, x + p*2, y, p, size, '#c49353');
            drawPixelRect(ctx, x + p*6, y, p, size, '#c49353');
            drawPixelRect(ctx, x, y + p*4, p*2, p/2, '#c49353');
            drawPixelRect(ctx, x + p*2, y + p*2, p*4, p/2, '#c49353');
            drawPixelRect(ctx, x + p*6, y + p*6, p*2, p/2, '#c49353');
        }

        // Wooden Door
        function drawDoorBlock(ctx, x, y, size, isOpen) {
            drawWoodFloor(ctx, x, y, size);
            const p = size / 8;

            if (isOpen) {
                drawPixelRect(ctx, x, y, p*2, size, '#8b4513');
                drawPixelRect(ctx, x + p*0.5, y + p, p, p*2, '#87ceeb');
                drawPixelRect(ctx, x + p*1.5, y + p*4.5, p/2, p, '#ffd700');
            } else {
                drawPixelRect(ctx, x + p, y, p*6, size, '#a0522d');
                drawPixelRect(ctx, x + p*1.5, y + p*1.5, p*3, p*2.5, '#5c310e');
                drawPixelRect(ctx, x + p*1.5, y + p*4.5, p*3, p*2.5, '#5c310e');
                drawPixelRect(ctx, x + p*2, y + p*2, p*2, p, '#87ceeb');
                drawPixelRect(ctx, x + p*5, y + p*4.5, p, p, '#ffd700');
            }
        }

        // Chests (Standard, Blue, Purple)
        function drawChestBlock(ctx, x, y, size, isOpened) {
            drawWoodFloor(ctx, x, y, size);
            const p = size / 8;
            const cx = x + p;
            const cy = y + p;
            const cs = size - p*2;

            if (!isOpened) {
                drawPixelRect(ctx, cx, cy, cs, cs, '#7a4215');
                drawPixelRect(ctx, cx, cy + p*2.5, cs, p, '#3d210a');
                drawPixelRect(ctx, cx + cs/2 - p/2, cy + p*2, p, p*1.5, '#c0c0c0');
                drawPixelRect(ctx, cx + cs/2 - p/2, cy + p*3.2, p, p/2, '#000000');
            } else {
                drawPixelRect(ctx, cx, cy + p, cs, cs - p, '#5c310e');
                drawPixelRect(ctx, cx, cy - p/2, cs, p*1.5, '#7a4215');
                drawPixelRect(ctx, cx + cs/2 - p/2, cy + p, p, p, '#c0c0c0');
            }
        }

        // 2F Premium Chest (Diamond Chest with Golden Trims)
        function drawChest2F(ctx, x, y, size, isOpened) {
            drawWoodFloor(ctx, x, y, size);
            const p = size / 8;
            const cx = x + p;
            const cy = y + p;
            const cs = size - p*2;

            if (!isOpened) {
                // Gold themed chest for 2F reward!
                drawPixelRect(ctx, cx, cy, cs, cs, '#4682b4'); // Steel blue chest base
                drawPixelRect(ctx, cx, cy, p, cs, '#ffd700'); // Gold left trim
                drawPixelRect(ctx, cx + cs - p, cy, p, cs, '#ffd700'); // Gold right trim
                drawPixelRect(ctx, cx, cy + p*2.5, cs, p, '#3d210a'); // partition
                drawPixelRect(ctx, cx + cs/2 - p, cy + p*1.8, p*2, p*1.5, '#ffd700'); // Gold latch lock
                drawPixelRect(ctx, cx + cs/2 - p/2, cy + p*2.8, p, p/2, '#000000');
            } else {
                drawPixelRect(ctx, cx, cy + p, cs, cs - p, '#2a4d6c'); // Open base
                drawPixelRect(ctx, cx, cy - p/2, cs, p*1.5, '#4682b4'); // Open lid
                drawPixelRect(ctx, cx, cy - p/2, p, p*1.5, '#ffd700'); // Open lid gold trim L
                drawPixelRect(ctx, cx + cs - p, cy - p/2, p, p*1.5, '#ffd700'); // Open lid gold trim R
                drawPixelRect(ctx, cx + cs/2 - p/2, cy + p, p, p, '#ffd700'); // lock hanging
            }
        }

        // Red Bed
        function drawBedBlock(ctx, x, y, size) {
            drawWoodFloor(ctx, x, y, size);
            const p = size / 8;
            drawPixelRect(ctx, x + p, y + p*2.5, p*6, p*4.5, '#cc2222');
            drawPixelRect(ctx, x + p, y + p*3.5, p*6, p/2, '#990000');
            drawPixelRect(ctx, x + p, y + p, p*6, p*1.5, '#dddddd');
            drawPixelRect(ctx, x + p*1.5, y + p*1.2, p*5, p, '#ffffff');
            drawPixelRect(ctx, x + p, y + p*7, p, p, '#5c310e');
            drawPixelRect(ctx, x + p*6, y + p*7, p, p, '#5c310e');
        }

        // Crafting Table
        function drawCraftingTable(ctx, x, y, size) {
            drawPixelRect(ctx, x, y, size, size, '#8b5a2b');
            const p = size / 8;
            drawPixelRect(ctx, x + p, y + p, p*6, p*6, '#a0522d');
            drawPixelRect(ctx, x + p*2, y, p/2, size, '#5c310e');
            drawPixelRect(ctx, x + p*6, y, p/2, size, '#5c310e');
            drawPixelRect(ctx, x, y + p*2, size, p/2, '#5c310e');
            drawPixelRect(ctx, x + p*1.5, y + p*4.5, p, p*3, '#ffffff');
            drawPixelRect(ctx, x + p*2.5, y + p*5.5, p, p, '#5c310e');
            drawPixelRect(ctx, x + p*5.5, y + p*4.5, p*1.5, p*1.5, '#87ceeb');
        }

        // Glass Window
        function drawGlassWindow(ctx, x, y, size) {
            drawWoodWall(ctx, x, y, size);
            const p = size / 8;
            drawPixelRect(ctx, x + p*1.5, y + p*1.5, p*5, p*5, 'rgba(135, 206, 235, 0.7)');
            drawPixelRect(ctx, x + p*2, y + p*2, p, p, '#ffffff');
            drawPixelRect(ctx, x + p*3, y + p*3, p, p, '#ffffff');
            drawPixelRect(ctx, x + p*5, y + p*5, p, p, '#ffffff');
        }

        // Stairs Up
        function drawStairsUp(ctx, x, y, size) {
            drawWoodFloor(ctx, x, y, size);
            const p = size / 8;
            const darkWood = '#5c310e';
            const lightWood = '#a0522d';
            drawPixelRect(ctx, x + p, y + p*5, p*6, p*2, darkWood);
            drawPixelRect(ctx, x + p*2, y + p*3, p*5, p*2, lightWood);
            drawPixelRect(ctx, x + p*3, y + p, p*4, p*2, '#cd853f');
            drawPixelRect(ctx, x + p, y + p*7, p*6, p, '#3d1a00');
        }

        // Stairs Down
        function drawStairsDown(ctx, x, y, size) {
            drawWoodFloor(ctx, x, y, size);
            const p = size / 8;
            drawPixelRect(ctx, x + p*1.5, y + p*1.5, p*5, p*5, '#150d05');
            const ladderColor = '#d2b48c';
            drawPixelRect(ctx, x + p*2.5, y + p*2, p, p*4, ladderColor);
            drawPixelRect(ctx, x + p*4.5, y + p*2, p, p*4, ladderColor);
            drawPixelRect(ctx, x + p*2.5, y + p*2.5, p*3, p*0.5, '#a0522d');
            drawPixelRect(ctx, x + p*2.5, y + p*3.5, p*3, p*0.5, '#a0522d');
            drawPixelRect(ctx, x + p*2.5, y + p*4.5, p*3, p*0.5, '#a0522d');
        }

        // Fence / Balcony Safety Railing
        function drawFence(ctx, x, y, size, backgroundGrass = false) {
            if (backgroundGrass) {
                drawGrassFloor(ctx, x, y, size);
            } else {
                drawWoodFloor(ctx, x, y, size);
            }
            const p = size / 8;
            const darkWood = '#5c310e';
            const lightWood = '#8b5a2b';
            drawPixelRect(ctx, x + p, y + p, p*1.2, p*6, darkWood);
            drawPixelRect(ctx, x + p*3.4, y + p, p*1.2, p*6, darkWood);
            drawPixelRect(ctx, x + p*5.8, y + p, p*1.2, p*6, darkWood);
            drawPixelRect(ctx, x + p, y + p*2, p*6, p, lightWood);
            drawPixelRect(ctx, x + p, y + p*4.5, p*6, p, lightWood);
            drawPixelRect(ctx, x + p, y + p, p*1.2, p/2, '#cd853f');
            drawPixelRect(ctx, x + p*3.4, y + p, p*1.2, p/2, '#cd853f');
            drawPixelRect(ctx, x + p*5.8, y + p, p*1.2, p/2, '#cd853f');
        }

        // Bookshelf
        function drawBookshelf(ctx, x, y, size) {
            drawWoodWall(ctx, x, y, size);
            const p = size / 8;
            const row1Y = y + p*1.2;
            const row2Y = y + p*4.7;
           
            // Row 1 Books
            drawPixelRect(ctx, x + p*1.5, row1Y, p*1.1, p*2.1, '#cc2222'); // Red
            drawPixelRect(ctx, x + p*2.6, row1Y, p*0.9, p*2.1, '#33cc33'); // Green
            drawPixelRect(ctx, x + p*3.5, row1Y + p*0.3, p*1.2, p*1.8, '#cccc33'); // Yellow
            drawPixelRect(ctx, x + p*5.5, row1Y, p*1.0, p*2.1, '#3333cc'); // Blue
           
            // Row 2 Books
            drawPixelRect(ctx, x + p*1.2, row2Y + p*0.3, p*1.3, p*1.8, '#33ccff'); // Lightblue
            drawPixelRect(ctx, x + p*2.5, row2Y, p*1.0, p*2.1, '#cc22cc'); // Pink
            drawPixelRect(ctx, x + p*4.5, row2Y, p*1.1, p*2.1, '#cc5522'); // Orange
            drawPixelRect(ctx, x + p*5.6, row2Y + p*0.4, p*1.2, p*1.7, '#dddddd'); // White
        }

        // Enchanting Table (Obsidian base, diamond corners, floating purple magic book)
        function drawEnchantTable(ctx, x, y, size) {
            drawWoodFloor(ctx, x, y, size);
            const p = size / 8;
            const cx = x + p;
            const cy = y + p*2;
            const cs = size - p*2;

            // Obsidian Base
            drawPixelRect(ctx, cx, cy, cs, cs - p, '#1c0d24');
            drawPixelRect(ctx, cx + p, cy - p, cs - p*2, p, '#ab1ccf'); // Purple carpet top
           
            // Diamond corners
            drawPixelRect(ctx, cx, cy + p*2.5, p*1.2, p*1.2, '#55ffff');
            drawPixelRect(ctx, cx + cs - p*1.2, cy + p*2.5, p*1.2, p*1.2, '#55ffff');

            // Floating purple book
            const pulse = Math.sin(tickCount * 0.1) * 3;
            const bx = x + size/2;
            const by = y + p*1.5 + pulse;

            // Open book pages (White) and leather cover (Red/Brown)
            drawPixelRect(ctx, bx - p*2, by - p, p*4, p*1.5, '#6a1b9a'); // Cover
            drawPixelRect(ctx, bx - p*1.6, by - p*0.8, p*1.5, p*1.2, '#ffffff'); // Left Page
            drawPixelRect(ctx, bx + p*0.1, by - p*0.8, p*1.5, p*1.2, '#ffffff'); // Right Page
            drawPixelRect(ctx, bx - p*0.1, by - p*0.8, p*0.2, p*1.2, '#9c27b0'); // Bookmark ribbon
        }

        // 4F Brewing Stand
        function drawBrewingStand(ctx, x, y, size) {
            drawWoodFloor(ctx, x, y, size);
            const p = size / 8;
            const cx = x + size/2;
            const cy = y + p*1.5;

            // Stand platform
            drawPixelRect(ctx, cx - p*2, y + p*6, p*4, p*1.5, '#7f8c8d'); // Cobble base
            drawPixelRect(ctx, cx - p/2, y + p*2.5, p, p*4, '#95a5a6'); // Center pole

            // Bubbling glowing potion flasks (yellow and pink)
            const bubble = Math.sin(tickCount * 0.15) * 1;
            drawPixelRect(ctx, cx - p*2.5, y + p*4 + bubble, p*1.2, p*1.5, '#eab308'); // left yellow speed
            drawPixelRect(ctx, cx + p*1.3, y + p*4.5 - bubble, p*1.2, p*1.5, '#c026d3'); // right pink health
            drawPixelRect(ctx, cx - p*0.6, y + p*1.5, p*1.2, p, '#ef4444'); // hot blaze rod fire
        }

        // 2: Diamond Ore block
        function drawDiamondOre(ctx, x, y, size) {
            drawCobbleWall(ctx, x, y, size);
            const p = size / 8;
            const oreColor = '#4dedf4';
            const shadowColor = '#1fb2bf';

            const veins = [
                {px: 2, py: 1}, {px: 5, py: 2},
                {px: 1, py: 4}, {px: 2, py: 5},
                {px: 6, py: 5}, {px: 5, py: 6}
            ];

            veins.forEach(v => {
                drawPixelRect(ctx, x + v.px*p, y + v.py*p, p, p, oreColor);
                drawPixelRect(ctx, x + (v.px + 1)*p, y + v.py*p, p, p, shadowColor);
            });
        }

        // 3: Portal / Goal block
        function drawGoal(ctx, x, y, size) {
            const p = size / 8;
            drawPixelRect(ctx, x, y, size, size, '#120b24');
           
            const pulse = (Math.sin(tickCount * 0.15) + 1) / 2;
            const portalColor = `rgba(${120 + pulse*80}, 20, ${200 + pulse*55}, 0.8)`;
           
            drawPixelRect(ctx, x + p*1.5, y + p*1.5, p*5, p*5, portalColor);
            drawPixelRect(ctx, x + p*2.5, y + p*2.5, p*3, p*3, '#e156ff');
            drawPixelRect(ctx, x, y, p, p, '#351c62');
            drawPixelRect(ctx, x + size - p, y, p, p, '#351c62');
            drawPixelRect(ctx, x, y + size - p, p, p, '#351c62');
        }

        // --- STREAMING_CHUNK: Modeling player and dynamic sword upgrades... ---
        // Draw Player with walking motion and sword swing (Iron or Diamond)
        function drawPlayer(ctx, x, y, size, direction, moveProgress) {
            const p = size / 8;
            let bob = 0;
            let limbSwing = 0;
            if (moveProgress > 0) {
                bob = Math.abs(Math.sin(moveProgress * Math.PI)) * 3;
                limbSwing = Math.sin(moveProgress * Math.PI * 2);
            }
           
            const drawY = y - bob;

            // Head (Hair, skin)
            drawPixelRect(ctx, x + p*2, drawY, p*4, p*3, '#a17452'); // Face skin
            drawPixelRect(ctx, x + p*2, drawY, p*4, p, '#533722'); // Hair top
            drawPixelRect(ctx, x + p*2, drawY + p, p, p*2, '#533722');
            drawPixelRect(ctx, x + p*5, drawY + p, p, p*2, '#533722');

            // Face
            if (direction !== 'up') {
                drawPixelRect(ctx, x + p*2.5, drawY + p*1.5, p, p*0.5, '#ffffff'); // Eye L
                drawPixelRect(ctx, x + p*4.5, drawY + p*1.5, p, p*0.5, '#ffffff'); // Eye R
                drawPixelRect(ctx, x + p*3.5, drawY + p*1.5, p, p, '#1c12cc'); // Pupils
                drawPixelRect(ctx, x + p*3, drawY + p*2, p*2, p, '#804c35'); // Beard
            }

            // Torso (Cyan shirt)
            drawPixelRect(ctx, x + p*1.5, drawY + p*3, p*5, p*3, '#009fa2');

            // Limbs Swing
            const swingOffset = Math.round(limbSwing * 1.5);

            if (direction === 'left' || direction === 'right') {
                const isRight = direction === 'right';
                const bodyCenter = x + p*3.5;
                const backLimbColor = '#007072';
                const backLegColor = '#1f255b';  
                const armSwingX = isRight ? -swingOffset : swingOffset;
                const legSwingX = isRight ? swingOffset : -swingOffset;

                // Back Arm
                drawPixelRect(ctx, bodyCenter + armSwingX - p, drawY + p*3, p*2, p*3, backLimbColor);
                drawPixelRect(ctx, bodyCenter + armSwingX - p, drawY + p*4.5, p*2, p*1.5, '#876043');

                // Back Leg
                drawPixelRect(ctx, bodyCenter - legSwingX - p*1.2, drawY + p*6, p*2.4, p*2, backLegColor);
                drawPixelRect(ctx, bodyCenter - legSwingX - p*1.2, drawY + p*7.5, p*2.4, p*0.5, '#404040');

                // Front Leg
                drawPixelRect(ctx, bodyCenter + legSwingX - p*1.2, drawY + p*6, p*2.4, p*2, '#2c3580');
                drawPixelRect(ctx, bodyCenter + legSwingX - p*1.2, drawY + p*7.5, p*2.4, p*0.5, '#5c5c5c');

                // Front Arm
                drawPixelRect(ctx, bodyCenter - armSwingX - p, drawY + p*3, p*2, p*3, '#00afb2');
                drawPixelRect(ctx, bodyCenter - armSwingX - p, drawY + p*4.5, p*2, p*1.5, '#a17452');
            } else {
                const leftSwing = swingOffset;
                const rightSwing = -swingOffset;

                // Arms L & R
                drawPixelRect(ctx, x + p*0.5, drawY + p*3 + leftSwing, p, p*3, '#009fa2');
                drawPixelRect(ctx, x + p*6.5, drawY + p*3 + rightSwing, p, p*3, '#009fa2');
                drawPixelRect(ctx, x + p*0.5, drawY + p*4.5 + leftSwing, p, p*1.5, '#a17452');
                drawPixelRect(ctx, x + p*6.5, drawY + p*4.5 + rightSwing, p, p*1.5, '#a17452');

                // Legs L & R
                drawPixelRect(ctx, x + p*1.5, drawY + p*6, p*2.2, p*1.8 + rightSwing, '#2c3580');
                drawPixelRect(ctx, x + p*4.3, drawY + p*6, p*2.2, p*1.8 + leftSwing, '#2c3580');
                drawPixelRect(ctx, x + p*1.5, drawY + p*7.5 + rightSwing, p*2.2, p*0.5, '#5c5c5c');
                drawPixelRect(ctx, x + p*4.3, drawY + p*7.5 + leftSwing, p*2.2, p*0.5, '#5c5c5c');
            }

            // --- SWORD DRAWING SYSTEM (If Equipped) ---
            if (swordLevel > 0) {
                ctx.save();
                let swordAngle = 0;
                let sx = x + p*6.5;
                let sy = drawY + p*4.5 + swingOffset;

                if (direction === 'left') {
                    sx = x + p*0.5;
                    sy = drawY + p*4.5 + swingOffset;
                }

                if (attackTicks > 0) {
                    const progress = (10 - attackTicks) / 10;
                    swordAngle = -0.5 + progress * Math.PI;
                }

                ctx.translate(sx, sy);
                ctx.rotate(swordAngle);

                const isDiamond = (swordLevel === 2);
                const bladeMain = isDiamond ? '#55ffff' : '#d0e0e3';
                const bladeShadow = isDiamond ? '#00aaaa' : '#95a5a6';
                const bladeSpecular = isDiamond ? '#e0ffff' : '#ffffff';

                // Hilt/Handle
                drawPixelRect(ctx, -p/2, -p, p, p*2, '#5c310e');
                drawPixelRect(ctx, -p*1.5, -p, p*3, p/2, isDiamond ? '#00aaaa' : '#4a4a4a');
               
                // Blade
                drawPixelRect(ctx, -p/2, -p*5, p, p*4, bladeMain);
                drawPixelRect(ctx, -p/4, -p*5.5, p/2, p/2, bladeSpecular);
                drawPixelRect(ctx, -p/2, -p*4, p/4, p*3, bladeSpecular);
                drawPixelRect(ctx, +p/4, -p*4, p/4, p*3, bladeShadow);

                ctx.restore();
            }
        }

        // Draw Creeper Enemy
        function drawCreeper(ctx, x, y, size, warning = false, moveProgress = 0) {
            const p = size / 8;
            let baseColor = '#4f9131';
            let faceColor = '#1d1d1d';
           
            if (warning && Math.floor(tickCount / 3) % 2 === 0) {
                baseColor = '#ffffff';
                faceColor = '#ff0000';
            }

            // Head and Body
            drawPixelRect(ctx, x + p*1.5, y, p*5, p*6, baseColor);
           
            if (!warning) {
                drawPixelRect(ctx, x + p*2, y + p, p, p, '#386a21');
                drawPixelRect(ctx, x + p*5, y + p*2, p, p, '#386a21');
                drawPixelRect(ctx, x + p*4, y + p*5, p, p, '#386a21');
                drawPixelRect(ctx, x + p*1.5, y + p*4, p, p, '#67ab47');
            }

            // Face
            drawPixelRect(ctx, x + p*2.5, y + p, p, p, faceColor);
            drawPixelRect(ctx, x + p*4.5, y + p, p, p, faceColor);
            drawPixelRect(ctx, x + p*3.5, y + p*2, p, p, faceColor);
            drawPixelRect(ctx, x + p*3, y + p*3, p*2, p*1.5, faceColor);
            drawPixelRect(ctx, x + p*2.5, y + p*4, p, p, faceColor);
            drawPixelRect(ctx, x + p*4.5, y + p*4, p, p, faceColor);

            // Leg swing
            const cycle = moveProgress > 0 ? moveProgress * Math.PI * 2 : tickCount * 0.2;
            const swing = Math.round(Math.sin(cycle) * 1.5);

            const flY = p*6 + swing;
            const frY = p*6 - swing;

            drawPixelRect(ctx, x + p*1.5, y + flY, p*2.2, p*2, baseColor);
            drawPixelRect(ctx, x + p*1.5, y + flY + p*1.5, p*2.2, p*0.5, '#1d1d1d');

            drawPixelRect(ctx, x + p*4.3, y + frY, p*2.2, p*2, baseColor);
            drawPixelRect(ctx, x + p*4.3, y + frY + p*1.5, p*2.2, p*0.5, '#1d1d1d');
        }

        // --- STREAMING_CHUNK: Generating maze grid map algorithms... ---
        function isInsideHouse(x, y) {
            return (x >= houseArea.minX && x <= houseArea.maxX && y >= houseArea.minY && y <= houseArea.maxY);
        }

        function generateMaze(width, height) {
            const maze = Array(height).fill(null).map(() => Array(width).fill(BLOCK.COBBLE));
            const stack = [];
            const startX = 1;
            const startY = 1;
            maze[startY][startX] = BLOCK.GRASS;
            stack.push({ x: startX, y: startY });

            while (stack.length > 0) {
                const current = stack[stack.length - 1];
                const neighbors = [];

                const directions = [
                    { x: 0, y: -2, wallX: 0, wallY: -1 },
                    { x: 2, y: 0, wallX: 1, wallY: 0 },  
                    { x: 0, y: 2, wallX: 0, wallY: 1 },  
                    { x: -2, y: 0, wallX: -1, wallY: 0 }
                ];

                for (const dir of directions) {
                    const nx = current.x + dir.x;
                    const ny = current.y + dir.y;

                    if (nx > 0 && nx < width - 1 && ny > 0 && ny < height - 1) {
                        if (maze[ny][nx] === BLOCK.COBBLE) {
                            neighbors.push({ nx, ny, wallX: current.x + dir.wallX, wallY: current.y + dir.wallY });
                        }
                    }
                }

                if (neighbors.length > 0) {
                    const next = neighbors[Math.floor(Math.random() * neighbors.length)];
                    maze[next.wallY][next.wallX] = BLOCK.GRASS;
                    maze[next.ny][next.nx] = BLOCK.GRASS;      
                    stack.push({ x: next.nx, y: next.ny });
                } else {
                    stack.pop();
                }
            }

            maze[height - 2][width - 2] = BLOCK.PORTAL;
            return maze;
        }

        // --- STREAMING_CHUNK: Spawning multi-floor Oak Mansion structure (6 stories, 7x7 size!)... ---
        function spawnHouse(maze, width, height) {
            // Expanded to massive 7x7 Oak Mansion!
            const hSize = 7;
            const cx = Math.floor(width / 2) - 3;
            const cy = Math.floor(height / 2) - 3;

            houseArea = {
                minX: cx,
                maxX: cx + hSize - 1,
                minY: cy,
                maxY: cy + hSize - 1
            };

            // Build House Structure on Ground (1F)
            for (let dy = 0; dy < hSize; dy++) {
                for (let dx = 0; dx < hSize; dx++) {
                    const hx = cx + dx;
                    const hy = cy + dy;

                    if (hx <= 0 || hx >= width - 1 || hy <= 0 || hy >= height - 1) continue;

                    if (dy === 0 || dy === hSize - 1 || dx === 0 || dx === hSize - 1) {
                        if (dy === 0 && (dx === 2 || dx === 4)) {
                            maze[hy][hx] = BLOCK.GLASS;
                        } else {
                            maze[hy][hx] = BLOCK.WOOD_WALL;
                        }
                    } else {
                        maze[hy][hx] = BLOCK.WOOD_FLOOR;
                    }
                }
            }

            // Door (Bottom center - dx=3)
            const doorX = cx + 3;
            const doorY = cy + hSize - 1;
            maze[doorY][doorX] = BLOCK.DOOR;

            if (doorY + 1 < height - 1) maze[doorY + 1][doorX] = BLOCK.GRASS;
            if (doorY + 2 < height - 1) maze[doorY + 2][doorX] = BLOCK.GRASS;

            // Spacious Furniture Ground Floor (1F)
            maze[cy + 1][cx + 1] = BLOCK.BED;
            maze[cy + 1][cx + 5] = BLOCK.CHEST;
            maze[cy + 5][cx + 1] = BLOCK.CRAFTING;

            // Stairways (Right bottom: 1F UP to 2F)
            maze[cy + 5][cx + 5] = BLOCK.STAIRS_UP;

            // --- 2F Layout Setup (With Spacious Safety Fence and premium chest) ---
            grid2F = Array(hSize).fill(null).map(() => Array(hSize).fill(BLOCK.WOOD_FLOOR));
            for (let dy = 0; dy < hSize; dy++) {
                for (let dx = 0; dx < hSize; dx++) {
                    if (dy === 0) {
                        grid2F[dy][dx] = (dx === 2 || dx === 4) ? BLOCK.GLASS : BLOCK.WOOD_WALL;
                    } else if (dx === 0 || dx === hSize - 1) {
                        grid2F[dy][dx] = BLOCK.WOOD_WALL;
                    } else if (dy === hSize - 1) {
                        grid2F[dy][dx] = BLOCK.FENCE; // Spacious balcony
                    }
                }
            }
            grid2F[5][5] = BLOCK.STAIRS_DOWN; // Stairs down to 1F
            grid2F[5][1] = BLOCK.STAIRS_UP;   // Stairs leading UP to 3F (Left bottom)
            grid2F[1][3] = BLOCK.CHEST_2F;     // 2F Chest placement

            // --- 3F Library & Enchanting Layout Setup ---
            grid3F = Array(hSize).fill(null).map(() => Array(hSize).fill(BLOCK.WOOD_FLOOR));
            for (let dy = 0; dy < hSize; dy++) {
                for (let dx = 0; dx < hSize; dx++) {
                    if (dy === 0) {
                        grid3F[dy][dx] = (dx === 3) ? BLOCK.GLASS : BLOCK.WOOD_WALL;
                    } else if (dx === 0 || dx === hSize - 1 || dy === hSize - 1) {
                        grid3F[dy][dx] = BLOCK.WOOD_WALL;
                    }
                }
            }
            grid3F[5][1] = BLOCK.STAIRS_DOWN; // Stairs down to 2F
            grid3F[1][1] = BLOCK.STAIRS_UP;   // Stairs leading UP to 4F (Left top)
            grid3F[3][3] = BLOCK.ENCHANT_TABLE; // Altar Center
            grid3F[2][2] = BLOCK.BOOKSHELF;    
            grid3F[2][4] = BLOCK.BOOKSHELF;    
            grid3F[4][2] = BLOCK.BOOKSHELF;    
            grid3F[4][4] = BLOCK.BOOKSHELF;    
            grid3F[1][3] = BLOCK.CHEST_3F;      // 3F Lapis Chest

            // --- 4F Alchemy Lab Setup ---
            grid4F = Array(hSize).fill(null).map(() => Array(hSize).fill(BLOCK.WOOD_FLOOR));
            for (let dy = 0; dy < hSize; dy++) {
                for (let dx = 0; dx < hSize; dx++) {
                    if (dy === 0) {
                        grid4F[dy][dx] = (dx === 3) ? BLOCK.GLASS : BLOCK.WOOD_WALL;
                    } else if (dx === 0 || dx === hSize - 1 || dy === hSize - 1) {
                        grid4F[dy][dx] = BLOCK.WOOD_WALL;
                    }
                }
            }
            grid4F[1][1] = BLOCK.STAIRS_DOWN; // Stairs down to 3F
            grid4F[1][5] = BLOCK.STAIRS_UP;   // Stairs leading UP to 5F (Right top)
            grid4F[3][3] = BLOCK.BREWING_STAND; // Center Brewing Stand
            grid4F[1][3] = BLOCK.CHEST_4F;      // 4F Alchemist Chest

            // --- 5F Nether Garden (Red Crimson Floor) ---
            grid5F = Array(hSize).fill(null).map(() => Array(hSize).fill(BLOCK.NETHER_WART));
            for (let dy = 0; dy < hSize; dy++) {
                for (let dx = 0; dx < hSize; dx++) {
                    // Wall boundaries
                    if (dy === 0 || dx === 0 || dx === hSize - 1 || dy === hSize - 1) {
                        grid5F[dy][dx] = BLOCK.NETHER_BRICK;
                    } else if (dy === 3 && dx === 3) {
                        grid5F[dy][dx] = BLOCK.WOOD_FLOOR; // solid walkway inside wart garden
                    }
                }
            }
            grid5F[1][5] = BLOCK.STAIRS_DOWN; // Stairs down to 4F
            grid5F[5][5] = BLOCK.STAIRS_UP;   // Stairs leading UP to 6F (Right bottom)
            grid5F[1][3] = BLOCK.CHEST_5F;      // Nether Chest

            // --- 6F Ender Sky Observatory (Top Terrace Floor) ---
            grid6F = Array(hSize).fill(null).map(() => Array(hSize).fill(BLOCK.WOOD_FLOOR));
            for (let dy = 0; dy < hSize; dy++) {
                for (let dx = 0; dx < hSize; dx++) {
                    if (dy === 0) {
                        grid6F[dy][dx] = BLOCK.WOOD_WALL;
                    } else if (dx === 0 || dx === hSize - 1 || dy === hSize - 1) {
                        grid6F[dy][dx] = BLOCK.FENCE; // open stargazing safety railing
                    }
                }
            }
            grid6F[5][5] = BLOCK.STAIRS_DOWN; // Stairs down to 5F
            grid6F[3][3] = BLOCK.DRAGON_EGG;  // Center Dragon Egg Altar!
            grid6F[1][1] = BLOCK.CHEST_6F;      // Ender Chest Final Reward

            // Main Road Clearance
            const doorFrontY = doorY + 1;
            for (let y = 1; y <= doorFrontY; y++) {
                if (maze[y][1] === BLOCK.COBBLE) maze[y][1] = BLOCK.GRASS;
            }
            for (let x = 1; x <= width - 2; x++) {
                if (maze[doorFrontY][x] === BLOCK.COBBLE) maze[doorFrontY][x] = BLOCK.GRASS;
            }
            for (let y = doorFrontY; y <= height - 2; y++) {
                if (maze[y][width - 2] === BLOCK.COBBLE) maze[y][width - 2] = BLOCK.GRASS;
            }
        }

        // --- STREAMING_CHUNK: Reset game states and place diamond targets... ---
        function initGame() {
            const conf = DIFFICULTIES[currentDifficultyIndex];
            mazeWidth = conf.size;
            mazeHeight = conf.size;

            currentFloor = 1;
            openedChests2F.clear();
            openedChests3F.clear();
            openedChests4F.clear();
            openedChests5F.clear();
            openedChests6F.clear();

            speedBuffTimer = 0; // Reset Potion Buffs

            resizeCanvas();

            grid = generateMaze(mazeWidth, mazeHeight);
            spawnHouse(grid, mazeWidth, mazeHeight);

            particles = [];
            openedChests.clear();
            openDoors.clear();

            player.x = 1;
            player.y = 1;
            player.targetX = 1;
            player.targetY = 1;
            player.moveProgress = 0;
            player.dir = 'down';

            swordLevel = 0;
            respawnX = 1;
            respawnY = 1;

            diamondsCollected = 0;
            // Balance Diamonds: Maze Ores + chests inside tower (1 on 2F, 2 on 3F, 2 on 4F, 3 on 5F, 4 on 6F)
            totalStageDiamonds = conf.diamonds + 1 + 2 + 2 + 3 + 4;

            let currentDiamondsPlaced = 0;
            while (currentDiamondsPlaced < conf.diamonds) {
                let rx = Math.floor(Math.random() * (mazeWidth - 2)) + 1;
                let ry = Math.floor(Math.random() * (mazeHeight - 2)) + 1;
               
                if (grid[ry][rx] === BLOCK.GRASS && (rx > 3 || ry > 3) && !isInsideHouse(rx, ry)) {
                    grid[ry][rx] = BLOCK.DIAMOND;
                    currentDiamondsPlaced++;
                }
            }

            // Spawn Creepers
            creepers = [];
            let currentCreepersPlaced = 0;
            while (currentCreepersPlaced < conf.creepers) {
                let rx = Math.floor(Math.random() * (mazeWidth - 2)) + 1;
                let ry = Math.floor(Math.random() * (mazeHeight - 2)) + 1;
                if (grid[ry][rx] === BLOCK.GRASS && (rx > 5 || ry > 5) && !isInsideHouse(rx, ry)) {
                    creepers.push({
                        x: rx,
                        y: ry,
                        targetX: rx,
                        targetY: ry,
                        moveProgress: 0,
                        direction: 'down',
                        alertState: false,
                        alertTimer: 0,
                        speed: 0.03 + (stage * 0.005)
                    });
                    currentCreepersPlaced++;
                }
            }

            gameOver = false;
            gameClear = false;
            updateUI();

            document.getElementById('overlay').classList.add('hidden');
            showSystemChat("迷路を探索し、6階建ての巨大なオークタワーを攻略しよう!");

            if (animationFrameId) cancelAnimationFrame(animationFrameId);
            gameLoop();
        }

        // --- STREAMING_CHUNK: Updating the game layout UI panel... ---
        function updateUI() {
            document.getElementById('diamond-counter').textContent = `${diamondsCollected} / ${totalStageDiamonds}`;
           
            const hearts = '❤️'.repeat(Math.max(0, lives));
            const deadHearts = '🖤'.repeat(Math.max(0, 3 - lives));
            document.getElementById('hearts-container').innerHTML = `<span class="text-red-500">${hearts}</span><span class="text-gray-600">${deadHearts}</span>`;

            document.getElementById('stage-num').textContent = stage;

            const conf = DIFFICULTIES[currentDifficultyIndex];
            document.getElementById('difficulty-btn').textContent = `難易度: ${conf.name}`;

            const activeFov = FOV_LEVELS[currentFovIndex];
            document.getElementById('fov-btn').textContent = `🔍 視野: ${activeFov.name.split(' ')[0]}`;

            // Update Sword Status UI
            const swordEl = document.getElementById('sword-status');
            let swordText = '';
            if (swordLevel === 2) {
                swordText = '<span class="text-[#55ffff] font-bold drop-shadow-[0_1px_2px_rgba(85,255,255,0.4)]">✨💎 ダイヤの剣 (覚醒)</span>';
            } else if (swordLevel === 1) {
                swordText = '<span class="text-gray-200 font-bold">🗡️ 鉄の剣 (装備中)</span>';
            } else {
                swordText = '❌ なし (素手)';
            }
           
            // Add potion indicator to UI if active
            if (speedBuffTimer > 0) {
                swordText += ` <span class="text-yellow-400 font-bold animate-pulse text-[10px]">⚡ 俊敏 II</span>`;
            }
            swordEl.innerHTML = swordText;

            // Update Floor display UI representing 6 levels
            const floorEl = document.getElementById('floor-status');
            if (currentFloor === 6) {
                floorEl.innerHTML = '<span class="text-indigo-400 font-bold">階層: 🌌 6F 天空ジ・エンド</span>';
            } else if (currentFloor === 5) {
                floorEl.innerHTML = '<span class="text-red-500 font-bold">階層: 🔥 5F ネザーの間</span>';
            } else if (currentFloor === 4) {
                floorEl.innerHTML = '<span class="text-yellow-400 font-bold">階層: 🧪 4F 醸造ラボ</span>';
            } else if (currentFloor === 3) {
                floorEl.innerHTML = '<span class="text-purple-400 font-bold">階層: 🔮 3F 魔術図書</span>';
            } else if (currentFloor === 2) {
                floorEl.innerHTML = '<span class="text-cyan-400 font-bold">階層: 🏠 2F 展望ロフト</span>';
            } else {
                floorEl.innerHTML = '<span class="text-green-500 font-bold">階層: 🏠 1F 地上</span>';
            }

            const respawnEl = document.getElementById('respawn-status');
            if (respawnX === 1 && respawnY === 1) {
                respawnEl.textContent = '📍 初期地点';
            } else {
                respawnEl.textContent = '🏠 マイマニア';
            }
        }

        // --- STREAMING_CHUNK: Implementing action swing and combat damage logic... ---
        function triggerAttack() {
            if (gameOver || gameClear || swordLevel === 0 || attackTicks > 0) return;

            attackTicks = 10;
            sound.playEquip();

            let ax = player.x;
            let ay = player.y;
            if (player.dir === 'up') ay--;
            if (player.dir === 'down') ay++;
            if (player.dir === 'left') ax--;
            if (player.dir === 'right') ax++;

            let hit = false;
            for (let i = creepers.length - 1; i >= 0; i--) {
                const c = creepers[i];
                if ((c.x === ax && c.y === ay) || (c.targetX === ax && c.targetY === ay)) {
                    const particleColor = (swordLevel === 2) ? '#55ffff' : '#ff2222';
                    for (let j = 0; j < 8; j++) {
                        particles.push({
                            x: ax * TILE_SIZE + TILE_SIZE / 2,
                            y: ay * TILE_SIZE + TILE_SIZE / 2,
                            vx: (Math.random() - 0.5) * 4,
                            vy: (Math.random() - 0.5) * 4,
                            color: particleColor,
                            alpha: 1.0,
                            size: 3,
                            life: 1.0,
                            decay: 0.05
                        });
                    }

                    sound.playHurt();
                    creepers.splice(i, 1);
                    hit = true;
                   
                    const dropChance = (swordLevel === 2) ? 1.0 : 0.4;
                    if (Math.random() <= dropChance) {
                        grid[ay][ax] = BLOCK.DIAMOND;
                        showSystemChat("クリーパーを撃破!ダイヤモンドがドロップ! 💎");
                    } else {
                        showSystemChat("クリーパーを撃破した!🗡️");
                    }
                }
            }
        }

        // --- STREAMING_CHUNK: Physics simulation loop variables... ---
        function update() {
            tickCount++;

            if (attackTicks > 0) {
                attackTicks--;
            }

            // Manage speed buff duration timer
            if (speedBuffTimer > 0) {
                speedBuffTimer--;
                spawnPotionParticles(player.x, player.y);
                if (speedBuffTimer === 0) {
                    updateUI();
                    showSystemChat("ポーションの効果が切れた!速度が通常に戻りました。");
                }
            }

            updateParticles();

            // Movement speed based on Swiftness Potion Buff (Step: 0.25 vs 0.15)
            const moveStep = (speedBuffTimer > 0) ? 0.30 : 0.15;

            if (player.moveProgress < 1 && (player.x !== player.targetX || player.y !== player.targetY)) {
                player.moveProgress += moveStep;
               
                if (tickCount % 3 === 0) {
                    const currentInterpX = player.x + (player.targetX - player.x) * player.moveProgress;
                    const currentInterpY = player.y + (player.targetY - player.y) * player.moveProgress;
                   
                    let currentWalkingBlock = grid[player.y][player.x];
                    if (isInsideHouse(player.x, player.y)) {
                        if (currentFloor === 2) currentWalkingBlock = grid2F[player.y - houseArea.minY][player.x - houseArea.minX];
                        else if (currentFloor === 3) currentWalkingBlock = grid3F[player.y - houseArea.minY][player.x - houseArea.minX];
                        else if (currentFloor === 4) currentWalkingBlock = grid4F[player.y - houseArea.minY][player.x - houseArea.minX];
                        else if (currentFloor === 5) currentWalkingBlock = grid5F[player.y - houseArea.minY][player.x - houseArea.minX];
                        else if (currentFloor === 6) currentWalkingBlock = grid6F[player.y - houseArea.minY][player.x - houseArea.minX];
                    }
                    spawnWalkParticle(currentInterpX, currentInterpY, currentWalkingBlock);
                }

                if (player.moveProgress >= 1) {
                    player.x = player.targetX;
                    player.y = player.targetY;
                    player.moveProgress = 0;

                    checkCollisionEvents();
                }
            }

            // Door Sensor System
            for (let ty = 0; ty < mazeHeight; ty++) {
                for (let tx = 0; tx < mazeWidth; tx++) {
                    if (grid[ty][tx] === BLOCK.DOOR) {
                        const distToPlayer = currentFloor === 1 ? (Math.abs(player.x - tx) + Math.abs(player.y - ty)) : 99;
                        const key = `${tx},${ty}`;
                       
                        if (distToPlayer <= 1 && !openDoors.has(key)) {
                            openDoors.add(key);
                            sound.playDoor();
                        } else if (distToPlayer > 1 && openDoors.has(key)) {
                            openDoors.delete(key);
                            sound.playDoor();
                        }
                    }
                }
            }

            creepers.forEach(creeper => {
                if (creeper.moveProgress < 1 && (creeper.x !== creeper.targetX || creeper.y !== creeper.targetY)) {
                    creeper.moveProgress += creeper.speed;
                   
                    if (tickCount % 5 === 0 && Math.random() < 0.5) {
                        const cx = creeper.x + (creeper.targetX - creeper.x) * creeper.moveProgress;
                        const cy = creeper.y + (creeper.targetY - creeper.y) * creeper.moveProgress;
                        spawnWalkParticle(cx, cy, BLOCK.GRASS);
                    }

                    if (creeper.moveProgress >= 1) {
                        creeper.x = creeper.targetX;
                        creeper.y = creeper.targetY;
                        creeper.moveProgress = 0;
                    }
                } else {
                    const dx = player.x - creeper.x;
                    const dy = player.y - creeper.y;
                    const distance = Math.sqrt(dx * dx + dy * dy);

                    const playerSafe = isInsideHouse(player.x, player.y) || currentFloor > 1;

                    if (distance < 5 && !playerSafe) {
                        if (!creeper.alertState) {
                            creeper.alertState = true;
                            creeper.alertTimer = 45;
                            sound.playHiss();
                        }
                    } else {
                        creeper.alertState = false;
                    }

                    if (creeper.alertState) {
                        creeper.alertTimer--;
                        if (creeper.alertTimer <= 0) {
                            triggerExplosion(creeper);
                            return;
                        }
                    }

                    let nextStep = { x: creeper.x, y: creeper.y };
                    if (creeper.alertState && distance > 1 && !playerSafe) {
                        const possibleDirections = [];
                        if (Math.abs(dx) > Math.abs(dy)) {
                            possibleDirections.push({ x: Math.sign(dx), y: 0 });
                            possibleDirections.push({ x: 0, y: Math.sign(dy) });
                        } else {
                            possibleDirections.push({ x: 0, y: Math.sign(dy) });
                            possibleDirections.push({ x: Math.sign(dx), y: 0 });
                        }
                       
                        possibleDirections.push({ x: 0, y: -1 }, { x: 1, y: 0 }, { x: 0, y: 1 }, { x: -1, y: 0 });

                        for (const step of possibleDirections) {
                            const tx = creeper.x + step.x;
                            const ty = creeper.y + step.y;
                            if (grid[ty] && grid[ty][tx] === BLOCK.GRASS && !isInsideHouse(tx, ty)) {
                                nextStep = { x: tx, y: ty };
                                if (step.x > 0) creeper.direction = 'right';
                                if (step.x < 0) creeper.direction = 'left';
                                if (step.y > 0) creeper.direction = 'down';
                                if (step.y < 0) creeper.direction = 'up';
                                break;
                            }
                        }
                    } else if (Math.random() < 0.3) {
                        const dirs = [
                            { x: 0, y: -1, d: 'up' }, { x: 1, y: 0, d: 'right' },
                            { x: 0, y: 1, d: 'down' }, { x: -1, y: 0, d: 'left' }
                        ];
                        const randomDir = dirs[Math.floor(Math.random() * dirs.length)];
                        const tx = creeper.x + randomDir.x;
                        const ty = creeper.y + randomDir.y;
                        if (grid[ty] && grid[ty][tx] === BLOCK.GRASS && !isInsideHouse(tx, ty)) {
                            nextStep = { x: tx, y: ty };
                            creeper.direction = randomDir.d;
                        }
                    }

                    creeper.targetX = nextStep.x;
                    creeper.targetY = nextStep.y;
                }
            });
        }

        // --- STREAMING_CHUNK: Checking physical object intersections and stair climbers... ---
        function checkCollisionEvents() {
            const px = player.x;
            const py = player.y;

            // Handle Ground Level (1F)
            if (currentFloor === 1) {
                const block = grid[py][px];

                if (block === BLOCK.DIAMOND) {
                    grid[py][px] = BLOCK.GRASS;
                    diamondsCollected++;
                    sound.playDiamond();
                    updateUI();
                    showSystemChat(`ダイヤを獲得! 💎 (${diamondsCollected}/${totalStageDiamonds})`);
                }

                if (block === BLOCK.CHEST) {
                    const coordKey = `${px},${py}`;
                    if (!openedChests.has(coordKey)) {
                        openedChests.add(coordKey);
                        if (swordLevel === 0) swordLevel = 1;
                        sound.playEquip();
                        showSystemChat("チェストから【鉄の剣】を手に入れた!🗡️ [Space]キーで攻撃!");
                        updateUI();
                    }
                }

                if (block === BLOCK.BED) {
                    if (respawnX !== px || respawnY !== py || lives < 3) {
                        respawnX = px;
                        respawnY = py;
                        lives = 3;
                        sound.playHeal();
                        updateUI();
                        showSystemChat("ベッドでリスポーン地点を設定した!ライフが全回復。🛌");
                    }
                }

                if (block === BLOCK.STAIRS_UP) {
                    currentFloor = 2;
                    sound.playStairs();
                    updateUI();
                    showSystemChat("階段を上って【2階 展望ロフト】へ移動しました!🪜");
                }

                if (block === BLOCK.PORTAL) {
                    if (diamondsCollected === totalStageDiamonds) {
                        levelComplete();
                    } else {
                        showSystemChat(`ダイヤが足りない! 残り: ${totalStageDiamonds - diamondsCollected}個 💎`);
                    }
                }
            }
            // Handle 2F Loft
            else if (currentFloor === 2) {
                const hx = px - houseArea.minX;
                const hy = py - houseArea.minY;
                const block2F = grid2F[hy][hx];

                if (block2F === BLOCK.STAIRS_DOWN) {
                    currentFloor = 1;
                    sound.playStairs();
                    updateUI();
                    showSystemChat("階段を下りて【1階 地上】に戻りました。🚪");
                }

                if (block2F === BLOCK.STAIRS_UP) {
                    currentFloor = 3;
                    sound.playStairs();
                    updateUI();
                    showSystemChat("階段をさらに上って【3階 魔術図書室】へ到達しました!🔮");
                }

                if (block2F === BLOCK.CHEST_2F) {
                    const coordKey = `${px},${py}`;
                    if (!openedChests2F.has(coordKey)) {
                        openedChests2F.add(coordKey);
                        diamondsCollected = Math.min(totalStageDiamonds, diamondsCollected + 1);
                        sound.playDiamond();
                        updateUI();
                        showSystemChat("プレミアムチェストからダイヤモンドを発見! 💎✨");
                    }
                }
            }
            // Handle 3F Magic Library
            else if (currentFloor === 3) {
                const hx = px - houseArea.minX;
                const hy = py - houseArea.minY;
                const block3F = grid3F[hy][hx];

                if (block3F === BLOCK.STAIRS_DOWN) {
                    currentFloor = 2;
                    sound.playStairs();
                    updateUI();
                    showSystemChat("階段を下りて【2階 展望ロフト】に戻りました。🪜");
                }

                if (block3F === BLOCK.STAIRS_UP) {
                    currentFloor = 4;
                    sound.playStairs();
                    updateUI();
                    showSystemChat("階段を上って【4階 醸造ラボ】へ到着しました!🧪");
                }

                if (block3F === BLOCK.ENCHANT_TABLE) {
                    if (swordLevel === 1) {
                        swordLevel = 2;
                        sound.playEnchant();
                        for (let i = 0; i < 15; i++) {
                            particles.push({
                                x: px * TILE_SIZE + TILE_SIZE/2,
                                y: py * TILE_SIZE + TILE_SIZE/2,
                                vx: (Math.random() - 0.5) * 3,
                                vy: (Math.random() - 0.5) * 3,
                                color: '#a21caf',
                                alpha: 1.0,
                                size: 3,
                                life: 1.0,
                                decay: 0.04
                            });
                        }
                        updateUI();
                        showSystemChat("鉄の剣をエンチャントした!最強の【ダイヤの剣】に覚醒!✨💎");
                    } else if (swordLevel === 0) {
                        showSystemChat("エンチャントするには、まず1Fのチェストから鉄の剣を回収してください!🗡️");
                    }
                }

                if (block3F === BLOCK.CHEST_3F) {
                    const coordKey = `${px},${py}`;
                    if (!openedChests3F.has(coordKey)) {
                        openedChests3F.add(coordKey);
                        diamondsCollected = Math.min(totalStageDiamonds, diamondsCollected + 2);
                        sound.playDiamond();
                        updateUI();
                        showSystemChat("ラピスチェストからダイヤモンドを2つ発見! 💎💎");
                    }
                }
            }
            // Handle 4F Alchemy Lab
            else if (currentFloor === 4) {
                const hx = px - houseArea.minX;
                const hy = py - houseArea.minY;
                const block4F = grid4F[hy][hx];

                if (block4F === BLOCK.STAIRS_DOWN) {
                    currentFloor = 3;
                    sound.playStairs();
                    updateUI();
                    showSystemChat("階段を下りて【3階 魔術図書室】に戻りました。🔮");
                }

                if (block4F === BLOCK.STAIRS_UP) {
                    currentFloor = 5;
                    sound.playStairs();
                    updateUI();
                    showSystemChat("怪しい螺旋階段を上り【5階 ネザーの間】へ移動しました!🔥");
                }

                // Interaction with Brewing stand -> Grants speed buff!
                if (block4F === BLOCK.BREWING_STAND) {
                    if (speedBuffTimer === 0) {
                        speedBuffTimer = 450; // Active speed for ~30 seconds (at 15fps engine check)
                        sound.playHeal();
                        for (let i = 0; i < 20; i++) {
                            particles.push({
                                x: px * TILE_SIZE + TILE_SIZE/2,
                                y: py * TILE_SIZE + TILE_SIZE/2,
                                vx: (Math.random() - 0.5) * 4,
                                vy: -Math.random() * 2 - 1,
                                color: '#eab308',
                                alpha: 1.0,
                                size: 2,
                                life: 1.0,
                                decay: 0.03
                            });
                        }
                        updateUI();
                        showSystemChat("醸造台でスピードポーションを飲んだ!移動速度が2倍にアップ!⚡");
                    }
                }

                if (block4F === BLOCK.CHEST_4F) {
                    const coordKey = `${px},${py}`;
                    if (!openedChests4F.has(coordKey)) {
                        openedChests4F.add(coordKey);
                        diamondsCollected = Math.min(totalStageDiamonds, diamondsCollected + 2);
                        sound.playDiamond();
                        updateUI();
                        showSystemChat("アルケミストの宝箱からダイヤモンドを2つ発見! 🧪💎💎");
                    }
                }
            }
            // Handle 5F Nether Floor
            else if (currentFloor === 5) {
                const hx = px - houseArea.minX;
                const hy = py - houseArea.minY;
                const block5F = grid5F[hy][hx];

                if (block5F === BLOCK.STAIRS_DOWN) {
                    currentFloor = 4;
                    sound.playStairs();
                    updateUI();
                    showSystemChat("階段を下りて【4階 醸造ラボ】に戻りました。🧪");
                }

                if (block5F === BLOCK.STAIRS_UP) {
                    currentFloor = 6;
                    sound.playStairs();
                    updateUI();
                    showSystemChat("タワーの頂点【6階 天空ジ・エンド】に到着しました!🌌🪐");
                }

                if (block5F === BLOCK.CHEST_5F) {
                    const coordKey = `${px},${py}`;
                    if (!openedChests5F.has(coordKey)) {
                        openedChests5F.add(coordKey);
                        diamondsCollected = Math.min(totalStageDiamonds, diamondsCollected + 3);
                        sound.playDiamond();
                        updateUI();
                        showSystemChat("ネザーチェストをこじ開けた!ダイヤモンドを3つ獲得! 🔥💎💎💎");
                    }
                }
            }
            // Handle 6F Sky Ender Altar (Final top floor)
            else if (currentFloor === 6) {
                const hx = px - houseArea.minX;
                const hy = py - houseArea.minY;
                const block6F = grid6F[hy][hx];

                if (block6F === BLOCK.STAIRS_DOWN) {
                    currentFloor = 5;
                    sound.playStairs();
                    updateUI();
                    showSystemChat("階段を下りて【5階 ネザーの間】に戻りました。🔥");
                }

                if (block6F === BLOCK.CHEST_6F) {
                    const coordKey = `${px},${py}`;
                    if (!openedChests6F.has(coordKey)) {
                        openedChests6F.add(coordKey);
                        // Final Ender chest gives 4 diamonds!
                        diamondsCollected = Math.min(totalStageDiamonds, diamondsCollected + 4);
                        sound.playDiamond();
                        updateUI();
                        showSystemChat("エンダーチェストが静かに開いた!ダイヤモンド4つ獲得! 🌌💎💎💎💎");
                    }
                }
            }
        }

        function triggerExplosion(creeper) {
            sound.playExplode();
           
            const dx = Math.abs(player.x - creeper.x);
            const dy = Math.abs(player.y - creeper.y);
            if (dx <= 2 && dy <= 2 && currentFloor === 1) {
                lives--;
                sound.playHurt();
                updateUI();

                if (lives <= 0) {
                    triggerGameOver();
                } else {
                    showSystemChat("クリーパーの爆発!リスポーン拠点へ退避します!");
                    player.x = respawnX;
                    player.y = respawnY;
                    player.targetX = respawnX;
                    player.targetY = respawnY;
                    player.moveProgress = 0;
                    currentFloor = 1;
                }
            }

            creepers = creepers.filter(c => c !== creeper);
        }

        function triggerGameOver() {
            gameOver = true;
            sound.playExplode();

            const overlay = document.getElementById('overlay');
            const title = document.getElementById('overlay-title');
            const sub = document.getElementById('overlay-sub');
            const btn = document.getElementById('overlay-btn');

            title.innerHTML = '<span class="text-red-500 text-3xl">GAME OVER</span>';
           
            if (respawnX === 1 && respawnY === 1) {
                sub.textContent = '初期地点から再スタートします。タワー1Fのベッドで寝ると、そこから復活できます!';
                btn.textContent = '最初からやり直す';
            } else {
                sub.textContent = 'ベッドから即時安全に復活し、タワー探索を再開できます!🛌';
                btn.textContent = 'タワーベッドから復活 🛌';
            }

            overlay.classList.remove('hidden');
        }

        function levelComplete() {
            gameClear = true;
            sound.playWin();

            const overlay = document.getElementById('overlay');
            const title = document.getElementById('overlay-title');
            const sub = document.getElementById('overlay-sub');
            const btn = document.getElementById('overlay-btn');

            title.innerHTML = '<span class="text-[#55FF55]">STAGE CLEAR!</span>';
            sub.textContent = `6階建てタワーに眠るすべてのお宝と、迷路のダイヤモンド(合計 ${diamondsCollected} 個)を集めてクリア!`;
            btn.textContent = '次のステージへ';
            overlay.classList.remove('hidden');
        }

        // --- STREAMING_CHUNK: Designing multi-layered rendering engines... ---
        function render() {
            ctx.fillStyle = '#0a0a0f';
            ctx.fillRect(0, 0, canvas.width, canvas.height);

            const drawPlayerX = player.x + (player.targetX - player.x) * player.moveProgress;
            const drawPlayerY = player.y + (player.targetY - player.y) * player.moveProgress;

            const cameraX = drawPlayerX - (viewportTiles / 2);
            const cameraY = drawPlayerY - (viewportTiles / 2);

            const startX = Math.floor(cameraX);
            const startY = Math.floor(cameraY);
            const endX = Math.ceil(cameraX + viewportTiles);
            const endY = Math.ceil(cameraY + viewportTiles);

            const offsetPxX = (cameraX - startX) * TILE_SIZE;
            const offsetPxY = (cameraY - startY) * TILE_SIZE;

            // Render Visible Terrain Layers
            for (let ty = startY; ty <= endY; ty++) {
                for (let tx = startX; tx <= endX; tx++) {
                    const canvasX = (tx - startX) * TILE_SIZE - offsetPxX;
                    const canvasY = (ty - startY) * TILE_SIZE - offsetPxY;

                    if (tx < 0 || tx >= mazeWidth || ty < 0 || ty >= mazeHeight) {
                        drawCobbleWall(ctx, canvasX, canvasY, TILE_SIZE);
                        continue;
                    }

                    const inHouse = isInsideHouse(tx, ty);

                    // --- Render 6F Sky End Terrace ---
                    if (currentFloor === 6 && inHouse) {
                        const hx = tx - houseArea.minX;
                        const hy = ty - houseArea.minY;
                        const block6F = grid6F[hy][hx];

                        switch (block6F) {
                            case BLOCK.WOOD_WALL:
                                drawWoodWall(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                            case BLOCK.DRAGON_EGG:
                                drawDragonEgg(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                            case BLOCK.CHEST_6F:
                                const isEnderOpen = openedChests6F.has(`${tx},${ty}`);
                                drawChestBlock(ctx, canvasX, canvasY, TILE_SIZE, isEnderOpen); // classic chests look but obsidian particles spawned in checks
                                break;
                            case BLOCK.FENCE:
                                drawFence(ctx, canvasX, canvasY, TILE_SIZE, false);
                                break;
                            case BLOCK.WOOD_FLOOR:
                            default:
                                drawWoodFloor(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                        }
                        continue;
                    }

                    // --- Render 5F Nether Room Layout ---
                    if (currentFloor === 5 && inHouse) {
                        const hx = tx - houseArea.minX;
                        const hy = ty - houseArea.minY;
                        const block5F = grid5F[hy][hx];

                        switch (block5F) {
                            case BLOCK.NETHER_BRICK:
                                drawNetherBrick(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                            case BLOCK.NETHER_WART:
                                drawNetherWart(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                            case BLOCK.STAIRS_DOWN:
                                drawStairsDown(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                            case BLOCK.STAIRS_UP:
                                drawStairsUp(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                            case BLOCK.CHEST_5F:
                                const isNetherOpen = openedChests5F.has(`${tx},${ty}`);
                                drawChestBlock(ctx, canvasX, canvasY, TILE_SIZE, isNetherOpen);
                                break;
                            case BLOCK.WOOD_FLOOR:
                            default:
                                drawWoodFloor(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                        }
                        continue;
                    }

                    // --- Render 4F Alchemy Lab Layout ---
                    if (currentFloor === 4 && inHouse) {
                        const hx = tx - houseArea.minX;
                        const hy = ty - houseArea.minY;
                        const block4F = grid4F[hy][hx];

                        switch (block4F) {
                            case BLOCK.WOOD_WALL:
                                drawWoodWall(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                            case BLOCK.GLASS:
                                drawGlassWindow(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                            case BLOCK.STAIRS_DOWN:
                                drawStairsDown(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                            case BLOCK.STAIRS_UP:
                                drawStairsUp(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                            case BLOCK.BREWING_STAND:
                                drawBrewingStand(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                            case BLOCK.CHEST_4F:
                                const isAlchemistOpen = openedChests4F.has(`${tx},${ty}`);
                                drawChestBlock(ctx, canvasX, canvasY, TILE_SIZE, isAlchemistOpen);
                                break;
                            case BLOCK.WOOD_FLOOR:
                            default:
                                drawWoodFloor(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                        }
                        continue;
                    }

                    // --- Render 3F Library Layout ---
                    if (currentFloor === 3 && inHouse) {
                        const hx = tx - houseArea.minX;
                        const hy = ty - houseArea.minY;
                        const block3F = grid3F[hy][hx];

                        switch (block3F) {
                            case BLOCK.WOOD_WALL:
                                drawWoodWall(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                            case BLOCK.GLASS:
                                drawGlassWindow(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                            case BLOCK.STAIRS_DOWN:
                                drawStairsDown(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                            case BLOCK.STAIRS_UP:
                                drawStairsUp(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                            case BLOCK.BOOKSHELF:
                                drawBookshelf(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                            case BLOCK.ENCHANT_TABLE:
                                drawEnchantTable(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                            case BLOCK.CHEST_3F:
                                const isLapisOpen = openedChests3F.has(`${tx},${ty}`);
                                drawChestBlock(ctx, canvasX, canvasY, TILE_SIZE, isLapisOpen);
                                break;
                            case BLOCK.WOOD_FLOOR:
                            default:
                                drawWoodFloor(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                        }
                        continue;
                    }

                    // --- Render 2F Loft Layout ---
                    if (currentFloor === 2 && inHouse) {
                        const hx = tx - houseArea.minX;
                        const hy = ty - houseArea.minY;
                        const block2F = grid2F[hy][hx];

                        switch (block2F) {
                            case BLOCK.WOOD_WALL:
                                drawWoodWall(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                            case BLOCK.GLASS:
                                drawGlassWindow(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                            case BLOCK.STAIRS_DOWN:
                                drawStairsDown(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                            case BLOCK.STAIRS_UP:
                                drawStairsUp(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                            case BLOCK.CHEST_2F:
                                const isPremiumOpen = openedChests2F.has(`${tx},${ty}`);
                                drawChest2F(ctx, canvasX, canvasY, TILE_SIZE, isPremiumOpen);
                                break;
                            case BLOCK.FENCE:
                                drawFence(ctx, canvasX, canvasY, TILE_SIZE, false);
                                break;
                            case BLOCK.WOOD_FLOOR:
                            default:
                                drawWoodFloor(ctx, canvasX, canvasY, TILE_SIZE);
                                break;
                        }
                        continue;
                    }

                    // Standard 1F rendering
                    const blockType = grid[ty][tx];
                   
                    switch (blockType) {
                        case BLOCK.COBBLE:
                            drawCobbleWall(ctx, canvasX, canvasY, TILE_SIZE);
                            break;
                        case BLOCK.WOOD_WALL:
                            drawWoodWall(ctx, canvasX, canvasY, TILE_SIZE);
                            break;
                        case BLOCK.GLASS:
                            drawGlassWindow(ctx, canvasX, canvasY, TILE_SIZE);
                            break;
                        case BLOCK.WOOD_FLOOR:
                            drawWoodFloor(ctx, canvasX, canvasY, TILE_SIZE);
                            break;
                        case BLOCK.DOOR:
                            const isDoorOpen = openDoors.has(`${tx},${ty}`);
                            drawDoorBlock(ctx, canvasX, canvasY, TILE_SIZE, isDoorOpen);
                            break;
                        case BLOCK.CHEST:
                            const isChestOpen = openedChests.has(`${tx},${ty}`);
                            drawChestBlock(ctx, canvasX, canvasY, TILE_SIZE, isChestOpen);
                            break;
                        case BLOCK.BED:
                            drawBedBlock(ctx, canvasX, canvasY, TILE_SIZE);
                            break;
                        case BLOCK.CRAFTING:
                            drawCraftingTable(ctx, canvasX, canvasY, TILE_SIZE);
                            break;
                        case BLOCK.STAIRS_UP:
                            drawStairsUp(ctx, canvasX, canvasY, TILE_SIZE);
                            break;
                        case BLOCK.GRASS:
                        default:
                            drawGrassFloor(ctx, canvasX, canvasY, TILE_SIZE);
                            break;
                    }

                    if (blockType === BLOCK.DIAMOND) {
                        drawGrassFloor(ctx, canvasX, canvasY, TILE_SIZE);
                        const bounceOffset = Math.sin(tickCount * 0.1 + tx) * 4;
                        drawDiamondOre(ctx, canvasX, canvasY + bounceOffset, TILE_SIZE);
                    } else if (blockType === BLOCK.PORTAL) {
                        drawGoal(ctx, canvasX, canvasY, TILE_SIZE);
                    }
                }
            }

            drawParticles(ctx, cameraX, cameraY);

            // Hide creepers if player is on safe elevated floors inside the house tower
            creepers.forEach(creeper => {
                const drawCreeperX = creeper.x + (creeper.targetX - creeper.x) * creeper.moveProgress;
                const drawCreeperY = creeper.y + (creeper.targetY - creeper.y) * creeper.moveProgress;

                const cx = (drawCreeperX - cameraX) * TILE_SIZE;
                const cy = (drawCreeperY - cameraY) * TILE_SIZE;

                drawCreeper(ctx, cx, cy, TILE_SIZE, creeper.alertState, creeper.moveProgress);
            });

            const px = (drawPlayerX - cameraX) * TILE_SIZE;
            const py = (drawPlayerY - cameraY) * TILE_SIZE;
            drawPlayer(ctx, px, py, TILE_SIZE, player.dir, player.moveProgress);
        }

        function gameLoop() {
            if (!gameOver && !gameClear) {
                update();
                render();
                animationFrameId = requestAnimationFrame(gameLoop);
            }
        }

        // --- STREAMING_CHUNK: Wiring controller buttons and arrow keyboard bindings... ---
        function movePlayer(dx, dy, dirName) {
            if (gameOver || gameClear) return;
            if (player.moveProgress > 0) return;

            player.dir = dirName;
            const nextX = player.x + dx;
            const nextY = player.y + dy;

            if (nextX >= 0 && nextX < mazeWidth && nextY >= 0 && nextY < mazeHeight) {
               
                // Elevated Floor Movement Rules
                if (currentFloor > 1) {
                    const isNextInHouse = isInsideHouse(nextX, nextY);
                   
                    if (isNextInHouse) {
                        const hx = nextX - houseArea.minX;
                        const hy = nextY - houseArea.minY;
                       
                        let blockAtNext = BLOCK.WOOD_FLOOR;
                        if (currentFloor === 2) blockAtNext = grid2F[hy][hx];
                        else if (currentFloor === 3) blockAtNext = grid3F[hy][hx];
                        else if (currentFloor === 4) blockAtNext = grid4F[hy][hx];
                        else if (currentFloor === 5) blockAtNext = grid5F[hy][hx];
                        else if (currentFloor === 6) blockAtNext = grid6F[hy][hx];
                       
                        const canPassTower = (
                            blockAtNext === BLOCK.WOOD_FLOOR ||
                            blockAtNext === BLOCK.STAIRS_DOWN ||
                            blockAtNext === BLOCK.STAIRS_UP ||
                            blockAtNext === BLOCK.CHEST_2F ||
                            blockAtNext === BLOCK.CHEST_3F ||
                            blockAtNext === BLOCK.CHEST_4F ||
                            blockAtNext === BLOCK.CHEST_5F ||
                            blockAtNext === BLOCK.CHEST_6F ||
                            blockAtNext === BLOCK.ENCHANT_TABLE ||
                            blockAtNext === BLOCK.BREWING_STAND ||
                            blockAtNext === BLOCK.DRAGON_EGG ||
                            blockAtNext === BLOCK.FENCE ||
                            blockAtNext === BLOCK.NETHER_WART
                        );
                       
                        if (canPassTower) {
                            player.targetX = nextX;
                            player.targetY = nextY;
                            player.moveProgress = 0;
                            sound.playStep();
                        }
                    }
                    return;
                }

                // Standard 1F Movement Rules
                const block = grid[nextY][nextX];
                const canPass = (
                    block === BLOCK.GRASS ||
                    block === BLOCK.WOOD_FLOOR ||
                    block === BLOCK.DOOR ||
                    block === BLOCK.CHEST ||
                    block === BLOCK.BED ||
                    block === BLOCK.CRAFTING ||
                    block === BLOCK.DIAMOND ||
                    block === BLOCK.PORTAL ||
                    block === BLOCK.STAIRS_UP
                );

                if (canPass) {
                    player.targetX = nextX;
                    player.targetY = nextY;
                    player.moveProgress = 0;
                    sound.playStep();
                }
            }
        }

        // Key listeners
        window.addEventListener('keydown', (e) => {
            const key = e.key.toLowerCase();
            if (key === 'arrowup' || key === 'w') movePlayer(0, -1, 'up');
            if (key === 'arrowdown' || key === 's') movePlayer(0, 1, 'down');
            if (key === 'arrowleft' || key === 'a') movePlayer(-1, 0, 'left');
            if (key === 'arrowright' || key === 'd') movePlayer(1, 0, 'right');
            if (e.key === ' ') {
                e.preventDefault();
                triggerAttack();
            }
            sound.init();
        });

        // Touch Control Listeners
        document.getElementById('btn-up').addEventListener('touchstart', (e) => { e.preventDefault(); movePlayer(0, -1, 'up'); });
        document.getElementById('btn-down').addEventListener('touchstart', (e) => { e.preventDefault(); movePlayer(0, 1, 'down'); });
        document.getElementById('btn-left').addEventListener('touchstart', (e) => { e.preventDefault(); movePlayer(-1, 0, 'left'); });
        document.getElementById('btn-right').addEventListener('touchstart', (e) => { e.preventDefault(); movePlayer(1, 0, 'right'); });
        document.getElementById('btn-attack').addEventListener('touchstart', (e) => { e.preventDefault(); triggerAttack(); });

        document.getElementById('btn-up').addEventListener('mousedown', () => movePlayer(0, -1, 'up'));
        document.getElementById('btn-down').addEventListener('mousedown', () => movePlayer(0, 1, 'down'));
        document.getElementById('btn-left').addEventListener('mousedown', () => movePlayer(-1, 0, 'left'));
        document.getElementById('btn-right').addEventListener('mousedown', () => movePlayer(1, 0, 'right'));
        document.getElementById('btn-attack').addEventListener('mousedown', () => triggerAttack());

        // Settings Buttons
        document.getElementById('difficulty-btn').addEventListener('click', () => {
            currentDifficultyIndex = (currentDifficultyIndex + 1) % DIFFICULTIES.length;
            stage = 1;
            lives = 3;
            initGame();
        });

        document.getElementById('fov-btn').addEventListener('click', () => {
            currentFovIndex = (currentFovIndex + 1) % FOV_LEVELS.length;
            viewportTiles = FOV_LEVELS[currentFovIndex].tiles;
            sound.playClick();
            resizeCanvas();
            updateUI();
            showSystemChat(`視野を調整しました: ${FOV_LEVELS[currentFovIndex].name}`);
        });

        document.getElementById('sound-btn').addEventListener('click', () => {
            sound.enabled = !sound.enabled;
            document.getElementById('sound-btn').textContent = `🔊 音: ${sound.enabled ? 'ON' : 'OFF'}`;
            sound.init();
        });

        document.getElementById('reset-btn').addEventListener('click', () => {
            stage = 1;
            lives = 3;
            initGame();
        });

        document.getElementById('overlay-btn').addEventListener('click', () => {
            if (gameOver) {
                lives = 3;
                player.x = respawnX;
                player.y = respawnY;
                player.targetX = respawnX;
                player.targetY = respawnY;
                player.moveProgress = 0;
                currentFloor = 1;
               
                if (respawnX === 1 && respawnY === 1) {
                    stage = 1;
                }
                initGame();
            } else if (gameClear) {
                stage++;
                initGame();
            }
        });

        window.onload = () => {
            initGame();
        };
    </script>
</body>
</html>

ユウクラめいろ

めいろをしながらお家に入ったり二階に行ったりできるのが楽しいゲームです。

👁 34 回閲覧
📅 投稿:2026年6月7日 🔄 更新:2026年8月13日
応援スタンプを押してみよう!