← Mike Higgins Home
Custom Code Experiment •

Apache Game

Source Code View HTML / CSS / JavaScript
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>Apache Game</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            -webkit-tap-highlight-color: transparent;
            -webkit-touch-callout: none;
            -webkit-user-select: none;
            user-select: none;
        }
        body {
            background: #0a0a0a;
            color: #00ff00;
            font-family: 'Courier New', monospace;
            overflow: hidden;
            width: 100vw;
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            background-image:
                linear-gradient(rgba(0, 255, 0, 0.05) 1px, transparent 1px),
                linear-gradient(90deg, rgba(0, 255, 0, 0.05) 1px, transparent 1px);
            background-size: 40px 40px;
            touch-action: none;
            position: relative;
        }
        #gameContainer {
            position: relative;
            width: 100%;
            height: 100%;
            max-width: 1200px;
            display: flex;
            border: 1px solid #00ff00;
            box-shadow: 0 0 30px rgba(0, 255, 0, 0.1);
            overflow: hidden;
        }

        #leftPanel, #rightPanel {
            background: rgba(10, 10, 10, 0.95);
            padding: clamp(8px, 2vh, 20px);
            display: flex;
            flex-direction: column;
            gap: clamp(12px, 2vh, 20px);
            font-size: clamp(10px, 1.6vh, 16px);
            border: 1px solid #00ff00;
            min-width: 0;
            flex-shrink: 0;
        }
        #leftPanel {
            border-right: none;
        }
        #rightPanel {
            border-left: none;
        }
        .panel-section {
            border-bottom: 1px solid #00ff00;
            padding-bottom: clamp(8px, 1.5vh, 15px);
            min-height: 0;
            overflow: hidden;
        }
        .stat-label {
            color: #00ff00;
            font-size: clamp(8px, 1.2vh, 12px);
            letter-spacing: 0.05em;
            margin-bottom: 4px;
            text-transform: uppercase;
            opacity: 0.7;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        .stat-value {
            color: #00ff00;
            font-size: clamp(16px, 2.5vh, 24px);
            font-weight: bold;
            text-shadow: 0 0 10px rgba(0, 255, 0, 0.5);
            letter-spacing: 0.05em;
            line-height: 1.2;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        .bar-container {
            width: 100%;
            height: clamp(60px, 15vh, 120px);
            border: 1px solid #00ff00;
            position: relative;
            margin-top: 8px;
            background: rgba(0, 0, 0, 0.5);
            overflow: hidden;
            min-height: 0;
        }
        .bar-fill {
            position: absolute;
            bottom: 0;
            left: 0;
            right: 0;
            background: linear-gradient(to top, #00ff00, #008800);
            transition: height 0.3s ease;
        }
        .bar-grid {
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-image:
                linear-gradient(to bottom, rgba(0, 255, 0, 0.1) 1px, transparent 1px);
            background-size: 100% 10%;
        }
        .bar-value {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            font-size: clamp(10px, 1.6vh, 16px);
            font-weight: bold;
            color: #00ff00;
            text-shadow: 0 0 5px #00ff00;
            white-space: nowrap;
        }
        #gameCanvas {
            flex: 1;
            min-width: 0;
            background: #000;
            border-left: 1px solid #00ff00;
            border-right: 1px solid #00ff00;
            touch-action: none;
            display: block;
        }
        #message {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            font-size: clamp(20px, 4vh, 32px);
            color: #00ff00;
            text-align: center;
            text-shadow: 0 0 20px #00ff00;
            display: none;
            z-index: 10;
            background: rgba(10, 10, 10, 0.95);
            padding: clamp(16px, 4vh, 32px);
            border: 2px solid #00ff00;
            box-shadow: 0 0 40px rgba(0, 255, 0, 0.3);
            max-width: 90vw;
            max-height: 90vh;
            overflow: auto;
        }
        .title-screen {
            text-align: center;
            line-height: 1.5;
        }
        .controls-hint {
            position: absolute;
            bottom: clamp(8px, 2vh, 16px);
            left: 50%;
            transform: translateX(-50%);
            font-size: clamp(10px, 1.4vh, 14px);
            color: #00ff00;
            text-align: center;
            letter-spacing: 0.05em;
            background: rgba(10, 10, 10, 0.95);
            padding: clamp(6px, 1vh, 10px) clamp(12px, 2vh, 16px);
            border: 1px solid #00ff00;
            opacity: 0.8;
            max-width: 90vw;
            white-space: normal;
            line-height: 1.4;
        }

        .mobile-warning {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100vw;
            height: 100vh;
            background: #0a0a0a;
            z-index: 1000;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            padding: 20px;
            text-align: center;
            border: 3px solid #00ff00;
            box-shadow: 0 0 50px rgba(0, 255, 0, 0.5) inset;
        }
        .warning-content {
            max-width: 800px;
            width: 90%;
            padding: 40px;
            background: rgba(10, 10, 10, 0.95);
            border: 2px solid #00ff00;
            box-shadow: 0 0 40px rgba(0, 255, 0, 0.3);
        }
        .warning-title {
            font-size: clamp(24px, 5vh, 48px);
            color: #00ff00;
            margin-bottom: 30px;
            text-shadow: 0 0 20px #00ff00;
            letter-spacing: 0.1em;
            line-height: 1.3;
        }
        .warning-message {
            font-size: clamp(16px, 3vh, 24px);
            color: #00ff00;
            margin-bottom: 40px;
            line-height: 1.6;
            opacity: 0.9;
        }
        .warning-subtitle {
            font-size: clamp(14px, 2.5vh, 20px);
            color: #00ff00;
            margin-top: 40px;
            opacity: 0.7;
            border-top: 1px solid #00ff00;
            padding-top: 20px;
        }
        .scan-effect {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 2px;
            background: rgba(0, 255, 0, 0.5);
            box-shadow: 0 0 10px #00ff00;
            animation: scan 3s linear infinite;
        }
        @keyframes scan {
            0% { top: 0; opacity: 1; }
            50% { opacity: 0.7; }
            100% { top: 100%; opacity: 1; }
        }
        .grid-overlay-warning {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-image:
                linear-gradient(rgba(0, 255, 0, 0.03) 1px, transparent 1px),
                linear-gradient(90deg, rgba(0, 255, 0, 0.03) 1px, transparent 1px);
            background-size: 30px 30px;
            pointer-events: none;
        }
        .version-label {
            position: absolute;
            top: clamp(8px, 2vh, 16px);
            right: clamp(8px, 2vw, 16px);
            font-size: clamp(8px, 1.2vh, 12px);
            color: #00ff00;
            opacity: 0.5;
            letter-spacing: 0.05em;
        }
        .scan-line {
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            height: 1px;
            background: rgba(0, 255, 0, 0.3);
            box-shadow: 0 0 10px rgba(0, 255, 0, 0.5);
            animation: scan 4s linear infinite;
            z-index: 1;
            display: none;
        }
        .data-readout {
            font-family: 'Courier New', monospace;
            font-size: clamp(8px, 1.2vh, 12px);
            color: #00ff00;
            opacity: 0.7;
            letter-spacing: 0.05em;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        .grid-overlay {
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-image:
                linear-gradient(rgba(0, 255, 0, 0.03) 1px, transparent 1px),
                linear-gradient(90deg, rgba(0, 255, 0, 0.03) 1px, transparent 1px);
            background-size: 20px 20px;
            pointer-events: none;
            z-index: 1;
        }

        @media (orientation: landscape) and (min-width: 768px) {
            #gameContainer {
                flex-direction: row;
            }
            #leftPanel, #rightPanel {
                width: clamp(120px, 15vw, 200px);
                height: 100%;
            }
            .controls-hint {
                width: auto;
            }
        }

        @media (orientation: landscape) and (max-width: 767px) {
            #gameContainer {
                flex-direction: row;
            }
            #leftPanel, #rightPanel {
                width: clamp(80px, 18vw, 150px);
                height: 100%;
                padding: clamp(6px, 1.5vh, 12px);
            }
            .stat-value {
                font-size: clamp(12px, 2vh, 18px);
            }
            .bar-container {
                height: clamp(50px, 12vh, 80px);
            }
        }

        @media (orientation: portrait) {
            #gameContainer {
                flex-direction: column;
                max-width: 100%;
            }
            #leftPanel, #rightPanel {
                width: 100%;
                height: auto;
                flex-direction: row;
                flex-wrap: wrap;
                gap: clamp(8px, 1.5vh, 12px);
                padding: clamp(6px, 1.5vh, 12px);
                justify-content: space-between;
            }
            .panel-section {
                flex: 1;
                min-width: 45%;
                max-width: 48%;
                border-right: 1px solid #00ff00;
                border-bottom: none;
                padding-right: clamp(8px, 1.5vh, 12px);
                margin-right: clamp(8px, 1.5vh, 12px);
            }
            .panel-section:last-child {
                border-right: none;
                margin-right: 0;
            }
            .stat-value {
                font-size: clamp(14px, 2.2vh, 20px);
            }
            .bar-container {
                height: clamp(40px, 8vh, 60px);
                margin-top: 4px;
            }
            #gameCanvas {
                order: 1;
                flex: 1;
                min-height: 50vh;
            }
            .controls-hint {
                font-size: clamp(9px, 1.2vh, 11px);
                bottom: clamp(4px, 1vh, 8px);
                width: 95%;
            }
        }

        @media (max-width: 320px) {
            .panel-section {
                min-width: 100%;
                max-width: 100%;
                border-right: none;
                margin-right: 0;
            }
            .stat-label {
                font-size: 10px;
            }
            .stat-value {
                font-size: 14px;
            }
        }

        @media (orientation: landscape) and (max-height: 400px) {
            #leftPanel, #rightPanel {
                display: none;
            }
            #gameCanvas {
                border-left: 1px solid #00ff00;
                border-right: 1px solid #00ff00;
            }
        }

        body.mobile-active #gameContainer {
            display: none !important;
        }
        body.mobile-active .mobile-warning {
            display: flex !important;
        }
    </style>
</head>
<body>
    <!-- FULL-SCREEN MOBILE WARNING -->
    <div class="mobile-warning" id="mobileWarning">
        <div class="grid-overlay-warning"></div>
        <div class="scan-effect"></div>
        <div class="warning-content">
            <div class="warning-title">
                APACHE//CAN.YON<br>
                VER 3.0GB
            </div>

            <div class="warning-message">
                <div style="margin-bottom: 20px; color: #ff0000; text-shadow: 0 0 10px #ff0000;">
                    ⚠️ DESKTOP KEYBOARD REQUIRED ⚠️
                </div>

                <div style="margin-bottom: 30px;">
                    This simulation requires physical keyboard controls<br>
                    and cannot be played on mobile devices.
                </div>

                <div style="font-size: 0.9em; opacity: 0.8;">
                    REQUIRED CONTROLS:<br>
                    [Z]: FIRE WEAPON<br>
                    [X]: LAUNCH MISSILE<br>
                    [←] [→]: NAVIGATE CANYON<br>
                    [SPACE]: START/PAUSE
                </div>
            </div>

            <div class="warning-subtitle">
                Please use a desktop or laptop computer<br>
                with a keyboard to play this game.
            </div>
        </div>
    </div>

    <div id="gameContainer">
        <div class="grid-overlay"></div>
        <div class="scan-line"></div>
        <div class="version-label">VER 3.0GB</div>

        <div id="leftPanel">
            <div class="panel-section">
                <div class="stat-label">HI-SCORE</div>
                <div class="stat-value" id="hiscore">000000</div>
                <div class="data-readout">MAX: 999999</div>
            </div>
            <div class="panel-section">
                <div class="stat-label">SCORE</div>
                <div class="stat-value" id="score">000000</div>
                <div class="data-readout">RUNNING...</div>
            </div>
            <div class="panel-section">
                <div class="stat-label">LIVES</div>
                <div class="stat-value" id="lives">03</div>
                <div class="data-readout">STATUS: ACTIVE</div>
            </div>
            <div class="panel-section">
                <div class="stat-label">SHIELDS</div>
                <div class="bar-container">
                    <div class="bar-grid"></div>
                    <div class="bar-fill" id="shieldsBar"></div>
                    <div class="bar-value" id="shieldsValue">100%</div>
                </div>
                <div class="data-readout">1.8V/10S</div>
            </div>
        </div>

        <canvas id="gameCanvas"></canvas>

        <div id="rightPanel">
            <div class="panel-section">
                <div class="stat-label">TIME</div>
                <div class="stat-value" id="time">000</div>
                <div class="data-readout">SECONDS</div>
            </div>
            <div class="panel-section">
                <div class="stat-label">MISSILES</div>
                <div class="stat-value" id="missiles">10</div>
                <div class="data-readout">5G/6V/12</div>
            </div>
            <div class="panel-section">
                <div class="stat-label">SPEED</div>
                <div class="stat-value" id="speed">2.5</div>
                <div class="data-readout">M/S</div>
            </div>
            <div class="panel-section">
                <div class="stat-label">FUEL</div>
                <div class="bar-container">
                    <div class="bar-grid"></div>
                    <div class="bar-fill" id="fuelBar"></div>
                    <div class="bar-value" id="fuelValue">100%</div>
                </div>
                <div class="data-readout">SYSTEM: ONLINE</div>
            </div>
        </div>

        <div id="message"></div>
        <div class="controls-hint">[Z]: FIRE | [X]: MISSILE | [<]: LEFT | [>]: RIGHT | [SPACE]: START/PAUSE</div>
    </div>

    <script>
        const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
        const mobileWarning = document.getElementById('mobileWarning');
        const body = document.body;

        if (isMobile) {
            body.classList.add('mobile-active');
        }

        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');

        function resizeCanvas() {
            if (isMobile) return;

            const container = document.getElementById('gameContainer');
            const leftPanel = document.getElementById('leftPanel');
            const rightPanel = document.getElementById('rightPanel');

            const containerRect = container.getBoundingClientRect();

            let leftPanelWidth = 0;
            let rightPanelWidth = 0;

            if (leftPanel && leftPanel.offsetParent !== null) {
                leftPanelWidth = leftPanel.getBoundingClientRect().width;
            }

            if (rightPanel && rightPanel.offsetParent !== null) {
                rightPanelWidth = rightPanel.getBoundingClientRect().width;
            }

            canvas.width = containerRect.width - leftPanelWidth - rightPanelWidth;
            canvas.height = containerRect.height;

            if (canvas.width < 100) canvas.width = 100;
            if (canvas.height < 100) canvas.height = 100;

            if (game && game.player) {
                game.player.x = Math.max(10, Math.min(canvas.width - game.player.width - 10, game.player.x));
                game.player.y = canvas.height * 0.7;
            }

            if (game && game.canyon && game.canyon.leftWall.length > 0) {
                const oldCanyon = [...game.canyon.leftWall];
                game.canyon.leftWall = [];
                game.canyon.rightWall = [];
                game.canyon.segmentCounter = 0;

                for (let i = 0; i < 200; i++) {
                    const y = -i * 4;
                    addCanyonSegment(y);
                }
            }
        }

        window.addEventListener('load', () => {
            if (!isMobile) {
                setTimeout(resizeCanvas, 100);
                setTimeout(resizeCanvas, 500);
            }
        });

        let resizeTimeout;
        window.addEventListener('resize', () => {
            if (isMobile) return;
            clearTimeout(resizeTimeout);
            resizeTimeout = setTimeout(resizeCanvas, 100);
        });

        let game = {
            state: 'start',
            score: 0,
            hiscore: 0,
            fuel: 100,
            shields: 100,
            missiles: 10,
            lives: 3,
            scrollSpeed: 2.5,
            time: 0,
            frame: 0,
            canyon: {
                leftWall: [],
                rightWall: [],
                width: 300,
                segmentCounter: 0
            },
            player: {
                x: 0,
                y: 0,
                width: 16,
                height: 16,
                speed: 4
            },
            bullets: [],
            playerMissiles: [],
            enemies: [],
            powerups: [],
            forceFields: [],
            particles: [],
            keys: {},
            enemySpawnTimer: 0,
            powerupSpawnTimer: 0
        };

        if (!isMobile) {
            function initCanyon() {
                game.canyon.leftWall = [];
                game.canyon.rightWall = [];
                game.canyon.segmentCounter = 0;

                for (let i = 0; i < 200; i++) {
                    const y = -i * 4;
                    addCanyonSegment(y);
                }
            }

            function addCanyonSegment(y) {
                const centerX = canvas.width / 2;
                const t = game.canyon.segmentCounter;

                const variation = Math.sin(t * 0.0234) * 70 +
                                Math.cos(t * 0.0431) * 55 +
                                Math.sin(t * 0.0627) * 40 +
                                Math.cos(t * 0.0089) * 60 +
                                Math.sin(t * 0.0153) * 35;

                const narrowing = Math.sin(t * 0.0179) * 55 +
                                Math.cos(t * 0.0347) * 45 +
                                Math.sin(t * 0.0521) * 30;

                const leftX = centerX - game.canyon.width / 2 + variation - narrowing;
                const rightX = centerX + game.canyon.width / 2 + variation + narrowing;

                game.canyon.leftWall.push({ x: leftX, y: y });
                game.canyon.rightWall.push({ x: rightX, y: y });
                game.canyon.segmentCounter++;
            }

            function updateCanyon() {
                game.canyon.width = Math.min(300, canvas.width * 0.7);

                game.canyon.leftWall.forEach(p => p.y += game.scrollSpeed);
                game.canyon.rightWall.forEach(p => p.y += game.scrollSpeed);

                while (game.canyon.leftWall[0] && game.canyon.leftWall[0].y > canvas.height + 50) {
                    game.canyon.leftWall.shift();
                    game.canyon.rightWall.shift();
                }

                while (game.canyon.leftWall.length < canvas.height / 4 + 100) {
                    const lastY = game.canyon.leftWall[game.canyon.leftWall.length - 1].y;
                    const newY = lastY - 4;
                    addCanyonSegment(newY);
                }
            }

            function drawCanyon() {
                ctx.fillStyle = '#000';
                ctx.fillRect(0, 0, canvas.width, canvas.height);

                ctx.strokeStyle = '#00ff00';
                ctx.lineWidth = Math.max(1, canvas.width / 800);

                ctx.beginPath();
                for (let i = 0; i < game.canyon.leftWall.length; i++) {
                    if (i % 2 === 0) {
                        const p = game.canyon.leftWall[i];
                        if (i === 0) {
                            ctx.moveTo(p.x, p.y);
                        } else {
                            ctx.lineTo(p.x, p.y);
                        }
                    }
                }
                ctx.stroke();

                ctx.beginPath();
                for (let i = 0; i < game.canyon.rightWall.length; i++) {
                    if (i % 2 === 0) {
                        const p = game.canyon.rightWall[i];
                        if (i === 0) {
                            ctx.moveTo(p.x, p.y);
                        } else {
                            ctx.lineTo(p.x, p.y);
                        }
                    }
                }
                ctx.stroke();

                ctx.strokeStyle = 'rgba(0, 255, 0, 0.1)';
                const gridStep = Math.max(10, Math.floor(canvas.height / 40));
                for (let i = 0; i < game.canyon.leftWall.length; i += gridStep) {
                    if (game.canyon.leftWall[i] && game.canyon.rightWall[i]) {
                        ctx.beginPath();
                        ctx.moveTo(game.canyon.leftWall[i].x, game.canyon.leftWall[i].y);
                        ctx.lineTo(game.canyon.rightWall[i].x, game.canyon.rightWall[i].y);
                        ctx.stroke();
                    }
                }

                ctx.strokeStyle = 'rgba(0, 255, 0, 0.05)';
                ctx.lineWidth = 0.5;
                const gridSize = Math.max(30, canvas.width / 20);
                for (let x = gridSize; x < canvas.width; x += gridSize) {
                    ctx.beginPath();
                    ctx.moveTo(x, 0);
                    ctx.lineTo(x, canvas.height);
                    ctx.stroke();
                }
                for (let y = gridSize; y < canvas.height; y += gridSize) {
                    ctx.beginPath();
                    ctx.moveTo(0, y);
                    ctx.lineTo(canvas.width, y);
                    ctx.stroke();
                }
            }

            function drawPlayer() {
                const p = game.player;
                const scale = Math.max(1, canvas.width / 800);
                const x = Math.floor(p.x);
                const y = Math.floor(p.y);

                ctx.fillStyle = '#00ff00';

                const scaledWidth = game.player.width * scale;
                const scaledHeight = game.player.height * scale;

                const rotorPhase = Math.floor(game.frame / 3) % 2;
                if (rotorPhase === 0) {
                    ctx.fillRect(x - 6 * scale, y + 2 * scale, 28 * scale, 2 * scale);
                } else {
                    ctx.fillRect(x + 6 * scale, y, 2 * scale, 6 * scale);
                }

                ctx.fillRect(x + 4 * scale, y + 6 * scale, 8 * scale, 6 * scale);

                ctx.fillRect(x + 2 * scale, y + 8 * scale, 12 * scale, 4 * scale);

                ctx.fillRect(x + 12 * scale, y + 9 * scale, 4 * scale, 2 * scale);

                ctx.fillRect(x + 15 * scale, y + 7 * scale, 2 * scale, 6 * scale);

                ctx.fillRect(x + 2 * scale, y + 12 * scale, 2 * scale, 2 * scale);
                ctx.fillRect(x + 10 * scale, y + 12 * scale, 2 * scale, 2 * scale);
            }

            function spawnEnemy() {
                const wallIndex = Math.min(60, Math.floor(game.canyon.leftWall.length * 0.3));
                if (wallIndex >= game.canyon.leftWall.length) return;

                const leftBound = game.canyon.leftWall[wallIndex].x + 15;
                const rightBound = game.canyon.rightWall[wallIndex].x - 30;
                const types = ['drone', 'uav', 'mine'];
                const type = types[Math.floor(Math.random() * types.length)];

                game.enemies.push({
                    x: leftBound + Math.random() * (rightBound - leftBound),
                    y: -20,
                    vx: (Math.random() - 0.5) * 1.5,
                    vy: type === 'mine' ? 0.5 : 1.5,
                    width: 16,
                    height: 16,
                    type: type,
                    health: type === 'mine' ? 1 : (type === 'uav' ? 3 : 2),
                    shootTimer: 60 + Math.random() * 60
                });
            }

            function spawnPowerup(type) {
                const wallIndex = Math.min(60, Math.floor(game.canyon.leftWall.length * 0.3));
                if (wallIndex >= game.canyon.leftWall.length) return;

                const leftBound = game.canyon.leftWall[wallIndex].x + 15;
                const rightBound = game.canyon.rightWall[wallIndex].x - 30;

                game.powerups.push({
                    x: leftBound + Math.random() * (rightBound - leftBound),
                    y: -20,
                    width: 12,
                    height: 12,
                    type: type,
                    vy: 1.5,
                    rotation: 0
                });
            }

            function spawnForceField() {
                const wallIndex = Math.min(60, Math.floor(game.canyon.leftWall.length * 0.3));
                if (wallIndex >= game.canyon.leftWall.length) return;

                const leftBound = game.canyon.leftWall[wallIndex].x + 15;
                const rightBound = game.canyon.rightWall[wallIndex].x - 50;

                game.forceFields.push({
                    x: leftBound + Math.random() * (rightBound - leftBound),
                    y: -30,
                    width: Math.min(40, canvas.width * 0.1),
                    height: 80,
                    health: 6,
                    vy: 1,
                    pulse: 0
                });
            }

            function createExplosion(x, y) {
                for (let i = 0; i < 12; i++) {
                    const angle = (i * Math.PI * 2) / 12;
                    game.particles.push({
                        x: x,
                        y: y,
                        vx: Math.cos(angle) * 3,
                        vy: Math.sin(angle) * 3,
                        life: 30,
                        size: 3
                    });
                }
            }

            function update() {
                if (game.state !== 'playing') return;

                game.frame++;
                if (game.frame % 60 === 0) game.time++;

                updateCanyon();

                const p = game.player;

                if (game.keys[','] || game.keys['<']) {
                    p.x -= p.speed;
                }
                if (game.keys['.'] || game.keys['>']) {
                    p.x += p.speed;
                }

                let playerCenterY = 0;
                let minDist = Infinity;
                for (let i = 0; i < game.canyon.leftWall.length; i++) {
                    const dist = Math.abs(game.canyon.leftWall[i].y - game.player.y);
                    if (dist < minDist) {
                        minDist = dist;
                        playerCenterY = i;
                    }
                }

                if (playerCenterY < game.canyon.leftWall.length) {
                    const leftBound = game.canyon.leftWall[playerCenterY].x + 10;
                    const rightBound = game.canyon.rightWall[playerCenterY].x - p.width - 10;
                    p.x = Math.max(leftBound, Math.min(rightBound, p.x));
                }

                if (playerCenterY < game.canyon.leftWall.length) {
                    const leftBound = game.canyon.leftWall[playerCenterY].x + 10;
                    const rightBound = game.canyon.rightWall[playerCenterY].x - p.width - 10;
                    if (p.x <= leftBound + 2 || p.x >= rightBound - 2) {
                        game.shields -= 0.5;
                        if (game.shields <= 0) {
                            loseLife();
                        }
                    }
                }

                if (game.keys['z'] && game.frame % 6 === 0) {
                    game.bullets.push({
                        x: p.x + p.width / 2 - 1,
                        y: p.y,
                        vy: -8,
                        width: 2,
                        height: 8
                    });
                }

                if (game.keys['x'] && !game.keys['x_fired'] && game.missiles > 0) {
                    game.missiles--;
                    let target = game.enemies[0];
                    game.playerMissiles.push({
                        x: p.x + p.width / 2 - 2,
                        y: p.y,
                        vx: 0,
                        vy: -6,
                        target: target,
                        width: 4,
                        height: 12
                    });
                    game.keys['x_fired'] = true;
                }
                if (!game.keys['x']) game.keys['x_fired'] = false;

                game.bullets = game.bullets.filter(b => {
                    b.y += b.vy;
                    return b.y > -10;
                });

                game.playerMissiles = game.playerMissiles.filter(m => {
                    if (m.target && game.enemies.includes(m.target)) {
                        const dx = m.target.x - m.x;
                        const dy = m.target.y - m.y;
                        const dist = Math.sqrt(dx * dx + dy * dy);
                        if (dist > 0) {
                            m.vx += (dx / dist) * 0.5;
                            m.vy += (dy / dist) * 0.5;
                        }
                    }
                    m.x += m.vx;
                    m.y += m.vy;
                    const speed = Math.sqrt(m.vx * m.vx + m.vy * m.vy);
                    if (speed > 8) {
                        m.vx = (m.vx / speed) * 8;
                        m.vy = (m.vy / speed) * 8;
                    }
                    return m.y > -10 && m.y < canvas.height;
                });

                game.enemySpawnTimer++;
                if (game.enemySpawnTimer > 80 && game.enemies.length < 6) {
                    spawnEnemy();
                    game.enemySpawnTimer = 0;

                    if (Math.random() < 0.15) {
                        spawnForceField();
                    }
                }

                game.powerupSpawnTimer++;
                if (game.powerupSpawnTimer > 240) {
                    const rand = Math.random();
                    if (rand < 0.4) spawnPowerup('fuel');
                    else if (rand < 0.7) spawnPowerup('shield');
                    else spawnPowerup('missile');
                    game.powerupSpawnTimer = 0;
                }

                game.enemies = game.enemies.filter(e => {
                    e.x += e.vx;
                    e.y += e.vy;

                    for (let i = game.bullets.length - 1; i >= 0; i--) {
                        const b = game.bullets[i];
                        if (b.x >= e.x && b.x <= e.x + e.width &&
                            b.y >= e.y && b.y <= e.y + e.height) {
                            e.health--;
                            game.bullets.splice(i, 1);
                            if (e.health <= 0) {
                                createExplosion(e.x + e.width / 2, e.y + e.height / 2);
                                game.score += e.type === 'uav' ? 300 : (e.type === 'mine' ? 100 : 200);
                                if (game.score > game.hiscore) game.hiscore = game.score;
                                return false;
                            }
                            break;
                        }
                    }

                    for (let i = game.playerMissiles.length - 1; i >= 0; i--) {
                        const m = game.playerMissiles[i];
                        if (m.x >= e.x && m.x <= e.x + e.width &&
                            m.y >= e.y && m.y <= e.y + e.height) {
                            createExplosion(e.x + e.width / 2, e.y + e.height / 2);
                            game.playerMissiles.splice(i, 1);
                            game.score += e.type === 'uav' ? 300 : (e.type === 'mine' ? 100 : 200);
                            if (game.score > game.hiscore) game.hiscore = game.score;
                            return false;
                        }
                    }

                    if (e.x < p.x + p.width && e.x + e.width > p.x &&
                        e.y < p.y + p.height && e.y + e.height > p.y) {
                        game.shields -= 25;
                        createExplosion(e.x + e.width / 2, e.y + e.height / 2);
                        if (game.shields <= 0) {
                            loseLife();
                        }
                        return false;
                    }

                    return e.y < canvas.height + 20;
                });

                game.powerups = game.powerups.filter(pw => {
                    pw.y += pw.vy;
                    pw.rotation += 0.1;

                    if (pw.x < p.x + p.width && pw.x + pw.width > p.x &&
                        pw.y < p.y + p.height && pw.y + pw.height > p.y) {
                        if (pw.type === 'fuel') {
                            game.fuel = Math.min(100, game.fuel + 30);
                        } else if (pw.type === 'shield') {
                            game.shields = Math.min(100, game.shields + 40);
                        } else if (pw.type === 'missile') {
                            game.missiles = Math.min(99, game.missiles + 5);
                        }
                        return false;
                    }

                    return pw.y < canvas.height;
                });

                game.forceFields.forEach(f => {
                    f.y += f.vy;
                    f.pulse = (f.pulse + 0.1) % (Math.PI * 2);
                });

                game.forceFields = game.forceFields.filter(f => {
                    for (let i = game.bullets.length - 1; i >= 0; i--) {
                        const b = game.bullets[i];
                        if (b.x >= f.x && b.x <= f.x + f.width &&
                            b.y >= f.y && b.y <= f.y + f.height) {
                            f.health--;
                            game.bullets.splice(i, 1);
                            if (f.health <= 0) {
                                createExplosion(f.x + f.width / 2, f.y + f.height / 2);
                                game.score += 400;
                                if (game.score > game.hiscore) game.hiscore = game.score;
                                return false;
                            }
                            break;
                        }
                    }

                    for (let i = game.playerMissiles.length - 1; i >= 0; i--) {
                        const m = game.playerMissiles[i];
                        if (m.x >= f.x && m.x <= f.x + f.width &&
                            m.y >= f.y && m.y <= f.y + f.height) {
                            f.health -= 2;
                            game.playerMissiles.splice(i, 1);
                            createExplosion(f.x + f.width / 2, f.y + f.height / 2);
                            if (f.health <= 0) {
                                game.score += 400;
                                if (game.score > game.hiscore) game.hiscore = game.score;
                                return false;
                            }
                            break;
                        }
                    }

                    if (f.x < p.x + p.width && f.x + f.width > p.x &&
                        f.y < p.y + p.height && f.y + f.height > p.y) {
                        game.shields -= 30;
                        createExplosion(p.x + p.width / 2, p.y + p.height / 2);
                        if (game.shields <= 0) {
                            loseLife();
                        }
                        return false;
                    }

                    return f.y < canvas.height;
                });

                game.particles = game.particles.filter(pt => {
                    pt.x += pt.vx;
                    pt.y += pt.vy;
                    pt.life--;
                    pt.size *= 0.95;
                    return pt.life > 0 && pt.size > 0.5;
                });

                game.fuel -= 0.03;
                if (game.fuel <= 0) {
                    loseLife();
                }

                if (game.frame % 900 === 0) {
                    game.scrollSpeed = Math.min(4.5, game.scrollSpeed + 0.2);
                }

                updateHUD();
            }

            function drawEnemies() {
                game.enemies.forEach(e => {
                    const x = Math.floor(e.x);
                    const y = Math.floor(e.y);

                    ctx.strokeStyle = '#00ff00';
                    ctx.lineWidth = 1;
                    ctx.fillStyle = 'rgba(0, 255, 0, 0.1)';

                    if (e.type === 'drone') {
                        ctx.fillRect(x, y, e.width, e.height);
                        ctx.strokeRect(x, y, e.width, e.height);
                        ctx.beginPath();
                        ctx.moveTo(x, y);
                        ctx.lineTo(x + e.width, y + e.height);
                        ctx.moveTo(x + e.width, y);
                        ctx.lineTo(x, y + e.height);
                        ctx.stroke();
                    } else if (e.type === 'uav') {
                        ctx.beginPath();
                        for (let i = 0; i < 6; i++) {
                            const angle = (i * Math.PI) / 3;
                            const px = x + e.width/2 + Math.cos(angle) * e.width/2;
                            const py = y + e.height/2 + Math.sin(angle) * e.height/2;
                            if (i === 0) ctx.moveTo(px, py);
                            else ctx.lineTo(px, py);
                        }
                        ctx.closePath();
                        ctx.fill();
                        ctx.stroke();
                    } else {
                        ctx.beginPath();
                        ctx.arc(x + e.width/2, y + e.height/2, e.width/2, 0, Math.PI * 2);
                        ctx.fill();
                        ctx.stroke();
                        ctx.fillStyle = '#00ff00';
                        ctx.beginPath();
                        ctx.arc(x + e.width/2, y + e.height/2, 2, 0, Math.PI * 2);
                        ctx.fill();
                    }

                    const healthRatio = e.health / (e.type === 'uav' ? 3 : (e.type === 'mine' ? 1 : 2));
                    ctx.fillStyle = healthRatio > 0.5 ? '#00ff00' : healthRatio > 0.2 ? '#ffff00' : '#ff0000';
                    ctx.fillRect(x, y - 4, e.width * healthRatio, 2);
                });
            }

            function drawPowerups() {
                game.powerups.forEach(pw => {
                    const x = Math.floor(pw.x);
                    const y = Math.floor(pw.y);

                    ctx.save();
                    ctx.translate(x + pw.width/2, y + pw.height/2);
                    ctx.rotate(pw.rotation);

                    ctx.strokeStyle = '#00ff00';
                    ctx.lineWidth = 1;
                    ctx.fillStyle = 'rgba(0, 255, 0, 0.2)';

                    ctx.beginPath();
                    ctx.moveTo(0, -pw.height/2);
                    ctx.lineTo(pw.width/2, 0);
                    ctx.lineTo(0, pw.height/2);
                    ctx.lineTo(-pw.width/2, 0);
                    ctx.closePath();
                    ctx.fill();
                    ctx.stroke();

                    ctx.fillStyle = '#00ff00';
                    ctx.font = '8px monospace';
                    ctx.textAlign = 'center';
                    ctx.textBaseline = 'middle';

                    if (pw.type === 'fuel') ctx.fillText('F', 0, 0);
                    else if (pw.type === 'shield') ctx.fillText('S', 0, 0);
                    else ctx.fillText('M', 0, 0);

                    ctx.restore();
                });
            }

            function draw() {
                if (canvas.width <= 0 || canvas.height <= 0) {
                    resizeCanvas();
                    return;
                }

                drawCanyon();

                game.forceFields.forEach(f => {
                    const x = Math.floor(f.x);
                    const y = Math.floor(f.y);

                    ctx.strokeStyle = '#00ff00';
                    ctx.lineWidth = 2;
                    ctx.globalAlpha = 0.3 + Math.sin(f.pulse) * 0.2;

                    for (let i = 0; i < f.width; i += 8) {
                        const offset = Math.sin(f.pulse + i * 0.2) * 4;
                        ctx.beginPath();
                        ctx.moveTo(x + i, y);
                        ctx.lineTo(x + i + offset, y + f.height);
                        ctx.stroke();
                    }

                    ctx.globalAlpha = 1;
                    ctx.strokeRect(x, y, f.width, f.height);

                    for (let i = 0; i < 3; i++) {
                        for (let j = 0; j < 6; j++) {
                            const sparkX = x + (i + 1) * f.width/4;
                            const sparkY = y + (j + 1) * f.height/7;
                            const pulse = Math.sin(f.pulse + i + j) * 2;
                            ctx.fillStyle = '#00ff00';
                            ctx.fillRect(sparkX + pulse, sparkY + pulse, 2, 2);
                        }
                    }
                });

                drawPowerups();
                drawEnemies();

                game.bullets.forEach(b => {
                    ctx.fillStyle = '#00ff00';
                    ctx.fillRect(Math.floor(b.x), Math.floor(b.y), b.width, b.height);
                    ctx.fillStyle = 'rgba(0, 255, 0, 0.3)';
                    ctx.fillRect(Math.floor(b.x) - 1, Math.floor(b.y) - 1, b.width + 2, b.height + 2);
                });

                game.playerMissiles.forEach(m => {
                    ctx.fillStyle = '#00ff00';
                    ctx.fillRect(Math.floor(m.x), Math.floor(m.y), m.width, m.height);
                    for (let i = 0; i < 3; i++) {
                        ctx.fillStyle = `rgba(0, 255, 0, ${0.5 - i * 0.15})`;
                        ctx.fillRect(Math.floor(m.x), Math.floor(m.y) + m.height + i * 3, m.width, 2);
                    }
                });

                game.particles.forEach(pt => {
                    ctx.fillStyle = `rgba(0, 255, 0, ${pt.life / 30})`;
                    ctx.fillRect(Math.floor(pt.x), Math.floor(pt.y), pt.size, pt.size);
                });

                drawPlayer();

                if (game.state === 'start') {
                    ctx.fillStyle = 'rgba(10, 10, 10, 0.95)';
                    ctx.fillRect(0, 0, canvas.width, canvas.height);
                    ctx.fillStyle = '#00ff00';
                    ctx.font = `bold ${Math.min(48, canvas.width / 15)}px monospace`;
                    ctx.textAlign = 'center';
                    ctx.fillText('APACHE//CAN.YON', canvas.width / 2, canvas.height / 2 - 60);
                    ctx.font = `${Math.min(24, canvas.width / 25)}px monospace`;
                    ctx.fillText('SYSTEM BOOT...', canvas.width / 2, canvas.height / 2 - 10);
                    ctx.fillText('VER 3.0GB', canvas.width / 2, canvas.height / 2 + 20);
                    ctx.font = `${Math.min(16, canvas.width / 35)}px monospace`;
                    ctx.fillText('INITIATE SEQUENCE [SPACE]', canvas.width / 2, canvas.height / 2 + 60);

                    const loadWidth = Math.min(300, canvas.width * 0.7);
                    const loadProgress = (game.frame % 120) / 120;
                    ctx.strokeStyle = '#00ff00';
                    ctx.strokeRect(canvas.width/2 - loadWidth/2, canvas.height/2 + 90, loadWidth, 4);
                    ctx.fillStyle = '#00ff00';
                    ctx.fillRect(canvas.width/2 - loadWidth/2, canvas.height/2 + 90, loadWidth * loadProgress, 4);
                }
            }

            function updateHUD() {
                document.getElementById('score').textContent = game.score.toString().padStart(6, '0');
                document.getElementById('hiscore').textContent = game.hiscore.toString().padStart(6, '0');
                document.getElementById('lives').textContent = game.lives.toString().padStart(2, '0');
                document.getElementById('missiles').textContent = game.missiles.toString().padStart(2, '0');
                document.getElementById('time').textContent = game.time.toString().padStart(3, '0');
                document.getElementById('speed').textContent = game.scrollSpeed.toFixed(1);

                const fuelBar = document.getElementById('fuelBar');
                const shieldsBar = document.getElementById('shieldsBar');
                const fuelValue = document.getElementById('fuelValue');
                const shieldsValue = document.getElementById('shieldsValue');

                fuelBar.style.height = game.fuel + '%';
                shieldsBar.style.height = game.shields + '%';

                fuelValue.textContent = Math.floor(game.fuel) + '%';
                shieldsValue.textContent = Math.floor(game.shields) + '%';

                if (game.fuel < 30) {
                    fuelBar.style.background = 'linear-gradient(to top, #ff0000, #880000)';
                    fuelValue.style.color = '#ff0000';
                } else {
                    fuelBar.style.background = 'linear-gradient(to top, #00ff00, #008800)';
                    fuelValue.style.color = '#00ff00';
                }

                if (game.shields < 30) {
                    shieldsBar.style.background = 'linear-gradient(to top, #ff0000, #880000)';
                    shieldsValue.style.color = '#ff0000';
                } else {
                    shieldsBar.style.background = 'linear-gradient(to top, #00ff00, #008800)';
                    shieldsValue.style.color = '#00ff00';
                }

                const scanLine = document.querySelector('.scan-line');
                if (game.state === 'playing') {
                    scanLine.style.display = 'block';
                } else {
                    scanLine.style.display = 'none';
                }
            }

            function loseLife() {
                game.lives--;
                if (game.lives <= 0) {
                    gameOver();
                } else {
                    game.shields = 100;
                    game.fuel = 100;
                    game.player.x = canvas.width / 2 - game.player.width / 2;
                    game.enemies = [];
                    game.bullets = [];
                    game.playerMissiles = [];
                }
            }

            function gameOver() {
                game.state = 'gameover';
                const msg = document.getElementById('message');
                msg.innerHTML = `<div class="title-screen">
                    <div style="font-size: clamp(20px, 32px, 4vh); margin-bottom: 20px;">SYSTEM FAILURE</div>
                    <div>MISSION TERMINATED</div>
                    <div style="margin: 20px 0; font-size: clamp(16px, 24px, 3vh);">SCORE: ${game.score.toString().padStart(6, '0')}</div>
                    <div>TIME: ${game.time.toString().padStart(3, '0')} SECONDS</div>
                    <div style="margin-top: 30px; font-size: clamp(12px, 16px, 2vh);">[SPACE] TO REBOOT</div>
                </div>`;
                msg.style.display = 'block';
            }

            function restart() {
                game.score = 0;
                game.fuel = 100;
                game.shields = 100;
                game.missiles = 10;
                game.lives = 3;
                game.scrollSpeed = 2.5;
                game.time = 0;
                game.frame = 0;
                game.bullets = [];
                game.playerMissiles = [];
                game.enemies = [];
                game.powerups = [];
                game.forceFields = [];
                game.particles = [];
                game.enemySpawnTimer = 0;
                game.powerupSpawnTimer = 0;
                game.player.x = canvas.width / 2 - game.player.width / 2;
                game.player.y = canvas.height * 0.7;

                initCanyon();

                document.getElementById('message').style.display = 'none';
                game.state = 'playing';
            }

            function gameLoop() {
                update();
                draw();
                requestAnimationFrame(gameLoop);
            }

            document.addEventListener('keydown', e => {
                game.keys[e.key.toLowerCase()] = true;

                if (e.key === ' ') {
                    e.preventDefault();
                    if (game.state === 'start' || game.state === 'gameover') {
                        restart();
                    } else if (game.state === 'playing') {
                        game.state = 'paused';
                        document.getElementById('message').innerHTML = `<div class="title-screen">
                            <div style="font-size: clamp(20px, 32px, 4vh); margin-bottom: 20px;">SYSTEM PAUSED</div>
                            <div>[SPACE] TO RESUME</div>
                        </div>`;
                        document.getElementById('message').style.display = 'block';
                    } else if (game.state === 'paused') {
                        game.state = 'playing';
                        document.getElementById('message').style.display = 'none';
                    }
                }

                if (e.key === 'Escape') {
                    if (game.state === 'playing') {
                        game.state = 'paused';
                        document.getElementById('message').innerHTML = `<div class="title-screen">
                            <div style="font-size: clamp(20px, 32px, 4vh); margin-bottom: 20px;">SYSTEM PAUSED</div>
                            <div>[SPACE] TO RESUME</div>
                        </div>`;
                        document.getElementById('message').style.display = 'block';
                    }
                }
            });

            document.addEventListener('keyup', e => {
                game.keys[e.key.toLowerCase()] = false;
            });

            window.addEventListener('load', () => {
                setTimeout(() => {
                    game.player.x = canvas.width / 2 - game.player.width / 2;
                    game.player.y = canvas.height * 0.7;
                    initCanyon();
                    updateHUD();
                    gameLoop();
                }, 500);
            });
        }

        document.addEventListener('contextmenu', e => {
            e.preventDefault();
        });
    </script>
</body>
</html>