Can you add enemy behavior such that they begin circling the player once they move close enough they begin to have an attack pattern (charging forward into the player, then backing up again) and add a right click to block ability (rotate the sword to the left while right click is held)? Output entire code please.


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>3D Environment with Labyrinth and Enhanced Enemies</title>
    <style>
        body { margin: 0; overflow: hidden; }
        canvas { display: block; }

        /* HUD Container */
        #hud {
            position: absolute;
            top: 10px;
            left: 10px;
            color: white;
            font-family: Arial, sans-serif;
            font-size: 20px;
            z-index: 1;
        }

        /* Health Bar Container */
        #healthBarContainer {
            width: 200px;
            height: 25px;
            background-color: #555; /* Dark gray background */
            border: 2px solid #fff; /* White border */
            border-radius: 5px;
            overflow: hidden;
            margin-bottom: 10px; /* Spacing below the health bar */
        }

        /* Health Bar (Foreground) */
        #healthBar {
            width: 100%; /* Full width initially */
            height: 100%;
            background-color: green; /* Initial color based on health */
            transition: width 0.2s ease, background-color 0.2s ease; /* Smooth transitions */
        }

        /* Time Display */
        #timeDisplay {
            margin-top: 10px; /* Spacing above the time display */
        }

        /* Game Over screen */
        #gameOver {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: red;
            font-family: Arial, sans-serif;
            font-size: 50px;
            display: none;
            z-index: 2;
        }

        /* YOU WIN screen */
        #youWin {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: #000033; /* Dark blue background */
            display: none;
            z-index: 3;
            overflow: hidden;
        }

        #winText {
            position: absolute;
            top: 20%;
            width: 100%;
            text-align: center;
            color: #FF00FF; /* Magenta */
            font-family: 'Comic Sans MS', cursive, sans-serif;
            font-size: 80px;
            text-shadow: 2px 2px #00FFFF; /* Cyan shadow */
        }
    </style>
</head>
<body>
    <!-- HUD Elements -->
    <div id="hud">
        <!-- Health Bar -->
        <div id="healthBarContainer">
            <div id="healthBar"></div>
        </div>
        <!-- Time Display -->
        <div id="timeDisplay">Time: 06:00 AM</div>
    </div>
    <!-- Game Over Screen -->
    <div id="gameOver">Game Over</div>
    <!-- YOU WIN Screen -->
    <div id="youWin">
        <div id="winText">YOU WIN!</div>
        <canvas id="winCanvas"></canvas>
    </div>
    <!-- Three.js and Controls Libraries -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/PointerLockControls.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/objects/Sky.js"></script>
    <script>
        // Set up scene, camera, and renderer
        const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.set(0, 10, 10);
        const renderer = new THREE.WebGLRenderer({ antialias: true });
        const mazeWallsBoxes = []; // Array to hold bounding boxes for collision
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        // HUD Elements
        const healthBar = document.getElementById('healthBar');
        const timeDisplay = document.getElementById('timeDisplay');
        const gameOverScreen = document.getElementById('gameOver');
        const youWinScreen = document.getElementById('youWin');

        // Player Health
        let playerHealth = 100;

        // Add ambient light and directional light
        const ambientLight = new THREE.AmbientLight(0xffffff, 0.7);
        scene.add(ambientLight);
        const sunLight = new THREE.DirectionalLight(0xffffff, 1);
        sunLight.position.set(100, 100, 100);
        scene.add(sunLight);

        // Add Sky Shader
        const sky = new THREE.Sky();
        sky.scale.setScalar(450000); // Scale the sky to cover a large area
        scene.add(sky);

        const sun = new THREE.Vector3();

        // Skybox parameters
        const skyUniforms = sky.material.uniforms;
        skyUniforms['turbidity'].value = 10;
        skyUniforms['rayleigh'].value = 2;
        skyUniforms['mieCoefficient'].value = 0.005;
        skyUniforms['mieDirectionalG'].value = 0.8;

        // Set the initial sun position
        const thetaInitial = Math.PI * (0.25); // Elevation angle in radians for midday
        const phiInitial = 2 * Math.PI * (0.25); // Azimuthal angle in radians
        sun.setFromSphericalCoords(1, thetaInitial, phiInitial);
        sky.material.uniforms['sunPosition'].value.copy(sun);
        sunLight.position.copy(sun);

        // Add ground with rolling hills
        const terrainGeometry = new THREE.PlaneBufferGeometry(1000, 1000, 128, 128);
        const terrainMaterial = new THREE.MeshLambertMaterial({ color: 0x228B22 });
        const terrain = new THREE.Mesh(terrainGeometry, terrainMaterial);
        terrain.rotation.x = -Math.PI / 2;

        const positionAttr = terrainGeometry.attributes.position;
        for (let i = 0; i < positionAttr.count; i++) {
            const x = positionAttr.getX(i);
            const y = positionAttr.getY(i);
            const z = Math.sin(x / 20) * 5 + Math.cos(y / 20) * 5;
            positionAttr.setZ(i, z);
        }
        terrainGeometry.computeVertexNormals();
        scene.add(terrain);

        // Function to get the height of the terrain at a given (x, z) position
        function getTerrainHeightAt(x, z) {
            const terrainPosition = terrainGeometry.attributes.position;
            const terrainWidth = terrainGeometry.parameters.width;
            const terrainSegments = terrainGeometry.parameters.widthSegments;
            const segmentSize = terrainWidth / terrainSegments;

            const xNormalized = (x + terrainWidth / 2) / terrainWidth;
            const zNormalized = (z + terrainWidth / 2) / terrainWidth;

            const xIndex = xNormalized * terrainSegments;
            const zIndex = zNormalized * terrainSegments;

            const x0 = Math.floor(xIndex);
            const x1 = Math.min(x0 + 1, terrainSegments);
            const z0 = Math.floor(zIndex);
            const z1 = Math.min(z0 + 1, terrainSegments);

            const s1 = xIndex - x0;
            const s0 = 1 - s1;
            const t1 = zIndex - z0;
            const t0 = 1 - t1;

            const index00 = z0 * (terrainSegments + 1) + x0;
            const index01 = z1 * (terrainSegments + 1) + x0;
            const index10 = z0 * (terrainSegments + 1) + x1;
            const index11 = z1 * (terrainSegments + 1) + x1;

            const height00 = terrainPosition.getZ(index00);
            const height01 = terrainPosition.getZ(index01);
            const height10 = terrainPosition.getZ(index10);
            const height11 = terrainPosition.getZ(index11);

            const height = (s0 * t0 * height00) + (s1 * t0 * height10) + (s0 * t1 * height01) + (s1 * t1 * height11);
            return height;
        }

        // Add trees
        for (let i = 0; i < 100; i++) {
            // Generate random position for the tree
            const treeX = Math.random() * 500 - 250;
            const treeZ = Math.random() * 500 - 250;
            const treeY = getTerrainHeightAt(treeX, treeZ);

            // Create tree trunk
            const trunkGeometry = new THREE.CylinderGeometry(0.5, 0.5, 10, 8);
            const trunkMaterial = new THREE.MeshLambertMaterial({ color: 0x8B4513 });
            const trunk = new THREE.Mesh(trunkGeometry, trunkMaterial);
            trunk.position.set(treeX, treeY + 5, treeZ);

            // Create evergreen leaves as stacked cones
            const leavesMaterial = new THREE.MeshLambertMaterial({ color: 0x228B22 });
            for (let j = 0; j < 3; j++) {
                const leavesGeometry = new THREE.ConeGeometry(3 + j * 1.5, 8, 16); // Biggest on bottom, smallest on top
                const leaves = new THREE.Mesh(leavesGeometry, leavesMaterial);
                leaves.position.set(0, 10 - j * 3, 0);
                trunk.add(leaves);
            }

            scene.add(trunk);
        }

        // Create a sword with blade, crossbar, and hilt
        const swordGroup = new THREE.Group();

        // Blade
        const bladeGeometry = new THREE.ConeGeometry(0.1, 1.5, 4);
        const bladeMaterial = new THREE.MeshLambertMaterial({ color: 0xC0C0C0 });
        const blade = new THREE.Mesh(bladeGeometry, bladeMaterial);
        blade.position.set(0, 0.75, 0);
        swordGroup.add(blade);

        // Crossbar
        const crossbarGeometry = new THREE.BoxGeometry(0.4, 0.05, 0.1);
        const crossbarMaterial = new THREE.MeshLambertMaterial({ color: 0x808080 });
        const crossbar = new THREE.Mesh(crossbarGeometry, crossbarMaterial);
        crossbar.position.set(0, 0, 0);
        swordGroup.add(crossbar);

        // Extra crossbar (vertical and perpendicular to the current one)
        const extraCrossbarGeometry = new THREE.BoxGeometry(0.4, 0.05, 0.1);
        const extraCrossbarMaterial = new THREE.MeshLambertMaterial({ color: 0x808080 });
        const extraCrossbar = new THREE.Mesh(extraCrossbarGeometry, extraCrossbarMaterial);
        extraCrossbar.rotation.y = Math.PI / 2;
        extraCrossbar.position.set(0, 0, 0);
        swordGroup.add(extraCrossbar);

        // Hilt
        const hiltGeometry = new THREE.CylinderGeometry(0.05, 0.05, 0.5, 8);
        const hiltMaterial = new THREE.MeshLambertMaterial({ color: 0x8B4513 });
        const hilt = new THREE.Mesh(hiltGeometry, hiltMaterial);
        hilt.position.set(0, -0.25, 0);
        swordGroup.add(hilt);

        // Position the sword relative to the camera
        swordGroup.position.set(0.5, -0.5, -1);
        camera.add(swordGroup);
        scene.add(camera);

        // Pointer Lock Controls for first-person movement
        const controls = new THREE.PointerLockControls(camera, document.body);
        document.body.addEventListener('click', () => {
            controls.lock();
        });

        // WASD movement controls for the player
        const movement = { forward: false, backward: false, left: false, right: false, jump: false, running: false };
        document.addEventListener('keydown', (event) => {
            switch (event.code) {
                case 'KeyW': movement.forward = true; break;
                case 'KeyS': movement.backward = true; break;
                case 'KeyA': movement.left = true; break;
                case 'KeyD': movement.right = true; break;
                case 'Space': if (!movement.jump) { velocity.y = 0.6; movement.jump = true; } break;
                case 'ShiftLeft': movement.running = true; break;
                case 'Digit1': incrementTimeByOneHour(); break; // Handle "1" key press
            }
        });
        document.addEventListener('keyup', (event) => {
            switch (event.code) {
                case 'KeyW': movement.forward = false; break;
                case 'KeyS': movement.backward = false; break;
                case 'KeyA': movement.left = false; break;
                case 'KeyD': movement.right = false; break;
                case 'Space': movement.jump = false; break;
                case 'ShiftLeft': movement.running = false; break;
            }
        });

        // Gravity and velocity setup
        let velocity = new THREE.Vector3();
        const gravity = -0.05;

        // **Moved goblins declaration before sword swing code to fix ReferenceError**
        // Array to hold all goblins
        const goblins = [];

        // Sword swing - forward arc animation
        let isSwinging = false;
        const swordDamage = 25; // Damage per swing
        document.addEventListener('mousedown', (event) => {
            if (event.button === 0 && !isSwinging) { // Left mouse button click
                isSwinging = true;
                const swingDuration = 200; // Swing duration in ms
                const swingSteps = swingDuration / 10;
                let currentStep = 0;
                const maxSwingAngle = Math.PI / 2; // 90 degrees

                const swingInterval = setInterval(() => {
                    currentStep++;
                    const swingProgress = currentStep / swingSteps;
                    const swingAngle = swingProgress * maxSwingAngle;

                    // Rotate the sword for swinging effect
                    swordGroup.rotation.x = -swingAngle;

                    // Detect hits during the swing
                    if (swingProgress > 0.3 && swingProgress < 0.7) { // Active swing window
                        const swordWorldPosition = new THREE.Vector3();
                        swordGroup.getWorldPosition(swordWorldPosition);

                        // Check for collisions with goblins
                        goblins.forEach(goblin => {
                            if (!goblin.isHit) { // Prevent multiple hits per swing
                                const distance = swordWorldPosition.distanceTo(goblin.mesh.position);
                                if (distance < 2) { // Adjust collision distance as needed
                                    goblin.takeDamage(swordDamage);
                                    goblin.isHit = true;
                                }
                            }
                        });
                    }

                    if (currentStep >= swingSteps) { // End of swing
                        clearInterval(swingInterval);
                        swordGroup.rotation.x = 0;
                        isSwinging = false;

                        // Reset goblins' hit status after swing
                        goblins.forEach(goblin => goblin.isHit = false);
                    }
                }, 10);
            }
        });

        // Bilinear interpolation for smoother terrain height detection
        function getInterpolatedHeightAt(x, z) {
            const terrainPosition = terrainGeometry.attributes.position;
            const terrainWidth = terrainGeometry.parameters.width;
            const terrainSegments = terrainGeometry.parameters.widthSegments;
            const segmentSize = terrainWidth / terrainSegments;

            const xNormalized = (x + terrainWidth / 2) / terrainWidth;
            const zNormalized = (z + terrainWidth / 2) / terrainWidth;

            const xIndex = xNormalized * terrainSegments;
            const zIndex = zNormalized * terrainSegments;

            const x0 = Math.floor(xIndex);
            const x1 = Math.min(x0 + 1, terrainSegments);
            const z0 = Math.floor(zIndex);
            const z1 = Math.min(z0 + 1, terrainSegments);

            const s1 = xIndex - x0;
            const s0 = 1 - s1;
            const t1 = zIndex - z0;
            const t0 = 1 - t1;

            const index00 = z0 * (terrainSegments + 1) + x0;
            const index01 = z1 * (terrainSegments + 1) + x0;
            const index10 = z0 * (terrainSegments + 1) + x1;
            const index11 = z1 * (terrainSegments + 1) + x1;

            const height00 = terrainPosition.getZ(index00);
            const height01 = terrainPosition.getZ(index01);
            const height10 = terrainPosition.getZ(index10);
            const height11 = terrainPosition.getZ(index11);

            const height = (s0 * t0 * height00) + (s1 * t0 * height10) + (s0 * t1 * height01) + (s1 * t1 * height11);
            return height;
        }

        // **Moved mazeWallsGroup declaration before createMazeMesh function to fix ReferenceError**
        // Maze Walls Collision Group and Bounding Boxes
        let mazeWallsGroup = new THREE.Group();

        // Maze Class
        class Maze {
            constructor(width, height) {
                this.width = width;
                this.height = height;

                // Initialize maze grid
                this.grid = [];
                for (let x = 0; x < width; x++) {
                    this.grid[x] = [];
                    for (let y = 0; y < height; y++) {
                        this.grid[x][y] = {
                            visited: false,
                            walls: { top: true, right: true, bottom: true, left: true }
                        };
                    }
                }

                // Generate maze
                this.generateMaze(0, 0);
            }

            // Recursive Backtracker algorithm
            generateMaze(x, y) {
                const stack = [];
                stack.push({ x: x, y: y });
                this.grid[x][y].visited = true;

                while (stack.length > 0) {
                    const current = stack.pop();
                    const neighbors = this.getUnvisitedNeighbors(current.x, current.y);

                    if (neighbors.length > 0) {
                        stack.push(current);

                        // Choose a random neighbor
                        const next = neighbors[Math.floor(Math.random() * neighbors.length)];

                        // Remove walls between current and next
                        if (next.x > current.x) {
                            this.grid[current.x][current.y].walls.right = false;
                            this.grid[next.x][next.y].walls.left = false;
                        } else if (next.x < current.x) {
                            this.grid[current.x][current.y].walls.left = false;
                            this.grid[next.x][next.y].walls.right = false;
                        } else if (next.y > current.y) {
                            this.grid[current.x][current.y].walls.bottom = false;
                            this.grid[next.x][next.y].walls.top = false;
                        } else if (next.y < current.y) {
                            this.grid[current.x][current.y].walls.top = false;
                            this.grid[next.x][next.y].walls.bottom = false;
                        }

                        this.grid[next.x][next.y].visited = true;
                        stack.push(next);
                    }
                }
            }

            getUnvisitedNeighbors(x, y) {
                const neighbors = [];

                if (x > 0 && !this.grid[x - 1][y].visited) {
                    neighbors.push({ x: x - 1, y: y });
                }
                if (x < this.width - 1 && !this.grid[x + 1][y].visited) {
                    neighbors.push({ x: x + 1, y: y });
                }
                if (y > 0 && !this.grid[x][y - 1].visited) {
                    neighbors.push({ x: x, y: y - 1 });
                }
                if (y < this.height - 1 && !this.grid[x][y + 1].visited) {
                    neighbors.push({ x: x, y: y + 1 });
                }

                return neighbors;
            }
        }

        // Function to create the maze mesh
        function createMazeMesh(maze, positionX, positionZ) {
            const cellSize = mazeCellSize;
            const wallHeight = 5;
            const wallThickness = 0.3; // Reduced thickness for wider passageways
            const wallMaterial = new THREE.MeshLambertMaterial({ color: 0x888888 });
            const mazeGroup = new THREE.Group();

            // **Removed duplicate mazeWallsGroup initialization inside function**
            mazeWallsGroup = new THREE.Group(); // Group to hold all walls for collision

            for (let x = 0; x < maze.width; x++) {
                for (let y = 0; y < maze.height; y++) {
                    const cell = maze.grid[x][y];
                    const cellX = positionX + x * cellSize;
                    const cellZ = positionZ + y * cellSize;
                    const cellY = getTerrainHeightAt(cellX, cellZ);

                    // Top wall
                    if (cell.walls.top) {
                        const wallGeometry = new THREE.BoxGeometry(cellSize, wallHeight, wallThickness);
                        const wall = new THREE.Mesh(wallGeometry, wallMaterial);
                        wall.position.set(
                            cellX,
                            cellY + wallHeight / 2,
                            cellZ - cellSize / 2
                        );
                        mazeGroup.add(wall);
                        mazeWallsGroup.add(wall);
                        const box = new THREE.Box3().setFromObject(wall);
                        mazeWallsBoxes.push(box);
                    }

                    // Bottom wall
                    if (cell.walls.bottom) {
                        const wallGeometry = new THREE.BoxGeometry(cellSize, wallHeight, wallThickness);
                        const wall = new THREE.Mesh(wallGeometry, wallMaterial);
                        wall.position.set(
                            cellX,
                            cellY + wallHeight / 2,
                            cellZ + cellSize / 2
                        );
                        mazeGroup.add(wall);
                        mazeWallsGroup.add(wall);
                        const box = new THREE.Box3().setFromObject(wall);
                        mazeWallsBoxes.push(box);
                    }

                    // Left wall
                    if (cell.walls.left) {
                        const wallGeometry = new THREE.BoxGeometry(wallThickness, wallHeight, cellSize);
                        const wall = new THREE.Mesh(wallGeometry, wallMaterial);
                        wall.position.set(
                            cellX - cellSize / 2,
                            cellY + wallHeight / 2,
                            cellZ
                        );
                        mazeGroup.add(wall);
                        mazeWallsGroup.add(wall);
                        const box = new THREE.Box3().setFromObject(wall);
                        mazeWallsBoxes.push(box);
                    }

                    // Right wall
                    if (cell.walls.right) {
                        const wallGeometry = new THREE.BoxGeometry(wallThickness, wallHeight, cellSize);
                        const wall = new THREE.Mesh(wallGeometry, wallMaterial);
                        wall.position.set(
                            cellX + cellSize / 2,
                            cellY + wallHeight / 2,
                            cellZ
                        );
                        mazeGroup.add(wall);
                        mazeWallsGroup.add(wall);
                        const box = new THREE.Box3().setFromObject(wall);
                        mazeWallsBoxes.push(box);
                    }
                }
            }

            scene.add(mazeGroup);
            scene.add(mazeWallsGroup);

            return mazeWallsBoxes; // Return the array of bounding boxes
        }

        // Function to flatten terrain under the maze
        function flattenTerrainUnderMaze(positionX, positionZ, mazeWidth, mazeHeight, cellSize) {
            const terrainPosition = terrainGeometry.attributes.position;

            // Maze bounding box
            const minX = positionX - cellSize / 2;
            const maxX = positionX + mazeWidth * cellSize - cellSize / 2;
            const minZ = positionZ - cellSize / 2;
            const maxZ = positionZ + mazeHeight * cellSize - cellSize / 2;

            for (let i = 0; i < terrainPosition.count; i++) {
                const x = terrainPosition.getX(i);
                const z = terrainPosition.getY(i); // Note: After rotation, y corresponds to z in world space

                if (x >= minX && x <= maxX && z >= minZ && z <= maxZ) {
                    // Set height to flat value, e.g., 0
                    terrainPosition.setZ(i, 0); // z is height (y-coordinate in world space)
                }
            }
            terrainGeometry.computeVertexNormals();
            terrainGeometry.attributes.position.needsUpdate = true;
        }

        // Generate the maze
        const mazeWidth = 20;
        const mazeHeight = 20;
        const maze = new Maze(mazeWidth, mazeHeight);

        // Choose a random position on the map
        const terrainSize = 1000;
        const mazeCellSize = 4;
        const mazeTotalSize = mazeWidth * mazeCellSize;

        const mazePositionX = Math.random() * (terrainSize - mazeTotalSize) - terrainSize / 2 + mazeTotalSize / 2;
        const mazePositionZ = Math.random() * (terrainSize - mazeTotalSize) - terrainSize / 2 + mazeTotalSize / 2;

        // Flatten the terrain under the maze
        flattenTerrainUnderMaze(mazePositionX, mazePositionZ, mazeWidth, mazeHeight, mazeCellSize);

        // Create the maze mesh
        // createMazeMesh(maze, mazePositionX, mazePositionZ);

        // Create a pulsing golden orb at the center of the maze
        const mazeCenterX = mazePositionX + (mazeWidth / 2) * mazeCellSize;
        const mazeCenterZ = mazePositionZ + (mazeHeight / 2) * mazeCellSize;
        const mazeCenterY = getTerrainHeightAt(mazeCenterX, mazeCenterZ) + 2.5; // Slightly above ground

        // Orb geometry and material
        const orbGeometry = new THREE.SphereGeometry(1, 32, 32);
        const orbMaterial = new THREE.MeshStandardMaterial({
            color: 0xFFD700,
            emissive: 0xFFD700,
            emissiveIntensity: 1,
            roughness: 0.3,
            metalness: 0.7,
        });
        const goldenOrb = new THREE.Mesh(orbGeometry, orbMaterial);
        goldenOrb.position.set(mazeCenterX, mazeCenterY, mazeCenterZ);
        scene.add(goldenOrb);

        // Add a PointLight to emit golden light
        const orbLight = new THREE.PointLight(0xFFD700, 2, 50); // Color, intensity, distance
        orbLight.position.set(mazeCenterX, mazeCenterY, mazeCenterZ);
        orbLight.castShadow = true; // Enable shadows for dramatic effect
        scene.add(orbLight);

        // Optional: Add a glowing effect using a small SphereGeometry with a transparent material
        const glowMaterial = new THREE.MeshBasicMaterial({
            color: 0xFFD700,
            transparent: true,
            opacity: 0.5,
        });
        const glowSphere = new THREE.Mesh(new THREE.SphereGeometry(1.5, 32, 32), glowMaterial);
        glowSphere.position.set(mazeCenterX, mazeCenterY, mazeCenterZ);
        scene.add(glowSphere);

        // Goblin Class Definition
        class Goblin {
            constructor(x, z) {
                // Create goblin mesh
                this.mesh = new THREE.Group();

                // Body
                const bodyGeometry = new THREE.CylinderGeometry(0.5, 0.5, 2, 8);
                const bodyMaterial = new THREE.MeshLambertMaterial({ color: 0xff0000 }); // Red color
                const body = new THREE.Mesh(bodyGeometry, bodyMaterial);
                body.position.y = 1;
                this.mesh.add(body);

                // Head
                const headGeometry = new THREE.SphereGeometry(0.6, 16, 16);
                const headMaterial = new THREE.MeshLambertMaterial({ color: 0xff0000 }); // Red color
                const head = new THREE.Mesh(headGeometry, headMaterial);
                head.position.y = 2.5;
                this.mesh.add(head);

                // Arms
                const armGeometry = new THREE.CylinderGeometry(0.1, 0.1, 1, 8);
                const armMaterial = new THREE.MeshLambertMaterial({ color: 0xff0000 });
                // Left Arm
                this.leftArm = new THREE.Mesh(armGeometry, armMaterial);
                this.leftArm.position.set(-0.6, 1.5, 0);
                this.leftArm.rotation.z = Math.PI / 4;
                this.mesh.add(this.leftArm);
                // Right Arm
                this.rightArm = new THREE.Mesh(armGeometry, armMaterial);
                this.rightArm.position.set(0.6, 1.5, 0);
                this.rightArm.rotation.z = -Math.PI / 4;
                this.mesh.add(this.rightArm);

                // Legs
                const legGeometry = new THREE.CylinderGeometry(0.1, 0.1, 1, 8);
                const legMaterial = new THREE.MeshLambertMaterial({ color: 0xff0000 });
                // Left Leg
                this.leftLeg = new THREE.Mesh(legGeometry, legMaterial);
                this.leftLeg.position.set(-0.3, -0.5, 0);
                this.mesh.add(this.leftLeg);
                // Right Leg
                this.rightLeg = new THREE.Mesh(legGeometry, legMaterial);
                this.rightLeg.position.set(0.3, -0.5, 0);
                this.mesh.add(this.rightLeg);

                // Weapon (e.g., club)
                const weaponGeometry = new THREE.BoxGeometry(0.2, 1, 0.2);
                const weaponMaterial = new THREE.MeshLambertMaterial({ color: 0x654321 });
                this.weapon = new THREE.Mesh(weaponGeometry, weaponMaterial);
                this.weapon.position.set(0, 1, -0.6);
                this.mesh.add(this.weapon);

                // Position goblin on terrain
                this.mesh.position.set(x, getTerrainHeightAt(x, z) + 1, z);

                // Add to scene
                scene.add(this.mesh);

                // Health
                this.health = 100;

                // Movement speed
                this.speed = 0.12;

                // Vertical velocity for gravity
                this.velocityY = 0;

                // Flag to prevent multiple hits per swing
                this.isHit = false;

                // Attack cooldown
                this.attackCooldown = 0;

                // Animation phase for walking
                this.walkPhase = Math.random() * Math.PI * 2; // Random initial phase
                this.walkSpeed = 0.05; // Speed of walking animation

                // Target position for wandering
                this.targetPosition = null;

                // Random movement cooldown
                this.wanderCooldown = 0;
            }

            // Method to move goblin towards the player
            moveTowardsPlayer() {
                const playerPosition = new THREE.Vector3();
                camera.getWorldPosition(playerPosition);
                const direction = new THREE.Vector3();
                direction.subVectors(playerPosition, this.mesh.position).normalize();
                const moveStep = direction.multiplyScalar(this.speed);

                // Check collision before moving
                if (!checkCollision(this.mesh.position.x + moveStep.x, this.mesh.position.z + moveStep.z, goblinCollisionRadius)) {
                    this.mesh.position.add(moveStep);
                }

                // Rotate to face the player
                const angle = Math.atan2(direction.x, direction.z);
                this.mesh.rotation.y = angle;
            }

            // Method to move goblin randomly
            wander() {
                if (!this.targetPosition || this.wanderCooldown <= 0) {
                    // Choose a new random direction
                    const angle = Math.random() * Math.PI * 2;
                    const distance = 5 + Math.random() * 10;
                    this.targetPosition = new THREE.Vector3(
                        this.mesh.position.x + Math.cos(angle) * distance,
                        this.mesh.position.y,
                        this.mesh.position.z + Math.sin(angle) * distance
                    );
                    this.wanderCooldown = 100 + Math.random() * 100;
                } else {
                    const direction = new THREE.Vector3();
                    direction.subVectors(this.targetPosition, this.mesh.position).normalize();
                    const moveStep = direction.multiplyScalar(this.speed);

                    // Check collision before moving
                    if (!checkCollision(this.mesh.position.x + moveStep.x, this.mesh.position.z + moveStep.z, goblinCollisionRadius)) {
                        this.mesh.position.add(moveStep);
                    }

                    // Rotate to face movement direction
                    const angle = Math.atan2(direction.x, direction.z);
                    this.mesh.rotation.y = angle;

                    // If reached target position
                    if (this.mesh.position.distanceTo(this.targetPosition) < 1) {
                        this.targetPosition = null;
                    }

                    this.wanderCooldown--;
                }
            }

            // Method to apply damage to goblin
            takeDamage(amount) {
                this.health -= amount;
                console.log('Goblin hit! Health:', this.health);
                if (this.health <= 0) {
                    this.die();
                }
            }

            // Method to handle goblin death
            die() {
                scene.remove(this.mesh);
                const index = goblins.indexOf(this);
                if (index > -1) {
                    goblins.splice(index, 1);
                }
                console.log('Goblin died!');
            }

            // Method to check if goblin can attack the player
            canAttackPlayer() {
                const playerPosition = new THREE.Vector3();
                camera.getWorldPosition(playerPosition);
                const distance = playerPosition.distanceTo(this.mesh.position);
                return distance < 2; // Attack range
            }

            // Method to attack the player
            attackPlayer() {
                if (this.attackCooldown <= 0) {
                    playerHealth -= 10; // Damage per attack
                    updateHealthBar();
                    console.log('Player hit! Health:', playerHealth);
                    if (playerHealth <= 0) {
                        gameOver();
                    }
                    this.attackCooldown = 100; // Cooldown frames
                }
            }

            // Apply gravity
            applyGravity() {
                this.velocityY += gravity;
                this.mesh.position.y += this.velocityY;

                // Collision detection with terrain
                const terrainHeight = getInterpolatedHeightAt(this.mesh.position.x, this.mesh.position.z) + 1;
                if (this.mesh.position.y < terrainHeight) {
                    this.mesh.position.y = terrainHeight;
                    this.velocityY = 0;
                }
            }

            // Update method for goblin behavior and animations
            update() {
                // Check if player is nearby
                const playerPosition = new THREE.Vector3();
                camera.getWorldPosition(playerPosition);
                const distanceToPlayer = playerPosition.distanceTo(this.mesh.position);

                if (distanceToPlayer < 50) {
                    // Move towards player
                    this.moveTowardsPlayer();
                } else {
                    // Wander randomly
                    this.wander();
                }

                // Apply gravity
                this.applyGravity();

                // Update walking animation
                this.walkPhase += this.walkSpeed;
                const armSwing = Math.sin(this.walkPhase) * 0.5; // Swing angle for arms
                const legSwing = Math.cos(this.walkPhase) * 0.5; // Swing angle for legs

                // Animate arms
                this.leftArm.rotation.z = Math.PI / 4 + armSwing;
                this.rightArm.rotation.z = -Math.PI / 4 - armSwing;

                // Animate legs
                this.leftLeg.rotation.x = legSwing;
                this.rightLeg.rotation.x = -legSwing;

                if (this.attackCooldown > 0) {
                    this.attackCooldown--;
                }

                // Check if can attack player
                if (this.canAttackPlayer()) {
                    this.attackPlayer();
                }
            }
        }

        // Goblin collision radius
        const goblinCollisionRadius = 1.0;

        // Function to check collision for player and goblins
        function checkCollision(x, z, radius) {
            const collisionPosition = new THREE.Vector3(x, 0, z); // y is irrelevant for horizontal collision

            for (let i = 0; i < mazeWallsBoxes.length; i++) {
                const wallBox = mazeWallsBoxes[i];
                if (wallBox.containsPoint(collisionPosition)) {
                    return true;
                }

                // Additional circle-box collision
                const closestPoint = wallBox.clampPoint(collisionPosition, new THREE.Vector3());
                const distance = collisionPosition.distanceTo(closestPoint);
                if (distance < radius) {
                    return true;
                }
            }

            return false;
        }

        // Spawn goblins at random positions
        function spawnGoblins(number) {
            for (let i = 0; i < number; i++) {
                let spawnX, spawnZ;
                // 50% chance to spawn in the maze
                if (Math.random() < 0.5) {
                    // Spawn inside the maze
                    const cellSize = mazeCellSize;
                    const mazeX = Math.floor(Math.random() * mazeWidth);
                    const mazeY = Math.floor(Math.random() * mazeHeight);
                    spawnX = mazePositionX + mazeX * cellSize;
                    spawnZ = mazePositionZ + mazeY * cellSize;
                } else {
                    // Spawn outside the maze
                    spawnX = Math.random() * 400 - 200;
                    spawnZ = Math.random() * 400 - 200;
                }
                // Ensure goblin spawns on terrain and not colliding with walls
                const spawnY = getTerrainHeightAt(spawnX, spawnZ) + 1;
                if (!checkCollision(spawnX, spawnZ, goblinCollisionRadius)) {
                    goblins.push(new Goblin(spawnX, spawnZ));
                } else {
                    // Retry spawning if collision detected
                    i--;
                }
            }
        }

        spawnGoblins(20); // Spawn 20 goblins

        // In-game time management: Start 1 hour and 10 minutes before dawn (assuming dawn is 6:00 AM)
        let inGameTime = 21; // Start at 4 AM
        let inGameMinutes = 50; // Start with 50 minutes past the hour (4:50 AM)

        // Function to update the sky and lighting based on in-game time
        function updateDayNightCycle(deltaTime) {
            // Increment in-game time
            inGameMinutes += deltaTime;
            if (inGameMinutes >= 60) { // Each minute represents an hour
                inGameMinutes = 0;
                inGameTime += 1;
                if (inGameTime >= 24) {
                    inGameTime = 0;
                }
            }

            // Calculate sun position based on in-game time
            const timeFraction = (inGameTime + inGameMinutes / 60) / 24; // 0 to 1
            const theta = Math.PI * (timeFraction - 0.25); // Adjusted to start at sunrise
            const phi = 2 * Math.PI * (0.25); // Fixed azimuthal angle for simplicity

            sun.setFromSphericalCoords(1, theta, phi);
            sky.material.uniforms['sunPosition'].value.copy(sun);
            sunLight.position.copy(sun);

            // Adjust lighting based on time of day
            if (inGameTime >= 6 && inGameTime < 18) { // Daytime
                ambientLight.intensity = 0.7;
                sunLight.intensity = 1;
                sunLight.color.set(0xffffff);
            } else { // Nighttime
                ambientLight.intensity = 0.2;
                sunLight.intensity = 0.2;
                sunLight.color.set(0x555577); // Dim bluish light
            }

            // Update HUD with current time
            updateTimeDisplay();
        }

        // Update Health Bar
        function updateHealthBar() {
            const healthPercentage = Math.max(playerHealth, 0) / 100; // Ensure non-negative
            healthBar.style.width = `${healthPercentage * 100}%`;
            if (healthPercentage > 0.6) {
                healthBar.style.backgroundColor = 'green';
            } else if (healthPercentage > 0.3) {
                healthBar.style.backgroundColor = 'yellow';
            } else {
                healthBar.style.backgroundColor = 'red';
            }
        }

        // Update Time Display
        function updateTimeDisplay() {
            // Format in-game time to HH:MM AM/PM
            let displayHour = inGameTime;
            let period = 'AM';
            if (displayHour >= 12) {
                period = 'PM';
                if (displayHour > 12) displayHour -= 12;
            }
            if (displayHour === 0) {
                displayHour = 12;
            }
            const displayMinutes = inGameMinutes.toString().padStart(2, '0');
            timeDisplay.innerText = `Time: ${displayHour}:${displayMinutes} ${period}`;
        }

        // Increment in-game time by one hour
        function incrementTimeByOneHour() {
            inGameTime += 1;
            if (inGameTime >= 24) {
                inGameTime = 0;
            }
            // Reset minutes to 0 to represent the start of the new hour
            inGameMinutes = 0;
            // Update sun position and lighting immediately
            updateDayNightCycle(0);
            console.log(`Time increased by 1 hour. Current time: ${inGameTime}:00`);
        }

        // Handle game over
        function gameOver() {
            gameOverScreen.style.display = 'block';
            // Stop the animation loop
            cancelAnimationFrame(animate.id);
        }

        // Handle game win
        function gameWin() {
            youWinScreen.style.display = 'block';
            // Stop the main animation loop
            cancelAnimationFrame(animate.id);
            // Start the YOU WIN animation
            startWinAnimation();
        }

        // Variables for the YOU WIN screen
        let winScene, winCamera, winRenderer, winObjects = [];

        function startWinAnimation() {
            // Set up the YOU WIN scene
            winScene = new THREE.Scene();
            winCamera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
            winCamera.position.z = 5;

            // Create renderer for the YOU WIN screen
            winRenderer = new THREE.WebGLRenderer({ canvas: document.getElementById('winCanvas'), alpha: true });
            winRenderer.setSize(window.innerWidth, window.innerHeight);

            // Add colorful 3D objects (90s themed)
            const colors = [0xFF00FF, 0x00FFFF, 0xFFFF00, 0xFF0000, 0x00FF00];
            const geometries = [
                new THREE.TorusGeometry(1, 0.4, 16, 100),
                new THREE.SphereGeometry(1, 32, 32),
                new THREE.ConeGeometry(1, 2, 32),
                new THREE.BoxGeometry(1, 1, 1),
                new THREE.DodecahedronGeometry(1)
            ];

            for (let i = 0; i < 20; i++) {
                const material = new THREE.MeshBasicMaterial({ color: colors[i % colors.length], wireframe: true });
                const geometry = geometries[i % geometries.length];
                const mesh = new THREE.Mesh(geometry, material);
                mesh.position.set(
                    Math.random() * 10 - 5,
                    Math.random() * 10 - 5,
                    Math.random() * -10
                );
                mesh.rotationSpeed = Math.random() * 0.05;
                winScene.add(mesh);
                winObjects.push(mesh);
            }

            // Animate the YOU WIN screen
            animateWinScreen();
        }

        function animateWinScreen() {
            requestAnimationFrame(animateWinScreen);

            // Rotate objects
            winObjects.forEach(obj => {
                obj.rotation.x += obj.rotationSpeed;
                obj.rotation.y += obj.rotationSpeed;
            });

            winRenderer.render(winScene, winCamera);
        }

        // Handle window resize
        window.addEventListener('resize', () => {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);

            if (winCamera && winRenderer) {
                winCamera.aspect = window.innerWidth / window.innerHeight;
                winCamera.updateProjectionMatrix();
                winRenderer.setSize(window.innerWidth, window.innerHeight);
            }
        });

        // Animation loop to render the scene
        let lastTime = performance.now();
        function animate() {
            animate.id = requestAnimationFrame(animate);

            const currentTime = performance.now();
            const deltaTime = (currentTime - lastTime) / 1000 * 60; // Convert to in-game minutes
            lastTime = currentTime;

            // Update day/night cycle
            updateDayNightCycle(deltaTime / 60); // Adjust deltaTime for smoother increment

            let speed = movement.running ? 0.2 : 0.1;
            if (movement.forward) controls.moveForward(speed);
            if (movement.backward) controls.moveForward(-speed);
            if (movement.left) controls.moveRight(-speed);
            if (movement.right) controls.moveRight(speed);

            // Apply gravity to the player
            velocity.y += gravity;
            camera.position.y += velocity.y;

            // Collision detection with terrain for the player
            const terrainHeight = getInterpolatedHeightAt(camera.position.x, camera.position.z) + 1.6; // Adjusted player height for better collision
            if (camera.position.y < terrainHeight) {
                camera.position.y = terrainHeight;
                velocity.y = 0;
            }

            // Collision detection with maze walls for the player
            const playerCollisionRadius = 1.0; // Adjust as needed
            const playerX = camera.position.x;
            const playerZ = camera.position.z;
            if (checkCollision(playerX, playerZ, playerCollisionRadius)) {
                // Revert player movement if collision detected
                if (movement.forward) controls.moveForward(-speed);
                if (movement.backward) controls.moveForward(speed);
                if (movement.left) controls.moveRight(speed);
                if (movement.right) controls.moveRight(-speed);
            }

            // Update goblins
            goblins.forEach(goblin => goblin.update());

            // Animate the pulsing golden orb
            const pulseSpeed = 2; // Pulses per second
            const pulseScale = 0.1; // Scale variation
            goldenOrb.scale.set(
                1 + Math.sin(performance.now() * 0.002 * pulseSpeed) * pulseScale,
                1 + Math.sin(performance.now() * 0.002 * pulseSpeed) * pulseScale,
                1 + Math.sin(performance.now() * 0.002 * pulseSpeed) * pulseScale
            );

            // Check for collision with the golden orb
            const orbDistance = camera.position.distanceTo(goldenOrb.position);
            if (orbDistance < 2) {
                gameWin();
            }

            // Render the scene
            renderer.render(scene, camera);
        }
        animate();
    </script>
</body>
</html>